@porulle/plugin-pos-restaurant 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +61 -0
  2. package/dist/hooks/modifier-validation.d.ts +21 -0
  3. package/dist/hooks/modifier-validation.d.ts.map +1 -0
  4. package/dist/hooks/modifier-validation.js +40 -0
  5. package/dist/hooks/table-lifecycle.d.ts +15 -0
  6. package/dist/hooks/table-lifecycle.d.ts.map +1 -0
  7. package/dist/hooks/table-lifecycle.js +40 -0
  8. package/dist/index.d.ts +60 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +169 -0
  11. package/dist/routes/kds.d.ts +9 -0
  12. package/dist/routes/kds.d.ts.map +1 -0
  13. package/dist/routes/kds.js +112 -0
  14. package/dist/routes/modifiers.d.ts +15 -0
  15. package/dist/routes/modifiers.d.ts.map +1 -0
  16. package/dist/routes/modifiers.js +117 -0
  17. package/dist/routes/operations.d.ts +34 -0
  18. package/dist/routes/operations.d.ts.map +1 -0
  19. package/dist/routes/operations.js +249 -0
  20. package/dist/routes/tables.d.ts +9 -0
  21. package/dist/routes/tables.d.ts.map +1 -0
  22. package/dist/routes/tables.js +110 -0
  23. package/dist/schema.d.ts +3831 -0
  24. package/dist/schema.d.ts.map +1 -0
  25. package/dist/schema.js +418 -0
  26. package/dist/services/alert-service.d.ts +56 -0
  27. package/dist/services/alert-service.d.ts.map +1 -0
  28. package/dist/services/alert-service.js +173 -0
  29. package/dist/services/analytics-service.d.ts +60 -0
  30. package/dist/services/analytics-service.d.ts.map +1 -0
  31. package/dist/services/analytics-service.js +178 -0
  32. package/dist/services/checklist-service.d.ts +66 -0
  33. package/dist/services/checklist-service.d.ts.map +1 -0
  34. package/dist/services/checklist-service.js +106 -0
  35. package/dist/services/kds-service.d.ts +77 -0
  36. package/dist/services/kds-service.d.ts.map +1 -0
  37. package/dist/services/kds-service.js +246 -0
  38. package/dist/services/modifier-service.d.ts +74 -0
  39. package/dist/services/modifier-service.d.ts.map +1 -0
  40. package/dist/services/modifier-service.js +180 -0
  41. package/dist/services/recipe-deduction-service.d.ts +64 -0
  42. package/dist/services/recipe-deduction-service.d.ts.map +1 -0
  43. package/dist/services/recipe-deduction-service.js +144 -0
  44. package/dist/services/recipe-service.d.ts +43 -0
  45. package/dist/services/recipe-service.d.ts.map +1 -0
  46. package/dist/services/recipe-service.js +85 -0
  47. package/dist/services/table-service.d.ts +61 -0
  48. package/dist/services/table-service.d.ts.map +1 -0
  49. package/dist/services/table-service.js +206 -0
  50. package/dist/types.d.ts +35 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +6 -0
  53. package/package.json +61 -0
  54. package/src/hooks/modifier-validation.ts +60 -0
  55. package/src/hooks/table-lifecycle.ts +50 -0
  56. package/src/index.ts +218 -0
  57. package/src/routes/kds.ts +121 -0
  58. package/src/routes/modifiers.ts +129 -0
  59. package/src/routes/operations.ts +276 -0
  60. package/src/routes/tables.ts +117 -0
  61. package/src/schema.ts +462 -0
  62. package/src/services/alert-service.ts +234 -0
  63. package/src/services/analytics-service.ts +242 -0
  64. package/src/services/checklist-service.ts +139 -0
  65. package/src/services/kds-service.ts +340 -0
  66. package/src/services/modifier-service.ts +251 -0
  67. package/src/services/recipe-deduction-service.ts +221 -0
  68. package/src/services/recipe-service.ts +115 -0
  69. package/src/services/table-service.ts +260 -0
  70. package/src/types.ts +63 -0
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @porulle/plugin-pos-restaurant
2
+
3
+ Restaurant layer on top of `@porulle/plugin-pos`: tables, floor zones, optional modifiers and KDS, checklists, alerts, recipes (food BOM), and analytics.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ bun add @porulle/plugin-pos @porulle/plugin-pos-restaurant
9
+ ```
10
+
11
+ Add to `commerce.config.ts`:
12
+
13
+ ```typescript
14
+ import { posPlugin } from "@porulle/plugin-pos";
15
+ import { posRestaurantPlugin } from "@porulle/plugin-pos-restaurant";
16
+
17
+ export default defineConfig({
18
+ plugins: [posPlugin(), posRestaurantPlugin()],
19
+ });
20
+ ```
21
+
22
+ (`posRestaurantPlugin` declares `requires: ["pos"]`.)
23
+
24
+ Add to `drizzle.config.ts`:
25
+
26
+ ```typescript
27
+ schema: [
28
+ "./node_modules/@porulle/plugin-pos-restaurant/src/schema.ts",
29
+ // include plugin-pos schema as well
30
+ ],
31
+ ```
32
+
33
+ ## What it does
34
+
35
+ Adds restaurant schema (modifiers, tables, KDS, checklists, alerts, recipes/combos/menu availability, P&L, favorites). Modifier and KDS route groups mount only when the corresponding options are enabled.
36
+
37
+ ## Routes exposed
38
+
39
+ - **`/pos/restaurant/tables`** — CRUD tables, zones, assign/clear/transfer, layout
40
+ - **`/pos/restaurant/modifier-groups`** (+ **`/pos/restaurant/modifier-options`**) — when `enableModifiers`
41
+ - **`/pos/restaurant/kds`** — stations, tickets, transitions — when `enableKDS`
42
+ - **`/pos/restaurant/checklists`**, **`/pos/restaurant/alerts`**, **`/pos/restaurant/recipes`**, **`/pos/restaurant/analytics`** — operational and reporting endpoints (see route files for full paths)
43
+
44
+ ## Hooks
45
+
46
+ **Emitted:** none.
47
+
48
+ **Consumed:** **`cart.beforeAddItem`** — validates modifier selections when `enableModifiers`. **`checkout.afterCreate`** — for POS transactions with table assignments, moves tables to `cleaning` and clears assignments (see `buildTableClearOnCompleteHook`).
49
+
50
+ ## MCP tools
51
+
52
+ - **`restaurant_tables`** — `list`, `set_status`, `transfer`
53
+ - **`restaurant_kds`** — `list_tickets`, `transition`, `list_zones`
54
+
55
+ ## Configuration options
56
+
57
+ `POSRestaurantPluginOptions`: `enableKDS`, `enableTips`, `enableModifiers`, `kdsAlertMinutes`.
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Modifier Validation Hook — cart.beforeAddItem
3
+ *
4
+ * Validates modifier selections when items are added to a POS cart.
5
+ * URY has no modifier validation (modifiers are just flat item links).
6
+ * This hook enforces:
7
+ * - Required modifier groups must have at least minSelect selections
8
+ * - No group may exceed maxSelect selections
9
+ * - Unavailable (86'd) options are rejected
10
+ * - Price adjustments are summed into cart line item metadata
11
+ */
12
+ import type { ModifierService } from "../services/modifier-service.js";
13
+ export declare function buildModifierValidationHook(getService: () => ModifierService): {
14
+ key: string;
15
+ handler: (...args: unknown[]) => Promise<{
16
+ [key: string]: unknown;
17
+ entityId?: string;
18
+ metadata?: Record<string, unknown>;
19
+ }>;
20
+ };
21
+ //# sourceMappingURL=modifier-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifier-validation.d.ts","sourceRoot":"","sources":["../../src/hooks/modifier-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,eAAe;;uBAGhD,OAAO,EAAE;;mBAGjB,MAAM;mBACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAsC3C"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Modifier Validation Hook — cart.beforeAddItem
3
+ *
4
+ * Validates modifier selections when items are added to a POS cart.
5
+ * URY has no modifier validation (modifiers are just flat item links).
6
+ * This hook enforces:
7
+ * - Required modifier groups must have at least minSelect selections
8
+ * - No group may exceed maxSelect selections
9
+ * - Unavailable (86'd) options are rejected
10
+ * - Price adjustments are summed into cart line item metadata
11
+ */
12
+ export function buildModifierValidationHook(getService) {
13
+ return {
14
+ key: "cart.beforeAddItem",
15
+ handler: async (...args) => {
16
+ const hook = args[0];
17
+ const { data, context } = hook;
18
+ const modifiers = data.metadata?.modifiers;
19
+ // If no modifiers provided, skip validation (non-restaurant items)
20
+ if (!modifiers || modifiers.length === 0)
21
+ return data;
22
+ if (!data.entityId)
23
+ return data;
24
+ const { resolveOrgId } = await import("@porulle/core");
25
+ const orgId = resolveOrgId(context.actor);
26
+ const service = getService();
27
+ const result = await service.validateModifiers(orgId, data.entityId, modifiers);
28
+ if (!result.ok) {
29
+ throw new Error(result.error);
30
+ }
31
+ // Inject validated modifiers and price adjustment into metadata
32
+ data.metadata = {
33
+ ...data.metadata,
34
+ validatedModifiers: result.value.validatedModifiers,
35
+ modifierPriceAdjustment: result.value.totalAdjustment,
36
+ };
37
+ return data;
38
+ },
39
+ };
40
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Table Lifecycle Hooks
3
+ *
4
+ * URY equivalent: table_status_delete() in ury_pos_invoice.py.
5
+ * URY clears occupied=0 on POS Invoice delete/cancel/submit.
6
+ *
7
+ * We hook into checkout.afterCreate to update table status when a
8
+ * POS transaction completes, and pos transaction void to clear tables.
9
+ */
10
+ import type { Db } from "../types.js";
11
+ export declare function buildTableClearOnCompleteHook(getDb: () => Db): {
12
+ key: string;
13
+ handler: (...args: unknown[]) => Promise<void>;
14
+ };
15
+ //# sourceMappingURL=table-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-lifecycle.d.ts","sourceRoot":"","sources":["../../src/hooks/table-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE;;uBAGhC,OAAO,EAAE;EAgCrC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Table Lifecycle Hooks
3
+ *
4
+ * URY equivalent: table_status_delete() in ury_pos_invoice.py.
5
+ * URY clears occupied=0 on POS Invoice delete/cancel/submit.
6
+ *
7
+ * We hook into checkout.afterCreate to update table status when a
8
+ * POS transaction completes, and pos transaction void to clear tables.
9
+ */
10
+ import { eq } from "@porulle/core/drizzle";
11
+ import { posTableAssignments, posTables } from "../schema.js";
12
+ export function buildTableClearOnCompleteHook(getDb) {
13
+ return {
14
+ key: "checkout.afterCreate",
15
+ handler: async (...args) => {
16
+ const hook = args[0];
17
+ const metadata = hook.result?.metadata;
18
+ const posTransactionId = metadata?.posTransactionId;
19
+ if (!posTransactionId)
20
+ return;
21
+ const db = getDb();
22
+ // Find table assignments for this transaction
23
+ const assignments = await db
24
+ .select()
25
+ .from(posTableAssignments)
26
+ .where(eq(posTableAssignments.transactionId, posTransactionId));
27
+ // Set tables to "cleaning" (staff will set to "available" after bussing)
28
+ for (const assignment of assignments) {
29
+ await db
30
+ .update(posTables)
31
+ .set({ status: "cleaning", updatedAt: new Date() })
32
+ .where(eq(posTables.id, assignment.tableId));
33
+ }
34
+ // Remove assignments
35
+ await db
36
+ .delete(posTableAssignments)
37
+ .where(eq(posTableAssignments.transactionId, posTransactionId));
38
+ },
39
+ };
40
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * POS Restaurant Extension — RFC-024a (Complete Feature Set)
3
+ *
4
+ * Extends @porulle/plugin-pos with all restaurant-specific features
5
+ * informed by URY Restaurant ERP (ury-erp/ury) production patterns.
6
+ *
7
+ * Feature coverage (maps to URY FEATURES.md):
8
+ *
9
+ * POS & Billing:
10
+ * - Pre-billing checklists (compliance enforcement)
11
+ * - Table service, QSR, and takeaway (order types)
12
+ * - Multi-cashier handling (via Tier 0 terminals)
13
+ * - Shift opening/closing with cash reconciliation (via Tier 0)
14
+ *
15
+ * Menu & Recipe Management:
16
+ * - Item modifiers (groups, options, required/optional, price adjustments)
17
+ * - Recipe/BOM mapping for COGS calculation
18
+ * - Combos and item bundles
19
+ * - Menu availability per outlet (86'd items)
20
+ *
21
+ * Table Order Management:
22
+ * - Table management with zones, floor plan, status lifecycle
23
+ * - Server section assignment
24
+ * - Table/captain transfer
25
+ * - Customer favorites (top ordered items)
26
+ *
27
+ * Kitchen Display & KOT Management:
28
+ * - Multi-station KDS with item-group routing
29
+ * - 4-state ticket flow (pending -> preparing -> ready -> served)
30
+ * - Item-level completion tracking (persistent, not localStorage)
31
+ * - Course sequencing with priority-based ordering
32
+ * - Delay and modification tracking
33
+ * - KOT reprint support
34
+ *
35
+ * Operational Red Flags & Alerts:
36
+ * - Delayed order alerts
37
+ * - KOT not started alerts
38
+ * - Prolonged table occupancy alerts
39
+ * - Excessive cancellation tracking
40
+ * - Configurable thresholds per alert type
41
+ *
42
+ * Reports & Analytics:
43
+ * - Daily Profit & Loss (gross sales, COGS, expenses, net profit)
44
+ * - Station performance (prep time, throughput)
45
+ * - Course-wise performance
46
+ * - Staff/captain performance
47
+ * - P&L expense breakdown
48
+ */
49
+ import type { POSRestaurantPluginOptions } from "./types.js";
50
+ export type { POSRestaurantPluginOptions, Db } from "./types.js";
51
+ export { ModifierService } from "./services/modifier-service.js";
52
+ export { TableService } from "./services/table-service.js";
53
+ export { KDSService } from "./services/kds-service.js";
54
+ export { ChecklistService } from "./services/checklist-service.js";
55
+ export { AlertService } from "./services/alert-service.js";
56
+ export { RecipeService } from "./services/recipe-service.js";
57
+ export { RestaurantAnalyticsService } from "./services/analytics-service.js";
58
+ export { RecipeDeductionService } from "./services/recipe-deduction-service.js";
59
+ export declare function posRestaurantPlugin(userOptions?: POSRestaurantPluginOptions): import("@porulle/core").CommercePlugin;
60
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AA6CH,OAAO,KAAK,EAAE,0BAA0B,EAAM,MAAM,YAAY,CAAC;AAGjE,YAAY,EAAE,0BAA0B,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAEhF,wBAAgB,mBAAmB,CAAC,WAAW,GAAE,0BAA+B,0CAgH/E"}
package/dist/index.js ADDED
@@ -0,0 +1,169 @@
1
+ /**
2
+ * POS Restaurant Extension — RFC-024a (Complete Feature Set)
3
+ *
4
+ * Extends @porulle/plugin-pos with all restaurant-specific features
5
+ * informed by URY Restaurant ERP (ury-erp/ury) production patterns.
6
+ *
7
+ * Feature coverage (maps to URY FEATURES.md):
8
+ *
9
+ * POS & Billing:
10
+ * - Pre-billing checklists (compliance enforcement)
11
+ * - Table service, QSR, and takeaway (order types)
12
+ * - Multi-cashier handling (via Tier 0 terminals)
13
+ * - Shift opening/closing with cash reconciliation (via Tier 0)
14
+ *
15
+ * Menu & Recipe Management:
16
+ * - Item modifiers (groups, options, required/optional, price adjustments)
17
+ * - Recipe/BOM mapping for COGS calculation
18
+ * - Combos and item bundles
19
+ * - Menu availability per outlet (86'd items)
20
+ *
21
+ * Table Order Management:
22
+ * - Table management with zones, floor plan, status lifecycle
23
+ * - Server section assignment
24
+ * - Table/captain transfer
25
+ * - Customer favorites (top ordered items)
26
+ *
27
+ * Kitchen Display & KOT Management:
28
+ * - Multi-station KDS with item-group routing
29
+ * - 4-state ticket flow (pending -> preparing -> ready -> served)
30
+ * - Item-level completion tracking (persistent, not localStorage)
31
+ * - Course sequencing with priority-based ordering
32
+ * - Delay and modification tracking
33
+ * - KOT reprint support
34
+ *
35
+ * Operational Red Flags & Alerts:
36
+ * - Delayed order alerts
37
+ * - KOT not started alerts
38
+ * - Prolonged table occupancy alerts
39
+ * - Excessive cancellation tracking
40
+ * - Configurable thresholds per alert type
41
+ *
42
+ * Reports & Analytics:
43
+ * - Daily Profit & Loss (gross sales, COGS, expenses, net profit)
44
+ * - Station performance (prep time, throughput)
45
+ * - Course-wise performance
46
+ * - Staff/captain performance
47
+ * - P&L expense breakdown
48
+ */
49
+ import { defineCommercePlugin } from "@porulle/core";
50
+ import { posModifierGroups, posModifierOptions, posTables, posTableAssignments, kdsStations, kdsStationItemGroups, kdsTickets, kdsTicketItems, posChecklists, posChecklistItems, posChecklistCompletions, posRestaurantAlerts, posAlertConfig, posRecipes, posRecipeIngredients, posCombos, posComboGroups, posComboItems, posMenuAvailability, posDailyPnl, posPnlExpenses, posCustomerFavorites, } from "./schema.js";
51
+ import { ModifierService } from "./services/modifier-service.js";
52
+ import { TableService } from "./services/table-service.js";
53
+ import { KDSService } from "./services/kds-service.js";
54
+ import { ChecklistService } from "./services/checklist-service.js";
55
+ import { AlertService } from "./services/alert-service.js";
56
+ import { RecipeService } from "./services/recipe-service.js";
57
+ import { RestaurantAnalyticsService } from "./services/analytics-service.js";
58
+ import { buildModifierRoutes, buildModifierOptionRoutes } from "./routes/modifiers.js";
59
+ import { buildTableRoutes } from "./routes/tables.js";
60
+ import { buildKDSRoutes } from "./routes/kds.js";
61
+ import { buildChecklistRoutes, buildAlertRoutes, buildRecipeRoutes, buildAnalyticsRoutes, } from "./routes/operations.js";
62
+ import { buildModifierValidationHook } from "./hooks/modifier-validation.js";
63
+ import { buildTableClearOnCompleteHook } from "./hooks/table-lifecycle.js";
64
+ import { DEFAULT_RESTAURANT_OPTIONS } from "./types.js";
65
+ export { ModifierService } from "./services/modifier-service.js";
66
+ export { TableService } from "./services/table-service.js";
67
+ export { KDSService } from "./services/kds-service.js";
68
+ export { ChecklistService } from "./services/checklist-service.js";
69
+ export { AlertService } from "./services/alert-service.js";
70
+ export { RecipeService } from "./services/recipe-service.js";
71
+ export { RestaurantAnalyticsService } from "./services/analytics-service.js";
72
+ export { RecipeDeductionService } from "./services/recipe-deduction-service.js";
73
+ export function posRestaurantPlugin(userOptions = {}) {
74
+ const options = {
75
+ ...DEFAULT_RESTAURANT_OPTIONS,
76
+ ...userOptions,
77
+ };
78
+ const dbRef = { current: null };
79
+ const modifierServiceRef = { current: null };
80
+ return defineCommercePlugin({
81
+ id: "pos-restaurant",
82
+ version: "1.0.0",
83
+ requires: ["pos"],
84
+ permissions: [
85
+ {
86
+ scope: "pos-restaurant:admin",
87
+ description: "Create/edit modifier groups, tables, KDS stations, checklists, recipes, alert config, analytics, floor plan layout.",
88
+ },
89
+ ],
90
+ schema: () => ({
91
+ // Core restaurant tables
92
+ posModifierGroups,
93
+ posModifierOptions,
94
+ posTables,
95
+ posTableAssignments,
96
+ kdsStations,
97
+ kdsStationItemGroups,
98
+ kdsTickets,
99
+ kdsTicketItems,
100
+ // Operational features
101
+ posChecklists,
102
+ posChecklistItems,
103
+ posChecklistCompletions,
104
+ posRestaurantAlerts,
105
+ posAlertConfig,
106
+ // Menu & recipe management
107
+ posRecipes,
108
+ posRecipeIngredients,
109
+ posCombos,
110
+ posComboGroups,
111
+ posComboItems,
112
+ posMenuAvailability,
113
+ // Analytics
114
+ posDailyPnl,
115
+ posPnlExpenses,
116
+ posCustomerFavorites,
117
+ }),
118
+ hooks: () => {
119
+ const hooks = [];
120
+ if (options.enableModifiers) {
121
+ hooks.push(buildModifierValidationHook(() => {
122
+ if (!modifierServiceRef.current)
123
+ throw new Error("ModifierService not initialized");
124
+ return modifierServiceRef.current;
125
+ }));
126
+ }
127
+ hooks.push(buildTableClearOnCompleteHook(() => {
128
+ if (!dbRef.current)
129
+ throw new Error("Restaurant plugin DB not initialized");
130
+ return dbRef.current;
131
+ }));
132
+ return hooks;
133
+ },
134
+ routes: (ctx) => {
135
+ const db = ctx.database.db;
136
+ if (!db)
137
+ return [];
138
+ dbRef.current = db;
139
+ // Initialize all services
140
+ const modifierService = new ModifierService(db);
141
+ const tableService = new TableService(db);
142
+ const kdsService = new KDSService(db);
143
+ const checklistService = new ChecklistService(db);
144
+ const alertService = new AlertService(db);
145
+ const recipeService = new RecipeService(db);
146
+ const analyticsService = new RestaurantAnalyticsService(db);
147
+ modifierServiceRef.current = modifierService;
148
+ const routes = [
149
+ // Table management (always enabled)
150
+ ...buildTableRoutes(tableService, ctx),
151
+ // Checklists (always enabled)
152
+ ...buildChecklistRoutes(checklistService, ctx),
153
+ // Alerts (always enabled)
154
+ ...buildAlertRoutes(alertService, ctx),
155
+ // Recipes/BOM (always enabled)
156
+ ...buildRecipeRoutes(recipeService, ctx),
157
+ // Analytics (always enabled)
158
+ ...buildAnalyticsRoutes(analyticsService, ctx),
159
+ ];
160
+ if (options.enableModifiers) {
161
+ routes.push(...buildModifierRoutes(modifierService, ctx), ...buildModifierOptionRoutes(modifierService, ctx));
162
+ }
163
+ if (options.enableKDS) {
164
+ routes.push(...buildKDSRoutes(kdsService, ctx));
165
+ }
166
+ return routes;
167
+ },
168
+ });
169
+ }
@@ -0,0 +1,9 @@
1
+ import type { KDSService } from "../services/kds-service.js";
2
+ import type { PluginRouteRegistration } from "@porulle/core";
3
+ export declare function buildKDSRoutes(service: KDSService, ctx: {
4
+ services?: Record<string, unknown>;
5
+ database?: {
6
+ db: unknown;
7
+ };
8
+ }): PluginRouteRegistration[];
9
+ //# sourceMappingURL=kds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kds.d.ts","sourceRoot":"","sources":["../../src/routes/kds.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE7D,wBAAgB,cAAc,CAC5B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAgH3B"}
@@ -0,0 +1,112 @@
1
+ import { router } from "@porulle/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildKDSRoutes(service, ctx) {
4
+ const r = router("POS Restaurant KDS", "/pos/restaurant/kds", ctx);
5
+ // ─── Stations ──────────────────────────────────────────────────────
6
+ r.post("/stations")
7
+ .summary("Create KDS station")
8
+ .permission("pos-restaurant:admin")
9
+ .input(z.object({
10
+ name: z.string().min(1).max(100),
11
+ alertThresholdMinutes: z.number().int().min(1).optional(),
12
+ metadata: z.record(z.string(), z.unknown()).optional(),
13
+ }))
14
+ .handler(async ({ input, orgId }) => {
15
+ const body = input;
16
+ const result = await service.createStation(orgId, body);
17
+ if (!result.ok)
18
+ throw new Error(result.error);
19
+ return result.value;
20
+ });
21
+ r.get("/stations")
22
+ .summary("List KDS stations")
23
+ .permission("pos:operate")
24
+ .handler(async ({ orgId }) => {
25
+ const result = await service.listStations(orgId);
26
+ if (!result.ok)
27
+ throw new Error(result.error);
28
+ return result.value;
29
+ });
30
+ r.patch("/stations/{id}")
31
+ .summary("Update KDS station")
32
+ .permission("pos-restaurant:admin")
33
+ .input(z.object({
34
+ name: z.string().min(1).max(100).optional(),
35
+ isActive: z.boolean().optional(),
36
+ alertThresholdMinutes: z.number().int().min(1).optional(),
37
+ }))
38
+ .handler(async ({ params, input, orgId }) => {
39
+ const body = input;
40
+ const result = await service.updateStation(orgId, params.id, body);
41
+ if (!result.ok)
42
+ throw new Error(result.error);
43
+ return result.value;
44
+ });
45
+ r.post("/stations/{id}/item-groups")
46
+ .summary("Add item group to station")
47
+ .permission("pos-restaurant:admin")
48
+ .input(z.object({ itemGroup: z.string().min(1) }))
49
+ .handler(async ({ params, input }) => {
50
+ const body = input;
51
+ const result = await service.addItemGroup(params.id, body.itemGroup);
52
+ if (!result.ok)
53
+ throw new Error(result.error);
54
+ return result.value;
55
+ });
56
+ r.delete("/stations/{id}/item-groups/{group}")
57
+ .summary("Remove item group from station")
58
+ .permission("pos-restaurant:admin")
59
+ .handler(async ({ params }) => {
60
+ const result = await service.removeItemGroup(params.id, params.group);
61
+ if (!result.ok)
62
+ throw new Error(result.error);
63
+ return result.value;
64
+ });
65
+ // ─── Tickets ───────────────────────────────────────────────────────
66
+ r.get("/stations/{id}/tickets")
67
+ .summary("List pending tickets for station")
68
+ .permission("pos:operate")
69
+ .handler(async ({ params, orgId }) => {
70
+ const result = await service.listPendingTickets(orgId, params.id);
71
+ if (!result.ok)
72
+ throw new Error(result.error);
73
+ return result.value;
74
+ });
75
+ r.post("/tickets/{id}/start")
76
+ .summary("Mark ticket as preparing")
77
+ .permission("pos:operate")
78
+ .handler(async ({ params }) => {
79
+ const result = await service.startTicket(params.id);
80
+ if (!result.ok)
81
+ throw new Error(result.error);
82
+ return result.value;
83
+ });
84
+ r.post("/tickets/{id}/ready")
85
+ .summary("Mark ticket as ready")
86
+ .permission("pos:operate")
87
+ .handler(async ({ params }) => {
88
+ const result = await service.readyTicket(params.id);
89
+ if (!result.ok)
90
+ throw new Error(result.error);
91
+ return result.value;
92
+ });
93
+ r.post("/tickets/{id}/serve")
94
+ .summary("Mark ticket as served")
95
+ .permission("pos:operate")
96
+ .handler(async ({ params }) => {
97
+ const result = await service.serveTicket(params.id);
98
+ if (!result.ok)
99
+ throw new Error(result.error);
100
+ return result.value;
101
+ });
102
+ r.post("/tickets/{id}/items/{itemId}/done")
103
+ .summary("Mark ticket item as done")
104
+ .permission("pos:operate")
105
+ .handler(async ({ params }) => {
106
+ const result = await service.markItemDone(params.id, params.itemId);
107
+ if (!result.ok)
108
+ throw new Error(result.error);
109
+ return result.value;
110
+ });
111
+ return r.routes();
112
+ }
@@ -0,0 +1,15 @@
1
+ import type { ModifierService } from "../services/modifier-service.js";
2
+ import type { PluginRouteRegistration } from "@porulle/core";
3
+ export declare function buildModifierRoutes(service: ModifierService, ctx: {
4
+ services?: Record<string, unknown>;
5
+ database?: {
6
+ db: unknown;
7
+ };
8
+ }): PluginRouteRegistration[];
9
+ export declare function buildModifierOptionRoutes(service: ModifierService, ctx: {
10
+ services?: Record<string, unknown>;
11
+ database?: {
12
+ db: unknown;
13
+ };
14
+ }): PluginRouteRegistration[];
15
+ //# sourceMappingURL=modifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifiers.d.ts","sourceRoot":"","sources":["../../src/routes/modifiers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE7D,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAqF3B;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CA8B3B"}