fix bug of pargar
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Customer;
|
||||
use App\Services\PargarSyncService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Rooyesh\Wallet\models\Transaction;
|
||||
|
||||
/**
|
||||
* ساخت دوبارهٔ سند ریالی برای واریز/برداشتهایی که سندشان به پرگار نرسیده است.
|
||||
*
|
||||
* تا وقتی سند نرسد، ماندهٔ پرگار این پول را ندارد و تطبیق مانده موجودی کیف را صفر میکند.
|
||||
*/
|
||||
class PargarRequeueWalletDocumentsCommand extends Command
|
||||
{
|
||||
protected $signature = 'pargar:requeue-wallet-documents
|
||||
{--customer= : فقط همین مشتری}
|
||||
{--days=30 : چند روز اخیر بررسی شود}
|
||||
{--execute : ثبت واقعی سندها (بدون این فلگ فقط پیشنمایش است)}';
|
||||
|
||||
protected $description = 'صفکردن دوبارهٔ اسناد ریالی جاافتادهٔ پرگار (واریز/برداشت بدون سند)';
|
||||
|
||||
public function handle(PargarSyncService $sync): int
|
||||
{
|
||||
if (! $sync->isSyncEnabled()) {
|
||||
$this->error('همگامسازی پرگار فعال نیست.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$days = max(1, (int) $this->option('days'));
|
||||
$execute = (bool) $this->option('execute');
|
||||
$customerId = (int) $this->option('customer');
|
||||
|
||||
$query = Transaction::query()
|
||||
->whereIn('type', [3, 4])
|
||||
->whereNotNull('withdraw_id')
|
||||
->where('created_at', '>=', now()->subDays($days))
|
||||
->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);
|
||||
})
|
||||
->orderBy('id');
|
||||
|
||||
if ($customerId > 0) {
|
||||
$query->where('customer_id', $customerId);
|
||||
}
|
||||
|
||||
$rows = $query->get(['id', 'customer_id', 'withdraw_id', 'cash', 'note', 'created_at']);
|
||||
if ($rows->isEmpty()) {
|
||||
$this->info('سند جاافتادهای پیدا نشد.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$customers = Customer::whereIn('id', $rows->pluck('customer_id')->unique())->get()->keyBy('id');
|
||||
$table = [];
|
||||
$queued = 0;
|
||||
$skipped = 0;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$customer = $customers->get((int) $row->customer_id);
|
||||
$status = 'آماده';
|
||||
|
||||
if ($customer === null || ! $customer->hasValidPargarAccountId()) {
|
||||
$status = 'بدون کد پرگار — رد شد';
|
||||
$skipped++;
|
||||
} elseif ($execute) {
|
||||
$log = $sync->queueWalletDocument($customer, 'cash', (float) $row->cash, [
|
||||
'withdraw_id' => (int) $row->withdraw_id,
|
||||
'note' => $row->note,
|
||||
'source' => 'requeue_missing',
|
||||
]);
|
||||
$status = $log !== null ? "ثبت شد (لاگ {$log->id})" : 'ثبت نشد';
|
||||
$log !== null ? $queued++ : $skipped++;
|
||||
}
|
||||
|
||||
$table[] = [
|
||||
$row->id,
|
||||
$row->customer_id,
|
||||
$customer->name ?? '—',
|
||||
$row->withdraw_id,
|
||||
number_format((float) $row->cash),
|
||||
(string) $row->created_at,
|
||||
$status,
|
||||
];
|
||||
}
|
||||
|
||||
$this->table(
|
||||
['تراکنش', 'مشتری', 'نام', 'سند برداشت', 'مبلغ', 'تاریخ', 'وضعیت'],
|
||||
$table
|
||||
);
|
||||
|
||||
if (! $execute) {
|
||||
$this->warn('پیشنمایش بود. برای ثبت واقعی --execute بزنید.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->info("ثبتشده: {$queued} — ردشده: {$skipped}");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,21 @@ class GiftCardController extends Controller
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true
|
||||
], 3, false, true);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$user,
|
||||
'cash',
|
||||
(float) $giftcode->amount,
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'کارت هدیه',
|
||||
'source' => 'gift_card',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
//set text for sms to customer
|
||||
|
||||
@@ -666,6 +666,13 @@ class ProductController extends SuperController
|
||||
unset($data['inventory']);
|
||||
}
|
||||
|
||||
if (!Product::hasDescriptionColumn()) {
|
||||
unset($data['description']);
|
||||
} elseif (array_key_exists('description', $data)) {
|
||||
$desc = is_string($data['description']) ? trim($data['description']) : '';
|
||||
$data['description'] = $desc === '' ? null : $desc;
|
||||
}
|
||||
|
||||
if (!Product::hasOverrideTradingHoursColumn()) {
|
||||
unset($data['override_trading_hours']);
|
||||
} elseif (array_key_exists('override_trading_hours', $data)) {
|
||||
|
||||
@@ -33,6 +33,40 @@ use Hekmatinasser\Verta\Verta;
|
||||
|
||||
class WalletController extends Controller
|
||||
{
|
||||
/** موجودی طلا با سه رقم اعشار نمایش داده میشود؛ نصف پلهٔ نمایش = بیشترین اختلاف ممکن با مقدار واقعی */
|
||||
private const GOLD_DISPLAY_STEP = 0.0005;
|
||||
|
||||
/** پنجرهٔ تشخیص سند تکراری — دوبار کلیک یا ارسال مجدد فرم */
|
||||
private const DUPLICATE_CHARGE_WINDOW_SECONDS = 60;
|
||||
|
||||
/**
|
||||
* جلوگیری از ثبت دوبارهٔ همان سند دستی. فقط روی کسر اعمال میشود تا شارژهای
|
||||
* مثبتِ پشتسرهم (مثلاً دو واریز یکسان) بسته نشوند.
|
||||
*/
|
||||
private function assertNotDuplicateCharge(int $customerId, float $value, string $column): void
|
||||
{
|
||||
if ($value >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$recent = Withdraw::query()
|
||||
->where('customer_id', $customerId)
|
||||
->where('sts', 4)
|
||||
->where('created_at', '>=', now()->subSeconds(self::DUPLICATE_CHARGE_WINDOW_SECONDS));
|
||||
|
||||
if ($column === 'cash') {
|
||||
$recent->where('cash', (int) $value);
|
||||
} else {
|
||||
$recent->whereBetween('gold', [$value - 1e-6, $value + 1e-6]);
|
||||
}
|
||||
|
||||
if ($recent->exists()) {
|
||||
throw new UnprocessableEntityHttpException(
|
||||
'همین سند لحظاتی پیش برای این مشتری ثبت شده است. اگر تکرارش عمدی است یک دقیقه صبر کنید.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function charge2(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
@@ -121,6 +155,7 @@ class WalletController extends Controller
|
||||
if (!is_null($wallet) && $wallet->cash < abs($data['value']) && !$deposit) {
|
||||
throw new UnprocessableEntityHttpException('مقدار موجودی کمتر از درخواست شماست');
|
||||
}
|
||||
$this->assertNotDuplicateCharge((int) $customer->id, (float) $data['value'], 'cash');
|
||||
$orders = Order::where('customer_id', $data['customer_id'])->where('sts', 1)->get();
|
||||
$gold_block = 0;
|
||||
|
||||
@@ -213,12 +248,20 @@ class WalletController extends Controller
|
||||
}
|
||||
$wallet_interface = new WalletInterface($data['customer_id'], (int) $customer->type);
|
||||
$wallet = $wallet_interface->wallet;
|
||||
// if (is_null($wallet) && !$deposit) {
|
||||
// throw new UnprocessableEntityHttpException('مقدار موجودی کمتر از درخواست شماست');
|
||||
// }
|
||||
// if (!is_null($wallet) && $wallet->cash < abs($data['value']) && !$deposit) {
|
||||
// throw new UnprocessableEntityHttpException('مقدار موجودی کمتر از درخواست شماست');
|
||||
// }
|
||||
// کسر دستی نباید موجودی طلا را منفی کند؛ شارژ مثبت بدون هیچ شرطی باز است
|
||||
if (!$deposit) {
|
||||
$available = is_null($wallet) ? 0.0 : (float) $wallet->gold;
|
||||
$requested = abs((float) $data['value']);
|
||||
// ادمین عدد را از نمایش سهرقمی میخواند؛ اختلاف تا نصف پلهٔ نمایش یعنی «کل موجودی»
|
||||
if ($requested > $available && $requested - $available <= self::GOLD_DISPLAY_STEP) {
|
||||
$requested = $available;
|
||||
$data['value'] = -$available;
|
||||
}
|
||||
if ($requested <= 0 || $requested > $available) {
|
||||
throw new UnprocessableEntityHttpException('مقدار موجودی طلا کمتر از درخواست شماست');
|
||||
}
|
||||
}
|
||||
$this->assertNotDuplicateCharge((int) $customer->id, (float) $data['value'], 'gold');
|
||||
$gold_block = 0;
|
||||
$user = auth()->user();
|
||||
$customer = Customer::findOrFail($data["customer_id"]);
|
||||
@@ -386,6 +429,7 @@ class WalletController extends Controller
|
||||
if (!$deposit && $wallet !== null && (float) $wallet->gold < abs((float) $data['value'])) {
|
||||
throw new UnprocessableEntityHttpException('مقدار موجودی کمتر از درخواست شماست');
|
||||
}
|
||||
$this->assertNotDuplicateCharge((int) $customer->id, (float) $data['value'], 'gold');
|
||||
|
||||
$goldBlock = 0;
|
||||
$user = auth()->user();
|
||||
|
||||
@@ -391,6 +391,22 @@ class WalletController extends Controller
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true
|
||||
], 4, false, false);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'cash',
|
||||
-1 * (float) $data['value'],
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'برداشت ریالی',
|
||||
'source' => 'customer_withdraw',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$userMobile = $customer->mobile; // User's mobile number
|
||||
$userName = $customer->name; // User's name
|
||||
$withdrawAmount = $data['value']; // amount
|
||||
|
||||
@@ -195,6 +195,21 @@ class FinanceController extends Controller
|
||||
'active' => true
|
||||
], 3, false, true);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$User,
|
||||
'cash',
|
||||
(float) ($decodedResponse['data']['amount'] * 10),
|
||||
[
|
||||
'withdraw_id' => (int) $_GET['clientrefid'],
|
||||
'note' => 'واریز درگاه',
|
||||
'source' => 'gateway',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
//----------sms
|
||||
// User information
|
||||
$userMobile = $Withdraw->customer->mobile; // User's mobile number
|
||||
|
||||
@@ -1589,6 +1589,22 @@ class SingleOrderController extends Controller
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true,
|
||||
], 3, true, true, 0);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'cash',
|
||||
(float) $customer_bonus,
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'پاداش اولین سفارش',
|
||||
'source' => 'bonus_first_order',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$message = 'کیف پول شما به اندازه ' . number_format($customer_bonus) . ' ریال در تاریخ ' . verta()->format('Y/n/j H:i:s') . " شارژ شد بابت\n"
|
||||
. 'پاداش اولین سفارش'
|
||||
. ' '
|
||||
@@ -1626,6 +1642,22 @@ class SingleOrderController extends Controller
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true,
|
||||
], 3, true, true, 0);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$referrer,
|
||||
'cash',
|
||||
(float) $referrer_bonus,
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'پاداش اولین سفارش زیرمجموعه',
|
||||
'source' => 'bonus_referrer',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$message = 'کیف پول شما به اندازه ' . number_format($referrer_bonus) . ' ریال در تاریخ ' . verta()->format('Y/n/j H:i:s') . " شارژ شد بابت\n"
|
||||
. 'بابت پاداش اولین سفارش زیرمجموعه'
|
||||
. ' '
|
||||
|
||||
@@ -27,6 +27,7 @@ class Product extends Model
|
||||
private static ?bool $overrideTradingHoursColumnExists = null;
|
||||
private static ?bool $cashFeePercentModeColumnsExist = null;
|
||||
private static ?bool $physicalDeliveryColumnsExist = null;
|
||||
private static ?bool $descriptionColumnExists = null;
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
@@ -59,6 +60,9 @@ class Product extends Model
|
||||
if (!static::hasInventoryColumn()) {
|
||||
unset($product->attributes['inventory']);
|
||||
}
|
||||
if (!static::hasDescriptionColumn()) {
|
||||
unset($product->attributes['description']);
|
||||
}
|
||||
if (!static::hasOverrideTradingHoursColumn()) {
|
||||
unset($product->attributes['override_trading_hours']);
|
||||
}
|
||||
@@ -293,6 +297,24 @@ class Product extends Model
|
||||
return static::$inventoryColumnExists;
|
||||
}
|
||||
|
||||
public static function hasDescriptionColumn(): bool
|
||||
{
|
||||
if (static::$descriptionColumnExists !== null) {
|
||||
return static::$descriptionColumnExists;
|
||||
}
|
||||
|
||||
try {
|
||||
static::$descriptionColumnExists = Schema::hasColumn(
|
||||
(new static)->getTable(),
|
||||
'description'
|
||||
);
|
||||
} catch (\Throwable) {
|
||||
static::$descriptionColumnExists = false;
|
||||
}
|
||||
|
||||
return static::$descriptionColumnExists;
|
||||
}
|
||||
|
||||
public function orderLimitsEnabled(): bool
|
||||
{
|
||||
if (!static::hasOrderLimitColumns() || !($this->order_limit_enabled ?? false)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ماندهٔ صفرِ هر دو فیلد برای مشتریای که کیفش خالی نیست، تقریباً همیشه یعنی
|
||||
* پرگار حساب را پیدا نکرده — نه اینکه مشتری تسویه کرده باشد.
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\PargarSyncLog;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
@@ -199,7 +200,7 @@ class PargarSyncService
|
||||
$desc = $isDeposit ? 'شارژ طلای کیف اصلی — ارسال به پرگار' : 'برداشت طلای کیف اصلی — ارسال به پرگار';
|
||||
}
|
||||
|
||||
return PargarSyncLog::create([
|
||||
$attributes = [
|
||||
'customer_id' => $customer->id,
|
||||
'amount' => abs($signedAmount),
|
||||
'desc' => $desc,
|
||||
@@ -215,7 +216,20 @@ class PargarSyncService
|
||||
'product_id' => $meta['product_id'] ?? null,
|
||||
'source' => $meta['source'] ?? null,
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
];
|
||||
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* سوییچ نمایش جزئیات/توضیح محصول در اپ مشتری + اطمینان از وجود ستون description روی products.
|
||||
* idempotent — value تنظیم موجود دست نخورده میماند.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (Schema::hasTable('products') && ! Schema::hasColumn('products', 'description')) {
|
||||
Schema::table('products', function ($table) {
|
||||
$table->text('description')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('settings')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! DB::table('settings')->where('key', 'show_product_details')->exists()) {
|
||||
DB::table('settings')->insert([
|
||||
'key' => 'show_product_details',
|
||||
'value' => 'true',
|
||||
'title_fa' => 'نمایش جزئیات اطلاعات محصول',
|
||||
'type' => 'switch',
|
||||
'can_edit' => 1,
|
||||
'is_active' => 1,
|
||||
'description' => 'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (Schema::hasTable('settings')) {
|
||||
DB::table('settings')->where('key', 'show_product_details')->delete();
|
||||
}
|
||||
// ستون description را حذف نمیکنیم — ممکن است داده داشته باشد
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* ستون amount با float() ساخته شده بود و لاراول ۸ آن را DOUBLE(8,2) میسازد؛
|
||||
* سقفش ۹۹۹٬۹۹۹٫۹۹ است. هر سند ریالی بزرگتر از یک میلیون در insert خطا میداد و
|
||||
* چون فراخوانیها داخل try/catch بودند، سند بیصدا گم میشد و پرگار واریز را نمیدید.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('pargar_sync_logs') || ! Schema::hasColumn('pargar_sync_logs', 'amount')) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::statement('ALTER TABLE `pargar_sync_logs` MODIFY `amount` DOUBLE NULL');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// برگرداندن به DOUBLE(8,2) داده را خراب میکند؛ عمداً بدون عملیات.
|
||||
}
|
||||
};
|
||||
@@ -221,6 +221,12 @@ SELECT 'show_home_price_when_closed', 'false', 'نمایش قیمت صفحه ا
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'show_home_price_when_closed' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'show_product_details', 'true', 'نمایش جزئیات اطلاعات محصول', 1, 1,
|
||||
'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.',
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'show_product_details' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||
SELECT 'main_product_price', 'false', 'قیمت از محصول (legacy)', 1, 1, 'از price_provider استفاده کنید'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'main_product_price' LIMIT 1);
|
||||
@@ -955,7 +961,7 @@ UPDATE `settings` SET `type` = 'select', `description` = 'bale,telegram,whatsapp
|
||||
UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
|
||||
'chart_use_local_data',
|
||||
'jibit_enabled', 'jibit_verification', 'register_jibit_verify', 'open_register', 'auto_active_customer',
|
||||
'close_price', 'show_last_price', 'show_gold_ounce_price', 'show_home_price_when_closed',
|
||||
'close_price', 'show_last_price', 'show_gold_ounce_price', 'show_home_price_when_closed', 'show_product_details',
|
||||
'fee_deduct_from_gold',
|
||||
'require_zero_main_gold_before_other_buy',
|
||||
'profit_gold_api_enabled', 'payping_round_toman', 'payping_strict_failed_withdraw',
|
||||
@@ -1298,6 +1304,7 @@ UPDATE `settings` SET `description` = 'کلید یا UUID ردیف قیمت در
|
||||
UPDATE `settings` SET `description` = 'روشن: اگر API قیمت در دسترس نباشد، آخرین قیمت ذخیرهشده در دیتابیس به کاربر نشان داده میشود. خاموش: در قطعی API ممکن است قیمت صفر نمایش داده شود.' WHERE `key` = 'show_last_price';
|
||||
UPDATE `settings` SET `description` = 'روشن: اگر آدرس API تابلو (zaarbox_api_url) تنظیم شده باشد، قیمت انس طلا در اپ مشتری نمایش داده میشود. خاموش: نمایش داده نمیشود.' WHERE `key` = 'show_gold_ounce_price';
|
||||
UPDATE `settings` SET `description` = 'روشن: وقتی فروشگاه خارج از ساعت کاری است، قیمت صفحه اصلی اپ همچنان نمایش داده میشود و پیام «فروشگاه بسته است» نشان داده نمیشود. خرید/فروش همچنان بسته میماند. خاموش: مثل قبل، خارج از ساعت پیام بسته بودن و قیمت صفر نشان داده میشود.' WHERE `key` = 'show_home_price_when_closed';
|
||||
UPDATE `settings` SET `description` = 'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.' WHERE `key` = 'show_product_details';
|
||||
UPDATE `settings` SET `description` = 'روشن: خارج از بازه «ساعت شروع» تا «ساعت پایان» معامله و نمایش قیمت بسته میشود. خاموش: محدودیت ساعتی سراسری اعمال نمیشود.' WHERE `key` = 'close_price';
|
||||
UPDATE `settings` SET `description` = 'ساعت شروع فعالیت روزانه. فقط وقتی «بستن خودکار خارج از ساعت کاری» روشن باشد اعمال میشود (مثلاً ۰۹:۰۰).' WHERE `key` = 'startDay';
|
||||
UPDATE `settings` SET `description` = 'ساعت پایان فعالیت روزانه. فقط وقتی «بستن خودکار خارج از ساعت کاری» روشن باشد اعمال میشود (مثلاً ۲۲:۰۰).' WHERE `key` = 'endDay';
|
||||
@@ -1602,6 +1609,7 @@ UPDATE `settings` SET `title_fa` = 'کارمزد درصدی (alias)' WHERE `key`
|
||||
UPDATE `settings` SET `title_fa` = 'نمایش آخرین قیمت ذخیرهشده' WHERE `key` = 'show_last_price';
|
||||
UPDATE `settings` SET `title_fa` = 'نمایش قیمت انس طلا' WHERE `key` = 'show_gold_ounce_price';
|
||||
UPDATE `settings` SET `title_fa` = 'نمایش قیمت صفحه اصلی خارج از ساعت کاری' WHERE `key` = 'show_home_price_when_closed';
|
||||
UPDATE `settings` SET `title_fa` = 'نمایش جزئیات اطلاعات محصول' WHERE `key` = 'show_product_details';
|
||||
UPDATE `settings` SET `title_fa` = 'مسیر SSE قیمت' WHERE `key` = 'sse_path';
|
||||
UPDATE `settings` SET `title_fa` = 'ساعت شروع' WHERE `key` = 'startDay';
|
||||
UPDATE `settings` SET `title_fa` = 'وضعیت فروشگاه' WHERE `key` = 'store_status';
|
||||
@@ -1703,7 +1711,7 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN (
|
||||
'open_register',
|
||||
'referral_id', 'referral_limit', 'referral_gift_on_first_order',
|
||||
'register_jibit_verify', 'register_referral_bonus_message', 'register_referral_sms_to_referrer',
|
||||
'sell_fee', 'show_last_price', 'show_home_price_when_closed', 'show_gold_ounce_price', 'startDay',
|
||||
'sell_fee', 'show_last_price', 'show_home_price_when_closed', 'show_gold_ounce_price', 'show_product_details', 'startDay',
|
||||
'support_messenger', 'support_messenger_id', 'support_messenger_text',
|
||||
'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_sheba',
|
||||
'text_about', 'text_rule',
|
||||
|
||||
@@ -171,6 +171,12 @@ SELECT 'show_home_price_when_closed', 'false', 'نمایش قیمت صفحه ا
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'show_home_price_when_closed' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'show_product_details', 'true', 'نمایش جزئیات اطلاعات محصول', 1, 1,
|
||||
'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.',
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'show_product_details' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||
SELECT 'main_product_price', 'false', 'قیمت از محصول (legacy)', 1, 1, 'از price_provider استفاده کنید'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'main_product_price' LIMIT 1);
|
||||
@@ -826,7 +832,7 @@ UPDATE `settings` SET `type` = 'select', `description` = 'bale,telegram,whatsapp
|
||||
UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
|
||||
'chart_use_local_data',
|
||||
'jibit_enabled', 'jibit_verification', 'register_jibit_verify', 'open_register', 'auto_active_customer',
|
||||
'close_price', 'show_last_price', 'show_home_price_when_closed',
|
||||
'close_price', 'show_last_price', 'show_home_price_when_closed', 'show_product_details',
|
||||
'fee_deduct_from_gold',
|
||||
'send_to_tahesab', 'profit_gold_api_enabled', 'payping_round_toman', 'payping_strict_failed_withdraw',
|
||||
'has_page_earn_money', 'has_page_price_trigger', 'has_page_notification', 'charge_notif', 'group_sms', 'sms_panel', 'customer_direct_sms',
|
||||
@@ -1185,6 +1191,7 @@ UPDATE `settings` SET `description` = 'آدرس پایه API سرویس تابل
|
||||
UPDATE `settings` SET `description` = 'کلید یا UUID ردیف قیمت در پاسخ API تابلو. باید با محصول/ردیف موردنظر در سرویس خارجی یکسان باشد.' WHERE `key` = 'zaarbox_price_key';
|
||||
UPDATE `settings` SET `description` = 'روشن: اگر API قیمت در دسترس نباشد، آخرین قیمت ذخیرهشده در دیتابیس به کاربر نشان داده میشود. خاموش: در قطعی API ممکن است قیمت صفر نمایش داده شود.' WHERE `key` = 'show_last_price';
|
||||
UPDATE `settings` SET `description` = 'روشن: وقتی فروشگاه خارج از ساعت کاری است، قیمت صفحه اصلی اپ همچنان نمایش داده میشود و پیام «فروشگاه بسته است» نشان داده نمیشود. خرید/فروش همچنان بسته میماند. خاموش: مثل قبل، خارج از ساعت پیام بسته بودن و قیمت صفر نشان داده میشود.' WHERE `key` = 'show_home_price_when_closed';
|
||||
UPDATE `settings` SET `description` = 'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.' WHERE `key` = 'show_product_details';
|
||||
UPDATE `settings` SET `description` = 'روشن: خارج از بازه «ساعت شروع» تا «ساعت پایان» معامله و نمایش قیمت بسته میشود. خاموش: محدودیت ساعتی سراسری اعمال نمیشود.' WHERE `key` = 'close_price';
|
||||
UPDATE `settings` SET `description` = 'ساعت شروع فعالیت روزانه. فقط وقتی «بستن خودکار خارج از ساعت کاری» روشن باشد اعمال میشود (مثلاً ۰۹:۰۰).' WHERE `key` = 'startDay';
|
||||
UPDATE `settings` SET `description` = 'ساعت پایان فعالیت روزانه. فقط وقتی «بستن خودکار خارج از ساعت کاری» روشن باشد اعمال میشود (مثلاً ۲۲:۰۰).' WHERE `key` = 'endDay';
|
||||
@@ -1407,7 +1414,7 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN (
|
||||
'open_register',
|
||||
'referral_id', 'referral_limit', 'referral_gift_on_first_order',
|
||||
'register_jibit_verify', 'register_referral_bonus_message', 'register_referral_sms_to_referrer',
|
||||
'sell_fee', 'show_last_price', 'show_home_price_when_closed', 'startDay',
|
||||
'sell_fee', 'show_last_price', 'show_home_price_when_closed', 'show_product_details', 'startDay',
|
||||
'support_messenger', 'support_messenger_id', 'support_messenger_text',
|
||||
'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_sheba',
|
||||
'text_about', 'text_rule',
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
-- رفع باگ گمشدن اسناد ریالی پرگار
|
||||
-- ستون pargar_sync_logs.amount با float() ساخته شده بود = DOUBLE(8,2) با سقف ۹۹۹٬۹۹۹٫۹۹
|
||||
-- هر سند واریز/برداشت ریالی بزرگتر از این سقف در insert خطا میداد و سند اصلاً ساخته نمیشد،
|
||||
-- پس پرگار واریز مشتری را نمیدید و در تطبیق مانده، موجودی ریالی کیف صفر میشد.
|
||||
-- idempotent: چند بار قابل اجرا
|
||||
|
||||
SET @db = DATABASE();
|
||||
|
||||
SET @sql = IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'pargar_sync_logs'
|
||||
AND COLUMN_NAME = 'amount' AND UPPER(COLUMN_TYPE) <> 'DOUBLE') = 1,
|
||||
'ALTER TABLE `pargar_sync_logs` MODIFY `amount` DOUBLE NULL',
|
||||
'SELECT ''skip pargar_sync_logs.amount'' AS info'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'pargar_sync_logs' AND COLUMN_NAME = 'amount';
|
||||
@@ -0,0 +1,35 @@
|
||||
-- سوییچ «نمایش جزئیات اطلاعات محصول» + ستون توضیح محصولات
|
||||
-- idempotent: چند بار قابل اجرا
|
||||
-- • اولین بار: INSERT با value='true' (پیشفرض روشن)
|
||||
-- • اجرای مجدد: value و is_active دست نمیخورند — title_fa / description / type / can_edit همیشه override میشوند
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
SET @db = DATABASE();
|
||||
|
||||
SET @sql = IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'products' AND COLUMN_NAME = 'description') = 0,
|
||||
'ALTER TABLE `products` ADD COLUMN `description` TEXT NULL',
|
||||
'SELECT ''skip products.description'' AS info'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'show_product_details', 'true', 'نمایش جزئیات اطلاعات محصول', 1, 1,
|
||||
'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.',
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'show_product_details' LIMIT 1);
|
||||
|
||||
UPDATE `settings`
|
||||
SET `title_fa` = 'نمایش جزئیات اطلاعات محصول',
|
||||
`description` = 'روشن: بعد از انتخاب محصول در صفحه خرید/فروش، متن توضیح محصول نمایش داده میشود. خاموش: توضیح نشان داده نمیشود.',
|
||||
`type` = 'switch',
|
||||
`can_edit` = 1
|
||||
WHERE `key` = 'show_product_details';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT `key`, `title_fa`, LEFT(`description`, 60) AS desc_preview, `can_edit`, `type`, `value`
|
||||
FROM `settings`
|
||||
WHERE `key` = 'show_product_details';
|
||||
@@ -18,10 +18,10 @@ class TransactionInterface
|
||||
private $wallet_interface;
|
||||
private $transaction;
|
||||
|
||||
function __construct($wallet_interface = null, $_inp = null, $_type = null,$deposit_gold = false,$deposit_cash=false, $gold_block = 0,$meta = [])
|
||||
function __construct($wallet_interface = null, $_inp = null, $_type = null,$deposit_gold = false,$deposit_cash=false, $gold_block = 0,$meta = [], $allow_negative = false)
|
||||
|
||||
{
|
||||
$this->transaction = TransactionInterface::apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold ,$deposit_cash,$gold_block,$meta);
|
||||
$this->transaction = TransactionInterface::apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold ,$deposit_cash,$gold_block,$meta,$allow_negative);
|
||||
}
|
||||
|
||||
static function validate_last_transaction($wallet_id)
|
||||
@@ -53,20 +53,53 @@ class TransactionInterface
|
||||
$transaction->save();
|
||||
}
|
||||
|
||||
public static function apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold,$deposit_cash,$gold_block, $meta = [])
|
||||
/**
|
||||
* کف موجودی طلا — فقط سمت کسر. شارژ مثبت هیچوقت بسته نمیشود، حتی اگر مانده منفی باشد.
|
||||
* ستون gold از نوع float است، پس رواداری نسبی میگذاریم تا «فروش کل موجودی» به خطای گرد کردن نخورد.
|
||||
*/
|
||||
private static function assert_gold_floor($wallet, $_inp, $deposit_gold)
|
||||
{
|
||||
if ($deposit_gold || !isset($_inp['gold'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requested = abs((float) $_inp['gold']);
|
||||
if ($requested <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$balance = (float) $wallet->gold;
|
||||
$tolerance = 1e-6 + abs($balance) * 1e-6;
|
||||
if ($balance + $tolerance < $requested) {
|
||||
throw new UnprocessableEntityHttpException('مقدار وارد شده بیشتر از موجودی طلای شماست');
|
||||
}
|
||||
}
|
||||
|
||||
/** کف موجودی ریالی — فقط سمت کسر؛ واریز و شارژ مثبت همیشه باز است. */
|
||||
private static function assert_cash_floor($wallet, $_inp, $deposit_cash)
|
||||
{
|
||||
if ($deposit_cash || !isset($_inp['cash'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requested = abs((float) $_inp['cash']);
|
||||
if ($requested > 0 && (float) $wallet->cash < $requested) {
|
||||
throw new UnprocessableEntityHttpException('موجودی ریالی کافی نیست');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allow_negative فقط برای تطبیق مانده با سیستم حسابداری؛ آنجا مانده میتواند
|
||||
* واقعاً منفی باشد و کیف باید همان را بازتاب دهد.
|
||||
*/
|
||||
public static function apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold,$deposit_cash,$gold_block, $meta = [], $allow_negative = false)
|
||||
{
|
||||
$wallet = $wallet_interface->wallet;
|
||||
TransactionInterface::validate_last_transaction($wallet->id);
|
||||
#-------------Check Balance --------
|
||||
if (!$deposit_gold) {
|
||||
// if ($_type === 1 && $wallet->cash < $_inp['value']) {
|
||||
// throw new Exceptions\NotEnoughCashBalance();
|
||||
//
|
||||
// }
|
||||
if ($_type === 2 && $wallet->gold < $_inp['gold']) {
|
||||
throw new UnprocessableEntityHttpException('مقدار وارد شده کمتر از موجودی شماست');
|
||||
|
||||
}
|
||||
if (!$allow_negative) {
|
||||
TransactionInterface::assert_gold_floor($wallet, $_inp, $deposit_gold);
|
||||
TransactionInterface::assert_cash_floor($wallet, $_inp, $deposit_cash);
|
||||
}
|
||||
// $_inp['value'] = abs($_inp['value']) * ($deposit ? 1 : -1);
|
||||
if (isset($_inp['gold'])){
|
||||
|
||||
Reference in New Issue
Block a user