From b5b39ffc3710f962919193c7b3b32acae0b9b8b1 Mon Sep 17 00:00:00 2001 From: adonis Date: Thu, 23 Jul 2026 11:09:31 +0330 Subject: [PATCH] fix borcecu edits --- .../Controllers/Admin/DashboardController.php | 185 +++++++++++++++--- 1 file changed, 153 insertions(+), 32 deletions(-) diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php index 28cedf1..360c28f 100644 --- a/app/Http/Controllers/Admin/DashboardController.php +++ b/app/Http/Controllers/Admin/DashboardController.php @@ -302,6 +302,34 @@ class DashboardController extends Controller } + /** + * محصول مقداری/آبشده‌ای که کارمزد مبلغ‌محور از کیف همان محصول کسر می‌شود. + * (trade_by_quantity یا دسته آبشده/کاتد؛ مفتول مس هم اگر مقداری باشد.) + */ + private function isQuantityProfitProduct(?Product $product): bool + { + if (!$product) { + return false; + } + + $payload = self::productUnitPayload($product); + if (self::usesQuantityTrade($payload)) { + return true; + } + + if (self::isMeltedTradeGroup($payload['group_type'] ?? null)) { + return true; + } + + // مفتول مس در لیست تعدادی قدیمی است؛ اگر واحد وزنی دارد در سود مقداری بیاید + $group = trim((string) ($payload['group_type'] ?? '')); + if ($group === 'مفتول مس' && self::isWeightBasedProductUnit($payload['unit'] ?? null)) { + return true; + } + + return !self::isCountBasedProduct($payload); + } + public function finance(Request $request) { $startDate = $request->startDate ? Carbon::parse($request->startDate)->startOfDay() : Carbon::now()->subDays(30)->startOfDay(); @@ -309,7 +337,13 @@ class DashboardController extends Controller // Fetch orders and transactions within the date range - $ords = Order::whereBetween('created_at', [$startDate, $endDate])->get(); + $productSelect = ['id', 'title', 'group_type', 'unit', 'amount', 'trade_by_quantity', 'direct_price']; + if (Product::hasStoredPriceColumns()) { + $productSelect[] = 'price'; + } + $ords = Order::with(['product' => function ($q) use ($productSelect) { + $q->withTrashed()->select($productSelect); + }])->whereBetween('created_at', [$startDate, $endDate])->get(); $TransactionsAdmin = TransactionsAdmin::whereBetween('created_at', [$startDate, $endDate])->get(); // Initialize response data @@ -323,9 +357,11 @@ class DashboardController extends Controller "GiftsPrise" => 0, "sumAll" => 0, // تفکیک سود بر اساس سمت کسر کارمزد - "profitGoldGrams" => 0, // سود طلایی: مجموع کارمزدهای کسرشده از طلا (گرم) + "profitGoldGrams" => 0, // سود طلایی/فلزی: مجموع کارمزدهای کسرشده از فلز (گرم) "profitRial" => 0, // سود ریالی: مجموع کارمزدهای کسرشده از ریال (ریال) "profitGoldValueRial" => 0, + /** @var array */ + "profitQuantityProducts" => [], "daily" => [], ]; @@ -338,6 +374,10 @@ class DashboardController extends Controller $lastGoldPrice = (float) (Price::latest()->first()?->price ?? 0); $response['GiftsPrise'] = $lastGoldPrice > 0 ? (int) floor($giftsGold * $lastGoldPrice) : 0; + + /** @var array $quantityBuckets */ + $quantityBuckets = []; + // Calculate order-related sums $daily = []; foreach ($ords as $ord) { @@ -346,8 +386,8 @@ class DashboardController extends Controller $response['fullPriceSood'] += $ord->total_fee; $response['fullPriceKarmozd'] += $ord->service_charge_price; - // تفکیک کارمزد به طلا/ریال بر اساس سمت کسر - // fee_asset === 'gold' → کارمزد از طلا گرفته شده (گرم)؛ در غیر این صورت ریالی محسوب می‌شود. + // تفکیک کارمزد به فلز/ریال بر اساس سمت کسر + // fee_asset === 'gold' → کارمزد از فلز/آبشده گرفته شده (گرم)؛ در غیر این صورت ریالی محسوب می‌شود. $feeFromGold = $ord->fee_asset === 'gold'; $goldFeeGrams = $feeFromGold ? (float) $ord->service_charge : 0.0; $rialFee = $feeFromGold ? 0.0 : (float) $ord->service_charge_price; @@ -355,6 +395,30 @@ class DashboardController extends Controller $response['profitGoldGrams'] += $goldFeeGrams; $response['profitRial'] += $rialFee; + $product = $ord->product; + $productId = (int) ($ord->product_id ?? 0); + if ($feeFromGold && $goldFeeGrams > 0 && $this->isQuantityProfitProduct($product)) { + $payload = self::productUnitPayload($product); + $bucketKey = (string) $productId; + if (!isset($quantityBuckets[$bucketKey])) { + $unitPrice = Product::hasStoredPriceColumns() + ? (float) ($product->price ?? 0) + : 0.0; + if ($unitPrice <= 0) { + $unitPrice = $lastGoldPrice; + } + $quantityBuckets[$bucketKey] = [ + 'product_id' => $productId, + 'title' => (string) ($product->title ?? ('محصول #' . $productId)), + 'group_type' => $product->group_type ?? null, + 'grams' => 0.0, + 'unit_price' => $unitPrice, + 'unit' => self::productQuantityUnit($payload), + ]; + } + $quantityBuckets[$bucketKey]['grams'] += $goldFeeGrams; + } + $dateKey = $ord->created_at ? Carbon::parse($ord->created_at)->toDateString() : 'نامشخص'; if (!isset($daily[$dateKey])) { $daily[$dateKey] = [ @@ -363,46 +427,66 @@ class DashboardController extends Controller 'profit_rial' => 0.0, // ریال (کارمزد ریالی) 'spread_rial' => 0.0, // سود اختلاف قیمت (ریال) 'order_count' => 0, + 'profit_by_product' => [], ]; } $daily[$dateKey]['profit_gold'] += $goldFeeGrams; $daily[$dateKey]['profit_rial'] += $rialFee; $daily[$dateKey]['spread_rial'] += (float) $ord->total_fee; $daily[$dateKey]['order_count']++; + + if ($feeFromGold && $goldFeeGrams > 0 && $this->isQuantityProfitProduct($product) && $productId > 0) { + $pidKey = (string) $productId; + if (!isset($daily[$dateKey]['profit_by_product'][$pidKey])) { + $daily[$dateKey]['profit_by_product'][$pidKey] = [ + 'product_id' => $productId, + 'title' => (string) ($product->title ?? ('محصول #' . $productId)), + 'grams' => 0.0, + ]; + } + $daily[$dateKey]['profit_by_product'][$pidKey]['grams'] += $goldFeeGrams; + } } $response['profitGoldGrams'] = round($response['profitGoldGrams'], 4); - // سندهای تبدیل سود ریالی به طلا: از سود ریالی کم و به سود طلایی (گرم) اضافه می‌شود. - $conversions = ProfitConversion::whereBetween('converted_at', [$startDate, $endDate])->get(); + // سندهای تبدیل سود ریالی به طلا — فقط برای فلز اصلی طلا معنا دارد + $mainMetal = trim((string) self::Config('main_metal')); + $applyProfitConversions = $mainMetal === '' || $mainMetal === 'طلا'; + $convertedRial = 0.0; $convertedGram = 0.0; - foreach ($conversions as $conversion) { - $rialAmount = (float) $conversion->rial_amount; - $gramAmount = (float) $conversion->gram_amount; - $convertedRial += $rialAmount; - $convertedGram += $gramAmount; + if ($applyProfitConversions) { + $conversions = ProfitConversion::whereBetween('converted_at', [$startDate, $endDate])->get(); - $dateKey = $conversion->converted_at - ? Carbon::parse($conversion->converted_at)->toDateString() - : null; - if (!$dateKey) { - continue; + foreach ($conversions as $conversion) { + $rialAmount = (float) $conversion->rial_amount; + $gramAmount = (float) $conversion->gram_amount; + $convertedRial += $rialAmount; + $convertedGram += $gramAmount; + + $dateKey = $conversion->converted_at + ? Carbon::parse($conversion->converted_at)->toDateString() + : null; + if (!$dateKey) { + continue; + } + + if (!isset($daily[$dateKey])) { + $daily[$dateKey] = [ + 'date' => $dateKey, + 'profit_gold' => 0.0, + 'profit_rial' => 0.0, + 'spread_rial' => 0.0, + 'order_count' => 0, + 'profit_by_product' => [], + ]; + } + + $daily[$dateKey]['profit_rial'] -= $rialAmount; + $daily[$dateKey]['profit_gold'] += $gramAmount; } - - if (!isset($daily[$dateKey])) { - $daily[$dateKey] = [ - 'date' => $dateKey, - 'profit_gold' => 0.0, - 'profit_rial' => 0.0, - 'spread_rial' => 0.0, - 'order_count' => 0, - ]; - } - - $daily[$dateKey]['profit_rial'] -= $rialAmount; - $daily[$dateKey]['profit_gold'] += $gramAmount; } $response['profitRialGross'] = $response['profitRial']; @@ -412,14 +496,51 @@ class DashboardController extends Controller $response['profitRial'] = round($response['profitRial'] - $convertedRial, 0); $response['profitGoldGrams'] = round($response['profitGoldGrams'] + $convertedGram, 4); - $response['profitGoldValueRial'] = $lastGoldPrice > 0 - ? (int) floor($response['profitGoldGrams'] * $lastGoldPrice) - : 0; + + $quantityProducts = []; + $quantityValueRial = 0; + foreach ($quantityBuckets as $bucket) { + $grams = round($bucket['grams'], 4); + $unitPrice = (float) $bucket['unit_price']; + $valueRial = $unitPrice > 0 ? (int) floor($grams * $unitPrice) : 0; + $quantityValueRial += $valueRial; + $quantityProducts[] = [ + 'product_id' => $bucket['product_id'], + 'title' => $bucket['title'], + 'group_type' => $bucket['group_type'], + 'grams' => $grams, + 'value_rial' => $valueRial, + 'unit' => $bucket['unit'], + ]; + } + usort($quantityProducts, function ($a, $b) { + return $b['grams'] <=> $a['grams']; + }); + $response['profitQuantityProducts'] = $quantityProducts; + + // ارزش ریالی: اگر تفکیک مقداری داریم از جمع همان‌ها (+تبدیل)، وگرنه مظنهٔ کلی + if (count($quantityProducts) > 0) { + $convertedValue = $lastGoldPrice > 0 ? (int) floor($convertedGram * $lastGoldPrice) : 0; + $response['profitGoldValueRial'] = $quantityValueRial + $convertedValue; + } else { + $response['profitGoldValueRial'] = $lastGoldPrice > 0 + ? (int) floor($response['profitGoldGrams'] * $lastGoldPrice) + : 0; + } krsort($daily); $response['daily'] = array_map(function ($row) { $row['profit_gold'] = round($row['profit_gold'], 4); $row['profit_rial'] = round($row['profit_rial'], 0); + $byProduct = array_values($row['profit_by_product'] ?? []); + foreach ($byProduct as &$p) { + $p['grams'] = round($p['grams'], 4); + } + unset($p); + usort($byProduct, function ($a, $b) { + return $b['grams'] <=> $a['grams']; + }); + $row['profit_by_product'] = $byProduct; return $row; }, array_values($daily));