@stacksjs/commerce 0.70.53 → 0.70.55

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 (165) hide show
  1. package/package.json +3 -2
  2. package/src/carts/destroy.ts +54 -0
  3. package/src/carts/fetch.ts +20 -0
  4. package/src/carts/index.ts +13 -0
  5. package/src/carts/store.ts +75 -0
  6. package/src/carts/update.ts +78 -0
  7. package/src/coupons/destroy.ts +49 -0
  8. package/src/coupons/fetch.ts +510 -0
  9. package/src/coupons/index.ts +30 -0
  10. package/src/coupons/store.ts +46 -0
  11. package/src/coupons/update.ts +147 -0
  12. package/src/customers/destroy.ts +62 -0
  13. package/src/customers/fetch.ts +20 -0
  14. package/src/customers/index.ts +17 -0
  15. package/src/customers/store.ts +45 -0
  16. package/src/customers/update.ts +44 -0
  17. package/src/devices/destroy.ts +54 -0
  18. package/src/devices/export.ts +98 -0
  19. package/src/devices/fetch.ts +125 -0
  20. package/src/devices/index.ts +31 -0
  21. package/src/devices/store.ts +82 -0
  22. package/src/devices/update.ts +125 -0
  23. package/src/errors/destroy.ts +54 -0
  24. package/src/errors/fetch.ts +197 -0
  25. package/src/errors/index.ts +28 -0
  26. package/src/errors/update.ts +116 -0
  27. package/src/gift-cards/destroy.ts +87 -0
  28. package/src/gift-cards/fetch.ts +431 -0
  29. package/src/gift-cards/index.ts +26 -0
  30. package/src/gift-cards/store.ts +56 -0
  31. package/src/gift-cards/update.ts +102 -0
  32. package/src/index.ts +78 -0
  33. package/src/orders/destroy.ts +111 -0
  34. package/src/orders/events.ts +121 -0
  35. package/src/orders/export.ts +158 -0
  36. package/src/orders/fetch.ts +379 -0
  37. package/src/orders/guards.ts +261 -0
  38. package/src/orders/index.ts +91 -0
  39. package/src/orders/place-order.ts +274 -0
  40. package/src/orders/store.ts +51 -0
  41. package/src/orders/totals.ts +190 -0
  42. package/src/orders/update.ts +164 -0
  43. package/src/orders/webhook.ts +312 -0
  44. package/src/payments/destroy.ts +56 -0
  45. package/src/payments/fetch.ts +288 -0
  46. package/src/payments/index.ts +16 -0
  47. package/src/payments/store.ts +63 -0
  48. package/src/payments/update.ts +52 -0
  49. package/src/product.ts +0 -0
  50. package/src/products/categories/destroy.ts +103 -0
  51. package/src/products/categories/fetch.ts +285 -0
  52. package/src/products/categories/index.ts +36 -0
  53. package/src/products/categories/store.ts +87 -0
  54. package/src/products/categories/update.ts +251 -0
  55. package/src/products/index.ts +35 -0
  56. package/src/products/items/destroy.ts +54 -0
  57. package/src/products/items/fetch.ts +282 -0
  58. package/src/products/items/index.ts +26 -0
  59. package/src/products/items/store.ts +84 -0
  60. package/src/products/items/update.ts +324 -0
  61. package/src/products/manufacturers/destroy.ts +56 -0
  62. package/src/products/manufacturers/fetch.ts +117 -0
  63. package/src/products/manufacturers/index.ts +24 -0
  64. package/src/products/manufacturers/store.ts +82 -0
  65. package/src/products/manufacturers/update.ts +113 -0
  66. package/src/products/reviews/destroy.ts +56 -0
  67. package/src/products/reviews/fetch.ts +63 -0
  68. package/src/products/reviews/index.ts +25 -0
  69. package/src/products/reviews/store.ts +46 -0
  70. package/src/products/reviews/update.ts +82 -0
  71. package/src/products/units/destroy.ts +56 -0
  72. package/src/products/units/fetch.ts +20 -0
  73. package/src/products/units/index.ts +13 -0
  74. package/src/products/units/store.ts +162 -0
  75. package/src/products/units/update.ts +159 -0
  76. package/src/products/variants/destroy.ts +56 -0
  77. package/src/products/variants/fetch.ts +20 -0
  78. package/src/products/variants/index.ts +21 -0
  79. package/src/products/variants/store.ts +136 -0
  80. package/src/products/variants/update.ts +104 -0
  81. package/src/receipts/destroy.ts +54 -0
  82. package/src/receipts/export.ts +0 -0
  83. package/src/receipts/fetch.ts +222 -0
  84. package/src/receipts/index.ts +24 -0
  85. package/src/receipts/printer.ts +69 -0
  86. package/src/receipts/store.ts +69 -0
  87. package/src/receipts/update.ts +124 -0
  88. package/src/shippings/delivery-routes/destroy.ts +54 -0
  89. package/src/shippings/delivery-routes/fetch.ts +42 -0
  90. package/src/shippings/delivery-routes/index.ts +26 -0
  91. package/src/shippings/delivery-routes/store.ts +69 -0
  92. package/src/shippings/delivery-routes/update.ts +120 -0
  93. package/src/shippings/digital-deliveries/destroy.ts +111 -0
  94. package/src/shippings/digital-deliveries/fetch.ts +20 -0
  95. package/src/shippings/digital-deliveries/index.ts +26 -0
  96. package/src/shippings/digital-deliveries/store.ts +76 -0
  97. package/src/shippings/digital-deliveries/update.ts +129 -0
  98. package/src/shippings/drivers/destroy.ts +78 -0
  99. package/src/shippings/drivers/fetch.ts +20 -0
  100. package/src/shippings/drivers/index.ts +24 -0
  101. package/src/shippings/drivers/store.ts +69 -0
  102. package/src/shippings/drivers/update.ts +117 -0
  103. package/src/shippings/index.ts +39 -0
  104. package/src/shippings/license-keys/destroy.ts +111 -0
  105. package/src/shippings/license-keys/fetch.ts +20 -0
  106. package/src/shippings/license-keys/index.ts +26 -0
  107. package/src/shippings/license-keys/store.ts +77 -0
  108. package/src/shippings/license-keys/update.ts +117 -0
  109. package/src/shippings/shipping-methods/destroy.ts +111 -0
  110. package/src/shippings/shipping-methods/fetch.ts +62 -0
  111. package/src/shippings/shipping-methods/index.ts +28 -0
  112. package/src/shippings/shipping-methods/store.ts +123 -0
  113. package/src/shippings/shipping-methods/update.ts +120 -0
  114. package/src/shippings/shipping-rates/destroy.ts +102 -0
  115. package/src/shippings/shipping-rates/fetch.ts +320 -0
  116. package/src/shippings/shipping-rates/index.ts +36 -0
  117. package/src/shippings/shipping-rates/store.ts +102 -0
  118. package/src/shippings/shipping-rates/update.ts +139 -0
  119. package/src/shippings/shipping-zones/destroy.ts +111 -0
  120. package/src/shippings/shipping-zones/fetch.ts +96 -0
  121. package/src/shippings/shipping-zones/index.ts +26 -0
  122. package/src/shippings/shipping-zones/store.ts +74 -0
  123. package/src/shippings/shipping-zones/update.ts +156 -0
  124. package/src/tax/destroy.ts +54 -0
  125. package/src/tax/fetch.ts +20 -0
  126. package/src/tax/index.ts +24 -0
  127. package/src/tax/store.ts +69 -0
  128. package/src/tax/update.ts +119 -0
  129. package/src/tests/coupons.test.ts +90 -0
  130. package/src/tests/customers.test.ts +39 -0
  131. package/src/tests/device.test.ts +111 -0
  132. package/src/tests/digitals.test.ts +31 -0
  133. package/src/tests/drivers.test.ts +25 -0
  134. package/src/tests/gift-cards.test.ts +36 -0
  135. package/src/tests/license.test.ts +31 -0
  136. package/src/tests/manufacturers.test.ts +80 -0
  137. package/src/tests/orders.test.ts +25 -0
  138. package/src/tests/payments.test.ts +75 -0
  139. package/src/tests/rates.test.ts +367 -0
  140. package/src/tests/receipts.test.ts +287 -0
  141. package/src/tests/restaurant.test.ts +522 -0
  142. package/src/tests/reviews.test.ts +165 -0
  143. package/src/tests/routes.test.ts +51 -0
  144. package/src/tests/setup.ts +149 -0
  145. package/src/tests/shipping.test.ts +88 -0
  146. package/src/tests/tax.test.ts +25 -0
  147. package/src/tests/units.test.ts +110 -0
  148. package/src/tests/variants.test.ts +133 -0
  149. package/src/tests/waitlist.test.ts +303 -0
  150. package/src/tests/zones.test.ts +86 -0
  151. package/src/types.ts +312 -0
  152. package/src/utils/typed-stats.ts +67 -0
  153. package/src/waitlists/index.ts +19 -0
  154. package/src/waitlists/products/destroy.ts +65 -0
  155. package/src/waitlists/products/export.ts +113 -0
  156. package/src/waitlists/products/fetch.ts +362 -0
  157. package/src/waitlists/products/index.ts +33 -0
  158. package/src/waitlists/products/store.ts +112 -0
  159. package/src/waitlists/products/update.ts +125 -0
  160. package/src/waitlists/restaurant/destroy.ts +65 -0
  161. package/src/waitlists/restaurant/export.ts +107 -0
  162. package/src/waitlists/restaurant/fetch.ts +538 -0
  163. package/src/waitlists/restaurant/index.ts +43 -0
  164. package/src/waitlists/restaurant/store.ts +109 -0
  165. package/src/waitlists/restaurant/update.ts +198 -0
