update empik

This commit is contained in:
2026-03-15 20:22:14 +01:00
parent 910807beb9
commit 5871764385
5 changed files with 153 additions and 153 deletions

View File

@@ -1,134 +1,85 @@
# Modyfikacje modułu empikmarketplace
# Modyfikacje modulu empikmarketplace
Data modyfikacji: 2026-03-11
## 2026-03-11 - powiadomienia i AUTO_INCREMENT
## Problem
### Problem
Przy nieudanym imporcie zamowienia z EMPIK do PrestaShop:
1. Nie bylo powiadomienia email o bledzie importu.
2. Powstawaly dziury w numeracji zamowien (`id_order`) po `ROLLBACK`.
Moduł empikmarketplace przy nieudanym imporcie zamówienia z EMPIK do PrestaShop powodował:
1. Brak powiadomienia o błędzie — nikt nie wiedział, że zamówienie nie przeszło
2. Dziury w numeracji zamówień (`id_order`) — MySQL AUTO_INCREMENT nie cofa się po ROLLBACK transakcji
### Zmodyfikowane pliki
## Zmodyfikowane pliki
#### `src/Processor/OrderProcessor.php`
- Dodano `use Mail;`.
- Dodano stala `ERROR_NOTIFICATION_EMAIL`.
- W `import()` po bledzie dodano:
- `ROLLBACK`,
- `resetOrderAutoIncrement()`,
- log bledu,
- `sendFailureNotification(...)`.
- Dodano metode `resetOrderAutoIncrement()`.
- Dodano metode `sendFailureNotification()`.
### `src/Processor/OrderProcessor.php`
#### `mails/pl/empik_import_error.html`
- Dodany szablon HTML maila z placeholderami:
- `{empik_order_id}`
- `{error_date}`
- `{error_message}`
- `{stack_trace}`
Dodany import `Mail` na górze pliku:
#### `mails/pl/empik_import_error.txt`
- Dodana tekstowa wersja szablonu maila.
```php
use Mail;
```
## 2026-03-15 - dokladniejsza diagnoza blednych zamowien
Dodana stała z adresem email do powiadomień:
### Cel
W mailu z bledem importu bylo widac tylko ogolny komunikat:
`Invalid order data for order: ...`.
Brakowalo informacji, ktore pole w danych zamowienia bylo niepoprawne.
```php
class OrderProcessor
{
const CODE_WAITING_ACCEPTANCE = 'WAITING_ACCEPTANCE';
const CODE_SHIPPING = 'SHIPPING';
const ERROR_NOTIFICATION_EMAIL = 'jacek.pyziak@project-pro.pl';
```
### Zmodyfikowane pliki
Zmodyfikowana metoda `import()` — dodano wywołanie resetu AUTO_INCREMENT i wysyłki emaila w bloku catch:
#### `src/OrderFulfiller/OrderFulfiller.php`
- Rozszerzono walidacje w `validate($data)`.
- Zamiast jednego ogolnego bledu zbierana jest lista konkretnych problemow, np.:
- oba adresy puste: `customer.shipping_address` i `customer.billing_address`,
- puste `order_id`,
- puste `order_lines`,
- puste `order_state`,
- puste `total_price`.
- Rzucany wyjatek zawiera teraz liste tych bledow (`Validation errors: ...`).
```php
protected function import(EmpikOrderWrapper $empikOrder)
{
try {
Db::getInstance()->execute('START TRANSACTION');
$this->orderFulfiller->fulfill($empikOrder);
Db::getInstance()->execute('COMMIT');
} catch (Exception $e) {
Db::getInstance()->execute('ROLLBACK');
$this->resetOrderAutoIncrement();
#### `src/Processor/OrderProcessor.php`
- W `import()` do `sendFailureNotification(...)` przekazywany jest payload zamowienia (`$data`).
- `sendFailureNotification(...)` przyjmuje teraz trzeci argument: `array $orderData = []`.
- Dodano metode `buildOrderContext(array $orderData)` budujaca skrot payloadu do maila:
- `order_id`
- `order_state`
- `total_price`
- `shipping_price`
- `order_lines_count`
- `has_shipping_address`
- `has_billing_address`
- Do placeholderow maila dodano:
- `{order_context}`
- `{order_context_html}`
$data = $empikOrder->getData();
$empikOrderId = isset($data['order_id']) ? $data['order_id'] : 'unknown';
$errorMsg = sprintf('Error importing EMPIK order [%s]: %s', $empikOrderId, $e->getMessage());
$this->logger->logError($errorMsg);
$this->sendFailureNotification($empikOrderId, $e);
}
}
```
#### `mails/pl/empik_import_error.html`
- Dodano sekcje `Szczegoly zamowienia` z placeholderem `{order_context_html}`.
Dodana metoda `resetOrderAutoIncrement()` — zapobiega dziurom w numeracji zamówień:
#### `mails/pl/empik_import_error.txt`
- Dodano sekcje `Szczegoly zamowienia` z placeholderem `{order_context}`.
```php
protected function resetOrderAutoIncrement()
{
try {
$lastId = (int) Db::getInstance()->getValue(
'SELECT MAX(id_order) FROM ' . _DB_PREFIX_ . 'orders'
);
Db::getInstance()->execute(
'ALTER TABLE ' . _DB_PREFIX_ . 'orders AUTO_INCREMENT = ' . ($lastId + 1)
);
} catch (Exception $e) {
$this->logger->logError(sprintf('Error resetting AUTO_INCREMENT: %s', $e->getMessage()));
}
}
```
### Efekt
Kolejny mail z nieudanym importem pokazuje:
1. konkretny powod walidacji,
2. skrot kluczowych pol payloadu zamowienia,
3. stack trace.
Dodana metoda `sendFailureNotification()` — wysyła email z informacją o błędzie:
To powinno wystarczyc do szybkiej diagnozy, co bylo nie tak w danych zamowienia z EMPIK.
```php
protected function sendFailureNotification($empikOrderId, Exception $exception)
{
try {
$shopName = Configuration::get('PS_SHOP_NAME');
$subject = sprintf('[%s] Błąd importu zamówienia EMPIK: %s', $shopName, $empikOrderId);
$body = sprintf(
"Zamówienie EMPIK: %s\nData: %s\nBłąd: %s\n\nStack trace:\n%s",
$empikOrderId,
date('Y-m-d H:i:s'),
$exception->getMessage(),
$exception->getTraceAsString()
);
Mail::send(
(int) Configuration::get('PS_LANG_DEFAULT'),
'empik_import_error',
$subject,
[
'{empik_order_id}' => $empikOrderId,
'{error_message}' => $exception->getMessage(),
'{error_date}' => date('Y-m-d H:i:s'),
'{stack_trace}' => nl2br($exception->getTraceAsString()),
],
self::ERROR_NOTIFICATION_EMAIL,
null,
Configuration::get('PS_SHOP_EMAIL'),
$shopName,
null,
null,
_PS_MODULE_DIR_ . 'empikmarketplace/mails/'
);
} catch (Exception $e) {
$this->logger->logError(sprintf('Error sending failure notification email: %s', $e->getMessage()));
}
}
```
## Dodane pliki
### `mails/pl/empik_import_error.html`
Szablon HTML emaila z powiadomieniem o błędzie. Zawiera placeholdery:
- `{empik_order_id}` — ID zamówienia EMPIK
- `{error_date}` — data błędu
- `{error_message}` — komunikat błędu
- `{stack_trace}` — stack trace wyjątku
### `mails/pl/empik_import_error.txt`
Wersja tekstowa tego samego szablonu (wymagana przez PrestaShop `Mail::send()`).
## Po aktualizacji modułu
Jeśli moduł empikmarketplace zostanie zaktualizowany, powyższe zmiany zostaną nadpisane. Należy ponownie:
1. Dodać `use Mail;` do importów w `OrderProcessor.php`
2. Dodać stałą `ERROR_NOTIFICATION_EMAIL`
3. Zmodyfikować metodę `import()` zgodnie z powyższym kodem
4. Dodać metody `resetOrderAutoIncrement()` i `sendFailureNotification()`
5. Skopiować szablony emaili do `mails/pl/`
## Po aktualizacji modulu
Jesli modul `empikmarketplace` zostanie zaktualizowany i nadpisze zmiany, trzeba ponownie naniesc modyfikacje:
1. `OrderProcessor.php` (import, auto-increment, powiadomienia, `buildOrderContext`).
2. `OrderFulfiller.php` (rozszerzona walidacja i szczegolowe komunikaty).
3. Szablony maili `mails/pl/empik_import_error.html` i `mails/pl/empik_import_error.txt`.

