@rovela-ai/sdk 0.5.17 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/admin/api/customer-groups.d.ts +61 -0
  2. package/dist/admin/api/customer-groups.d.ts.map +1 -0
  3. package/dist/admin/api/customer-groups.js +147 -0
  4. package/dist/admin/api/customer-groups.js.map +1 -0
  5. package/dist/admin/api/customers.d.ts.map +1 -1
  6. package/dist/admin/api/customers.js +28 -9
  7. package/dist/admin/api/customers.js.map +1 -1
  8. package/dist/admin/api/index.d.ts +2 -0
  9. package/dist/admin/api/index.d.ts.map +1 -1
  10. package/dist/admin/api/index.js +4 -0
  11. package/dist/admin/api/index.js.map +1 -1
  12. package/dist/admin/api/payment-methods.d.ts +56 -0
  13. package/dist/admin/api/payment-methods.d.ts.map +1 -0
  14. package/dist/admin/api/payment-methods.js +150 -0
  15. package/dist/admin/api/payment-methods.js.map +1 -0
  16. package/dist/admin/components/CustomerDetails.d.ts.map +1 -1
  17. package/dist/admin/components/CustomerDetails.js +9 -3
  18. package/dist/admin/components/CustomerDetails.js.map +1 -1
  19. package/dist/admin/components/CustomerGroupsManager.d.ts +7 -0
  20. package/dist/admin/components/CustomerGroupsManager.d.ts.map +1 -0
  21. package/dist/admin/components/CustomerGroupsManager.js +86 -0
  22. package/dist/admin/components/CustomerGroupsManager.js.map +1 -0
  23. package/dist/admin/components/CustomerTable.d.ts.map +1 -1
  24. package/dist/admin/components/CustomerTable.js +21 -8
  25. package/dist/admin/components/CustomerTable.js.map +1 -1
  26. package/dist/admin/components/OrderDetails.d.ts.map +1 -1
  27. package/dist/admin/components/OrderDetails.js +7 -2
  28. package/dist/admin/components/OrderDetails.js.map +1 -1
  29. package/dist/admin/components/PaymentMethodsManager.d.ts +5 -0
  30. package/dist/admin/components/PaymentMethodsManager.d.ts.map +1 -0
  31. package/dist/admin/components/PaymentMethodsManager.js +92 -0
  32. package/dist/admin/components/PaymentMethodsManager.js.map +1 -0
  33. package/dist/admin/components/PaymentSettings.d.ts.map +1 -1
  34. package/dist/admin/components/PaymentSettings.js +2 -1
  35. package/dist/admin/components/PaymentSettings.js.map +1 -1
  36. package/dist/admin/components/index.d.ts +4 -0
  37. package/dist/admin/components/index.d.ts.map +1 -1
  38. package/dist/admin/components/index.js +2 -0
  39. package/dist/admin/components/index.js.map +1 -1
  40. package/dist/admin/hooks/index.d.ts +4 -0
  41. package/dist/admin/hooks/index.d.ts.map +1 -1
  42. package/dist/admin/hooks/index.js +2 -0
  43. package/dist/admin/hooks/index.js.map +1 -1
  44. package/dist/admin/hooks/useAdminCustomerGroups.d.ts +12 -0
  45. package/dist/admin/hooks/useAdminCustomerGroups.d.ts.map +1 -0
  46. package/dist/admin/hooks/useAdminCustomerGroups.js +79 -0
  47. package/dist/admin/hooks/useAdminCustomerGroups.js.map +1 -0
  48. package/dist/admin/hooks/useAdminCustomers.d.ts.map +1 -1
  49. package/dist/admin/hooks/useAdminCustomers.js +5 -1
  50. package/dist/admin/hooks/useAdminCustomers.js.map +1 -1
  51. package/dist/admin/hooks/useAdminPaymentMethods.d.ts +12 -0
  52. package/dist/admin/hooks/useAdminPaymentMethods.d.ts.map +1 -0
  53. package/dist/admin/hooks/useAdminPaymentMethods.js +78 -0
  54. package/dist/admin/hooks/useAdminPaymentMethods.js.map +1 -0
  55. package/dist/admin/index.d.ts +3 -3
  56. package/dist/admin/index.d.ts.map +1 -1
  57. package/dist/admin/index.js +3 -3
  58. package/dist/admin/index.js.map +1 -1
  59. package/dist/admin/types.d.ts +53 -0
  60. package/dist/admin/types.d.ts.map +1 -1
  61. package/dist/auth/server/customer-service.d.ts.map +1 -1
  62. package/dist/auth/server/customer-service.js +7 -1
  63. package/dist/auth/server/customer-service.js.map +1 -1
  64. package/dist/checkout/api/index.d.ts +2 -0
  65. package/dist/checkout/api/index.d.ts.map +1 -1
  66. package/dist/checkout/api/index.js +2 -0
  67. package/dist/checkout/api/index.js.map +1 -1
  68. package/dist/checkout/api/manual.d.ts +36 -0
  69. package/dist/checkout/api/manual.d.ts.map +1 -0
  70. package/dist/checkout/api/manual.js +289 -0
  71. package/dist/checkout/api/manual.js.map +1 -0
  72. package/dist/checkout/api/payment-methods.d.ts +25 -0
  73. package/dist/checkout/api/payment-methods.d.ts.map +1 -0
  74. package/dist/checkout/api/payment-methods.js +36 -0
  75. package/dist/checkout/api/payment-methods.js.map +1 -0
  76. package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
  77. package/dist/checkout/components/CheckoutFlow.js +33 -4
  78. package/dist/checkout/components/CheckoutFlow.js.map +1 -1
  79. package/dist/checkout/hooks/useCheckout.d.ts.map +1 -1
  80. package/dist/checkout/hooks/useCheckout.js +76 -0
  81. package/dist/checkout/hooks/useCheckout.js.map +1 -1
  82. package/dist/checkout/server/order-service.d.ts.map +1 -1
  83. package/dist/checkout/server/order-service.js +17 -7
  84. package/dist/checkout/server/order-service.js.map +1 -1
  85. package/dist/checkout/types.d.ts +24 -2
  86. package/dist/checkout/types.d.ts.map +1 -1
  87. package/dist/core/db/index.d.ts +3 -3
  88. package/dist/core/db/index.d.ts.map +1 -1
  89. package/dist/core/db/index.js +4 -0
  90. package/dist/core/db/index.js.map +1 -1
  91. package/dist/core/db/queries.d.ts +194 -10
  92. package/dist/core/db/queries.d.ts.map +1 -1
  93. package/dist/core/db/queries.js +300 -2
  94. package/dist/core/db/queries.js.map +1 -1
  95. package/dist/core/db/schema.d.ts +376 -0
  96. package/dist/core/db/schema.d.ts.map +1 -1
  97. package/dist/core/db/schema.js +70 -1
  98. package/dist/core/db/schema.js.map +1 -1
  99. package/dist/core/server/index.d.ts +2 -2
  100. package/dist/core/server/index.d.ts.map +1 -1
  101. package/dist/core/server/index.js +4 -0
  102. package/dist/core/server/index.js.map +1 -1
  103. package/dist/emails/send/orders.d.ts +2 -0
  104. package/dist/emails/send/orders.d.ts.map +1 -1
  105. package/dist/emails/send/orders.js +1 -0
  106. package/dist/emails/send/orders.js.map +1 -1
  107. package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
  108. package/dist/emails/templates/order-confirmation.js +9 -0
  109. package/dist/emails/templates/order-confirmation.js.map +1 -1
  110. package/dist/emails/types.d.ts +2 -0
  111. package/dist/emails/types.d.ts.map +1 -1
  112. package/package.json +9 -1
