@mohasinac/appkit 4.59.0 → 4.60.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.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
- package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
- package/dist/_internal/server/features/brands/actions.js +78 -4
- package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
- package/dist/_internal/server/features/checkout/actions.js +668 -183
- package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
- package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
- package/dist/_internal/server/features/gateway-events/index.js +10 -0
- package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
- package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
- package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
- package/dist/_internal/server/features/gateway-events/redact.js +151 -0
- package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
- package/dist/_internal/server/features/grievance/actions.js +173 -0
- package/dist/_internal/server/features/grievance/index.d.ts +8 -0
- package/dist/_internal/server/features/grievance/index.js +8 -0
- package/dist/_internal/server/features/grouped/data.js +28 -3
- package/dist/_internal/server/features/lottery/actions.js +99 -4
- package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
- package/dist/_internal/server/features/order-completion/actions.js +336 -0
- package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
- package/dist/_internal/server/features/order-completion/index.js +7 -0
- package/dist/_internal/server/features/orders/actions.d.ts +13 -0
- package/dist/_internal/server/features/orders/actions.js +56 -2
- package/dist/_internal/server/features/orders/adapters.js +26 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
- package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
- package/dist/_internal/server/features/orders/index.d.ts +2 -1
- package/dist/_internal/server/features/orders/index.js +1 -1
- package/dist/_internal/server/features/orders/service.d.ts +60 -0
- package/dist/_internal/server/features/orders/service.js +74 -0
- package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
- package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
- package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
- package/dist/_internal/server/features/payment-cases/index.js +9 -0
- package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
- package/dist/_internal/server/features/payouts/actions.js +84 -10
- package/dist/_internal/server/features/points/adjust.d.ts +61 -0
- package/dist/_internal/server/features/points/adjust.js +121 -0
- package/dist/_internal/server/features/points/award.d.ts +65 -0
- package/dist/_internal/server/features/points/award.js +145 -0
- package/dist/_internal/server/features/price-index/market.d.ts +33 -0
- package/dist/_internal/server/features/price-index/market.js +54 -1
- package/dist/_internal/server/features/products/data.js +40 -22
- package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
- package/dist/_internal/server/features/protection-claims/actions.js +228 -0
- package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
- package/dist/_internal/server/features/protection-claims/index.js +8 -0
- package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
- package/dist/_internal/server/features/refunds/actions.js +259 -17
- package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
- package/dist/_internal/server/features/refunds/capacity.js +37 -0
- package/dist/_internal/server/features/reviews/actions.js +3 -2
- package/dist/_internal/server/features/search/index-build/sources.js +20 -1
- package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
- package/dist/_internal/server/features/shipping/reconcile.js +34 -3
- package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
- package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
- package/dist/_internal/server/features/stores/tabs.js +24 -4
- package/dist/_internal/server/functions/https.d.ts +31 -1
- package/dist/_internal/server/functions/https.js +52 -1
- package/dist/_internal/server/functions/scheduled.d.ts +72 -1
- package/dist/_internal/server/functions/scheduled.js +124 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
- package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
- package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
- package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
- package/dist/_internal/server/jobs/core/index.d.ts +2 -0
- package/dist/_internal/server/jobs/core/index.js +2 -0
- package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
- package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
- package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
- package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
- package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
- package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
- package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
- package/dist/_internal/server/jobs/handlers/index.js +5 -0
- package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
- package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
- package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +71 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
- package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
- package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
- package/dist/_internal/shared/checkout/lanes.js +46 -0
- package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
- package/dist/_internal/shared/checkout/order-math.js +251 -3
- package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
- package/dist/_internal/shared/checkout/refundable-base.js +122 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
- package/dist/_internal/shared/features/auctions/config.js +30 -1
- package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
- package/dist/_internal/shared/features/brands/schema.js +18 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
- package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
- package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
- package/dist/_internal/shared/features/print/label-profiles.js +350 -0
- package/dist/_internal/shared/features/products/to-product-item.js +33 -5
- package/dist/_internal/shared/fees/calculator.d.ts +31 -2
- package/dist/_internal/shared/fees/calculator.js +103 -5
- package/dist/_internal/shared/fees/india-states.d.ts +195 -0
- package/dist/_internal/shared/fees/india-states.js +190 -0
- package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
- package/dist/_internal/shared/fees/payout-hold.js +74 -0
- package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
- package/dist/_internal/shared/obligations/deadlines.js +155 -0
- package/dist/_internal/shared/shipping/quote.d.ts +96 -0
- package/dist/_internal/shared/shipping/quote.js +67 -0
- package/dist/_internal/shared/time/business-days.d.ts +91 -0
- package/dist/_internal/shared/time/business-days.js +185 -0
- package/dist/cli/index.js +0 -2
- package/dist/client.d.ts +9 -4
- package/dist/client.js +26 -3
- package/dist/configs/tailwind.d.ts +0 -12
- package/dist/configs/tailwind.js +28 -15
- package/dist/constants/api-endpoints.d.ts +51 -9
- package/dist/constants/api-endpoints.js +23 -7
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/payment.d.ts +131 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/about/components/DeveloperView.js +5 -2
- package/dist/features/about/components/FAQPageView.js +2 -1
- package/dist/features/about/components/FeesView.js +2 -1
- package/dist/features/about/components/HelpPageView.js +2 -1
- package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
- package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
- package/dist/features/about/components/HowEmiWorksView.js +2 -1
- package/dist/features/about/components/HowOffersWorkView.js +2 -1
- package/dist/features/about/components/HowOrdersWorkView.js +2 -1
- package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
- package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
- package/dist/features/about/components/HowReviewsWorkView.js +2 -1
- package/dist/features/about/components/PolicyPageView.js +2 -1
- package/dist/features/about/components/ProseHero.d.ts +73 -0
- package/dist/features/about/components/ProseHero.js +18 -0
- package/dist/features/about/components/SecurityPrivacyView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +2 -1
- package/dist/features/about/components/TrackOrderView.js +2 -1
- package/dist/features/about/components/UnauthorizedView.js +1 -1
- package/dist/features/about/index.d.ts +2 -0
- package/dist/features/about/index.js +5 -0
- package/dist/features/account/actions/address-actions.d.ts +26 -2
- package/dist/features/account/actions/address-actions.js +25 -1
- package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
- package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
- package/dist/features/account/components/UserOrdersView.js +17 -0
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/account/hooks/useNotifications.js +29 -0
- package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
- package/dist/features/admin/components/AdminBeysView.js +2 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
- package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
- package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
- package/dist/features/admin/components/AdminCategoriesView.js +1 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
- package/dist/features/admin/components/AdminContactEditorView.js +1 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
- package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
- package/dist/features/admin/components/AdminFaqsView.js +2 -2
- package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
- package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
- package/dist/features/admin/components/AdminGuideHubView.js +1 -1
- package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
- package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
- package/dist/features/admin/components/AdminPartsView.js +2 -2
- package/dist/features/admin/components/AdminProductsView.js +75 -4
- package/dist/features/admin/components/AdminSidebar.js +2 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
- package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
- package/dist/features/admin/components/AdminUsersView.js +72 -1
- package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
- package/dist/features/admin/components/AdminViewCards.js +4 -4
- package/dist/features/admin/components/DataListingView.d.ts +28 -0
- package/dist/features/admin/components/DataListingView.js +175 -14
- package/dist/features/admin/components/DataTable.d.ts +12 -1
- package/dist/features/admin/components/DataTable.js +3 -3
- package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
- package/dist/features/admin/components/OwnerQuickActions.js +60 -2
- package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
- package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
- package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
- package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
- package/dist/features/admin/components/index.d.ts +4 -0
- package/dist/features/admin/components/index.js +6 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
- package/dist/features/admin/constants/filter-tabs.js +106 -0
- package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
- package/dist/features/admin/repository/site-settings.repository.js +82 -1
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
- package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
- package/dist/features/admin/schemas/firestore.js +5 -1
- package/dist/features/admin/schemas/site-settings-form.js +30 -1
- package/dist/features/auctions/actions/bid-actions.js +13 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
- package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
- package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
- package/dist/features/audit-log/schemas/firestore.js +14 -0
- package/dist/features/auth/permissions/constants.d.ts +17 -1
- package/dist/features/auth/permissions/constants.js +18 -0
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
- package/dist/features/categories/api/[id]/description-template/route.js +107 -1
- package/dist/features/categories/components/BrandDetailPageView.js +2 -2
- package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
- package/dist/features/categories/components/BundleDetailView.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
- package/dist/features/categories/components/CategoryForm.js +12 -1
- package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
- package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
- package/dist/features/categories/repository/market-price-index.repository.js +105 -0
- package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
- package/dist/features/categories/repository/price-observation.repository.js +132 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/events/components/EventStatusBadge.js +1 -1
- package/dist/features/faq/components/FAQAccordion.js +2 -1
- package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
- package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
- package/dist/features/faq/components/RelatedFAQs.js +1 -1
- package/dist/features/filters/FilterFacetSection.js +1 -1
- package/dist/features/filters/SwitchFilter.js +1 -1
- package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
- package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
- package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
- package/dist/features/gateway-events/schemas/firestore.js +125 -0
- package/dist/features/gateway-events/schemas/index.d.ts +81 -0
- package/dist/features/gateway-events/schemas/index.js +79 -0
- package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.js +37 -1
- package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
- package/dist/features/homepage/components/BrandsSection.js +1 -1
- package/dist/features/homepage/components/CTABannerSection.js +1 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
- package/dist/features/homepage/components/HeroCarousel.js +2 -2
- package/dist/features/homepage/components/SocialPostCard.js +1 -1
- package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
- package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
- package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
- package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
- package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
- package/dist/features/inventory/components/ReceiveStationView.js +413 -0
- package/dist/features/inventory/components/operator-message.d.ts +29 -0
- package/dist/features/inventory/components/operator-message.js +41 -0
- package/dist/features/inventory/index.d.ts +13 -0
- package/dist/features/inventory/index.js +28 -0
- package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
- package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
- package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
- package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
- package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
- package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
- package/dist/features/inventory/schemas/firestore.d.ts +197 -0
- package/dist/features/inventory/schemas/firestore.js +159 -0
- package/dist/features/layout/AppLayoutShell.d.ts +12 -1
- package/dist/features/layout/AppLayoutShell.js +25 -12
- package/dist/features/layout/AutoBreadcrumbs.js +162 -3
- package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
- package/dist/features/layout/BottomNavbar.d.ts +1 -1
- package/dist/features/layout/BottomNavbar.js +2 -2
- package/dist/features/media/MediaAvatar.js +1 -1
- package/dist/features/media/MediaImage.d.ts +24 -4
- package/dist/features/media/MediaImage.js +44 -4
- package/dist/features/media/MediaLightbox.js +1 -1
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/modals/ImageEditor.js +1 -1
- package/dist/features/media/upload/MediaUploadField.js +91 -3
- package/dist/features/obligations/constants/policies.d.ts +92 -0
- package/dist/features/obligations/constants/policies.js +378 -0
- package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
- package/dist/features/obligations/repository/obligations.repository.js +158 -0
- package/dist/features/obligations/schemas/firestore.d.ts +160 -0
- package/dist/features/obligations/schemas/firestore.js +87 -0
- package/dist/features/orders/actions/order-actions.d.ts +43 -4
- package/dist/features/orders/actions/order-actions.js +60 -3
- package/dist/features/orders/actions/refund-actions.js +70 -10
- package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
- package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
- package/dist/features/orders/components/OrdersList.js +2 -2
- package/dist/features/orders/components/RefundHistoryTable.js +3 -1
- package/dist/features/orders/components/index.d.ts +2 -0
- package/dist/features/orders/components/index.js +6 -0
- package/dist/features/orders/constants/transitions.d.ts +59 -0
- package/dist/features/orders/constants/transitions.js +104 -0
- package/dist/features/orders/repository/orders.repository.d.ts +109 -6
- package/dist/features/orders/repository/orders.repository.js +464 -21
- package/dist/features/orders/schemas/firestore.d.ts +270 -0
- package/dist/features/orders/schemas/firestore.js +24 -0
- package/dist/features/orders/schemas/index.d.ts +61 -0
- package/dist/features/orders/schemas/index.js +22 -0
- package/dist/features/orders/types/index.d.ts +79 -0
- package/dist/features/parts/components/PartsIndexPageView.js +8 -1
- package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
- package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
- package/dist/features/payment-cases/schemas/firestore.js +105 -0
- package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
- package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
- package/dist/features/payments/repository/payout.repository.d.ts +0 -1
- package/dist/features/payments/repository/payout.repository.js +0 -1
- package/dist/features/points/repository/points.repository.d.ts +122 -0
- package/dist/features/points/repository/points.repository.js +304 -1
- package/dist/features/points/schemas/adjust-form.d.ts +58 -0
- package/dist/features/points/schemas/adjust-form.js +63 -0
- package/dist/features/points/schemas/firestore.d.ts +108 -1
- package/dist/features/points/schemas/firestore.js +84 -0
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
- package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
- package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
- package/dist/features/price-index/market-stats.d.ts +82 -0
- package/dist/features/price-index/market-stats.js +230 -0
- package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
- package/dist/features/print/components/BoxLabelPrintView.js +66 -0
- package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
- package/dist/features/print/components/LabelProfilePicker.js +38 -0
- package/dist/features/print/components/labels.d.ts +117 -0
- package/dist/features/print/components/labels.js +258 -0
- package/dist/features/print/components/labels.style.css +46 -0
- package/dist/features/print/index.d.ts +6 -0
- package/dist/features/print/index.js +16 -0
- package/dist/features/products/columns/productTableColumns.js +5 -4
- package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
- package/dist/features/products/components/PrizeDrawCollage.js +1 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
- package/dist/features/products/components/PrizeRevealModal.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.js +18 -4
- package/dist/features/products/components/ProductForm.js +34 -23
- package/dist/features/products/components/ProductGrid.js +86 -62
- package/dist/features/products/constants/card-badges.d.ts +97 -0
- package/dist/features/products/constants/card-badges.js +100 -0
- package/dist/features/products/repository/products.repository.js +34 -1
- package/dist/features/products/schemas/firestore.d.ts +46 -3
- package/dist/features/products/schemas/firestore.js +21 -0
- package/dist/features/promotions/components/PromotionsView.js +1 -1
- package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
- package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
- package/dist/features/promotions/schemas/firestore.js +30 -3
- package/dist/features/promotions/schemas/index.d.ts +6 -6
- package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
- package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
- package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
- package/dist/features/protection-claims/schemas/firestore.js +130 -0
- package/dist/features/reviews/actions/review-actions.js +3 -2
- package/dist/features/reviews/components/ReviewModal.js +1 -1
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/reviews/schemas/firestore.d.ts +20 -1
- package/dist/features/scams/constants/scam-types.d.ts +2 -0
- package/dist/features/scams/constants/scam-types.js +18 -0
- package/dist/features/scams/schemas/report-form.d.ts +3 -3
- package/dist/features/scams/schemas/report-form.js +26 -1
- package/dist/features/search/components/Search.js +9 -9
- package/dist/features/search/components/SearchResultsClient.js +18 -3
- package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/seller/actions/offer-actions.js +16 -1
- package/dist/features/seller/actions/seller-actions.js +14 -3
- package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
- package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
- package/dist/features/seller/components/PrintCenterView.js +41 -30
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
- package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
- package/dist/features/seller/components/SellerProductShell.js +123 -13
- package/dist/features/seller/components/SellerReviewsView.js +4 -2
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
- package/dist/features/seller/schemas/coupon-form.js +27 -0
- package/dist/features/seller/schemas/product-form.d.ts +3 -0
- package/dist/features/seller/schemas/product-form.js +5 -0
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +14 -0
- package/dist/features/shell/SectionForm.d.ts +19 -0
- package/dist/features/shell/SectionForm.js +133 -9
- package/dist/features/shell/SectionForm.style.css +54 -0
- package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
- package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
- package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
- package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
- package/dist/features/stores/components/StoreGuideHubView.js +1 -1
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/support/schemas/firestore.d.ts +73 -2
- package/dist/features/support/schemas/firestore.js +59 -0
- package/dist/index.d.ts +16 -24
- package/dist/index.js +38 -47
- package/dist/next/ErrorBoundary.js +1 -1
- package/dist/next/routing/route-map.d.ts +24 -0
- package/dist/next/routing/route-map.js +40 -0
- package/dist/providers/payment-manual/index.d.ts +15 -1
- package/dist/providers/payment-manual/index.js +37 -0
- package/dist/providers/payment-phonepe/index.d.ts +14 -1
- package/dist/providers/payment-phonepe/index.js +36 -0
- package/dist/providers/payment-razorpay/index.d.ts +44 -1
- package/dist/providers/payment-razorpay/index.js +99 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
- package/dist/providers/shipping-shiprocket/index.js +18 -0
- package/dist/schemas/registry.d.ts +44 -11
- package/dist/server-entry.d.ts +2 -0
- package/dist/server-entry.js +27 -0
- package/dist/server.d.ts +42 -0
- package/dist/server.js +93 -0
- package/dist/styles.css +418 -149
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +15 -12
- package/dist/tokens/themes/default-light.js +14 -11
- package/dist/tokens/tokens.css +106 -23
- package/dist/ui/DataTable.style.css +4 -4
- package/dist/ui/columns/cell-renderers.d.ts +20 -0
- package/dist/ui/columns/cell-renderers.js +26 -1
- package/dist/ui/columns/index.d.ts +1 -1
- package/dist/ui/columns/index.js +4 -1
- package/dist/ui/components/Badge.style.css +1 -1
- package/dist/ui/components/Breadcrumb.js +19 -1
- package/dist/ui/components/BulkActionBar.style.css +4 -4
- package/dist/ui/components/Button.style.css +1 -1
- package/dist/ui/components/Checkbox.style.css +1 -1
- package/dist/ui/components/FallbackShell.js +1 -1
- package/dist/ui/components/Form.d.ts +14 -1
- package/dist/ui/components/Form.js +2 -2
- package/dist/ui/components/FormField.js +18 -4
- package/dist/ui/components/FormField.style.css +43 -3
- package/dist/ui/components/GatedPrice.style.css +1 -1
- package/dist/ui/components/IconButton.style.css +1 -1
- package/dist/ui/components/Input.js +22 -1
- package/dist/ui/components/Input.style.css +38 -22
- package/dist/ui/components/ListingFilterDrawer.js +1 -1
- package/dist/ui/components/ListingToolbar.js +1 -1
- package/dist/ui/components/PaginatedSelect.js +0 -0
- package/dist/ui/components/Radio.style.css +1 -1
- package/dist/ui/components/Repeater.d.ts +53 -0
- package/dist/ui/components/Repeater.js +7 -0
- package/dist/ui/components/RichTextEditor.d.ts +20 -1
- package/dist/ui/components/RichTextEditor.js +23 -2
- package/dist/ui/components/Select.style.css +7 -21
- package/dist/ui/components/Semantic.js +27 -3
- package/dist/ui/components/TagInput.style.css +4 -9
- package/dist/ui/components/Textarea.style.css +4 -18
- package/dist/ui/components/Toggle.style.css +1 -1
- package/dist/ui/components/Typography.d.ts +3 -3
- package/dist/ui/components/Typography.js +15 -15
- package/dist/ui/components/ViewToggle.style.css +4 -4
- package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
- package/dist/ui/forms/AddAnotherToggle.js +56 -0
- package/dist/ui/forms/ColorPickerField.js +15 -2
- package/dist/ui/forms/FieldCheckbox.js +15 -2
- package/dist/ui/forms/FieldInput.d.ts +22 -1
- package/dist/ui/forms/FieldInput.js +19 -5
- package/dist/ui/forms/FieldLabel.d.ts +35 -0
- package/dist/ui/forms/FieldLabel.js +70 -0
- package/dist/ui/forms/FieldSelect.d.ts +4 -1
- package/dist/ui/forms/FieldSelect.js +27 -5
- package/dist/ui/forms/FieldTextarea.d.ts +4 -1
- package/dist/ui/forms/FieldTextarea.js +22 -5
- package/dist/ui/forms/FormShell.d.ts +17 -1
- package/dist/ui/forms/FormShell.js +36 -2
- package/dist/ui/forms/FormShell.style.css +41 -33
- package/dist/ui/forms/index.d.ts +5 -1
- package/dist/ui/forms/index.js +2 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/utils/id-generators.d.ts +80 -0
- package/dist/utils/id-generators.js +93 -0
- package/dist/utils/search-txt-builders.d.ts +12 -0
- package/dist/utils/search-txt-builders.js +17 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +106 -5
- package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
- package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
- package/dist/features/loyalty/api/balance/route.d.ts +0 -12
- package/dist/features/loyalty/api/balance/route.js +0 -41
- package/dist/features/loyalty/api/earn/route.d.ts +0 -12
- package/dist/features/loyalty/api/earn/route.js +0 -38
- package/dist/features/loyalty/api/history/route.d.ts +0 -12
- package/dist/features/loyalty/api/history/route.js +0 -58
- package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
- package/dist/features/loyalty/api/redeem/route.js +0 -38
- package/dist/features/loyalty/columns/index.d.ts +0 -17
- package/dist/features/loyalty/columns/index.js +0 -40
- package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
- package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
- package/dist/features/loyalty/components/index.d.ts +0 -1
- package/dist/features/loyalty/components/index.js +0 -1
- package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
- package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
- package/dist/features/loyalty/index.d.ts +0 -6
- package/dist/features/loyalty/index.js +0 -6
- package/dist/features/loyalty/manifest.d.ts +0 -2
- package/dist/features/loyalty/manifest.js +0 -16
- package/dist/features/loyalty/messages/en.json +0 -19
- package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
- package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
- package/dist/features/loyalty/schemas/index.d.ts +0 -85
- package/dist/features/loyalty/schemas/index.js +0 -40
- package/dist/features/loyalty/server.d.ts +0 -6
- package/dist/features/loyalty/server.js +0 -6
- package/dist/features/loyalty/types/index.d.ts +0 -31
- package/dist/features/loyalty/types/index.js +0 -1
- package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
- package/dist/features/loyalty/types/loyalty-config.js +0 -1
- package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
- package/dist/features/loyalty/types/loyalty-math.js +0 -27
- package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
- package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
|
@@ -9,12 +9,83 @@ export declare const productStatsSync: import("./types").ScheduledFunctionDefini
|
|
|
9
9
|
export declare const revenueRollup: import("./types").ScheduledFunctionDefinition;
|
|
10
10
|
export declare const searchIndexBuild: import("./types").ScheduledFunctionDefinition;
|
|
11
11
|
export declare const priceIndexRollup: import("./types").ScheduledFunctionDefinition;
|
|
12
|
+
export declare const marketPriceRollup: import("./types").ScheduledFunctionDefinition;
|
|
12
13
|
export declare const analyticsAlertEvaluate: import("./types").ScheduledFunctionDefinition;
|
|
13
14
|
export declare const pageViewRollup: import("./types").ScheduledFunctionDefinition;
|
|
14
15
|
export declare const pageViewPrune: import("./types").ScheduledFunctionDefinition;
|
|
15
16
|
export declare const dailyStatusDigest: import("./types").ScheduledFunctionDefinition;
|
|
16
17
|
export declare const dailyDataCleanup: import("./types").ScheduledFunctionDefinition;
|
|
17
18
|
export declare const countersReconcile: import("./types").ScheduledFunctionDefinition;
|
|
19
|
+
/**
|
|
20
|
+
* Payment reconciliation — R2, R3 and R4. Daily 05:30 UTC.
|
|
21
|
+
*
|
|
22
|
+
* 🛑 ITS OWN FUNCTION, and the two obvious places to fold it are both wrong.
|
|
23
|
+
*
|
|
24
|
+
* `countersReconcile` above already runs at its 540 s ceiling, so adding work
|
|
25
|
+
* there is how a job starts timing out and taking category metrics with it.
|
|
26
|
+
* `autoPayoutEligibility` is tempting because both touch orders, but
|
|
27
|
+
* `priceIndexRollup`'s own comment sets the precedent: a job should be able to
|
|
28
|
+
* fail without taking an unrelated one down, and these two share nothing beyond
|
|
29
|
+
* the collection.
|
|
30
|
+
*
|
|
31
|
+
* Cloud Scheduler bills **per registered job** (3 free, 28 already registered),
|
|
32
|
+
* so this is ~$0.10/month — a cost the Firebase budget table explicitly accepts
|
|
33
|
+
* for a distinct cadence rather than contorting the schedule around it.
|
|
34
|
+
*
|
|
35
|
+
* 🛑 R1 is NOT here. It is folded into `paymentWindowTimeout` (every 5 minutes),
|
|
36
|
+
* because a webhook we received and lost should not wait up to 24 hours to be
|
|
37
|
+
* noticed — and its query is one indexed read, so the tight loop is free.
|
|
38
|
+
*
|
|
39
|
+
* 05:30 UTC = 11:00 IST, deliberately after `countersReconcile` (03:00) and
|
|
40
|
+
* `autoPayoutEligibility` so a payout decision is never taken on the same tick
|
|
41
|
+
* as the reconciliation that might open a case blocking it.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Every deadline in the order lifecycle — one job, every 5 minutes.
|
|
45
|
+
*
|
|
46
|
+
* 🛑 ONE JOB FOR ~20 SCENARIOS, and the Scheduler count goes DOWN.
|
|
47
|
+
*
|
|
48
|
+
* The alternative was a cron per scenario, which is ~$2/month *and* `O(n²)`
|
|
49
|
+
* coverage reasoning — D25, D27 and the duplicate buyout notification are all
|
|
50
|
+
* that pattern failing. Here it is one indexed query per tick, empty when idle,
|
|
51
|
+
* and `obligations`' deterministic document id gives "at most one open
|
|
52
|
+
* obligation per (subject, kind)" so a double reconcile is a no-op.
|
|
53
|
+
*
|
|
54
|
+
* Phase 8 retires `paymentWindowTimeout`, `pendingOrderTimeout` and
|
|
55
|
+
* `paymentReviewAutoApprove` once their policy rows are proven, taking the
|
|
56
|
+
* registered count **28 → 29 → 27**.
|
|
57
|
+
*
|
|
58
|
+
* 🛑 NOT a Firestore trigger on `orders`. A trigger writing `obligations`
|
|
59
|
+
* whose sweep writes `orders` is Root Cause #92's self-write loop — the one
|
|
60
|
+
* that cost 1,017,548 invocations in 24 hours. Obligations are reconciled
|
|
61
|
+
* inside the order's own write, where the document is already in hand.
|
|
62
|
+
*/
|
|
63
|
+
export declare const obligationSweep: import("./types").ScheduledFunctionDefinition;
|
|
64
|
+
export declare const paymentReconcile: import("./types").ScheduledFunctionDefinition;
|
|
65
|
+
/**
|
|
66
|
+
* 🛑 ITS OWN FUNCTION, AND DELIBERATELY NOT A FIRESTORE TRIGGER.
|
|
67
|
+
*
|
|
68
|
+
* A trigger on `inventoryPlacements` writing back to `storageBoxes` would fire
|
|
69
|
+
* on every pick, move and receive — a 50-row receive is 50 placement writes and
|
|
70
|
+
* would wake it 50 times to recompute the same two boxes. It is also one
|
|
71
|
+
* refactor away from Root Cause #92's shape, which cost 1,017,548 invocations
|
|
72
|
+
* in 24 hours against a 2M/month free quota.
|
|
73
|
+
*
|
|
74
|
+
* Nightly is right because the rollup is ADVISORY: every surface that must be
|
|
75
|
+
* correct reads placements directly (the box detail page does, and says so),
|
|
76
|
+
* so a day-stale rollup costs a slightly wrong number in a list and never a
|
|
77
|
+
* wrong decision.
|
|
78
|
+
*
|
|
79
|
+
* 🛑 06:15 UTC, AND THE SLOT WAS CHOSEN BY COUNTING, NOT BY EYE. My first
|
|
80
|
+
* pick was 04:30 with a comment claiming it kept three collection-walking jobs
|
|
81
|
+
* out of the same minute — while `30 4 * * *` ALREADY held two
|
|
82
|
+
* (`priceIndexRollup` at 540s/512MiB among them), so it would have made three
|
|
83
|
+
* and the comment would have asserted the opposite of what it did.
|
|
84
|
+
*
|
|
85
|
+
* `grep -o 'cron: "…"' | sort | uniq -c` over this file is the check: 06:15 is
|
|
86
|
+
* empty, clear of the dense 00:00–05:30 band and of the 10:00 IST digest.
|
|
87
|
+
*/
|
|
88
|
+
export declare const boxRollupReconcile: import("./types").ScheduledFunctionDefinition;
|
|
18
89
|
export declare const positionsReconcile: import("./types").ScheduledFunctionDefinition;
|
|
19
90
|
export declare const cartPrune: import("./types").ScheduledFunctionDefinition;
|
|
20
91
|
export declare const notificationPrune: import("./types").ScheduledFunctionDefinition;
|
|
@@ -28,4 +99,4 @@ export declare const prizeDrawExpiryReveal: import("./types").ScheduledFunctionD
|
|
|
28
99
|
export declare const bundleStockSync: import("./types").ScheduledFunctionDefinition;
|
|
29
100
|
export declare const emiInstallmentReminder: import("./types").ScheduledFunctionDefinition;
|
|
30
101
|
export declare const catalogueImageStalenessReminder: import("./types").ScheduledFunctionDefinition;
|
|
31
|
-
export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
|
|
102
|
+
export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Scheduled function definitions (Cloud Scheduler triggers).
|
|
2
2
|
// Cron syntax accepts both Firebase shorthand and standard cron expressions.
|
|
3
|
-
import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, priceIndexRollupHandler, searchIndexBuildHandler, analyticsAlertEvaluateHandler, pageViewRollupHandler, pageViewPruneHandler, dailyStatusDigestHandler, weeklyPayoutEligibilityHandler, testDataCleanupHandler, } from "../jobs/handlers/index.js";
|
|
3
|
+
import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, boxRollupReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, obligationSweepHandler, paymentReconcileHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, priceIndexRollupHandler, marketPriceRollupHandler, searchIndexBuildHandler, analyticsAlertEvaluateHandler, pageViewRollupHandler, pageViewPruneHandler, dailyStatusDigestHandler, weeklyPayoutEligibilityHandler, testDataCleanupHandler, } from "../jobs/handlers/index.js";
|
|
4
4
|
import { defineFunction } from "./define.js";
|
|
5
5
|
const REGION = "asia-south1";
|
|
6
6
|
const EVERY_5_MIN = "every 5 minutes";
|
|
@@ -113,6 +113,28 @@ export const priceIndexRollup = defineFunction({
|
|
|
113
113
|
handler: priceIndexRollupHandler,
|
|
114
114
|
options: { region: REGION, timeoutSeconds: 540, memory: "512MiB", maxInstances: 1 },
|
|
115
115
|
});
|
|
116
|
+
/*
|
|
117
|
+
* The ASKING half of the same page, from dated `priceObservations` rows.
|
|
118
|
+
*
|
|
119
|
+
* 🛑 A separate function from `priceIndexRollup`, not a second pass inside it,
|
|
120
|
+
* and the reason is the one that file already states for itself: these two
|
|
121
|
+
* bands are *"rendered side by side and never averaged"*. Sharing a function
|
|
122
|
+
* would also share a failure — a bad observation import taking the realised-
|
|
123
|
+
* sale index down with it, when the two read entirely different collections and
|
|
124
|
+
* have no reason to fail together.
|
|
125
|
+
*
|
|
126
|
+
* 05:00 UTC, half an hour after the sold half: both feed one page, and running
|
|
127
|
+
* them adjacently means a reader never sees one half a day fresher than the
|
|
128
|
+
* other. Not simultaneously — `maxInstances: 1` on each, but they would still
|
|
129
|
+
* contend for the same Firestore read budget in the same minute for no gain.
|
|
130
|
+
*/
|
|
131
|
+
export const marketPriceRollup = defineFunction({
|
|
132
|
+
name: "marketPriceRollup",
|
|
133
|
+
description: "Roll up dated price observations into marketPriceIndex/{leafId} — mode, 6-month low/high (daily 05:00 UTC = 10:30 IST).",
|
|
134
|
+
trigger: { kind: "schedule", cron: "0 5 * * *", timeZone: "UTC" },
|
|
135
|
+
handler: marketPriceRollupHandler,
|
|
136
|
+
options: { region: REGION, timeoutSeconds: 540, memory: "512MiB", maxInstances: 1 },
|
|
137
|
+
});
|
|
116
138
|
/*
|
|
117
139
|
* Evaluate the alert rules sellers and admins configured — hourly, 20 past.
|
|
118
140
|
*
|
|
@@ -178,6 +200,94 @@ export const countersReconcile = defineFunction({
|
|
|
178
200
|
handler: countersReconcileHandler,
|
|
179
201
|
options: { region: REGION, timeoutSeconds: 540, memory: "256MiB", maxInstances: 1 },
|
|
180
202
|
});
|
|
203
|
+
/**
|
|
204
|
+
* Payment reconciliation — R2, R3 and R4. Daily 05:30 UTC.
|
|
205
|
+
*
|
|
206
|
+
* 🛑 ITS OWN FUNCTION, and the two obvious places to fold it are both wrong.
|
|
207
|
+
*
|
|
208
|
+
* `countersReconcile` above already runs at its 540 s ceiling, so adding work
|
|
209
|
+
* there is how a job starts timing out and taking category metrics with it.
|
|
210
|
+
* `autoPayoutEligibility` is tempting because both touch orders, but
|
|
211
|
+
* `priceIndexRollup`'s own comment sets the precedent: a job should be able to
|
|
212
|
+
* fail without taking an unrelated one down, and these two share nothing beyond
|
|
213
|
+
* the collection.
|
|
214
|
+
*
|
|
215
|
+
* Cloud Scheduler bills **per registered job** (3 free, 28 already registered),
|
|
216
|
+
* so this is ~$0.10/month — a cost the Firebase budget table explicitly accepts
|
|
217
|
+
* for a distinct cadence rather than contorting the schedule around it.
|
|
218
|
+
*
|
|
219
|
+
* 🛑 R1 is NOT here. It is folded into `paymentWindowTimeout` (every 5 minutes),
|
|
220
|
+
* because a webhook we received and lost should not wait up to 24 hours to be
|
|
221
|
+
* noticed — and its query is one indexed read, so the tight loop is free.
|
|
222
|
+
*
|
|
223
|
+
* 05:30 UTC = 11:00 IST, deliberately after `countersReconcile` (03:00) and
|
|
224
|
+
* `autoPayoutEligibility` so a payout decision is never taken on the same tick
|
|
225
|
+
* as the reconciliation that might open a case blocking it.
|
|
226
|
+
*/
|
|
227
|
+
/**
|
|
228
|
+
* Every deadline in the order lifecycle — one job, every 5 minutes.
|
|
229
|
+
*
|
|
230
|
+
* 🛑 ONE JOB FOR ~20 SCENARIOS, and the Scheduler count goes DOWN.
|
|
231
|
+
*
|
|
232
|
+
* The alternative was a cron per scenario, which is ~$2/month *and* `O(n²)`
|
|
233
|
+
* coverage reasoning — D25, D27 and the duplicate buyout notification are all
|
|
234
|
+
* that pattern failing. Here it is one indexed query per tick, empty when idle,
|
|
235
|
+
* and `obligations`' deterministic document id gives "at most one open
|
|
236
|
+
* obligation per (subject, kind)" so a double reconcile is a no-op.
|
|
237
|
+
*
|
|
238
|
+
* Phase 8 retires `paymentWindowTimeout`, `pendingOrderTimeout` and
|
|
239
|
+
* `paymentReviewAutoApprove` once their policy rows are proven, taking the
|
|
240
|
+
* registered count **28 → 29 → 27**.
|
|
241
|
+
*
|
|
242
|
+
* 🛑 NOT a Firestore trigger on `orders`. A trigger writing `obligations`
|
|
243
|
+
* whose sweep writes `orders` is Root Cause #92's self-write loop — the one
|
|
244
|
+
* that cost 1,017,548 invocations in 24 hours. Obligations are reconciled
|
|
245
|
+
* inside the order's own write, where the document is already in hand.
|
|
246
|
+
*/
|
|
247
|
+
export const obligationSweep = defineFunction({
|
|
248
|
+
name: "obligationSweep",
|
|
249
|
+
description: "Fire, warn on, or escalate every order-lifecycle deadline that has come due (every 5 minutes).",
|
|
250
|
+
trigger: { kind: "schedule", cron: EVERY_5_MIN },
|
|
251
|
+
handler: obligationSweepHandler,
|
|
252
|
+
options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
|
|
253
|
+
});
|
|
254
|
+
export const paymentReconcile = defineFunction({
|
|
255
|
+
name: "paymentReconcile",
|
|
256
|
+
description: "Reconcile the gateway's payments, refunds and disputes against our orders; open paymentCases (daily 05:30 UTC).",
|
|
257
|
+
trigger: { kind: "schedule", cron: "30 5 * * *", timeZone: "UTC" },
|
|
258
|
+
handler: paymentReconcileHandler,
|
|
259
|
+
options: { region: REGION, timeoutSeconds: 540, memory: "256MiB", maxInstances: 1 },
|
|
260
|
+
});
|
|
261
|
+
/**
|
|
262
|
+
* 🛑 ITS OWN FUNCTION, AND DELIBERATELY NOT A FIRESTORE TRIGGER.
|
|
263
|
+
*
|
|
264
|
+
* A trigger on `inventoryPlacements` writing back to `storageBoxes` would fire
|
|
265
|
+
* on every pick, move and receive — a 50-row receive is 50 placement writes and
|
|
266
|
+
* would wake it 50 times to recompute the same two boxes. It is also one
|
|
267
|
+
* refactor away from Root Cause #92's shape, which cost 1,017,548 invocations
|
|
268
|
+
* in 24 hours against a 2M/month free quota.
|
|
269
|
+
*
|
|
270
|
+
* Nightly is right because the rollup is ADVISORY: every surface that must be
|
|
271
|
+
* correct reads placements directly (the box detail page does, and says so),
|
|
272
|
+
* so a day-stale rollup costs a slightly wrong number in a list and never a
|
|
273
|
+
* wrong decision.
|
|
274
|
+
*
|
|
275
|
+
* 🛑 06:15 UTC, AND THE SLOT WAS CHOSEN BY COUNTING, NOT BY EYE. My first
|
|
276
|
+
* pick was 04:30 with a comment claiming it kept three collection-walking jobs
|
|
277
|
+
* out of the same minute — while `30 4 * * *` ALREADY held two
|
|
278
|
+
* (`priceIndexRollup` at 540s/512MiB among them), so it would have made three
|
|
279
|
+
* and the comment would have asserted the opposite of what it did.
|
|
280
|
+
*
|
|
281
|
+
* `grep -o 'cron: "…"' | sort | uniq -c` over this file is the check: 06:15 is
|
|
282
|
+
* empty, clear of the dense 00:00–05:30 band and of the 10:00 IST digest.
|
|
283
|
+
*/
|
|
284
|
+
export const boxRollupReconcile = defineFunction({
|
|
285
|
+
name: "boxRollupReconcile",
|
|
286
|
+
description: "Recompute each storage box's product/unit rollup from its real placements (daily 06:15 UTC).",
|
|
287
|
+
trigger: { kind: "schedule", cron: "15 6 * * *", timeZone: "UTC" },
|
|
288
|
+
handler: boxRollupReconcileHandler,
|
|
289
|
+
options: { region: REGION, timeoutSeconds: 540, memory: "256MiB", maxInstances: 1 },
|
|
290
|
+
});
|
|
181
291
|
export const positionsReconcile = defineFunction({
|
|
182
292
|
name: "positionsReconcile",
|
|
183
293
|
description: "Reconcile bid/auction positions (daily 03:30 UTC).",
|
|
@@ -300,6 +410,7 @@ export const SCHEDULED_FUNCTIONS = [
|
|
|
300
410
|
productStatsSync,
|
|
301
411
|
revenueRollup,
|
|
302
412
|
priceIndexRollup,
|
|
413
|
+
marketPriceRollup,
|
|
303
414
|
searchIndexBuild,
|
|
304
415
|
analyticsAlertEvaluate,
|
|
305
416
|
pageViewRollup,
|
|
@@ -307,6 +418,18 @@ export const SCHEDULED_FUNCTIONS = [
|
|
|
307
418
|
dailyStatusDigest,
|
|
308
419
|
dailyDataCleanup,
|
|
309
420
|
countersReconcile,
|
|
421
|
+
/*
|
|
422
|
+
* 🛑 Registering here is NOT optional and is easy to miss: `defineFunction`
|
|
423
|
+
* only creates the definition — `SCHEDULED_FUNCTIONS` is what
|
|
424
|
+
* `APPKIT_FUNCTIONS` spreads and `bindAllFromRegistry` binds. A function
|
|
425
|
+
* defined and not listed deploys nowhere and NOTHING ERRORS: the export
|
|
426
|
+
* exists, the file compiles, and the job simply never runs. That is the same
|
|
427
|
+
* silent-omission shape as `audit-barrel-no-seed`'s (an export whose absence
|
|
428
|
+
* makes a loader quietly skip a collection).
|
|
429
|
+
*/
|
|
430
|
+
paymentReconcile,
|
|
431
|
+
obligationSweep,
|
|
432
|
+
boxRollupReconcile,
|
|
310
433
|
positionsReconcile,
|
|
311
434
|
cartPrune,
|
|
312
435
|
notificationPrune,
|
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
import { orderRepository, payoutRepository, storeRepository, userRepository, siteSettingsRepository, } from "../../../../repositories/index.js";
|
|
2
2
|
import { getDefaultCurrency } from "../../../../core/index.js";
|
|
3
3
|
import { computePayoutDeduction } from "../../../shared/fees/calculator.js";
|
|
4
|
-
import {
|
|
4
|
+
import { payoutCutoff } from "../../../shared/fees/payout-hold.js";
|
|
5
|
+
import { PROTECTION_CLAIM_WINDOW_HOURS } from "../../../shared/features/shipping/protections.js";
|
|
6
|
+
import { ordersTaxableValue, ordersShippingReimbursement, } from "../../../shared/checkout/order-math.js";
|
|
5
7
|
import { BATCH_LIMIT } from "../handlers/messages.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
/*
|
|
9
|
+
* 🛑 `AUTO_PAYOUT_WINDOW_DAYS = 7` and `getBusinessDayCutoff` were REMOVED on
|
|
10
|
+
* 2026-10-21. Do not reinstate either.
|
|
11
|
+
*
|
|
12
|
+
* The constant was a hardcoded duplicate of `commissions.payoutHoldDays`,
|
|
13
|
+
* which no code read (D28) — so the admin-facing setting was inert while this
|
|
14
|
+
* number decided every payout.
|
|
15
|
+
*
|
|
16
|
+
* The helper was worse: it did `cutoff.setUTCDate(cutoff.getUTCDate() -
|
|
17
|
+
* daysAgo)`, i.e. it subtracted CALENDAR days under a name that said business
|
|
18
|
+
* days. Measured from Monday 2026-10-19, 7 business days back is 2026-10-08
|
|
19
|
+
* and that helper returned 2026-10-12 — **four calendar days short**, so the
|
|
20
|
+
* stated 7-business-day hold was really about five, and every hold spanning a
|
|
21
|
+
* weekend released early in the seller's favour with nothing recording that
|
|
22
|
+
* the stated hold had not been honoured.
|
|
23
|
+
*
|
|
24
|
+
* Both now come from `payoutCutoff`, which is shared with
|
|
25
|
+
* `weeklyPayoutEligibility` so the two sweeps cannot disagree about the hold —
|
|
26
|
+
* they did, and one of them had no cutoff at all.
|
|
27
|
+
*/
|
|
14
28
|
export async function runAutoPayoutEligibility(ctx) {
|
|
15
29
|
// `FEATURE_PAYOUTS` gate deleted 2026-10-19 — see `auctionSettlement.ts`.
|
|
16
30
|
// This was the one flag actually set (`functions/.env.letitrip-in-app`), so
|
|
17
31
|
// unlike its four siblings this job was running; removing the gate is a
|
|
18
32
|
// no-op in behaviour and removes the lever that could silently stop payouts.
|
|
19
|
-
ctx.logger.info("Starting daily auto-payout eligibility sweep", {
|
|
20
|
-
windowDays: AUTO_PAYOUT_WINDOW_DAYS,
|
|
21
|
-
});
|
|
22
33
|
const siteSettings = await siteSettingsRepository.getSingleton();
|
|
23
34
|
const commissions = siteSettings.commissions;
|
|
24
|
-
const cutoff =
|
|
25
|
-
|
|
35
|
+
const { cutoff, hold } = payoutCutoff({
|
|
36
|
+
payoutHoldDays: commissions?.payoutHoldDays,
|
|
37
|
+
returnWindowDays: siteSettings.returns?.windowDays,
|
|
38
|
+
maxClaimWindowHours: Math.max(PROTECTION_CLAIM_WINDOW_HOURS.shipping, PROTECTION_CLAIM_WINDOW_HOURS.sale),
|
|
39
|
+
}, { onWarn: (m, meta) => ctx.logger.warn(m, meta) });
|
|
40
|
+
/*
|
|
41
|
+
* Log the hold AND which input won. The admin setting is seeded at 2 days
|
|
42
|
+
* against a 7-day floor, so the honoured value will usually not be the one
|
|
43
|
+
* they configured — saying `source: "floor"` is what stops that reading as
|
|
44
|
+
* a bug to whoever set it.
|
|
45
|
+
*/
|
|
46
|
+
ctx.logger.info("Starting daily auto-payout eligibility sweep", {
|
|
47
|
+
holdDays: hold.days,
|
|
48
|
+
holdSource: hold.source,
|
|
49
|
+
floorDays: hold.floor,
|
|
50
|
+
configured: commissions?.payoutHoldDays ?? null,
|
|
51
|
+
cutoff: cutoff.toISOString(),
|
|
52
|
+
});
|
|
53
|
+
const eligible = await orderRepository.getEligibleAutomatic(cutoff, {
|
|
54
|
+
onWarn: (m, meta) => ctx.logger.warn(m, meta),
|
|
55
|
+
});
|
|
26
56
|
if (eligible.length === 0) {
|
|
27
57
|
ctx.logger.info("No auto-payout eligible orders found");
|
|
28
58
|
return;
|
|
@@ -82,7 +112,15 @@ export async function runAutoPayoutEligibility(ctx) {
|
|
|
82
112
|
* so the goods value still has our GST inside it.
|
|
83
113
|
*/
|
|
84
114
|
const grossAmount = ordersTaxableValue(orders.map((o) => o.data));
|
|
85
|
-
const { platformFee, gatewayFee, gstOnFee: gstAmount, netAmount } = computePayoutDeduction(grossAmount, commissions
|
|
115
|
+
const { platformFee, gatewayFee, gstOnFee: gstAmount, netAmount } = computePayoutDeduction(grossAmount, commissions,
|
|
116
|
+
/*
|
|
117
|
+
* D45 — postage refunded to the seller, added AFTER the fee bases so no
|
|
118
|
+
* commission is charged on a cost being refunded. `.data` for the same
|
|
119
|
+
* reason `ordersTaxableValue` above needs it: `orders` holds
|
|
120
|
+
* `{ id, data }` wrappers, and passing the wrapper would read every field
|
|
121
|
+
* as undefined and silently reimburse zero.
|
|
122
|
+
*/
|
|
123
|
+
ordersShippingReimbursement(orders.map((o) => o.data)));
|
|
86
124
|
const payoutInput = {
|
|
87
125
|
storeId,
|
|
88
126
|
// `displayName` is plaintext by D1; the email fallback must be revealed.
|
|
@@ -121,7 +159,15 @@ export async function runAutoPayoutEligibility(ctx) {
|
|
|
121
159
|
bankName: sellerPlain.payoutDetails.bankAccount.bankName,
|
|
122
160
|
}
|
|
123
161
|
: undefined,
|
|
124
|
-
|
|
162
|
+
/*
|
|
163
|
+
* 🛑 `hold.days`, NOT the deleted `AUTO_PAYOUT_WINDOW_DAYS`. This note
|
|
164
|
+
* still named the constant that was removed on 2026-10-21 for being a
|
|
165
|
+
* hardcoded duplicate of `commissions.payoutHoldDays` — see the header.
|
|
166
|
+
* Reinstating it is explicitly forbidden there, and it would also make
|
|
167
|
+
* the note LIE: `hold.days` is the value actually honoured, which is
|
|
168
|
+
* the floor or the admin setting, whichever won.
|
|
169
|
+
*/
|
|
170
|
+
notes: `Auto-payout — ${orders.length} delivered order(s) past the ${hold.days}-day hold`,
|
|
125
171
|
requestedAt: new Date(),
|
|
126
172
|
};
|
|
127
173
|
const { id: payoutId } = await payoutRepository.createPayout(payoutInput);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recompute every storage box's `rollup` from its real placements.
|
|
3
|
+
*
|
|
4
|
+
* ── WHY A JOB AND NOT A TRIGGER ─────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* `rollup` exists so the boxes LIST can show "8 products · 23 units" without
|
|
7
|
+
* one placements query per row. It is a cache, and this is its only writer.
|
|
8
|
+
*
|
|
9
|
+
* 🛑 DELIBERATELY NOT A FIRESTORE TRIGGER ON `inventoryPlacements`. A trigger
|
|
10
|
+
* that watched placements and wrote back to `storageBoxes` would fire on every
|
|
11
|
+
* single pick, move and receive — a 50-row receive is 50 placement writes and
|
|
12
|
+
* would wake it 50 times to recompute the same two boxes. Worse, it is one
|
|
13
|
+
* refactor away from Root Cause #92's shape: a trigger whose write-back lands
|
|
14
|
+
* in a collection it also watches, which cost this project 1,017,548
|
|
15
|
+
* invocations in 24 hours against a 2M/month free quota.
|
|
16
|
+
*
|
|
17
|
+
* A nightly pass is the right cadence BECAUSE THE CACHE IS ADVISORY. Every
|
|
18
|
+
* surface that must be correct reads placements directly — the box detail page
|
|
19
|
+
* does, and its own note says why — so a rollup up to a day stale costs a
|
|
20
|
+
* slightly wrong number in a list, never a wrong decision.
|
|
21
|
+
*
|
|
22
|
+
* ── WHAT IT FIXES, AS OPPOSED TO MAINTAINS ──────────────────────────────────
|
|
23
|
+
*
|
|
24
|
+
* It is a REPAIR job, which is the lesson from Root Cause #102: a reconciler
|
|
25
|
+
* must enumerate the ENTITIES, not the events, or it can only ever add. A box
|
|
26
|
+
* whose last product was picked yesterday has no placements at all — so a pass
|
|
27
|
+
* built from placements would never visit it, and it would keep advertising
|
|
28
|
+
* the count it had when it was last full. Walking `storageBoxes` and treating
|
|
29
|
+
* "no placements" as a real zero is the whole point.
|
|
30
|
+
*
|
|
31
|
+
* It also logs `drifted`. On a quiet day that number should be 0, and a
|
|
32
|
+
* non-zero one is a real signal that something wrote placements without the
|
|
33
|
+
* repository — which `audit-inventory-ledger-append-only` is supposed to make
|
|
34
|
+
* impossible.
|
|
35
|
+
*
|
|
36
|
+
* @tag domain:inventory
|
|
37
|
+
* @tag layer:job
|
|
38
|
+
* @tag access:server
|
|
39
|
+
*/
|
|
40
|
+
import type { JobContext } from "../runtime/types";
|
|
41
|
+
export interface BoxRollupReconcileResult {
|
|
42
|
+
boxesVisited: number;
|
|
43
|
+
drifted: number;
|
|
44
|
+
written: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function runBoxRollupReconcile(ctx: JobContext): Promise<BoxRollupReconcileResult>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recompute every storage box's `rollup` from its real placements.
|
|
3
|
+
*
|
|
4
|
+
* ── WHY A JOB AND NOT A TRIGGER ─────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* `rollup` exists so the boxes LIST can show "8 products · 23 units" without
|
|
7
|
+
* one placements query per row. It is a cache, and this is its only writer.
|
|
8
|
+
*
|
|
9
|
+
* 🛑 DELIBERATELY NOT A FIRESTORE TRIGGER ON `inventoryPlacements`. A trigger
|
|
10
|
+
* that watched placements and wrote back to `storageBoxes` would fire on every
|
|
11
|
+
* single pick, move and receive — a 50-row receive is 50 placement writes and
|
|
12
|
+
* would wake it 50 times to recompute the same two boxes. Worse, it is one
|
|
13
|
+
* refactor away from Root Cause #92's shape: a trigger whose write-back lands
|
|
14
|
+
* in a collection it also watches, which cost this project 1,017,548
|
|
15
|
+
* invocations in 24 hours against a 2M/month free quota.
|
|
16
|
+
*
|
|
17
|
+
* A nightly pass is the right cadence BECAUSE THE CACHE IS ADVISORY. Every
|
|
18
|
+
* surface that must be correct reads placements directly — the box detail page
|
|
19
|
+
* does, and its own note says why — so a rollup up to a day stale costs a
|
|
20
|
+
* slightly wrong number in a list, never a wrong decision.
|
|
21
|
+
*
|
|
22
|
+
* ── WHAT IT FIXES, AS OPPOSED TO MAINTAINS ──────────────────────────────────
|
|
23
|
+
*
|
|
24
|
+
* It is a REPAIR job, which is the lesson from Root Cause #102: a reconciler
|
|
25
|
+
* must enumerate the ENTITIES, not the events, or it can only ever add. A box
|
|
26
|
+
* whose last product was picked yesterday has no placements at all — so a pass
|
|
27
|
+
* built from placements would never visit it, and it would keep advertising
|
|
28
|
+
* the count it had when it was last full. Walking `storageBoxes` and treating
|
|
29
|
+
* "no placements" as a real zero is the whole point.
|
|
30
|
+
*
|
|
31
|
+
* It also logs `drifted`. On a quiet day that number should be 0, and a
|
|
32
|
+
* non-zero one is a real signal that something wrote placements without the
|
|
33
|
+
* repository — which `audit-inventory-ledger-append-only` is supposed to make
|
|
34
|
+
* impossible.
|
|
35
|
+
*
|
|
36
|
+
* @tag domain:inventory
|
|
37
|
+
* @tag layer:job
|
|
38
|
+
* @tag access:server
|
|
39
|
+
*/
|
|
40
|
+
import { INVENTORY_PLACEMENTS_COLLECTION, STORAGE_BOXES_COLLECTION, } from "../../../../features/inventory/schemas/firestore.js";
|
|
41
|
+
/** Pages rather than `.limit(1000)` — see the note at the call. */
|
|
42
|
+
const BOX_PAGE = 200;
|
|
43
|
+
export async function runBoxRollupReconcile(ctx) {
|
|
44
|
+
const db = ctx.db;
|
|
45
|
+
let boxesVisited = 0;
|
|
46
|
+
let drifted = 0;
|
|
47
|
+
let written = 0;
|
|
48
|
+
/*
|
|
49
|
+
* 🛑 PAGINATED, NOT `.limit(N)`. A truncated reconcile is indistinguishable
|
|
50
|
+
* from a complete one — it logs "reconciliation complete" having silently
|
|
51
|
+
* ignored every box past the cap, which is exactly how the counters job
|
|
52
|
+
* under-reported for weeks (Root Cause #102). Ordering by document id gives
|
|
53
|
+
* a stable cursor with no index.
|
|
54
|
+
*/
|
|
55
|
+
let cursor = null;
|
|
56
|
+
for (;;) {
|
|
57
|
+
let q = db
|
|
58
|
+
.collection(STORAGE_BOXES_COLLECTION)
|
|
59
|
+
.orderBy("__name__")
|
|
60
|
+
.limit(BOX_PAGE);
|
|
61
|
+
if (cursor)
|
|
62
|
+
q = q.startAfter(cursor);
|
|
63
|
+
const page = await q.get();
|
|
64
|
+
if (page.empty)
|
|
65
|
+
break;
|
|
66
|
+
for (const doc of page.docs) {
|
|
67
|
+
boxesVisited += 1;
|
|
68
|
+
const box = doc.data();
|
|
69
|
+
/*
|
|
70
|
+
* One query per box. Bounded and cheap — a box holds tens of products,
|
|
71
|
+
* not thousands — and `.select()` fetches only the two fields the tally
|
|
72
|
+
* needs rather than every placement's denormalised title and SKU.
|
|
73
|
+
*/
|
|
74
|
+
const placements = await db
|
|
75
|
+
.collection(INVENTORY_PLACEMENTS_COLLECTION)
|
|
76
|
+
.where("boxId", "==", doc.id)
|
|
77
|
+
.select("quantity")
|
|
78
|
+
.get();
|
|
79
|
+
let distinctProducts = 0;
|
|
80
|
+
let totalUnits = 0;
|
|
81
|
+
for (const p of placements.docs) {
|
|
82
|
+
const qty = p.data()
|
|
83
|
+
.quantity;
|
|
84
|
+
/*
|
|
85
|
+
* A zero- or negative-quantity placement should not exist — `pick`
|
|
86
|
+
* deletes at zero — so it is counted as neither a product nor a unit
|
|
87
|
+
* and reported, rather than quietly inflating `distinctProducts` with
|
|
88
|
+
* a row representing nothing.
|
|
89
|
+
*/
|
|
90
|
+
if (!(typeof qty === "number" && qty > 0))
|
|
91
|
+
continue;
|
|
92
|
+
distinctProducts += 1;
|
|
93
|
+
totalUnits += qty;
|
|
94
|
+
}
|
|
95
|
+
const prior = box.rollup;
|
|
96
|
+
const changed = !prior ||
|
|
97
|
+
prior.distinctProducts !== distinctProducts ||
|
|
98
|
+
prior.totalUnits !== totalUnits;
|
|
99
|
+
if (!changed)
|
|
100
|
+
continue;
|
|
101
|
+
drifted += 1;
|
|
102
|
+
/*
|
|
103
|
+
* A direct `update`, not `storageBoxesRepository.setRollup`. The job
|
|
104
|
+
* owns thousands of these and a repository call per box would re-read
|
|
105
|
+
* the document it already holds — and the repository's own note says
|
|
106
|
+
* `setRollup` is for a caller that has a box id and nothing else.
|
|
107
|
+
*
|
|
108
|
+
* Only the three rollup fields plus `updatedAt` are written: a merge of
|
|
109
|
+
* the whole document would resurrect any field a concurrent edit had
|
|
110
|
+
* just cleared.
|
|
111
|
+
*/
|
|
112
|
+
/*
|
|
113
|
+
* `ctx.now`, not `new Date()`. Every box in one pass then carries the
|
|
114
|
+
* SAME `computedAt`, so "as of" on a printed label means the pass rather
|
|
115
|
+
* than the millisecond that box happened to be reached — and two boxes
|
|
116
|
+
* reconciled by one run cannot appear to have been counted minutes
|
|
117
|
+
* apart.
|
|
118
|
+
*/
|
|
119
|
+
await doc.ref.update({
|
|
120
|
+
rollup: { distinctProducts, totalUnits, computedAt: ctx.now },
|
|
121
|
+
updatedAt: ctx.now,
|
|
122
|
+
});
|
|
123
|
+
written += 1;
|
|
124
|
+
}
|
|
125
|
+
if (page.size < BOX_PAGE)
|
|
126
|
+
break;
|
|
127
|
+
cursor = page.docs[page.docs.length - 1].id;
|
|
128
|
+
}
|
|
129
|
+
/*
|
|
130
|
+
* `drifted` is the signal, not `boxesVisited`. Every placement write goes
|
|
131
|
+
* through the repository, which keeps nothing cached — so on a quiet day
|
|
132
|
+
* this should be the number of boxes whose contents actually changed since
|
|
133
|
+
* the last pass. A number far larger than that, or one that never falls,
|
|
134
|
+
* means something is writing placements outside the repository.
|
|
135
|
+
*/
|
|
136
|
+
ctx.logger.info("boxRollupReconcile complete", {
|
|
137
|
+
boxesVisited,
|
|
138
|
+
drifted,
|
|
139
|
+
written,
|
|
140
|
+
});
|
|
141
|
+
return { boxesVisited, drifted, written };
|
|
142
|
+
}
|