Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b17463bcbc | |||
| 76de81bca4 | |||
| 842ed77f5b | |||
| 96ed86649a |
@@ -89,6 +89,19 @@ $orderId = (int)($this -> order['id'] ?? 0);
|
|||||||
<div>
|
<div>
|
||||||
<b><?= $this -> order[ 'payment_method' ];?> </b>
|
<b><?= $this -> order[ 'payment_method' ];?> </b>
|
||||||
</div>
|
</div>
|
||||||
|
<? if ( !empty($this -> order['apilo_order_id']) ):?>
|
||||||
|
<br/>
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-cloud"></i> Apilo: <b style="color: #27ae60;">tak</b>
|
||||||
|
— ID: <b id="order-apilo-id"><?= htmlspecialchars((string)$this -> order['apilo_order_id'], ENT_QUOTES, 'UTF-8');?></b>
|
||||||
|
<i class="fa fa-copy" onclick="copyToClipboard( 'order-apilo-id' ); return false;"></i>
|
||||||
|
</div>
|
||||||
|
<? else:?>
|
||||||
|
<br/>
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-cloud"></i> Apilo: <b style="color: #c0392b;">nie</b>
|
||||||
|
</div>
|
||||||
|
<? endif;?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="paid-status panel">
|
<div class="paid-status panel">
|
||||||
|
|||||||
@@ -393,17 +393,38 @@ class OrderAdminService
|
|||||||
global $mdb;
|
global $mdb;
|
||||||
|
|
||||||
if ($orderId <= 0) {
|
if ($orderId <= 0) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$mdb,
|
||||||
|
'resend_order',
|
||||||
|
$orderId,
|
||||||
|
'Nieprawidlowe ID zamowienia (orderId <= 0)',
|
||||||
|
['order_id' => $orderId]
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$order = $this->orders->findForAdmin($orderId);
|
$order = $this->orders->findForAdmin($orderId);
|
||||||
if (empty($order) || empty($order['apilo_order_id'])) {
|
if (empty($order) || empty($order['apilo_order_id'])) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$mdb,
|
||||||
|
'resend_order',
|
||||||
|
$orderId,
|
||||||
|
'Brak zamowienia lub brak apilo_order_id',
|
||||||
|
['order_found' => !empty($order), 'apilo_order_id' => $order['apilo_order_id'] ?? null]
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository( $mdb );
|
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository( $mdb );
|
||||||
$accessToken = $integrationsRepository -> apiloGetAccessToken();
|
$accessToken = $integrationsRepository -> apiloGetAccessToken();
|
||||||
if (!$accessToken) {
|
if (!$accessToken) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$mdb,
|
||||||
|
'resend_order',
|
||||||
|
$orderId,
|
||||||
|
'Nie udalo sie uzyskac tokenu Apilo (access token)',
|
||||||
|
['apilo_order_id' => $order['apilo_order_id']]
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,6 +662,17 @@ class OrderAdminService
|
|||||||
$apilo_settings = $integrationsRepository->getSettings('apilo');
|
$apilo_settings = $integrationsRepository->getSettings('apilo');
|
||||||
|
|
||||||
if (!$apilo_settings['enabled'] || !$apilo_settings['access-token'] || !$apilo_settings['sync_orders']) {
|
if (!$apilo_settings['enabled'] || !$apilo_settings['access-token'] || !$apilo_settings['sync_orders']) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'payment_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Pominięto sync płatności — Apilo wyłączone lub brak tokenu/sync_orders',
|
||||||
|
[
|
||||||
|
'enabled' => $apilo_settings['enabled'] ?? false,
|
||||||
|
'has_token' => !empty($apilo_settings['access-token']),
|
||||||
|
'sync_orders' => $apilo_settings['sync_orders'] ?? false,
|
||||||
|
]
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,8 +682,22 @@ class OrderAdminService
|
|||||||
|
|
||||||
if (!$order['apilo_order_id']) {
|
if (!$order['apilo_order_id']) {
|
||||||
// Zamówienie jeszcze nie wysłane do Apilo — kolejkuj sync płatności na później
|
// Zamówienie jeszcze nie wysłane do Apilo — kolejkuj sync płatności na później
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'payment_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Brak apilo_order_id — płatność zakolejkowana do sync',
|
||||||
|
['apilo_order_id' => $order['apilo_order_id'] ?? null]
|
||||||
|
);
|
||||||
self::queueApiloSync((int)$order['id'], true, null, 'awaiting_apilo_order');
|
self::queueApiloSync((int)$order['id'], true, null, 'awaiting_apilo_order');
|
||||||
} elseif (!$this->syncApiloPayment($order)) {
|
} elseif (!$this->syncApiloPayment($order)) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'payment_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Sync płatności nieudany — zakolejkowano ponowną próbę',
|
||||||
|
['apilo_order_id' => $order['apilo_order_id']]
|
||||||
|
);
|
||||||
self::queueApiloSync((int)$order['id'], true, null, 'payment_sync_failed');
|
self::queueApiloSync((int)$order['id'], true, null, 'payment_sync_failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,6 +711,18 @@ class OrderAdminService
|
|||||||
$apilo_settings = $integrationsRepository->getSettings('apilo');
|
$apilo_settings = $integrationsRepository->getSettings('apilo');
|
||||||
|
|
||||||
if (!$apilo_settings['enabled'] || !$apilo_settings['access-token'] || !$apilo_settings['sync_orders']) {
|
if (!$apilo_settings['enabled'] || !$apilo_settings['access-token'] || !$apilo_settings['sync_orders']) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'status_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Pominięto sync statusu — Apilo wyłączone lub brak tokenu/sync_orders',
|
||||||
|
[
|
||||||
|
'target_status' => $status,
|
||||||
|
'enabled' => $apilo_settings['enabled'] ?? false,
|
||||||
|
'has_token' => !empty($apilo_settings['access-token']),
|
||||||
|
'sync_orders' => $apilo_settings['sync_orders'] ?? false,
|
||||||
|
]
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,8 +732,22 @@ class OrderAdminService
|
|||||||
|
|
||||||
if (!$order['apilo_order_id']) {
|
if (!$order['apilo_order_id']) {
|
||||||
// Zamówienie jeszcze nie wysłane do Apilo — kolejkuj sync statusu na później
|
// Zamówienie jeszcze nie wysłane do Apilo — kolejkuj sync statusu na później
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'status_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Brak apilo_order_id — status zakolejkowany do sync',
|
||||||
|
['apilo_order_id' => $order['apilo_order_id'] ?? null, 'target_status' => $status]
|
||||||
|
);
|
||||||
self::queueApiloSync((int)$order['id'], false, $status, 'awaiting_apilo_order');
|
self::queueApiloSync((int)$order['id'], false, $status, 'awaiting_apilo_order');
|
||||||
} elseif (!$this->syncApiloStatus($order, $status)) {
|
} elseif (!$this->syncApiloStatus($order, $status)) {
|
||||||
|
\Domain\Integrations\ApiloLogger::log(
|
||||||
|
$db,
|
||||||
|
'status_sync',
|
||||||
|
(int)$order['id'],
|
||||||
|
'Sync statusu nieudany — zakolejkowano ponowną próbę',
|
||||||
|
['apilo_order_id' => $order['apilo_order_id'], 'target_status' => $status]
|
||||||
|
);
|
||||||
self::queueApiloSync((int)$order['id'], false, $status, 'status_sync_failed');
|
self::queueApiloSync((int)$order['id'], false, $status, 'status_sync_failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -687,7 +759,7 @@ class OrderAdminService
|
|||||||
$db = $this->orders->getDb();
|
$db = $this->orders->getDb();
|
||||||
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository($db);
|
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository($db);
|
||||||
|
|
||||||
if (!(int)$order['apilo_order_id']) {
|
if (empty($order['apilo_order_id'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,7 +826,7 @@ class OrderAdminService
|
|||||||
$db = $this->orders->getDb();
|
$db = $this->orders->getDb();
|
||||||
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository($db);
|
$integrationsRepository = new \Domain\Integrations\IntegrationsRepository($db);
|
||||||
|
|
||||||
if (!(int)$order['apilo_order_id']) {
|
if (empty($order['apilo_order_id'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
cron.php
40
cron.php
@@ -201,6 +201,7 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se
|
|||||||
{
|
{
|
||||||
$products = $mdb -> select( 'pp_shop_order_products', '*', [ 'order_id' => $order['id'] ] );
|
$products = $mdb -> select( 'pp_shop_order_products', '*', [ 'order_id' => $order['id'] ] );
|
||||||
$products_array = [];
|
$products_array = [];
|
||||||
|
$order_message = '';
|
||||||
foreach ( $products as $product )
|
foreach ( $products as $product )
|
||||||
{
|
{
|
||||||
$productRepo = new \Domain\Product\ProductRepository( $mdb );
|
$productRepo = new \Domain\Product\ProductRepository( $mdb );
|
||||||
@@ -211,8 +212,8 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se
|
|||||||
'ean' => $productRepo->getEanWithFallback( (int)$product['product_id'], true ),
|
'ean' => $productRepo->getEanWithFallback( (int)$product['product_id'], true ),
|
||||||
'sku' => $sku ? $sku : md5( $product['product_id'] ),
|
'sku' => $sku ? $sku : md5( $product['product_id'] ),
|
||||||
'originalName' => $product['name'],
|
'originalName' => $product['name'],
|
||||||
'originalPriceWithTax' => $product['price_brutto_promo'] ? str_replace( ',', '.', $product['price_brutto_promo'] ) : str_replace( ',', '.', $product['price_brutto'] ),
|
'originalPriceWithTax' => (float)$product['price_brutto_promo'] > 0 ? str_replace( ',', '.', $product['price_brutto_promo'] ) : str_replace( ',', '.', $product['price_brutto'] ),
|
||||||
'originalPriceWithoutTax' => $product['price_brutto_promo'] ? str_replace( ',', '.', round( $product['price_brutto_promo'] / ( 1 + $product['vat']/100 ), 2 ) ) : str_replace( ',', '.', round( $product['price_brutto'] / ( 1 + $product['vat']/100 ), 2 ) ),
|
'originalPriceWithoutTax' => (float)$product['price_brutto_promo'] > 0 ? str_replace( ',', '.', round( $product['price_brutto_promo'] / ( 1 + $product['vat']/100 ), 2 ) ) : str_replace( ',', '.', round( $product['price_brutto'] / ( 1 + $product['vat']/100 ), 2 ) ),
|
||||||
'quantity' => $product['quantity'],
|
'quantity' => $product['quantity'],
|
||||||
'tax' => number_format( $product['vat'], 2, '.', '' ),
|
'tax' => number_format( $product['vat'], 2, '.', '' ),
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
@@ -255,6 +256,25 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se
|
|||||||
'media' => null
|
'media' => null
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Walidacja: sprawdź czy zamówienie ma produkty z cenami > 0
|
||||||
|
$has_priced_products = false;
|
||||||
|
foreach ( $products_array as $pa )
|
||||||
|
{
|
||||||
|
if ( $pa['type'] == 1 && (float)$pa['originalPriceWithTax'] > 0 )
|
||||||
|
{
|
||||||
|
$has_priced_products = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !$has_priced_products )
|
||||||
|
{
|
||||||
|
\Domain\Integrations\ApiloLogger::log( $mdb, 'send_order', (int)$order['id'], 'Pominięto zamówienie - wszystkie produkty mają cenę 0.00', [ 'products' => $products_array ] );
|
||||||
|
\Shared\Helpers\Helpers::send_email( 'biuro@project-pro.pl', 'Apilo: zamówienie #' . $order['id'] . ' ma zerowe ceny produktów', 'Zamówienie #' . $order['id'] . ' nie zostało wysłane do Apilo, ponieważ wszystkie produkty mają cenę 0.00 PLN. Sprawdź zamówienie w panelu sklepu.' );
|
||||||
|
$mdb -> update( 'pp_shop_orders', [ 'apilo_order_id' => -2 ], [ 'id' => $order['id'] ] );
|
||||||
|
echo '<p>Pominięto zamówienie #' . $order['id'] . ' - zerowe ceny produktów</p>';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$access_token = $integrationsRepository -> apiloGetAccessToken();
|
$access_token = $integrationsRepository -> apiloGetAccessToken();
|
||||||
|
|
||||||
$order_date = new DateTime( $order['date_order'] );
|
$order_date = new DateTime( $order['date_order'] );
|
||||||
@@ -410,9 +430,9 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se
|
|||||||
\Domain\Integrations\ApiloLogger::log( $mdb, 'send_order', (int)$order['id'], 'Błąd cURL przy wysyłaniu zamówienia: ' . $curl_error_send, [ 'curl_error' => $curl_error_send ] );
|
\Domain\Integrations\ApiloLogger::log( $mdb, 'send_order', (int)$order['id'], 'Błąd cURL przy wysyłaniu zamówienia: ' . $curl_error_send, [ 'curl_error' => $curl_error_send ] );
|
||||||
echo 'Błąd cURL: ' . $curl_error_send;
|
echo 'Błąd cURL: ' . $curl_error_send;
|
||||||
}
|
}
|
||||||
|
$http_code_send = (int)curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
||||||
curl_close( $ch );
|
curl_close( $ch );
|
||||||
|
|
||||||
$http_code_send = (int)curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
|
||||||
$response = json_decode( $response, true );
|
$response = json_decode( $response, true );
|
||||||
|
|
||||||
if ( $config['debug']['apilo'] )
|
if ( $config['debug']['apilo'] )
|
||||||
@@ -497,6 +517,20 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se
|
|||||||
\Shared\Helpers\Helpers::send_email( 'biuro@project-pro.pl', 'Błąd wysyłania zamówienia do apilo.com', $email_data );
|
\Shared\Helpers\Helpers::send_email( 'biuro@project-pro.pl', 'Błąd wysyłania zamówienia do apilo.com', $email_data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif ( $http_code_send >= 400 || !isset( $response['id'] ) )
|
||||||
|
{
|
||||||
|
// Błąd serwera lub brak ID w odpowiedzi — logujemy i pomijamy, NIE ustawiamy apilo_order_id
|
||||||
|
// żeby zamówienie nie wpadło w nieskończoną pętlę, ustawiamy apilo_order_id na -1 (błąd)
|
||||||
|
$mdb -> update( 'pp_shop_orders', [ 'apilo_order_id' => -1 ], [ 'id' => $order['id'] ] );
|
||||||
|
\Domain\Integrations\ApiloLogger::log( $mdb, 'send_order', (int)$order['id'], 'Błąd wysyłania zamówienia do Apilo (HTTP ' . $http_code_send . ')', [ 'http_code' => $http_code_send, 'response' => $response ] );
|
||||||
|
|
||||||
|
$email_data = 'HTTP Code: ' . $http_code_send . "\n\n";
|
||||||
|
$email_data .= print_r( $response, true );
|
||||||
|
$email_data .= print_r( $postData, true );
|
||||||
|
\Shared\Helpers\Helpers::send_email( 'biuro@project-pro.pl', 'Błąd wysyłania zamówienia #' . $order['id'] . ' do apilo.com (HTTP ' . $http_code_send . ')', $email_data );
|
||||||
|
|
||||||
|
echo '<p>Błąd wysyłania zamówienia do apilo.com: ID: ' . $order['id'] . ' (HTTP ' . $http_code_send . ')</p>';
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$mdb -> update( 'pp_shop_orders', [ 'apilo_order_id' => $response['id'] ], [ 'id' => $order['id'] ] );
|
$mdb -> update( 'pp_shop_orders', [ 'apilo_order_id' => $response['id'] ], [ 'id' => $order['id'] ] );
|
||||||
|
|||||||
@@ -4,6 +4,23 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ver. 0.313 (2026-02-23) - Fix sync płatności Apilo + logowanie
|
||||||
|
|
||||||
|
- **FIX**: `syncApiloPayment()` i `syncApiloStatus()` — `(int)` cast na `apilo_order_id` (format `"PPxxxxxx"`) dawał `0`, przez co metody pomijały sync z API Apilo. Zmiana na `empty()`
|
||||||
|
- **NEW**: Logowanie w `syncApiloPaymentIfNeeded()` i `syncApiloStatusIfNeeded()` — każda ścieżka decyzyjna (Apilo wyłączone, brak tokenu, brak `apilo_order_id`, sync nieudany) zapisuje wpis do `pp_log` z kontekstem
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ver. 0.312 (2026-02-23) - Fix krytycznych bugów integracji Apilo
|
||||||
|
|
||||||
|
- **FIX**: `curl_getinfo()` wywoływane po `curl_close()` — HTTP code zawsze wynosił 0, uniemożliwiając prawidłową obsługę odpowiedzi Apilo
|
||||||
|
- **FIX**: Nieskończona pętla wysyłania zamówienia — gdy Apilo zwracało błąd serwera, zamówienie nie dostawało `apilo_order_id` i było ponownie wybierane w każdym cyklu crona. Teraz błędne zamówienia oznaczane `apilo_order_id = -1` z powiadomieniem email
|
||||||
|
- **FIX**: Ceny produktów 0.00 PLN w Apilo — string `"0.00"` z MySQL jest truthy w PHP, więc ternary wybierał `price_brutto_promo` (0.00) zamiast `price_brutto`. Zmiana na `(float)... > 0`
|
||||||
|
- **FIX**: Walidacja cen przed wysyłką — zamówienia z zerowymi cenami produktów nie są wysyłane do Apilo (`apilo_order_id = -2`) z powiadomieniem email
|
||||||
|
- **FIX**: Niezainicjalizowana zmienna `$order_message` powodująca PHP warning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## ver. 0.311 (2026-02-23) - Fix race condition Apilo + persistence filtrów + poprawki cen
|
## ver. 0.311 (2026-02-23) - Fix race condition Apilo + persistence filtrów + poprawki cen
|
||||||
|
|
||||||
- **FIX**: Race condition — callback płatności przed wysłaniem zamówienia do Apilo nie synchronizował płatności (task trafiał w pustkę). Teraz `syncApiloPaymentIfNeeded` i `syncApiloStatusIfNeeded` kolejkują sync do retry gdy `apilo_order_id` jeszcze nie istnieje
|
- **FIX**: Race condition — callback płatności przed wysłaniem zamówienia do Apilo nie synchronizował płatności (task trafiał w pustkę). Teraz `syncApiloPaymentIfNeeded` i `syncApiloStatusIfNeeded` kolejkują sync do retry gdy `apilo_order_id` jeszcze nie istnieje
|
||||||
|
|||||||
BIN
updates/0.30/ver_0.311.zip
Normal file
BIN
updates/0.30/ver_0.311.zip
Normal file
Binary file not shown.
27
updates/0.30/ver_0.311_manifest.json
Normal file
27
updates/0.30/ver_0.311_manifest.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"changelog": "FIX - race condition callback płatności Apilo, persistence filtrów tabel admin, poprawki cen zamówień",
|
||||||
|
"version": "0.311",
|
||||||
|
"files": {
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"deleted": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"admin/templates/components/table-list.php",
|
||||||
|
"admin/templates/shop-order/order-details.php",
|
||||||
|
"autoload/Domain/Order/OrderAdminService.php",
|
||||||
|
"cron.php",
|
||||||
|
"templates/shop-order/order-details.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checksum_zip": "sha256:542f599e844d48bba1378fbe91c06ef00d5487aca56af118ad9c9ea27343ebdb",
|
||||||
|
"sql": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"date": "2026-02-23",
|
||||||
|
"directories_deleted": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
updates/0.30/ver_0.312.zip
Normal file
BIN
updates/0.30/ver_0.312.zip
Normal file
Binary file not shown.
23
updates/0.30/ver_0.312_manifest.json
Normal file
23
updates/0.30/ver_0.312_manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"changelog": "FIX - krytyczne bugi integracji Apilo: curl_getinfo po curl_close, nieskończona pętla wysyłki, ceny 0.00 PLN, walidacja cen",
|
||||||
|
"version": "0.312",
|
||||||
|
"files": {
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"deleted": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"cron.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checksum_zip": "sha256:07f9efd02a6a83327ab8dd9403e0c072a5f38b680d6e3f6c67a96d2af8b8fc85",
|
||||||
|
"sql": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"date": "2026-02-23",
|
||||||
|
"directories_deleted": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
<b>ver. 0.312 - 23.02.2026</b><br />
|
||||||
|
FIX - krytyczne bugi integracji Apilo: curl_getinfo po curl_close, nieskończona pętla wysyłki, ceny 0.00 PLN, walidacja cen
|
||||||
|
<hr>
|
||||||
|
<b>ver. 0.311 - 23.02.2026</b><br />
|
||||||
|
FIX - race condition callback płatności Apilo, persistence filtrów tabel admin, poprawki cen zamówień
|
||||||
|
<hr>
|
||||||
<b>ver. 0.310 - 23.02.2026</b><br />
|
<b>ver. 0.310 - 23.02.2026</b><br />
|
||||||
NEW - Zakladka Logi w sekcji Integracje (podglad pp_log z paginacja, sortowaniem, filtrami)
|
NEW - Zakladka Logi w sekcji Integracje (podglad pp_log z paginacja, sortowaniem, filtrami)
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?
|
<?
|
||||||
$current_ver = 311;
|
$current_ver = 313;
|
||||||
|
|
||||||
for ($i = 1; $i <= $current_ver; $i++)
|
for ($i = 1; $i <= $current_ver; $i++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user