diff --git a/app/Http/Controllers/Admin/AnalysisController.php b/app/Http/Controllers/Admin/AnalysisController.php index 3b913ab..4357105 100644 --- a/app/Http/Controllers/Admin/AnalysisController.php +++ b/app/Http/Controllers/Admin/AnalysisController.php @@ -16,12 +16,260 @@ class AnalysisController extends Controller ]); } - // 機台報表分析 - public function machineReports() + public function machineReports(Request $request) { - return view('admin.placeholder', [ + $user = auth()->user(); + $companyId = $user->company_id; + + // 1. 取得篩選參數 + $selectedCompanyId = $request->input('company_id'); + $selectedMachineId = $request->input('machine_id', 'ALL'); + $selectedProductId = $request->input('product_id', 'ALL'); + $paymentTypes = $request->input('payment_types', []); + $dateRange = $request->input('date_range'); + + if (!is_array($paymentTypes)) { + $paymentTypes = $paymentTypes ? explode(',', $paymentTypes) : []; + } + $paymentTypes = array_filter(array_map('intval', $paymentTypes)); + + // 2. 解析日期區間 + if ($dateRange) { + $dates = explode(' to ', $dateRange); + if (count($dates) === 2) { + $startDate = \Illuminate\Support\Carbon::parse($dates[0])->startOfDay(); + $endDate = \Illuminate\Support\Carbon::parse($dates[1])->endOfDay(); + } else { + $startDate = \Illuminate\Support\Carbon::parse($dates[0])->startOfDay(); + $endDate = \Illuminate\Support\Carbon::parse($dates[0])->endOfDay(); + } + } else { + // 預設為最近 7 天 (含今日) + $startDate = now()->subDays(6)->startOfDay(); + $endDate = now()->endOfDay(); + $dateRange = $startDate->format('Y-m-d') . ' to ' . $endDate->format('Y-m-d'); + } + + // 3. 租戶隔離:非系統管理員強制限制為其所屬公司 + if (!$user->isSystemAdmin()) { + $effectiveCompanyId = $companyId; + } else { + $effectiveCompanyId = $selectedCompanyId; + } + + // 取得使用者授權的機台 ID 範圍 (一般用戶) + $allowedMachineIds = null; + if (!$user->isSystemAdmin()) { + $allowedMachineIds = \App\Models\Machine\Machine::pluck('id')->toArray(); + } + + // 4. 加載下拉選單選項 + // 公司選單 (僅限 Super Admin) + $companies = []; + if ($user->isSystemAdmin()) { + $companies = \App\Models\System\Company::active()->get(['id', 'name']); + } + + // 機台選單 (自動套用多租戶與授權隔離) + $machinesQuery = \App\Models\Machine\Machine::query(); + if ($effectiveCompanyId) { + $machinesQuery->where('company_id', $effectiveCompanyId); + } + $machines = $machinesQuery->get(['id', 'name', 'serial_no']); + + // 商品選單 + $productsQuery = \App\Models\Product\Product::query(); + if ($effectiveCompanyId) { + $productsQuery->where('company_id', $effectiveCompanyId); + } + $products = $productsQuery->active()->get(['id', 'name', 'barcode']); + + // 5. 支付工具選項 (使用者指定之 11 種) + $availablePaymentTypes = [ + 1 => __('Credit Card'), + 2 => __('E-Ticket (EasyCard/iPass)'), + 3 => __('QR Code Payment'), + 4 => __('Bill Acceptor'), + 5 => __('Pass Code'), + 6 => __('Pickup Code'), + 7 => __('Welcome Gift'), + 8 => __('Questionnaire'), + 9 => __('Coin Acceptor'), + 41 => __('Staff Card'), + 42 => __('Pickup Voucher'), + ]; + + // 6. 執行主報表統計 SQL (按機台分組) + $mainQuery = \Illuminate\Support\Facades\DB::table('order_items as oi') + ->join('orders as o', 'o.id', '=', 'oi.order_id') + ->leftJoin('machines as m', 'm.id', '=', 'o.machine_id') + ->leftJoin('products as p', 'p.id', '=', 'oi.product_id') + ->select([ + 'o.machine_id', + \Illuminate\Support\Facades\DB::raw('COALESCE(m.serial_no, "UNKNOWN") as serial_no'), + \Illuminate\Support\Facades\DB::raw('COALESCE(m.name, "未知機台") as name'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.quantity) as total_quantity'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.subtotal) as total_sales'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.quantity * COALESCE(p.cost, 0)) as total_cost'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.subtotal) - SUM(oi.quantity * COALESCE(p.cost, 0)) as total_profit') + ]) + ->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS) + ->whereNull('o.deleted_at') + ->whereBetween('o.created_at', [$startDate, $endDate]); + + // 套用公司篩選 + if ($effectiveCompanyId) { + $mainQuery->where('o.company_id', $effectiveCompanyId); + } + + // 套用機台權限限制 + if ($allowedMachineIds !== null) { + if (empty($allowedMachineIds)) { + $mainQuery->whereRaw('1 = 0'); + } else { + $mainQuery->whereIn('o.machine_id', $allowedMachineIds); + } + } + + // 套用特定機台篩選 + if ($selectedMachineId && $selectedMachineId !== 'ALL') { + $mainQuery->where('o.machine_id', $selectedMachineId); + } + + // 套用特定商品篩選 + if ($selectedProductId && $selectedProductId !== 'ALL') { + $mainQuery->where('oi.product_id', $selectedProductId); + } + + // 套用支付工具多選篩選 + if (!empty($paymentTypes)) { + $mainQuery->whereIn('o.payment_type', $paymentTypes); + } + + $mainQuery->groupBy('o.machine_id') + ->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(m.serial_no, "UNKNOWN")')) + ->groupBy(\Illuminate\Support\Facades\DB::raw('COALESCE(m.name, "未知機台")')); + $tableData = $mainQuery->get(); + + // 7. 計算總計 Summary + $totalQuantity = 0; + $totalSales = 0.0; + $totalCost = 0.0; + $totalProfit = 0.0; + + foreach ($tableData as $row) { + $row->total_quantity = (int)$row->total_quantity; + $row->total_sales = (float)$row->total_sales; + $row->total_cost = (float)$row->total_cost; + $row->total_profit = (float)$row->total_profit; + + $totalQuantity += $row->total_quantity; + $totalSales += $row->total_sales; + $totalCost += $row->total_cost; + $totalProfit += $row->total_profit; + } + + $summary = [ + 'total_quantity' => $totalQuantity, + 'total_sales' => round($totalSales, 2), + 'total_cost' => round($totalCost, 2), + 'total_profit' => round($totalProfit, 2), + ]; + + // 8. 圖表日走勢統計 SQL + $trendQuery = \Illuminate\Support\Facades\DB::table('order_items as oi') + ->join('orders as o', 'o.id', '=', 'oi.order_id') + ->leftJoin('products as p', 'p.id', '=', 'oi.product_id') + ->select([ + \Illuminate\Support\Facades\DB::raw("DATE_FORMAT(o.created_at, '%Y-%m-%d') as date"), + \Illuminate\Support\Facades\DB::raw('SUM(oi.quantity) as total_quantity'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.subtotal) as total_sales'), + \Illuminate\Support\Facades\DB::raw('SUM(oi.quantity * COALESCE(p.cost, 0)) as total_cost'), + ]) + ->where('o.payment_status', \App\Models\Transaction\Order::PAYMENT_STATUS_SUCCESS) + ->whereNull('o.deleted_at') + ->whereBetween('o.created_at', [$startDate, $endDate]); + + if ($effectiveCompanyId) { + $trendQuery->where('o.company_id', $effectiveCompanyId); + } + + if ($allowedMachineIds !== null) { + if (empty($allowedMachineIds)) { + $trendQuery->whereRaw('1 = 0'); + } else { + $trendQuery->whereIn('o.machine_id', $allowedMachineIds); + } + } + + if ($selectedMachineId && $selectedMachineId !== 'ALL') { + $trendQuery->where('o.machine_id', $selectedMachineId); + } + + if ($selectedProductId && $selectedProductId !== 'ALL') { + $trendQuery->where('oi.product_id', $selectedProductId); + } + + if (!empty($paymentTypes)) { + $trendQuery->whereIn('o.payment_type', $paymentTypes); + } + + $trendQuery->groupBy('date')->orderBy('date', 'asc'); + $trendData = $trendQuery->get(); + + // 補齊日期區間內所有空缺日走勢 + $period = new \DatePeriod( + $startDate->copy()->startOfDay(), + new \DateInterval('P1D'), + $endDate->copy()->endOfDay() + ); + + $chartData = []; + foreach ($period as $date) { + $dateStr = $date->format('Y-m-d'); + $chartData[$dateStr] = [ + 'date' => $dateStr, + 'quantity' => 0, + 'sales' => 0.0, + 'cost' => 0.0, + ]; + } + + foreach ($trendData as $row) { + if (isset($chartData[$row->date])) { + $chartData[$row->date]['quantity'] = (int)$row->total_quantity; + $chartData[$row->date]['sales'] = round((float)$row->total_sales, 2); + $chartData[$row->date]['cost'] = round((float)$row->total_cost, 2); + } + } + $chartData = array_values($chartData); + + // 9. 判斷是否為 AJAX 請求,回傳 JSON 格式 + if ($request->ajax() || $request->wantsJson()) { + return response()->json([ + 'success' => true, + 'summary' => $summary, + 'chart_data' => $chartData, + 'table_data' => $tableData, + ]); + } + + // 10. 一般 GET 載入視圖 + return view('admin.analysis.machine-reports', [ 'title' => '機台報表分析', 'description' => '機台運營數據分析報表', + 'companies' => $companies, + 'machines' => $machines, + 'products' => $products, + 'availablePaymentTypes' => $availablePaymentTypes, + 'selectedCompanyId' => $selectedCompanyId, + 'selectedMachineId' => $selectedMachineId, + 'selectedProductId' => $selectedProductId, + 'selectedPaymentTypes' => $paymentTypes, + 'dateRange' => $dateRange, + 'summary' => $summary, + 'chartData' => $chartData, + 'tableData' => $tableData, ]); } @@ -34,6 +282,7 @@ class AnalysisController extends Controller // 1. 取得篩選參數 $selectedCompanyId = $request->input('company_id'); $selectedProductId = $request->input('product_id', 'ALL'); + $selectedMachineId = $request->input('machine_id', 'ALL'); $dateRange = $request->input('date_range'); // 2. 解析日期區間 @@ -60,6 +309,12 @@ class AnalysisController extends Controller $effectiveCompanyId = $selectedCompanyId; } + // 取得使用者授權的機台 ID 範圍 (一般用戶) + $allowedMachineIds = null; + if (!$user->isSystemAdmin()) { + $allowedMachineIds = \App\Models\Machine\Machine::pluck('id')->toArray(); + } + // 4. 加載下拉選單選項 // 公司選單 (僅限 Super Admin) $companies = []; @@ -67,6 +322,13 @@ class AnalysisController extends Controller $companies = \App\Models\System\Company::active()->get(['id', 'name']); } + // 機台選單 (自動套用多租戶與授權隔離) + $machinesQuery = \App\Models\Machine\Machine::query(); + if ($effectiveCompanyId) { + $machinesQuery->where('company_id', $effectiveCompanyId); + } + $machines = $machinesQuery->get(['id', 'name', 'serial_no']); + // 商品選單 $productsQuery = \App\Models\Product\Product::query(); if ($effectiveCompanyId) { @@ -97,6 +359,20 @@ class AnalysisController extends Controller $mainQuery->where('o.company_id', $effectiveCompanyId); } + // 套用機台權限限制 + if ($allowedMachineIds !== null) { + if (empty($allowedMachineIds)) { + $mainQuery->whereRaw('1 = 0'); + } else { + $mainQuery->whereIn('o.machine_id', $allowedMachineIds); + } + } + + // 套用特定機台篩選 + if ($selectedMachineId && $selectedMachineId !== 'ALL') { + $mainQuery->where('o.machine_id', $selectedMachineId); + } + // 套用特定商品篩選 if ($selectedProductId && $selectedProductId !== 'ALL') { $mainQuery->where('oi.product_id', $selectedProductId); @@ -150,6 +426,18 @@ class AnalysisController extends Controller $trendQuery->where('o.company_id', $effectiveCompanyId); } + if ($allowedMachineIds !== null) { + if (empty($allowedMachineIds)) { + $trendQuery->whereRaw('1 = 0'); + } else { + $trendQuery->whereIn('o.machine_id', $allowedMachineIds); + } + } + + if ($selectedMachineId && $selectedMachineId !== 'ALL') { + $trendQuery->where('o.machine_id', $selectedMachineId); + } + if ($selectedProductId && $selectedProductId !== 'ALL') { $trendQuery->where('oi.product_id', $selectedProductId); } @@ -185,7 +473,7 @@ class AnalysisController extends Controller $chartData = array_values($chartData); // 8. 判斷是否為 AJAX 請求,回傳 JSON 格式 - if ($request->ajax()) { + if ($request->ajax() || $request->wantsJson()) { return response()->json([ 'success' => true, 'summary' => $summary, @@ -197,10 +485,12 @@ class AnalysisController extends Controller // 9. 一般 GET 載入視圖 return view('admin.analysis.product-reports', [ 'title' => '商品報表分析', - 'description' => '商品銷售數據分析', + 'description' => '商品銷售數據 analysis', 'companies' => $companies, + 'machines' => $machines, 'products' => $products, 'selectedCompanyId' => $selectedCompanyId, + 'selectedMachineId' => $selectedMachineId, 'selectedProductId' => $selectedProductId, 'dateRange' => $dateRange, 'summary' => $summary, diff --git a/app/Models/Machine/Machine.php b/app/Models/Machine/Machine.php index 378fcd6..ee1380a 100644 --- a/app/Models/Machine/Machine.php +++ b/app/Models/Machine/Machine.php @@ -16,8 +16,8 @@ class Machine extends Model // 權限隔離:一般帳號登入時只能看到自己被分配的機台 static::addGlobalScope('machine_access', function (\Illuminate\Database\Eloquent\Builder $builder) { $user = auth()->user(); - // 如果是在 Console、或是系統管理員,則不限制 (可看所有機台) - if (app()->runningInConsole() || !$user || $user->isSystemAdmin()) { + // 如果是在 Console(且非單元測試)、或是系統管理員,則不限制 (可看所有機台) + if ((app()->runningInConsole() && !app()->runningUnitTests()) || !$user || $user->isSystemAdmin()) { return; } diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index 50859d9..2a98060 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -106,6 +106,7 @@ class RoleSeeder extends Seeder 'menu.sales.pass-codes', 'menu.sales.store-gifts', 'menu.analysis', + 'menu.analysis.machine-reports', 'menu.analysis.product-reports', 'menu.audit', 'menu.data-config', diff --git a/lang/en.json b/lang/en.json index a732410..72a711a 100644 --- a/lang/en.json +++ b/lang/en.json @@ -735,6 +735,7 @@ "Fill in the product details below": "Fill in the product details below", "Filter": "Filter", "Filter by Company": "Filter by Company", + "Filter by Payment Method": "Filter by Payment Method", "Filter by Warehouse Presence": "Filter by Warehouse Presence", "Firmware Version": "Firmware Version", "Firmware identification details": "Firmware identification details", @@ -995,6 +996,7 @@ "Low Stock Alerts": "Low Stock Alerts", "Low stock and out-of-stock alerts": "Low stock and out-of-stock alerts", "Loyalty & Features": "Loyalty & Features", + "M2W": "M2W", "Machine": "Machine", "Machine / Date": "Machine / Date", "Machine / Employee": "Machine / Employee", @@ -1034,9 +1036,11 @@ "Machine Reboot": "Machine Reboot", "Machine Registry": "Machine Registry", "Machine Replenishment": "Machine Replenishment", + "Machine Report Analysis": "Machine Report Analysis", "Machine Reports": "Machine Reports", "Machine Restart": "Machine Restart", "Machine Return": "Machine Return", + "Machine Sales & Profit Trend": "Machine Sales & Profit Trend", "Machine Serial": "Machine Serial", "Machine Serial No": "Machine Serial No", "Machine Settings": "Machine Settings", @@ -1064,7 +1068,6 @@ "Machine to Warehouse": "Machine to Warehouse", "Machine to Warehouse Return": "Machine to Warehouse Return", "Machine to warehouse returns": "Machine to warehouse returns", - "M2W": "M2W", "Machine updated successfully.": "Machine updated successfully.", "Machine-Specific Webhook": "Machine-Specific Webhook", "Machines": "Machines", @@ -1244,6 +1247,7 @@ "No location set": "No location set", "No login history yet": "No login history yet", "No logs found": "No logs found", + "No machine data matching search criteria": "No machine data matching search criteria", "No machines assigned": "No machines assigned", "No machines available": "No machines available", "No machines available in this company.": "No machines available in this company.", @@ -1750,6 +1754,7 @@ "Search logs...": "Search logs...", "Search machine name or SN...": "Search machine name or SN...", "Search machine name, S/N, or location...": "Search machine name, S/N, or location...", + "Search machine name, serial no...": "Search machine name, serial no...", "Search machines by name or serial...": "Search machines by name or serial...", "Search machines...": "Search machines...", "Search models...": "Search models...", @@ -2178,6 +2183,7 @@ "Vending Machine Product Replenishment": "Vending Machine Product Replenishment", "Vending Page": "Vending Page", "Vending machine reported a submachine hardware error.": "Vending machine reported a submachine hardware error.", + "Vending machine revenue and payment analysis report": "Vending machine revenue and payment analysis report", "Venue Management": "Venue Management", "Verified": "Verified", "Verified Only": "Verified Only", @@ -2202,6 +2208,7 @@ "Visual overview of all machine locations": "Visual overview of all machine locations", "Void": "Void", "Void Invoice": "Void Invoice", + "W2W": "W2W", "Waiting": "Waiting", "Waiting for Payment": "Waiting for Payment", "Warehouse": "Warehouse", @@ -2229,7 +2236,6 @@ "Warehouse to Warehouse": "Warehouse to Warehouse", "Warehouse to Warehouse Transfer": "Warehouse to Warehouse Transfer", "Warehouse to warehouse transfers": "Warehouse to warehouse transfers", - "W2W": "W2W", "Warehouse updated successfully": "Warehouse updated successfully", "Warehouse updated successfully.": "Warehouse updated successfully.", "Warning": "Warning", diff --git a/lang/ja.json b/lang/ja.json index 1c076fb..e0f1933 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -735,6 +735,7 @@ "Fill in the product details below": "以下に商品の詳細情報を入力してください", "Filter": "フィルター", "Filter by Company": "Filter by Company", + "Filter by Payment Method": "決済方法でフィルター", "Filter by Warehouse Presence": "倉庫の在庫状況で絞り込む", "Firmware Version": "ファームウェアバージョン", "Firmware identification details": "Firmware identification details", @@ -995,6 +996,7 @@ "Low Stock Alerts": "低在庫アラート", "Low stock and out-of-stock alerts": "低在庫と欠品のアラート", "Loyalty & Features": "マーケティング・ポイント", + "M2W": "機器から倉庫", "Machine": "自販機", "Machine / Date": "機器 / 日付", "Machine / Employee": "機器 / 従業員", @@ -1034,9 +1036,11 @@ "Machine Reboot": "機器アプリ再起動", "Machine Registry": "機器リスト", "Machine Replenishment": "機器補充伝票", + "Machine Report Analysis": "マシン別売上レポート", "Machine Reports": "機器レポート", "Machine Restart": "機器アプリ再起動", "Machine Return": "機器返却", + "Machine Sales & Profit Trend": "マシン別売上・利益トレンド", "Machine Serial": "機器シリアル", "Machine Serial No": "機器シリアル番号", "Machine Settings": "機器設定", @@ -1064,7 +1068,6 @@ "Machine to Warehouse": "機器から倉庫", "Machine to Warehouse Return": "自販機から倉庫への返品", "Machine to warehouse returns": "機器から倉庫への返却", - "M2W": "機器から倉庫", "Machine updated successfully.": "機器が正常に更新されました。", "Machine-Specific Webhook": "機器専用 Webhook", "Machines": "機器管理", @@ -1244,6 +1247,7 @@ "No location set": "場所が設定されていません", "No login history yet": "ログイン履歴はまだありません", "No logs found": "ログが見つかりません", + "No machine data matching search criteria": "検索条件に一致するマシンデータはありません", "No machines assigned": "機器が割り当てられていません", "No machines available": "利用可能な機器がありません", "No machines available in this company.": "この会社で利用可能な機器がありません。", @@ -1750,6 +1754,7 @@ "Search logs...": "ログを検索...", "Search machine name or SN...": "機器名またはシリアル番号で検索...", "Search machine name, S/N, or location...": "Search machine name, S/N, or location...", + "Search machine name, serial no...": "マシン名、シリアル番号で検索...", "Search machines by name or serial...": "機器名またはシリアルで検索...", "Search machines...": "機器を検索...", "Search models...": "モデルを検索...", @@ -2178,6 +2183,7 @@ "Vending Machine Product Replenishment": "自販機商品補充", "Vending Page": "販売ページ", "Vending machine reported a submachine hardware error.": "マシンが下位機のハードウェア動作エラーを報告しました。", + "Vending machine revenue and payment analysis report": "自販機売上・決済方法分析レポート", "Venue Management": "施設管理", "Verified": "検証済み", "Verified Only": "検証済みのみ", @@ -2202,6 +2208,7 @@ "Visual overview of all machine locations": "すべての機器の位置の視覚的概要", "Void": "無効化 (作廢)", "Void Invoice": "領収書無効化", + "W2W": "倉庫間", "Waiting": "待機中", "Waiting for Payment": "支払待機中", "Warehouse": "倉庫", @@ -2229,7 +2236,6 @@ "Warehouse to Warehouse": "倉庫から倉庫", "Warehouse to Warehouse Transfer": "倉庫間移動", "Warehouse to warehouse transfers": "倉庫から倉庫への在庫移動", - "W2W": "倉庫間", "Warehouse updated successfully": "倉庫が正常に更新されました", "Warehouse updated successfully.": "倉庫が正常に更新されました。", "Warning": "期限間近", diff --git a/lang/zh_TW.json b/lang/zh_TW.json index 728130d..9130367 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -735,6 +735,7 @@ "Fill in the product details below": "請在下方填寫商品的詳細資訊", "Filter": "篩選", "Filter by Company": "依公司篩選", + "Filter by Payment Method": "篩選支付工具", "Filter by Warehouse Presence": "依據倉庫存貨篩選", "Firmware Version": "韌體版本", "Firmware identification details": "韌體識別詳情", @@ -995,6 +996,7 @@ "Low Stock Alerts": "低庫存警示", "Low stock and out-of-stock alerts": "低庫存與缺貨警示", "Loyalty & Features": "行銷與點數", + "M2W": "機對倉", "Machine": "機台", "Machine / Date": "機台 / 日期", "Machine / Employee": "機台 / 員工", @@ -1034,9 +1036,11 @@ "Machine Reboot": "機台 APP 重啟", "Machine Registry": "機台清冊", "Machine Replenishment": "機台補貨單", + "Machine Report Analysis": "機台報表分析", "Machine Reports": "機台報表", "Machine Restart": "機台 APP 重啟", "Machine Return": "機台退庫", + "Machine Sales & Profit Trend": "機台銷售與利潤趨勢", "Machine Serial": "機台序號", "Machine Serial No": "機台序號", "Machine Settings": "機台設定", @@ -1064,7 +1068,6 @@ "Machine to Warehouse": "機台對倉庫", "Machine to Warehouse Return": "機台退庫至倉庫", "Machine to warehouse returns": "機台退回倉庫", - "M2W": "機對倉", "Machine updated successfully.": "機台更新成功。", "Machine-Specific Webhook": "機台專屬 Webhook", "Machines": "機台管理", @@ -1244,6 +1247,7 @@ "No location set": "尚未設定位置", "No login history yet": "尚無登入紀錄", "No logs found": "暫無相關日誌", + "No machine data matching search criteria": "無符合搜尋條件的機台數據", "No machines assigned": "未分配機台", "No machines available": "目前沒有可供分配的機台", "No machines available in this company.": "此客戶目前沒有可供分配的機台。", @@ -1750,6 +1754,7 @@ "Search logs...": "搜尋紀錄...", "Search machine name or SN...": "搜尋機台名稱或序號...", "Search machine name, S/N, or location...": "搜尋機台名稱、序號 (S/N) 或位置...", + "Search machine name, serial no...": "搜尋機台名稱、編號...", "Search machines by name or serial...": "搜尋機台名稱或序號...", "Search machines...": "搜尋機台...", "Search models...": "搜尋型號...", @@ -2178,6 +2183,7 @@ "Vending Machine Product Replenishment": "機台商品補貨", "Vending Page": "販賣頁", "Vending machine reported a submachine hardware error.": "機台回報下位機硬體運作錯誤。", + "Vending machine revenue and payment analysis report": "販賣機營運與支付方式分析", "Venue Management": "場地管理", "Verified": "驗證成功", "Verified Only": "僅限驗證", @@ -2202,6 +2208,7 @@ "Visual overview of all machine locations": "所有機台位置的視覺化概覽", "Void": "作廢", "Void Invoice": "作廢發票", + "W2W": "倉對倉", "Waiting": "等待中", "Waiting for Payment": "等待付款", "Warehouse": "倉庫", @@ -2229,7 +2236,6 @@ "Warehouse to Warehouse": "倉庫對倉庫", "Warehouse to Warehouse Transfer": "倉庫至倉庫調撥", "Warehouse to warehouse transfers": "倉庫對倉庫調撥", - "W2W": "倉對倉", "Warehouse updated successfully": "倉庫更新成功", "Warehouse updated successfully.": "倉庫已成功更新。", "Warning": "警告", diff --git a/resources/views/admin/analysis/machine-reports.blade.php b/resources/views/admin/analysis/machine-reports.blade.php new file mode 100644 index 0000000..b23f69b --- /dev/null +++ b/resources/views/admin/analysis/machine-reports.blade.php @@ -0,0 +1,1144 @@ +@extends('layouts.admin') + +@section('scripts') + +@endsection + +@section('content') +
{{ __('Sales Quantity') }}
+{{ __('Total Sales Amount') }}
+{{ __('Total Product Cost') }}
+{{ __('Total Sales Profit') }}
+{{ __('Daily operational variance curve for selected timeframe') }}
+|
+
+ {{ __('Rank') }}
+
+ |
+
+
+ {{ __('Machine Serial No') }}
+
+
+
+
+ |
+
+
+ {{ __('Machine Name') }}
+
+
+
+
+ |
+
+
+ {{ __('Quantity Sold') }}
+
+
+
+
+ |
+
+
+ {{ __('Total Sales') }}
+
+
+
+
+ |
+
+
+ {{ __('Total Product Cost') }}
+
+
+
+
+ |
+
+
+ {{ __('Total Net Profit') }}
+
+
+
+
+ |
+
+
+ {{ __('Gross Margin') }}
+
+
+
+
+ |
+
|---|---|---|---|---|---|---|---|
| + + 1 + + + 2 + + + 3 + + + + + | ++ | + | + | + | + | + | + |
|
+
+
+
+ {{ __('No machine data matching search criteria') }} + |
+ |||||||
{{ __('Sales Quantity') }}
+ +{{ __('Total Sales') }}
+ +{{ __('Product Cost') }}
+ +{{ __('Total Net Profit') }}
+ +{{ __('No machine data matching search criteria') }}
++ {{ __('Showing') }} + + {{ __('to') }} + + {{ __('of') }} + / + + {{ __('items') }} +
+