diff --git a/.agents/skills/mqtt-communication-specs/SKILL.md b/.agents/skills/mqtt-communication-specs/SKILL.md index 0b50835..c1ec773 100644 --- a/.agents/skills/mqtt-communication-specs/SKILL.md +++ b/.agents/skills/mqtt-communication-specs/SKILL.md @@ -174,7 +174,7 @@ Mqtt3Client client = MqttClient.builder() | :--- | :--- | :--- | :--- | | **0416** | Microwave delivery door opening | info | 正在打開微波爐進貨口門 | | **0417** | Microwave delivery door open error | error | 微波爐進貨口門打開錯誤 | -| **0418** | Pushing bento into microwave | info | 正在將便當推入微波爐 | +| **0418** | Pushing product into microwave | info | 正在將商品推入微波爐 | | **0419** | Microwave delivery door closing | info | 正在關閉微波爐進貨口門 | | **0420** | Microwave delivery door close error | error | 微波爐進貨口門關閉錯誤 | @@ -182,9 +182,9 @@ Mqtt3Client client = MqttClient.builder() | 代碼 | 英文 Key (i18n) | 級別 | 範例繁中翻譯 | | :--- | :--- | :--- | :--- | -| **0421** | Bento not detected in microwave | error | 微波爐內沒檢測到便當 | -| **0422** | Bento heating | info | 便當正在加熱 | -| **0423** | Bento heating remaining time | info | 便當加熱剩餘時間秒 | +| **0421** | Product not detected in microwave | error | 微波爐內未檢測到商品 | +| **0422** | Product heating | info | 商品正在加熱 | +| **0423** | Product heating remaining time | info | 商品加熱剩餘時間秒 | | **0424** | Purchase successful | info | ✅ 購買成功 | | **0431** | Microwave push rod push error | error | 微波爐內推桿推出錯誤 | | **0432** | Microwave push rod retract error | error | 微波爐內推桿收回錯誤 | @@ -212,7 +212,7 @@ Mqtt3Client client = MqttClient.builder() | **0434** | Pickup door closed (cart mode) | info | 取貨口門關閉成功 (購物車) | | **0435** | Liquid dispense paused | warning | 暫停出液 (液體機) | | **0441** | Pickup door unlocked | info | 取貨口門開鎖上報 | -| **04FF** | Bento purchase terminated | error | 便當購買終止 | +| **04FF** | Purchase terminated | error | 購買終止 | ### 3.3 交易生命週期上報 (Transaction) - `machine/{serial_no}/transaction` diff --git a/app/Models/Machine/MachineLog.php b/app/Models/Machine/MachineLog.php index ae3de14..231dd52 100644 --- a/app/Models/Machine/MachineLog.php +++ b/app/Models/Machine/MachineLog.php @@ -99,11 +99,12 @@ class MachineLog extends Model { $context = $this->context; - // 若 context 中已有翻譯標籤 (B013 封裝),則進行動態重組 + // B013 封裝:優先用目前代碼表重組,讓舊日誌也能吃到最新文案。 if (isset($context['translated_label'])) { - $label = __($context['translated_label']); + $code = $context['raw_code'] ?? $context['error_code'] ?? '0000'; + $mapping = \App\Services\Machine\MachineService::ERROR_CODE_MAP[$code] ?? null; + $label = __($mapping['label'] ?? $context['translated_label']); $tid = $context['tid'] ?? null; - $code = $context['raw_code'] ?? '0000'; if ($tid) { return __('Slot') . " {$tid}: {$label} (Code: {$code})"; diff --git a/app/Models/Transaction/Order.php b/app/Models/Transaction/Order.php index 23d87fb..ba72068 100644 --- a/app/Models/Transaction/Order.php +++ b/app/Models/Transaction/Order.php @@ -121,6 +121,47 @@ class Order extends Model return self::getPaymentTypeLabels()[$this->payment_type] ?? __('Unknown'); } + public function getMaskedPickupRecipientAttribute(): ?string + { + if (empty($this->member_barcode)) { + return null; + } + + return self::maskPickupRecipientName($this->member_barcode); + } + + public static function maskPickupRecipientName(string $value): string + { + $value = trim($value); + + if ($value === '') { + return $value; + } + + if (preg_match('/^([^\s((]+)(.*)$/us', $value, $matches) !== 1) { + return self::maskName($value); + } + + return self::maskName($matches[1]) . ($matches[2] ?? ''); + } + + private static function maskName(string $name): string + { + $length = mb_strlen($name); + + if ($length <= 1) { + return $name; + } + + if ($length === 2) { + return mb_substr($name, 0, 1) . 'O'; + } + + return mb_substr($name, 0, 1) + . str_repeat('O', $length - 2) + . mb_substr($name, -1); + } + public function machine() { return $this->belongsTo(Machine::class); diff --git a/app/Services/Machine/MachineService.php b/app/Services/Machine/MachineService.php index a2efa8e..d11a05f 100644 --- a/app/Services/Machine/MachineService.php +++ b/app/Services/Machine/MachineService.php @@ -18,7 +18,7 @@ class MachineService * B013: 硬體狀態代碼對照表 (Hardware Status Code Mapping) * * 代碼格式:Command 0x04 + Status Byte,例如 0x04+0x03 = '0403' - * 出貨結果判定:僅 0402 (出貨成功) 與 0424 (便當取出成功) 視為成功, + * 出貨結果判定:僅 0402 (出貨成功) 與 0424 (商品取出成功) 視為成功, * 其餘出貨結果碼均應觸發退款。 * * 參考文件:廠商硬體通訊協議 Command(0x04) 狀態定義 @@ -57,15 +57,15 @@ class MachineService // --- 微波爐進貨口門 --- '0416' => ['label' => 'Microwave delivery door opening', 'level' => 'info'], // 正在打開微波爐進貨口門 '0417' => ['label' => 'Microwave delivery door open error', 'level' => 'error'], // 微波爐進貨口門打開錯誤 - '0418' => ['label' => 'Pushing bento into microwave', 'level' => 'info'], // 正在將便當推入微波爐 + '0418' => ['label' => 'Pushing product into microwave', 'level' => 'info'], // 正在將商品推入微波爐 '0419' => ['label' => 'Microwave delivery door closing', 'level' => 'info'], // 正在關閉微波爐進貨口門 '0420' => ['label' => 'Microwave delivery door close error', 'level' => 'error'], // 微波爐進貨口門關閉錯誤 // --- 微波爐內部 --- - '0421' => ['label' => 'Bento not detected in microwave', 'level' => 'error'], // 微波爐內沒檢測到便當 - '0422' => ['label' => 'Bento heating', 'level' => 'info'], // 便當正在加熱 - '0423' => ['label' => 'Bento heating remaining time', 'level' => 'info'], // 便當加熱剩餘時間 (貨道號=秒數) - '0424' => ['label' => 'Purchase successful', 'level' => 'info'], // ✅ 購買成功 (原 Bento ready for pickup) + '0421' => ['label' => 'Product not detected in microwave', 'level' => 'error'], // 微波爐內未檢測到商品 + '0422' => ['label' => 'Product heating', 'level' => 'info'], // 商品正在加熱 + '0423' => ['label' => 'Product heating remaining time', 'level' => 'info'], // 商品加熱剩餘時間 (貨道號=秒數) + '0424' => ['label' => 'Purchase successful', 'level' => 'info'], // ✅ 購買成功 '0431' => ['label' => 'Microwave push rod push error', 'level' => 'error'], // 微波爐內推桿推出錯誤 '0432' => ['label' => 'Microwave push rod retract error', 'level' => 'error'], // 微波爐內推桿收回錯誤 @@ -87,7 +87,7 @@ class MachineService '0435' => ['label' => 'Liquid dispense paused', 'level' => 'warning'], // 暫停出液 // --- 終止 --- - '04FF' => ['label' => 'Bento purchase terminated', 'level' => 'error'], // 便當購買終止 + '04FF' => ['label' => 'Purchase terminated', 'level' => 'error'], // 購買終止 // ═══════════════════════════════════════════════════════════════ // 貨道與馬達狀態類 (Prefix: 02 - SLOT_STATUS) @@ -116,7 +116,7 @@ class MachineService * * 僅以下代碼視為出貨成功,其餘出貨結果碼均應觸發退款。 * - 0402: 一般出貨成功 - * - 0424: 便當取出成功 (微波爐機型) + * - 0424: 商品取出成功 (微波爐機型) */ public const DISPENSE_SUCCESS_CODES = ['0402', '0424']; diff --git a/lang/en.json b/lang/en.json index e76b31f..2ae2520 100644 --- a/lang/en.json +++ b/lang/en.json @@ -219,10 +219,10 @@ "Before Qty": "Before Qty", "Belongs To": "Belongs To", "Belongs To Company": "Belongs To Company", - "Bento heating": "Bento heating", - "Bento heating remaining time": "Bento heating remaining time", - "Bento not detected in microwave": "Bento not detected in microwave", - "Bento purchase terminated": "Bento purchase terminated", + "Product heating": "Product heating", + "Product heating remaining time": "Product heating remaining time", + "Product not detected in microwave": "Product not detected in microwave", + "Purchase terminated": "Purchase terminated", "Bill Acceptor": "Bill Acceptor", "Bracelet drop not detected": "Bracelet drop not detected", "Bracelet scan failed": "Bracelet scan failed", @@ -1490,7 +1490,7 @@ "Purchasing": "Purchasing", "Purpose": "Purpose", "Push Status": "Push Status", - "Pushing bento into microwave": "Pushing bento into microwave", + "Pushing product into microwave": "Pushing product into microwave", "QR": "QR", "QR CODE": "QR CODE", "QR Code": "QR Code", diff --git a/lang/ja.json b/lang/ja.json index 0d8a840..5482f0a 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -219,10 +219,10 @@ "Before Qty": "変動前数量", "Belongs To": "会社名", "Belongs To Company": "所属会社", - "Bento heating": "お弁当加熱中", - "Bento heating remaining time": "お弁当加熱残り時間", - "Bento not detected in microwave": "電子レンジ内お弁当未検出", - "Bento purchase terminated": "お弁当購入中止", + "Product heating": "商品加熱中", + "Product heating remaining time": "商品加熱残り時間", + "Product not detected in microwave": "電子レンジ内商品未検出", + "Purchase terminated": "購入中止", "Bill Acceptor": "紙幣識別機", "Bracelet drop not detected": "ブレスレット落下未検出", "Bracelet scan failed": "ブレスレットスキャン失敗", @@ -1490,7 +1490,7 @@ "Purchasing": "購入中", "Purpose": "用途", "Push Status": "アラート状態", - "Pushing bento into microwave": "お弁当を電子レンジに投入中", + "Pushing product into microwave": "商品を電子レンジに投入中", "QR": "QR", "QR CODE": "QRコード", "QR Code": "QRコード", diff --git a/lang/zh_TW.json b/lang/zh_TW.json index ad7dbc9..99e576d 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -219,10 +219,10 @@ "Before Qty": "異動前數量", "Belongs To": "公司名稱", "Belongs To Company": "公司名稱", - "Bento heating": "便當正在加熱", - "Bento heating remaining time": "便當加熱剩餘時間", - "Bento not detected in microwave": "微波爐內沒檢測到便當", - "Bento purchase terminated": "便當購買終止", + "Product heating": "商品正在加熱", + "Product heating remaining time": "商品加熱剩餘時間", + "Product not detected in microwave": "微波爐內未檢測到商品", + "Purchase terminated": "購買終止", "Bill Acceptor": "紙鈔機", "Bracelet drop not detected": "沒檢測到手環掉入取貨斗", "Bracelet scan failed": "沒掃碼到手環", @@ -1490,7 +1490,7 @@ "Purchasing": "購買中", "Purpose": "用途", "Push Status": "告警狀態", - "Pushing bento into microwave": "正在將便當推入微波爐", + "Pushing product into microwave": "正在將商品推入微波爐", "QR": "二維碼", "QR CODE": "二維碼", "QR Code": "QR Code", diff --git a/resources/views/admin/sales/partials/order-detail-panel.blade.php b/resources/views/admin/sales/partials/order-detail-panel.blade.php index a201394..b35bb64 100644 --- a/resources/views/admin/sales/partials/order-detail-panel.blade.php +++ b/resources/views/admin/sales/partials/order-detail-panel.blade.php @@ -137,7 +137,7 @@

