@rovela-ai/sdk 0.1.25 → 0.1.26
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/dist/admin/components/ProductTable.d.ts.map +1 -1
- package/dist/admin/components/ProductTable.js +6 -1
- package/dist/admin/components/ProductTable.js.map +1 -1
- package/dist/admin/server/admin-service.d.ts +3 -3
- package/dist/admin/server/admin-service.d.ts.map +1 -1
- package/dist/admin/server/admin-service.js +12 -22
- package/dist/admin/server/admin-service.js.map +1 -1
- package/dist/auth/server/customer-service.d.ts +2 -2
- package/dist/auth/server/customer-service.d.ts.map +1 -1
- package/dist/auth/server/customer-service.js +11 -20
- package/dist/auth/server/customer-service.js.map +1 -1
- package/dist/auth/server/password-reset-service.d.ts +1 -0
- package/dist/auth/server/password-reset-service.d.ts.map +1 -1
- package/dist/auth/server/password-reset-service.js +5 -7
- package/dist/auth/server/password-reset-service.js.map +1 -1
- package/dist/auth/server/verification-service.d.ts +1 -0
- package/dist/auth/server/verification-service.d.ts.map +1 -1
- package/dist/auth/server/verification-service.js +6 -9
- package/dist/auth/server/verification-service.js.map +1 -1
- package/dist/core/db/client.d.ts +2 -44
- package/dist/core/db/client.d.ts.map +1 -1
- package/dist/core/db/client.js +2 -106
- package/dist/core/db/client.js.map +1 -1
- package/dist/core/db/index.d.ts +1 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +2 -2
- package/dist/core/db/index.js.map +1 -1
- package/dist/core/db/queries.d.ts +20 -37
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +69 -110
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +1 -137
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +6 -23
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/server/index.d.ts +1 -1
- package/dist/core/server/index.d.ts.map +1 -1
- package/dist/core/server/index.js +1 -3
- package/dist/core/server/index.js.map +1 -1
- package/dist/core/types.d.ts +0 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/emails/config.d.ts.map +1 -1
- package/dist/emails/config.js +11 -17
- package/dist/emails/config.js.map +1 -1
- package/package.json +1 -1
package/dist/core/db/queries.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @rovela/sdk/core/db/queries
|
|
3
3
|
*
|
|
4
|
-
* Type-safe query helpers
|
|
5
|
-
*
|
|
4
|
+
* Type-safe query helpers for e-commerce stores
|
|
5
|
+
* Each store has its own database (via Neon branches) - no tenant filtering needed
|
|
6
6
|
*/
|
|
7
7
|
import { eq, and, desc, asc, ilike, sql, inArray } from 'drizzle-orm';
|
|
8
|
-
import { getDb
|
|
8
|
+
import { getDb } from './client';
|
|
9
9
|
import * as schema from './schema';
|
|
10
10
|
/**
|
|
11
11
|
* Find products with filtering, sorting, and pagination
|
|
12
|
-
* Automatically scoped to current tenant
|
|
13
12
|
*/
|
|
14
13
|
export async function findProducts(options = {}) {
|
|
15
14
|
const db = getDb();
|
|
16
|
-
const
|
|
17
|
-
const conditions = [eq(schema.products.tenantId, tenantId)];
|
|
15
|
+
const conditions = [];
|
|
18
16
|
if (options.categoryId) {
|
|
19
17
|
conditions.push(eq(schema.products.categoryId, options.categoryId));
|
|
20
18
|
}
|
|
@@ -43,7 +41,7 @@ export async function findProducts(options = {}) {
|
|
|
43
41
|
const query = db
|
|
44
42
|
.select()
|
|
45
43
|
.from(schema.products)
|
|
46
|
-
.where(and(...conditions))
|
|
44
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
|
47
45
|
.orderBy(orderBy);
|
|
48
46
|
if (options.limit) {
|
|
49
47
|
query.limit(options.limit);
|
|
@@ -58,11 +56,10 @@ export async function findProducts(options = {}) {
|
|
|
58
56
|
*/
|
|
59
57
|
export async function findProductBySlug(slug) {
|
|
60
58
|
const db = getDb();
|
|
61
|
-
const tenantId = getTenantId();
|
|
62
59
|
const result = await db
|
|
63
60
|
.select()
|
|
64
61
|
.from(schema.products)
|
|
65
|
-
.where(
|
|
62
|
+
.where(eq(schema.products.slug, slug))
|
|
66
63
|
.limit(1);
|
|
67
64
|
return result[0] || null;
|
|
68
65
|
}
|
|
@@ -71,11 +68,10 @@ export async function findProductBySlug(slug) {
|
|
|
71
68
|
*/
|
|
72
69
|
export async function findProductById(id) {
|
|
73
70
|
const db = getDb();
|
|
74
|
-
const tenantId = getTenantId();
|
|
75
71
|
const result = await db
|
|
76
72
|
.select()
|
|
77
73
|
.from(schema.products)
|
|
78
|
-
.where(
|
|
74
|
+
.where(eq(schema.products.id, id))
|
|
79
75
|
.limit(1);
|
|
80
76
|
return result[0] || null;
|
|
81
77
|
}
|
|
@@ -94,8 +90,7 @@ export async function findProductVariants(productId) {
|
|
|
94
90
|
*/
|
|
95
91
|
export async function countProducts(options = {}) {
|
|
96
92
|
const db = getDb();
|
|
97
|
-
const
|
|
98
|
-
const conditions = [eq(schema.products.tenantId, tenantId)];
|
|
93
|
+
const conditions = [];
|
|
99
94
|
if (options.categoryId) {
|
|
100
95
|
conditions.push(eq(schema.products.categoryId, options.categoryId));
|
|
101
96
|
}
|
|
@@ -108,22 +103,20 @@ export async function countProducts(options = {}) {
|
|
|
108
103
|
const result = await db
|
|
109
104
|
.select({ count: sql `count(*)` })
|
|
110
105
|
.from(schema.products)
|
|
111
|
-
.where(and(...conditions));
|
|
106
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined);
|
|
112
107
|
return Number(result[0]?.count || 0);
|
|
113
108
|
}
|
|
114
109
|
// =============================================================================
|
|
115
110
|
// Categories
|
|
116
111
|
// =============================================================================
|
|
117
112
|
/**
|
|
118
|
-
* Find all categories
|
|
113
|
+
* Find all categories
|
|
119
114
|
*/
|
|
120
115
|
export async function findCategories() {
|
|
121
116
|
const db = getDb();
|
|
122
|
-
const tenantId = getTenantId();
|
|
123
117
|
return db
|
|
124
118
|
.select()
|
|
125
119
|
.from(schema.categories)
|
|
126
|
-
.where(eq(schema.categories.tenantId, tenantId))
|
|
127
120
|
.orderBy(asc(schema.categories.order), asc(schema.categories.name));
|
|
128
121
|
}
|
|
129
122
|
/**
|
|
@@ -131,11 +124,10 @@ export async function findCategories() {
|
|
|
131
124
|
*/
|
|
132
125
|
export async function findCategoryBySlug(slug) {
|
|
133
126
|
const db = getDb();
|
|
134
|
-
const tenantId = getTenantId();
|
|
135
127
|
const result = await db
|
|
136
128
|
.select()
|
|
137
129
|
.from(schema.categories)
|
|
138
|
-
.where(
|
|
130
|
+
.where(eq(schema.categories.slug, slug))
|
|
139
131
|
.limit(1);
|
|
140
132
|
return result[0] || null;
|
|
141
133
|
}
|
|
@@ -144,8 +136,7 @@ export async function findCategoryBySlug(slug) {
|
|
|
144
136
|
*/
|
|
145
137
|
export async function findOrders(options = {}) {
|
|
146
138
|
const db = getDb();
|
|
147
|
-
const
|
|
148
|
-
const conditions = [eq(schema.orders.tenantId, tenantId)];
|
|
139
|
+
const conditions = [];
|
|
149
140
|
if (options.status) {
|
|
150
141
|
conditions.push(eq(schema.orders.status, options.status));
|
|
151
142
|
}
|
|
@@ -155,7 +146,7 @@ export async function findOrders(options = {}) {
|
|
|
155
146
|
const query = db
|
|
156
147
|
.select()
|
|
157
148
|
.from(schema.orders)
|
|
158
|
-
.where(and(...conditions))
|
|
149
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
|
159
150
|
.orderBy(desc(schema.orders.createdAt));
|
|
160
151
|
if (options.limit) {
|
|
161
152
|
query.limit(options.limit);
|
|
@@ -170,11 +161,10 @@ export async function findOrders(options = {}) {
|
|
|
170
161
|
*/
|
|
171
162
|
export async function findOrderById(id) {
|
|
172
163
|
const db = getDb();
|
|
173
|
-
const tenantId = getTenantId();
|
|
174
164
|
const order = await db
|
|
175
165
|
.select()
|
|
176
166
|
.from(schema.orders)
|
|
177
|
-
.where(
|
|
167
|
+
.where(eq(schema.orders.id, id))
|
|
178
168
|
.limit(1);
|
|
179
169
|
if (!order[0])
|
|
180
170
|
return null;
|
|
@@ -205,11 +195,10 @@ export async function findOrderItems(orderId) {
|
|
|
205
195
|
*/
|
|
206
196
|
export async function findCustomerByEmail(email) {
|
|
207
197
|
const db = getDb();
|
|
208
|
-
const tenantId = getTenantId();
|
|
209
198
|
const result = await db
|
|
210
199
|
.select()
|
|
211
200
|
.from(schema.customers)
|
|
212
|
-
.where(
|
|
201
|
+
.where(eq(schema.customers.email, email.toLowerCase()))
|
|
213
202
|
.limit(1);
|
|
214
203
|
return result[0] || null;
|
|
215
204
|
}
|
|
@@ -218,11 +207,10 @@ export async function findCustomerByEmail(email) {
|
|
|
218
207
|
*/
|
|
219
208
|
export async function findCustomerById(id) {
|
|
220
209
|
const db = getDb();
|
|
221
|
-
const tenantId = getTenantId();
|
|
222
210
|
const result = await db
|
|
223
211
|
.select()
|
|
224
212
|
.from(schema.customers)
|
|
225
|
-
.where(
|
|
213
|
+
.where(eq(schema.customers.id, id))
|
|
226
214
|
.limit(1);
|
|
227
215
|
return result[0] || null;
|
|
228
216
|
}
|
|
@@ -231,15 +219,14 @@ export async function findCustomerById(id) {
|
|
|
231
219
|
*/
|
|
232
220
|
export async function findCustomers(options = {}) {
|
|
233
221
|
const db = getDb();
|
|
234
|
-
const
|
|
235
|
-
const conditions = [eq(schema.customers.tenantId, tenantId)];
|
|
222
|
+
const conditions = [];
|
|
236
223
|
if (options.search) {
|
|
237
224
|
conditions.push(ilike(schema.customers.email, `%${options.search}%`));
|
|
238
225
|
}
|
|
239
226
|
const query = db
|
|
240
227
|
.select()
|
|
241
228
|
.from(schema.customers)
|
|
242
|
-
.where(and(...conditions))
|
|
229
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
|
243
230
|
.orderBy(desc(schema.customers.createdAt));
|
|
244
231
|
if (options.limit) {
|
|
245
232
|
query.limit(options.limit);
|
|
@@ -257,11 +244,10 @@ export async function findCustomers(options = {}) {
|
|
|
257
244
|
*/
|
|
258
245
|
export async function findAdminByEmail(email) {
|
|
259
246
|
const db = getDb();
|
|
260
|
-
const tenantId = getTenantId();
|
|
261
247
|
const result = await db
|
|
262
248
|
.select()
|
|
263
249
|
.from(schema.storeAdmins)
|
|
264
|
-
.where(
|
|
250
|
+
.where(eq(schema.storeAdmins.email, email.toLowerCase()))
|
|
265
251
|
.limit(1);
|
|
266
252
|
return result[0] || null;
|
|
267
253
|
}
|
|
@@ -273,28 +259,25 @@ export async function findAdminByEmail(email) {
|
|
|
273
259
|
*/
|
|
274
260
|
export async function getStoreStats() {
|
|
275
261
|
const db = getDb();
|
|
276
|
-
const tenantId = getTenantId();
|
|
277
262
|
const [productCount, orderCount, customerCount, revenue] = await Promise.all([
|
|
278
263
|
// Total products
|
|
279
264
|
db
|
|
280
265
|
.select({ count: sql `count(*)` })
|
|
281
266
|
.from(schema.products)
|
|
282
|
-
.where(
|
|
267
|
+
.where(eq(schema.products.status, 'active')),
|
|
283
268
|
// Total orders
|
|
284
269
|
db
|
|
285
270
|
.select({ count: sql `count(*)` })
|
|
286
|
-
.from(schema.orders)
|
|
287
|
-
.where(eq(schema.orders.tenantId, tenantId)),
|
|
271
|
+
.from(schema.orders),
|
|
288
272
|
// Total customers
|
|
289
273
|
db
|
|
290
274
|
.select({ count: sql `count(*)` })
|
|
291
|
-
.from(schema.customers)
|
|
292
|
-
.where(eq(schema.customers.tenantId, tenantId)),
|
|
275
|
+
.from(schema.customers),
|
|
293
276
|
// Total revenue (paid orders only)
|
|
294
277
|
db
|
|
295
278
|
.select({ total: sql `COALESCE(SUM(total), 0)` })
|
|
296
279
|
.from(schema.orders)
|
|
297
|
-
.where(
|
|
280
|
+
.where(inArray(schema.orders.status, ['paid', 'shipped', 'delivered'])),
|
|
298
281
|
]);
|
|
299
282
|
return {
|
|
300
283
|
products: Number(productCount[0]?.count || 0),
|
|
@@ -308,7 +291,6 @@ export async function getStoreStats() {
|
|
|
308
291
|
*/
|
|
309
292
|
export async function getLowStockProducts(threshold = 10) {
|
|
310
293
|
const db = getDb();
|
|
311
|
-
const tenantId = getTenantId();
|
|
312
294
|
// Get products with variants that have low stock
|
|
313
295
|
const lowStockVariants = await db
|
|
314
296
|
.select({
|
|
@@ -317,7 +299,7 @@ export async function getLowStockProducts(threshold = 10) {
|
|
|
317
299
|
})
|
|
318
300
|
.from(schema.productVariants)
|
|
319
301
|
.innerJoin(schema.products, eq(schema.productVariants.productId, schema.products.id))
|
|
320
|
-
.where(and(eq(schema.products.
|
|
302
|
+
.where(and(eq(schema.products.status, 'active'), sql `${schema.productVariants.inventory} < ${threshold}`))
|
|
321
303
|
.orderBy(asc(schema.productVariants.inventory));
|
|
322
304
|
return lowStockVariants;
|
|
323
305
|
}
|
|
@@ -326,11 +308,9 @@ export async function getLowStockProducts(threshold = 10) {
|
|
|
326
308
|
*/
|
|
327
309
|
export async function getRecentOrders(limit = 5) {
|
|
328
310
|
const db = getDb();
|
|
329
|
-
const tenantId = getTenantId();
|
|
330
311
|
return db
|
|
331
312
|
.select()
|
|
332
313
|
.from(schema.orders)
|
|
333
|
-
.where(eq(schema.orders.tenantId, tenantId))
|
|
334
314
|
.orderBy(desc(schema.orders.createdAt))
|
|
335
315
|
.limit(limit);
|
|
336
316
|
}
|
|
@@ -342,10 +322,9 @@ export async function getRecentOrders(limit = 5) {
|
|
|
342
322
|
*/
|
|
343
323
|
export async function createOrder(data) {
|
|
344
324
|
const db = getDb();
|
|
345
|
-
const tenantId = getTenantId();
|
|
346
325
|
const [order] = await db
|
|
347
326
|
.insert(schema.orders)
|
|
348
|
-
.values(
|
|
327
|
+
.values(data)
|
|
349
328
|
.returning();
|
|
350
329
|
return order;
|
|
351
330
|
}
|
|
@@ -364,11 +343,10 @@ export async function createOrderItems(items) {
|
|
|
364
343
|
*/
|
|
365
344
|
export async function updateOrderStatus(orderId, status) {
|
|
366
345
|
const db = getDb();
|
|
367
|
-
const tenantId = getTenantId();
|
|
368
346
|
const [order] = await db
|
|
369
347
|
.update(schema.orders)
|
|
370
348
|
.set({ status, updatedAt: new Date() })
|
|
371
|
-
.where(
|
|
349
|
+
.where(eq(schema.orders.id, orderId))
|
|
372
350
|
.returning();
|
|
373
351
|
return order || null;
|
|
374
352
|
}
|
|
@@ -378,11 +356,10 @@ export async function updateOrderStatus(orderId, status) {
|
|
|
378
356
|
*/
|
|
379
357
|
export async function findOrderByPaymentIntent(paymentIntentId) {
|
|
380
358
|
const db = getDb();
|
|
381
|
-
const tenantId = getTenantId();
|
|
382
359
|
const [order] = await db
|
|
383
360
|
.select()
|
|
384
361
|
.from(schema.orders)
|
|
385
|
-
.where(
|
|
362
|
+
.where(eq(schema.orders.stripePaymentIntentId, paymentIntentId))
|
|
386
363
|
.limit(1);
|
|
387
364
|
return order || null;
|
|
388
365
|
}
|
|
@@ -394,10 +371,9 @@ export async function findOrderByPaymentIntent(paymentIntentId) {
|
|
|
394
371
|
*/
|
|
395
372
|
export async function createProduct(data) {
|
|
396
373
|
const db = getDb();
|
|
397
|
-
const tenantId = getTenantId();
|
|
398
374
|
const [product] = await db
|
|
399
375
|
.insert(schema.products)
|
|
400
|
-
.values(
|
|
376
|
+
.values(data)
|
|
401
377
|
.returning();
|
|
402
378
|
return product;
|
|
403
379
|
}
|
|
@@ -406,11 +382,10 @@ export async function createProduct(data) {
|
|
|
406
382
|
*/
|
|
407
383
|
export async function updateProduct(id, data) {
|
|
408
384
|
const db = getDb();
|
|
409
|
-
const tenantId = getTenantId();
|
|
410
385
|
const [product] = await db
|
|
411
386
|
.update(schema.products)
|
|
412
387
|
.set({ ...data, updatedAt: new Date() })
|
|
413
|
-
.where(
|
|
388
|
+
.where(eq(schema.products.id, id))
|
|
414
389
|
.returning();
|
|
415
390
|
return product || null;
|
|
416
391
|
}
|
|
@@ -430,10 +405,9 @@ export async function deleteProduct(id) {
|
|
|
430
405
|
*/
|
|
431
406
|
export async function hardDeleteProduct(id) {
|
|
432
407
|
const db = getDb();
|
|
433
|
-
const tenantId = getTenantId();
|
|
434
408
|
const result = await db
|
|
435
409
|
.delete(schema.products)
|
|
436
|
-
.where(
|
|
410
|
+
.where(eq(schema.products.id, id))
|
|
437
411
|
.returning({ id: schema.products.id });
|
|
438
412
|
return result.length > 0;
|
|
439
413
|
}
|
|
@@ -504,11 +478,10 @@ export async function findVariantById(id) {
|
|
|
504
478
|
*/
|
|
505
479
|
export async function findCategoryById(id) {
|
|
506
480
|
const db = getDb();
|
|
507
|
-
const tenantId = getTenantId();
|
|
508
481
|
const [category] = await db
|
|
509
482
|
.select()
|
|
510
483
|
.from(schema.categories)
|
|
511
|
-
.where(
|
|
484
|
+
.where(eq(schema.categories.id, id))
|
|
512
485
|
.limit(1);
|
|
513
486
|
return category || null;
|
|
514
487
|
}
|
|
@@ -517,10 +490,9 @@ export async function findCategoryById(id) {
|
|
|
517
490
|
*/
|
|
518
491
|
export async function createCategory(data) {
|
|
519
492
|
const db = getDb();
|
|
520
|
-
const tenantId = getTenantId();
|
|
521
493
|
const [category] = await db
|
|
522
494
|
.insert(schema.categories)
|
|
523
|
-
.values(
|
|
495
|
+
.values(data)
|
|
524
496
|
.returning();
|
|
525
497
|
return category;
|
|
526
498
|
}
|
|
@@ -529,11 +501,10 @@ export async function createCategory(data) {
|
|
|
529
501
|
*/
|
|
530
502
|
export async function updateCategory(id, data) {
|
|
531
503
|
const db = getDb();
|
|
532
|
-
const tenantId = getTenantId();
|
|
533
504
|
const [category] = await db
|
|
534
505
|
.update(schema.categories)
|
|
535
506
|
.set(data)
|
|
536
|
-
.where(
|
|
507
|
+
.where(eq(schema.categories.id, id))
|
|
537
508
|
.returning();
|
|
538
509
|
return category || null;
|
|
539
510
|
}
|
|
@@ -542,42 +513,38 @@ export async function updateCategory(id, data) {
|
|
|
542
513
|
*/
|
|
543
514
|
export async function deleteCategory(id) {
|
|
544
515
|
const db = getDb();
|
|
545
|
-
const tenantId = getTenantId();
|
|
546
516
|
const result = await db
|
|
547
517
|
.delete(schema.categories)
|
|
548
|
-
.where(
|
|
518
|
+
.where(eq(schema.categories.id, id))
|
|
549
519
|
.returning({ id: schema.categories.id });
|
|
550
520
|
return result.length > 0;
|
|
551
521
|
}
|
|
552
522
|
/**
|
|
553
|
-
* Count categories
|
|
523
|
+
* Count categories
|
|
554
524
|
*/
|
|
555
525
|
export async function countCategories() {
|
|
556
526
|
const db = getDb();
|
|
557
|
-
const tenantId = getTenantId();
|
|
558
527
|
const result = await db
|
|
559
528
|
.select({ count: sql `count(*)` })
|
|
560
|
-
.from(schema.categories)
|
|
561
|
-
.where(eq(schema.categories.tenantId, tenantId));
|
|
529
|
+
.from(schema.categories);
|
|
562
530
|
return Number(result[0]?.count || 0);
|
|
563
531
|
}
|
|
564
532
|
// =============================================================================
|
|
565
533
|
// Customer Queries (for admin module)
|
|
566
534
|
// =============================================================================
|
|
567
535
|
/**
|
|
568
|
-
* Count customers
|
|
536
|
+
* Count customers with optional search
|
|
569
537
|
*/
|
|
570
538
|
export async function countCustomers(options = {}) {
|
|
571
539
|
const db = getDb();
|
|
572
|
-
const
|
|
573
|
-
const conditions = [eq(schema.customers.tenantId, tenantId)];
|
|
540
|
+
const conditions = [];
|
|
574
541
|
if (options.search) {
|
|
575
542
|
conditions.push(ilike(schema.customers.email, `%${options.search}%`));
|
|
576
543
|
}
|
|
577
544
|
const result = await db
|
|
578
545
|
.select({ count: sql `count(*)` })
|
|
579
546
|
.from(schema.customers)
|
|
580
|
-
.where(and(...conditions));
|
|
547
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined);
|
|
581
548
|
return Number(result[0]?.count || 0);
|
|
582
549
|
}
|
|
583
550
|
/**
|
|
@@ -585,11 +552,10 @@ export async function countCustomers(options = {}) {
|
|
|
585
552
|
*/
|
|
586
553
|
export async function findCustomerOrders(customerId) {
|
|
587
554
|
const db = getDb();
|
|
588
|
-
const tenantId = getTenantId();
|
|
589
555
|
return db
|
|
590
556
|
.select()
|
|
591
557
|
.from(schema.orders)
|
|
592
|
-
.where(
|
|
558
|
+
.where(eq(schema.orders.customerId, customerId))
|
|
593
559
|
.orderBy(desc(schema.orders.createdAt));
|
|
594
560
|
}
|
|
595
561
|
/**
|
|
@@ -609,7 +575,6 @@ export async function findCustomerOrders(customerId) {
|
|
|
609
575
|
*/
|
|
610
576
|
export async function deleteCustomer(id) {
|
|
611
577
|
const db = getDb();
|
|
612
|
-
const tenantId = getTenantId();
|
|
613
578
|
// Anonymize customer data instead of hard delete
|
|
614
579
|
const result = await db
|
|
615
580
|
.update(schema.customers)
|
|
@@ -620,7 +585,7 @@ export async function deleteCustomer(id) {
|
|
|
620
585
|
emailVerified: null,
|
|
621
586
|
stripeCustomerId: null,
|
|
622
587
|
})
|
|
623
|
-
.where(
|
|
588
|
+
.where(eq(schema.customers.id, id))
|
|
624
589
|
.returning({ id: schema.customers.id });
|
|
625
590
|
return result.length > 0;
|
|
626
591
|
}
|
|
@@ -632,15 +597,14 @@ export async function deleteCustomer(id) {
|
|
|
632
597
|
*/
|
|
633
598
|
export async function countOrders(options = {}) {
|
|
634
599
|
const db = getDb();
|
|
635
|
-
const
|
|
636
|
-
const conditions = [eq(schema.orders.tenantId, tenantId)];
|
|
600
|
+
const conditions = [];
|
|
637
601
|
if (options.status) {
|
|
638
602
|
conditions.push(eq(schema.orders.status, options.status));
|
|
639
603
|
}
|
|
640
604
|
const result = await db
|
|
641
605
|
.select({ count: sql `count(*)` })
|
|
642
606
|
.from(schema.orders)
|
|
643
|
-
.where(and(...conditions));
|
|
607
|
+
.where(conditions.length > 0 ? and(...conditions) : undefined);
|
|
644
608
|
return Number(result[0]?.count || 0);
|
|
645
609
|
}
|
|
646
610
|
/**
|
|
@@ -648,7 +612,6 @@ export async function countOrders(options = {}) {
|
|
|
648
612
|
*/
|
|
649
613
|
export async function getRevenueByPeriod(days) {
|
|
650
614
|
const db = getDb();
|
|
651
|
-
const tenantId = getTenantId();
|
|
652
615
|
const startDate = new Date();
|
|
653
616
|
startDate.setDate(startDate.getDate() - days);
|
|
654
617
|
const result = await db
|
|
@@ -657,7 +620,7 @@ export async function getRevenueByPeriod(days) {
|
|
|
657
620
|
revenue: sql `COALESCE(SUM(${schema.orders.total}), 0)`,
|
|
658
621
|
})
|
|
659
622
|
.from(schema.orders)
|
|
660
|
-
.where(and(
|
|
623
|
+
.where(and(inArray(schema.orders.status, ['paid', 'shipped', 'delivered']), sql `${schema.orders.createdAt} >= ${startDate.toISOString()}`))
|
|
661
624
|
.groupBy(sql `DATE(${schema.orders.createdAt})`)
|
|
662
625
|
.orderBy(sql `DATE(${schema.orders.createdAt})`);
|
|
663
626
|
return result.map((r) => ({
|
|
@@ -670,14 +633,12 @@ export async function getRevenueByPeriod(days) {
|
|
|
670
633
|
*/
|
|
671
634
|
export async function getOrdersByStatus() {
|
|
672
635
|
const db = getDb();
|
|
673
|
-
const tenantId = getTenantId();
|
|
674
636
|
const result = await db
|
|
675
637
|
.select({
|
|
676
638
|
status: schema.orders.status,
|
|
677
639
|
count: sql `count(*)`,
|
|
678
640
|
})
|
|
679
641
|
.from(schema.orders)
|
|
680
|
-
.where(eq(schema.orders.tenantId, tenantId))
|
|
681
642
|
.groupBy(schema.orders.status);
|
|
682
643
|
return result.map((r) => ({
|
|
683
644
|
status: r.status,
|
|
@@ -685,16 +646,15 @@ export async function getOrdersByStatus() {
|
|
|
685
646
|
}));
|
|
686
647
|
}
|
|
687
648
|
/**
|
|
688
|
-
* Find store settings
|
|
649
|
+
* Find store settings.
|
|
689
650
|
* Returns null if no settings exist (first time access).
|
|
651
|
+
* Each store has only one settings row.
|
|
690
652
|
*/
|
|
691
653
|
export async function findSettings() {
|
|
692
654
|
const db = getDb();
|
|
693
|
-
const tenantId = getTenantId();
|
|
694
655
|
const [settings] = await db
|
|
695
656
|
.select()
|
|
696
657
|
.from(schema.storeSettings)
|
|
697
|
-
.where(eq(schema.storeSettings.tenantId, tenantId))
|
|
698
658
|
.limit(1);
|
|
699
659
|
if (!settings)
|
|
700
660
|
return null;
|
|
@@ -712,15 +672,17 @@ export async function findSettings() {
|
|
|
712
672
|
};
|
|
713
673
|
}
|
|
714
674
|
/**
|
|
715
|
-
* Upsert (create or update) store settings
|
|
716
|
-
*
|
|
675
|
+
* Upsert (create or update) store settings.
|
|
676
|
+
* Each store has only one settings row.
|
|
717
677
|
*/
|
|
718
678
|
export async function upsertSettings(data) {
|
|
719
679
|
const db = getDb();
|
|
720
|
-
|
|
721
|
-
|
|
680
|
+
// Check if settings exist
|
|
681
|
+
const existing = await db
|
|
682
|
+
.select({ id: schema.storeSettings.id })
|
|
683
|
+
.from(schema.storeSettings)
|
|
684
|
+
.limit(1);
|
|
722
685
|
const values = {
|
|
723
|
-
tenantId,
|
|
724
686
|
storeName: data.storeName ?? undefined,
|
|
725
687
|
storeEmail: data.storeEmail ?? undefined,
|
|
726
688
|
storeCurrency: data.storeCurrency ?? undefined,
|
|
@@ -735,25 +697,22 @@ export async function upsertSettings(data) {
|
|
|
735
697
|
: undefined,
|
|
736
698
|
updatedAt: new Date(),
|
|
737
699
|
};
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
},
|
|
755
|
-
})
|
|
756
|
-
.returning();
|
|
700
|
+
let result;
|
|
701
|
+
if (existing.length > 0) {
|
|
702
|
+
// Update existing
|
|
703
|
+
[result] = await db
|
|
704
|
+
.update(schema.storeSettings)
|
|
705
|
+
.set(values)
|
|
706
|
+
.where(eq(schema.storeSettings.id, existing[0].id))
|
|
707
|
+
.returning();
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
// Insert new
|
|
711
|
+
[result] = await db
|
|
712
|
+
.insert(schema.storeSettings)
|
|
713
|
+
.values(values)
|
|
714
|
+
.returning();
|
|
715
|
+
}
|
|
757
716
|
return {
|
|
758
717
|
storeName: result.storeName,
|
|
759
718
|
storeEmail: result.storeEmail,
|