This commit is contained in:
2026-04-22 22:54:26 +02:00
parent cd1ea4a9db
commit c73b2fe9f6
26 changed files with 1377 additions and 34 deletions

View File

@@ -182,7 +182,8 @@ final class OrdersRepository
COALESCE(oi_agg.projects_total, 0) AS projects_total,
COALESCE(sh_agg.shipments_count, 0) AS shipments_count,
COALESCE(od_agg.documents_count, 0) AS documents_count,
ig.name AS integration_name
ig.name AS integration_name,
' . $this->customerReturnedCountSubquerySql('o', 'a') . ' AS customer_returned_count
FROM orders o
LEFT JOIN order_addresses a ON a.order_id = o.id AND a.address_type = "customer"
LEFT JOIN allegro_order_status_mappings asm ON o.source = "allegro" AND LOWER(o.status_code) = asm.allegro_status_code
@@ -246,6 +247,7 @@ final class OrdersRepository
'items_preview' => (array) ($itemPreviewsByOrderId[$orderId] ?? []),
'projects_done' => (int) ($row['projects_done'] ?? 0),
'projects_total' => (int) ($row['projects_total'] ?? 0),
'customer_returned_count' => max(0, (int) ($row['customer_returned_count'] ?? 0)),
];
}
@@ -479,10 +481,15 @@ final class OrdersRepository
$effectiveStatusSql = $this->effectiveStatusSql('o', 'asm');
$orderStmt = $this->pdo->prepare(
'SELECT o.*, ' . $effectiveStatusSql . ' AS effective_status_id,
ig.name AS integration_name
ig.name AS integration_name,
a.email AS buyer_email,
a.phone AS buyer_phone,
a.name AS buyer_name,
' . $this->customerReturnedCountSubquerySql('o', 'a') . ' AS customer_returned_count
FROM orders o
LEFT JOIN allegro_order_status_mappings asm ON o.source = "allegro" AND LOWER(o.status_code) = asm.allegro_status_code
LEFT JOIN integrations ig ON ig.id = o.integration_id
LEFT JOIN order_addresses a ON a.order_id = o.id AND a.address_type = "customer"
WHERE o.id = :id
LIMIT 1'
);
@@ -491,6 +498,7 @@ final class OrdersRepository
if (!is_array($order)) {
return null;
}
$order['customer_returned_count'] = max(0, (int) ($order['customer_returned_count'] ?? 0));
return [
'order' => $order,
@@ -669,6 +677,38 @@ final class OrdersRepository
return $result;
}
/**
* Subquery zliczajaca zamowienia klienta biezacego wiersza, ktore w historii
* mialy paczke z delivery_status='returned' (zwrot do nadawcy).
* Matching po email LUB phone (tylko cyfry, min 6) LUB name — identyczne dopasowanie
* po LOWER/TRIM. Wyklucza biezace zamowienie (self-exclusion).
*
* Wymagania: MySQL 8.0+ (REGEXP_REPLACE).
*
* @param string $orderAlias alias tabeli orders w outer query (np. 'o')
* @param string $addressAlias alias joina order_addresses (customer) w outer query (np. 'a')
*/
private function customerReturnedCountSubquerySql(string $orderAlias, string $addressAlias): string
{
return '(SELECT COUNT(DISTINCT sp.order_id)
FROM shipment_packages sp
INNER JOIN order_addresses a2
ON a2.order_id = sp.order_id AND a2.address_type = "customer"
WHERE sp.delivery_status = "returned"
AND sp.order_id != ' . $orderAlias . '.id
AND (
(' . $addressAlias . '.email IS NOT NULL AND ' . $addressAlias . '.email <> ""
AND LOWER(TRIM(a2.email)) = LOWER(TRIM(' . $addressAlias . '.email)))
OR
(' . $addressAlias . '.phone IS NOT NULL
AND LENGTH(REGEXP_REPLACE(' . $addressAlias . '.phone, "[^0-9]+", "")) >= 6
AND REGEXP_REPLACE(a2.phone, "[^0-9]+", "") = REGEXP_REPLACE(' . $addressAlias . '.phone, "[^0-9]+", ""))
OR
(' . $addressAlias . '.name IS NOT NULL AND ' . $addressAlias . '.name <> ""
AND LOWER(TRIM(a2.name)) = LOWER(TRIM(' . $addressAlias . '.name)))
))';
}
private function effectiveStatusSql(string $orderAlias, string $mappingAlias): string
{
return 'CASE