star-cloud/PHARMACY_PICKUP_DESIGN.md
terrylee 8977e7eb0f feat(pharmacy-pickup): 領藥單模組(後台建單→QR→機台B660掃碼→出貨回報)
- 機台系統設定:取物單模式(pickup_sheet)下新增「領藥單」開關 pharmacy_pickup_enabled,B014 下發 FunctionSet.PharmacyPickup
- 權限:銷售管理→領藥單 menu.sales.pharmacy-pickup(角色/帳號可勾選授權,租戶模板預設關)
- 資料模型:orders 加 order_type/pricing_slip_no/created_by(領藥單序號=flow_id)、pickup_codes.slot_no 可空
- 後台:PharmacyPickupController + PharmacyPickupService(以商品為單位建單、庫存不預扣)+ 建單/列表/列印頁(QR內嵌,不顯姓名)
- B660:領藥單回多貨道 items[](保留 slot_no 向後相容)+ 模式 gate + 標記已領
- 出貨回報:finalizePharmacyDispense(獨立於銷售/發票/閉環)+ flow_id 終態冪等 + 庫存只扣一次
- 修正 PickupCode::isValid() 對 null expires_at 的 NPE、status 補入 fillable

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 09:54:04 +08:00

5.9 KiB
Raw Permalink Blame History

領藥單 / 批價單取藥模組 — 設計文件v2已納入交叉檢查修正

分支:feat/pharmacy-pickup(自 dev 切出)。

star-cloud 是自動販賣機智能機雲端後台Laravel 12 + Sail + MySQL + Redis + EMQX + Go mqtt-gateway。 本模組為可授權功能,只開放給部分客戶/機台:藥師依病人「批價單」人工建立「領藥單」→ 系統產序號 + 一張 QR → 病人到智能機掃碼 → 雲端驗證回多貨道 → 一次出全部 → 出貨結果回傳後台。不串 HIS、不存病人姓名病歷比照中國醫取物單僅存編號


一、目標流程

  1. 病人拿批價單到櫃台。
  2. 藥師在後台人工勾選該機台貨道上的藥品 + 數量,建立「領藥單」;可選填批價單號當依據。
  3. 領藥單序號系統自動產生(RX + 日期 + 流水,如 RX26061800001),並同時作為 orders.flow_id(見修正②)。
  4. 系統產生一張 QR 領藥單,列印給病人。
  5. 病人到智能機掃 QR → 機台呼叫 B660 → 雲端確認該機台為 pickup_sheet 模式且 pharmacy_pickup_enabled 開啟 → 回傳該單所有貨道清單 → 機台一次出全部。
  6. 出貨結果經 MQTT transaction/finalize(帶 dispense[])回傳 → 彙整更新領藥單出貨狀態。

二、模組授權機制(定案:取物單模式下的開關)

領藥單不是獨立的 shopping_mode而是既有「取物單(pickup_sheet)」模式底下的一個開關 pharmacy_pickup_enabled

  • machines.settings.shopping_mode 維持三種:basic / employee_card / pickup_sheet(取物單,中國醫物料編號領藥)。
  • 在「機台系統設定 → 購物方式」選 pickup_sheet 時,下方出現「領藥單」開關 settings.pharmacy_pickup_enabled
  • 授權 = 機台為 pickup_sheet 模式且 pharmacy_pickup_enabled=true;後台「領藥單」選單僅在「公司有任一機台符合此條件」時顯示。
  • B014 getSettingsFunctionSet 新增 PharmacyPickup 旗標下發給機台;ShoppingMode 仍為 pickup_sheet。
  • 控制器強制:非 pickup_sheet 模式時 pharmacy_pickup_enabled 一律存 false。
  • (後續可選)公司層級 license gate由系統管理員授權哪些公司可開此開關。

