431 lines
18 KiB
PHP
431 lines
18 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Orders;
|
|
|
|
use PDO;
|
|
use Throwable;
|
|
|
|
final class OrderImportRepository
|
|
{
|
|
public function __construct(private readonly PDO $pdo)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $orderData
|
|
* @param array<int, array<string, mixed>> $addresses
|
|
* @param array<int, array<string, mixed>> $items
|
|
* @param array<int, array<string, mixed>> $payments
|
|
* @param array<int, array<string, mixed>> $shipments
|
|
* @param array<int, array<string, mixed>> $notes
|
|
* @param array<int, array<string, mixed>> $statusHistory
|
|
* @return array{order_id:int, created:bool}
|
|
*/
|
|
public function upsertOrderAggregate(
|
|
array $orderData,
|
|
array $addresses,
|
|
array $items,
|
|
array $payments,
|
|
array $shipments,
|
|
array $notes,
|
|
array $statusHistory
|
|
): array {
|
|
$this->pdo->beginTransaction();
|
|
|
|
try {
|
|
$source = trim((string) ($orderData['source'] ?? 'allegro'));
|
|
$sourceOrderId = trim((string) ($orderData['source_order_id'] ?? ''));
|
|
$existingOrderId = $this->findOrderIdBySource($source, $sourceOrderId);
|
|
$created = $existingOrderId === null;
|
|
$orderId = $created
|
|
? $this->insertOrder($orderData)
|
|
: $this->updateOrder($existingOrderId, $orderData);
|
|
|
|
$this->replaceAddresses($orderId, $addresses);
|
|
$this->replaceItems($orderId, $items);
|
|
$this->replaceNotes($orderId, $notes);
|
|
|
|
if ($created) {
|
|
$this->replacePayments($orderId, $payments);
|
|
$this->replaceShipments($orderId, $shipments);
|
|
$this->replaceStatusHistory($orderId, $statusHistory);
|
|
}
|
|
|
|
$this->pdo->commit();
|
|
} catch (Throwable $exception) {
|
|
if ($this->pdo->inTransaction()) {
|
|
$this->pdo->rollBack();
|
|
}
|
|
throw $exception;
|
|
}
|
|
|
|
return [
|
|
'order_id' => $orderId,
|
|
'created' => $created,
|
|
];
|
|
}
|
|
|
|
private function findOrderIdBySource(string $source, string $sourceOrderId): ?int
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id
|
|
FROM orders
|
|
WHERE source = :source AND source_order_id = :source_order_id
|
|
LIMIT 1'
|
|
);
|
|
$statement->execute([
|
|
'source' => $source,
|
|
'source_order_id' => $sourceOrderId,
|
|
]);
|
|
$value = $statement->fetchColumn();
|
|
if ($value === false) {
|
|
return null;
|
|
}
|
|
|
|
$id = (int) $value;
|
|
return $id > 0 ? $id : null;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $orderData
|
|
*/
|
|
private function insertOrder(array $orderData): int
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO orders (
|
|
integration_id, source, source_order_id, external_order_id, external_platform_id, external_platform_account_id,
|
|
external_status_id, external_payment_type_id, payment_status, external_carrier_id, external_carrier_account_id,
|
|
customer_login, is_invoice, is_encrypted, is_canceled_by_buyer, currency,
|
|
total_without_tax, total_with_tax, total_paid, send_date_min, send_date_max, ordered_at,
|
|
source_created_at, source_updated_at, preferences_json, payload_json, fetched_at
|
|
) VALUES (
|
|
:integration_id, :source, :source_order_id, :external_order_id, :external_platform_id, :external_platform_account_id,
|
|
:external_status_id, :external_payment_type_id, :payment_status, :external_carrier_id, :external_carrier_account_id,
|
|
:customer_login, :is_invoice, :is_encrypted, :is_canceled_by_buyer, :currency,
|
|
:total_without_tax, :total_with_tax, :total_paid, :send_date_min, :send_date_max, :ordered_at,
|
|
:source_created_at, :source_updated_at, :preferences_json, :payload_json, :fetched_at
|
|
)'
|
|
);
|
|
$statement->execute($this->orderParams($orderData));
|
|
|
|
$newId = (int) $this->pdo->lastInsertId();
|
|
$this->pdo->prepare(
|
|
"UPDATE orders SET internal_order_number = CONCAT('OP', LPAD(id, 9, '0')) WHERE id = :id AND (internal_order_number IS NULL OR internal_order_number = '')"
|
|
)->execute(['id' => $newId]);
|
|
|
|
return $newId;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $orderData
|
|
*/
|
|
private function updateOrder(int $orderId, array $orderData): int
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'UPDATE orders
|
|
SET integration_id = :integration_id,
|
|
source = :source,
|
|
source_order_id = :source_order_id,
|
|
external_order_id = :external_order_id,
|
|
external_platform_id = :external_platform_id,
|
|
external_platform_account_id = :external_platform_account_id,
|
|
external_status_id = :external_status_id,
|
|
external_payment_type_id = :external_payment_type_id,
|
|
payment_status = :payment_status,
|
|
external_carrier_id = :external_carrier_id,
|
|
external_carrier_account_id = :external_carrier_account_id,
|
|
customer_login = :customer_login,
|
|
is_invoice = :is_invoice,
|
|
is_encrypted = :is_encrypted,
|
|
is_canceled_by_buyer = :is_canceled_by_buyer,
|
|
currency = :currency,
|
|
total_without_tax = :total_without_tax,
|
|
total_with_tax = :total_with_tax,
|
|
total_paid = :total_paid,
|
|
send_date_min = :send_date_min,
|
|
send_date_max = :send_date_max,
|
|
ordered_at = :ordered_at,
|
|
source_created_at = :source_created_at,
|
|
source_updated_at = :source_updated_at,
|
|
preferences_json = :preferences_json,
|
|
payload_json = :payload_json,
|
|
fetched_at = :fetched_at,
|
|
updated_at = NOW()
|
|
WHERE id = :id'
|
|
);
|
|
|
|
$params = $this->orderParams($orderData);
|
|
$params['id'] = $orderId;
|
|
$statement->execute($params);
|
|
|
|
return $orderId;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $orderData
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function orderParams(array $orderData): array
|
|
{
|
|
return [
|
|
'integration_id' => $orderData['integration_id'] ?? null,
|
|
'source' => (string) ($orderData['source'] ?? 'allegro'),
|
|
'source_order_id' => (string) ($orderData['source_order_id'] ?? ''),
|
|
'external_order_id' => $orderData['external_order_id'] ?? null,
|
|
'external_platform_id' => $orderData['external_platform_id'] ?? null,
|
|
'external_platform_account_id' => $orderData['external_platform_account_id'] ?? null,
|
|
'external_status_id' => $orderData['external_status_id'] ?? null,
|
|
'external_payment_type_id' => $orderData['external_payment_type_id'] ?? null,
|
|
'payment_status' => $orderData['payment_status'] ?? null,
|
|
'external_carrier_id' => $orderData['external_carrier_id'] ?? null,
|
|
'external_carrier_account_id' => $orderData['external_carrier_account_id'] ?? null,
|
|
'customer_login' => $orderData['customer_login'] ?? null,
|
|
'is_invoice' => !empty($orderData['is_invoice']) ? 1 : 0,
|
|
'is_encrypted' => !empty($orderData['is_encrypted']) ? 1 : 0,
|
|
'is_canceled_by_buyer' => !empty($orderData['is_canceled_by_buyer']) ? 1 : 0,
|
|
'currency' => (string) ($orderData['currency'] ?? 'PLN'),
|
|
'total_without_tax' => $orderData['total_without_tax'] ?? null,
|
|
'total_with_tax' => $orderData['total_with_tax'] ?? null,
|
|
'total_paid' => $orderData['total_paid'] ?? null,
|
|
'send_date_min' => $orderData['send_date_min'] ?? null,
|
|
'send_date_max' => $orderData['send_date_max'] ?? null,
|
|
'ordered_at' => $orderData['ordered_at'] ?? null,
|
|
'source_created_at' => $orderData['source_created_at'] ?? null,
|
|
'source_updated_at' => $orderData['source_updated_at'] ?? null,
|
|
'preferences_json' => $this->encodeJson($orderData['preferences_json'] ?? null),
|
|
'payload_json' => $this->encodeJson($orderData['payload_json'] ?? null),
|
|
'fetched_at' => $orderData['fetched_at'] ?? date('Y-m-d H:i:s'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replaceAddresses(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_addresses WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_addresses (
|
|
order_id, address_type, name, phone, email, street_name, street_number, city, zip_code, country,
|
|
department, parcel_external_id, parcel_name, address_class, company_tax_number, company_name, payload_json
|
|
) VALUES (
|
|
:order_id, :address_type, :name, :phone, :email, :street_name, :street_number, :city, :zip_code, :country,
|
|
:department, :parcel_external_id, :parcel_name, :address_class, :company_tax_number, :company_name, :payload_json
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'address_type' => (string) ($row['address_type'] ?? 'customer'),
|
|
'name' => (string) ($row['name'] ?? ''),
|
|
'phone' => $row['phone'] ?? null,
|
|
'email' => $row['email'] ?? null,
|
|
'street_name' => $row['street_name'] ?? null,
|
|
'street_number' => $row['street_number'] ?? null,
|
|
'city' => $row['city'] ?? null,
|
|
'zip_code' => $row['zip_code'] ?? null,
|
|
'country' => $row['country'] ?? null,
|
|
'department' => $row['department'] ?? null,
|
|
'parcel_external_id' => $row['parcel_external_id'] ?? null,
|
|
'parcel_name' => $row['parcel_name'] ?? null,
|
|
'address_class' => $row['address_class'] ?? null,
|
|
'company_tax_number' => $row['company_tax_number'] ?? null,
|
|
'company_name' => $row['company_name'] ?? null,
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replaceItems(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_items WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_items (
|
|
order_id, source_item_id, external_item_id, ean, sku, original_name, original_code,
|
|
original_price_with_tax, original_price_without_tax, media_url, quantity, tax_rate, item_status,
|
|
unit, item_type, source_product_id, source_product_set_id, sort_order, payload_json, personalization
|
|
) VALUES (
|
|
:order_id, :source_item_id, :external_item_id, :ean, :sku, :original_name, :original_code,
|
|
:original_price_with_tax, :original_price_without_tax, :media_url, :quantity, :tax_rate, :item_status,
|
|
:unit, :item_type, :source_product_id, :source_product_set_id, :sort_order, :payload_json, :personalization
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'source_item_id' => $row['source_item_id'] ?? null,
|
|
'external_item_id' => $row['external_item_id'] ?? null,
|
|
'ean' => $row['ean'] ?? null,
|
|
'sku' => $row['sku'] ?? null,
|
|
'original_name' => (string) ($row['original_name'] ?? ''),
|
|
'original_code' => $row['original_code'] ?? null,
|
|
'original_price_with_tax' => $row['original_price_with_tax'] ?? null,
|
|
'original_price_without_tax' => $row['original_price_without_tax'] ?? null,
|
|
'media_url' => $row['media_url'] ?? null,
|
|
'quantity' => $row['quantity'] ?? 1,
|
|
'tax_rate' => $row['tax_rate'] ?? null,
|
|
'item_status' => $row['item_status'] ?? null,
|
|
'unit' => $row['unit'] ?? null,
|
|
'item_type' => (string) ($row['item_type'] ?? 'product'),
|
|
'source_product_id' => $row['source_product_id'] ?? null,
|
|
'source_product_set_id' => $row['source_product_set_id'] ?? null,
|
|
'sort_order' => (int) ($row['sort_order'] ?? 0),
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
'personalization' => $row['personalization'] ?? null,
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replacePayments(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_payments WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_payments (
|
|
order_id, source_payment_id, external_payment_id, payment_type_id, payment_date, amount, currency, comment, payload_json
|
|
) VALUES (
|
|
:order_id, :source_payment_id, :external_payment_id, :payment_type_id, :payment_date, :amount, :currency, :comment, :payload_json
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'source_payment_id' => $row['source_payment_id'] ?? null,
|
|
'external_payment_id' => $row['external_payment_id'] ?? null,
|
|
'payment_type_id' => (string) ($row['payment_type_id'] ?? 'unknown'),
|
|
'payment_date' => $row['payment_date'] ?? null,
|
|
'amount' => $row['amount'] ?? null,
|
|
'currency' => $row['currency'] ?? null,
|
|
'comment' => $row['comment'] ?? null,
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replaceShipments(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_shipments WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_shipments (
|
|
order_id, source_shipment_id, external_shipment_id, tracking_number, carrier_provider_id, posted_at, media_uuid, payload_json
|
|
) VALUES (
|
|
:order_id, :source_shipment_id, :external_shipment_id, :tracking_number, :carrier_provider_id, :posted_at, :media_uuid, :payload_json
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'source_shipment_id' => $row['source_shipment_id'] ?? null,
|
|
'external_shipment_id' => $row['external_shipment_id'] ?? null,
|
|
'tracking_number' => (string) ($row['tracking_number'] ?? ''),
|
|
'carrier_provider_id' => (string) ($row['carrier_provider_id'] ?? 'unknown'),
|
|
'posted_at' => $row['posted_at'] ?? null,
|
|
'media_uuid' => $row['media_uuid'] ?? null,
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replaceNotes(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_notes WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_notes (
|
|
order_id, source_note_id, note_type, created_at_external, comment, payload_json
|
|
) VALUES (
|
|
:order_id, :source_note_id, :note_type, :created_at_external, :comment, :payload_json
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'source_note_id' => $row['source_note_id'] ?? null,
|
|
'note_type' => (string) ($row['note_type'] ?? 'message'),
|
|
'created_at_external' => $row['created_at_external'] ?? null,
|
|
'comment' => (string) ($row['comment'] ?? ''),
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $rows
|
|
*/
|
|
private function replaceStatusHistory(int $orderId, array $rows): void
|
|
{
|
|
$this->pdo->prepare('DELETE FROM order_status_history WHERE order_id = :order_id')->execute(['order_id' => $orderId]);
|
|
if ($rows === []) {
|
|
return;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO order_status_history (
|
|
order_id, from_status_id, to_status_id, changed_at, change_source, comment, payload_json
|
|
) VALUES (
|
|
:order_id, :from_status_id, :to_status_id, :changed_at, :change_source, :comment, :payload_json
|
|
)'
|
|
);
|
|
|
|
foreach ($rows as $row) {
|
|
$statement->execute([
|
|
'order_id' => $orderId,
|
|
'from_status_id' => $row['from_status_id'] ?? null,
|
|
'to_status_id' => (string) ($row['to_status_id'] ?? ''),
|
|
'changed_at' => $row['changed_at'] ?? date('Y-m-d H:i:s'),
|
|
'change_source' => (string) ($row['change_source'] ?? 'import'),
|
|
'comment' => $row['comment'] ?? null,
|
|
'payload_json' => $this->encodeJson($row['payload_json'] ?? null),
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function encodeJson(mixed $value): ?string
|
|
{
|
|
if ($value === null || $value === '') {
|
|
return null;
|
|
}
|
|
if (!is_array($value)) {
|
|
return null;
|
|
}
|
|
|
|
return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: null;
|
|
}
|
|
}
|