@@ -387,6 +387,8 @@ export async function findCategoryBySlug(slug) {
387
387
  * Find orders with filtering and pagination
388
388
  */
389
389
  export async function findOrders(options = {}) {
390
+ // orders SELECT enumerates the payment columns — self-heal older stores first.
391
+ await ensurePaymentMethodsSchemaSafe();
390
392
  const db = getDb();
391
393
  const conditions = [];
392
394
  if (options.status) {
@@ -412,6 +414,8 @@ export async function findOrders(options = {}) {
412
414
  * Find order by ID with items (includes product images)
413
415
  */
414
416
  export async function findOrderById(id) {
417
+ // orders SELECT enumerates the payment columns — self-heal older stores first.
418
+ await ensurePaymentMethodsSchemaSafe();
415
419
  const db = getDb();
416
420
  const order = await db
417
421
  .select()
@@ -520,6 +524,8 @@ export async function findOrCreateGuestCustomer(email, name) {
520
524
  * Find customer by email
521
525
  */
522
526
  export async function findCustomerByEmail(email) {
527
+ // SELECT enumerates customers.group_id — self-heal older stores first.
528
+ await ensureCustomerGroupsSchemaSafe();
523
529
  const db = getDb();
524
530
  const result = await db
525
531
  .select()
@@ -532,6 +538,8 @@ export async function findCustomerByEmail(email) {
532
538
  * Find customer by ID
533
539
  */
534
540
  export async function findCustomerById(id) {
541
+ // SELECT enumerates customers.group_id — self-heal older stores first.
542
+ await ensureCustomerGroupsSchemaSafe();
535
543
  const db = getDb();
536
544
  const result = await db
537
545
  .select()
@@ -544,10 +552,15 @@ export async function findCustomerById(id) {
544
552
  * Find all customers with pagination
545
553
  */
546
554
  export async function findCustomers(options = {}) {
555
+ // SELECT enumerates customers.group_id — self-heal older stores first.
556
+ await ensureCustomerGroupsSchemaSafe();
547
557
  const db = getDb();
548
558
  const conditions = [];
549
559
  if (options.search) {
550
- conditions.push(ilike(schema.customers.email, `%${options.search}%`));
560
+ conditions.push(or(ilike(schema.customers.email, `%${options.search}%`), ilike(schema.customers.name, `%${options.search}%`)));
561
+ }
562
+ if (options.groupId) {
563
+ conditions.push(eq(schema.customers.groupId, options.groupId));
551
564
  }
552
565
  const query = db
553
566
  .select()
@@ -857,6 +870,8 @@ export async function getRecentOrders(limit = 5, periodDays) {
857
870
  * Create a new order
858
871
  */
859
872
  export async function createOrder(data) {
873
+ // orders SELECT enumerates the payment columns — self-heal older stores first.
874
+ await ensurePaymentMethodsSchemaSafe();
860
875
  const db = getDb();
861
876
  const [order] = await db
862
877
  .insert(schema.orders)
@@ -906,6 +921,8 @@ export async function updateOrderShipping(orderId, shippingData) {
906
921
  * Used for idempotency in webhook handling
907
922
  */
908
923
  export async function findOrderByPaymentIntent(paymentIntentId) {
924
+ // orders SELECT enumerates the payment columns — self-heal older stores first.
925
+ await ensurePaymentMethodsSchemaSafe();
909
926
  const db = getDb();
910
927
  const [order] = await db
911
928
  .select()
@@ -1153,10 +1170,14 @@ export async function countCategories() {
1153
1170
  * Count customers with optional search
1154
1171
  */
1155
1172
  export async function countCustomers(options = {}) {
1173
+ await ensureCustomerGroupsSchemaSafe();
1156
1174
  const db = getDb();
1157
1175
  const conditions = [];
1158
1176
  if (options.search) {
1159
- conditions.push(ilike(schema.customers.email, `%${options.search}%`));
1177
+ conditions.push(or(ilike(schema.customers.email, `%${options.search}%`), ilike(schema.customers.name, `%${options.search}%`)));
1178
+ }
1179
+ if (options.groupId) {
1180
+ conditions.push(eq(schema.customers.groupId, options.groupId));
1160
1181
  }
1161
1182
  const result = await db
1162
1183
  .select({ count: sql `count(*)` })
@@ -1168,6 +1189,8 @@ export async function countCustomers(options = {}) {
1168
1189
  * Find orders for a specific customer
1169
1190
  */
1170
1191
  export async function findCustomerOrders(customerId) {
1192
+ // orders SELECT enumerates the payment columns — self-heal older stores first.
1193
+ await ensurePaymentMethodsSchemaSafe();
1171
1194
  const db = getDb();
1172
1195
  return db
1173
1196
  .select()
@@ -1445,6 +1468,281 @@ export async function setDefaultCustomerAddress(id, customerId, kind) {
1445
1468
  return true;
1446
1469
  }
1447
1470
  // =============================================================================
1471
+ // Customer Groups (merchant-defined customer types)
1472
+ // =============================================================================
1473
+ let customerGroupsSchemaEnsured = false;
1474
+ /**
1475
+ * Self-heal the customer-groups schema on stores provisioned before this
1476
+ * feature. New stores get it from schema.ts at branch creation. Idempotent +
1477
+ * module-cached (mirrors ensureCustomerAddressSchema). ALSO guards the
1478
+ * `customers.group_id` column that every `customers` SELECT now enumerates —
1479
+ * called (best-effort) from the customer read chokepoints so an SDK upgrade
1480
+ * self-migrates instead of breaking reads.
1481
+ */
1482
+ export async function ensureCustomerGroupsSchema() {
1483
+ if (customerGroupsSchemaEnsured)
1484
+ return;
1485
+ const db = getDb();
1486
+ try {
1487
+ await db.execute(sql `ALTER TABLE customers ADD COLUMN IF NOT EXISTS group_id uuid`);
1488
+ await db.execute(sql `CREATE INDEX IF NOT EXISTS customers_group_id_idx ON customers (group_id)`);
1489
+ await db.execute(sql `
1490
+ CREATE TABLE IF NOT EXISTS customer_groups (
1491
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
1492
+ name varchar(100) NOT NULL,
1493
+ description varchar(255),
1494
+ is_active boolean NOT NULL DEFAULT true,
1495
+ sort_order integer NOT NULL DEFAULT 0,
1496
+ created_at timestamp NOT NULL DEFAULT now(),
1497
+ updated_at timestamp NOT NULL DEFAULT now()
1498
+ )
1499
+ `);
1500
+ await db.execute(sql `CREATE INDEX IF NOT EXISTS customer_groups_sort_order_idx ON customer_groups (sort_order)`);
1501
+ customerGroupsSchemaEnsured = true;
1502
+ }
1503
+ catch (err) {
1504
+ console.error('[ensureCustomerGroupsSchema] migration failed:', err);
1505
+ throw err;
1506
+ }
1507
+ }
1508
+ /** Best-effort variant for hot read paths (login, listings): a transient
1509
+ * ensure failure must not block the read — if the schema truly is missing,
1510
+ * the subsequent SELECT fails with a clear error anyway. Exported for the
1511
+ * customer-service read paths that select customers.* directly. */
1512
+ export async function ensureCustomerGroupsSchemaSafe() {
1513
+ try {
1514
+ await ensureCustomerGroupsSchema();
1515
+ }
1516
+ catch {
1517
+ // logged inside ensureCustomerGroupsSchema
1518
+ }
1519
+ }
1520
+ /** List all groups (sorted), each with its live member count. */
1521
+ export async function findCustomerGroups() {
1522
+ await ensureCustomerGroupsSchema();
1523
+ const db = getDb();
1524
+ return db
1525
+ .select({
1526
+ id: schema.customerGroups.id,
1527
+ name: schema.customerGroups.name,
1528
+ description: schema.customerGroups.description,
1529
+ isActive: schema.customerGroups.isActive,
1530
+ sortOrder: schema.customerGroups.sortOrder,
1531
+ createdAt: schema.customerGroups.createdAt,
1532
+ updatedAt: schema.customerGroups.updatedAt,
1533
+ // Plain identifier (not a drizzle column interpolation): inside a raw
1534
+ // correlated subquery the interpolated form mis-renders and the count
1535
+ // silently returns 0. Outer table is unaliased `customer_groups`.
1536
+ customerCount: sql `(
1537
+ SELECT count(*)::int FROM customers c WHERE c.group_id = customer_groups.id
1538
+ )`,
1539
+ })
1540
+ .from(schema.customerGroups)
1541
+ .orderBy(asc(schema.customerGroups.sortOrder), asc(schema.customerGroups.createdAt));
1542
+ }
1543
+ export async function findCustomerGroupById(id) {
1544
+ await ensureCustomerGroupsSchema();
1545
+ const db = getDb();
1546
+ const rows = await db
1547
+ .select()
1548
+ .from(schema.customerGroups)
1549
+ .where(eq(schema.customerGroups.id, id))
1550
+ .limit(1);
1551
+ return rows[0] ?? null;
1552
+ }
1553
+ export async function createCustomerGroup(data) {
1554
+ await ensureCustomerGroupsSchema();
1555
+ const db = getDb();
1556
+ const [group] = await db
1557
+ .insert(schema.customerGroups)
1558
+ .values({
1559
+ name: data.name,
1560
+ description: data.description ?? null,
1561
+ isActive: data.isActive ?? true,
1562
+ sortOrder: data.sortOrder ?? 0,
1563
+ })
1564
+ .returning();
1565
+ return group;
1566
+ }
1567
+ export async function updateCustomerGroup(id, data) {
1568
+ await ensureCustomerGroupsSchema();
1569
+ const db = getDb();
1570
+ const set = { updatedAt: new Date() };
1571
+ if (data.name !== undefined)
1572
+ set.name = data.name;
1573
+ if (data.description !== undefined)
1574
+ set.description = data.description ?? null;
1575
+ if (data.isActive !== undefined)
1576
+ set.isActive = data.isActive;
1577
+ if (data.sortOrder !== undefined)
1578
+ set.sortOrder = data.sortOrder;
1579
+ const [group] = await db
1580
+ .update(schema.customerGroups)
1581
+ .set(set)
1582
+ .where(eq(schema.customerGroups.id, id))
1583
+ .returning();
1584
+ return group ?? null;
1585
+ }
1586
+ /**
1587
+ * Delete a group. Members are UNGROUPED (group_id set to null) first — there
1588
+ * is no hard FK, so the unset is explicit here to avoid dangling references.
1589
+ */
1590
+ export async function deleteCustomerGroup(id) {
1591
+ await ensureCustomerGroupsSchema();
1592
+ const db = getDb();
1593
+ await db
1594
+ .update(schema.customers)
1595
+ .set({ groupId: null })
1596
+ .where(eq(schema.customers.groupId, id));
1597
+ const deleted = await db
1598
+ .delete(schema.customerGroups)
1599
+ .where(eq(schema.customerGroups.id, id))
1600
+ .returning({ id: schema.customerGroups.id });
1601
+ return deleted.length > 0;
1602
+ }
1603
+ /** Assign (or unassign with null) a customer's group. Caller validates the group id. */
1604
+ export async function setCustomerGroup(customerId, groupId) {
1605
+ await ensureCustomerGroupsSchema();
1606
+ const db = getDb();
1607
+ const [customer] = await db
1608
+ .update(schema.customers)
1609
+ .set({ groupId, updatedAt: new Date() })
1610
+ .where(eq(schema.customers.id, customerId))
1611
+ .returning();
1612
+ return customer ?? null;
1613
+ }
1614
+ // =============================================================================
1615
+ // Payment Methods (merchant-managed payment options beyond native Stripe)
1616
+ // =============================================================================
1617
+ let paymentMethodsSchemaEnsured = false;
1618
+ /**
1619
+ * Self-heal the payment-methods schema on stores provisioned before this
1620
+ * feature: the payment_methods table + the orders payment columns that every
1621
+ * `orders` SELECT now enumerates. `payment_provider` matches the PayPal
1622
+ * feature card's lazy column EXACTLY so both converge idempotently.
1623
+ * Idempotent + module-cached.
1624
+ */
1625
+ export async function ensurePaymentMethodsSchema() {
1626
+ if (paymentMethodsSchemaEnsured)
1627
+ return;
1628
+ const db = getDb();
1629
+ try {
1630
+ await db.execute(sql `
1631
+ CREATE TABLE IF NOT EXISTS payment_methods (
1632
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
1633
+ kind varchar(20) NOT NULL DEFAULT 'manual',
1634
+ name varchar(100) NOT NULL,
1635
+ instructions text,
1636
+ enabled boolean NOT NULL DEFAULT true,
1637
+ sort_order integer NOT NULL DEFAULT 0,
1638
+ config jsonb NOT NULL DEFAULT '{}'::jsonb,
1639
+ created_at timestamp NOT NULL DEFAULT now(),
1640
+ updated_at timestamp NOT NULL DEFAULT now()
1641
+ )
1642
+ `);
1643
+ await db.execute(sql `CREATE INDEX IF NOT EXISTS payment_methods_enabled_idx ON payment_methods (enabled)`);
1644
+ await db.execute(sql `CREATE INDEX IF NOT EXISTS payment_methods_sort_order_idx ON payment_methods (sort_order)`);
1645
+ await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS payment_provider varchar(20) NOT NULL DEFAULT 'stripe'`);
1646
+ await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS payment_method_id uuid`);
1647
+ await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS payment_method_label varchar(100)`);
1648
+ paymentMethodsSchemaEnsured = true;
1649
+ }
1650
+ catch (err) {
1651
+ console.error('[ensurePaymentMethodsSchema] migration failed:', err);
1652
+ throw err;
1653
+ }
1654
+ }
1655
+ /** Best-effort variant for hot order read/write paths (see groups sibling). */
1656
+ async function ensurePaymentMethodsSchemaSafe() {
1657
+ try {
1658
+ await ensurePaymentMethodsSchema();
1659
+ }
1660
+ catch {
1661
+ // logged inside ensurePaymentMethodsSchema
1662
+ }
1663
+ }
1664
+ /** All methods, admin view (sorted). */
1665
+ export async function findPaymentMethods() {
1666
+ await ensurePaymentMethodsSchema();
1667
+ const db = getDb();
1668
+ return db
1669
+ .select()
1670
+ .from(schema.paymentMethods)
1671
+ .orderBy(asc(schema.paymentMethods.sortOrder), asc(schema.paymentMethods.createdAt));
1672
+ }
1673
+ /** Enabled methods only — what checkout offers alongside native Stripe. */
1674
+ export async function findEnabledPaymentMethods() {
1675
+ await ensurePaymentMethodsSchema();
1676
+ const db = getDb();
1677
+ return db
1678
+ .select()
1679
+ .from(schema.paymentMethods)
1680
+ .where(eq(schema.paymentMethods.enabled, true))
1681
+ .orderBy(asc(schema.paymentMethods.sortOrder), asc(schema.paymentMethods.createdAt));
1682
+ }
1683
+ export async function findPaymentMethodById(id) {
1684
+ await ensurePaymentMethodsSchema();
1685
+ const db = getDb();
1686
+ const rows = await db
1687
+ .select()
1688
+ .from(schema.paymentMethods)
1689
+ .where(eq(schema.paymentMethods.id, id))
1690
+ .limit(1);
1691
+ return rows[0] ?? null;
1692
+ }
1693
+ export async function createPaymentMethod(data) {
1694
+ await ensurePaymentMethodsSchema();
1695
+ const db = getDb();
1696
+ const [method] = await db
1697
+ .insert(schema.paymentMethods)
1698
+ .values({
1699
+ kind: data.kind ?? 'manual',
1700
+ name: data.name,
1701
+ instructions: data.instructions ?? null,
1702
+ enabled: data.enabled ?? true,
1703
+ sortOrder: data.sortOrder ?? 0,
1704
+ config: data.config ?? {},
1705
+ })
1706
+ .returning();
1707
+ return method;
1708
+ }
1709
+ export async function updatePaymentMethod(id, data) {
1710
+ await ensurePaymentMethodsSchema();
1711
+ const db = getDb();
1712
+ const set = { updatedAt: new Date() };
1713
+ if (data.kind !== undefined)
1714
+ set.kind = data.kind;
1715
+ if (data.name !== undefined)
1716
+ set.name = data.name;
1717
+ if (data.instructions !== undefined)
1718
+ set.instructions = data.instructions ?? null;
1719
+ if (data.enabled !== undefined)
1720
+ set.enabled = data.enabled;
1721
+ if (data.sortOrder !== undefined)
1722
+ set.sortOrder = data.sortOrder;
1723
+ if (data.config !== undefined)
1724
+ set.config = data.config;
1725
+ const [method] = await db
1726
+ .update(schema.paymentMethods)
1727
+ .set(set)
1728
+ .where(eq(schema.paymentMethods.id, id))
1729
+ .returning();
1730
+ return method ?? null;
1731
+ }
1732
+ /**
1733
+ * Hard delete is safe: orders snapshot the method's id + LABEL at order time,
1734
+ * so history stays readable after the method row is gone.
1735
+ */
1736
+ export async function deletePaymentMethod(id) {
1737
+ await ensurePaymentMethodsSchema();
1738
+ const db = getDb();
1739
+ const deleted = await db
1740
+ .delete(schema.paymentMethods)
1741
+ .where(eq(schema.paymentMethods.id, id))
1742
+ .returning({ id: schema.paymentMethods.id });
1743
+ return deleted.length > 0;
1744
+ }
1745
+ // =============================================================================
1448
1746
  // Order Queries (for admin module)
1449
1747
  // =============================================================================
1450
1748
  /**