[PROMOTE] 晉升 dev 到 demo
1. [FIX] 修正商品與機台報表因 order_items 與 dispense_records 聯結產生笛卡爾積導致件數重複加總的問題
This commit is contained in:
commit
b8fea39e2b
@ -99,6 +99,15 @@ class AnalysisController extends Controller
|
||||
42 => __('Pickup Voucher'),
|
||||
];
|
||||
|
||||
// 子查詢:取得每個 order_id + product_id 的銷售單價
|
||||
$itemPriceQuery = \Illuminate\Support\Facades\DB::table('order_items')
|
||||
->select([
|
||||
'order_id',
|
||||
'product_id',
|
||||
\Illuminate\Support\Facades\DB::raw('MIN(price) as unit_price')
|
||||
])
|
||||
->groupBy('order_id', 'product_id');
|
||||
|
||||
// 6. 執行主報表統計 SQL (按機台分組)
|
||||
// 子查詢 A:營業額 (計算機台實收)
|
||||
$salesQuery = \Illuminate\Support\Facades\DB::table('orders as o')
|
||||
@ -130,16 +139,18 @@ class AnalysisController extends Controller
|
||||
|
||||
// 如果篩選特定商品,營業額只計算有成功出貨的該商品金額
|
||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||
$salesQuery->join('order_items as oi', 'oi.order_id', '=', 'o.id')
|
||||
->leftJoin('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
||||
->on('dr.product_id', '=', 'oi.product_id')
|
||||
$salesQuery->join('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'o.id')
|
||||
->where('dr.dispense_status', '=', 1);
|
||||
})
|
||||
->where('oi.product_id', $selectedProductId)
|
||||
->leftJoinSub($itemPriceQuery, 'oi', function($join) {
|
||||
$join->on('oi.order_id', '=', 'dr.order_id')
|
||||
->on('oi.product_id', '=', 'dr.product_id');
|
||||
})
|
||||
->where('dr.product_id', $selectedProductId)
|
||||
->select([
|
||||
'o.machine_id',
|
||||
\Illuminate\Support\Facades\DB::raw('SUM(CASE WHEN dr.id IS NOT NULL THEN oi.subtotal ELSE 0 END) as total_sales')
|
||||
\Illuminate\Support\Facades\DB::raw('SUM(COALESCE(oi.unit_price, 0)) as total_sales')
|
||||
]);
|
||||
}
|
||||
$salesQuery->groupBy('o.machine_id');
|
||||
@ -269,16 +280,18 @@ class AnalysisController extends Controller
|
||||
|
||||
// 如果篩選特定商品,營業額只計算有成功出貨的商品價格
|
||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||
$trendSalesQuery->join('order_items as oi', 'oi.order_id', '=', 'o.id')
|
||||
->leftJoin('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
||||
->on('dr.product_id', '=', 'oi.product_id')
|
||||
$trendSalesQuery->join('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'o.id')
|
||||
->where('dr.dispense_status', '=', 1);
|
||||
})
|
||||
->where('oi.product_id', $selectedProductId)
|
||||
->leftJoinSub($itemPriceQuery, 'oi', function($join) {
|
||||
$join->on('oi.order_id', '=', 'dr.order_id')
|
||||
->on('oi.product_id', '=', 'dr.product_id');
|
||||
})
|
||||
->where('dr.product_id', $selectedProductId)
|
||||
->select([
|
||||
\Illuminate\Support\Facades\DB::raw("DATE_FORMAT(o.created_at, '%Y-%m-%d') as date"),
|
||||
\Illuminate\Support\Facades\DB::raw('SUM(CASE WHEN dr.id IS NOT NULL THEN oi.subtotal ELSE 0 END) as total_sales')
|
||||
\Illuminate\Support\Facades\DB::raw('SUM(COALESCE(oi.unit_price, 0)) as total_sales')
|
||||
]);
|
||||
}
|
||||
$trendSalesQuery->groupBy('date');
|
||||
@ -449,24 +462,35 @@ class AnalysisController extends Controller
|
||||
$products = $productsQuery->active()->get(['id', 'name', 'barcode']);
|
||||
|
||||
// 5. 執行主報表統計 SQL
|
||||
// 計算各商品的銷售數量、銷售額、總成本、利潤
|
||||
$mainQuery = \Illuminate\Support\Facades\DB::table('order_items as oi')
|
||||
->join('orders as o', 'o.id', '=', 'oi.order_id')
|
||||
->leftJoin('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
||||
->on('dr.product_id', '=', 'oi.product_id')
|
||||
->where('dr.dispense_status', '=', 1);
|
||||
})
|
||||
->leftJoin('products as p', 'p.id', '=', 'oi.product_id')
|
||||
// 子查詢:取得每個 order_id + product_id 的銷售單價與品名
|
||||
$itemPriceQuery = \Illuminate\Support\Facades\DB::table('order_items')
|
||||
->select([
|
||||
'oi.product_id',
|
||||
'order_id',
|
||||
'product_id',
|
||||
\Illuminate\Support\Facades\DB::raw('MIN(price) as unit_price'),
|
||||
\Illuminate\Support\Facades\DB::raw('MIN(barcode) as barcode'),
|
||||
\Illuminate\Support\Facades\DB::raw('MIN(product_name) as product_name')
|
||||
])
|
||||
->groupBy('order_id', 'product_id');
|
||||
|
||||
// 計算各商品的銷售數量、銷售額、總成本、利潤 (以出貨成功為主體)
|
||||
$mainQuery = \Illuminate\Support\Facades\DB::table('dispense_records as dr')
|
||||
->join('orders as o', 'o.id', '=', 'dr.order_id')
|
||||
->leftJoinSub($itemPriceQuery, 'oi', function($join) {
|
||||
$join->on('oi.order_id', '=', 'dr.order_id')
|
||||
->on('oi.product_id', '=', 'dr.product_id');
|
||||
})
|
||||
->leftJoin('products as p', 'p.id', '=', 'dr.product_id')
|
||||
->select([
|
||||
'dr.product_id',
|
||||
\Illuminate\Support\Facades\DB::raw('COALESCE(p.barcode, oi.barcode) as barcode'),
|
||||
\Illuminate\Support\Facades\DB::raw('COALESCE(p.name, oi.product_name) as name'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN 1 ELSE 0 END) as SIGNED) as total_quantity'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN oi.price ELSE 0 END) as DECIMAL(10,2)) as total_sales'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN COALESCE(p.cost, 0) ELSE 0 END) as DECIMAL(10,2)) as total_cost'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST((SUM(CASE WHEN dr.id IS NOT NULL THEN oi.price ELSE 0 END) - SUM(CASE WHEN dr.id IS NOT NULL THEN COALESCE(p.cost, 0) ELSE 0 END)) as DECIMAL(10,2)) as total_profit')
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(COUNT(dr.id) as SIGNED) as total_quantity'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(COALESCE(oi.unit_price, 0)) as DECIMAL(10,2)) as total_sales'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(COALESCE(p.cost, 0)) as DECIMAL(10,2)) as total_cost'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST((SUM(COALESCE(oi.unit_price, 0)) - SUM(COALESCE(p.cost, 0))) as DECIMAL(10,2)) as total_profit')
|
||||
])
|
||||
->where('dr.dispense_status', 1)
|
||||
->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS)
|
||||
->whereNull('o.deleted_at')
|
||||
->whereBetween('o.created_at', [$startDate, $endDate]);
|
||||
@ -492,10 +516,10 @@ class AnalysisController extends Controller
|
||||
|
||||
// 套用特定商品篩選
|
||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||
$mainQuery->where('oi.product_id', $selectedProductId);
|
||||
$mainQuery->where('dr.product_id', $selectedProductId);
|
||||
}
|
||||
|
||||
$mainQuery->groupBy('oi.product_id')
|
||||
$mainQuery->groupBy('dr.product_id')
|
||||
->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(p.barcode, oi.barcode)'))
|
||||
->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(p.name, oi.product_name)'));
|
||||
$tableData = $mainQuery->get();
|
||||
@ -526,20 +550,20 @@ class AnalysisController extends Controller
|
||||
];
|
||||
|
||||
// 7. 圖表日走勢統計 SQL
|
||||
$trendQuery = \Illuminate\Support\Facades\DB::table('order_items as oi')
|
||||
->join('orders as o', 'o.id', '=', 'oi.order_id')
|
||||
->leftJoin('dispense_records as dr', function($join) {
|
||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
||||
->on('dr.product_id', '=', 'oi.product_id')
|
||||
->where('dr.dispense_status', '=', 1);
|
||||
$trendQuery = \Illuminate\Support\Facades\DB::table('dispense_records as dr')
|
||||
->join('orders as o', 'o.id', '=', 'dr.order_id')
|
||||
->leftJoinSub($itemPriceQuery, 'oi', function($join) {
|
||||
$join->on('oi.order_id', '=', 'dr.order_id')
|
||||
->on('oi.product_id', '=', 'dr.product_id');
|
||||
})
|
||||
->leftJoin('products as p', 'p.id', '=', 'oi.product_id')
|
||||
->leftJoin('products as p', 'p.id', '=', 'dr.product_id')
|
||||
->select([
|
||||
\Illuminate\Support\Facades\DB::raw("DATE_FORMAT(o.created_at, '%Y-%m-%d') as date"),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN 1 ELSE 0 END) as SIGNED) as total_quantity'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN oi.price ELSE 0 END) as DECIMAL(10,2)) as total_sales'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(CASE WHEN dr.id IS NOT NULL THEN COALESCE(p.cost, 0) ELSE 0 END) as DECIMAL(10,2)) as total_cost')
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(COUNT(dr.id) as SIGNED) as total_quantity'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(COALESCE(oi.unit_price, 0)) as DECIMAL(10,2)) as total_sales'),
|
||||
\Illuminate\Support\Facades\DB::raw('CAST(SUM(COALESCE(p.cost, 0)) as DECIMAL(10,2)) as total_cost')
|
||||
])
|
||||
->where('dr.dispense_status', 1)
|
||||
->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS)
|
||||
->whereNull('o.deleted_at')
|
||||
->whereBetween('o.created_at', [$startDate, $endDate]);
|
||||
@ -561,7 +585,7 @@ class AnalysisController extends Controller
|
||||
}
|
||||
|
||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||
$trendQuery->where('oi.product_id', $selectedProductId);
|
||||
$trendQuery->where('dr.product_id', $selectedProductId);
|
||||
}
|
||||
|
||||
$trendQuery->groupBy('date')->orderBy('date', 'asc');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user