fix some handling 2
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\DB\Te\TableEngine;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Address;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\Price;
|
||||
@@ -21,6 +22,7 @@ use App\Http\Controllers\Admin\TahesabController;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\TransactionsAdmin;
|
||||
use App\Services\AssetSummaryService;
|
||||
use App\Services\BalanceReportService;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\WalletBalanceService;
|
||||
@@ -623,6 +625,266 @@ class WalletController extends Controller
|
||||
return response()->json($withdraw);
|
||||
}
|
||||
|
||||
public function indexPhysicalWithdraw(Request $request)
|
||||
{
|
||||
$records = Withdraw::with(['customer', 'Address', 'Transaction.product']);
|
||||
Withdraw::scopePhysicalWithdrawals($records);
|
||||
|
||||
TableEngine::create($records, $request->all())
|
||||
->initSearch(['customer.name', 'customer.mobile'])
|
||||
->select([
|
||||
'*', Withdraw::$SELECT_STS_STR, Withdraw::$SELECT_DAJ
|
||||
])->export($records);
|
||||
|
||||
return response()->json($records);
|
||||
}
|
||||
|
||||
public function physicalWithdrawOptions($customerId, AssetSummaryService $assetSummaryService)
|
||||
{
|
||||
$customer = Customer::findOrFail($customerId);
|
||||
$summary = $assetSummaryService->buildForCustomer((int) $customer->id, (int) $customer->type);
|
||||
$inventoryByProduct = collect($summary['inventory_cards'] ?? [])->keyBy('product_id');
|
||||
$configService = app(ConfigService::class);
|
||||
$mainWalletProductIds = $configService->mainWalletProductIds();
|
||||
|
||||
$products = Product::where(function ($query) use ($customer, $mainWalletProductIds) {
|
||||
$query->whereHas('wallet', function ($q) use ($customer) {
|
||||
$q->where('owner', $customer->id);
|
||||
});
|
||||
if ($mainWalletProductIds !== []) {
|
||||
$query->orWhereIn('id', $mainWalletProductIds);
|
||||
}
|
||||
})->with(['wallet' => function ($query) use ($customer) {
|
||||
$query->where('owner', $customer->id);
|
||||
}])->get();
|
||||
|
||||
$representativeId = null;
|
||||
if ($mainWalletProductIds !== []) {
|
||||
foreach ($mainWalletProductIds as $pid) {
|
||||
if ($products->firstWhere('id', $pid)) {
|
||||
$representativeId = (int) $pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$products = $products->filter(function ($product) use ($mainWalletProductIds, $representativeId) {
|
||||
if (in_array((int) $product->id, array_map('intval', $mainWalletProductIds), true)) {
|
||||
return (int) $product->id === $representativeId;
|
||||
}
|
||||
|
||||
return true;
|
||||
})->values();
|
||||
}
|
||||
|
||||
$productRows = $products->map(function ($product) use ($customer, $assetSummaryService, $inventoryByProduct, $representativeId) {
|
||||
$card = $inventoryByProduct->get((int) $product->id);
|
||||
$displayQty = $card !== null ? (float) ($card['quantity'] ?? 0) : 0.0;
|
||||
|
||||
$walletInterface = new WalletInterface(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
null,
|
||||
$assetSummaryService->effectiveProductWalletIdForCustomer(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
(int) $product->id
|
||||
)
|
||||
);
|
||||
$wallet = $walletInterface->wallet;
|
||||
if (!$wallet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'product_id' => (int) $product->id,
|
||||
'title' => (string) $product->title,
|
||||
'wallet_id' => (int) $wallet->id,
|
||||
'available' => $displayQty,
|
||||
'unit' => self::productQuantityUnit([
|
||||
'unit' => $product->unit ?? null,
|
||||
'direct_price' => $product->direct_price ?? null,
|
||||
'group_type' => $product->group_type ?? null,
|
||||
]),
|
||||
'is_main_wallet' => $representativeId !== null && (int) $product->id === $representativeId,
|
||||
];
|
||||
})->filter(function ($row) {
|
||||
return $row !== null && ($row['available'] ?? 0) > 0 && $row['title'] !== 'آبشده نقدی';
|
||||
})->values();
|
||||
|
||||
$addresses = Address::query()
|
||||
->where('customer_id', $customer->id)
|
||||
->orderByDesc('default_address')
|
||||
->orderByDesc('id')
|
||||
->get(['id', 'province', 'city', 'address', 'phone', 'zip', 'default_address']);
|
||||
|
||||
return response()->json([
|
||||
'products' => $productRows,
|
||||
'addresses' => $addresses,
|
||||
]);
|
||||
}
|
||||
|
||||
public function createPhysicalWithdraw(Request $request, AssetSummaryService $assetSummaryService)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'customer_id' => 'required|integer|exists:customers,id',
|
||||
'address_id' => 'required|integer|exists:addresses,id',
|
||||
'wallets' => 'required|array|min:1',
|
||||
'wallets.*.wallet_id' => 'required|integer|exists:wallets,id',
|
||||
'wallets.*.value' => 'required|numeric|min:0.0001',
|
||||
]);
|
||||
|
||||
$customer = Customer::findOrFail($data['customer_id']);
|
||||
$address = Address::find($data['address_id']);
|
||||
if (!$address || (int) $address->customer_id !== (int) $customer->id) {
|
||||
return response()->json(['message' => 'آدرس معتبر نیست یا متعلق به این مشتری نمیباشد'], 403);
|
||||
}
|
||||
|
||||
$withdraw = DB::transaction(function () use ($data, $customer, $address, $assetSummaryService) {
|
||||
$withdraw = new Withdraw();
|
||||
$withdraw->note = 'برداشت فیزیکی';
|
||||
$withdraw->address_id = $address->id;
|
||||
$withdraw->customer_id = $customer->id;
|
||||
$withdraw->user_id = auth('user')->id();
|
||||
$withdraw->sts = 50;
|
||||
$withdraw->save();
|
||||
|
||||
foreach ($data['wallets'] as $walletRow) {
|
||||
$wallet = Wallet::with('product')->findOrFail($walletRow['wallet_id']);
|
||||
if ((int) $wallet->owner !== (int) $customer->id) {
|
||||
throw new UnprocessableEntityHttpException('کیف پول انتخابشده متعلق به این مشتری نیست');
|
||||
}
|
||||
if (!$wallet->product) {
|
||||
throw new UnprocessableEntityHttpException('محصولی در کیف پول مورد نظر یافت نشد');
|
||||
}
|
||||
|
||||
$productId = (int) $wallet->product_id;
|
||||
$value = (float) $walletRow['value'];
|
||||
$effectiveProductId = $assetSummaryService->effectiveProductWalletIdForCustomer(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
$productId
|
||||
);
|
||||
$availableGold = $assetSummaryService->productDisplayQuantity(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
$productId
|
||||
);
|
||||
|
||||
if ($value > $availableGold) {
|
||||
throw new UnprocessableEntityHttpException(
|
||||
"مشتری به اندازه کافی از {$wallet->product->title} ندارد"
|
||||
);
|
||||
}
|
||||
|
||||
$walletInterface = new WalletInterface(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
null,
|
||||
$effectiveProductId
|
||||
);
|
||||
|
||||
new TransactionInterface($walletInterface, [
|
||||
'gold' => $value,
|
||||
'number' => (float) $wallet->product->amount * $value,
|
||||
'product_id' => $wallet->product->id,
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
'title' => " برداشت {$wallet->product->title}",
|
||||
'note' => " برداشت محصول {$wallet->product->title} شماره سند {$withdraw->id}",
|
||||
'withdraw_id' => $withdraw->id,
|
||||
], 6, false);
|
||||
}
|
||||
|
||||
return $withdraw;
|
||||
});
|
||||
|
||||
$this->broadcastCustomerWalletAssets($customer);
|
||||
|
||||
return response()->json(['id' => $withdraw->id]);
|
||||
}
|
||||
|
||||
public function adjustPhysicalWithdraw(Request $request, $id, AssetSummaryService $assetSummaryService)
|
||||
{
|
||||
$payload = $request->validate([
|
||||
'transaction_id' => 'required|integer|exists:transactions,id',
|
||||
'direction' => 'required|in:increase,decrease',
|
||||
]);
|
||||
|
||||
$withdraw = Withdraw::with(['Transaction.product'])->findOrFail($id);
|
||||
if (!Withdraw::isPhysicalWithdrawNote($withdraw->note)) {
|
||||
return response()->json(['message' => 'این سند برداشت فیزیکی نیست'], 422);
|
||||
}
|
||||
if ((int) $withdraw->sts !== 50) {
|
||||
return response()->json(['message' => 'تغییر مقدار فقط در وضعیت «در انتظار ارسال» مجاز است'], 422);
|
||||
}
|
||||
|
||||
$transaction = Transaction::with('product')->findOrFail($payload['transaction_id']);
|
||||
if ((int) $transaction->withdraw_id !== (int) $withdraw->id) {
|
||||
return response()->json(['message' => 'تراکنش به این سند تعلق ندارد'], 422);
|
||||
}
|
||||
|
||||
$product = $transaction->product;
|
||||
if (!$product) {
|
||||
return response()->json(['message' => 'محصول تراکنش یافت نشد'], 422);
|
||||
}
|
||||
|
||||
$step = 1.0;
|
||||
$currentUnits = abs((float) $transaction->gold);
|
||||
$direction = $payload['direction'];
|
||||
|
||||
if ($direction === 'decrease' && $currentUnits <= $step) {
|
||||
return response()->json(['message' => 'حداقل مقدار قابل برداشت یک واحد است'], 422);
|
||||
}
|
||||
|
||||
$customer = Customer::findOrFail($withdraw->customer_id);
|
||||
$effectiveProductId = $assetSummaryService->effectiveProductWalletIdForCustomer(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
(int) $product->id
|
||||
);
|
||||
$walletInterface = new WalletInterface(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
null,
|
||||
$effectiveProductId
|
||||
);
|
||||
$wallet = $walletInterface->wallet;
|
||||
if (!$wallet) {
|
||||
return response()->json(['message' => 'کیف پول مشتری یافت نشد'], 422);
|
||||
}
|
||||
|
||||
if ($direction === 'increase') {
|
||||
$available = $assetSummaryService->productDisplayQuantity(
|
||||
(int) $customer->id,
|
||||
(int) $customer->type,
|
||||
(int) $product->id
|
||||
);
|
||||
if ($available < $step) {
|
||||
return response()->json(['message' => "موجودی {$product->title} کافی نیست"], 422);
|
||||
}
|
||||
|
||||
$wallet->gold -= $step;
|
||||
$transaction->gold = -($currentUnits + $step);
|
||||
$transaction->number = (float) $transaction->number + ((float) $product->amount * $step);
|
||||
} else {
|
||||
$wallet->gold += $step;
|
||||
$transaction->gold = -($currentUnits - $step);
|
||||
$transaction->number = max(0, (float) $transaction->number - ((float) $product->amount * $step));
|
||||
}
|
||||
|
||||
$transaction->balance_gold = $wallet->gold;
|
||||
$wallet->save();
|
||||
$transaction->save();
|
||||
$walletInterface->set_hash();
|
||||
|
||||
$this->broadcastCustomerWalletAssets($customer);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'مقدار برداشت بهروزرسانی شد',
|
||||
'transaction' => $transaction->fresh('product'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function completeWithdraw(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
|
||||
@@ -34,6 +34,7 @@ class Withdraw extends Model
|
||||
50 => 'در انتظار ارسال',
|
||||
51 => 'ارسال شده',
|
||||
52 => 'لغو شده',
|
||||
53 => 'در انتظار تعیین مجدد قیمت',
|
||||
];
|
||||
|
||||
public function customer()
|
||||
@@ -56,6 +57,18 @@ class Withdraw extends Model
|
||||
return $this->hasOne('App\Models\BankAccount', 'id', 'bank_account_id');
|
||||
}
|
||||
|
||||
/** برداشت فیزیکی — درخواست تحویل محصول */
|
||||
public static function scopePhysicalWithdrawals($query)
|
||||
{
|
||||
return $query->where('note', 'like', '%برداشت فیزیکی%')
|
||||
->whereBetween('sts', [49, 70]);
|
||||
}
|
||||
|
||||
public static function isPhysicalWithdrawNote(?string $note): bool
|
||||
{
|
||||
return $note !== null && str_contains($note, 'برداشت فیزیکی');
|
||||
}
|
||||
|
||||
public static function applyFlowFilter($query, ?string $flowType = 'all')
|
||||
{
|
||||
if (!$flowType || $flowType === 'all') {
|
||||
|
||||
@@ -122,6 +122,10 @@ Route::middleware('auth:user')->group(function (){
|
||||
Route::put('/wallet/withdraw/{id}',[WalletController::class,'updateWithdraw']);
|
||||
Route::get('/wallet/withdraw/{id}',[WalletController::class,'getWithdraw']);
|
||||
Route::post('/wallet/withdraw/complete',[WalletController::class,'completeWithdraw']);
|
||||
Route::post('/wallet/withdraw_physical/table',[WalletController::class,'indexPhysicalWithdraw']);
|
||||
Route::get('/wallet/withdraw_physical/options/{customerId}',[WalletController::class,'physicalWithdrawOptions']);
|
||||
Route::post('/wallet/withdraw_physical',[WalletController::class,'createPhysicalWithdraw']);
|
||||
Route::post('/wallet/withdraw_physical/{id}/adjust',[WalletController::class,'adjustPhysicalWithdraw']);
|
||||
|
||||
//---------------order
|
||||
Route::post('order/table', [OrderController::class, 'table']);
|
||||
|
||||
Reference in New Issue
Block a user