fix bug of pargar
This commit is contained in:
@@ -6,9 +6,11 @@ use App\Models\Customer;
|
||||
use App\Models\PargarSyncLog;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Rooyesh\Wallet\interfaces\TransactionInterface;
|
||||
use Rooyesh\Wallet\interfaces\WalletInterface;
|
||||
use Rooyesh\Wallet\models\Transaction;
|
||||
|
||||
/**
|
||||
* همگامسازی کیف با پرگار.
|
||||
@@ -21,7 +23,9 @@ use Rooyesh\Wallet\interfaces\WalletInterface;
|
||||
* پیش از ثبت سند گرفته شده باشد، اعمال نمیشود و منتظر ماندهٔ بعدی میمانیم.
|
||||
* 4) اعمال فقط با دو snapshot پیاپیِ هممقدار — تا ماندهای که وسط ثبت اسناد گرفته شده
|
||||
* موجودی مشتری را عقب نبرد.
|
||||
* 5) دکمهٔ ادمین با force میتواند همهٔ گیتهای بالا را رد کند (ابزار اصلاح دستی).
|
||||
* 5) اگر واریز/برداشت ریالیای اصلاً سند پرگار نداشته باشد، مانده اعمال نمیشود؛
|
||||
* پرگار از آن پول خبر ندارد و اعمال مانده موجودی مشتری را پاک میکند.
|
||||
* 6) دکمهٔ ادمین با force میتواند همهٔ گیتهای بالا را رد کند (ابزار اصلاح دستی).
|
||||
*/
|
||||
class PargarInboundWalletService
|
||||
{
|
||||
@@ -29,6 +33,9 @@ class PargarInboundWalletService
|
||||
|
||||
public const KILL_SWITCH_CACHE_KEY = 'pargar_wallet_apply_disabled';
|
||||
|
||||
/** واریز و برداشت ریالی — دو نوعی که باید سند ریالی پرگار داشته باشند */
|
||||
public const CASH_DOCUMENT_TX_TYPES = [3, 4];
|
||||
|
||||
/** سقف تعداد دسته برای علامتزدن در هر کلیک */
|
||||
private const MAX_BATCHES_PER_SYNC = 50;
|
||||
|
||||
@@ -342,12 +349,16 @@ class PargarInboundWalletService
|
||||
$input['cash'] = abs($rialDiff);
|
||||
}
|
||||
|
||||
// مانده پرگار میتواند منفی باشد و کیف باید همان را نشان دهد؛ کف موجودی اینجا اعمال نمیشود
|
||||
new TransactionInterface(
|
||||
$walletInterface,
|
||||
$input,
|
||||
self::TX_TYPE_PARGAR,
|
||||
$goldDiff > 0,
|
||||
$rialDiff > 0
|
||||
$rialDiff > 0,
|
||||
0,
|
||||
[],
|
||||
true
|
||||
);
|
||||
|
||||
$data['wallet_applied_from_mande'] = true;
|
||||
@@ -404,6 +415,16 @@ class PargarInboundWalletService
|
||||
];
|
||||
}
|
||||
|
||||
$missing = $this->unexportedCashMovement($customer, $lastConfirmedAt);
|
||||
if ($missing !== null) {
|
||||
return [
|
||||
'reason' => 'unexported_wallet_movement',
|
||||
'message' => 'حرکت ریالی '
|
||||
. number_format($missing['amount'])
|
||||
. ' ریال هنوز سندی در پرگار ندارد — تا ثبت سند، مانده اعمال نمیشود',
|
||||
];
|
||||
}
|
||||
|
||||
$previous = $this->previousComparableMande($log, $lastConfirmedAt);
|
||||
if ($previous === null) {
|
||||
return [
|
||||
@@ -429,6 +450,67 @@ class PargarInboundWalletService
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* واریز/برداشت ریالی که سند پرگارش ساخته نشده است.
|
||||
*
|
||||
* تا وقتی پرگار از این حرکت خبر ندارد، ماندهٔ آن هم شامل این پول نیست؛ اعمال آن
|
||||
* موجودی مشتری را پاک میکند. پس مانده را نگه میداریم تا سند ساخته و ثبت شود.
|
||||
*
|
||||
* @return array{amount: float, withdraw_ids: list<int>}|null
|
||||
*/
|
||||
private function unexportedCashMovement(Customer $customer, ?Carbon $lastConfirmedAt): ?array
|
||||
{
|
||||
$since = $this->cashMovementScanStart($customer, $lastConfirmedAt);
|
||||
if ($since === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rows = Transaction::query()
|
||||
->where('customer_id', $customer->id)
|
||||
->whereIn('type', self::CASH_DOCUMENT_TX_TYPES)
|
||||
->whereNotNull('withdraw_id')
|
||||
->where('created_at', '>', $since)
|
||||
->where(function ($q) {
|
||||
$q->where('cash', '>=', 1)->orWhere('cash', '<=', -1);
|
||||
})
|
||||
->whereNotExists(function ($q) {
|
||||
$q->select(DB::raw(1))
|
||||
->from('pargar_sync_logs')
|
||||
->whereColumn('pargar_sync_logs.withdraw_id', 'transactions.withdraw_id')
|
||||
->where('pargar_sync_logs.type', PargarSyncService::TYPE_WALLET_CASH);
|
||||
})
|
||||
->get(['withdraw_id', 'cash']);
|
||||
|
||||
if ($rows->isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'amount' => (float) $rows->sum(fn ($row) => abs((float) $row->cash)),
|
||||
'withdraw_ids' => $rows->pluck('withdraw_id')->map(fn ($id) => (int) $id)->all(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* از کجا دنبال سند جاافتاده بگردیم: بعد از آخرین سند ثبتشده، و اگر نبود از
|
||||
* شروع اتصال همین مشتری به پرگار. تراکنشهای قبل از اتصال سند ندارند و نباید
|
||||
* سینک را برای همیشه قفل کنند.
|
||||
*/
|
||||
private function cashMovementScanStart(Customer $customer, ?Carbon $lastConfirmedAt): ?Carbon
|
||||
{
|
||||
$firstLogAt = PargarSyncLog::query()
|
||||
->where('customer_id', $customer->id)
|
||||
->min('created_at');
|
||||
|
||||
$integrationStart = $firstLogAt !== null ? Carbon::parse($firstLogAt) : null;
|
||||
|
||||
if ($lastConfirmedAt !== null && $integrationStart !== null) {
|
||||
return $lastConfirmedAt->greaterThan($integrationStart) ? $lastConfirmedAt : $integrationStart;
|
||||
}
|
||||
|
||||
return $lastConfirmedAt ?? $integrationStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* ماندهٔ صفرِ هر دو فیلد برای مشتریای که کیفش خالی نیست، تقریباً همیشه یعنی
|
||||
* پرگار حساب را پیدا نکرده — نه اینکه مشتری تسویه کرده باشد.
|
||||
|
||||
Reference in New Issue
Block a user