some edits for pargar
This commit is contained in:
@@ -336,7 +336,7 @@ class PargarInboundController extends Controller
|
|||||||
$desc = $pendingOutbound
|
$desc = $pendingOutbound
|
||||||
? 'مانده دریافت شد — منتظر ثبت سند پنل در پرگار'
|
? 'مانده دریافت شد — منتظر ثبت سند پنل در پرگار'
|
||||||
: ($hasDiff
|
: ($hasDiff
|
||||||
? 'اختلاف مانده پرگار با اپ — پس از تأیید پایداری اعمال میشود'
|
? 'اختلاف مانده پرگار با اپ — در حال اعمال روی کیف'
|
||||||
: 'دریافت مانده از پرگار — بدون اختلاف');
|
: 'دریافت مانده از پرگار — بدون اختلاف');
|
||||||
|
|
||||||
PargarSyncLog::create([
|
PargarSyncLog::create([
|
||||||
@@ -356,17 +356,33 @@ class PargarInboundController extends Controller
|
|||||||
]), JSON_UNESCAPED_UNICODE),
|
]), JSON_UNESCAPED_UNICODE),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// همیشه صف همگامسازی: اگر سند pending نباشد اعمال میشود؛ وگرنه بعد از تأیید سند اعمال میشود
|
// سند pending نباشد → مانده را همینجا اعمال کن تا تغییر دستی حسابدار فوری روی اپ بنشیند
|
||||||
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customer->id);
|
// (صف afterResponse برای وقتی است که هنوز باید منتظر ثبت سند پنل بمانیم)
|
||||||
|
if ($pendingOutbound) {
|
||||||
|
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customer->id);
|
||||||
|
$appliedNow = false;
|
||||||
|
} else {
|
||||||
|
$appliedNow = false;
|
||||||
|
try {
|
||||||
|
$syncResult = $this->inboundWallet()->syncWalletFromPargar($customer, forceMande: false, auto: true);
|
||||||
|
$appliedNow = (bool) ($syncResult['mande']['applied'] ?? false);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
report($e);
|
||||||
|
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customer->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => $pendingOutbound
|
'message' => $pendingOutbound
|
||||||
? 'مانده ذخیره شد؛ بعد از ثبت سند در پرگار خودکار سینک میشود'
|
? 'مانده ذخیره شد؛ بعد از ثبت سند در پرگار خودکار سینک میشود'
|
||||||
: 'مانده دریافت شد؛ همگامسازی خودکار در صف است',
|
: ($appliedNow
|
||||||
|
? 'مانده دریافت و روی کیف اپ اعمال شد'
|
||||||
|
: 'مانده دریافت شد؛ همگامسازی انجام شد'),
|
||||||
'data' => [
|
'data' => [
|
||||||
'awaiting_outbound_confirm' => $pendingOutbound,
|
'awaiting_outbound_confirm' => $pendingOutbound,
|
||||||
'auto_sync_queued' => true,
|
'wallet_applied' => $appliedNow,
|
||||||
|
'auto_sync_queued' => $pendingOutbound,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ use Rooyesh\Wallet\models\Transaction;
|
|||||||
* محصولات خارج از کیف اصلی هرگز از مانده اثر نمیگیرند.
|
* محصولات خارج از کیف اصلی هرگز از مانده اثر نمیگیرند.
|
||||||
* 3) ماندهٔ کهنه دور ریخته میشود، نه معوق: اگر سند ما هنوز pending باشد یا snapshot
|
* 3) ماندهٔ کهنه دور ریخته میشود، نه معوق: اگر سند ما هنوز pending باشد یا snapshot
|
||||||
* پیش از ثبت سند گرفته شده باشد، اعمال نمیشود و منتظر ماندهٔ بعدی میمانیم.
|
* پیش از ثبت سند گرفته شده باشد، اعمال نمیشود و منتظر ماندهٔ بعدی میمانیم.
|
||||||
* 4) اعمال فقط با دو snapshot پیاپیِ هممقدار — تا ماندهای که وسط ثبت اسناد گرفته شده
|
* 4) ماندهٔ تازهٔ پرگار (از جمله صفر/تغییر دستی حسابدار) بلافاصله اعمال میشود —
|
||||||
* موجودی مشتری را عقب نبرد.
|
* دیگر منتظر دو snapshot یکسان یا بلوک صفر نمیمانیم.
|
||||||
* 5) اگر واریز/برداشت ریالیای اصلاً سند پرگار نداشته باشد، مانده اعمال نمیشود؛
|
* 5) اگر واریز/برداشت ریالیای اصلاً سند پرگار نداشته باشد، مانده اعمال نمیشود؛
|
||||||
* پرگار از آن پول خبر ندارد و اعمال مانده موجودی مشتری را پاک میکند.
|
* پرگار از آن پول خبر ندارد و اعمال مانده موجودی مشتری را پاک میکند.
|
||||||
* 6) دکمهٔ ادمین با force میتواند همهٔ گیتهای بالا را رد کند (ابزار اصلاح دستی).
|
* 6) دکمهٔ ادمین با force میتواند گیتهای سند pending را رد کند (ابزار اصلاح دستی).
|
||||||
*/
|
*/
|
||||||
class PargarInboundWalletService
|
class PargarInboundWalletService
|
||||||
{
|
{
|
||||||
@@ -461,9 +461,12 @@ class PargarInboundWalletService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ماندهٔ پرگار فقط وقتی معتبر است که همهٔ اسناد ما در پرگار ثبت شده باشند و
|
* ماندهٔ پرگار منبع حقیقت است — از جمله تغییر دستی حسابدار در پنل پرگار.
|
||||||
* snapshot بعد از آن ثبت گرفته شده باشد. اعمال ماندهٔ قدیمی یعنی برگرداندن
|
* فقط وقتی نگه میداریم که هنوز سندِ ساختهشدهٔ خودمان در پرگار ثبت نشده باشد؛
|
||||||
* موجودی مشتری به قبل از سند — همان «وزن/ریالم کم شد».
|
* وگرنه موجودی مشتری به قبل از آن سند برمیگردد («وزن/ریالم کم شد»).
|
||||||
|
*
|
||||||
|
* دیگر منتظر «دو snapshot یکسان» یا بلوک صفر نمیمانیم: حسابدار ممکن است عمداً
|
||||||
|
* مانده را صفر/عوض کند و باید همان لحظه روی اپ بنشیند.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $data
|
* @param array<string, mixed> $data
|
||||||
* @return array{reason: string, message: string}|null null یعنی معتبر
|
* @return array{reason: string, message: string}|null null یعنی معتبر
|
||||||
@@ -499,28 +502,6 @@ class PargarInboundWalletService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$previous = $this->previousComparableMande($log, $lastConfirmedAt);
|
|
||||||
if ($previous === null) {
|
|
||||||
return [
|
|
||||||
'reason' => 'awaiting_second_snapshot',
|
|
||||||
'message' => 'منتظر ماندهٔ بعدی برای تأیید پایداری',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $this->mandeValuesMatch($data, $previous)) {
|
|
||||||
return [
|
|
||||||
'reason' => 'unstable_snapshot',
|
|
||||||
'message' => 'ماندهٔ پرگار هنوز در حال تغییر است — منتظر مقدار پایدار',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isSuspiciousZeroSnapshot($customer, $data)) {
|
|
||||||
return [
|
|
||||||
'reason' => 'zero_snapshot',
|
|
||||||
'message' => 'ماندهٔ پرگار صفر است ولی کیف مشتری خالی نیست — برای جلوگیری از صفر شدن اشتباه اعمال نشد',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,29 +576,6 @@ class PargarInboundWalletService
|
|||||||
return $lastConfirmedAt ?? $integrationStart;
|
return $lastConfirmedAt ?? $integrationStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ماندهٔ صفرِ هر دو فیلد برای مشتریای که کیفش خالی نیست، تقریباً همیشه یعنی
|
|
||||||
* پرگار حساب را پیدا نکرده — نه اینکه مشتری تسویه کرده باشد.
|
|
||||||
*
|
|
||||||
* @param array<string, mixed> $data
|
|
||||||
*/
|
|
||||||
private function isSuspiciousZeroSnapshot(Customer $customer, array $data): bool
|
|
||||||
{
|
|
||||||
$goldInv = $this->parseNumber($data['GoldInv'] ?? 0);
|
|
||||||
$rialInv = $this->parseNumber($data['RialInv'] ?? 0);
|
|
||||||
|
|
||||||
if (abs($goldInv) >= 0.001 || abs($rialInv) >= 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ownerType = (int) ($customer->type ?? 2);
|
|
||||||
$mainGold = app(WalletBalanceService::class)
|
|
||||||
->effectiveMainWalletGold((int) $customer->id, $ownerType);
|
|
||||||
$cash = (float) ((new WalletInterface((int) $customer->id, $ownerType))->wallet->cash ?? 0);
|
|
||||||
|
|
||||||
return abs($mainGold) >= 0.01 || abs($cash) >= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* آخرین لحظهای که پرگار یکی از اسناد ما را ثبت کرده است.
|
* آخرین لحظهای که پرگار یکی از اسناد ما را ثبت کرده است.
|
||||||
*/
|
*/
|
||||||
@@ -640,50 +598,6 @@ class PargarInboundWalletService
|
|||||||
return $value !== null ? Carbon::parse($value) : null;
|
return $value !== null ? Carbon::parse($value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ماندهٔ قبلی که آن هم بعد از ثبت آخرین سند گرفته شده باشد.
|
|
||||||
*
|
|
||||||
* @return array<string, mixed>|null
|
|
||||||
*/
|
|
||||||
private function previousComparableMande(PargarSyncLog $log, ?Carbon $lastConfirmedAt): ?array
|
|
||||||
{
|
|
||||||
$query = PargarSyncLog::query()
|
|
||||||
->where('customer_id', $log->customer_id)
|
|
||||||
->where('type', PargarSyncService::TYPE_MANDE)
|
|
||||||
->where('id', '<', $log->id)
|
|
||||||
->orderByDesc('id');
|
|
||||||
|
|
||||||
if ($lastConfirmedAt !== null) {
|
|
||||||
$query->where('created_at', '>', $lastConfirmedAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
$previous = $query->first();
|
|
||||||
if ($previous === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = json_decode((string) $previous->data, true);
|
|
||||||
|
|
||||||
return is_array($data) ? $data : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array<string, mixed> $current
|
|
||||||
* @param array<string, mixed> $previous
|
|
||||||
*/
|
|
||||||
private function mandeValuesMatch(array $current, array $previous): bool
|
|
||||||
{
|
|
||||||
$goldMatch = abs(
|
|
||||||
$this->parseNumber($current['GoldInv'] ?? 0) - $this->parseNumber($previous['GoldInv'] ?? 0)
|
|
||||||
) < 0.001;
|
|
||||||
|
|
||||||
$rialMatch = abs(
|
|
||||||
$this->parseNumber($current['RialInv'] ?? 0) - $this->parseNumber($previous['RialInv'] ?? 0)
|
|
||||||
) < 1;
|
|
||||||
|
|
||||||
return $goldMatch && $rialMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $data
|
* @param array<string, mixed> $data
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user