@fayz-ai/plugin-orders 0.14.3 → 0.15.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.
- package/README.md +1 -0
- package/dist/{OrderDetailRoute-LTPDQXQU.js → OrderDetailRoute-QGZIMEQ3.js} +9 -7
- package/dist/OrderDetailRoute-QGZIMEQ3.js.map +1 -0
- package/dist/{OrdersPage-5326V62H.js → OrdersPage-3KNCFC7K.js} +3 -3
- package/dist/OrdersPage-3KNCFC7K.js.map +1 -0
- package/dist/context.d.ts +9 -6
- package/dist/context.d.ts.map +1 -1
- package/dist/index.d.ts +20 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -1425
- package/dist/index.js.map +1 -1
- package/dist/lib/list-query.d.ts +1 -1
- package/dist/lib/list-query.d.ts.map +1 -1
- package/dist/settings/DeliverySettings.d.ts.map +1 -1
- package/dist/settings/v1-settings.d.ts +2 -0
- package/dist/settings/v1-settings.d.ts.map +1 -0
- package/dist/views/OrderReceivableActions.d.ts.map +1 -1
- package/dist/views/OrdersPage.d.ts +2 -2
- package/dist/views/OrdersPage.d.ts.map +1 -1
- package/package.json +8 -9
- package/dist/OrderDetailRoute-LTPDQXQU.js.map +0 -1
- package/dist/OrdersPage-5326V62H.js.map +0 -1
- package/dist/data/core-supabase.d.ts +0 -26
- package/dist/data/core-supabase.d.ts.map +0 -1
- package/dist/data/mock.d.ts +0 -3
- package/dist/data/mock.d.ts.map +0 -1
- package/dist/data/platform.d.ts +0 -19
- package/dist/data/platform.d.ts.map +0 -1
- package/dist/data/types.d.ts +0 -17
- package/dist/data/types.d.ts.map +0 -1
- package/dist/integrations/index.d.ts +0 -8
- package/dist/integrations/index.d.ts.map +0 -1
- package/dist/store.d.ts +0 -33
- package/dist/store.d.ts.map +0 -1
- package/dist/types.d.ts +0 -145
- package/dist/types.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,573 +1,16 @@
|
|
|
1
1
|
export { ORDER_DETAIL_COMPONENT_ID } from './chunk-YVC7R552.js';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { createConnectionStore, connectionRuns, connectionSettings, connectionStatus, settingsStatus,
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import {
|
|
3
|
+
import { createConnectionStore, connectionRuns, connectionSettings, connectionStatus, settingsStatus, tl, getSupabaseClientOptional } from '@fayz-ai/core';
|
|
4
|
+
import { createSupabaseOrdersProvider } from '@fayz-ai/orders/data/supabase';
|
|
5
|
+
export { createSupabaseOrdersProvider as createCoreOrdersProvider } from '@fayz-ai/orders/data/supabase';
|
|
6
|
+
import { createOrdersStore } from '@fayz-ai/orders/store';
|
|
7
|
+
import { fayzConnectorOAuth, defineSettingsTab, PluginSettingsPanel, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, SettingsGroup, ToggleRow, AddConnectorButton, ConnectorRow, AddConnectorPanel, ConnectorDetail, TextRow } from '@fayz-ai/admin';
|
|
7
8
|
import { Skeleton } from '@fayz-ai/ui';
|
|
8
9
|
import { AlertTriangle, Loader2, Check } from 'lucide-react';
|
|
9
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var DEFAULT_CHANNELS = {
|
|
14
|
-
dine_in: "dine_in",
|
|
15
|
-
delivery: "delivery",
|
|
16
|
-
takeout: "balcao"
|
|
17
|
-
};
|
|
18
|
-
function searchTerm(raw) {
|
|
19
|
-
return (raw ?? "").replace(/[,()%*\\"]/g, " ").trim();
|
|
20
|
-
}
|
|
21
|
-
function createCoreOrdersProvider(options) {
|
|
22
|
-
const db = () => {
|
|
23
|
-
const client = getSupabaseClientOptional();
|
|
24
|
-
if (!client) throw new Error("Supabase client is not configured");
|
|
25
|
-
return client;
|
|
26
|
-
};
|
|
27
|
-
const writes = options?.writes;
|
|
28
|
-
function requireWrites() {
|
|
29
|
-
if (!writes) throw new Error(READ_ONLY);
|
|
30
|
-
return writes;
|
|
31
|
-
}
|
|
32
|
-
async function load(query, only) {
|
|
33
|
-
const client = db();
|
|
34
|
-
let q = client.from("v_orders").select("id, tenant_id, unit_id, kind, channel, status, reference_number, party_id, assignee_id, subtotal, discount, tax, total, currency, notes, created_at, updated_at, completed_at, fulfillment_status, metadata", { count: "exact" }).order("created_at", { ascending: false });
|
|
35
|
-
if (only?.id) q = q.eq("id", only.id);
|
|
36
|
-
if (options?.kinds?.length) q = q.in("kind", options.kinds);
|
|
37
|
-
if (options?.channel) q = q.eq("channel", options.channel);
|
|
38
|
-
if (query?.kind) {
|
|
39
|
-
q = Array.isArray(query.kind) ? q.in("kind", query.kind) : q.eq("kind", query.kind);
|
|
40
|
-
}
|
|
41
|
-
if (query?.status) {
|
|
42
|
-
q = Array.isArray(query.status) ? q.in("status", query.status) : q.eq("status", query.status);
|
|
43
|
-
}
|
|
44
|
-
if (query?.channel) q = q.eq("channel", query.channel);
|
|
45
|
-
if (query?.excludeKinds?.length) q = q.not("kind", "in", `(${query.excludeKinds.join(",")})`);
|
|
46
|
-
if (query?.fulfillmentStatus) q = q.eq("fulfillment_status", query.fulfillmentStatus);
|
|
47
|
-
if (query?.tableId) q = q.eq("metadata->>tableId", query.tableId);
|
|
48
|
-
if (query?.assigneeId) q = q.eq("assignee_id", query.assigneeId);
|
|
49
|
-
if (query?.dateRange) {
|
|
50
|
-
q = q.gte("created_at", query.dateRange.from).lte("created_at", query.dateRange.to);
|
|
51
|
-
}
|
|
52
|
-
const term = searchTerm(query?.search);
|
|
53
|
-
if (term) {
|
|
54
|
-
const { data: named } = await client.from("people").select("id").ilike("name", `%${term}%`).limit(50);
|
|
55
|
-
const ids2 = (named ?? []).map((p) => p.id);
|
|
56
|
-
q = q.or([
|
|
57
|
-
`reference_number.ilike.%${term}%`,
|
|
58
|
-
...ids2.length ? [`party_id.in.(${ids2.join(",")})`] : []
|
|
59
|
-
].join(","));
|
|
60
|
-
}
|
|
61
|
-
const pageSize = query?.pageSize ?? 100;
|
|
62
|
-
const from = ((query?.page ?? 1) - 1) * pageSize;
|
|
63
|
-
q = q.range(from, from + pageSize - 1);
|
|
64
|
-
const { data, error, count } = await q;
|
|
65
|
-
if (error) throw new Error(error.message);
|
|
66
|
-
const rows = data ?? [];
|
|
67
|
-
const ids = rows.map((r) => r.id);
|
|
68
|
-
const withItems = query?.withItems !== false;
|
|
69
|
-
const [{ data: people }, { data: payments }, { data: items }, { data: shipments }] = await Promise.all([
|
|
70
|
-
ids.length ? client.from("people").select("id, name").in("id", [...new Set(rows.flatMap((r) => [r.party_id, r.assignee_id]).filter(Boolean))]) : Promise.resolve({ data: [] }),
|
|
71
|
-
ids.length ? client.from("v_order_payment_status").select("order_id, status, total_amount, paid_amount").in("order_id", ids) : Promise.resolve({ data: [] }),
|
|
72
|
-
ids.length && withItems ? client.from("items").select("id, order_id, product_id, name, description, quantity, unit_price, discount, total, sort_order, metadata, created_at").in("order_id", ids).order("sort_order") : Promise.resolve({ data: [] }),
|
|
73
|
-
ids.length ? client.from("fulfillments").select("order_id, status").in("order_id", ids).in("kind", ["shipment", "pickup"]) : Promise.resolve({ data: [] })
|
|
74
|
-
]);
|
|
75
|
-
const shipmentsByOrder = /* @__PURE__ */ new Map();
|
|
76
|
-
for (const s of shipments ?? []) {
|
|
77
|
-
shipmentsByOrder.set(s.order_id, [...shipmentsByOrder.get(s.order_id) ?? [], s.status]);
|
|
78
|
-
}
|
|
79
|
-
const nameById = new Map((people ?? []).map((p) => [p.id, p.name]));
|
|
80
|
-
const payById = new Map((payments ?? []).map((p) => [p.order_id, p]));
|
|
81
|
-
const itemsByOrder = /* @__PURE__ */ new Map();
|
|
82
|
-
for (const item of items ?? []) {
|
|
83
|
-
const list = itemsByOrder.get(item.order_id) ?? [];
|
|
84
|
-
list.push(toItem(item));
|
|
85
|
-
itemsByOrder.set(item.order_id, list);
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
data: rows.map((r) => {
|
|
89
|
-
const pay = payById.get(r.id);
|
|
90
|
-
const meta = r.metadata ?? {};
|
|
91
|
-
return {
|
|
92
|
-
id: r.id,
|
|
93
|
-
referenceNumber: r.reference_number ?? String(r.id).slice(0, 8),
|
|
94
|
-
kind: r.kind,
|
|
95
|
-
status: r.status,
|
|
96
|
-
partyId: r.party_id ?? void 0,
|
|
97
|
-
partyName: r.party_id ? nameById.get(r.party_id) : void 0,
|
|
98
|
-
assigneeId: r.assignee_id ?? void 0,
|
|
99
|
-
assigneeName: r.assignee_id ? nameById.get(r.assignee_id) : void 0,
|
|
100
|
-
subtotal: Number(r.subtotal) || 0,
|
|
101
|
-
discount: Number(r.discount) || 0,
|
|
102
|
-
tax: Number(r.tax) || 0,
|
|
103
|
-
total: Number(r.total) || 0,
|
|
104
|
-
currency: r.currency ?? "BRL",
|
|
105
|
-
notes: r.notes ?? void 0,
|
|
106
|
-
tags: [],
|
|
107
|
-
// `source` is the archetype's channel where it has one; the salon's
|
|
108
|
-
// counter sale has none, and 'balcao' is what that means.
|
|
109
|
-
source: r.channel ?? "balcao",
|
|
110
|
-
// NOT location_id: that column is a FK to `app.units`, i.e. the
|
|
111
|
-
// BRANCH this order belongs to. A mesa has no table of its own yet,
|
|
112
|
-
// so its id rides in metadata until the floor plan gets one.
|
|
113
|
-
tableId: typeof meta.tableId === "string" ? meta.tableId : void 0,
|
|
114
|
-
estimatedMinutes: typeof meta.estimatedMinutes === "number" ? meta.estimatedMinutes : void 0,
|
|
115
|
-
items: itemsByOrder.get(r.id) ?? [],
|
|
116
|
-
metadata: {
|
|
117
|
-
...meta,
|
|
118
|
-
channel: r.channel ?? null,
|
|
119
|
-
fulfillmentStatus: r.fulfillment_status ?? null,
|
|
120
|
-
paymentStatus: pay?.status ?? "none",
|
|
121
|
-
invoicedAmount: Number(pay?.total_amount) || 0,
|
|
122
|
-
paidAmount: Number(pay?.paid_amount) || 0,
|
|
123
|
-
shipmentStatuses: shipmentsByOrder.get(r.id) ?? []
|
|
124
|
-
},
|
|
125
|
-
tenantId: r.tenant_id,
|
|
126
|
-
unitId: r.unit_id ?? void 0,
|
|
127
|
-
createdAt: r.created_at,
|
|
128
|
-
updatedAt: r.updated_at,
|
|
129
|
-
completedAt: r.completed_at ?? void 0
|
|
130
|
-
};
|
|
131
|
-
}),
|
|
132
|
-
total: count ?? rows.length
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
function toItem(row) {
|
|
136
|
-
const meta = row.metadata ?? {};
|
|
137
|
-
return {
|
|
138
|
-
id: row.id,
|
|
139
|
-
orderId: row.order_id,
|
|
140
|
-
productId: row.product_id ?? void 0,
|
|
141
|
-
name: row.name ?? "",
|
|
142
|
-
description: row.description ?? void 0,
|
|
143
|
-
quantity: Number(row.quantity) || 0,
|
|
144
|
-
unitPrice: Number(row.unit_price) || 0,
|
|
145
|
-
discount: Number(row.discount) || 0,
|
|
146
|
-
total: Number(row.total) || 0,
|
|
147
|
-
sortOrder: row.sort_order ?? 0,
|
|
148
|
-
modifiers: typeof meta.modifiers === "string" ? meta.modifiers : void 0,
|
|
149
|
-
kitchenNotes: typeof meta.kitchenNotes === "string" ? meta.kitchenNotes : void 0,
|
|
150
|
-
metadata: meta,
|
|
151
|
-
createdAt: row.created_at
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
function lineTotal(item) {
|
|
155
|
-
return item.quantity * item.unitPrice - (item.discount ?? 0);
|
|
156
|
-
}
|
|
157
|
-
async function loadOne(id) {
|
|
158
|
-
const page = await load(void 0, { id });
|
|
159
|
-
return page.data[0] ?? null;
|
|
160
|
-
}
|
|
161
|
-
async function recalc(orderId) {
|
|
162
|
-
const client = db();
|
|
163
|
-
const { data, error } = await client.from("items").select("total").eq("order_id", orderId);
|
|
164
|
-
if (error) throw new Error(error.message);
|
|
165
|
-
const subtotal = (data ?? []).reduce((sum, r) => sum + (Number(r.total) || 0), 0);
|
|
166
|
-
const { error: upErr } = await client.from("orders").update({ subtotal, total: subtotal }).eq("id", orderId);
|
|
167
|
-
if (upErr) throw new Error(upErr.message);
|
|
168
|
-
}
|
|
169
|
-
async function orderIdOfItem(itemId) {
|
|
170
|
-
const client = db();
|
|
171
|
-
const { data, error } = await client.from("items").select("order_id").eq("id", itemId).single();
|
|
172
|
-
if (error) throw new Error(error.message);
|
|
173
|
-
return data.order_id;
|
|
174
|
-
}
|
|
175
|
-
return {
|
|
176
|
-
getOrders: (query) => load(query),
|
|
177
|
-
getOrderById: loadOne,
|
|
178
|
-
async createOrder(input) {
|
|
179
|
-
const w = requireWrites();
|
|
180
|
-
const client = db();
|
|
181
|
-
const tenantId = w.tenantId();
|
|
182
|
-
if (!tenantId) throw new Error("No active organization: an order cannot be opened without one");
|
|
183
|
-
const channel = (w.channelFor ?? ((k) => DEFAULT_CHANNELS[k]))(input.kind);
|
|
184
|
-
const subtotal = input.items.reduce(
|
|
185
|
-
(sum, i) => sum + lineTotal({ quantity: i.quantity, unitPrice: i.unitPrice, discount: i.discount }),
|
|
186
|
-
0
|
|
187
|
-
);
|
|
188
|
-
const { data: order, error } = await client.from("orders").insert({
|
|
189
|
-
tenant_id: tenantId,
|
|
190
|
-
unit_id: w.unitId?.() ?? null,
|
|
191
|
-
kind: input.kind,
|
|
192
|
-
status: "new",
|
|
193
|
-
...channel ? { channel } : {},
|
|
194
|
-
// party_id is left out on purpose: `trg_orders_require_party` fills it
|
|
195
|
-
// with `public.walkin_party(tenant_id)`, which is exactly what a table
|
|
196
|
-
// with no named customer is.
|
|
197
|
-
...input.partyId ? { party_id: input.partyId } : {},
|
|
198
|
-
...input.assigneeId ? { assignee_id: input.assigneeId } : {},
|
|
199
|
-
...input.notes ? { notes: input.notes } : {},
|
|
200
|
-
subtotal,
|
|
201
|
-
total: subtotal,
|
|
202
|
-
currency: "BRL",
|
|
203
|
-
metadata: {
|
|
204
|
-
...input.tableId ? { tableId: input.tableId } : {},
|
|
205
|
-
...input.estimatedMinutes ? { estimatedMinutes: input.estimatedMinutes } : {}
|
|
206
|
-
}
|
|
207
|
-
}).select("id").single();
|
|
208
|
-
if (error) throw new Error(error.message);
|
|
209
|
-
if (input.items.length) {
|
|
210
|
-
const { error: itemsErr } = await client.from("items").insert(
|
|
211
|
-
input.items.map((item, index) => ({
|
|
212
|
-
order_id: order.id,
|
|
213
|
-
// tenant_id and parent_kind are inherited from the parent by
|
|
214
|
-
// `trg_items_inherit`; setting them here would only duplicate it.
|
|
215
|
-
product_id: item.productId ?? null,
|
|
216
|
-
name: item.name,
|
|
217
|
-
quantity: item.quantity,
|
|
218
|
-
unit_price: item.unitPrice,
|
|
219
|
-
discount: item.discount ?? 0,
|
|
220
|
-
total: lineTotal(item),
|
|
221
|
-
sort_order: index,
|
|
222
|
-
metadata: {
|
|
223
|
-
...item.modifiers ? { modifiers: item.modifiers } : {},
|
|
224
|
-
...item.kitchenNotes ? { kitchenNotes: item.kitchenNotes } : {}
|
|
225
|
-
}
|
|
226
|
-
}))
|
|
227
|
-
);
|
|
228
|
-
if (itemsErr) throw new Error(itemsErr.message);
|
|
229
|
-
}
|
|
230
|
-
const created = await loadOne(order.id);
|
|
231
|
-
if (!created) throw new Error("The order was created but is not readable \u2014 check the orders.read permission");
|
|
232
|
-
return created;
|
|
233
|
-
},
|
|
234
|
-
async updateOrderStatus(input) {
|
|
235
|
-
requireWrites();
|
|
236
|
-
const client = db();
|
|
237
|
-
const { error } = await client.from("orders").update({ status: input.status }).eq("id", input.orderId);
|
|
238
|
-
if (error) throw new Error(error.message);
|
|
239
|
-
const order = await loadOne(input.orderId);
|
|
240
|
-
if (!order) throw new Error("Order not found after the status change");
|
|
241
|
-
return order;
|
|
242
|
-
},
|
|
243
|
-
async updateOrder(id, data) {
|
|
244
|
-
requireWrites();
|
|
245
|
-
const client = db();
|
|
246
|
-
const patch = {};
|
|
247
|
-
if (data.status !== void 0) patch.status = data.status;
|
|
248
|
-
if (data.notes !== void 0) patch.notes = data.notes;
|
|
249
|
-
if (data.partyId !== void 0) patch.party_id = data.partyId;
|
|
250
|
-
if (data.assigneeId !== void 0) patch.assignee_id = data.assigneeId;
|
|
251
|
-
if (data.discount !== void 0) patch.discount = data.discount;
|
|
252
|
-
if (data.tax !== void 0) patch.tax = data.tax;
|
|
253
|
-
if (Object.keys(patch).length) {
|
|
254
|
-
const { error } = await client.from("orders").update(patch).eq("id", id);
|
|
255
|
-
if (error) throw new Error(error.message);
|
|
256
|
-
}
|
|
257
|
-
const order = await loadOne(id);
|
|
258
|
-
if (!order) throw new Error("Order not found after the update");
|
|
259
|
-
return order;
|
|
260
|
-
},
|
|
261
|
-
async cancelOrder(id, reason) {
|
|
262
|
-
requireWrites();
|
|
263
|
-
const client = db();
|
|
264
|
-
const { error } = await client.from("orders").update({ status: "cancelled", ...reason ? { notes: reason } : {} }).eq("id", id);
|
|
265
|
-
if (error) throw new Error(error.message);
|
|
266
|
-
},
|
|
267
|
-
async addOrderItem(orderId, item) {
|
|
268
|
-
requireWrites();
|
|
269
|
-
const client = db();
|
|
270
|
-
const { count } = await client.from("items").select("id", { count: "exact", head: true }).eq("order_id", orderId);
|
|
271
|
-
const { data, error } = await client.from("items").insert({
|
|
272
|
-
order_id: orderId,
|
|
273
|
-
product_id: item.productId ?? null,
|
|
274
|
-
name: item.name,
|
|
275
|
-
quantity: item.quantity,
|
|
276
|
-
unit_price: item.unitPrice,
|
|
277
|
-
discount: item.discount ?? 0,
|
|
278
|
-
total: lineTotal(item),
|
|
279
|
-
sort_order: count ?? 0,
|
|
280
|
-
metadata: {
|
|
281
|
-
...item.modifiers ? { modifiers: item.modifiers } : {},
|
|
282
|
-
...item.kitchenNotes ? { kitchenNotes: item.kitchenNotes } : {}
|
|
283
|
-
}
|
|
284
|
-
}).select("id, order_id, product_id, name, description, quantity, unit_price, discount, total, sort_order, metadata, created_at").single();
|
|
285
|
-
if (error) throw new Error(error.message);
|
|
286
|
-
await recalc(orderId);
|
|
287
|
-
return toItem(data);
|
|
288
|
-
},
|
|
289
|
-
async removeOrderItem(itemId) {
|
|
290
|
-
requireWrites();
|
|
291
|
-
const client = db();
|
|
292
|
-
const orderId = await orderIdOfItem(itemId);
|
|
293
|
-
const { error } = await client.from("items").delete().eq("id", itemId);
|
|
294
|
-
if (error) throw new Error(error.message);
|
|
295
|
-
await recalc(orderId);
|
|
296
|
-
},
|
|
297
|
-
async updateOrderItem(itemId, data) {
|
|
298
|
-
requireWrites();
|
|
299
|
-
const client = db();
|
|
300
|
-
const orderId = await orderIdOfItem(itemId);
|
|
301
|
-
const patch = {};
|
|
302
|
-
if (data.name !== void 0) patch.name = data.name;
|
|
303
|
-
if (data.quantity !== void 0) patch.quantity = data.quantity;
|
|
304
|
-
if (data.unitPrice !== void 0) patch.unit_price = data.unitPrice;
|
|
305
|
-
if (data.discount !== void 0) patch.discount = data.discount;
|
|
306
|
-
if (data.quantity !== void 0 || data.unitPrice !== void 0 || data.discount !== void 0) {
|
|
307
|
-
const { data: current, error: readErr } = await client.from("items").select("quantity, unit_price, discount").eq("id", itemId).single();
|
|
308
|
-
if (readErr) throw new Error(readErr.message);
|
|
309
|
-
patch.total = lineTotal({
|
|
310
|
-
quantity: Number(data.quantity ?? current.quantity) || 0,
|
|
311
|
-
unitPrice: Number(data.unitPrice ?? current.unit_price) || 0,
|
|
312
|
-
discount: Number(data.discount ?? current.discount) || 0
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
const { data: row, error } = await client.from("items").update(patch).eq("id", itemId).select("id, order_id, product_id, name, description, quantity, unit_price, discount, total, sort_order, metadata, created_at").single();
|
|
316
|
-
if (error) throw new Error(error.message);
|
|
317
|
-
await recalc(orderId);
|
|
318
|
-
return toItem(row);
|
|
319
|
-
},
|
|
320
|
-
async getSummary(dateRange) {
|
|
321
|
-
const page = await load({ pageSize: 500, ...dateRange ? { dateRange } : {} });
|
|
322
|
-
const live = page.data.filter((o) => o.status !== "cancelled");
|
|
323
|
-
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
324
|
-
const todays = live.filter((o) => o.createdAt.slice(0, 10) === today);
|
|
325
|
-
const revenue = todays.reduce((sum, o) => sum + o.total, 0);
|
|
326
|
-
const byKind = {};
|
|
327
|
-
const byStatus = {};
|
|
328
|
-
for (const o of live) {
|
|
329
|
-
byKind[o.kind] = (byKind[o.kind] ?? 0) + 1;
|
|
330
|
-
byStatus[o.status] = (byStatus[o.status] ?? 0) + 1;
|
|
331
|
-
}
|
|
332
|
-
return {
|
|
333
|
-
todayOrderCount: todays.length,
|
|
334
|
-
todayRevenue: revenue,
|
|
335
|
-
averageTicket: todays.length ? revenue / todays.length : 0,
|
|
336
|
-
activeOrderCount: live.filter((o) => o.status !== "completed").length,
|
|
337
|
-
ordersByKind: byKind,
|
|
338
|
-
ordersByStatus: byStatus,
|
|
339
|
-
topItems: []
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// src/types.ts
|
|
346
|
-
var STATUS_FLOW = {
|
|
347
|
-
dine_in: ["draft", "new", "confirmed", "preparing", "ready", "served", "completed"],
|
|
348
|
-
takeout: ["draft", "new", "confirmed", "preparing", "ready", "picked_up", "completed"],
|
|
349
|
-
delivery: ["draft", "new", "confirmed", "preparing", "ready", "dispatched", "delivered", "completed"]
|
|
350
|
-
};
|
|
351
|
-
var OUT_STATUSES = ["served", "picked_up", "dispatched", "delivered"];
|
|
352
|
-
function getNextStatus(kind, current) {
|
|
353
|
-
const flow = STATUS_FLOW[kind];
|
|
354
|
-
let idx = flow.indexOf(current);
|
|
355
|
-
if (idx === -1 && OUT_STATUSES.includes(current)) {
|
|
356
|
-
idx = flow.findIndex((status) => OUT_STATUSES.includes(status));
|
|
357
|
-
}
|
|
358
|
-
return idx >= 0 && idx < flow.length - 1 ? flow[idx + 1] : null;
|
|
359
|
-
}
|
|
360
|
-
var ADVANCE_VERB = {
|
|
361
|
-
draft: "Salvar rascunho",
|
|
362
|
-
new: "Enviar",
|
|
363
|
-
confirmed: "Confirmar",
|
|
364
|
-
preparing: "Preparar",
|
|
365
|
-
ready: "Marcar pronto",
|
|
366
|
-
served: "Servir",
|
|
367
|
-
picked_up: "Entregar",
|
|
368
|
-
dispatched: "Despachar",
|
|
369
|
-
delivered: "Confirmar entrega",
|
|
370
|
-
completed: "Concluir",
|
|
371
|
-
cancelled: "Cancelar"
|
|
372
|
-
};
|
|
373
|
-
function getPreviousStatus(kind, current) {
|
|
374
|
-
const flow = STATUS_FLOW[kind];
|
|
375
|
-
const idx = flow.indexOf(current);
|
|
376
|
-
return idx > 0 ? flow[idx - 1] : null;
|
|
377
|
-
}
|
|
378
|
-
function mapToKanbanColumn(status) {
|
|
379
|
-
if (["served", "picked_up", "dispatched", "delivered"].includes(status)) return "out";
|
|
380
|
-
if (["new", "confirmed", "preparing", "ready", "completed", "cancelled"].includes(status)) {
|
|
381
|
-
return status;
|
|
382
|
-
}
|
|
383
|
-
return "new";
|
|
384
|
-
}
|
|
385
|
-
var KANBAN_COLUMNS = ["new", "confirmed", "preparing", "ready", "out", "completed"];
|
|
386
|
-
var DEFAULT_STATUS_CONFIGS = [
|
|
387
|
-
{ value: "new", label: "New", color: "#6366f1", icon: "PlusCircle" },
|
|
388
|
-
{ value: "confirmed", label: "Confirmed", color: "#3b82f6", icon: "CheckCircle" },
|
|
389
|
-
{ value: "preparing", label: "Preparing", color: "#f59e0b", icon: "ChefHat" },
|
|
390
|
-
{ value: "ready", label: "Ready", color: "#10b981", icon: "Bell" },
|
|
391
|
-
{ value: "served", label: "Served", color: "#06b6d4", icon: "Utensils" },
|
|
392
|
-
{ value: "picked_up", label: "Picked Up", color: "#06b6d4", icon: "ShoppingBag" },
|
|
393
|
-
{ value: "dispatched", label: "Dispatched", color: "#8b5cf6", icon: "Truck" },
|
|
394
|
-
{ value: "delivered", label: "Delivered", color: "#06b6d4", icon: "PackageCheck" },
|
|
395
|
-
{ value: "completed", label: "Completed", color: "#22c55e", icon: "CircleCheck" },
|
|
396
|
-
{ value: "cancelled", label: "Cancelled", color: "#ef4444", icon: "XCircle" }
|
|
397
|
-
];
|
|
398
|
-
|
|
399
|
-
// src/store.ts
|
|
400
|
-
var ACTIVE_STATUSES = [
|
|
401
|
-
"new",
|
|
402
|
-
"confirmed",
|
|
403
|
-
"preparing",
|
|
404
|
-
"ready",
|
|
405
|
-
// The `Saiu` column: one word per kind for the same moment.
|
|
406
|
-
"served",
|
|
407
|
-
"picked_up",
|
|
408
|
-
"dispatched",
|
|
409
|
-
"delivered"
|
|
410
|
-
];
|
|
411
|
-
function emitOrderLifecycleEvent(key, order) {
|
|
412
|
-
emitDomainEvent(key, {
|
|
413
|
-
order_id: order.id,
|
|
414
|
-
reference_number: order.referenceNumber,
|
|
415
|
-
total: order.total,
|
|
416
|
-
item_count: order.items.length,
|
|
417
|
-
source: order.source
|
|
418
|
-
}, {
|
|
419
|
-
tenantId: order.tenantId,
|
|
420
|
-
subject: { type: "order", id: order.id }
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
async function runLifecycleHook(label, order, hook) {
|
|
424
|
-
if (!hook) return;
|
|
425
|
-
try {
|
|
426
|
-
await hook(order);
|
|
427
|
-
} catch (error) {
|
|
428
|
-
const message2 = errorMessage(error);
|
|
429
|
-
throw new Error(`Order was ${label}, but downstream synchronization is pending: ${message2}`);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function createOrdersStore(provider, hooks = {}) {
|
|
433
|
-
return createStore((set, get) => ({
|
|
434
|
-
orders: [],
|
|
435
|
-
ordersTotal: 0,
|
|
436
|
-
ordersLoading: false,
|
|
437
|
-
orderQuery: {},
|
|
438
|
-
activeOrders: [],
|
|
439
|
-
activeOrdersLoading: false,
|
|
440
|
-
summary: null,
|
|
441
|
-
summaryLoading: false,
|
|
442
|
-
selectedOrderId: null,
|
|
443
|
-
async fetchOrders(query) {
|
|
444
|
-
return dedup("orders:list:" + JSON.stringify(query), async () => {
|
|
445
|
-
set({ ordersLoading: true, orderQuery: query });
|
|
446
|
-
const result = await provider.getOrders(query);
|
|
447
|
-
set({ orders: result.data, ordersTotal: result.total, ordersLoading: false });
|
|
448
|
-
});
|
|
449
|
-
},
|
|
450
|
-
async fetchActiveOrders() {
|
|
451
|
-
return dedup("orders:active", async () => {
|
|
452
|
-
set({ activeOrdersLoading: true });
|
|
453
|
-
const result = await provider.getOrders({ status: [...ACTIVE_STATUSES] });
|
|
454
|
-
set({ activeOrders: result.data, activeOrdersLoading: false });
|
|
455
|
-
});
|
|
456
|
-
},
|
|
457
|
-
async fetchSummary(dateRange) {
|
|
458
|
-
return dedup("orders:summary", async () => {
|
|
459
|
-
set({ summaryLoading: true });
|
|
460
|
-
const summary = await provider.getSummary(dateRange);
|
|
461
|
-
set({ summary, summaryLoading: false });
|
|
462
|
-
});
|
|
463
|
-
},
|
|
464
|
-
selectOrder(id) {
|
|
465
|
-
set({ selectedOrderId: id });
|
|
466
|
-
},
|
|
467
|
-
async createOrder(input) {
|
|
468
|
-
try {
|
|
469
|
-
const order = await provider.createOrder(input);
|
|
470
|
-
const query = get().orderQuery;
|
|
471
|
-
const [result, summary] = await Promise.all([
|
|
472
|
-
provider.getOrders(query),
|
|
473
|
-
provider.getSummary()
|
|
474
|
-
]);
|
|
475
|
-
set({ orders: result.data, ordersTotal: result.total, summary });
|
|
476
|
-
toast.success("Pedido criado");
|
|
477
|
-
return order;
|
|
478
|
-
} catch (err) {
|
|
479
|
-
toast.error("N\xE3o foi poss\xEDvel criar o pedido", { description: err?.message });
|
|
480
|
-
throw err;
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
async advanceOrderStatus(orderId) {
|
|
484
|
-
try {
|
|
485
|
-
const { orders, activeOrders } = get();
|
|
486
|
-
const order = orders.find((o) => o.id === orderId) ?? activeOrders.find((o) => o.id === orderId);
|
|
487
|
-
if (!order) throw new Error("Order not found");
|
|
488
|
-
const nextStatus = getNextStatus(order.kind, order.status);
|
|
489
|
-
if (!nextStatus) throw new Error("No next status available");
|
|
490
|
-
const updated = await provider.updateOrderStatus({ orderId, status: nextStatus });
|
|
491
|
-
if (updated.status === "completed") {
|
|
492
|
-
emitOrderLifecycleEvent("orders.order_completed", updated);
|
|
493
|
-
await runLifecycleHook("completed", updated, hooks.onOrderCompleted);
|
|
494
|
-
}
|
|
495
|
-
const activeResult = await provider.getOrders({ status: [...ACTIVE_STATUSES] });
|
|
496
|
-
set({ activeOrders: activeResult.data });
|
|
497
|
-
toast.success("Pedido avan\xE7ado");
|
|
498
|
-
} catch (err) {
|
|
499
|
-
toast.error("N\xE3o foi poss\xEDvel avan\xE7ar o pedido", { description: err?.message });
|
|
500
|
-
throw err;
|
|
501
|
-
}
|
|
502
|
-
},
|
|
503
|
-
async updateOrderStatus(input) {
|
|
504
|
-
try {
|
|
505
|
-
const before = await provider.getOrderById(input.orderId);
|
|
506
|
-
const updated = await provider.updateOrderStatus(input);
|
|
507
|
-
if (updated.status === "completed") {
|
|
508
|
-
if (before?.status !== "completed") emitOrderLifecycleEvent("orders.order_completed", updated);
|
|
509
|
-
await runLifecycleHook("completed", updated, hooks.onOrderCompleted);
|
|
510
|
-
}
|
|
511
|
-
const query = get().orderQuery;
|
|
512
|
-
const [result, summary] = await Promise.all([
|
|
513
|
-
provider.getOrders(query),
|
|
514
|
-
provider.getSummary()
|
|
515
|
-
]);
|
|
516
|
-
set({ orders: result.data, ordersTotal: result.total, summary });
|
|
517
|
-
toast.success("Status atualizado");
|
|
518
|
-
} catch (err) {
|
|
519
|
-
toast.error("N\xE3o foi poss\xEDvel atualizar o status", { description: err?.message });
|
|
520
|
-
throw err;
|
|
521
|
-
}
|
|
522
|
-
},
|
|
523
|
-
async cancelOrder(id, reason) {
|
|
524
|
-
try {
|
|
525
|
-
const before = await provider.getOrderById(id);
|
|
526
|
-
await provider.cancelOrder(id, reason);
|
|
527
|
-
const cancelled = await provider.getOrderById(id);
|
|
528
|
-
const order = cancelled ?? (before ? { ...before, status: "cancelled" } : null);
|
|
529
|
-
if (order) {
|
|
530
|
-
if (before?.status !== "cancelled") emitOrderLifecycleEvent("orders.order_cancelled", order);
|
|
531
|
-
await runLifecycleHook("cancelled", order, hooks.onOrderCancelled);
|
|
532
|
-
}
|
|
533
|
-
const query = get().orderQuery;
|
|
534
|
-
const [result, summary] = await Promise.all([
|
|
535
|
-
provider.getOrders(query),
|
|
536
|
-
provider.getSummary()
|
|
537
|
-
]);
|
|
538
|
-
set({ orders: result.data, ordersTotal: result.total, summary });
|
|
539
|
-
toast.success("Pedido cancelado");
|
|
540
|
-
} catch (err) {
|
|
541
|
-
toast.error("N\xE3o foi poss\xEDvel cancelar o pedido", { description: err?.message });
|
|
542
|
-
throw err;
|
|
543
|
-
}
|
|
544
|
-
},
|
|
545
|
-
async addOrderItem(orderId, item) {
|
|
546
|
-
try {
|
|
547
|
-
await provider.addOrderItem(orderId, item);
|
|
548
|
-
const query = get().orderQuery;
|
|
549
|
-
const result = await provider.getOrders(query);
|
|
550
|
-
set({ orders: result.data, ordersTotal: result.total });
|
|
551
|
-
toast.success("Item adicionado");
|
|
552
|
-
} catch (err) {
|
|
553
|
-
toast.error("N\xE3o foi poss\xEDvel adicionar o item", { description: err?.message });
|
|
554
|
-
throw err;
|
|
555
|
-
}
|
|
556
|
-
},
|
|
557
|
-
async removeOrderItem(itemId) {
|
|
558
|
-
try {
|
|
559
|
-
await provider.removeOrderItem(itemId);
|
|
560
|
-
const query = get().orderQuery;
|
|
561
|
-
const result = await provider.getOrders(query);
|
|
562
|
-
set({ orders: result.data, ordersTotal: result.total });
|
|
563
|
-
toast.success("Item removido");
|
|
564
|
-
} catch (err) {
|
|
565
|
-
toast.error("N\xE3o foi poss\xEDvel remover o item", { description: err?.message });
|
|
566
|
-
throw err;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}));
|
|
570
|
-
}
|
|
11
|
+
export { ADVANCE_VERB, DEFAULT_STATUS_CONFIGS, KANBAN_COLUMNS, STATUS_FLOW, getNextStatus, getPreviousStatus, mapToKanbanColumn } from '@fayz-ai/orders/domain/order';
|
|
12
|
+
export { createFayzOrdersProvider } from '@fayz-ai/orders/data/platform';
|
|
13
|
+
export { createMockOrdersProvider } from '@fayz-ai/orders/data/mock';
|
|
571
14
|
|
|
572
15
|
// src/data/registries.ts
|
|
573
16
|
var orderSourceEntity = {
|
|
@@ -1587,7 +1030,7 @@ function amountText(value) {
|
|
|
1587
1030
|
if (value === null || value === void 0) return "";
|
|
1588
1031
|
return String(value).replace(".", ",");
|
|
1589
1032
|
}
|
|
1590
|
-
function AmountRow({ label, description, hint, value, onCommit }) {
|
|
1033
|
+
function AmountRow({ label, description, hint, value, onCommit, pending }) {
|
|
1591
1034
|
const [text, setText] = React.useState(() => amountText(value));
|
|
1592
1035
|
const [invalid, setInvalid] = React.useState(false);
|
|
1593
1036
|
React.useEffect(() => {
|
|
@@ -1596,6 +1039,7 @@ function AmountRow({ label, description, hint, value, onCommit }) {
|
|
|
1596
1039
|
return /* @__PURE__ */ jsx(
|
|
1597
1040
|
TextRow,
|
|
1598
1041
|
{
|
|
1042
|
+
pending,
|
|
1599
1043
|
label,
|
|
1600
1044
|
description,
|
|
1601
1045
|
value: text,
|
|
@@ -1667,6 +1111,7 @@ function DeliverySettings() {
|
|
|
1667
1111
|
/* @__PURE__ */ jsx(
|
|
1668
1112
|
ToggleRow,
|
|
1669
1113
|
{
|
|
1114
|
+
pending: true,
|
|
1670
1115
|
label: "A casa entrega",
|
|
1671
1116
|
description: "Desligado, nenhum canal novo nasce como entrega.",
|
|
1672
1117
|
checked: value.enabled !== false,
|
|
@@ -1676,6 +1121,7 @@ function DeliverySettings() {
|
|
|
1676
1121
|
/* @__PURE__ */ jsx(
|
|
1677
1122
|
AmountRow,
|
|
1678
1123
|
{
|
|
1124
|
+
pending: true,
|
|
1679
1125
|
label: "Taxa de entrega",
|
|
1680
1126
|
description: "Cobrada por pedido, na moeda da casa.",
|
|
1681
1127
|
hint: "Zero = entrega sem taxa.",
|
|
@@ -1686,6 +1132,7 @@ function DeliverySettings() {
|
|
|
1686
1132
|
/* @__PURE__ */ jsx(
|
|
1687
1133
|
AmountRow,
|
|
1688
1134
|
{
|
|
1135
|
+
pending: true,
|
|
1689
1136
|
label: "Frete gr\xE1tis acima de",
|
|
1690
1137
|
description: "Acima deste valor de pedido a taxa \xE9 zerada.",
|
|
1691
1138
|
hint: "Vazio = a taxa vale sempre.",
|
|
@@ -1696,6 +1143,7 @@ function DeliverySettings() {
|
|
|
1696
1143
|
/* @__PURE__ */ jsx(
|
|
1697
1144
|
AmountRow,
|
|
1698
1145
|
{
|
|
1146
|
+
pending: true,
|
|
1699
1147
|
label: "Pedido m\xEDnimo",
|
|
1700
1148
|
description: "Abaixo disso a casa n\xE3o entrega.",
|
|
1701
1149
|
hint: "Zero = sem m\xEDnimo.",
|
|
@@ -1715,6 +1163,7 @@ function DeliverySettings() {
|
|
|
1715
1163
|
/* @__PURE__ */ jsx(
|
|
1716
1164
|
AmountRow,
|
|
1717
1165
|
{
|
|
1166
|
+
pending: true,
|
|
1718
1167
|
label: "Tempo estimado (min)",
|
|
1719
1168
|
description: "Da confirma\xE7\xE3o at\xE9 a porta.",
|
|
1720
1169
|
value: value.etaMinutes,
|
|
@@ -1724,6 +1173,7 @@ function DeliverySettings() {
|
|
|
1724
1173
|
/* @__PURE__ */ jsx(
|
|
1725
1174
|
AmountRow,
|
|
1726
1175
|
{
|
|
1176
|
+
pending: true,
|
|
1727
1177
|
label: "Raio de entrega (km)",
|
|
1728
1178
|
description: "Dist\xE2ncia m\xE1xima a partir da casa.",
|
|
1729
1179
|
hint: "Zero = sem limite declarado.",
|
|
@@ -1780,845 +1230,37 @@ function DeliverySettings() {
|
|
|
1780
1230
|
)
|
|
1781
1231
|
] });
|
|
1782
1232
|
}
|
|
1783
|
-
var
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
return `ORD-${Date.now().toString().slice(-6)}`;
|
|
1812
|
-
}
|
|
1813
|
-
function objectValue(value) {
|
|
1814
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1815
|
-
}
|
|
1816
|
-
function canonicalStatus(status) {
|
|
1817
|
-
if (status === "new") return "draft";
|
|
1818
|
-
if (status === "completed" || status === "cancelled") return status;
|
|
1819
|
-
return "confirmed";
|
|
1820
|
-
}
|
|
1821
|
-
function restaurantStatus(rowStatus, metadata) {
|
|
1822
|
-
if (rowStatus === "completed" || rowStatus === "cancelled") return rowStatus;
|
|
1823
|
-
const stored = metadata.restaurantStatus;
|
|
1824
|
-
if (typeof stored === "string" && RESTAURANT_STATUSES.has(stored)) return stored;
|
|
1825
|
-
if (rowStatus === "draft") return "new";
|
|
1826
|
-
if (typeof rowStatus === "string" && RESTAURANT_STATUSES.has(rowStatus)) return rowStatus;
|
|
1827
|
-
return "confirmed";
|
|
1828
|
-
}
|
|
1829
|
-
function ordersMetadata(metadata) {
|
|
1830
|
-
return objectValue(metadata?.[ORDERS_METADATA_KEY]);
|
|
1831
|
-
}
|
|
1832
|
-
function mergeOrdersMetadata(metadata, patch) {
|
|
1833
|
-
const base = { ...metadata ?? {} };
|
|
1834
|
-
const current = ordersMetadata(base);
|
|
1835
|
-
const definedPatch = Object.fromEntries(
|
|
1836
|
-
Object.entries(patch).filter(([, value]) => value !== void 0)
|
|
1837
|
-
);
|
|
1838
|
-
const next = { ...current, ...definedPatch };
|
|
1839
|
-
return { ...base, [ORDERS_METADATA_KEY]: next };
|
|
1840
|
-
}
|
|
1841
|
-
function itemToRow(item, orderId, sortOrder, tenantId, unitId) {
|
|
1842
|
-
const discount = item.discount ?? 0;
|
|
1843
|
-
return {
|
|
1844
|
-
order_id: orderId,
|
|
1845
|
-
...tenantId ? { tenant_id: tenantId } : {},
|
|
1846
|
-
...unitId ? { unit_id: unitId } : {},
|
|
1847
|
-
product_id: item.productId ?? null,
|
|
1848
|
-
name: item.name,
|
|
1849
|
-
quantity: item.quantity,
|
|
1850
|
-
unit_price: item.unitPrice,
|
|
1851
|
-
discount,
|
|
1852
|
-
total: item.quantity * item.unitPrice - discount,
|
|
1853
|
-
sort_order: sortOrder,
|
|
1854
|
-
metadata: mergeOrdersMetadata(void 0, {
|
|
1855
|
-
modifiers: item.modifiers ?? null,
|
|
1856
|
-
kitchenNotes: item.kitchenNotes ?? null
|
|
1857
|
-
})
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
function rowToItem(row) {
|
|
1861
|
-
const quantity = numberValue(row.quantity);
|
|
1862
|
-
const unitPrice = numberValue(row.unit_price);
|
|
1863
|
-
const discount = numberValue(row.discount);
|
|
1864
|
-
const restaurant = ordersMetadata(row.metadata);
|
|
1865
|
-
return {
|
|
1866
|
-
id: row.id,
|
|
1867
|
-
orderId: row.order_id ?? "",
|
|
1868
|
-
productId: row.product_id ?? void 0,
|
|
1869
|
-
name: row.name ?? "Item",
|
|
1870
|
-
description: row.description ?? void 0,
|
|
1871
|
-
quantity,
|
|
1872
|
-
unitPrice,
|
|
1873
|
-
discount,
|
|
1874
|
-
total: numberValue(row.total) || quantity * unitPrice - discount,
|
|
1875
|
-
sortOrder: row.sort_order ?? 0,
|
|
1876
|
-
modifiers: row.modifiers ?? (typeof restaurant.modifiers === "string" ? restaurant.modifiers : void 0),
|
|
1877
|
-
kitchenNotes: row.kitchen_notes ?? (typeof restaurant.kitchenNotes === "string" ? restaurant.kitchenNotes : void 0),
|
|
1878
|
-
metadata: row.metadata ?? {},
|
|
1879
|
-
createdAt: row.created_at ?? nowIso()
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
1882
|
-
function rowToOrder(row, items = []) {
|
|
1883
|
-
const subtotal = numberValue(row.subtotal) || items.reduce((sum, item) => sum + item.total, 0);
|
|
1884
|
-
const discount = numberValue(row.discount);
|
|
1885
|
-
const tax = numberValue(row.tax);
|
|
1886
|
-
const restaurant = ordersMetadata(row.metadata);
|
|
1887
|
-
return {
|
|
1888
|
-
id: row.id,
|
|
1889
|
-
referenceNumber: row.reference_number ?? row.id,
|
|
1890
|
-
kind: row.kind ?? "dine_in",
|
|
1891
|
-
status: restaurantStatus(row.status, restaurant),
|
|
1892
|
-
partyId: row.party_id ?? void 0,
|
|
1893
|
-
partyName: row.party_name ?? (typeof restaurant.partyName === "string" ? restaurant.partyName : void 0),
|
|
1894
|
-
assigneeId: row.assignee_id ?? void 0,
|
|
1895
|
-
assigneeName: row.assignee_name ?? (typeof restaurant.assigneeName === "string" ? restaurant.assigneeName : void 0),
|
|
1896
|
-
locationId: row.location_id ?? void 0,
|
|
1897
|
-
subtotal,
|
|
1898
|
-
discount,
|
|
1899
|
-
tax,
|
|
1900
|
-
total: numberValue(row.total) || subtotal - discount + tax,
|
|
1901
|
-
currency: row.currency ?? "BRL",
|
|
1902
|
-
notes: row.notes ?? void 0,
|
|
1903
|
-
tags: row.tags ?? [],
|
|
1904
|
-
source: row.source ?? (typeof restaurant.source === "string" ? restaurant.source : "pos"),
|
|
1905
|
-
tableId: row.table_id ?? (typeof restaurant.tableId === "string" ? restaurant.tableId : void 0),
|
|
1906
|
-
tableName: row.table_name ?? (typeof restaurant.tableName === "string" ? restaurant.tableName : void 0),
|
|
1907
|
-
estimatedMinutes: row.estimated_minutes ?? (typeof restaurant.estimatedMinutes === "number" ? restaurant.estimatedMinutes : void 0),
|
|
1908
|
-
items,
|
|
1909
|
-
metadata: row.metadata ?? {},
|
|
1910
|
-
tenantId: row.tenant_id ?? "runtime-tenant",
|
|
1911
|
-
unitId: row.unit_id ?? void 0,
|
|
1912
|
-
createdAt: row.created_at ?? nowIso(),
|
|
1913
|
-
updatedAt: row.updated_at ?? row.created_at ?? nowIso(),
|
|
1914
|
-
completedAt: row.completed_at ?? void 0
|
|
1915
|
-
};
|
|
1916
|
-
}
|
|
1917
|
-
function orderPayload(input) {
|
|
1918
|
-
const subtotal = input.items.reduce((sum, item) => sum + item.quantity * item.unitPrice - (item.discount ?? 0), 0);
|
|
1919
|
-
return {
|
|
1920
|
-
reference_number: referenceNumber(),
|
|
1921
|
-
kind: input.kind,
|
|
1922
|
-
status: "draft",
|
|
1923
|
-
party_id: input.partyId ?? null,
|
|
1924
|
-
assignee_id: input.assigneeId ?? null,
|
|
1925
|
-
notes: input.notes ?? null,
|
|
1926
|
-
subtotal,
|
|
1927
|
-
discount: 0,
|
|
1928
|
-
tax: 0,
|
|
1929
|
-
total: subtotal,
|
|
1930
|
-
currency: "BRL",
|
|
1931
|
-
tags: [],
|
|
1932
|
-
metadata: mergeOrdersMetadata(void 0, {
|
|
1933
|
-
source: input.source ?? "pos",
|
|
1934
|
-
tableId: input.tableId ?? null,
|
|
1935
|
-
estimatedMinutes: input.estimatedMinutes ?? null,
|
|
1936
|
-
restaurantStatus: "new"
|
|
1937
|
-
})
|
|
1938
|
-
};
|
|
1939
|
-
}
|
|
1940
|
-
function updatePayload(data, existingMetadata) {
|
|
1941
|
-
const payload = {};
|
|
1942
|
-
if (data.referenceNumber !== void 0) payload.reference_number = data.referenceNumber;
|
|
1943
|
-
if (data.kind !== void 0) payload.kind = data.kind;
|
|
1944
|
-
if (data.status !== void 0) payload.status = canonicalStatus(data.status);
|
|
1945
|
-
if (data.partyId !== void 0) payload.party_id = data.partyId;
|
|
1946
|
-
if (data.assigneeId !== void 0) payload.assignee_id = data.assigneeId;
|
|
1947
|
-
if (data.locationId !== void 0) payload.location_id = data.locationId;
|
|
1948
|
-
if (data.subtotal !== void 0) payload.subtotal = data.subtotal;
|
|
1949
|
-
if (data.discount !== void 0) payload.discount = data.discount;
|
|
1950
|
-
if (data.tax !== void 0) payload.tax = data.tax;
|
|
1951
|
-
if (data.total !== void 0) payload.total = data.total;
|
|
1952
|
-
if (data.currency !== void 0) payload.currency = data.currency;
|
|
1953
|
-
if (data.notes !== void 0) payload.notes = data.notes;
|
|
1954
|
-
if (data.tags !== void 0) payload.tags = data.tags;
|
|
1955
|
-
const metadataBase = data.metadata !== void 0 ? { ...existingMetadata ?? {}, ...data.metadata } : existingMetadata;
|
|
1956
|
-
const metadataPatch = {
|
|
1957
|
-
partyName: data.partyName,
|
|
1958
|
-
assigneeName: data.assigneeName,
|
|
1959
|
-
source: data.source,
|
|
1960
|
-
tableId: data.tableId,
|
|
1961
|
-
tableName: data.tableName,
|
|
1962
|
-
estimatedMinutes: data.estimatedMinutes,
|
|
1963
|
-
restaurantStatus: data.status
|
|
1964
|
-
};
|
|
1965
|
-
if (data.metadata !== void 0 || Object.values(metadataPatch).some((value) => value !== void 0)) {
|
|
1966
|
-
payload.metadata = mergeOrdersMetadata(metadataBase, metadataPatch);
|
|
1967
|
-
}
|
|
1968
|
-
if (data.completedAt !== void 0) payload.completed_at = data.completedAt;
|
|
1969
|
-
return payload;
|
|
1970
|
-
}
|
|
1971
|
-
function filtersFromQuery(query) {
|
|
1972
|
-
const filters = [];
|
|
1973
|
-
if (query.kind && !Array.isArray(query.kind)) filters.push({ column: "kind", operator: "eq", value: query.kind });
|
|
1974
|
-
if (query.assigneeId) filters.push({ column: "assignee_id", operator: "eq", value: query.assigneeId });
|
|
1975
|
-
return filters;
|
|
1976
|
-
}
|
|
1977
|
-
function matchesClientQuery(order, query) {
|
|
1978
|
-
if (Array.isArray(query.kind) && !query.kind.includes(order.kind)) return false;
|
|
1979
|
-
if (Array.isArray(query.status) && !query.status.includes(order.status)) return false;
|
|
1980
|
-
if (query.status && !Array.isArray(query.status) && order.status !== query.status) return false;
|
|
1981
|
-
if (query.source && order.source !== query.source) return false;
|
|
1982
|
-
if (query.tableId && order.tableId !== query.tableId) return false;
|
|
1983
|
-
if (query.assigneeId && order.assigneeId !== query.assigneeId) return false;
|
|
1984
|
-
if (query.dateRange) {
|
|
1985
|
-
const created = dateKey(order.createdAt);
|
|
1986
|
-
if (created < query.dateRange.from || created > query.dateRange.to) return false;
|
|
1987
|
-
}
|
|
1988
|
-
if (query.search) {
|
|
1989
|
-
const search = query.search.toLowerCase();
|
|
1990
|
-
return order.referenceNumber.toLowerCase().includes(search) || (order.partyName?.toLowerCase().includes(search) ?? false) || (order.tableName?.toLowerCase().includes(search) ?? false) || order.items.some((item) => item.name.toLowerCase().includes(search));
|
|
1991
|
-
}
|
|
1992
|
-
return true;
|
|
1993
|
-
}
|
|
1994
|
-
function paginate(items, page, pageSize) {
|
|
1995
|
-
const currentPage = page ?? 1;
|
|
1996
|
-
const limit = pageSize ?? 20;
|
|
1997
|
-
const start = (currentPage - 1) * limit;
|
|
1998
|
-
return { data: items.slice(start, start + limit), total: items.length };
|
|
1999
|
-
}
|
|
2000
|
-
function summarize(orders, dateRange) {
|
|
2001
|
-
const today = dateKey(nowIso());
|
|
2002
|
-
const from = dateRange?.from ?? today;
|
|
2003
|
-
const to = dateRange?.to ?? today;
|
|
2004
|
-
const inRange = orders.filter((order) => {
|
|
2005
|
-
const created = dateKey(order.createdAt);
|
|
2006
|
-
return created >= from && created <= to;
|
|
2007
|
-
});
|
|
2008
|
-
const billable = inRange.filter((order) => order.status !== "cancelled");
|
|
2009
|
-
const revenue = billable.reduce((sum, order) => sum + order.total, 0);
|
|
2010
|
-
const ordersByKind = { dine_in: 0, takeout: 0, delivery: 0 };
|
|
2011
|
-
const ordersByStatus = {};
|
|
2012
|
-
const top = /* @__PURE__ */ new Map();
|
|
2013
|
-
for (const order of inRange) {
|
|
2014
|
-
ordersByKind[order.kind] = (ordersByKind[order.kind] ?? 0) + 1;
|
|
2015
|
-
ordersByStatus[order.status] = (ordersByStatus[order.status] ?? 0) + 1;
|
|
2016
|
-
if (order.status === "cancelled") continue;
|
|
2017
|
-
for (const item of order.items) {
|
|
2018
|
-
const current = top.get(item.name) ?? { name: item.name, quantity: 0, revenue: 0 };
|
|
2019
|
-
current.quantity += item.quantity;
|
|
2020
|
-
current.revenue += item.total;
|
|
2021
|
-
top.set(item.name, current);
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
return {
|
|
2025
|
-
todayOrderCount: inRange.length,
|
|
2026
|
-
todayRevenue: revenue,
|
|
2027
|
-
averageTicket: billable.length > 0 ? revenue / billable.length : 0,
|
|
2028
|
-
activeOrderCount: orders.filter((order) => ACTIVE_STATUSES2.has(order.status)).length,
|
|
2029
|
-
ordersByKind,
|
|
2030
|
-
ordersByStatus,
|
|
2031
|
-
topItems: [...top.values()].sort((a, b) => b.quantity - a.quantity).slice(0, 5)
|
|
2032
|
-
};
|
|
2033
|
-
}
|
|
2034
|
-
function createFayzOrdersProvider(options = {}) {
|
|
2035
|
-
const client = createFayzClient(options);
|
|
2036
|
-
const ordersTable = options.ordersTable ?? DEFAULT_ORDERS_TABLE;
|
|
2037
|
-
const orderItemsTable = options.orderItemsTable ?? DEFAULT_ORDER_ITEMS_TABLE;
|
|
2038
|
-
const tableOptions = { projectId: options.projectId, schema: options.schema, runtime: options.runtime };
|
|
2039
|
-
function resolveTenant() {
|
|
2040
|
-
const value = typeof options.tenantId === "function" ? options.tenantId() : options.tenantId;
|
|
2041
|
-
return value ?? void 0;
|
|
2042
|
-
}
|
|
2043
|
-
function resolveUnit() {
|
|
2044
|
-
const value = typeof options.unitId === "function" ? options.unitId() : options.unitId;
|
|
2045
|
-
return value ?? void 0;
|
|
2046
|
-
}
|
|
2047
|
-
function withTenant(filters) {
|
|
2048
|
-
const tenantId = resolveTenant();
|
|
2049
|
-
return tenantId ? [{ column: "tenant_id", operator: "eq", value: tenantId }, ...filters] : filters;
|
|
2050
|
-
}
|
|
2051
|
-
async function listItemRows(orderIds) {
|
|
2052
|
-
if (orderIds.length === 0) return [];
|
|
2053
|
-
const rows = [];
|
|
2054
|
-
await Promise.all(orderIds.map(async (orderId) => {
|
|
2055
|
-
const response = await client.data.listRows({
|
|
2056
|
-
...tableOptions,
|
|
2057
|
-
table: orderItemsTable,
|
|
2058
|
-
filters: [{ column: "order_id", operator: "eq", value: orderId }],
|
|
2059
|
-
sortColumn: "sort_order",
|
|
2060
|
-
sortDirection: "asc",
|
|
2061
|
-
limit: 200
|
|
2062
|
-
});
|
|
2063
|
-
rows.push(...response.rows);
|
|
2064
|
-
}));
|
|
2065
|
-
return rows;
|
|
2066
|
-
}
|
|
2067
|
-
async function hydrate(rows) {
|
|
2068
|
-
const itemRows = await listItemRows(rows.map((row) => row.id));
|
|
2069
|
-
const byOrder = /* @__PURE__ */ new Map();
|
|
2070
|
-
for (const itemRow of itemRows) {
|
|
2071
|
-
const item = rowToItem(itemRow);
|
|
2072
|
-
const list = byOrder.get(item.orderId) ?? [];
|
|
2073
|
-
list.push(item);
|
|
2074
|
-
byOrder.set(item.orderId, list);
|
|
2075
|
-
}
|
|
2076
|
-
return rows.map((row) => rowToOrder(row, byOrder.get(row.id) ?? []));
|
|
2077
|
-
}
|
|
2078
|
-
async function listOrders(query = {}) {
|
|
2079
|
-
const response = await client.data.listRows({
|
|
2080
|
-
...tableOptions,
|
|
2081
|
-
table: ordersTable,
|
|
2082
|
-
filters: withTenant(filtersFromQuery(query)),
|
|
2083
|
-
sortColumn: "created_at",
|
|
2084
|
-
sortDirection: "desc",
|
|
2085
|
-
limit: 500
|
|
2086
|
-
});
|
|
2087
|
-
return (await hydrate(response.rows)).filter((order) => matchesClientQuery(order, query));
|
|
2088
|
-
}
|
|
2089
|
-
async function getById(id) {
|
|
2090
|
-
const response = await client.data.listRows({
|
|
2091
|
-
...tableOptions,
|
|
2092
|
-
table: ordersTable,
|
|
2093
|
-
filters: withTenant([{ column: "id", operator: "eq", value: id }]),
|
|
2094
|
-
limit: 1
|
|
2095
|
-
});
|
|
2096
|
-
return (await hydrate(response.rows))[0] ?? null;
|
|
2097
|
-
}
|
|
2098
|
-
return {
|
|
2099
|
-
async getOrders(query) {
|
|
2100
|
-
const orders = await listOrders(query);
|
|
2101
|
-
return paginate(orders, query.page, query.pageSize);
|
|
2102
|
-
},
|
|
2103
|
-
async getOrderById(id) {
|
|
2104
|
-
return getById(id);
|
|
2105
|
-
},
|
|
2106
|
-
async createOrder(input) {
|
|
2107
|
-
const tenantId = resolveTenant();
|
|
2108
|
-
const unitId = resolveUnit();
|
|
2109
|
-
const orderRow = await client.data.createRow({
|
|
2110
|
-
...tableOptions,
|
|
2111
|
-
table: ordersTable,
|
|
2112
|
-
row: {
|
|
2113
|
-
...orderPayload(input),
|
|
2114
|
-
...tenantId ? { tenant_id: tenantId } : {},
|
|
2115
|
-
...unitId ? { unit_id: unitId } : {}
|
|
2116
|
-
}
|
|
2117
|
-
});
|
|
2118
|
-
await Promise.all(input.items.map((item, index) => client.data.createRow({
|
|
2119
|
-
...tableOptions,
|
|
2120
|
-
table: orderItemsTable,
|
|
2121
|
-
row: itemToRow(item, orderRow.id, index, tenantId, unitId)
|
|
2122
|
-
})));
|
|
2123
|
-
return await getById(orderRow.id) ?? rowToOrder(orderRow);
|
|
2124
|
-
},
|
|
2125
|
-
async updateOrderStatus(input) {
|
|
2126
|
-
const completedAt = input.status === "completed" ? nowIso() : void 0;
|
|
2127
|
-
return this.updateOrder(input.orderId, { status: input.status, completedAt });
|
|
2128
|
-
},
|
|
2129
|
-
async updateOrder(id, data) {
|
|
2130
|
-
const existing = await getById(id);
|
|
2131
|
-
const row = await client.data.updateRow({
|
|
2132
|
-
...tableOptions,
|
|
2133
|
-
table: ordersTable,
|
|
2134
|
-
primaryKeys: { id },
|
|
2135
|
-
row: updatePayload(data, existing?.metadata)
|
|
2136
|
-
});
|
|
2137
|
-
return await getById(row.id) ?? rowToOrder(row);
|
|
2138
|
-
},
|
|
2139
|
-
async cancelOrder(id, reason) {
|
|
2140
|
-
const order = await getById(id);
|
|
2141
|
-
await this.updateOrder(id, {
|
|
2142
|
-
status: "cancelled",
|
|
2143
|
-
notes: reason ? `${order?.notes ? `${order.notes}
|
|
2144
|
-
` : ""}Cancelled: ${reason}` : order?.notes
|
|
2145
|
-
});
|
|
2146
|
-
},
|
|
2147
|
-
async addOrderItem(orderId, item) {
|
|
2148
|
-
const order = await getById(orderId);
|
|
2149
|
-
const row = await client.data.createRow({
|
|
2150
|
-
...tableOptions,
|
|
2151
|
-
table: orderItemsTable,
|
|
2152
|
-
row: itemToRow(item, orderId, order?.items.length ?? 0, order?.tenantId, order?.unitId ?? resolveUnit())
|
|
2153
|
-
});
|
|
2154
|
-
const created = rowToItem(row);
|
|
2155
|
-
const items = [...order?.items ?? [], created];
|
|
2156
|
-
await this.updateOrder(orderId, {
|
|
2157
|
-
subtotal: items.reduce((sum, orderItem) => sum + orderItem.total, 0),
|
|
2158
|
-
total: items.reduce((sum, orderItem) => sum + orderItem.total, 0) - (order?.discount ?? 0) + (order?.tax ?? 0)
|
|
2159
|
-
});
|
|
2160
|
-
return created;
|
|
2161
|
-
},
|
|
2162
|
-
async removeOrderItem(itemId) {
|
|
2163
|
-
const orders = await listOrders();
|
|
2164
|
-
const order = orders.find((item) => item.items.some((orderItem) => orderItem.id === itemId));
|
|
2165
|
-
await client.data.deleteRows({ ...tableOptions, table: orderItemsTable, rows: [{ id: itemId }] });
|
|
2166
|
-
if (order) {
|
|
2167
|
-
const items = order.items.filter((item) => item.id !== itemId);
|
|
2168
|
-
const subtotal = items.reduce((sum, item) => sum + item.total, 0);
|
|
2169
|
-
await this.updateOrder(order.id, { subtotal, total: subtotal - order.discount + order.tax });
|
|
2170
|
-
}
|
|
2171
|
-
},
|
|
2172
|
-
async updateOrderItem(itemId, data) {
|
|
2173
|
-
const existingResult = await client.data.listRows({
|
|
2174
|
-
...tableOptions,
|
|
2175
|
-
table: orderItemsTable,
|
|
2176
|
-
filters: [{ column: "id", operator: "eq", value: itemId }],
|
|
2177
|
-
limit: 1
|
|
2178
|
-
});
|
|
2179
|
-
const existingMetadata = existingResult.rows[0]?.metadata ?? void 0;
|
|
2180
|
-
const metadataPatch = {
|
|
2181
|
-
modifiers: data.modifiers,
|
|
2182
|
-
kitchenNotes: data.kitchenNotes
|
|
2183
|
-
};
|
|
2184
|
-
const row = await client.data.updateRow({
|
|
2185
|
-
...tableOptions,
|
|
2186
|
-
table: orderItemsTable,
|
|
2187
|
-
primaryKeys: { id: itemId },
|
|
2188
|
-
row: {
|
|
2189
|
-
product_id: data.productId,
|
|
2190
|
-
name: data.name,
|
|
2191
|
-
description: data.description,
|
|
2192
|
-
quantity: data.quantity,
|
|
2193
|
-
unit_price: data.unitPrice,
|
|
2194
|
-
discount: data.discount,
|
|
2195
|
-
total: data.total,
|
|
2196
|
-
sort_order: data.sortOrder,
|
|
2197
|
-
metadata: data.metadata !== void 0 || Object.values(metadataPatch).some((value) => value !== void 0) ? mergeOrdersMetadata(
|
|
2198
|
-
data.metadata !== void 0 ? { ...existingMetadata ?? {}, ...data.metadata } : existingMetadata,
|
|
2199
|
-
metadataPatch
|
|
2200
|
-
) : void 0
|
|
2201
|
-
}
|
|
2202
|
-
});
|
|
2203
|
-
return rowToItem(row);
|
|
2204
|
-
},
|
|
2205
|
-
async getSummary(dateRange) {
|
|
2206
|
-
return summarize(await listOrders({ dateRange }), dateRange);
|
|
2207
|
-
}
|
|
2208
|
-
};
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
// src/data/mock.ts
|
|
2212
|
-
var uid = 100;
|
|
2213
|
-
function nextId(prefix) {
|
|
2214
|
-
return prefix + "-" + ++uid;
|
|
2215
|
-
}
|
|
2216
|
-
var now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2217
|
-
function makeItem(orderId, name, quantity, unitPrice, sortOrder, productId) {
|
|
2218
|
-
const id = nextId("item");
|
|
2219
|
-
return {
|
|
2220
|
-
id,
|
|
2221
|
-
orderId,
|
|
2222
|
-
productId,
|
|
2223
|
-
name,
|
|
2224
|
-
quantity,
|
|
2225
|
-
unitPrice,
|
|
2226
|
-
discount: 0,
|
|
2227
|
-
total: quantity * unitPrice,
|
|
2228
|
-
sortOrder,
|
|
2229
|
-
createdAt: now
|
|
2230
|
-
};
|
|
2231
|
-
}
|
|
2232
|
-
function createSeedOrders() {
|
|
2233
|
-
const order1Id = nextId("order");
|
|
2234
|
-
const order1Items = [
|
|
2235
|
-
makeItem(order1Id, "Classic Burger", 1, 32, 0, "prod-burger-classic"),
|
|
2236
|
-
makeItem(order1Id, "Fries", 1, 15, 1, "prod-fries")
|
|
2237
|
-
];
|
|
2238
|
-
const order1 = {
|
|
2239
|
-
id: order1Id,
|
|
2240
|
-
referenceNumber: "ORD-0001",
|
|
2241
|
-
kind: "dine_in",
|
|
2242
|
-
status: "preparing",
|
|
2243
|
-
source: "pos",
|
|
2244
|
-
tableId: "table-3",
|
|
2245
|
-
tableName: "Table 3",
|
|
2246
|
-
subtotal: 47,
|
|
2247
|
-
discount: 0,
|
|
2248
|
-
tax: 0,
|
|
2249
|
-
total: 47,
|
|
2250
|
-
currency: "BRL",
|
|
2251
|
-
tags: [],
|
|
2252
|
-
items: order1Items,
|
|
2253
|
-
tenantId: "tenant-mock",
|
|
2254
|
-
createdAt: now,
|
|
2255
|
-
updatedAt: now
|
|
2256
|
-
};
|
|
2257
|
-
const order2Id = nextId("order");
|
|
2258
|
-
const order2Items = [
|
|
2259
|
-
makeItem(order2Id, "Cheese Burger", 1, 36, 0, "prod-burger-cheese")
|
|
2260
|
-
];
|
|
2261
|
-
const order2 = {
|
|
2262
|
-
id: order2Id,
|
|
2263
|
-
referenceNumber: "ORD-0002",
|
|
2264
|
-
kind: "takeout",
|
|
2265
|
-
status: "ready",
|
|
2266
|
-
source: "pos",
|
|
2267
|
-
subtotal: 36,
|
|
2268
|
-
discount: 0,
|
|
2269
|
-
tax: 0,
|
|
2270
|
-
total: 36,
|
|
2271
|
-
currency: "BRL",
|
|
2272
|
-
tags: [],
|
|
2273
|
-
items: order2Items,
|
|
2274
|
-
tenantId: "tenant-mock",
|
|
2275
|
-
createdAt: now,
|
|
2276
|
-
updatedAt: now
|
|
2277
|
-
};
|
|
2278
|
-
const order3Id = nextId("order");
|
|
2279
|
-
const order3Items = [
|
|
2280
|
-
makeItem(order3Id, "Margherita Pizza", 1, 38, 0, "prod-pizza-margherita"),
|
|
2281
|
-
makeItem(order3Id, "Caesar Salad", 1, 22, 1, "prod-salad-caesar"),
|
|
2282
|
-
makeItem(order3Id, "Soda 350ml", 1, 12, 2, "prod-soda")
|
|
2283
|
-
];
|
|
2284
|
-
const order3 = {
|
|
2285
|
-
id: order3Id,
|
|
2286
|
-
referenceNumber: "ORD-0003",
|
|
2287
|
-
kind: "delivery",
|
|
2288
|
-
status: "confirmed",
|
|
2289
|
-
source: "ifood",
|
|
2290
|
-
subtotal: 72,
|
|
2291
|
-
discount: 0,
|
|
2292
|
-
tax: 0,
|
|
2293
|
-
total: 72,
|
|
2294
|
-
currency: "BRL",
|
|
2295
|
-
tags: [],
|
|
2296
|
-
items: order3Items,
|
|
2297
|
-
tenantId: "tenant-mock",
|
|
2298
|
-
createdAt: now,
|
|
2299
|
-
updatedAt: now
|
|
2300
|
-
};
|
|
2301
|
-
const order4Id = nextId("order");
|
|
2302
|
-
const order4Items = [
|
|
2303
|
-
makeItem(order4Id, "BBQ Bacon Burger", 1, 42, 0, "prod-burger-bbq")
|
|
2304
|
-
];
|
|
2305
|
-
const order4 = {
|
|
2306
|
-
id: order4Id,
|
|
2307
|
-
referenceNumber: "ORD-0004",
|
|
2308
|
-
kind: "dine_in",
|
|
2309
|
-
status: "new",
|
|
2310
|
-
source: "pos",
|
|
2311
|
-
tableId: "table-7",
|
|
2312
|
-
tableName: "Table 7",
|
|
2313
|
-
subtotal: 42,
|
|
2314
|
-
discount: 0,
|
|
2315
|
-
tax: 0,
|
|
2316
|
-
total: 42,
|
|
2317
|
-
currency: "BRL",
|
|
2318
|
-
tags: [],
|
|
2319
|
-
items: order4Items,
|
|
2320
|
-
tenantId: "tenant-mock",
|
|
2321
|
-
createdAt: now,
|
|
2322
|
-
updatedAt: now
|
|
2323
|
-
};
|
|
2324
|
-
const order5Id = nextId("order");
|
|
2325
|
-
const order5Items = [
|
|
2326
|
-
makeItem(order5Id, "Classic Burger", 2, 32, 0, "prod-burger-classic"),
|
|
2327
|
-
makeItem(order5Id, "Fries", 1, 15, 1, "prod-fries"),
|
|
2328
|
-
makeItem(order5Id, "Onion Rings", 1, 18, 2, "prod-onion-rings"),
|
|
2329
|
-
makeItem(order5Id, "Milkshake", 1, 23, 3, "prod-milkshake")
|
|
2330
|
-
];
|
|
2331
|
-
const order5 = {
|
|
2332
|
-
id: order5Id,
|
|
2333
|
-
referenceNumber: "ORD-0005",
|
|
2334
|
-
kind: "dine_in",
|
|
2335
|
-
status: "completed",
|
|
2336
|
-
source: "pos",
|
|
2337
|
-
tableId: "table-1",
|
|
2338
|
-
tableName: "Table 1",
|
|
2339
|
-
subtotal: 120,
|
|
2340
|
-
discount: 0,
|
|
2341
|
-
tax: 0,
|
|
2342
|
-
total: 120,
|
|
2343
|
-
currency: "BRL",
|
|
2344
|
-
tags: [],
|
|
2345
|
-
items: order5Items,
|
|
2346
|
-
tenantId: "tenant-mock",
|
|
2347
|
-
createdAt: now,
|
|
2348
|
-
updatedAt: now,
|
|
2349
|
-
completedAt: now
|
|
2350
|
-
};
|
|
2351
|
-
return [order1, order2, order3, order4, order5];
|
|
2352
|
-
}
|
|
2353
|
-
function recomputeTotals(order) {
|
|
2354
|
-
order.subtotal = order.items.reduce((sum, i) => sum + i.total, 0);
|
|
2355
|
-
order.total = order.subtotal - order.discount + order.tax;
|
|
2356
|
-
}
|
|
2357
|
-
var refCounter = 5;
|
|
2358
|
-
function generateReferenceNumber() {
|
|
2359
|
-
refCounter++;
|
|
2360
|
-
return "ORD-" + String(refCounter).padStart(4, "0");
|
|
2361
|
-
}
|
|
2362
|
-
function toDateStr(d) {
|
|
2363
|
-
return d.toISOString().slice(0, 10);
|
|
2364
|
-
}
|
|
2365
|
-
function createMockOrdersProvider() {
|
|
2366
|
-
const orders = createSeedOrders();
|
|
2367
|
-
function findOrder(id) {
|
|
2368
|
-
return orders.find((o) => o.id === id);
|
|
2369
|
-
}
|
|
2370
|
-
function findItem(itemId) {
|
|
2371
|
-
for (const order of orders) {
|
|
2372
|
-
const index = order.items.findIndex((i) => i.id === itemId);
|
|
2373
|
-
if (index !== -1) return { order, item: order.items[index], index };
|
|
2374
|
-
}
|
|
2375
|
-
return void 0;
|
|
2376
|
-
}
|
|
2377
|
-
const provider = {
|
|
2378
|
-
// ------------------------------------------------------------------
|
|
2379
|
-
// getOrders
|
|
2380
|
-
// ------------------------------------------------------------------
|
|
2381
|
-
async getOrders(query) {
|
|
2382
|
-
let result = [...orders];
|
|
2383
|
-
if (query.kind) {
|
|
2384
|
-
const kinds = Array.isArray(query.kind) ? query.kind : [query.kind];
|
|
2385
|
-
result = result.filter((o) => kinds.includes(o.kind));
|
|
2386
|
-
}
|
|
2387
|
-
if (query.status) {
|
|
2388
|
-
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
2389
|
-
result = result.filter((o) => statuses.includes(o.status));
|
|
2390
|
-
}
|
|
2391
|
-
if (query.source) {
|
|
2392
|
-
result = result.filter((o) => o.source === query.source);
|
|
2393
|
-
}
|
|
2394
|
-
if (query.tableId) {
|
|
2395
|
-
result = result.filter((o) => o.tableId === query.tableId);
|
|
2396
|
-
}
|
|
2397
|
-
if (query.assigneeId) {
|
|
2398
|
-
result = result.filter((o) => o.assigneeId === query.assigneeId);
|
|
2399
|
-
}
|
|
2400
|
-
if (query.search) {
|
|
2401
|
-
const q = query.search.toLowerCase();
|
|
2402
|
-
result = result.filter(
|
|
2403
|
-
(o) => o.referenceNumber.toLowerCase().includes(q) || o.partyName?.toLowerCase().includes(q) || o.tableName?.toLowerCase().includes(q) || o.items.some((i) => i.name.toLowerCase().includes(q))
|
|
2404
|
-
);
|
|
2405
|
-
}
|
|
2406
|
-
if (query.dateRange) {
|
|
2407
|
-
const from = query.dateRange.from;
|
|
2408
|
-
const to = query.dateRange.to;
|
|
2409
|
-
result = result.filter((o) => {
|
|
2410
|
-
const d = o.createdAt.slice(0, 10);
|
|
2411
|
-
return d >= from && d <= to;
|
|
2412
|
-
});
|
|
2413
|
-
}
|
|
2414
|
-
result.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
2415
|
-
const total = result.length;
|
|
2416
|
-
const page = query.page ?? 1;
|
|
2417
|
-
const pageSize = query.pageSize ?? 20;
|
|
2418
|
-
const start = (page - 1) * pageSize;
|
|
2419
|
-
const data = result.slice(start, start + pageSize);
|
|
2420
|
-
return { data, total };
|
|
2421
|
-
},
|
|
2422
|
-
// ------------------------------------------------------------------
|
|
2423
|
-
// getOrderById
|
|
2424
|
-
// ------------------------------------------------------------------
|
|
2425
|
-
async getOrderById(id) {
|
|
2426
|
-
return findOrder(id) ?? null;
|
|
2427
|
-
},
|
|
2428
|
-
// ------------------------------------------------------------------
|
|
2429
|
-
// createOrder
|
|
2430
|
-
// ------------------------------------------------------------------
|
|
2431
|
-
async createOrder(input) {
|
|
2432
|
-
const orderId = nextId("order");
|
|
2433
|
-
const items = input.items.map((item, idx) => ({
|
|
2434
|
-
id: nextId("item"),
|
|
2435
|
-
orderId,
|
|
2436
|
-
productId: item.productId,
|
|
2437
|
-
name: item.name,
|
|
2438
|
-
quantity: item.quantity,
|
|
2439
|
-
unitPrice: item.unitPrice,
|
|
2440
|
-
discount: item.discount ?? 0,
|
|
2441
|
-
total: item.quantity * item.unitPrice - (item.discount ?? 0),
|
|
2442
|
-
sortOrder: idx,
|
|
2443
|
-
modifiers: item.modifiers,
|
|
2444
|
-
kitchenNotes: item.kitchenNotes,
|
|
2445
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2446
|
-
}));
|
|
2447
|
-
const subtotal = items.reduce((sum, i) => sum + i.total, 0);
|
|
2448
|
-
const order = {
|
|
2449
|
-
id: orderId,
|
|
2450
|
-
referenceNumber: generateReferenceNumber(),
|
|
2451
|
-
kind: input.kind,
|
|
2452
|
-
status: "new",
|
|
2453
|
-
source: input.source ?? "pos",
|
|
2454
|
-
tableId: input.tableId,
|
|
2455
|
-
partyId: input.partyId,
|
|
2456
|
-
assigneeId: input.assigneeId,
|
|
2457
|
-
notes: input.notes,
|
|
2458
|
-
estimatedMinutes: input.estimatedMinutes,
|
|
2459
|
-
subtotal,
|
|
2460
|
-
discount: 0,
|
|
2461
|
-
tax: 0,
|
|
2462
|
-
total: subtotal,
|
|
2463
|
-
currency: "BRL",
|
|
2464
|
-
tags: [],
|
|
2465
|
-
items,
|
|
2466
|
-
tenantId: "tenant-mock",
|
|
2467
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2468
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2469
|
-
};
|
|
2470
|
-
orders.push(order);
|
|
2471
|
-
return order;
|
|
2472
|
-
},
|
|
2473
|
-
// ------------------------------------------------------------------
|
|
2474
|
-
// updateOrderStatus
|
|
2475
|
-
// ------------------------------------------------------------------
|
|
2476
|
-
async updateOrderStatus(input) {
|
|
2477
|
-
const order = findOrder(input.orderId);
|
|
2478
|
-
if (!order) throw new Error(`Order not found: ${input.orderId}`);
|
|
2479
|
-
if (input.status !== "cancelled") {
|
|
2480
|
-
const flow = STATUS_FLOW[order.kind];
|
|
2481
|
-
const currentIdx = flow.indexOf(order.status);
|
|
2482
|
-
const targetIdx = flow.indexOf(input.status);
|
|
2483
|
-
if (targetIdx < 0 || targetIdx !== currentIdx && targetIdx !== currentIdx + 1) {
|
|
2484
|
-
const next = getNextStatus(order.kind, order.status);
|
|
2485
|
-
throw new Error(
|
|
2486
|
-
`Invalid status transition: ${order.status} \u2192 ${input.status}. ` + (next ? `Expected next status: ${next}` : "Order is already in a terminal state.")
|
|
2487
|
-
);
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
order.status = input.status;
|
|
2491
|
-
order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2492
|
-
if (input.status === "completed") {
|
|
2493
|
-
order.completedAt = order.updatedAt;
|
|
2494
|
-
}
|
|
2495
|
-
return order;
|
|
2496
|
-
},
|
|
2497
|
-
// ------------------------------------------------------------------
|
|
2498
|
-
// updateOrder
|
|
2499
|
-
// ------------------------------------------------------------------
|
|
2500
|
-
async updateOrder(id, data) {
|
|
2501
|
-
const order = findOrder(id);
|
|
2502
|
-
if (!order) throw new Error(`Order not found: ${id}`);
|
|
2503
|
-
const { id: _id, items: _items, tenantId: _t, createdAt: _c, ...safe } = data;
|
|
2504
|
-
Object.assign(order, safe);
|
|
2505
|
-
order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2506
|
-
return order;
|
|
2507
|
-
},
|
|
2508
|
-
// ------------------------------------------------------------------
|
|
2509
|
-
// cancelOrder
|
|
2510
|
-
// ------------------------------------------------------------------
|
|
2511
|
-
async cancelOrder(id, reason) {
|
|
2512
|
-
const order = findOrder(id);
|
|
2513
|
-
if (!order) throw new Error(`Order not found: ${id}`);
|
|
2514
|
-
order.status = "cancelled";
|
|
2515
|
-
order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2516
|
-
if (reason) {
|
|
2517
|
-
order.notes = order.notes ? `${order.notes}
|
|
2518
|
-
Cancelled: ${reason}` : `Cancelled: ${reason}`;
|
|
2519
|
-
}
|
|
2520
|
-
},
|
|
2521
|
-
// ------------------------------------------------------------------
|
|
2522
|
-
// addOrderItem
|
|
2523
|
-
// ------------------------------------------------------------------
|
|
2524
|
-
async addOrderItem(orderId, item) {
|
|
2525
|
-
const order = findOrder(orderId);
|
|
2526
|
-
if (!order) throw new Error(`Order not found: ${orderId}`);
|
|
2527
|
-
const newItem = {
|
|
2528
|
-
id: nextId("item"),
|
|
2529
|
-
orderId,
|
|
2530
|
-
productId: item.productId,
|
|
2531
|
-
name: item.name,
|
|
2532
|
-
quantity: item.quantity,
|
|
2533
|
-
unitPrice: item.unitPrice,
|
|
2534
|
-
discount: item.discount ?? 0,
|
|
2535
|
-
total: item.quantity * item.unitPrice - (item.discount ?? 0),
|
|
2536
|
-
sortOrder: order.items.length,
|
|
2537
|
-
modifiers: item.modifiers,
|
|
2538
|
-
kitchenNotes: item.kitchenNotes,
|
|
2539
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2540
|
-
};
|
|
2541
|
-
order.items.push(newItem);
|
|
2542
|
-
recomputeTotals(order);
|
|
2543
|
-
order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2544
|
-
return newItem;
|
|
2545
|
-
},
|
|
2546
|
-
// ------------------------------------------------------------------
|
|
2547
|
-
// removeOrderItem
|
|
2548
|
-
// ------------------------------------------------------------------
|
|
2549
|
-
async removeOrderItem(itemId) {
|
|
2550
|
-
const found = findItem(itemId);
|
|
2551
|
-
if (!found) throw new Error(`Order item not found: ${itemId}`);
|
|
2552
|
-
found.order.items.splice(found.index, 1);
|
|
2553
|
-
recomputeTotals(found.order);
|
|
2554
|
-
found.order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2555
|
-
},
|
|
2556
|
-
// ------------------------------------------------------------------
|
|
2557
|
-
// updateOrderItem
|
|
2558
|
-
// ------------------------------------------------------------------
|
|
2559
|
-
async updateOrderItem(itemId, data) {
|
|
2560
|
-
const found = findItem(itemId);
|
|
2561
|
-
if (!found) throw new Error(`Order item not found: ${itemId}`);
|
|
2562
|
-
const { id: _id, orderId: _oid, createdAt: _c, ...safe } = data;
|
|
2563
|
-
Object.assign(found.item, safe);
|
|
2564
|
-
found.item.total = found.item.quantity * found.item.unitPrice - found.item.discount;
|
|
2565
|
-
recomputeTotals(found.order);
|
|
2566
|
-
found.order.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2567
|
-
return found.item;
|
|
2568
|
-
},
|
|
2569
|
-
// ------------------------------------------------------------------
|
|
2570
|
-
// getSummary
|
|
2571
|
-
// ------------------------------------------------------------------
|
|
2572
|
-
async getSummary(dateRange) {
|
|
2573
|
-
const today = toDateStr(/* @__PURE__ */ new Date());
|
|
2574
|
-
const from = dateRange?.from ?? today;
|
|
2575
|
-
const to = dateRange?.to ?? today;
|
|
2576
|
-
const inRange = orders.filter((o) => {
|
|
2577
|
-
const d = o.createdAt.slice(0, 10);
|
|
2578
|
-
return d >= from && d <= to;
|
|
2579
|
-
});
|
|
2580
|
-
const completed = inRange.filter((o) => o.status !== "cancelled");
|
|
2581
|
-
const revenue = completed.reduce((sum, o) => sum + o.total, 0);
|
|
2582
|
-
const activeStatuses = /* @__PURE__ */ new Set(["new", "confirmed", "preparing", "ready", "served", "dispatched"]);
|
|
2583
|
-
const active = orders.filter((o) => activeStatuses.has(o.status));
|
|
2584
|
-
const ordersByKind = { dine_in: 0, takeout: 0, delivery: 0 };
|
|
2585
|
-
const ordersByStatus = {};
|
|
2586
|
-
for (const o of inRange) {
|
|
2587
|
-
ordersByKind[o.kind] = (ordersByKind[o.kind] || 0) + 1;
|
|
2588
|
-
ordersByStatus[o.status] = (ordersByStatus[o.status] || 0) + 1;
|
|
2589
|
-
}
|
|
2590
|
-
const itemMap = /* @__PURE__ */ new Map();
|
|
2591
|
-
for (const o of completed) {
|
|
2592
|
-
for (const item of o.items) {
|
|
2593
|
-
const existing = itemMap.get(item.name);
|
|
2594
|
-
if (existing) {
|
|
2595
|
-
existing.quantity += item.quantity;
|
|
2596
|
-
existing.revenue += item.total;
|
|
2597
|
-
} else {
|
|
2598
|
-
itemMap.set(item.name, { name: item.name, quantity: item.quantity, revenue: item.total });
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
const topItems = Array.from(itemMap.values()).sort((a, b) => b.quantity - a.quantity).slice(0, 5);
|
|
2603
|
-
return {
|
|
2604
|
-
todayOrderCount: inRange.length,
|
|
2605
|
-
todayRevenue: revenue,
|
|
2606
|
-
averageTicket: completed.length > 0 ? revenue / completed.length : 0,
|
|
2607
|
-
activeOrderCount: active.length,
|
|
2608
|
-
ordersByKind,
|
|
2609
|
-
ordersByStatus,
|
|
2610
|
-
topItems
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
};
|
|
2614
|
-
return provider;
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
// src/index.ts
|
|
2618
|
-
var OrdersPage = React.lazy(() => import('./OrdersPage-5326V62H.js').then((m) => ({ default: m.OrdersPage })));
|
|
2619
|
-
var OrderDetailRoute = React.lazy(() => import('./OrderDetailRoute-LTPDQXQU.js').then((m) => ({ default: m.OrderDetailRoute })));
|
|
1233
|
+
var ordersV1SettingsTabs = [
|
|
1234
|
+
defineSettingsTab({
|
|
1235
|
+
id: "orders-scale",
|
|
1236
|
+
label: tl("Scale & sale by weight", "Balan\xE7a e venda por peso"),
|
|
1237
|
+
icon: "Scale",
|
|
1238
|
+
section: "operations",
|
|
1239
|
+
requiresFacet: "scale",
|
|
1240
|
+
pending: true,
|
|
1241
|
+
defaults: { "scale.auto_launch": false, "scale.min_weight_g": 10, "scale.label_enabled": false, "scale.label_prefix": "2", "scale.label_code_length": 4, "scale.label_value_kind": "price" },
|
|
1242
|
+
sections: [
|
|
1243
|
+
{ title: tl("Weighing", "Pesagem"), fields: [
|
|
1244
|
+
{ key: "scale.auto_launch", type: "boolean", scope: "unit", label: tl("Launch on its own once the weight settles", "Lan\xE7ar sozinho quando o peso estabilizar") },
|
|
1245
|
+
{ key: "scale.min_weight_g", type: "number", scope: "unit", min: 1, max: 5e3, label: tl("Minimum weight (g)", "Peso m\xEDnimo (g)") }
|
|
1246
|
+
] },
|
|
1247
|
+
{ title: tl("Scale labels", "Etiqueta da balan\xE7a"), fields: [
|
|
1248
|
+
{ key: "scale.label_enabled", type: "boolean", scope: "unit", label: tl("Read scale labels at the POS", "Ler etiqueta de balan\xE7a no PDV") },
|
|
1249
|
+
{ key: "scale.label_prefix", type: "string", scope: "unit", label: tl("Barcode prefix", "Prefixo do c\xF3digo") },
|
|
1250
|
+
{ key: "scale.label_code_length", type: "number", scope: "unit", min: 4, max: 6, label: tl("Product code digits", "D\xEDgitos do c\xF3digo do produto") },
|
|
1251
|
+
{ key: "scale.label_value_kind", type: "select", scope: "unit", label: tl("The label carries", "A etiqueta traz"), options: [
|
|
1252
|
+
{ value: "price", label: tl("Price", "Pre\xE7o") },
|
|
1253
|
+
{ value: "weight", label: tl("Weight", "Peso") }
|
|
1254
|
+
] }
|
|
1255
|
+
] }
|
|
1256
|
+
]
|
|
1257
|
+
})
|
|
1258
|
+
];
|
|
1259
|
+
var OrdersPage = React.lazy(() => import('./OrdersPage-3KNCFC7K.js').then((m) => ({ default: m.OrdersPage })));
|
|
1260
|
+
var OrderDetailRoute = React.lazy(() => import('./OrderDetailRoute-QGZIMEQ3.js').then((m) => ({ default: m.OrderDetailRoute })));
|
|
2620
1261
|
var DEFAULT_LABELS = {
|
|
2621
1262
|
pageTitle: "Orders",
|
|
1263
|
+
moduleName: tl("Orders & POS", "Pedidos e PDV"),
|
|
2622
1264
|
kanban: "Orders",
|
|
2623
1265
|
newOrder: "New Order",
|
|
2624
1266
|
orderList: "History"
|
|
@@ -2649,7 +1291,7 @@ function resolveConfig(options) {
|
|
|
2649
1291
|
}
|
|
2650
1292
|
function createOrdersPlugin(options) {
|
|
2651
1293
|
const config = resolveConfig(options);
|
|
2652
|
-
const provider = options?.dataProvider ??
|
|
1294
|
+
const provider = options?.dataProvider ?? createSupabaseOrdersProvider();
|
|
2653
1295
|
const store7 = createOrdersStore(provider, {
|
|
2654
1296
|
onOrderCompleted: config.onOrderCompleted,
|
|
2655
1297
|
onOrderCancelled: config.onOrderCancelled
|
|
@@ -2669,16 +1311,11 @@ function createOrdersPlugin(options) {
|
|
|
2669
1311
|
);
|
|
2670
1312
|
return {
|
|
2671
1313
|
id: "orders",
|
|
2672
|
-
//
|
|
2673
|
-
// a fábrica roda no carregamento do aplicativo, muito antes de a
|
|
2674
|
-
// configuração da conta existir, e sem isto `app.tenant_plugins.config`
|
|
2675
|
-
// não tinha como chegar aqui. A fusão é RASA e por bloco — a conta troca
|
|
2676
|
-
// `modules` inteiro ou não o troca —, que é o mesmo contrato que a chamada
|
|
2677
|
-
// do aplicativo já tem.
|
|
1314
|
+
// The tenant's config arrives after load; the merge is shallow, per block, like the app's own call.
|
|
2678
1315
|
rebuild: (tenantConfig) => createOrdersPlugin({ ...options, ...tenantConfig }),
|
|
2679
1316
|
defaultAgentRole: "operations",
|
|
2680
|
-
name: config.labels.
|
|
2681
|
-
icon: "
|
|
1317
|
+
name: config.labels.moduleName,
|
|
1318
|
+
icon: "Coins",
|
|
2682
1319
|
version: "1.0.0",
|
|
2683
1320
|
scope: options?.scope ?? "vertical",
|
|
2684
1321
|
verticalId: options?.verticalId,
|
|
@@ -2729,9 +1366,7 @@ function createOrdersPlugin(options) {
|
|
|
2729
1366
|
}
|
|
2730
1367
|
}
|
|
2731
1368
|
],
|
|
2732
|
-
//
|
|
2733
|
-
// store/AI-tool (createOrder) with no dedicated UI create handler, so no
|
|
2734
|
-
// client-side guard is wired yet — the declaration keeps the cap countable.
|
|
1369
|
+
// No client-side guard yet: creation goes through the AI tool; the declaration keeps the cap countable.
|
|
2735
1370
|
declaredLimits: [
|
|
2736
1371
|
{ key: "orders_month", label: "Orders / month", table: "orders", kindFilter: "order", period: "month" }
|
|
2737
1372
|
],
|
|
@@ -2741,7 +1376,7 @@ function createOrdersPlugin(options) {
|
|
|
2741
1376
|
position: options?.navPosition ?? 2,
|
|
2742
1377
|
label: config.labels.pageTitle,
|
|
2743
1378
|
route: "/orders",
|
|
2744
|
-
icon: "
|
|
1379
|
+
icon: "Coins",
|
|
2745
1380
|
permission: { feature: "orders", action: "read" }
|
|
2746
1381
|
}
|
|
2747
1382
|
],
|
|
@@ -2818,7 +1453,12 @@ function createOrdersPlugin(options) {
|
|
|
2818
1453
|
}
|
|
2819
1454
|
],
|
|
2820
1455
|
registries: ordersRegistries,
|
|
1456
|
+
facets: [
|
|
1457
|
+
{ id: "scale", label: "Balan\xE7a", description: "Venda por peso com balan\xE7a e etiqueta." },
|
|
1458
|
+
{ id: "delivery", label: "Delivery e iFood", description: "Entrega pr\xF3pria e pedidos do iFood e outros marketplaces.", defaultEnabled: true }
|
|
1459
|
+
],
|
|
2821
1460
|
settings: [
|
|
1461
|
+
...ordersV1SettingsTabs,
|
|
2822
1462
|
{
|
|
2823
1463
|
id: "orders",
|
|
2824
1464
|
label: config.labels.pageTitle,
|
|
@@ -2835,14 +1475,12 @@ function createOrdersPlugin(options) {
|
|
|
2835
1475
|
order: 22,
|
|
2836
1476
|
permission: { feature: "orders", action: "read" }
|
|
2837
1477
|
},
|
|
2838
|
-
// Entrega — política da casa (taxa, mínimo, tempo, raio) e os
|
|
2839
|
-
// marketplaces que trazem o pedido. Só existe onde o delivery existe: um
|
|
2840
|
-
// app sem `modules.delivery` não ganha uma tela para configurar um
|
|
2841
|
-
// serviço que não presta.
|
|
2842
1478
|
...config.modules.delivery ? [{
|
|
2843
1479
|
id: "orders-delivery",
|
|
2844
1480
|
label: "Delivery",
|
|
2845
1481
|
icon: "Bike",
|
|
1482
|
+
// Delivery is sold apart: its settings appear once the account turns it on.
|
|
1483
|
+
requiresFacet: "delivery",
|
|
2846
1484
|
component: (() => {
|
|
2847
1485
|
const DeliverySettingsTab = () => React.createElement(
|
|
2848
1486
|
React.Suspense,
|
|
@@ -2853,14 +1491,12 @@ function createOrdersPlugin(options) {
|
|
|
2853
1491
|
return DeliverySettingsTab;
|
|
2854
1492
|
})(),
|
|
2855
1493
|
order: 23,
|
|
2856
|
-
//
|
|
2857
|
-
// despacha: mesma régua da taxa de serviço em plugin-tables.
|
|
1494
|
+
// The delivery fee is the owner's decision, like the service charge in plugin-tables.
|
|
2858
1495
|
permission: { feature: "orders", action: "edit" }
|
|
2859
1496
|
}] : []
|
|
2860
1497
|
],
|
|
2861
1498
|
locales: ordersLocales,
|
|
2862
|
-
// Offered regardless of `modules.delivery
|
|
2863
|
-
// iFood retirada orders. Control plane only: src/integrations/DELIVERY-MARKETPLACES.md.
|
|
1499
|
+
// Offered regardless of `modules.delivery`: a takeout-only house still takes iFood pickup orders.
|
|
2864
1500
|
connectors: [
|
|
2865
1501
|
ifoodConnectorDef,
|
|
2866
1502
|
nineNineFoodConnectorDef,
|
|
@@ -2872,6 +1508,6 @@ function createOrdersPlugin(options) {
|
|
|
2872
1508
|
};
|
|
2873
1509
|
}
|
|
2874
1510
|
|
|
2875
|
-
export {
|
|
1511
|
+
export { AIQFOME_CONNECTOR_ID, AIQFOME_SETTINGS, AUTO_ACCEPT_SETTING, IFOOD_CONNECTOR_ID, IFOOD_SETTINGS, KEETA_CONNECTOR_ID, KEETA_SETTINGS, NINETY_NINE_FOOD_CONNECTOR_ID, NINETY_NINE_FOOD_SETTINGS, PREP_TIME_SETTING, RAPPI_CONNECTOR_ID, RAPPI_SETTINGS, UBER_EATS_CONNECTOR_ID, UBER_EATS_SETTINGS, aiqfomeConnectorDef, createOrdersPlugin, ifoodConnectorDef, keetaConnectorDef, marketplacePermissions, nineNineFoodConnectorDef, rappiConnectorDef, uberEatsConnectorDef };
|
|
2876
1512
|
//# sourceMappingURL=index.js.map
|
|
2877
1513
|
//# sourceMappingURL=index.js.map
|