Phase 1 已完成(本次)

  • machines/index.blade.php選「取物單」時下方顯示「領藥單」開關checkbox settings[pharmacy_pickup_enabled]+ Alpine 資料。
  • partials/tab-system-settings.blade.php:取物單模式且開關開時,摘要加顯示 領藥單
  • MachineSettingController.phpshopping_mode 白名單(basic/employee_card/pickup_sheet);新增持久化 pharmacy_pickup_enabled(僅 pickup_sheet 模式可為 true
  • MachineController.phpB014FunctionSet.PharmacyPickup 下發。
  • lang/{en,zh_TW,ja}.json:新增 Pharmacy Pickup (Rx)zh_TW=「領藥單」)+ 開關說明。
  • 驗證2 controller PHP lint 通過、view:cache 成功、3 JSON 合法、登入頁 200。已部署測試機 192.168.0.130。

三、交叉檢查修正(必須遵守)

  • 修正①(旗標):領藥單做成「取物單(pickup_sheet)模式下的開關 pharmacy_pickup_enabled」,並完整接上 B014 FunctionSet.PharmacyPickup 下發(非孤立旗標)。 已採用。
  • 修正②(冪等/扣庫存):領藥單必須有 flow_id(用領藥單序號),讓出貨上報套用既有 finalizeTransaction 終態冪等保護;庫存只在 finalize 扣一次,建單不預扣(避免雙重扣減 / 重送 MQTT 重複扣)。
  • 修正③B660 相容):保留回傳 slot_no(領藥單填第一筆或 nulladditive 新增 items:[{slot_no,product_name,qty}];用 order_type 分流;靠 shopping_mode=pharmacy_pickup gate 只放行新版機台。
  • 修正④(報表/發票隔離)ordersorder_typeSalesController 銷售分頁與 CSV 匯出預設 where order_type='sale',領藥單獨立頁;確認領藥 finalize 上報不帶 invoice 區塊(不會誤開發票)。
  • 修正⑤(既有脆弱點):先修 PickupCode::isValid() 對 null expires_at 的 NPE$this->expires_at?->isFuture() ?? true);把 status 補進 PickupCode $fillable;確認 order_items 實際欄位(sku vs barcode)。
  • 修正⑥(建單必填)orders.payment_status / payment_type 為 NOT NULL建單須明確給值領藥單給 0 / 特定碼);多貨道「一次出全部」需與機台端對齊(既有 B055/dispatchDispense 為單貨道)。

四、資料模型變更

  • orders 新增:order_type ENUM('sale','pharmacy_pickup') default 'sale'pricing_slip_no VARCHAR NULLcreated_by BIGINT NULL。序號存 order_no等於 flow_id
  • pickup_codes.slot_no 改 nullable領藥單多貨道由 order_items×machine_slots 解析;一般取貨碼仍走 slot_no以 order_type 區分讀取)。
  • 一張領藥單 = 1 Order(pharmacy_pickup) + N OrderItem + 1 PickupCode付款欄位給定值delivery_status 初始 0。

五、後續任務(修正後)

  • Phase 2 資料模型:上述 migrationOrder 加常數/scope先修正⑤的 PickupCode 脆弱點。
  • Phase 3 後台建單 + 列印PharmacyPickupService::create()(產序號=flow_id、庫存檢查、交易內建單Admin/PharmacyPickupController、勾選頁 + 列印頁QR、不顯示姓名。建單僅限 pharmacy_pickup 模式機台。
  • Phase 4 B660additive items[] + order_type 分流 + 模式 gate + 標記碼已領。
  • Phase 5 回報finalize 帶 dispense[] 一次彙整(復用 resolveDeliveryStatusFromDispense),靠 flow_id 終態冪等;庫存只扣一次;領藥單詳情顯示逐道結果。
  • Phase 6 Android另 reposhopping_mode=pharmacy_pickup 啟用領藥 SaleFlow沿用中國醫 TakeMedicineDialog/DispatchDialog資料來源換 B660