import { OOReasonCode } from './online-integration'; import { SOOrderErrorType, SOValidateCart, SOValidateCartItem } from './online-ordering'; import { OrderItem } from './order'; /** * 吃到飽加點的購物車品項。 * * 結構就是既有 `SOValidateCartItem`,只是 `menuId` 與 `productCategoryId` 改為選填: * 後端完全不使用前端送來的這兩個值。可點範圍以方案綁定菜單為準,商品分類以伺服器解析的 * `Product.categoryId` 為準,前端不需要送。 * * `productName` 後端同樣不使用(快照名稱一律以伺服器解析結果為準),但共用型別把它列為 * 必填,這裡不另外放寬。`productAmount` 則必須送:後端會拿它與伺服器價格嚴格比對, * 不一致回 `amountChanged`,讓前端知道菜單已經變動。 */ export declare type SOBuffetValidateCartItem = Omit & { menuId?: string; productCategoryId?: string; children?: SOBuffetValidateCartItem[]; }; /** 吃到飽加點的 request body;沿用既有購物車結構,不新增吃到飽專用欄位。 */ export interface SOBuffetValidateCart extends Omit { items: SOBuffetValidateCartItem[]; } /** POS 結束吃到飽主單時,由 POS 後端寫入 SDIT 的原因。 */ export declare type BuffetOrderEndReason = /** POS 已完成內用桌關桌流程;主單之後不可再加點。 */ 'posTableClosed' /** POS 已作廢正式訂單;主單之後不可再加點。 */ | 'posOrderVoided' /** POS 已完成結帳;主單之後不可再加點。 */ | 'posOrderCheckout' /** POS 重試建立本地正式訂單仍失敗後,由 POS 後端補關閉。 */ | 'posOrderCreationFailed' /** 保留給未來受權流程的取消;本期消費者不可自行取消。 */ | 'canceled'; /** 每一筆 `OrderAddition` 的內部單一狀態機;由 SDIT 後端更新,不直接回傳給 SO Web。 */ export declare type OrderAdditionStatus = /** 已建立歷程,正等待 SDIT 對 POS 的首次或重試通知;消費者不可修改此筆。 */ 'pendingPosDelivery' /** POS 已建立待接單,正等待店員整筆接受或拒絕;消費者不可撤回或編輯。 */ | 'pendingPosDecision' /** 三次通知 POS 都失敗;歷程保留,消費者不可手動重送。 */ | 'deliveryFailed' /** POS 已接受並由 SDIT 記錄決策;此筆為永久完成歷程。 */ | 'accepted' /** POS 已拒絕並記錄原因;此筆為永久完成歷程。 */ | 'rejected'; /** * Admin 在 SDIT 管理的吃到飽方案。 * 建立與更新由 Admin API 寫入;POS 只讀取可開桌方案,消費者不可信任或修改。 * * 刪除是永久移除,沒有軟刪除:進行中的桌次會因此無法再以 QR 加點, * 所以 Admin 必須提醒店家於打烊後才刪除方案。 */ export interface BuffetPlan { /** SDIT 方案 ID;Admin 建立時由後端產生,亦寫入 `Order.buffet.planId`。 */ id: string; /** SDIT 店家 ID;由授權上下文決定,不能由 Admin body 任意指定。 */ storeId: string; /** Admin 輸入的方案顯示名稱,供 Admin、POS 選方案與 SO Web 狀態顯示。 */ name: string; /** 已同步至 SDIT 的方案收費商品 ID;必須是可單獨販售的單品,絕不是 POS `product_no`。 */ productId: string; /** Admin 選擇的專屬菜單 ID;後端必須驗證其 path 為 `MenuPath.poskyProBuffet`。 */ menuId: string; /** Admin 設定的用餐時長,單位為分鐘;POS 開桌時由 SDIT 用它計算結束時間。 */ diningDurationMinutes: number; /** Admin 設定的結束前停止加點分鐘數;POS 開桌時由 SDIT 計算最後加點截止時間。 */ lastAdditionBeforeEndMinutes: number; /** Admin 選填的單輪品項總數上限;`0` 或省略代表不限,由後端在送出時驗證。 */ maxTotalQuantityPerAddition?: number; /** Admin 選填的同一商品單輪數量上限;`0` 或省略代表不限,由後端在送出時驗證。 */ maxQuantityPerProductPerAddition?: number; /** Admin 選填的單輪不同 `productId` 數量上限;`0` 或省略代表不限。 */ maxDistinctProductIdCountPerAddition?: number; /** Admin 選填的兩次消費者送出最小間隔,單位為分鐘;`0` 或省略代表不限。 */ minAdditionIntervalMinutes?: number; /** Admin 啟用狀態;`false` 只阻擋 POS 新開桌,不中斷已開桌主單。 */ isActive: boolean; /** SDIT 後端建立方案時寫入的 Unix epoch milliseconds。 */ createdAt: number; /** SDIT 後端每次更新方案時寫入的 Unix epoch milliseconds。 */ updatedAt: number; } /** * Admin 建立或更新方案時可提交的資料;ID、店家歸屬與時間一律由 SDIT 後端處理。 * * 後端的關聯驗證(同店商品、專屬菜單、方案商品排除)只在 `isActive` 為 `true` 時執行, * 所以停用的方案可以先存起來、之後再修正關聯後啟用。 */ export interface BuffetPlanInput { /** Admin 輸入的方案名稱;SDIT 後端驗證後保存,長度上限 100 字。 */ name: string; /** 同店、已同步至 SDIT 的方案收費商品 ID;必須是可單獨販售的單品,不得傳 POS 商品編號。 */ productId: string; /** 同店且 path 為 `MenuPath.poskyProBuffet` 的專屬吃到飽菜單 ID。 */ menuId: string; /** Admin 設定的用餐時長,單位為分鐘;必須是大於 `0` 的整數。 */ diningDurationMinutes: number; /** Admin 設定的結束前停止加點分鐘數;必須是非負整數且小於用餐時長。 */ lastAdditionBeforeEndMinutes: number; /** 單輪品項總數上限;省略或 `0` 為不限。 */ maxTotalQuantityPerAddition?: number; /** 同一 `productId` 單輪數量上限;省略或 `0` 為不限。 */ maxQuantityPerProductPerAddition?: number; /** 單輪不同 `productId` 種類上限;省略或 `0` 為不限。 */ maxDistinctProductIdCountPerAddition?: number; /** 兩次消費者成功送出加點的最小間隔,單位為分鐘;省略或 `0` 為不限。 */ minAdditionIntervalMinutes?: number; /** 方案是否允許 POS 新開桌;由 Admin 決定,後端照此值寫入。 */ isActive: boolean; } /** SDIT `Order` 的 `buffet` 擴充欄位;只由開桌、送出加點與關桌 Use Case 寫入。 */ export interface OrderBuffet { /** 來源為 SDIT `BuffetPlan.id`;開桌時固定,供顯示與後續規則查詢。 */ planId: string; /** 開桌時由 SDIT 依方案用餐時長計算的預計結束 Unix epoch milliseconds。 */ estimatedDiningEndAt: number; /** 開桌時由 SDIT 計算的最後可送加點 Unix epoch milliseconds。 */ lastAdditionDeadlineAt: number; /** 消費者最近一次成功送出加點時由 SDIT 更新的 Unix epoch milliseconds;尚未送出時省略。 */ latestAdditionSubmittedAt?: number; /** POS 本地關桌/結帳/作廢成功後,由 SDIT 關桌 Use Case 寫入的實際結束 Unix epoch milliseconds。 */ endedAt?: number; /** 僅在 `endedAt` 出現時,由 POS 後端提供並由 SDIT 驗證保存的結束原因。 */ endReason?: BuffetOrderEndReason; } /** POS 對某一筆加點的關聯與決策;只由 POS → SDIT 接受或拒絕 API 寫入。 */ export interface OrderAdditionPosReference { /** POS 正式訂單號;接受後必有,拒絕時僅在 POS 願意提供對應主單時出現。 */ formalOrderNo?: string; /** POS `customer_take_order.orders_no` 待接單號;POS 建立待接單後出現。 */ pendingTakeOrderNo?: string; /** POS 店員做出接受或拒絕決策時提供的 Unix epoch milliseconds。 */ decidedAt?: number; /** 僅拒絕時出現;沿用既有線上訂單取消原因 `OOReasonCode`。 */ rejectReasonCode?: OOReasonCode; /** 僅拒絕且 POS 有說明文字時出現;不可作為程式判斷依據。 */ rejectReasonMessage?: string; } /** * 一次消費者加點的歷程,不是購物車,也不是另一張主訂單。 * SDIT 建立後保存不可變品項快照;POS 接受或拒絕只更新其狀態與 POS 關聯資料。 * 保存於 `TimeToLiveTable`,自送出起保留半年後由 TTL 清除;帳務歷史以 POS `orders_detail` 為準。 */ export interface OrderAddition { /** SDIT ULID 加點 ID;由 SDIT 送出加點時產生,供 POS 通知、決策與冪等對應。 */ id: string; /** SDIT 店家 ID;由 QR 解析出的主單歸屬取得,供資料分區與 POS 請求核對。 */ storeId: string; /** SDIT 吃到飽 `Order.id` 主單 ID;由 QR 對應取得,不由消費者 body 信任。 */ masterOrderId: string; /** SDIT 後端在送出時解析的不可變 `OrderItem` 價格快照;不是前端購物車資料。 */ items: OrderItem[]; /** 消費者本輪整筆備註;未填時省略,SDIT 保存原始可接受內容。 */ note?: string; /** 消費者成功送出、SDIT 寫入此歷程時的 Unix epoch milliseconds。 */ submittedAt: number; /** SDIT 最後一次變更此筆通知或 POS 決策狀態時寫入的 Unix epoch milliseconds。 */ updatedAt: number; /** 由 SDIT 狀態機寫入;POS 依此避免重複決策。SO Web 歷史 API 會轉為公開狀態。 */ status: OrderAdditionStatus; /** SDIT 對 POS 已執行的通知次數,建立時為 `0`,最多依既定重試規則增加。 */ notificationAttemptCount: number; /** 每次通知 POS 前由 SDIT 寫入的 Unix epoch milliseconds;尚未通知時省略。 */ lastNotificationAttemptAt?: number; /** 僅最近一次通知失敗時出現;僅供受權維運流程使用的技術錯誤碼,不得公開給 SO Web。 */ lastNotificationErrorCode?: string; /** 僅最近一次通知失敗且有安全訊息時出現;不得向消費者揭露敏感內容。 */ lastNotificationErrorMessage?: string; /** POS 已建立待接單、接受或拒絕後,由 SDIT 保存的 POS 對應資料;尚未建立時省略。 */ pos?: OrderAdditionPosReference; } /** * SO Web 可公開顯示的「目前不能加點」原因。 * 不包含 POS、通知、資料庫或其他跨系統處理細節;需要調整菜單時沿用既有 SO 錯誤原因。 */ export declare type SOBuffetAdditionDisabledReason = 'buffetOrderEnded' | 'buffetAdditionDeadlinePassed' | 'buffetAdditionIntervalNotReached' | SOOrderErrorType; /** * SO Web 歷史頁可顯示的公開處理結果。 * `pending` 對應內部 `pendingPosDelivery`、`pendingPosDecision`; * `failed` 對應內部 `deliveryFailed`,不揭露失敗系統或原因。 */ export declare type SOBuffetAdditionHistoryStatus = 'pending' | 'accepted' | 'rejected' | 'failed'; /** * SO Web 公開 API 回傳的穩定機器可讀錯誤碼。 * 僅保留會影響消費者下一步操作的資訊;不得用它辨識 POS、SDIT、通知或資料庫的失敗來源。 */ export declare type SOBuffetPublicErrorCode = /** 公開碼錯誤、已失效、店家不符或找不到時統一回傳;不可藉此判斷訂單是否存在。 */ 'buffetPublicAccessInvalid' /** 吃到飽主單已由 POS 關閉、作廢或結帳;消費者之後不可送出加點。 */ | 'buffetOrderEnded' /** 已超過 `Order.buffet.lastAdditionDeadlineAt`;保留本機草稿但不可送出。 */ | 'buffetAdditionDeadlinePassed' /** 最近送出時間尚未滿方案最小間隔;回應可帶下一次可送時間。 */ | 'buffetAdditionIntervalNotReached' /** 本輪總數、同品項數或不同商品種類數超過方案限制。 */ | 'buffetAdditionLimitExceeded' /** 本次加點未能完成店家處理;不揭露是 POS、SDIT、網路或其他內部失敗。 */ | 'buffetAdditionSubmissionFailed'; /** * 僅限 Admin、POS 與 SDIT 受權 API 的錯誤碼,不得透過公開 QR API 回傳給 SO Web。 * 這些錯誤用於受權流程的修正、冪等與維運,而非消費者操作提示。 */ export declare type BuffetPrivilegedErrorCode = /** 方案已停用、已刪除或不符合 POS 開桌條件。 */ 'buffetPlanUnavailable' /** POS 指定的加點 ID 不存在於指定店家與主單。 */ | 'buffetAdditionNotFound' /** POS 對已完成或不允許決策的加點再次接受/拒絕。 */ | 'buffetAdditionDecisionConflict'; /** 吃到飽錯誤碼聯集;實際上線時放在既有 `TSSDITError.errorType`。 */ export declare type BuffetErrorCode = SOBuffetPublicErrorCode | BuffetPrivilegedErrorCode; /** * 僅供吃到飽專屬規則使用的 SDIT API 錯誤 response。 * 菜單時段、缺貨、停售與價格異動一律直接使用既有 `SOOrderError`/`SOUnavailableCartItem`。 * * 注意:這是語意契約。實際 wire format 沿用既有 `TSSDITError`,`code` 放在 * `errorType`,`nextAdditionAvailableAt` 與 `details` 放在(字串化的)`data`。 */ export interface BuffetApiError { /** 公開操作錯誤碼;SO Web 只用於決定可採取的下一步,不可推論後端或 POS 的失敗來源。 */ code: SOBuffetPublicErrorCode; /** 面向消費者的說明文字;不得作為前端邏輯判斷或依賴固定字串。 */ message: string; /** 僅加點間隔未到時出現的下一次可送 Unix epoch milliseconds。 */ nextAdditionAvailableAt?: number; /** 驗證失敗時可選提供的欄位級資訊;非驗證錯誤時省略。 */ details?: Array<{ /** 對應 client input 的欄位路徑,例如 `items[0].quantity`。 */ path: string; /** 該欄位的細部驗證碼;供 UI 對應提示,不取代外層 `code`。 */ code: string; /** 該欄位可顯示的說明文字;前端不可依賴固定字串做判斷。 */ message: string; }>; }