Files
esun3d/app/code/Esun/LingxingErp/Model/Sync/ShipmentSyncRepository.php
T
2026-09-15 10:35:56 +08:00

108 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\LingxingErp\Model\Sync;
use Magento\Framework\App\ResourceConnection;
class ShipmentSyncRepository
{
private string $table;
public function __construct(private readonly ResourceConnection $resource)
{
$this->table = $resource->getTableName('esun_lingxing_shipment_sync');
}
public function enqueue(array $payload, string $requestId = ''): void
{
$connection = $this->resource->getConnection();
$externalKey = (string)$payload['external_key'];
$existing = $connection->fetchRow($connection->select()->from($this->table)
->where('external_key = ?', $externalKey)->limit(1));
$data = [
'global_order_no' => (string)($payload['global_order_no'] ?? ''),
'wo_id' => !empty($payload['wo_id']) ? (int)$payload['wo_id'] : null,
'wo_number' => (string)$payload['wo_number'],
'package_no' => (string)($payload['package_no'] ?? '') ?: null,
'tracking_no' => implode(',', array_values(array_filter(array_column($payload['tracks'] ?? [], 'number')))),
'request_id' => $requestId ?: null,
'payload_json' => (string)json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
'updated_at' => gmdate('Y-m-d H:i:s'),
];
if (!$existing) {
$data += [
'external_key' => $externalKey,
'status' => 'pending',
'created_at' => gmdate('Y-m-d H:i:s'),
];
$connection->insert($this->table, $data);
return;
}
if ((string)$existing['status'] !== 'success') {
$connection->update($this->table, $data, ['entity_id = ?' => (int)$existing['entity_id']]);
}
}
public function getDue(int $limit): array
{
$connection = $this->resource->getConnection();
return $connection->fetchAll($connection->select()->from($this->table)
->where('status IN (?)', ['pending', 'retrying'])
->where('next_retry_at IS NULL OR next_retry_at <= ?', gmdate('Y-m-d H:i:s'))
->order('entity_id ASC')->limit($limit));
}
public function claim(int $entityId): bool
{
return $this->resource->getConnection()->update($this->table, [
'status' => 'processing',
'last_attempt_at' => gmdate('Y-m-d H:i:s'),
], ['entity_id = ?' => $entityId, 'status IN (?)' => ['pending', 'retrying']]) === 1;
}
public function markSuccess(int $entityId, int $orderId, string $incrementId, int $shipmentId): void
{
$now = gmdate('Y-m-d H:i:s');
$this->resource->getConnection()->update($this->table, [
'order_id' => $orderId,
'increment_id' => $incrementId,
'shipment_id' => $shipmentId,
'status' => 'success',
'last_error_code' => null,
'last_error_message' => null,
'next_retry_at' => null,
'synced_at' => $now,
'updated_at' => $now,
], ['entity_id = ?' => $entityId]);
}
public function markFailure(int $entityId, int $attemptCount, int $maxAttempts, string $code, string $message): string
{
$attemptCount++;
$status = $attemptCount >= $maxAttempts ? 'failed' : 'retrying';
$delay = min(3600, 30 * (2 ** min(7, max(0, $attemptCount - 1))));
$this->resource->getConnection()->update($this->table, [
'status' => $status,
'attempt_count' => $attemptCount,
'next_retry_at' => $status === 'retrying' ? gmdate('Y-m-d H:i:s', time() + $delay) : null,
'last_error_code' => $code ?: null,
'last_error_message' => mb_substr($message, 0, 65535),
'updated_at' => gmdate('Y-m-d H:i:s'),
], ['entity_id = ?' => $entityId]);
return $status;
}
public function retry(int $entityId): bool
{
return $this->resource->getConnection()->update($this->table, [
'status' => 'pending',
'attempt_count' => 0,
'next_retry_at' => null,
'last_error_code' => null,
'last_error_message' => null,
'updated_at' => gmdate('Y-m-d H:i:s'),
], ['entity_id = ?' => $entityId, 'status IN (?)' => ['failed', 'retrying']]) === 1;
}
}