Enable gated multi-level referral profit and harden chat/SMS notify paths.
Honor enable_customer_level_profit for order referral payouts, and tighten support-chat webhook/SMS plus SuperAdmin SMS panel sync settings. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -82,6 +82,10 @@ class GiftCardController extends Controller
|
||||
throw new UnprocessableEntityHttpException('auth failed!');
|
||||
}
|
||||
|
||||
if (!app(ConfigService::class)->getBool('has_page_gift_card', false)) {
|
||||
throw new UnprocessableEntityHttpException('قابلیت کارت هدیه غیرفعال است.');
|
||||
}
|
||||
|
||||
$redeem = $request->code;
|
||||
$giftcode = GiftCardCodes::where('code', $redeem)->first();
|
||||
$gift = GiftCard::find($giftcode->giftcard_id);
|
||||
|
||||
@@ -144,6 +144,7 @@ class SmsPanelController extends Controller
|
||||
|
||||
/**
|
||||
* خلاصه سبک کیف پول برای نمایش «اعتبار پیامک» در هدر؛ برای همه ادمینها.
|
||||
* اگر سوپرادمین قطع باشد، روی آینهٔ محلی برمیگردیم — نه 502 (ویجت هدر نباید بترکد).
|
||||
*/
|
||||
public function walletSummary()
|
||||
{
|
||||
@@ -159,24 +160,39 @@ class SmsPanelController extends Controller
|
||||
if ($this->useSuperAdmin()) {
|
||||
$balanceData = $this->sa()->balance();
|
||||
$charge = $this->sa()->chargeInfo();
|
||||
if ($balanceData === null || $charge === null) {
|
||||
$this->abortSaUnavailable();
|
||||
|
||||
if ($balanceData !== null) {
|
||||
$deposit = is_array($charge)
|
||||
? $this->depositFromChargeInfo($charge)
|
||||
: SmsWalletService::getDepositInfo();
|
||||
|
||||
$this->mirrorLocalFromSa(array_merge($balanceData, [
|
||||
'charge_info' => is_array($charge) ? $charge : [],
|
||||
'deposit' => $deposit,
|
||||
]));
|
||||
|
||||
return response()->json([
|
||||
'enabled' => true,
|
||||
'balance' => (int) ($balanceData['balance'] ?? 0),
|
||||
'is_blocked' => (bool) ($balanceData['is_blocked'] ?? false),
|
||||
'deposit' => $deposit,
|
||||
'source' => 'superadmin',
|
||||
'sa_partial' => $charge === null,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->mirrorLocalFromSa(array_merge($balanceData, [
|
||||
'charge_info' => $charge,
|
||||
'deposit' => $this->depositFromChargeInfo($charge),
|
||||
]));
|
||||
|
||||
return response()->json([
|
||||
'enabled' => true,
|
||||
'balance' => (int) ($balanceData['balance'] ?? 0),
|
||||
'is_blocked' => (bool) ($balanceData['is_blocked'] ?? false),
|
||||
'deposit' => $this->depositFromChargeInfo($charge),
|
||||
'source' => 'superadmin',
|
||||
]);
|
||||
// SA فعال است ولی balance نرسید — آخرین آینهٔ محلی
|
||||
return response()->json($this->localWalletSummaryPayload('local_fallback'));
|
||||
}
|
||||
|
||||
return response()->json($this->localWalletSummaryPayload('local'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled: bool, balance: int, is_blocked: bool, deposit: array, source: string}
|
||||
*/
|
||||
private function localWalletSummaryPayload(string $source): array
|
||||
{
|
||||
$balance = 0;
|
||||
$isBlocked = false;
|
||||
|
||||
@@ -186,12 +202,13 @@ class SmsPanelController extends Controller
|
||||
$isBlocked = (bool) $wallet->is_blocked;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
return [
|
||||
'enabled' => true,
|
||||
'balance' => $balance,
|
||||
'is_blocked' => $isBlocked,
|
||||
'deposit' => SmsWalletService::getDepositInfo(),
|
||||
]);
|
||||
'source' => $source,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -134,16 +134,18 @@ class SupportChatNotifyController extends Controller
|
||||
|
||||
/**
|
||||
* ثبت/تازهسازی وبهوک روی ah_chat (از پنل ادمین).
|
||||
* همیشه HTTP 200 — شکست ثبت best-effort است و نباید toast خطای 422 بسازد.
|
||||
*/
|
||||
public function ensureWebhook()
|
||||
{
|
||||
$service = app(ChatWebhookService::class);
|
||||
$ok = $service->ensureRegistered();
|
||||
$result = app(ChatWebhookService::class)->ensureRegisteredDetailed();
|
||||
|
||||
return response()->json([
|
||||
'ok' => $ok,
|
||||
'webhook_url' => $service->webhookUrl(),
|
||||
'message' => $ok ? 'webhook registered' : 'webhook register skipped or failed',
|
||||
], $ok ? 200 : 422);
|
||||
'ok' => (bool) ($result['ok'] ?? false),
|
||||
'webhook_url' => (string) ($result['webhook_url'] ?? ''),
|
||||
'reason' => (string) ($result['reason'] ?? ''),
|
||||
'message' => (string) ($result['message'] ?? ''),
|
||||
'attempts' => (int) ($result['attempts'] ?? 0),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ class SingleOrderController extends Controller
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
// $response['reward'] = $this->give_order_reward($data, $wallet, $wallet_interface);
|
||||
$response['reward'] = $this->give_order_reward($data, $wallet, $wallet_interface);
|
||||
if ((int) $data['direction'] === 1 && $customer) {
|
||||
$referrer = Customer::where('referral_id', $customer->referral_to_id)->first();
|
||||
if (!empty($referrer) && $referrer->first_buy_order == 1 && $customer->first_buy_order !== 1) {
|
||||
@@ -810,64 +810,97 @@ class SingleOrderController extends Controller
|
||||
|
||||
private function give_order_reward(&$data, $wallet, $wallet_interface)
|
||||
{
|
||||
if (!app(\App\Services\ConfigService::class)->getBool('enable_customer_level_profit', false)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$serviceCharge = (float) ($data['order']['service_charge'] ?? 0);
|
||||
if ($serviceCharge <= 0) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['aCustomers'] = [];
|
||||
$i = 0;
|
||||
$data['aCustomers'][$i] = Customer::findOrFail($data['customer_id']);
|
||||
while ($data['aCustomers'][$i + 1] = Customer::where('referral_id', $data['aCustomers'][$i]->referral_to_id)->first()) {
|
||||
if ($data['aCustomers'][$i + 1]->profit_amount_by_lvl) {
|
||||
$levels = json_decode(str_replace(['{', '}'], ['[', ']'], $data['aCustomers'][$i + 1]->profit_amount_by_lvl), true);
|
||||
foreach ($levels as $level) {
|
||||
if ($level[0] == $i + 1) {
|
||||
// [$level[1],$data['aCustomers'][$i+1]];
|
||||
|
||||
if ($this->Config('has_page_earn_money') == true) {
|
||||
$gift_for_invite = ($data['order']['service_charge'] * $level[1]) / 100;
|
||||
$profit_receiver = $data['aCustomers'][$i + 1]->id;
|
||||
$profit_sender = $data['aCustomers'][0]->id;
|
||||
$Withdraw = Withdraw::create([
|
||||
'user_id' => $profit_sender,
|
||||
'customer_id' => $profit_receiver,
|
||||
"cash" => 0,
|
||||
"gold" => $gift_for_invite,
|
||||
'sts' => 9,
|
||||
]);
|
||||
$wallet_interface = new WalletInterface($profit_receiver, 2);
|
||||
new TransactionInterface($wallet_interface, $_inp = [
|
||||
"cash" => 0,
|
||||
"gold" => $gift_for_invite,
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'start_at' => now(),
|
||||
], 9, true, false);
|
||||
$transaction = Transaction::where('customer_id', $profit_receiver)->latest()->first();
|
||||
TransactionsAdmin::create([
|
||||
'customer_id' => $profit_sender,
|
||||
'customer_to_id' => $profit_receiver,
|
||||
'user_id' => $profit_sender,
|
||||
'order_id' => $data['order']['id'],
|
||||
'wallet' => null, // یا مقدار مناسب دیگری
|
||||
'transaction_id' => $transaction->id,
|
||||
'cash' => 0,
|
||||
'note' => ' سود بابت سفارش',
|
||||
'type' => 1, // یا مقدار مناسب دیگری
|
||||
'gold' => $gift_for_invite,
|
||||
'balance_cash' => 0, // یا مقدار مناسب دیگری
|
||||
'balance_gold' => $gift_for_invite, // مقدار صحیح برای `balance_gold`
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$levels = $this->parseProfitAmountByLevel($data['aCustomers'][$i + 1]->profit_amount_by_lvl);
|
||||
foreach ($levels as $levelRow) {
|
||||
$levelNo = (int) ($levelRow['level'] ?? $levelRow[0] ?? 0);
|
||||
$percent = (float) ($levelRow['present'] ?? $levelRow[1] ?? 0);
|
||||
if ($levelNo !== ($i + 1) || $percent <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$gift_for_invite = ($serviceCharge * $percent) / 100;
|
||||
if ($gift_for_invite <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$profit_receiver = $data['aCustomers'][$i + 1]->id;
|
||||
$profit_sender = $data['aCustomers'][0]->id;
|
||||
$Withdraw = Withdraw::create([
|
||||
'user_id' => $profit_sender,
|
||||
'customer_id' => $profit_receiver,
|
||||
'cash' => 0,
|
||||
'gold' => $gift_for_invite,
|
||||
'sts' => 9,
|
||||
]);
|
||||
$wallet_interface = new WalletInterface($profit_receiver, 2);
|
||||
new TransactionInterface($wallet_interface, [
|
||||
'cash' => 0,
|
||||
'gold' => $gift_for_invite,
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'start_at' => now(),
|
||||
], 9, true, false);
|
||||
$transaction = Transaction::where('customer_id', $profit_receiver)->latest()->first();
|
||||
TransactionsAdmin::create([
|
||||
'customer_id' => $profit_sender,
|
||||
'customer_to_id' => $profit_receiver,
|
||||
'user_id' => $profit_sender,
|
||||
'order_id' => $data['order']['id'],
|
||||
'wallet' => null,
|
||||
'transaction_id' => $transaction->id,
|
||||
'cash' => 0,
|
||||
'note' => ' سود بابت سفارش',
|
||||
'type' => 1,
|
||||
'gold' => $gift_for_invite,
|
||||
'balance_cash' => 0,
|
||||
'balance_gold' => $gift_for_invite,
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
]);
|
||||
}
|
||||
if ($i == 100) break;
|
||||
$i++; // برای جلوگیری از حلقه بینهایت
|
||||
if ($i == 100) {
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @return list<array{level?:int,present?:float}|array{0:int,1:float}> */
|
||||
private function parseProfitAmountByLevel(mixed $raw): array
|
||||
{
|
||||
if (is_array($raw)) {
|
||||
return $raw;
|
||||
}
|
||||
if (!is_string($raw) || trim($raw) === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = json_decode($raw, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
// فرمت قدیمی: رشته شبیه {1,5},{2,2}
|
||||
$legacy = json_decode(str_replace(['{', '}'], ['[', ']'], $raw), true);
|
||||
|
||||
return is_array($legacy) ? $legacy : [];
|
||||
}
|
||||
|
||||
private function sendTransactionNotifications(array $data, string $transactionType)
|
||||
{
|
||||
$customer = Customer::findOrFail($data['customer_id']);
|
||||
@@ -880,8 +913,9 @@ class SingleOrderController extends Controller
|
||||
$totalPrice = $data['total_price'] ?? ($data['payment_amount'] ?? 0);
|
||||
$subjectTitle = $this->transactionSubjectTitle($data);
|
||||
|
||||
$amountLabel = self::formatSmsGoldWeight($amount);
|
||||
$message = "کاربر {$customer->name} با شماره موبایل {$customer->mobile} اقدام به $transactionType {$subjectTitle} به مقدار " .
|
||||
"{$amount} گرم به مبلغ " . number_format($totalPrice) .
|
||||
"{$amountLabel} گرم به مبلغ " . number_format($totalPrice) .
|
||||
" ریال کرد. با تشکر، $companyName";
|
||||
if (self::isSmsNotifEnabled('sms_notif_order_admin')) {
|
||||
User::where('send_sms', 1)->get()->each(function ($admin) use ($message) {
|
||||
@@ -895,9 +929,10 @@ class SingleOrderController extends Controller
|
||||
$balanceLabel = self::metalTypeLabel();
|
||||
$goldBalance = $wallet ? ($wallet->gold ?? 0) : 0;
|
||||
$cashBalance = $wallet ? ($wallet->cash ?? 0) : 0;
|
||||
$customerMessage = "$companyName\n$transactionType {$subjectTitle}\nگرم: {$amount}\n" .
|
||||
$goldBalanceLabel = self::formatSmsGoldWeight($goldBalance);
|
||||
$customerMessage = "$companyName\n$transactionType {$subjectTitle}\nگرم: {$amountLabel}\n" .
|
||||
"مبلغ کل: " . number_format($totalPrice) . "\n\n" .
|
||||
"موجودی {$balanceLabel}: {$goldBalance}\n" .
|
||||
"موجودی {$balanceLabel}: {$goldBalanceLabel}\n" .
|
||||
"مانده ریالی: " . number_format($cashBalance) . "\n" .
|
||||
self::publicSiteUrl(request());
|
||||
|
||||
@@ -1036,7 +1071,7 @@ class SingleOrderController extends Controller
|
||||
$userMobile = $customer->mobile; // User's mobile number
|
||||
$userName = $customer->name; // User's name
|
||||
$chargedAmount = $data['total_price']; // Total price in Rial
|
||||
$chargedAmountGold = $data['amount']; // Amount of gold
|
||||
$chargedAmountGold = self::formatSmsGoldWeight($data['amount']); // Amount of gold
|
||||
|
||||
// Company name
|
||||
$companyName = $this->Config('name_fa'); // Company name from configuration
|
||||
@@ -1055,15 +1090,16 @@ class SingleOrderController extends Controller
|
||||
->main()
|
||||
->first();
|
||||
$companyurl = self::publicSiteUrl(request());
|
||||
$weight = $data['amount'];
|
||||
$weight = (float) $data['amount'];
|
||||
$weightLabel = self::formatSmsGoldWeight($weight);
|
||||
$totalAmount = $data['total_price'];
|
||||
$pricePerGram = $weight > 0 ? $totalAmount / $weight : 0;
|
||||
$goldBalance = $mainWallet->gold ?? 0;
|
||||
$goldBalance = self::formatSmsGoldWeight($mainWallet->gold ?? 0);
|
||||
$remainingBalance = $mainWallet->cash ?? 0;
|
||||
|
||||
$message = "$companyName\n";
|
||||
$message .= "خرید آبشده\n";
|
||||
$message .= "گرم: $weight\n";
|
||||
$message .= "گرم: $weightLabel\n";
|
||||
$message .= "قیمت گرم: " . number_format($pricePerGram) . "\n";
|
||||
$message .= "مبلغ کل: " . number_format($totalAmount) . "\n\n";
|
||||
$message .= "موجودی طلایی: $goldBalance\n";
|
||||
@@ -1110,6 +1146,28 @@ class SingleOrderController extends Controller
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* مقدار ضربشونده در قیمت واحد برای مبلغ سفارش.
|
||||
* قیمت فرمولی = قیمت هر عدد (وزن داخل فرمول است) → فقط تعداد.
|
||||
* بقیه = تعداد × وزن واحد محصول.
|
||||
*/
|
||||
private function resolveProductOrderPricingAmount(Product|array|null $product, float $number): float
|
||||
{
|
||||
if ($product instanceof Product && FormulaPriceService::isEnabled($product)) {
|
||||
return $number;
|
||||
}
|
||||
|
||||
if (is_array($product) && ! empty($product['price_formula_enabled'])) {
|
||||
return $number;
|
||||
}
|
||||
|
||||
$unitAmount = $product instanceof Product
|
||||
? (float) ($product->amount ?? 0)
|
||||
: (float) (is_array($product) ? ($product['amount'] ?? 0) : 0);
|
||||
|
||||
return $number * $unitAmount;
|
||||
}
|
||||
|
||||
private function assertMinimumSellCash(array $data): void
|
||||
{
|
||||
$minSell = Setting::where('key', 'minimum_sell')->where('is_active', 1)->first();
|
||||
|
||||
@@ -158,8 +158,9 @@ class RequestsController extends Controller
|
||||
$message = "کاربر {$customer->name} با شماره موبایل {$customer->mobile} اقدام به برداشت موجودی از طرف $montifyCompanyName به مقدار " .
|
||||
"{$data['amount']} ریال " . " کرد. با تشکر، $companyName";
|
||||
}elseif ($data['method'] == 'gold') {
|
||||
$amountLabel = self::formatSmsGoldWeight($data['amount']);
|
||||
$message = "کاربر {$customer->name} با شماره موبایل {$customer->mobile} اقدام به $transactionType طلا به مقدار " .
|
||||
"{$data['amount']} گرم به مبلغ " . number_format($data['total_price']) .
|
||||
"{$amountLabel} گرم به مبلغ " . number_format($data['total_price']) .
|
||||
" ریال کرد. با تشکر، $companyName";
|
||||
}
|
||||
User::where('send_sms', 1)->get()->each(function ($admin) use ($message, $data, $transactionType, $companyName) {
|
||||
|
||||
@@ -52,7 +52,7 @@ class Customer extends Authenticatable implements JWTSubject
|
||||
'credential_id',
|
||||
'moshtari_code',
|
||||
'pargar_account_id',
|
||||
|
||||
'profit_amount_by_lvl',
|
||||
];
|
||||
/**
|
||||
* The attributes that should be hidden for arrays.
|
||||
@@ -75,6 +75,7 @@ class Customer extends Authenticatable implements JWTSubject
|
||||
"finger_print" => "boolean",
|
||||
"conditional_order_active" => "boolean",
|
||||
"conditional_order_limit" => "integer",
|
||||
"profit_amount_by_lvl" => "array",
|
||||
];
|
||||
static $TYPE = [
|
||||
1=>'همکار',
|
||||
|
||||
@@ -12,62 +12,114 @@ class ChatWebhookService
|
||||
{
|
||||
public function ensureRegistered(): bool
|
||||
{
|
||||
return (bool) ($this->ensureRegisteredDetailed()['ok'] ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{ok: bool, reason: string, message: string, webhook_url: string, attempts?: int}
|
||||
*/
|
||||
public function ensureRegisteredDetailed(int $maxAttempts = 3): array
|
||||
{
|
||||
$webhookUrl = $this->webhookUrl();
|
||||
$chatApi = Controller::Config('chat_api');
|
||||
$chatApiKey = Controller::Config('chat_api_key');
|
||||
|
||||
if (!$chatApi || !$chatApiKey) {
|
||||
return false;
|
||||
if (! $chatApi || ! $chatApiKey) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'reason' => 'missing_chat_config',
|
||||
'message' => 'تنظیمات chat_api یا chat_api_key خالی است',
|
||||
'webhook_url' => $webhookUrl,
|
||||
];
|
||||
}
|
||||
|
||||
$host = preg_replace('#^https?://#', '', rtrim((string) $chatApi, '/'));
|
||||
$secret = $this->ensureSecret();
|
||||
if ($host === '' || $secret === '') {
|
||||
return false;
|
||||
return [
|
||||
'ok' => false,
|
||||
'reason' => 'invalid_host_or_secret',
|
||||
'message' => 'آدرس چت یا رمز وبهوک نامعتبر است',
|
||||
'webhook_url' => $webhookUrl,
|
||||
];
|
||||
}
|
||||
|
||||
$webhookUrl = $this->webhookUrl();
|
||||
if ($this->isUnreachableWebhookUrl($webhookUrl)) {
|
||||
Log::warning('chat webhook register refused: unreachable/local URL', [
|
||||
'webhook_url' => $webhookUrl,
|
||||
'hint' => 'Set chat_webhook_base_url to public Laravel URL (e.g. https://niazitala.ir/server) or fix APP_URL',
|
||||
]);
|
||||
|
||||
return false;
|
||||
return [
|
||||
'ok' => false,
|
||||
'reason' => 'unreachable_webhook_url',
|
||||
'message' => 'آدرس وبهوک محلی/غیرقابلدسترس است؛ chat_webhook_base_url را روی آدرس عمومی سرور بگذارید',
|
||||
'webhook_url' => $webhookUrl,
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Http::timeout(8)->post('https://'.$host.'/api/projects/set-webhook', [
|
||||
'api_key' => $chatApiKey,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'webhook_secret' => $secret,
|
||||
]);
|
||||
$attempts = max(1, $maxAttempts);
|
||||
$lastReason = 'unknown';
|
||||
$lastMessage = 'ثبت وبهوک ناموفق بود';
|
||||
|
||||
if (! $response->successful()) {
|
||||
for ($i = 1; $i <= $attempts; $i++) {
|
||||
try {
|
||||
$response = Http::timeout(8)
|
||||
->retry(0)
|
||||
->post('https://'.$host.'/api/projects/set-webhook', [
|
||||
'api_key' => $chatApiKey,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'webhook_secret' => $secret,
|
||||
]);
|
||||
|
||||
if ($response->successful()) {
|
||||
Log::info('chat webhook registered', [
|
||||
'host' => $host,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'attempt' => $i,
|
||||
]);
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'reason' => 'registered',
|
||||
'message' => 'webhook registered',
|
||||
'webhook_url' => $webhookUrl,
|
||||
'attempts' => $i,
|
||||
];
|
||||
}
|
||||
|
||||
$lastReason = 'chat_api_http_'.$response->status();
|
||||
$lastMessage = 'سرور چت ثبت وبهوک را رد کرد (HTTP '.$response->status().')';
|
||||
Log::warning('chat webhook register non-2xx', [
|
||||
'host' => $host,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'status' => $response->status(),
|
||||
'body' => mb_substr($response->body(), 0, 300),
|
||||
'attempt' => $i,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
$lastReason = 'chat_api_exception';
|
||||
$lastMessage = 'ارتباط با سرور چت برای ثبت وبهوک برقرار نشد';
|
||||
Log::warning('chat webhook register failed', [
|
||||
'host' => $host,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'error' => $e->getMessage(),
|
||||
'attempt' => $i,
|
||||
]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Log::info('chat webhook registered', [
|
||||
'host' => $host,
|
||||
'webhook_url' => $webhookUrl,
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('chat webhook register failed', [
|
||||
'host' => $host,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return false;
|
||||
if ($i < $attempts) {
|
||||
usleep(250000 * $i);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => false,
|
||||
'reason' => $lastReason,
|
||||
'message' => $lastMessage,
|
||||
'webhook_url' => $webhookUrl,
|
||||
'attempts' => $attempts,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -405,6 +405,18 @@ SELECT 'enable_product_funds', 'false', 'قلک محصول', 0, 1,
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'enable_product_funds' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'has_page_gift_card', 'false', 'کارت هدیه', 0, 1,
|
||||
'روشن: منوی «ثبت کارت هدیه» و صفحه ثبت کد در اپ کاربر فعال است. خاموش: منو و صفحه مخفی است و API استفاده از کد هدیه در دسترس نیست. فقط از دیپلوی قابل تغییر است.',
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'has_page_gift_card' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'enable_customer_level_profit', 'false', 'سود چندسطحی معرف', 0, 1,
|
||||
'روشن: در لیست مشتریان آیکون تنظیم درصد سود هر سطح زیرمجموعه فعال است و پس از سفارش، سهم کارمزد طبق درصدهای هر معرف به کیف طلا واریز میشود. خاموش: آیکون و واریز سود چندسطحی غیرفعال است. فقط از دیپلوی قابل تغییر است.',
|
||||
'switch'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'enable_customer_level_profit' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'has_page_price_trigger', 'true', 'هشدار قیمت', 0, 1,
|
||||
'روشن: منوی هشدار قیمت در اپ کاربر نمایش داده میشود. خاموش: منو و صفحه مخفی است. فقط از دیپلوی قابل تغییر است.',
|
||||
@@ -773,6 +785,11 @@ SELECT 'deposit_card_number', '', 'شماره کارت واریز', 1, 1,
|
||||
'شماره کارت واریز — در متنها با ٪کارت یا %کارت جایگزین میشود.', 'text'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'deposit_card_number' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'deposit_account_number', '', 'شماره حساب واریز', 1, 1,
|
||||
'شماره حساب بانکی واریز — در مودال راهنمای شارژ کنار کارت و شبا نمایش داده میشود. در متنها با ٪حساب یا %حساب جایگزین میشود.', 'text'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'deposit_account_number' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'deposit_sheba', '', 'شبا واریز', 1, 1,
|
||||
'شماره شبا واریز — در متنها با ٪شبا یا %شبا جایگزین میشود.', 'text'
|
||||
@@ -1110,7 +1127,8 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
|
||||
'fee_deduct_from_gold',
|
||||
'require_zero_main_gold_before_other_buy',
|
||||
'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',
|
||||
'has_page_earn_money', 'has_page_price_trigger', 'has_page_notification', 'has_page_gift_card',
|
||||
'enable_customer_level_profit', 'charge_notif', 'group_sms', 'sms_panel', 'customer_direct_sms',
|
||||
'enable_conditional_order', 'enable_product_funds',
|
||||
'sms_notif_order_admin', 'sms_notif_order_customer',
|
||||
'sms_notif_withdraw_admin', 'sms_notif_withdraw_otp', 'sms_notif_login_otp',
|
||||
@@ -1358,6 +1376,13 @@ UPDATE `settings` SET
|
||||
`description` = 'شماره کارت واریز — در متنها با ٪کارت یا %کارت جایگزین میشود.'
|
||||
WHERE `key` = 'deposit_card_number';
|
||||
|
||||
UPDATE `settings` SET
|
||||
`title_fa` = 'شماره حساب واریز',
|
||||
`type` = 'text',
|
||||
`can_edit` = 1,
|
||||
`description` = 'شماره حساب بانکی واریز — در مودال راهنمای شارژ کنار کارت و شبا نمایش داده میشود. در متنها با ٪حساب یا %حساب جایگزین میشود.'
|
||||
WHERE `key` = 'deposit_account_number';
|
||||
|
||||
UPDATE `settings` SET
|
||||
`title_fa` = 'شبا واریز',
|
||||
`type` = 'text',
|
||||
@@ -1603,6 +1628,10 @@ UPDATE `settings` SET `title_fa` = 'احراز هویت جیبیت' WHERE `key`
|
||||
UPDATE `settings` SET `title_fa` = 'سفارش شرطی' WHERE `key` = 'enable_conditional_order';
|
||||
UPDATE `settings` SET `title_fa` = 'قلک محصول' WHERE `key` = 'enable_product_funds';
|
||||
UPDATE `settings` SET `description` = 'روشن: ساخت و مدیریت قلک per-product در اپ مشتری فعال است (یک محصول در هر قلک؛ انتقال بدون سند حسابداری). خاموش: منو و API ساخت قلک جدید در دسترس نیست. فقط از دیپلوی قابل تغییر است.' WHERE `key` = 'enable_product_funds';
|
||||
UPDATE `settings` SET `title_fa` = 'کارت هدیه' WHERE `key` = 'has_page_gift_card';
|
||||
UPDATE `settings` SET `description` = 'روشن: منوی «ثبت کارت هدیه» و صفحه ثبت کد در اپ کاربر فعال است. خاموش: منو و صفحه مخفی است و API استفاده از کد هدیه در دسترس نیست. فقط از دیپلوی قابل تغییر است.' WHERE `key` = 'has_page_gift_card';
|
||||
UPDATE `settings` SET `title_fa` = 'سود چندسطحی معرف' WHERE `key` = 'enable_customer_level_profit';
|
||||
UPDATE `settings` SET `description` = 'روشن: در لیست مشتریان آیکون تنظیم درصد سود هر سطح زیرمجموعه فعال است و پس از سفارش، سهم کارمزد طبق درصدهای هر معرف به کیف طلا واریز میشود. خاموش: آیکون و واریز سود چندسطحی غیرفعال است. فقط از دیپلوی قابل تغییر است.' WHERE `key` = 'enable_customer_level_profit';
|
||||
UPDATE `settings` SET `description` = 'روشن: امکان ارسال پیامک گروهی از پنل ادمین فعال است.' WHERE `key` = 'group_sms';
|
||||
UPDATE `settings` SET `description` = 'روشن: پنل پیامک و کیف پول billing فعال است. خاموش: پیامکها مثل قبل ارسال میشوند بدون billing.' WHERE `key` = 'sms_panel';
|
||||
|
||||
@@ -1817,6 +1846,7 @@ UPDATE `settings` SET `title_fa` = 'متن راهنمای واریز' WHERE `key
|
||||
UPDATE `settings` SET `title_fa` = 'متن پیام به پشتیبانی (واریز)' WHERE `key` = 'deposit_support_message_text';
|
||||
UPDATE `settings` SET `title_fa` = 'نام صاحب حساب واریز' WHERE `key` = 'deposit_account_holder';
|
||||
UPDATE `settings` SET `title_fa` = 'شماره کارت واریز' WHERE `key` = 'deposit_card_number';
|
||||
UPDATE `settings` SET `title_fa` = 'شماره حساب واریز' WHERE `key` = 'deposit_account_number';
|
||||
UPDATE `settings` SET `title_fa` = 'شبا واریز' WHERE `key` = 'deposit_sheba';
|
||||
UPDATE `settings` SET `title_fa` = 'حساب بانکی تهحساب' WHERE `key` = 'tahesab_bank_account';
|
||||
UPDATE `settings` SET `title_fa` = 'نام دیتابیس تهحساب' WHERE `key` = 'tahesab_db';
|
||||
@@ -1863,6 +1893,8 @@ UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
|
||||
'enable_product_funds',
|
||||
'has_page_price_trigger',
|
||||
'has_page_notification',
|
||||
'has_page_gift_card',
|
||||
'enable_customer_level_profit',
|
||||
'jibit_enabled',
|
||||
'has_page_earn_money',
|
||||
'is_store',
|
||||
@@ -1906,7 +1938,7 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN (
|
||||
'sms_notif_fund_withdraw_admin', 'sms_notif_fund_withdraw_customer',
|
||||
'sms_notif_price_trigger', 'sms_notif_wallet_alert', 'sms_notif_support_admin',
|
||||
'deposit_sms_support_number', 'deposit_support_message_text',
|
||||
'deposit_account_holder', 'deposit_card_number', 'deposit_sheba',
|
||||
'deposit_account_holder', 'deposit_card_number', 'deposit_account_number', 'deposit_sheba',
|
||||
'endDay',
|
||||
'fee_free', 'fee_service_charge_percentage',
|
||||
'gift_for_referral', 'gift_for_referrer',
|
||||
@@ -1925,7 +1957,7 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN (
|
||||
'startDay',
|
||||
'support_messenger', 'support_messenger_id', 'support_messenger_text', 'support_messengers',
|
||||
'has_chat',
|
||||
'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_sheba',
|
||||
'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_account_number', 'deposit_sheba',
|
||||
'text_about', 'text_rule',
|
||||
'price_channel_enabled', 'price_channel_messengers', 'price_channel_diff',
|
||||
'price_channel_min_seconds', 'price_channel_message_text',
|
||||
|
||||
Reference in New Issue
Block a user