View File

@@ -2,13 +2,13 @@
<html>
<head>
<meta charset="utf-8">
<title>Błąd importu zamówienia EMPIK</title>
<title>Blad importu zamowienia EMPIK</title>
</head>
<body style="font-family: Arial, sans-serif; font-size: 14px; color: #333;">
<h2 style="color: #c0392b;">Błąd importu zamówienia EMPIK</h2>
<h2 style="color: #c0392b;">Blad importu zamowienia EMPIK</h2>
<table style="border-collapse: collapse; width: 100%; max-width: 600px;">
<tr>
<td style="padding: 8px; border: 1px solid #ddd; font-weight: bold;">Zamówienie EMPIK:</td>
<td style="padding: 8px; border: 1px solid #ddd; font-weight: bold;">Zamowienie EMPIK:</td>
<td style="padding: 8px; border: 1px solid #ddd;">{empik_order_id}</td>
</tr>
<tr>
@@ -16,10 +16,12 @@
<td style="padding: 8px; border: 1px solid #ddd;">{error_date}</td>
</tr>
<tr>
<td style="padding: 8px; border: 1px solid #ddd; font-weight: bold;">Komunikat błędu:</td>
<td style="padding: 8px; border: 1px solid #ddd; font-weight: bold;">Komunikat bledu:</td>
<td style="padding: 8px; border: 1px solid #ddd;">{error_message}</td>
</tr>
</table>
<h3>Szczegoly zamowienia:</h3>
<pre style="background: #f5f5f5; padding: 10px; font-size: 12px; overflow-x: auto;">{order_context_html}</pre>
<h3>Stack trace:</h3>
<pre style="background: #f5f5f5; padding: 10px; font-size: 12px; overflow-x: auto;">{stack_trace}</pre>
</body>

