@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.
- 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.d.ts +20 -2
- package/dist/_internal/server/features/orders/adapters.js +44 -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 +10 -4
- package/dist/client.js +29 -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 +43 -0
- package/dist/server.js +98 -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
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: "What is in AC60-03" and "where is this product" are the two questions
|
|
3
|
+
* the whole feature exists to answer, and both must be one bounded read.
|
|
4
|
+
* WHAT: The current placement of stock, moved only through transactions that
|
|
5
|
+
* also append to the ledger.
|
|
6
|
+
*
|
|
7
|
+
* ── 🛑 A ZERO-QUANTITY PLACEMENT IS DELETED, NEVER STORED AT ZERO ──────────
|
|
8
|
+
*
|
|
9
|
+
* Keeping zeros would force every box read to pair `quantity > 0` with an
|
|
10
|
+
* `orderBy`. Firestore appends an inequality's field to the sort implicitly,
|
|
11
|
+
* so that demands a composite index in an order nobody declares, fails with
|
|
12
|
+
* FAILED_PRECONDITION, and every caller in this codebase wraps such a read in
|
|
13
|
+
* `.catch(() => null)` — which renders as an EMPTY BOX rather than an error.
|
|
14
|
+
* Root Cause #59. Absence means zero, and no query needs an inequality.
|
|
15
|
+
*
|
|
16
|
+
* ── 🛑 EVERY MOVE IS A TRANSACTION THAT ALSO WRITES THE LEDGER ────────────
|
|
17
|
+
*
|
|
18
|
+
* A placement changed without a movement row is stock that teleported: the
|
|
19
|
+
* count is right and nobody can say why. Doing them in one transaction is
|
|
20
|
+
* what makes the ledger complete rather than best-effort — the alternative
|
|
21
|
+
* (write the placement, then append) leaves a gap whenever the second write
|
|
22
|
+
* fails, and a ledger with gaps cannot be used to find a missing item.
|
|
23
|
+
*
|
|
24
|
+
* Holds no PII.
|
|
25
|
+
*
|
|
26
|
+
* EXPORTS: InventoryPlacementsRepository, inventoryPlacementsRepository
|
|
27
|
+
*
|
|
28
|
+
* @tag domain:inventory
|
|
29
|
+
* @tag layer:feature
|
|
30
|
+
* @tag pattern:repository
|
|
31
|
+
* @tag access:server
|
|
32
|
+
* @tag sideEffects:firestore
|
|
33
|
+
*/
|
|
34
|
+
import { BaseRepository, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
|
|
35
|
+
import { unitOfWork } from "../../../core/unit-of-work.js";
|
|
36
|
+
import { INVENTORY_MOVEMENTS_COLLECTION, INVENTORY_PLACEMENTS_COLLECTION, INVENTORY_PLACEMENT_FIELDS, placementId, } from "../schemas/firestore.js";
|
|
37
|
+
export class InventoryPlacementsRepository extends BaseRepository {
|
|
38
|
+
constructor() {
|
|
39
|
+
super(INVENTORY_PLACEMENTS_COLLECTION);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Is this product in this box, and how many?
|
|
43
|
+
*
|
|
44
|
+
* 🛑 One document READ, because the id is deterministic. With a generated
|
|
45
|
+
* id this would be a two-field query needing its own composite index — and
|
|
46
|
+
* a double-submit could create a second row for the same pair that silently
|
|
47
|
+
* doubles the count.
|
|
48
|
+
*/
|
|
49
|
+
async get(boxId, productId) {
|
|
50
|
+
return this.findById(placementId(boxId, productId));
|
|
51
|
+
}
|
|
52
|
+
/** What is in this box. One equality, served by the automatic index. */
|
|
53
|
+
async listByBox(boxId, limit = 200) {
|
|
54
|
+
const snap = await this.getCollection()
|
|
55
|
+
.where(INVENTORY_PLACEMENT_FIELDS.BOX_ID, "==", boxId)
|
|
56
|
+
.limit(limit)
|
|
57
|
+
.get();
|
|
58
|
+
return snap.docs.map((d) => this.mapDoc(d));
|
|
59
|
+
}
|
|
60
|
+
/** Where is this product. Also one equality — this is the pair that matters. */
|
|
61
|
+
async listByProduct(productId, limit = 50) {
|
|
62
|
+
const snap = await this.getCollection()
|
|
63
|
+
.where(INVENTORY_PLACEMENT_FIELDS.PRODUCT_ID, "==", productId)
|
|
64
|
+
.limit(limit)
|
|
65
|
+
.get();
|
|
66
|
+
return snap.docs.map((d) => this.mapDoc(d));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Put stock into a box — a receive, or an adjustment that found some.
|
|
70
|
+
*
|
|
71
|
+
* 🛑 Idempotent upsert via the deterministic id, and the increment happens
|
|
72
|
+
* INSIDE the transaction from the value read inside it. Reading first and
|
|
73
|
+
* writing after would lose one of two concurrent receives of the same
|
|
74
|
+
* product into the same box, which is exactly what a receive station with
|
|
75
|
+
* two people scanning does.
|
|
76
|
+
*/
|
|
77
|
+
async place(input) {
|
|
78
|
+
this.assertQuantity(input.quantity);
|
|
79
|
+
const pid = placementId(input.boxId, input.productId);
|
|
80
|
+
await unitOfWork.runTransaction(async (tx) => {
|
|
81
|
+
const ref = this.getCollection().doc(pid);
|
|
82
|
+
const snap = await tx.get(ref);
|
|
83
|
+
const now = new Date();
|
|
84
|
+
const prior = snap.exists ? snap.data()?.quantity ?? 0 : 0;
|
|
85
|
+
tx.set(ref, {
|
|
86
|
+
boxId: input.boxId,
|
|
87
|
+
productId: input.productId,
|
|
88
|
+
boxCode: input.boxCode,
|
|
89
|
+
productTitle: input.productTitle,
|
|
90
|
+
...(input.productSku ? { productSku: input.productSku } : {}),
|
|
91
|
+
...(input.slot ? { slot: input.slot } : {}),
|
|
92
|
+
quantity: prior + input.quantity,
|
|
93
|
+
updatedAt: now,
|
|
94
|
+
...(snap.exists ? {} : { createdAt: now }),
|
|
95
|
+
}, { merge: true });
|
|
96
|
+
this.appendMovement(tx, {
|
|
97
|
+
kind: input.kind,
|
|
98
|
+
productId: input.productId,
|
|
99
|
+
quantity: input.quantity,
|
|
100
|
+
toBoxId: input.boxId,
|
|
101
|
+
toBoxCode: input.boxCode,
|
|
102
|
+
productTitle: input.productTitle,
|
|
103
|
+
actorUid: input.actorUid,
|
|
104
|
+
...(input.reason ? { reason: input.reason } : {}),
|
|
105
|
+
...(input.shipmentId ? { shipmentId: input.shipmentId } : {}),
|
|
106
|
+
occurredAt: new Date(),
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Box → box.
|
|
112
|
+
*
|
|
113
|
+
* 🛑 REFUSES rather than going negative. A move of more than the source
|
|
114
|
+
* holds is a miscount, and clamping it would make the ledger assert a
|
|
115
|
+
* movement of a quantity that was not there — the one thing that makes the
|
|
116
|
+
* ledger unusable as evidence.
|
|
117
|
+
*/
|
|
118
|
+
async move(input) {
|
|
119
|
+
this.assertQuantity(input.quantity);
|
|
120
|
+
if (input.fromBoxId === input.toBoxId) {
|
|
121
|
+
throw new Error("Source and destination box are the same");
|
|
122
|
+
}
|
|
123
|
+
const fromId = placementId(input.fromBoxId, input.productId);
|
|
124
|
+
const toId = placementId(input.toBoxId, input.productId);
|
|
125
|
+
await unitOfWork.runTransaction(async (tx) => {
|
|
126
|
+
const fromRef = this.getCollection().doc(fromId);
|
|
127
|
+
const toRef = this.getCollection().doc(toId);
|
|
128
|
+
/*
|
|
129
|
+
* Both reads before either write — a transaction cannot read after a
|
|
130
|
+
* write, and the destination read is what makes the upsert correct when
|
|
131
|
+
* the product is already in the target box.
|
|
132
|
+
*/
|
|
133
|
+
const [fromSnap, toSnap] = await Promise.all([tx.get(fromRef), tx.get(toRef)]);
|
|
134
|
+
const have = fromSnap.exists ? fromSnap.data()?.quantity ?? 0 : 0;
|
|
135
|
+
if (have < input.quantity) {
|
|
136
|
+
throw new Error(`${input.fromBoxCode} holds ${have} of that product, cannot move ${input.quantity}. ` +
|
|
137
|
+
`Record an \`adjust\` with a reason if the count is wrong.`);
|
|
138
|
+
}
|
|
139
|
+
const now = new Date();
|
|
140
|
+
const remaining = have - input.quantity;
|
|
141
|
+
// Absence means zero — see the header.
|
|
142
|
+
if (remaining === 0)
|
|
143
|
+
tx.delete(fromRef);
|
|
144
|
+
else
|
|
145
|
+
tx.update(fromRef, { quantity: remaining, updatedAt: now });
|
|
146
|
+
const already = toSnap.exists ? toSnap.data()?.quantity ?? 0 : 0;
|
|
147
|
+
tx.set(toRef, {
|
|
148
|
+
boxId: input.toBoxId,
|
|
149
|
+
productId: input.productId,
|
|
150
|
+
boxCode: input.toBoxCode,
|
|
151
|
+
productTitle: input.productTitle,
|
|
152
|
+
...(input.productSku ? { productSku: input.productSku } : {}),
|
|
153
|
+
quantity: already + input.quantity,
|
|
154
|
+
updatedAt: now,
|
|
155
|
+
...(toSnap.exists ? {} : { createdAt: now }),
|
|
156
|
+
}, { merge: true });
|
|
157
|
+
this.appendMovement(tx, {
|
|
158
|
+
kind: "move",
|
|
159
|
+
productId: input.productId,
|
|
160
|
+
quantity: input.quantity,
|
|
161
|
+
fromBoxId: input.fromBoxId,
|
|
162
|
+
fromBoxCode: input.fromBoxCode,
|
|
163
|
+
toBoxId: input.toBoxId,
|
|
164
|
+
toBoxCode: input.toBoxCode,
|
|
165
|
+
productTitle: input.productTitle,
|
|
166
|
+
actorUid: input.actorUid,
|
|
167
|
+
occurredAt: now,
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Take stock out of a box.
|
|
173
|
+
*
|
|
174
|
+
* 🛑 MANUAL, and never fired from checkout. An automatic decrement on
|
|
175
|
+
* payment would have the ledger assert a movement nobody performed — the
|
|
176
|
+
* stock is sold, but it is still in the box until a person walks over and
|
|
177
|
+
* picks it. A ledger recording intentions instead of actions cannot be used
|
|
178
|
+
* to find a missing item, which is its only real job.
|
|
179
|
+
*
|
|
180
|
+
* 🛑 And this does NOT touch `product.stockQuantity`. That stays
|
|
181
|
+
* authoritative and is owned by the order path; writing both is how a
|
|
182
|
+
* reserved unit gets handed back to the shelf (see the schema header).
|
|
183
|
+
*/
|
|
184
|
+
async pick(input) {
|
|
185
|
+
this.assertQuantity(input.quantity);
|
|
186
|
+
const pid = placementId(input.boxId, input.productId);
|
|
187
|
+
await unitOfWork.runTransaction(async (tx) => {
|
|
188
|
+
const ref = this.getCollection().doc(pid);
|
|
189
|
+
const snap = await tx.get(ref);
|
|
190
|
+
const have = snap.exists ? snap.data()?.quantity ?? 0 : 0;
|
|
191
|
+
if (have < input.quantity) {
|
|
192
|
+
throw new Error(`${input.boxCode} holds ${have} of that product, cannot pick ${input.quantity}.`);
|
|
193
|
+
}
|
|
194
|
+
const now = new Date();
|
|
195
|
+
const remaining = have - input.quantity;
|
|
196
|
+
if (remaining === 0)
|
|
197
|
+
tx.delete(ref);
|
|
198
|
+
else
|
|
199
|
+
tx.update(ref, { quantity: remaining, updatedAt: now });
|
|
200
|
+
this.appendMovement(tx, {
|
|
201
|
+
kind: "pick",
|
|
202
|
+
productId: input.productId,
|
|
203
|
+
quantity: input.quantity,
|
|
204
|
+
fromBoxId: input.boxId,
|
|
205
|
+
fromBoxCode: input.boxCode,
|
|
206
|
+
productTitle: input.productTitle,
|
|
207
|
+
actorUid: input.actorUid,
|
|
208
|
+
...(input.reason ? { reason: input.reason } : {}),
|
|
209
|
+
occurredAt: now,
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The receive station's bulk commit — many rows, ONE transaction.
|
|
215
|
+
*
|
|
216
|
+
* 🛑 ONE TRANSACTION FOR THE WHOLE TABLE, not a loop of them. A partial
|
|
217
|
+
* receive is the worst outcome available: the operator has already
|
|
218
|
+
* physically put everything in the boxes, so a half-written commit leaves
|
|
219
|
+
* the ledger disagreeing with the shelf and no way to tell which rows
|
|
220
|
+
* landed.
|
|
221
|
+
*
|
|
222
|
+
* Firestore caps a transaction at 500 writes and each row here is two (the
|
|
223
|
+
* placement and its movement), so the caller's row limit of 50 is what
|
|
224
|
+
* keeps this inside the cap — that is why the limit exists, rather than
|
|
225
|
+
* being a UI preference.
|
|
226
|
+
*
|
|
227
|
+
* 🛑 Lives HERE rather than in the route for two reasons. API routes do not
|
|
228
|
+
* touch Firestore directly in this codebase, and more specifically
|
|
229
|
+
* `audit-inventory-ledger-append-only` allows only this file and the
|
|
230
|
+
* movements repository to write the ledger — a route doing it would be the
|
|
231
|
+
* second writer the audit exists to prevent, and I wrote exactly that before
|
|
232
|
+
* the audit caught me.
|
|
233
|
+
*
|
|
234
|
+
* 🛑 Does NOT touch `product.stockQuantity`. The shipment-link route already
|
|
235
|
+
* does, and doing both double-counts. This records WHERE stock is, never how
|
|
236
|
+
* much exists.
|
|
237
|
+
*/
|
|
238
|
+
async receiveBatch(input) {
|
|
239
|
+
if (input.rows.length === 0)
|
|
240
|
+
throw new Error("Nothing to receive");
|
|
241
|
+
for (const r of input.rows)
|
|
242
|
+
this.assertQuantity(r.quantity);
|
|
243
|
+
await unitOfWork.runTransaction(async (tx) => {
|
|
244
|
+
const col = this.getCollection();
|
|
245
|
+
/*
|
|
246
|
+
* All reads first — a transaction cannot read after a write. The
|
|
247
|
+
* existing quantity is read INSIDE the transaction and the increment
|
|
248
|
+
* computed from it, so two operators receiving the same product into
|
|
249
|
+
* the same box cannot lose one of the two. Not hypothetical: that is
|
|
250
|
+
* what two people with scanners do.
|
|
251
|
+
*/
|
|
252
|
+
const refs = input.rows.map((r) => col.doc(placementId(r.boxId, r.productId)));
|
|
253
|
+
const snaps = await Promise.all(refs.map((ref) => tx.get(ref)));
|
|
254
|
+
const now = new Date();
|
|
255
|
+
input.rows.forEach((r, i) => {
|
|
256
|
+
const snap = snaps[i];
|
|
257
|
+
const prior = snap.exists ? (snap.data()?.quantity ?? 0) : 0;
|
|
258
|
+
tx.set(refs[i], {
|
|
259
|
+
boxId: r.boxId,
|
|
260
|
+
productId: r.productId,
|
|
261
|
+
boxCode: r.boxCode,
|
|
262
|
+
productTitle: r.productTitle,
|
|
263
|
+
...(r.productSku ? { productSku: r.productSku } : {}),
|
|
264
|
+
...(r.slot ? { slot: r.slot } : {}),
|
|
265
|
+
quantity: prior + r.quantity,
|
|
266
|
+
updatedAt: now,
|
|
267
|
+
...(snap.exists ? {} : { createdAt: now }),
|
|
268
|
+
}, { merge: true });
|
|
269
|
+
this.appendMovement(tx, {
|
|
270
|
+
kind: "receive",
|
|
271
|
+
productId: r.productId,
|
|
272
|
+
quantity: r.quantity,
|
|
273
|
+
toBoxId: r.boxId,
|
|
274
|
+
toBoxCode: r.boxCode,
|
|
275
|
+
productTitle: r.productTitle,
|
|
276
|
+
actorUid: input.actorUid,
|
|
277
|
+
...(input.shipmentId ? { shipmentId: input.shipmentId } : {}),
|
|
278
|
+
occurredAt: now,
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
rows: input.rows.length,
|
|
284
|
+
units: input.rows.reduce((n, r) => n + r.quantity, 0),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
assertQuantity(q) {
|
|
288
|
+
if (!Number.isInteger(q) || q < 1) {
|
|
289
|
+
throw new Error(`Quantity must be a positive whole number, got ${q}. Direction is carried by the operation, never by the sign.`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Append a ledger row inside the caller's transaction.
|
|
294
|
+
*
|
|
295
|
+
* 🛑 Written through the raw collection rather than
|
|
296
|
+
* `inventoryMovementsRepository.append`, because that method is not
|
|
297
|
+
* transaction-aware and a second, non-transactional write would reopen the
|
|
298
|
+
* gap this whole design closes. The VALIDATION it performs is mirrored by
|
|
299
|
+
* the typed `MovementKind` endpoints above and by the quantity assert — so
|
|
300
|
+
* the shape is still checked, by the compiler rather than at runtime.
|
|
301
|
+
*
|
|
302
|
+
* `audit-inventory-ledger-append-only` allows this one path by name.
|
|
303
|
+
*/
|
|
304
|
+
/*
|
|
305
|
+
* 🛑 `Transaction`, not a structural `{ set: (ref: unknown, data: unknown)
|
|
306
|
+
* => void }`. That shortcut did not compile and the reason is worth keeping:
|
|
307
|
+
* parameter types are CONTRAVARIANT, so a parameter annotated
|
|
308
|
+
* `(ref: unknown) => void` promises to accept anything at all — a stronger
|
|
309
|
+
* guarantee than `Transaction.set`, whose first argument must be a
|
|
310
|
+
* `DocumentReference`. So `Transaction` was not assignable to it and all
|
|
311
|
+
* three call sites failed. Widening a parameter to `unknown` narrows what
|
|
312
|
+
* can be passed IN, which is the opposite of what it looks like.
|
|
313
|
+
*
|
|
314
|
+
* `import type` keeps this free at runtime — it emits nothing, which is the
|
|
315
|
+
* same reason `unit-of-work.ts` can name the type without pulling
|
|
316
|
+
* firebase-admin into the graph (Root Cause #24).
|
|
317
|
+
*/
|
|
318
|
+
appendMovement(tx, row) {
|
|
319
|
+
const ref = this.db.collection(INVENTORY_MOVEMENTS_COLLECTION).doc();
|
|
320
|
+
tx.set(ref, { ...row, createdAt: new Date(), updatedAt: new Date() });
|
|
321
|
+
}
|
|
322
|
+
async listForAdmin(model) {
|
|
323
|
+
return this.sieveQuery(model, InventoryPlacementsRepository.SIEVE_FIELDS, { defaultPageSize: 25, maxPageSize: 50 });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
|
|
327
|
+
InventoryPlacementsRepository.SIEVE_FIELDS = {
|
|
328
|
+
id: { canFilter: true, canSort: false },
|
|
329
|
+
[INVENTORY_PLACEMENT_FIELDS.BOX_ID]: { canFilter: true, canSort: false },
|
|
330
|
+
[INVENTORY_PLACEMENT_FIELDS.PRODUCT_ID]: { canFilter: true, canSort: false },
|
|
331
|
+
[INVENTORY_PLACEMENT_FIELDS.QUANTITY]: { canFilter: true, canSort: true },
|
|
332
|
+
[INVENTORY_PLACEMENT_FIELDS.BOX_CODE]: { canFilter: true, canSort: true },
|
|
333
|
+
[INVENTORY_PLACEMENT_FIELDS.PRODUCT_SKU]: { canFilter: true, canSort: false },
|
|
334
|
+
[INVENTORY_PLACEMENT_FIELDS.CREATED_AT]: {
|
|
335
|
+
canFilter: true,
|
|
336
|
+
canSort: true,
|
|
337
|
+
parseValue: parseSieveDateValue,
|
|
338
|
+
},
|
|
339
|
+
[INVENTORY_PLACEMENT_FIELDS.UPDATED_AT]: {
|
|
340
|
+
canFilter: true,
|
|
341
|
+
canSort: true,
|
|
342
|
+
parseValue: parseSieveDateValue,
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
export const inventoryPlacementsRepository = new InventoryPlacementsRepository();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BaseRepository, parseSieveDateValue, type SieveModel, type FirebaseSieveResult } from "../../../providers/db-firebase";
|
|
2
|
+
import { type BoxStatus, type BoxType, type StorageBoxDocument } from "../schemas/firestore";
|
|
3
|
+
export interface StorageBoxCreateInput {
|
|
4
|
+
code: string;
|
|
5
|
+
boxType: BoxType;
|
|
6
|
+
location?: string;
|
|
7
|
+
capacityNote?: string;
|
|
8
|
+
status?: BoxStatus;
|
|
9
|
+
}
|
|
10
|
+
export declare class StorageBoxesRepository extends BaseRepository<StorageBoxDocument> {
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Create a box at its own code.
|
|
14
|
+
*
|
|
15
|
+
* 🛑 `createWithId`, not `create`, and that is the uniqueness guarantee: the
|
|
16
|
+
* id IS `storagebox-{code}`, so a second `AC60-03` lands on the same
|
|
17
|
+
* document instead of making a second registry row for one physical object.
|
|
18
|
+
*
|
|
19
|
+
* 🛑 And it REFUSES rather than overwriting. An operator labelling a new box
|
|
20
|
+
* who types a code already in use has made a mistake that silently merging
|
|
21
|
+
* two boxes would hide — and the merge would be unrecoverable, because the
|
|
22
|
+
* placements of both would then point at one id.
|
|
23
|
+
*/
|
|
24
|
+
createBox(input: StorageBoxCreateInput): Promise<StorageBoxDocument>;
|
|
25
|
+
/** Box by its printed code, which is what a scan or a typed search gives. */
|
|
26
|
+
findByCode(code: string): Promise<StorageBoxDocument | null>;
|
|
27
|
+
setStatus(id: string, status: BoxStatus): Promise<StorageBoxDocument>;
|
|
28
|
+
/**
|
|
29
|
+
* Write the advisory rollup.
|
|
30
|
+
*
|
|
31
|
+
* 🛑 Called ONLY by the scheduled repair job, never from a trigger on a
|
|
32
|
+
* collection this also writes. That shape is Root Cause #92 — a
|
|
33
|
+
* documentWritten trigger writing back to its own collection, whose no-op
|
|
34
|
+
* guard compared maps with `JSON.stringify` while Firestore returns map keys
|
|
35
|
+
* alphabetically, so the guard could never match and it recursed to 12M
|
|
36
|
+
* invocations against a 2M/month quota. A scheduled recompute cannot
|
|
37
|
+
* recurse, which is the entire reason for the choice.
|
|
38
|
+
*/
|
|
39
|
+
setRollup(id: string, distinctProducts: number, totalUnits: number): Promise<void>;
|
|
40
|
+
listForAdmin(model: SieveModel): Promise<FirebaseSieveResult<StorageBoxDocument>>;
|
|
41
|
+
/** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
|
|
42
|
+
static readonly SIEVE_FIELDS: {
|
|
43
|
+
id: {
|
|
44
|
+
canFilter: boolean;
|
|
45
|
+
canSort: boolean;
|
|
46
|
+
};
|
|
47
|
+
code: {
|
|
48
|
+
canFilter: boolean;
|
|
49
|
+
canSort: boolean;
|
|
50
|
+
};
|
|
51
|
+
boxType: {
|
|
52
|
+
canFilter: boolean;
|
|
53
|
+
canSort: boolean;
|
|
54
|
+
};
|
|
55
|
+
ordinal: {
|
|
56
|
+
canFilter: boolean;
|
|
57
|
+
canSort: boolean;
|
|
58
|
+
};
|
|
59
|
+
status: {
|
|
60
|
+
canFilter: boolean;
|
|
61
|
+
canSort: boolean;
|
|
62
|
+
};
|
|
63
|
+
location: {
|
|
64
|
+
canFilter: boolean;
|
|
65
|
+
canSort: boolean;
|
|
66
|
+
};
|
|
67
|
+
searchTxt: {
|
|
68
|
+
canFilter: boolean;
|
|
69
|
+
canSort: boolean;
|
|
70
|
+
};
|
|
71
|
+
createdAt: {
|
|
72
|
+
canFilter: boolean;
|
|
73
|
+
canSort: boolean;
|
|
74
|
+
parseValue: typeof parseSieveDateValue;
|
|
75
|
+
};
|
|
76
|
+
updatedAt: {
|
|
77
|
+
canFilter: boolean;
|
|
78
|
+
canSort: boolean;
|
|
79
|
+
parseValue: typeof parseSieveDateValue;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export declare const storageBoxesRepository: StorageBoxesRepository;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: A box is a physical object with a label on it, and the registry is
|
|
3
|
+
* what makes "AC60-03" mean something to the software.
|
|
4
|
+
* WHAT: Create by code, list, status transitions, and the rollup write the
|
|
5
|
+
* scheduled repair job calls.
|
|
6
|
+
*
|
|
7
|
+
* Holds no PII.
|
|
8
|
+
*
|
|
9
|
+
* EXPORTS: StorageBoxesRepository, storageBoxesRepository,
|
|
10
|
+
* StorageBoxCreateInput
|
|
11
|
+
*
|
|
12
|
+
* @tag domain:inventory
|
|
13
|
+
* @tag layer:feature
|
|
14
|
+
* @tag pattern:repository
|
|
15
|
+
* @tag access:server
|
|
16
|
+
* @tag sideEffects:firestore
|
|
17
|
+
*/
|
|
18
|
+
import { BaseRepository, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
|
|
19
|
+
import { generateStorageBoxId } from "../../../utils/id-generators.js";
|
|
20
|
+
import { buildStorageBoxSearchTxt } from "../../../utils/search-txt-builders.js";
|
|
21
|
+
import { BoxStatusValues, BoxTypeValues, STORAGE_BOXES_COLLECTION, STORAGE_BOX_FIELDS, } from "../schemas/firestore.js";
|
|
22
|
+
/**
|
|
23
|
+
* `AC60-03` → ordinal 3.
|
|
24
|
+
*
|
|
25
|
+
* Denormalised because a list sorted by `code` as a STRING puts AC60-10
|
|
26
|
+
* before AC60-2, which is the kind of ordering that makes an operator
|
|
27
|
+
* distrust the whole screen. Derived on write, never typed.
|
|
28
|
+
*/
|
|
29
|
+
function ordinalOf(code) {
|
|
30
|
+
const m = code.match(/(\d+)\s*$/);
|
|
31
|
+
return m ? Number.parseInt(m[1], 10) : 0;
|
|
32
|
+
}
|
|
33
|
+
export class StorageBoxesRepository extends BaseRepository {
|
|
34
|
+
constructor() {
|
|
35
|
+
super(STORAGE_BOXES_COLLECTION);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a box at its own code.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 `createWithId`, not `create`, and that is the uniqueness guarantee: the
|
|
41
|
+
* id IS `storagebox-{code}`, so a second `AC60-03` lands on the same
|
|
42
|
+
* document instead of making a second registry row for one physical object.
|
|
43
|
+
*
|
|
44
|
+
* 🛑 And it REFUSES rather than overwriting. An operator labelling a new box
|
|
45
|
+
* who types a code already in use has made a mistake that silently merging
|
|
46
|
+
* two boxes would hide — and the merge would be unrecoverable, because the
|
|
47
|
+
* placements of both would then point at one id.
|
|
48
|
+
*/
|
|
49
|
+
async createBox(input) {
|
|
50
|
+
const code = input.code.trim().toUpperCase();
|
|
51
|
+
if (!code)
|
|
52
|
+
throw new Error("A box needs a code");
|
|
53
|
+
if (!BoxTypeValues.includes(input.boxType)) {
|
|
54
|
+
throw new Error(`Unknown box type: ${input.boxType}`);
|
|
55
|
+
}
|
|
56
|
+
const id = generateStorageBoxId({ code });
|
|
57
|
+
const existing = await this.findById(id);
|
|
58
|
+
if (existing) {
|
|
59
|
+
throw new Error(`Box ${code} already exists. A second ${code} is the same box — ` +
|
|
60
|
+
`edit it instead, or use a new code.`);
|
|
61
|
+
}
|
|
62
|
+
return this.createWithId(id, {
|
|
63
|
+
code,
|
|
64
|
+
boxType: input.boxType,
|
|
65
|
+
ordinal: ordinalOf(code),
|
|
66
|
+
status: input.status ?? "active",
|
|
67
|
+
...(input.location ? { location: input.location } : {}),
|
|
68
|
+
...(input.capacityNote ? { capacityNote: input.capacityNote } : {}),
|
|
69
|
+
searchTxt: buildStorageBoxSearchTxt({
|
|
70
|
+
code,
|
|
71
|
+
boxType: input.boxType,
|
|
72
|
+
location: input.location,
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** Box by its printed code, which is what a scan or a typed search gives. */
|
|
77
|
+
async findByCode(code) {
|
|
78
|
+
return this.findById(generateStorageBoxId({ code: code.trim().toUpperCase() }));
|
|
79
|
+
}
|
|
80
|
+
async setStatus(id, status) {
|
|
81
|
+
if (!BoxStatusValues.includes(status)) {
|
|
82
|
+
throw new Error(`Unknown box status: ${status}`);
|
|
83
|
+
}
|
|
84
|
+
return this.update(id, { status, updatedAt: new Date() });
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Write the advisory rollup.
|
|
88
|
+
*
|
|
89
|
+
* 🛑 Called ONLY by the scheduled repair job, never from a trigger on a
|
|
90
|
+
* collection this also writes. That shape is Root Cause #92 — a
|
|
91
|
+
* documentWritten trigger writing back to its own collection, whose no-op
|
|
92
|
+
* guard compared maps with `JSON.stringify` while Firestore returns map keys
|
|
93
|
+
* alphabetically, so the guard could never match and it recursed to 12M
|
|
94
|
+
* invocations against a 2M/month quota. A scheduled recompute cannot
|
|
95
|
+
* recurse, which is the entire reason for the choice.
|
|
96
|
+
*/
|
|
97
|
+
async setRollup(id, distinctProducts, totalUnits) {
|
|
98
|
+
await this.update(id, {
|
|
99
|
+
rollup: { distinctProducts, totalUnits, computedAt: new Date() },
|
|
100
|
+
updatedAt: new Date(),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async listForAdmin(model) {
|
|
104
|
+
return this.sieveQuery(model, StorageBoxesRepository.SIEVE_FIELDS, { defaultPageSize: 25, maxPageSize: 50 });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
|
|
108
|
+
StorageBoxesRepository.SIEVE_FIELDS = {
|
|
109
|
+
id: { canFilter: true, canSort: false },
|
|
110
|
+
[STORAGE_BOX_FIELDS.CODE]: { canFilter: true, canSort: true },
|
|
111
|
+
[STORAGE_BOX_FIELDS.BOX_TYPE]: { canFilter: true, canSort: false },
|
|
112
|
+
[STORAGE_BOX_FIELDS.ORDINAL]: { canFilter: true, canSort: true },
|
|
113
|
+
[STORAGE_BOX_FIELDS.STATUS]: { canFilter: true, canSort: false },
|
|
114
|
+
[STORAGE_BOX_FIELDS.LOCATION]: { canFilter: true, canSort: false },
|
|
115
|
+
[STORAGE_BOX_FIELDS.SEARCH_TXT]: { canFilter: true, canSort: false },
|
|
116
|
+
[STORAGE_BOX_FIELDS.CREATED_AT]: {
|
|
117
|
+
canFilter: true,
|
|
118
|
+
canSort: true,
|
|
119
|
+
parseValue: parseSieveDateValue,
|
|
120
|
+
},
|
|
121
|
+
[STORAGE_BOX_FIELDS.UPDATED_AT]: {
|
|
122
|
+
canFilter: true,
|
|
123
|
+
canSort: true,
|
|
124
|
+
parseValue: parseSieveDateValue,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
export const storageBoxesRepository = new StorageBoxesRepository();
|