This commit is contained in:
2026-06-14 21:09:43 +03:30
parent 6f86e8242c
commit b84b2df01a
9 changed files with 287 additions and 66 deletions
@@ -69,6 +69,30 @@ class ProductController extends SuperController
}
public function archiveTable(Request $request)
{
$data = $request->all();
if (isset($data['select']) && is_null($data['select'])) {
$data['select'] = [];
}
$query_table = Product::onlyTrashed()->with($this->with);
TableEngine::create($query_table, $data)
->initSearch($this->search)
->select($this->select)
->export($query_table);
return $query_table;
}
public function archive($id)
{
$product = Product::onlyTrashed()->findOrFail($id);
$product->restore();
return response()->json(true);
}
public function editProducts(Request $request)
{
if (isset($request->auto_open_at, $request->auto_close_at)) {
+20 -29
View File
@@ -90,35 +90,24 @@ class Controller extends BaseController
$send_sms = true;
$user = User::where('mobile', $to)->first() ?: Customer::where('mobile', $to)->first();
if ($user) {
//
// // Telegram
// if (isset($credentials['telegram']) && $user->telegram) {
// try {
// $res = Http::get("https://api.wwwapp.ir/telegran_send.php", [
// 'botToken' => $credentials['telegram']['token'],
// 'chatId' => $user->telegram,
// 'message' => "جناب {$user->name} {$msg}",
// ]);
// $data = $res->json();
// if (isset($data['success']) && $data['success'] === true) {
// $platforms[] = "telegram:{$user->telegram}";
// $send_sms = false;
// }
// } catch (\Exception $e) {
// }
// }
//
// Bale
if (isset($credentials['bale']) && $user->bale) {
$baleToken = trim((string) ($credentials['bale']['token'] ?? ''));
$baleChatId = trim((string) ($user->bale ?? ''));
if ($baleToken !== '' && $baleChatId !== '') {
try {
Http::withoutVerifying()->get("https://tapi.bale.ai/{$credentials['bale']['token']}/sendMessage", [
'chat_id' => $user->bale,
'text' => "جناب {$user->name} \n{$msg}",
]);
$platforms[] = "bale:{$user->bale}";
$send_sms = false;
} catch (\Exception $e) {
return $e->getMessage();
$baleResponse = Http::withoutVerifying()->get(
"https://tapi.bale.ai/bot{$baleToken}/sendMessage",
[
'chat_id' => $baleChatId,
'text' => "جناب {$user->name} \n{$msg}",
]
);
$balePayload = $baleResponse->json();
if ($baleResponse->successful() && ($balePayload['ok'] ?? false) === true) {
$platforms[] = "bale:{$baleChatId}";
$send_sms = false;
}
} catch (\Throwable $e) {
report($e);
}
}
}
@@ -153,7 +142,9 @@ class Controller extends BaseController
'platform' => 'rayegansms',
]);
$platforms[] = "rayegansms:{$to}";
$platforms[] = $response->successful()
? "rayegansms:{$to}"
: "rayegansms_failed:{$to}:{$response->status()}";
}
@@ -583,13 +583,17 @@ class SingleOrderController extends Controller
User::where('send_sms', 1)->get()->each(function ($admin) use ($message, $data, $transactionType, $companyName) {
$this->send($admin->mobile, $message);
});
$wallet = Wallet::where('owner', $data['customer_id'])->whereNull('fund_id')->first();
$wallet = Wallet::where('owner', $data['customer_id'])
->whereNull('fund_id')
->whereNull('product_id')
->first();
$balanceLabel = self::metalTypeLabel();
// $pricePerGram = $totalPrice / $amount;
$goldBalance = $wallet ? ($wallet->gold ?? 0) : 0;
$cashBalance = $wallet ? ($wallet->cash ?? 0) : 0;
$customerMessage = "$companyName\n$transactionType {$subjectTitle}\nگرم: {$amount}\n" .
"مبلغ کل: " . number_format($totalPrice) . "\n\n" .
"موجودی {$balanceLabel}: {$wallet->gold}\n" .
"مانده ریالی: " . number_format($wallet->cash) . "\n" .
"موجودی {$balanceLabel}: {$goldBalance}\n" .
"مانده ریالی: " . number_format($cashBalance) . "\n" .
$this->Config('app_url');
@@ -181,21 +181,27 @@ class RequestsController extends Controller
// $this->send($admin->mobile, $messageExam);
// });
$wallet = Wallet::where('owner', $data['customer_id'])->whereNull('fund_id')->first();
$wallet = Wallet::where('owner', $data['customer_id'])
->whereNull('fund_id')
->whereNull('product_id')
->first();
if($data['method'] == 'cash') {
$pricePerGram = $data['total_price'];
}elseif ($data['method'] == 'gold') {
$pricePerGram = $data['total_price'] / $data['amount'];
}
$goldBalance = $wallet ? ($wallet->gold ?? 0) : 0;
$cashBalance = $wallet ? ($wallet->cash ?? 0) : 0;
if($data['method'] == 'cash') {
$customerMessage = "$companyName\nبرداشت ریالی \nمبلغ: {$data['amount']}\n" .
"\nموجودی طلایی: {$wallet->gold}\n" .
"مانده ریالی: " . number_format($wallet->cash) . "\n" . $this->Config('app_url');
"\nموجودی طلایی: {$goldBalance}\n" .
"مانده ریالی: " . number_format($cashBalance) . "\n" . $this->Config('app_url');
}elseif ($data['method'] == 'gold') {
$customerMessage = "$companyName\nبرداشت طلایی \nگرم: {$data['amount']}\nقیمت گرم: " . number_format($pricePerGram) .
"\nمبلغ کل: " . number_format($data['total_price']) . "\nموجودی طلایی: {$wallet->gold}\n" .
"مانده ریالی: " . number_format($wallet->cash) . "\n" . $this->Config('app_url');
"\nمبلغ کل: " . number_format($data['total_price']) . "\nموجودی طلایی: {$goldBalance}\n" .
"مانده ریالی: " . number_format($cashBalance) . "\n" . $this->Config('app_url');
}
+4 -2
View File
@@ -29,8 +29,10 @@ class LivePriceTickService
| (قبل از sync محصولات تا آبشدهٔ «قیمت اپ» تازه باشد)
*/
$request = Request::create('/api/price/last', 'GET', ['force_refresh' => '1']);
$response = app(ReportController::class)->lastPrice($request);
$payload = json_decode($response->getContent(), true);
$result = app(ReportController::class)->lastPrice($request);
$payload = is_array($result)
? $result
: (json_decode($result->getContent(), true) ?: []);
if (! is_array($payload)) {
$payload = [];
}
+80 -8
View File
@@ -8,13 +8,16 @@ use Carbon\Carbon;
class PriceSnapshotService
{
/** حداقل قیمت معتبر آبشده (ریال) — زیر این در نمودار نمایش داده نمی‌شود */
public const MIN_VALID_CHART_PRICE_RIAL = 30_000_000;
/** هر تیک کران — ذخیره در prices برای نمودار (هرگز صفر ثبت نمی‌شود) */
public function recordTick(array $payload): void
{
$priceValue = (int) ($payload['price'] ?? 0);
if ($priceValue <= 30_000_000) {
if ($priceValue <= self::MIN_VALID_CHART_PRICE_RIAL) {
$last = Price::orderByDesc('id')->first();
if (! $last || (int) $last->price <= 30_000_000) {
if (! $last || (int) $last->price <= self::MIN_VALID_CHART_PRICE_RIAL) {
return;
}
$priceValue = (int) $last->price;
@@ -119,11 +122,7 @@ class PriceSnapshotService
->orderBy('created_at')
->get(['price', 'created_at']);
$dailyPoints = $daily->map(function (Price $row) {
$ts = ($row->created_at ?? now())->timestamp * 1000;
return ['timestamp' => $ts, 'value' => (int) $row->price];
})->values()->all();
$dailyPoints = $this->mapValidPriceRows($daily);
$weekRows = Price::query()
->where('created_at', '>=', now()->subDays(7))
@@ -153,11 +152,16 @@ class PriceSnapshotService
$lastBucket = null;
foreach ($rows as $row) {
$price = (int) $row->price;
if ($price <= self::MIN_VALID_CHART_PRICE_RIAL) {
continue;
}
$ts = $row->created_at?->timestamp ?? 0;
$bucket = (int) floor($ts / $bucketSeconds);
$point = [
'timestamp' => $ts * 1000,
'value' => (int) $row->price,
'value' => $price,
];
if ($bucket !== $lastBucket) {
@@ -170,4 +174,72 @@ class PriceSnapshotService
return $points;
}
/** @param \Illuminate\Support\Collection<int, Price> $rows */
private function mapValidPriceRows($rows): array
{
$points = [];
foreach ($rows as $row) {
$price = (int) $row->price;
if ($price <= self::MIN_VALID_CHART_PRICE_RIAL) {
continue;
}
$points[] = [
'timestamp' => ($row->created_at ?? now())->timestamp * 1000,
'value' => $price,
];
}
return $points;
}
/**
* @param array{DAILY?: array, WEEKLY?: array, MONTHLY?: array} $prices
* @return array{DAILY: array, WEEKLY: array, MONTHLY: array}
*/
public function sanitizeChartPrices(array $prices): array
{
$minScaled = intdiv(self::MIN_VALID_CHART_PRICE_RIAL, 1000);
foreach (['DAILY', 'WEEKLY', 'MONTHLY'] as $period) {
if (! isset($prices[$period]) || ! is_array($prices[$period])) {
$prices[$period] = [];
continue;
}
$lastValid = null;
$sanitized = [];
foreach ($prices[$period] as $point) {
$value = (int) ($point['value'] ?? 0);
$timestamp = (int) ($point['timestamp'] ?? 0);
if ($timestamp <= 0) {
continue;
}
$isValid = $value > self::MIN_VALID_CHART_PRICE_RIAL
|| ($value > $minScaled && $value <= self::MIN_VALID_CHART_PRICE_RIAL);
if ($isValid) {
$lastValid = $value;
} elseif ($lastValid !== null) {
$value = $lastValid;
} else {
continue;
}
$sanitized[] = [
'timestamp' => $timestamp,
'value' => $value,
];
}
$prices[$period] = $sanitized;
}
return $prices;
}
}
+6 -4
View File
@@ -93,17 +93,17 @@ class ZaarboxPriceService
if ($this->config->getBool('chart_use_local_data', false)) {
$local = app(PriceSnapshotService::class)->chartFromDatabase();
if (! empty($local['DAILY'])) {
return $local;
return app(PriceSnapshotService::class)->sanitizeChartPrices($local);
}
}
$cached = Cache::get($this->cacheKey());
if (is_array($cached) && isset($cached['prices'])) {
return $cached['prices'];
return app(PriceSnapshotService::class)->sanitizeChartPrices($cached['prices']);
}
return $this->refreshCache();
return app(PriceSnapshotService::class)->sanitizeChartPrices($this->refreshCache());
}
/**
@@ -566,7 +566,9 @@ class ZaarboxPriceService
for ($bucket = $firstBucket; $bucket <= $endMs; $bucket += $intervalMs) {
while ($index < $count && $points[$index]['timestamp'] <= $bucket) {
$lastPoint = $points[$index];
if ($points[$index]['price'] > PriceSnapshotService::MIN_VALID_CHART_PRICE_RIAL) {
$lastPoint = $points[$index];
}
$index++;
}
+132 -14
View File
@@ -90,11 +90,11 @@ SELECT 'admin_url', '', 'آدرس پنل ادمین', 1, 1, NULL, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'admin_url' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'logo_login', '', 'لوگوی صفحه ورود', 1, 1, NULL, 'text'
SELECT 'logo_login', '', 'لوگوی صفحه ورود', 0, 0, NULL, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'logo_login' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'logo_register', '', 'لوگوی ثبت‌نام', 1, 1, NULL, 'text'
SELECT 'logo_register', '', 'لوگوی ثبت‌نام', 0, 0, NULL, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'logo_register' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
@@ -407,11 +407,11 @@ SELECT 'minimum_sell', '', 'حداقل فروش', 1, 1, NULL, 'number'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'minimum_sell' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'referral_bonus_amount', '', 'مبلغ پاداش معرف', 1, 1, NULL, 'text'
SELECT 'referral_bonus_amount', '', 'مقدار پاداش معرف', 1, 1, NULL, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'referral_bonus_amount' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'balance_report_exclude_customer_id', '', 'حذف مشتری از تراز', 1, 1, NULL, 'number'
SELECT 'balance_report_exclude_customer_id', '', 'حذف مشتری از تراز', 1, 1, NULL, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'balance_report_exclude_customer_id' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
@@ -450,7 +450,7 @@ UPDATE `settings` SET `title_fa` = 'چت پشتیبانی' WHERE `key` = 'has_ch
UPDATE `settings` SET `title_fa` = 'آدرس API سرور' WHERE `key` = 'server_url' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'کلید داخلی اپ' WHERE `key` = 'key' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'تعداد معرف برای هدیه' WHERE `key` = 'referral_count_for_gift' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'مبلغ پاداش معرف' WHERE `key` = 'referral_bonus_amount' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'مقدار پاداش معرف' WHERE `key` = 'referral_bonus_amount' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '' OR `title_fa` = 'مبلغ پاداش معرف');
UPDATE `settings` SET `title_fa` = 'حداقل برداشت (ریال)' WHERE `key` = 'min_withdraw' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'حداقل اولین خرید (ریال)' WHERE `key` = 'min_first_buy' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
UPDATE `settings` SET `title_fa` = 'حداقل فروش' WHERE `key` = 'minimum_sell' AND (`title_fa` IS NULL OR TRIM(`title_fa`) = '');
@@ -583,13 +583,13 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
UPDATE `settings` SET `type` = 'number' WHERE `key` IN (
'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'fee_service_charge_percentage', 'fee_free',
'min_withdraw', 'min_first_buy', 'minimum_sell',
'montzar_product_id', 'balance_report_exclude_customer_id', 'gift_for_referrer',
'montzar_product_id', 'gift_for_referrer',
'gift_for_referral', 'up_price', 'down_price', 'payping_fin_customer_id', 'tahesab_port'
);
-- text (بقیه — URL، توکن، کلید API، ساعت، ...)
UPDATE `settings` SET `type` = 'text' WHERE `key` IN (
'name_fa', 'name_en', 'app_url', 'bace_url', 'logo_register', 'admin_url', 'title_pwa', 'title_fav',
'name_fa', 'name_en', 'app_url', 'bace_url', 'logo_login', 'logo_register', 'admin_url', 'title_pwa', 'title_fav',
'server_url', 'key', 'main_product', 'zaarbox_api_url', 'zaarbox_price_key', 'chart_id',
'etehadie_api_url', 'montzar_mobile', 'montzar_password', 'montzar_base_url',
'montzar_token', 'montzar_diff', 'montzar_live_price', 'montzar_mazaneh',
@@ -598,7 +598,7 @@ UPDATE `settings` SET `type` = 'text' WHERE `key` IN (
'payping_fin_token', 'payping_gateway_item', 'tahesab_host', 'tahesab_token', 'tahesab_db',
'node_client_id', 'node_shared_secret',
'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id', 'support_messenger_text', 'referral_limit',
'referral_bonus_amount', 'metal_type', 'montify_name', 'price_extreme_date',
'referral_bonus_amount', 'balance_report_exclude_customer_id', 'metal_type', 'montify_name', 'price_extreme_date',
'default_vc_number', 'liman_token'
);
@@ -622,11 +622,11 @@ SELECT 'service_charge_percentage', 'کارمزد درصدی (alias)', COALESCE(
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'service_charge_percentage' LIMIT 1);
INSERT INTO `settings` (`key`, `title_fa`, `value`, `can_edit`, `is_exist`, `is_active`, `type`)
SELECT 'title_pwa', 'عنوان PWA', '', 1, 0, 1, 'text'
SELECT 'title_pwa', 'عنوان PWA', '', 0, 0, 0, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'title_pwa' LIMIT 1);
INSERT INTO `settings` (`key`, `title_fa`, `value`, `can_edit`, `is_exist`, `is_active`, `type`)
SELECT 'title_fav', 'عنوان favicon', '', 1, 0, 1, 'text'
SELECT 'title_fav', 'عنوان favicon', '', 0, 0, 0, 'text'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'title_fav' LIMIT 1);
INSERT INTO `settings` (`key`, `title_fa`, `value`, `can_edit`, `is_exist`, `is_active`, `type`)
@@ -816,6 +816,14 @@ WHERE `key` = 'send_to_tahesab' AND TRIM(COALESCE(`value`, '')) = '';
-- is_store فقط از دیتابیس/دیپلوی — در پنل قابل ویرایش نیست
UPDATE `settings` SET `can_edit` = 0 WHERE `key` = 'is_store';
-- لوگو / PWA / favicon — فقط از دیپلوی؛ در پنل نمایش داده نمی‌شوند
UPDATE `settings` SET `can_edit` = 0, `is_active` = 0
WHERE `key` IN ('logo_login', 'logo_register', 'title_pwa', 'title_fav');
UPDATE `settings` SET `title_fa` = 'مقدار پاداش معرف' WHERE `key` = 'referral_bonus_amount';
UPDATE `settings` SET `type` = 'text' WHERE `key` = 'balance_report_exclude_customer_id';
-- پاکسازی title_fa / description از نام پروژه یا ارجاع کد
UPDATE `settings` SET `title_fa` = 'حالت فروشگاهی'
WHERE `key` = 'is_store' AND (`title_fa` LIKE '%قطره%' OR `title_fa` LIKE '%کشکول%');
@@ -823,12 +831,10 @@ WHERE `key` = 'is_store' AND (`title_fa` LIKE '%قطره%' OR `title_fa` LIKE '%
UPDATE `settings` SET `title_fa` = 'همگام‌سازی fin'
WHERE `key` = 'payping_fin_sync_enabled' AND `title_fa` LIKE '%لیمان%';
UPDATE `settings` SET `title_fa` = 'نام فروشگاه در درگاه', `description` = NULL
UPDATE `settings` SET `title_fa` = 'نام فروشگاه در درگاه', `description` = 'نام فروشگاه که در درگاه پرداخت و رسید بانکی به کاربر نمایش داده می‌شود.'
WHERE `key` = 'montify_name';
UPDATE `settings` SET `description` = NULL
WHERE `key` IN ('jibit_verification', 'register_jibit_verify', 'up_price', 'node_client_id', 'node_shared_secret')
AND (`description` LIKE '%Controller%' OR `description` LIKE '%.env%');
-- descriptionهای قدیمی که عمداً NULL می‌شدند — در بلوک پایانی بازنویسی می‌شوند
UPDATE `const` SET `title_fa` = 'توکن fin (legacy)' WHERE `key` = 'liman' AND `title_fa` LIKE '%لیمان%';
@@ -837,6 +843,118 @@ UPDATE `const` SET `title_fa` = COALESCE(NULLIF(TRIM(`title_fa`), ''), 'باز
UPDATE `const` SET `title_fa` = COALESCE(NULLIF(TRIM(`title_fa`), ''), 'سقف واریز اولیه') WHERE `key` = 'limited_price';
UPDATE `const` SET `title_fa` = COALESCE(NULLIF(TRIM(`title_fa`), ''), 'لاگ آخرین سفارش') WHERE `key` = 'last_order_log';
-- ---------------------------------------------------------------------------
-- راهنمای کامل تنظیمات (description) — برای نمایش در پنل ادمین
-- فرمت select: «متن راهنما|گزینه۱,گزینه۲»
-- ---------------------------------------------------------------------------
UPDATE `settings` SET `description` = 'نام فارسی برند که در پیامک‌ها، عنوان صفحات و بخش‌های عمومی اپ کاربر نمایش داده می‌شود.' WHERE `key` = 'name_fa';
UPDATE `settings` SET `description` = 'آدرس کامل وب‌اپ کاربر (با https). در لینک‌های پیامک، بازگشت از درگاه و ارجاعات داخلی استفاده می‌شود.' WHERE `key` = 'app_url';
UPDATE `settings` SET `description` = 'آدرس کامل پنل مدیریت (با https). برای لینک‌های ادمین و تنظیمات CORS در صورت نیاز.' WHERE `key` = 'admin_url';
UPDATE `settings` SET `description` = 'آدرس تصویر لوگو در صفحه ورود. معمولاً از طریق دیپلوی یا آپلود فایل تنظیم می‌شود؛ در پنل قابل ویرایش نیست.' WHERE `key` = 'logo_login';
UPDATE `settings` SET `description` = 'آدرس تصویر لوگو در صفحه ثبت‌نام. معمولاً از طریق دیپلوی تنظیم می‌شود؛ در پنل قابل ویرایش نیست.' WHERE `key` = 'logo_register';
UPDATE `settings` SET `description` = 'عنوان کوتاه برای نصب PWA روی موبایل. از دیپلوی مدیریت می‌شود.' WHERE `key` = 'title_pwa';
UPDATE `settings` SET `description` = 'عنوان نمایش‌داده‌شده در تب مرورگر (favicon). از دیپلوی مدیریت می‌شود.' WHERE `key` = 'title_fav';
UPDATE `settings` SET `description` = 'عنوان فلز اصلی در رابط کاربر (مثلاً «طلای آبشده»). در دارایی، کیف پول و برچسب‌های معامله دیده می‌شود.' WHERE `key` = 'metal_type';
UPDATE `settings` SET `description` = 'واحد نمایش وزن در دارایی‌ها، کیف پول و جزئیات معاملات|گرم,کیلوگرم' WHERE `key` = 'unit';
UPDATE `settings` SET `description` = 'روشن: کاربران جدید می‌توانند ثبت‌نام کنند. خاموش: فقط ورود کاربران موجود مجاز است.' WHERE `key` = 'open_register';
UPDATE `settings` SET `description` = 'روشن: حساب کاربر بلافاصله پس از ثبت‌نام فعال می‌شود. خاموش: نیاز به تأیید دستی ادمین دارد.' WHERE `key` = 'auto_active_customer';
UPDATE `settings` SET `description` = 'نوع چیدمان اپ: روشن = حالت فروشگاهی (سبد، دسته‌بندی، حواله و …). خاموش = حالت معامله آبشده/محصولات کلاسیک. فقط از دیپلوی تغییر می‌کند.' WHERE `key` = 'is_store';
UPDATE `settings` SET `description` = 'پیشوند اختیاری برای شماره‌گذاری حواله‌ها در سیستم حسابداری خارجی. خالی = بدون پیشوند.' WHERE `key` = 'default_vc_number';
UPDATE `settings` SET `description` = 'روشن: نمودار قیمت از تاریخچه ذخیره‌شده در دیتابیس خودتان. خاموش: از سرویس تابلو آنلاین (با شناسه chart_id) استفاده می‌شود.' WHERE `key` = 'chart_use_local_data';
UPDATE `settings` SET `description` = 'شناسه یکتا (UUID) نمودار در سرویس تابلو. اگر خالی باشد از شناسه پیش‌فرض سرویس استفاده می‌شود.' WHERE `key` = 'chart_id';
UPDATE `settings` SET `description` = 'منبع دریافت قیمت لحظه‌ای برای اپ کاربر و همگام‌سازی محصولات|montzar,zaarbox,main_product' WHERE `key` = 'price_provider';
UPDATE `settings` SET `description` = 'شناسه عددی یا نام reading_method محصول آبشده مرجع. وقتی منبع قیمت روی main_product باشد برای محاسبه استفاده می‌شود.' WHERE `key` = 'main_product';
UPDATE `settings` SET `description` = 'آدرس پایه API سرویس تابلو آنلاین (بدون مسیر انتهایی). مثال: https://example.com/api' WHERE `key` = 'zaarbox_api_url';
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` = 'روشن: خارج از بازه startDay تا endDay معامله و نمایش قیمت بسته می‌شود. خاموش: محدودیت ساعتی اعمال نمی‌شود.' WHERE `key` = 'close_price';
UPDATE `settings` SET `description` = 'ساعت شروع بازه معامله روزانه (فرمت 24 ساعته، مثال 09:00). فقط وقتی close_price روشن باشد اثر دارد.' WHERE `key` = 'startDay';
UPDATE `settings` SET `description` = 'ساعت پایان بازه معامله روزانه (فرمت 24 ساعته، مثال 22:00). فقط وقتی close_price روشن باشد اثر دارد.' WHERE `key` = 'endDay';
UPDATE `settings` SET `description` = 'اختلاف پایه (ریال) برای محاسبه قیمت خرید و فروش نمایشی روی مظنه. معمولاً نصف فاصله اسپرد کل است.' WHERE `key` = 'fee_single';
UPDATE `settings` SET `description` = 'مبلغ اضافه (ریال) روی قیمت پایه برای نمایش/محاسبه سمت خرید. خالی = استفاده از fee_single.' WHERE `key` = 'buy_fee';
UPDATE `settings` SET `description` = 'مبلغ کسر (ریال) از قیمت پایه برای نمایش/محاسبه سمت فروش. خالی = استفاده از fee_single.' WHERE `key` = 'sell_fee';
UPDATE `settings` SET `description` = 'کارمزد ثابت ریالی هر سفارش (legacy). در صورت تنظیم fee_service_charge_percentage معمولاً اولویت با درصد است.' WHERE `key` = 'fee_cash';
UPDATE `settings` SET `description` = 'درصد کارمزد هر سفارش از مبلغ معامله (اعشاری، مثال 0.005 یعنی ۰٫۵٪). روی payment_amount اعمال می‌شود.' WHERE `key` = 'fee_service_charge_percentage';
UPDATE `settings` SET `description` = 'تعداد اولین سفارش‌های هر کاربر که از کارمزد معاف می‌شوند. ۰ = غیرفعال.' WHERE `key` = 'fee_free';
UPDATE `settings` SET `description` = 'حداقل مبلغ درخواست برداشت وجه (ریال). درخواست‌های کمتر رد می‌شوند.' WHERE `key` = 'min_withdraw';
UPDATE `settings` SET `description` = 'حداقل مبلغ اولین خرید هر کاربر (ریال). برای فعال‌سازی کیف یا احراز سطح اول استفاده می‌شود.' WHERE `key` = 'min_first_buy';
UPDATE `settings` SET `description` = 'حداقل مقدار/مبلغ مجاز برای ثبت سفارش فروش. بسته به نوع محصول می‌تواند وزن یا ریال باشد.' WHERE `key` = 'minimum_sell';
UPDATE `settings` SET `description` = 'بیشترین قیمت ثبت‌شده در روز جاری (ریال). توسط سیستم به‌روز می‌شود؛ دستی تغییر ندهید.' WHERE `key` = 'up_price';
UPDATE `settings` SET `description` = 'کمترین قیمت ثبت‌شده در روز جاری (ریال). توسط سیستم به‌روز می‌شود؛ دستی تغییر ندهید.' WHERE `key` = 'down_price';
UPDATE `settings` SET `description` = 'تاریخ آخرین به‌روزرسانی بیشترین/کمترین قیمت روز. توسط سیستم پر می‌شود.' WHERE `key` = 'price_extreme_date';
UPDATE `settings` SET `description` = 'شناسه عددی مشتری که از گزارش تراز و آمار تجمیعی حذف می‌شود (مثلاً حساب تست). چند id با کاما.' WHERE `key` = 'balance_report_exclude_customer_id';
UPDATE `settings` SET `description` = 'تنظیم legacy — از price_provider استفاده کنید. روشن بودن این گزینه دیگر توصیه نمی‌شود.' WHERE `key` = 'main_product_price';
UPDATE `settings` SET `description` = 'تنظیم legacy — از price_provider استفاده کنید. معمولاً خاموش بماند.' WHERE `key` = 'montzar_price';
UPDATE `settings` SET `description` = 'متن کامل قوانین و مقررات استفاده از اپ که در صفحه قوانین به کاربر نشان داده می‌شود. HTML ساده مجاز است.' WHERE `key` = 'text_rule';
UPDATE `settings` SET `description` = 'متن «درباره ما» شامل معرفی مجموعه، راه‌های ارتباطی و توضیح خدمات. در صفحه مربوطه در اپ کاربر نمایش داده می‌شود.' WHERE `key` = 'text_about';
UPDATE `settings` SET `description` = 'روشن: وارد کردن کد معرف در ثبت‌نام اجباری است. خاموش: کد معرف اختیاری است.' WHERE `key` = 'referral_id';
UPDATE `settings` SET `description` = 'مقدار پاداش (معمولاً وزن فلز به گرم) که به کیف معرف پس از ثبت‌نام موفق معرف‌شونده واریز می‌شود.' WHERE `key` = 'gift_for_referrer';
UPDATE `settings` SET `description` = 'مقدار پاداش (معمولاً وزن فلز) که به کاربر تازه‌ثبت‌نام‌شده (معرف‌شونده) داده می‌شود. ۰ = بدون پاداش.' WHERE `key` = 'gift_for_referral';
UPDATE `settings` SET `description` = 'روشن: پس از ثبت‌نام کاربر جدید، پیامک اطلاع‌رسانی برای معرف ارسال می‌شود.' WHERE `key` = 'register_referral_sms_to_referrer';
UPDATE `settings` SET `description` = 'روشن: متن پاداش معرف در پیامک خوش‌آمد ثبت‌نام گنجانده می‌شود.' WHERE `key` = 'register_referral_bonus_message';
UPDATE `settings` SET `description` = 'حداکثر تعداد دعوت‌های مجاز برای هر کاربر. خالی = بدون محدودیت.' WHERE `key` = 'referral_limit';
UPDATE `settings` SET `description` = 'مبلغ یا مقدار پاداش معرف (متن آزاد — بسته به پیاده‌سازی پیامک/اعتبار). برای نمایش در پیام‌ها.' WHERE `key` = 'referral_bonus_amount';
UPDATE `settings` SET `description` = 'روشن: تطبیق شماره کارت بانکی کاربر با سرویس احراز هویت جیبیت هنگام ثبت/ویرایش کارت.' WHERE `key` = 'jibit_verification';
UPDATE `settings` SET `description` = 'روشن: تطبیق کد ملی و موبایل در فرآیند ثبت‌نام از طریق سرویس جیبیت.' WHERE `key` = 'register_jibit_verify';
UPDATE `settings` SET `description` = 'روشن: منوی «کسب درآمد / دعوت دوستان» در اپ کاربر نمایش داده می‌شود.' WHERE `key` = 'has_page_earn_money';
UPDATE `settings` SET `description` = 'شماره موبایل حساب API سرویس همکار قیمت. برای دریافت توکن و لیست محصولات.' WHERE `key` = 'montzar_mobile';
UPDATE `settings` SET `description` = 'رمز عبور حساب API سرویس همکار قیمت. محرمانه نگه دارید.' WHERE `key` = 'montzar_password';
UPDATE `settings` SET `description` = 'شناسه محصول آبشده در API همکار. باید با محصول مرجع در سرویس خارجی یکسان باشد.' WHERE `key` = 'montzar_product_id';
UPDATE `settings` SET `description` = 'آدرس پایه سرور API همکار (بدون اسلش انتهایی). مثال: https://example.com' WHERE `key` = 'montzar_base_url';
UPDATE `settings` SET `description` = 'توکن دسترسی API همکار. پس از ورود موفق توسط سیستم پر می‌شود؛ دستی ویرایش نکنید.' WHERE `key` = 'montzar_token';
UPDATE `settings` SET `description` = 'اختلاف قیمت دریافتی از همکار (ریال). توسط cron/همگام‌سازی پر می‌شود.' WHERE `key` = 'montzar_diff';
UPDATE `settings` SET `description` = 'آخرین قیمت لحظه‌ای دریافت‌شده از همکار (ریال). فقط خواندنی — توسط سیستم به‌روز می‌شود.' WHERE `key` = 'montzar_live_price';
UPDATE `settings` SET `description` = 'مظنه میانی دریافت‌شده از همکار. توسط سیستم به‌روز می‌شود.' WHERE `key` = 'montzar_mazaneh';
UPDATE `settings` SET `description` = 'مظنه واقعی سمت خرید از همکار. توسط سیستم به‌روز می‌شود.' WHERE `key` = 'montzar_truly_buy_mazaneh';
UPDATE `settings` SET `description` = 'مظنه واقعی سمت فروش از همکار. توسط سیستم به‌روز می‌شود.' WHERE `key` = 'montzar_truly_sell_mazaneh';
UPDATE `settings` SET `description` = 'روشن: امکان ثبت سفارش خرید از طریق قیمت همکار باز است (طبق وضعیت سرویس خارجی).' WHERE `key` = 'montzar_open_buy';
UPDATE `settings` SET `description` = 'روشن: امکان ثبت سفارش فروش از طریق قیمت همکار باز است.' WHERE `key` = 'montzar_open_sell';
UPDATE `settings` SET `description` = 'روشن: سرویس همکار در حال حاضر بسته/غیرفعال گزارش شده است.' WHERE `key` = 'montzar_closed';
UPDATE `settings` SET `description` = 'پاسخ JSON آخرین سفارش ارسالی به همکار. برای عیب‌یابی؛ توسط سیستم پر می‌شود.' WHERE `key` = 'montzar_order_response';
UPDATE `settings` SET `description` = 'شناسه کلاینت برای API سفارش خارجی (هدر X-Client-Id). باید با مقدار تنظیم‌شده در سرویس مقصد یکسان باشد.' WHERE `key` = 'node_client_id';
UPDATE `settings` SET `description` = 'کلید مشترک امضای HMAC برای احراز درخواست‌های API سفارش خارجی. محرمانه نگه دارید.' WHERE `key` = 'node_shared_secret';
UPDATE `settings` SET `description` = 'روشن: API دریافت کیف پول و ثبت سفارش از سرویس فروشگاه خارجی فعال است. نیاز به node_client_id و node_shared_secret دارد.' WHERE `key` = 'external_order_api_enabled';
UPDATE `settings` SET `description` = 'نام فروشگاه که در درگاه پرداخت و رسید بانکی به کاربر نمایش داده می‌شود.' WHERE `key` = 'montify_name';
UPDATE `settings` SET `description` = 'روشن: پس از واریز/برداشت، تراکنش به سامانه حسابداری fin همگام‌سازی می‌شود.' WHERE `key` = 'payping_fin_sync_enabled';
UPDATE `settings` SET `description` = 'آدرس کامل endpoint ثبت تراکنش در سامانه fin (POST).' WHERE `key` = 'payping_fin_url';
UPDATE `settings` SET `description` = 'توکن احراز هویت برای API سامانه fin.' WHERE `key` = 'payping_fin_token';
UPDATE `settings` SET `description` = 'شناسه مشتری/حساب در سامانه fin که تراکنش‌ها به نام آن ثبت می‌شوند.' WHERE `key` = 'payping_fin_customer_id';
UPDATE `settings` SET `description` = 'کد item تکی درگاه (legacy). اگر payping_gateway_items پر باشد اولویت با لیست چرخشی است.' WHERE `key` = 'payping_gateway_item';
UPDATE `settings` SET `description` = 'آدرس API شروع پرداخت (redirect کاربر به درگاه).' WHERE `key` = 'payping_start_url';
UPDATE `settings` SET `description` = 'آدرس API تأیید و نهایی‌سازی پرداخت پس از بازگشت از درگاه.' WHERE `key` = 'payping_verify_url';
UPDATE `settings` SET `description` = 'نام درگاه پرداخت فعال که به سرویس واسط درگاه ارسال می‌شود|sepal,' WHERE `key` = 'payping_gateway_name';
UPDATE `settings` SET `description` = 'لیست کدهای item درگاه (با کاما) برای چرخش بین چند merchant. خالی = استفاده از payping_gateway_item.' WHERE `key` = 'payping_gateway_items';
UPDATE `settings` SET `description` = 'روشن: مبلغ پرداخت به نزدیک‌ترین تومان گرد می‌شود. خاموش: مبلغ دقیق ریالی.' WHERE `key` = 'payping_round_toman';
UPDATE `settings` SET `description` = 'روشن: در صورت وجود برداشت ناموفق قبلی، تسویه جدید با احتیاط بیشتر انجام می‌شود.' WHERE `key` = 'payping_strict_failed_withdraw';
UPDATE `settings` SET `description` = 'آدرس IP یا hostname سرور نرم‌افزار ته‌حساب روی شبکه داخلی.' WHERE `key` = 'tahesab_host';
UPDATE `settings` SET `description` = 'شماره پورت اتصال به API ته‌حساب (معمولاً 8080 یا مقدار مستندات ته‌حساب).' WHERE `key` = 'tahesab_port';
UPDATE `settings` SET `description` = 'توکن/API Key اتصال به ته‌حساب. از پنل ته‌حساب دریافت می‌شود.' WHERE `key` = 'tahesab_token';
UPDATE `settings` SET `description` = 'نام دیتابیس یا شناسه پایگاه در ته‌حساب که سند به آن ارسال می‌شود.' WHERE `key` = 'tahesab_db';
UPDATE `settings` SET `description` = 'نام یا کد حساب بانکی در سند واریز/برداشت ته‌حساب.' WHERE `key` = 'tahesab_bank_account';
UPDATE `settings` SET `description` = 'روشن: واریز و برداشت مشتریان به‌صورت خودکار به ته‌حساب ارسال می‌شود.' WHERE `key` = 'send_to_tahesab';
UPDATE `settings` SET `description` = 'نوع پیام‌رسان برای دکمه پشتیبانی در اپ کاربر|bale,telegram,whatsapp,rubika,eitaa,soroush' WHERE `key` = 'support_messenger';
UPDATE `settings` SET `description` = 'شناسه تماس پشتیبانی: یوزرنیم (تلگرام)، شماره (واتساپ/بله) یا آیدی بسته به پیام‌رسان انتخاب‌شده.' WHERE `key` = 'support_messenger_id';
UPDATE `settings` SET `description` = 'متن دکمه یا توضیح کوتاه کنار لینک پشتیبانی در اپ کاربر.' WHERE `key` = 'support_messenger_text';
UPDATE `settings` SET `description` = 'توکن ربات تلگرام برای ارسال اعلان‌ها. از BotFather دریافت می‌شود. محرمانه.' WHERE `key` = 'telegram_bot_token';
UPDATE `settings` SET `description` = 'توکن ربات بله برای ارسال اعلان‌ها. محرمانه.' WHERE `key` = 'bale_bot_token';
UPDATE `settings` SET `description` = 'روشن: پس از شارژ کیف توسط ادمین، پیامک به مشتری ارسال می‌شود.' WHERE `key` = 'charge_notif';
UPDATE `settings` SET `description` = 'روشن: امکان ارسال پیامک گروهی از پنل ادمین فعال است.' WHERE `key` = 'group_sms';
UPDATE `settings` SET `description` = 'شناسه‌های عددی محصول (با کاما) که موجودی آن‌ها از کیف طلای اصلی خوانده می‌شود. خالی = غیرفعال.' WHERE `key` = 'main_wallet_products';
UPDATE `settings` SET `description` = 'روشن: در حالت فروشگاهی قیمت از API نصیریان خوانده می‌شود (در صورت پیکربندی). فقط برای برخی نصب‌ها.' WHERE `key` = 'price_from_nasiryan';
UPDATE `settings` SET `description` = 'روشن: API محاسبه سود طلا فعال است. در اکثر نصب‌ها خاموش می‌ماند.' WHERE `key` = 'profit_gold_api_enabled';
COMMIT;
SELECT 'deploy_settings_const.sql finished' AS status;
+2
View File
@@ -41,6 +41,8 @@ Route::middleware('auth:user')->group(function (){
Route::post('price_triggers/table', [PriceTriggerController::class, 'table']);
//-----------product
Route::post('/product/table', [ProductController::class, 'tableProduct']);
Route::post('/product/archive/table', [ProductController::class, 'archiveTable']);
Route::get('/product/archive/{id}', [ProductController::class, 'archive']);
Route::get('/product/active/{id}',[ProductController::class, 'active']);
Route::get('/product/hide/{id}',[ProductController::class, 'hide']);
Route::get('/product/credit',[ProductController::class, 'listProductCredit']);