[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'),
|
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 (按機台分組)
|
// 6. 執行主報表統計 SQL (按機台分組)
|
||||||
// 子查詢 A:營業額 (計算機台實收)
|
// 子查詢 A:營業額 (計算機台實收)
|
||||||
$salesQuery = \Illuminate\Support\Facades\DB::table('orders as o')
|
$salesQuery = \Illuminate\Support\Facades\DB::table('orders as o')
|
||||||
@ -130,16 +139,18 @@ class AnalysisController extends Controller
|
|||||||
|
|
||||||
// 如果篩選特定商品,營業額只計算有成功出貨的該商品金額
|
// 如果篩選特定商品,營業額只計算有成功出貨的該商品金額
|
||||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||||
$salesQuery->join('order_items as oi', 'oi.order_id', '=', 'o.id')
|
$salesQuery->join('dispense_records as dr', function($join) {
|
||||||
->leftJoin('dispense_records as dr', function($join) {
|
$join->on('dr.order_id', '=', 'o.id')
|
||||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
|
||||||
->on('dr.product_id', '=', 'oi.product_id')
|
|
||||||
->where('dr.dispense_status', '=', 1);
|
->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([
|
->select([
|
||||||
'o.machine_id',
|
'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');
|
$salesQuery->groupBy('o.machine_id');
|
||||||
@ -269,16 +280,18 @@ class AnalysisController extends Controller
|
|||||||
|
|
||||||
// 如果篩選特定商品,營業額只計算有成功出貨的商品價格
|
// 如果篩選特定商品,營業額只計算有成功出貨的商品價格
|
||||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||||
$trendSalesQuery->join('order_items as oi', 'oi.order_id', '=', 'o.id')
|
$trendSalesQuery->join('dispense_records as dr', function($join) {
|
||||||
->leftJoin('dispense_records as dr', function($join) {
|
$join->on('dr.order_id', '=', 'o.id')
|
||||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
|
||||||
->on('dr.product_id', '=', 'oi.product_id')
|
|
||||||
->where('dr.dispense_status', '=', 1);
|
->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([
|
->select([
|
||||||
\Illuminate\Support\Facades\DB::raw("DATE_FORMAT(o.created_at, '%Y-%m-%d') as date"),
|
\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');
|
$trendSalesQuery->groupBy('date');
|
||||||
@ -449,24 +462,35 @@ class AnalysisController extends Controller
|
|||||||
$products = $productsQuery->active()->get(['id', 'name', 'barcode']);
|
$products = $productsQuery->active()->get(['id', 'name', 'barcode']);
|
||||||
|
|
||||||
// 5. 執行主報表統計 SQL
|
// 5. 執行主報表統計 SQL
|
||||||
// 計算各商品的銷售數量、銷售額、總成本、利潤
|
// 子查詢:取得每個 order_id + product_id 的銷售單價與品名
|
||||||
$mainQuery = \Illuminate\Support\Facades\DB::table('order_items as oi')
|
$itemPriceQuery = \Illuminate\Support\Facades\DB::table('order_items')
|
||||||
->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')
|
|
||||||
->select([
|
->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.barcode, oi.barcode) as barcode'),
|
||||||
\Illuminate\Support\Facades\DB::raw('COALESCE(p.name, oi.product_name) as name'),
|
\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(COUNT(dr.id) 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(COALESCE(oi.unit_price, 0)) 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(COALESCE(p.cost, 0)) 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((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)
|
->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS)
|
||||||
->whereNull('o.deleted_at')
|
->whereNull('o.deleted_at')
|
||||||
->whereBetween('o.created_at', [$startDate, $endDate]);
|
->whereBetween('o.created_at', [$startDate, $endDate]);
|
||||||
@ -492,10 +516,10 @@ class AnalysisController extends Controller
|
|||||||
|
|
||||||
// 套用特定商品篩選
|
// 套用特定商品篩選
|
||||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
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.barcode, oi.barcode)'))
|
||||||
->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(p.name, oi.product_name)'));
|
->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(p.name, oi.product_name)'));
|
||||||
$tableData = $mainQuery->get();
|
$tableData = $mainQuery->get();
|
||||||
@ -526,20 +550,20 @@ class AnalysisController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
// 7. 圖表日走勢統計 SQL
|
// 7. 圖表日走勢統計 SQL
|
||||||
$trendQuery = \Illuminate\Support\Facades\DB::table('order_items as oi')
|
$trendQuery = \Illuminate\Support\Facades\DB::table('dispense_records as dr')
|
||||||
->join('orders as o', 'o.id', '=', 'oi.order_id')
|
->join('orders as o', 'o.id', '=', 'dr.order_id')
|
||||||
->leftJoin('dispense_records as dr', function($join) {
|
->leftJoinSub($itemPriceQuery, 'oi', function($join) {
|
||||||
$join->on('dr.order_id', '=', 'oi.order_id')
|
$join->on('oi.order_id', '=', 'dr.order_id')
|
||||||
->on('dr.product_id', '=', 'oi.product_id')
|
->on('oi.product_id', '=', 'dr.product_id');
|
||||||
->where('dr.dispense_status', '=', 1);
|
|
||||||
})
|
})
|
||||||
->leftJoin('products as p', 'p.id', '=', 'oi.product_id')
|
->leftJoin('products as p', 'p.id', '=', 'dr.product_id')
|
||||||
->select([
|
->select([
|
||||||
\Illuminate\Support\Facades\DB::raw("DATE_FORMAT(o.created_at, '%Y-%m-%d') as date"),
|
\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(COUNT(dr.id) 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(COALESCE(oi.unit_price, 0)) 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(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)
|
->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS)
|
||||||
->whereNull('o.deleted_at')
|
->whereNull('o.deleted_at')
|
||||||
->whereBetween('o.created_at', [$startDate, $endDate]);
|
->whereBetween('o.created_at', [$startDate, $endDate]);
|
||||||
@ -561,7 +585,7 @@ class AnalysisController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
if ($selectedProductId && $selectedProductId !== 'ALL') {
|
||||||
$trendQuery->where('oi.product_id', $selectedProductId);
|
$trendQuery->where('dr.product_id', $selectedProductId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$trendQuery->groupBy('date')->orderBy('date', 'asc');
|
$trendQuery->groupBy('date')->orderBy('date', 'asc');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user