進口貿易與食品進口模組 — 系統圖表

dobtor_trade_import + dobtor_food_import_inspection | Odoo 18 | 規格書 v3.1(含庫存保留單補充)

模型關係圖(ER Diagram)
涵蓋兩個模組的所有核心模型。藍色 為 dobtor_trade_import 核心模型;綠色 為 dobtor_food_import_inspection 擴充模型。

核心模組:dobtor_trade_import

erDiagram TRADE-IMPORT-BRAND { char code PK "品牌碼(唯一),驅動序號" char name "品牌名稱(中)" char name_en "品牌名稱(英)" sel food_category "🆕 seasoning/spread/snack/frozen/beverage" m2o sequence_id "ir.sequence" m2o partner_id "供應商" m2o default_forwarder_id "預設貨代" m2o default_customs_broker_id "預設報關行" m2o default_incoterm_id "預設貿易條件" sel default_payment_basis "付款基準" int default_payment_days "付款天數" } TRADE-IMPORT-CASE { char name PK "品牌序號 AY-010" char title "案件名稱" m2o brand_id FK sel source "boss / marketing" m2o buyer_id "採購負責人" m2o supplier_id "供應商" date order_date date payment_deadline "compute" sel payment_basis bool can_release "compute,放行閘門" sel state "主狀態機 11 態" m2o company_id } TRADE-IMPORT-SHIPMENT { char name PK "SHP/YYYY/00001" m2o case_id FK sel transport_mode "sea / air" char master_bl_no date bl_date "提單日" date etd date eta date atd date ata sel release_type "original/telex/seaway" sel state "booked/in_transit/arrived" } TRADE-IMPORT-CONTAINER { char name PK "貨櫃號" m2o shipment_id FK sel container_type "20gp/40gp/40hq/rf/lcl" int free_days date demurrage_date "押櫃起算" int overdue_days "compute" monetary demurrage_fee_est "compute" } TRADE-IMPORT-CONTAINER-LINE { m2o container_id FK m2o product_id float qty } TRADE-IMPORT-DECLARATION { char name PK "DCL/YYYY/00001" sel declaration_type "g1/d2/b6..." m2o case_id FK date declaration_date float exchange_rate sel clearance_channel "c1/c2/c3" monetary cif_value monetary duty_total "compute" monetary vat_amount "compute (CIF+關稅+貨物稅)×5%" monetary trade_fee "compute 0.04%,未逾100免徵" sel state "draft/declared/inspecting/released" } TRADE-IMPORT-DECLARATION-LINE { m2o declaration_id FK m2o product_id m2o hs_code_id FK char import_permit_no "食品報驗連動鍵" monetary customs_value "完稅價格(關稅基底)" float duty_rate monetary duty_amount } TRADE-IMPORT-HS-CODE { char name PK "0901.21.00.00-5" float duty_rate sel tax_basis "ad_valorem / specific" bool requires_food_inspection bool requires_quarantine } TRADE-IMPORT-PORT { char name char code "LOCODE TWKHH" sel port_type "sea / air" } TRADE-IMPORT-PAYMENT { m2o case_id FK date pay_date monetary amount bool is_prepaid } TRADE-IMPORT-RECYCLE-DECLARATION { char period "2026-1" m2o case_id FK monetary amount_total "compute" sel state "draft/declared/paid" } TRADE-STOCK-RESERVATION { char name PK "🆕 RSV/YYYY/00001" m2o product_id FK "商品" m2o lot_id FK "批號(選填)" m2o location_id FK "倉位" float reserved_qty "保留數量" float available_qty "compute 即時庫存" char channel "通路名稱" char reason "保留原因" m2o applicant_id "申請人" date apply_date "申請日" date expected_ship_date "預計出貨日" date end_date "保留結束日" sel state "active/released/cancelled" } TRADE-IMPORT-BRAND ||--o{ TRADE-IMPORT-CASE : "brand_id" TRADE-IMPORT-CASE ||--o{ TRADE-IMPORT-SHIPMENT : "shipment_ids" TRADE-IMPORT-CASE ||--o{ TRADE-IMPORT-DECLARATION : "declaration_ids" TRADE-IMPORT-CASE ||--o{ TRADE-IMPORT-PAYMENT : "payment_ids" TRADE-IMPORT-CASE ||--o{ TRADE-IMPORT-RECYCLE-DECLARATION : "recycle_declaration_ids" TRADE-IMPORT-SHIPMENT ||--o{ TRADE-IMPORT-CONTAINER : "container_ids" TRADE-IMPORT-CONTAINER ||--o{ TRADE-IMPORT-CONTAINER-LINE : "line_ids" TRADE-IMPORT-DECLARATION ||--o{ TRADE-IMPORT-DECLARATION-LINE : "line_ids" TRADE-IMPORT-DECLARATION-LINE }o--|| TRADE-IMPORT-HS-CODE : "hs_code_id" TRADE-IMPORT-SHIPMENT }o--|| TRADE-IMPORT-PORT : "pol_id / pod_id"

食品擴充模組:dobtor_food_import_inspection

erDiagram FOOD-REGULATION-PROFILE { char name sel food_category char tfda_category sel inspection_method "paper/batch/enhanced/each/verify/monitor" sel risk_level "low/medium/high" int shelf_life_days bool requires_quarantine } PRODUCT-TEMPLATE-EXT { bool is_food char name_en char factory_code m2o regulation_profile_id FK m2o default_hs_code_id FK sel product_state "new/normal/barcode_changed/renamed/discontinued/stop_import" sel label_print_mark "print / label" int pack_qty } FOOD-LABEL { m2o product_id FK int version sel label_method "oem_preprint/oem_send/we_print/we_send/sanxin_label/none" sel state "draft/review/approved/applied" char product_name_zh text ingredients_zh text label_preview "compute,中文標全文" } FOOD-ALLERGEN { char name } FOOD-NUTRITION-LINE { m2o product_id FK char nutrient float amount char unit } TRADE-IMPORT-INSPECTION { char name PK "報驗序號" sel inspection_type "border / self" m2o case_id FK m2o declaration_id FK m2o inspection_agent_id "三信" sel inspection_method date apply_deadline "到港前15日內" date amend_deadline "補正通知+30日" bool requires_quarantine sel quarantine_state "na/pending/passed/rejected" sel state "pending/sampling/testing/released/rejected" } TRADE-IMPORT-INSPECTION-SAMPLE { m2o inspection_id FK m2o product_id FK m2o purchase_order_id FK date sample_date float sample_qty sel result } TRADE-IMPORT-DOCUMENT { m2o case_id FK m2o product_id FK sel doc_type "spec/coa/tw_test/image/zh_label/health_cert/official_cert/import_permit" date issue_date date expiry_date sel state "draft/valid/expired" } STOCK-LOT-EXT { date manufacture_date char supplier_lot "原廠批號" m2o trade_import_case_id FK int remaining_days "compute" float life_ratio "compute" sel expiry_alert "fresh/half/two_third/expired" } FOOD-RECALL-DEFERRED { char name PK "📌延後 Phase4 RCL/YYYY/00001" text reason "lot回連即可手動追溯" sel state "draft/notified/recovering/closed" } FOOD-TRACEBOOK-REPORT { char period "月份" } FOOD-REGULATION-PROFILE ||--o{ PRODUCT-TEMPLATE-EXT : "regulation_profile_id" PRODUCT-TEMPLATE-EXT ||--o{ FOOD-LABEL : "label_ids" PRODUCT-TEMPLATE-EXT }o--o{ FOOD-ALLERGEN : "allergen_ids" PRODUCT-TEMPLATE-EXT ||--o{ FOOD-NUTRITION-LINE : "nutrition_ids" TRADE-IMPORT-INSPECTION ||--o{ TRADE-IMPORT-INSPECTION-SAMPLE : "sample_ids" FOOD-RECALL-DEFERRED }o--o{ STOCK-LOT-EXT : "lot_ids"
主狀態機與子狀態
trade.import.case 為主狀態機,declaration 與 inspection 各有獨立子狀態機,三者以 can_release 閘門匯流。⚠️ 本次範圍:draft → released + done(到岸成本);delivering/stored 屬倉後作業,暫不開發

trade.import.case — 主狀態機

stateDiagram-v2 direction TB [*] --> draft draft --> confirmed : action_confirm confirmed --> production : 備貨中 production --> ready : 文件齊備 ready --> in_transit : ATD 開船 in_transit --> arrived : ATA 到港 arrived --> customs : 送關 customs --> released : action_release note right of customs 放行閘門 can_release 報單全數 released 查驗全數通過(食品模組) end note released --> done : action_done draft --> cancel confirmed --> cancel production --> cancel ready --> cancel in_transit --> cancel arrived --> cancel customs --> cancel cancel --> [*] state "倉後 delivering/stored 後期擴充" as oos released --> oos

子狀態機:報單 + 查驗

stateDiagram-v2 direction TB state "報單 trade.import.declaration" as D { [*] --> d_draft d_draft --> d_declared : 送關 d_declared --> d_released : C1 直接放行 d_declared --> d_inspecting : C2/C3 查驗 d_inspecting --> d_released : 海關放行 d_released --> [*] } state "查驗 trade.import.inspection" as I { [*] --> i_pending i_pending --> i_sampling : 食藥署抽中 i_sampling --> i_testing : 抽驗中 i_testing --> i_released : 查驗合格 i_testing --> i_rejected : 不合格 i_released --> [*] i_rejected --> [*] } state "防檢 quarantine_state" as Q { [*] --> q_na q_na --> q_pending : requires_quarantine q_pending --> q_passed : 防檢放行 q_pending --> q_rejected : 防檢退駁 q_passed --> [*] q_rejected --> [*] }

can_release 閘門計算邏輯(雙模組繼承覆寫)

flowchart LR A([開始評估 can_release]) --> B{declaration_ids\n全部 released?} B -- 否 --> Z1([can_release = False]) B -- 是 --> C{安裝了\n食品模組?} C -- 否 --> Z2([can_release = True ✅\n基礎模組]) C -- 是 --> D{有 border\ntype 查驗記錄?} D -- 否 --> Z3([can_release = False]) D -- 是 --> E{所有 border\n查驗 released?} E -- 否 --> Z4([can_release = False]) E -- 是 --> F{有 requires_quarantine\n的查驗?} F -- 否 --> Z5([can_release = True ✅\n食品模組]) F -- 是 --> G{quarantine_state\n全部 passed?} G -- 否 --> Z6([can_release = False]) G -- 是 --> Z7([can_release = True ✅\n食品+防檢雙軌])
業務流程泳道圖
依角色(採購、原廠/貨代、報關行/三信、財務)劃分責任,對應 trade.import.case 主狀態。✅ 範圍:建單 → 海關放行 → 到岸成本結算

進口作業流程(含食品查驗)— 範圍至出關+費用結算

flowchart TD subgraph sg1["👔 採購/業務"] A1([老闆下單/行銷建單\nstate=draft]) --> A2[建立 trade.import.case\n選品牌帶出預設] A2 --> A3[建立採購單 PO\n設定 Incoterm/幣別] A3 --> A4[action_confirm\nstate=confirmed] A4 --> A5[追蹤原廠備貨\nstate=production] A5 --> A6{規格書比對\nspec_confirmed?} A6 -- OK --> A7[確認中文標方式\nfood.label approved] A7 --> A8[文件齊備\nstate=ready] end subgraph sg2["🚢 貨代/船公司"] B1[建立 shipment\n填訂艙號/船名/航次] --> B2[建立貨櫃\n設定 container_type] B2 --> B3[更新 ETD→ATD\nstate=in_transit] B3 --> B4[更新 ETA→ATA\nstate=arrived] end subgraph sg3["📑 報關行"] C1[建立 declaration\n填海關別/通關方式] --> C2[回填報單號\n提交 declaration_date] C2 --> C3{clearance_channel} C3 -- 類型C1 --> C4[海關放行\ndeclaration.state=released] C3 -- 類型C2C3 --> C5[文審/查驗中\nstate=inspecting] C5 --> C4 end subgraph sg4["🔬 三信/食藥署"] D1[建立 inspection\ntype=border] --> D2[預報驗\napply_deadline 前] D2 --> D3{食藥署抽中?} D3 -- 抽中 --> D4[建立 sample\nstate=sampling] D4 --> D5[送驗\nstate=testing] D5 --> D6{檢驗結果} D6 -- 合格 --> D7[inspection.state=released] D6 -- 不合格 --> D8[state=rejected\n退運/銷毀] D3 -- 免驗 --> D7 end subgraph sg5["💰 財務(範圍終點)"] E1[閘門通過\ncan_release=True] --> E2[action_release\nstate=released] E2 --> E3[登錄各項費用\n關稅/運費/保險/倉租/報關費] E3 --> E4[到岸成本結算\nstock.landed.cost] E4 --> E5([state=done 本次範圍終點]) end subgraph sg6["🚫 後期擴充(倉後)"] F1[車輛調度\nstate=delivering] F2[action_store 收貨/批號登錄] F3[效期管制/FEFO] end A8 --> B1 A8 --> C1 A8 --> D1 B4 --> C1 C4 --> E1 D7 --> E1 E5 -.-> F1

📌 保稅倉精靈(Phase 3 條件式)

延後至 Phase 3,僅保稅倉客戶才需要。Phase 2 只建 l10n_tw_is_bonded 欄位。
flowchart LR A([保稅入倉\nl10n_tw_is_bonded=True]) --> B[出保稅完稅精靈\n需要時才做] B --> C[依批量計稅\n保稅→已稅調撥] C --> D[產生 D2 報單] D --> E([完稅完成])

📌 部分扣倉精靈(Phase 3 條件式)

延後至 Phase 3 尾端,C3 比例低先用手動 picking 處理。
flowchart TD A([C3 查驗\n部分不合格]) --> B{line_can_release} B -- 合格品 --> C[放行至一般倉] B -- 待驗品 --> D[is_hold 庫位\n等待結果] D --> E{最終} E -- released --> C E -- rejected --> F[退運/銷毀]
放行閘門邏輯詳解
action_release 執行前必須通過 can_release 閘門,食品模組覆寫後為雙軌(報關+食藥署/防檢署)。

基礎模組閘門(dobtor_trade_import)

flowchart TD A[action_release 呼叫] --> B{declaration_ids\n是否存在?} B -- 無報單 --> E1([❌ 擋住\ncan_release=False]) B -- 有 --> C{所有 declaration\nstate == released?} C -- 任一未放行 --> E1 C -- 全部放行 --> OK1([✅ 放行通過])

食品模組閘門(覆寫,僅認 border 類型)

flowchart TD A[super._compute_can_release] --> B{base can_release\n已通過?} B -- False --> Skip([跳過,維持 False]) B -- True --> C[篩選 border type\ninspection_ids] C --> D{border 記錄\n存在?} D -- 無 --> E1([❌ can_release=False]) D -- 有 --> E{所有 border\nstate == released?} E -- 否 --> E1 E -- 是 --> F{任一 border\nrequires_quarantine?} F -- 否 --> OK([✅ can_release=True]) F -- 是 --> G{所有 quarantine\nstate == passed?} G -- 否 --> E1 G -- 是 --> OK style OK fill:#48bb78,color:white style E1 fill:#fc8181,color:white

海關狀態彙整邏輯(customs_state compute)

flowchart LR A[declaration_ids] --> B{全部 released?} B -- 是 --> S1([customs_state = released]) B -- 否 --> C{任一 inspecting?} C -- 是 --> S2([customs_state = inspecting]) C -- 否 --> D{有 declared\n其餘未送?} D -- 是 --> S3([customs_state = declaring]) D -- 否 --> E{皆 draft?} E -- 是 --> S4([customs_state = draft]) E -- 否 --> F{無報單?} F -- 是 --> S5([customs_state = none])
稅費計算流程
action_compute_taxes 強制順序計算,完稅價格(customs_value)≠ CIF,禁止直接代入。

稅費計算四步驟(declaration.action_compute_taxes)

flowchart TD INPUT([報單明細\ndeclaration.line_ids]) --> S1 subgraph S1["Step 1 — 關稅"] 1A[Σ 各明細 customs_value × duty_rate] --> 1B[duty_total] 1C["⚠️ 基底 = customs_value(完稅價格)\n≠ cif_value(起岸價格)"] end subgraph S2["Step 2 — 貨物稅"] 2A[適用品項依貨物稅率計] --> 2B[commodity_tax] end subgraph S3["Step 3 — 營業稅(可扣抵進項)"] 3A["(完稅價格總額 + 關稅 + 貨物稅 + 菸酒稅/菸品健康捐)× 5%"] --> 3B[vat_amount] 3C["📌 非成本,為可扣抵進項稅額"] end subgraph S4["Step 4 — 推廣貿易服務費"] 4A[完稅價格 × 0.04%] --> 4B{金額 > NT$100?} 4B -- 是 --> 4C[trade_fee = 計算值] 4B -- 否 --> 4D[trade_fee = 0\n免徵] end S1 --> S2 --> S3 --> S4 S4 --> OUT([稅費彙總\n供到岸成本分攤])

付款期限 compute(依 payment_basis 選擇基準日)

flowchart LR PB{payment_basis} --> TT[tt_prepaid\n基準 = order_date] PB --> IV[iv_days\n基準 = invoice_date] PB --> BL[bl_days\n基準 = 最早 bl_date] PB --> DA[da_days\n基準 = acceptance_date] PB --> SP[split\n多筆 payment 各自計] PB --> CC[credit_card\n不計期限] TT --> CALC[基準日 + payment_days\n= payment_deadline] IV --> CALC BL --> CALC DA --> CALC CALC --> CRON[Cron: 到期前\n建 mail.activity 通知財務]
🚫 本次範圍外 — 倉後流程,暫不開發
效期管制(stock.lot expiry tracking)、FEFO 揀貨策略、效期預警 Cron 均屬收貨入倉後的倉庫管理功能。
本次模組範圍以海關放行(released)+ 到岸成本結算(done)為終點,不含物理入倉與批號效期操作。
此頁面為規格參考,列為後期擴充項目。
效期管制流程(食品模組)— 後期參考
沿用原生 stock.lot expiration_date + product_expiry 模組,擴充效期預警 compute 與 FEFO 庫存策略。

效期 compute 計算鏈

flowchart LR subgraph Input["入庫登錄"] I1[manufacture_date\n製造日] I2[expiration_date\n到期日(原生)] I3[shelf_life_days\n=regulation_profile.shelf_life_days] end subgraph Compute["每日 compute(UTC+8)"] C1["remaining_days\n= expiration_date − today\n(需 UTC→UTC+8 偏移)"] C2["life_ratio\n= remaining_days / shelf_life_days"] C3["half_life_days\n= remaining_days − shelf_life_days/2"] C4["third_life_days\n= remaining_days − shelf_life_days/3"] end subgraph Alert["expiry_alert Selection"] A1["🟢 fresh\nlife_ratio > 0.5"] A2["🟡 half\n0.33 < life_ratio ≤ 0.5\n過半效期"] A3["🟠 two_third\n0 < life_ratio ≤ 0.33\n過2/3效期"] A4["🔴 expired\nremaining_days ≤ 0"] end I1 --> C1 I2 --> C1 I3 --> C2 C1 --> C2 C1 --> C3 C1 --> C4 C2 --> A1 C2 --> A2 C2 --> A3 C2 --> A4

效期預警觸發流程(每日 Cron)

flowchart TD CRON([每日 Cron 執行]) --> Q1[查詢所有\nexpiry_alert IN half, two_third\n且仍有庫存的 stock.lot] Q1 --> L1{逐批號檢查} L1 --> A1[建立 mail.activity\n通知促銷/下架負責人] A1 --> A2[lot list 著色顯示\nhalf=黃 / two_third=橘 / expired=紅] A2 --> R1[效期預警報表\n「二分之一庫存表」] R1 --> R2{維度切換} R2 --> V1[依庫別] R2 --> V2[依品牌] R2 --> V3[依警示級] Q2([FEFO 策略]) --> F1[removal_date\n= expiration_date\n由原生 product_expiry 提供] F1 --> F2[出庫自動選最早到期批號\nstock.removal_strategy = FEFO]
延後/縮減開發決策(v3.1)
依據客戶業務文件(2026-06-04)評估後,以下項目正式調整優先順序。未出現在業務文件中的功能一律延後。

📌 開發優先順序調整流程圖

flowchart TD subgraph P1["Phase 1 MVP(維持)"] P1A[trade.import.brand\n🆕 加 food_category] P1B[trade.import.case 主狀態機] P1C[shipment + container + 多視圖] P1D["📌 前移:product_state 警語\n(Alice痛點:誤訂停產品)"] P1E["📌 前移:factory_quote_price PO line\n(Alice痛點:報價分散)"] end subgraph P2["Phase 2 貿易核心(調整)"] P2A[報單/稅費/HS Code] P2B[付款管理 + cron 到期提醒] P2C[到岸成本 / 回收費申報] P2E["📌 縮減:保稅倉欄位架構預留\n精靈移到Phase3(條件式)"] end subgraph P3["Phase 3 食品合規(調整)"] P3A[法規主檔/中文標/查驗/效期] P3B[食品業者登錄/非追不可申報] P3C[放行閘門覆寫] P3D["📌 移至此:保稅出倉精靈D2\n(有保稅倉需求才做)"] P3E["📌 移至此:部分扣倉精靈\n(C3比例低,有需求才做)"] P3F["📌 縮減:food.recall 只做lot回連\n完整流程移Phase4"] end subgraph P4["Phase 4 產品化(縮減)"] P4A[CorPaaS 多租戶] P4B[Kanban 儀表板強化] P4C["📌 food.recall 完整流程\n(有需求才做)"] P4D["❌ 移除:OCA spreadsheet\n無需求依據,原生pivot+Excel夠用"] end subgraph OOS["🚫 不在本模組範圍(本次決策)"] O1["先付款後分批出貨\n→ 銷售端SO功能,非進口模組"] O2["EDI電子報關直連\n→ 只保留edi_ref欄位即可"] O3["倉後流程(出關後)\n→ 批號效期/FEFO/保留單\n→ 後期另立模組/Phase擴充"] end P1 --> P2 --> P3 --> P4

🆕 新增:庫存保留單狀態機

stateDiagram-v2 direction LR [*] --> active : 申請確認 active --> released : 出貨解除/手動結清 active --> cancelled : 取消保留 released --> [*] cancelled --> [*] note right of active Cron: end_date < today → mail.activity 提醒申請人 end note
觸發 activity 警示的條件:
· 保留結束日到期未解除
· 保留量 > 實際庫存(超額保留)
倉庫揀貨整合:
· stock.quant 顯示「已被保留數量」
· 揀貨時可見 smart button 保留單計數

確認不納入 / 正式移除

❌ 移除出開發範圍
OCA spreadsheet 互動報表
理由:無任何客戶需求依據。Odoo 原生 pivot + Excel export 已足夠,不需額外依賴 OCA 模組。
🚫 不在本模組範圍
先付款後分批出貨
理由:銷售端邏輯(SO backorder)。進口模組管採購端,銷售端另行處理,兩者不應混用。
⏸ 只保留欄位,不實作介接
EDI 電子報關直連(Trade-Van)
理由:政府介接成本高,客戶未要求。edi_ref 欄位保留供日後擴充。
🚫 出關後倉後流程 — 本次全部不開發
批號登錄 / 效期管制(stock.lot expiry)/ FEFO 揀貨
庫存保留單(trade.stock.reservation)
收貨入倉(action_store)/ 追溯回收(food.recall)
理由:本次模組範圍以海關放行(released)+ 到岸成本結算(done)為終點,物理入倉與倉庫管理後期另立需求再做。
✅ 已驗證必要功能(本次範圍內)
付款期限 cron 提醒、product_state 警語、factory_quote_price、非追不可申報
→ 均在 Alice 文件中有明確痛點對應,且均屬出關前流程
付款期限計算與款項追蹤
trade.import.case 依 payment_basis 決定付款基準日,加 payment_days 算出 payment_deadline;Cron 到期前建 activity 通知財務。

payment_deadline compute 邏輯

flowchart TD A([action_confirm 確認作業單]) --> B{payment_basis?} B -- tt_prepaid 電匯預付 --> C[base = order_date 訂貨日] B -- iv_days 發票天數 --> D[base = invoice_date 發票日] B -- bl_days 提單天數 --> E["base = min(shipment.bl_date)\n取最早船務提單日"] B -- da_days 承兌天數 --> F[base = acceptance_date 承兌日] B -- split 分批匯款 --> G[手動新增 payment_ids\npayment_deadline = N/A] B -- credit_card 信用卡 --> H[信用卡帳單\npayment_deadline = N/A] C & D & E & F --> I["payment_deadline =\nbase + relativedelta(days=payment_days)"] I --> J[store=True 存資料庫\n支援日曆/filter] I --> K{今日 vs payment_deadline} K -- 距到期 N 天 --> L[Cron 建 mail.activity\n通知財務人員] K -- 已逾期 --> M[逾期旗標\nlist 著紅色]

款項追蹤 payment_ids

flowchart TD subgraph CASE["trade.import.case"] PD[payment_deadline] PT[paid_total compute] BAL[balance compute] end subgraph PMT["trade.import.payment (One2many)"] P1["匯款 1\npay_date / amount / currency_id\nexchange_rate / is_prepaid"] P2["匯款 2 (換匯扣抵)"] P3["..."] end PMT -- Σ amount --> PT PT & PD --> BAL BAL --> W{balance > 0?} W -- 是 --> X[仍有未付款項] W -- 否 --> Y[✅ 已結清] subgraph RATE["匯率快照"] R1[exchange_rate = 報關日匯率] R2[不隨市場浮動] end PMT -.-> RATE

payment_basis 各選項對照

flowchart LR subgraph BASIS["payment_basis 六種"] A1["tt_prepaid\n電匯預付\n基準:訂貨日"] A2["iv_days\n發票天數\n基準:發票日"] A3["bl_days\n提單天數\n基準:B/L 日"] A4["da_days\n承兌天數\n基準:承兌日"] A5["split\n分批匯款\n手動輸入"] A6["credit_card\n信用卡"] end A1 & A2 & A3 & A4 --> DL["payment_deadline\n= base + payment_days"] A5 --> ML["多筆 payment_ids\n逐批追蹤"] A6 --> CC["帳單日另計\n不走 deadline 欄位"] DL --> CAL["calendar 視圖\n付款期限維度"] DL --> ACT["mail.activity\n到期提醒財務"]
食品查驗雙軌詳細流程
trade.import.inspection 以 inspection_type 區分邊境報驗(進放行閘門)與自主送驗(不進閘門)。border type 再分防檢署雙軌。

邊境報驗(border)完整流程

flowchart TD A([case → arrived 到港]) --> B[向食藥署申請邊境報驗\ntrade.import.inspection\ntype=border] B --> DL[apply_deadline\n到港前15日內/到港後法定期限] B --> C{海關通關方式\nclearance_channel} C -- C1 免審免驗 --> D[state = released\n直接進放行閘門] C -- C2 應審免驗 --> E[文件審查\nstate = inspecting] C -- C3 應審應驗 --> F[抽驗\nstate = sampling] E --> G{審查結果} F --> F2[建 inspection.sample\n記錄抽驗批號/機構/項目] F2 --> H[state = testing\n檢驗中] H --> G G -- 合格 --> I[state = released] G -- 不合格 --> J[state = rejected\n補正通知日+30=amend_deadline\n可展延一次30日] J --> K{補正結果} K -- 補正合格 --> I K -- 不合格/逾期 --> L[退運/銷毀] I --> M{requires_quarantine?} M -- False --> N([✅ 進放行閘門\nborder released]) M -- True 防疫動植物 --> O[quarantine_state = pending\n防檢署平行審查] O --> P{防檢署結果} P -- passed --> N P -- rejected --> Q([❌ 防檢署退駁])

自主送驗(self)流程

flowchart TD A([上市前自主品管]) --> B[建 trade.import.inspection\ntype=self\nchannel=請購選號] B --> C[送驗至 lab_id 檢驗機構] C --> D[state = testing] D --> E{lab 出具報告} E -- 合格 --> F[state = released\nreport_email_date 記錄] E -- 不合格 --> G[state = rejected\n通知品管] F --> H[❌ 不進放行閘門\n僅供品管留痕] H --> I[product_id 累積\ninspection_sample_ids 歷史]

抽驗歷史回連 product

flowchart TD A[trade.import.inspection.sample] --> B[product_id\ncase_id\npurchase_order_id] B --> C{product.template\nhas_open_doc_gap\n或最近 rejected?} C -- 是 --> D[下次建 PO line\nonchange 跳警語] D --> E[列出缺漏文件\npending inspection] C -- 否 --> F[正常建單] A --> G[product smart button\n查驗歷史 N 筆]
中文標版本控管(food.label)
food.label 一產品多版本;approved 後鎖定不可改,新需求另開版本。採購單可覆寫 label_method 但不回寫產品主檔。

food.label 狀態機

stateDiagram-v2 direction TB [*] --> draft : 新建中文標 draft --> review : 送審 review --> approved : 主管核准 review --> draft : 退回修改 approved --> applied : 已用於進口作業 approved --> [*] : 建新版本 V+1 note right of approved approved 後任何欄位均 readonly 如需修改請另開新版本 end note

label_method 決策與 override

flowchart TD A[product.template\ndefault_label_method] --> B{採購單 PO line\n有 label_method_override?} B -- 無 override --> C[沿用產品預設\nlabel_method] B -- 有 override --> D[以 override 為準\n不回寫產品主檔] C & D --> E{label_method 值} E -- oem_preprint --> F[原廠已印於外觀\n不貼標] E -- oem_send --> G[寄標至原廠\n原廠自貼] E -- we_print --> H[進口商自印貼] E -- we_send --> I[自印後寄原廠] E -- sanxin_label --> J[三信代貼\n配合報驗時序] E -- none --> K[免標示商品] F & G & H & I & J & K --> L[出貨/報驗以此為準] L --> M[food.label.label_preview\n彙整中文標全文供平台複貼]

中文標 × 報驗 × 作業單 三者關係

flowchart LR subgraph BRAND["品牌主檔"] BR[trade.import.brand\ndefault_label_method\nregulation_profile_id] end subgraph PRODUCT["產品主檔"] PT[product.template\nlabel_method\nis_food\nregulation_profile_id] FL["food.label\nV1 approved ✅\nV2 draft 🔧"] end subgraph CASE["作業單"] IC[trade.import.case\nlabel_method] PO["purchase.order.line\nlabel_method_override\n(不回寫)"] INS[trade.import.inspection\nborder / self] end BR -- onchange 帶入 --> IC IC -- 建立 --> PO PT -- 預設 --> PO PO -- override 優先 --> INS FL -- V最新approved --> PT PT -- 關聯 --> INS
進口來源追溯鏈
本次範圍:從作業單向上追溯至品牌/供應商/報單/船務(進口來源追溯)。批號效期管制、向下客戶追蹤屬倉後流程,後期再做。

進口來源追溯鏈(本次範圍)

flowchart TD subgraph CORE["本次範圍:作業單 → 供應來源"] CASE["trade.import.case\nname: AY-010\nbrand_id / supplier_id\nstate: released"] CASE --> BRAND["trade.import.brand\n品牌/供應商/貨代\nfood_category"] CASE --> PO["purchase.order\n採購單號 / 品項 / 價格\n原廠 PI/Invoice"] CASE --> SHIP["trade.import.shipment\n船名 / BL / ETD / ATA\nmaster_bl_no"] CASE --> DECL["trade.import.declaration\n報單號 / clearance_channel\n關稅 / 完稅價格"] CASE --> INSP["trade.import.inspection\nborder: 報驗號 / 放行日\nquarantine_state"] CASE --> DOC["trade.import.document\nspec / coa / health_cert\n到期日管控"] SHIP --> PORT["trade.import.port\n起運港 POL / 目的港 POD"] DECL --> HS["trade.import.hs.code\n稅則 / duty_rate\ninspection_no"] end subgraph LATER["🚫 後期擴充(倉後)"] LOT["stock.lot\ntrade_import_case_id 回連\n批號 / 效期"] LOT --> DOWN["向下追溯\n出貨 → 客戶"] LOT --> RECALL["food.recall\n條件式 Phase 4"] end CASE -.-> LOT

報單 ← HS Code ← 報驗 三角連動(本次範圍)

flowchart LR HS["trade.import.hs.code\nname: 0901.21.00.00-5\nduty_rate / inspection_no\ntax_basis"] DLINE["declaration.line\nhs_code_id / customs_value\nduty_rate / import_permit_no"] INSP["trade.import.inspection\nborder type\nimport_permit_no 連動鍵"] HS -- onchange 帶入 --> DLINE HS -- inspection_no 反推 --> INSP DLINE -- import_permit_no --> INSP INSP -- 食藥署查驗合格 --> GATE([can_release 閘門]) DLINE -- customs_value × duty_rate --> TAX([關稅 + 營業稅])

夥伴角色旗標(res.partner 擴充)

flowchart TD P["res.partner\n(單一模型,多角色)"] P --> F[is_forwarder 貨代] P --> CB[is_customs_broker 報關行] P --> SL[is_shipping_line 船公司] P --> TR[is_trucking 拖車] P --> IA[is_inspection_agent 報驗行三信] P --> BW[is_bonded_warehouse 保稅倉] F -- domain --> CASE_F["case.forwarder_id"] CB -- domain --> CASE_CB["case.customs_broker_id"] SL -- domain --> SHIP_SL["shipment.shipping_line_id"] IA -- domain --> INSP_IA["inspection.inspection_agent_id"] subgraph FOOD["食品模組擴充"] RC[food_business_no\n食品業者登錄字號] INS[insurance_no\n保險字號] end P --> FOOD
結構化文件管控(trade.import.document)
取代純 attachment 池;對文件到期日主動提醒;連動報驗前查核與證照效期(工廠執照、健康證明、進口許可)。

文件狀態機

stateDiagram-v2 direction LR [*] --> draft : 上傳文件 draft --> valid : 填入 expiry_date valid --> expired : expiry_date < today expired --> valid : 補件/換新 draft --> valid : 無到期限制文件

文件到期 Cron 流程

flowchart TD A([Cron 每日執行]) --> B["掃描 trade.import.document\nexpiry_date < today\nstate != expired"] B --> C[更新 state → expired] C --> D[建 mail.activity\n通知 case 負責人] D --> E{doc_type 分類} E -- health_cert 健康證明 --> F[通知採購補健康證] E -- official_cert 官方證明 --> G[通知報關行] E -- import_permit 輸入許可 --> H[通知食藥署報驗負責人] E -- spec 規格書 --> I[通知品管更新規格] E -- tw_test 台灣檢驗 --> J[通知品管重新送驗]

文件類型 × 使用時機對照

flowchart LR subgraph TYPES["doc_type 八種"] T1[spec 規格書] T2[coa 聲明書/合格證] T3[tw_test 台灣檢驗報告] T4[image 產品圖檔] T5[zh_label 中文標] T6[health_cert 健康證明正本] T7[official_cert 官方證明] T8[import_permit 輸入許可] end subgraph WHEN["使用時機"] W1[報驗前查核\n確認 spec/coa/health_cert 齊備] W2[報驗申請時\n上傳 import_permit/official_cert] W3[中文標審核\nzh_label → food.label 對應] W4[通關時\ntw_test 合格才放行 C2] end T1 & T2 & T6 --> W1 T7 & T8 --> W2 T5 --> W3 T3 --> W4 subgraph GAP["缺件警示"] G1["product.template\nhas_open_doc_gap compute\nPO line onchange 跳警語"] end T1 & T2 & T3 -.-> G1