{{ __('Pickup Recipient (Prescription Slip)') }}

-

{{ $order->member_barcode }}

+

{{ $order->masked_pickup_recipient }}

diff --git a/resources/views/admin/sales/partials/tab-orders.blade.php b/resources/views/admin/sales/partials/tab-orders.blade.php index 0463c11..3a32b21 100644 --- a/resources/views/admin/sales/partials/tab-orders.blade.php +++ b/resources/views/admin/sales/partials/tab-orders.blade.php @@ -252,7 +252,7 @@ - {{ $order->member_barcode }} + {{ $order->masked_pickup_recipient }} @endif @@ -409,7 +409,7 @@ - {{ $order->member_barcode }} + {{ $order->masked_pickup_recipient }} @endif diff --git a/tests/Unit/OrderPickupRecipientMaskTest.php b/tests/Unit/OrderPickupRecipientMaskTest.php new file mode 100644 index 0000000..8129665 --- /dev/null +++ b/tests/Unit/OrderPickupRecipientMaskTest.php @@ -0,0 +1,22 @@ +assertSame('鄭O', Order::maskPickupRecipientName('鄭英')); + $this->assertSame('鄭O英', Order::maskPickupRecipientName('鄭小英')); + $this->assertSame('鄭OO英', Order::maskPickupRecipientName('鄭曉小英')); + } + + public function test_it_keeps_pickup_recipient_suffix(): void + { + $this->assertSame('黃O美 (2593)', Order::maskPickupRecipientName('黃麗美 (2593)')); + $this->assertSame("黃O美\n(2593)", Order::maskPickupRecipientName("黃麗美\n(2593)")); + } +}