@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,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The delivery snapshot — what the buyer chose, frozen at checkout.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Why the fields are flat and ugly
|
|
5
|
+
*
|
|
6
|
+
* 🛑 **CORRECTED.** This read "`encryptPiiFields` is a flat top-level loop
|
|
7
|
+
* that never descends", which is FALSE — it handles `a.b` and `a[].b` via
|
|
8
|
+
* `encryptInArray`, and `CONVERSATION_PII_FIELDS` ships `lastMessage.body`.
|
|
9
|
+
*
|
|
10
|
+
* What it does not do is INFER. A nested `deliveryAddress: {fullName, …}`
|
|
11
|
+
* is covered only if somebody writes `deliveryAddress.fullName` into
|
|
12
|
+
* `ORDER_PII_FIELDS`, and the near-miss `"fullName"` reads as covering it
|
|
13
|
+
* while storing plaintext.
|
|
14
|
+
*
|
|
15
|
+
* The decisive argument is not tidiness: **an unencrypted nested field looks
|
|
16
|
+
* identical to an encrypted one in every inspection** — both are `string`,
|
|
17
|
+
* and `Encrypted<string>` is erased at runtime. Flat keys cannot
|
|
18
|
+
* silently half-apply, because `ORDER_PII_FIELDS` either names them or does
|
|
19
|
+
* not and the audit can see which.
|
|
20
|
+
*
|
|
21
|
+
* ## 🛑 Four fields are deliberately NOT encrypted
|
|
22
|
+
*
|
|
23
|
+
* `city` / `state` / `pincode` / `country` decide tax and serviceability and
|
|
24
|
+
* must stay QUERYABLE. An encrypted pincode cannot be filtered, grouped into
|
|
25
|
+
* a courier manifest, or read by `placeOfSupply` without a decrypt per row.
|
|
26
|
+
* They are not PII in any useful sense on their own.
|
|
27
|
+
*/
|
|
28
|
+
import type { AddressPlain } from "../../../../features/addresses/schemas/firestore";
|
|
29
|
+
/** The plaintext shape — what a caller builds and what the repository encrypts. */
|
|
30
|
+
export interface DeliverySnapshot {
|
|
31
|
+
deliveryFullName: string;
|
|
32
|
+
deliveryPhone: string;
|
|
33
|
+
deliveryAddressLine1: string;
|
|
34
|
+
deliveryAddressLine2?: string;
|
|
35
|
+
deliveryLandmark?: string;
|
|
36
|
+
deliveryCity: string;
|
|
37
|
+
deliveryState: string;
|
|
38
|
+
deliveryPincode: string;
|
|
39
|
+
deliveryCountry: string;
|
|
40
|
+
deliveryAddressId: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Freeze a chosen address onto an order.
|
|
44
|
+
*
|
|
45
|
+
* 🛑 Takes the resolved DOCUMENT, never an id. Resolving here would mean a
|
|
46
|
+
* second read on the money path, and — worse — would invite a caller to pass
|
|
47
|
+
* an id it had not verified belongs to the buyer. The checkout already loads
|
|
48
|
+
* and ownership-checks the address; this just copies it.
|
|
49
|
+
*
|
|
50
|
+
* 🛑 Takes `AddressPlain`, not `AddressDocument`, and that is the point.
|
|
51
|
+
* `addressesRepository` encrypts `fullName` / `phone` / `addressLine1` on
|
|
52
|
+
* write, so a raw `findById` returns CIPHERTEXT — snapshotting it would put
|
|
53
|
+
* `enc:v1:…` on the invoice, and nothing would catch it because both are
|
|
54
|
+
* `string` at runtime and `Encrypted<string>` is erased.
|
|
55
|
+
*
|
|
56
|
+
* Demanding the revealed type makes the mistake a COMPILE error instead of a
|
|
57
|
+
* comment nobody reads. Call `addressesRepository.revealAddress(doc)` first.
|
|
58
|
+
*/
|
|
59
|
+
export declare function snapshotDeliveryAddress(address: AddressPlain): DeliverySnapshot;
|
|
60
|
+
/** Everything a carrier booking needs, in `CreateShipmentInput`'s shape. */
|
|
61
|
+
export interface DeliveryParty {
|
|
62
|
+
name: string;
|
|
63
|
+
phone: string;
|
|
64
|
+
addressLine1: string;
|
|
65
|
+
addressLine2?: string;
|
|
66
|
+
city: string;
|
|
67
|
+
state: string;
|
|
68
|
+
pincode: string;
|
|
69
|
+
country: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* What the PARCEL goes to — the latest amendment, or the snapshot.
|
|
73
|
+
*
|
|
74
|
+
* 🛑 This is the one read that must NOT use the snapshot, and the invoice is
|
|
75
|
+
* the one that must. A buyer who corrects their address before dispatch
|
|
76
|
+
* expects the parcel to follow; the invoice records what was agreed when they
|
|
77
|
+
* paid. Collapsing the two is how a parcel goes to the old address or an
|
|
78
|
+
* invoice silently restates itself.
|
|
79
|
+
*
|
|
80
|
+
* Returns `null` rather than a partial party when a required field is
|
|
81
|
+
* missing — a booking built from blanks is accepted by the carrier and
|
|
82
|
+
* delivered nowhere.
|
|
83
|
+
*/
|
|
84
|
+
export declare function deliveryPartyFor(order: {
|
|
85
|
+
deliveryFullName?: string;
|
|
86
|
+
deliveryPhone?: string;
|
|
87
|
+
deliveryAddressLine1?: string;
|
|
88
|
+
deliveryAddressLine2?: string;
|
|
89
|
+
deliveryCity?: string;
|
|
90
|
+
deliveryState?: string;
|
|
91
|
+
deliveryPincode?: string;
|
|
92
|
+
deliveryCountry?: string;
|
|
93
|
+
deliveryAmendments?: Array<{
|
|
94
|
+
fullName: string;
|
|
95
|
+
phone: string;
|
|
96
|
+
addressLine1: string;
|
|
97
|
+
addressLine2?: string;
|
|
98
|
+
city: string;
|
|
99
|
+
state: string;
|
|
100
|
+
pincode: string;
|
|
101
|
+
country: string;
|
|
102
|
+
}>;
|
|
103
|
+
}): DeliveryParty | null;
|
|
104
|
+
/**
|
|
105
|
+
* The state the tax split was decided from.
|
|
106
|
+
*
|
|
107
|
+
* 🛑 Reads the SNAPSHOT, never an amendment. Place of supply is fixed at the
|
|
108
|
+
* time of supply; an address correction after the fact does not re-decide
|
|
109
|
+
* CGST/SGST versus IGST on an invoice that has been issued and may have been
|
|
110
|
+
* filed. That is the same forward-only rule `/admin/pricing` holds for rates.
|
|
111
|
+
*/
|
|
112
|
+
export declare function placeOfSupplyFrom(order: {
|
|
113
|
+
deliveryState?: string;
|
|
114
|
+
}): string | undefined;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The delivery snapshot — what the buyer chose, frozen at checkout.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Why the fields are flat and ugly
|
|
5
|
+
*
|
|
6
|
+
* 🛑 **CORRECTED.** This read "`encryptPiiFields` is a flat top-level loop
|
|
7
|
+
* that never descends", which is FALSE — it handles `a.b` and `a[].b` via
|
|
8
|
+
* `encryptInArray`, and `CONVERSATION_PII_FIELDS` ships `lastMessage.body`.
|
|
9
|
+
*
|
|
10
|
+
* What it does not do is INFER. A nested `deliveryAddress: {fullName, …}`
|
|
11
|
+
* is covered only if somebody writes `deliveryAddress.fullName` into
|
|
12
|
+
* `ORDER_PII_FIELDS`, and the near-miss `"fullName"` reads as covering it
|
|
13
|
+
* while storing plaintext.
|
|
14
|
+
*
|
|
15
|
+
* The decisive argument is not tidiness: **an unencrypted nested field looks
|
|
16
|
+
* identical to an encrypted one in every inspection** — both are `string`,
|
|
17
|
+
* and `Encrypted<string>` is erased at runtime. Flat keys cannot
|
|
18
|
+
* silently half-apply, because `ORDER_PII_FIELDS` either names them or does
|
|
19
|
+
* not and the audit can see which.
|
|
20
|
+
*
|
|
21
|
+
* ## 🛑 Four fields are deliberately NOT encrypted
|
|
22
|
+
*
|
|
23
|
+
* `city` / `state` / `pincode` / `country` decide tax and serviceability and
|
|
24
|
+
* must stay QUERYABLE. An encrypted pincode cannot be filtered, grouped into
|
|
25
|
+
* a courier manifest, or read by `placeOfSupply` without a decrypt per row.
|
|
26
|
+
* They are not PII in any useful sense on their own.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Freeze a chosen address onto an order.
|
|
30
|
+
*
|
|
31
|
+
* 🛑 Takes the resolved DOCUMENT, never an id. Resolving here would mean a
|
|
32
|
+
* second read on the money path, and — worse — would invite a caller to pass
|
|
33
|
+
* an id it had not verified belongs to the buyer. The checkout already loads
|
|
34
|
+
* and ownership-checks the address; this just copies it.
|
|
35
|
+
*
|
|
36
|
+
* 🛑 Takes `AddressPlain`, not `AddressDocument`, and that is the point.
|
|
37
|
+
* `addressesRepository` encrypts `fullName` / `phone` / `addressLine1` on
|
|
38
|
+
* write, so a raw `findById` returns CIPHERTEXT — snapshotting it would put
|
|
39
|
+
* `enc:v1:…` on the invoice, and nothing would catch it because both are
|
|
40
|
+
* `string` at runtime and `Encrypted<string>` is erased.
|
|
41
|
+
*
|
|
42
|
+
* Demanding the revealed type makes the mistake a COMPILE error instead of a
|
|
43
|
+
* comment nobody reads. Call `addressesRepository.revealAddress(doc)` first.
|
|
44
|
+
*/
|
|
45
|
+
export function snapshotDeliveryAddress(address) {
|
|
46
|
+
return {
|
|
47
|
+
deliveryFullName: String(address.fullName ?? ""),
|
|
48
|
+
deliveryPhone: String(address.phone ?? ""),
|
|
49
|
+
deliveryAddressLine1: String(address.addressLine1 ?? ""),
|
|
50
|
+
...(address.addressLine2 ? { deliveryAddressLine2: String(address.addressLine2) } : {}),
|
|
51
|
+
...(address.landmark ? { deliveryLandmark: String(address.landmark) } : {}),
|
|
52
|
+
deliveryCity: address.city ?? "",
|
|
53
|
+
deliveryState: address.state ?? "",
|
|
54
|
+
deliveryPincode: address.postalCode ?? "",
|
|
55
|
+
deliveryCountry: address.country ?? "",
|
|
56
|
+
deliveryAddressId: address.id,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* What the PARCEL goes to — the latest amendment, or the snapshot.
|
|
61
|
+
*
|
|
62
|
+
* 🛑 This is the one read that must NOT use the snapshot, and the invoice is
|
|
63
|
+
* the one that must. A buyer who corrects their address before dispatch
|
|
64
|
+
* expects the parcel to follow; the invoice records what was agreed when they
|
|
65
|
+
* paid. Collapsing the two is how a parcel goes to the old address or an
|
|
66
|
+
* invoice silently restates itself.
|
|
67
|
+
*
|
|
68
|
+
* Returns `null` rather than a partial party when a required field is
|
|
69
|
+
* missing — a booking built from blanks is accepted by the carrier and
|
|
70
|
+
* delivered nowhere.
|
|
71
|
+
*/
|
|
72
|
+
export function deliveryPartyFor(order) {
|
|
73
|
+
const latest = order.deliveryAmendments?.[order.deliveryAmendments.length - 1];
|
|
74
|
+
const party = latest
|
|
75
|
+
? {
|
|
76
|
+
name: latest.fullName,
|
|
77
|
+
phone: latest.phone,
|
|
78
|
+
addressLine1: latest.addressLine1,
|
|
79
|
+
...(latest.addressLine2 ? { addressLine2: latest.addressLine2 } : {}),
|
|
80
|
+
city: latest.city,
|
|
81
|
+
state: latest.state,
|
|
82
|
+
pincode: latest.pincode,
|
|
83
|
+
country: latest.country,
|
|
84
|
+
}
|
|
85
|
+
: {
|
|
86
|
+
name: order.deliveryFullName ?? "",
|
|
87
|
+
phone: order.deliveryPhone ?? "",
|
|
88
|
+
addressLine1: order.deliveryAddressLine1 ?? "",
|
|
89
|
+
...(order.deliveryAddressLine2 ? { addressLine2: order.deliveryAddressLine2 } : {}),
|
|
90
|
+
city: order.deliveryCity ?? "",
|
|
91
|
+
state: order.deliveryState ?? "",
|
|
92
|
+
pincode: order.deliveryPincode ?? "",
|
|
93
|
+
country: order.deliveryCountry ?? "",
|
|
94
|
+
};
|
|
95
|
+
const required = [
|
|
96
|
+
party.name,
|
|
97
|
+
party.phone,
|
|
98
|
+
party.addressLine1,
|
|
99
|
+
party.city,
|
|
100
|
+
party.state,
|
|
101
|
+
party.pincode,
|
|
102
|
+
party.country,
|
|
103
|
+
];
|
|
104
|
+
return required.every((v) => v.trim().length > 0) ? party : null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The state the tax split was decided from.
|
|
108
|
+
*
|
|
109
|
+
* 🛑 Reads the SNAPSHOT, never an amendment. Place of supply is fixed at the
|
|
110
|
+
* time of supply; an address correction after the fact does not re-decide
|
|
111
|
+
* CGST/SGST versus IGST on an invoice that has been issued and may have been
|
|
112
|
+
* filed. That is the same forward-only rule `/admin/pricing` holds for rates.
|
|
113
|
+
*/
|
|
114
|
+
export function placeOfSupplyFrom(order) {
|
|
115
|
+
return order.deliveryState || undefined;
|
|
116
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispute KINDS and the gate each one must pass.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the kind is closed and the reason list is not
|
|
5
|
+
*
|
|
6
|
+
* The owner's two rules are policy:
|
|
7
|
+
*
|
|
8
|
+
* > An item dispute can only be raised after the order was received. A
|
|
9
|
+
* > "not reached" dispute is allowed once the ETD is more than 3 days past.
|
|
10
|
+
*
|
|
11
|
+
* A gate cannot branch on a user-created string. `return-reasons.ts` already
|
|
12
|
+
* makes this argument in its own header — *"'No returns, unless the buyer
|
|
13
|
+
* didn't get what they paid for' is not a policy that can be enforced against
|
|
14
|
+
* a free-text box: it needs a machine-readable statement of what went
|
|
15
|
+
* wrong"* — and it applies with more force here, because these two gates are
|
|
16
|
+
* MUTUALLY EXCLUSIVE.
|
|
17
|
+
*
|
|
18
|
+
* So there are two levels:
|
|
19
|
+
*
|
|
20
|
+
* 1. **`DisputeKind` — closed, here, two values.** It picks the gate.
|
|
21
|
+
* 2. **`disputeReasons` — a staff-creatable Firestore collection.** Every row
|
|
22
|
+
* carries a `kind`, so a new reason inherits an existing gate and cannot
|
|
23
|
+
* invent one. That list is for triage and analytics, never for policy.
|
|
24
|
+
*
|
|
25
|
+
* ## What this replaces
|
|
26
|
+
*
|
|
27
|
+
* `raiseOrderDisputeAction` took `reason: string` and checked only that it was
|
|
28
|
+
* non-empty. So today a buyer can file "it never arrived" on an order that was
|
|
29
|
+
* delivered last week, and "it arrived damaged" on one still in transit — both
|
|
30
|
+
* nonsense, both accepted, and both raising a `severity: "error"` fraud-category
|
|
31
|
+
* admin alert. The gate is the point of this file.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DISPUTE_KIND: readonly ["item", "not_reached"];
|
|
34
|
+
export type DisputeKind = (typeof DISPUTE_KIND)[number];
|
|
35
|
+
/**
|
|
36
|
+
* 🛑 `Record<DisputeKind, string>`, so a third kind is a COMPILE error here
|
|
37
|
+
* rather than a dispute that renders `undefined` and passes no gate.
|
|
38
|
+
*/
|
|
39
|
+
export declare const DISPUTE_KIND_LABEL: Record<DisputeKind, string>;
|
|
40
|
+
export declare function isDisputeKind(value: unknown): value is DisputeKind;
|
|
41
|
+
/**
|
|
42
|
+
* How long after dispatch a parcel is ASSUMED to have been deliverable, when
|
|
43
|
+
* the courier gave us no estimate.
|
|
44
|
+
*
|
|
45
|
+
* 🛑 This exists so the `not_reached` gate is reachable AT ALL. There is no
|
|
46
|
+
* courier ETD on an order today: nothing platform-books (`createShipment` has
|
|
47
|
+
* zero callers), and a self-shipping seller types a tracking number with no
|
|
48
|
+
* estimate attached. Gate solely on a stored ETD and no buyer could ever file
|
|
49
|
+
* a non-delivery dispute — a gate nobody can pass is the same as no feature.
|
|
50
|
+
*
|
|
51
|
+
* Published through `PublishedValueKey` so the policy page and this gate
|
|
52
|
+
* cannot disagree (Phase 9).
|
|
53
|
+
*/
|
|
54
|
+
export declare const DISPUTE_TRANSIT_WINDOW_DAYS = 7;
|
|
55
|
+
/**
|
|
56
|
+
* The owner's "more than 3 days" grace, measured from the ETD.
|
|
57
|
+
*
|
|
58
|
+
* Separate from the transit window on purpose: one is "when should it have
|
|
59
|
+
* arrived", the other is "how long after that before we believe it is lost".
|
|
60
|
+
* Folding them into a single 10 would make neither number explicable on a
|
|
61
|
+
* policy page.
|
|
62
|
+
*/
|
|
63
|
+
export declare const DISPUTE_NOT_REACHED_GRACE_DAYS = 3;
|
|
64
|
+
/** Fields the gates read. Narrow, so a caller need not hold a whole order. */
|
|
65
|
+
export interface DisputeGateOrder {
|
|
66
|
+
deliveryDate?: Date | null;
|
|
67
|
+
completedAt?: Date | null;
|
|
68
|
+
shippingDate?: Date | null;
|
|
69
|
+
estimatedDeliveryDate?: Date | null;
|
|
70
|
+
}
|
|
71
|
+
export type DisputeGateResult = {
|
|
72
|
+
allowed: true;
|
|
73
|
+
}
|
|
74
|
+
/** `message` is buyer-facing and must name the next action, not just refuse. */
|
|
75
|
+
| {
|
|
76
|
+
allowed: false;
|
|
77
|
+
message: string;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The effective ETD, and WHY we think so.
|
|
81
|
+
*
|
|
82
|
+
* Exported because the buyer-facing form needs to show the date they can file
|
|
83
|
+
* from — telling someone "not yet" without saying when is a dead end.
|
|
84
|
+
*/
|
|
85
|
+
export declare function resolveDisputeEtd(order: DisputeGateOrder, transitWindowDays?: number): {
|
|
86
|
+
etd: Date;
|
|
87
|
+
source: "courier" | "assumed";
|
|
88
|
+
} | null;
|
|
89
|
+
/** The date from which a `not_reached` dispute becomes filable. */
|
|
90
|
+
export declare function disputeNotReachedFilableFrom(order: DisputeGateOrder, graceDays?: number): Date | null;
|
|
91
|
+
/**
|
|
92
|
+
* 🛑 `Record<DisputeKind, …>`. A third kind cannot be added without deciding
|
|
93
|
+
* what gates it — which is the whole reason the kind is closed.
|
|
94
|
+
*/
|
|
95
|
+
export declare const DISPUTE_GATE: Record<DisputeKind, (order: DisputeGateOrder, now?: Date) => DisputeGateResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Convenience wrapper so callers do not index the record by hand.
|
|
98
|
+
*
|
|
99
|
+
* 🛑 Takes the NARROW `DisputeGateOrder`, and an `OrderDocument` satisfies it
|
|
100
|
+
* structurally — so no adapter is needed and none should be added.
|
|
101
|
+
*
|
|
102
|
+
* A first draft had a `toDisputeGateOrder(order: OrderDocument)` helper, which
|
|
103
|
+
* meant this module imported the order schema while the order schema imports
|
|
104
|
+
* `DisputeKind` from here. That cycle is type-only and therefore erased, so it
|
|
105
|
+
* would have compiled and run — but it is also entirely avoidable, and a
|
|
106
|
+
* module that defines a policy should not depend on the document the policy is
|
|
107
|
+
* applied to. `return-reasons.ts` beside it has no imports at all for the same
|
|
108
|
+
* reason.
|
|
109
|
+
*
|
|
110
|
+
* Nothing leaks by passing the whole order in: what crosses back out is a
|
|
111
|
+
* `DisputeGateResult`, never the document (Root Cause #70).
|
|
112
|
+
*/
|
|
113
|
+
export declare function checkDisputeGate(kind: DisputeKind, order: DisputeGateOrder, now?: Date): DisputeGateResult;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispute KINDS and the gate each one must pass.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the kind is closed and the reason list is not
|
|
5
|
+
*
|
|
6
|
+
* The owner's two rules are policy:
|
|
7
|
+
*
|
|
8
|
+
* > An item dispute can only be raised after the order was received. A
|
|
9
|
+
* > "not reached" dispute is allowed once the ETD is more than 3 days past.
|
|
10
|
+
*
|
|
11
|
+
* A gate cannot branch on a user-created string. `return-reasons.ts` already
|
|
12
|
+
* makes this argument in its own header — *"'No returns, unless the buyer
|
|
13
|
+
* didn't get what they paid for' is not a policy that can be enforced against
|
|
14
|
+
* a free-text box: it needs a machine-readable statement of what went
|
|
15
|
+
* wrong"* — and it applies with more force here, because these two gates are
|
|
16
|
+
* MUTUALLY EXCLUSIVE.
|
|
17
|
+
*
|
|
18
|
+
* So there are two levels:
|
|
19
|
+
*
|
|
20
|
+
* 1. **`DisputeKind` — closed, here, two values.** It picks the gate.
|
|
21
|
+
* 2. **`disputeReasons` — a staff-creatable Firestore collection.** Every row
|
|
22
|
+
* carries a `kind`, so a new reason inherits an existing gate and cannot
|
|
23
|
+
* invent one. That list is for triage and analytics, never for policy.
|
|
24
|
+
*
|
|
25
|
+
* ## What this replaces
|
|
26
|
+
*
|
|
27
|
+
* `raiseOrderDisputeAction` took `reason: string` and checked only that it was
|
|
28
|
+
* non-empty. So today a buyer can file "it never arrived" on an order that was
|
|
29
|
+
* delivered last week, and "it arrived damaged" on one still in transit — both
|
|
30
|
+
* nonsense, both accepted, and both raising a `severity: "error"` fraud-category
|
|
31
|
+
* admin alert. The gate is the point of this file.
|
|
32
|
+
*/
|
|
33
|
+
export const DISPUTE_KIND = ["item", "not_reached"];
|
|
34
|
+
/**
|
|
35
|
+
* 🛑 `Record<DisputeKind, string>`, so a third kind is a COMPILE error here
|
|
36
|
+
* rather than a dispute that renders `undefined` and passes no gate.
|
|
37
|
+
*/
|
|
38
|
+
export const DISPUTE_KIND_LABEL = {
|
|
39
|
+
item: "There's a problem with what I received",
|
|
40
|
+
not_reached: "My order hasn't arrived",
|
|
41
|
+
};
|
|
42
|
+
export function isDisputeKind(value) {
|
|
43
|
+
return typeof value === "string" && DISPUTE_KIND.includes(value);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* How long after dispatch a parcel is ASSUMED to have been deliverable, when
|
|
47
|
+
* the courier gave us no estimate.
|
|
48
|
+
*
|
|
49
|
+
* 🛑 This exists so the `not_reached` gate is reachable AT ALL. There is no
|
|
50
|
+
* courier ETD on an order today: nothing platform-books (`createShipment` has
|
|
51
|
+
* zero callers), and a self-shipping seller types a tracking number with no
|
|
52
|
+
* estimate attached. Gate solely on a stored ETD and no buyer could ever file
|
|
53
|
+
* a non-delivery dispute — a gate nobody can pass is the same as no feature.
|
|
54
|
+
*
|
|
55
|
+
* Published through `PublishedValueKey` so the policy page and this gate
|
|
56
|
+
* cannot disagree (Phase 9).
|
|
57
|
+
*/
|
|
58
|
+
export const DISPUTE_TRANSIT_WINDOW_DAYS = 7;
|
|
59
|
+
/**
|
|
60
|
+
* The owner's "more than 3 days" grace, measured from the ETD.
|
|
61
|
+
*
|
|
62
|
+
* Separate from the transit window on purpose: one is "when should it have
|
|
63
|
+
* arrived", the other is "how long after that before we believe it is lost".
|
|
64
|
+
* Folding them into a single 10 would make neither number explicable on a
|
|
65
|
+
* policy page.
|
|
66
|
+
*/
|
|
67
|
+
export const DISPUTE_NOT_REACHED_GRACE_DAYS = 3;
|
|
68
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
69
|
+
function asDate(v) {
|
|
70
|
+
if (!v)
|
|
71
|
+
return null;
|
|
72
|
+
const d = v instanceof Date ? v : new Date(v);
|
|
73
|
+
return Number.isFinite(d.getTime()) ? d : null;
|
|
74
|
+
}
|
|
75
|
+
function fmt(d) {
|
|
76
|
+
return d.toLocaleDateString("en-IN", { day: "numeric", month: "short", year: "numeric" });
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The effective ETD, and WHY we think so.
|
|
80
|
+
*
|
|
81
|
+
* Exported because the buyer-facing form needs to show the date they can file
|
|
82
|
+
* from — telling someone "not yet" without saying when is a dead end.
|
|
83
|
+
*/
|
|
84
|
+
export function resolveDisputeEtd(order, transitWindowDays = DISPUTE_TRANSIT_WINDOW_DAYS) {
|
|
85
|
+
const courier = asDate(order.estimatedDeliveryDate);
|
|
86
|
+
if (courier)
|
|
87
|
+
return { etd: courier, source: "courier" };
|
|
88
|
+
const shipped = asDate(order.shippingDate);
|
|
89
|
+
if (shipped) {
|
|
90
|
+
return { etd: new Date(shipped.getTime() + transitWindowDays * DAY_MS), source: "assumed" };
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
/** The date from which a `not_reached` dispute becomes filable. */
|
|
95
|
+
export function disputeNotReachedFilableFrom(order, graceDays = DISPUTE_NOT_REACHED_GRACE_DAYS) {
|
|
96
|
+
const resolved = resolveDisputeEtd(order);
|
|
97
|
+
if (!resolved)
|
|
98
|
+
return null;
|
|
99
|
+
return new Date(resolved.etd.getTime() + graceDays * DAY_MS);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 🛑 `Record<DisputeKind, …>`. A third kind cannot be added without deciding
|
|
103
|
+
* what gates it — which is the whole reason the kind is closed.
|
|
104
|
+
*/
|
|
105
|
+
export const DISPUTE_GATE = {
|
|
106
|
+
/**
|
|
107
|
+
* You cannot judge an item you have not seen.
|
|
108
|
+
*
|
|
109
|
+
* `completedAt` counts as well as `deliveryDate`: a buyer who pressed "Mark
|
|
110
|
+
* complete" has told us they received it, and refusing them because no
|
|
111
|
+
* courier scan landed would be refusing the more reliable signal of the two.
|
|
112
|
+
*/
|
|
113
|
+
item: (order) => {
|
|
114
|
+
if (asDate(order.deliveryDate) || asDate(order.completedAt))
|
|
115
|
+
return { allowed: true };
|
|
116
|
+
return {
|
|
117
|
+
allowed: false,
|
|
118
|
+
message: "You can report a problem with an item once it arrives. If it hasn't arrived, raise a delivery issue instead.",
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Only valid BEFORE receipt, and only once the parcel is genuinely late.
|
|
123
|
+
*
|
|
124
|
+
* Three refusals, each pointing somewhere:
|
|
125
|
+
* - delivered → the wrong kind; offer the item route or a return.
|
|
126
|
+
* - never dispatched → not a courier problem at all. That is the
|
|
127
|
+
* `seller-dispatch` obligation's job, and it is already running.
|
|
128
|
+
* - too early → say the date, not just "not yet".
|
|
129
|
+
*/
|
|
130
|
+
not_reached: (order, now = new Date()) => {
|
|
131
|
+
const delivered = asDate(order.deliveryDate);
|
|
132
|
+
if (delivered) {
|
|
133
|
+
return {
|
|
134
|
+
allowed: false,
|
|
135
|
+
message: `This order was marked delivered on ${fmt(delivered)}. If something is wrong with what arrived, report a problem with the item instead.`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (!asDate(order.shippingDate) && !asDate(order.estimatedDeliveryDate)) {
|
|
139
|
+
return {
|
|
140
|
+
allowed: false,
|
|
141
|
+
message: "This order hasn't been dispatched yet, so there's nothing in transit to chase. We already track late dispatch and will act on it without you needing to do anything.",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const filableFrom = disputeNotReachedFilableFrom(order);
|
|
145
|
+
if (!filableFrom) {
|
|
146
|
+
// Unreachable given the check above; kept rather than asserted, because
|
|
147
|
+
// a thrown non-null assertion here would be a 500 on a buyer action.
|
|
148
|
+
return {
|
|
149
|
+
allowed: false,
|
|
150
|
+
message: "We can't work out an expected delivery date for this order yet. Contact support.",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (now.getTime() < filableFrom.getTime()) {
|
|
154
|
+
return {
|
|
155
|
+
allowed: false,
|
|
156
|
+
message: `It's still within the expected delivery window. If it hasn't arrived by ${fmt(filableFrom)}, you can raise a delivery issue then.`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return { allowed: true };
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Convenience wrapper so callers do not index the record by hand.
|
|
164
|
+
*
|
|
165
|
+
* 🛑 Takes the NARROW `DisputeGateOrder`, and an `OrderDocument` satisfies it
|
|
166
|
+
* structurally — so no adapter is needed and none should be added.
|
|
167
|
+
*
|
|
168
|
+
* A first draft had a `toDisputeGateOrder(order: OrderDocument)` helper, which
|
|
169
|
+
* meant this module imported the order schema while the order schema imports
|
|
170
|
+
* `DisputeKind` from here. That cycle is type-only and therefore erased, so it
|
|
171
|
+
* would have compiled and run — but it is also entirely avoidable, and a
|
|
172
|
+
* module that defines a policy should not depend on the document the policy is
|
|
173
|
+
* applied to. `return-reasons.ts` beside it has no imports at all for the same
|
|
174
|
+
* reason.
|
|
175
|
+
*
|
|
176
|
+
* Nothing leaks by passing the whole order in: what crosses back out is a
|
|
177
|
+
* `DisputeGateResult`, never the document (Root Cause #70).
|
|
178
|
+
*/
|
|
179
|
+
export function checkDisputeGate(kind, order, now) {
|
|
180
|
+
return DISPUTE_GATE[kind](order, now);
|
|
181
|
+
}
|
|
@@ -35,7 +35,7 @@ export declare const REFUND_COPY: {
|
|
|
35
35
|
readonly reasonSelectPlaceholder: "Choose a reason";
|
|
36
36
|
readonly reasonNoteLabel: "Anything else we should know? (optional)";
|
|
37
37
|
readonly alreadyRefundedMessage: "A refund has already been processed on this order. No further disputes or refund requests can be filed.";
|
|
38
|
-
readonly acknowledgments: readonly ["I understand this refund request, once approved, permanently removes my ability to file any dispute or RMA claim on this order.", "I confirm the item has not been used, worn, or damaged by me, and I am returning it in original condition (if a return is required).", "I understand the refund amount may take
|
|
38
|
+
readonly acknowledgments: readonly ["I understand this refund request, once approved, permanently removes my ability to file any dispute or RMA claim on this order.", "I confirm the item has not been used, worn, or damaged by me, and I am returning it in original condition (if a return is required).", "I understand the refund amount may take {{refundBusinessDaysMin}}–{{refundBusinessDaysMax}} business days to reflect and that platform fees may be non-recoverable."];
|
|
39
39
|
};
|
|
40
40
|
readonly siblingPayments: {
|
|
41
41
|
readonly heading: (count: number) => string;
|
|
@@ -38,7 +38,24 @@ export const REFUND_COPY = {
|
|
|
38
38
|
acknowledgments: [
|
|
39
39
|
"I understand this refund request, once approved, permanently removes my ability to file any dispute or RMA claim on this order.",
|
|
40
40
|
"I confirm the item has not been used, worn, or damaged by me, and I am returning it in original condition (if a return is required).",
|
|
41
|
-
|
|
41
|
+
/*
|
|
42
|
+
* 🛑 Phase 9 — TOKENS, resolved by `resolvePublishedCopy` at render.
|
|
43
|
+
*
|
|
44
|
+
* This literal was one of the three contradicting owners of the refund
|
|
45
|
+
* timeline: "5–7 business days" here, "5–7 business days via Razorpay"
|
|
46
|
+
* on the policy page (naming a gateway that was not even the one in
|
|
47
|
+
* use), and "3–5 business days" in the FAQ. Three statements of one
|
|
48
|
+
* fact, no reconciliation, and the FAQ one admin-editable so it could
|
|
49
|
+
* drift further after deployment.
|
|
50
|
+
*
|
|
51
|
+
* The caller renders this through `resolvePublishedCopy`, so the number
|
|
52
|
+
* now has exactly one definition. Note this string is an
|
|
53
|
+
* ACKNOWLEDGEMENT the buyer ticks — a token left unresolved here would
|
|
54
|
+
* appear in something they are agreeing to, which is the strongest
|
|
55
|
+
* possible argument for the unknown-token rule leaving `{{…}}` visible
|
|
56
|
+
* rather than blanking it.
|
|
57
|
+
*/
|
|
58
|
+
"I understand the refund amount may take {{refundBusinessDaysMin}}–{{refundBusinessDaysMax}} business days to reflect and that platform fees may be non-recoverable.",
|
|
42
59
|
],
|
|
43
60
|
},
|
|
44
61
|
siblingPayments: {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pay periods for employee payouts — ONE resolver, two cadences.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Why this is a module and not a ternary at each call site
|
|
5
|
+
*
|
|
6
|
+
* Two cadences means two period-boundary rules, and a reopened ticket can
|
|
7
|
+
* straddle a boundary differently per employee: the same reopen is inside the
|
|
8
|
+
* period for a monthly payee and across it for a weekly one. A branch written
|
|
9
|
+
* at each call site is two chances per site to disagree about where a week
|
|
10
|
+
* starts — and the symptom is a payslip that is quietly short, which nobody
|
|
11
|
+
* reports as a bug because nobody has the other number to compare it to.
|
|
12
|
+
*
|
|
13
|
+
* So the period is resolved once, from a date and a cadence, and every caller
|
|
14
|
+
* takes the pair it returns.
|
|
15
|
+
*
|
|
16
|
+
* ## 🛑 Go-forward, no clawback
|
|
17
|
+
*
|
|
18
|
+
* A payslip is final once issued. If a ticket is reopened after the period it
|
|
19
|
+
* was paid in has closed, the money is not recovered and the period is not
|
|
20
|
+
* recomputed — the ticket simply does not count again in the period where it
|
|
21
|
+
* is next resolved. Recomputing a closed period would mean an employee's pay
|
|
22
|
+
* changing after they were told what it was, which is a worse failure than
|
|
23
|
+
* occasionally paying for work that was later reopened.
|
|
24
|
+
*/
|
|
25
|
+
export type PayCadence = "weekly" | "monthly";
|
|
26
|
+
export declare const PAY_CADENCE_VALUES: readonly ["weekly", "monthly"];
|
|
27
|
+
export interface PayPeriod {
|
|
28
|
+
start: Date;
|
|
29
|
+
/** EXCLUSIVE. See the note below — this is the half-open convention. */
|
|
30
|
+
end: Date;
|
|
31
|
+
cadence: PayCadence;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The period containing `when`.
|
|
35
|
+
*
|
|
36
|
+
* ## 🛑 Half-open: `start <= t < end`
|
|
37
|
+
*
|
|
38
|
+
* An inclusive end means the last millisecond of a period is also the first of
|
|
39
|
+
* the next, so a ticket resolved exactly at midnight is counted twice — paid
|
|
40
|
+
* in two periods — or, if one side uses `<` and the other `<=`, in neither.
|
|
41
|
+
* Half-open makes both impossible by construction, and every consumer must
|
|
42
|
+
* compare with `< end`, never `<= end`.
|
|
43
|
+
*
|
|
44
|
+
* ## 🛑 Weeks start MONDAY
|
|
45
|
+
*
|
|
46
|
+
* `Date.getDay()` returns 0 for Sunday, so the naive `d - d.getDay()` produces
|
|
47
|
+
* a Sunday-start week. India's working week is Monday–Saturday and a support
|
|
48
|
+
* rota is read that way, so a Sunday boundary would split every weekend across
|
|
49
|
+
* two payslips. The `(day + 6) % 7` shift is what makes Monday day 0.
|
|
50
|
+
*
|
|
51
|
+
* ## 🛑 Local midnight, not UTC
|
|
52
|
+
*
|
|
53
|
+
* Wages are a human-calendar concept: an employee's Monday is their Monday.
|
|
54
|
+
* `setHours(0,0,0,0)` is local, and the server runs in the deployment's zone —
|
|
55
|
+
* which is why `periodLabel` renders the same boundary a payslip prints.
|
|
56
|
+
*/
|
|
57
|
+
export declare function payPeriodFor(when: Date, cadence: PayCadence): PayPeriod;
|
|
58
|
+
/** The period immediately before the one containing `when`. */
|
|
59
|
+
export declare function previousPayPeriod(when: Date, cadence: PayCadence): PayPeriod;
|
|
60
|
+
/** Half-open membership. The ONLY correct way to ask; see `payPeriodFor`. */
|
|
61
|
+
export declare function isWithinPeriod(t: Date, period: PayPeriod): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* What a payslip prints.
|
|
64
|
+
*
|
|
65
|
+
* 🛑 Renders the end as the LAST DAY INSIDE the period, not the exclusive
|
|
66
|
+
* boundary. "1 Jan – 1 Feb" on a January payslip reads as an overlap with
|
|
67
|
+
* February's and invites someone to "fix" the half-open convention that makes
|
|
68
|
+
* the arithmetic correct.
|
|
69
|
+
*/
|
|
70
|
+
export declare function periodLabel(period: PayPeriod, locale?: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* The tickets a period actually pays for.
|
|
73
|
+
*
|
|
74
|
+
* 🛑 **Tickets STILL RESOLVED at period end — not tickets closed during it.**
|
|
75
|
+
* Paying per ticket closed rewards closing rather than resolving: close it,
|
|
76
|
+
* let the buyer reopen it, close it again, and it pays twice. So a ticket
|
|
77
|
+
* counts only when it is resolved, was resolved inside the period, and is
|
|
78
|
+
* still resolved when the period ends.
|
|
79
|
+
*
|
|
80
|
+
* A reopen therefore removes the ticket from that period even if the reopen
|
|
81
|
+
* happened after the resolution — which is why this takes the whole ticket
|
|
82
|
+
* rather than a timestamp, and why `resolvedBy` must be CLEARED on reopen.
|
|
83
|
+
*/
|
|
84
|
+
export interface PayableTicket {
|
|
85
|
+
id: string;
|
|
86
|
+
resolvedAt?: Date | null;
|
|
87
|
+
resolvedBy?: string | null;
|
|
88
|
+
/** The live status, read at the moment the period is computed. */
|
|
89
|
+
isResolved: boolean;
|
|
90
|
+
}
|
|
91
|
+
export declare function resolvedTicketsForPeriod(tickets: readonly PayableTicket[], employeeUid: string, period: PayPeriod): string[];
|