From ae4556584f4af745fbfa65973c011a4aa9120ecf Mon Sep 17 00:00:00 2001 From: sky121113 Date: Fri, 19 Jun 2026 09:16:13 +0800 Subject: [PATCH] =?UTF-8?q?[FEAT]=20=E9=8A=B7=E5=94=AE=E7=B4=80=E9=8C=84?= =?UTF-8?q?=E6=B5=81=E6=B0=B4=E8=99=9F=E9=A1=AF=E7=A4=BA=E5=89=9D=E9=99=A4?= =?UTF-8?q?=E6=A9=9F=E5=8F=B0=E5=BA=8F=E8=99=9F=E5=89=8D=E7=B6=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增 HasDisplayFlowId trait,提供 display_flow_id accessor:僅顯示時剝除 flow_id 開頭的機台序號前綴,DB 仍存完整 serial+flow_id 唯一值供去重/冪等/對帳判斷。 2. Order 與 Invoice 兩 Model 套用此 trait。 3. 訂單詳情面板 (order-detail-panel) 與發票匯出 (SalesController) 改顯示 display_flow_id,呈現乾淨易讀的機台流水號。 4. accessor 具防禦性:機台關聯為 null 或舊的未前綴資料皆原樣顯示,不誤剝。 5. 新增測試驗證 display_flow_id 正確剝除序號前綴且 DB 值維持完整。 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Controllers/Admin/SalesController.php | 2 +- app/Models/Transaction/Invoice.php | 3 +- app/Models/Transaction/Order.php | 3 +- app/Traits/HasDisplayFlowId.php | 28 +++++++++++++++++++ .../partials/order-detail-panel.blade.php | 3 +- .../Transaction/FinalizeIdempotencyTest.php | 14 ++++++++++ 6 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 app/Traits/HasDisplayFlowId.php diff --git a/app/Http/Controllers/Admin/SalesController.php b/app/Http/Controllers/Admin/SalesController.php index 5f41984..e328e4c 100644 --- a/app/Http/Controllers/Admin/SalesController.php +++ b/app/Http/Controllers/Admin/SalesController.php @@ -1030,7 +1030,7 @@ class SalesController extends Controller $row = [ $inv->invoice_no ?: '---', $inv->invoice_date ?: '---', - $inv->flow_id ?: '---', + $inv->display_flow_id ?: '---', $inv->machine->name ?? ($inv->order->machine->name ?? 'Unknown'), $inv->machine->serial_no ?? ($inv->order->machine->serial_no ?? '---'), $inv->order->order_no ?? '---', diff --git a/app/Models/Transaction/Invoice.php b/app/Models/Transaction/Invoice.php index 2fb7991..f802f44 100644 --- a/app/Models/Transaction/Invoice.php +++ b/app/Models/Transaction/Invoice.php @@ -6,13 +6,14 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use App\Traits\TenantScoped; +use App\Traits\HasDisplayFlowId; class Invoice extends Model { // TenantScoped:自動以登入者 company_id 過濾(含 route-model binding 與列表查詢), // 防止跨公司讀取/操作他人發票。console(佇列 Job / reconcile 命令)會自動跳過 scope, // 系統身分仍可跨公司開立/對帳。 - use HasFactory, SoftDeletes, TenantScoped; + use HasFactory, SoftDeletes, TenantScoped, HasDisplayFlowId; protected $fillable = [ 'company_id', diff --git a/app/Models/Transaction/Order.php b/app/Models/Transaction/Order.php index 5f6ccbb..d8840ce 100644 --- a/app/Models/Transaction/Order.php +++ b/app/Models/Transaction/Order.php @@ -6,12 +6,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use App\Traits\TenantScoped; +use App\Traits\HasDisplayFlowId; use App\Models\Machine\Machine; use App\Models\Member\Member; class Order extends Model { - use HasFactory, SoftDeletes, TenantScoped; + use HasFactory, SoftDeletes, TenantScoped, HasDisplayFlowId; // 支付狀態 public const PAYMENT_STATUS_FAILED = 0; diff --git a/app/Traits/HasDisplayFlowId.php b/app/Traits/HasDisplayFlowId.php new file mode 100644 index 0000000..4088b1f --- /dev/null +++ b/app/Traits/HasDisplayFlowId.php @@ -0,0 +1,28 @@ +flow_id ?? ''); + $serial = $this->machine?->serial_no; + + // 僅在確實以該機台序號開頭時才剝除前綴;舊的未前綴資料原樣顯示(防禦)。 + if ($serial !== null && $serial !== '' && str_starts_with($flowId, $serial)) { + return substr($flowId, strlen($serial)); + } + + return $flowId; + } +} 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 cc457f6..d93a9ca 100644 --- a/resources/views/admin/sales/partials/order-detail-panel.blade.php +++ b/resources/views/admin/sales/partials/order-detail-panel.blade.php @@ -102,7 +102,8 @@

{{ __('Machine Flow ID') }}

-

{{ $order->flow_id }}

+ {{-- 顯示去前綴序號的乾淨流水號(DB 仍存完整 serial+flow_id 唯一值供後台判斷) --}} +

{{ $order->display_flow_id }}

diff --git a/tests/Feature/Transaction/FinalizeIdempotencyTest.php b/tests/Feature/Transaction/FinalizeIdempotencyTest.php index 684610a..ec9480c 100644 --- a/tests/Feature/Transaction/FinalizeIdempotencyTest.php +++ b/tests/Feature/Transaction/FinalizeIdempotencyTest.php @@ -101,6 +101,20 @@ class FinalizeIdempotencyTest extends TestCase $this->assertEquals('2222222222' . $raw, $orderB->flow_id); } + /** display_flow_id 顯示用 accessor:剝除機台序號前綴,DB 仍存完整 serial+raw 唯一值。 */ + public function test_display_flow_id_strips_serial_prefix(): void + { + $serial = '2501000062'; + $raw = '202606190839470011'; + $this->makeMachine($serial); + + $order = $this->service->finalizeTransaction($this->completedPayload($serial, $raw)); + + // DB 值維持完整 28 碼;顯示值剝掉序號前綴 → 乾淨 18 碼 + $this->assertEquals($serial . $raw, $order->flow_id); + $this->assertEquals($raw, $order->fresh()->display_flow_id); + } + /** RelateNumber = serial + rawFlowId(無分隔符、≤30、與線上推導逐字等價,不可雙重 serial)。 */ public function test_relate_number_equals_serial_plus_raw_flow_id(): void {