147 lines
5.6 KiB
PHP
147 lines
5.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\LingxingErp\Model\Sync;
|
|
|
|
use Magento\Framework\App\ResourceConnection;
|
|
use Magento\Sales\Api\Data\OrderInterface;
|
|
use Magento\Sales\Model\Order;
|
|
|
|
class OrderSyncRepository
|
|
{
|
|
private string $table;
|
|
|
|
public function __construct(private readonly ResourceConnection $resource)
|
|
{
|
|
$this->table = $resource->getTableName('esun_lingxing_order_sync');
|
|
}
|
|
|
|
public function enqueue(OrderInterface $order): void
|
|
{
|
|
$connection = $this->resource->getConnection();
|
|
$exists = $connection->fetchOne(
|
|
$connection->select()->from($this->table, ['entity_id'])->where('order_id = ?', (int)$order->getEntityId())
|
|
);
|
|
if ($exists) {
|
|
return;
|
|
}
|
|
$now = gmdate('Y-m-d H:i:s');
|
|
$connection->insert($this->table, [
|
|
'order_id' => (int)$order->getEntityId(),
|
|
'increment_id' => (string)$order->getIncrementId(),
|
|
'platform_order_no' => (string)$order->getIncrementId(),
|
|
'status' => 'pending',
|
|
'created_at' => $now,
|
|
'updated_at' => $now,
|
|
]);
|
|
}
|
|
|
|
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, string $globalOrderNo, string $requestId, string $payloadHash): void
|
|
{
|
|
$now = gmdate('Y-m-d H:i:s');
|
|
$this->resource->getConnection()->update($this->table, [
|
|
'global_order_no' => $globalOrderNo,
|
|
'status' => 'success',
|
|
'request_id' => $requestId ?: null,
|
|
'payload_hash' => $payloadHash,
|
|
'last_error_code' => null,
|
|
'last_error_message' => null,
|
|
'next_retry_at' => null,
|
|
'synced_at' => $now,
|
|
'updated_at' => $now,
|
|
], ['entity_id = ?' => $entityId]);
|
|
}
|
|
|
|
public function markCreationCanceled(int $entityId): void
|
|
{
|
|
$now = gmdate('Y-m-d H:i:s');
|
|
$this->resource->getConnection()->update($this->table, [
|
|
'status' => 'canceled',
|
|
'next_retry_at' => null,
|
|
'updated_at' => $now,
|
|
], ['entity_id = ?' => $entityId]);
|
|
}
|
|
|
|
public function markFailure(int $entityId, int $attemptCount, int $maxAttempts, string $code, string $message, string $requestId = ''): 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),
|
|
'request_id' => $requestId ?: null,
|
|
'updated_at' => gmdate('Y-m-d H:i:s'),
|
|
], ['entity_id = ?' => $entityId]);
|
|
return $status;
|
|
}
|
|
|
|
public function findByGlobalOrderNo(string $globalOrderNo): ?array
|
|
{
|
|
$connection = $this->resource->getConnection();
|
|
$row = $connection->fetchRow($connection->select()->from($this->table)
|
|
->where('global_order_no = ?', $globalOrderNo)->limit(1));
|
|
return is_array($row) ? $row : null;
|
|
}
|
|
|
|
public function findByIncrementId(string $incrementId): ?array
|
|
{
|
|
$connection = $this->resource->getConnection();
|
|
$row = $connection->fetchRow($connection->select()->from($this->table)
|
|
->where('increment_id = ?', $incrementId)->limit(1));
|
|
return is_array($row) ? $row : null;
|
|
}
|
|
|
|
/** @return string[] */
|
|
public function getTrackablePlatformOrderNos(): array
|
|
{
|
|
$connection = $this->resource->getConnection();
|
|
$salesOrderTable = $this->resource->getTableName('sales_order');
|
|
$select = $connection->select()
|
|
->from(['sync' => $this->table], ['platform_order_no'])
|
|
->joinInner(['sales_order' => $salesOrderTable], 'sales_order.entity_id = sync.order_id', [])
|
|
->where('sync.status = ?', 'success')
|
|
->where('sync.platform_order_no <> ?', '')
|
|
->where('sales_order.state NOT IN (?)', [
|
|
Order::STATE_COMPLETE,
|
|
Order::STATE_CLOSED,
|
|
Order::STATE_CANCELED,
|
|
])
|
|
->order('sync.entity_id ASC');
|
|
return array_values(array_unique(array_map('strval', $connection->fetchCol($select))));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|