Files
boursecu_server/app/Services/PargarSyncService.php
T

268 lines
8.4 KiB
PHP

<?php
namespace App\Services;
use App\Models\Customer;
use App\Models\Order;
use App\Models\PargarSyncLog;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
class PargarSyncService
{
public const STATUS_PENDING = 'pending';
public const STATUS_SUCCESS = 'success';
public const STATUS_FAILED = 'failed';
public function buildLog(mixed $response = null, ?string $extra = null): string
{
$parts = array_filter([
$extra,
is_array($response) ? json_encode($response, JSON_UNESCAPED_UNICODE) : (is_string($response) ? $response : null),
]);
return implode("\n", $parts);
}
public function markSuccess(PargarSyncLog $log, ?string $ref = null, mixed $response = null, ?array $payload = null): void
{
$update = [
'pargar_ref' => $ref,
'res' => is_array($response)
? json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
: (is_string($response) ? $response : null),
'sync_status' => self::STATUS_SUCCESS,
'sync_log' => null,
];
if ($payload !== null) {
$update['data'] = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
PargarSyncLog::where('id', $log->id)->update($update);
}
public function markFailed(PargarSyncLog $log, mixed $response = null, ?string $extra = null): void
{
PargarSyncLog::where('id', $log->id)->update([
'res' => is_array($response)
? json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
: (is_string($response) ? $response : null),
'sync_status' => self::STATUS_FAILED,
'sync_log' => $this->buildLog($response, $extra),
]);
}
public function isFailed(PargarSyncLog $log): bool
{
return ($log->sync_status ?? null) === self::STATUS_FAILED
|| (empty($log->pargar_ref) && ($log->sync_status ?? null) !== self::STATUS_SUCCESS);
}
public function registerOnCreate(Customer $customer): void
{
if (! empty($customer->pargar_account_id) || ! $this->isSyncEnabled()) {
return;
}
$customerId = (int) $customer->id;
dispatch(function () use ($customerId) {
$service = app(self::class);
if (! $service->isSyncEnabled()) {
return;
}
$customer = Customer::find($customerId);
if ($customer === null || ! empty($customer->pargar_account_id)) {
return;
}
try {
$service->queueCustomerExport($customer);
} catch (\Throwable $e) {
Log::warning('Pargar auto-queue on customer create failed', [
'customer_id' => $customerId,
'error' => $e->getMessage(),
]);
}
})->afterResponse();
}
public function queueCustomerExport(Customer $customer): PargarSyncLog
{
$existing = PargarSyncLog::query()
->where('customer_id', $customer->id)
->where('type', 'customer')
->where('sync_status', self::STATUS_PENDING)
->latest('id')
->first();
if ($existing) {
return $existing;
}
return PargarSyncLog::create([
'customer_id' => $customer->id,
'desc' => 'در انتظار دریافت توسط پرگار',
'type' => 'customer',
'sync_status' => self::STATUS_PENDING,
'data' => json_encode(['handler' => 'exportCustomer'], JSON_UNESCAPED_UNICODE),
]);
}
public function registerCustomer(Customer $customer): array
{
$customer->refresh();
if (! empty($customer->pargar_account_id)) {
return [
'ok' => true,
'message' => 'مشتری قبلاً در پرگار ثبت شده است',
'pargar_account_id' => $customer->pargar_account_id,
];
}
$this->queueCustomerExport($customer);
return [
'ok' => true,
'message' => 'مشتری در صف دریافت پرگار قرار گرفت',
'pargar_account_id' => null,
];
}
public function recordTrade(?Order $order, bool $fromCart = false): ?PargarSyncLog
{
if (! $order || ! $order->id || ! $this->isSyncEnabled()) {
return null;
}
$existing = PargarSyncLog::where('order_id', $order->id)->first();
if ($existing) {
return $existing;
}
$direction = (int) ($order->direction ?? 0);
$desc = \App\Http\Controllers\Controller::accountingShopTradeDesc($direction, $fromCart);
return PargarSyncLog::create([
'customer_id' => $order->customer_id,
'amount' => $order->amount,
'desc' => $desc,
'order_id' => $order->id,
'date' => $order->pay_at ?? $order->created_at,
'type' => 'order',
'sync_status' => self::STATUS_PENDING,
'data' => json_encode([
'handler' => 'exportOrder',
'direction' => $direction,
'price' => $order->price,
'total_price' => $order->total_price,
], JSON_UNESCAPED_UNICODE),
]);
}
public function confirmOrders(array $orderIds): array
{
$confirmed = 0;
foreach ($orderIds as $orderId) {
$order = Order::find($orderId);
if (! $order) {
continue;
}
$order->pargar_confirmed_at = now();
$order->save();
$log = PargarSyncLog::where('order_id', $order->id)->latest('id')->first();
if ($log) {
$this->markSuccess($log, (string) $order->id, ['OrderId' => (string) $order->id]);
}
$confirmed++;
}
return ['confirmed' => $confirmed];
}
public function retry(PargarSyncLog $log): array
{
if (! $this->isFailed($log) && ! empty($log->pargar_ref)) {
return ['ok' => false, 'message' => 'این سند قبلاً در پرگار ثبت شده است'];
}
$payload = json_decode((string) $log->data, true) ?: [];
$handler = $payload['handler'] ?? $this->inferHandler($log);
if ($handler === 'exportOrder' && $log->order_id) {
Order::where('id', $log->order_id)->update(['pargar_confirmed_at' => null]);
PargarSyncLog::where('id', $log->id)->update([
'sync_status' => self::STATUS_PENDING,
'sync_log' => null,
'pargar_ref' => null,
]);
$log->refresh();
return [
'ok' => true,
'message' => 'سفارش دوباره در صف ارسال به پرگار قرار گرفت',
'pargar' => $log,
];
}
if ($handler === 'exportCustomer' && $log->customer_id) {
PargarSyncLog::where('id', $log->id)->update([
'sync_status' => self::STATUS_PENDING,
'sync_log' => null,
'pargar_ref' => null,
]);
$log->refresh();
return [
'ok' => true,
'message' => 'مشتری دوباره در صف دریافت پرگار قرار گرفت',
'pargar' => $log,
];
}
return [
'ok' => false,
'message' => $log->sync_log ?: 'ارسال مجدد به پرگار ناموفق بود',
'pargar' => $log,
];
}
private function inferHandler(PargarSyncLog $log): string
{
if ($log->order_id) {
return 'exportOrder';
}
if ($log->type === 'customer') {
return 'exportCustomer';
}
if ($log->type === 'mande') {
return 'importMande';
}
return 'importDocument';
}
public function isSyncEnabled(): bool
{
$config = app(ConfigService::class);
return $config->isPargarAccounting()
&& trim($config->getString('pargar_username', '')) !== ''
&& trim($config->getString('pargar_password', '')) !== '';
}
public function hasSyncTable(): bool
{
return Schema::hasTable('pargar_sync_logs');
}
}