fix(wallet): absorb cash left on old owner type
Deposits credited before customer type was set stayed on owner_type 0 and assets ignored them. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
فرمت هر خط:
|
||||
- YYYY-MM-DD | موضوع | مسیر فایل(ها) | نکتهٔ ۱ خطی
|
||||
|
||||
- 2026-11-14 | کیف ریال owner_type ناهماهنگ | `WalletBalanceService::absorbMismatchedOwnerTypeBalances` + `WalletInterface` | واریز روی owner_type=0 در دارایی نوع مشتری دیده نمیشود؛ با باز شدن کیف به نوع فعلی منتقل میشود
|
||||
- 2026-11-05 | کد کاربری مشتری بعدی | `Customer::nextSequentialId` در `creating` | کد کاربری=`customers.id`؛ بعد از UPDATE دستی id، AUTO_INCREMENT پایین نمیآید (۵۵۱ بهجای ۲۴). ایجاد مشتری = اولین id خالی، نه شمارندهٔ InnoDB
|
||||
- 2026-11-04 | فرمت کد تفصیلی شایگان | `ShayeganSyncService::customerTafsilNumber` | کل `shayegan_kol_customer` (121) + کد کاربر ۷رقمی: مشتری 1 → `1210000001`. کد ذخیرهشدهٔ قبلی عوض نمیشود
|
||||
- 2026-11-02 | جدول اسناد شایگان | `shayeganTable.vue` + `ShayeganController::table` | BaseTable؛ پاسخ بدون `query` را خود فرانت به `{rows,query}` برمیگرداند. ستون عملیات `ops` است تا در RTL هشدار fixed ندهد
|
||||
|
||||
@@ -89,6 +89,7 @@ class WalletController extends Controller
|
||||
$customer = auth('customer')->user();
|
||||
$customerId = (int) $customer->id;
|
||||
$ownerType = (int) $customer->type;
|
||||
$balanceService->absorbMismatchedOwnerTypeBalances($customerId, $ownerType);
|
||||
|
||||
$wallets = Wallet::query()
|
||||
->where('owner', $customerId)
|
||||
|
||||
@@ -26,6 +26,10 @@ class AssetSummaryService
|
||||
|
||||
public function buildForCustomer(int $customerId, int $ownerType, bool $includeInactiveProducts = false): array
|
||||
{
|
||||
if ($customerId > 0 && $ownerType > 0) {
|
||||
$this->walletBalanceService->absorbMismatchedOwnerTypeBalances($customerId, $ownerType);
|
||||
}
|
||||
|
||||
$catalogQuery = Product::query()->with('file');
|
||||
if (!$includeInactiveProducts) {
|
||||
$catalogQuery->where('active', 1);
|
||||
|
||||
@@ -7,6 +7,8 @@ use App\Models\Price;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Rooyesh\Wallet\interfaces\TransactionInterface;
|
||||
use Rooyesh\Wallet\interfaces\WalletInterface;
|
||||
use Rooyesh\Wallet\models\Wallet;
|
||||
|
||||
/**
|
||||
@@ -17,6 +19,11 @@ use Rooyesh\Wallet\models\Wallet;
|
||||
*/
|
||||
class WalletBalanceService
|
||||
{
|
||||
/** @var array<string, true> */
|
||||
private static array $absorbedOwnerTypes = [];
|
||||
|
||||
private static bool $absorbingOwnerType = false;
|
||||
|
||||
public function __construct(
|
||||
private ConfigService $configService,
|
||||
private BalanceReportService $balanceReportService
|
||||
@@ -161,6 +168,85 @@ class WalletBalanceService
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ماندهٔ کیفهایی که owner_typeشان با نوع فعلی مشتری یکی نیست
|
||||
* (مثلاً واریز وقتی type هنوز ۰ بوده) به کیف همان محصول/قلک روی نوع فعلی منتقل میشود.
|
||||
*/
|
||||
public function absorbMismatchedOwnerTypeBalances(int $ownerId, int $canonicalType): bool
|
||||
{
|
||||
if ($ownerId <= 0 || $canonicalType <= 0 || self::$absorbingOwnerType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = $ownerId.':'.$canonicalType;
|
||||
if (isset(self::$absorbedOwnerTypes[$key])) {
|
||||
return false;
|
||||
}
|
||||
self::$absorbedOwnerTypes[$key] = true;
|
||||
|
||||
$foreign = Wallet::query()
|
||||
->where('owner', $ownerId)
|
||||
->where('owner_type', '!=', $canonicalType)
|
||||
->where(function ($query) {
|
||||
$query->where('cash', '!=', 0)->orWhere('gold', '!=', 0);
|
||||
})
|
||||
->get();
|
||||
|
||||
if ($foreign->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$absorbingOwnerType = true;
|
||||
try {
|
||||
foreach ($foreign as $row) {
|
||||
DB::transaction(function () use ($row, $ownerId, $canonicalType) {
|
||||
$locked = Wallet::query()->whereKey($row->id)->lockForUpdate()->first();
|
||||
if (!$locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cash = (int) round((float) $locked->cash);
|
||||
$gold = (float) $locked->gold;
|
||||
if ($cash === 0 && abs($gold) < 0.0000001) {
|
||||
return;
|
||||
}
|
||||
|
||||
$from = new WalletInterface($ownerId, (int) $locked->owner_type, $locked->fund_id, $locked->product_id);
|
||||
$to = new WalletInterface($ownerId, $canonicalType, $locked->fund_id, $locked->product_id);
|
||||
$note = 'انتقال مانده به کیف اصلی مشتری';
|
||||
|
||||
if ($cash !== 0) {
|
||||
$payload = [
|
||||
'cash' => abs($cash),
|
||||
'gold' => 0,
|
||||
'note' => $note,
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
];
|
||||
new TransactionInterface($from, $payload, 7, false, $cash < 0);
|
||||
new TransactionInterface($to, $payload, 7, false, $cash > 0);
|
||||
}
|
||||
|
||||
if (abs($gold) >= 0.0000001) {
|
||||
$payload = [
|
||||
'gold' => abs($gold),
|
||||
'cash' => 0,
|
||||
'note' => $note,
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
];
|
||||
new TransactionInterface($from, $payload, 7, $gold < 0, false);
|
||||
new TransactionInterface($to, $payload, 7, $gold > 0, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
self::$absorbingOwnerType = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** ادغام همهٔ کیفهای legacy محصولات main_wallet_products برای یک کاربر */
|
||||
public function consolidateAllMainWalletProductsForOwner(int $ownerId, int $ownerType): void
|
||||
{
|
||||
|
||||
@@ -44,6 +44,22 @@ class WalletInterface
|
||||
]);
|
||||
$this->set_hash();
|
||||
}
|
||||
|
||||
$this->absorbMismatchedOwnerTypeBalances();
|
||||
}
|
||||
|
||||
/** واریزِ مانده روی owner_type قدیمی را به نوع فعلی مشتری برمیگرداند. */
|
||||
private function absorbMismatchedOwnerTypeBalances(): void
|
||||
{
|
||||
$ownerType = (int) $this->owner_type;
|
||||
$ownerId = (int) $this->owner_id;
|
||||
if ($ownerType <= 0 || $ownerId <= 0 || !$this->wallet) {
|
||||
return;
|
||||
}
|
||||
|
||||
app(\App\Services\WalletBalanceService::class)
|
||||
->absorbMismatchedOwnerTypeBalances($ownerId, $ownerType);
|
||||
$this->wallet->refresh();
|
||||
}
|
||||
|
||||
public function validate(): bool
|
||||
|
||||
Reference in New Issue
Block a user