@mohasinac/appkit 4.62.0 → 4.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -29
  3. package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
  4. package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
  5. package/dist/_internal/server/features/ads/booking.d.ts +118 -0
  6. package/dist/_internal/server/features/ads/booking.js +326 -0
  7. package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
  8. package/dist/_internal/server/features/checkout/actions.js +850 -79
  9. package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
  10. package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
  11. package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
  12. package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
  13. package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
  14. package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
  15. package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
  16. package/dist/_internal/server/features/dashboard/attention.js +183 -0
  17. package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
  18. package/dist/_internal/server/features/dashboard/data.js +82 -0
  19. package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
  20. package/dist/_internal/server/features/inventory/reservations.js +273 -0
  21. package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
  22. package/dist/_internal/server/features/invoicing/allocate.js +162 -0
  23. package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
  24. package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
  25. package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
  26. package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
  27. package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
  28. package/dist/_internal/server/features/invoicing/issue.js +202 -0
  29. package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
  30. package/dist/_internal/server/features/offers/destinations.js +65 -0
  31. package/dist/_internal/server/features/orders/actions.d.ts +8 -1
  32. package/dist/_internal/server/features/orders/actions.js +81 -8
  33. package/dist/_internal/server/features/orders/adapters.js +54 -0
  34. package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
  35. package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
  36. package/dist/_internal/server/features/orders/balance.d.ts +89 -0
  37. package/dist/_internal/server/features/orders/balance.js +256 -0
  38. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
  39. package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
  40. package/dist/_internal/server/features/points/award.js +46 -4
  41. package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
  42. package/dist/_internal/server/features/pricing/actions.js +144 -0
  43. package/dist/_internal/server/features/refunds/actions.js +26 -0
  44. package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
  45. package/dist/_internal/server/features/shipping/book-split.js +130 -0
  46. package/dist/_internal/server/features/shipping/book.d.ts +61 -0
  47. package/dist/_internal/server/features/shipping/book.js +176 -0
  48. package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
  49. package/dist/_internal/server/features/shipping/courier-block.js +264 -0
  50. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  51. package/dist/_internal/server/features/site-settings/adapters.js +29 -0
  52. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  53. package/dist/_internal/server/features/stores/adapters.js +65 -0
  54. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  55. package/dist/_internal/server/functions/scheduled.js +95 -2
  56. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
  57. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
  58. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
  59. package/dist/_internal/server/jobs/core/index.d.ts +2 -1
  60. package/dist/_internal/server/jobs/core/index.js +2 -1
  61. package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
  62. package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
  63. package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
  64. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
  65. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
  66. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
  67. package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
  68. package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
  69. package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
  70. package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
  71. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
  72. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  73. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  74. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
  75. package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
  76. package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
  77. package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
  78. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  79. package/dist/_internal/shared/actions/action-registry.js +296 -0
  80. package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
  81. package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
  82. package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
  83. package/dist/_internal/shared/checkout/order-math.js +159 -0
  84. package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
  85. package/dist/_internal/shared/checkout/refundable-base.js +13 -1
  86. package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
  87. package/dist/_internal/shared/checkout/rules/index.js +1 -1
  88. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
  89. package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
  90. package/dist/_internal/shared/checkout/split.d.ts +75 -0
  91. package/dist/_internal/shared/checkout/split.js +120 -0
  92. package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
  93. package/dist/_internal/shared/content/disclaimers.js +217 -0
  94. package/dist/_internal/shared/content/published-values.d.ts +93 -0
  95. package/dist/_internal/shared/content/published-values.js +206 -0
  96. package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
  97. package/dist/_internal/shared/features/admin/integrations.js +263 -0
  98. package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
  99. package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
  100. package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
  101. package/dist/_internal/shared/features/emi/choice.js +69 -0
  102. package/dist/_internal/shared/features/emi/group.d.ts +84 -0
  103. package/dist/_internal/shared/features/emi/group.js +126 -0
  104. package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
  105. package/dist/_internal/shared/features/ledger/posting.js +165 -0
  106. package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
  107. package/dist/_internal/shared/features/ledger/reports.js +127 -0
  108. package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
  109. package/dist/_internal/shared/features/ledger/rules.js +221 -0
  110. package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
  111. package/dist/_internal/shared/features/offers/coordination.js +80 -0
  112. package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
  113. package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
  114. package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
  115. package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
  116. package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
  117. package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
  118. package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
  119. package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
  120. package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
  121. package/dist/_internal/shared/features/points/accepts.js +49 -0
  122. package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
  123. package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
  124. package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
  125. package/dist/_internal/shared/features/shipping/parcel.js +139 -0
  126. package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
  127. package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
  128. package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
  129. package/dist/_internal/shared/features/site-settings/fees.js +12 -8
  130. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  131. package/dist/_internal/shared/fees/calculator.d.ts +33 -1
  132. package/dist/_internal/shared/fees/calculator.js +32 -2
  133. package/dist/_internal/shared/fees/explain.d.ts +81 -0
  134. package/dist/_internal/shared/fees/explain.js +101 -0
  135. package/dist/_internal/shared/history/index.d.ts +1 -1
  136. package/dist/_internal/shared/history/index.js +1 -1
  137. package/dist/_internal/shared/history/types.d.ts +7 -1
  138. package/dist/_internal/shared/history/types.js +25 -0
  139. package/dist/client.d.ts +21 -0
  140. package/dist/client.js +43 -0
  141. package/dist/constants/api-endpoints.d.ts +114 -0
  142. package/dist/constants/api-endpoints.js +55 -0
  143. package/dist/constants/field-names.d.ts +42 -0
  144. package/dist/constants/field-names.js +52 -0
  145. package/dist/contracts/index.d.ts +1 -1
  146. package/dist/contracts/shipping.d.ts +45 -0
  147. package/dist/contracts/shipping.js +15 -0
  148. package/dist/features/about/components/AboutView.js +1 -1
  149. package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
  150. package/dist/features/account/components/UserOrdersView.js +47 -35
  151. package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
  152. package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
  153. package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
  154. package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
  155. package/dist/features/admin/components/AdminInvoicingView.js +65 -0
  156. package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
  157. package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
  158. package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
  159. package/dist/features/admin/components/AdminOrdersView.js +86 -5
  160. package/dist/features/admin/components/OwnerQuickActions.js +24 -2
  161. package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
  162. package/dist/features/admin/constants/filter-tabs.js +6 -0
  163. package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
  164. package/dist/features/admin/hooks/useAdminListingData.js +16 -0
  165. package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
  166. package/dist/features/admin/schemas/firestore.d.ts +62 -0
  167. package/dist/features/admin/schemas/firestore.js +5 -0
  168. package/dist/features/ads/schemas/booking-write.d.ts +120 -0
  169. package/dist/features/ads/schemas/booking-write.js +75 -0
  170. package/dist/features/ads/schemas/creative-form.d.ts +18 -0
  171. package/dist/features/ads/schemas/creative-form.js +51 -0
  172. package/dist/features/ads/schemas/firestore.d.ts +140 -0
  173. package/dist/features/ads/schemas/firestore.js +109 -0
  174. package/dist/features/auctions/repository/bid.repository.js +3 -1
  175. package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
  176. package/dist/features/audit-log/schemas/firestore.js +89 -0
  177. package/dist/features/auth/actions/profile-actions.d.ts +69 -1
  178. package/dist/features/auth/actions/profile-actions.js +62 -1
  179. package/dist/features/auth/permissions/constants.js +13 -0
  180. package/dist/features/auth/schemas/firestore.d.ts +16 -2
  181. package/dist/features/auth/schemas/firestore.js +2 -1
  182. package/dist/features/blog/actions/blog-actions.d.ts +6 -0
  183. package/dist/features/blog/actions/blog-actions.js +17 -2
  184. package/dist/features/blog/api/route.js +4 -1
  185. package/dist/features/blog/columns/index.js +5 -0
  186. package/dist/features/blog/components/BlogIndexPageView.js +2 -1
  187. package/dist/features/blog/repository/blog.repository.d.ts +4 -0
  188. package/dist/features/blog/repository/blog.repository.js +5 -0
  189. package/dist/features/blog/schemas/blog-form.d.ts +3 -0
  190. package/dist/features/blog/schemas/blog-form.js +1 -0
  191. package/dist/features/blog/schemas/firestore.d.ts +38 -1
  192. package/dist/features/blog/schemas/firestore.js +23 -0
  193. package/dist/features/blog/schemas/index.d.ts +6 -0
  194. package/dist/features/blog/schemas/index.js +2 -0
  195. package/dist/features/blog/types/index.d.ts +2 -0
  196. package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
  197. package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
  198. package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
  199. package/dist/features/cart/components/PointsTenderPicker.js +15 -0
  200. package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
  201. package/dist/features/cart/components/index.d.ts +2 -0
  202. package/dist/features/cart/components/index.js +1 -0
  203. package/dist/features/cart/repository/cart.repository.d.ts +33 -0
  204. package/dist/features/cart/repository/cart.repository.js +47 -0
  205. package/dist/features/cart/schemas/firestore.d.ts +116 -0
  206. package/dist/features/contact/email.d.ts +27 -10
  207. package/dist/features/contact/email.js +20 -3
  208. package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
  209. package/dist/features/dashboard/components/DashboardHubView.js +56 -0
  210. package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
  211. package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
  212. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
  213. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
  214. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
  215. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
  216. package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
  217. package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
  218. package/dist/features/events/components/EventSaleBanner.js +1 -1
  219. package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
  220. package/dist/features/faq/components/FAQAccordion.js +29 -4
  221. package/dist/features/faq/components/FAQPageContent.js +2 -2
  222. package/dist/features/gateway-events/schemas/index.d.ts +2 -2
  223. package/dist/features/homepage/schemas/index.d.ts +8 -8
  224. package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
  225. package/dist/features/inventory/schemas/stock-reservation.js +103 -0
  226. package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
  227. package/dist/features/invoicing/schemas/firestore.js +45 -0
  228. package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
  229. package/dist/features/invoicing/utils/financial-year.js +53 -0
  230. package/dist/features/jobs/actions/enqueue-job.js +18 -1
  231. package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
  232. package/dist/features/jobs/repository/jobs.repository.js +84 -1
  233. package/dist/features/jobs/schemas/firestore.d.ts +80 -0
  234. package/dist/features/jobs/schemas/firestore.js +37 -0
  235. package/dist/features/layout/AppLayoutShell.d.ts +9 -1
  236. package/dist/features/layout/AppLayoutShell.js +12 -4
  237. package/dist/features/layout/BottomActions.js +2 -1
  238. package/dist/features/layout/BottomNavbar.d.ts +10 -2
  239. package/dist/features/layout/SideActionDock.js +52 -2
  240. package/dist/features/layout/TitleBarLayout.js +13 -4
  241. package/dist/features/layout/TitleBarLayout.style.css +59 -0
  242. package/dist/features/layout/useCtaReveal.d.ts +16 -1
  243. package/dist/features/layout/useCtaReveal.js +17 -26
  244. package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
  245. package/dist/features/ledger/repository/journal.repository.js +312 -0
  246. package/dist/features/ledger/schemas/expenses.d.ts +87 -0
  247. package/dist/features/ledger/schemas/expenses.js +27 -0
  248. package/dist/features/ledger/schemas/firestore.d.ts +183 -0
  249. package/dist/features/ledger/schemas/firestore.js +69 -0
  250. package/dist/features/lottery/schemas/zod.d.ts +6 -6
  251. package/dist/features/media/MediaImage.js +22 -1
  252. package/dist/features/media/upload/ImageUpload.js +1 -1
  253. package/dist/features/obligations/constants/policies.js +24 -1
  254. package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
  255. package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
  256. package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
  257. package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
  258. package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
  259. package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
  260. package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
  261. package/dist/features/orders/components/RefundRequestView.js +19 -1
  262. package/dist/features/orders/components/index.d.ts +4 -0
  263. package/dist/features/orders/components/index.js +2 -0
  264. package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
  265. package/dist/features/orders/constants/order-lane-tabs.js +88 -0
  266. package/dist/features/orders/repository/orders.repository.d.ts +85 -1
  267. package/dist/features/orders/repository/orders.repository.js +205 -6
  268. package/dist/features/orders/schemas/balance.d.ts +40 -0
  269. package/dist/features/orders/schemas/balance.js +47 -0
  270. package/dist/features/orders/schemas/firestore.d.ts +398 -1
  271. package/dist/features/orders/schemas/firestore.js +43 -0
  272. package/dist/features/orders/schemas/index.d.ts +56 -8
  273. package/dist/features/orders/schemas/index.js +12 -0
  274. package/dist/features/orders/types/index.d.ts +47 -0
  275. package/dist/features/orders/utils/courier-block.d.ts +25 -0
  276. package/dist/features/orders/utils/courier-block.js +23 -0
  277. package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
  278. package/dist/features/payment-cases/schemas/firestore.js +1 -0
  279. package/dist/features/payments/repository/payout.repository.js +3 -2
  280. package/dist/features/payments/schemas/firestore.d.ts +92 -1
  281. package/dist/features/payments/schemas/firestore.js +23 -0
  282. package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
  283. package/dist/features/pricing/components/AdminPricingView.js +157 -0
  284. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  285. package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
  286. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  287. package/dist/features/products/schemas/firestore.d.ts +26 -1
  288. package/dist/features/products/schemas/firestore.js +2 -0
  289. package/dist/features/products/schemas/index.d.ts +2 -2
  290. package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
  291. package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
  292. package/dist/features/promotions/actions/coupon-stacking.js +21 -2
  293. package/dist/features/promotions/components/CouponCard.js +13 -0
  294. package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
  295. package/dist/features/promotions/constants/coupon-help.js +9 -1
  296. package/dist/features/promotions/schemas/firestore.d.ts +24 -0
  297. package/dist/features/promotions/schemas/firestore.js +4 -0
  298. package/dist/features/promotions/types/index.d.ts +19 -1
  299. package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
  300. package/dist/features/reviews/repository/reviews.repository.js +16 -0
  301. package/dist/features/scams/components/ScamProfileView.js +2 -2
  302. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  303. package/dist/features/scams/repository/scammer.repository.js +2 -1
  304. package/dist/features/scams/schemas/firestore.d.ts +2 -1
  305. package/dist/features/scams/schemas/firestore.js +2 -1
  306. package/dist/features/search/action-index/tab-entries.js +1 -1
  307. package/dist/features/seller/actions/offer-actions.js +56 -0
  308. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  309. package/dist/features/seller/actions/seller-actions.js +37 -3
  310. package/dist/features/seller/components/DispatchForm.d.ts +11 -0
  311. package/dist/features/seller/components/DispatchForm.js +190 -0
  312. package/dist/features/seller/components/SellerOrdersView.js +221 -27
  313. package/dist/features/seller/components/index.d.ts +1 -0
  314. package/dist/features/seller/components/index.js +1 -0
  315. package/dist/features/seller/hooks/useSellerListingData.js +25 -0
  316. package/dist/features/seller/repository/offer.repository.js +4 -3
  317. package/dist/features/seller/schemas/firestore.d.ts +23 -2
  318. package/dist/features/seller/schemas/firestore.js +3 -2
  319. package/dist/features/seller/schemas/index.d.ts +4 -4
  320. package/dist/features/seller/schemas/order-forms.d.ts +61 -4
  321. package/dist/features/seller/schemas/order-forms.js +41 -8
  322. package/dist/features/shipments/schemas/firestore.d.ts +25 -0
  323. package/dist/features/shipments/schemas/validation.d.ts +4 -4
  324. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
  325. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
  326. package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
  327. package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
  328. package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
  329. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
  330. package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
  331. package/dist/features/stores/repository/store.repository.d.ts +18 -0
  332. package/dist/features/stores/repository/store.repository.js +27 -1
  333. package/dist/features/stores/schemas/firestore.d.ts +112 -0
  334. package/dist/features/stores/schemas/firestore.js +20 -0
  335. package/dist/features/stores/schemas/index.d.ts +6 -6
  336. package/dist/features/stores/types/index.d.ts +19 -0
  337. package/dist/features/support/repository/support.repository.js +72 -6
  338. package/dist/features/support/schemas/firestore.d.ts +17 -0
  339. package/dist/features/support/schemas/index.d.ts +8 -8
  340. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  341. package/dist/index.d.ts +11 -1
  342. package/dist/index.js +33 -1
  343. package/dist/next/routing/route-map.d.ts +112 -0
  344. package/dist/next/routing/route-map.js +63 -0
  345. package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
  346. package/dist/providers/shipping-shiprocket/index.js +84 -1
  347. package/dist/react/contexts/SessionContext.d.ts +17 -1
  348. package/dist/schemas/registry.d.ts +69 -34
  349. package/dist/schemas/sieve.d.ts +2 -2
  350. package/dist/security/pii-schemas.d.ts +1 -1
  351. package/dist/security/pii-schemas.js +45 -0
  352. package/dist/server-entry.d.ts +2 -2
  353. package/dist/server-entry.js +8 -1
  354. package/dist/server.d.ts +36 -1
  355. package/dist/server.js +183 -1
  356. package/dist/styles.css +412 -80
  357. package/dist/tailwind-utilities.css +1 -1
  358. package/dist/tokens/themes/default-dark.js +1 -0
  359. package/dist/tokens/themes/default-light.js +1 -0
  360. package/dist/tokens/themes/required.d.ts +1 -1
  361. package/dist/tokens/themes/required.js +1 -0
  362. package/dist/tokens/tokens.css +15 -0
  363. package/dist/ui/components/Button.d.ts +10 -1
  364. package/dist/ui/components/Button.js +25 -3
  365. package/dist/ui/components/Chart.d.ts +63 -0
  366. package/dist/ui/components/Chart.js +169 -0
  367. package/dist/ui/components/Chart.style.css +214 -0
  368. package/dist/ui/components/Disclaimer.d.ts +19 -0
  369. package/dist/ui/components/Disclaimer.js +83 -0
  370. package/dist/ui/components/OverflowRow.js +54 -2
  371. package/dist/ui/components/OverflowRow.style.css +38 -0
  372. package/dist/ui/components/RichTextEditor.js +99 -8
  373. package/dist/ui/components/chart-spec.d.ts +68 -0
  374. package/dist/ui/components/chart-spec.js +140 -0
  375. package/dist/ui/components/index.style.css +1 -0
  376. package/dist/ui/components/surface-tokens.d.ts +1 -1
  377. package/dist/ui/components/surface-tokens.js +9 -0
  378. package/dist/ui/components/tabs-overflow.js +64 -11
  379. package/dist/ui/components/toolbar-collapse.d.ts +13 -0
  380. package/dist/ui/components/toolbar-collapse.js +10 -1
  381. package/dist/ui/index.d.ts +8 -0
  382. package/dist/ui/index.js +9 -0
  383. package/dist/ui/rich-text/RichText.d.ts +10 -1
  384. package/dist/ui/rich-text/RichText.js +33 -2
  385. package/dist/ui/rich-text/RichText.style.css +83 -79
  386. package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
  387. package/dist/ui/rich-text/RichTextRenderer.js +34 -2
  388. package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
  389. package/dist/ui/rich-text/chart-blocks.js +87 -0
  390. package/package.json +1 -1
  391. package/scripts/seed-cli.mjs +1834 -1822
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Allocating a number from a gapless series (Phase 7, D12).
3
+ *
4
+ * ## The whole design in one paragraph
5
+ *
6
+ * One transaction does three things: read the (series, FY) counter, `.create()`
7
+ * an allocation claim keyed on the subject, and write `lastNumber + 1`. Any one
8
+ * of the three failing rolls back all of them, so there is no state where a
9
+ * number was consumed without being recorded, and no state where a subject
10
+ * holds two numbers.
11
+ *
12
+ * ## 🛑 Why the claim is INSIDE the transaction
13
+ *
14
+ * The obvious shape is "check whether this order already has a number, then
15
+ * allocate". That is a read-then-write race: two concurrent triggers both read
16
+ * "no number", both allocate, and the order ends up with two — one of which is
17
+ * a permanent gap in a series an auditor reads.
18
+ *
19
+ * `.create()` inside the transaction makes it impossible rather than unlikely.
20
+ * A duplicate attempt fails the transaction, and the caller treats that as
21
+ * "already allocated" and reads the existing number back. This is the fourth
22
+ * use of that primitive in this codebase (refund claims, the gateway-event
23
+ * inbox, the gateway-order claim), and the one with the least recoverable
24
+ * failure mode.
25
+ *
26
+ * ## 🛑 Allocate on `paymentStatus → paid`, never at order creation
27
+ *
28
+ * COD and manual orders are created `pending`. Numbering at creation burns a
29
+ * number on every abandoned order, and *gapless* means those gaps are
30
+ * unexplainable — "that one was abandoned" is not an answer an auditor accepts
31
+ * for a missing invoice number.
32
+ */
33
+ import { getAdminDb } from "../../../../providers/db-firebase/index.js";
34
+ import { serverLogger } from "../../../../monitoring/index.js";
35
+ import { normalizeError } from "../../../../errors/normalize.js";
36
+ import { INVOICE_ALLOCATION_COLLECTION, INVOICE_COUNTER_COLLECTION, } from "../../../../features/invoicing/schemas/firestore.js";
37
+ import { CREDIT_NOTE_PREFIX, INVOICE_PREFIX, financialYearLabel, formatSeriesNumber, } from "../../../../features/invoicing/utils/financial-year.js";
38
+ function prefixFor(kind) {
39
+ return kind === "credit_note" ? CREDIT_NOTE_PREFIX : INVOICE_PREFIX;
40
+ }
41
+ /**
42
+ * Allocate (or return the already-allocated) number for one subject.
43
+ *
44
+ * 🛑 Idempotent and NOT best-effort. It throws rather than returning a
45
+ * sentinel, because every caller's correct response to "we could not number
46
+ * this" is to leave the order un-invoiced and retry — a caller that treated
47
+ * failure as "no number needed" would produce a paid order with no invoice,
48
+ * silently.
49
+ */
50
+ export async function allocateSeriesNumber(input) {
51
+ const db = getAdminDb();
52
+ const at = input.at ?? new Date();
53
+ const fy = financialYearLabel(at);
54
+ const counterRef = db
55
+ .collection(INVOICE_COUNTER_COLLECTION)
56
+ .doc(`${input.kind}_${fy}`);
57
+ const claimRef = db.collection(INVOICE_ALLOCATION_COLLECTION).doc(input.subjectId);
58
+ try {
59
+ return await db.runTransaction(async (tx) => {
60
+ /*
61
+ * 🛑 Both reads BEFORE any write — a Firestore transaction requires it,
62
+ * and the claim read is what lets an already-allocated subject return
63
+ * its existing number instead of failing.
64
+ */
65
+ const [claimSnap, counterSnap] = await Promise.all([
66
+ tx.get(claimRef),
67
+ tx.get(counterRef),
68
+ ]);
69
+ if (claimSnap.exists) {
70
+ const existing = claimSnap.data();
71
+ return {
72
+ number: existing.number,
73
+ fy: existing.fy,
74
+ sequence: existing.sequence,
75
+ allocated: false,
76
+ };
77
+ }
78
+ const last = counterSnap.exists
79
+ ? (counterSnap.data().lastNumber ?? 0)
80
+ : 0;
81
+ const sequence = last + 1;
82
+ const number = formatSeriesNumber(prefixFor(input.kind), fy, sequence);
83
+ /*
84
+ * `set(..., { merge: true })` on the counter rather than `update`,
85
+ * because the first allocation of a financial year creates it — and
86
+ * `update` on a missing document throws, which would make 1 April the
87
+ * one day of the year invoicing breaks.
88
+ */
89
+ tx.set(counterRef, {
90
+ kind: input.kind,
91
+ fy,
92
+ lastNumber: sequence,
93
+ lastIssuedAt: at,
94
+ updatedAt: at,
95
+ ...(counterSnap.exists ? {} : { createdAt: at }),
96
+ }, { merge: true });
97
+ /*
98
+ * 🛑 `create`, not `set`. Within a transaction both are atomic against
99
+ * the counter, but `create` additionally refuses if the claim appeared
100
+ * between our read and our write — which is exactly the window a
101
+ * concurrent trigger occupies.
102
+ */
103
+ tx.create(claimRef, {
104
+ kind: input.kind,
105
+ subjectId: input.subjectId,
106
+ orderId: input.orderId,
107
+ number,
108
+ fy,
109
+ sequence,
110
+ issuedAt: at,
111
+ createdAt: at,
112
+ updatedAt: at,
113
+ });
114
+ return { number, fy, sequence, allocated: true };
115
+ });
116
+ }
117
+ catch (err) {
118
+ const normalized = normalizeError(err);
119
+ /*
120
+ * A lost race: the other side created the claim first. Read it back rather
121
+ * than failing — both callers want the same answer, and whoever wrote it
122
+ * wrote the number this subject now permanently has.
123
+ */
124
+ /*
125
+ * Logged, not swallowed. `.catch(() => null)` alone made a Firestore
126
+ * failure indistinguishable from "the claim genuinely is not there" — and
127
+ * the two take opposite branches below: one must fall through to a fresh
128
+ * allocation, the other must NOT, because re-allocating over a claim that
129
+ * exists is how an invoice number gets issued twice. Root Cause #59's
130
+ * shape, in the one place in this codebase where a silent degrade would
131
+ * duplicate a filed document number.
132
+ */
133
+ const after = await claimRef.get().catch((readErr) => {
134
+ const e = normalizeError(readErr);
135
+ serverLogger.error("[invoicing] could not re-read the allocation claim after a race", {
136
+ collection: INVOICE_ALLOCATION_COLLECTION,
137
+ subjectId: input.subjectId,
138
+ error: e.message,
139
+ });
140
+ return null;
141
+ });
142
+ if (after?.exists) {
143
+ const existing = after.data();
144
+ serverLogger.info("[invoicing] allocation race resolved to the existing number", {
145
+ subjectId: input.subjectId,
146
+ number: existing.number,
147
+ });
148
+ return {
149
+ number: existing.number,
150
+ fy: existing.fy,
151
+ sequence: existing.sequence,
152
+ allocated: false,
153
+ };
154
+ }
155
+ serverLogger.error("[invoicing] allocation failed", {
156
+ subjectId: input.subjectId,
157
+ kind: input.kind,
158
+ error: normalized.message,
159
+ });
160
+ throw err;
161
+ }
162
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Credit notes — the document that reverses tax on a refund (Phase 7, 7c).
3
+ *
4
+ * ## 🛑 A refund needs a credit note; it never needs a re-issued invoice
5
+ *
6
+ * A GST invoice is issued once. When money goes back, the reversal is its own
7
+ * numbered document referencing the original invoice — which is why there are
8
+ * two series rather than a revision suffix on one.
9
+ *
10
+ * ## 🛑 Numbered on SETTLEMENT, not on reservation
11
+ *
12
+ * `processRefundAction` is two-phase: it reserves an entry, calls the provider,
13
+ * then settles to `processed` or `failed`. A credit note numbered at
14
+ * reservation would leave a numbered reversal in the series for money that
15
+ * never moved, on every provider failure — and the number could not be
16
+ * withdrawn.
17
+ *
18
+ * So this is called from the SETTLE step, for `processed` only.
19
+ *
20
+ * ## One per refund event, keyed accordingly
21
+ *
22
+ * An order can be refunded several times. The allocation claim is therefore
23
+ * `${orderId}_${refundId}` — keying on the order alone would refuse the second
24
+ * credit note, which is the inverse of the invoice's rule and is why
25
+ * `allocateSeriesNumber` takes `subjectId` separately from `orderId`.
26
+ */
27
+ import type { OrderDocument, OrderRefundEvent } from "../../../../features/orders/schemas/firestore";
28
+ /** Same private prefix family as invoices — refused by the media proxy. */
29
+ export declare const CREDIT_NOTE_PREFIX_PATH = "private/credit-notes";
30
+ /**
31
+ * Renders a credit note. Injected for the same reason as `InvoiceRenderer`:
32
+ * `pdfkit` is a Functions dependency.
33
+ */
34
+ export type CreditNoteRenderer = (order: OrderDocument, refund: OrderRefundEvent, creditNoteNumber: string) => Promise<Buffer>;
35
+ export interface IssueCreditNoteResult {
36
+ creditNoteNumber: string;
37
+ creditNoteStoragePath?: string;
38
+ issued: boolean;
39
+ }
40
+ /**
41
+ * Number and (optionally) render the credit note for one settled refund.
42
+ *
43
+ * 🛑 **Best-effort by design, and that is the opposite of the invoice rule.**
44
+ * It is called from the refund settle path, where the money has ALREADY left
45
+ * the gateway. Throwing here would turn a successful refund into a failed
46
+ * action — the buyer has their money, our code reports an error, and an
47
+ * operator retries a refund that already happened. A missing credit note is a
48
+ * reporting gap recoverable by a backfill; a double refund is not.
49
+ *
50
+ * The invoice path throws for the mirror-image reason: nothing irreversible has
51
+ * happened yet there, so refusing to proceed is the safe direction.
52
+ *
53
+ * `render` is optional — passing none numbers the reversal without producing a
54
+ * document, which is what the GSTR-1 export actually needs (it reconciles
55
+ * numbers and amounts, not PDFs). The PDF is for the buyer.
56
+ */
57
+ export declare function issueCreditNoteForRefund(order: OrderDocument, refund: OrderRefundEvent, render?: CreditNoteRenderer): Promise<IssueCreditNoteResult | null>;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Credit notes — the document that reverses tax on a refund (Phase 7, 7c).
3
+ *
4
+ * ## 🛑 A refund needs a credit note; it never needs a re-issued invoice
5
+ *
6
+ * A GST invoice is issued once. When money goes back, the reversal is its own
7
+ * numbered document referencing the original invoice — which is why there are
8
+ * two series rather than a revision suffix on one.
9
+ *
10
+ * ## 🛑 Numbered on SETTLEMENT, not on reservation
11
+ *
12
+ * `processRefundAction` is two-phase: it reserves an entry, calls the provider,
13
+ * then settles to `processed` or `failed`. A credit note numbered at
14
+ * reservation would leave a numbered reversal in the series for money that
15
+ * never moved, on every provider failure — and the number could not be
16
+ * withdrawn.
17
+ *
18
+ * So this is called from the SETTLE step, for `processed` only.
19
+ *
20
+ * ## One per refund event, keyed accordingly
21
+ *
22
+ * An order can be refunded several times. The allocation claim is therefore
23
+ * `${orderId}_${refundId}` — keying on the order alone would refuse the second
24
+ * credit note, which is the inverse of the invoice's rule and is why
25
+ * `allocateSeriesNumber` takes `subjectId` separately from `orderId`.
26
+ */
27
+ import { randomUUID } from "node:crypto";
28
+ import { getAdminStorage } from "../../../../providers/db-firebase/index.js";
29
+ import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
30
+ import { serverLogger } from "../../../../monitoring/index.js";
31
+ import { normalizeError } from "../../../../errors/normalize.js";
32
+ import { allocateSeriesNumber } from "./allocate.js";
33
+ /** Same private prefix family as invoices — refused by the media proxy. */
34
+ export const CREDIT_NOTE_PREFIX_PATH = "private/credit-notes";
35
+ /**
36
+ * Number and (optionally) render the credit note for one settled refund.
37
+ *
38
+ * 🛑 **Best-effort by design, and that is the opposite of the invoice rule.**
39
+ * It is called from the refund settle path, where the money has ALREADY left
40
+ * the gateway. Throwing here would turn a successful refund into a failed
41
+ * action — the buyer has their money, our code reports an error, and an
42
+ * operator retries a refund that already happened. A missing credit note is a
43
+ * reporting gap recoverable by a backfill; a double refund is not.
44
+ *
45
+ * The invoice path throws for the mirror-image reason: nothing irreversible has
46
+ * happened yet there, so refusing to proceed is the safe direction.
47
+ *
48
+ * `render` is optional — passing none numbers the reversal without producing a
49
+ * document, which is what the GSTR-1 export actually needs (it reconciles
50
+ * numbers and amounts, not PDFs). The PDF is for the buyer.
51
+ */
52
+ export async function issueCreditNoteForRefund(order, refund, render) {
53
+ if (refund.creditNoteNumber) {
54
+ return {
55
+ creditNoteNumber: refund.creditNoteNumber,
56
+ creditNoteStoragePath: refund.creditNoteStoragePath,
57
+ issued: false,
58
+ };
59
+ }
60
+ /*
61
+ * 🛑 Only a refund that actually moved money gets a number. `status`
62
+ * undefined means "committed" to every reader (rows written before the
63
+ * two-phase lifecycle existed carry none), so the test admits those and
64
+ * refuses only an explicit `reserved` or `failed`.
65
+ */
66
+ if (refund.status === "reserved" || refund.status === "failed") {
67
+ return null;
68
+ }
69
+ try {
70
+ const issuedAt = new Date();
71
+ const allocation = await allocateSeriesNumber({
72
+ kind: "credit_note",
73
+ subjectId: `${order.id}_${refund.refundId}`,
74
+ orderId: order.id,
75
+ at: issuedAt,
76
+ });
77
+ let storagePath;
78
+ if (render) {
79
+ storagePath = `${CREDIT_NOTE_PREFIX_PATH}/${order.id}/${randomUUID()}.pdf`;
80
+ const buffer = await render(order, refund, allocation.number);
81
+ await getAdminStorage()
82
+ .bucket()
83
+ .file(storagePath)
84
+ .save(buffer, {
85
+ contentType: "application/pdf",
86
+ metadata: { cacheControl: "private, no-store" },
87
+ resumable: false,
88
+ });
89
+ }
90
+ /*
91
+ * 🛑 Written through the repository's own refund-event mutator, NOT by
92
+ * read-modify-writing `refunds[]`. That array is appended by a transaction
93
+ * precisely because a read-then-`[...existing, event]` write LOSES an
94
+ * event under concurrency (D6), and stamping a credit-note number the
95
+ * naive way would reintroduce exactly that defect on the same array.
96
+ */
97
+ await orderRepository.setRefundCreditNote(order.id, refund.refundId, {
98
+ creditNoteNumber: allocation.number,
99
+ creditNoteIssuedAt: issuedAt,
100
+ ...(storagePath ? { creditNoteStoragePath: storagePath } : {}),
101
+ });
102
+ serverLogger.info("[invoicing] credit note issued", {
103
+ orderId: order.id,
104
+ refundId: refund.refundId,
105
+ creditNoteNumber: allocation.number,
106
+ });
107
+ return {
108
+ creditNoteNumber: allocation.number,
109
+ creditNoteStoragePath: storagePath,
110
+ issued: allocation.allocated,
111
+ };
112
+ }
113
+ catch (err) {
114
+ /*
115
+ * Reported loudly and swallowed — see the 🛑 on this function. A refund
116
+ * that succeeded must not be reported as failed because its paperwork
117
+ * could not be numbered.
118
+ */
119
+ serverLogger.error("[invoicing] credit note FAILED — refund stands, reporting gap", {
120
+ orderId: order.id,
121
+ refundId: refund.refundId,
122
+ error: normalizeError(err).message,
123
+ });
124
+ return null;
125
+ }
126
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * GSTR-1 export (Phase 7d) — the INPUT to a human filing, never a filing.
3
+ *
4
+ * ## 🛑 What this is and is not
5
+ *
6
+ * It is a CSV an accountant opens, checks and uses. It is not a return, it is
7
+ * not filed, and nothing here talks to the GST portal — there is no webhook
8
+ * facility in existence and no GSP contract. Labelling it otherwise would be
9
+ * the most consequential lie in this codebase.
10
+ *
11
+ * ## 🛑 Credit notes are not optional
12
+ *
13
+ * A return listing invoices and no credit notes **does not reconcile**: the
14
+ * output tax declared would be the tax on every sale including the ones that
15
+ * were reversed. So both series are exported, the credit notes as negative
16
+ * amounts, and the file's own total is the net.
17
+ *
18
+ * That is also why the two series exist in the first place — a reversal is its
19
+ * own numbered document, so it has its own row here.
20
+ *
21
+ * ## The rate split comes from `gstByRate`
22
+ *
23
+ * Already on the order (`firestore.ts`), already per rate, already recorded at
24
+ * the moment of supply. Nothing is recomputed from today's tax codes: an order
25
+ * supplied under a rate that has since changed must appear at the rate it was
26
+ * charged, and re-deriving it would silently restate history — the same defect
27
+ * the PDF renderer's own 🛑 records about reading live site settings.
28
+ */
29
+ export interface Gstr1Row {
30
+ /** `LIR/26-27/0001` or `LIRCN/26-27/0001`. */
31
+ documentNumber: string;
32
+ documentType: "invoice" | "credit_note";
33
+ documentDate: string;
34
+ orderId: string;
35
+ /** The buyer's state, which decides CGST+SGST vs IGST. */
36
+ placeOfSupply: string;
37
+ gstRate: number;
38
+ taxableValue: number;
39
+ cgst: number;
40
+ sgst: number;
41
+ igst: number;
42
+ total: number;
43
+ }
44
+ export interface Gstr1Export {
45
+ rows: Gstr1Row[];
46
+ /** Net of credit notes — what the period actually owes. */
47
+ totals: {
48
+ taxableValue: number;
49
+ cgst: number;
50
+ sgst: number;
51
+ igst: number;
52
+ total: number;
53
+ };
54
+ /**
55
+ * Orders in the window that are PAID but carry no invoice number.
56
+ *
57
+ * 🛑 Reported, never silently excluded. A paid order missing from a tax
58
+ * return is the one error this export must not hide, and "the row simply
59
+ * wasn't there" is indistinguishable from "there was nothing to report" in a
60
+ * CSV. Root Cause #84's lesson applied to an accounting artefact: a count
61
+ * that goes quiet is as likely to have stopped looking as to be satisfied.
62
+ */
63
+ unnumberedPaidOrders: string[];
64
+ }
65
+ /**
66
+ * Build the export for a date window.
67
+ *
68
+ * 🛑 Windowed on the INVOICE date, not the order date. A COD order placed on
69
+ * 30 March and paid on 2 April is invoiced in the new financial year, and that
70
+ * is the period its tax belongs to — numbering happens at payment for exactly
71
+ * this reason.
72
+ */
73
+ export declare function buildGstr1Export(from: Date, to: Date): Promise<Gstr1Export>;
74
+ export declare function gstr1ToCsv(data: Gstr1Export): string;
@@ -0,0 +1,251 @@
1
+ /**
2
+ * GSTR-1 export (Phase 7d) — the INPUT to a human filing, never a filing.
3
+ *
4
+ * ## 🛑 What this is and is not
5
+ *
6
+ * It is a CSV an accountant opens, checks and uses. It is not a return, it is
7
+ * not filed, and nothing here talks to the GST portal — there is no webhook
8
+ * facility in existence and no GSP contract. Labelling it otherwise would be
9
+ * the most consequential lie in this codebase.
10
+ *
11
+ * ## 🛑 Credit notes are not optional
12
+ *
13
+ * A return listing invoices and no credit notes **does not reconcile**: the
14
+ * output tax declared would be the tax on every sale including the ones that
15
+ * were reversed. So both series are exported, the credit notes as negative
16
+ * amounts, and the file's own total is the net.
17
+ *
18
+ * That is also why the two series exist in the first place — a reversal is its
19
+ * own numbered document, so it has its own row here.
20
+ *
21
+ * ## The rate split comes from `gstByRate`
22
+ *
23
+ * Already on the order (`firestore.ts`), already per rate, already recorded at
24
+ * the moment of supply. Nothing is recomputed from today's tax codes: an order
25
+ * supplied under a rate that has since changed must appear at the rate it was
26
+ * charged, and re-deriving it would silently restate history — the same defect
27
+ * the PDF renderer's own 🛑 records about reading live site settings.
28
+ */
29
+ import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
30
+ import { roundRupees } from "../../../../utils/number.formatter.js";
31
+ import { serverLogger } from "../../../../monitoring/index.js";
32
+ /** One row per (document, rate) slice — which is what a GSTR-1 line is. */
33
+ function rowsForOrder(order) {
34
+ /*
35
+ * 🛑 `placeOfSupply` ONLY — never parsed out of `shippingAddress`, which is
36
+ * a flat string on this document. Deriving a state from free text to file a
37
+ * tax return is not a thing to do, and an order placed before the field
38
+ * existed is reported as blank rather than guessed at.
39
+ */
40
+ const placeOfSupply = order.placeOfSupply ?? "";
41
+ const date = order.invoiceIssuedAt ?? order.orderDate ?? order.createdAt;
42
+ const dateStr = date instanceof Date ? date.toISOString().slice(0, 10) : "";
43
+ const byRate = order.gstByRate ?? [];
44
+ const invoiceRows = order.invoiceNumber
45
+ ? byRate.map((slice) => ({
46
+ documentNumber: order.invoiceNumber,
47
+ documentType: "invoice",
48
+ documentDate: dateStr,
49
+ orderId: order.id,
50
+ placeOfSupply,
51
+ gstRate: slice.gstRate,
52
+ taxableValue: roundRupees(slice.taxableAmount),
53
+ cgst: roundRupees(slice.cgst),
54
+ sgst: roundRupees(slice.sgst),
55
+ igst: roundRupees(slice.igst),
56
+ total: roundRupees(slice.taxableAmount + slice.cgst + slice.sgst + slice.igst),
57
+ }))
58
+ : [];
59
+ /*
60
+ * ── Credit notes, as NEGATIVE rows ────────────────────────────────────────
61
+ *
62
+ * 🛑 The tax reversed is apportioned across the SAME rate slices the invoice
63
+ * carried, pro-rata on the refunded amount. A refund is a rupee figure with
64
+ * no rate attached, and a multi-rate order's reversal has to be split
65
+ * somehow — pro-rata on the invoice's own slices is the only split that
66
+ * reconciles back to the invoice it adjusts.
67
+ *
68
+ * 🛑 Only SETTLED refunds appear, and only ones that were numbered. A
69
+ * `reserved` entry is money that has not moved; a numbered reversal for it
70
+ * would overstate the period's credit notes.
71
+ */
72
+ const invoiceTotal = byRate.reduce((s, r) => s + r.taxableAmount, 0);
73
+ const creditRows = [];
74
+ for (const refund of order.refunds ?? []) {
75
+ if (!refund.creditNoteNumber)
76
+ continue;
77
+ if (refund.status === "reserved" || refund.status === "failed")
78
+ continue;
79
+ const refundDate = refund.creditNoteIssuedAt ?? refund.refundedAt;
80
+ const refundDateStr = refundDate instanceof Date ? refundDate.toISOString().slice(0, 10) : dateStr;
81
+ // No rate information at all — reported as one untaxed row rather than
82
+ // dropped, so the CSV's total still matches the money that moved.
83
+ if (invoiceTotal <= 0 || byRate.length === 0) {
84
+ creditRows.push({
85
+ documentNumber: refund.creditNoteNumber,
86
+ documentType: "credit_note",
87
+ documentDate: refundDateStr,
88
+ orderId: order.id,
89
+ placeOfSupply,
90
+ gstRate: 0,
91
+ taxableValue: -roundRupees(refund.amount),
92
+ cgst: 0,
93
+ sgst: 0,
94
+ igst: 0,
95
+ total: -roundRupees(refund.amount),
96
+ });
97
+ continue;
98
+ }
99
+ for (const slice of byRate) {
100
+ /*
101
+ * The slice's share of the refund, and then that amount's share of the
102
+ * slice — two ratios, because a refund is a gross rupee figure while a
103
+ * slice is split into taxable value and tax.
104
+ *
105
+ * 🛑 `sliceTotal > 0` guards a 0%-rated (exempt) slice, where the tax is
106
+ * legitimately zero and a naive `portion / sliceTotal` would be a
107
+ * division by zero producing `Infinity` — and `roundRupees(Infinity)` is
108
+ * `NaN`, which propagates into the file's TOTAL row and makes every
109
+ * figure in it unusable. One bad cell would be visible; a NaN total is
110
+ * the whole return.
111
+ */
112
+ const share = slice.taxableAmount / invoiceTotal;
113
+ const portion = refund.amount * share;
114
+ const sliceTotal = slice.taxableAmount + slice.cgst + slice.sgst + slice.igst;
115
+ const taxFraction = sliceTotal > 0 ? portion / sliceTotal : 0;
116
+ creditRows.push({
117
+ documentNumber: refund.creditNoteNumber,
118
+ documentType: "credit_note",
119
+ documentDate: refundDateStr,
120
+ orderId: order.id,
121
+ placeOfSupply,
122
+ gstRate: slice.gstRate,
123
+ taxableValue: -roundRupees(slice.taxableAmount * taxFraction),
124
+ cgst: -roundRupees(slice.cgst * taxFraction),
125
+ sgst: -roundRupees(slice.sgst * taxFraction),
126
+ igst: -roundRupees(slice.igst * taxFraction),
127
+ total: -roundRupees(portion),
128
+ });
129
+ }
130
+ }
131
+ return [...invoiceRows, ...creditRows];
132
+ }
133
+ /**
134
+ * Build the export for a date window.
135
+ *
136
+ * 🛑 Windowed on the INVOICE date, not the order date. A COD order placed on
137
+ * 30 March and paid on 2 April is invoiced in the new financial year, and that
138
+ * is the period its tax belongs to — numbering happens at payment for exactly
139
+ * this reason.
140
+ */
141
+ export async function buildGstr1Export(from, to) {
142
+ const orders = await orderRepository.listInvoicedBetween(from, to);
143
+ const rows = [];
144
+ const unnumberedPaidOrders = [];
145
+ for (const order of orders) {
146
+ if (order.paymentStatus === "paid" && !order.invoiceNumber) {
147
+ unnumberedPaidOrders.push(order.id);
148
+ continue;
149
+ }
150
+ rows.push(...rowsForOrder(order));
151
+ }
152
+ const totals = rows.reduce((acc, r) => ({
153
+ taxableValue: acc.taxableValue + r.taxableValue,
154
+ cgst: acc.cgst + r.cgst,
155
+ sgst: acc.sgst + r.sgst,
156
+ igst: acc.igst + r.igst,
157
+ total: acc.total + r.total,
158
+ }), { taxableValue: 0, cgst: 0, sgst: 0, igst: 0, total: 0 });
159
+ if (unnumberedPaidOrders.length > 0) {
160
+ serverLogger.warn("[gstr1] paid orders with no invoice number in window", {
161
+ count: unnumberedPaidOrders.length,
162
+ from: from.toISOString(),
163
+ to: to.toISOString(),
164
+ });
165
+ }
166
+ return {
167
+ rows,
168
+ totals: {
169
+ taxableValue: roundRupees(totals.taxableValue),
170
+ cgst: roundRupees(totals.cgst),
171
+ sgst: roundRupees(totals.sgst),
172
+ igst: roundRupees(totals.igst),
173
+ total: roundRupees(totals.total),
174
+ },
175
+ unnumberedPaidOrders,
176
+ };
177
+ }
178
+ const CSV_HEADER = [
179
+ "Document Number",
180
+ "Document Type",
181
+ "Document Date",
182
+ "Order ID",
183
+ "Place of Supply",
184
+ "GST Rate",
185
+ "Taxable Value",
186
+ "CGST",
187
+ "SGST",
188
+ "IGST",
189
+ "Total",
190
+ ].join(",");
191
+ /**
192
+ * 🛑 Every field is quoted and internal quotes are doubled.
193
+ *
194
+ * An invoice number contains `/`, a place of supply can contain a comma, and a
195
+ * CSV whose columns shift by one on a single row is worse than no CSV — it
196
+ * reconciles to a plausible wrong number rather than failing to open.
197
+ */
198
+ function csvCell(value) {
199
+ const s = String(value);
200
+ return `"${s.replace(/"/g, '""')}"`;
201
+ }
202
+ export function gstr1ToCsv(data) {
203
+ const lines = [CSV_HEADER];
204
+ for (const r of data.rows) {
205
+ lines.push([
206
+ r.documentNumber,
207
+ r.documentType === "credit_note" ? "Credit Note" : "Invoice",
208
+ r.documentDate,
209
+ r.orderId,
210
+ r.placeOfSupply,
211
+ r.gstRate,
212
+ r.taxableValue.toFixed(2),
213
+ r.cgst.toFixed(2),
214
+ r.sgst.toFixed(2),
215
+ r.igst.toFixed(2),
216
+ r.total.toFixed(2),
217
+ ]
218
+ .map(csvCell)
219
+ .join(","));
220
+ }
221
+ /*
222
+ * A TOTAL row, and it is net of credit notes. An accountant's first act is to
223
+ * check the file's own total against their own figure; making them sum 400
224
+ * rows to do it is how a transcription error enters a tax return.
225
+ */
226
+ lines.push([
227
+ "TOTAL",
228
+ "",
229
+ "",
230
+ "",
231
+ "",
232
+ "",
233
+ data.totals.taxableValue.toFixed(2),
234
+ data.totals.cgst.toFixed(2),
235
+ data.totals.sgst.toFixed(2),
236
+ data.totals.igst.toFixed(2),
237
+ data.totals.total.toFixed(2),
238
+ ]
239
+ .map(csvCell)
240
+ .join(","));
241
+ /*
242
+ * 🛑 The exceptions go IN the file, not only in a log. The person filing is
243
+ * not the person reading our logs, and a paid order absent from a tax return
244
+ * is the one error this export must not hide.
245
+ */
246
+ if (data.unnumberedPaidOrders.length > 0) {
247
+ lines.push("");
248
+ lines.push(csvCell(`WARNING: ${data.unnumberedPaidOrders.length} paid order(s) in this window carry no invoice number and are NOT included above: ${data.unnumberedPaidOrders.join(" ")}`));
249
+ }
250
+ return lines.join("\n");
251
+ }