@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,121 @@
|
|
|
1
|
+
import { pointsRepository } from "../../../../features/points/repository/points.repository.js";
|
|
2
|
+
import { pointsExpiryFrom } from "../../../../features/points/schemas/firestore.js";
|
|
3
|
+
import { AdminAuditActionValues } from "../../../../features/audit-log/schemas/firestore.js";
|
|
4
|
+
import { recordAdminAction } from "../audit-log/actions.js";
|
|
5
|
+
import { sendNotification } from "../../../../features/admin/actions/notification-actions.js";
|
|
6
|
+
import { normalizeError } from "../../../../errors/normalize.js";
|
|
7
|
+
import { serverLogger } from "../../../../monitoring/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* `admin_adjustment`'s first HUMAN writer.
|
|
10
|
+
*
|
|
11
|
+
* ## Why this is the last piece of D48 rather than the first
|
|
12
|
+
*
|
|
13
|
+
* `admin_adjustment` and `redemption_reversal` were both fully specified —
|
|
14
|
+
* signed-amount invariant, mandatory `adminReason`, the lot — and had **zero
|
|
15
|
+
* writers**. The reversal got one when cancellation was built. This is the
|
|
16
|
+
* other, and it was left until last on purpose: it is the only path by which a
|
|
17
|
+
* human can create spendable money from nothing, so it should not have existed
|
|
18
|
+
* before the ledger could expire a batch, consume FIFO, reverse a spend and
|
|
19
|
+
* reconcile against its own mirror. All four now do.
|
|
20
|
+
*
|
|
21
|
+
* ## 🛑 The one writer it must NOT be confused with
|
|
22
|
+
*
|
|
23
|
+
* `expireLapsedBatches` also appends `admin_adjustment`, with
|
|
24
|
+
* `actorUid: "system:points-expiry"`, and its docstring calls that **the one
|
|
25
|
+
* place a system actor may write an adjustment** — because expiry is a rule
|
|
26
|
+
* with a date attached rather than a discretionary decision.
|
|
27
|
+
*
|
|
28
|
+
* So this function takes a REAL `actorUid` and never that sentinel. Reusing it
|
|
29
|
+
* would make a human's decision indistinguishable from a scheduled rule in the
|
|
30
|
+
* one record that exists to tell them apart.
|
|
31
|
+
*
|
|
32
|
+
* ## Credits expire; debits and the reason do not
|
|
33
|
+
*
|
|
34
|
+
* A positive adjustment gets `pointsExpiryFrom(now)` like any other credit — an
|
|
35
|
+
* admin-granted goodwill credit is not more permanent than an earned one, and
|
|
36
|
+
* leaving `expiresAt` absent would mean NEVER EXPIRES, quietly making this the
|
|
37
|
+
* one way to mint a perpetual balance.
|
|
38
|
+
*
|
|
39
|
+
* A negative adjustment passes nothing, matching every other spend: there is
|
|
40
|
+
* nothing left to expire.
|
|
41
|
+
*
|
|
42
|
+
* ## Two records, deliberately
|
|
43
|
+
*
|
|
44
|
+
* The ledger entry answers "why does this account have 53 points". The
|
|
45
|
+
* `adminAuditLog` row answers "what have admins done lately". The second is the
|
|
46
|
+
* one you need when the account is not yet suspected, which is why a feature
|
|
47
|
+
* that already records `actorUid` on the entry still writes both.
|
|
48
|
+
*
|
|
49
|
+
* ## The buyer is told
|
|
50
|
+
*
|
|
51
|
+
* A balance that changes with no explanation is indistinguishable from a bug,
|
|
52
|
+
* and the buyer is the only party who cannot query the ledger. `description` is
|
|
53
|
+
* the buyer-facing line and is already mandatory in the schema; the
|
|
54
|
+
* notification carries it. `adminReason` is NOT sent — it is written for the
|
|
55
|
+
* next admin and may name an internal case.
|
|
56
|
+
*
|
|
57
|
+
* Best-effort: a notification that fails must not undo an applied adjustment,
|
|
58
|
+
* because the money has already moved and the ledger is the record that
|
|
59
|
+
* matters.
|
|
60
|
+
*/
|
|
61
|
+
export async function adjustUserPoints(input, actor) {
|
|
62
|
+
/*
|
|
63
|
+
* 🛑 No validation here, on purpose. `pointsAdjustFormSchema` is parsed at
|
|
64
|
+
* the route and `isPointsEntryWellFormed` is re-checked inside
|
|
65
|
+
* `append()` — which THROWS rather than writing a row it knows is
|
|
66
|
+
* malformed. A third copy of the rule here is the sixth-hand-rolled-copy
|
|
67
|
+
* shape (Root Cause #75); what this function owns is the side effects.
|
|
68
|
+
*/
|
|
69
|
+
const isCredit = input.amount > 0;
|
|
70
|
+
const { entryId, balance } = await pointsRepository.append({
|
|
71
|
+
userId: input.userId,
|
|
72
|
+
kind: "admin_adjustment",
|
|
73
|
+
amount: input.amount,
|
|
74
|
+
description: input.description,
|
|
75
|
+
adminReason: input.adminReason,
|
|
76
|
+
actorUid: actor.uid,
|
|
77
|
+
...(isCredit ? { expiresAt: pointsExpiryFrom(new Date()) } : {}),
|
|
78
|
+
});
|
|
79
|
+
serverLogger.info("adjustUserPoints", {
|
|
80
|
+
actorUid: actor.uid,
|
|
81
|
+
userId: input.userId,
|
|
82
|
+
amount: input.amount,
|
|
83
|
+
balance,
|
|
84
|
+
entryId,
|
|
85
|
+
});
|
|
86
|
+
void recordAdminAction({
|
|
87
|
+
actorUid: actor.uid,
|
|
88
|
+
actorName: actor.name,
|
|
89
|
+
action: AdminAuditActionValues.POINTS_ADJUST,
|
|
90
|
+
targetType: "user",
|
|
91
|
+
targetId: input.userId,
|
|
92
|
+
reason: input.adminReason,
|
|
93
|
+
metadata: { amount: input.amount, balanceAfter: balance, entryId },
|
|
94
|
+
});
|
|
95
|
+
await sendNotification({
|
|
96
|
+
userId: input.userId,
|
|
97
|
+
type: "account_action",
|
|
98
|
+
/*
|
|
99
|
+
* `account_action` is email-ELIGIBLE, which is correct here: a balance that
|
|
100
|
+
* changed is money news, and the buyer is the one party who cannot query
|
|
101
|
+
* the ledger to find out why.
|
|
102
|
+
*
|
|
103
|
+
* 🛑 And the type is right rather than convenient — `account_action` means
|
|
104
|
+
* "something was done TO your account by us", which is exactly this. It was
|
|
105
|
+
* split away from support-ticket and scam-report activity precisely so a
|
|
106
|
+
* type-level email decision could distinguish them.
|
|
107
|
+
*/
|
|
108
|
+
priority: "normal",
|
|
109
|
+
title: isCredit ? "Points added to your account" : "Points removed from your account",
|
|
110
|
+
message: input.description,
|
|
111
|
+
relatedType: "user",
|
|
112
|
+
relatedId: input.userId,
|
|
113
|
+
}).catch((err) => {
|
|
114
|
+
void normalizeError(err);
|
|
115
|
+
serverLogger.warn("adjustUserPoints: buyer notification failed (adjustment stands)", {
|
|
116
|
+
userId: input.userId,
|
|
117
|
+
entryId,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
return { entryId, balance };
|
|
121
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Award purchase points on a COMPLETED order — the owner's rule, made real.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this had to wait for completion to exist
|
|
5
|
+
*
|
|
6
|
+
* *"Points only get issued on successful purchases after buyer put reviews,
|
|
7
|
+
* then only, if no review no points, that marks the complete order; they are
|
|
8
|
+
* also assigned if the user [raises] no issues or updates after 7 days of
|
|
9
|
+
* delivery."* Then: *"auto assigned after 7 days of delivery, when order is
|
|
10
|
+
* marked complete; if review is given and order marked complete by the buyer
|
|
11
|
+
* before — immediate disburse."*
|
|
12
|
+
*
|
|
13
|
+
* So the trigger is completion, and completion has TWO writers — the buyer's
|
|
14
|
+
* fast path and the 7-day `order-complete` sweep — converging on one fact,
|
|
15
|
+
* `completedAt`.
|
|
16
|
+
*
|
|
17
|
+
* ## 🛑 `pointsAwardedAt` IS the idempotency key, and it cannot be added later
|
|
18
|
+
*
|
|
19
|
+
* `pointsLedger` is append-only. An append does not deduplicate itself, and
|
|
20
|
+
* `pointsRepository.append` takes no key — so two completion triggers firing
|
|
21
|
+
* on one order would credit twice, **permanently, with no way to net it off.**
|
|
22
|
+
* That is why the award was deliberately NOT written when the completion fact
|
|
23
|
+
* was (the sweep's own comment says so): writing the expensive half of a
|
|
24
|
+
* feature before its key exists is how an append-only ledger acquires a double
|
|
25
|
+
* credit nobody can remove.
|
|
26
|
+
*
|
|
27
|
+
* The pattern is copied from `reconcileOrderShipping`, which faced exactly this
|
|
28
|
+
* and solved it without a transaction: it writes `order.shippingReconciliation`
|
|
29
|
+
* in the same step as the credit, precisely so that field can be the key.
|
|
30
|
+
*
|
|
31
|
+
* ## The base is post-discount GOODS
|
|
32
|
+
*
|
|
33
|
+
* Not the order total. "5% of what you paid" read literally includes shipping
|
|
34
|
+
* and the platform fee, so we would issue points against postage handed to a
|
|
35
|
+
* courier. And it excludes the points tender itself, or points breed points.
|
|
36
|
+
*
|
|
37
|
+
* `orderTaxableValue` is reused rather than a fresh sum: it is already the
|
|
38
|
+
* post-discount, per-line, tax-backed-out goods figure, and it is already the
|
|
39
|
+
* payout base — so the number the seller is paid on and the number they fund
|
|
40
|
+
* points on are the same number, which is the property that makes the
|
|
41
|
+
* seller-funded model explicable to them.
|
|
42
|
+
*
|
|
43
|
+
* ## 🛑 The STORE bears it
|
|
44
|
+
*
|
|
45
|
+
* Owner: *"so stores bear it"*, framed as *"like a sale discount for getting a
|
|
46
|
+
* repeat customer."* So it is a DEDUCTION TERM in the payout, never a
|
|
47
|
+
* clawback — and that works only because of an ordering guarantee worth
|
|
48
|
+
* stating: `payout-release` is `blockedBy: ["order-complete"]`, so the gate
|
|
49
|
+
* opens BECAUSE the order completed, and completion is the same event that
|
|
50
|
+
* issues the points. The award is therefore always strictly before the payout
|
|
51
|
+
* is computed, by construction rather than by timing luck.
|
|
52
|
+
*/
|
|
53
|
+
import type { OrderDocument } from "../../../../features/orders/schemas/firestore";
|
|
54
|
+
export interface AwardPurchasePointsResult {
|
|
55
|
+
awarded: number;
|
|
56
|
+
skipped?: "already-awarded" | "not-complete" | "no-buyer" | "nothing-earnable";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Award points for one completed order. Safe to call from both triggers.
|
|
60
|
+
*
|
|
61
|
+
* Takes the order rather than an id when the caller already holds one — both
|
|
62
|
+
* completion paths do, and re-reading it would pay a Firestore read to learn
|
|
63
|
+
* what the caller just wrote.
|
|
64
|
+
*/
|
|
65
|
+
export declare function awardPurchasePoints(order: OrderDocument): Promise<AwardPurchasePointsResult>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Award purchase points on a COMPLETED order — the owner's rule, made real.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this had to wait for completion to exist
|
|
5
|
+
*
|
|
6
|
+
* *"Points only get issued on successful purchases after buyer put reviews,
|
|
7
|
+
* then only, if no review no points, that marks the complete order; they are
|
|
8
|
+
* also assigned if the user [raises] no issues or updates after 7 days of
|
|
9
|
+
* delivery."* Then: *"auto assigned after 7 days of delivery, when order is
|
|
10
|
+
* marked complete; if review is given and order marked complete by the buyer
|
|
11
|
+
* before — immediate disburse."*
|
|
12
|
+
*
|
|
13
|
+
* So the trigger is completion, and completion has TWO writers — the buyer's
|
|
14
|
+
* fast path and the 7-day `order-complete` sweep — converging on one fact,
|
|
15
|
+
* `completedAt`.
|
|
16
|
+
*
|
|
17
|
+
* ## 🛑 `pointsAwardedAt` IS the idempotency key, and it cannot be added later
|
|
18
|
+
*
|
|
19
|
+
* `pointsLedger` is append-only. An append does not deduplicate itself, and
|
|
20
|
+
* `pointsRepository.append` takes no key — so two completion triggers firing
|
|
21
|
+
* on one order would credit twice, **permanently, with no way to net it off.**
|
|
22
|
+
* That is why the award was deliberately NOT written when the completion fact
|
|
23
|
+
* was (the sweep's own comment says so): writing the expensive half of a
|
|
24
|
+
* feature before its key exists is how an append-only ledger acquires a double
|
|
25
|
+
* credit nobody can remove.
|
|
26
|
+
*
|
|
27
|
+
* The pattern is copied from `reconcileOrderShipping`, which faced exactly this
|
|
28
|
+
* and solved it without a transaction: it writes `order.shippingReconciliation`
|
|
29
|
+
* in the same step as the credit, precisely so that field can be the key.
|
|
30
|
+
*
|
|
31
|
+
* ## The base is post-discount GOODS
|
|
32
|
+
*
|
|
33
|
+
* Not the order total. "5% of what you paid" read literally includes shipping
|
|
34
|
+
* and the platform fee, so we would issue points against postage handed to a
|
|
35
|
+
* courier. And it excludes the points tender itself, or points breed points.
|
|
36
|
+
*
|
|
37
|
+
* `orderTaxableValue` is reused rather than a fresh sum: it is already the
|
|
38
|
+
* post-discount, per-line, tax-backed-out goods figure, and it is already the
|
|
39
|
+
* payout base — so the number the seller is paid on and the number they fund
|
|
40
|
+
* points on are the same number, which is the property that makes the
|
|
41
|
+
* seller-funded model explicable to them.
|
|
42
|
+
*
|
|
43
|
+
* ## 🛑 The STORE bears it
|
|
44
|
+
*
|
|
45
|
+
* Owner: *"so stores bear it"*, framed as *"like a sale discount for getting a
|
|
46
|
+
* repeat customer."* So it is a DEDUCTION TERM in the payout, never a
|
|
47
|
+
* clawback — and that works only because of an ordering guarantee worth
|
|
48
|
+
* stating: `payout-release` is `blockedBy: ["order-complete"]`, so the gate
|
|
49
|
+
* opens BECAUSE the order completed, and completion is the same event that
|
|
50
|
+
* issues the points. The award is therefore always strictly before the payout
|
|
51
|
+
* is computed, by construction rather than by timing luck.
|
|
52
|
+
*/
|
|
53
|
+
import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
|
|
54
|
+
import { pointsRepository } from "../../../../features/points/repository/points.repository.js";
|
|
55
|
+
import { POINTS_EARN_PERCENT, pointsExpiryFrom, } from "../../../../features/points/schemas/firestore.js";
|
|
56
|
+
import { orderTaxableValue } from "../../../shared/checkout/order-math.js";
|
|
57
|
+
import { normalizeError } from "../../../../errors/normalize.js";
|
|
58
|
+
import { serverLogger } from "../../../../monitoring/index.js";
|
|
59
|
+
function roundPoints(value) {
|
|
60
|
+
return Math.round(value * 100) / 100;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Award points for one completed order. Safe to call from both triggers.
|
|
64
|
+
*
|
|
65
|
+
* Takes the order rather than an id when the caller already holds one — both
|
|
66
|
+
* completion paths do, and re-reading it would pay a Firestore read to learn
|
|
67
|
+
* what the caller just wrote.
|
|
68
|
+
*/
|
|
69
|
+
export async function awardPurchasePoints(order) {
|
|
70
|
+
/*
|
|
71
|
+
* The key. Checked first and checked again by the caller's own write
|
|
72
|
+
* ordering — a double call is the NORMAL case here, not an edge: the buyer
|
|
73
|
+
* completes early and the 7-day sweep later finds the order already
|
|
74
|
+
* complete, or a retried action runs twice.
|
|
75
|
+
*/
|
|
76
|
+
if (order.pointsAwardedAt) {
|
|
77
|
+
return { awarded: 0, skipped: "already-awarded" };
|
|
78
|
+
}
|
|
79
|
+
if (!order.completedAt) {
|
|
80
|
+
/*
|
|
81
|
+
* Refused rather than treated as an implicit completion. The award is a
|
|
82
|
+
* consequence of a fact somebody recorded; inferring the fact from the
|
|
83
|
+
* award's own call site would let any caller mint points by asking.
|
|
84
|
+
*/
|
|
85
|
+
return { awarded: 0, skipped: "not-complete" };
|
|
86
|
+
}
|
|
87
|
+
if (!order.userId) {
|
|
88
|
+
serverLogger.error("purchase points: completed order has no buyer", {
|
|
89
|
+
orderId: order.id,
|
|
90
|
+
});
|
|
91
|
+
return { awarded: 0, skipped: "no-buyer" };
|
|
92
|
+
}
|
|
93
|
+
const goods = orderTaxableValue(order);
|
|
94
|
+
const amount = roundPoints((goods * POINTS_EARN_PERCENT) / 100);
|
|
95
|
+
if (amount <= 0) {
|
|
96
|
+
/*
|
|
97
|
+
* A fully-cancelled or zero-value order. Marked as awarded anyway below so
|
|
98
|
+
* the sweep stops revisiting it — "we looked and there was nothing to
|
|
99
|
+
* give" is a decision, and leaving it unmarked would re-read this order on
|
|
100
|
+
* every tick forever.
|
|
101
|
+
*/
|
|
102
|
+
await orderRepository
|
|
103
|
+
.update(order.id, { pointsAwardedAt: new Date() })
|
|
104
|
+
.catch((err) => {
|
|
105
|
+
void normalizeError(err);
|
|
106
|
+
});
|
|
107
|
+
return { awarded: 0, skipped: "nothing-earnable" };
|
|
108
|
+
}
|
|
109
|
+
const now = new Date();
|
|
110
|
+
await pointsRepository.append({
|
|
111
|
+
userId: order.userId,
|
|
112
|
+
kind: "purchase_earn",
|
|
113
|
+
amount,
|
|
114
|
+
orderId: order.id,
|
|
115
|
+
/*
|
|
116
|
+
* Names the base and the rate, because "47 points" alone is unexplainable
|
|
117
|
+
* later — and written once rather than re-derived, so it stays true of this
|
|
118
|
+
* moment even if the order is edited afterwards.
|
|
119
|
+
*/
|
|
120
|
+
description: `${POINTS_EARN_PERCENT}% back on ${order.id}: ₹${goods.toFixed(2)} of items.`,
|
|
121
|
+
expiresAt: pointsExpiryFrom(now),
|
|
122
|
+
});
|
|
123
|
+
/*
|
|
124
|
+
* 🛑 The key is written AFTER the credit, and that ordering is deliberate.
|
|
125
|
+
*
|
|
126
|
+
* A crash between them leaves a credited buyer and an order that looks
|
|
127
|
+
* unawarded — so the next trigger credits a second time. That is the lesser
|
|
128
|
+
* evil, and the same choice `reconcileOrderShipping` documents: the reverse
|
|
129
|
+
* ordering would mark the order done and then fail to pay, which is money a
|
|
130
|
+
* buyer was promised and silently never got. An extra credit is visible in
|
|
131
|
+
* the ledger and reversible by an `admin_adjustment`; a missing one is
|
|
132
|
+
* invisible to everybody.
|
|
133
|
+
*/
|
|
134
|
+
await orderRepository.update(order.id, {
|
|
135
|
+
pointsAwardedAt: now,
|
|
136
|
+
pointsAwarded: amount,
|
|
137
|
+
});
|
|
138
|
+
serverLogger.info("purchase points awarded", {
|
|
139
|
+
orderId: order.id,
|
|
140
|
+
userId: order.userId,
|
|
141
|
+
goods,
|
|
142
|
+
amount,
|
|
143
|
+
});
|
|
144
|
+
return { awarded: amount };
|
|
145
|
+
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { PRICE_GUIDANCE_TAX_BASIS } from "../../../shared/features/categories/price-guidance";
|
|
2
|
+
/**
|
|
3
|
+
* Where a row's figures came from, and therefore what may be claimed for them.
|
|
4
|
+
*
|
|
5
|
+
* 🛑 This is not decoration and a renderer that drops it will overclaim. A
|
|
6
|
+
* `computed` row is a mode over dated sightings of THIS leaf and may be
|
|
7
|
+
* labelled "most common price, last 6 months". A `seeded` row is the 2026-10
|
|
8
|
+
* crawl's median for an entire GENERATION, frozen at one date — calling that
|
|
9
|
+
* "most common" or "recent" would be false in both halves.
|
|
10
|
+
*/
|
|
11
|
+
export type PriceIndexMarketOrigin = "computed" | "seeded";
|
|
2
12
|
export interface PriceIndexMarketRow {
|
|
3
13
|
categoryId: string;
|
|
4
14
|
/**
|
|
@@ -16,6 +26,29 @@ export interface PriceIndexMarketRow {
|
|
|
16
26
|
p75?: number;
|
|
17
27
|
sampleSize?: number;
|
|
18
28
|
asOf?: string;
|
|
29
|
+
origin: PriceIndexMarketOrigin;
|
|
30
|
+
/**
|
|
31
|
+
* The price sightings cluster on. `computed` rows only.
|
|
32
|
+
*
|
|
33
|
+
* 🛑 Optional even there: absent means no price bucket held two or more
|
|
34
|
+
* sightings, so there is no cluster and the renderer must fall back to
|
|
35
|
+
* `median` under a different label rather than printing a lone sighting as
|
|
36
|
+
* though it were a consensus.
|
|
37
|
+
*/
|
|
38
|
+
mode?: number;
|
|
39
|
+
modeCount?: number;
|
|
40
|
+
/** Observed low/high over the window below. `computed` rows only. */
|
|
41
|
+
low?: number;
|
|
42
|
+
high?: number;
|
|
43
|
+
/**
|
|
44
|
+
* 🛑 FALSE means `low`/`high`/`mode` describe ALL TIME — the six-month window
|
|
45
|
+
* held too little to stand alone. The renderer must relabel; a stale figure
|
|
46
|
+
* is indistinguishable from a current one once printed.
|
|
47
|
+
*/
|
|
48
|
+
basedOnRecent?: boolean;
|
|
49
|
+
windowDays?: number;
|
|
50
|
+
/** Newest sighting behind a `computed` row. Not the rollup time. */
|
|
51
|
+
lastSeenAt?: string;
|
|
19
52
|
/**
|
|
20
53
|
* The share of competitor listings at this level that are SOLD OUT (0.85,
|
|
21
54
|
* measured across the five largest catalogues).
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
*/
|
|
56
56
|
import { resolveInheritedGuidanceMany } from "../categories/price-guidance-resolve.js";
|
|
57
57
|
import { PRICE_GUIDANCE_TAX_BASIS } from "../../../shared/features/categories/price-guidance.js";
|
|
58
|
+
import { marketPriceIndexRepository } from "../../../../features/categories/repository/market-price-index.repository.js";
|
|
58
59
|
import { PRICE_INDEX_SEARCH_LIMIT } from "./search.js";
|
|
59
60
|
/**
|
|
60
61
|
* Market bands for the leaves the client already resolved.
|
|
@@ -72,9 +73,60 @@ export async function getPriceIndexMarketForIds(rawIds) {
|
|
|
72
73
|
const ids = [...new Set(rawIds.filter((id) => typeof id === "string" && id.length > 0))].slice(0, PRICE_INDEX_SEARCH_LIMIT);
|
|
73
74
|
if (ids.length === 0)
|
|
74
75
|
return [];
|
|
75
|
-
|
|
76
|
+
/*
|
|
77
|
+
* Both halves in parallel. The computed read is one `getAll`, the seeded one
|
|
78
|
+
* is two batched reads — three round trips total against Rule #6's budget,
|
|
79
|
+
* and sequencing them would make it three in series for no benefit since
|
|
80
|
+
* neither depends on the other.
|
|
81
|
+
*/
|
|
82
|
+
const [guidanceById, computedById] = await Promise.all([
|
|
83
|
+
resolveInheritedGuidanceMany(ids),
|
|
84
|
+
marketPriceIndexRepository.getManyForLeaves(ids),
|
|
85
|
+
]);
|
|
76
86
|
const rows = [];
|
|
77
87
|
for (const id of ids) {
|
|
88
|
+
/*
|
|
89
|
+
* 🛑 A COMPUTED band for this exact leaf outranks any seeded one.
|
|
90
|
+
*
|
|
91
|
+
* The seeded band is a crawl median for a whole generation, so every model
|
|
92
|
+
* in an era carries the same number — which is how Dragoon MS and Strata
|
|
93
|
+
* Dragoon MS, different beys with different markets, both reported ₹3,999.
|
|
94
|
+
* A computed band is dated sightings of THIS leaf. Where both exist the
|
|
95
|
+
* specific measurement wins; where only the generation band exists it still
|
|
96
|
+
* shows, labelled as the generation's.
|
|
97
|
+
*
|
|
98
|
+
* 🛑 Looked up for the LEAF ONLY, deliberately. Computed bands do not walk
|
|
99
|
+
* the ancestor chain: observations are recorded against the thing that was
|
|
100
|
+
* actually priced, so an era-level row would be evidence about the era and
|
|
101
|
+
* inheriting it down to a model would re-create the exact conflation this
|
|
102
|
+
* precedence exists to end. The seeded band remains the inherited fallback,
|
|
103
|
+
* and it says so on the card.
|
|
104
|
+
*/
|
|
105
|
+
const computed = computedById.get(id)?.byKind?.ask;
|
|
106
|
+
if (computed) {
|
|
107
|
+
rows.push({
|
|
108
|
+
categoryId: id,
|
|
109
|
+
origin: "computed",
|
|
110
|
+
median: computed.median,
|
|
111
|
+
...(computed.mode === undefined
|
|
112
|
+
? {}
|
|
113
|
+
: { mode: computed.mode, modeCount: computed.modeCount }),
|
|
114
|
+
low: computed.low,
|
|
115
|
+
high: computed.high,
|
|
116
|
+
sampleSize: computed.sampleSize,
|
|
117
|
+
basedOnRecent: computed.basedOnRecent,
|
|
118
|
+
windowDays: computed.windowDays,
|
|
119
|
+
...(toIso(computed.lastSeenAt) ? { lastSeenAt: toIso(computed.lastSeenAt) } : {}),
|
|
120
|
+
/*
|
|
121
|
+
* A computed band is this leaf's own measurement by construction — it
|
|
122
|
+
* is keyed on the leaf id and never inherited — so `inherited` is
|
|
123
|
+
* false and no `via*` attribution applies.
|
|
124
|
+
*/
|
|
125
|
+
inherited: false,
|
|
126
|
+
taxBasis: PRICE_GUIDANCE_TAX_BASIS,
|
|
127
|
+
});
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
78
130
|
const resolved = guidanceById.get(id);
|
|
79
131
|
const market = resolved?.guidance.market;
|
|
80
132
|
// No band anywhere up the chain. Omitted, never zeroed.
|
|
@@ -82,6 +134,7 @@ export async function getPriceIndexMarketForIds(rawIds) {
|
|
|
82
134
|
continue;
|
|
83
135
|
rows.push({
|
|
84
136
|
categoryId: id,
|
|
137
|
+
origin: "seeded",
|
|
85
138
|
median: market.median,
|
|
86
139
|
...(market.p25 === undefined ? {} : { p25: market.p25 }),
|
|
87
140
|
...(market.p75 === undefined ? {} : { p75: market.p75 }),
|
|
@@ -14,6 +14,9 @@ import { PRODUCT_COLLECTION } from "../../../../features/products/schemas/firest
|
|
|
14
14
|
import { PRODUCTS_SITEMAP_LIMIT } from "../../../shared/features/products/config.js";
|
|
15
15
|
import { isListingRowAvailable } from "../../../shared/listing-types/_registry.js";
|
|
16
16
|
import { isPubliclyVisible } from "../../../shared/listing-types/availability.js";
|
|
17
|
+
import { isListingTypeEnabled } from "../../../shared/listing-types/feature-flags.js";
|
|
18
|
+
import { normalizeListingType } from "../../../../features/products/utils/listing-type.js";
|
|
19
|
+
import { getSiteSettingsSafe } from "../site-settings/safe-settings.js";
|
|
17
20
|
import { PRODUCT_FIELDS } from "../../../../constants/field-names.js";
|
|
18
21
|
import { SIEVE_OP, sieveAnd, sieveFilter, sortBy } from "../../../../utils/sieve-builder.js";
|
|
19
22
|
import { REVIEW_FIELDS } from "../../../../constants/field-names.js";
|
|
@@ -163,7 +166,17 @@ export async function listSitemapProducts() {
|
|
|
163
166
|
.select("slug", "id", "updatedAt", "listingType")
|
|
164
167
|
.limit(PRODUCTS_SITEMAP_LIMIT)
|
|
165
168
|
.get();
|
|
166
|
-
|
|
169
|
+
/*
|
|
170
|
+
* 🛑 A disabled listing type must not be advertised to search engines.
|
|
171
|
+
* This is the furthest-reaching surface of the lot: a sitemap entry
|
|
172
|
+
* survives the admin toggle, gets crawled, and lands a visitor on a type
|
|
173
|
+
* the site has switched off. Filtered in memory rather than in the query
|
|
174
|
+
* because the enabled set is a settings map, not a Firestore field.
|
|
175
|
+
*/
|
|
176
|
+
const settings = await getSiteSettingsSafe();
|
|
177
|
+
return snapshot.docs
|
|
178
|
+
.filter((doc) => isListingTypeEnabled(normalizeListingType(doc.data()), settings))
|
|
179
|
+
.map((doc) => {
|
|
167
180
|
const data = doc.data();
|
|
168
181
|
const rawListingType = data.listingType;
|
|
169
182
|
const listingType = rawListingType === "auction" ||
|
|
@@ -190,25 +203,21 @@ export async function listSitemapProducts() {
|
|
|
190
203
|
// ---------------------------------------------------------------------------
|
|
191
204
|
const RELATED_QUERY_PAGE_SIZE = 9;
|
|
192
205
|
const RELATED_DISPLAY_LIMIT = 8;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Excludes the current product, anything not publicly visible, and anything
|
|
196
|
-
* no longer available — ended auctions, closed prize-draws, filled pre-orders,
|
|
197
|
-
* depleted code pools, sold-out stock.
|
|
198
|
-
*
|
|
199
|
-
* This used to be a private `isValidRelatedItem` here, and it was the only
|
|
200
|
-
* per-type availability predicate in the codebase — which meant it was also
|
|
201
|
-
* the only place three bugs could hide: it read `codesAvailable` at the top
|
|
202
|
-
* level when the schema nests it under `digitalCode.codesAvailable` (so that
|
|
203
|
-
* branch never fired), it excluded `status` values ("sold", "out_of_stock",
|
|
204
|
-
* "discontinued") that are not members of the real `ProductStatus` union, and
|
|
205
|
-
* it had no branch at all for classified / live / art / stickers. It now
|
|
206
|
-
* shares one definition with the listing query and the homepage.
|
|
207
|
-
*/
|
|
208
|
-
function toRelatedItems(docs, currentProductId) {
|
|
206
|
+
function toRelatedItems(docs, currentProductId, settings) {
|
|
209
207
|
const now = new Date();
|
|
210
208
|
return docs
|
|
211
|
-
.filter((r) => r.id !== currentProductId &&
|
|
209
|
+
.filter((r) => r.id !== currentProductId &&
|
|
210
|
+
isPubliclyVisible(r) &&
|
|
211
|
+
/*
|
|
212
|
+
* 🛑 A DISABLED listing type must not appear here. Related items are
|
|
213
|
+
* pure DISCOVERY — unlike a won auction sitting in the cart, nothing
|
|
214
|
+
* here is an obligation the buyer already holds, so there is no reason
|
|
215
|
+
* to surface a type the admin has switched off. Without this an
|
|
216
|
+
* auction card rendered on every related carousel with auctions
|
|
217
|
+
* disabled, and it was reachable by clicking it.
|
|
218
|
+
*/
|
|
219
|
+
isListingTypeEnabled(normalizeListingType(r), settings) &&
|
|
220
|
+
isListingRowAvailable(r, now))
|
|
212
221
|
.slice(0, RELATED_DISPLAY_LIMIT)
|
|
213
222
|
.map(toProductItem);
|
|
214
223
|
}
|
|
@@ -256,10 +265,19 @@ export const computeRelatedItems = cache(async (product) => {
|
|
|
256
265
|
.catch(() => [])
|
|
257
266
|
: Promise.resolve([]),
|
|
258
267
|
]);
|
|
268
|
+
/*
|
|
269
|
+
* Fetched AFTER the four queries rather than inside the Promise.all: it is
|
|
270
|
+
* a cached single-doc read, and keeping it out of the fan-out keeps the
|
|
271
|
+
* four product queries parallel. `getSiteSettingsSafe` returns null on
|
|
272
|
+
* failure, and `isListingTypeEnabled` reads a missing flag as ENABLED — so
|
|
273
|
+
* a settings read that fails shows everything rather than hiding the page,
|
|
274
|
+
* which is the right failure direction for a discovery surface.
|
|
275
|
+
*/
|
|
276
|
+
const settings = await getSiteSettingsSafe();
|
|
259
277
|
return {
|
|
260
|
-
relatedItems: toRelatedItems(sameCategoryDocs, currentProductId),
|
|
261
|
-
relatedByBrand: toRelatedItems(sameBrandDocs, currentProductId),
|
|
262
|
-
relatedByTags: toRelatedItems(tagOverlapDocs, currentProductId),
|
|
263
|
-
relatedByStore: toRelatedItems(sameStoreDocs, currentProductId),
|
|
278
|
+
relatedItems: toRelatedItems(sameCategoryDocs, currentProductId, settings),
|
|
279
|
+
relatedByBrand: toRelatedItems(sameBrandDocs, currentProductId, settings),
|
|
280
|
+
relatedByTags: toRelatedItems(tagOverlapDocs, currentProductId, settings),
|
|
281
|
+
relatedByStore: toRelatedItems(sameStoreDocs, currentProductId, settings),
|
|
264
282
|
};
|
|
265
283
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filing and adjudicating a protection claim — the first callers
|
|
3
|
+
* `protectionAvailability()` and `adjudicateClaim()` have ever had.
|
|
4
|
+
*
|
|
5
|
+
* ## What was wrong (D11)
|
|
6
|
+
*
|
|
7
|
+
* We charge 2% (min ₹30) shipment protection and 3% (min ₹49) sale protection
|
|
8
|
+
* at four money sites. The decision logic, the custody state machine, the
|
|
9
|
+
* window constants and the order fields all existed with **zero callers**, and
|
|
10
|
+
* the refund path did not know the add-on existed. A FAQ promised *"we pursue
|
|
11
|
+
* the courier and refund you"* and *"refunded no questions asked"*.
|
|
12
|
+
*
|
|
13
|
+
* ## The two gates, and why both are server-side
|
|
14
|
+
*
|
|
15
|
+
* 1. **Did the buyer actually buy this cover?** Read off the ORDER's own
|
|
16
|
+
* `shipmentProtectionFee` / `saleProtectionFee` — the amount charged — not
|
|
17
|
+
* off the live store or the live settings. A seller must not be able to
|
|
18
|
+
* withdraw cover after the sale, which is the same snapshot reasoning
|
|
19
|
+
* `finalSale` uses on the refund path.
|
|
20
|
+
* 2. **Is the window still open?** The `claim-shipping` / `claim-sale`
|
|
21
|
+
* obligations, derived from `deliveryDate` through
|
|
22
|
+
* `PROTECTION_CLAIM_WINDOW_HOURS` (48h / 168h). One definition, shared with
|
|
23
|
+
* the sweep that closes the window and earns the premium.
|
|
24
|
+
*/
|
|
25
|
+
import { type ActionResult } from "../../../shared/types/action-result";
|
|
26
|
+
import { type ProtectionClaimDocument, type ProtectionClaimReason } from "../../../../features/protection-claims/schemas/firestore";
|
|
27
|
+
import { adjudicateClaim, type ClaimFinding } from "../../../shared/features/shipping/protections";
|
|
28
|
+
import { deadlinesFor } from "../../../shared/obligations/deadlines";
|
|
29
|
+
export interface FileProtectionClaimInput {
|
|
30
|
+
orderId: string;
|
|
31
|
+
reason: ProtectionClaimReason;
|
|
32
|
+
detail: string;
|
|
33
|
+
itemIds?: string[];
|
|
34
|
+
evidenceUrls?: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* File a claim as the buyer.
|
|
38
|
+
*
|
|
39
|
+
* 🛑 The COVER KIND is derived from the reason, never taken from the caller.
|
|
40
|
+
* `REASON_TO_KIND` maps transit failures to shipment cover and item failures
|
|
41
|
+
* to sale cover — because letting the buyer pick would let them file a
|
|
42
|
+
* non-delivery against the 7-day sale window after the 48-hour transit window
|
|
43
|
+
* had closed, which is the window rule defeated by a dropdown.
|
|
44
|
+
*/
|
|
45
|
+
export declare function fileProtectionClaimAction(input: FileProtectionClaimInput): Promise<ActionResult<{
|
|
46
|
+
claimId: string;
|
|
47
|
+
}>>;
|
|
48
|
+
/**
|
|
49
|
+
* Adjudicate as an admin or moderator.
|
|
50
|
+
*
|
|
51
|
+
* 🛑 THE FINDING DECIDES WHO PAYS, NEVER WHETHER A PROTECTED BUYER IS
|
|
52
|
+
* REFUNDED. `adjudicateClaim` encodes that and this action does not
|
|
53
|
+
* second-guess it: on protected cover a `change-of-mind` finding STILL refunds
|
|
54
|
+
* the buyer and moves the cost to the platform, raising a report — because the
|
|
55
|
+
* promise sold was unconditional, and the only honest enforcement against
|
|
56
|
+
* repeat abuse is withdrawing FUTURE eligibility, not denying this claim.
|
|
57
|
+
*
|
|
58
|
+
* 🛑 It records the decision and does NOT move money. The refund is
|
|
59
|
+
* `processRefundAction`'s job, with its own idempotency key — and keeping them
|
|
60
|
+
* apart means a claim that adjudicated but failed to refund leaves an `upheld`
|
|
61
|
+
* claim with no `refundId`, which is a findable state rather than a lost one.
|
|
62
|
+
*/
|
|
63
|
+
export declare function adjudicateProtectionClaimAction(claimId: string, finding: ClaimFinding): Promise<ActionResult<{
|
|
64
|
+
outcome: ReturnType<typeof adjudicateClaim>;
|
|
65
|
+
}>>;
|
|
66
|
+
/** A buyer's own claims, for their order detail page. */
|
|
67
|
+
export declare function getMyProtectionClaimsAction(): Promise<ActionResult<ProtectionClaimDocument[]>>;
|
|
68
|
+
/** Whether this order can be claimed against right now, for rendering the CTA. */
|
|
69
|
+
export declare function canClaimProtection(order: Parameters<typeof deadlinesFor>[0], kind: "shipping" | "sale"): Promise<{
|
|
70
|
+
can: boolean;
|
|
71
|
+
reason?: string;
|
|
72
|
+
}>;
|