View File

@@ -1,8 +1,11 @@
Błąd importu zamówienia EMPIK
Blad importu zamowienia EMPIK
Zamówienie EMPIK: {empik_order_id}
Zamowienie EMPIK: {empik_order_id}
Data: {error_date}
Komunikat błędu: {error_message}
Komunikat bledu: {error_message}
Szczegoly zamowienia:
{order_context}
Stack trace:
{stack_trace}

View File

@@ -106,17 +106,39 @@ class OrderFulfiller
*/
protected function validate($data)
{
if (
(
empty($data['customer']['shipping_address']) &&
empty($data['customer']['billing_address'])
) ||
empty($data['order_id']) ||
empty($data['order_lines']) ||
empty($data['order_state']) ||
empty($data['total_price'])
) {
throw new OrderProcessException(sprintf('Invalid order data for order: %s', $data['order_id']));
$customer = isset($data['customer']) && is_array($data['customer']) ? $data['customer'] : [];
$shippingAddress = isset($customer['shipping_address']) ? $customer['shipping_address'] : null;
$billingAddress = isset($customer['billing_address']) ? $customer['billing_address'] : null;
$orderId = isset($data['order_id']) ? $data['order_id'] : 'unknown';
$errors = [];
if (empty($shippingAddress) && empty($billingAddress)) {
$errors[] = 'both customer.shipping_address and customer.billing_address are empty';
}
if (empty($data['order_id'])) {
$errors[] = 'order_id is empty';
}
if (empty($data['order_lines'])) {
$errors[] = 'order_lines is empty';
}
if (empty($data['order_state'])) {
$errors[] = 'order_state is empty';
}
if (empty($data['total_price'])) {
$errors[] = 'total_price is empty';
}
if (!empty($errors)) {
throw new OrderProcessException(sprintf(
'Invalid order data for order: %s. Validation errors: %s',
$orderId,
implode('; ', $errors)
));
}
}
}

View File

