added gholak

This commit is contained in:
2026-08-01 17:30:14 +03:30
parent 9642e603e7
commit eaff9dead2
12 changed files with 538 additions and 75 deletions
@@ -204,14 +204,16 @@ class CustomerController extends SuperController
$catalogMetalIds = $balanceService->catalogMetalIds();
$mainWalletMetalId = $balanceService->resolveMainWalletMetalId();
$productCols = implode(',', self::WALLET_PRODUCT_COLUMNS);
$ownerType = (int) (Customer::find($customer_id)?->type ?? 0);
// فقط کیف محصول‌ها (نه کیف اصلی) — هر ردیف = موجودی واقعی یک محصول/فلز
// فقط کیف محصول آزاد (نه کیف اصلی، نه قلک) — هر ردیف = یک دارایی
$query_table = Wallet::with([
'product' => static function ($q) use ($productCols) {
$q->withTrashed()->select(explode(',', $productCols));
},
])
->where('owner', $customer_id)
->whereNull('fund_id')
->whereNotNull('product_id');
if ($mainWalletProductIds !== []) {
// کیف‌های قدیمیِ محصولات متصل به کیف اصلی نمایش داده نمی‌شوند
@@ -240,11 +242,15 @@ class CustomerController extends SuperController
->first();
if ($representative && $mainWallet) {
$freeGold = $balanceService->effectiveMainWalletGold((int) $customer_id, $ownerType);
$fundGold = $balanceService->fundGoldForMainWalletProducts((int) $customer_id, $ownerType);
$mainRow = [
'id' => $mainWallet->id,
'owner' => (int) $customer_id,
'cash' => 0,
'gold' => (float) $mainWallet->gold,
'gold' => $freeGold + $fundGold,
'free_gold' => $freeGold,
'fund_gold' => $fundGold,
'fund_id' => null,
'product_id' => (int) $representative->id,
'created_at' => $mainWallet->created_at,
@@ -260,7 +266,6 @@ class CustomerController extends SuperController
if (isset($query_table['rows'])) {
foreach ($query_table['rows'] as &$row) {
$balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId);
// اگر eager-load محصول نیامده بود، از lookup پر کن
$productId = (int) (is_array($row) ? ($row['product_id'] ?? 0) : ($row->product_id ?? 0));
$hasProduct = is_array($row)
? ! empty($row['product'])
@@ -278,12 +283,149 @@ class CustomerController extends SuperController
$balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId);
}
}
// جمع دارایی = آزاد + قلک‌های همان محصول (برای ردیف اصلی قبلاً ست شده)
$isMain = is_array($row)
? ! empty($row['is_main_wallet'])
: ! empty($row->is_main_wallet);
if ($productId > 0 && ! $isMain) {
$freeGold = $balanceService->freeProductGold((int) $customer_id, $productId, $ownerType);
$fundGold = $balanceService->fundGoldForProduct((int) $customer_id, $productId, $ownerType);
if (is_array($row)) {
$row['free_gold'] = $freeGold;
$row['fund_gold'] = $fundGold;
$row['gold'] = $freeGold + $fundGold;
} else {
$row->free_gold = $freeGold;
$row->fund_gold = $fundGold;
$row->gold = $freeGold + $fundGold;
}
}
}
unset($row);
}
return response()->json($query_table);
}
/** جدول قلک‌های واقعی مشتری (مدل Fund) */
public function piggyFunds(Request $request, $customer_id)
{
$query_table = \App\Models\Fund::with(['wallet', 'product'])
->where('customer_id', $customer_id);
TableEngine::create($query_table, $request)
->initSearch(['title'])
->select(['*'])
->export($query_table);
if (isset($query_table['rows'])) {
foreach ($query_table['rows'] as &$row) {
$wallets = is_array($row)
? collect($row['wallet'] ?? [])
: collect($row->wallet ?? []);
$gold = (float) $wallets->sum('gold');
if (is_array($row)) {
$row['gold'] = $gold;
$row['product_title'] = $row['product']['title'] ?? ($row['product']->title ?? null);
} else {
$row->gold = $gold;
$row->product_title = $row->product?->title;
}
}
unset($row);
}
return response()->json($query_table);
}
/** قلک‌های یک دارایی (محصول) */
public function assetPiggyFunds(Request $request, $customer_id, $product_id)
{
$request->merge(['product_id' => (int) $product_id]);
$query_table = \App\Models\Fund::with(['wallet', 'product'])
->where('customer_id', $customer_id)
->where('product_id', (int) $product_id);
TableEngine::create($query_table, $request)
->initSearch(['title'])
->select(['*'])
->export($query_table);
if (isset($query_table['rows'])) {
foreach ($query_table['rows'] as &$row) {
$wallets = is_array($row)
? collect($row['wallet'] ?? [])
: collect($row->wallet ?? []);
$gold = (float) $wallets->sum('gold');
if (is_array($row)) {
$row['gold'] = $gold;
} else {
$row->gold = $gold;
}
}
unset($row);
}
return response()->json($query_table);
}
/** تراکنش‌های مربوط به یک دارایی (کیف آزاد + قلک‌های همان محصول) */
public function assetTransactions(Request $request, $customer_id, $product_id)
{
$config = app(ConfigService::class);
$productId = (int) $product_id;
$walletIds = Wallet::query()
->where('owner', $customer_id)
->where(function ($q) use ($config, $productId) {
if ($config->isMainWalletProduct($productId)) {
$q->where(function ($inner) {
$inner->whereNull('fund_id')->whereNull('product_id');
})->orWhere(function ($inner) use ($productId) {
$inner->whereNotNull('fund_id')
->where(function ($f) use ($productId) {
$f->where('product_id', $productId)->orWhereNull('product_id');
});
});
} else {
$q->where('product_id', $productId);
}
})
->pluck('id');
$records = \Rooyesh\Wallet\models\Transaction::whereIn('wallet', $walletIds);
TableEngine::create($records, $request->all())
->initSearch([])
->select([
'*',
\Rooyesh\Wallet\models\Transaction::$SELECT_CAJ,
\Rooyesh\Wallet\models\Transaction::$SELECT_TYPE_STR,
])->export($records);
return response()->json($records);
}
/** تراکنش‌های یک قلک */
public function piggyFundTransactions(Request $request, $customer_id, $fund_id)
{
$fund = \App\Models\Fund::where('customer_id', $customer_id)->findOrFail($fund_id);
$walletIds = Wallet::query()
->where('owner', $customer_id)
->where('fund_id', $fund->id)
->pluck('id');
$records = \Rooyesh\Wallet\models\Transaction::whereIn('wallet', $walletIds);
TableEngine::create($records, $request->all())
->initSearch([])
->select([
'*',
\Rooyesh\Wallet\models\Transaction::$SELECT_CAJ,
\Rooyesh\Wallet\models\Transaction::$SELECT_TYPE_STR,
])->export($records);
return response()->json($records);
}
public function archive($id){
$query = Customer::findOrFail($id);
$query->update([
+211 -64
View File
@@ -2,96 +2,243 @@
namespace App\Http\Controllers\Customer;
use App\DB\Te\TableEngine;
use App\Http\Controllers\Controller;
use App\Http\Controllers\SuperController;
use App\Models\Fund;
use App\Models\Product;
use App\Services\ConfigService;
use App\Services\WalletBalanceService;
use Illuminate\Http\Request;
use Rooyesh\Wallet\interfaces\TransactionInterface;
use Rooyesh\Wallet\interfaces\WalletInterface;
use Rooyesh\Wallet\models\Transaction;
use Rooyesh\Wallet\models\Wallet;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
/**
* قلک per-product — انتقال فقط TransactionInterface؛ بدون سند حسابداری.
*/
class FundController extends SuperController
{
public function __construct(Request $request)
{
$model = Fund::class;
$this->with=['wallet'];
$this->with = ['wallet', 'product'];
$select = ['*'];
$search=['name'];
$request->request->add(['customer_id'=>auth('customer')->id()]);
$query = Fund::with($this->with)->where('customer_id',auth('customer')->id());
parent::__construct($model, $this->with, $select, null,$query,$search);
$search = ['title'];
$request->request->add(['customer_id' => auth('customer')->id()]);
$query = Fund::with($this->with)->where('customer_id', auth('customer')->id());
parent::__construct($model, $this->with, $select, null, $query, $search);
}
public function deposit(Request $request){
public function store(Request $request)
{
$this->assertProductFundsEnabled();
$data = $request->all();
$wallet_interface = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type,null);
$wallet = $wallet_interface->wallet;
if($wallet->gold < $data['value']){
$productId = (int) ($data['product_id'] ?? 0);
if ($productId <= 0) {
throw new UnprocessableEntityHttpException('انتخاب محصول برای قلک الزامی است');
}
$product = Product::query()->find($productId);
if (! $product) {
throw new UnprocessableEntityHttpException('محصول یافت نشد');
}
$title = trim((string) ($data['title'] ?? ''));
if ($title === '') {
throw new UnprocessableEntityHttpException('عنوان قلک الزامی است');
}
$customerId = (int) auth('customer')->id();
$fund = Fund::create([
'title' => $title,
'file_id' => $data['file_id'] ?? null,
'customer_id' => $customerId,
'product_id' => $productId,
]);
// کیف قلک را از همان ابتدا با product_id بساز (بدون سند حسابداری)
new WalletInterface(
$customerId,
auth('customer')->user()->type,
$fund->id,
$productId
);
return response()->json($fund->load(['wallet', 'product']));
}
public function update(Request $request, $id)
{
$this->assertProductFundsEnabled();
$fund = $this->ownedFund((int) $id);
$title = trim((string) ($request->input('title') ?? $fund->title));
if ($title === '') {
throw new UnprocessableEntityHttpException('عنوان قلک الزامی است');
}
// product_id بعد از ساخت عوض نمی‌شود
$fund->update([
'title' => $title,
'file_id' => $request->input('file_id', $fund->file_id),
]);
return response()->json($fund->fresh(['wallet', 'product']));
}
public function deposit(Request $request)
{
$this->assertProductFundsEnabled();
$data = $request->all();
$fund = $this->ownedFund((int) ($data['fund_id'] ?? 0));
$value = (float) ($data['value'] ?? 0);
if ($value <= 0) {
throw new UnprocessableEntityHttpException('مقدار نامعتبر است');
}
$customer = auth('customer')->user();
$customerId = (int) $customer->id;
$ownerType = (int) $customer->type;
$productId = (int) ($fund->product_id ?? 0);
$balanceService = app(WalletBalanceService::class);
$free = $productId > 0
? $balanceService->freeProductGold($customerId, $productId, $ownerType)
: $balanceService->effectiveMainWalletGold($customerId, $ownerType);
if ($free < $value) {
throw new UnprocessableEntityHttpException('موجودی کمتر از مقدار وارد شده است');
}
$transaction = new TransactionInterface($wallet_interface, $_inp = [
"gold" => $data['value'],
"fund_id"=>$data["fund_id"],
'expire_at'=>now(),
'active'=>true
[$sourceFundId, $sourceProductId] = $this->sourceWalletKeys($productId);
$source = new WalletInterface($customerId, $ownerType, $sourceFundId, $sourceProductId);
$dest = new WalletInterface($customerId, $ownerType, $fund->id, $productId > 0 ? $productId : null);
// فقط جابه‌جایی داخلی — بدون Accounting*
new TransactionInterface($source, [
'gold' => $value,
'fund_id' => $fund->id,
'product_id' => $productId > 0 ? $productId : null,
'expire_at' => now(),
'active' => true,
], 6, false);
$wallet_interface_fund = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type,$data["fund_id"]);
$transaction = new TransactionInterface($wallet_interface_fund, $_inp = [
"gold" => $data['value'],
"fund_id"=>$data["fund_id"],
'expire_at'=>now(),
'active'=>true
new TransactionInterface($dest, [
'gold' => $value,
'fund_id' => $fund->id,
'product_id' => $productId > 0 ? $productId : null,
'expire_at' => now(),
'active' => true,
], 5, true);
return response()->json(true);
}
public function withdraw(Request $request){
$data = $request->all();
$wallet_interface_fund = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type,$data["fund_id"]);
$wallet = $wallet_interface_fund->wallet;
if($wallet->gold < $data['value']){
throw new UnprocessableEntityHttpException('موجودی کمتر از مقدار وارد شده است');
}
$transaction = new TransactionInterface($wallet_interface_fund, $_inp = [
"gold" => $data['value'],
"fund_id"=>$data["fund_id"],
'expire_at'=>now(),
'active'=>true
], 6, false);
$wallet_interface = new WalletInterface(auth('customer')->id(), auth('customer')->user()->type);
$transaction = new TransactionInterface($wallet_interface, $_inp = [
"gold" => $data['value'],
"fund_id"=>$data["fund_id"],
'expire_at'=>now(),
'active'=>true
], 5, true);
return response()->json(true);
}
public function show($id){
$query = Fund::with($this->with)->findOrFail($id);
return response()->json($query);
}
public function destroy($id){
$wallet_interface_fund = Wallet::where('owner',auth('customer')->id())->where('fund_id',$id)->first();
if (!is_null($wallet_interface_fund)){
if ($wallet_interface_fund->gold > 0){
throw new UnprocessableEntityHttpException('به علت داشتن موجودی امکان حذف صندوق وجود ندارد');
}
public function withdraw(Request $request)
{
$this->assertProductFundsEnabled();
$data = $request->all();
$fund = $this->ownedFund((int) ($data['fund_id'] ?? 0));
$value = (float) ($data['value'] ?? 0);
if ($value <= 0) {
throw new UnprocessableEntityHttpException('مقدار نامعتبر است');
}
Fund::destroy($id);
$customer = auth('customer')->user();
$customerId = (int) $customer->id;
$ownerType = (int) $customer->type;
$productId = (int) ($fund->product_id ?? 0);
$source = new WalletInterface($customerId, $ownerType, $fund->id, $productId > 0 ? $productId : null);
if ((float) $source->wallet->gold < $value) {
throw new UnprocessableEntityHttpException('موجودی کمتر از مقدار وارد شده است');
}
[$destFundId, $destProductId] = $this->sourceWalletKeys($productId);
$dest = new WalletInterface($customerId, $ownerType, $destFundId, $destProductId);
new TransactionInterface($source, [
'gold' => $value,
'fund_id' => $fund->id,
'product_id' => $productId > 0 ? $productId : null,
'expire_at' => now(),
'active' => true,
], 6, false);
new TransactionInterface($dest, [
'gold' => $value,
'fund_id' => $fund->id,
'product_id' => $productId > 0 ? $productId : null,
'expire_at' => now(),
'active' => true,
], 5, true);
return response()->json(true);
}
public function transactionTable(Request $request){
$records = Transaction::where('wallet',$request->wallet_id);
TableEngine::create($records, $request->all())
->initSearch([])
->select([
'*',Transaction::$SELECT_CAJ,Transaction::$SELECT_TYPE_STR
])->export($records);
return response()->json($records);
public function show($id)
{
$fund = $this->ownedFund((int) $id);
return response()->json($fund->load(['wallet', 'product']));
}
public function destroy($id)
{
$this->assertProductFundsEnabled();
$fund = $this->ownedFund((int) $id);
$wallet = Wallet::where('owner', auth('customer')->id())
->where('fund_id', $fund->id)
->first();
if ($wallet && (float) $wallet->gold > 0) {
throw new UnprocessableEntityHttpException('به علت داشتن موجودی امکان حذف قلک وجود ندارد');
}
Fund::destroy($fund->id);
return response()->json(true);
}
private function assertProductFundsEnabled(): void
{
if (! app(ConfigService::class)->isProductFundsEnabled()) {
throw new UnprocessableEntityHttpException('قابلیت قلک محصول غیرفعال است');
}
}
private function ownedFund(int $id): Fund
{
if ($id <= 0) {
throw new UnprocessableEntityHttpException('قلک نامعتبر است');
}
$fund = Fund::with(['wallet', 'product'])
->where('customer_id', auth('customer')->id())
->find($id);
if (! $fund) {
throw new UnprocessableEntityHttpException('قلک یافت نشد');
}
return $fund;
}
/** @return array{0: null, 1: int|null} */
private function sourceWalletKeys(int $productId): array
{
if ($productId <= 0) {
return [null, null];
}
if (app(ConfigService::class)->isMainWalletProduct($productId)) {
return [null, null];
}
return [null, $productId];
}
}
@@ -145,7 +145,16 @@ class WalletController extends Controller
},
'wallet.product',
'product',
])->whereIn('wallet', $walletIds)->whereNull('fund_id');
])->whereIn('wallet', $walletIds);
// جدول عمومی تراکنش‌ها: جابه‌جایی قلک را قاطی نکند؛ برای کیف قلک همهٔ ردیف‌ها بیاید
$includesFundWallet = Wallet::query()
->whereIn('id', $walletIds)
->whereNotNull('fund_id')
->exists();
if (! $includesFundWallet) {
$records->whereNull('fund_id');
}
TableEngine::create($records, $request->all())
->initSearch(['customer.name'])
@@ -323,9 +323,9 @@ class PargarInboundController extends Controller
$walletInterface = new WalletInterface($customer->id, $ownerType);
$wallet = $walletInterface->wallet;
// GoldInv پرگار فقط با طلای کیف اصلی مقایسه می‌شود — محصولات جدا سهمی ندارند
// GoldInv پرگار با جمع آزاد+قلک محصولات کیف اصلی مقایسه می‌شود (انتقال قلک سند نمی‌زند)
$appGold = app(WalletBalanceService::class)
->effectiveMainWalletGold((int) $customer->id, $ownerType);
->accountingVisibleMainWalletGold((int) $customer->id, $ownerType);
$appCash = (float) ($wallet->cash ?? 0);
$goldDiff = $goldInv - $appGold;
$rialDiff = $rialInv - $appCash;
+15 -2
View File
@@ -9,14 +9,27 @@ use Rooyesh\Wallet\models\Wallet;
class Fund extends Model
{
use HasFactory,Selector,SoftDeletes;
protected $fillable =[
use HasFactory, Selector, SoftDeletes;
protected $fillable = [
'title',
'file_id',
'customer_id',
'product_id',
];
public function wallet()
{
return $this->hasMany(Wallet::class);
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
public function customer()
{
return $this->belongsTo(Customer::class, 'customer_id');
}
}
+6
View File
@@ -747,6 +747,12 @@ class ConfigService
return $this->getBool('enable_conditional_order', false);
}
/** سوییچ دیپلوی قلک per-product (can_edit=0، پیش‌فرض خاموش). */
public function isProductFundsEnabled(): bool
{
return $this->getBool('enable_product_funds', false);
}
/**
* سوییچ اصلی جیبیت (can_edit=0، پیش‌فرض روشن).
* خاموش = هیچ فراخوانی احراز هویت به جیبیت انجام نمی‌شود.
+1 -1
View File
@@ -399,7 +399,7 @@ class PargarInboundWalletService
$wallet = $walletInterface->wallet;
$mainGold = app(WalletBalanceService::class)
->effectiveMainWalletGold((int) $customer->id, $ownerType);
->accountingVisibleMainWalletGold((int) $customer->id, $ownerType);
$goldDiff = $goldInv - $mainGold;
$rialDiff = $rialInv - (float) ($wallet->cash ?? 0);
+89
View File
@@ -77,6 +77,95 @@ class WalletBalanceService
return round($mainGold + $orphanedGold, 3);
}
/**
* طلای داخل قلک‌های یک محصول (یا همهٔ محصولات main_wallet اگر $productId=null و فقط main).
*/
public function fundGoldForProduct(int $ownerId, ?int $productId, ?int $ownerType = null): float
{
$query = Wallet::query()
->where('owner', $ownerId)
->whereNotNull('fund_id');
if ($ownerType !== null) {
$query->where('owner_type', $ownerType);
}
if ($productId === null) {
$query->whereNull('product_id');
} else {
$query->where('product_id', $productId);
}
return round((float) $query->sum('gold'), 3);
}
/**
* جمع طلای قلک‌های محصولات متصل به کیف اصلی (+ قلک‌های legacy بدون product_id).
*/
public function fundGoldForMainWalletProducts(int $ownerId, ?int $ownerType = null): float
{
$productIds = $this->mainWalletProductIds();
$query = Wallet::query()
->where('owner', $ownerId)
->whereNotNull('fund_id');
if ($ownerType !== null) {
$query->where('owner_type', $ownerType);
}
if ($productIds === []) {
$query->whereNull('product_id');
} else {
$query->where(function ($q) use ($productIds) {
$q->whereIn('product_id', $productIds)->orWhereNull('product_id');
});
}
return round((float) $query->sum('gold'), 3);
}
/**
* موجودی قابل‌مقایسه با حسابداری برای طلای کیف اصلی =
* آزاد (effectiveMain) + قلک‌های همان محصولات.
* برای معامله استفاده نشود — فقط sync/مانده.
*/
public function accountingVisibleMainWalletGold(int $ownerId, ?int $ownerType = null): float
{
return round(
$this->effectiveMainWalletGold($ownerId, $ownerType)
+ $this->fundGoldForMainWalletProducts($ownerId, $ownerType),
3
);
}
/**
* موجودی آزاد یک محصول (بدون قلک) — برای معامله و واریز به قلک.
*/
public function freeProductGold(int $ownerId, int $productId, ?int $ownerType = null): float
{
if ($this->configService->isMainWalletProduct($productId)) {
return $this->effectiveMainWalletGold($ownerId, $ownerType);
}
$query = Wallet::query()
->where('owner', $ownerId)
->whereNull('fund_id')
->where('product_id', $productId);
if ($ownerType !== null) {
$query->where('owner_type', $ownerType);
}
return round((float) $query->sum('gold'), 3);
}
/**
* جمع نمایشی دارایی یک محصول = آزاد + قلک‌های همان محصول.
*/
public function totalProductGold(int $ownerId, int $productId, ?int $ownerType = null): float
{
return round(
$this->freeProductGold($ownerId, $productId, $ownerType)
+ $this->fundGoldForProduct($ownerId, $productId, $ownerType),
3
);
}
/**
* جمع طلای قابل‌نمایش: کیف اصلی + کیف محصولات + قلک‌ها.
* کیف‌های legacy محصولات main_wallet_products شمرده نمی‌شوند.
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('funds')) {
return;
}
Schema::table('funds', function (Blueprint $table) {
if (! Schema::hasColumn('funds', 'product_id')) {
$table->unsignedBigInteger('product_id')->nullable()->after('customer_id');
$table->index('product_id');
}
});
}
public function down(): void
{
if (! Schema::hasTable('funds') || ! Schema::hasColumn('funds', 'product_id')) {
return;
}
Schema::table('funds', function (Blueprint $table) {
$table->dropIndex(['product_id']);
$table->dropColumn('product_id');
});
}
};
+10 -1
View File
@@ -399,6 +399,12 @@ SELECT 'enable_conditional_order', 'false', 'سفارش شرطی', 0, 1,
'switch'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'enable_conditional_order' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'enable_product_funds', 'false', 'قلک محصول', 0, 1,
'روشن: ساخت و مدیریت قلک per-product در اپ مشتری فعال است (یک محصول در هر قلک؛ انتقال بدون سند حسابداری). خاموش: منو و API ساخت قلک جدید در دسترس نیست. فقط از دیپلوی قابل تغییر است.',
'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_price_trigger', 'true', 'هشدار قیمت', 0, 1,
'روشن: منوی هشدار قیمت در اپ کاربر نمایش داده می‌شود. خاموش: منو و صفحه مخفی است. فقط از دیپلوی قابل تغییر است.',
@@ -1077,7 +1083,7 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
'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',
'enable_conditional_order',
'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',
'sms_notif_gateway_charge_admin', 'sms_notif_register_customer', 'sms_notif_register_admin',
@@ -1551,6 +1557,8 @@ UPDATE `settings` SET `title_fa` = 'پیامک تکی به مشتری از لی
UPDATE `settings` SET `description` = 'روشن: سرویس احراز هویت جیبیت (تطبیق کد ملی/موبایل و کارت بانکی) فعال است. خاموش: هیچ فراخوانی به جیبیت انجام نمی‌شود و احراز هویت خودکار کار نمی‌کند. فقط از صفحه دیپلوی قابل تغییر است.' WHERE `key` = 'jibit_enabled';
UPDATE `settings` SET `title_fa` = 'احراز هویت جیبیت' WHERE `key` = 'jibit_enabled';
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 `description` = 'روشن: امکان ارسال پیامک گروهی از پنل ادمین فعال است.' WHERE `key` = 'group_sms';
UPDATE `settings` SET `description` = 'روشن: پنل پیامک و کیف پول billing فعال است. خاموش: پیامک‌ها مثل قبل ارسال می‌شوند بدون billing.' WHERE `key` = 'sms_panel';
@@ -1805,6 +1813,7 @@ UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
'group_sms',
'customer_direct_sms',
'enable_conditional_order',
'enable_product_funds',
'has_page_price_trigger',
'has_page_notification',
'jibit_enabled',
@@ -354,6 +354,12 @@ SELECT 'enable_conditional_order', 'false', 'سفارش شرطی', 0, 1,
'switch'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'enable_conditional_order' LIMIT 1);
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
SELECT 'enable_product_funds', 'false', 'قلک محصول', 0, 1,
'روشن: ساخت و مدیریت قلک per-product در اپ مشتری فعال است (یک محصول در هر قلک؛ انتقال بدون سند حسابداری). خاموش: منو و API ساخت قلک جدید در دسترس نیست. فقط از دیپلوی قابل تغییر است.',
'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_price_trigger', 'true', 'هشدار قیمت', 0, 1,
'روشن: منوی هشدار قیمت در اپ کاربر نمایش داده می‌شود. خاموش: منو و صفحه مخفی است. فقط از دیپلوی قابل تغییر است.',
@@ -861,7 +867,7 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN (
'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',
'enable_conditional_order',
'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',
'sms_notif_gateway_charge_admin', 'sms_notif_register_customer', 'sms_notif_register_admin',
@@ -1333,6 +1339,9 @@ UPDATE `settings` SET `title_fa` = 'پیامک تکی به مشتری از لی
UPDATE `settings` SET `description` = 'روشن: سرویس احراز هویت جیبیت (تطبیق کد ملی/موبایل و کارت بانکی) فعال است. خاموش: هیچ فراخوانی به جیبیت انجام نمی‌شود و احراز هویت خودکار کار نمی‌کند. فقط از صفحه دیپلوی قابل تغییر است.' WHERE `key` = 'jibit_enabled';
UPDATE `settings` SET `title_fa` = 'احراز هویت جیبیت' WHERE `key` = 'jibit_enabled';
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 `can_edit` = 0 WHERE `key` = 'enable_product_funds';
UPDATE `settings` SET `description` = 'روشن: بعد از شارژ یا کسر کیف توسط ادمین، پیامک به مشتری و ادمین‌های دارای «ارسال پیامک» می‌رود. خاموش: هیچ‌کدام ارسال نمی‌شود.' WHERE `key` = 'charge_notif';
UPDATE `settings` SET `description` = 'روشن: بعد از خرید یا فروش موفق، پیامک خلاصه معامله به ادمین‌های دارای «ارسال پیامک» می‌رود. خاموش: ادمین پیامک معامله نمی‌گیرد.' WHERE `key` = 'sms_notif_order_admin';
UPDATE `settings` SET `description` = 'روشن: بعد از خرید یا فروش موفق، پیامک رسید به مشتری می‌رود. خاموش: مشتری پیامک معامله نمی‌گیرد.' WHERE `key` = 'sms_notif_order_customer';
@@ -1401,6 +1410,7 @@ UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
'group_sms',
'customer_direct_sms',
'enable_conditional_order',
'enable_product_funds',
'has_page_price_trigger',
'has_page_notification',
'jibit_enabled',
+4
View File
@@ -118,6 +118,10 @@ Route::middleware('auth:user')->group(function (){
Route::get('/customer/list',[CustomerController::class,'listUser']);
Route::post('/customers/{customer_id}/referrals',[CustomerController::class,'referrals']);
Route::post('/customers/{customer_id}/funds',[CustomerController::class,'funds']);
Route::post('/customers/{customer_id}/piggy-funds',[CustomerController::class,'piggyFunds']);
Route::post('/customers/{customer_id}/assets/{product_id}/piggy-funds',[CustomerController::class,'assetPiggyFunds']);
Route::post('/customers/{customer_id}/assets/{product_id}/transactions',[CustomerController::class,'assetTransactions']);
Route::post('/customers/{customer_id}/piggy-funds/{fund_id}/transactions',[CustomerController::class,'piggyFundTransactions']);
Route::put('/customer/{id}',[CustomerController::class,'updateAdmin']);
Route::resource('/customer', CustomerController::class)->except(['update']);