@bash-app/bash-common 30.235.0 → 30.237.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/__tests__/statusEnums.test.js +88 -7
- package/dist/__tests__/statusEnums.test.js.map +1 -1
- package/dist/definitions.d.ts +45 -14
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +38 -17
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +8 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/mirroredPrismaEnums.d.ts +145 -0
- package/dist/mirroredPrismaEnums.d.ts.map +1 -0
- package/dist/mirroredPrismaEnums.js +136 -0
- package/dist/mirroredPrismaEnums.js.map +1 -0
- package/dist/utils/__tests__/nonprofitUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/nonprofitUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/nonprofitUtils.test.js +84 -0
- package/dist/utils/__tests__/nonprofitUtils.test.js.map +1 -0
- package/dist/utils/__tests__/paymentUtils.test.js +87 -0
- package/dist/utils/__tests__/paymentUtils.test.js.map +1 -1
- package/dist/utils/nonprofitUtils.d.ts +21 -0
- package/dist/utils/nonprofitUtils.d.ts.map +1 -0
- package/dist/utils/nonprofitUtils.js +29 -0
- package/dist/utils/nonprofitUtils.js.map +1 -0
- package/dist/utils/paymentUtils.d.ts +23 -0
- package/dist/utils/paymentUtils.d.ts.map +1 -1
- package/dist/utils/paymentUtils.js +24 -7
- package/dist/utils/paymentUtils.js.map +1 -1
- package/dist/utils/service/__tests__/billingCapUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/billingCapUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/billingCapUtils.test.js +120 -0
- package/dist/utils/service/__tests__/billingCapUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/cancellationPolicyRefundResolver.test.js +1 -1
- package/dist/utils/service/__tests__/cancellationPolicyRefundResolver.test.js.map +1 -1
- package/dist/utils/service/__tests__/eventPromoterPhase3.test.d.ts +2 -0
- package/dist/utils/service/__tests__/eventPromoterPhase3.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/eventPromoterPhase3.test.js +243 -0
- package/dist/utils/service/__tests__/eventPromoterPhase3.test.js.map +1 -0
- package/dist/utils/service/__tests__/eventPromoterUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/eventPromoterUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/eventPromoterUtils.test.js +333 -0
- package/dist/utils/service/__tests__/eventPromoterUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/offerAllowListUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/offerAllowListUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/offerAllowListUtils.test.js +52 -0
- package/dist/utils/service/__tests__/offerAllowListUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/offerComparisonUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/offerComparisonUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/offerComparisonUtils.test.js +111 -0
- package/dist/utils/service/__tests__/offerComparisonUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.js +155 -0
- package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/unifiedPricingResolver.test.d.ts +2 -0
- package/dist/utils/service/__tests__/unifiedPricingResolver.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/unifiedPricingResolver.test.js +77 -0
- package/dist/utils/service/__tests__/unifiedPricingResolver.test.js.map +1 -0
- package/dist/utils/service/__tests__/venueFBSettlementUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/venueFBSettlementUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/venueFBSettlementUtils.test.js +157 -0
- package/dist/utils/service/__tests__/venueFBSettlementUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/venueSettlementUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/venueSettlementUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/venueSettlementUtils.test.js +175 -0
- package/dist/utils/service/__tests__/venueSettlementUtils.test.js.map +1 -0
- package/dist/utils/service/__tests__/volunteerCompensationUtils.test.d.ts +2 -0
- package/dist/utils/service/__tests__/volunteerCompensationUtils.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/volunteerCompensationUtils.test.js +118 -0
- package/dist/utils/service/__tests__/volunteerCompensationUtils.test.js.map +1 -0
- package/dist/utils/service/apiServiceBookingApiUtils.d.ts.map +1 -1
- package/dist/utils/service/apiServiceBookingApiUtils.js +4 -0
- package/dist/utils/service/apiServiceBookingApiUtils.js.map +1 -1
- package/dist/utils/service/billingCapUtils.d.ts +86 -0
- package/dist/utils/service/billingCapUtils.d.ts.map +1 -0
- package/dist/utils/service/billingCapUtils.js +96 -0
- package/dist/utils/service/billingCapUtils.js.map +1 -0
- package/dist/utils/service/cancellationPolicyRefundResolver.d.ts +1 -1
- package/dist/utils/service/cancellationPolicyRefundResolver.d.ts.map +1 -1
- package/dist/utils/service/cancellationPolicyRefundResolver.js +1 -1
- package/dist/utils/service/cancellationPolicyRefundResolver.js.map +1 -1
- package/dist/utils/service/eventPromoterUtils.d.ts +319 -0
- package/dist/utils/service/eventPromoterUtils.d.ts.map +1 -0
- package/dist/utils/service/eventPromoterUtils.js +372 -0
- package/dist/utils/service/eventPromoterUtils.js.map +1 -0
- package/dist/utils/service/offerAllowListUtils.d.ts +42 -0
- package/dist/utils/service/offerAllowListUtils.d.ts.map +1 -0
- package/dist/utils/service/offerAllowListUtils.js +49 -0
- package/dist/utils/service/offerAllowListUtils.js.map +1 -0
- package/dist/utils/service/offerComparisonUtils.d.ts +69 -0
- package/dist/utils/service/offerComparisonUtils.d.ts.map +1 -0
- package/dist/utils/service/offerComparisonUtils.js +110 -0
- package/dist/utils/service/offerComparisonUtils.js.map +1 -0
- package/dist/utils/service/serviceBookingExposureUtils.d.ts +111 -0
- package/dist/utils/service/serviceBookingExposureUtils.d.ts.map +1 -0
- package/dist/utils/service/serviceBookingExposureUtils.js +133 -0
- package/dist/utils/service/serviceBookingExposureUtils.js.map +1 -0
- package/dist/utils/service/serviceBookingTypes.d.ts +1 -1
- package/dist/utils/service/serviceBookingTypes.d.ts.map +1 -1
- package/dist/utils/service/serviceUtils.d.ts +2 -1
- package/dist/utils/service/serviceUtils.d.ts.map +1 -1
- package/dist/utils/service/serviceUtils.js +17 -16
- package/dist/utils/service/serviceUtils.js.map +1 -1
- package/dist/utils/service/unifiedPricingResolver.d.ts +67 -0
- package/dist/utils/service/unifiedPricingResolver.d.ts.map +1 -0
- package/dist/utils/service/unifiedPricingResolver.js +75 -0
- package/dist/utils/service/unifiedPricingResolver.js.map +1 -0
- package/dist/utils/service/venueFBSettlementUtils.d.ts +122 -0
- package/dist/utils/service/venueFBSettlementUtils.d.ts.map +1 -0
- package/dist/utils/service/venueFBSettlementUtils.js +106 -0
- package/dist/utils/service/venueFBSettlementUtils.js.map +1 -0
- package/dist/utils/service/venueSettlementUtils.d.ts +107 -0
- package/dist/utils/service/venueSettlementUtils.d.ts.map +1 -0
- package/dist/utils/service/venueSettlementUtils.js +117 -0
- package/dist/utils/service/venueSettlementUtils.js.map +1 -0
- package/dist/utils/service/volunteerCompensationUtils.d.ts +75 -0
- package/dist/utils/service/volunteerCompensationUtils.d.ts.map +1 -0
- package/dist/utils/service/volunteerCompensationUtils.js +88 -0
- package/dist/utils/service/volunteerCompensationUtils.js.map +1 -0
- package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.d.ts +2 -0
- package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.d.ts.map +1 -0
- package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.js +67 -0
- package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.js.map +1 -0
- package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.d.ts +2 -0
- package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.d.ts.map +1 -0
- package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.js +71 -0
- package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.js.map +1 -0
- package/dist/utils/venueLoyalty/eligibilityUtils.d.ts +33 -0
- package/dist/utils/venueLoyalty/eligibilityUtils.d.ts.map +1 -0
- package/dist/utils/venueLoyalty/eligibilityUtils.js +49 -0
- package/dist/utils/venueLoyalty/eligibilityUtils.js.map +1 -0
- package/dist/utils/venueLoyalty/redemptionCodeUtils.d.ts +35 -0
- package/dist/utils/venueLoyalty/redemptionCodeUtils.d.ts.map +1 -0
- package/dist/utils/venueLoyalty/redemptionCodeUtils.js +74 -0
- package/dist/utils/venueLoyalty/redemptionCodeUtils.js.map +1 -0
- package/dist/venueLoyaltyRedemption.d.ts +146 -1
- package/dist/venueLoyaltyRedemption.d.ts.map +1 -1
- package/dist/venueLoyaltyRedemption.js +18 -2
- package/dist/venueLoyaltyRedemption.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +638 -214
- package/src/__tests__/statusEnums.test.ts +119 -11
- package/src/definitions.ts +65 -22
- package/src/extendedSchemas.ts +8 -0
- package/src/index.ts +16 -6
- package/src/mirroredPrismaEnums.ts +181 -0
- package/src/utils/__tests__/nonprofitUtils.test.ts +117 -0
- package/src/utils/__tests__/paymentUtils.test.ts +93 -0
- package/src/utils/nonprofitUtils.ts +44 -0
- package/src/utils/paymentUtils.ts +33 -7
- package/src/utils/service/__tests__/billingCapUtils.test.ts +175 -0
- package/src/utils/service/__tests__/cancellationPolicyRefundResolver.test.ts +1 -1
- package/src/utils/service/__tests__/eventPromoterPhase3.test.ts +296 -0
- package/src/utils/service/__tests__/eventPromoterUtils.test.ts +396 -0
- package/src/utils/service/__tests__/offerAllowListUtils.test.ts +76 -0
- package/src/utils/service/__tests__/offerComparisonUtils.test.ts +124 -0
- package/src/utils/service/__tests__/serviceBookingExposureUtils.test.ts +171 -0
- package/src/utils/service/__tests__/unifiedPricingResolver.test.ts +83 -0
- package/src/utils/service/__tests__/venueSettlementUtils.test.ts +219 -0
- package/src/utils/service/__tests__/volunteerCompensationUtils.test.ts +172 -0
- package/src/utils/service/apiServiceBookingApiUtils.ts +4 -0
- package/src/utils/service/billingCapUtils.ts +145 -0
- package/src/utils/service/cancellationPolicyRefundResolver.ts +1 -1
- package/src/utils/service/eventPromoterUtils.ts +644 -0
- package/src/utils/service/offerAllowListUtils.ts +81 -0
- package/src/utils/service/offerComparisonUtils.ts +197 -0
- package/src/utils/service/serviceBookingExposureUtils.ts +218 -0
- package/src/utils/service/serviceBookingTypes.ts +4 -0
- package/src/utils/service/serviceUtils.ts +18 -21
- package/src/utils/service/unifiedPricingResolver.ts +149 -0
- package/src/utils/service/venueSettlementUtils.ts +198 -0
- package/src/utils/service/volunteerCompensationUtils.ts +145 -0
- package/src/utils/venueLoyalty/__tests__/eligibilityUtils.test.ts +103 -0
- package/src/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.ts +92 -0
- package/src/utils/venueLoyalty/eligibilityUtils.ts +84 -0
- package/src/utils/venueLoyalty/redemptionCodeUtils.ts +94 -0
- package/src/venueLoyaltyRedemption.ts +177 -2
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 4 of the unified-pricing roadmap — host-side pricing-model allow-list
|
|
3
|
+
* validation.
|
|
4
|
+
*
|
|
5
|
+
* Each vertical request entity (`VendorBookingRequest`,
|
|
6
|
+
* `ExhibitorBookingRequest`, `SponsorBookingRequest`) carries an optional
|
|
7
|
+
* `pricingModelAllowList String[]`. When empty, the host hasn't restricted
|
|
8
|
+
* anything and providers may bid in any of their supported models. When
|
|
9
|
+
* non-empty, providers can only bid in models that appear in the list.
|
|
10
|
+
*
|
|
11
|
+
* Pure function so the wizard, api validators, and offer-suggestion AI all
|
|
12
|
+
* share one rule.
|
|
13
|
+
*/
|
|
14
|
+
import type { PricingModel } from "@prisma/client";
|
|
15
|
+
|
|
16
|
+
export type AllowListValidation =
|
|
17
|
+
| { ok: true }
|
|
18
|
+
| {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: string;
|
|
21
|
+
offered: PricingModel | string;
|
|
22
|
+
allowList: ReadonlyArray<string>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns `{ ok: true }` if either:
|
|
27
|
+
* - the allow-list is empty / null (host has no restriction), or
|
|
28
|
+
* - the offered model appears in the allow-list.
|
|
29
|
+
*
|
|
30
|
+
* Otherwise returns `{ ok: false }` with a friendly reason suitable for
|
|
31
|
+
* surfacing in the SendOfferSheet error region.
|
|
32
|
+
*/
|
|
33
|
+
export function validateOfferAgainstAllowList(args: {
|
|
34
|
+
offered: PricingModel | string | null | undefined;
|
|
35
|
+
allowList: ReadonlyArray<string> | null | undefined;
|
|
36
|
+
}): AllowListValidation {
|
|
37
|
+
if (!args.offered) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
reason: "Offer is missing a pricing model.",
|
|
41
|
+
offered: "",
|
|
42
|
+
allowList: args.allowList ?? [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const list = args.allowList ?? [];
|
|
46
|
+
if (list.length === 0) {
|
|
47
|
+
return { ok: true };
|
|
48
|
+
}
|
|
49
|
+
if (list.includes(args.offered)) {
|
|
50
|
+
return { ok: true };
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
reason: `Host accepts bids priced as ${list.join(
|
|
55
|
+
", "
|
|
56
|
+
)}. ${args.offered} is not on the list.`,
|
|
57
|
+
offered: args.offered,
|
|
58
|
+
allowList: list,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Per-vertical sensible defaults for what a wizard should pre-check in the
|
|
64
|
+
* "I'll consider bids priced as…" group when the host hasn't customized.
|
|
65
|
+
* Used by Phase 4 wizard sections; safe to share with the AI service so its
|
|
66
|
+
* suggestions match the wizard's defaults.
|
|
67
|
+
*/
|
|
68
|
+
export const DEFAULT_PRICING_MODEL_ALLOW_LIST_BY_SERVICE_TYPE: Record<
|
|
69
|
+
string,
|
|
70
|
+
ReadonlyArray<PricingModel>
|
|
71
|
+
> = {
|
|
72
|
+
// Strings match the Prisma `ServiceTypes` enum values (see schema.prisma).
|
|
73
|
+
Vendors: ["FLAT_FEE", "PRODUCT_SALES_PERCENTAGE"],
|
|
74
|
+
Exhibitors: ["FLAT_FEE"],
|
|
75
|
+
Sponsors: ["TIERED", "FLAT_FEE"],
|
|
76
|
+
Venues: ["FLAT_FEE", "TICKET_REVENUE_PERCENTAGE"],
|
|
77
|
+
EntertainmentServices: ["HOURLY", "FLAT_FEE"],
|
|
78
|
+
EventServices: ["FLAT_FEE", "PER_ATTENDEE"],
|
|
79
|
+
Volunteers: ["FLAT_FEE"],
|
|
80
|
+
Organizations: ["FLAT_FEE"],
|
|
81
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 5 of the unified-pricing roadmap — pure projection of a `ServiceBookingOffer`
|
|
3
|
+
* candidate into expected / worst-case / best-case totals (in cents).
|
|
4
|
+
*
|
|
5
|
+
* Used by:
|
|
6
|
+
* - the offer-suggestion AI to return one suggestion per allowed model with
|
|
7
|
+
* bands the host can compare side-by-side,
|
|
8
|
+
* - the SendOfferSheet preview row that renders the same bands,
|
|
9
|
+
* - the api validator that double-checks an accepted offer against the
|
|
10
|
+
* host's expected attendees and any host-side caps.
|
|
11
|
+
*
|
|
12
|
+
* Heuristics for `worstCaseCents` / `bestCaseCents`:
|
|
13
|
+
* - `FLAT_FEE` / `HOURLY` / `PER_DAY` / `CUSTOM` — all three bands equal the
|
|
14
|
+
* expected total (no variability).
|
|
15
|
+
* - `PER_ATTENDEE` / `PER_PAID_ATTENDEE` — worst case = floor (minimumQuantity
|
|
16
|
+
* * baseRateCents, capped by minimumChargeCents); best case = capped to
|
|
17
|
+
* `maxBillableCents` when present, else `expectedAttendees * 1.5`.
|
|
18
|
+
* - `PER_BASHPOINTS_ATTENDEE` — same shape but in BashPoints, so we surface
|
|
19
|
+
* `expectedTotalBp` and the USD bands return null.
|
|
20
|
+
* - `TICKET_REVENUE_PERCENTAGE` / `PRODUCT_SALES_PERCENTAGE` — caller passes
|
|
21
|
+
* an `expectedBasisCents` (usually the bash's projected ticket revenue or
|
|
22
|
+
* vendor gross sales). Worst case = 0 if pre-sale, best case = basis * pct.
|
|
23
|
+
* - `TIERED` — worst case = lowest tier price, best case = highest tier
|
|
24
|
+
* price; expected resolves via the supplied `tieredExpectedTierCents`.
|
|
25
|
+
*/
|
|
26
|
+
import type { PricingModel } from "@prisma/client";
|
|
27
|
+
|
|
28
|
+
export interface OfferComparisonInput {
|
|
29
|
+
pricingModel: PricingModel | string;
|
|
30
|
+
baseRateCents?: number | null;
|
|
31
|
+
baseRateBashPoints?: number | null;
|
|
32
|
+
minimumChargeCents?: number | null;
|
|
33
|
+
minimumQuantity?: number | null;
|
|
34
|
+
maxBillableCents?: number | null;
|
|
35
|
+
/** Bash's expectedAttendees at offer time. */
|
|
36
|
+
expectedAttendees?: number | null;
|
|
37
|
+
/** Optional expected basis for revenue-share models. */
|
|
38
|
+
expectedBasisCents?: number | null;
|
|
39
|
+
/** Percentage (0..100) for revenue-share models. */
|
|
40
|
+
percentage?: number | null;
|
|
41
|
+
/** Pre-resolved expected total for TIERED (already chosen tier). */
|
|
42
|
+
tieredExpectedTierCents?: number | null;
|
|
43
|
+
tieredLowestTierCents?: number | null;
|
|
44
|
+
tieredHighestTierCents?: number | null;
|
|
45
|
+
/** Optional flat amount the caller already computed (e.g. from priceToBook). */
|
|
46
|
+
flatRateCents?: number | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface OfferComparisonResult {
|
|
50
|
+
/** Most-likely total in USD cents. `null` for BashPoints-only models. */
|
|
51
|
+
expectedTotalCents: number | null;
|
|
52
|
+
/** Worst case in USD cents the host could end up owing (or null for BP). */
|
|
53
|
+
worstCaseCents: number | null;
|
|
54
|
+
/** Best case for the host (cheapest plausible total). */
|
|
55
|
+
bestCaseCents: number | null;
|
|
56
|
+
/** Same triple in BashPoints when the model settles in BP. */
|
|
57
|
+
expectedTotalBp: number | null;
|
|
58
|
+
worstCaseBp: number | null;
|
|
59
|
+
bestCaseBp: number | null;
|
|
60
|
+
/**
|
|
61
|
+
* Plain-English tradeoff sentence to surface next to the bands. AI may
|
|
62
|
+
* override with its own copy; this is a deterministic fallback.
|
|
63
|
+
*/
|
|
64
|
+
reasoning: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function nn(v: number | null | undefined): number {
|
|
68
|
+
return v == null || !Number.isFinite(v) || v <= 0 ? 0 : Math.round(v);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function fmt(cents: number): string {
|
|
72
|
+
return `$${(cents / 100).toFixed(0)}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Project an offer candidate into expected / worst / best totals.
|
|
77
|
+
* Returns sensible-but-defensive defaults if the input model is unknown.
|
|
78
|
+
*/
|
|
79
|
+
export function computeOfferComparisonBands(
|
|
80
|
+
input: OfferComparisonInput
|
|
81
|
+
): OfferComparisonResult {
|
|
82
|
+
const expected = nn(input.expectedAttendees);
|
|
83
|
+
const minQty = nn(input.minimumQuantity);
|
|
84
|
+
|
|
85
|
+
switch (input.pricingModel) {
|
|
86
|
+
case "FLAT_FEE":
|
|
87
|
+
case "HOURLY":
|
|
88
|
+
case "PER_DAY":
|
|
89
|
+
case "CUSTOM": {
|
|
90
|
+
const total =
|
|
91
|
+
nn(input.flatRateCents) || nn(input.baseRateCents) || 0;
|
|
92
|
+
return {
|
|
93
|
+
expectedTotalCents: total,
|
|
94
|
+
worstCaseCents: total,
|
|
95
|
+
bestCaseCents: total,
|
|
96
|
+
expectedTotalBp: null,
|
|
97
|
+
worstCaseBp: null,
|
|
98
|
+
bestCaseBp: null,
|
|
99
|
+
reasoning:
|
|
100
|
+
total > 0
|
|
101
|
+
? `Fixed price: you pay ${fmt(total)} regardless of turnout.`
|
|
102
|
+
: "Fixed price — provider has not set a rate.",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
case "PER_ATTENDEE":
|
|
107
|
+
case "PER_PAID_ATTENDEE": {
|
|
108
|
+
const rate = nn(input.baseRateCents);
|
|
109
|
+
const expectedTotal = expected * rate;
|
|
110
|
+
const floor = Math.max(
|
|
111
|
+
nn(input.minimumChargeCents),
|
|
112
|
+
minQty * rate
|
|
113
|
+
);
|
|
114
|
+
const worst = Math.max(expectedTotal, floor);
|
|
115
|
+
const ceiling =
|
|
116
|
+
nn(input.maxBillableCents) ||
|
|
117
|
+
Math.max(expectedTotal, Math.round(expected * rate * 1.5));
|
|
118
|
+
const best = Math.max(floor, 0);
|
|
119
|
+
return {
|
|
120
|
+
expectedTotalCents: expectedTotal,
|
|
121
|
+
worstCaseCents: ceiling,
|
|
122
|
+
bestCaseCents: best,
|
|
123
|
+
expectedTotalBp: null,
|
|
124
|
+
worstCaseBp: null,
|
|
125
|
+
bestCaseBp: null,
|
|
126
|
+
reasoning: `Per-${input.pricingModel === "PER_PAID_ATTENDEE" ? "paid-" : ""}attendee: expected ${fmt(
|
|
127
|
+
expectedTotal
|
|
128
|
+
)} at ${expected} guests, with a floor of ${fmt(floor)} and a host cap of ${fmt(ceiling)}.`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
case "PER_BASHPOINTS_ATTENDEE": {
|
|
133
|
+
const rate = nn(input.baseRateBashPoints);
|
|
134
|
+
const expectedTotalBp = expected * rate;
|
|
135
|
+
const floorBp = minQty * rate;
|
|
136
|
+
const worstBp = Math.max(expectedTotalBp, floorBp);
|
|
137
|
+
const bestBp = Math.max(floorBp, 0);
|
|
138
|
+
return {
|
|
139
|
+
expectedTotalCents: null,
|
|
140
|
+
worstCaseCents: null,
|
|
141
|
+
bestCaseCents: null,
|
|
142
|
+
expectedTotalBp,
|
|
143
|
+
worstCaseBp: worstBp,
|
|
144
|
+
bestCaseBp: bestBp,
|
|
145
|
+
reasoning: `Per-attendee BashPoints: expected ${expectedTotalBp} BP at ${expected} guests, floor ${floorBp} BP.`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
case "TICKET_REVENUE_PERCENTAGE":
|
|
150
|
+
case "PRODUCT_SALES_PERCENTAGE": {
|
|
151
|
+
const basis = nn(input.expectedBasisCents);
|
|
152
|
+
const pct = Math.max(0, Math.min(100, input.percentage ?? 0));
|
|
153
|
+
const expectedTotal = Math.round((basis * pct) / 100);
|
|
154
|
+
return {
|
|
155
|
+
expectedTotalCents: expectedTotal,
|
|
156
|
+
worstCaseCents: 0,
|
|
157
|
+
bestCaseCents: expectedTotal,
|
|
158
|
+
expectedTotalBp: null,
|
|
159
|
+
worstCaseBp: null,
|
|
160
|
+
bestCaseBp: null,
|
|
161
|
+
reasoning: `Revenue share: provider takes ${pct}% of ${fmt(
|
|
162
|
+
basis
|
|
163
|
+
)} projected. Worst case for you (slow night, no revenue): $0.`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
case "TIERED": {
|
|
168
|
+
const exp = nn(input.tieredExpectedTierCents);
|
|
169
|
+
const low = nn(input.tieredLowestTierCents);
|
|
170
|
+
const high = nn(input.tieredHighestTierCents);
|
|
171
|
+
return {
|
|
172
|
+
expectedTotalCents: exp || low || high || 0,
|
|
173
|
+
worstCaseCents: high || exp || low,
|
|
174
|
+
bestCaseCents: low || exp || high,
|
|
175
|
+
expectedTotalBp: null,
|
|
176
|
+
worstCaseBp: null,
|
|
177
|
+
bestCaseBp: null,
|
|
178
|
+
reasoning: `Tiered: from ${fmt(low)} to ${fmt(
|
|
179
|
+
high
|
|
180
|
+
)} depending on the tier you pick.`,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
default: {
|
|
185
|
+
const fallback = nn(input.flatRateCents) || nn(input.baseRateCents);
|
|
186
|
+
return {
|
|
187
|
+
expectedTotalCents: fallback,
|
|
188
|
+
worstCaseCents: fallback,
|
|
189
|
+
bestCaseCents: fallback,
|
|
190
|
+
expectedTotalBp: null,
|
|
191
|
+
worstCaseBp: null,
|
|
192
|
+
bestCaseBp: null,
|
|
193
|
+
reasoning: `Unrecognized pricing model "${input.pricingModel}" — treated as flat.`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 0 adoption guardrails — aggregate cost exposure for a bash's service
|
|
3
|
+
* bookings. Pure functions so the api endpoint (Prisma query, then this util)
|
|
4
|
+
* and bash-app (display) share one source of truth.
|
|
5
|
+
*
|
|
6
|
+
* Each booking resolves to:
|
|
7
|
+
* - `expectedCents` — the most-likely total at expected attendance.
|
|
8
|
+
* - `worstCaseCents` — the dollar ceiling if the host's caps trip. For flat
|
|
9
|
+
* models this equals `expectedCents` (no variance). For variable models it
|
|
10
|
+
* equals `maxBillableCents` if set; otherwise `1.5x expected` (matches the
|
|
11
|
+
* `defaultMaxBillableCents` heuristic in `billingCapUtils.ts`).
|
|
12
|
+
*
|
|
13
|
+
* Forward-looking: the input shape uses the unified pricing block fields
|
|
14
|
+
* (`pricingModel`, `baseRateCents`, etc.). Phase 1 adds them to every subtype;
|
|
15
|
+
* Phase 0 callers passing in `pricingModel: null` for legacy bookings still get
|
|
16
|
+
* a sensible flat-fee fallback.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
DEFAULT_MAX_BILLABLE_MULTIPLIER,
|
|
21
|
+
isFlatPricingModel,
|
|
22
|
+
} from "./billingCapUtils";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Pricing-model strings recognized by the exposure util. Stays a string
|
|
26
|
+
* literal (not the Prisma enum) so this util compiles for the browser bundle.
|
|
27
|
+
*/
|
|
28
|
+
export const KNOWN_VARIABLE_PRICING_MODELS = [
|
|
29
|
+
"PER_ATTENDEE",
|
|
30
|
+
"PER_PAID_ATTENDEE",
|
|
31
|
+
"PER_BASHPOINTS_ATTENDEE",
|
|
32
|
+
"TICKET_REVENUE_PERCENTAGE",
|
|
33
|
+
"PRODUCT_SALES_PERCENTAGE",
|
|
34
|
+
"TIERED",
|
|
35
|
+
"CUSTOM",
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
export interface ServiceBookingExposureInput {
|
|
39
|
+
bookingId: string;
|
|
40
|
+
/** Display label (e.g. service name). Echoed back for UI. */
|
|
41
|
+
label: string;
|
|
42
|
+
/**
|
|
43
|
+
* The pricing model from the booked service's subtype, if known. Phase 0
|
|
44
|
+
* bookings that predate the unified block pass `null` — exposure falls
|
|
45
|
+
* back to flat-rate math.
|
|
46
|
+
*/
|
|
47
|
+
pricingModel?: string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Per-unit rate the booking is priced at. Cents-per-attendee for
|
|
50
|
+
* PER_ATTENDEE; cents-per-hour for HOURLY; etc. Optional fallback.
|
|
51
|
+
*/
|
|
52
|
+
baseRateCents?: number | null;
|
|
53
|
+
/**
|
|
54
|
+
* Expected attendance at booking time (snapshot from
|
|
55
|
+
* `bashEvent.expectedAttendees`).
|
|
56
|
+
*/
|
|
57
|
+
expectedAttendeesAtBooking?: number | null;
|
|
58
|
+
/** Host-set ceiling on billable check-ins for PER_ATTENDEE bookings. */
|
|
59
|
+
maxAttendeesAttributable?: number | null;
|
|
60
|
+
/**
|
|
61
|
+
* Phase 0 soft cap: host-set per-booking dollar ceiling. Overrides the
|
|
62
|
+
* 1.5x worst-case heuristic when set.
|
|
63
|
+
*/
|
|
64
|
+
maxBillableCents?: number | null;
|
|
65
|
+
/**
|
|
66
|
+
* The booking's grand total (cents) when it was confirmed — used as the
|
|
67
|
+
* fallback "expected" amount for non-variable bookings whose pricing model
|
|
68
|
+
* isn't yet tracked. Mirrors `ServiceBooking.totalATBCents`.
|
|
69
|
+
*/
|
|
70
|
+
totalATBCents?: number | null;
|
|
71
|
+
/**
|
|
72
|
+
* Optional flat-rate snapshot (`ServiceBooking.flatRateCents`). Used as a
|
|
73
|
+
* narrow fallback when both `pricingModel` and `totalATBCents` are missing.
|
|
74
|
+
*/
|
|
75
|
+
flatRateCents?: number | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ServiceBookingExposure {
|
|
79
|
+
bookingId: string;
|
|
80
|
+
label: string;
|
|
81
|
+
pricingModel: string | null;
|
|
82
|
+
isVariable: boolean;
|
|
83
|
+
/** Most likely total (cents). */
|
|
84
|
+
expectedCents: number;
|
|
85
|
+
/** Worst-case total (cents) the host might owe if the cap trips. */
|
|
86
|
+
worstCaseCents: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface AggregateExposureSummary {
|
|
90
|
+
/** Sum of `expectedCents` across all bookings (cents). */
|
|
91
|
+
projectedTotalCents: number;
|
|
92
|
+
/** Sum of `worstCaseCents` across all bookings (cents). */
|
|
93
|
+
worstCaseTotalCents: number;
|
|
94
|
+
/**
|
|
95
|
+
* Per-booking breakdown — preserves input order so callers can render rows
|
|
96
|
+
* alongside the booking list without re-sorting.
|
|
97
|
+
*/
|
|
98
|
+
byBooking: ServiceBookingExposure[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns `true` for any pricing model whose total depends on event-day
|
|
103
|
+
* variables (attendance, revenue, etc.).
|
|
104
|
+
*/
|
|
105
|
+
export function isVariablePricingModel(
|
|
106
|
+
model: string | null | undefined
|
|
107
|
+
): boolean {
|
|
108
|
+
if (!model) return false;
|
|
109
|
+
if (isFlatPricingModel(model)) return false;
|
|
110
|
+
return (KNOWN_VARIABLE_PRICING_MODELS as readonly string[]).includes(model);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resolve one booking's exposure (expected + worst case). Pure.
|
|
115
|
+
*
|
|
116
|
+
* Decision matrix:
|
|
117
|
+
* - PER_ATTENDEE / PER_PAID_ATTENDEE:
|
|
118
|
+
* expected = expectedAttendees * baseRateCents
|
|
119
|
+
* worst = maxBillableCents ?? maxAttendeesAttributable * baseRateCents
|
|
120
|
+
* ?? expected * 1.5
|
|
121
|
+
* - PER_BASHPOINTS_ATTENDEE: same shape but reported in cents-of-BP-equivalent.
|
|
122
|
+
* Caller should treat this booking's contribution as informational only;
|
|
123
|
+
* `expectedCents`/`worstCaseCents` reflect BP units, not dollars.
|
|
124
|
+
* - TICKET_REVENUE_PERCENTAGE / PRODUCT_SALES_PERCENTAGE / TIERED / CUSTOM:
|
|
125
|
+
* expected = totalATBCents ?? 0
|
|
126
|
+
* worst = maxBillableCents ?? expected * 1.5 (variance unknown without
|
|
127
|
+
* settlement basis math — see Phase 2 for venue rev-share).
|
|
128
|
+
* - FLAT_FEE / HOURLY / PER_DAY (or null pricingModel): flat → expected = worst.
|
|
129
|
+
*/
|
|
130
|
+
export function computeServiceBookingExposure(
|
|
131
|
+
input: ServiceBookingExposureInput
|
|
132
|
+
): ServiceBookingExposure {
|
|
133
|
+
const flatFallback =
|
|
134
|
+
input.totalATBCents ?? input.flatRateCents ?? 0;
|
|
135
|
+
|
|
136
|
+
const variable = isVariablePricingModel(input.pricingModel);
|
|
137
|
+
|
|
138
|
+
if (!variable) {
|
|
139
|
+
return {
|
|
140
|
+
bookingId: input.bookingId,
|
|
141
|
+
label: input.label,
|
|
142
|
+
pricingModel: input.pricingModel ?? null,
|
|
143
|
+
isVariable: false,
|
|
144
|
+
expectedCents: Math.max(0, flatFallback),
|
|
145
|
+
worstCaseCents: Math.max(0, flatFallback),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const expectedAttendees = Math.max(
|
|
150
|
+
0,
|
|
151
|
+
Math.floor(input.expectedAttendeesAtBooking ?? 0)
|
|
152
|
+
);
|
|
153
|
+
const baseRate = Math.max(0, Math.floor(input.baseRateCents ?? 0));
|
|
154
|
+
|
|
155
|
+
// For attendee-driven models, expected = N * rate.
|
|
156
|
+
const isAttendeeDriven =
|
|
157
|
+
input.pricingModel === "PER_ATTENDEE" ||
|
|
158
|
+
input.pricingModel === "PER_PAID_ATTENDEE" ||
|
|
159
|
+
input.pricingModel === "PER_BASHPOINTS_ATTENDEE";
|
|
160
|
+
|
|
161
|
+
let expected: number;
|
|
162
|
+
if (isAttendeeDriven) {
|
|
163
|
+
expected = expectedAttendees * baseRate;
|
|
164
|
+
} else {
|
|
165
|
+
// Revenue-share / tiered / custom — totalATBCents is the most we know.
|
|
166
|
+
expected = Math.max(0, flatFallback);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Worst case prefers the explicit `maxBillableCents` snapshot, then the
|
|
170
|
+
// attendee ceiling math, then a 1.5x fallback.
|
|
171
|
+
let worst: number;
|
|
172
|
+
if (input.maxBillableCents != null && input.maxBillableCents > 0) {
|
|
173
|
+
worst = input.maxBillableCents;
|
|
174
|
+
} else if (
|
|
175
|
+
isAttendeeDriven &&
|
|
176
|
+
input.maxAttendeesAttributable != null &&
|
|
177
|
+
input.maxAttendeesAttributable > 0
|
|
178
|
+
) {
|
|
179
|
+
worst = input.maxAttendeesAttributable * baseRate;
|
|
180
|
+
} else if (expected > 0) {
|
|
181
|
+
worst = Math.ceil(expected * DEFAULT_MAX_BILLABLE_MULTIPLIER);
|
|
182
|
+
} else {
|
|
183
|
+
worst = 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Sanity: worst should never be below expected.
|
|
187
|
+
worst = Math.max(worst, expected);
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
bookingId: input.bookingId,
|
|
191
|
+
label: input.label,
|
|
192
|
+
pricingModel: input.pricingModel ?? null,
|
|
193
|
+
isVariable: true,
|
|
194
|
+
expectedCents: expected,
|
|
195
|
+
worstCaseCents: worst,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Sum a list of booking exposures into the host-facing summary used by
|
|
201
|
+
* the budget step's projected-cost and worst-case lines.
|
|
202
|
+
*/
|
|
203
|
+
export function summarizeServiceBookingExposures(
|
|
204
|
+
inputs: ServiceBookingExposureInput[]
|
|
205
|
+
): AggregateExposureSummary {
|
|
206
|
+
const byBooking = inputs.map(computeServiceBookingExposure);
|
|
207
|
+
let projected = 0;
|
|
208
|
+
let worstCase = 0;
|
|
209
|
+
for (const row of byBooking) {
|
|
210
|
+
projected += row.expectedCents;
|
|
211
|
+
worstCase += row.worstCaseCents;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
projectedTotalCents: projected,
|
|
215
|
+
worstCaseTotalCents: worstCase,
|
|
216
|
+
byBooking,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
@@ -63,6 +63,10 @@ export type ServiceBookingRequiredData = MakeNullablePropsOptional<
|
|
|
63
63
|
| "creatorId"
|
|
64
64
|
| "creator"
|
|
65
65
|
| "checkout"
|
|
66
|
+
// Event Promoter settlement fields — DB applies defaults at creation,
|
|
67
|
+
// so callers building a new booking shape may omit them.
|
|
68
|
+
| "settlementStatus"
|
|
69
|
+
| "settlementAttempts"
|
|
66
70
|
>
|
|
67
71
|
>;
|
|
68
72
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
ServiceSubscriptionStatus,
|
|
5
|
-
ServiceTypes,
|
|
6
|
-
} from "@prisma/client";
|
|
1
|
+
import { Service, ServiceSubscriptionStatus, ServiceTypes } from "@prisma/client";
|
|
2
|
+
import type { ServiceCancellationPolicy as ServiceCancellationPolicyOption } from "@prisma/client";
|
|
3
|
+
import { ServiceCancellationPolicy } from "../../mirroredPrismaEnums.js";
|
|
7
4
|
import {
|
|
8
5
|
ServiceExt,
|
|
9
6
|
ServiceExtNoIds,
|
|
@@ -27,12 +24,12 @@ export type ServiceCancellationPolicyMap = {
|
|
|
27
24
|
};
|
|
28
25
|
|
|
29
26
|
export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
30
|
-
[
|
|
27
|
+
[ServiceCancellationPolicy.None]: {
|
|
31
28
|
name: "None",
|
|
32
29
|
refundPolicy: [],
|
|
33
30
|
description: "No cancellation policy.",
|
|
34
31
|
},
|
|
35
|
-
[
|
|
32
|
+
[ServiceCancellationPolicy.VeryFlexible]: {
|
|
36
33
|
name: "Very Flexible",
|
|
37
34
|
refundPolicy: [
|
|
38
35
|
{
|
|
@@ -41,7 +38,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
41
38
|
},
|
|
42
39
|
],
|
|
43
40
|
},
|
|
44
|
-
[
|
|
41
|
+
[ServiceCancellationPolicy.Flexible]: {
|
|
45
42
|
name: "Flexible",
|
|
46
43
|
refundPolicy: [
|
|
47
44
|
{
|
|
@@ -54,7 +51,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
54
51
|
},
|
|
55
52
|
],
|
|
56
53
|
},
|
|
57
|
-
[
|
|
54
|
+
[ServiceCancellationPolicy.Standard30Day]: {
|
|
58
55
|
name: "Standard 30 Day",
|
|
59
56
|
refundPolicy: [
|
|
60
57
|
{
|
|
@@ -67,7 +64,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
67
64
|
},
|
|
68
65
|
],
|
|
69
66
|
},
|
|
70
|
-
[
|
|
67
|
+
[ServiceCancellationPolicy.Standard90Day]: {
|
|
71
68
|
name: "Standard 90 Day",
|
|
72
69
|
refundPolicy: [
|
|
73
70
|
{
|
|
@@ -81,7 +78,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
81
78
|
],
|
|
82
79
|
},
|
|
83
80
|
// Vendor-specific policies (vendor pays host, different language needed)
|
|
84
|
-
[
|
|
81
|
+
[ServiceCancellationPolicy.VendorFlexible]: {
|
|
85
82
|
name: "Vendor Flexible",
|
|
86
83
|
refundPolicy: [
|
|
87
84
|
{
|
|
@@ -95,7 +92,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
95
92
|
],
|
|
96
93
|
description: "Flexible policy for vendor bookings",
|
|
97
94
|
},
|
|
98
|
-
[
|
|
95
|
+
[ServiceCancellationPolicy.VendorStandard]: {
|
|
99
96
|
name: "Vendor Standard",
|
|
100
97
|
refundPolicy: [
|
|
101
98
|
{
|
|
@@ -109,7 +106,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
109
106
|
],
|
|
110
107
|
description: "Standard policy for vendor bookings",
|
|
111
108
|
},
|
|
112
|
-
[
|
|
109
|
+
[ServiceCancellationPolicy.VendorStrict]: {
|
|
113
110
|
name: "Vendor Strict",
|
|
114
111
|
refundPolicy: [
|
|
115
112
|
{
|
|
@@ -124,7 +121,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
124
121
|
description: "Strict policy for vendor bookings with longer notice periods",
|
|
125
122
|
},
|
|
126
123
|
// Exhibitor / Sponsor: same tier math as vendor; separate enum + copy for role clarity
|
|
127
|
-
[
|
|
124
|
+
[ServiceCancellationPolicy.ExhibitorFlexible]: {
|
|
128
125
|
name: "Exhibitor Flexible",
|
|
129
126
|
refundPolicy: [
|
|
130
127
|
{
|
|
@@ -138,7 +135,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
138
135
|
],
|
|
139
136
|
description: "Flexible policy for exhibitor bookings",
|
|
140
137
|
},
|
|
141
|
-
[
|
|
138
|
+
[ServiceCancellationPolicy.ExhibitorStandard]: {
|
|
142
139
|
name: "Exhibitor Standard",
|
|
143
140
|
refundPolicy: [
|
|
144
141
|
{
|
|
@@ -152,7 +149,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
152
149
|
],
|
|
153
150
|
description: "Standard policy for exhibitor bookings",
|
|
154
151
|
},
|
|
155
|
-
[
|
|
152
|
+
[ServiceCancellationPolicy.ExhibitorStrict]: {
|
|
156
153
|
name: "Exhibitor Strict",
|
|
157
154
|
refundPolicy: [
|
|
158
155
|
{
|
|
@@ -166,7 +163,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
166
163
|
],
|
|
167
164
|
description: "Strict policy for exhibitor bookings",
|
|
168
165
|
},
|
|
169
|
-
[
|
|
166
|
+
[ServiceCancellationPolicy.SponsorFlexible]: {
|
|
170
167
|
name: "Sponsor Flexible",
|
|
171
168
|
refundPolicy: [
|
|
172
169
|
{
|
|
@@ -180,7 +177,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
180
177
|
],
|
|
181
178
|
description: "Flexible policy for sponsorship bookings",
|
|
182
179
|
},
|
|
183
|
-
[
|
|
180
|
+
[ServiceCancellationPolicy.SponsorStandard]: {
|
|
184
181
|
name: "Sponsor Standard",
|
|
185
182
|
refundPolicy: [
|
|
186
183
|
{
|
|
@@ -194,7 +191,7 @@ export const SERVICE_CANCELLATION_POLICY_DATA: ServiceCancellationPolicyMap = {
|
|
|
194
191
|
],
|
|
195
192
|
description: "Standard policy for sponsorship bookings",
|
|
196
193
|
},
|
|
197
|
-
[
|
|
194
|
+
[ServiceCancellationPolicy.SponsorStrict]: {
|
|
198
195
|
name: "Sponsor Strict",
|
|
199
196
|
refundPolicy: [
|
|
200
197
|
{
|
|
@@ -376,7 +373,7 @@ Object.keys(SERVICE_CANCELLATION_POLICY_DATA)
|
|
|
376
373
|
.filter(
|
|
377
374
|
(policyKey) =>
|
|
378
375
|
(policyKey as ServiceCancellationPolicyOption) !=
|
|
379
|
-
|
|
376
|
+
ServiceCancellationPolicy.None
|
|
380
377
|
)
|
|
381
378
|
.forEach((policyKey) => {
|
|
382
379
|
const policy =
|