[FEAT] 銷售紀錄流水號顯示剝除機台序號前綴
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) <noreply@anthropic.com>
This commit is contained in:
parent
b7e8401a99
commit
ae4556584f
@ -1030,7 +1030,7 @@ class SalesController extends Controller
|
|||||||
$row = [
|
$row = [
|
||||||
$inv->invoice_no ?: '---',
|
$inv->invoice_no ?: '---',
|
||||||
$inv->invoice_date ?: '---',
|
$inv->invoice_date ?: '---',
|
||||||
$inv->flow_id ?: '---',
|
$inv->display_flow_id ?: '---',
|
||||||
$inv->machine->name ?? ($inv->order->machine->name ?? 'Unknown'),
|
$inv->machine->name ?? ($inv->order->machine->name ?? 'Unknown'),
|
||||||
$inv->machine->serial_no ?? ($inv->order->machine->serial_no ?? '---'),
|
$inv->machine->serial_no ?? ($inv->order->machine->serial_no ?? '---'),
|
||||||
$inv->order->order_no ?? '---',
|
$inv->order->order_no ?? '---',
|
||||||
|
|||||||
@ -6,13 +6,14 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use App\Traits\TenantScoped;
|
use App\Traits\TenantScoped;
|
||||||
|
use App\Traits\HasDisplayFlowId;
|
||||||
|
|
||||||
class Invoice extends Model
|
class Invoice extends Model
|
||||||
{
|
{
|
||||||
// TenantScoped:自動以登入者 company_id 過濾(含 route-model binding 與列表查詢),
|
// TenantScoped:自動以登入者 company_id 過濾(含 route-model binding 與列表查詢),
|
||||||
// 防止跨公司讀取/操作他人發票。console(佇列 Job / reconcile 命令)會自動跳過 scope,
|
// 防止跨公司讀取/操作他人發票。console(佇列 Job / reconcile 命令)會自動跳過 scope,
|
||||||
// 系統身分仍可跨公司開立/對帳。
|
// 系統身分仍可跨公司開立/對帳。
|
||||||
use HasFactory, SoftDeletes, TenantScoped;
|
use HasFactory, SoftDeletes, TenantScoped, HasDisplayFlowId;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'company_id',
|
'company_id',
|
||||||
|
|||||||
@ -6,12 +6,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use App\Traits\TenantScoped;
|
use App\Traits\TenantScoped;
|
||||||
|
use App\Traits\HasDisplayFlowId;
|
||||||
use App\Models\Machine\Machine;
|
use App\Models\Machine\Machine;
|
||||||
use App\Models\Member\Member;
|
use App\Models\Member\Member;
|
||||||
|
|
||||||
class Order extends Model
|
class Order extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes, TenantScoped;
|
use HasFactory, SoftDeletes, TenantScoped, HasDisplayFlowId;
|
||||||
|
|
||||||
// 支付狀態
|
// 支付狀態
|
||||||
public const PAYMENT_STATUS_FAILED = 0;
|
public const PAYMENT_STATUS_FAILED = 0;
|
||||||
|
|||||||
28
app/Traits/HasDisplayFlowId.php
Normal file
28
app/Traits/HasDisplayFlowId.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供「給人看的 flow_id」accessor:去掉機台序號前綴,顯示乾淨易讀的機台流水號。
|
||||||
|
*
|
||||||
|
* 資料庫仍儲存完整的 `serial_no . flow_id`(全域唯一值),供後台去重 / 冪等 / 對帳判斷使用;
|
||||||
|
* 此 accessor 只用於畫面與匯出顯示,不改動任何 DB 值。
|
||||||
|
*
|
||||||
|
* flow_id 格式:serial_no . YYYYMMDDHHMMSSXXXX(無分隔符)。
|
||||||
|
* 套用此 trait 的 Model 需具備 `flow_id` 欄位與 `machine`(含 serial_no)關聯。
|
||||||
|
*/
|
||||||
|
trait HasDisplayFlowId
|
||||||
|
{
|
||||||
|
public function getDisplayFlowIdAttribute(): string
|
||||||
|
{
|
||||||
|
$flowId = (string) ($this->flow_id ?? '');
|
||||||
|
$serial = $this->machine?->serial_no;
|
||||||
|
|
||||||
|
// 僅在確實以該機台序號開頭時才剝除前綴;舊的未前綴資料原樣顯示(防禦)。
|
||||||
|
if ($serial !== null && $serial !== '' && str_starts_with($flowId, $serial)) {
|
||||||
|
return substr($flowId, strlen($serial));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $flowId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -102,7 +102,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Machine Flow ID') }}</p>
|
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Machine Flow ID') }}</p>
|
||||||
<p class="text-xs font-black text-slate-400 dark:text-slate-500 font-mono uppercase tracking-widest">{{ $order->flow_id }}</p>
|
{{-- 顯示去前綴序號的乾淨流水號(DB 仍存完整 serial+flow_id 唯一值供後台判斷) --}}
|
||||||
|
<p class="text-xs font-black text-slate-400 dark:text-slate-500 font-mono uppercase tracking-widest">{{ $order->display_flow_id }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -101,6 +101,20 @@ class FinalizeIdempotencyTest extends TestCase
|
|||||||
$this->assertEquals('2222222222' . $raw, $orderB->flow_id);
|
$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)。 */
|
/** RelateNumber = serial + rawFlowId(無分隔符、≤30、與線上推導逐字等價,不可雙重 serial)。 */
|
||||||
public function test_relate_number_equals_serial_plus_raw_flow_id(): void
|
public function test_relate_number_equals_serial_plus_raw_flow_id(): void
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user