@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,110 @@
|
|
|
1
|
+
import { BaseRepository } from "../../../providers/db-firebase";
|
|
2
|
+
import { type JournalEntryDocument } from "../schemas/firestore";
|
|
3
|
+
import { type PostingInput } from "../../../_internal/shared/features/ledger/posting";
|
|
4
|
+
/**
|
|
5
|
+
* How many entries one period read may return.
|
|
6
|
+
*
|
|
7
|
+
* Sized against a plausible month rather than a round number: a few hundred
|
|
8
|
+
* orders, each posting two or three entries, plus settlements and expenses.
|
|
9
|
+
* 2,000 leaves real headroom and still fits comfortably inside a function's
|
|
10
|
+
* memory and the ~3-round-trip budget.
|
|
11
|
+
*/
|
|
12
|
+
export declare const JOURNAL_PERIOD_SCAN_LIMIT = 2000;
|
|
13
|
+
export declare class JournalRepository extends BaseRepository<JournalEntryDocument> {
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* 🛑 APPEND-ONLY, and the method bodies refuse rather than a comment
|
|
17
|
+
* asking nicely.
|
|
18
|
+
*
|
|
19
|
+
* `inventoryMovements` takes the same stance for the same reason: a
|
|
20
|
+
* Firestore update succeeds silently, so a caller who edits history never
|
|
21
|
+
* finds out, and a ledger whose rows can be edited cannot be used as
|
|
22
|
+
* evidence of anything. The correction mechanism is `reverse()`.
|
|
23
|
+
*/
|
|
24
|
+
update(): Promise<never>;
|
|
25
|
+
delete(): Promise<never>;
|
|
26
|
+
/**
|
|
27
|
+
* Post one entry.
|
|
28
|
+
*
|
|
29
|
+
* 🛑 **The balance check and the lock check are INSIDE the transaction.**
|
|
30
|
+
* Reading the period's state first and writing after is a TOCTOU window: an
|
|
31
|
+
* admin filing a return between the two gets an entry in the period they
|
|
32
|
+
* just closed, which is the one outcome the lock exists to prevent. It is a
|
|
33
|
+
* narrow window and it is exactly the kind that shows up once, in the
|
|
34
|
+
* quarter it matters.
|
|
35
|
+
*/
|
|
36
|
+
post(input: PostingInput): Promise<JournalEntryDocument>;
|
|
37
|
+
/**
|
|
38
|
+
* Reverse an entry.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 **Refuses a SECOND reversal of the same entry.** Without the check a
|
|
41
|
+
* double-click posts the opposite legs twice, and the books then show the
|
|
42
|
+
* original plus two reversals — a net position that is the mirror image of
|
|
43
|
+
* the truth, balanced, and wrong. `reversedByEntryId` is set inside the
|
|
44
|
+
* same transaction that reads it, so the second attempt loses the race
|
|
45
|
+
* rather than both succeeding.
|
|
46
|
+
*/
|
|
47
|
+
reverse(entryId: string, reason: string, at?: Date): Promise<JournalEntryDocument>;
|
|
48
|
+
/**
|
|
49
|
+
* Close a period.
|
|
50
|
+
*
|
|
51
|
+
* 🛑 Takes the reason and the actor, both required. "Who closed October
|
|
52
|
+
* and under which return" is the first question anyone asks when a figure
|
|
53
|
+
* disagrees with a filing, and a lock with no answer to it is a lock
|
|
54
|
+
* somebody will simply reopen.
|
|
55
|
+
*/
|
|
56
|
+
lockPeriod(period: string, lockedByUid: string, lockedReason: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* 🛑 There is deliberately NO `unlockPeriod`.
|
|
59
|
+
*
|
|
60
|
+
* Reopening a period a return was filed from is not an operation the
|
|
61
|
+
* system should make easy — the correct response to a late correction is a
|
|
62
|
+
* reversing entry in the OPEN period, which is what `resolvePostingPeriod`
|
|
63
|
+
* computes and what every accountant expects. If a period genuinely must
|
|
64
|
+
* be reopened (a return withdrawn, say), that is a deliberate act with a
|
|
65
|
+
* paper trail outside this system, and a console write is the right amount
|
|
66
|
+
* of friction for it.
|
|
67
|
+
*
|
|
68
|
+
* This method exists only to say so. Deleting it would leave the absence
|
|
69
|
+
* looking like an oversight somebody helpfully fills in.
|
|
70
|
+
*/
|
|
71
|
+
/**
|
|
72
|
+
* Every entry in a period, for a trial balance or a return.
|
|
73
|
+
*
|
|
74
|
+
* 🛑 **BOUNDED, and truncation is REPORTED rather than silent.** An
|
|
75
|
+
* unbounded read is the Rule #6 violation, but the reason it matters here
|
|
76
|
+
* is sharper than cost: a trial balance computed from a silently truncated
|
|
77
|
+
* page is a trial balance that BALANCES — both sides lose the same
|
|
78
|
+
* entries — while being wrong. It would look perfect and reconcile to
|
|
79
|
+
* nothing.
|
|
80
|
+
*
|
|
81
|
+
* So `truncated` is part of the return type and callers must handle it.
|
|
82
|
+
* The same stance `listPublicProducts` takes with its own `truncated`
|
|
83
|
+
* flag: a floor rendered as "50+", never a figure presented as a total.
|
|
84
|
+
*
|
|
85
|
+
* The real answer at volume is a period rollup written by a scheduled job
|
|
86
|
+
* — the `revenueRollup` pattern — and this is deliberately NOT that, so
|
|
87
|
+
* the flag is what forces the question rather than hiding it.
|
|
88
|
+
*/
|
|
89
|
+
listByPeriod(period: string, limit?: number): Promise<{
|
|
90
|
+
entries: JournalEntryDocument[];
|
|
91
|
+
truncated: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
/** Whether a period is closed. Absence means open — see `post`. */
|
|
94
|
+
isPeriodLocked(period: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* The cutover entry.
|
|
97
|
+
*
|
|
98
|
+
* 🛑 **NOT a backfill.** Pre-cutover data here is seeded and test, so
|
|
99
|
+
* replaying it would post fixtures as trade — the first financial year is
|
|
100
|
+
* therefore split across the old rollups and this ledger, and the
|
|
101
|
+
* "pre-ledger estimate" label on the old reports is what keeps that
|
|
102
|
+
* honest rather than hiding it.
|
|
103
|
+
*
|
|
104
|
+
* 🛑 Refuses to run twice. An opening balance posted a second time doubles
|
|
105
|
+
* every starting figure, and because both entries balance nothing
|
|
106
|
+
* downstream would object.
|
|
107
|
+
*/
|
|
108
|
+
postOpeningBalances(at: Date, lines: PostingInput["lines"]): Promise<JournalEntryDocument>;
|
|
109
|
+
}
|
|
110
|
+
export declare const journalRepository: JournalRepository;
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: The only write path into the books. Every rule that makes a ledger
|
|
3
|
+
* trustworthy — balanced, append-only, period-locked — is enforced here
|
|
4
|
+
* rather than asked of callers, because a caller who gets one wrong
|
|
5
|
+
* produces a successful write and finds out at the next GST return.
|
|
6
|
+
*
|
|
7
|
+
* WHAT: JournalRepository — post, reverse, lock, read.
|
|
8
|
+
*
|
|
9
|
+
* @tag domain:ledger,finance
|
|
10
|
+
* @tag layer:repository
|
|
11
|
+
* @tag access:server
|
|
12
|
+
* @tag sideEffects:firestore
|
|
13
|
+
*/
|
|
14
|
+
/* The DIRECTORY barrel, which is where every other repository gets this
|
|
15
|
+
* from — `providers/db-firebase/base` exports only `FirebaseRepository`,
|
|
16
|
+
* and `BaseRepository` (the one with `this.db` and `mapDoc`) is composed
|
|
17
|
+
* one level up. */
|
|
18
|
+
import { BaseRepository } from "../../../providers/db-firebase/index.js";
|
|
19
|
+
import { unitOfWork } from "../../../core/unit-of-work.js";
|
|
20
|
+
import { JOURNAL_ENTRIES_COLLECTION, ACCOUNTING_PERIODS_COLLECTION, LEDGER_FIELDS, } from "../schemas/firestore.js";
|
|
21
|
+
import { assertBalanced, buildReversal, periodOf, UnbalancedEntryError, } from "../../../_internal/shared/features/ledger/posting.js";
|
|
22
|
+
import { NotFoundError } from "../../../errors/not-found-error.js";
|
|
23
|
+
import { ValidationError } from "../../../errors/validation-error.js";
|
|
24
|
+
/**
|
|
25
|
+
* How many entries one period read may return.
|
|
26
|
+
*
|
|
27
|
+
* Sized against a plausible month rather than a round number: a few hundred
|
|
28
|
+
* orders, each posting two or three entries, plus settlements and expenses.
|
|
29
|
+
* 2,000 leaves real headroom and still fits comfortably inside a function's
|
|
30
|
+
* memory and the ~3-round-trip budget.
|
|
31
|
+
*/
|
|
32
|
+
export const JOURNAL_PERIOD_SCAN_LIMIT = 2000;
|
|
33
|
+
export class JournalRepository extends BaseRepository {
|
|
34
|
+
/*
|
|
35
|
+
* 🛑 NO `SIEVE_FIELDS`, same reasoning as `obligations`. The reports read
|
|
36
|
+
* by period and by account code — two fixed shapes, both served by the
|
|
37
|
+
* automatic index — and an admin looking at a figure opens the ORDER it
|
|
38
|
+
* came from, not a filtered journal list. A Sieve surface nothing calls is
|
|
39
|
+
* the `route-schema-registry` pattern: 576 keys into a layer with no
|
|
40
|
+
* readers.
|
|
41
|
+
*/
|
|
42
|
+
constructor() {
|
|
43
|
+
super(JOURNAL_ENTRIES_COLLECTION);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 🛑 APPEND-ONLY, and the method bodies refuse rather than a comment
|
|
47
|
+
* asking nicely.
|
|
48
|
+
*
|
|
49
|
+
* `inventoryMovements` takes the same stance for the same reason: a
|
|
50
|
+
* Firestore update succeeds silently, so a caller who edits history never
|
|
51
|
+
* finds out, and a ledger whose rows can be edited cannot be used as
|
|
52
|
+
* evidence of anything. The correction mechanism is `reverse()`.
|
|
53
|
+
*/
|
|
54
|
+
async update() {
|
|
55
|
+
throw new Error("journalEntries is append-only. Correct an entry with reverse(), which posts the opposite legs and links the two — an edit would silently rewrite a period a GST return may already have been filed from.");
|
|
56
|
+
}
|
|
57
|
+
async delete() {
|
|
58
|
+
throw new Error("journalEntries is append-only. An entry that should not have been posted is reversed, not removed; the reversal is the record that it was wrong.");
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Post one entry.
|
|
62
|
+
*
|
|
63
|
+
* 🛑 **The balance check and the lock check are INSIDE the transaction.**
|
|
64
|
+
* Reading the period's state first and writing after is a TOCTOU window: an
|
|
65
|
+
* admin filing a return between the two gets an entry in the period they
|
|
66
|
+
* just closed, which is the one outcome the lock exists to prevent. It is a
|
|
67
|
+
* narrow window and it is exactly the kind that shows up once, in the
|
|
68
|
+
* quarter it matters.
|
|
69
|
+
*/
|
|
70
|
+
async post(input) {
|
|
71
|
+
const balanced = assertBalanced(input);
|
|
72
|
+
return unitOfWork.runTransaction(async (tx) => {
|
|
73
|
+
const db = this.db;
|
|
74
|
+
const periodRef = db
|
|
75
|
+
.collection(ACCOUNTING_PERIODS_COLLECTION)
|
|
76
|
+
.doc(`period-${balanced.period}`);
|
|
77
|
+
const snap = await tx.get(periodRef);
|
|
78
|
+
const period = snap.exists ? snap.data() : null;
|
|
79
|
+
/*
|
|
80
|
+
* 🛑 A period with NO row is OPEN, not closed.
|
|
81
|
+
*
|
|
82
|
+
* Fail-open here and fail-closed everywhere else is deliberate: a
|
|
83
|
+
* period is closed by someone filing a return, which is an action that
|
|
84
|
+
* writes a row. Treating absence as closed would mean the books refuse
|
|
85
|
+
* every posting until an admin opens each month by hand — and the
|
|
86
|
+
* first missed month silently stops the entire ingest, which looks
|
|
87
|
+
* like a broken job rather than a missing row.
|
|
88
|
+
*/
|
|
89
|
+
if (period?.status === "locked") {
|
|
90
|
+
throw new ValidationError(`Period ${balanced.period} is closed and cannot accept new entries.`, {
|
|
91
|
+
period: period.lockedReason ??
|
|
92
|
+
"A return has been filed for this period. Post the correction to the open period instead.",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const ref = db.collection(JOURNAL_ENTRIES_COLLECTION).doc();
|
|
96
|
+
const now = new Date();
|
|
97
|
+
const doc = {
|
|
98
|
+
...balanced,
|
|
99
|
+
id: ref.id,
|
|
100
|
+
createdAt: now,
|
|
101
|
+
updatedAt: now,
|
|
102
|
+
};
|
|
103
|
+
tx.set(ref, doc);
|
|
104
|
+
return doc;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Reverse an entry.
|
|
109
|
+
*
|
|
110
|
+
* 🛑 **Refuses a SECOND reversal of the same entry.** Without the check a
|
|
111
|
+
* double-click posts the opposite legs twice, and the books then show the
|
|
112
|
+
* original plus two reversals — a net position that is the mirror image of
|
|
113
|
+
* the truth, balanced, and wrong. `reversedByEntryId` is set inside the
|
|
114
|
+
* same transaction that reads it, so the second attempt loses the race
|
|
115
|
+
* rather than both succeeding.
|
|
116
|
+
*/
|
|
117
|
+
async reverse(entryId, reason, at = new Date()) {
|
|
118
|
+
if (!reason.trim()) {
|
|
119
|
+
/*
|
|
120
|
+
* A reversal with no stated reason is the one thing a reader of the
|
|
121
|
+
* books cannot reconstruct later. The original entry says what was
|
|
122
|
+
* posted; only this says why it was wrong.
|
|
123
|
+
*/
|
|
124
|
+
throw new ValidationError("A reversal needs a reason.", {
|
|
125
|
+
reason: "Say what was wrong with the original entry.",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return unitOfWork.runTransaction(async (tx) => {
|
|
129
|
+
const db = this.db;
|
|
130
|
+
const originalRef = db.collection(JOURNAL_ENTRIES_COLLECTION).doc(entryId);
|
|
131
|
+
const snap = await tx.get(originalRef);
|
|
132
|
+
if (!snap.exists)
|
|
133
|
+
throw new NotFoundError(`Journal entry ${entryId} not found.`);
|
|
134
|
+
const original = snap.data();
|
|
135
|
+
if (original.reversedByEntryId) {
|
|
136
|
+
throw new ValidationError(`Entry ${entryId} has already been reversed by ${original.reversedByEntryId}.`, { entryId: "Reversing it again would double the correction." });
|
|
137
|
+
}
|
|
138
|
+
if (original.sourceEvent === "reversal") {
|
|
139
|
+
/*
|
|
140
|
+
* Reversing a reversal is re-instating the original, and saying so
|
|
141
|
+
* is clearer than letting someone build a chain nobody can read. If
|
|
142
|
+
* the original was right after all, post it again with a narration
|
|
143
|
+
* that says why.
|
|
144
|
+
*/
|
|
145
|
+
throw new ValidationError(`Entry ${entryId} is itself a reversal.`, { entryId: "To re-instate the original, post it again with a narration explaining why." });
|
|
146
|
+
}
|
|
147
|
+
const reversalInput = buildReversal({ id: entryId, lines: original.lines, narration: original.narration }, at, reason.trim());
|
|
148
|
+
const balanced = assertBalanced(reversalInput);
|
|
149
|
+
/*
|
|
150
|
+
* The reversal's OWN period must be open. It is `at`'s period, not the
|
|
151
|
+
* original's — see `buildReversal`, which deliberately does not
|
|
152
|
+
* back-date. A correction found after a return was filed posts to the
|
|
153
|
+
* open month and references the closed one.
|
|
154
|
+
*/
|
|
155
|
+
const periodRef = db
|
|
156
|
+
.collection(ACCOUNTING_PERIODS_COLLECTION)
|
|
157
|
+
.doc(`period-${balanced.period}`);
|
|
158
|
+
const periodSnap = await tx.get(periodRef);
|
|
159
|
+
const period = periodSnap.exists
|
|
160
|
+
? periodSnap.data()
|
|
161
|
+
: null;
|
|
162
|
+
if (period?.status === "locked") {
|
|
163
|
+
throw new ValidationError(`Period ${balanced.period} is closed, so the correction has nowhere to post.`, { period: "Open the current period before reversing." });
|
|
164
|
+
}
|
|
165
|
+
const ref = db.collection(JOURNAL_ENTRIES_COLLECTION).doc();
|
|
166
|
+
const now = new Date();
|
|
167
|
+
const reversal = {
|
|
168
|
+
...balanced,
|
|
169
|
+
id: ref.id,
|
|
170
|
+
reversesEntryId: entryId,
|
|
171
|
+
createdAt: now,
|
|
172
|
+
updatedAt: now,
|
|
173
|
+
};
|
|
174
|
+
tx.set(ref, reversal);
|
|
175
|
+
/*
|
|
176
|
+
* 🛑 The back-link is written with `tx.update` on the ORIGINAL, which
|
|
177
|
+
* is the one edit to a posted entry this class permits — and it adds a
|
|
178
|
+
* pointer rather than changing a figure. Without it `reverse()` has no
|
|
179
|
+
* way to refuse a second attempt, and nothing reading the original can
|
|
180
|
+
* tell it has been corrected.
|
|
181
|
+
*/
|
|
182
|
+
tx.update(originalRef, { reversedByEntryId: ref.id, updatedAt: now });
|
|
183
|
+
return reversal;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Close a period.
|
|
188
|
+
*
|
|
189
|
+
* 🛑 Takes the reason and the actor, both required. "Who closed October
|
|
190
|
+
* and under which return" is the first question anyone asks when a figure
|
|
191
|
+
* disagrees with a filing, and a lock with no answer to it is a lock
|
|
192
|
+
* somebody will simply reopen.
|
|
193
|
+
*/
|
|
194
|
+
async lockPeriod(period, lockedByUid, lockedReason) {
|
|
195
|
+
if (!/^\d{4}-\d{2}$/.test(period)) {
|
|
196
|
+
throw new ValidationError(`"${period}" is not a YYYY-MM period.`, {
|
|
197
|
+
period: "Expected a month such as 2026-10.",
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (!lockedReason.trim()) {
|
|
201
|
+
throw new ValidationError("Closing a period needs a reason.", {
|
|
202
|
+
lockedReason: "Name the return this period was filed under.",
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
await unitOfWork.runTransaction(async (tx) => {
|
|
206
|
+
const db = this.db;
|
|
207
|
+
const ref = db.collection(ACCOUNTING_PERIODS_COLLECTION).doc(`period-${period}`);
|
|
208
|
+
const snap = await tx.get(ref);
|
|
209
|
+
if (snap.data()?.status === "locked") {
|
|
210
|
+
/*
|
|
211
|
+
* Idempotent rather than an error: a retried request must not read
|
|
212
|
+
* as a failure, and re-closing a closed period changes nothing.
|
|
213
|
+
*/
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const now = new Date();
|
|
217
|
+
tx.set(ref, {
|
|
218
|
+
id: `period-${period}`,
|
|
219
|
+
period,
|
|
220
|
+
status: "locked",
|
|
221
|
+
lockedReason: lockedReason.trim(),
|
|
222
|
+
lockedAt: now,
|
|
223
|
+
lockedByUid,
|
|
224
|
+
createdAt: now,
|
|
225
|
+
updatedAt: now,
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 🛑 There is deliberately NO `unlockPeriod`.
|
|
231
|
+
*
|
|
232
|
+
* Reopening a period a return was filed from is not an operation the
|
|
233
|
+
* system should make easy — the correct response to a late correction is a
|
|
234
|
+
* reversing entry in the OPEN period, which is what `resolvePostingPeriod`
|
|
235
|
+
* computes and what every accountant expects. If a period genuinely must
|
|
236
|
+
* be reopened (a return withdrawn, say), that is a deliberate act with a
|
|
237
|
+
* paper trail outside this system, and a console write is the right amount
|
|
238
|
+
* of friction for it.
|
|
239
|
+
*
|
|
240
|
+
* This method exists only to say so. Deleting it would leave the absence
|
|
241
|
+
* looking like an oversight somebody helpfully fills in.
|
|
242
|
+
*/
|
|
243
|
+
/**
|
|
244
|
+
* Every entry in a period, for a trial balance or a return.
|
|
245
|
+
*
|
|
246
|
+
* 🛑 **BOUNDED, and truncation is REPORTED rather than silent.** An
|
|
247
|
+
* unbounded read is the Rule #6 violation, but the reason it matters here
|
|
248
|
+
* is sharper than cost: a trial balance computed from a silently truncated
|
|
249
|
+
* page is a trial balance that BALANCES — both sides lose the same
|
|
250
|
+
* entries — while being wrong. It would look perfect and reconcile to
|
|
251
|
+
* nothing.
|
|
252
|
+
*
|
|
253
|
+
* So `truncated` is part of the return type and callers must handle it.
|
|
254
|
+
* The same stance `listPublicProducts` takes with its own `truncated`
|
|
255
|
+
* flag: a floor rendered as "50+", never a figure presented as a total.
|
|
256
|
+
*
|
|
257
|
+
* The real answer at volume is a period rollup written by a scheduled job
|
|
258
|
+
* — the `revenueRollup` pattern — and this is deliberately NOT that, so
|
|
259
|
+
* the flag is what forces the question rather than hiding it.
|
|
260
|
+
*/
|
|
261
|
+
async listByPeriod(period, limit = JOURNAL_PERIOD_SCAN_LIMIT) {
|
|
262
|
+
const snap = await this.db
|
|
263
|
+
.collection(JOURNAL_ENTRIES_COLLECTION)
|
|
264
|
+
.where(LEDGER_FIELDS.PERIOD, "==", period)
|
|
265
|
+
.orderBy(LEDGER_FIELDS.ENTRY_DATE)
|
|
266
|
+
.limit(limit + 1)
|
|
267
|
+
.get();
|
|
268
|
+
const docs = snap.docs.slice(0, limit);
|
|
269
|
+
return {
|
|
270
|
+
entries: docs.map((d) => this.mapDoc(d)),
|
|
271
|
+
truncated: snap.docs.length > limit,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/** Whether a period is closed. Absence means open — see `post`. */
|
|
275
|
+
async isPeriodLocked(period) {
|
|
276
|
+
const snap = await this.db
|
|
277
|
+
.collection(ACCOUNTING_PERIODS_COLLECTION)
|
|
278
|
+
.doc(`period-${period}`)
|
|
279
|
+
.get();
|
|
280
|
+
return snap.data()?.status === "locked";
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* The cutover entry.
|
|
284
|
+
*
|
|
285
|
+
* 🛑 **NOT a backfill.** Pre-cutover data here is seeded and test, so
|
|
286
|
+
* replaying it would post fixtures as trade — the first financial year is
|
|
287
|
+
* therefore split across the old rollups and this ledger, and the
|
|
288
|
+
* "pre-ledger estimate" label on the old reports is what keeps that
|
|
289
|
+
* honest rather than hiding it.
|
|
290
|
+
*
|
|
291
|
+
* 🛑 Refuses to run twice. An opening balance posted a second time doubles
|
|
292
|
+
* every starting figure, and because both entries balance nothing
|
|
293
|
+
* downstream would object.
|
|
294
|
+
*/
|
|
295
|
+
async postOpeningBalances(at, lines) {
|
|
296
|
+
const existing = await this.db
|
|
297
|
+
.collection(JOURNAL_ENTRIES_COLLECTION)
|
|
298
|
+
.where(LEDGER_FIELDS.SOURCE_EVENT, "==", "opening-balance")
|
|
299
|
+
.limit(1)
|
|
300
|
+
.get();
|
|
301
|
+
if (!existing.empty) {
|
|
302
|
+
throw new UnbalancedEntryError("Opening balances have already been posted. Correct them with a reversing entry rather than posting a second opening.");
|
|
303
|
+
}
|
|
304
|
+
return this.post({
|
|
305
|
+
entryDate: at,
|
|
306
|
+
sourceEvent: "opening-balance",
|
|
307
|
+
narration: `Opening balances at cutover, ${periodOf(at)}`,
|
|
308
|
+
lines,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
export const journalRepository = new JournalRepository();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vendors` + `expenses` — money that leaves the business for something
|
|
3
|
+
* other than a payout or a refund.
|
|
4
|
+
*
|
|
5
|
+
* ## 🛑 A VENDOR IS AN IDENTITY, which `supplierName` never was
|
|
6
|
+
*
|
|
7
|
+
* `ShipmentDocument.supplierName` is free text, so four shipments from one
|
|
8
|
+
* supplier are four unjoined strings and "what have we spent with Acme" is
|
|
9
|
+
* unanswerable. That is not a reporting nicety: it is also the join that
|
|
10
|
+
* makes input GST claimable per supplier, which is what a GSTR-2B
|
|
11
|
+
* reconciliation needs.
|
|
12
|
+
*
|
|
13
|
+
* ## 🛑 An expense is TRUTH; its journal entry is the projection
|
|
14
|
+
*
|
|
15
|
+
* Same split as orders and payouts. The expense row is what somebody
|
|
16
|
+
* actually paid for, with the bill attached; the ledger says how it was
|
|
17
|
+
* classified. Re-classifying an expense posts a reversal and a new entry —
|
|
18
|
+
* it never edits the old one — so the two stay reconcilable.
|
|
19
|
+
*/
|
|
20
|
+
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
21
|
+
export declare const VENDORS_COLLECTION = "vendors";
|
|
22
|
+
export declare const EXPENSES_COLLECTION = "expenses";
|
|
23
|
+
export interface VendorDocument extends BaseDocument {
|
|
24
|
+
/** `vendor-{slug}` — a pure slug, like every other named entity here. */
|
|
25
|
+
name: string;
|
|
26
|
+
/**
|
|
27
|
+
* 🛑 The GSTIN is what makes input tax claimable, and it is NOT PII.
|
|
28
|
+
*
|
|
29
|
+
* It is a business registration number, printed on every invoice the
|
|
30
|
+
* vendor issues and published in the GST portal's public search. Treating
|
|
31
|
+
* it as PII would mean encrypting the one field a GSTR-2B reconciliation
|
|
32
|
+
* has to match on — which would make the reconciliation impossible for no
|
|
33
|
+
* privacy gain.
|
|
34
|
+
*/
|
|
35
|
+
gstin?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Where the vendor is registered, for the place-of-supply rule.
|
|
38
|
+
*
|
|
39
|
+
* An intra-state purchase splits input tax into CGST + SGST and an
|
|
40
|
+
* inter-state one is IGST; they are different ledger accounts and a wrong
|
|
41
|
+
* one is a wrong return. Optional because a vendor with no GSTIN charges
|
|
42
|
+
* no GST and the question does not arise.
|
|
43
|
+
*/
|
|
44
|
+
stateCode?: string;
|
|
45
|
+
notes?: string;
|
|
46
|
+
isActive: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* What the money was for. Drives the expense account the posting hits.
|
|
50
|
+
*
|
|
51
|
+
* 🛑 A closed union rather than free text, and `other` is a real member
|
|
52
|
+
* precisely so the exception stays countable — "how much of our spend is
|
|
53
|
+
* unclassified" is one query, and a growing answer is the signal to add a
|
|
54
|
+
* category rather than a reason to allow typing one.
|
|
55
|
+
*/
|
|
56
|
+
export type ExpenseCategory = "freight" | "platform-software" | "wages" | "packaging" | "asset" | "other";
|
|
57
|
+
export interface ExpenseDocument extends BaseDocument {
|
|
58
|
+
vendorId?: string;
|
|
59
|
+
/** As written on the bill, for the same reason `supplierName` survives. */
|
|
60
|
+
vendorName: string;
|
|
61
|
+
category: ExpenseCategory;
|
|
62
|
+
/** The date on the BILL, not when it was entered — the period follows this. */
|
|
63
|
+
billDate: Date;
|
|
64
|
+
billNumber?: string;
|
|
65
|
+
/** Excluding tax. */
|
|
66
|
+
amount: number;
|
|
67
|
+
/**
|
|
68
|
+
* Input GST on this bill, claimable as ITC.
|
|
69
|
+
*
|
|
70
|
+
* 🛑 Stored SEPARATELY from `amount` rather than as a rate, because the
|
|
71
|
+
* figure on the bill is authoritative and re-deriving it from a
|
|
72
|
+
* percentage reproduces the supplier's rounding wrongly about as often as
|
|
73
|
+
* it reproduces it rightly — and the difference is what a GSTR-2B
|
|
74
|
+
* mismatch is made of.
|
|
75
|
+
*/
|
|
76
|
+
inputGst?: number;
|
|
77
|
+
/** Set once posted, so a re-run cannot double-post. */
|
|
78
|
+
journalEntryId?: string;
|
|
79
|
+
attachmentUrl?: string;
|
|
80
|
+
recordedByUid: string;
|
|
81
|
+
}
|
|
82
|
+
export declare const EXPENSE_FIELDS: {
|
|
83
|
+
readonly VENDOR_ID: "vendorId";
|
|
84
|
+
readonly CATEGORY: "category";
|
|
85
|
+
readonly BILL_DATE: "billDate";
|
|
86
|
+
readonly JOURNAL_ENTRY_ID: "journalEntryId";
|
|
87
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vendors` + `expenses` — money that leaves the business for something
|
|
3
|
+
* other than a payout or a refund.
|
|
4
|
+
*
|
|
5
|
+
* ## 🛑 A VENDOR IS AN IDENTITY, which `supplierName` never was
|
|
6
|
+
*
|
|
7
|
+
* `ShipmentDocument.supplierName` is free text, so four shipments from one
|
|
8
|
+
* supplier are four unjoined strings and "what have we spent with Acme" is
|
|
9
|
+
* unanswerable. That is not a reporting nicety: it is also the join that
|
|
10
|
+
* makes input GST claimable per supplier, which is what a GSTR-2B
|
|
11
|
+
* reconciliation needs.
|
|
12
|
+
*
|
|
13
|
+
* ## 🛑 An expense is TRUTH; its journal entry is the projection
|
|
14
|
+
*
|
|
15
|
+
* Same split as orders and payouts. The expense row is what somebody
|
|
16
|
+
* actually paid for, with the bill attached; the ledger says how it was
|
|
17
|
+
* classified. Re-classifying an expense posts a reversal and a new entry —
|
|
18
|
+
* it never edits the old one — so the two stay reconcilable.
|
|
19
|
+
*/
|
|
20
|
+
export const VENDORS_COLLECTION = "vendors";
|
|
21
|
+
export const EXPENSES_COLLECTION = "expenses";
|
|
22
|
+
export const EXPENSE_FIELDS = {
|
|
23
|
+
VENDOR_ID: "vendorId",
|
|
24
|
+
CATEGORY: "category",
|
|
25
|
+
BILL_DATE: "billDate",
|
|
26
|
+
JOURNAL_ENTRY_ID: "journalEntryId",
|
|
27
|
+
};
|