@@ -58,8 +58,8 @@ class OrderProcessor
$this->empikClient = $this->empikClientFactory->createClient();
$this->allowAccept = (bool)Configuration::get(ConfigurationAdapter::CONF_AUTO_ACCEPT_ORDERS);
$this->allowImport = (bool)Configuration::get(ConfigurationAdapter::CONF_IMPORT_ORDERS);
$this->allowAccept = (bool) Configuration::get(ConfigurationAdapter::CONF_AUTO_ACCEPT_ORDERS);
$this->allowImport = (bool) Configuration::get(ConfigurationAdapter::CONF_IMPORT_ORDERS);
}
public function process()
@@ -85,7 +85,7 @@ class OrderProcessor
$this->import($empikOrder);
}
} catch (OrderProcessException $exception) {
$this->logger->logError('Empikplaces: import order process, order id ' . $order['order_id'] . ', message:' . $exception->getMessage());
$this->logger->logError('Empikplaces: import order process, order id ' . $order['order_id'] . ', message:' . $exception->getMessage());
} catch (Exception $exception) {
$this->logger->logError('Empikplaces: ' . $exception->getMessage());
}
@@ -106,13 +106,13 @@ class OrderProcessor
$empikOrderId = isset($data['order_id']) ? $data['order_id'] : 'unknown';
$errorMsg = sprintf('Error importing EMPIK order [%s]: %s', $empikOrderId, $e->getMessage());
$this->logger->logError($errorMsg);
$this->sendFailureNotification($empikOrderId, $e);
$this->sendFailureNotification($empikOrderId, $e, $data);
}
}
/**
* Resetuje AUTO_INCREMENT tabeli ps_orders do MAX(id_order) + 1
* aby uniknąć dziur w numeracji zamówień po ROLLBACK.
* Resets AUTO_INCREMENT of ps_orders to MAX(id_order) + 1
* to avoid gaps after ROLLBACK.
*/
protected function resetOrderAutoIncrement()
{
@@ -129,24 +129,18 @@ class OrderProcessor
}
/**
* Wysyła email z powiadomieniem o nieudanym imporcie zamówienia EMPIK.
* Sends notification email when EMPIK order import fails.
*
* @param string $empikOrderId
* @param Exception $exception
* @param array $orderData
*/
protected function sendFailureNotification($empikOrderId, Exception $exception)
protected function sendFailureNotification($empikOrderId, Exception $exception, array $orderData = [])
{
try {
$shopName = Configuration::get('PS_SHOP_NAME');
$subject = sprintf('[%s] Błąd importu zamówienia EMPIK: %s', $shopName, $empikOrderId);
$body = sprintf(
"Zamówienie EMPIK: %s\nData: %s\nBłąd: %s\n\nStack trace:\n%s",
$empikOrderId,
date('Y-m-d H:i:s'),
$exception->getMessage(),
$exception->getTraceAsString()
);
$subject = sprintf('[%s] Blad importu zamowienia EMPIK: %s', $shopName, $empikOrderId);
$orderContext = $this->buildOrderContext($orderData);
Mail::send(
(int) Configuration::get('PS_LANG_DEFAULT'),
@@ -156,6 +150,8 @@ class OrderProcessor
'{empik_order_id}' => $empikOrderId,
'{error_message}' => $exception->getMessage(),
'{error_date}' => date('Y-m-d H:i:s'),
'{order_context}' => $orderContext,
'{order_context_html}' => nl2br(htmlspecialchars($orderContext, ENT_QUOTES, 'UTF-8')),
'{stack_trace}' => nl2br($exception->getTraceAsString()),
],
self::ERROR_NOTIFICATION_EMAIL,
@@ -171,6 +167,32 @@ class OrderProcessor
}
}
/**
* @param array $orderData
* @return string
*/
protected function buildOrderContext(array $orderData)
{
if (empty($orderData)) {
return 'No order payload available.';
}
$customer = isset($orderData['customer']) && is_array($orderData['customer']) ? $orderData['customer'] : [];
$summary = [
'order_id' => isset($orderData['order_id']) ? $orderData['order_id'] : null,
'order_state' => isset($orderData['order_state']) ? $orderData['order_state'] : null,
'total_price' => isset($orderData['total_price']) ? $orderData['total_price'] : null,
'shipping_price' => isset($orderData['shipping_price']) ? $orderData['shipping_price'] : null,
'order_lines_count' => isset($orderData['order_lines']) && is_array($orderData['order_lines']) ? count($orderData['order_lines']) : 0,
'has_shipping_address' => !empty($customer['shipping_address']) ? 1 : 0,
'has_billing_address' => !empty($customer['billing_address']) ? 1 : 0,
];
$json = json_encode($summary, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
return $json !== false ? $json : 'Unable to serialize order payload summary.';
}
protected function accept(EmpikOrderWrapper $empikOrder)
{
$acceptLines = $empikOrder->getAcceptanceLines();