@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,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-order-group EMI terms, and the one definition of what is COLLECTED NOW
|
|
3
|
+
* on an instalment order.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this file exists ──────────────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* Four money paths have to agree about an EMI order: the pricing preview (what
|
|
8
|
+
* the buyer is shown), `createOrderForGroup` (COD/manual), the gateway capture
|
|
9
|
+
* in `/api/payment/create-order`, and `createPhonePeGroupOrder` (the order
|
|
10
|
+
* written after that capture). Three of them had no EMI code at all, and the
|
|
11
|
+
* fourth computed its schedule inline — so adding the online tender by copying
|
|
12
|
+
* that block would have produced the exact shape Root Cause #75 is about: a
|
|
13
|
+
* rule reachable by copy-paste, copied, and the copy never learning about the
|
|
14
|
+
* branch added later. `lineTotalFor` was the last instance; this is the same
|
|
15
|
+
* fix applied before the divergence rather than after it.
|
|
16
|
+
*
|
|
17
|
+
* ── 🛑 THE DEFECT THIS CLOSES, which is larger than the refactor ──────────
|
|
18
|
+
*
|
|
19
|
+
* `emiTokenAmount` was written onto every EMI order and had **ZERO readers**,
|
|
20
|
+
* measured across `src` and `appkit/src`. The buyer's manual-payment page asks
|
|
21
|
+
* for `order.amountDue ?? order.total`, and `amountDue` was set only when
|
|
22
|
+
* points applied — so an EMI buyer was asked to transfer the **entire order
|
|
23
|
+
* total up front** *and* handed a schedule of monthly instalments. The token
|
|
24
|
+
* percentage was computed, stored, scheduled around, and never charged.
|
|
25
|
+
*
|
|
26
|
+
* `amountDueNow` below is that fix, and it is deliberately a SUBTRACTION
|
|
27
|
+
* rather than a re-derivation:
|
|
28
|
+
*
|
|
29
|
+
* orderTotal − remainingBalance
|
|
30
|
+
* = (subtotal + surcharge + fees) − (principalRemaining + surcharge)
|
|
31
|
+
* = (subtotal − principalRemaining) + fees
|
|
32
|
+
* = token + fees
|
|
33
|
+
*
|
|
34
|
+
* Provably the token plus every additive charge, with no second arithmetic to
|
|
35
|
+
* drift from `computeBuyerEmiQuote`'s own. A function that recomputed
|
|
36
|
+
* `tokenPercent × subtotal + …` would be a fifth place rounding money.
|
|
37
|
+
*/
|
|
38
|
+
import { roundRupees } from "../../../../utils/number.formatter.js";
|
|
39
|
+
import { checkEmiEligibility, computeBuyerEmiQuote, computeEmiSchedule, } from "./schedule.js";
|
|
40
|
+
export function groupEmiGate(input, settings) {
|
|
41
|
+
if (!input.emiOptIn)
|
|
42
|
+
return { applies: false, reason: "not_opted_in" };
|
|
43
|
+
if (!input.emiTenureMonths)
|
|
44
|
+
return { applies: false, reason: "no_tenure" };
|
|
45
|
+
if (!settings)
|
|
46
|
+
return { applies: false, reason: "no_settings" };
|
|
47
|
+
const eligibility = checkEmiEligibility(input.groupSubtotal, input.sellerEmiEnabled, settings);
|
|
48
|
+
if (!eligibility.eligible)
|
|
49
|
+
return { applies: false, reason: eligibility.reason };
|
|
50
|
+
return { applies: true };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The buyer-visible quote for one group, or `null` when EMI does not apply.
|
|
54
|
+
*
|
|
55
|
+
* For the preview and for the gateway CAPTURE amount — neither needs the
|
|
56
|
+
* platform/seller surcharge split, and neither should be able to print it.
|
|
57
|
+
*/
|
|
58
|
+
export function groupEmiQuote(input, settings, purchaseDate) {
|
|
59
|
+
if (!settings)
|
|
60
|
+
return null;
|
|
61
|
+
if (!groupEmiGate(input, settings).applies)
|
|
62
|
+
return null;
|
|
63
|
+
return computeBuyerEmiQuote(input.groupSubtotal, input.emiTenureMonths, settings, purchaseDate);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The server-side schedule for one group, including the surcharge split that
|
|
67
|
+
* is persisted onto the order. For the two order WRITERS only.
|
|
68
|
+
*/
|
|
69
|
+
export function groupEmiSchedule(input, settings, purchaseDate) {
|
|
70
|
+
if (!settings)
|
|
71
|
+
return null;
|
|
72
|
+
if (!groupEmiGate(input, settings).applies)
|
|
73
|
+
return null;
|
|
74
|
+
return computeEmiSchedule(input.groupSubtotal, input.emiTenureMonths, settings, purchaseDate);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* What is actually collected at checkout: the order total, less any points
|
|
78
|
+
* tendered, less whatever has been deferred into instalments.
|
|
79
|
+
*
|
|
80
|
+
* 🛑 Composes with the points tender rather than replacing it. Both reduce
|
|
81
|
+
* what is collected and they are independent, so an EMI order part-funded by
|
|
82
|
+
* points must subtract both — writing `total − remainingBalance` would hand
|
|
83
|
+
* back the points discount, and `total − pointsApplied` alone is the bug this
|
|
84
|
+
* function exists to fix. Floored at zero: points can cover at most half an
|
|
85
|
+
* order, so the sum cannot genuinely go negative, and clamping means a future
|
|
86
|
+
* change to that cap degrades to "collect nothing" rather than to a refund.
|
|
87
|
+
*/
|
|
88
|
+
export function amountDueNow(args) {
|
|
89
|
+
return roundRupees(Math.max(0, args.orderTotal - args.pointsApplied - args.emiRemainingBalance));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The `emi*` fields written onto an order document.
|
|
93
|
+
*
|
|
94
|
+
* 🛑 One builder for both creation paths. These are eleven fields that have to
|
|
95
|
+
* be written identically by `createOrderForGroup` and
|
|
96
|
+
* `createPhonePeGroupOrder`, and the second one carried **none of them** —
|
|
97
|
+
* every order paid online lost its instalment plan entirely. Two hand-written
|
|
98
|
+
* copies is the create-vs-create axis of Root Cause #39, and these two
|
|
99
|
+
* functions have already drifted once before over add-on fees (#65).
|
|
100
|
+
*/
|
|
101
|
+
export function emiOrderFields(schedule, emiTenureMonths) {
|
|
102
|
+
if (!schedule)
|
|
103
|
+
return {};
|
|
104
|
+
return {
|
|
105
|
+
emiEnabled: true,
|
|
106
|
+
emiTenureMonths,
|
|
107
|
+
emiTokenAmount: schedule.tokenAmount,
|
|
108
|
+
emiSurchargeAmount: schedule.surchargeAmount,
|
|
109
|
+
/*
|
|
110
|
+
* Persisted even though it moves no money at checkout: it is the
|
|
111
|
+
* platform/seller split of the surcharge, and the payout run needs it to
|
|
112
|
+
* credit the seller their share. It was discarded on every EMI order until
|
|
113
|
+
* it was added here. 🛑 It is `PRIVATE_*_FIELDS` — it belongs on the
|
|
114
|
+
* document and must never reach a buyer-facing projection.
|
|
115
|
+
*/
|
|
116
|
+
emiSurchargeSellerShare: schedule.surchargeSellerShare,
|
|
117
|
+
emiInstallments: schedule.installments.map((i) => ({
|
|
118
|
+
index: i.index,
|
|
119
|
+
dueDate: i.dueDate,
|
|
120
|
+
amount: i.amount,
|
|
121
|
+
status: "pending",
|
|
122
|
+
})),
|
|
123
|
+
emiRemainingBalance: schedule.remainingBalance,
|
|
124
|
+
emiComplete: false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The posting rules — pure, so they can be tested by an audit rather than by
|
|
3
|
+
* a `*.test.ts` the project forbids.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here touches Firestore. `assertBalanced` and `buildReversal` are
|
|
6
|
+
* the two decisions that must never be wrong, and keeping them pure is what
|
|
7
|
+
* lets `verify-posting-rules.mjs` exercise them directly — the same shape as
|
|
8
|
+
* `verify-shipment-allocation-guard.mjs`, which reproduces a real failure
|
|
9
|
+
* against the real data shape and carries negative controls.
|
|
10
|
+
*/
|
|
11
|
+
import type { JournalLine, JournalSourceEvent } from "../../../../features/ledger/schemas/firestore";
|
|
12
|
+
/**
|
|
13
|
+
* `YYYY-MM` for a date, in the ONE place that derives it.
|
|
14
|
+
*
|
|
15
|
+
* 🛑 **LOCAL, not UTC, and the difference is a GST return.** A sale at 02:00
|
|
16
|
+
* IST on 1 November is 20:30 UTC on 31 October, so `getUTCMonth()` files it
|
|
17
|
+
* under the wrong month — and the month is exactly what a GSTR-1 period is.
|
|
18
|
+
* Every evening sale in India would land in the previous return.
|
|
19
|
+
*
|
|
20
|
+
* Local is correct because `vercel.json` pins functions to `bom1` and the
|
|
21
|
+
* Firebase region is `asia-south1`, so "local" IS IST on every server that
|
|
22
|
+
* runs this. It also matches `financialYearLabel`, which uses `getMonth()`
|
|
23
|
+
* for the same reason and whose boundary error would be unrecoverable —
|
|
24
|
+
* these two must agree or a March entry could sit in one FY and one period
|
|
25
|
+
* that disagree about which year it belongs to.
|
|
26
|
+
*
|
|
27
|
+
* 🛑 It therefore DISAGREES with nothing by accident but with
|
|
28
|
+
* `payPeriodFor`'s UTC-free local midnight by design — both are local; if
|
|
29
|
+
* either is ever moved to UTC, move both, and expect the invoice series to
|
|
30
|
+
* need the same treatment.
|
|
31
|
+
*/
|
|
32
|
+
export declare function periodOf(date: Date): string;
|
|
33
|
+
/**
|
|
34
|
+
* 🛑 Money comparison needs a TOLERANCE, and omitting one is the same bug
|
|
35
|
+
* Root Cause #92 cost a million invocations a day.
|
|
36
|
+
*
|
|
37
|
+
* Every leg here is a rupee amount with at most two decimals, and the
|
|
38
|
+
* arithmetic that produces them (a GST split, a pro-rata allocation) is
|
|
39
|
+
* floating point — `0.1 + 0.2 !== 0.3`. An exact `===` on the two totals
|
|
40
|
+
* would refuse a correct entry whose halves differ in the last bit, and the
|
|
41
|
+
* refusal would look like a posting-rule bug rather than a float.
|
|
42
|
+
*
|
|
43
|
+
* Half of the smallest representable unit (0.005): tight enough that a real
|
|
44
|
+
* 0.01 imbalance still fails, loose enough that no accumulation of
|
|
45
|
+
* two-decimal values can reach it.
|
|
46
|
+
*/
|
|
47
|
+
export declare const BALANCE_TOLERANCE = 0.005;
|
|
48
|
+
export interface PostingInput {
|
|
49
|
+
entryDate: Date;
|
|
50
|
+
sourceEvent: JournalSourceEvent;
|
|
51
|
+
sourceId?: string;
|
|
52
|
+
narration: string;
|
|
53
|
+
lines: JournalLine[];
|
|
54
|
+
}
|
|
55
|
+
export interface BalancedPosting extends PostingInput {
|
|
56
|
+
period: string;
|
|
57
|
+
totalDebit: number;
|
|
58
|
+
totalCredit: number;
|
|
59
|
+
}
|
|
60
|
+
export declare class UnbalancedEntryError extends Error {
|
|
61
|
+
constructor(message: string);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate a posting and compute its totals, or refuse it.
|
|
65
|
+
*
|
|
66
|
+
* 🛑 **Refuses rather than correcting.** A plausible repair — dropping a
|
|
67
|
+
* zero line, inferring the missing side from the difference — is how a wrong
|
|
68
|
+
* posting rule gets a correct-looking entry written for it, and the books
|
|
69
|
+
* then balance while saying something false. An unbalanced entry is always a
|
|
70
|
+
* bug in the rule that built it, and the only safe response is to not write.
|
|
71
|
+
*
|
|
72
|
+
* The five checks, each of which has a distinct failure it prevents:
|
|
73
|
+
*/
|
|
74
|
+
export declare function assertBalanced(input: PostingInput): BalancedPosting;
|
|
75
|
+
/**
|
|
76
|
+
* The reversing entry for a posting — every leg's sides swapped.
|
|
77
|
+
*
|
|
78
|
+
* 🛑 **Swapped, never negated.** `debit: -100` would balance arithmetically
|
|
79
|
+
* and is wrong in every other way: it breaks the non-negative rule above, it
|
|
80
|
+
* makes a trial balance sum to the right number through cancelling errors
|
|
81
|
+
* rather than through correct postings, and a ledger export to Tally would
|
|
82
|
+
* reject it. A credit of 100 against a debit of 100 is what a reversal IS.
|
|
83
|
+
*
|
|
84
|
+
* 🛑 **The reversal's `entryDate` is the CALLER's, not the original's.** A
|
|
85
|
+
* correction discovered in November for an October entry posts in November
|
|
86
|
+
* when October is locked — that is the whole point of the lock, and
|
|
87
|
+
* back-dating the reversal to the original would silently reopen a filed
|
|
88
|
+
* period. The link between them is `reversesEntryId`, not a shared date.
|
|
89
|
+
*/
|
|
90
|
+
export declare function buildReversal(original: {
|
|
91
|
+
id: string;
|
|
92
|
+
lines: JournalLine[];
|
|
93
|
+
narration: string;
|
|
94
|
+
}, at: Date, reason: string): PostingInput;
|
|
95
|
+
/**
|
|
96
|
+
* Where a late correction must post.
|
|
97
|
+
*
|
|
98
|
+
* 🛑 Returns the entry's OWN period when it is open, and the caller's
|
|
99
|
+
* fallback when it is not — it never silently moves a posting. A rule that
|
|
100
|
+
* quietly re-dated anything landing in a closed period would make the lock
|
|
101
|
+
* invisible, and the first anyone knew of it would be a GST return that no
|
|
102
|
+
* longer reconciles to the books it was filed from.
|
|
103
|
+
*/
|
|
104
|
+
export declare function resolvePostingPeriod(wanted: string, isLocked: (period: string) => boolean, openFallback: string): {
|
|
105
|
+
period: string;
|
|
106
|
+
deferred: boolean;
|
|
107
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The posting rules — pure, so they can be tested by an audit rather than by
|
|
3
|
+
* a `*.test.ts` the project forbids.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here touches Firestore. `assertBalanced` and `buildReversal` are
|
|
6
|
+
* the two decisions that must never be wrong, and keeping them pure is what
|
|
7
|
+
* lets `verify-posting-rules.mjs` exercise them directly — the same shape as
|
|
8
|
+
* `verify-shipment-allocation-guard.mjs`, which reproduces a real failure
|
|
9
|
+
* against the real data shape and carries negative controls.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* `YYYY-MM` for a date, in the ONE place that derives it.
|
|
13
|
+
*
|
|
14
|
+
* 🛑 **LOCAL, not UTC, and the difference is a GST return.** A sale at 02:00
|
|
15
|
+
* IST on 1 November is 20:30 UTC on 31 October, so `getUTCMonth()` files it
|
|
16
|
+
* under the wrong month — and the month is exactly what a GSTR-1 period is.
|
|
17
|
+
* Every evening sale in India would land in the previous return.
|
|
18
|
+
*
|
|
19
|
+
* Local is correct because `vercel.json` pins functions to `bom1` and the
|
|
20
|
+
* Firebase region is `asia-south1`, so "local" IS IST on every server that
|
|
21
|
+
* runs this. It also matches `financialYearLabel`, which uses `getMonth()`
|
|
22
|
+
* for the same reason and whose boundary error would be unrecoverable —
|
|
23
|
+
* these two must agree or a March entry could sit in one FY and one period
|
|
24
|
+
* that disagree about which year it belongs to.
|
|
25
|
+
*
|
|
26
|
+
* 🛑 It therefore DISAGREES with nothing by accident but with
|
|
27
|
+
* `payPeriodFor`'s UTC-free local midnight by design — both are local; if
|
|
28
|
+
* either is ever moved to UTC, move both, and expect the invoice series to
|
|
29
|
+
* need the same treatment.
|
|
30
|
+
*/
|
|
31
|
+
export function periodOf(date) {
|
|
32
|
+
const y = date.getFullYear();
|
|
33
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
34
|
+
return `${y}-${m}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 🛑 Money comparison needs a TOLERANCE, and omitting one is the same bug
|
|
38
|
+
* Root Cause #92 cost a million invocations a day.
|
|
39
|
+
*
|
|
40
|
+
* Every leg here is a rupee amount with at most two decimals, and the
|
|
41
|
+
* arithmetic that produces them (a GST split, a pro-rata allocation) is
|
|
42
|
+
* floating point — `0.1 + 0.2 !== 0.3`. An exact `===` on the two totals
|
|
43
|
+
* would refuse a correct entry whose halves differ in the last bit, and the
|
|
44
|
+
* refusal would look like a posting-rule bug rather than a float.
|
|
45
|
+
*
|
|
46
|
+
* Half of the smallest representable unit (0.005): tight enough that a real
|
|
47
|
+
* 0.01 imbalance still fails, loose enough that no accumulation of
|
|
48
|
+
* two-decimal values can reach it.
|
|
49
|
+
*/
|
|
50
|
+
export const BALANCE_TOLERANCE = 0.005;
|
|
51
|
+
export class UnbalancedEntryError extends Error {
|
|
52
|
+
constructor(message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.name = "UnbalancedEntryError";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate a posting and compute its totals, or refuse it.
|
|
59
|
+
*
|
|
60
|
+
* 🛑 **Refuses rather than correcting.** A plausible repair — dropping a
|
|
61
|
+
* zero line, inferring the missing side from the difference — is how a wrong
|
|
62
|
+
* posting rule gets a correct-looking entry written for it, and the books
|
|
63
|
+
* then balance while saying something false. An unbalanced entry is always a
|
|
64
|
+
* bug in the rule that built it, and the only safe response is to not write.
|
|
65
|
+
*
|
|
66
|
+
* The five checks, each of which has a distinct failure it prevents:
|
|
67
|
+
*/
|
|
68
|
+
export function assertBalanced(input) {
|
|
69
|
+
const { lines } = input;
|
|
70
|
+
// 1. A single-legged entry is not double entry. One line can never balance,
|
|
71
|
+
// and the commonest way to get one is a rule that forgot its credit.
|
|
72
|
+
if (lines.length < 2) {
|
|
73
|
+
throw new UnbalancedEntryError(`A journal entry needs at least two lines; got ${lines.length}.`);
|
|
74
|
+
}
|
|
75
|
+
let totalDebit = 0;
|
|
76
|
+
let totalCredit = 0;
|
|
77
|
+
for (const [i, line] of lines.entries()) {
|
|
78
|
+
const d = line.debit ?? 0;
|
|
79
|
+
const c = line.credit ?? 0;
|
|
80
|
+
// 2. NEGATIVE amounts are refused outright. A negative debit is a credit
|
|
81
|
+
// written the wrong way round, and allowing it means every report has
|
|
82
|
+
// to handle a sign it should never see — plus the two totals could
|
|
83
|
+
// then balance while both sides are nonsense.
|
|
84
|
+
if (d < 0 || c < 0) {
|
|
85
|
+
throw new UnbalancedEntryError(`Line ${i} (${line.accountCode}) has a negative amount. A reversal swaps the sides; it never negates them.`);
|
|
86
|
+
}
|
|
87
|
+
// 3. EXACTLY ONE SIDE per line. A line carrying both is ambiguous about
|
|
88
|
+
// what it asserts, and its net effect depends on a subtraction the
|
|
89
|
+
// reader has to perform — which is precisely what two separate fields
|
|
90
|
+
// exist to avoid.
|
|
91
|
+
if (d > 0 && c > 0) {
|
|
92
|
+
throw new UnbalancedEntryError(`Line ${i} (${line.accountCode}) carries both a debit and a credit. Split it into two lines.`);
|
|
93
|
+
}
|
|
94
|
+
// 4. A ZERO line asserts nothing and is almost always a rule that
|
|
95
|
+
// computed an amount it then failed to use.
|
|
96
|
+
if (d === 0 && c === 0) {
|
|
97
|
+
throw new UnbalancedEntryError(`Line ${i} (${line.accountCode}) is zero on both sides.`);
|
|
98
|
+
}
|
|
99
|
+
totalDebit += d;
|
|
100
|
+
totalCredit += c;
|
|
101
|
+
}
|
|
102
|
+
// 5. The accounting identity itself.
|
|
103
|
+
if (Math.abs(totalDebit - totalCredit) > BALANCE_TOLERANCE) {
|
|
104
|
+
throw new UnbalancedEntryError(`Entry does not balance: debits ${totalDebit.toFixed(2)} vs credits ${totalCredit.toFixed(2)}.`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
...input,
|
|
108
|
+
period: periodOf(input.entryDate),
|
|
109
|
+
/*
|
|
110
|
+
* Rounded to two decimals AFTER the comparison, not before. Rounding
|
|
111
|
+
* first would mask a genuine sub-unit imbalance by making both sides
|
|
112
|
+
* equal; rounding after records a figure a human can reconcile against
|
|
113
|
+
* a bank statement.
|
|
114
|
+
*/
|
|
115
|
+
totalDebit: Math.round(totalDebit * 100) / 100,
|
|
116
|
+
totalCredit: Math.round(totalCredit * 100) / 100,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The reversing entry for a posting — every leg's sides swapped.
|
|
121
|
+
*
|
|
122
|
+
* 🛑 **Swapped, never negated.** `debit: -100` would balance arithmetically
|
|
123
|
+
* and is wrong in every other way: it breaks the non-negative rule above, it
|
|
124
|
+
* makes a trial balance sum to the right number through cancelling errors
|
|
125
|
+
* rather than through correct postings, and a ledger export to Tally would
|
|
126
|
+
* reject it. A credit of 100 against a debit of 100 is what a reversal IS.
|
|
127
|
+
*
|
|
128
|
+
* 🛑 **The reversal's `entryDate` is the CALLER's, not the original's.** A
|
|
129
|
+
* correction discovered in November for an October entry posts in November
|
|
130
|
+
* when October is locked — that is the whole point of the lock, and
|
|
131
|
+
* back-dating the reversal to the original would silently reopen a filed
|
|
132
|
+
* period. The link between them is `reversesEntryId`, not a shared date.
|
|
133
|
+
*/
|
|
134
|
+
export function buildReversal(original, at, reason) {
|
|
135
|
+
return {
|
|
136
|
+
entryDate: at,
|
|
137
|
+
sourceEvent: "reversal",
|
|
138
|
+
sourceId: original.id,
|
|
139
|
+
narration: `Reversal of ${original.id}: ${reason}`,
|
|
140
|
+
lines: original.lines.map((l) => ({
|
|
141
|
+
accountCode: l.accountCode,
|
|
142
|
+
debit: l.credit,
|
|
143
|
+
credit: l.debit,
|
|
144
|
+
...(l.memo ? { memo: l.memo } : {}),
|
|
145
|
+
...(l.counterpartyId ? { counterpartyId: l.counterpartyId } : {}),
|
|
146
|
+
})),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Where a late correction must post.
|
|
151
|
+
*
|
|
152
|
+
* 🛑 Returns the entry's OWN period when it is open, and the caller's
|
|
153
|
+
* fallback when it is not — it never silently moves a posting. A rule that
|
|
154
|
+
* quietly re-dated anything landing in a closed period would make the lock
|
|
155
|
+
* invisible, and the first anyone knew of it would be a GST return that no
|
|
156
|
+
* longer reconciles to the books it was filed from.
|
|
157
|
+
*/
|
|
158
|
+
export function resolvePostingPeriod(wanted, isLocked, openFallback) {
|
|
159
|
+
if (!isLocked(wanted))
|
|
160
|
+
return { period: wanted, deferred: false };
|
|
161
|
+
if (isLocked(openFallback)) {
|
|
162
|
+
throw new UnbalancedEntryError(`Both ${wanted} and the fallback period ${openFallback} are locked; there is nowhere to post.`);
|
|
163
|
+
}
|
|
164
|
+
return { period: openFallback, deferred: true };
|
|
165
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trial balance and P&L — derived views, pure, so the audit can exercise them.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 These are REPORTS, not truth, and they carry the disclaimer
|
|
5
|
+
*
|
|
6
|
+
* Phase 12's `accounting-output` label applies to every figure produced
|
|
7
|
+
* here. The ledger is already a projection of orders and payouts; a report
|
|
8
|
+
* is a projection of the ledger. Nobody files a return from this without a
|
|
9
|
+
* CA reading it, and the label is what stops the number being treated as
|
|
10
|
+
* though they had.
|
|
11
|
+
*
|
|
12
|
+
* ## 🛑 Signs are applied ONCE, at the boundary
|
|
13
|
+
*
|
|
14
|
+
* A trial balance lists raw debit and credit totals per account, which is
|
|
15
|
+
* what makes it a check: the two columns must agree, and that is only
|
|
16
|
+
* meaningful if nothing has been netted on the way. The P&L is where a
|
|
17
|
+
* normal-balance sign is applied, and it is applied in exactly one place
|
|
18
|
+
* (`signedBalance`) so an income account can never be summed as though it
|
|
19
|
+
* were an expense.
|
|
20
|
+
*/
|
|
21
|
+
import type { AccountType, JournalEntryDocument, JournalLine } from "../../../../features/ledger/schemas/firestore";
|
|
22
|
+
/** Which side increases this type. Duplicated from the schema's own helper? No — see below. */
|
|
23
|
+
type Side = "debit" | "credit";
|
|
24
|
+
export interface AccountTotals {
|
|
25
|
+
accountCode: string;
|
|
26
|
+
debit: number;
|
|
27
|
+
credit: number;
|
|
28
|
+
}
|
|
29
|
+
export interface TrialBalance {
|
|
30
|
+
period: string;
|
|
31
|
+
rows: AccountTotals[];
|
|
32
|
+
totalDebit: number;
|
|
33
|
+
totalCredit: number;
|
|
34
|
+
/** The identity. False means an entry was written outside `post()`. */
|
|
35
|
+
balanced: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Propagated from the read that produced it.
|
|
38
|
+
*
|
|
39
|
+
* 🛑 A truncated trial balance BALANCES — both columns lose the same
|
|
40
|
+
* entries — so `balanced: true` with `truncated: true` says nothing at
|
|
41
|
+
* all. A caller that renders the first and ignores the second is showing
|
|
42
|
+
* a reconciliation that did not happen.
|
|
43
|
+
*/
|
|
44
|
+
truncated: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Sum every line by account. Raw columns, nothing netted. */
|
|
47
|
+
export declare function trialBalance(period: string, entries: readonly JournalEntryDocument[], truncated?: boolean): TrialBalance;
|
|
48
|
+
/**
|
|
49
|
+
* The net movement on an account, signed by its normal balance.
|
|
50
|
+
*
|
|
51
|
+
* 🛑 The ONE place a sign is applied. An income account with ₹1,000 credited
|
|
52
|
+
* and ₹100 debited has earned ₹900; the same raw figures on an expense
|
|
53
|
+
* account are a ₹900 loss in the other direction. Applying this per call
|
|
54
|
+
* site is how one of the two gets inverted and a P&L reads profitable.
|
|
55
|
+
*/
|
|
56
|
+
export declare function signedBalance(type: AccountType, totals: AccountTotals): number;
|
|
57
|
+
export interface ProfitAndLoss {
|
|
58
|
+
period: string;
|
|
59
|
+
income: number;
|
|
60
|
+
expenses: number;
|
|
61
|
+
net: number;
|
|
62
|
+
truncated: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Income less expenses for a period.
|
|
66
|
+
*
|
|
67
|
+
* 🛑 Needs the account TYPES, which it takes as a map rather than inferring
|
|
68
|
+
* from the code's leading digit. The range convention is for humans (see the
|
|
69
|
+
* chart's own header); inferring from it makes the first out-of-range
|
|
70
|
+
* account silently land in the wrong half of the P&L, and the total would
|
|
71
|
+
* still look plausible.
|
|
72
|
+
*/
|
|
73
|
+
export declare function profitAndLoss(tb: TrialBalance, typeOf: (accountCode: string) => AccountType | undefined): ProfitAndLoss;
|
|
74
|
+
/** Re-exported for the audit, which checks the two mappings agree. */
|
|
75
|
+
export declare const NORMAL_SIDE_TABLE: Readonly<Record<AccountType, Side>>;
|
|
76
|
+
export type { JournalLine };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trial balance and P&L — derived views, pure, so the audit can exercise them.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 These are REPORTS, not truth, and they carry the disclaimer
|
|
5
|
+
*
|
|
6
|
+
* Phase 12's `accounting-output` label applies to every figure produced
|
|
7
|
+
* here. The ledger is already a projection of orders and payouts; a report
|
|
8
|
+
* is a projection of the ledger. Nobody files a return from this without a
|
|
9
|
+
* CA reading it, and the label is what stops the number being treated as
|
|
10
|
+
* though they had.
|
|
11
|
+
*
|
|
12
|
+
* ## 🛑 Signs are applied ONCE, at the boundary
|
|
13
|
+
*
|
|
14
|
+
* A trial balance lists raw debit and credit totals per account, which is
|
|
15
|
+
* what makes it a check: the two columns must agree, and that is only
|
|
16
|
+
* meaningful if nothing has been netted on the way. The P&L is where a
|
|
17
|
+
* normal-balance sign is applied, and it is applied in exactly one place
|
|
18
|
+
* (`signedBalance`) so an income account can never be summed as though it
|
|
19
|
+
* were an expense.
|
|
20
|
+
*/
|
|
21
|
+
/*
|
|
22
|
+
* 🛑 `normalBalanceFor` lives on the SCHEMA and is not imported here, for the
|
|
23
|
+
* same mechanical reason `periodOf` moved out of it: `verify-posting-rules`
|
|
24
|
+
* loads these modules through Node's type stripping, which erases
|
|
25
|
+
* `import type` but cannot resolve a runtime import against extensionless
|
|
26
|
+
* appkit source.
|
|
27
|
+
*
|
|
28
|
+
* So this is NOT a second definition — the table below is the same mapping,
|
|
29
|
+
* and the schema's function is what application code calls. Two copies of a
|
|
30
|
+
* rule is Root Cause #42, and the honest mitigation is that `R6` in the
|
|
31
|
+
* audit asserts they agree for all five types rather than trusting a
|
|
32
|
+
* comment to keep them in step.
|
|
33
|
+
*/
|
|
34
|
+
const NORMAL_SIDE = {
|
|
35
|
+
asset: "debit",
|
|
36
|
+
expense: "debit",
|
|
37
|
+
liability: "credit",
|
|
38
|
+
equity: "credit",
|
|
39
|
+
income: "credit",
|
|
40
|
+
};
|
|
41
|
+
/** Sum every line by account. Raw columns, nothing netted. */
|
|
42
|
+
export function trialBalance(period, entries, truncated = false) {
|
|
43
|
+
const byAccount = new Map();
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
for (const line of entry.lines) {
|
|
46
|
+
const row = byAccount.get(line.accountCode) ??
|
|
47
|
+
{ accountCode: line.accountCode, debit: 0, credit: 0 };
|
|
48
|
+
row.debit += line.debit ?? 0;
|
|
49
|
+
row.credit += line.credit ?? 0;
|
|
50
|
+
byAccount.set(line.accountCode, row);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const rows = [...byAccount.values()]
|
|
54
|
+
.map((r) => ({
|
|
55
|
+
accountCode: r.accountCode,
|
|
56
|
+
debit: round2(r.debit),
|
|
57
|
+
credit: round2(r.credit),
|
|
58
|
+
}))
|
|
59
|
+
.sort((a, b) => a.accountCode.localeCompare(b.accountCode));
|
|
60
|
+
const totalDebit = round2(rows.reduce((s, r) => s + r.debit, 0));
|
|
61
|
+
const totalCredit = round2(rows.reduce((s, r) => s + r.credit, 0));
|
|
62
|
+
return {
|
|
63
|
+
period,
|
|
64
|
+
rows,
|
|
65
|
+
totalDebit,
|
|
66
|
+
totalCredit,
|
|
67
|
+
/*
|
|
68
|
+
* 🛑 Compared with the SAME tolerance the posting rules use. A trial
|
|
69
|
+
* balance stricter than the gate that wrote the entries would report an
|
|
70
|
+
* imbalance nobody can act on — every entry in it passed `assertBalanced`.
|
|
71
|
+
*/
|
|
72
|
+
balanced: Math.abs(totalDebit - totalCredit) <= 0.005,
|
|
73
|
+
truncated,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The net movement on an account, signed by its normal balance.
|
|
78
|
+
*
|
|
79
|
+
* 🛑 The ONE place a sign is applied. An income account with ₹1,000 credited
|
|
80
|
+
* and ₹100 debited has earned ₹900; the same raw figures on an expense
|
|
81
|
+
* account are a ₹900 loss in the other direction. Applying this per call
|
|
82
|
+
* site is how one of the two gets inverted and a P&L reads profitable.
|
|
83
|
+
*/
|
|
84
|
+
export function signedBalance(type, totals) {
|
|
85
|
+
return NORMAL_SIDE[type] === "debit"
|
|
86
|
+
? round2(totals.debit - totals.credit)
|
|
87
|
+
: round2(totals.credit - totals.debit);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Income less expenses for a period.
|
|
91
|
+
*
|
|
92
|
+
* 🛑 Needs the account TYPES, which it takes as a map rather than inferring
|
|
93
|
+
* from the code's leading digit. The range convention is for humans (see the
|
|
94
|
+
* chart's own header); inferring from it makes the first out-of-range
|
|
95
|
+
* account silently land in the wrong half of the P&L, and the total would
|
|
96
|
+
* still look plausible.
|
|
97
|
+
*/
|
|
98
|
+
export function profitAndLoss(tb, typeOf) {
|
|
99
|
+
let income = 0;
|
|
100
|
+
let expenses = 0;
|
|
101
|
+
for (const row of tb.rows) {
|
|
102
|
+
const type = typeOf(row.accountCode);
|
|
103
|
+
/*
|
|
104
|
+
* 🛑 An UNKNOWN account is skipped and that is why `truncated` is not
|
|
105
|
+
* the only honesty flag this needs — but it is the behaviour with the
|
|
106
|
+
* least bad failure: including it would need a guessed type, and a
|
|
107
|
+
* guessed type puts real money on the wrong side. An account code with
|
|
108
|
+
* no account is a `chartOfAccounts` wipe (the orphan case its
|
|
109
|
+
* `seedPurpose: "permanent"` exists to prevent), and the trial balance
|
|
110
|
+
* above still shows the row, so the discrepancy is visible there.
|
|
111
|
+
*/
|
|
112
|
+
if (!type)
|
|
113
|
+
continue;
|
|
114
|
+
if (type === "income")
|
|
115
|
+
income += signedBalance(type, row);
|
|
116
|
+
else if (type === "expense")
|
|
117
|
+
expenses += signedBalance(type, row);
|
|
118
|
+
}
|
|
119
|
+
income = round2(income);
|
|
120
|
+
expenses = round2(expenses);
|
|
121
|
+
return { period: tb.period, income, expenses, net: round2(income - expenses), truncated: tb.truncated };
|
|
122
|
+
}
|
|
123
|
+
function round2(n) {
|
|
124
|
+
return Math.round(n * 100) / 100;
|
|
125
|
+
}
|
|
126
|
+
/** Re-exported for the audit, which checks the two mappings agree. */
|
|
127
|
+
export const NORMAL_SIDE_TABLE = NORMAL_SIDE;
|