feat(111): payment transition event for Allegro+shopPRO re-import

Re-import zamowienia wykrywa tranzycje payment_status 0/1->2 i emituje
payment.status_changed, dzieki czemu chain reguly automatyzacji #7 zmienia
status na w_realizacji.

- OrderImportRepository: rozdzielenie paymentTransition (event 0/1->2) i
  statusOverwriteAllowed (preservacja status_code z Phase 62)
- AllegroOrderImportService + ShopproOrdersSyncService: emit
  payment.status_changed na re-imporcie (gate !wasCreated && wasPaymentTransition)
- bin/backfill_payment_transition_111.php: jednorazowy CLI dla zamowien
  payment_status=2 && status_code='nieoplacone' (Allegro + shopPRO)
- Naprawa luki znalezionej w analizie zamowienia #864

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 23:35:14 +02:00
parent 0da0241ebf
commit 5cf531d718
12 changed files with 691 additions and 31 deletions

View File

@@ -39,12 +39,18 @@ final class OrderImportRepository
$existingOrderId = $this->findOrderIdBySource($source, $sourceOrderId);
$created = $existingOrderId === null;
$paymentTransition = false;
$statusOverwriteAllowed = false;
if (!$created) {
$currentStatus = $this->getCurrentStatus($existingOrderId);
$existing = $this->getCurrentStatusAndPaymentStatus($existingOrderId);
$currentStatus = $existing['status_code'];
$oldPaymentStatus = $existing['payment_status'];
$newPaymentStatus = (int) ($orderData['payment_status'] ?? 0);
$paymentTransition = $currentStatus === 'nieoplacone' && $newPaymentStatus === 2;
if (!$paymentTransition) {
$paymentTransition = in_array($oldPaymentStatus, [0, 1], true) && $newPaymentStatus === 2;
$statusOverwriteAllowed = $currentStatus === 'nieoplacone' && $newPaymentStatus === 2;
if (!$statusOverwriteAllowed) {
$orderData['status_code'] = $currentStatus;
}
}
@@ -61,7 +67,7 @@ final class OrderImportRepository
$this->replacePayments($orderId, $payments);
$this->replaceShipments($orderId, $shipments);
$this->replaceStatusHistory($orderId, $statusHistory);
} elseif ($paymentTransition) {
} elseif ($paymentTransition || $statusOverwriteAllowed) {
$this->replacePayments($orderId, $payments);
}
@@ -101,15 +107,25 @@ final class OrderImportRepository
return $id > 0 ? $id : null;
}
private function getCurrentStatus(int $orderId): string
/**
* @return array{status_code:string, payment_status:int}
*/
private function getCurrentStatusAndPaymentStatus(int $orderId): array
{
$statement = $this->pdo->prepare(
'SELECT status_code FROM orders WHERE id = :id LIMIT 1'
'SELECT status_code, payment_status FROM orders WHERE id = :id LIMIT 1'
);
$statement->execute(['id' => $orderId]);
$value = $statement->fetchColumn();
$row = $statement->fetch(PDO::FETCH_ASSOC);
return strtolower(trim((string) ($value ?: '')));
if (!is_array($row)) {
return ['status_code' => '', 'payment_status' => 0];
}
return [
'status_code' => strtolower(trim((string) ($row['status_code'] ?? ''))),
'payment_status' => (int) ($row['payment_status'] ?? 0),
];
}
/**

View File

@@ -104,6 +104,16 @@ final class AllegroOrderImportService
'new_payment_status' => (string) ($mapped['order']['payment_status'] ?? ''),
]);
}
$wasPaymentTransition = !empty($saveResult['payment_transition']);
if (!$wasCreated && $wasPaymentTransition && $this->automationService !== null) {
$this->automationService->trigger('payment.status_changed', $savedOrderId, [
'source' => IntegrationSources::ALLEGRO,
'integration_id' => (int) ($mapped['order']['integration_id'] ?? 0),
'old_payment_status' => '',
'new_payment_status' => (string) ($mapped['order']['payment_status'] ?? ''),
]);
}
}
return [

View File

@@ -278,6 +278,15 @@ final class ShopproOrdersSyncService
'new_payment_status' => (string) ($aggregate['order']['payment_status'] ?? ''),
]);
}
if ($savedOrderId > 0 && !$wasCreated && $wasPaymentTransition && $this->automationService !== null) {
$this->automationService->trigger('payment.status_changed', $savedOrderId, [
'source' => 'shoppro',
'integration_id' => $integrationId,
'old_payment_status' => '',
'new_payment_status' => (string) ($aggregate['order']['payment_status'] ?? ''),
]);
}
} catch (Throwable $exception) {
$result['failed'] = (int) $result['failed'] + 1;
$errors = is_array($result['errors']) ? $result['errors'] : [];