@mohasinac/appkit 4.59.0 → 4.60.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 (532) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
  3. package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
  4. package/dist/_internal/server/features/brands/actions.js +78 -4
  5. package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
  6. package/dist/_internal/server/features/checkout/actions.js +668 -183
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
  8. package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
  9. package/dist/_internal/server/features/gateway-events/index.js +10 -0
  10. package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
  11. package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
  12. package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
  13. package/dist/_internal/server/features/gateway-events/redact.js +151 -0
  14. package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
  15. package/dist/_internal/server/features/grievance/actions.js +173 -0
  16. package/dist/_internal/server/features/grievance/index.d.ts +8 -0
  17. package/dist/_internal/server/features/grievance/index.js +8 -0
  18. package/dist/_internal/server/features/grouped/data.js +28 -3
  19. package/dist/_internal/server/features/lottery/actions.js +99 -4
  20. package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
  21. package/dist/_internal/server/features/order-completion/actions.js +336 -0
  22. package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
  23. package/dist/_internal/server/features/order-completion/index.js +7 -0
  24. package/dist/_internal/server/features/orders/actions.d.ts +13 -0
  25. package/dist/_internal/server/features/orders/actions.js +56 -2
  26. package/dist/_internal/server/features/orders/adapters.d.ts +20 -2
  27. package/dist/_internal/server/features/orders/adapters.js +44 -0
  28. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
  29. package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
  30. package/dist/_internal/server/features/orders/index.d.ts +2 -1
  31. package/dist/_internal/server/features/orders/index.js +1 -1
  32. package/dist/_internal/server/features/orders/service.d.ts +60 -0
  33. package/dist/_internal/server/features/orders/service.js +74 -0
  34. package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
  35. package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
  36. package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
  37. package/dist/_internal/server/features/payment-cases/index.js +9 -0
  38. package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
  39. package/dist/_internal/server/features/payouts/actions.js +84 -10
  40. package/dist/_internal/server/features/points/adjust.d.ts +61 -0
  41. package/dist/_internal/server/features/points/adjust.js +121 -0
  42. package/dist/_internal/server/features/points/award.d.ts +65 -0
  43. package/dist/_internal/server/features/points/award.js +145 -0
  44. package/dist/_internal/server/features/price-index/market.d.ts +33 -0
  45. package/dist/_internal/server/features/price-index/market.js +54 -1
  46. package/dist/_internal/server/features/products/data.js +40 -22
  47. package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
  48. package/dist/_internal/server/features/protection-claims/actions.js +228 -0
  49. package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
  50. package/dist/_internal/server/features/protection-claims/index.js +8 -0
  51. package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
  52. package/dist/_internal/server/features/refunds/actions.js +259 -17
  53. package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
  54. package/dist/_internal/server/features/refunds/capacity.js +37 -0
  55. package/dist/_internal/server/features/reviews/actions.js +3 -2
  56. package/dist/_internal/server/features/search/index-build/sources.js +20 -1
  57. package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
  58. package/dist/_internal/server/features/shipping/reconcile.js +34 -3
  59. package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
  60. package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
  61. package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
  62. package/dist/_internal/server/features/stores/tabs.js +24 -4
  63. package/dist/_internal/server/functions/https.d.ts +31 -1
  64. package/dist/_internal/server/functions/https.js +52 -1
  65. package/dist/_internal/server/functions/scheduled.d.ts +72 -1
  66. package/dist/_internal/server/functions/scheduled.js +124 -1
  67. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
  68. package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
  69. package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
  70. package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
  71. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
  72. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
  73. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  74. package/dist/_internal/server/jobs/core/index.js +2 -0
  75. package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
  76. package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
  77. package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
  78. package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
  79. package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
  80. package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
  81. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
  82. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
  83. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
  84. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
  85. package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
  86. package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
  87. package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
  88. package/dist/_internal/server/jobs/handlers/index.js +5 -0
  89. package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
  90. package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
  91. package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
  92. package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
  93. package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
  94. package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
  95. package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
  96. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  97. package/dist/_internal/shared/actions/action-registry.js +71 -0
  98. package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
  99. package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
  100. package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
  101. package/dist/_internal/shared/checkout/lanes.js +46 -0
  102. package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
  103. package/dist/_internal/shared/checkout/order-math.js +251 -3
  104. package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
  105. package/dist/_internal/shared/checkout/refundable-base.js +122 -0
  106. package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
  107. package/dist/_internal/shared/features/auctions/config.js +30 -1
  108. package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
  109. package/dist/_internal/shared/features/brands/schema.js +18 -0
  110. package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
  111. package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
  112. package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
  113. package/dist/_internal/shared/features/print/label-profiles.js +350 -0
  114. package/dist/_internal/shared/features/products/to-product-item.js +33 -5
  115. package/dist/_internal/shared/fees/calculator.d.ts +31 -2
  116. package/dist/_internal/shared/fees/calculator.js +103 -5
  117. package/dist/_internal/shared/fees/india-states.d.ts +195 -0
  118. package/dist/_internal/shared/fees/india-states.js +190 -0
  119. package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
  120. package/dist/_internal/shared/fees/payout-hold.js +74 -0
  121. package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
  122. package/dist/_internal/shared/obligations/deadlines.js +155 -0
  123. package/dist/_internal/shared/shipping/quote.d.ts +96 -0
  124. package/dist/_internal/shared/shipping/quote.js +67 -0
  125. package/dist/_internal/shared/time/business-days.d.ts +91 -0
  126. package/dist/_internal/shared/time/business-days.js +185 -0
  127. package/dist/cli/index.js +0 -2
  128. package/dist/client.d.ts +10 -4
  129. package/dist/client.js +29 -3
  130. package/dist/configs/tailwind.d.ts +0 -12
  131. package/dist/configs/tailwind.js +28 -15
  132. package/dist/constants/api-endpoints.d.ts +51 -9
  133. package/dist/constants/api-endpoints.js +23 -7
  134. package/dist/constants/index.d.ts +1 -1
  135. package/dist/constants/index.js +1 -1
  136. package/dist/contracts/index.d.ts +1 -1
  137. package/dist/contracts/payment.d.ts +131 -0
  138. package/dist/features/about/components/AboutView.js +1 -1
  139. package/dist/features/about/components/DeveloperView.js +5 -2
  140. package/dist/features/about/components/FAQPageView.js +2 -1
  141. package/dist/features/about/components/FeesView.js +2 -1
  142. package/dist/features/about/components/HelpPageView.js +2 -1
  143. package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
  144. package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
  145. package/dist/features/about/components/HowEmiWorksView.js +2 -1
  146. package/dist/features/about/components/HowOffersWorkView.js +2 -1
  147. package/dist/features/about/components/HowOrdersWorkView.js +2 -1
  148. package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
  149. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
  150. package/dist/features/about/components/HowReviewsWorkView.js +2 -1
  151. package/dist/features/about/components/PolicyPageView.js +2 -1
  152. package/dist/features/about/components/ProseHero.d.ts +73 -0
  153. package/dist/features/about/components/ProseHero.js +18 -0
  154. package/dist/features/about/components/SecurityPrivacyView.js +2 -1
  155. package/dist/features/about/components/ShippingPolicyView.js +2 -1
  156. package/dist/features/about/components/TrackOrderView.js +2 -1
  157. package/dist/features/about/components/UnauthorizedView.js +1 -1
  158. package/dist/features/about/index.d.ts +2 -0
  159. package/dist/features/about/index.js +5 -0
  160. package/dist/features/account/actions/address-actions.d.ts +26 -2
  161. package/dist/features/account/actions/address-actions.js +25 -1
  162. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  163. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  164. package/dist/features/account/components/UserOrdersView.js +17 -0
  165. package/dist/features/account/components/UserSidebar.js +1 -1
  166. package/dist/features/account/hooks/useNotifications.js +29 -0
  167. package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
  168. package/dist/features/admin/components/AdminBeysView.js +2 -2
  169. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  170. package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
  171. package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
  172. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  173. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  174. package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
  175. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  176. package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
  177. package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
  178. package/dist/features/admin/components/AdminFaqsView.js +2 -2
  179. package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
  180. package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
  181. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  182. package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
  183. package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
  184. package/dist/features/admin/components/AdminPartsView.js +2 -2
  185. package/dist/features/admin/components/AdminProductsView.js +75 -4
  186. package/dist/features/admin/components/AdminSidebar.js +2 -2
  187. package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
  188. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  189. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  190. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  191. package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
  192. package/dist/features/admin/components/AdminUsersView.js +72 -1
  193. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  194. package/dist/features/admin/components/AdminViewCards.js +4 -4
  195. package/dist/features/admin/components/DataListingView.d.ts +28 -0
  196. package/dist/features/admin/components/DataListingView.js +175 -14
  197. package/dist/features/admin/components/DataTable.d.ts +12 -1
  198. package/dist/features/admin/components/DataTable.js +3 -3
  199. package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
  200. package/dist/features/admin/components/OwnerQuickActions.js +60 -2
  201. package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
  202. package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
  203. package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
  204. package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
  205. package/dist/features/admin/components/index.d.ts +4 -0
  206. package/dist/features/admin/components/index.js +6 -0
  207. package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
  208. package/dist/features/admin/constants/filter-tabs.js +106 -0
  209. package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
  210. package/dist/features/admin/repository/site-settings.repository.js +82 -1
  211. package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
  212. package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
  213. package/dist/features/admin/schemas/firestore.js +5 -1
  214. package/dist/features/admin/schemas/site-settings-form.js +30 -1
  215. package/dist/features/auctions/actions/bid-actions.js +13 -1
  216. package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
  217. package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
  218. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
  219. package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
  220. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
  221. package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
  222. package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
  223. package/dist/features/audit-log/schemas/firestore.js +14 -0
  224. package/dist/features/auth/permissions/constants.d.ts +17 -1
  225. package/dist/features/auth/permissions/constants.js +18 -0
  226. package/dist/features/blog/components/BlogPostView.js +1 -1
  227. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
  228. package/dist/features/categories/api/[id]/description-template/route.js +107 -1
  229. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  230. package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
  231. package/dist/features/categories/components/BundleDetailView.js +1 -1
  232. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  233. package/dist/features/categories/components/CategoryForm.js +12 -1
  234. package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
  235. package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
  236. package/dist/features/categories/repository/market-price-index.repository.js +105 -0
  237. package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
  238. package/dist/features/categories/repository/price-observation.repository.js +132 -0
  239. package/dist/features/events/components/EventSaleBanner.js +1 -1
  240. package/dist/features/events/components/EventStatusBadge.js +1 -1
  241. package/dist/features/faq/components/FAQAccordion.js +2 -1
  242. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  243. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  244. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  245. package/dist/features/filters/FilterFacetSection.js +1 -1
  246. package/dist/features/filters/SwitchFilter.js +1 -1
  247. package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
  248. package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
  249. package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
  250. package/dist/features/gateway-events/schemas/firestore.js +125 -0
  251. package/dist/features/gateway-events/schemas/index.d.ts +81 -0
  252. package/dist/features/gateway-events/schemas/index.js +79 -0
  253. package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
  254. package/dist/features/homepage/components/AnnouncementBar.js +37 -1
  255. package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
  256. package/dist/features/homepage/components/BrandsSection.js +1 -1
  257. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  258. package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
  259. package/dist/features/homepage/components/HeroCarousel.js +2 -2
  260. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  261. package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
  262. package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
  263. package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
  264. package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
  265. package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
  266. package/dist/features/inventory/components/ReceiveStationView.js +413 -0
  267. package/dist/features/inventory/components/operator-message.d.ts +29 -0
  268. package/dist/features/inventory/components/operator-message.js +41 -0
  269. package/dist/features/inventory/index.d.ts +13 -0
  270. package/dist/features/inventory/index.js +28 -0
  271. package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
  272. package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
  273. package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
  274. package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
  275. package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
  276. package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
  277. package/dist/features/inventory/schemas/firestore.d.ts +197 -0
  278. package/dist/features/inventory/schemas/firestore.js +159 -0
  279. package/dist/features/layout/AppLayoutShell.d.ts +12 -1
  280. package/dist/features/layout/AppLayoutShell.js +25 -12
  281. package/dist/features/layout/AutoBreadcrumbs.js +162 -3
  282. package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
  283. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  284. package/dist/features/layout/BottomNavbar.js +2 -2
  285. package/dist/features/media/MediaAvatar.js +1 -1
  286. package/dist/features/media/MediaImage.d.ts +24 -4
  287. package/dist/features/media/MediaImage.js +44 -4
  288. package/dist/features/media/MediaLightbox.js +1 -1
  289. package/dist/features/media/modals/ImageCropModal.js +1 -1
  290. package/dist/features/media/modals/ImageEditor.js +1 -1
  291. package/dist/features/media/upload/MediaUploadField.js +91 -3
  292. package/dist/features/obligations/constants/policies.d.ts +92 -0
  293. package/dist/features/obligations/constants/policies.js +378 -0
  294. package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
  295. package/dist/features/obligations/repository/obligations.repository.js +158 -0
  296. package/dist/features/obligations/schemas/firestore.d.ts +160 -0
  297. package/dist/features/obligations/schemas/firestore.js +87 -0
  298. package/dist/features/orders/actions/order-actions.d.ts +43 -4
  299. package/dist/features/orders/actions/order-actions.js +60 -3
  300. package/dist/features/orders/actions/refund-actions.js +70 -10
  301. package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
  302. package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
  303. package/dist/features/orders/components/OrdersList.js +2 -2
  304. package/dist/features/orders/components/RefundHistoryTable.js +3 -1
  305. package/dist/features/orders/components/index.d.ts +2 -0
  306. package/dist/features/orders/components/index.js +6 -0
  307. package/dist/features/orders/constants/transitions.d.ts +59 -0
  308. package/dist/features/orders/constants/transitions.js +104 -0
  309. package/dist/features/orders/repository/orders.repository.d.ts +109 -6
  310. package/dist/features/orders/repository/orders.repository.js +464 -21
  311. package/dist/features/orders/schemas/firestore.d.ts +270 -0
  312. package/dist/features/orders/schemas/firestore.js +24 -0
  313. package/dist/features/orders/schemas/index.d.ts +61 -0
  314. package/dist/features/orders/schemas/index.js +22 -0
  315. package/dist/features/orders/types/index.d.ts +79 -0
  316. package/dist/features/parts/components/PartsIndexPageView.js +8 -1
  317. package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
  318. package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
  319. package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
  320. package/dist/features/payment-cases/schemas/firestore.js +105 -0
  321. package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
  322. package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
  323. package/dist/features/payments/repository/payout.repository.d.ts +0 -1
  324. package/dist/features/payments/repository/payout.repository.js +0 -1
  325. package/dist/features/points/repository/points.repository.d.ts +122 -0
  326. package/dist/features/points/repository/points.repository.js +304 -1
  327. package/dist/features/points/schemas/adjust-form.d.ts +58 -0
  328. package/dist/features/points/schemas/adjust-form.js +63 -0
  329. package/dist/features/points/schemas/firestore.d.ts +108 -1
  330. package/dist/features/points/schemas/firestore.js +84 -0
  331. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
  332. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  333. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  334. package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
  335. package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
  336. package/dist/features/price-index/market-stats.d.ts +82 -0
  337. package/dist/features/price-index/market-stats.js +230 -0
  338. package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
  339. package/dist/features/print/components/BoxLabelPrintView.js +66 -0
  340. package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
  341. package/dist/features/print/components/LabelProfilePicker.js +38 -0
  342. package/dist/features/print/components/labels.d.ts +117 -0
  343. package/dist/features/print/components/labels.js +258 -0
  344. package/dist/features/print/components/labels.style.css +46 -0
  345. package/dist/features/print/index.d.ts +6 -0
  346. package/dist/features/print/index.js +16 -0
  347. package/dist/features/products/columns/productTableColumns.js +5 -4
  348. package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
  349. package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
  350. package/dist/features/products/components/PrizeDrawCollage.js +1 -1
  351. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  352. package/dist/features/products/components/PrizeRevealModal.js +2 -2
  353. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  354. package/dist/features/products/components/ProductForm.js +34 -23
  355. package/dist/features/products/components/ProductGrid.js +86 -62
  356. package/dist/features/products/constants/card-badges.d.ts +97 -0
  357. package/dist/features/products/constants/card-badges.js +100 -0
  358. package/dist/features/products/repository/products.repository.js +34 -1
  359. package/dist/features/products/schemas/firestore.d.ts +46 -3
  360. package/dist/features/products/schemas/firestore.js +21 -0
  361. package/dist/features/promotions/components/PromotionsView.js +1 -1
  362. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
  363. package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
  364. package/dist/features/promotions/schemas/firestore.js +30 -3
  365. package/dist/features/promotions/schemas/index.d.ts +6 -6
  366. package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
  367. package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
  368. package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
  369. package/dist/features/protection-claims/schemas/firestore.js +130 -0
  370. package/dist/features/reviews/actions/review-actions.js +3 -2
  371. package/dist/features/reviews/components/ReviewModal.js +1 -1
  372. package/dist/features/reviews/components/ReviewsList.js +1 -1
  373. package/dist/features/reviews/schemas/firestore.d.ts +20 -1
  374. package/dist/features/scams/constants/scam-types.d.ts +2 -0
  375. package/dist/features/scams/constants/scam-types.js +18 -0
  376. package/dist/features/scams/schemas/report-form.d.ts +3 -3
  377. package/dist/features/scams/schemas/report-form.js +26 -1
  378. package/dist/features/search/components/Search.js +9 -9
  379. package/dist/features/search/components/SearchResultsClient.js +18 -3
  380. package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
  381. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  382. package/dist/features/seller/actions/offer-actions.js +16 -1
  383. package/dist/features/seller/actions/seller-actions.js +14 -3
  384. package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
  385. package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
  386. package/dist/features/seller/components/PrintCenterView.js +41 -30
  387. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  388. package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
  389. package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
  390. package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
  391. package/dist/features/seller/components/SellerProductShell.js +123 -13
  392. package/dist/features/seller/components/SellerReviewsView.js +4 -2
  393. package/dist/features/seller/components/SellerSidebar.js +1 -1
  394. package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
  395. package/dist/features/seller/schemas/coupon-form.js +27 -0
  396. package/dist/features/seller/schemas/product-form.d.ts +3 -0
  397. package/dist/features/seller/schemas/product-form.js +5 -0
  398. package/dist/features/shell/FormShell.js +2 -2
  399. package/dist/features/shell/QuickFormDrawer.js +14 -0
  400. package/dist/features/shell/SectionForm.d.ts +19 -0
  401. package/dist/features/shell/SectionForm.js +133 -9
  402. package/dist/features/shell/SectionForm.style.css +54 -0
  403. package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
  404. package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
  405. package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
  406. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  407. package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
  408. package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
  409. package/dist/features/stores/components/StoreGuideHubView.js +1 -1
  410. package/dist/features/stores/components/StoreHeader.js +1 -1
  411. package/dist/features/support/schemas/firestore.d.ts +73 -2
  412. package/dist/features/support/schemas/firestore.js +59 -0
  413. package/dist/index.d.ts +16 -24
  414. package/dist/index.js +38 -47
  415. package/dist/next/ErrorBoundary.js +1 -1
  416. package/dist/next/routing/route-map.d.ts +24 -0
  417. package/dist/next/routing/route-map.js +40 -0
  418. package/dist/providers/payment-manual/index.d.ts +15 -1
  419. package/dist/providers/payment-manual/index.js +37 -0
  420. package/dist/providers/payment-phonepe/index.d.ts +14 -1
  421. package/dist/providers/payment-phonepe/index.js +36 -0
  422. package/dist/providers/payment-razorpay/index.d.ts +44 -1
  423. package/dist/providers/payment-razorpay/index.js +99 -0
  424. package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
  425. package/dist/providers/shipping-shiprocket/index.js +18 -0
  426. package/dist/schemas/registry.d.ts +44 -11
  427. package/dist/server-entry.d.ts +2 -0
  428. package/dist/server-entry.js +27 -0
  429. package/dist/server.d.ts +43 -0
  430. package/dist/server.js +98 -0
  431. package/dist/styles.css +418 -149
  432. package/dist/tailwind-utilities.css +1 -1
  433. package/dist/tokens/themes/default-dark.js +15 -12
  434. package/dist/tokens/themes/default-light.js +14 -11
  435. package/dist/tokens/tokens.css +106 -23
  436. package/dist/ui/DataTable.style.css +4 -4
  437. package/dist/ui/columns/cell-renderers.d.ts +20 -0
  438. package/dist/ui/columns/cell-renderers.js +26 -1
  439. package/dist/ui/columns/index.d.ts +1 -1
  440. package/dist/ui/columns/index.js +4 -1
  441. package/dist/ui/components/Badge.style.css +1 -1
  442. package/dist/ui/components/Breadcrumb.js +19 -1
  443. package/dist/ui/components/BulkActionBar.style.css +4 -4
  444. package/dist/ui/components/Button.style.css +1 -1
  445. package/dist/ui/components/Checkbox.style.css +1 -1
  446. package/dist/ui/components/FallbackShell.js +1 -1
  447. package/dist/ui/components/Form.d.ts +14 -1
  448. package/dist/ui/components/Form.js +2 -2
  449. package/dist/ui/components/FormField.js +18 -4
  450. package/dist/ui/components/FormField.style.css +43 -3
  451. package/dist/ui/components/GatedPrice.style.css +1 -1
  452. package/dist/ui/components/IconButton.style.css +1 -1
  453. package/dist/ui/components/Input.js +22 -1
  454. package/dist/ui/components/Input.style.css +38 -22
  455. package/dist/ui/components/ListingFilterDrawer.js +1 -1
  456. package/dist/ui/components/ListingToolbar.js +1 -1
  457. package/dist/ui/components/PaginatedSelect.js +0 -0
  458. package/dist/ui/components/Radio.style.css +1 -1
  459. package/dist/ui/components/Repeater.d.ts +53 -0
  460. package/dist/ui/components/Repeater.js +7 -0
  461. package/dist/ui/components/RichTextEditor.d.ts +20 -1
  462. package/dist/ui/components/RichTextEditor.js +23 -2
  463. package/dist/ui/components/Select.style.css +7 -21
  464. package/dist/ui/components/Semantic.js +27 -3
  465. package/dist/ui/components/TagInput.style.css +4 -9
  466. package/dist/ui/components/Textarea.style.css +4 -18
  467. package/dist/ui/components/Toggle.style.css +1 -1
  468. package/dist/ui/components/Typography.d.ts +3 -3
  469. package/dist/ui/components/Typography.js +15 -15
  470. package/dist/ui/components/ViewToggle.style.css +4 -4
  471. package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
  472. package/dist/ui/forms/AddAnotherToggle.js +56 -0
  473. package/dist/ui/forms/ColorPickerField.js +15 -2
  474. package/dist/ui/forms/FieldCheckbox.js +15 -2
  475. package/dist/ui/forms/FieldInput.d.ts +22 -1
  476. package/dist/ui/forms/FieldInput.js +19 -5
  477. package/dist/ui/forms/FieldLabel.d.ts +35 -0
  478. package/dist/ui/forms/FieldLabel.js +70 -0
  479. package/dist/ui/forms/FieldSelect.d.ts +4 -1
  480. package/dist/ui/forms/FieldSelect.js +27 -5
  481. package/dist/ui/forms/FieldTextarea.d.ts +4 -1
  482. package/dist/ui/forms/FieldTextarea.js +22 -5
  483. package/dist/ui/forms/FormShell.d.ts +17 -1
  484. package/dist/ui/forms/FormShell.js +36 -2
  485. package/dist/ui/forms/FormShell.style.css +41 -33
  486. package/dist/ui/forms/index.d.ts +5 -1
  487. package/dist/ui/forms/index.js +2 -0
  488. package/dist/ui/icons/icon-registry.d.ts +1 -0
  489. package/dist/ui/icons/icon-registry.js +17 -1
  490. package/dist/utils/id-generators.d.ts +80 -0
  491. package/dist/utils/id-generators.js +93 -0
  492. package/dist/utils/search-txt-builders.d.ts +12 -0
  493. package/dist/utils/search-txt-builders.js +17 -0
  494. package/package.json +1 -1
  495. package/scripts/seed-cli.mjs +106 -5
  496. package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
  497. package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
  498. package/dist/features/loyalty/api/balance/route.d.ts +0 -12
  499. package/dist/features/loyalty/api/balance/route.js +0 -41
  500. package/dist/features/loyalty/api/earn/route.d.ts +0 -12
  501. package/dist/features/loyalty/api/earn/route.js +0 -38
  502. package/dist/features/loyalty/api/history/route.d.ts +0 -12
  503. package/dist/features/loyalty/api/history/route.js +0 -58
  504. package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
  505. package/dist/features/loyalty/api/redeem/route.js +0 -38
  506. package/dist/features/loyalty/columns/index.d.ts +0 -17
  507. package/dist/features/loyalty/columns/index.js +0 -40
  508. package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
  509. package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
  510. package/dist/features/loyalty/components/index.d.ts +0 -1
  511. package/dist/features/loyalty/components/index.js +0 -1
  512. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
  513. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
  514. package/dist/features/loyalty/index.d.ts +0 -6
  515. package/dist/features/loyalty/index.js +0 -6
  516. package/dist/features/loyalty/manifest.d.ts +0 -2
  517. package/dist/features/loyalty/manifest.js +0 -16
  518. package/dist/features/loyalty/messages/en.json +0 -19
  519. package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
  520. package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
  521. package/dist/features/loyalty/schemas/index.d.ts +0 -85
  522. package/dist/features/loyalty/schemas/index.js +0 -40
  523. package/dist/features/loyalty/server.d.ts +0 -6
  524. package/dist/features/loyalty/server.js +0 -6
  525. package/dist/features/loyalty/types/index.d.ts +0 -31
  526. package/dist/features/loyalty/types/index.js +0 -1
  527. package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
  528. package/dist/features/loyalty/types/loyalty-config.js +0 -1
  529. package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
  530. package/dist/features/loyalty/types/loyalty-math.js +0 -27
  531. package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
  532. package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
