@mohasinac/appkit 4.62.0 → 4.63.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 +8 -29
- package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
- package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
- package/dist/_internal/server/features/ads/booking.d.ts +118 -0
- package/dist/_internal/server/features/ads/booking.js +326 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
- package/dist/_internal/server/features/checkout/actions.js +850 -79
- package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
- package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
- package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
- package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
- package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
- package/dist/_internal/server/features/dashboard/attention.js +183 -0
- package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
- package/dist/_internal/server/features/dashboard/data.js +82 -0
- package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
- package/dist/_internal/server/features/inventory/reservations.js +273 -0
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
- package/dist/_internal/server/features/offers/destinations.js +65 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +54 -0
- package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
- package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
- package/dist/_internal/server/features/orders/balance.d.ts +89 -0
- package/dist/_internal/server/features/orders/balance.js +256 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
- package/dist/_internal/server/features/pricing/actions.js +144 -0
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
- package/dist/_internal/server/features/shipping/book-split.js +130 -0
- package/dist/_internal/server/features/shipping/book.d.ts +61 -0
- package/dist/_internal/server/features/shipping/book.js +176 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +264 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +29 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +65 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +95 -2
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +296 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
- package/dist/_internal/shared/checkout/order-math.js +159 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
- package/dist/_internal/shared/checkout/rules/index.js +1 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
- package/dist/_internal/shared/checkout/split.d.ts +75 -0
- package/dist/_internal/shared/checkout/split.js +120 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +93 -0
- package/dist/_internal/shared/content/published-values.js +206 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
- package/dist/_internal/shared/features/admin/integrations.js +263 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
- package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
- package/dist/_internal/shared/features/emi/choice.js +69 -0
- package/dist/_internal/shared/features/emi/group.d.ts +84 -0
- package/dist/_internal/shared/features/emi/group.js +126 -0
- package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
- package/dist/_internal/shared/features/ledger/posting.js +165 -0
- package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
- package/dist/_internal/shared/features/ledger/reports.js +127 -0
- package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
- package/dist/_internal/shared/features/ledger/rules.js +221 -0
- package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
- package/dist/_internal/shared/features/offers/coordination.js +80 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
- package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
- package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
- package/dist/_internal/shared/features/points/accepts.js +49 -0
- package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
- package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
- package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
- package/dist/_internal/shared/features/shipping/parcel.js +139 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
- package/dist/_internal/shared/features/site-settings/fees.js +12 -8
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/fees/explain.d.ts +81 -0
- package/dist/_internal/shared/fees/explain.js +101 -0
- package/dist/_internal/shared/history/index.d.ts +1 -1
- package/dist/_internal/shared/history/index.js +1 -1
- package/dist/_internal/shared/history/types.d.ts +7 -1
- package/dist/_internal/shared/history/types.js +25 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +43 -0
- package/dist/constants/api-endpoints.d.ts +114 -0
- package/dist/constants/api-endpoints.js +55 -0
- package/dist/constants/field-names.d.ts +42 -0
- package/dist/constants/field-names.js +52 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOrdersView.js +47 -35
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
- package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +86 -5
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +62 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/ads/schemas/booking-write.d.ts +120 -0
- package/dist/features/ads/schemas/booking-write.js +75 -0
- package/dist/features/ads/schemas/creative-form.d.ts +18 -0
- package/dist/features/ads/schemas/creative-form.js +51 -0
- package/dist/features/ads/schemas/firestore.d.ts +140 -0
- package/dist/features/ads/schemas/firestore.js +109 -0
- package/dist/features/auctions/repository/bid.repository.js +3 -1
- package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
- package/dist/features/audit-log/schemas/firestore.js +89 -0
- package/dist/features/auth/actions/profile-actions.d.ts +69 -1
- package/dist/features/auth/actions/profile-actions.js +62 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/auth/schemas/firestore.d.ts +16 -2
- package/dist/features/auth/schemas/firestore.js +2 -1
- package/dist/features/blog/actions/blog-actions.d.ts +6 -0
- package/dist/features/blog/actions/blog-actions.js +17 -2
- package/dist/features/blog/api/route.js +4 -1
- package/dist/features/blog/columns/index.js +5 -0
- package/dist/features/blog/components/BlogIndexPageView.js +2 -1
- package/dist/features/blog/repository/blog.repository.d.ts +4 -0
- package/dist/features/blog/repository/blog.repository.js +5 -0
- package/dist/features/blog/schemas/blog-form.d.ts +3 -0
- package/dist/features/blog/schemas/blog-form.js +1 -0
- package/dist/features/blog/schemas/firestore.d.ts +38 -1
- package/dist/features/blog/schemas/firestore.js +23 -0
- package/dist/features/blog/schemas/index.d.ts +6 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +2 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
- package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +33 -0
- package/dist/features/cart/repository/cart.repository.js +47 -0
- package/dist/features/cart/schemas/firestore.d.ts +116 -0
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
- package/dist/features/dashboard/components/DashboardHubView.js +56 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/faq/components/FAQPageContent.js +2 -2
- package/dist/features/gateway-events/schemas/index.d.ts +2 -2
- package/dist/features/homepage/schemas/index.d.ts +8 -8
- package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
- package/dist/features/inventory/schemas/stock-reservation.js +103 -0
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/AppLayoutShell.d.ts +9 -1
- package/dist/features/layout/AppLayoutShell.js +12 -4
- package/dist/features/layout/BottomActions.js +2 -1
- package/dist/features/layout/BottomNavbar.d.ts +10 -2
- package/dist/features/layout/SideActionDock.js +52 -2
- package/dist/features/layout/TitleBarLayout.js +13 -4
- package/dist/features/layout/TitleBarLayout.style.css +59 -0
- package/dist/features/layout/useCtaReveal.d.ts +16 -1
- package/dist/features/layout/useCtaReveal.js +17 -26
- package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
- package/dist/features/ledger/repository/journal.repository.js +312 -0
- package/dist/features/ledger/schemas/expenses.d.ts +87 -0
- package/dist/features/ledger/schemas/expenses.js +27 -0
- package/dist/features/ledger/schemas/firestore.d.ts +183 -0
- package/dist/features/ledger/schemas/firestore.js +69 -0
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
- package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
- package/dist/features/orders/components/RefundRequestView.js +19 -1
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +85 -1
- package/dist/features/orders/repository/orders.repository.js +205 -6
- package/dist/features/orders/schemas/balance.d.ts +40 -0
- package/dist/features/orders/schemas/balance.js +47 -0
- package/dist/features/orders/schemas/firestore.d.ts +398 -1
- package/dist/features/orders/schemas/firestore.js +43 -0
- package/dist/features/orders/schemas/index.d.ts +56 -8
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +47 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/payments/repository/payout.repository.js +3 -2
- package/dist/features/payments/schemas/firestore.d.ts +92 -1
- package/dist/features/payments/schemas/firestore.js +23 -0
- package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
- package/dist/features/pricing/components/AdminPricingView.js +157 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/firestore.d.ts +26 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
- package/dist/features/reviews/repository/reviews.repository.js +16 -0
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/scams/repository/scammer.repository.js +2 -1
- package/dist/features/scams/schemas/firestore.d.ts +2 -1
- package/dist/features/scams/schemas/firestore.js +2 -1
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/offer-actions.js +56 -0
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +37 -3
- package/dist/features/seller/components/DispatchForm.d.ts +11 -0
- package/dist/features/seller/components/DispatchForm.js +190 -0
- package/dist/features/seller/components/SellerOrdersView.js +221 -27
- package/dist/features/seller/components/index.d.ts +1 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/seller/repository/offer.repository.js +4 -3
- package/dist/features/seller/schemas/firestore.d.ts +23 -2
- package/dist/features/seller/schemas/firestore.js +3 -2
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +61 -4
- package/dist/features/seller/schemas/order-forms.js +41 -8
- package/dist/features/shipments/schemas/firestore.d.ts +25 -0
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/repository/store.repository.d.ts +18 -0
- package/dist/features/stores/repository/store.repository.js +27 -1
- package/dist/features/stores/schemas/firestore.d.ts +112 -0
- package/dist/features/stores/schemas/firestore.js +20 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/repository/support.repository.js +72 -6
- package/dist/features/support/schemas/firestore.d.ts +17 -0
- package/dist/features/support/schemas/index.d.ts +8 -8
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +33 -1
- package/dist/next/routing/route-map.d.ts +112 -0
- package/dist/next/routing/route-map.js +63 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/react/contexts/SessionContext.d.ts +17 -1
- package/dist/schemas/registry.d.ts +69 -34
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/security/pii-schemas.d.ts +1 -1
- package/dist/security/pii-schemas.js +45 -0
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +36 -1
- package/dist/server.js +183 -1
- package/dist/styles.css +412 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Button.d.ts +10 -1
- package/dist/ui/components/Button.js +25 -3
- package/dist/ui/components/Chart.d.ts +63 -0
- package/dist/ui/components/Chart.js +169 -0
- package/dist/ui/components/Chart.style.css +214 -0
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +83 -0
- package/dist/ui/components/OverflowRow.js +54 -2
- package/dist/ui/components/OverflowRow.style.css +38 -0
- package/dist/ui/components/RichTextEditor.js +99 -8
- package/dist/ui/components/chart-spec.d.ts +68 -0
- package/dist/ui/components/chart-spec.js +140 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/surface-tokens.d.ts +1 -1
- package/dist/ui/components/surface-tokens.js +9 -0
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/components/toolbar-collapse.d.ts +13 -0
- package/dist/ui/components/toolbar-collapse.js +10 -1
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/rich-text/RichText.d.ts +10 -1
- package/dist/ui/rich-text/RichText.js +33 -2
- package/dist/ui/rich-text/RichText.style.css +83 -79
- package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
- package/dist/ui/rich-text/RichTextRenderer.js +34 -2
- package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
- package/dist/ui/rich-text/chart-blocks.js +87 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1834 -1822
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE write path for a platform rate.
|
|
3
|
+
*
|
|
4
|
+
* ## Why there is exactly one
|
|
5
|
+
*
|
|
6
|
+
* Rates live on `siteSettings`, which `PUT /api/admin/site` can already write
|
|
7
|
+
* — so this is not the only way the numbers CAN move. It is the only way they
|
|
8
|
+
* move with a recorded reason, an effective date and an `adminAuditLog` row,
|
|
9
|
+
* and that difference is the whole point of `/admin/pricing`.
|
|
10
|
+
*
|
|
11
|
+
* The general settings form stays able to write them. Locking it out would
|
|
12
|
+
* mean an admin fixing a typo in the COD ceiling gets a 400 from the page that
|
|
13
|
+
* has always owned it, and the fix would be to come here — which is a worse
|
|
14
|
+
* outcome than an occasional unlogged edit. What this buys is that the
|
|
15
|
+
* DELIBERATE act of repricing has one door with a record behind it.
|
|
16
|
+
*
|
|
17
|
+
* ## 🛑 Forward-only, enforced at the WRITE
|
|
18
|
+
*
|
|
19
|
+
* `rejectRateChange` is a pure function and lives in the registry so the form
|
|
20
|
+
* can run it too — but the form running it is a courtesy, and this is the
|
|
21
|
+
* enforcement. A backdated change here would restate figures already invoiced
|
|
22
|
+
* and already paid out; see the registry header.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* How many changes the log keeps, newest first.
|
|
26
|
+
*
|
|
27
|
+
* Sized so a year of ordinary repricing fits: 16 rates changed a few times
|
|
28
|
+
* each is well under this, and the page shows only the most recent per rate
|
|
29
|
+
* anyway. The cap exists because the array rides on a document every request
|
|
30
|
+
* reads, not because 200 entries is a lot of data.
|
|
31
|
+
*/
|
|
32
|
+
export declare const RATE_CHANGE_LOG_MAX = 200;
|
|
33
|
+
export interface ApplyRateChangeInput {
|
|
34
|
+
path: string;
|
|
35
|
+
newValue: number;
|
|
36
|
+
/** Omit for "now". Never earlier than now — see `rejectRateChange`. */
|
|
37
|
+
effectiveFrom?: Date;
|
|
38
|
+
reason?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ApplyRateChangeResult {
|
|
41
|
+
path: string;
|
|
42
|
+
previousValue: number | null;
|
|
43
|
+
newValue: number;
|
|
44
|
+
effectiveFrom: Date;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Change one rate.
|
|
48
|
+
*
|
|
49
|
+
* 🛑 **One rate per call, on purpose.** A bulk form would need one reason
|
|
50
|
+
* covering a heterogeneous set, which is the same argument that removed the
|
|
51
|
+
* bulk offer-cancel: one shared reason across unlike records is worse audit
|
|
52
|
+
* data than no bulk action. Repricing three things is three decisions.
|
|
53
|
+
*/
|
|
54
|
+
export declare function applyRateChange(input: ApplyRateChangeInput, actor: {
|
|
55
|
+
uid: string;
|
|
56
|
+
name?: string;
|
|
57
|
+
isAdmin: boolean;
|
|
58
|
+
}, now?: Date): Promise<ApplyRateChangeResult>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE write path for a platform rate.
|
|
3
|
+
*
|
|
4
|
+
* ## Why there is exactly one
|
|
5
|
+
*
|
|
6
|
+
* Rates live on `siteSettings`, which `PUT /api/admin/site` can already write
|
|
7
|
+
* — so this is not the only way the numbers CAN move. It is the only way they
|
|
8
|
+
* move with a recorded reason, an effective date and an `adminAuditLog` row,
|
|
9
|
+
* and that difference is the whole point of `/admin/pricing`.
|
|
10
|
+
*
|
|
11
|
+
* The general settings form stays able to write them. Locking it out would
|
|
12
|
+
* mean an admin fixing a typo in the COD ceiling gets a 400 from the page that
|
|
13
|
+
* has always owned it, and the fix would be to come here — which is a worse
|
|
14
|
+
* outcome than an occasional unlogged edit. What this buys is that the
|
|
15
|
+
* DELIBERATE act of repricing has one door with a record behind it.
|
|
16
|
+
*
|
|
17
|
+
* ## 🛑 Forward-only, enforced at the WRITE
|
|
18
|
+
*
|
|
19
|
+
* `rejectRateChange` is a pure function and lives in the registry so the form
|
|
20
|
+
* can run it too — but the form running it is a courtesy, and this is the
|
|
21
|
+
* enforcement. A backdated change here would restate figures already invoiced
|
|
22
|
+
* and already paid out; see the registry header.
|
|
23
|
+
*/
|
|
24
|
+
import { getAdminDb } from "../../../../providers/db-firebase/index.js";
|
|
25
|
+
import { siteSettingsRepository } from "../../../../features/admin/repository/site-settings.repository.js";
|
|
26
|
+
import { SITE_SETTINGS_COLLECTION, } from "../../../../features/admin/schemas/firestore.js";
|
|
27
|
+
import { canEditRate, rateByPath, rejectRateChange, } from "../../../shared/features/pricing/rate-registry.js";
|
|
28
|
+
import { recordAdminAction } from "../audit-log/actions.js";
|
|
29
|
+
import { AdminAuditActionValues } from "../../../../features/audit-log/schemas/firestore.js";
|
|
30
|
+
import { normalizeError } from "../../../../errors/normalize.js";
|
|
31
|
+
import { serverLogger } from "../../../../monitoring/server-logger.js";
|
|
32
|
+
import { ValidationError } from "../../../../errors/validation-error.js";
|
|
33
|
+
const SINGLETON_ID = "global";
|
|
34
|
+
/**
|
|
35
|
+
* How many changes the log keeps, newest first.
|
|
36
|
+
*
|
|
37
|
+
* Sized so a year of ordinary repricing fits: 16 rates changed a few times
|
|
38
|
+
* each is well under this, and the page shows only the most recent per rate
|
|
39
|
+
* anyway. The cap exists because the array rides on a document every request
|
|
40
|
+
* reads, not because 200 entries is a lot of data.
|
|
41
|
+
*/
|
|
42
|
+
export const RATE_CHANGE_LOG_MAX = 200;
|
|
43
|
+
/** Read a dotted path off the settings document. `null` when absent. */
|
|
44
|
+
function readRate(settings, path) {
|
|
45
|
+
const value = path
|
|
46
|
+
.split(".")
|
|
47
|
+
.reduce((acc, key) => (acc && typeof acc === "object" ? acc[key] : undefined), settings);
|
|
48
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Change one rate.
|
|
52
|
+
*
|
|
53
|
+
* 🛑 **One rate per call, on purpose.** A bulk form would need one reason
|
|
54
|
+
* covering a heterogeneous set, which is the same argument that removed the
|
|
55
|
+
* bulk offer-cancel: one shared reason across unlike records is worse audit
|
|
56
|
+
* data than no bulk action. Repricing three things is three decisions.
|
|
57
|
+
*/
|
|
58
|
+
export async function applyRateChange(input, actor, now = new Date()) {
|
|
59
|
+
const descriptor = rateByPath(input.path);
|
|
60
|
+
if (!descriptor) {
|
|
61
|
+
throw new ValidationError("That is not a rate this platform charges.", {
|
|
62
|
+
path: `Unknown rate: ${input.path}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (!canEditRate(descriptor.tier, actor.isAdmin)) {
|
|
66
|
+
/*
|
|
67
|
+
* A statutory rate reaches this branch for EVERYONE, admins included —
|
|
68
|
+
* which is why the message names the real destination rather than
|
|
69
|
+
* implying the caller lacks a permission they could be granted.
|
|
70
|
+
*/
|
|
71
|
+
throw new ValidationError(descriptor.tier === "statutory"
|
|
72
|
+
? "Statutory rates are not set here — they are sourced per HSN code in Tax codes."
|
|
73
|
+
: "Only an administrator can change a policy ceiling.", { path: descriptor.label });
|
|
74
|
+
}
|
|
75
|
+
const settings = await siteSettingsRepository.getSingleton();
|
|
76
|
+
const previousValue = readRate(settings, descriptor.path);
|
|
77
|
+
const effectiveFrom = input.effectiveFrom ?? now;
|
|
78
|
+
const problem = rejectRateChange({ effectiveFrom, previousValue, newValue: input.newValue, reason: input.reason }, descriptor.tier, now);
|
|
79
|
+
if (problem) {
|
|
80
|
+
throw new ValidationError(problem, { newValue: problem });
|
|
81
|
+
}
|
|
82
|
+
const entry = {
|
|
83
|
+
path: descriptor.path,
|
|
84
|
+
previousValue,
|
|
85
|
+
newValue: input.newValue,
|
|
86
|
+
effectiveFrom,
|
|
87
|
+
changedByUid: actor.uid,
|
|
88
|
+
changedByName: actor.name ?? "",
|
|
89
|
+
...(input.reason?.trim() ? { reason: input.reason.trim() } : {}),
|
|
90
|
+
changedAt: now,
|
|
91
|
+
};
|
|
92
|
+
/*
|
|
93
|
+
* 🛑 A DOTTED path for the rate, and a whole-array write for the log.
|
|
94
|
+
*
|
|
95
|
+
* `update()` replaces a nested map wholesale (D13, recorded at length in
|
|
96
|
+
* `updateSingleton`), so writing `{ commissions: { platformFeePercent: 2 } }`
|
|
97
|
+
* would delete every other commission. The dotted form touches one leaf.
|
|
98
|
+
*
|
|
99
|
+
* The log cannot use `arrayUnion` because that cannot enforce the cap — the
|
|
100
|
+
* same reason `withHistory`'s batch paths fold in memory. Newest first, so
|
|
101
|
+
* the slice drops the OLDEST.
|
|
102
|
+
*/
|
|
103
|
+
const nextLog = [entry, ...(settings.rateChanges ?? [])].slice(0, RATE_CHANGE_LOG_MAX);
|
|
104
|
+
await getAdminDb()
|
|
105
|
+
.collection(SITE_SETTINGS_COLLECTION)
|
|
106
|
+
.doc(SINGLETON_ID)
|
|
107
|
+
.update({
|
|
108
|
+
[descriptor.path]: input.newValue,
|
|
109
|
+
rateChanges: nextLog,
|
|
110
|
+
updatedAt: now,
|
|
111
|
+
});
|
|
112
|
+
/*
|
|
113
|
+
* Best-effort, never fails the change — the same contract every other
|
|
114
|
+
* `recordAdminAction` caller has. The rate has already moved; refusing to
|
|
115
|
+
* acknowledge it because the log write failed would leave the admin
|
|
116
|
+
* believing it had not.
|
|
117
|
+
*/
|
|
118
|
+
try {
|
|
119
|
+
await recordAdminAction({
|
|
120
|
+
actorUid: actor.uid,
|
|
121
|
+
actorName: actor.name,
|
|
122
|
+
action: AdminAuditActionValues.PRICING_UPDATE,
|
|
123
|
+
targetType: "siteSettings",
|
|
124
|
+
targetId: descriptor.path,
|
|
125
|
+
targetLabel: descriptor.label,
|
|
126
|
+
...(input.reason?.trim() ? { reason: input.reason.trim() } : {}),
|
|
127
|
+
metadata: {
|
|
128
|
+
tier: descriptor.tier,
|
|
129
|
+
unit: descriptor.unit,
|
|
130
|
+
previousValue,
|
|
131
|
+
newValue: input.newValue,
|
|
132
|
+
effectiveFrom: effectiveFrom.toISOString(),
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const normalized = normalizeError(err);
|
|
138
|
+
serverLogger.warn("applyRateChange: audit log write failed", {
|
|
139
|
+
path: descriptor.path,
|
|
140
|
+
message: normalized.message,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return { path: descriptor.path, previousValue, newValue: input.newValue, effectiveFrom };
|
|
144
|
+
}
|
|
@@ -45,6 +45,8 @@ import { serverLogger } from "../../../../monitoring/index.js";
|
|
|
45
45
|
import { isFinalSaleExempt, RETURN_REASON_LABEL, } from "../../../shared/features/orders/return-reasons.js";
|
|
46
46
|
import { REFUND_COPY } from "../../../shared/features/orders/refund-copy.js";
|
|
47
47
|
import { applyRefundDeductionAction } from "../payouts/actions.js";
|
|
48
|
+
/* Phase 7c — the credit note. Swallows its own failures by design: see its 🛑. */
|
|
49
|
+
import { issueCreditNoteForRefund } from "../invoicing/credit-note.js";
|
|
48
50
|
import { getAdminDb } from "../../../../providers/db-firebase/index.js";
|
|
49
51
|
import { PRODUCT_COLLECTION, PRODUCT_CODES_SUBCOLLECTION, } from "../../../../features/products/schemas/firestore.js";
|
|
50
52
|
/**
|
|
@@ -362,6 +364,30 @@ export async function processRefundAction(input) {
|
|
|
362
364
|
// the reconciler will look at it once and find it already done.
|
|
363
365
|
serverLogger.warn("refund: claim not marked settled", { refundId });
|
|
364
366
|
});
|
|
367
|
+
/*
|
|
368
|
+
* ── PHASE 7c: the credit note that documents this reversal ────────────
|
|
369
|
+
*
|
|
370
|
+
* 🛑 HERE, at settlement, and not at reservation. A credit note numbered
|
|
371
|
+
* when the entry was reserved would leave a numbered reversal in the
|
|
372
|
+
* series on every provider failure — for money that never moved, with a
|
|
373
|
+
* number that cannot be withdrawn.
|
|
374
|
+
*
|
|
375
|
+
* 🛑 AWAITED but never allowed to throw (the issuer swallows its own
|
|
376
|
+
* failures and says so). The money has already left the gateway by this
|
|
377
|
+
* line; raising here would report a successful refund as failed, and an
|
|
378
|
+
* operator would retry a refund that already happened. A missing credit
|
|
379
|
+
* note is a reporting gap a backfill can close; a double refund is not.
|
|
380
|
+
*
|
|
381
|
+
* No renderer is passed, so this NUMBERS the reversal without producing
|
|
382
|
+
* a PDF. That is what the GSTR-1 export needs — it reconciles numbers
|
|
383
|
+
* and amounts. The buyer's PDF follows the invoice's own lazy pattern
|
|
384
|
+
* when a surface asks for it.
|
|
385
|
+
*/
|
|
386
|
+
const settledOrder = await orderRepository.findById(input.orderId);
|
|
387
|
+
const settledEvent = settledOrder?.refunds?.find((r) => r.refundId === refundId);
|
|
388
|
+
if (settledOrder && settledEvent) {
|
|
389
|
+
await issueCreditNoteForRefund(settledOrder, settledEvent);
|
|
390
|
+
}
|
|
365
391
|
// SB-UNI-N — revoke any available (unclaimed) digital codes linked to this order.
|
|
366
392
|
revokeAvailableDigitalCodes(input.orderId, digitalCodeItems);
|
|
367
393
|
/*
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S5a — one parcel per destination on a coordinated purchase.
|
|
3
|
+
*
|
|
4
|
+
* A coordinated purchase can send each member's share to their own address
|
|
5
|
+
* (`CoordinationMember.destinationAddressId`). That is N parcels from one
|
|
6
|
+
* order, which is N bookings and N serviceability checks.
|
|
7
|
+
*
|
|
8
|
+
* ## 🛑 Serviceability is checked for EVERY destination BEFORE any booking
|
|
9
|
+
*
|
|
10
|
+
* Booking as you go and failing on the fourth leaves three parcels already
|
|
11
|
+
* accepted by the carrier and a coordinator who cannot undo them — the
|
|
12
|
+
* cancel path exists but the money and the pickup slot are gone. A
|
|
13
|
+
* pre-flight over all destinations turns that into one refusal naming the
|
|
14
|
+
* pincode that cannot be served, before anything is committed.
|
|
15
|
+
*
|
|
16
|
+
* Two-phase on purpose, and it is NOT a transaction: a carrier booking has
|
|
17
|
+
* no rollback. What the pre-flight buys is that the common failure — an
|
|
18
|
+
* unservable pincode — is caught while rolling back is still free.
|
|
19
|
+
*
|
|
20
|
+
* ## 🛑 Bounded by `SHARED_PURCHASE_MAX_MEMBERS`
|
|
21
|
+
*
|
|
22
|
+
* Five destinations is five outbound calls for serviceability and five more
|
|
23
|
+
* to book, on a path somebody is waiting on. That ceiling is why the limit
|
|
24
|
+
* exists at all; see the registry's own header.
|
|
25
|
+
*/
|
|
26
|
+
import { type CoordinationMember } from "../../../shared/features/offers/coordination";
|
|
27
|
+
export interface DestinationCheck {
|
|
28
|
+
addressId: string;
|
|
29
|
+
pincode: string;
|
|
30
|
+
serviceable: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Can every named destination actually be delivered to?
|
|
34
|
+
*
|
|
35
|
+
* 🛑 Returns the FULL list, not the first failure. A coordinator fixing one
|
|
36
|
+
* unservable address only to be told about the next one is three round trips
|
|
37
|
+
* for a problem that was knowable in one — and each round trip is another
|
|
38
|
+
* chance for someone to give up with the arrangement half-built.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 An UNREADABLE check is treated as serviceable. A provider timeout is not
|
|
41
|
+
* evidence that a pincode cannot be served, and refusing on it would block a
|
|
42
|
+
* legitimate purchase on an outage we caused. The booking itself will fail
|
|
43
|
+
* loudly if the address really is unservable, which is the recoverable
|
|
44
|
+
* direction — and it is the same reasoning `bookShipment` applies to a wallet
|
|
45
|
+
* balance it could not read.
|
|
46
|
+
*
|
|
47
|
+
* A MISSING pincode is the opposite case and is reported unserviceable: that
|
|
48
|
+
* is a fact about the stored address, not about the provider, and it will not
|
|
49
|
+
* fix itself on a retry.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkDestinations(members: readonly CoordinationMember[],
|
|
52
|
+
/**
|
|
53
|
+
* 🛑 The parcel's weight in kg, NOT an origin pincode.
|
|
54
|
+
*
|
|
55
|
+
* `IShippingProvider.checkServiceability(pincode, weight)` reads its first
|
|
56
|
+
* argument as the DESTINATION. A reasonable guess of `(origin, destination)`
|
|
57
|
+
* would pass two strings into a `(string, number)` signature — caught by
|
|
58
|
+
* `tsc` here, but worth naming because the argument ORDER is the part a
|
|
59
|
+
* reader assumes.
|
|
60
|
+
*/
|
|
61
|
+
weightKg: number): Promise<DestinationCheck[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Refuse the whole arrangement if any destination cannot be served.
|
|
64
|
+
*
|
|
65
|
+
* Names every failing pincode, for the reason above.
|
|
66
|
+
*/
|
|
67
|
+
export declare function assertAllServiceable(checks: readonly DestinationCheck[]): void;
|
|
68
|
+
/**
|
|
69
|
+
* The parcels one coordinated order produces.
|
|
70
|
+
*
|
|
71
|
+
* 🛑 **Keyed by ADDRESS, not by member.** Two members naming the same address
|
|
72
|
+
* are one parcel, not two — that is the whole reason `destinationIds` returns
|
|
73
|
+
* a distinct set. Fanning out per member would book the courier twice to the
|
|
74
|
+
* same door and bill for both.
|
|
75
|
+
*
|
|
76
|
+
* 🛑 **A member with no `destinationAddressId` is NOT in this list.** Absent
|
|
77
|
+
* means "the coordinator's address", which is the ordinary one-parcel case
|
|
78
|
+
* and is handled by `bookShipment`'s existing single-delivery path — the
|
|
79
|
+
* order's own snapshot. Inventing a parcel for them here would duplicate it.
|
|
80
|
+
*/
|
|
81
|
+
export interface ParcelPlan {
|
|
82
|
+
addressId: string;
|
|
83
|
+
/** Members whose share rides in this parcel. Never empty. */
|
|
84
|
+
memberUids: string[];
|
|
85
|
+
}
|
|
86
|
+
export declare function planParcels(members: readonly CoordinationMember[]): ParcelPlan[];
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S5a — one parcel per destination on a coordinated purchase.
|
|
3
|
+
*
|
|
4
|
+
* A coordinated purchase can send each member's share to their own address
|
|
5
|
+
* (`CoordinationMember.destinationAddressId`). That is N parcels from one
|
|
6
|
+
* order, which is N bookings and N serviceability checks.
|
|
7
|
+
*
|
|
8
|
+
* ## 🛑 Serviceability is checked for EVERY destination BEFORE any booking
|
|
9
|
+
*
|
|
10
|
+
* Booking as you go and failing on the fourth leaves three parcels already
|
|
11
|
+
* accepted by the carrier and a coordinator who cannot undo them — the
|
|
12
|
+
* cancel path exists but the money and the pickup slot are gone. A
|
|
13
|
+
* pre-flight over all destinations turns that into one refusal naming the
|
|
14
|
+
* pincode that cannot be served, before anything is committed.
|
|
15
|
+
*
|
|
16
|
+
* Two-phase on purpose, and it is NOT a transaction: a carrier booking has
|
|
17
|
+
* no rollback. What the pre-flight buys is that the common failure — an
|
|
18
|
+
* unservable pincode — is caught while rolling back is still free.
|
|
19
|
+
*
|
|
20
|
+
* ## 🛑 Bounded by `SHARED_PURCHASE_MAX_MEMBERS`
|
|
21
|
+
*
|
|
22
|
+
* Five destinations is five outbound calls for serviceability and five more
|
|
23
|
+
* to book, on a path somebody is waiting on. That ceiling is why the limit
|
|
24
|
+
* exists at all; see the registry's own header.
|
|
25
|
+
*/
|
|
26
|
+
import { getProviders } from "../../../../contracts/registry.js";
|
|
27
|
+
import { addressesRepository } from "../../../../features/addresses/repository/addresses.repository.js";
|
|
28
|
+
import { SHARED_PURCHASE_MAX_MEMBERS, destinationIds, } from "../../../shared/features/offers/coordination.js";
|
|
29
|
+
import { ValidationError } from "../../../../errors/validation-error.js";
|
|
30
|
+
import { normalizeError } from "../../../../errors/normalize.js";
|
|
31
|
+
import { serverLogger } from "../../../../monitoring/server-logger.js";
|
|
32
|
+
/**
|
|
33
|
+
* Can every named destination actually be delivered to?
|
|
34
|
+
*
|
|
35
|
+
* 🛑 Returns the FULL list, not the first failure. A coordinator fixing one
|
|
36
|
+
* unservable address only to be told about the next one is three round trips
|
|
37
|
+
* for a problem that was knowable in one — and each round trip is another
|
|
38
|
+
* chance for someone to give up with the arrangement half-built.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 An UNREADABLE check is treated as serviceable. A provider timeout is not
|
|
41
|
+
* evidence that a pincode cannot be served, and refusing on it would block a
|
|
42
|
+
* legitimate purchase on an outage we caused. The booking itself will fail
|
|
43
|
+
* loudly if the address really is unservable, which is the recoverable
|
|
44
|
+
* direction — and it is the same reasoning `bookShipment` applies to a wallet
|
|
45
|
+
* balance it could not read.
|
|
46
|
+
*
|
|
47
|
+
* A MISSING pincode is the opposite case and is reported unserviceable: that
|
|
48
|
+
* is a fact about the stored address, not about the provider, and it will not
|
|
49
|
+
* fix itself on a retry.
|
|
50
|
+
*/
|
|
51
|
+
export async function checkDestinations(members,
|
|
52
|
+
/**
|
|
53
|
+
* 🛑 The parcel's weight in kg, NOT an origin pincode.
|
|
54
|
+
*
|
|
55
|
+
* `IShippingProvider.checkServiceability(pincode, weight)` reads its first
|
|
56
|
+
* argument as the DESTINATION. A reasonable guess of `(origin, destination)`
|
|
57
|
+
* would pass two strings into a `(string, number)` signature — caught by
|
|
58
|
+
* `tsc` here, but worth naming because the argument ORDER is the part a
|
|
59
|
+
* reader assumes.
|
|
60
|
+
*/
|
|
61
|
+
weightKg) {
|
|
62
|
+
const ids = destinationIds(members);
|
|
63
|
+
if (ids.length === 0)
|
|
64
|
+
return [];
|
|
65
|
+
if (ids.length > SHARED_PURCHASE_MAX_MEMBERS) {
|
|
66
|
+
throw new ValidationError(`A coordinated purchase can ship to at most ${SHARED_PURCHASE_MAX_MEMBERS} addresses.`, { destinations: `${ids.length} distinct addresses named.` });
|
|
67
|
+
}
|
|
68
|
+
/*
|
|
69
|
+
* 🛑 Optional on the registry. This is the serviceability PRE-FLIGHT, so
|
|
70
|
+
* with no provider the honest answer is "unknown", not "unserviceable":
|
|
71
|
+
* reporting every destination as unserviceable would block an accept that
|
|
72
|
+
* manual dispatch handles perfectly well.
|
|
73
|
+
*/
|
|
74
|
+
const provider = getProviders().shipping;
|
|
75
|
+
if (!provider) {
|
|
76
|
+
return ids.map((addressId) => ({ addressId, pincode: "", serviceable: true }));
|
|
77
|
+
}
|
|
78
|
+
const docs = await Promise.all(ids.map((id) => addressesRepository.findById(id)));
|
|
79
|
+
return Promise.all(ids.map(async (addressId, i) => {
|
|
80
|
+
/*
|
|
81
|
+
* 🛑 `.postalCode` needs no reveal — it is not PII and
|
|
82
|
+
* `AddressRepository` deliberately leaves it unencrypted so it stays
|
|
83
|
+
* queryable (see its own `computeAddressHash` comment). Calling
|
|
84
|
+
* `revealAddress` here would decrypt a name and a phone number we have
|
|
85
|
+
* no use for, on a path that only needs six digits.
|
|
86
|
+
*/
|
|
87
|
+
const pincode = docs[i]?.postalCode ?? "";
|
|
88
|
+
if (!pincode)
|
|
89
|
+
return { addressId, pincode, serviceable: false };
|
|
90
|
+
try {
|
|
91
|
+
const res = await provider.checkServiceability(pincode, weightKg);
|
|
92
|
+
return { addressId, pincode, serviceable: res.isServiceable };
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
void normalizeError(err);
|
|
96
|
+
serverLogger.warn("checkDestinations: serviceability unreadable", { addressId, pincode });
|
|
97
|
+
return { addressId, pincode, serviceable: true };
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Refuse the whole arrangement if any destination cannot be served.
|
|
103
|
+
*
|
|
104
|
+
* Names every failing pincode, for the reason above.
|
|
105
|
+
*/
|
|
106
|
+
export function assertAllServiceable(checks) {
|
|
107
|
+
const bad = checks.filter((c) => !c.serviceable);
|
|
108
|
+
if (bad.length === 0)
|
|
109
|
+
return;
|
|
110
|
+
throw new ValidationError(bad.length === 1
|
|
111
|
+
? "One delivery address cannot be served by the courier."
|
|
112
|
+
: `${bad.length} delivery addresses cannot be served by the courier.`, {
|
|
113
|
+
destinations: bad
|
|
114
|
+
.map((b) => (b.pincode ? `${b.pincode}: not serviceable` : "missing pincode"))
|
|
115
|
+
.join("; "),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
export function planParcels(members) {
|
|
119
|
+
const byAddress = new Map();
|
|
120
|
+
for (const m of members) {
|
|
121
|
+
if (!m.destinationAddressId)
|
|
122
|
+
continue;
|
|
123
|
+
const uids = byAddress.get(m.destinationAddressId);
|
|
124
|
+
if (uids)
|
|
125
|
+
uids.push(m.uid);
|
|
126
|
+
else
|
|
127
|
+
byAddress.set(m.destinationAddressId, [m.uid]);
|
|
128
|
+
}
|
|
129
|
+
return [...byAddress].map(([addressId, memberUids]) => ({ addressId, memberUids }));
|
|
130
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Booking a parcel through the platform's own carrier account — Part 1′.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Why this could not be built until Part 14
|
|
5
|
+
*
|
|
6
|
+
* `CreateShipmentInput` needs a structured `{name, phone, addressLine1, city,
|
|
7
|
+
* state, pincode, country}` for BOTH ends. Until the delivery snapshot landed
|
|
8
|
+
* the order carried `shippingAddress?: string` — flat free text with no
|
|
9
|
+
* pincode and no phone — and the only way to produce a party from it was to
|
|
10
|
+
* parse prose. The `placeOfSupply` comment already refuses that for tax, and
|
|
11
|
+
* the same argument holds here: a mis-parsed pincode is a parcel that goes to
|
|
12
|
+
* the wrong city, except nothing errors and the label prints fine.
|
|
13
|
+
*
|
|
14
|
+
* `deliveryPartyFor(order)` now returns exactly that shape, or `null` when a
|
|
15
|
+
* required field is missing — which is the only honest answer for an order
|
|
16
|
+
* placed before the snapshot existed.
|
|
17
|
+
*
|
|
18
|
+
* ## 🛑 `platformBookedShipment` is the flag this writes
|
|
19
|
+
*
|
|
20
|
+
* `order-math.ts` gates shipping reimbursement on it
|
|
21
|
+
* (`if (order.platformBookedShipment === true) return 0`) and
|
|
22
|
+
* `quote.ts:241` records that it has had **ZERO writers** — so the
|
|
23
|
+
* reimbursement rule has been reading a flag nothing sets. This is its
|
|
24
|
+
* writer, which is why the booking and the dispatch form are one unit of
|
|
25
|
+
* work and why the form must not ship first: a "Book through us" button with
|
|
26
|
+
* no booking behind it is a control the server refuses.
|
|
27
|
+
*/
|
|
28
|
+
export interface BookShipmentInput {
|
|
29
|
+
orderId: string;
|
|
30
|
+
/** Centimetres and kilograms, from the dispatch form's box preset. */
|
|
31
|
+
dimensions: {
|
|
32
|
+
weight: number;
|
|
33
|
+
length: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
};
|
|
37
|
+
/** The store address the courier collects from. */
|
|
38
|
+
pickupAddressId: string;
|
|
39
|
+
}
|
|
40
|
+
export interface BookShipmentResult {
|
|
41
|
+
trackingId: string;
|
|
42
|
+
courier?: string;
|
|
43
|
+
estimatedDelivery?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Book one parcel.
|
|
47
|
+
*
|
|
48
|
+
* ## 🛑 The wallet is checked BEFORE the booking, and a failure is a 409
|
|
49
|
+
*
|
|
50
|
+
* A carrier account with no balance rejects the booking — but some providers
|
|
51
|
+
* accept it and then silently fail to hand over, which produces a tracking id
|
|
52
|
+
* that never moves. Checking first turns "the parcel vanished" into "top up
|
|
53
|
+
* the account", and the 409 is deliberate: the request is well-formed and the
|
|
54
|
+
* seller is not confused, the world is simply not ready.
|
|
55
|
+
*
|
|
56
|
+
* 🛑 `getWalletBalance` is NOT abstract on `IShippingProvider` — manual
|
|
57
|
+
* shipping has no wallet, so a provider that does not implement it returns
|
|
58
|
+
* undefined and the check is SKIPPED rather than failing. A missing balance
|
|
59
|
+
* must never block a manual dispatch.
|
|
60
|
+
*/
|
|
61
|
+
export declare function bookShipment(input: BookShipmentInput): Promise<BookShipmentResult>;
|