feat: landing settings, instant withdraw deduct, and OTP site URL
Add has_landing plus landing_* deploy keys, deduct balance on withdraw request, keep app_url for SMS login links, and clarify Zarin rial wallet document titles. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -235,7 +235,7 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* تنظیمات پیشرفته: ۱۵ دسترسی از سوپرادمین + بقیهٔ can_edit=0 از DB لوکال.
|
||||
* تنظیمات پیشرفته: ۱۶ دسترسی از سوپرادمین + بقیهٔ can_edit=0 از DB لوکال.
|
||||
*/
|
||||
private function composeSystemSettings($localRows)
|
||||
{
|
||||
@@ -319,7 +319,7 @@ class SettingsController extends Controller
|
||||
/**
|
||||
* get_settings ادمین (و پایهٔ publicIndex قبل از فیلتر show_to_user):
|
||||
* can_edit=1 (+ runtime + local-owned) از DB لوکال
|
||||
* فقط ۱۵ دسترسی سوپرادمین از overlay؛ بقیهٔ can_edit=0 از کپی لوکال
|
||||
* فقط ۱۶ دسترسی سوپرادمین از overlay؛ بقیهٔ can_edit=0 از کپی لوکال
|
||||
* اگر سوپرادمین در دسترس نباشد کل جدول لوکال برمیگردد.
|
||||
*/
|
||||
private function composeGetSettings($localRows)
|
||||
|
||||
@@ -275,6 +275,9 @@ class WalletController extends Controller
|
||||
try {
|
||||
$data['direction'] = $deposit ? 0 : 1;
|
||||
$data['withdraw_id'] = $Withdraw->id;
|
||||
if (!$deposit && trim((string) ($data['note'] ?? '')) === '') {
|
||||
$data['note'] = 'برداشت وجه';
|
||||
}
|
||||
app(\App\Http\Controllers\Admin\ZarinController::class)->wallet($data);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
@@ -1446,6 +1449,10 @@ class WalletController extends Controller
|
||||
|
||||
$withdraw = Withdraw::findOrFail($request->id);
|
||||
$withdraw->update($data);
|
||||
|
||||
if ($withdraw->customer) {
|
||||
$this->broadcastCustomerWalletAssets($withdraw->customer);
|
||||
}
|
||||
// $tahesab = new TahesabController();
|
||||
// $tahesab->wallet([
|
||||
// 'customer_id' => $withdraw->customer_id,
|
||||
|
||||
@@ -1861,12 +1861,21 @@ class ZarinController extends Controller
|
||||
: ['korf' => 'k', 'parDar' => 1];
|
||||
}
|
||||
|
||||
/** شرح سند ریالی زرین — همیشه با واریز/برداشت شروع شود تا «خرید فی» دیده نشود */
|
||||
/**
|
||||
* شرح سند ریالی زرین — همیشه «واریز وجه» یا «برداشت وجه».
|
||||
* دشارژ ادمین و برداشت مشتری هر دو → «برداشت وجه» (پیشوند «واریز اینترنتی به» را زرین خودش میگذارد).
|
||||
*/
|
||||
private function zarinRialWalletSharh(bool $isDeposit, ?string $note): string
|
||||
{
|
||||
$base = $isDeposit ? 'واریز' : 'برداشت';
|
||||
$base = $isDeposit ? 'واریز وجه' : 'برداشت وجه';
|
||||
$normalized = self::accountingWalletDesc($isDeposit, $note);
|
||||
if ($normalized === '' || $normalized === $base) {
|
||||
$generic = [
|
||||
'', 'واریز', 'برداشت', 'واریز وجه', 'برداشت وجه',
|
||||
'واریز ریالی', 'برداشت ریالی',
|
||||
'شارژ', 'دشارژ', 'شارژ حساب', 'کسر',
|
||||
'واریز به کیف پول', 'برداشت از کیف پول', 'برداشت از حساب',
|
||||
];
|
||||
if (in_array($normalized, $generic, true) || in_array(trim((string) $note), $generic, true)) {
|
||||
return $base;
|
||||
}
|
||||
if (str_starts_with($normalized, $base)) {
|
||||
@@ -2029,7 +2038,7 @@ class ZarinController extends Controller
|
||||
$data = array_merge($data, [
|
||||
'customer_id' => $existing->customer_id,
|
||||
'value' => $existing->amount,
|
||||
'direction' => str_contains((string) $existing->desc, 'برداشت') ? 1 : 0,
|
||||
'direction' => $this->sync()->rialWalletDirectionFromDesc((string) $existing->desc),
|
||||
'withdraw_id' => $existing->withdraw_id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -227,13 +227,13 @@ class Controller extends BaseController
|
||||
return app(ConfigService::class)->Config($name);
|
||||
}
|
||||
|
||||
/** دامنهٔ عمومی سایت — فقط از درخواست HTTP فعلی */
|
||||
/** دامنهٔ عمومی سایت — settings.app_url؛ نه هاست API */
|
||||
protected static function publicHost(?\Illuminate\Http\Request $request = null): string
|
||||
{
|
||||
return app(ConfigService::class)->resolvePublicHost($request);
|
||||
}
|
||||
|
||||
/** آدرس کامل وباپ کاربر — مثلاً https://example.ir */
|
||||
/** آدرس کامل وباپ کاربر از settings.app_url — مثلاً https://example.ir */
|
||||
protected static function publicSiteUrl(?\Illuminate\Http\Request $request = null): string
|
||||
{
|
||||
return app(ConfigService::class)->resolvePublicSiteUrl($request);
|
||||
|
||||
@@ -17,8 +17,11 @@ use App\Http\Controllers\Admin\TahesabController;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\AssetSummaryService;
|
||||
use App\Services\WalletBalanceService;
|
||||
use App\Services\WalletBroadcastService;
|
||||
use App\Services\ZaarboxPriceService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
use Rooyesh\Wallet\interfaces\TransactionInterface;
|
||||
@@ -372,43 +375,72 @@ class WalletController extends Controller
|
||||
return response()->json(['message' => 'لطفا کارت بانکی را وارد کنید'], 422);
|
||||
}
|
||||
$bCart = BankAccount::where('id', $data['card_id'])->first();
|
||||
if ($bCart->sts != 2) {
|
||||
if (!$bCart || $bCart->sts != 2) {
|
||||
return response()->json(['message' => 'کارت انتخاب شده نا معتبر است'], 422);
|
||||
}
|
||||
|
||||
$wallet_interface_fund = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type);
|
||||
if ($data['value'] < 0) {
|
||||
|
||||
$amount = (int) ($data['value'] ?? 0);
|
||||
if ($amount <= 0) {
|
||||
throw new UnprocessableEntityHttpException('مقدار برداشت باید مثبت باشد');
|
||||
}
|
||||
|
||||
$this->validateWithdrawAmount((int) $data['value']);
|
||||
|
||||
$extraNote = trim((string) ($data['extra_note'] ?? ''));
|
||||
if (strlen($extraNote) > 500) {
|
||||
return response()->json(['message' => 'توضیحات اضافی حداکثر ۵۰۰ کاراکتر است'], 422);
|
||||
}
|
||||
|
||||
$Withdraw = Withdraw::create([
|
||||
'customer_id' => auth('customer')->id(),
|
||||
"cash" => $data['value'],
|
||||
"note" => "برداشت ریالی",
|
||||
'extra_note' => $extraNote !== '' ? $extraNote : null,
|
||||
"bank_account_id" => $data['card_id'],
|
||||
'sts' => 1,
|
||||
'type' => 2
|
||||
]);
|
||||
$transaction = new TransactionInterface($wallet_interface_fund, $_inp = [
|
||||
"cash" => $data['value'],
|
||||
'expire_at' => now(),
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true
|
||||
], 4, false, false);
|
||||
$otp = (string) ($request->otp ?? '');
|
||||
if ($otp === '' || (string) ($customer->token_sms ?? '') !== $otp) {
|
||||
return response()->json(['message' => 'رمز دوم اشتباه میباشد'], 422);
|
||||
}
|
||||
|
||||
$lock = Cache::lock('customer-rial-withdraw:'.$customer->id, 20);
|
||||
if (!$lock->get()) {
|
||||
return response()->json(['message' => 'درخواست برداشت در حال انجام است'], 429);
|
||||
}
|
||||
|
||||
try {
|
||||
$customer->refresh();
|
||||
if ((string) ($customer->token_sms ?? '') !== $otp) {
|
||||
return response()->json(['message' => 'رمز دوم اشتباه میباشد'], 422);
|
||||
}
|
||||
|
||||
$this->validateWithdrawAmount($amount);
|
||||
|
||||
$Withdraw = DB::transaction(function () use ($customer, $data, $amount, $extraNote) {
|
||||
$withdraw = Withdraw::create([
|
||||
'customer_id' => $customer->id,
|
||||
'cash' => $amount,
|
||||
'note' => 'برداشت ریالی',
|
||||
'extra_note' => $extraNote !== '' ? $extraNote : null,
|
||||
'bank_account_id' => $data['card_id'],
|
||||
'sts' => 1,
|
||||
'type' => 2,
|
||||
]);
|
||||
$this->debitCustomerRialWithdrawOnce($withdraw, $amount, $customer);
|
||||
$customer->token_sms = null;
|
||||
$customer->save();
|
||||
|
||||
return $withdraw;
|
||||
});
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
|
||||
try {
|
||||
app(WalletBroadcastService::class)->broadcastForCustomer(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'cash',
|
||||
-1 * (float) $data['value'],
|
||||
-1 * (float) $amount,
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'برداشت ریالی',
|
||||
@@ -421,18 +453,18 @@ class WalletController extends Controller
|
||||
|
||||
$userMobile = $customer->mobile; // User's mobile number
|
||||
$userName = $customer->name; // User's name
|
||||
$withdrawAmount = $data['value']; // amount
|
||||
$withdrawAmount = $amount; // amount
|
||||
if (app(ConfigService::class)->isTahesabAccounting()) {
|
||||
try {
|
||||
$result = app(TahesabController::class)->wallet([
|
||||
"customer_id" => auth('customer')->id(),
|
||||
"value" => $data['value'],
|
||||
"value" => $amount,
|
||||
"direction" => 1,
|
||||
]);
|
||||
|
||||
\Log::info('Tahesab withdraw result', [
|
||||
'customer_id' => auth('customer')->id(),
|
||||
'value' => $data['value'],
|
||||
'value' => $amount,
|
||||
'result' => $result,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
@@ -444,8 +476,10 @@ class WalletController extends Controller
|
||||
try {
|
||||
app(\App\Http\Controllers\Admin\ZarinController::class)->wallet([
|
||||
"customer_id" => auth('customer')->id(),
|
||||
"value" => $data['value'],
|
||||
"value" => $amount,
|
||||
"direction" => 1,
|
||||
"withdraw_id" => $Withdraw->id,
|
||||
"note" => 'برداشت ریالی',
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
@@ -454,11 +488,6 @@ class WalletController extends Controller
|
||||
|
||||
$companyName = $this->Config('name_fa'); // Company name from configuration
|
||||
$message = "کاربر $userName با شماره موبایل $userMobile درخواست برداشت مبلغ " . number_format($withdrawAmount) . " ریال را دارد. با تشکر، $companyName";
|
||||
if (isset($request->otp)) {
|
||||
if (Customer::where("id", $customer->id)->first()->token_sms != $request->otp) {
|
||||
return response()->json(['message' => 'رمز دوم اشتباه میباشد'], 422);
|
||||
}
|
||||
}
|
||||
User::where('send_sms', 1)->get()->each(function ($admin) use ($message) {
|
||||
if (self::isSmsNotifEnabled('sms_notif_withdraw_admin')) {
|
||||
$this->Send($admin->mobile, $message . ' ' . now()->format('H:i:s'));
|
||||
@@ -675,6 +704,25 @@ class WalletController extends Controller
|
||||
return response()->json(true);
|
||||
}
|
||||
|
||||
private function debitCustomerRialWithdrawOnce(Withdraw $withdraw, int $amount, Customer $customer): void
|
||||
{
|
||||
$alreadyDebited = Transaction::query()
|
||||
->where('withdraw_id', $withdraw->id)
|
||||
->where('cash', '<', 0)
|
||||
->exists();
|
||||
if ($alreadyDebited) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wallet = new WalletInterface((int) $customer->id, (int) $customer->type);
|
||||
new TransactionInterface($wallet, [
|
||||
'cash' => $amount,
|
||||
'expire_at' => now(),
|
||||
'withdraw_id' => $withdraw->id,
|
||||
'active' => true,
|
||||
], 4, false, false);
|
||||
}
|
||||
|
||||
private function validateWithdrawAmount(int $value): void
|
||||
{
|
||||
$wallet_interface_fund = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type);
|
||||
|
||||
Reference in New Issue
Block a user