diff --git a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
index c10316c..4de285d 100644
--- a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
+++ b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
@@ -47,6 +47,17 @@ class MachineSettingController extends AdminController
$machines = $machineQuery->latest()->paginate($per_page)->withQueryString();
break;
+ case 'system_settings':
+ $machineQuery = Machine::query()->with(['company']);
+ if ($search) {
+ $machineQuery->where(function ($q) use ($search) {
+ $q->where('name', 'like', "%{$search}%")
+ ->orWhere('serial_no', 'like', "%{$search}%");
+ });
+ }
+ $machines = $machineQuery->latest()->paginate($per_page)->withQueryString();
+ break;
+
case 'models':
$modelQuery = MachineModel::query()->withCount('machines');
if ($search) {
@@ -70,6 +81,7 @@ class MachineSettingController extends AdminController
}
$users_list = $userQuery->latest()->paginate($per_page)->withQueryString();
break;
+
}
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
@@ -77,6 +89,7 @@ class MachineSettingController extends AdminController
$tabView = match($tab) {
'models' => 'admin.basic-settings.machines.partials.tab-models',
'permissions' => 'admin.basic-settings.machines.partials.tab-permissions',
+ 'system_settings' => 'admin.basic-settings.machines.partials.tab-system-settings',
default => 'admin.basic-settings.machines.partials.tab-machines',
};
return response()->view($tabView, compact(
@@ -194,6 +207,12 @@ class MachineSettingController extends AdminController
'is_spring_slot_41_50' => 'boolean',
'is_spring_slot_51_60' => 'boolean',
'member_system_enabled' => 'boolean',
+ 'tax_invoice_enabled' => 'boolean',
+ 'card_terminal_enabled' => 'boolean',
+ 'scan_pay_esun_enabled' => 'boolean',
+ 'scan_pay_linepay_enabled' => 'boolean',
+ 'shopping_cart_enabled' => 'boolean',
+ 'cash_module_enabled' => 'boolean',
'machine_model_id' => 'required|exists:machine_models,id',
'payment_config_id' => 'nullable|exists:payment_configs,id',
'location' => 'nullable|string|max:255',
@@ -287,6 +306,62 @@ class MachineSettingController extends AdminController
]);
}
+ public function updateSystemSettings(Request $request, Machine $machine): \Illuminate\Http\JsonResponse|RedirectResponse
+ {
+ \Log::info('Update System Settings Request:', $request->all());
+ if ($request->has('settings')) {
+ $settings = $request->input('settings');
+ $allowedFields = [
+ 'tax_invoice_enabled',
+ 'card_terminal_enabled',
+ 'scan_pay_esun_enabled',
+ 'scan_pay_linepay_enabled',
+ 'shopping_cart_enabled',
+ 'welcome_gift_enabled',
+ 'cash_module_enabled',
+ 'member_system_enabled',
+ ];
+ $data = [];
+ foreach ($allowedFields as $field) {
+ $data[$field] = isset($settings[$field]) ? (bool)$settings[$field] : false;
+ }
+ $machine->update(array_merge($data, ['updater_id' => auth()->id()]));
+
+ if ($request->expectsJson()) {
+ return response()->json([
+ 'success' => true,
+ 'message' => __('Settings updated successfully.')
+ ]);
+ }
+ return redirect()->back()->with('success', __('Settings updated successfully.'));
+ }
+
+ $field = $request->input('field');
+ $value = $request->boolean('value');
+
+ $allowedFields = [
+ 'tax_invoice_enabled',
+ 'card_terminal_enabled',
+ 'scan_pay_esun_enabled',
+ 'scan_pay_linepay_enabled',
+ 'shopping_cart_enabled',
+ 'welcome_gift_enabled',
+ 'cash_module_enabled',
+ 'member_system_enabled',
+ ];
+
+ if (!in_array($field, $allowedFields)) {
+ return response()->json(['success' => false, 'message' => 'Invalid field'], 400);
+ }
+
+ $machine->update([$field => $value, 'updater_id' => auth()->id()]);
+
+ return response()->json([
+ 'success' => true,
+ 'message' => __('Setting updated successfully.')
+ ]);
+ }
+
/**
* 公開機台分布地圖
*/
diff --git a/app/Http/Controllers/Admin/CompanyController.php b/app/Http/Controllers/Admin/CompanyController.php
index 466b558..ab7c24a 100644
--- a/app/Http/Controllers/Admin/CompanyController.php
+++ b/app/Http/Controllers/Admin/CompanyController.php
@@ -74,13 +74,6 @@ class CompanyController extends Controller
if (isset($validated['settings'])) {
$validated['settings']['enable_material_code'] = filter_var($validated['settings']['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN);
$validated['settings']['enable_points'] = filter_var($validated['settings']['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['tax_invoice'] = filter_var($validated['settings']['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['card_terminal'] = filter_var($validated['settings']['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['scan_pay_esun'] = filter_var($validated['settings']['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['scan_pay_linepay'] = filter_var($validated['settings']['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['shopping_cart'] = filter_var($validated['settings']['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['welcome_gift'] = filter_var($validated['settings']['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['cash_module'] = filter_var($validated['settings']['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN);
}
DB::transaction(function () use ($validated) {
@@ -185,13 +178,6 @@ class CompanyController extends Controller
if (isset($validated['settings'])) {
$validated['settings']['enable_material_code'] = filter_var($validated['settings']['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN);
$validated['settings']['enable_points'] = filter_var($validated['settings']['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['tax_invoice'] = filter_var($validated['settings']['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['card_terminal'] = filter_var($validated['settings']['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['scan_pay_esun'] = filter_var($validated['settings']['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['scan_pay_linepay'] = filter_var($validated['settings']['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['shopping_cart'] = filter_var($validated['settings']['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['welcome_gift'] = filter_var($validated['settings']['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN);
- $validated['settings']['cash_module'] = filter_var($validated['settings']['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN);
}
DB::transaction(function () use ($validated, $company) {
@@ -230,13 +216,6 @@ class CompanyController extends Controller
$formattedSettings = [
'enable_material_code' => filter_var($settings['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN),
'enable_points' => filter_var($settings['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'tax_invoice' => filter_var($settings['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'card_terminal' => filter_var($settings['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'scan_pay_esun' => filter_var($settings['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'scan_pay_linepay' => filter_var($settings['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'shopping_cart' => filter_var($settings['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'welcome_gift' => filter_var($settings['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN),
- 'cash_module' => filter_var($settings['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN),
];
// Ensure we force save the JSON cast properly
diff --git a/app/Http/Controllers/Admin/WarehouseController.php b/app/Http/Controllers/Admin/WarehouseController.php
index 34058ed..4608255 100644
--- a/app/Http/Controllers/Admin/WarehouseController.php
+++ b/app/Http/Controllers/Admin/WarehouseController.php
@@ -147,20 +147,26 @@ class WarehouseController extends Controller
public function inventory(Request $request)
{
- $tab = $request->input('tab', 'stock-in');
+ $tab = $request->input('tab', 'stock');
$warehouses = Warehouse::active()->orderBy('name')->get();
+ $isAjax = $request->ajax();
$data = compact('warehouses', 'tab');
- if ($tab === 'stock') {
- $inventory_warehouses = Warehouse::active()->orderBy('name')->get(['id', 'name', 'type']);
+ // 1. Current Stocks (stock)
+ if (!$isAjax || $tab === 'stock') {
+ $warehouse_ids = $request->input('warehouse_ids');
+ $inventory_warehouses = Warehouse::active()
+ ->when($warehouse_ids, fn($q) => $q->whereIn('id', (array)$warehouse_ids))
+ ->orderBy('name')
+ ->get(['id', 'name', 'type']);
$query = Product::with(['stocks' => function($q) {
$q->select('id', 'product_id', 'warehouse_id', 'quantity', 'safety_stock');
}, 'translations']);
- if ($request->filled('warehouse_id')) {
- $query->whereHas('stocks', fn($q) => $q->where('warehouse_id', $request->input('warehouse_id')));
+ if ($warehouse_ids) {
+ $query->whereHas('stocks', fn($q) => $q->whereIn('warehouse_id', (array)$warehouse_ids));
}
if ($search = $request->input('search')) {
$query->where('name', 'like', "%{$search}%");
@@ -168,20 +174,30 @@ class WarehouseController extends Controller
$data['inventory_warehouses'] = $inventory_warehouses;
$data['products'] = $query->orderBy('name')
- ->paginate($request->input('per_page', 15))
+ ->paginate($request->input('per_page', 15), ['*'], 'stock_page')
->withQueryString();
+ }
- } elseif ($tab === 'stock-in') {
+ // 2. Stock-In Orders (stock-in)
+ if (!$isAjax || $tab === 'stock-in') {
$query = StockInOrder::with(['warehouse:id,name', 'creator:id,name'])
->latest();
if ($request->filled('status')) {
$query->where('status', $request->input('status'));
}
- $data['orders'] = $query->paginate($request->input('per_page', 10))->withQueryString();
- $data['products'] = Product::orderBy('name')->get(['id', 'name', 'image_url']);
+ if ($search = $request->input('search_order')) {
+ $query->where('order_no', 'like', "%{$search}%");
+ }
+ if ($request->filled('start_date') && $request->filled('end_date')) {
+ $query->whereBetween('created_at', [$request->start_date, $request->end_date]);
+ }
+ $data['orders'] = $query->paginate($request->input('per_page', 10), ['*'], 'order_page')->withQueryString();
+ $data['stock_in_products'] = Product::orderBy('name')->get(['id', 'name', 'image_url']);
+ }
- } elseif ($tab === 'movements') {
+ // 3. Movement History (movements)
+ if (!$isAjax || $tab === 'movements') {
$query = StockMovement::with(['warehouse:id,name', 'product:id,name', 'creator:id,name'])
->orderBy('created_at', 'desc');
@@ -191,10 +207,13 @@ class WarehouseController extends Controller
if ($request->filled('type')) {
$query->where('type', $request->input('type'));
}
- $data['movements'] = $query->paginate($request->input('per_page', 15))->withQueryString();
+ if ($request->filled('start_date') && $request->filled('end_date')) {
+ $query->whereBetween('created_at', [$request->start_date, $request->end_date]);
+ }
+ $data['movements'] = $query->paginate($request->input('per_page', 15), ['*'], 'movement_page')->withQueryString();
}
- if ($request->ajax()) {
+ if ($isAjax) {
return response()->json([
'success' => true,
'tab' => $tab,
diff --git a/app/Models/Machine/Machine.php b/app/Models/Machine/Machine.php
index 8b50ed7..bea51a1 100644
--- a/app/Models/Machine/Machine.php
+++ b/app/Models/Machine/Machine.php
@@ -85,6 +85,12 @@ class Machine extends Model
'images',
'creator_id',
'updater_id',
+ 'tax_invoice_enabled',
+ 'card_terminal_enabled',
+ 'scan_pay_esun_enabled',
+ 'scan_pay_linepay_enabled',
+ 'shopping_cart_enabled',
+ 'cash_module_enabled',
];
protected $appends = ['image_urls', 'calculated_status'];
@@ -177,6 +183,12 @@ class Machine extends Model
'is_spring_slot_41_50' => 'boolean',
'is_spring_slot_51_60' => 'boolean',
'member_system_enabled' => 'boolean',
+ 'tax_invoice_enabled' => 'boolean',
+ 'card_terminal_enabled' => 'boolean',
+ 'scan_pay_esun_enabled' => 'boolean',
+ 'scan_pay_linepay_enabled' => 'boolean',
+ 'shopping_cart_enabled' => 'boolean',
+ 'cash_module_enabled' => 'boolean',
'images' => 'array',
];
diff --git a/database/migrations/2026_04_24_082553_add_system_settings_to_machines_table.php b/database/migrations/2026_04_24_082553_add_system_settings_to_machines_table.php
new file mode 100644
index 0000000..909cc53
--- /dev/null
+++ b/database/migrations/2026_04_24_082553_add_system_settings_to_machines_table.php
@@ -0,0 +1,42 @@
+boolean('tax_invoice_enabled')->default(0)->after('invoice_status')->comment('電子發票開關');
+ $table->boolean('card_terminal_enabled')->default(0)->after('card_reader_no')->comment('刷卡機系統開關');
+ $table->boolean('scan_pay_esun_enabled')->default(0)->after('card_terminal_enabled')->comment('玉山掃碼支付開關');
+ $table->boolean('scan_pay_linepay_enabled')->default(0)->after('scan_pay_esun_enabled')->comment('LinePay支付開關');
+ $table->boolean('shopping_cart_enabled')->default(0)->after('scan_pay_linepay_enabled')->comment('購物車功能開關');
+ $table->boolean('welcome_gift_enabled')->default(0)->after('shopping_cart_enabled')->comment('迎賓禮功能開關');
+ $table->boolean('cash_module_enabled')->default(0)->after('welcome_gift_enabled')->comment('現金模組開關');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('machines', function (Blueprint $table) {
+ $table->dropColumn([
+ 'tax_invoice_enabled',
+ 'card_terminal_enabled',
+ 'scan_pay_esun_enabled',
+ 'scan_pay_linepay_enabled',
+ 'shopping_cart_enabled',
+ 'welcome_gift_enabled',
+ 'cash_module_enabled',
+ ]);
+ });
+ }
+};
diff --git a/lang/en.json b/lang/en.json
index eb4c89e..e7ca684 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -194,6 +194,7 @@
"Click to Open Dashboard": "Click to Open Dashboard",
"Click to upload": "Click to upload",
"Close Panel": "Close Panel",
+ "Coin\/Banknote Machine": "Coin\/Banknote Machine",
"Coin\/Bill Acceptor": "Coin\/Bill Acceptor",
"Command Center": "Command Center",
"Command Confirmation": "Command Confirmation",
@@ -264,6 +265,7 @@
"Created By": "Created By",
"Creation Time": "Creation Time",
"Creator": "Creator",
+ "Credit Card": "Credit Card",
"Credit Card \/ Contactless": "Credit Card \/ Contactless",
"Critical": "Critical",
"Current": "Current",
@@ -334,6 +336,8 @@
"Draft": "Draft",
"Duration": "Duration",
"Duration (Seconds)": "Duration (Seconds)",
+ "E.SUN Bank Scan": "E.SUN Bank Scan",
+ "E.SUN Pay": "E.SUN Pay",
"E.SUN QR Pay": "E.SUN QR Pay",
"E.SUN QR Scan": "E.SUN QR Scan",
"E.SUN QR Scan Settings Description": "E.SUN Bank QR Scan Payment Settings",
@@ -703,6 +707,7 @@
"No products found matching your criteria.": "No products found matching your criteria.",
"No records found": "No records found",
"No replenishment orders found": "No replenishment orders found",
+ "No results found": "No results found",
"No roles available": "No roles available",
"No roles found.": "No roles found.",
"No slot data": "No slot data",
@@ -1027,6 +1032,7 @@
"Serial Number": "Serial Number",
"Service Periods": "Service Periods",
"Service Terms": "Service Periods",
+ "Settings updated successfully.": "Settings updated successfully.",
"Settlement": "Settlement",
"Shopping Cart": "Shopping Cart",
"Shopping Cart Feature": "Shopping Cart Feature",
@@ -1213,6 +1219,7 @@
"Update Product": "Update Product",
"Update Settings": "Update Settings",
"Update existing role and permissions.": "Update existing role and permissions.",
+ "Update failed": "Update failed",
"Update identification for your asset": "Update identification for your asset",
"Update your account's profile information and email address.": "Update your account's profile information and email address.",
"Upload Image": "Upload Image",
diff --git a/lang/ja.json b/lang/ja.json
index bbe4a4a..c3fa709 100644
--- a/lang/ja.json
+++ b/lang/ja.json
@@ -18,6 +18,7 @@
"Card Terminal System": "カード端末システム",
"Cash Module": "現金決済モジュール",
"Cash Module Feature": "現金モジュール機能",
+ "Coin\/Banknote Machine": "硬貨\/紙幣モジュール",
"Coin\/Bill Acceptor": "コイン\/紙幣機",
"Completed": "完了",
"Confirm": "確認",
@@ -31,10 +32,13 @@
"Create stock transfers between warehouses and machine returns": "倉庫間の転送および機台からの返品伝票を作成",
"Created At": "作成日時",
"Created By": "作成者",
+ "Credit Card": "クレジットカード",
"Damage": "破損",
"Delivering": "配送中",
"Display Material Code": "素材コードを表示",
"Draft": "下書き",
+ "E.SUN Bank Scan": "玉山銀行スキャン",
+ "E.SUN Pay": "E.SUN Pay",
"E.SUN QR Pay": "玉山QR決済",
"ESUN": "玉山銀行 (ESUN)",
"Electronic Invoice": "電子翻訳",
@@ -52,10 +56,12 @@
"Includes Credit Card\/Mobile Pay": "クレジットカード\/モバイル決済を含む",
"Inventory Management": "在庫管理",
"LinePay": "LinePay",
- "LinePay Payment": "LinePay決済",
+ "LinePay Payment": "LinePay 決済",
"Loading...": "読み込み中...",
"Low Stock": "在庫不足",
"Low Stock Alerts": "低在庫アラート",
+ "Machine Distribution": "機器分布",
+ "Machine Distribution Map": "機器分布マップ",
"Machine Inventory Overview": "機台在庫概要",
"Machine Replenishment": "機台補充",
"Machine Return": "機台返品",
@@ -113,6 +119,7 @@
"Select Product": "商品を選択",
"Select Warehouse": "倉庫を選択",
"Serial No.": "シリアル番号",
+ "Settings updated successfully.": "設定が正常に更新されました。",
"Shopping Cart": "ショッピングカート",
"Shopping Cart Feature": "ショッピングカート機能",
"Slot": "貨道",
@@ -145,6 +152,7 @@
"Transfers": "転送",
"Unpublish": "配信終了",
"Update Settings": "設定を更新",
+ "Update failed": "更新に失敗しました",
"Video": "動画",
"View Details": "詳細を表示",
"View Inventory": "在庫を表示",
@@ -161,5 +169,9 @@
"Warehouse to Warehouse": "倉庫間転送",
"Warehouse updated successfully.": "倉庫が正常に更新されました。",
"Welcome Gift": "登録特典",
- "Welcome Gift Feature": "来店特典機能"
+ "Welcome Gift Feature": "来店特典機能",
+ "Visual overview of all machine locations": "全機器位置のビジュアル概要",
+ "Online": "オンライン",
+ "Offline": "オフライン",
+ "Error": "エラー"
}
\ No newline at end of file
diff --git a/lang/zh_TW.json b/lang/zh_TW.json
index e26bad8..bca9352 100644
--- a/lang/zh_TW.json
+++ b/lang/zh_TW.json
@@ -165,6 +165,7 @@
"Cannot delete model that is currently in use by machines.": "無法刪除目前正在被機台使用的型號。",
"Cannot delete role with active users.": "無法刪除已有綁定帳號的角色。",
"Cannot delete warehouse with existing stock": "無法刪除仍有庫存的倉庫",
+ "Card Machine System": "刷卡機系統",
"Card Reader": "刷卡機",
"Card Reader No": "刷卡機編號",
"Card Reader Reboot": "刷卡機重啟",
@@ -175,6 +176,7 @@
"Card Terminal System": "刷卡機系統",
"Cash Module": "硬幣機 \/ 紙鈔機模組",
"Cash Module Feature": "現金模組功能",
+ "Cash Module Function": "現金模組功能",
"Category": "類別",
"Category Management": "分類管理",
"Category Name": "分類名稱",
@@ -198,6 +200,7 @@
"Click to Open Dashboard": "點擊開啟儀表板",
"Click to upload": "點擊上傳",
"Close Panel": "關閉面板",
+ "Coin\/Banknote Machine": "硬幣機\/紙鈔機",
"Coin\/Bill Acceptor": "硬幣機\/紙鈔機",
"Command Center": "指令中心",
"Command Confirmation": "指令確認",
@@ -229,7 +232,6 @@
"Confirm replenishment completed?": "確定補貨已完成?",
"Confirm this stock-in order?": "確定要確認此進貨單嗎?",
"Confirm this transfer?": "確定要確認此調撥作業嗎?",
- "Current Stocks": "目前庫存",
"Connected": "通訊中",
"Connecting...": "連線中",
"Connection lost (LWT)": "連線中斷",
@@ -273,12 +275,14 @@
"Created By": "建立者",
"Creation Time": "建立時間",
"Creator": "建立者",
+ "Credit Card": "信用卡",
"Credit Card \/ Contactless": "支援信用卡 \/ 感應支付",
"Critical": "嚴重",
"Current": "當前",
"Current Password": "當前密碼",
"Current Status": "當前狀態",
"Current Stock": "當前庫存",
+ "Current Stocks": "目前庫存",
"Current Type": "當前類型",
"Current:": "現:",
"Customer Details": "客戶詳情",
@@ -350,7 +354,9 @@
"Draft": "草稿",
"Duration": "時長",
"Duration (Seconds)": "播放秒數",
- "E.SUN QR Pay": "玉山掃碼支付",
+ "E.SUN Bank Scan": "玉山銀行掃碼",
+ "E.SUN Pay": "玉山 Pay",
+ "E.SUN QR Pay": "玉山銀行掃碼",
"E.SUN QR Scan": "玉山銀行標籤支付",
"E.SUN QR Scan Settings Description": "玉山銀行掃碼支付設定",
"EASY_MERCHANT_ID": "悠遊付 商店代號",
@@ -437,10 +443,11 @@
"Failed to update machine images: ": "更新機台圖片失敗:",
"Feature Settings": "功能設定",
"Feature Toggles": "功能開關",
- "Filter": "篩選",
"Fill Rate": "滿載率",
"Fill in the device repair or maintenance details": "填寫設備維修或保養詳情",
"Fill in the product details below": "請在下方填寫商品的詳細資訊",
+ "Filter": "篩選",
+ "Filter by Warehouse Presence": "依據倉庫存貨篩選",
"Firmware Version": "韌體版本",
"Firmware updated to :version": "韌體版本更新 : :version",
"Fleet Avg OEE": "全機台平均 OEE",
@@ -454,6 +461,7 @@
"Full Access": "全機台授權",
"Full Name": "名稱",
"Full Points": "全點數",
+ "Functional Settings": "功能設定",
"Games": "互動遊戲",
"General permissions not linked to a specific menu.": "未連結到特定選單的一般權限。",
"Gift Definitions": "禮品設定",
@@ -483,7 +491,7 @@
"Image": "圖片",
"Immediate": "立即",
"In Stock": "當前庫存",
- "Includes Credit Card\/Mobile Pay": "包括 \/信用卡\/卡片支付\/手機支付",
+ "Includes Credit Card\/Mobile Pay": "含信用卡\/行動支付",
"Indefinite": "無限期",
"Info": "一般",
"Initial Admin Account": "初始管理帳號",
@@ -559,6 +567,7 @@
"Machine Details": "機台詳情",
"Machine Distribution": "機台分布",
"Machine Distribution Map": "機台分布地圖",
+ "Visual overview of all machine locations": "所有機台位置的視覺化概覽",
"Machine Images": "機台照片",
"Machine Info": "機台資訊",
"Machine Information": "機台資訊",
@@ -583,6 +592,7 @@
"Machine Settings": "機台設定",
"Machine Status": "機台狀態",
"Machine Status List": "機台運行狀態列表",
+ "Machine System Settings": "機台系統設定",
"Machine Utilization": "機台稼動率",
"Machine created successfully.": "機台已成功建立。",
"Machine images updated successfully.": "機台圖片已成功更新。",
@@ -725,6 +735,7 @@
"No products found matching your criteria.": "找不到符合條件的商品。",
"No records found": "未找到相關紀錄",
"No replenishment orders found": "查無補貨單紀錄",
+ "No results found": "查無搜尋結果",
"No roles available": "目前沒有角色資料。",
"No roles found.": "找不到角色資料。",
"No slot data": "找不到貨道資料",
@@ -871,7 +882,7 @@
"Price \/ Member": "售價 \/ 會員價",
"Pricing Information": "價格資訊",
"Product": "商品",
- "Product / Stock": "商品 / 庫存",
+ "Product \/ Stock": "商品 \/ 庫存",
"Product Count": "商品數量",
"Product Details": "商品細項",
"Product ID": "商品編號",
@@ -1000,7 +1011,7 @@
"Saved.": "已儲存",
"Saving...": "儲存中...",
"Scale level and access control": "層級與存取控制",
- "Scan Pay": "掃碼支付",
+ "Scan Pay": "掃碼支付功能",
"Scan this code to quickly access the maintenance form for this device.": "掃描此 QR Code 即可快速進入此設備的維修單填寫頁面。",
"Schedule": "排程區間",
"Search Company Title...": "搜尋公司名稱...",
@@ -1062,9 +1073,11 @@
"Service Periods": "服務區間",
"Service Terms": "服務期程",
"Settings Saved": "設定已儲存",
+ "Settings updated successfully.": "設定更新成功。",
"Settlement": "結帳處理",
- "Shopping Cart": "購物車功能",
+ "Shopping Cart": "購物車",
"Shopping Cart Feature": "購物車功能",
+ "Shopping Cart Function": "購物車功能",
"Show": "顯示",
"Show material code field in products": "在商品資料中顯示物料編號欄位",
"Show points rules in products": "在商品資料中顯示點數規則相關欄位",
@@ -1259,6 +1272,7 @@
"Update Product": "更新商品",
"Update Settings": "更新設定",
"Update existing role and permissions.": "更新現有角色與權限設定。",
+ "Update failed": "更新失敗",
"Update identification for your asset": "更新您的資產識別名稱",
"Update your account's profile information and email address.": "更新您的帳號名稱、手機號碼與電子郵件地址。",
"Upload Image": "上傳圖片",
@@ -1320,10 +1334,9 @@
"Warranty Service": "保固服務",
"Warranty Start": "保固起始",
"Welcome Gift": "來店禮",
- "Welcome Gift Feature": "來店禮功能",
+ "Welcome Gift Feature": "迎賓禮功能",
+ "Welcome Gift Function": "迎賓禮功能",
"Welcome Gift Status": "來店禮",
- "Work Content": "工作內容",
- "Yes, regenerate": "確認重新產生",
"Yesterday": "昨日",
"You cannot assign permissions you do not possess.": "您無法指派您自身不具備的權限。",
"You cannot delete your own account.": "您無法刪除自己的帳號。",
@@ -1422,6 +1435,5 @@
"visit_gift": "來店禮",
"vs Yesterday": "較昨日",
"warehouses": "倉庫管理",
- "Filter by Warehouse Presence": "依據倉庫存貨篩選",
"待填寫": "待填寫"
}
\ No newline at end of file
diff --git a/resources/views/admin/basic-settings/machines/index.blade.php b/resources/views/admin/basic-settings/machines/index.blade.php
index 11215d2..7df50d1 100644
--- a/resources/views/admin/basic-settings/machines/index.blade.php
+++ b/resources/views/admin/basic-settings/machines/index.blade.php
@@ -8,6 +8,61 @@
modelSearch: '',
permissionSearch: '',
permissionCompanyId: '{{ request('company_id') }}',
+ isUpdatingSetting: false,
+ async toggleSystemSetting(machineId, field, value) {
+ if (this.isUpdatingSetting) return;
+ this.isUpdatingSetting = true;
+ try {
+ const res = await fetch(`/admin/basic-settings/machines/${machineId}/update-system-settings`, {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-TOKEN': document.querySelector('meta[name=\'csrf-token\']').content,
+ 'Accept': 'application/json'
+ },
+ body: JSON.stringify({ field, value })
+ });
+ const data = await res.json();
+ if (data.success) {
+ window.dispatchEvent(new CustomEvent('toast', { detail: { message: data.message, type: 'success' } }));
+ } else {
+ throw new Error(data.message || 'Update failed');
+ }
+ } catch (e) {
+ window.dispatchEvent(new CustomEvent('toast', { detail: { message: e.message, type: 'error' } }));
+ // Refresh content to reset toggle state on UI
+ this.searchInTab('system_settings');
+ } finally {
+ this.isUpdatingSetting = false;
+ }
+ },
+ async submitMachineSettings() {
+ if (this.isUpdatingSetting || !this.currentMachine) return;
+ this.isUpdatingSetting = true;
+ try {
+ const res = await fetch(`/admin/basic-settings/machines/${this.currentMachine.id}/update-system-settings`, {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-TOKEN': document.querySelector('meta[name=\'csrf-token\']').content,
+ 'Accept': 'application/json'
+ },
+ body: JSON.stringify({ settings: this.machineSettings })
+ });
+ const data = await res.json();
+ if (data.success) {
+ window.dispatchEvent(new CustomEvent('toast', { detail: { message: data.message, type: 'success' } }));
+ this.showMachineSettingsModal = false;
+ this.searchInTab('system_settings');
+ } else {
+ throw new Error(data.message || '{{ __('Update failed') }}');
+ }
+ } catch (e) {
+ window.dispatchEvent(new CustomEvent('toast', { detail: { message: e.message, type: 'error' } }));
+ } finally {
+ this.isUpdatingSetting = false;
+ }
+ },
showCreateMachineModal: false,
showPhotoModal: false,
showDetailDrawer: false,
@@ -25,6 +80,22 @@
maintenanceQrMachineName: '',
maintenanceQrUrl: '',
permissionSearchQuery: '',
+ showMachineSettingsModal: false,
+ machineSettings: {},
+ openMachineSettingsModal(machine) {
+ this.currentMachine = machine;
+ this.machineSettings = {
+ tax_invoice_enabled: machine.tax_invoice_enabled === true || machine.tax_invoice_enabled === 1 || machine.tax_invoice_enabled === '1',
+ card_terminal_enabled: machine.card_terminal_enabled === true || machine.card_terminal_enabled === 1 || machine.card_terminal_enabled === '1',
+ scan_pay_esun_enabled: machine.scan_pay_esun_enabled === true || machine.scan_pay_esun_enabled === 1 || machine.scan_pay_esun_enabled === '1',
+ scan_pay_linepay_enabled: machine.scan_pay_linepay_enabled === true || machine.scan_pay_linepay_enabled === 1 || machine.scan_pay_linepay_enabled === '1',
+ shopping_cart_enabled: machine.shopping_cart_enabled === true || machine.shopping_cart_enabled === 1 || machine.shopping_cart_enabled === '1',
+ welcome_gift_enabled: machine.welcome_gift_enabled === true || machine.welcome_gift_enabled === 1 || machine.welcome_gift_enabled === '1',
+ cash_module_enabled: machine.cash_module_enabled === true || machine.cash_module_enabled === 1 || machine.cash_module_enabled === '1',
+ member_system_enabled: machine.member_system_enabled === true || machine.member_system_enabled === 1 || machine.member_system_enabled === '1'
+ };
+ this.showMachineSettingsModal = true;
+ },
openMaintenanceQr(machine) {
this.maintenanceQrMachineName = machine.name;
const baseUrl = '{{ route('admin.maintenance.create', ['serial_no' => 'SERIAL_NO']) }}';
@@ -197,7 +268,7 @@
// === 搜尋/分頁 AJAX(僅在搜尋或換頁時觸發,Tab 切換不走此路) ===
async searchInTab(tabName, extraQuery = '') {
this.tabLoading = true;
- const searchMap = { machines: this.machineSearch, models: this.modelSearch, permissions: this.permissionSearch };
+ const searchMap = { machines: this.machineSearch, models: this.modelSearch, permissions: this.permissionSearch, system_settings: this.machineSearch, distribution: '' };
const search = searchMap[tabName] || '';
let qs = `tab=${tabName}&_ajax=1`;
if (search) qs += `&search=${encodeURIComponent(search)}`;
@@ -286,7 +357,7 @@
});
// 首次載入時綁定每個 Tab 的分頁連結
this.$nextTick(() => {
- ['machines', 'models', 'permissions'].forEach(t => {
+ ['machines', 'models', 'permissions', 'system_settings'].forEach(t => {
const ref = this.$refs[t + 'Content'];
if (ref) this.bindPaginationLinks(ref, t);
});
@@ -294,6 +365,7 @@
// Tab 切換時同步 URL
this.$watch('tab', (newTab) => {
history.pushState({}, '', `{{ route('admin.basic-settings.machines.index') }}?tab=${newTab}`);
+ window.dispatchEvent(new CustomEvent('tab-changed', { detail: { tab: newTab } }));
});
// 瀏覽器上一頁/下一頁
window.addEventListener('popstate', () => {
@@ -302,19 +374,209 @@
});
}
}" @execute-regenerate.window="executeRegeneration($event.detail)">
+
+
+
+ {{ __('Edit Machine System Settings') }}
+
+
{{ __('Management of operational parameters and models') }}
+{{ __('Management of operational parameters and models') }}
{{ __('Visual overview of all machine locations') }}
+| + {{ __('Machine Information') }} + | ++ {{ __('Company') }} + | ++ {{ __('Enabled Features') }} + | ++ {{ __('Actions') }} + | +
|---|---|---|---|
|
+
+
+
+
+
+
+
+
+ {{ $machine->name }}
+
+
+ {{ $machine->serial_no }}
+
+ |
+ + {{ $machine->company?->name ?? __('System') }} + | +
+
+ @php
+ $activeFeatures = [];
+ if ($machine->tax_invoice_enabled) $activeFeatures[] = __('Electronic Invoice');
+ if ($machine->card_terminal_enabled) $activeFeatures[] = __('Includes Credit Card/Mobile Pay');
+ if ($machine->scan_pay_esun_enabled) $activeFeatures[] = __('E.SUN Bank Scan');
+ if ($machine->scan_pay_linepay_enabled) $activeFeatures[] = __('LinePay Payment');
+ if ($machine->shopping_cart_enabled) $activeFeatures[] = __('Shopping Cart');
+ if ($machine->welcome_gift_enabled) $activeFeatures[] = __('Welcome Gift');
+ if ($machine->cash_module_enabled) $activeFeatures[] = __('Coin/Banknote Machine');
+ if ($machine->member_system_enabled) $activeFeatures[] = __('Member System');
+ @endphp
+
+ @forelse($activeFeatures as $feature)
+ {{ $feature }}
+ @empty
+ {{ __('None') }}
+ @endforelse
+
+ |
+ + + | +
|
+
+
+
+
+
+ {{ __('No machines found') }} + |
+ |||
{{ __('Manage all tenant accounts and validity') }} @@ -603,27 +555,6 @@ @if($settings['enable_points'] ?? false) {{ __('Points') }} @endif - @if($settings['tax_invoice'] ?? false) - {{ __('Electronic Invoice') }} - @endif - @if($settings['card_terminal'] ?? false) - {{ __('Card System') }} - @endif - @if($settings['scan_pay_esun'] ?? false) - {{ __('ESUN') }} - @endif - @if($settings['scan_pay_linepay'] ?? false) - {{ __('LinePay') }} - @endif - @if($settings['shopping_cart'] ?? false) - {{ __('Shopping Cart') }} - @endif - @if($settings['welcome_gift'] ?? false) - {{ __('Welcome Gift') }} - @endif - @if($settings['cash_module'] ?? false) - {{ __('Cash Module') }} - @endif @endif
{{ __('Status') }}
+{{ __('Status') }}
{{ __('Created By') }}
- +{{ __('Created By') }}
+{{ __('Created At') }}
- +{{ __('Created At') }}
+{{ __('Approved At') }}
- +{{ __('Approved At') }}
+{{ __('Note') }}
+{{ __('Note') }}
| {{ __('Product') }} | +{{ __('Product') }} | ++ {{ __('Total') }} + | @foreach($inventory_warehouses as $w) -+ |
- {{ $w->name }}
- {{ $w->type === 'main' ? __('Main') : __('Branch') }}
+ {{ $w->name }}
+ {{ $w->type === 'main' ? __('Main') : __('Branch') }}
|
@endforeach
- {{ __('Total') }} |
|---|---|---|---|---|---|
|
-
-
+
+ |
+
+
@if($product->image_url)
-
- {{ $product->localized_name }}
- {{ $product->barcode ?? '-' }}
+
+ {{ $product->localized_name }}
+ @if($product->barcode)
+ {{ $product->barcode }}
+ @endif
+
+ {{ $totalQuantity }}
+
+ |
@foreach($inventory_warehouses as $w)
@php
$stock = $product->stocks->firstWhere('warehouse_id', $w->id);
@@ -72,11 +89,6 @@
@endif
|
@endforeach
- - - {{ $totalQuantity }} - - | ||