@@ -0,0 +1,102 @@
1
+ // Import dependencies
2
+ type ShippingRateJsonResponse = ModelRow<typeof ShippingRate>
3
+ type NewShippingRate = NewModelData<typeof ShippingRate>
4
+ import { randomUUIDv7 } from 'bun'
5
+ import { db } from '@stacksjs/database'
6
+ import { fetchById as fetchShippingMethodById } from '../shipping-methods/fetch'
7
+ import { fetchById as fetchShippingZoneById } from '../shipping-zones/fetch'
8
+ import { fetchById } from './fetch'
9
+
10
+ /**
11
+ * Create a new shipping rate
12
+ *
13
+ * @param data The shipping rate data to store
14
+ * @returns The newly created shipping rate record
15
+ */
16
+ export async function store(data: NewShippingRate): Promise<ShippingRateJsonResponse> {
17
+ try {
18
+ // Validate that the shipping method and zone exist
19
+ const method = await fetchShippingMethodById(Number(data.shippingmethod_id))
20
+ const zone = await fetchShippingZoneById(Number(data.shippingzone_id))
21
+
22
+ const rateData = {
23
+ weightFrom: data.weightFrom,
24
+ weightTo: data.weightTo,
25
+ rate: data.rate,
26
+ shippingmethod_id: method?.id,
27
+ shippingzone_id: zone?.id,
28
+ uuid: randomUUIDv7(),
29
+ }
30
+
31
+ const result = await db
32
+ .insertInto('shipping_rates')
33
+ .values(rateData)
34
+ .executeTakeFirst()
35
+
36
+ if (!result)
37
+ throw new Error('Failed to create shipping rate')
38
+
39
+ const insertId = Number(result.insertId) || Number(result.numInsertedOrUpdatedRows)
40
+
41
+ const model = await fetchById(insertId)
42
+
43
+ return model as ShippingRateJsonResponse
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error) {
47
+ throw new TypeError(`Failed to create shipping rate: ${error.message}`)
48
+ }
49
+
50
+ throw error
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Create multiple shipping rates at once
56
+ *
57
+ * @param data Array of shipping rate data to store
58
+ * @returns Number of shipping rates created
59
+ */
60
+ export async function bulkStore(data: NewShippingRate[]): Promise<number> {
61
+ if (!data.length)
62
+ return 0
63
+
64
+ try {
65
+ // Validate all methods and zones before bulk insert
66
+ for (const item of data) {
67
+ const method = await fetchShippingMethodById(Number(item.shippingmethod_id))
68
+ const zone = await fetchShippingZoneById(Number(item.shippingzone_id))
69
+
70
+ if (!method) {
71
+ console.warn(`Shipping method with ID "${item.shippingmethod_id}" not found for bulk insert`)
72
+ }
73
+
74
+ if (!zone) {
75
+ console.warn(`Shipping zone with ID "${item.shippingzone_id}" not found for bulk insert`)
76
+ }
77
+ }
78
+
79
+ const rateDataArray = data.map(item => ({
80
+ weightFrom: item.weightFrom,
81
+ weightTo: item.weightTo,
82
+ rate: item.rate,
83
+ shippingmethod_id: item.shippingmethod_id,
84
+ shippingzone_id: item.shippingzone_id,
85
+ uuid: randomUUIDv7(),
86
+ }))
87
+
88
+ const result = await db
89
+ .insertInto('shipping_rates')
90
+ .values(rateDataArray)
91
+ .executeTakeFirst()
92
+
93
+ return Number(result.numInsertedOrUpdatedRows)
94
+ }
95
+ catch (error) {
96
+ if (error instanceof Error) {
97
+ throw new TypeError(`Failed to create shipping rates in bulk: ${error.message}`)
98
+ }
99
+
100
+ throw error
101
+ }
102
+ }
@@ -0,0 +1,139 @@
1
+ import { db } from '@stacksjs/database'
2
+ import { formatDate } from '@stacksjs/orm'
3
+ type ShippingRateJsonResponse = ModelRow<typeof ShippingRate>
4
+ type ShippingRateUpdate = UpdateModelData<typeof ShippingRate>
5
+
6
+ /**
7
+ * Update a shipping rate
8
+ *
9
+ * @param id The shipping rate ID to update
10
+ * @param data The shipping rate data to update
11
+ * @returns The updated shipping rate record
12
+ */
13
+ export async function update(id: number, data: ShippingRateUpdate): Promise<ShippingRateJsonResponse> {
14
+ try {
15
+ if (!id)
16
+ throw new Error('Shipping rate ID is required for update')
17
+
18
+ const result = await db
19
+ .updateTable('shipping_rates')
20
+ .set({
21
+ ...data,
22
+ updated_at: formatDate(new Date()),
23
+ })
24
+ .where('id', '=', id)
25
+ .returningAll()
26
+ .executeTakeFirst()
27
+
28
+ if (!result)
29
+ throw new Error('Failed to update shipping rate')
30
+
31
+ return result as ShippingRateJsonResponse
32
+ }
33
+ catch (error) {
34
+ if (error instanceof Error) {
35
+ throw new TypeError(`Failed to update shipping rate: ${error.message}`)
36
+ }
37
+
38
+ throw error
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Update multiple shipping rates at once
44
+ *
45
+ * @param updates Array of objects containing rate ID and update data
46
+ * @returns Number of shipping rates updated
47
+ */
48
+ export async function bulkUpdate(updates: Array<{
49
+ id: number
50
+ data: ShippingRateUpdate
51
+ }>): Promise<number> {
52
+ if (!updates.length)
53
+ return 0
54
+
55
+ try {
56
+ let updatedCount = 0
57
+
58
+ for (const { id, data } of updates) {
59
+ const result = await db
60
+ .updateTable('shipping_rates')
61
+ .set({
62
+ ...data,
63
+ updated_at: formatDate(new Date()),
64
+ })
65
+ .where('id', '=', id)
66
+ .executeTakeFirst()
67
+
68
+ if (Number(result.numUpdatedRows) > 0)
69
+ updatedCount++
70
+ }
71
+
72
+ return updatedCount
73
+ }
74
+ catch (error) {
75
+ if (error instanceof Error) {
76
+ throw new TypeError(`Failed to update shipping rates in bulk: ${error.message}`)
77
+ }
78
+
79
+ throw error
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Update shipping rates by zone
85
+ *
86
+ * @param zone The zone to update rates for
87
+ * @param data The update data to apply
88
+ * @returns Number of shipping rates updated
89
+ */
90
+ export async function updateByZone(zone: number, data: ShippingRateUpdate): Promise<number> {
91
+ try {
92
+ const result = await db
93
+ .updateTable('shipping_rates')
94
+ .set({
95
+ ...data,
96
+ updated_at: formatDate(new Date()),
97
+ })
98
+ .where('zone_id', '=', zone)
99
+ .executeTakeFirst()
100
+
101
+ return Number(result.numUpdatedRows)
102
+ }
103
+ catch (error) {
104
+ if (error instanceof Error) {
105
+ throw new TypeError(`Failed to update shipping rates by zone: ${error.message}`)
106
+ }
107
+
108
+ throw error
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Update shipping rates by method
114
+ *
115
+ * @param method The shipping method to update rates for
116
+ * @param data The update data to apply
117
+ * @returns Number of shipping rates updated
118
+ */
119
+ export async function updateByMethod(method: string, data: ShippingRateUpdate): Promise<number> {
120
+ try {
121
+ const result = await db
122
+ .updateTable('shipping_rates')
123
+ .set({
124
+ ...data,
125
+ updated_at: formatDate(new Date()),
126
+ })
127
+ .where('method', '=', method)
128
+ .executeTakeFirst()
129
+
130
+ return Number(result.numUpdatedRows)
131
+ }
132
+ catch (error) {
133
+ if (error instanceof Error) {
134
+ throw new TypeError(`Failed to update shipping rates by method: ${error.message}`)
135
+ }
136
+
137
+ throw error
138
+ }
139
+ }
@@ -0,0 +1,111 @@
1
+ import { db } from '@stacksjs/database'
2
+
3
+ /**
4
+ * Delete a shipping zone by ID
5
+ *
6
+ * @param id The ID of the shipping zone to delete
7
+ * @returns True if the shipping zone was deleted, false otherwise
8
+ */
9
+ export async function destroy(id: number): Promise<boolean> {
10
+ try {
11
+ const result = await db
12
+ .deleteFrom('shipping_zones')
13
+ .where('id', '=', id)
14
+ .executeTakeFirst()
15
+
16
+ return Number(result.numDeletedRows) > 0
17
+ }
18
+ catch (error) {
19
+ if (error instanceof Error) {
20
+ throw new TypeError(`Failed to delete shipping zone: ${error.message}`)
21
+ }
22
+
23
+ throw error
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Soft delete a shipping zone by ID (updates status to 'inactive')
29
+ *
30
+ * @param id The ID of the shipping zone to soft delete
31
+ * @returns True if the shipping zone was soft deleted, false otherwise
32
+ */
33
+ export async function softDelete(id: number): Promise<boolean> {
34
+ try {
35
+ // Update the status to 'inactive' instead of deleting
36
+ const result = await db
37
+ .updateTable('shipping_zones')
38
+ .set({ status: 'inactive' })
39
+ .where('id', '=', id)
40
+ .executeTakeFirst()
41
+
42
+ // Return true if any row was affected (updated)
43
+ return Number(result.numUpdatedRows) > 0
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error) {
47
+ throw new TypeError(`Failed to soft delete shipping zone: ${error.message}`)
48
+ }
49
+
50
+ throw error
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Delete multiple shipping zones by ID
56
+ *
57
+ * @param ids Array of shipping zone IDs to delete
58
+ * @returns Number of shipping zones deleted
59
+ */
60
+ export async function bulkDestroy(ids: number[]): Promise<number> {
61
+ if (!ids.length)
62
+ return 0
63
+
64
+ try {
65
+ // Perform the delete operation
66
+ const result = await db
67
+ .deleteFrom('shipping_zones')
68
+ .where('id', 'in', ids)
69
+ .executeTakeFirst()
70
+
71
+ // Return the number of deleted rows
72
+ return Number(result.numDeletedRows)
73
+ }
74
+ catch (error) {
75
+ if (error instanceof Error) {
76
+ throw new TypeError(`Failed to delete shipping zones: ${error.message}`)
77
+ }
78
+
79
+ throw error
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Soft delete multiple shipping zones by ID (updates status to 'inactive')
85
+ *
86
+ * @param ids Array of shipping zone IDs to soft delete
87
+ * @returns Number of shipping zones soft deleted
88
+ */
89
+ export async function bulkSoftDelete(ids: number[]): Promise<number> {
90
+ if (!ids.length)
91
+ return 0
92
+
93
+ try {
94
+ // Update the status to 'inactive' instead of deleting
95
+ const result = await db
96
+ .updateTable('shipping_zones')
97
+ .set({ status: 'inactive' })
98
+ .where('id', 'in', ids)
99
+ .executeTakeFirst()
100
+
101
+ // Return the number of updated rows
102
+ return Number(result.numUpdatedRows)
103
+ }
104
+ catch (error) {
105
+ if (error instanceof Error) {
106
+ throw new TypeError(`Failed to soft delete shipping zones: ${error.message}`)
107
+ }
108
+
109
+ throw error
110
+ }
111
+ }
@@ -0,0 +1,96 @@
1
+ type ShippingZoneJsonResponse = ModelRow<typeof ShippingZone>
2
+ import { db } from '@stacksjs/database'
3
+
4
+ /**
5
+ * Fetch all shipping zones
6
+ */
7
+ export async function fetchAll(): Promise<ShippingZoneJsonResponse[]> {
8
+ return await db.selectFrom('shipping_zones').selectAll().execute() as ShippingZoneJsonResponse[]
9
+ }
10
+
11
+ /**
12
+ * Fetch a shipping zone by ID
13
+ */
14
+ export async function fetchById(id: number): Promise<ShippingZoneJsonResponse | undefined> {
15
+ return await db
16
+ .selectFrom('shipping_zones')
17
+ .where('id', '=', id)
18
+ .selectAll()
19
+ .executeTakeFirst() as ShippingZoneJsonResponse | undefined
20
+ }
21
+
22
+ /**
23
+ * Format shipping zone options for dropdown menus or selectors
24
+ *
25
+ * @returns Array of formatted shipping zone options with id, name, and status
26
+ */
27
+ export function formatZoneOptions(): Promise<{ id: number, name: string, status: string | string[], countries: string | undefined }[]> {
28
+ try {
29
+ return db
30
+ .selectFrom('shipping_zones')
31
+ .select(['id', 'name', 'status', 'countries'])
32
+ .orderBy('name')
33
+ .execute() as any
34
+ }
35
+ catch (error) {
36
+ if (error instanceof Error) {
37
+ throw new TypeError(`Failed to format shipping zone options: ${error.message}`)
38
+ }
39
+
40
+ throw error
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Get active shipping zones
46
+ *
47
+ * @returns List of active shipping zones
48
+ */
49
+ export async function getActiveShippingZones(): Promise<ShippingZoneJsonResponse[]> {
50
+ try {
51
+ const activeZones = await db
52
+ .selectFrom('shipping_zones')
53
+ .selectAll()
54
+ .where('status', '=', 'active')
55
+ .orderBy('name')
56
+ .execute()
57
+
58
+ return activeZones as ShippingZoneJsonResponse[]
59
+ }
60
+ catch (error) {
61
+ if (error instanceof Error) {
62
+ throw new TypeError(`Failed to get active shipping zones: ${error.message}`)
63
+ }
64
+
65
+ throw error
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Get shipping zones by country code
71
+ *
72
+ * @param countryCode ISO country code
73
+ * @returns List of shipping zones covering the specified country
74
+ */
75
+ export async function getZonesByCountry(countryCode: string): Promise<ShippingZoneJsonResponse[]> {
76
+ try {
77
+ // This uses a LIKE query assuming countries are stored as JSON strings
78
+ // You may need to adjust based on your actual data structure
79
+ const zones = await db
80
+ .selectFrom('shipping_zones')
81
+ .selectAll()
82
+ .where('countries', 'like', `%${countryCode}%`)
83
+ .where('status', '=', 'active')
84
+ .orderBy('name')
85
+ .execute()
86
+
87
+ return zones as ShippingZoneJsonResponse[]
88
+ }
89
+ catch (error) {
90
+ if (error instanceof Error) {
91
+ throw new TypeError(`Failed to get shipping zones by country: ${error.message}`)
92
+ }
93
+
94
+ throw error
95
+ }
96
+ }
@@ -0,0 +1,26 @@
1
+ export {
2
+ bulkDestroy,
3
+ bulkSoftDelete,
4
+ destroy,
5
+ softDelete,
6
+ } from './destroy'
7
+
8
+ export {
9
+ fetchAll,
10
+ fetchById,
11
+ formatZoneOptions,
12
+ getActiveShippingZones,
13
+ getZonesByCountry,
14
+ } from './fetch'
15
+
16
+ export {
17
+ bulkStore,
18
+ store,
19
+ } from './store'
20
+
21
+ export {
22
+ update,
23
+ updateCountries,
24
+ updateRegionsAndPostalCodes,
25
+ updateStatus,
26
+ } from './update'
@@ -0,0 +1,74 @@
1
+ // Import dependencies
2
+ type ShippingZoneJsonResponse = ModelRow<typeof ShippingZone>
3
+ type NewShippingZone = NewModelData<typeof ShippingZone>
4
+ import { randomUUIDv7 } from 'bun'
5
+ import { db } from '@stacksjs/database'
6
+ import { fetchById } from './fetch'
7
+
8
+ /**
9
+ * Create a new shipping zone
10
+ *
11
+ * @param data The shipping zone data to store
12
+ * @returns The newly created shipping zone record
13
+ */
14
+ export async function store(data: NewShippingZone): Promise<ShippingZoneJsonResponse> {
15
+ try {
16
+ const zoneData = {
17
+ ...data,
18
+ uuid: randomUUIDv7(),
19
+ }
20
+
21
+ const result = await db
22
+ .insertInto('shipping_zones')
23
+ .values(zoneData)
24
+ .executeTakeFirst()
25
+
26
+ if (!result)
27
+ throw new Error('Failed to create shipping zone')
28
+
29
+ const insertId = Number(result.insertId) || Number(result.numInsertedOrUpdatedRows)
30
+
31
+ const model = await fetchById(insertId)
32
+
33
+ return model as ShippingZoneJsonResponse
34
+ }
35
+ catch (error) {
36
+ if (error instanceof Error) {
37
+ throw new TypeError(`Failed to create shipping zone: ${error.message}`)
38
+ }
39
+
40
+ throw error
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Create multiple shipping zones at once
46
+ *
47
+ * @param data Array of shipping zone data to store
48
+ * @returns Number of shipping zones created
49
+ */
50
+ export async function bulkStore(data: NewShippingZone[]): Promise<number> {
51
+ if (!data.length)
52
+ return 0
53
+
54
+ try {
55
+ const zoneDataArray = data.map(item => ({
56
+ ...item,
57
+ uuid: randomUUIDv7(),
58
+ }))
59
+
60
+ const result = await db
61
+ .insertInto('shipping_zones')
62
+ .values(zoneDataArray)
63
+ .executeTakeFirst()
64
+
65
+ return Number(result.numInsertedOrUpdatedRows)
66
+ }
67
+ catch (error) {
68
+ if (error instanceof Error) {
69
+ throw new TypeError(`Failed to create shipping zones in bulk: ${error.message}`)
70
+ }
71
+
72
+ throw error
73
+ }
74
+ }
@@ -0,0 +1,156 @@
1
+ import { db } from '@stacksjs/database'
2
+ import { formatDate } from '@stacksjs/orm'
3
+ type ShippingZoneJsonResponse = ModelRow<typeof ShippingZone>
4
+ type ShippingZoneUpdate = UpdateModelData<typeof ShippingZone>
5
+
6
+ /**
7
+ * Update a shipping zone
8
+ *
9
+ * @param id The ID of the shipping zone
10
+ * @param data The shipping zone data to update
11
+ * @returns The updated shipping zone record
12
+ */
13
+ export async function update(id: number, data: ShippingZoneUpdate): Promise<ShippingZoneJsonResponse> {
14
+ try {
15
+ if (!id)
16
+ throw new Error('Shipping zone ID is required for update')
17
+
18
+ const result = await db
19
+ .updateTable('shipping_zones')
20
+ .set({
21
+ ...data,
22
+ updated_at: formatDate(new Date()),
23
+ })
24
+ .where('id', '=', id)
25
+ .returningAll()
26
+ .executeTakeFirst()
27
+
28
+ if (!result)
29
+ throw new Error('Failed to update shipping zone')
30
+
31
+ return result as ShippingZoneJsonResponse
32
+ }
33
+ catch (error) {
34
+ if (error instanceof Error) {
35
+ throw new TypeError(`Failed to update shipping zone: ${error.message}`)
36
+ }
37
+
38
+ throw error
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Update a shipping zone's status
44
+ *
45
+ * @param id The ID of the shipping zone
46
+ * @param status The new status
47
+ * @returns The updated shipping zone with the new status
48
+ */
49
+ export async function updateStatus(
50
+ id: number,
51
+ status: string | string[],
52
+ ): Promise<ShippingZoneJsonResponse> {
53
+ try {
54
+ const result = await db
55
+ .updateTable('shipping_zones')
56
+ .set({
57
+ status,
58
+ updated_at: formatDate(new Date()),
59
+ })
60
+ .where('id', '=', id)
61
+ .returningAll()
62
+ .executeTakeFirst()
63
+
64
+ if (!result)
65
+ throw new Error('Failed to update shipping zone status')
66
+
67
+ return result as ShippingZoneJsonResponse
68
+ }
69
+ catch (error) {
70
+ if (error instanceof Error) {
71
+ throw new TypeError(`Failed to update shipping zone status: ${error.message}`)
72
+ }
73
+
74
+ throw error
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Update countries for a shipping zone
80
+ *
81
+ * @param id The ID of the shipping zone
82
+ * @param countries The updated countries JSON string
83
+ * @returns The updated shipping zone
84
+ */
85
+ export async function updateCountries(
86
+ id: number,
87
+ countries: string,
88
+ ): Promise<ShippingZoneJsonResponse> {
89
+ try {
90
+ const result = await db
91
+ .updateTable('shipping_zones')
92
+ .set({
93
+ countries,
94
+ updated_at: formatDate(new Date()),
95
+ })
96
+ .where('id', '=', id)
97
+ .returningAll()
98
+ .executeTakeFirst()
99
+
100
+ if (!result)
101
+ throw new Error('Failed to update shipping zone countries')
102
+
103
+ return result as ShippingZoneJsonResponse
104
+ }
105
+ catch (error) {
106
+ if (error instanceof Error) {
107
+ throw new TypeError(`Failed to update shipping zone countries: ${error.message}`)
108
+ }
109
+
110
+ throw error
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Update regions and/or postal codes for a shipping zone
116
+ *
117
+ * @param id The ID of the shipping zone
118
+ * @param regions Optional updated regions JSON string
119
+ * @param postal_codes Optional updated postal codes JSON string
120
+ * @returns The updated shipping zone
121
+ */
122
+ export async function updateRegionsAndPostalCodes(
123
+ id: number,
124
+ regions?: string,
125
+ postal_codes?: string,
126
+ ): Promise<ShippingZoneJsonResponse> {
127
+ try {
128
+ const updateData: Record<string, any> = {
129
+ updated_at: formatDate(new Date()),
130
+ }
131
+
132
+ if (regions !== undefined)
133
+ updateData.regions = regions
134
+ if (postal_codes !== undefined)
135
+ updateData.postal_codes = postal_codes
136
+
137
+ const result = await db
138
+ .updateTable('shipping_zones')
139
+ .set(updateData)
140
+ .where('id', '=', id)
141
+ .returningAll()
142
+ .executeTakeFirst()
143
+
144
+ if (!result)
145
+ throw new Error('Failed to update regions and postal codes')
146
+
147
+ return result as ShippingZoneJsonResponse
148
+ }
149
+ catch (error) {
150
+ if (error instanceof Error) {
151
+ throw new TypeError(`Failed to update regions and postal codes: ${error.message}`)
152
+ }
153
+
154
+ throw error
155
+ }
156
+ }