- 機台系統設定:取物單模式(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>
5.9 KiB
5.9 KiB
領藥單 / 批價單取藥模組 — 設計文件(v2,已納入交叉檢查修正)
分支:feat/pharmacy-pickup(自 dev 切出)。
star-cloud 是自動販賣機(智能機)雲端後台(Laravel 12 + Sail + MySQL + Redis + EMQX + Go mqtt-gateway)。
本模組為可授權功能,只開放給部分客戶/機台:藥師依病人「批價單」人工建立「領藥單」→ 系統產序號 + 一張 QR → 病人到智能機掃碼 → 雲端驗證回多貨道 → 一次出全部 → 出貨結果回傳後台。不串 HIS、不存病人姓名病歷(比照中國醫取物單僅存編號)。
一、目標流程
- 病人拿批價單到櫃台。
- 藥師在後台人工勾選該機台貨道上的藥品 + 數量,建立「領藥單」;可選填批價單號當依據。
- 領藥單序號系統自動產生(
RX+ 日期 + 流水,如RX26061800001),並同時作為orders.flow_id(見修正②)。 - 系統產生一張 QR 領藥單,列印給病人。
- 病人到智能機掃 QR → 機台呼叫 B660 → 雲端確認該機台為
pickup_sheet模式且pharmacy_pickup_enabled開啟 → 回傳該單所有貨道清單 → 機台一次出全部。 - 出貨結果經 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
getSettings的FunctionSet新增PharmacyPickup旗標下發給機台;ShoppingMode仍為 pickup_sheet。 - 控制器強制:非 pickup_sheet 模式時
pharmacy_pickup_enabled一律存 false。 - (後續可選)公司層級 license gate,由系統管理員授權哪些公司可開此開關。
✅ Phase 1 已完成(本次)
machines/index.blade.php:選「取物單」時,下方顯示「領藥單」開關(checkboxsettings[pharmacy_pickup_enabled])+ Alpine 資料。partials/tab-system-settings.blade.php:取物單模式且開關開時,摘要加顯示領藥單。MachineSettingController.php:shopping_mode白名單(basic/employee_card/pickup_sheet);新增持久化pharmacy_pickup_enabled(僅 pickup_sheet 模式可為 true)。MachineController.php(B014):FunctionSet.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」,並完整接上 B014FunctionSet.PharmacyPickup下發(非孤立旗標)。✅ 已採用。 - 修正②(冪等/扣庫存):領藥單必須有
flow_id(用領藥單序號),讓出貨上報套用既有finalizeTransaction終態冪等保護;庫存只在 finalize 扣一次,建單不預扣(避免雙重扣減 / 重送 MQTT 重複扣)。 - 修正③(B660 相容):保留回傳
slot_no(領藥單填第一筆或 null),additive 新增items:[{slot_no,product_name,qty}];用order_type分流;靠shopping_mode=pharmacy_pickupgate 只放行新版機台。 - 修正④(報表/發票隔離):
orders加order_type;SalesController銷售分頁與 CSV 匯出預設where order_type='sale',領藥單獨立頁;確認領藥 finalize 上報不帶 invoice 區塊(不會誤開發票)。 - 修正⑤(既有脆弱點):先修
PickupCode::isValid()對 nullexpires_at的 NPE($this->expires_at?->isFuture() ?? true);把status補進 PickupCode$fillable;確認order_items實際欄位(skuvsbarcode)。 - 修正⑥(建單必填):
orders.payment_status/payment_type為 NOT NULL,建單須明確給值(領藥單給 0 / 特定碼);多貨道「一次出全部」需與機台端對齊(既有 B055/dispatchDispense 為單貨道)。
四、資料模型變更
orders新增:order_type ENUM('sale','pharmacy_pickup') default 'sale'、pricing_slip_no VARCHAR NULL、created_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 資料模型:上述 migration;Order 加常數/scope;先修正⑤的 PickupCode 脆弱點。
- Phase 3 後台建單 + 列印:
PharmacyPickupService::create()(產序號=flow_id、庫存檢查、交易內建單)、Admin/PharmacyPickupController、勾選頁 + 列印頁(QR、不顯示姓名)。建單僅限pharmacy_pickup模式機台。 - Phase 4 B660:additive items[] + order_type 分流 + 模式 gate + 標記碼已領。
- Phase 5 回報:finalize 帶 dispense[] 一次彙整(復用
resolveDeliveryStatusFromDispense),靠 flow_id 終態冪等;庫存只扣一次;領藥單詳情顯示逐道結果。 - Phase 6 Android(另 repo):
shopping_mode=pharmacy_pickup啟用領藥 SaleFlow(沿用中國醫 TakeMedicineDialog/DispatchDialog,資料來源換 B660)。