diff --git a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
index 042c9c3..b007952 100644
--- a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
+++ b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php
@@ -3,17 +3,12 @@
namespace App\Http\Controllers\Admin\BasicSettings;
use App\Http\Controllers\Admin\AdminController;
-use App\Jobs\Product\SendProductSyncCommandJob;
use App\Models\Machine\Machine;
use App\Models\Machine\MachineModel;
-use App\Models\Machine\MachineProductPrice;
-use App\Models\Product\Product;
use App\Models\System\Company;
use App\Models\System\PaymentConfig;
use App\Traits\ImageHandler;
use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Storage;
@@ -202,91 +197,6 @@ class MachineSettingController extends AdminController
return view('admin.basic-settings.machines.edit', compact('machine', 'models', 'paymentConfigs', 'companies'));
}
- /**
- * 機台專屬定價頁:列出該機台「所屬公司的完整商品目錄」(非僅貨道商品),
- * 可在上貨前先把機台價/會員價訂好。未填=沿用全域 products 價。
- */
- public function pricing(Machine $machine): View
- {
- $products = Product::where('company_id', $machine->company_id)
- ->active()
- ->orderBy('name')
- ->get(['id', 'name', 'image_url', 'barcode', 'price', 'member_price']);
-
- $overrides = $machine->productPrices()->get()->keyBy('product_id');
-
- $items = $products->map(function (Product $p) use ($overrides) {
- $ov = $overrides->get($p->id);
- return [
- 'product_id' => $p->id,
- 'name' => $p->name,
- 'image_url' => $p->image_url,
- 'barcode' => $p->barcode,
- 'global_price' => (float) $p->price,
- 'global_member_price' => $p->member_price !== null ? (float) $p->member_price : null,
- 'override_price' => $ov && $ov->price !== null ? (float) $ov->price : null,
- 'override_member_price' => $ov && $ov->member_price !== null ? (float) $ov->member_price : null,
- ];
- })->values();
-
- return view('admin.basic-settings.machines.pricing', compact('machine', 'items'));
- }
-
- /**
- * 批次儲存機台專屬定價。
- *
- * - price/member_price 皆空 → 刪除覆蓋,回到全域價。
- * - 任一有值 → 建立/更新覆蓋;會員價於 B012 下發時自動夾為不高於機台售價。
- * - 用 quiet 寫入避免逐筆觸發 observer 重複推送,最後統一推一次 B012。
- * - 商品須屬於該機台公司(跨租戶防護)。
- */
- public function updatePricing(Request $request, Machine $machine): \Illuminate\Http\JsonResponse
- {
- $validated = $request->validate([
- 'items' => 'required|array',
- 'items.*.product_id' => 'required|integer|exists:products,id',
- 'items.*.price' => 'nullable|numeric|min:1|max:99999999',
- 'items.*.member_price' => 'nullable|numeric|min:1|max:99999999',
- ]);
-
- $allowedProductIds = Product::where('company_id', $machine->company_id)
- ->pluck('id')
- ->flip();
-
- DB::transaction(function () use ($validated, $machine, $allowedProductIds) {
- foreach ($validated['items'] as $item) {
- $productId = (int) $item['product_id'];
- if (!$allowedProductIds->has($productId)) {
- continue;
- }
-
- $price = isset($item['price']) && $item['price'] !== '' ? (float) $item['price'] : null;
- $memberPrice = isset($item['member_price']) && $item['member_price'] !== '' ? (float) $item['member_price'] : null;
-
- if ($price === null && $memberPrice === null) {
- $machine->productPrices()->where('product_id', $productId)->delete();
- continue;
- }
-
- $row = MachineProductPrice::firstOrNew([
- 'machine_id' => $machine->id,
- 'product_id' => $productId,
- ]);
- $row->price = $price;
- $row->member_price = $memberPrice;
- $row->saveQuietly();
- }
- });
-
- // 統一推一次 B012 同步給該機台(覆蓋於請求當下即時套用,無需失效公司快取)
- SendProductSyncCommandJob::dispatch($machine->id, __('Machine pricing updated'), Auth::id());
-
- return response()->json([
- 'success' => true,
- 'message' => __('Machine pricing saved and sync command pushed.'),
- ]);
- }
-
/**
* 更新機台詳細參數
*/
diff --git a/app/Http/Controllers/Admin/MachineController.php b/app/Http/Controllers/Admin/MachineController.php
index 6ac1339..fe8d57b 100644
--- a/app/Http/Controllers/Admin/MachineController.php
+++ b/app/Http/Controllers/Admin/MachineController.php
@@ -2,10 +2,15 @@
namespace App\Http\Controllers\Admin;
+use App\Jobs\Product\SendProductSyncCommandJob;
use App\Models\Machine\Machine;
+use App\Models\Machine\MachineProductPrice;
+use App\Models\Product\Product;
use App\Models\System\Company;
use App\Services\Machine\MachineService;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class MachineController extends AdminController
@@ -257,6 +262,91 @@ class MachineController extends AdminController
}
}
+ /**
+ * 機台專屬定價頁:列出該機台「所屬公司的完整商品目錄」(非僅貨道商品),
+ * 可在上貨前先把機台價/會員價訂好。未填=沿用全域 products 價。
+ */
+ public function pricing(Machine $machine): View
+ {
+ $products = Product::where('company_id', $machine->company_id)
+ ->active()
+ ->orderBy('name')
+ ->get(['id', 'name', 'image_url', 'barcode', 'price', 'member_price']);
+
+ $overrides = $machine->productPrices()->get()->keyBy('product_id');
+
+ $items = $products->map(function (Product $p) use ($overrides) {
+ $ov = $overrides->get($p->id);
+ return [
+ 'product_id' => $p->id,
+ 'name' => $p->name,
+ 'image_url' => $p->image_url,
+ 'barcode' => $p->barcode,
+ 'global_price' => (float) $p->price,
+ 'global_member_price' => $p->member_price !== null ? (float) $p->member_price : null,
+ 'override_price' => $ov && $ov->price !== null ? (float) $ov->price : null,
+ 'override_member_price' => $ov && $ov->member_price !== null ? (float) $ov->member_price : null,
+ ];
+ })->values();
+
+ return view('admin.machines.pricing', compact('machine', 'items'));
+ }
+
+ /**
+ * 批次儲存機台專屬定價。
+ *
+ * - price/member_price 皆空 → 刪除覆蓋,回到全域價。
+ * - 任一有值 → 建立/更新覆蓋;會員價於 B012 下發時自動夾為不高於機台售價。
+ * - 用 quiet 寫入避免逐筆觸發 observer 重複推送,最後統一推一次 B012。
+ * - 商品須屬於該機台公司(跨租戶防護)。
+ */
+ public function updatePricing(Request $request, Machine $machine): \Illuminate\Http\JsonResponse
+ {
+ $validated = $request->validate([
+ 'items' => 'required|array',
+ 'items.*.product_id' => 'required|integer|exists:products,id',
+ 'items.*.price' => 'nullable|numeric|min:1|max:99999999',
+ 'items.*.member_price' => 'nullable|numeric|min:1|max:99999999',
+ ]);
+
+ $allowedProductIds = Product::where('company_id', $machine->company_id)
+ ->pluck('id')
+ ->flip();
+
+ DB::transaction(function () use ($validated, $machine, $allowedProductIds) {
+ foreach ($validated['items'] as $item) {
+ $productId = (int) $item['product_id'];
+ if (!$allowedProductIds->has($productId)) {
+ continue;
+ }
+
+ $price = isset($item['price']) && $item['price'] !== '' ? (float) $item['price'] : null;
+ $memberPrice = isset($item['member_price']) && $item['member_price'] !== '' ? (float) $item['member_price'] : null;
+
+ if ($price === null && $memberPrice === null) {
+ $machine->productPrices()->where('product_id', $productId)->delete();
+ continue;
+ }
+
+ $row = MachineProductPrice::firstOrNew([
+ 'machine_id' => $machine->id,
+ 'product_id' => $productId,
+ ]);
+ $row->price = $price;
+ $row->member_price = $memberPrice;
+ $row->saveQuietly();
+ }
+ });
+
+ // 統一推一次 B012 同步給該機台(覆蓋於請求當下即時套用,無需失效公司快取)
+ SendProductSyncCommandJob::dispatch($machine->id, __('Machine pricing updated'), Auth::id());
+
+ return response()->json([
+ 'success' => true,
+ 'message' => __('Machine pricing saved and sync command pushed.'),
+ ]);
+ }
+
/**
* 取得機台統計數據 (AJAX)
*/
diff --git a/resources/views/admin/basic-settings/machines/partials/tab-machines.blade.php b/resources/views/admin/basic-settings/machines/partials/tab-machines.blade.php
index 3fcdbf2..cea18f6 100644
--- a/resources/views/admin/basic-settings/machines/partials/tab-machines.blade.php
+++ b/resources/views/admin/basic-settings/machines/partials/tab-machines.blade.php
@@ -149,13 +149,6 @@