@mohasinac/appkit 3.2.20 → 3.3.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/_internal/server/features/checkout/actions.d.ts +2 -0
- package/dist/_internal/server/features/checkout/actions.js +239 -190
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +9 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +8 -11
- package/dist/_internal/server/jobs/core/emiInstallmentReminder.d.ts +8 -0
- package/dist/_internal/server/jobs/core/emiInstallmentReminder.js +78 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.d.ts +2 -2
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +15 -10
- package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/providers/index.d.ts +4 -4
- package/dist/_internal/server/providers/index.js +4 -4
- package/dist/_internal/server/providers/payment/razorpay-mock.d.ts +3 -2
- package/dist/_internal/server/providers/payment/razorpay-mock.js +3 -1
- package/dist/_internal/server/providers/resolve.d.ts +10 -13
- package/dist/_internal/server/providers/resolve.js +9 -15
- package/dist/_internal/shared/actions/action-registry.js +28 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +1 -0
- package/dist/_internal/shared/checkout/rules/_registry.js +4 -0
- package/dist/_internal/shared/checkout/rules/art.rule.d.ts +9 -0
- package/dist/_internal/shared/checkout/rules/art.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +1 -0
- package/dist/_internal/shared/checkout/rules/classified.rule.js +1 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +2 -0
- package/dist/_internal/shared/checkout/rules/stickers.rule.d.ts +9 -0
- package/dist/_internal/shared/checkout/rules/stickers.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +6 -0
- package/dist/_internal/shared/features/checkout/config.d.ts +16 -1
- package/dist/_internal/shared/features/checkout/config.js +16 -1
- package/dist/_internal/shared/features/emi/schedule.d.ts +63 -0
- package/dist/_internal/shared/features/emi/schedule.js +62 -0
- package/dist/_internal/shared/fees/calculator.d.ts +53 -0
- package/dist/_internal/shared/fees/calculator.js +40 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +22 -66
- package/dist/_internal/shared/listing-types/_registry.js +19 -2
- package/dist/_internal/shared/listing-types/art/config.d.ts +15 -0
- package/dist/_internal/shared/listing-types/art/config.js +14 -0
- package/dist/_internal/shared/listing-types/art/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/ctas.js +3 -0
- package/dist/_internal/shared/listing-types/art/og.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/og.js +1 -0
- package/dist/_internal/shared/listing-types/art/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/art/schema.js +3 -0
- package/dist/_internal/shared/listing-types/art/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/auction/config.js +6 -0
- package/dist/_internal/shared/listing-types/capabilities.js +17 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/classified/config.js +6 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +6 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/live/config.js +6 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +6 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +6 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/standard/config.js +6 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +15 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +14 -0
- package/dist/_internal/shared/listing-types/stickers/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/ctas.js +3 -0
- package/dist/_internal/shared/listing-types/stickers/og.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/og.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/stickers/schema.js +3 -0
- package/dist/_internal/shared/listing-types/stickers/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/seed-factory.js +1 -0
- package/dist/client.d.ts +7 -2
- package/dist/client.js +4 -2
- package/dist/constants/field-names.d.ts +2 -6
- package/dist/constants/field-names.js +2 -6
- package/dist/contracts/index.d.ts +4 -2
- package/dist/contracts/index.js +6 -0
- package/dist/contracts/payment.d.ts +14 -9
- package/dist/contracts/payment.js +11 -1
- package/dist/contracts/shipping.d.ts +14 -9
- package/dist/contracts/shipping.js +11 -1
- package/dist/features/about/components/PublicProfileView.js +3 -6
- package/dist/features/admin/components/AdminAddressBookView.d.ts +11 -0
- package/dist/features/admin/components/AdminAddressBookView.js +30 -0
- package/dist/features/admin/components/AdminArtView.d.ts +3 -0
- package/dist/features/admin/components/AdminArtView.js +45 -0
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +14 -9
- package/dist/features/admin/components/AdminStickersView.d.ts +3 -0
- package/dist/features/admin/components/AdminStickersView.js +45 -0
- package/dist/features/admin/components/index.d.ts +6 -0
- package/dist/features/admin/components/index.js +4 -0
- package/dist/features/admin/schemas/firestore.d.ts +19 -11
- package/dist/features/admin/schemas/firestore.js +12 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +3 -2
- package/dist/features/auth/hooks/useAuth.js +35 -9
- package/dist/features/auth/schemas/firestore.d.ts +2 -6
- package/dist/features/cart/schemas/firestore.d.ts +3 -2
- package/dist/features/consultation/schemas/index.d.ts +2 -2
- package/dist/features/loyalty/schemas/index.d.ts +6 -6
- package/dist/features/orders/repository/orders.repository.d.ts +20 -2
- package/dist/features/orders/repository/orders.repository.js +34 -5
- package/dist/features/orders/schemas/firestore.d.ts +33 -7
- package/dist/features/orders/schemas/firestore.js +1 -1
- package/dist/features/orders/schemas/index.d.ts +176 -31
- package/dist/features/orders/schemas/index.js +20 -6
- package/dist/features/orders/types/index.d.ts +3 -3
- package/dist/features/payments/repository/payout.repository.js +2 -2
- package/dist/features/payments/schemas/firestore.d.ts +3 -3
- package/dist/features/payments/schemas/firestore.js +2 -2
- package/dist/features/payments/schemas/index.d.ts +5 -5
- package/dist/features/payments/schemas/index.js +2 -2
- package/dist/features/products/api/[id]/route.js +4 -1
- package/dist/features/products/api/route.js +4 -1
- package/dist/features/products/components/CompareOverlay.js +7 -9
- package/dist/features/products/components/ProductDetailPageView.d.ts +3 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/components/ProductForm.js +18 -7
- package/dist/features/products/components/ProductGrid.js +7 -12
- package/dist/features/products/components/ShowGroupSection.js +3 -5
- package/dist/features/products/components/SublistingCarouselSection.js +3 -6
- package/dist/features/products/constants/listing-tabs.d.ts +32 -0
- package/dist/features/products/constants/listing-tabs.js +8 -0
- package/dist/features/products/index.d.ts +1 -1
- package/dist/features/products/index.js +3 -1
- package/dist/features/products/schemas/firestore.d.ts +20 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +48 -0
- package/dist/features/products/schemas/index.js +9 -0
- package/dist/features/products/schemas/product-features.d.ts +1 -1
- package/dist/features/products/types/index.d.ts +5 -3
- package/dist/features/products/utils/listing-type.d.ts +6 -0
- package/dist/features/products/utils/listing-type.js +3 -0
- package/dist/features/reviews/api/[id]/route.js +5 -4
- package/dist/features/seller/actions/seller-actions.d.ts +29 -14
- package/dist/features/seller/actions/seller-actions.js +101 -27
- package/dist/features/seller/components/SellerArtView.d.ts +7 -0
- package/dist/features/seller/components/SellerArtView.js +114 -0
- package/dist/features/seller/components/SellerOrdersView.js +38 -1
- package/dist/features/seller/components/SellerProductShell.d.ts +5 -1
- package/dist/features/seller/components/SellerProductShell.js +69 -59
- package/dist/features/seller/components/SellerShippingView.js +6 -25
- package/dist/features/seller/components/SellerStickersView.d.ts +7 -0
- package/dist/features/seller/components/SellerStickersView.js +114 -0
- package/dist/features/seller/components/index.d.ts +4 -0
- package/dist/features/seller/components/index.js +2 -0
- package/dist/features/seller/messages/en.json +1 -1
- package/dist/features/seller/schemas/index.d.ts +7 -7
- package/dist/features/seller/schemas/index.js +1 -1
- package/dist/features/seller/types/index.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +18 -2
- package/dist/features/stores/schemas/firestore.d.ts +7 -1
- package/dist/features/stores/schemas/index.d.ts +19 -16
- package/dist/features/stores/schemas/index.js +1 -1
- package/dist/index.d.ts +21 -36
- package/dist/index.js +27 -39
- package/dist/next/routing/route-map.d.ts +22 -0
- package/dist/next/routing/route-map.js +10 -0
- package/dist/providers/payment-manual/index.d.ts +40 -0
- package/dist/providers/payment-manual/index.js +91 -0
- package/dist/providers/payment-razorpay/index.d.ts +4 -2
- package/dist/providers/payment-razorpay/index.js +4 -1
- package/dist/providers/shipping-manual/index.d.ts +22 -0
- package/dist/providers/shipping-manual/index.js +47 -0
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +5 -3
- package/dist/schemas/registry.d.ts +129 -70
- package/dist/schemas/registry.js +0 -4
- package/dist/security/pii-encrypt.js +0 -7
- package/dist/security/pii-redact.js +0 -1
- package/dist/seed/conversations-seed-data.js +2 -2
- package/dist/seed/faq-seed-data.js +7 -7
- package/dist/seed/grouped-listings-seed-data.d.ts +2 -0
- package/dist/seed/index.d.ts +2 -0
- package/dist/seed/index.js +2 -0
- package/dist/seed/manifest.js +20 -16
- package/dist/seed/payouts-seed-data.js +5 -5
- package/dist/seed/products-art-seed-data.d.ts +11 -0
- package/dist/seed/products-art-seed-data.js +125 -0
- package/dist/seed/products-preorders-seed-data.d.ts +2 -0
- package/dist/seed/products-stickers-seed-data.d.ts +11 -0
- package/dist/seed/products-stickers-seed-data.js +125 -0
- package/dist/seed/site-settings-seed-data.js +13 -4
- package/dist/seed/stores-seed-data.js +11 -11
- package/dist/server.d.ts +7 -15
- package/dist/server.js +17 -42
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* AdminStickersView — admin browse of sticker listings (EMI/art-stickers session).
|
|
5
|
+
* Mirrors AdminClassifiedView's thin config-driven pattern.
|
|
6
|
+
*/
|
|
7
|
+
import { sortBy } from "@mohasinac/appkit";
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { ListingLayout } from "../../../ui";
|
|
10
|
+
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
|
+
import { toRecordArray, toRelativeDate, toRupees, toStringValue, } from "../hooks/useAdminListingData";
|
|
12
|
+
import { DataListingView } from "./DataListingView";
|
|
13
|
+
const ADMIN_STICKERS_CONFIG = {
|
|
14
|
+
portal: "admin",
|
|
15
|
+
title: "Stickers",
|
|
16
|
+
searchPlaceholder: "Search stickers by name or seller",
|
|
17
|
+
emptyLabel: "No sticker listings",
|
|
18
|
+
filterKeys: [],
|
|
19
|
+
defaultSort: sortBy("createdAt", "DESC"),
|
|
20
|
+
queryKey: ["admin", "stickers", "listing"],
|
|
21
|
+
endpoint: ADMIN_ENDPOINTS.PRODUCTS,
|
|
22
|
+
sortOptions: [
|
|
23
|
+
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
24
|
+
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
25
|
+
{ value: "title", label: "Title A–Z" },
|
|
26
|
+
],
|
|
27
|
+
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
28
|
+
id: toStringValue(item.id, `stickers-${index}`),
|
|
29
|
+
primary: toStringValue(item.title ?? item.productTitle, "Untitled sticker listing"),
|
|
30
|
+
secondary: [
|
|
31
|
+
toStringValue(item.sellerName, "Unknown seller"),
|
|
32
|
+
toRupees(item.price),
|
|
33
|
+
].join(" · "),
|
|
34
|
+
status: toStringValue(item.status, "draft"),
|
|
35
|
+
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
36
|
+
})),
|
|
37
|
+
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
38
|
+
buildFilters: () => "listingType==stickers",
|
|
39
|
+
};
|
|
40
|
+
export function AdminStickersView({ children, ...props }) {
|
|
41
|
+
if (React.Children.count(children) > 0) {
|
|
42
|
+
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
43
|
+
}
|
|
44
|
+
return _jsx(DataListingView, { config: ADMIN_STICKERS_CONFIG });
|
|
45
|
+
}
|
|
@@ -40,6 +40,10 @@ export { AdminDigitalCodesView } from "./AdminDigitalCodesView";
|
|
|
40
40
|
export type { AdminDigitalCodesViewProps } from "./AdminDigitalCodesView";
|
|
41
41
|
export { AdminLiveView } from "./AdminLiveView";
|
|
42
42
|
export type { AdminLiveViewProps } from "./AdminLiveView";
|
|
43
|
+
export { AdminArtView } from "./AdminArtView";
|
|
44
|
+
export type { AdminArtViewProps } from "./AdminArtView";
|
|
45
|
+
export { AdminStickersView } from "./AdminStickersView";
|
|
46
|
+
export type { AdminStickersViewProps } from "./AdminStickersView";
|
|
43
47
|
export { AdminGroupedListingsView } from "./AdminGroupedListingsView";
|
|
44
48
|
export type { AdminGroupedListingsViewProps } from "./AdminGroupedListingsView";
|
|
45
49
|
export { AdminBundlesView } from "./AdminBundlesView";
|
|
@@ -157,6 +161,8 @@ export { AdminFulfillmentView } from "./AdminFulfillmentView";
|
|
|
157
161
|
export type { AdminFulfillmentViewProps } from "./AdminFulfillmentView";
|
|
158
162
|
export { AdminAddressesView } from "./AdminAddressesView";
|
|
159
163
|
export type { AdminAddressesViewProps } from "./AdminAddressesView";
|
|
164
|
+
export { AdminAddressBookView } from "./AdminAddressBookView";
|
|
165
|
+
export type { AdminAddressBookViewProps } from "./AdminAddressBookView";
|
|
160
166
|
export { AdminAddressClustersView } from "./AdminAddressClustersView";
|
|
161
167
|
export type { AdminAddressClustersViewProps } from "./AdminAddressClustersView";
|
|
162
168
|
export { AdminPaymentMethodsView } from "./AdminPaymentMethodsView";
|
|
@@ -22,6 +22,9 @@ export { AdminPrizeDrawsView } from "./AdminPrizeDrawsView";
|
|
|
22
22
|
export { AdminClassifiedView } from "./AdminClassifiedView";
|
|
23
23
|
export { AdminDigitalCodesView } from "./AdminDigitalCodesView";
|
|
24
24
|
export { AdminLiveView } from "./AdminLiveView";
|
|
25
|
+
// EMI/art-stickers session — admin listing views for art / stickers.
|
|
26
|
+
export { AdminArtView } from "./AdminArtView";
|
|
27
|
+
export { AdminStickersView } from "./AdminStickersView";
|
|
25
28
|
export { AdminGroupedListingsView } from "./AdminGroupedListingsView";
|
|
26
29
|
// S-SBUNI-4 2026-05-13 — admin bundle CRUD views.
|
|
27
30
|
export { AdminBundlesView } from "./AdminBundlesView";
|
|
@@ -82,6 +85,7 @@ export { AdminScammersView } from "./AdminScammersView";
|
|
|
82
85
|
export { AdminScammerEditorView } from "./AdminScammerEditorView";
|
|
83
86
|
export { AdminFulfillmentView } from "./AdminFulfillmentView";
|
|
84
87
|
export { AdminAddressesView } from "./AdminAddressesView";
|
|
88
|
+
export { AdminAddressBookView } from "./AdminAddressBookView";
|
|
85
89
|
export { AdminAddressClustersView } from "./AdminAddressClustersView";
|
|
86
90
|
export { AdminPaymentMethodsView } from "./AdminPaymentMethodsView";
|
|
87
91
|
export { AdminPaymentClustersView } from "./AdminPaymentClustersView";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Covers: notifications, chat rooms, site settings
|
|
4
4
|
*/
|
|
5
5
|
export declare const ADMIN_CHECKOUT_BYPASS_FLAG_KEY: "adminCheckoutBypass";
|
|
6
|
-
export type NotificationType = "order_placed" | "order_confirmed" | "order_shipped" | "order_delivered" | "order_cancelled" | "bid_placed" | "bid_outbid" | "bid_won" | "bid_lost" | "review_approved" | "review_replied" | "product_available" | "promotion" | "system" | "welcome" | "account_action" | "offer_received" | "offer_responded" | "offer_expired" | "offer_counter_accepted" | "refund_initiated" | "prize_reveal_ready" | "prize_reveal_expired" | "prize_reveal_reminder";
|
|
6
|
+
export type NotificationType = "order_placed" | "order_confirmed" | "order_shipped" | "order_delivered" | "order_cancelled" | "bid_placed" | "bid_outbid" | "bid_won" | "bid_lost" | "review_approved" | "review_replied" | "product_available" | "promotion" | "system" | "welcome" | "account_action" | "offer_received" | "offer_responded" | "offer_expired" | "offer_counter_accepted" | "refund_initiated" | "prize_reveal_ready" | "prize_reveal_expired" | "prize_reveal_reminder" | "emi_installment_due_soon" | "emi_installment_overdue";
|
|
7
7
|
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
8
8
|
export type NotificationPriority = "low" | "normal" | "high";
|
|
9
9
|
export interface NotificationDocument extends BaseDocument {
|
|
@@ -143,8 +143,6 @@ export interface SiteSettingsCredentials {
|
|
|
143
143
|
razorpayWebhookSecret?: string;
|
|
144
144
|
resendApiKey?: string;
|
|
145
145
|
whatsappApiKey?: string;
|
|
146
|
-
shiprocketEmail?: string;
|
|
147
|
-
shiprocketPassword?: string;
|
|
148
146
|
metaAppId?: string;
|
|
149
147
|
metaAppSecret?: string;
|
|
150
148
|
metaPageAccessToken?: string;
|
|
@@ -171,8 +169,6 @@ export interface SiteSettingsCredentialsMasked {
|
|
|
171
169
|
razorpayWebhookSecret?: string;
|
|
172
170
|
resendApiKey?: string;
|
|
173
171
|
whatsappApiKey?: string;
|
|
174
|
-
shiprocketEmail?: string;
|
|
175
|
-
shiprocketPassword?: string;
|
|
176
172
|
metaAppId?: string;
|
|
177
173
|
metaAppSecret?: string;
|
|
178
174
|
metaPageAccessToken?: string;
|
|
@@ -293,6 +289,21 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
293
289
|
upiManualEnabled: boolean;
|
|
294
290
|
codEnabled: boolean;
|
|
295
291
|
};
|
|
292
|
+
/** Site-wide EMI (installment) settings. A seller must ALSO have `StoreDocument.emiEnabled` on for EMI to appear at checkout for their items. */
|
|
293
|
+
emi: {
|
|
294
|
+
enabled: boolean;
|
|
295
|
+
/** Paise — a seller's cart subtotal must exceed this for EMI to appear as an option. */
|
|
296
|
+
minOrderValueInPaise: number;
|
|
297
|
+
tenureOptions: number[];
|
|
298
|
+
/** Down payment % collected at checkout. */
|
|
299
|
+
tokenPercent: number;
|
|
300
|
+
/** Day of month (1–10) each installment is due. */
|
|
301
|
+
billingDay: number;
|
|
302
|
+
/** Extra % of principal per month of tenure — the "excess EMI fee" the buyer pays for spreading payment. */
|
|
303
|
+
surchargePercentPerMonth: number;
|
|
304
|
+
/** Share of the surcharge that goes to the seller (0–100); the rest is the platform's cut. */
|
|
305
|
+
surchargeSellerSharePercent: number;
|
|
306
|
+
};
|
|
296
307
|
commissions: {
|
|
297
308
|
/** Our platform cut charged to the buyer as a % of order value (e.g. 5 = 5%). */
|
|
298
309
|
platformFeePercent: number;
|
|
@@ -303,6 +314,9 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
303
314
|
/** Razorpay gateway cost % (absorbed by platform, not passed through separately). */
|
|
304
315
|
gatewayFeePercent: number;
|
|
305
316
|
codDepositPercent: number;
|
|
317
|
+
/** COD handling fee charged to the buyer: max(codHandlingFeeMinInPaise, subtotal × codHandlingFeePercent / 100). */
|
|
318
|
+
codHandlingFeeMinInPaise: number;
|
|
319
|
+
codHandlingFeePercent: number;
|
|
306
320
|
sellerShippingFixed: number;
|
|
307
321
|
platformShippingPercent: number;
|
|
308
322
|
platformShippingFixedMin: number;
|
|
@@ -362,12 +376,6 @@ export interface SiteSettingsDocument extends BaseDocument {
|
|
|
362
376
|
* if this is ever true. Default false.
|
|
363
377
|
*/
|
|
364
378
|
useMockPayment?: boolean;
|
|
365
|
-
/**
|
|
366
|
-
* Track H — when true and NODE_ENV !== "production", the shipping provider
|
|
367
|
-
* resolver returns MockShiprocketProvider. In production the resolver throws
|
|
368
|
-
* if this is ever true. Default false.
|
|
369
|
-
*/
|
|
370
|
-
useMockShipping?: boolean;
|
|
371
379
|
listingTypes?: {
|
|
372
380
|
standard?: boolean;
|
|
373
381
|
auction?: boolean;
|
|
@@ -167,16 +167,27 @@ export const DEFAULT_SITE_SETTINGS_DATA = {
|
|
|
167
167
|
motto: "Your Marketplace, Your Rules",
|
|
168
168
|
theme: DEFAULT_SITE_SETTINGS_THEME,
|
|
169
169
|
payment: {
|
|
170
|
-
razorpayEnabled:
|
|
170
|
+
razorpayEnabled: false,
|
|
171
171
|
upiManualEnabled: true,
|
|
172
172
|
codEnabled: true,
|
|
173
173
|
},
|
|
174
|
+
emi: {
|
|
175
|
+
enabled: false,
|
|
176
|
+
minOrderValueInPaise: 1000000,
|
|
177
|
+
tenureOptions: [2, 3, 4, 5, 6],
|
|
178
|
+
tokenPercent: 10,
|
|
179
|
+
billingDay: 5,
|
|
180
|
+
surchargePercentPerMonth: 1,
|
|
181
|
+
surchargeSellerSharePercent: 50,
|
|
182
|
+
},
|
|
174
183
|
commissions: {
|
|
175
184
|
platformFeePercent: 5,
|
|
176
185
|
gstPercent: 18,
|
|
177
186
|
minimumTransactionFee: 0,
|
|
178
187
|
gatewayFeePercent: 2,
|
|
179
188
|
codDepositPercent: 10,
|
|
189
|
+
codHandlingFeeMinInPaise: 20000,
|
|
190
|
+
codHandlingFeePercent: 10,
|
|
180
191
|
sellerShippingFixed: 0,
|
|
181
192
|
platformShippingPercent: 10,
|
|
182
193
|
platformShippingFixedMin: 0,
|
|
@@ -205,7 +216,6 @@ export const DEFAULT_SITE_SETTINGS_DATA = {
|
|
|
205
216
|
// Track H — both mock-provider flags default to false. Production
|
|
206
217
|
// deployments must never flip these on (the resolver throws if they are).
|
|
207
218
|
useMockPayment: false,
|
|
208
|
-
useMockShipping: false,
|
|
209
219
|
// W1-37 2026-05-23 — Phase 2 listing types enabled by default; all per-type
|
|
210
220
|
// surfaces (seller + admin via W1-29 + public) are now shipped.
|
|
211
221
|
listingTypes: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type WishlistToggleActions } from "../../wishlist";
|
|
2
|
+
import type { ListingType } from "../../products/types/index";
|
|
2
3
|
export interface MarketplaceAuctionCardData {
|
|
3
4
|
id: string;
|
|
4
5
|
title: string;
|
|
@@ -11,8 +12,8 @@ export interface MarketplaceAuctionCardData {
|
|
|
11
12
|
url?: string;
|
|
12
13
|
thumbnailUrl?: string;
|
|
13
14
|
};
|
|
14
|
-
/** Canonical discriminator (SB1-G Phase 4
|
|
15
|
-
listingType?:
|
|
15
|
+
/** Canonical discriminator (SB1-G Phase 4). */
|
|
16
|
+
listingType?: ListingType;
|
|
16
17
|
auctionEndDate?: string | Date;
|
|
17
18
|
startingBid?: number;
|
|
18
19
|
currentBid?: number;
|
|
@@ -57,6 +57,17 @@ export function useGoogleLogin(options) {
|
|
|
57
57
|
const [popupPending, setPopupPending] = useState(false);
|
|
58
58
|
// calledRef prevents both RTDB and postMessage from firing the callbacks
|
|
59
59
|
const calledRef = useRef(false);
|
|
60
|
+
// Polls for the popup being closed manually (without completing sign-in).
|
|
61
|
+
// Without this, a user who closes the popup before RTDB/postMessage
|
|
62
|
+
// resolves leaves popupPending stuck true forever — the button never
|
|
63
|
+
// recovers from its loading state.
|
|
64
|
+
const closePollRef = useRef(null);
|
|
65
|
+
const clearClosePoll = useCallback(() => {
|
|
66
|
+
if (closePollRef.current !== null) {
|
|
67
|
+
clearInterval(closePollRef.current);
|
|
68
|
+
closePollRef.current = null;
|
|
69
|
+
}
|
|
70
|
+
}, []);
|
|
60
71
|
const onSuccessRef = useRef(options?.onSuccess);
|
|
61
72
|
const onErrorRef = useRef(options?.onError);
|
|
62
73
|
const onSessionSyncedRef = useRef(options?.onSessionSynced);
|
|
@@ -65,6 +76,8 @@ export function useGoogleLogin(options) {
|
|
|
65
76
|
useEffect(() => { onErrorRef.current = options?.onError; }, [options?.onError]);
|
|
66
77
|
useEffect(() => { onSessionSyncedRef.current = options?.onSessionSynced; }, [options?.onSessionSynced]);
|
|
67
78
|
useEffect(() => { authEventResetRef.current = authEvent.reset; }, [authEvent.reset]);
|
|
79
|
+
// Stop polling for popup-closed if the component unmounts mid-flow.
|
|
80
|
+
useEffect(() => clearClosePoll, [clearClosePoll]);
|
|
68
81
|
// RTDB status watcher — fast path when RTDB is available.
|
|
69
82
|
// FAILED is intentionally not forwarded to onError here: RTDB connection
|
|
70
83
|
// failures (e.g. missing database URL) should fall through to the postMessage
|
|
@@ -75,6 +88,7 @@ export function useGoogleLogin(options) {
|
|
|
75
88
|
if (calledRef.current)
|
|
76
89
|
return;
|
|
77
90
|
calledRef.current = true;
|
|
91
|
+
clearClosePoll();
|
|
78
92
|
Promise.resolve(onSessionSyncedRef.current?.()).then(() => {
|
|
79
93
|
onSuccessRef.current?.(authEvent.data);
|
|
80
94
|
});
|
|
@@ -85,10 +99,11 @@ export function useGoogleLogin(options) {
|
|
|
85
99
|
if (calledRef.current)
|
|
86
100
|
return;
|
|
87
101
|
calledRef.current = true;
|
|
102
|
+
clearClosePoll();
|
|
88
103
|
onErrorRef.current?.(new Error(authEvent.error ?? "Sign-in timed out. Please try again."));
|
|
89
104
|
}
|
|
90
105
|
// FAILED: do not call onError — wait for the postMessage from /auth/close
|
|
91
|
-
}, [authEvent.status, authEvent.error, authEvent.data]);
|
|
106
|
+
}, [authEvent.status, authEvent.error, authEvent.data, clearClosePoll]);
|
|
92
107
|
// postMessage fallback — fires when /auth/close sends window.opener.postMessage.
|
|
93
108
|
// This covers two cases:
|
|
94
109
|
// 1. RTDB is unavailable (the primary channel failed)
|
|
@@ -104,6 +119,7 @@ export function useGoogleLogin(options) {
|
|
|
104
119
|
return;
|
|
105
120
|
calledRef.current = true;
|
|
106
121
|
setPopupPending(false);
|
|
122
|
+
clearClosePoll();
|
|
107
123
|
authEventResetRef.current();
|
|
108
124
|
if (event.data.status === "success") {
|
|
109
125
|
const data = event.data.uid
|
|
@@ -119,7 +135,7 @@ export function useGoogleLogin(options) {
|
|
|
119
135
|
};
|
|
120
136
|
window.addEventListener("message", handleMessage);
|
|
121
137
|
return () => window.removeEventListener("message", handleMessage);
|
|
122
|
-
}, []); //
|
|
138
|
+
}, [clearClosePoll]); // clearClosePoll has a stable identity — effectively mount-once
|
|
123
139
|
const mutate = useCallback(async () => {
|
|
124
140
|
calledRef.current = false; // reset for each new auth flow
|
|
125
141
|
const popup = window.open(`${window.location.origin}/auth.html`, "oauth_google", "width=500,height=660,left=400,top=100");
|
|
@@ -128,6 +144,16 @@ export function useGoogleLogin(options) {
|
|
|
128
144
|
return;
|
|
129
145
|
}
|
|
130
146
|
setPopupPending(true);
|
|
147
|
+
clearClosePoll();
|
|
148
|
+
closePollRef.current = setInterval(() => {
|
|
149
|
+
if (popup.closed && !calledRef.current) {
|
|
150
|
+
calledRef.current = true;
|
|
151
|
+
clearClosePoll();
|
|
152
|
+
setPopupPending(false);
|
|
153
|
+
authEventResetRef.current();
|
|
154
|
+
onErrorRef.current?.(new Error("Sign-in was cancelled."));
|
|
155
|
+
}
|
|
156
|
+
}, 500);
|
|
131
157
|
try {
|
|
132
158
|
setInitiating(true);
|
|
133
159
|
authEvent.reset();
|
|
@@ -142,6 +168,7 @@ export function useGoogleLogin(options) {
|
|
|
142
168
|
}
|
|
143
169
|
catch (err) {
|
|
144
170
|
void normalizeError(err);
|
|
171
|
+
clearClosePoll();
|
|
145
172
|
popup.close();
|
|
146
173
|
setPopupPending(false);
|
|
147
174
|
onErrorRef.current?.(err instanceof Error ? err : new Error("Failed to start sign-in."));
|
|
@@ -149,7 +176,7 @@ export function useGoogleLogin(options) {
|
|
|
149
176
|
finally {
|
|
150
177
|
setInitiating(false);
|
|
151
178
|
}
|
|
152
|
-
}, [authEvent]);
|
|
179
|
+
}, [authEvent, clearClosePoll]);
|
|
153
180
|
const isLoading = initiating ||
|
|
154
181
|
popupPending ||
|
|
155
182
|
authEvent.status === RealtimeEventStatus.SUBSCRIBING ||
|
|
@@ -166,13 +193,12 @@ export function useRegister(options) {
|
|
|
166
193
|
displayName: data.displayName?.trim() || "",
|
|
167
194
|
acceptTerms: data.acceptTerms,
|
|
168
195
|
});
|
|
169
|
-
//
|
|
196
|
+
// /api/auth/register already created the server-side session cookie +
|
|
197
|
+
// Firestore session doc. Sign in via the client SDK only so
|
|
198
|
+
// `auth.currentUser` is populated for client-side Firebase usage
|
|
199
|
+
// (RTDB presence, etc) — do NOT call /api/auth/session again here,
|
|
200
|
+
// that would create a second, orphaned session document.
|
|
170
201
|
await getClientAuthProvider().signInWithEmailAndPassword(data.email.trim(), data.password);
|
|
171
|
-
const currentUser = getClientSessionAdapter().getCurrentUser();
|
|
172
|
-
if (currentUser) {
|
|
173
|
-
const idToken = await currentUser.getIdToken(true);
|
|
174
|
-
await apiClient.post(AUTH_ENDPOINTS.SESSION, { idToken });
|
|
175
|
-
}
|
|
176
202
|
return { success: true, ...response };
|
|
177
203
|
},
|
|
178
204
|
onSuccess: options?.onSuccess,
|
|
@@ -109,7 +109,8 @@ export interface UserSoftBan {
|
|
|
109
109
|
/** Null or absent = permanent. Past date = expired (treated as lifted without deletion). */
|
|
110
110
|
expiresAt?: Date | null;
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
/** Manual shipping is the only supported method — sellers enter carrier + tracking directly, no carrier API integration. */
|
|
113
|
+
export type SellerShippingMethod = "custom";
|
|
113
114
|
export interface SellerPickupAddress {
|
|
114
115
|
locationName: string;
|
|
115
116
|
name: string;
|
|
@@ -122,16 +123,11 @@ export interface SellerPickupAddress {
|
|
|
122
123
|
pincode: string;
|
|
123
124
|
country: string;
|
|
124
125
|
isVerified: boolean;
|
|
125
|
-
shiprocketAddressId?: number;
|
|
126
126
|
}
|
|
127
127
|
export interface SellerShippingConfig {
|
|
128
128
|
method: SellerShippingMethod;
|
|
129
129
|
customShippingPrice?: number;
|
|
130
130
|
customCarrierName?: string;
|
|
131
|
-
shiprocketEmail?: string;
|
|
132
|
-
/** Shiprocket JWT — server-only, never returned to client. */
|
|
133
|
-
shiprocketToken?: string;
|
|
134
|
-
shiprocketTokenExpiry?: Date;
|
|
135
131
|
pickupAddress?: SellerPickupAddress;
|
|
136
132
|
isConfigured: boolean;
|
|
137
133
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* for the cart feature.
|
|
6
6
|
*/
|
|
7
7
|
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
8
|
+
import type { ListingType } from "../../products/types/index";
|
|
8
9
|
export interface CartItemDocument {
|
|
9
10
|
itemId: string;
|
|
10
11
|
productId: string;
|
|
@@ -22,7 +23,7 @@ export interface CartItemDocument {
|
|
|
22
23
|
* carts) and cart-side UI badges. Replaces the legacy `isAuction`/`isPreOrder`
|
|
23
24
|
* pair on the cart item.
|
|
24
25
|
*/
|
|
25
|
-
listingType:
|
|
26
|
+
listingType: ListingType;
|
|
26
27
|
/** True when item was added from an accepted Make-an-Offer */
|
|
27
28
|
isOffer?: boolean;
|
|
28
29
|
offerId?: string;
|
|
@@ -110,7 +111,7 @@ export type AddToCartInput = {
|
|
|
110
111
|
/** Store slug (= storeId = store.id) */
|
|
111
112
|
storeId: string;
|
|
112
113
|
storeName: string;
|
|
113
|
-
listingType:
|
|
114
|
+
listingType: ListingType;
|
|
114
115
|
isOffer?: boolean;
|
|
115
116
|
offerId?: string;
|
|
116
117
|
lockedPrice?: number;
|
|
@@ -26,7 +26,7 @@ export declare const consultationBookingSchema: z.ZodObject<{
|
|
|
26
26
|
adminNote: z.ZodOptional<z.ZodString>;
|
|
27
27
|
createdAt: z.ZodOptional<z.ZodString>;
|
|
28
28
|
}, "strip", z.ZodTypeAny, {
|
|
29
|
-
status: "cancelled" | "pending" | "
|
|
29
|
+
status: "cancelled" | "pending" | "confirmed" | "completed" | "no_show";
|
|
30
30
|
id: string;
|
|
31
31
|
name: string;
|
|
32
32
|
email: string;
|
|
@@ -43,7 +43,7 @@ export declare const consultationBookingSchema: z.ZodObject<{
|
|
|
43
43
|
id: string;
|
|
44
44
|
name: string;
|
|
45
45
|
email: string;
|
|
46
|
-
status?: "cancelled" | "pending" | "
|
|
46
|
+
status?: "cancelled" | "pending" | "confirmed" | "completed" | "no_show" | undefined;
|
|
47
47
|
message?: string | undefined;
|
|
48
48
|
phone?: string | undefined;
|
|
49
49
|
createdAt?: string | undefined;
|
|
@@ -9,12 +9,12 @@ export declare const coinHistoryEntrySchema: z.ZodObject<{
|
|
|
9
9
|
orderId: z.ZodOptional<z.ZodString>;
|
|
10
10
|
timestamp: z.ZodOptional<z.ZodString>;
|
|
11
11
|
}, "strip", z.ZodTypeAny, {
|
|
12
|
-
reason: "
|
|
12
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
13
13
|
delta: number;
|
|
14
14
|
orderId?: string | undefined;
|
|
15
15
|
timestamp?: string | undefined;
|
|
16
16
|
}, {
|
|
17
|
-
reason: "
|
|
17
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
18
18
|
delta: number;
|
|
19
19
|
orderId?: string | undefined;
|
|
20
20
|
timestamp?: string | undefined;
|
|
@@ -38,12 +38,12 @@ export declare const loyaltyBalanceSchema: z.ZodObject<{
|
|
|
38
38
|
orderId: z.ZodOptional<z.ZodString>;
|
|
39
39
|
timestamp: z.ZodOptional<z.ZodString>;
|
|
40
40
|
}, "strip", z.ZodTypeAny, {
|
|
41
|
-
reason: "
|
|
41
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
42
42
|
delta: number;
|
|
43
43
|
orderId?: string | undefined;
|
|
44
44
|
timestamp?: string | undefined;
|
|
45
45
|
}, {
|
|
46
|
-
reason: "
|
|
46
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
47
47
|
delta: number;
|
|
48
48
|
orderId?: string | undefined;
|
|
49
49
|
timestamp?: string | undefined;
|
|
@@ -52,7 +52,7 @@ export declare const loyaltyBalanceSchema: z.ZodObject<{
|
|
|
52
52
|
uid: string;
|
|
53
53
|
hcCoins: number;
|
|
54
54
|
coinHistory?: {
|
|
55
|
-
reason: "
|
|
55
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
56
56
|
delta: number;
|
|
57
57
|
orderId?: string | undefined;
|
|
58
58
|
timestamp?: string | undefined;
|
|
@@ -61,7 +61,7 @@ export declare const loyaltyBalanceSchema: z.ZodObject<{
|
|
|
61
61
|
uid: string;
|
|
62
62
|
hcCoins?: number | undefined;
|
|
63
63
|
coinHistory?: {
|
|
64
|
-
reason: "
|
|
64
|
+
reason: "redemption" | "order_reward" | "referral" | "review_reward" | "manual_credit" | "manual_debit" | "expiry";
|
|
65
65
|
delta: number;
|
|
66
66
|
orderId?: string | undefined;
|
|
67
67
|
timestamp?: string | undefined;
|
|
@@ -181,9 +181,14 @@ declare class OrderRepository extends BaseRepository<OrderDocument> {
|
|
|
181
181
|
data: OrderDocument;
|
|
182
182
|
}>>;
|
|
183
183
|
/**
|
|
184
|
-
* Cloud Functions: find
|
|
184
|
+
* Cloud Functions: find delivered orders eligible for the weekly payout sweep.
|
|
185
|
+
*
|
|
186
|
+
* EMI orders that still have unpaid installments are excluded — the seller
|
|
187
|
+
* is only eligible once the buyer has fully paid off the order, not merely
|
|
188
|
+
* once it's delivered (a seller-enabled `allowShipBeforeEmiComplete` item
|
|
189
|
+
* can be delivered long before EMI collection finishes).
|
|
185
190
|
*/
|
|
186
|
-
|
|
191
|
+
getEligibleForPayoutSweep(): Promise<Array<{
|
|
187
192
|
id: string;
|
|
188
193
|
ref: DocumentReference;
|
|
189
194
|
data: OrderDocument;
|
|
@@ -192,12 +197,25 @@ declare class OrderRepository extends BaseRepository<OrderDocument> {
|
|
|
192
197
|
* Cloud Functions: find auto-payout eligible delivered orders older than windowDays business days.
|
|
193
198
|
* @param windowDays - number of business days since delivery
|
|
194
199
|
* @param cutoff - pre-computed business-day cutoff date (computed by caller)
|
|
200
|
+
*
|
|
201
|
+
* See {@link getEligibleForPayoutSweep} for the EMI-incomplete exclusion rationale.
|
|
195
202
|
*/
|
|
196
203
|
getEligibleAutomatic(cutoff: Date): Promise<Array<{
|
|
197
204
|
id: string;
|
|
198
205
|
ref: DocumentReference;
|
|
199
206
|
data: OrderDocument;
|
|
200
207
|
}>>;
|
|
208
|
+
/**
|
|
209
|
+
* Cloud Functions: EMI reminder sweep — orders on an active (not yet fully
|
|
210
|
+
* paid) EMI plan. Per-installment due-date filtering happens in the job
|
|
211
|
+
* itself since `emiInstallments` is an array field Firestore can't range-
|
|
212
|
+
* query on.
|
|
213
|
+
*/
|
|
214
|
+
getActiveEmiOrders(): Promise<Array<{
|
|
215
|
+
id: string;
|
|
216
|
+
ref: DocumentReference;
|
|
217
|
+
data: OrderDocument;
|
|
218
|
+
}>>;
|
|
201
219
|
/**
|
|
202
220
|
* Cloud Functions: stage a payout-requested update into a caller-owned WriteBatch.
|
|
203
221
|
*/
|
|
@@ -268,26 +268,34 @@ class OrderRepository extends BaseRepository {
|
|
|
268
268
|
}));
|
|
269
269
|
}
|
|
270
270
|
/**
|
|
271
|
-
* Cloud Functions: find
|
|
271
|
+
* Cloud Functions: find delivered orders eligible for the weekly payout sweep.
|
|
272
|
+
*
|
|
273
|
+
* EMI orders that still have unpaid installments are excluded — the seller
|
|
274
|
+
* is only eligible once the buyer has fully paid off the order, not merely
|
|
275
|
+
* once it's delivered (a seller-enabled `allowShipBeforeEmiComplete` item
|
|
276
|
+
* can be delivered long before EMI collection finishes).
|
|
272
277
|
*/
|
|
273
|
-
async
|
|
278
|
+
async getEligibleForPayoutSweep() {
|
|
274
279
|
const snap = await this.db
|
|
275
280
|
.collection(this.collection)
|
|
276
281
|
.where(ORDER_FIELDS.PAYOUT_STATUS, "==", "eligible")
|
|
277
|
-
.where(ORDER_FIELDS.SHIPPING_METHOD, "==", "shiprocket")
|
|
278
282
|
.where(ORDER_FIELDS.STATUS, "==", OrderStatusValues.DELIVERED)
|
|
279
283
|
.limit(500)
|
|
280
284
|
.get();
|
|
281
|
-
return snap.docs
|
|
285
|
+
return snap.docs
|
|
286
|
+
.map((d) => ({
|
|
282
287
|
id: d.id,
|
|
283
288
|
ref: d.ref,
|
|
284
289
|
data: this.decryptOrder({ id: d.id, ...d.data() }),
|
|
285
|
-
}))
|
|
290
|
+
}))
|
|
291
|
+
.filter((o) => !o.data.emiEnabled || o.data.emiComplete);
|
|
286
292
|
}
|
|
287
293
|
/**
|
|
288
294
|
* Cloud Functions: find auto-payout eligible delivered orders older than windowDays business days.
|
|
289
295
|
* @param windowDays - number of business days since delivery
|
|
290
296
|
* @param cutoff - pre-computed business-day cutoff date (computed by caller)
|
|
297
|
+
*
|
|
298
|
+
* See {@link getEligibleForPayoutSweep} for the EMI-incomplete exclusion rationale.
|
|
291
299
|
*/
|
|
292
300
|
async getEligibleAutomatic(cutoff) {
|
|
293
301
|
const snap = await this.db
|
|
@@ -297,6 +305,27 @@ class OrderRepository extends BaseRepository {
|
|
|
297
305
|
.where(ORDER_FIELDS.UPDATED_AT, "<=", cutoff)
|
|
298
306
|
.limit(500)
|
|
299
307
|
.get();
|
|
308
|
+
return snap.docs
|
|
309
|
+
.map((d) => ({
|
|
310
|
+
id: d.id,
|
|
311
|
+
ref: d.ref,
|
|
312
|
+
data: this.decryptOrder({ id: d.id, ...d.data() }),
|
|
313
|
+
}))
|
|
314
|
+
.filter((o) => !o.data.emiEnabled || o.data.emiComplete);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Cloud Functions: EMI reminder sweep — orders on an active (not yet fully
|
|
318
|
+
* paid) EMI plan. Per-installment due-date filtering happens in the job
|
|
319
|
+
* itself since `emiInstallments` is an array field Firestore can't range-
|
|
320
|
+
* query on.
|
|
321
|
+
*/
|
|
322
|
+
async getActiveEmiOrders() {
|
|
323
|
+
const snap = await this.db
|
|
324
|
+
.collection(this.collection)
|
|
325
|
+
.where("emiEnabled", "==", true)
|
|
326
|
+
.where("emiComplete", "==", false)
|
|
327
|
+
.limit(500)
|
|
328
|
+
.get();
|
|
300
329
|
return snap.docs.map((d) => ({
|
|
301
330
|
id: d.id,
|
|
302
331
|
ref: d.ref,
|
|
@@ -5,14 +5,14 @@ import type { OrderStatus, PaymentStatus } from "../types";
|
|
|
5
5
|
import type { OrderType } from "../utils/order-splitter";
|
|
6
6
|
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
7
7
|
import type { ListingType } from "../../products/types";
|
|
8
|
-
|
|
8
|
+
/** Manual shipping is the only supported method — sellers enter carrier + tracking directly, no carrier API integration. */
|
|
9
|
+
export type ShippingMethod = "custom";
|
|
9
10
|
export type RefundType = "full" | "partial";
|
|
10
11
|
export type OrderPayoutStatus = "eligible" | "requested" | "paid";
|
|
11
12
|
export type RefundStatus = "pending" | "processing" | "completed" | "rejected";
|
|
12
13
|
/** Runtime-accessible shipping method values â€" use instead of bare string literals. */
|
|
13
14
|
export declare const ShippingMethodValues: {
|
|
14
15
|
readonly CUSTOM: "custom";
|
|
15
|
-
readonly SHIPROCKET: "shiprocket";
|
|
16
16
|
};
|
|
17
17
|
/** Runtime-accessible order status values â€" use instead of bare string literals. */
|
|
18
18
|
export declare const OrderStatusValues: {
|
|
@@ -43,7 +43,24 @@ export declare const PaymentMethodValues: {
|
|
|
43
43
|
readonly UPI_MANUAL: "upi_manual";
|
|
44
44
|
readonly RAZORPAY: "razorpay";
|
|
45
45
|
readonly ADMIN_BYPASS: "admin_bypass";
|
|
46
|
+
readonly EMI: "emi";
|
|
46
47
|
};
|
|
48
|
+
export type EmiInstallmentStatus = "pending" | "paid" | "overdue";
|
|
49
|
+
export interface EmiInstallment {
|
|
50
|
+
/** 1-based installment number. */
|
|
51
|
+
index: number;
|
|
52
|
+
dueDate: Date;
|
|
53
|
+
/** Installment amount in paise (principal share + surcharge share for this installment). */
|
|
54
|
+
amount: number;
|
|
55
|
+
status: EmiInstallmentStatus;
|
|
56
|
+
paidAt?: Date;
|
|
57
|
+
/** Buyer-uploaded UTR/reference number for this installment's manual payment. */
|
|
58
|
+
transactionId?: string;
|
|
59
|
+
/** Signed-URL media slug for the buyer's payment proof for this installment. */
|
|
60
|
+
proofUrl?: string;
|
|
61
|
+
/** Set once the reminder sweep has notified the buyer for this installment, so it isn't re-sent on every sweep run. */
|
|
62
|
+
reminderSentAt?: Date;
|
|
63
|
+
}
|
|
47
64
|
/** Runtime-accessible refund status values â€" use instead of bare string literals. */
|
|
48
65
|
export declare const RefundStatusValues: {
|
|
49
66
|
readonly PENDING: "pending";
|
|
@@ -141,15 +158,24 @@ export interface OrderDocument extends BaseDocument {
|
|
|
141
158
|
platformFee?: number;
|
|
142
159
|
depositAmount?: number;
|
|
143
160
|
codRemainingAmount?: number;
|
|
161
|
+
/** COD handling fee charged to the buyer: max(codHandlingFeeMinInPaise, subtotal × codHandlingFeePercent / 100). Only set when paymentMethod === "cod". */
|
|
162
|
+
codHandlingFee?: number;
|
|
163
|
+
emiEnabled?: boolean;
|
|
164
|
+
/** Number of monthly installments the buyer chose (2–6). */
|
|
165
|
+
emiTenureMonths?: number;
|
|
166
|
+
/** Down payment collected at checkout, in paise (emiTokenPercent × seller subtotal). */
|
|
167
|
+
emiTokenAmount?: number;
|
|
168
|
+
/** Extra cost of choosing EMI over full payment, in paise — split between platform and seller. */
|
|
169
|
+
emiSurchargeAmount?: number;
|
|
170
|
+
emiInstallments?: EmiInstallment[];
|
|
171
|
+
/** Sum of unpaid installment amounts, in paise. 0 once all installments are paid. */
|
|
172
|
+
emiRemainingBalance?: number;
|
|
173
|
+
/** True once every installment's status is "paid". Gates shipment unless the product's `allowShipBeforeEmiComplete` flag is set. */
|
|
174
|
+
emiComplete?: boolean;
|
|
144
175
|
shippingFee?: number;
|
|
145
176
|
shippingMethod?: ShippingMethod;
|
|
146
177
|
shippingCarrier?: string;
|
|
147
178
|
trackingUrl?: string;
|
|
148
|
-
shiprocketOrderId?: number;
|
|
149
|
-
shiprocketShipmentId?: number;
|
|
150
|
-
shiprocketAWB?: string;
|
|
151
|
-
shiprocketStatus?: string;
|
|
152
|
-
shiprocketUpdatedAt?: Date;
|
|
153
179
|
payoutStatus?: OrderPayoutStatus;
|
|
154
180
|
payoutId?: string;
|
|
155
181
|
offerId?: string;
|
|
@@ -5,7 +5,6 @@ import { generateOrderId } from "../../../utils/id-generators";
|
|
|
5
5
|
/** Runtime-accessible shipping method values â€" use instead of bare string literals. */
|
|
6
6
|
export const ShippingMethodValues = {
|
|
7
7
|
CUSTOM: "custom",
|
|
8
|
-
SHIPROCKET: "shiprocket",
|
|
9
8
|
};
|
|
10
9
|
/** Runtime-accessible order status values â€" use instead of bare string literals. */
|
|
11
10
|
export const OrderStatusValues = {
|
|
@@ -36,6 +35,7 @@ export const PaymentMethodValues = {
|
|
|
36
35
|
UPI_MANUAL: "upi_manual",
|
|
37
36
|
RAZORPAY: "razorpay",
|
|
38
37
|
ADMIN_BYPASS: "admin_bypass",
|
|
38
|
+
EMI: "emi",
|
|
39
39
|
};
|
|
40
40
|
/** Runtime-accessible refund status values â€" use instead of bare string literals. */
|
|
41
41
|
export const RefundStatusValues = {
|