@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { DocumentReference } from "firebase-admin/firestore";
|
|
2
|
+
import { BaseRepository } from "../../../providers/db-firebase";
|
|
3
|
+
import { type ObligationDocument, type ObligationKind, type ObligationState } from "../schemas/firestore";
|
|
4
|
+
export interface OpenObligationInput {
|
|
5
|
+
kind: ObligationKind;
|
|
6
|
+
subjectCollection: string;
|
|
7
|
+
subjectId: string;
|
|
8
|
+
dueAt: Date;
|
|
9
|
+
isTestData?: boolean;
|
|
10
|
+
note?: string;
|
|
11
|
+
now?: Date;
|
|
12
|
+
}
|
|
13
|
+
export interface CloseObligationInput {
|
|
14
|
+
state: Exclude<ObligationState, "open">;
|
|
15
|
+
closeReason: string;
|
|
16
|
+
now?: Date;
|
|
17
|
+
}
|
|
18
|
+
export declare class ObligationsRepository extends BaseRepository<ObligationDocument> {
|
|
19
|
+
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Open an obligation, or leave an existing open one exactly as it is.
|
|
22
|
+
*
|
|
23
|
+
* 🛑 `.create()`, fails-if-exists — which gives the invariant **at most one
|
|
24
|
+
* open obligation per (subject, kind)**. That is what makes it safe to
|
|
25
|
+
* reconcile obligations on EVERY order write, including the great majority
|
|
26
|
+
* that change nothing relevant: a double create is a no-op, not a second
|
|
27
|
+
* timer.
|
|
28
|
+
*
|
|
29
|
+
* 🛑 It deliberately does NOT update the `dueAt` of an existing row. The
|
|
30
|
+
* clock starts once, at the anchoring event, and a later write re-deriving a
|
|
31
|
+
* slightly different deadline must not quietly extend it — that would let a
|
|
32
|
+
* seller refresh their own dispatch deadline by touching the order.
|
|
33
|
+
*/
|
|
34
|
+
open(input: OpenObligationInput): Promise<{
|
|
35
|
+
id: string;
|
|
36
|
+
created: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/** Close one, with a reason. Never throws — see `open`. */
|
|
39
|
+
close(subjectId: string, kind: ObligationKind, input: CloseObligationInput): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* The sweep's ONE query: open obligations past due.
|
|
42
|
+
*
|
|
43
|
+
* 🛑 One equality (`state`) and one inequality (`dueAt`), ordered by `dueAt`
|
|
44
|
+
* — the only shape Firestore serves without demanding the inequality field
|
|
45
|
+
* lead the sort (Root Cause #59). **ONE composite index for every kind**,
|
|
46
|
+
* which is the whole reason `kind` is a field rather than named deadline
|
|
47
|
+
* columns on the order: fifteen named deadline fields would mean fifteen
|
|
48
|
+
* queries per tick and fifteen new composite indexes on a collection that
|
|
49
|
+
* already carries 55. The two orphan `prizeRevealDeadline` indexes — on a
|
|
50
|
+
* field that exists in no TypeScript file — are a preview of that failure.
|
|
51
|
+
*/
|
|
52
|
+
listDue(now: Date, limit?: number): Promise<ObligationDocument[]>;
|
|
53
|
+
/** Open obligations approaching their deadline, for the warning pass. */
|
|
54
|
+
listUpcoming(horizon: Date, now: Date, limit?: number): Promise<ObligationDocument[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Every open obligation for one subject — the quiet-period check.
|
|
57
|
+
*
|
|
58
|
+
* 🛑 This is the QUIET PERIOD invariant's query, and the payout path must
|
|
59
|
+
* call it at BOTH batch-creation and settlement time. A refund posted between
|
|
60
|
+
* the two would otherwise silently shrink a payout an admin had already sent.
|
|
61
|
+
*/
|
|
62
|
+
listOpenForSubject(subjectId: string): Promise<ObligationDocument[]>;
|
|
63
|
+
/** Record that a warning was sent, so a re-run does not re-warn. */
|
|
64
|
+
recordWarning(id: string, at: Date): Promise<void>;
|
|
65
|
+
/** Refs for a subject's obligations — used when an order is hard-deleted. */
|
|
66
|
+
refsForSubject(subjectId: string): Promise<DocumentReference[]>;
|
|
67
|
+
}
|
|
68
|
+
export declare function obligationsRepository(): ObligationsRepository;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { BaseRepository, prepareForFirestore } from "../../../providers/db-firebase/index.js";
|
|
2
|
+
import { normalizeError } from "../../../errors/normalize.js";
|
|
3
|
+
import { OBLIGATIONS_COLLECTION, OBLIGATION_ACTIVE_STATES, OBLIGATION_FIELDS, createObligationId, } from "../schemas/firestore.js";
|
|
4
|
+
export class ObligationsRepository extends BaseRepository {
|
|
5
|
+
/*
|
|
6
|
+
* 🛑 NO `SIEVE_FIELDS`, deliberately.
|
|
7
|
+
*
|
|
8
|
+
* `audit-sieve-field-coverage` targets every `*.repository.ts` defining one,
|
|
9
|
+
* and this collection has no filterable admin list to justify it: the sweep
|
|
10
|
+
* uses exactly one query shape, and an operator looking at a deadline looks
|
|
11
|
+
* at the ORDER, not at the index row. Declaring a Sieve surface nothing calls
|
|
12
|
+
* is the speculative-infra pattern — the `route-schema-registry` lesson, 576
|
|
13
|
+
* keys into a layer with no readers.
|
|
14
|
+
*/
|
|
15
|
+
constructor() {
|
|
16
|
+
super(OBLIGATIONS_COLLECTION);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Open an obligation, or leave an existing open one exactly as it is.
|
|
20
|
+
*
|
|
21
|
+
* 🛑 `.create()`, fails-if-exists — which gives the invariant **at most one
|
|
22
|
+
* open obligation per (subject, kind)**. That is what makes it safe to
|
|
23
|
+
* reconcile obligations on EVERY order write, including the great majority
|
|
24
|
+
* that change nothing relevant: a double create is a no-op, not a second
|
|
25
|
+
* timer.
|
|
26
|
+
*
|
|
27
|
+
* 🛑 It deliberately does NOT update the `dueAt` of an existing row. The
|
|
28
|
+
* clock starts once, at the anchoring event, and a later write re-deriving a
|
|
29
|
+
* slightly different deadline must not quietly extend it — that would let a
|
|
30
|
+
* seller refresh their own dispatch deadline by touching the order.
|
|
31
|
+
*/
|
|
32
|
+
async open(input) {
|
|
33
|
+
const now = input.now ?? new Date();
|
|
34
|
+
const id = createObligationId(input.subjectId, input.kind);
|
|
35
|
+
const doc = {
|
|
36
|
+
id,
|
|
37
|
+
kind: input.kind,
|
|
38
|
+
subjectCollection: input.subjectCollection,
|
|
39
|
+
subjectId: input.subjectId,
|
|
40
|
+
dueAt: input.dueAt,
|
|
41
|
+
state: "open",
|
|
42
|
+
...(input.isTestData ? { isTestData: true } : {}),
|
|
43
|
+
...(input.note ? { note: input.note } : {}),
|
|
44
|
+
createdAt: now,
|
|
45
|
+
updatedAt: now,
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
await this.getCollection().doc(id).create(prepareForFirestore(doc));
|
|
49
|
+
return { id, created: true };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
/*
|
|
53
|
+
* Any failure is treated as "already there". Unlike the gateway-event
|
|
54
|
+
* inbox — which must fail OPEN because a lost event is unrecoverable —
|
|
55
|
+
* an obligation is a derived hint: the next order write reconciles again,
|
|
56
|
+
* and the subject itself still carries the facts. Rethrowing here would
|
|
57
|
+
* let a transient Firestore blip fail the ORDER WRITE that triggered the
|
|
58
|
+
* reconcile, which is the one thing that must not happen.
|
|
59
|
+
*/
|
|
60
|
+
void normalizeError(err);
|
|
61
|
+
return { id, created: false };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Close one, with a reason. Never throws — see `open`. */
|
|
65
|
+
async close(subjectId, kind, input) {
|
|
66
|
+
const now = input.now ?? new Date();
|
|
67
|
+
try {
|
|
68
|
+
await this.getCollection()
|
|
69
|
+
.doc(createObligationId(subjectId, kind))
|
|
70
|
+
.update({
|
|
71
|
+
state: input.state,
|
|
72
|
+
closeReason: input.closeReason,
|
|
73
|
+
closedAt: now,
|
|
74
|
+
updatedAt: now,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// Closing one that does not exist is the normal case, not a fault.
|
|
79
|
+
void normalizeError(err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The sweep's ONE query: open obligations past due.
|
|
84
|
+
*
|
|
85
|
+
* 🛑 One equality (`state`) and one inequality (`dueAt`), ordered by `dueAt`
|
|
86
|
+
* — the only shape Firestore serves without demanding the inequality field
|
|
87
|
+
* lead the sort (Root Cause #59). **ONE composite index for every kind**,
|
|
88
|
+
* which is the whole reason `kind` is a field rather than named deadline
|
|
89
|
+
* columns on the order: fifteen named deadline fields would mean fifteen
|
|
90
|
+
* queries per tick and fifteen new composite indexes on a collection that
|
|
91
|
+
* already carries 55. The two orphan `prizeRevealDeadline` indexes — on a
|
|
92
|
+
* field that exists in no TypeScript file — are a preview of that failure.
|
|
93
|
+
*/
|
|
94
|
+
async listDue(now, limit = 100) {
|
|
95
|
+
const snap = await this.getCollection()
|
|
96
|
+
.where(OBLIGATION_FIELDS.STATE, "in", [...OBLIGATION_ACTIVE_STATES])
|
|
97
|
+
.where(OBLIGATION_FIELDS.DUE_AT, "<=", now)
|
|
98
|
+
.orderBy(OBLIGATION_FIELDS.DUE_AT, "asc")
|
|
99
|
+
.limit(limit)
|
|
100
|
+
.get();
|
|
101
|
+
return snap.docs.map((d) => this.mapDoc(d));
|
|
102
|
+
}
|
|
103
|
+
/** Open obligations approaching their deadline, for the warning pass. */
|
|
104
|
+
async listUpcoming(horizon, now, limit = 100) {
|
|
105
|
+
const snap = await this.getCollection()
|
|
106
|
+
.where(OBLIGATION_FIELDS.STATE, "in", [...OBLIGATION_ACTIVE_STATES])
|
|
107
|
+
.where(OBLIGATION_FIELDS.DUE_AT, "<=", horizon)
|
|
108
|
+
.orderBy(OBLIGATION_FIELDS.DUE_AT, "asc")
|
|
109
|
+
.limit(limit)
|
|
110
|
+
.get();
|
|
111
|
+
return snap.docs
|
|
112
|
+
.map((d) => this.mapDoc(d))
|
|
113
|
+
.filter((o) => o.dueAt.getTime() > now.getTime());
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Every open obligation for one subject — the quiet-period check.
|
|
117
|
+
*
|
|
118
|
+
* 🛑 This is the QUIET PERIOD invariant's query, and the payout path must
|
|
119
|
+
* call it at BOTH batch-creation and settlement time. A refund posted between
|
|
120
|
+
* the two would otherwise silently shrink a payout an admin had already sent.
|
|
121
|
+
*/
|
|
122
|
+
async listOpenForSubject(subjectId) {
|
|
123
|
+
const snap = await this.getCollection()
|
|
124
|
+
.where(OBLIGATION_FIELDS.SUBJECT_ID, "==", subjectId)
|
|
125
|
+
.where(OBLIGATION_FIELDS.STATE, "in", [...OBLIGATION_ACTIVE_STATES])
|
|
126
|
+
.get();
|
|
127
|
+
return snap.docs.map((d) => this.mapDoc(d));
|
|
128
|
+
}
|
|
129
|
+
/** Record that a warning was sent, so a re-run does not re-warn. */
|
|
130
|
+
async recordWarning(id, at) {
|
|
131
|
+
try {
|
|
132
|
+
const existing = await this.findById(id);
|
|
133
|
+
await this.getCollection()
|
|
134
|
+
.doc(id)
|
|
135
|
+
.update({
|
|
136
|
+
warnedAt: [...(existing?.warnedAt ?? []), at],
|
|
137
|
+
updatedAt: at,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
void normalizeError(err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Refs for a subject's obligations — used when an order is hard-deleted. */
|
|
145
|
+
async refsForSubject(subjectId) {
|
|
146
|
+
const snap = await this.getCollection()
|
|
147
|
+
.where(OBLIGATION_FIELDS.SUBJECT_ID, "==", subjectId)
|
|
148
|
+
.limit(50)
|
|
149
|
+
.get();
|
|
150
|
+
return snap.docs.map((d) => d.ref);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
let cached = null;
|
|
154
|
+
export function obligationsRepository() {
|
|
155
|
+
if (!cached)
|
|
156
|
+
cached = new ObligationsRepository();
|
|
157
|
+
return cached;
|
|
158
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `obligations` — deadlines with money consequences.
|
|
3
|
+
*
|
|
4
|
+
* ## Why a mechanism rather than more cron jobs
|
|
5
|
+
*
|
|
6
|
+
* The order lifecycle has roughly seventy timer-driven scenarios ("seller never
|
|
7
|
+
* accepts → auto-cancel + full refund at 3 days", "buyer cancels before
|
|
8
|
+
* shipping", "return approved but never posted"…). The approach before this was
|
|
9
|
+
* eight hand-written sweeps whose coverage could only be established by
|
|
10
|
+
* checking that every pair of `.filter()` predicates agreed — and
|
|
11
|
+
* Root Cause #27 is that reasoning having already failed at n=3: an order in
|
|
12
|
+
* `reupload_requested` was excluded by `getExpiredPaymentDeadlines` (it HAS a
|
|
13
|
+
* proof), by `getUnreviewedProofPastDeadline` (it HAS an outcome) and by
|
|
14
|
+
* `runPendingOrderTimeout` (it HAS a deadline). Three sweeps, pairwise
|
|
15
|
+
* disjoint, and the order held stock forever with no terminal state.
|
|
16
|
+
*
|
|
17
|
+
* This collection makes "which sweep owns this order" answerable by
|
|
18
|
+
* construction instead of by three filters happening to agree.
|
|
19
|
+
*
|
|
20
|
+
* ## 🛑 IT IS A DUE-DATE INDEX, NOT TRUTH
|
|
21
|
+
*
|
|
22
|
+
* The order is authoritative. An obligation row exists so the sweep can FIND
|
|
23
|
+
* candidates cheaply with one indexed query; having found one it **re-reads the
|
|
24
|
+
* subject and re-evaluates the policy's `precondition`**, and a row whose
|
|
25
|
+
* premise no longer holds closes as `superseded` rather than acting.
|
|
26
|
+
*
|
|
27
|
+
* That is what keeps this out of the stored-mirror drift class (Root Cause
|
|
28
|
+
* #42). A row saying "cancel this order at 15:00" is a HINT; the order saying
|
|
29
|
+
* "I was paid at 14:58" is the fact, and the fact wins.
|
|
30
|
+
*
|
|
31
|
+
* ## 🛑 NOT A FIRESTORE TRIGGER
|
|
32
|
+
*
|
|
33
|
+
* An `onOrderWrite` trigger that wrote `obligations`, whose sweep then wrote
|
|
34
|
+
* `orders`, is Root Cause #92's self-write loop exactly — the one that cost
|
|
35
|
+
* 1,017,548 invocations in 24 hours against a 2M/month free quota, plus a
|
|
36
|
+
* sibling function woken a million times just to return. Obligations are
|
|
37
|
+
* reconciled **inside the order's own write**, in `updateWithHistory`, where
|
|
38
|
+
* the current document is already in hand.
|
|
39
|
+
*/
|
|
40
|
+
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
41
|
+
export declare const OBLIGATIONS_COLLECTION = "obligations";
|
|
42
|
+
/**
|
|
43
|
+
* Every kind of deadline the system owes somebody.
|
|
44
|
+
*
|
|
45
|
+
* 🛑 A `Record<ObligationKind, ObligationPolicy>` in `constants/policies.ts`
|
|
46
|
+
* consumes this union, so **adding a kind without declaring its anchor,
|
|
47
|
+
* duration and guardrail tier is a compile error.** That is the property that
|
|
48
|
+
* makes the Nth scenario cheap instead of another bespoke cron job.
|
|
49
|
+
*/
|
|
50
|
+
export type ObligationKind = "seller-accept" | "seller-dispatch" | "proof-reupload" | "delivery-confirm" | "return-respond" | "return-post" | "return-receive" | "return-inspect" | "claim-shipping" | "claim-sale"
|
|
51
|
+
/**
|
|
52
|
+
* The order is COMPLETE: 7 days have passed since delivery with no issue
|
|
53
|
+
* raised, so points are awarded and no new dispute may be opened.
|
|
54
|
+
*
|
|
55
|
+
* 🛑 Owner's requirement, 2026-10-21, verbatim: *"points only get issued on
|
|
56
|
+
* successful purchases after buyer put reviews, then only, if no review no
|
|
57
|
+
* points, that marks the complete order, they are also assigned if the user
|
|
58
|
+
* no issues or updates after 7 days of delivery — no further disputes should
|
|
59
|
+
* be entertained as well."*
|
|
60
|
+
*
|
|
61
|
+
* So completion has TWO triggers and this is the second: the first is the
|
|
62
|
+
* buyer posting a review (event-driven, no timer needed), and this is the
|
|
63
|
+
* silence fallback. Whichever fires first completes the order; the award must
|
|
64
|
+
* therefore be IDEMPOTENT, which is why it is keyed on the order in the
|
|
65
|
+
* points ledger rather than appended blindly.
|
|
66
|
+
*
|
|
67
|
+
* It is also the dispute cutoff, which is the part with teeth: after this
|
|
68
|
+
* fires, a new dispute is refused. Existing ones are unaffected — see the
|
|
69
|
+
* policy's own note on why "no further disputes" cannot mean "everything
|
|
70
|
+
* closes at 7 days".
|
|
71
|
+
*/
|
|
72
|
+
| "order-complete" | "payout-release";
|
|
73
|
+
/**
|
|
74
|
+
* Lifecycle of one obligation.
|
|
75
|
+
*
|
|
76
|
+
* | state | meaning |
|
|
77
|
+
* |---|---|
|
|
78
|
+
* | `open` | the clock is running |
|
|
79
|
+
* | `met` | the thing happened in time — closed by the order's own write |
|
|
80
|
+
* | `acted` | the deadline passed and the sweep did what the policy says |
|
|
81
|
+
* | `escalated` | the deadline passed and a human was asked instead |
|
|
82
|
+
* | `superseded` | the premise no longer holds; nothing was owed after all |
|
|
83
|
+
*
|
|
84
|
+
* 🛑 `superseded` is not a failure and must not be reported as one. It is the
|
|
85
|
+
* normal outcome of the index disagreeing with the subject, which is exactly
|
|
86
|
+
* the case the re-read exists to catch.
|
|
87
|
+
*/
|
|
88
|
+
export type ObligationState = "open" | "met" | "acted" | "escalated" | "superseded";
|
|
89
|
+
/**
|
|
90
|
+
* What the sweep is allowed to do when a deadline passes.
|
|
91
|
+
*
|
|
92
|
+
* 🛑 THIS LIVES IN THE TYPE, not in the sweep's code, and that is deliberate:
|
|
93
|
+
* the guardrail tier is a property of the SCENARIO, so it belongs beside the
|
|
94
|
+
* duration rather than in a conditional somebody can quietly widen.
|
|
95
|
+
*
|
|
96
|
+
* - `act` — the ceiling is an amount we captured, the recipient is the payer,
|
|
97
|
+
* and no counterparty is debited. A pre-dispatch cancellation with a full
|
|
98
|
+
* refund qualifies; so does writing an anchor, closing a window, or
|
|
99
|
+
* BLOCKING a payout (withholding is always safe).
|
|
100
|
+
* - `escalate` — goods have left the seller, or somebody other than the payer
|
|
101
|
+
* is debited, or a prior refund exists. Open a case; a human decides.
|
|
102
|
+
*/
|
|
103
|
+
export type ObligationDueAction = "act" | "escalate";
|
|
104
|
+
export interface ObligationDocument extends BaseDocument {
|
|
105
|
+
kind: ObligationKind;
|
|
106
|
+
/** Collection the subject lives in — `orders` for all of today's kinds. */
|
|
107
|
+
subjectCollection: string;
|
|
108
|
+
subjectId: string;
|
|
109
|
+
/**
|
|
110
|
+
* When it comes due. The ONE field the sweep queries on.
|
|
111
|
+
*
|
|
112
|
+
* 🛑 Required, not optional. The sweep filters `dueAt <= now`, and a
|
|
113
|
+
* Firestore inequality **excludes every document that lacks the field**
|
|
114
|
+
* (Root Cause #100) — so an optional `dueAt` would make the sweep
|
|
115
|
+
* structurally unable to see exactly the rows that failed to compute one.
|
|
116
|
+
*/
|
|
117
|
+
dueAt: Date;
|
|
118
|
+
state: ObligationState;
|
|
119
|
+
/** Why it closed. Free text for a human; never parsed. */
|
|
120
|
+
closeReason?: string;
|
|
121
|
+
closedAt?: Date;
|
|
122
|
+
/** Warnings already sent, so a re-run does not re-warn. */
|
|
123
|
+
warnedAt?: Date[];
|
|
124
|
+
/**
|
|
125
|
+
* Mirrors the subject's own flag so the sweep can compress deadlines for a
|
|
126
|
+
* test fixture **without reading the subject first**.
|
|
127
|
+
*
|
|
128
|
+
* 🛑 Per-subject, never global. A global compression would shorten every
|
|
129
|
+
* live buyer's deadline the moment someone ran the tester.
|
|
130
|
+
*/
|
|
131
|
+
isTestData?: boolean;
|
|
132
|
+
/** For the admin detail view, and for a case opened from here. */
|
|
133
|
+
note?: string;
|
|
134
|
+
}
|
|
135
|
+
export declare const OBLIGATION_FIELDS: {
|
|
136
|
+
readonly ID: "id";
|
|
137
|
+
readonly KIND: "kind";
|
|
138
|
+
readonly SUBJECT_COLLECTION: "subjectCollection";
|
|
139
|
+
readonly SUBJECT_ID: "subjectId";
|
|
140
|
+
readonly DUE_AT: "dueAt";
|
|
141
|
+
readonly STATE: "state";
|
|
142
|
+
readonly CLOSE_REASON: "closeReason";
|
|
143
|
+
readonly CLOSED_AT: "closedAt";
|
|
144
|
+
readonly IS_TEST_DATA: "isTestData";
|
|
145
|
+
};
|
|
146
|
+
/** States from which the sweep still has work to do. */
|
|
147
|
+
export declare const OBLIGATION_ACTIVE_STATES: readonly ObligationState[];
|
|
148
|
+
/**
|
|
149
|
+
* 🛑 THE IDEMPOTENCY KEY, and the invariant it buys.
|
|
150
|
+
*
|
|
151
|
+
* Deterministic `${subjectId}__${kind}` means **at most one open obligation per
|
|
152
|
+
* (subject, kind)**. A double create is a no-op write rather than a second
|
|
153
|
+
* timer, which is what makes it safe to reconcile obligations on EVERY order
|
|
154
|
+
* write — including the many writes that change nothing relevant.
|
|
155
|
+
*
|
|
156
|
+
* Double underscore, matching `createClaimedCouponId`'s convention, so a
|
|
157
|
+
* subject id containing a single underscore cannot collide with a kind.
|
|
158
|
+
*/
|
|
159
|
+
export declare function createObligationId(subjectId: string, kind: ObligationKind): string;
|
|
160
|
+
export declare const ALL_OBLIGATION_KINDS: ObligationKind[];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `obligations` — deadlines with money consequences.
|
|
3
|
+
*
|
|
4
|
+
* ## Why a mechanism rather than more cron jobs
|
|
5
|
+
*
|
|
6
|
+
* The order lifecycle has roughly seventy timer-driven scenarios ("seller never
|
|
7
|
+
* accepts → auto-cancel + full refund at 3 days", "buyer cancels before
|
|
8
|
+
* shipping", "return approved but never posted"…). The approach before this was
|
|
9
|
+
* eight hand-written sweeps whose coverage could only be established by
|
|
10
|
+
* checking that every pair of `.filter()` predicates agreed — and
|
|
11
|
+
* Root Cause #27 is that reasoning having already failed at n=3: an order in
|
|
12
|
+
* `reupload_requested` was excluded by `getExpiredPaymentDeadlines` (it HAS a
|
|
13
|
+
* proof), by `getUnreviewedProofPastDeadline` (it HAS an outcome) and by
|
|
14
|
+
* `runPendingOrderTimeout` (it HAS a deadline). Three sweeps, pairwise
|
|
15
|
+
* disjoint, and the order held stock forever with no terminal state.
|
|
16
|
+
*
|
|
17
|
+
* This collection makes "which sweep owns this order" answerable by
|
|
18
|
+
* construction instead of by three filters happening to agree.
|
|
19
|
+
*
|
|
20
|
+
* ## 🛑 IT IS A DUE-DATE INDEX, NOT TRUTH
|
|
21
|
+
*
|
|
22
|
+
* The order is authoritative. An obligation row exists so the sweep can FIND
|
|
23
|
+
* candidates cheaply with one indexed query; having found one it **re-reads the
|
|
24
|
+
* subject and re-evaluates the policy's `precondition`**, and a row whose
|
|
25
|
+
* premise no longer holds closes as `superseded` rather than acting.
|
|
26
|
+
*
|
|
27
|
+
* That is what keeps this out of the stored-mirror drift class (Root Cause
|
|
28
|
+
* #42). A row saying "cancel this order at 15:00" is a HINT; the order saying
|
|
29
|
+
* "I was paid at 14:58" is the fact, and the fact wins.
|
|
30
|
+
*
|
|
31
|
+
* ## 🛑 NOT A FIRESTORE TRIGGER
|
|
32
|
+
*
|
|
33
|
+
* An `onOrderWrite` trigger that wrote `obligations`, whose sweep then wrote
|
|
34
|
+
* `orders`, is Root Cause #92's self-write loop exactly — the one that cost
|
|
35
|
+
* 1,017,548 invocations in 24 hours against a 2M/month free quota, plus a
|
|
36
|
+
* sibling function woken a million times just to return. Obligations are
|
|
37
|
+
* reconciled **inside the order's own write**, in `updateWithHistory`, where
|
|
38
|
+
* the current document is already in hand.
|
|
39
|
+
*/
|
|
40
|
+
export const OBLIGATIONS_COLLECTION = "obligations";
|
|
41
|
+
export const OBLIGATION_FIELDS = {
|
|
42
|
+
ID: "id",
|
|
43
|
+
KIND: "kind",
|
|
44
|
+
SUBJECT_COLLECTION: "subjectCollection",
|
|
45
|
+
SUBJECT_ID: "subjectId",
|
|
46
|
+
DUE_AT: "dueAt",
|
|
47
|
+
STATE: "state",
|
|
48
|
+
CLOSE_REASON: "closeReason",
|
|
49
|
+
CLOSED_AT: "closedAt",
|
|
50
|
+
IS_TEST_DATA: "isTestData",
|
|
51
|
+
};
|
|
52
|
+
/** States from which the sweep still has work to do. */
|
|
53
|
+
export const OBLIGATION_ACTIVE_STATES = ["open"];
|
|
54
|
+
/**
|
|
55
|
+
* 🛑 THE IDEMPOTENCY KEY, and the invariant it buys.
|
|
56
|
+
*
|
|
57
|
+
* Deterministic `${subjectId}__${kind}` means **at most one open obligation per
|
|
58
|
+
* (subject, kind)**. A double create is a no-op write rather than a second
|
|
59
|
+
* timer, which is what makes it safe to reconcile obligations on EVERY order
|
|
60
|
+
* write — including the many writes that change nothing relevant.
|
|
61
|
+
*
|
|
62
|
+
* Double underscore, matching `createClaimedCouponId`'s convention, so a
|
|
63
|
+
* subject id containing a single underscore cannot collide with a kind.
|
|
64
|
+
*/
|
|
65
|
+
export function createObligationId(subjectId, kind) {
|
|
66
|
+
return `${subjectId}__${kind}`.replace(/[^A-Za-z0-9_.:-]/g, "_").slice(0, 1500);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Runtime companion, keyed `Record<Union, true>` so both mistakes are compile
|
|
70
|
+
* errors: a kind added to the union and forgotten here, and a key here that is
|
|
71
|
+
* not a real kind. An array literal catches neither (Root Cause #61).
|
|
72
|
+
*/
|
|
73
|
+
const OBLIGATION_KIND_MAP = {
|
|
74
|
+
"seller-accept": true,
|
|
75
|
+
"seller-dispatch": true,
|
|
76
|
+
"proof-reupload": true,
|
|
77
|
+
"delivery-confirm": true,
|
|
78
|
+
"return-respond": true,
|
|
79
|
+
"return-post": true,
|
|
80
|
+
"return-receive": true,
|
|
81
|
+
"return-inspect": true,
|
|
82
|
+
"claim-shipping": true,
|
|
83
|
+
"claim-sale": true,
|
|
84
|
+
"order-complete": true,
|
|
85
|
+
"payout-release": true,
|
|
86
|
+
};
|
|
87
|
+
export const ALL_OBLIGATION_KINDS = Object.keys(OBLIGATION_KIND_MAP);
|
|
@@ -4,9 +4,25 @@
|
|
|
4
4
|
* Pure business functions — auth, rate-limiting, and Next.js specifics
|
|
5
5
|
* are handled by the calling server action in the consumer.
|
|
6
6
|
*/
|
|
7
|
-
import type { OrderDocument } from "../schemas";
|
|
7
|
+
import type { OrderDocument, OrderPlain } from "../schemas";
|
|
8
|
+
import type { CancellationRefundOutcome } from "../types/index";
|
|
8
9
|
import type { TrackingInfo } from "../../../contracts/shipping";
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Cancel a whole order on the buyer's own request.
|
|
12
|
+
*
|
|
13
|
+
* 🛑 **Returns the refund outcome now, and used to return `void` (D14).** This
|
|
14
|
+
* called `orderRepository.cancelOrder(orderId, reason)` — omitting the optional
|
|
15
|
+
* third argument, as all four callers did — so a *paid* order was cancelled,
|
|
16
|
+
* its stock restored, and **the money kept**, while
|
|
17
|
+
* `previewCancellationRefund` had already shown the buyer a figure nothing
|
|
18
|
+
* honoured.
|
|
19
|
+
*
|
|
20
|
+
* Both halves live in `cancelOrderWithRefund`, deliberately not here: passing
|
|
21
|
+
* the amount alone would only record an intent `cancelOrder` has no code to
|
|
22
|
+
* settle, which reads in the database as a refund on its way and is worse than
|
|
23
|
+
* the honest silence it replaces. See that module's header for the full table.
|
|
24
|
+
*/
|
|
25
|
+
export declare function cancelOrderForUser(userId: string, orderId: string, reason: string): Promise<CancellationRefundOutcome>;
|
|
10
26
|
/**
|
|
11
27
|
* Cancels a subset of line items on an already-placed order and lets the rest
|
|
12
28
|
* proceed. Matches today's whole-order cancellation behavior: marks the items
|
|
@@ -15,10 +31,33 @@ export declare function cancelOrderForUser(userId: string, orderId: string, reas
|
|
|
15
31
|
* the order ends up cancelled, falls through to the same whole-order
|
|
16
32
|
* `cancelOrder` path `cancelOrderForUser` uses, rather than leaving a
|
|
17
33
|
* zero-item live order.
|
|
34
|
+
*
|
|
35
|
+
* 🛑 Returns `null` on the genuinely-partial path, and an outcome only when it
|
|
36
|
+
* fell through to cancelling the whole order. That is not a convenience: a
|
|
37
|
+
* partial cancellation's add-on and per-item refund arithmetic is **D15/D16**
|
|
38
|
+
* and is not built — it still sets `refundPending: true` and leaves the money
|
|
39
|
+
* to the admin refund flow, exactly as before. Returning a zero-amount outcome
|
|
40
|
+
* here would claim a decision had been made about money when none has.
|
|
18
41
|
*/
|
|
19
|
-
export declare function cancelOrderItemsForUser(userId: string, orderId: string, itemIds: string[], reason: string): Promise<
|
|
42
|
+
export declare function cancelOrderItemsForUser(userId: string, orderId: string, itemIds: string[], reason: string): Promise<CancellationRefundOutcome | null>;
|
|
20
43
|
export declare function listOrdersForUser(userId: string): Promise<OrderDocument[]>;
|
|
21
|
-
|
|
44
|
+
/**
|
|
45
|
+
* One order, for the buyer who placed it.
|
|
46
|
+
*
|
|
47
|
+
* 🛑 RETURNS PLAINTEXT, and the return TYPE says so. See
|
|
48
|
+
* `getAddressByIdForUser` for the full reasoning — same defect, same shape.
|
|
49
|
+
*
|
|
50
|
+
* `OrderRepository.mapDoc` does not decrypt, so this returned `enc:v1:` blobs
|
|
51
|
+
* for `userName`, `userEmail` and the `shippingAddress` name and phone, to
|
|
52
|
+
* the buyer, about their own order. Its caller is a server action that hands
|
|
53
|
+
* the result straight to the client.
|
|
54
|
+
*
|
|
55
|
+
* Revealing here rather than at the caller, because this function is what
|
|
56
|
+
* knows the read is owner-scoped: it throws `NotFoundError` — not Forbidden,
|
|
57
|
+
* deliberately, so the response cannot confirm an order exists — for any
|
|
58
|
+
* order whose `userId` is not the caller's.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getOrderByIdForUser(userId: string, orderId: string): Promise<OrderPlain>;
|
|
22
61
|
/**
|
|
23
62
|
* Retrieve live tracking info for an order via the registered IShippingProvider.
|
|
24
63
|
* Returns null when no shipping provider is registered or no trackingNumber exists.
|
|
@@ -9,12 +9,28 @@ import { serverLogger } from "../../../monitoring/index.js";
|
|
|
9
9
|
import { getProviders } from "../../../contracts/index.js";
|
|
10
10
|
import { orderRepository } from "../repository/orders.repository.js";
|
|
11
11
|
import { ORDER_CANCELLABLE_STATUSES } from "../../../_internal/shared/features/orders/config.js";
|
|
12
|
+
import { cancelOrderWithRefund } from "../../../_internal/server/features/orders/cancellation-refund.js";
|
|
12
13
|
const ERR_ORDER_NOT_FOUND = "Order not found";
|
|
13
14
|
function assertCancellable(order) {
|
|
14
15
|
if (!ORDER_CANCELLABLE_STATUSES.includes(order.status)) {
|
|
15
16
|
throw new ValidationError("Only pending or confirmed orders can be cancelled");
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Cancel a whole order on the buyer's own request.
|
|
21
|
+
*
|
|
22
|
+
* 🛑 **Returns the refund outcome now, and used to return `void` (D14).** This
|
|
23
|
+
* called `orderRepository.cancelOrder(orderId, reason)` — omitting the optional
|
|
24
|
+
* third argument, as all four callers did — so a *paid* order was cancelled,
|
|
25
|
+
* its stock restored, and **the money kept**, while
|
|
26
|
+
* `previewCancellationRefund` had already shown the buyer a figure nothing
|
|
27
|
+
* honoured.
|
|
28
|
+
*
|
|
29
|
+
* Both halves live in `cancelOrderWithRefund`, deliberately not here: passing
|
|
30
|
+
* the amount alone would only record an intent `cancelOrder` has no code to
|
|
31
|
+
* settle, which reads in the database as a refund on its way and is worse than
|
|
32
|
+
* the honest silence it replaces. See that module's header for the full table.
|
|
33
|
+
*/
|
|
18
34
|
export async function cancelOrderForUser(userId, orderId, reason) {
|
|
19
35
|
const order = await orderRepository.findById(orderId);
|
|
20
36
|
if (!order)
|
|
@@ -22,8 +38,20 @@ export async function cancelOrderForUser(userId, orderId, reason) {
|
|
|
22
38
|
if (order.userId !== userId)
|
|
23
39
|
throw new AuthorizationError("You are not authorised to cancel this order");
|
|
24
40
|
assertCancellable(order);
|
|
25
|
-
await
|
|
26
|
-
|
|
41
|
+
const { refund } = await cancelOrderWithRefund(order, {
|
|
42
|
+
reason,
|
|
43
|
+
actorUid: userId,
|
|
44
|
+
actorRole: "buyer",
|
|
45
|
+
trigger: "cancelOrderForUser",
|
|
46
|
+
});
|
|
47
|
+
serverLogger.info("Order cancelled by user", {
|
|
48
|
+
userId,
|
|
49
|
+
orderId,
|
|
50
|
+
reason,
|
|
51
|
+
refundMoved: refund.moved,
|
|
52
|
+
refundAmount: refund.amount,
|
|
53
|
+
});
|
|
54
|
+
return refund;
|
|
27
55
|
}
|
|
28
56
|
/**
|
|
29
57
|
* Cancels a subset of line items on an already-placed order and lets the rest
|
|
@@ -33,6 +61,13 @@ export async function cancelOrderForUser(userId, orderId, reason) {
|
|
|
33
61
|
* the order ends up cancelled, falls through to the same whole-order
|
|
34
62
|
* `cancelOrder` path `cancelOrderForUser` uses, rather than leaving a
|
|
35
63
|
* zero-item live order.
|
|
64
|
+
*
|
|
65
|
+
* 🛑 Returns `null` on the genuinely-partial path, and an outcome only when it
|
|
66
|
+
* fell through to cancelling the whole order. That is not a convenience: a
|
|
67
|
+
* partial cancellation's add-on and per-item refund arithmetic is **D15/D16**
|
|
68
|
+
* and is not built — it still sets `refundPending: true` and leaves the money
|
|
69
|
+
* to the admin refund flow, exactly as before. Returning a zero-amount outcome
|
|
70
|
+
* here would claim a decision had been made about money when none has.
|
|
36
71
|
*/
|
|
37
72
|
export async function cancelOrderItemsForUser(userId, orderId, itemIds, reason) {
|
|
38
73
|
if (itemIds.length === 0) {
|
|
@@ -74,17 +109,39 @@ export async function cancelOrderItemsForUser(userId, orderId, itemIds, reason)
|
|
|
74
109
|
itemIds: [...matchedIds],
|
|
75
110
|
reason,
|
|
76
111
|
});
|
|
112
|
+
/*
|
|
113
|
+
* Explicit, because the declared return type is a union and an implicit
|
|
114
|
+
* `undefined` is not a member of it. It also says the thing worth saying:
|
|
115
|
+
* no refund decision was taken here.
|
|
116
|
+
*/
|
|
117
|
+
return null;
|
|
77
118
|
}
|
|
78
119
|
export async function listOrdersForUser(userId) {
|
|
79
120
|
return orderRepository.findByUser(userId);
|
|
80
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* One order, for the buyer who placed it.
|
|
124
|
+
*
|
|
125
|
+
* 🛑 RETURNS PLAINTEXT, and the return TYPE says so. See
|
|
126
|
+
* `getAddressByIdForUser` for the full reasoning — same defect, same shape.
|
|
127
|
+
*
|
|
128
|
+
* `OrderRepository.mapDoc` does not decrypt, so this returned `enc:v1:` blobs
|
|
129
|
+
* for `userName`, `userEmail` and the `shippingAddress` name and phone, to
|
|
130
|
+
* the buyer, about their own order. Its caller is a server action that hands
|
|
131
|
+
* the result straight to the client.
|
|
132
|
+
*
|
|
133
|
+
* Revealing here rather than at the caller, because this function is what
|
|
134
|
+
* knows the read is owner-scoped: it throws `NotFoundError` — not Forbidden,
|
|
135
|
+
* deliberately, so the response cannot confirm an order exists — for any
|
|
136
|
+
* order whose `userId` is not the caller's.
|
|
137
|
+
*/
|
|
81
138
|
export async function getOrderByIdForUser(userId, orderId) {
|
|
82
139
|
const order = await orderRepository.findById(orderId);
|
|
83
140
|
if (!order)
|
|
84
141
|
throw new NotFoundError(ERR_ORDER_NOT_FOUND);
|
|
85
142
|
if (order.userId !== userId)
|
|
86
143
|
throw new NotFoundError(ERR_ORDER_NOT_FOUND);
|
|
87
|
-
return order;
|
|
144
|
+
return orderRepository.revealOrder(order);
|
|
88
145
|
}
|
|
89
146
|
/**
|
|
90
147
|
* Retrieve live tracking info for an order via the registered IShippingProvider.
|