@@ -6,13 +6,36 @@ import { storeRepository, userRepository, orderRepository, payoutRepository, sit
6
6
  import { BATCH_LIMIT } from "../handlers/messages.js";
7
7
  import { getDefaultCurrency } from "../../../../core/index.js";
8
8
  import { computePayoutDeduction } from "../../../shared/fees/calculator.js";
9
- import { ordersTaxableValue } from "../../../shared/checkout/order-math.js";
9
+ import { payoutCutoff } from "../../../shared/fees/payout-hold.js";
10
+ import { PROTECTION_CLAIM_WINDOW_HOURS } from "../../../shared/features/shipping/protections.js";
11
+ import { ordersTaxableValue, ordersShippingReimbursement, } from "../../../shared/checkout/order-math.js";
10
12
  export async function runWeeklyPayoutEligibility(ctx) {
11
13
  // `FEATURE_PAYOUTS` gate deleted 2026-10-19 — see `autoPayoutEligibility.ts`.
12
- ctx.logger.info("Starting weekly payout eligibility sweep");
13
14
  const siteSettings = await siteSettingsRepository.getSingleton();
14
15
  const commissions = siteSettings.commissions;
15
- const eligible = await orderRepository.getEligibleForPayoutSweep();
16
+ /*
17
+ * 🛑 This sweep used to call `getEligibleForPayoutSweep()`, which filtered
18
+ * on `payoutStatus == "eligible" && status == "delivered"` and **nothing
19
+ * else** — no time cutoff of any kind. So every Saturday it paid out orders
20
+ * delivered the day before, which made the 7-day hold in the sibling daily
21
+ * job unreachable as a floor: whatever that one withheld, this one released.
22
+ *
23
+ * It now consumes the SAME `payoutCutoff` the daily sweep does. Two sweeps
24
+ * with two predicates is how one intended hold ended up honoured by neither.
25
+ */
26
+ const { cutoff, hold } = payoutCutoff({
27
+ payoutHoldDays: commissions?.payoutHoldDays,
28
+ returnWindowDays: siteSettings.returns?.windowDays,
29
+ maxClaimWindowHours: Math.max(PROTECTION_CLAIM_WINDOW_HOURS.shipping, PROTECTION_CLAIM_WINDOW_HOURS.sale),
30
+ }, { onWarn: (m, meta) => ctx.logger.warn(m, meta) });
31
+ ctx.logger.info("Starting weekly payout eligibility sweep", {
32
+ holdDays: hold.days,
33
+ holdSource: hold.source,
34
+ cutoff: cutoff.toISOString(),
35
+ });
36
+ const eligible = await orderRepository.getEligibleAutomatic(cutoff, {
37
+ onWarn: (m, meta) => ctx.logger.warn(m, meta),
38
+ });
16
39
  if (eligible.length === 0) {
17
40
  ctx.logger.info("No eligible delivered orders found");
18
41
  return { payoutsCreated: 0, ordersProcessed: 0, payoutIds: [] };
@@ -44,7 +67,15 @@ export async function runWeeklyPayoutEligibility(ctx) {
44
67
  * `autoPayoutEligibility` must agree, or the weekly run and the automatic
45
68
  * one pay different amounts for the same orders. */
46
69
  const grossAmount = ordersTaxableValue(orders.map((o) => o.data));
47
- const { platformFee, gatewayFee, gstOnFee, netAmount } = computePayoutDeduction(grossAmount, commissions);
70
+ const { platformFee, gatewayFee, gstOnFee, netAmount } = computePayoutDeduction(grossAmount, commissions,
71
+ /*
72
+ * D45 — postage refunded to the seller, added AFTER the fee bases so no
73
+ * commission is charged on a cost being refunded. `.data` for the same
74
+ * reason `ordersTaxableValue` above needs it: `orders` holds
75
+ * `{ id, data }` wrappers, and passing the wrapper would read every field
76
+ * as undefined and silently reimburse zero.
77
+ */
78
+ ordersShippingReimbursement(orders.map((o) => o.data)));
48
79
  /*
49
80
  * 🛑 REVEALED before building a payout — see the identical note in
50
81
  * `autoPayoutEligibility.ts`. `findById` is ciphertext-by-default and
@@ -0,0 +1,2 @@
1
+ import type { ScheduleHandler } from "../runtime/types";
2
+ export declare const boxRollupReconcileHandler: ScheduleHandler;
@@ -0,0 +1,15 @@
1
+ import { runBoxRollupReconcile } from "../core/boxRollupReconcile.js";
2
+ /*
3
+ * 🛑 Wrapped rather than assigned directly. `ScheduleHandler` is
4
+ * `(ctx) => Promise<void>` and `runBoxRollupReconcile` resolves to a
5
+ * `BoxRollupReconcileResult`, which is NOT assignable — TypeScript's
6
+ * return-type `void` exemption covers `() => void`, where any return value is
7
+ * discardable, but it does not reach through `Promise<T>` to `Promise<void>`.
8
+ *
9
+ * The result is deliberately still returned by the core function: the
10
+ * scheduler has no use for it, but a manual trigger does, and the job already
11
+ * logs `drifted` itself so nothing is lost by dropping it here.
12
+ */
13
+ export const boxRollupReconcileHandler = async (ctx) => {
14
+ await runBoxRollupReconcile(ctx);
15
+ };
@@ -0,0 +1,65 @@
1
+ import type { CallableHandler } from "../runtime/types";
2
+ /**
3
+ * What an on-demand reconcile reports back to its caller.
4
+ *
5
+ * `degraded` is the point of this type. See the handler.
6
+ */
7
+ export interface CountersReconcileNowResult {
8
+ categoryRows: number;
9
+ publishedProductsScanned: number;
10
+ drifted: number;
11
+ written: number;
12
+ countsWritten: number;
13
+ unknownCategory: number;
14
+ storesProcessed: number;
15
+ storeErrors: number;
16
+ /**
17
+ * `true` when drift was found and nothing was written — the signature of a
18
+ * run that did no work while reporting completion. See the handler.
19
+ */
20
+ degraded: boolean;
21
+ ranForMs: number;
22
+ }
23
+ /**
24
+ * Run the counters reconciliation on demand and RETURN what it did.
25
+ *
26
+ * ## Why this exists at all
27
+ *
28
+ * `countersReconcile` already runs daily at 03:00 UTC, and that is the right
29
+ * cadence for drift that accumulates on its own. It is the wrong cadence for
30
+ * drift you have just CAUSED: seeding a collection, purging demo data, or a
31
+ * bulk import all leave the counters wrong immediately, and waiting until the
32
+ * next night means the catalogue reads as empty until then.
33
+ *
34
+ * Measured 2026-10-21: a demo purge left all 17 stocked categories reading
35
+ * `total=0` while their products were filed correctly — `category-beyblade-x`
36
+ * stored 0 against an actual 14. Nothing errored, because a wrong count is
37
+ * just a number; the only symptom is a human seeing an empty category.
38
+ *
39
+ * ## 🛑 Why it returns a summary instead of void
40
+ *
41
+ * The scheduled handler returns `void` and reports through logs, which is
42
+ * fine for a cron nobody watches. An on-demand run has a caller waiting on an
43
+ * answer, and the failure that matters here is SILENT: `runCountersReconcile`
44
+ * catches its own category and store errors and still logs
45
+ * "Counters reconciliation complete". Driving it standalone produced exactly
46
+ * that — `processed: 0, errors: 1`, then "complete" — three times in a row
47
+ * while writing nothing, because `ctx.db` was missing.
48
+ *
49
+ * So the one thing this must never do is answer 200-with-success for a run
50
+ * that wrote nothing. `drifted > 0 && written === 0` is that signature, and
51
+ * it is surfaced as `degraded` rather than buried in a log line. A caller
52
+ * that sees `degraded: true` has been told the run failed even though it
53
+ * completed.
54
+ *
55
+ * ## Why it wraps the logger rather than changing the core
56
+ *
57
+ * `runCountersReconcile` already emits its own counts as structured metadata
58
+ * on two "reconciliation complete" lines. Reading those is enough, and leaves
59
+ * the scheduled path byte-identical — one implementation, two entry points,
60
+ * which is the shape the Functions registry is for. Changing the core's
61
+ * signature to return a summary would mean the cron and the callable run
62
+ * different code, and the whole reason this bug was findable is that they do
63
+ * not.
64
+ */
65
+ export declare const countersReconcileNowHandler: CallableHandler<void, CountersReconcileNowResult>;
@@ -0,0 +1,89 @@
1
+ import { runCountersReconcile } from "../core/countersReconcile.js";
2
+ const num = (m, k) => typeof m?.[k] === "number" ? m[k] : 0;
3
+ /**
4
+ * Run the counters reconciliation on demand and RETURN what it did.
5
+ *
6
+ * ## Why this exists at all
7
+ *
8
+ * `countersReconcile` already runs daily at 03:00 UTC, and that is the right
9
+ * cadence for drift that accumulates on its own. It is the wrong cadence for
10
+ * drift you have just CAUSED: seeding a collection, purging demo data, or a
11
+ * bulk import all leave the counters wrong immediately, and waiting until the
12
+ * next night means the catalogue reads as empty until then.
13
+ *
14
+ * Measured 2026-10-21: a demo purge left all 17 stocked categories reading
15
+ * `total=0` while their products were filed correctly — `category-beyblade-x`
16
+ * stored 0 against an actual 14. Nothing errored, because a wrong count is
17
+ * just a number; the only symptom is a human seeing an empty category.
18
+ *
19
+ * ## 🛑 Why it returns a summary instead of void
20
+ *
21
+ * The scheduled handler returns `void` and reports through logs, which is
22
+ * fine for a cron nobody watches. An on-demand run has a caller waiting on an
23
+ * answer, and the failure that matters here is SILENT: `runCountersReconcile`
24
+ * catches its own category and store errors and still logs
25
+ * "Counters reconciliation complete". Driving it standalone produced exactly
26
+ * that — `processed: 0, errors: 1`, then "complete" — three times in a row
27
+ * while writing nothing, because `ctx.db` was missing.
28
+ *
29
+ * So the one thing this must never do is answer 200-with-success for a run
30
+ * that wrote nothing. `drifted > 0 && written === 0` is that signature, and
31
+ * it is surfaced as `degraded` rather than buried in a log line. A caller
32
+ * that sees `degraded: true` has been told the run failed even though it
33
+ * completed.
34
+ *
35
+ * ## Why it wraps the logger rather than changing the core
36
+ *
37
+ * `runCountersReconcile` already emits its own counts as structured metadata
38
+ * on two "reconciliation complete" lines. Reading those is enough, and leaves
39
+ * the scheduled path byte-identical — one implementation, two entry points,
40
+ * which is the shape the Functions registry is for. Changing the core's
41
+ * signature to return a summary would mean the cron and the callable run
42
+ * different code, and the whole reason this bug was findable is that they do
43
+ * not.
44
+ */
45
+ export const countersReconcileNowHandler = async (_input, ctx) => {
46
+ const startedAt = Date.now();
47
+ let categories;
48
+ let stores;
49
+ /*
50
+ * A pass-through logger: everything still reaches the real one, so the
51
+ * Function's logs are unchanged and this cannot swallow a message.
52
+ */
53
+ const capturing = {
54
+ info: (msg, meta) => {
55
+ if (msg.includes("[categories] reconciliation complete"))
56
+ categories = meta;
57
+ if (msg.includes("[stores] reconciliation complete"))
58
+ stores = meta;
59
+ ctx.logger.info(msg, meta);
60
+ },
61
+ warn: (msg, meta) => ctx.logger.warn(msg, meta),
62
+ error: (msg, err, meta) => ctx.logger.error(msg, err, meta),
63
+ };
64
+ await runCountersReconcile({ ...ctx, logger: capturing });
65
+ const drifted = num(categories, "drifted");
66
+ const written = num(categories, "written");
67
+ const result = {
68
+ categoryRows: num(categories, "categoryRows"),
69
+ publishedProductsScanned: num(categories, "publishedProductsScanned"),
70
+ drifted,
71
+ written,
72
+ countsWritten: num(categories, "countsWritten"),
73
+ unknownCategory: num(categories, "unknownCategory"),
74
+ storesProcessed: num(stores, "processed"),
75
+ storeErrors: num(stores, "errors"),
76
+ /*
77
+ * 🛑 Also degraded when the category pass reported NOTHING. A missing
78
+ * summary means `reconcileCategories` threw before its final log line --
79
+ * which `runCountersReconcile` catches and continues past, so the run
80
+ * still "completes" with zero evidence it did anything.
81
+ */
82
+ degraded: (drifted > 0 && written === 0) || categories === undefined,
83
+ ranForMs: Date.now() - startedAt,
84
+ };
85
+ if (result.degraded) {
86
+ ctx.logger.error("[countersReconcileNow] completed but wrote nothing against observed drift — treat as FAILED", undefined, { ...result });
87
+ }
88
+ return result;
89
+ };
@@ -16,6 +16,9 @@ export { cleanupRtdbEventsHandler } from "./cleanupRtdbEvents";
16
16
  export { auctionSettlementHandler } from "./auctionSettlement";
17
17
  export { autoPayoutEligibilityHandler } from "./autoPayoutEligibility";
18
18
  export { countersReconcileHandler } from "./countersReconcile";
19
+ export { paymentReconcileHandler } from "./paymentReconcile";
20
+ export { obligationSweepHandler } from "./obligationSweep";
21
+ export { boxRollupReconcileHandler } from "./boxRollupReconcile";
19
22
  export { onOrderCreateHandler } from "./onOrderCreate";
20
23
  export { onOrderStatusChangeHandler } from "./onOrderStatusChange";
21
24
  export { onJobCreatedHandler } from "./onJobCreated";
@@ -29,6 +32,7 @@ export { paymentReviewAutoApproveHandler } from "./paymentReviewAutoApprove";
29
32
  export { productStatsSyncHandler } from "./productStatsSync";
30
33
  export { revenueRollupHandler } from "./revenueRollup";
31
34
  export { priceIndexRollupHandler } from "./priceIndexRollup";
35
+ export { marketPriceRollupHandler } from "./marketPriceRollup";
32
36
  export { searchIndexBuildHandler } from "./searchIndexBuild";
33
37
  export { analyticsAlertEvaluateHandler } from "./analyticsAlertEvaluate";
34
38
  export { pageViewRollupHandler } from "./pageViewRollup";
@@ -40,6 +44,7 @@ export { onCategoryWriteHandler } from "./onCategoryWrite";
40
44
  export { onProductWriteHandler } from "./onProductWrite";
41
45
  export { onStoreWriteHandler } from "./onStoreWrite";
42
46
  export { adminAnalyticsHandler, type AdminAnalyticsResult } from "./adminAnalytics";
47
+ export { countersReconcileNowHandler, type CountersReconcileNowResult, } from "./countersReconcileNow";
43
48
  export { storeAnalyticsHandler, type StoreAnalyticsInput, type StoreAnalyticsResult, } from "./storeAnalytics";
44
49
  export { listingProcessorHandler, supportedListingCollections, type ListingRequestBody, type ListingResponseBody, } from "./listingProcessor";
45
50
  export { bundleStockSyncHandler } from "./bundleStockSync";
@@ -16,6 +16,9 @@ export { cleanupRtdbEventsHandler } from "./cleanupRtdbEvents.js";
16
16
  export { auctionSettlementHandler } from "./auctionSettlement.js";
17
17
  export { autoPayoutEligibilityHandler } from "./autoPayoutEligibility.js";
18
18
  export { countersReconcileHandler } from "./countersReconcile.js";
19
+ export { paymentReconcileHandler } from "./paymentReconcile.js";
20
+ export { obligationSweepHandler } from "./obligationSweep.js";
21
+ export { boxRollupReconcileHandler } from "./boxRollupReconcile.js";
19
22
  export { onOrderCreateHandler } from "./onOrderCreate.js";
20
23
  export { onOrderStatusChangeHandler } from "./onOrderStatusChange.js";
21
24
  export { onJobCreatedHandler } from "./onJobCreated.js";
@@ -29,6 +32,7 @@ export { paymentReviewAutoApproveHandler } from "./paymentReviewAutoApprove.js";
29
32
  export { productStatsSyncHandler } from "./productStatsSync.js";
30
33
  export { revenueRollupHandler } from "./revenueRollup.js";
31
34
  export { priceIndexRollupHandler } from "./priceIndexRollup.js";
35
+ export { marketPriceRollupHandler } from "./marketPriceRollup.js";
32
36
  export { searchIndexBuildHandler } from "./searchIndexBuild.js";
33
37
  export { analyticsAlertEvaluateHandler } from "./analyticsAlertEvaluate.js";
34
38
  export { pageViewRollupHandler } from "./pageViewRollup.js";
@@ -40,6 +44,7 @@ export { onCategoryWriteHandler } from "./onCategoryWrite.js";
40
44
  export { onProductWriteHandler } from "./onProductWrite.js";
41
45
  export { onStoreWriteHandler } from "./onStoreWrite.js";
42
46
  export { adminAnalyticsHandler } from "./adminAnalytics.js";
47
+ export { countersReconcileNowHandler, } from "./countersReconcileNow.js";
43
48
  export { storeAnalyticsHandler, } from "./storeAnalytics.js";
44
49
  export { listingProcessorHandler, supportedListingCollections, } from "./listingProcessor.js";
45
50
  // SB1-L (S7-PrizeDraws) — bundle sync, event raffles, and spin-the-wheel.
@@ -0,0 +1,2 @@
1
+ import type { ScheduleHandler } from "../runtime/types";
2
+ export declare const marketPriceRollupHandler: ScheduleHandler;
@@ -0,0 +1,2 @@
1
+ import { runMarketPriceRollup } from "../core/marketPriceRollup.js";
2
+ export const marketPriceRollupHandler = runMarketPriceRollup;
@@ -0,0 +1,2 @@
1
+ import type { ScheduleHandler } from "../runtime/types";
2
+ export declare const obligationSweepHandler: ScheduleHandler;
@@ -0,0 +1,15 @@
1
+ import { runObligationSweep } from "../core/obligationSweep.js";
2
+ /*
3
+ * 🛑 Wrapped rather than assigned directly. `ScheduleHandler` is
4
+ * `(ctx) => Promise<void>` and `runObligationSweep` resolves a RESULT object,
5
+ * which is not assignable: the return-type `void` exemption covers
6
+ * `() => void`, where any return value is discardable, but it does not reach
7
+ * through `Promise<T>` to `Promise<void>`.
8
+ *
9
+ * The result stays on the core function deliberately — the scheduler has no
10
+ * use for it, a manual trigger does, and the job logs its own summary either
11
+ * way. Same shape as `boxRollupReconcileHandler`.
12
+ */
13
+ export const obligationSweepHandler = async (ctx) => {
14
+ await runObligationSweep(ctx);
15
+ };
@@ -1,4 +1,21 @@
1
1
  import { allocateShipmentCosts } from "../../../../features/shipments/utils/cost-allocation.js";
2
+ import { siteSettingsRepository } from "../../../../features/admin/repository/site-settings.repository.js";
3
+ /*
4
+ * ── D58: the admin saw 6 while this used 4 ───────────────────────────────
5
+ *
6
+ * 🛑 `siteSettings.laborRate.maxHoursPerDay` is admin-editable and read by
7
+ * NOTHING (verified: zero readers outside the form, the schema and the seed).
8
+ * The form's own fallback is **6**; this constant is **4**. So an admin could
9
+ * set the value, see it persist, and the allocation would keep using a
10
+ * different number — which is the same class as D13's silent control, with
11
+ * the extra twist that the two numbers disagreed.
12
+ *
13
+ * Now read from settings with this as the FALLBACK, so the admin control is
14
+ * live and the two cannot diverge. 4 is kept as the fallback rather than 6
15
+ * because 4 is what every existing allocation was computed with — switching
16
+ * the default to the form's 6 would silently re-base historical cost figures,
17
+ * which is worse than the disagreement it fixes.
18
+ */
2
19
  const DEFAULT_MAX_HOURS_PER_DAY = 4;
3
20
  /*
4
21
  * 🛑 THIS COMPARISON IS LOAD-BEARING. GETTING IT WRONG IS AN INFINITE LOOP THAT
@@ -75,13 +92,25 @@ async function recomputeShipmentAllocation(shipmentId, ctx) {
75
92
  // matching what the admin editor's preview also uses.
76
93
  const laborRatePerHour = shipment.laborRatePerHour ?? 0;
77
94
  const laborHoursSpent = shipment.laborHoursSpent ?? 0;
95
+ /*
96
+ * One settings read per allocation. This job is a Firestore trigger on a
97
+ * single shipment, not a sweep, so the read is bounded — and the
98
+ * alternative (keep ignoring the admin control) is the defect.
99
+ */
100
+ const laborSettings = await siteSettingsRepository
101
+ .getSingleton()
102
+ .then((s) => s.laborRate)
103
+ .catch(() => undefined);
104
+ const settingsMaxHours = laborSettings?.maxHoursPerDay;
78
105
  const { perLot, totals } = allocateShipmentCosts({
79
106
  lots: allocationInputs,
80
107
  customsTotal: shipment.customsTotal ?? 0,
81
108
  shippingTotal: shipment.shippingTotal ?? 0,
82
109
  laborHoursSpent,
83
110
  laborRatePerHour,
84
- maxHoursPerDay: DEFAULT_MAX_HOURS_PER_DAY,
111
+ maxHoursPerDay: typeof settingsMaxHours === "number" && Number.isFinite(settingsMaxHours) && settingsMaxHours > 0
112
+ ? settingsMaxHours
113
+ : DEFAULT_MAX_HOURS_PER_DAY,
85
114
  });
86
115
  const batch = ctx.db.batch();
87
116
  let anyLotChanged = false;
@@ -0,0 +1,2 @@
1
+ import type { ScheduleHandler } from "../runtime/types";
2
+ export declare const paymentReconcileHandler: ScheduleHandler;
@@ -0,0 +1,6 @@
1
+ import { runPaymentReconcile } from "../core/paymentReconcile.js";
2
+ /* Wrapped for the same reason as `obligationSweepHandler` — see the note
3
+ * there: a `Promise<Result>` is not assignable to a `Promise<void>` handler. */
4
+ export const paymentReconcileHandler = async (ctx) => {
5
+ await runPaymentReconcile(ctx);
6
+ };
@@ -29,7 +29,7 @@ import type { IconKey } from "../../../ui/icons/icon-registry";
29
29
  /** What KIND of action — drives default UI affordance (link vs button vs danger). */
30
30
  export type ActionKind = "primary" | "secondary" | "danger" | "ghost" | "link" | "chip";
31
31
  /** Resource bucket — keyed top-level in the ACTIONS tree. */
32
- export type ActionResource = "PRODUCT" | "AUCTION" | "PRE_ORDER" | "PRIZE_DRAW" | "DIGITAL_CODE" | "BUNDLE" | "GROUP" | "CATEGORY" | "BRAND" | "PART" | "BEY" | "SUBLISTING" | "STORE" | "BLOG" | "EVENT" | "REVIEW" | "SHIPMENT" | "CATALOGUE" | "USER" | "SELLER" | "ADMIN" | "CART" | "CHECKOUT" | "NAV" | "MEDIA" | "SUPPORT" | "LOTTERY" | "TESTER";
32
+ export type ActionResource = "PRODUCT" | "AUCTION" | "PRE_ORDER" | "PRIZE_DRAW" | "DIGITAL_CODE" | "BUNDLE" | "GROUP" | "CATEGORY" | "BRAND" | "PART" | "BEY" | "FAQ" | "SUBLISTING" | "STORE" | "BLOG" | "EVENT" | "REVIEW" | "SHIPMENT" | "CATALOGUE" | "USER" | "SELLER" | "ADMIN" | "CART" | "CHECKOUT" | "NAV" | "MEDIA" | "SUPPORT" | "LOTTERY" | "TESTER";
33
33
  /** Confirmation modal config — when set, <Button action={...}> opens
34
34
  * a confirm dialog before firing the actual handler. */
35
35
  export interface ActionConfirmation {
@@ -483,6 +483,53 @@ export const ACTIONS = {
483
483
  },
484
484
  },
485
485
  },
486
+ /*
487
+ * FAQ — a real record with its own `faq-` slug, admin editor and endpoint,
488
+ * which had no bucket here at all. That absence is what kept the owner
489
+ * toolbar off every FAQ: `RESOURCE_LEAVES` resolves its labels and confirm
490
+ * copy through this tree, so a missing bucket is a missing control.
491
+ */
492
+ FAQ: {
493
+ view: {
494
+ iconKey: "view",
495
+ id: "faq.view",
496
+ label: "View",
497
+ ariaLabel: "View FAQ",
498
+ description: "Open this question on the help centre.",
499
+ kind: "secondary",
500
+ },
501
+ edit: {
502
+ iconKey: "edit",
503
+ id: "faq.edit",
504
+ label: "Edit",
505
+ ariaLabel: "Edit FAQ",
506
+ description: "Correct this question or its answer.",
507
+ kind: "secondary",
508
+ permissions: ["admin"],
509
+ },
510
+ delete: {
511
+ iconKey: "delete",
512
+ id: "faq.delete",
513
+ label: "Delete",
514
+ ariaLabel: "Delete FAQ",
515
+ description: "Remove this question from the help centre.",
516
+ kind: "danger",
517
+ permissions: ["admin"],
518
+ confirmation: {
519
+ title: "Remove this question from the help centre?",
520
+ /*
521
+ * 🛑 Names the two places it disappears from, because a FAQ is
522
+ * surfaced in more than one: `showOnHomepage` and `showInFooter` are
523
+ * fields on the document, so deleting one can quietly empty a
524
+ * homepage block an admin never associated with this screen.
525
+ */
526
+ body: "It stops appearing in the help centre, and in the homepage and footer blocks if it was " +
527
+ "flagged for those. Seeded questions come back on the next reseed — to remove one for " +
528
+ "good, take it out of the seed data.",
529
+ confirmLabel: "Remove",
530
+ },
531
+ },
532
+ },
486
533
  BEY: {
487
534
  view: {
488
535
  iconKey: "view",
@@ -1696,6 +1743,30 @@ export const ACTIONS = {
1696
1743
  kind: "secondary",
1697
1744
  permissions: ["admin"],
1698
1745
  },
1746
+ /**
1747
+ * Credit or debit a buyer's points by hand — `admin_adjustment`'s first
1748
+ * human writer (D48).
1749
+ *
1750
+ * 🛑 `permissions: ["admin"]` only, no moderator. 1 point = ₹1 of spendable
1751
+ * discount, so a credit is a liability the platform must honour and a debit
1752
+ * removes value a buyer already holds. `ban-user` admits a moderator
1753
+ * because a ban is reversible and moves no money; this is neither.
1754
+ *
1755
+ * No `confirmation` block, deliberately — the drawer it opens IS the
1756
+ * confirmation, and it collects three mandatory fields (a signed amount
1757
+ * under `POINTS_ADJUSTMENT_MAX`, a buyer-facing line, and a ≥10-character
1758
+ * internal reason). A confirm dialog in front of a form that already
1759
+ * demands a written justification is a click that asks nothing.
1760
+ */
1761
+ "adjust-user-points": {
1762
+ iconKey: "points",
1763
+ id: "admin.adjust-user-points",
1764
+ label: "Adjust points",
1765
+ ariaLabel: "Credit or debit this user's points",
1766
+ description: "Credit or debit a buyer's points balance, with a reason recorded in the ledger and the admin audit log.",
1767
+ kind: "secondary",
1768
+ permissions: ["admin"],
1769
+ },
1699
1770
  "bulk-suspend-users": {
1700
1771
  iconKey: "ban",
1701
1772
  id: "admin.bulk-suspend-users",
@@ -0,0 +1,73 @@
1
+ /**
2
+ * How a buyer-applied coupon splits across the sellers in one cart.
3
+ *
4
+ * WHY THIS MOVED HERE (2026-10-21): the implementation was module-private
5
+ * inside `_internal/server/features/checkout/actions.ts`, where three order
6
+ * paths could reach it and the **gateway capture route could not**.
7
+ *
8
+ * 🛑 So `/api/payment/create-order` — the one place that decides what the
9
+ * buyer's card is actually charged — had NO COUPON TERM ANYWHERE IN THE FILE.
10
+ * Measured: zero occurrences of "coupon" or "discount", and
11
+ *
12
+ * rawTotal = subtotalRs + platformFee + gstOnFee + addonFees + shippingFee
13
+ *
14
+ * while `createOrderForGroup` (COD/UPI), `previewCheckoutPricing` and
15
+ * `createRazorpayGroupOrder` all compute `max(0, total − couponDiscount) + …`.
16
+ *
17
+ * The consequence is a live overcharge on every coupon order paid by card: the
18
+ * preview shows ₹X−discount, the gateway captures ₹X, and the order records
19
+ * ₹X−discount. And it is invisible in our own data, because the post-capture
20
+ * amount guard is ONE-SIDED (`paid < expected − 1`), so an over-capture never
21
+ * trips it. Nothing in the system disagreed with itself; only the buyer's card
22
+ * statement did.
23
+ *
24
+ * `_internal/shared/` rather than `_internal/server/` because this is pure
25
+ * arithmetic with no Firestore reach, and because `_internal/shared` is the
26
+ * only one of the three a consumer route can be served from. It is the first
27
+ * increment of the single-pipeline extraction.
28
+ */
29
+ import type { CartAppliedCoupon } from "../../../features/cart/schemas/firestore";
30
+ export interface GroupCouponDiscountResult {
31
+ couponDiscount: number;
32
+ appliedDiscounts: {
33
+ code: string;
34
+ couponId?: string;
35
+ type: "coupon" | "deal" | "auto";
36
+ discountAmount: number;
37
+ scope?: "admin" | "seller";
38
+ storeId?: string;
39
+ }[];
40
+ }
41
+ /**
42
+ * Prorates every buyer-applied coupon against one seller-group's total.
43
+ *
44
+ * Pure — no side effects. Usage-accumulator bookkeeping is layered on by the
45
+ * callers that actually place an order, which is what lets the preview and the
46
+ * capture route call this without recording a redemption.
47
+ *
48
+ * A seller-scoped coupon applies only to its own store's group; an admin
49
+ * coupon prorates across every group by `groupTotal / cartSubtotal`. Clamped
50
+ * to the group total at the end, so a coupon can never make a group negative.
51
+ */
52
+ export declare function computeGroupCouponDiscount(appliedCoupons: CartAppliedCoupon[], groupLines: {
53
+ itemId: string;
54
+ lineTotal: number;
55
+ }[], groupTotal: number, cartSubtotal: number, storeId: string | undefined): GroupCouponDiscountResult;
56
+ /**
57
+ * The whole cart's discount, summed over its seller-groups.
58
+ *
59
+ * 🛑 This exists so a caller holding only a cart-wide subtotal cannot be
60
+ * tempted to apply a coupon to it directly. Doing so is wrong in two ways that
61
+ * cancel out on a single-seller cart and diverge on a multi-seller one: a
62
+ * seller-scoped coupon would be applied to other sellers' items, and the
63
+ * per-group clamp (`min(discount, groupTotal)`) would not bind. The capture
64
+ * route holds exactly that shape, which is how it ended up with no discount at
65
+ * all rather than a wrong one.
66
+ */
67
+ export declare function computeCartCouponDiscount(appliedCoupons: CartAppliedCoupon[], groups: {
68
+ storeId: string | undefined;
69
+ lines: {
70
+ itemId: string;
71
+ lineTotal: number;
72
+ }[];
73
+ }[]): GroupCouponDiscountResult;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * How a buyer-applied coupon splits across the sellers in one cart.
3
+ *
4
+ * WHY THIS MOVED HERE (2026-10-21): the implementation was module-private
5
+ * inside `_internal/server/features/checkout/actions.ts`, where three order
6
+ * paths could reach it and the **gateway capture route could not**.
7
+ *
8
+ * 🛑 So `/api/payment/create-order` — the one place that decides what the
9
+ * buyer's card is actually charged — had NO COUPON TERM ANYWHERE IN THE FILE.
10
+ * Measured: zero occurrences of "coupon" or "discount", and
11
+ *
12
+ * rawTotal = subtotalRs + platformFee + gstOnFee + addonFees + shippingFee
13
+ *
14
+ * while `createOrderForGroup` (COD/UPI), `previewCheckoutPricing` and
15
+ * `createRazorpayGroupOrder` all compute `max(0, total − couponDiscount) + …`.
16
+ *
17
+ * The consequence is a live overcharge on every coupon order paid by card: the
18
+ * preview shows ₹X−discount, the gateway captures ₹X, and the order records
19
+ * ₹X−discount. And it is invisible in our own data, because the post-capture
20
+ * amount guard is ONE-SIDED (`paid < expected − 1`), so an over-capture never
21
+ * trips it. Nothing in the system disagreed with itself; only the buyer's card
22
+ * statement did.
23
+ *
24
+ * `_internal/shared/` rather than `_internal/server/` because this is pure
25
+ * arithmetic with no Firestore reach, and because `_internal/shared` is the
26
+ * only one of the three a consumer route can be served from. It is the first
27
+ * increment of the single-pipeline extraction.
28
+ */
29
+ import { roundRupees } from "../../../utils/number.formatter.js";
30
+ /**
31
+ * Prorates every buyer-applied coupon against one seller-group's total.
32
+ *
33
+ * Pure — no side effects. Usage-accumulator bookkeeping is layered on by the
34
+ * callers that actually place an order, which is what lets the preview and the
35
+ * capture route call this without recording a redemption.
36
+ *
37
+ * A seller-scoped coupon applies only to its own store's group; an admin
38
+ * coupon prorates across every group by `groupTotal / cartSubtotal`. Clamped
39
+ * to the group total at the end, so a coupon can never make a group negative.
40
+ */
41
+ export function computeGroupCouponDiscount(appliedCoupons, groupLines, groupTotal, cartSubtotal, storeId) {
42
+ let couponDiscount = 0;
43
+ const appliedDiscounts = [];
44
+ for (const coupon of appliedCoupons) {
45
+ let couponGroupDiscount = 0;
46
+ const isSellerScoped = coupon.scope === "seller" && coupon.storeId;
47
+ if (isSellerScoped) {
48
+ if (coupon.storeId !== storeId)
49
+ continue;
50
+ if (coupon.applicableItemIds?.length) {
51
+ const eligibleTotal = groupLines
52
+ .filter((l) => coupon.applicableItemIds.includes(l.itemId))
53
+ .reduce((s, l) => s + l.lineTotal, 0);
54
+ couponGroupDiscount =
55
+ eligibleTotal > 0
56
+ ? Math.min(roundRupees((eligibleTotal / groupTotal) * coupon.discountAmount), eligibleTotal)
57
+ : 0;
58
+ }
59
+ else {
60
+ couponGroupDiscount = Math.min(coupon.discountAmount, groupTotal);
61
+ }
62
+ }
63
+ else if (cartSubtotal > 0) {
64
+ couponGroupDiscount = Math.min(roundRupees((groupTotal / cartSubtotal) * coupon.discountAmount), groupTotal);
65
+ }
66
+ if (couponGroupDiscount > 0) {
67
+ couponDiscount += couponGroupDiscount;
68
+ appliedDiscounts.push({
69
+ code: coupon.code,
70
+ couponId: coupon.couponId,
71
+ type: "coupon",
72
+ discountAmount: couponGroupDiscount,
73
+ scope: coupon.scope,
74
+ storeId: coupon.storeId,
75
+ });
76
+ }
77
+ }
78
+ couponDiscount = Math.min(couponDiscount, groupTotal);
79
+ return { couponDiscount, appliedDiscounts };
80
+ }
81
+ /**
82
+ * The whole cart's discount, summed over its seller-groups.
83
+ *
84
+ * 🛑 This exists so a caller holding only a cart-wide subtotal cannot be
85
+ * tempted to apply a coupon to it directly. Doing so is wrong in two ways that
86
+ * cancel out on a single-seller cart and diverge on a multi-seller one: a
87
+ * seller-scoped coupon would be applied to other sellers' items, and the
88
+ * per-group clamp (`min(discount, groupTotal)`) would not bind. The capture
89
+ * route holds exactly that shape, which is how it ended up with no discount at
90
+ * all rather than a wrong one.
91
+ */
92
+ export function computeCartCouponDiscount(appliedCoupons, groups) {
93
+ const cartSubtotal = groups.reduce((sum, g) => sum + g.lines.reduce((s, l) => s + l.lineTotal, 0), 0);
94
+ let couponDiscount = 0;
95
+ const appliedDiscounts = [];
96
+ for (const group of groups) {
97
+ const groupTotal = group.lines.reduce((s, l) => s + l.lineTotal, 0);
98
+ const res = computeGroupCouponDiscount(appliedCoupons, group.lines, groupTotal, cartSubtotal, group.storeId);
99
+ couponDiscount += res.couponDiscount;
100
+ appliedDiscounts.push(...res.appliedDiscounts);
101
+ }
102
+ return { couponDiscount: roundRupees(couponDiscount), appliedDiscounts };
103
+ }