fix pargar and login

This commit is contained in:
2026-08-01 14:04:01 +03:30
parent 6e75b9632b
commit 87f0e2beed
9 changed files with 248 additions and 38 deletions
+143 -4
View File
@@ -151,9 +151,18 @@ class PargarSyncService
];
}
/**
* سقف تاریخی ستون amount وقتی هنوز DOUBLE(8,2) است (~۹۹۹٬۹۹۹٫۹۹).
* مبلغ واقعی همیشه در data.signed_amount نگه داشته می‌شود.
*/
private const AMOUNT_COLUMN_SAFE_MAX = 999999.99;
/**
* صف سند کیف برای سینک مانده پرگار با اپ.
*
* سند pending باید حتماً ساخته شود؛ اگر ستون amount مبلغ بزرگ را نپذیرد،
* بدون amount ثبت می‌شود تا حرکت کیف بی‌سندی نماند و مانده قفل نشود.
*
* @param 'cash'|'gold' $kind
* @param array{withdraw_id?:int|null,note?:string|null,product_id?:int|null,source?:string|null} $meta
*/
@@ -201,9 +210,14 @@ class PargarSyncService
$desc = $isDeposit ? 'شارژ طلای کیف اصلی — ارسال به پرگار' : 'برداشت طلای کیف اصلی — ارسال به پرگار';
}
$absAmount = abs($signedAmount);
// اگر هنوز مایگریشن widen اجرا نشده، مبلغ بزرگ را از همان اول در ستون نگذار
// تا insert نترکد؛ خروجی/مانده از signed_amount می‌خوانند.
$columnAmount = $absAmount <= self::AMOUNT_COLUMN_SAFE_MAX ? $absAmount : null;
$attributes = [
'customer_id' => $customer->id,
'amount' => abs($signedAmount),
'amount' => $columnAmount,
'desc' => $desc,
'withdraw_id' => $withdrawId,
'date' => now(),
@@ -219,20 +233,145 @@ class PargarSyncService
], JSON_UNESCAPED_UNICODE),
];
if ($columnAmount === null) {
$attributes['sync_log'] = 'amount بزرگ‌تر از سقف ستون بود؛ مبلغ در data.signed_amount است';
}
return $this->createWalletSyncLogSafely($attributes, $absAmount);
}
/**
* ساخت لاگ سند کیف بدون امکان گم‌شدن به‌خاطر سقف ستون amount.
*
* @param array<string, mixed> $attributes
*/
private function createWalletSyncLogSafely(array $attributes, float $absAmount): PargarSyncLog
{
try {
// اگر ستون widen شده، مبلغ کامل را هم در amount بنویس (نمایش ادمین)
if (($attributes['amount'] ?? null) === null && $absAmount > self::AMOUNT_COLUMN_SAFE_MAX) {
$withAmount = $attributes;
$withAmount['amount'] = $absAmount;
unset($withAmount['sync_log']);
try {
return PargarSyncLog::create($withAmount);
} catch (QueryException $e) {
report($e);
$attributes['sync_log'] = mb_substr(
'amount ثبت نشد: ' . $e->getMessage(),
0,
500
);
}
}
return PargarSyncLog::create($attributes);
} catch (QueryException $e) {
report($e);
// مبلغ واقعی در data.signed_amount است و خروجی از همان می‌خواند؛
// پس اگر ستون amount مبلغ را نپذیرفت، سند را بدون آن ثبت می‌کنیم تا گم نشود.
$attributes['amount'] = null;
$attributes['sync_log'] = mb_substr('amount ثبت نشد: ' . $e->getMessage(), 0, 500);
return PargarSyncLog::create($attributes);
try {
return PargarSyncLog::create($attributes);
} catch (\Throwable $e2) {
report($e2);
return $this->insertWalletSyncLogRaw($attributes, $e2);
}
}
}
/**
* آخرین پناه: insert خام تا سند pending حتماً در DB بماند.
*
* @param array<string, mixed> $attributes
*/
private function insertWalletSyncLogRaw(array $attributes, \Throwable $previous): PargarSyncLog
{
$now = now();
$row = [
'customer_id' => $attributes['customer_id'] ?? null,
'amount' => null,
'desc' => $attributes['desc'] ?? null,
'order_id' => $attributes['order_id'] ?? null,
'withdraw_id' => $attributes['withdraw_id'] ?? null,
'date' => $attributes['date'] ?? $now,
'type' => $attributes['type'] ?? null,
'sync_status' => $attributes['sync_status'] ?? self::STATUS_PENDING,
'sync_log' => mb_substr(
(string) ($attributes['sync_log'] ?? '') . ' | raw insert: ' . $previous->getMessage(),
0,
500
),
'data' => $attributes['data'] ?? null,
'created_at' => $now,
'updated_at' => $now,
];
try {
$id = DB::table('pargar_sync_logs')->insertGetId($row);
$log = PargarSyncLog::find($id);
if ($log !== null) {
Log::warning('Pargar wallet document saved via raw insert', [
'pargar_sync_log_id' => $id,
'withdraw_id' => $row['withdraw_id'],
'customer_id' => $row['customer_id'],
]);
return $log;
}
} catch (\Throwable $e) {
report($e);
Log::critical('Pargar wallet document queue failed completely', [
'customer_id' => $row['customer_id'],
'withdraw_id' => $row['withdraw_id'],
'type' => $row['type'],
'error' => $e->getMessage(),
]);
throw $e;
}
throw new \RuntimeException(
'ساخت سند کیف پرگار ناموفق بود (withdraw_id=' . ($row['withdraw_id'] ?? 'null') . ')'
);
}
/**
* صف‌کردن سند برای واریز/برداشت‌هایی که لاگ پرگار ندارند.
*
* @param iterable<int, object{withdraw_id?:mixed,cash?:mixed,note?:mixed}> $rows
* @return int تعداد سند تازه‌ساخته یا موجود
*/
public function queueMissingCashDocuments(Customer $customer, iterable $rows, string $source = 'auto_missing'): int
{
if (! $this->isSyncEnabled() || ! $this->hasSyncTable()) {
return 0;
}
$queued = 0;
foreach ($rows as $row) {
$withdrawId = (int) ($row->withdraw_id ?? 0);
$cash = (float) ($row->cash ?? 0);
if ($withdrawId <= 0 || abs($cash) < 1) {
continue;
}
$log = $this->queueWalletDocument($customer, 'cash', $cash, [
'withdraw_id' => $withdrawId,
'note' => $row->note ?? null,
'source' => $source,
]);
if ($log !== null) {
$queued++;
}
}
return $queued;
}
/**
* @param array{
* payment_kind?: string,