From d43c5e1f2579a87a204f17fd17be777a4eb0fa2c Mon Sep 17 00:00:00 2001 From: adonis Date: Tue, 21 Jul 2026 12:49:08 +0330 Subject: [PATCH] fix pargar bugs --- .../Controllers/Admin/PargarController.php | 32 ++++ app/Services/PargarInboundWalletService.php | 148 +++++++++++++++++- routes/admin.php | 1 + 3 files changed, 179 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Admin/PargarController.php b/app/Http/Controllers/Admin/PargarController.php index 2055596..b8f016e 100644 --- a/app/Http/Controllers/Admin/PargarController.php +++ b/app/Http/Controllers/Admin/PargarController.php @@ -5,6 +5,8 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Customer; use App\Models\PargarSyncLog; +use App\Services\ConfigService; +use App\Services\PargarInboundWalletService; use App\Services\PargarSyncService; use Illuminate\Http\Request; @@ -253,6 +255,36 @@ class PargarController extends Controller return response()->json($result, ($result['ok'] ?? false) ? 200 : 422); } + public function syncCustomerWallet($customerId) + { + if (! app(ConfigService::class)->isPargarAccounting()) { + return response()->json([ + 'ok' => false, + 'message' => 'حسابداری پرگار فعال نیست', + ], 422); + } + + $customer = Customer::findOrFail($customerId); + if (trim((string) ($customer->pargar_account_id ?? '')) === '') { + return response()->json([ + 'ok' => false, + 'message' => 'این مشتری کد حساب پرگار ندارد', + ], 422); + } + + $result = app(PargarInboundWalletService::class)->syncWalletFromPargar($customer); + $appliedDocs = (int) ($result['documents']['applied'] ?? 0); + $appliedMande = (bool) ($result['mande']['applied'] ?? false); + + return response()->json([ + 'ok' => $appliedDocs > 0 || $appliedMande, + 'message' => $appliedDocs > 0 || $appliedMande + ? 'مانده از پرگار روی کیف اعمال شد' + : ($result['mande']['message'] ?? 'سند قابل‌اعمالی یافت نشد'), + 'result' => $result, + ], $appliedDocs > 0 || $appliedMande ? 200 : 422); + } + private function uniqueReferralId(): string { do { diff --git a/app/Services/PargarInboundWalletService.php b/app/Services/PargarInboundWalletService.php index f215cc6..3dce010 100644 --- a/app/Services/PargarInboundWalletService.php +++ b/app/Services/PargarInboundWalletService.php @@ -122,17 +122,161 @@ class PargarInboundWalletService return $result; } + /** + * اسناد ذخیره‌شدهٔ قبلی (قبل از deploy) را از لاگ دوباره اعمال می‌کند. + * + * @return array{applied: int, skipped: int, errors: list, logs: list} + */ + public function replayStoredDocuments(Customer $customer): array + { + $accountId = trim((string) ($customer->pargar_account_id ?? '')); + + $logs = PargarSyncLog::query() + ->where('type', PargarSyncService::TYPE_DOCUMENT) + ->where(function ($q) use ($customer, $accountId) { + $q->where('customer_id', $customer->id); + if ($accountId !== '') { + $q->orWhere('pargar_ref', $accountId); + } + }) + ->orderBy('id') + ->get(); + + $total = [ + 'applied' => 0, + 'skipped' => 0, + 'errors' => [], + 'logs' => [], + ]; + + foreach ($logs as $log) { + $data = json_decode((string) $log->data, true); + if (! is_array($data) || empty($data['transactions']) || ! is_array($data['transactions'])) { + continue; + } + + $batch = $this->applyDocuments($customer, $data); + $total['applied'] += $batch['applied']; + $total['skipped'] += $batch['skipped']; + $total['errors'] = array_merge($total['errors'], $batch['errors']); + $total['logs'] = array_merge($total['logs'], $batch['logs']); + } + + return $total; + } + + /** + * آخرین ماندهٔ پرگار را (در صورت اختلاف) یک‌بار روی کیف اعمال می‌کند — فقط با درخواست ادمین. + * + * @return array{applied: bool, gold_delta?: float, rial_delta?: float, message: string} + */ + public function applyLatestMandeDifference(Customer $customer): array + { + $log = PargarSyncLog::query() + ->where('customer_id', $customer->id) + ->where('type', PargarSyncService::TYPE_MANDE) + ->orderByDesc('id') + ->first(); + + if ($log === null) { + return ['applied' => false, 'message' => 'لاگ ماندهٔ پرگار برای این مشتری یافت نشد']; + } + + $data = json_decode((string) $log->data, true) ?: []; + if (! empty($data['wallet_applied_from_mande'])) { + return ['applied' => false, 'message' => 'ماندهٔ پرگار قبلاً روی کیف اعمال شده است']; + } + + $goldInv = $this->parseNumber($data['GoldInv'] ?? 0); + $rialInv = $this->parseNumber($data['RialInv'] ?? 0); + + $ownerType = (int) ($customer->type ?? 2); + $walletInterface = new WalletInterface((int) $customer->id, $ownerType); + $wallet = $walletInterface->wallet; + + $goldDiff = $goldInv - (float) ($wallet->gold ?? 0); + $rialDiff = $rialInv - (float) ($wallet->cash ?? 0); + + if (abs($goldDiff) < 0.01 && abs($rialDiff) < 1) { + $data['wallet_applied_from_mande'] = true; + $log->data = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + $log->save(); + + return ['applied' => false, 'message' => 'اختلافی بین ماندهٔ پرگار و کیف اپ نیست']; + } + + $input = [ + 'title' => 'تطبیق ماندهٔ پرگار', + 'note' => 'mande-log:' . $log->id, + 'expire_at' => now(), + 'active' => true, + ]; + if (abs($goldDiff) >= 0.01) { + $input['gold'] = abs($goldDiff); + } + if (abs($rialDiff) >= 1) { + $input['cash'] = abs($rialDiff); + } + + new TransactionInterface( + $walletInterface, + $input, + self::TX_TYPE_PARGAR, + $goldDiff > 0, + $rialDiff > 0 + ); + + $data['wallet_applied_from_mande'] = true; + $data['applied_gold_delta'] = $goldDiff; + $data['applied_rial_delta'] = $rialDiff; + $log->data = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + $log->desc = 'اعمال ماندهٔ پرگار روی کیف اپ'; + $log->save(); + + $this->walletBroadcast->broadcastForCustomer((int) $customer->id, $ownerType); + + return [ + 'applied' => true, + 'gold_delta' => $goldDiff, + 'rial_delta' => $rialDiff, + 'message' => 'ماندهٔ پرگار روی کیف اعمال شد', + ]; + } + + /** + * @return array{ + * documents: array{applied: int, skipped: int, errors: list, logs: list}, + * mande: array{applied: bool, gold_delta?: float, rial_delta?: float, message: string} + * } + */ + public function syncWalletFromPargar(Customer $customer): array + { + return [ + 'documents' => $this->replayStoredDocuments($customer), + 'mande' => $this->applyLatestMandeDifference($customer), + ]; + } + public function isDocumentApplied(string $docId): bool { if ($docId === '') { return false; } - return PargarSyncLog::query() + $logs = PargarSyncLog::query() ->where('type', PargarSyncService::TYPE_DOCUMENT) ->where('pargar_ref', $docId) ->where('sync_status', PargarSyncService::STATUS_SUCCESS) - ->exists(); + ->get(['data']); + + foreach ($logs as $log) { + $data = json_decode((string) $log->data, true); + if (($data['wallet_applied'] ?? false) === true) { + return true; + } + } + + return false; } /** diff --git a/routes/admin.php b/routes/admin.php index e83452b..a45c14d 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -186,6 +186,7 @@ Route::middleware('auth:user')->group(function (){ Route::get('pargar/{id}', [PargarController::class, 'show']); Route::post('pargar/{id}/retry', [PargarController::class, 'retrySanad']); Route::post('customer/{id}/pargar/register', [PargarController::class, 'registerCustomer']); + Route::post('customer/{id}/pargar/sync-wallet', [PargarController::class, 'syncCustomerWallet']); Route::get('test', function () { $data = [