@bash-app/bash-common 30.226.0 → 30.228.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.
Files changed (49) hide show
  1. package/dist/aiApproval.d.ts +25 -0
  2. package/dist/aiApproval.d.ts.map +1 -1
  3. package/dist/aiApproval.js +32 -4
  4. package/dist/aiApproval.js.map +1 -1
  5. package/dist/extendedSchemas.d.ts +54 -1
  6. package/dist/extendedSchemas.d.ts.map +1 -1
  7. package/dist/extendedSchemas.js +22 -0
  8. package/dist/extendedSchemas.js.map +1 -1
  9. package/dist/index.d.ts +4 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/utils/__tests__/flyerUtils.test.d.ts +2 -0
  14. package/dist/utils/__tests__/flyerUtils.test.d.ts.map +1 -0
  15. package/dist/utils/__tests__/flyerUtils.test.js +49 -0
  16. package/dist/utils/__tests__/flyerUtils.test.js.map +1 -0
  17. package/dist/utils/flyerUtils.d.ts +42 -0
  18. package/dist/utils/flyerUtils.d.ts.map +1 -0
  19. package/dist/utils/flyerUtils.js +104 -0
  20. package/dist/utils/flyerUtils.js.map +1 -0
  21. package/package.json +1 -1
  22. package/prisma/schema.prisma +319 -50
  23. package/src/aiApproval.ts +118 -0
  24. package/src/extendedSchemas.ts +57 -2
  25. package/src/index.ts +14 -0
  26. package/src/utils/__tests__/flyerUtils.test.ts +70 -0
  27. package/src/utils/flyerUtils.ts +137 -0
  28. package/dist/utils/__tests__/cancellationPolicyRefundResolver.test.d.ts +0 -6
  29. package/dist/utils/__tests__/cancellationPolicyRefundResolver.test.d.ts.map +0 -1
  30. package/dist/utils/__tests__/cancellationPolicyRefundResolver.test.js +0 -104
  31. package/dist/utils/__tests__/cancellationPolicyRefundResolver.test.js.map +0 -1
  32. package/dist/utils/service/serviceRateDBUtils.d.ts +0 -1
  33. package/dist/utils/service/serviceRateDBUtils.d.ts.map +0 -1
  34. package/dist/utils/service/serviceRateDBUtils.js +0 -159
  35. package/dist/utils/service/serviceRateDBUtils.js.map +0 -1
  36. package/prisma/migrations/add_bash_availability.sql +0 -53
  37. package/prisma/migrations/add_bashcash_pricing_to_ticket_tier.sql +0 -15
  38. package/prisma/migrations/add_bashpoints_purchase_tracking.sql +0 -33
  39. package/prisma/migrations/add_event_group_allow_auto_join.sql +0 -17
  40. package/prisma/migrations/add_group_member_status_not_going_maybe.sql +0 -5
  41. package/prisma/migrations/add_groups_and_momentum.sql +0 -135
  42. package/prisma/migrations/add_groups_momentum_phase0_4.sql +0 -200
  43. package/prisma/migrations/add_new_feature_tables.sql +0 -140
  44. package/prisma/migrations/add_pricing_type_enum.sql +0 -88
  45. package/prisma/migrations/add_tier_privacy_and_fee_handling.sql +0 -29
  46. package/prisma/migrations/diagnostic_bashcash_columns.sql +0 -157
  47. package/prisma/migrations/fix_bashcash_referral_code_schema_mismatch.sql +0 -81
  48. package/prisma/migrations/rename_bashcash_to_bashpoints.sql +0 -183
  49. package/prisma/migrations/rename_bashcredits_to_bashpoints.sql +0 -96
@@ -79,7 +79,13 @@ import {
79
79
  VendorPreferences,
80
80
  VendorSocialMediaExpectation,
81
81
  Venue,
82
- VolunteerService
82
+ VolunteerService,
83
+ FlyerCampaign,
84
+ FlyerMailingRoute,
85
+ FlyerArtwork,
86
+ FlyerCampaignSponsor,
87
+ FlyerConversion,
88
+ PostalCarrierRoute,
83
89
  } from "@prisma/client";
84
90
  import { BlogStatus, SERVICE_LINK_DATA_TO_INCLUDE } from "./definitions.js";
85
91
  import {
@@ -842,6 +848,9 @@ export type ServiceBookingCheckoutRef = Pick<
842
848
  > & { creator: PublicUser };
843
849
 
844
850
  export interface ServiceBookingExt extends ServiceBooking {
851
+ /** Some list/card payloads denormalize a single window alongside `bookedDays` */
852
+ startDateTime?: Date | string;
853
+ endDateTime?: Date | string;
845
854
  bookedDays: ServiceBookingDayExt[];
846
855
  additionalFees: ServiceBookingFeeExt[];
847
856
  addOns: ServiceBookingAddOnExt[];
@@ -889,7 +898,9 @@ export interface ServiceExt extends Service {
889
898
 
890
899
  // For availability filtering - matches Prisma relation name "bookings"
891
900
  bookings?: ServiceBookingExt[];
892
-
901
+ /** Some list endpoints historically used this key; prefer `bookings` */
902
+ serviceBookings?: ServiceBookingExt[];
903
+
893
904
  // bookedCheckouts: ServiceBookingCheckoutExt[]; //not necessary to include
894
905
  }
895
906
 
@@ -981,11 +992,17 @@ export interface VenueExt extends Venue {
981
992
  // Note: unavailableDates field doesn't exist in database yet
982
993
  // When implemented, add: unavailableDates?: UnavailableDate[];
983
994
  // Pricing fields (pricingModel, baseRateCents, etc.) live on Prisma `Venue`.
995
+ /** ISO date strings when API/cards attach blocked dates (browse payloads, etc.) */
996
+ unavailableDates?: string[];
984
997
  }
985
998
 
986
999
  export interface OrganizationExt extends Organization {
987
1000
  amountOfGuests?: AmountOfGuests;
988
1001
  sportsProfile?: SportsProfile | null;
1002
+ /** Present when Prisma `_count` is included on organization queries */
1003
+ _count?: {
1004
+ members?: number;
1005
+ };
989
1006
  }
990
1007
 
991
1008
  /** Computed league table row for GET .../seasons/:seasonId/standings */
@@ -1463,3 +1480,41 @@ export interface BlogTagFormData {
1463
1480
  slug?: string;
1464
1481
  color?: string;
1465
1482
  }
1483
+
1484
+ // --- Flyer Blast (EDDM campaigns) ---
1485
+ export const FLYER_CAMPAIGN_WITH_RELATIONS_INCLUDE = {
1486
+ bashEvent: {
1487
+ select: {
1488
+ id: true,
1489
+ title: true,
1490
+ slug: true,
1491
+ coverPhoto: true,
1492
+ themeColor: true,
1493
+ startDateTime: true,
1494
+ endDateTime: true,
1495
+ location: true,
1496
+ street: true,
1497
+ city: true,
1498
+ state: true,
1499
+ zipCode: true,
1500
+ },
1501
+ },
1502
+ routes: true,
1503
+ sponsors: true,
1504
+ artworkVersions: { orderBy: { version: "desc" as const }, take: 3 },
1505
+ } satisfies Prisma.FlyerCampaignInclude;
1506
+
1507
+ export type FlyerCampaignExt = Prisma.FlyerCampaignGetPayload<{
1508
+ include: typeof FLYER_CAMPAIGN_WITH_RELATIONS_INCLUDE;
1509
+ }>;
1510
+
1511
+ export interface FlyerAnalyticsSummary {
1512
+ campaignId: string;
1513
+ qrScans: number;
1514
+ sponsorQrScans: number;
1515
+ rsvps: number;
1516
+ ticketPurchases: number;
1517
+ byRoute: { crrtCode: string; zipCode: string; scans: number }[];
1518
+ }
1519
+
1520
+ export type PostalCarrierRouteExt = PostalCarrierRoute;
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./extendedSchemas.js";
7
7
  export * from "./partnerStoreTypes.js";
8
8
  export * from "./bashFeedTypes.js";
9
9
  export * from "./membershipDefinitions.js";
10
+ export * from "./aiApproval.js";
10
11
 
11
12
  // Re-export ALL Prisma enums as values (usable as runtime constants, e.g. ServiceTypes.Entertainment)
12
13
  // Excludes enums already re-exported by definitions.ts and membershipDefinitions.ts:
@@ -16,6 +17,7 @@ export * from "./membershipDefinitions.js";
16
17
  export {
17
18
  $Enums,
18
19
  AISpecialistFormat,
20
+ AiApprovalVerdict,
19
21
  AVTechnicianFormat,
20
22
  AgeRange,
21
23
  AmbashadorApplicationStatus,
@@ -84,6 +86,11 @@ export {
84
86
  EventTemplateCategory,
85
87
  ExhibitorBookingStatus,
86
88
  FinancingSubType,
89
+ FlyerCampaignStatus,
90
+ FlyerConversionType,
91
+ FlyerFulfillmentType,
92
+ FlyerSponsorSlot,
93
+ FlyerTargetingMode,
87
94
  FloralFormat,
88
95
  FoodAndBeverageSubType,
89
96
  FoodCartStandFormat,
@@ -222,7 +229,13 @@ export type {
222
229
  DocumentID,
223
230
  EventTask,
224
231
  Exhibitor,
232
+ FlyerArtwork,
233
+ FlyerCampaign,
234
+ FlyerCampaignSponsor,
235
+ FlyerConversion,
236
+ FlyerMailingRoute,
225
237
  GoogleReview,
238
+ PostalCarrierRoute,
226
239
  Invitation,
227
240
  Link,
228
241
  Media,
@@ -296,6 +309,7 @@ export * from "./utils/blog/blogDbUtils.js";
296
309
  export * from "./utils/blog/blogCommentDbUtils.js";
297
310
  export * from "./utils/blogUtils.js";
298
311
  export * from "./utils/entityUtils.js";
312
+ export * from "./utils/flyerUtils.js";
299
313
  export * from "./utils/generalDateTimeUtils.js";
300
314
  export * from "./utils/luxonUtils.js";
301
315
  export * from "./utils/mediaClientDefaults.js";
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+ import {
3
+ isEddmFlatSizeCompliant,
4
+ quoteFlyerTierForHouseholds,
5
+ computeHostTotalAfterSponsors,
6
+ FLYER_PRICING_TIERS,
7
+ USPS_EDDM_RETAIL_MIN_MAILPIECES,
8
+ flyerQrScanPath,
9
+ generateFlyerCampaignSlug,
10
+ distanceMiles,
11
+ } from "../flyerUtils.js";
12
+
13
+ describe("flyerUtils", () => {
14
+ it("isEddmFlatSizeCompliant accepts 6.25 x 11", () => {
15
+ expect(isEddmFlatSizeCompliant(6.25, 11)).toBe(true);
16
+ });
17
+
18
+ it("isEddmFlatSizeCompliant rejects too-small flats", () => {
19
+ expect(isEddmFlatSizeCompliant(4, 6)).toBe(false);
20
+ });
21
+
22
+ it("quoteFlyerTierForHouseholds returns null below minimum", () => {
23
+ expect(quoteFlyerTierForHouseholds(50)).toBeNull();
24
+ });
25
+
26
+ it("quoteFlyerTierForHouseholds returns Starter for 200 homes", () => {
27
+ const q = quoteFlyerTierForHouseholds(200);
28
+ expect(q?.tierId).toBe("starter");
29
+ expect(q?.hostPriceCents).toBe(FLYER_PRICING_TIERS[0].hostPriceCents);
30
+ });
31
+
32
+ it("computeHostTotalAfterSponsors never goes negative", () => {
33
+ expect(computeHostTotalAfterSponsors(32900, 50000)).toBe(0);
34
+ });
35
+
36
+ it("min mailpieces matches starter tier floor", () => {
37
+ expect(USPS_EDDM_RETAIL_MIN_MAILPIECES).toBe(
38
+ FLYER_PRICING_TIERS[0].minHouseholds
39
+ );
40
+ });
41
+
42
+ it("flyerQrScanPath encodes campaign slug for query", () => {
43
+ expect(flyerQrScanPath("abc")).toBe("/api/flyer/qr-scan?c=abc");
44
+ expect(flyerQrScanPath("a&b=c")).toBe(
45
+ "/api/flyer/qr-scan?c=" + encodeURIComponent("a&b=c")
46
+ );
47
+ });
48
+
49
+ it("generateFlyerCampaignSlug yields fb prefix, fixed length, allowed charset", () => {
50
+ const rnd = jest.spyOn(Math, "random").mockReturnValue(0);
51
+ try {
52
+ const slug = generateFlyerCampaignSlug();
53
+ expect(slug.startsWith("fb")).toBe(true);
54
+ expect(slug).toHaveLength(14);
55
+ expect(slug.slice(2)).toMatch(/^[23456789abcdefghjkmnpqrstuvwxyz]{12}$/);
56
+ } finally {
57
+ rnd.mockRestore();
58
+ }
59
+ });
60
+
61
+ it("distanceMiles is ~0 for identical points", () => {
62
+ expect(distanceMiles(40.7, -112, 40.7, -112)).toBe(0);
63
+ });
64
+
65
+ it("distanceMiles SLC to Provo is in plausible range (~35–50 mi)", () => {
66
+ const mi = distanceMiles(40.7608, -111.891, 40.2338, -111.6585);
67
+ expect(mi).toBeGreaterThan(30);
68
+ expect(mi).toBeLessThan(55);
69
+ });
70
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * USPS EDDM flat minimum: 6.125" × 11" (one dimension must be at least 11").
3
+ * Product standard used by Flyer Blast: 6.25" × 11" portrait.
4
+ */
5
+ export const FLYER_EDDM_WIDTH_IN = 6.25;
6
+ export const FLYER_EDDM_HEIGHT_IN = 11;
7
+ export const FLYER_EDDM_MIN_WIDTH_IN = 6.125;
8
+ export const FLYER_EDDM_MIN_HEIGHT_IN = 11;
9
+
10
+ /** USPS EDDM Retail per-piece postage (2026 — verify periodically). */
11
+ export const USPS_EDDM_RETAIL_PER_PIECE_CENTS = 24.7;
12
+
13
+ /**
14
+ * USPS EDDM Retail minimum mailpieces per mailing (saturation).
15
+ * Aligns with starter tier lower bound in `FLYER_PRICING_TIERS`.
16
+ */
17
+ export const USPS_EDDM_RETAIL_MIN_MAILPIECES = 200;
18
+
19
+ export type FlyerPricingTierId = "starter" | "neighborhood" | "district" | "metro";
20
+
21
+ export interface FlyerTierQuote {
22
+ tierId: FlyerPricingTierId;
23
+ label: string;
24
+ minHouseholds: number;
25
+ maxHouseholds: number;
26
+ hostPriceCents: number;
27
+ }
28
+
29
+ export const FLYER_PRICING_TIERS: FlyerTierQuote[] = [
30
+ {
31
+ tierId: "starter",
32
+ label: "Starter",
33
+ minHouseholds: 200,
34
+ maxHouseholds: 499,
35
+ hostPriceCents: 14900,
36
+ },
37
+ {
38
+ tierId: "neighborhood",
39
+ label: "Neighborhood",
40
+ minHouseholds: 500,
41
+ maxHouseholds: 1499,
42
+ hostPriceCents: 32900,
43
+ },
44
+ {
45
+ tierId: "district",
46
+ label: "District",
47
+ minHouseholds: 1500,
48
+ maxHouseholds: 3999,
49
+ hostPriceCents: 69900,
50
+ },
51
+ {
52
+ tierId: "metro",
53
+ label: "Metro",
54
+ minHouseholds: 4000,
55
+ maxHouseholds: 9999,
56
+ hostPriceCents: 139900,
57
+ },
58
+ ];
59
+
60
+ /** Default sponsor slot list prices (Utah / intermountain — cents). */
61
+ export const FLYER_SPONSOR_DEFAULT_FEATURED_CENTS = 10000;
62
+ export const FLYER_SPONSOR_DEFAULT_SUPPORTING_CENTS = 5000;
63
+
64
+ export function isEddmFlatSizeCompliant(widthIn: number, heightIn: number): boolean {
65
+ const long = Math.max(widthIn, heightIn);
66
+ const short = Math.min(widthIn, heightIn);
67
+ return long >= FLYER_EDDM_MIN_HEIGHT_IN && short >= FLYER_EDDM_MIN_WIDTH_IN;
68
+ }
69
+
70
+ /**
71
+ * Map total selected households to a pricing tier. Returns null if below minimum (200 for EDDM Retail).
72
+ */
73
+ export function quoteFlyerTierForHouseholds(
74
+ totalHouseholds: number
75
+ ): FlyerTierQuote | null {
76
+ if (totalHouseholds < FLYER_PRICING_TIERS[0].minHouseholds) {
77
+ return null;
78
+ }
79
+ for (const tier of FLYER_PRICING_TIERS) {
80
+ if (
81
+ totalHouseholds >= tier.minHouseholds &&
82
+ totalHouseholds <= tier.maxHouseholds
83
+ ) {
84
+ return tier;
85
+ }
86
+ }
87
+ // Above metro max — use metro as ceiling for MVP
88
+ const last = FLYER_PRICING_TIERS[FLYER_PRICING_TIERS.length - 1];
89
+ if (totalHouseholds > last.maxHouseholds) {
90
+ return last;
91
+ }
92
+ return null;
93
+ }
94
+
95
+ export function computeHostTotalAfterSponsors(
96
+ printPostageCostCents: number,
97
+ sponsorRevenueCents: number
98
+ ): number {
99
+ return Math.max(0, printPostageCostCents - sponsorRevenueCents);
100
+ }
101
+
102
+ const EARTH_RADIUS_MI = 3958.8;
103
+
104
+ /** Haversine distance in miles between two WGS84 points. */
105
+ export function distanceMiles(
106
+ lat1: number,
107
+ lng1: number,
108
+ lat2: number,
109
+ lng2: number
110
+ ): number {
111
+ const rlat1 = (lat1 * Math.PI) / 180;
112
+ const rlat2 = (lat2 * Math.PI) / 180;
113
+ const dLat = rlat2 - rlat1;
114
+ const dLng = ((lng2 - lng1) * Math.PI) / 180;
115
+ const a =
116
+ Math.sin(dLat / 2) * Math.sin(dLat / 2) +
117
+ Math.cos(rlat1) * Math.cos(rlat2) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
118
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
119
+ return EARTH_RADIUS_MI * c;
120
+ }
121
+
122
+ /** URL path for the public QR scan endpoint (prepend API origin in clients). */
123
+ export function flyerQrScanPath(campaignQrSlug: string): string {
124
+ return `/api/flyer/qr-scan?c=${encodeURIComponent(campaignQrSlug)}`;
125
+ }
126
+
127
+ /**
128
+ * Short slug for campaign QR (avoid ambiguous chars); unique enforced in DB.
129
+ */
130
+ export function generateFlyerCampaignSlug(): string {
131
+ const alphabet = "23456789abcdefghjkmnpqrstuvwxyz";
132
+ let out = "fb";
133
+ for (let i = 0; i < 12; i++) {
134
+ out += alphabet[Math.floor(Math.random() * alphabet.length)];
135
+ }
136
+ return out;
137
+ }
@@ -1,6 +0,0 @@
1
- /**
2
- * Tests for cancellation refund resolution (single source of truth:
3
- * SERVICE_CANCELLATION_POLICY_DATA).
4
- */
5
- export {};
6
- //# sourceMappingURL=cancellationPolicyRefundResolver.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cancellationPolicyRefundResolver.test.d.ts","sourceRoot":"","sources":["../../../src/utils/__tests__/cancellationPolicyRefundResolver.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -1,104 +0,0 @@
1
- /**
2
- * Tests for cancellation refund resolution (single source of truth:
3
- * SERVICE_CANCELLATION_POLICY_DATA).
4
- */
5
- import { ServiceCancellationPolicy } from "@prisma/client";
6
- import { cancellationRuleThresholdHours, getMatchingCancellationRefundRule, hoursUntilEventStart, resolveCancellationRefundFraction, } from "../service/cancellationPolicyRefundResolver.js";
7
- describe("cancellationPolicyRefundResolver", () => {
8
- const fixedNow = new Date("2026-01-01T12:00:00.000Z");
9
- describe("hoursUntilEventStart", () => {
10
- test("returns 0 when event is in the past", () => {
11
- expect(hoursUntilEventStart(new Date("2025-12-01T12:00:00.000Z"), fixedNow)).toBe(0);
12
- });
13
- test("returns positive hours until start", () => {
14
- const start = new Date("2026-01-03T12:00:00.000Z");
15
- expect(hoursUntilEventStart(start, fixedNow)).toBe(48);
16
- });
17
- });
18
- describe("cancellationRuleThresholdHours", () => {
19
- test("converts days to hours", () => {
20
- expect(cancellationRuleThresholdHours({ days: 7, refundPercentage: 100 })).toBe(168);
21
- });
22
- test("uses hours when set", () => {
23
- expect(cancellationRuleThresholdHours({ hours: 24, refundPercentage: 50 })).toBe(24);
24
- });
25
- });
26
- describe("VendorStandard (14d full, 3d partial)", () => {
27
- test("20 days before: 100%", () => {
28
- const eventStart = new Date("2026-01-21T12:00:00.000Z");
29
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorStandard, {
30
- eventStart,
31
- now: fixedNow,
32
- })).toBe(1);
33
- });
34
- test("10 days before: 50%", () => {
35
- const eventStart = new Date("2026-01-11T12:00:00.000Z");
36
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorStandard, {
37
- eventStart,
38
- now: fixedNow,
39
- })).toBe(0.5);
40
- });
41
- test("2 days before: 0%", () => {
42
- const eventStart = new Date("2026-01-03T12:00:00.000Z");
43
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorStandard, {
44
- eventStart,
45
- now: fixedNow,
46
- })).toBe(0);
47
- });
48
- });
49
- describe("VendorFlexible (7d full, 24h partial)", () => {
50
- test("8 days before: 100%", () => {
51
- const eventStart = new Date("2026-01-09T12:00:00.000Z");
52
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorFlexible, {
53
- eventStart,
54
- now: fixedNow,
55
- })).toBe(1);
56
- });
57
- test("5 days before: 50%", () => {
58
- const eventStart = new Date("2026-01-06T12:00:00.000Z");
59
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorFlexible, {
60
- eventStart,
61
- now: fixedNow,
62
- })).toBe(0.5);
63
- });
64
- test("12 hours before: 0%", () => {
65
- const eventStart = new Date("2026-01-02T00:00:00.000Z");
66
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorFlexible, {
67
- eventStart,
68
- now: fixedNow,
69
- })).toBe(0);
70
- });
71
- test("6d 23h before (~167h): still 50% tier, not full 7d", () => {
72
- const eventStart = new Date("2026-01-08T11:00:00.000Z");
73
- expect(hoursUntilEventStart(eventStart, fixedNow)).toBeCloseTo(167, 0);
74
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VendorFlexible, {
75
- eventStart,
76
- now: fixedNow,
77
- })).toBe(0.5);
78
- });
79
- });
80
- describe("VeryFlexible (24h full only)", () => {
81
- test("2 days before: 100%", () => {
82
- const eventStart = new Date("2026-01-03T12:00:00.000Z");
83
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VeryFlexible, {
84
- eventStart,
85
- now: fixedNow,
86
- })).toBe(1);
87
- });
88
- test("12 hours before: 0%", () => {
89
- const eventStart = new Date("2026-01-02T00:00:00.000Z");
90
- expect(resolveCancellationRefundFraction(ServiceCancellationPolicy.VeryFlexible, {
91
- eventStart,
92
- now: fixedNow,
93
- })).toBe(0);
94
- });
95
- });
96
- describe("getMatchingCancellationRefundRule", () => {
97
- test("returns the winning tier rule object", () => {
98
- const eventStart = new Date("2026-01-11T12:00:00.000Z");
99
- const rule = getMatchingCancellationRefundRule(ServiceCancellationPolicy.VendorStandard, { eventStart, now: fixedNow });
100
- expect(rule).toEqual({ days: 3, refundPercentage: 50 });
101
- });
102
- });
103
- });
104
- //# sourceMappingURL=cancellationPolicyRefundResolver.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cancellationPolicyRefundResolver.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/cancellationPolicyRefundResolver.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=serviceRateDBUtils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serviceRateDBUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/service/serviceRateDBUtils.ts"],"names":[],"mappings":""}
@@ -1,159 +0,0 @@
1
- "use strict";
2
- // import { ServiceRate } from "@prisma/client";
3
- // import { ApiResult } from "../../definitions";
4
- // import { ServiceSpecialRatesExt } from "../../extendedSchemas";
5
- // import { convertDollarsToCents, convertCentsToDollars } from "../paymentUtils";
6
- // export function specialRateConvertToDb(
7
- // specialRate: Partial<ServiceSpecialRatesExt>
8
- // ): Partial<ServiceSpecialRatesExt> {
9
- // return specialRateConvertRatesToDB(
10
- // specialRateConvertDateStringsToDb(structuredClone(specialRate))
11
- // );
12
- // }
13
- // export function specialRateConvertFromDb(
14
- // specialRate: ServiceSpecialRatesExt
15
- // ): ServiceSpecialRatesExt {
16
- // // console.log(`specialRateConvertFromDb`);
17
- // return specialRateConvertRatesFromDB(
18
- // specialRateConvertDateStringsFromDb(specialRate)
19
- // );
20
- // }
21
- // function specialRateConvertDateStringsToDb(
22
- // specialRate: Partial<ServiceSpecialRatesExt>
23
- // ): Partial<ServiceSpecialRatesExt> {
24
- // // const oldStart = new Date(specialRate.startDate!);
25
- // // const oldEnd = new Date(specialRate.endDate!);
26
- // // specialRate.startDate = dateTimeLocalToUTCDate(specialRate.startDate!);
27
- // // specialRate.endDate = dateTimeLocalToUTCDate(specialRate.endDate!);
28
- // // specialRate.startDate = normalizeDate(specialRate.startDate!);
29
- // // specialRate.endDate = normalizeDate(specialRate.endDate!);
30
- // // const localStart = dateTimeLocalFromUTCDate(new Date(specialRate.startDate!));
31
- // // const localEnd = dateTimeLocalFromUTCDate(new Date(specialRate.endDate!));
32
- // // console.log(
33
- // // `specialRateConvertDateStringsToDb oldStart: ${oldStart?.toString()}`
34
- // // );
35
- // // console.log(
36
- // // `specialRateConvertDateStringsToDb oldEnd: ${oldEnd?.toString()}`
37
- // // );
38
- // // console.log(
39
- // // `specialRateConvertDateStringsToDb specialRate.startDate: ${specialRate.startDate?.toString()}`
40
- // // );
41
- // // console.log(
42
- // // `specialRateConvertDateStringsToDb specialRate.endDate: ${specialRate.endDate?.toString()}`
43
- // // );
44
- // // console.log(
45
- // // `specialRateConvertDateStringsToDb localStart: ${localStart?.toString()}`
46
- // // );
47
- // // console.log(
48
- // // `specialRateConvertDateStringsToDb localEnd: ${localEnd?.toString()}`
49
- // // );
50
- // // const a = 3 + 4;
51
- // // specialRate.startDate = specialRate.startDate.toISOString();
52
- // // specialRate.endDate = specialRate.endDate.toISOString();
53
- // // return specialRate;
54
- // return specialRate;
55
- // }
56
- // function specialRateConvertDateStringsFromDb(
57
- // specialRate: ServiceSpecialRatesExt
58
- // ): ServiceSpecialRatesExt {
59
- // // specialRate.startDate = localDateToUTC(new Date(specialRate.startDate));
60
- // // specialRate.endDate = localDateToUTC(new Date(specialRate.endDate));
61
- // //this shouldnt even be necessary as javascript dates are always stored in UTC timezone (they lack timezone information)
62
- // // specialRate.startDate = ensureDateTimeIsLocalDateTime(
63
- // // new Date(specialRate.startDate)
64
- // // ).toDate();
65
- // // specialRate.endDate = ensureDateTimeIsLocalDateTime(
66
- // // new Date(specialRate.endDate)
67
- // // ).toDate();
68
- // specialRate.startDate = new Date(specialRate.startDate);
69
- // specialRate.endDate = new Date(specialRate.endDate);
70
- // // const oldStart = new Date(specialRate.startDate!);
71
- // // const oldEnd = new Date(specialRate.endDate!);
72
- // // specialRate.startDate = dateTimeLocalFromUTCDate(
73
- // // new Date(specialRate.startDate)
74
- // // );
75
- // // specialRate.endDate = dateTimeLocalFromUTCDate(new Date(specialRate.endDate));
76
- // // // specialRate.startDate = ensureDateTimeIsLocalDateTime(
77
- // // // new Date(specialRate.startDate)
78
- // // // ).toDate();
79
- // // // specialRate.endDate = ensureDateTimeIsLocalDateTime(
80
- // // // new Date(specialRate.endDate)
81
- // // // ).toDate();
82
- // // // specialRate.startDate = localDateToUTC(new Date(specialRate.startDate));
83
- // // // specialRate.endDate = localDateToUTC(new Date(specialRate.endDate));
84
- // // const date2 = normalizeDate(specialRate.startDate)!;
85
- // // const date3 = normalizeDate(specialRate.endDate)!;
86
- // // const a = 3 + 4;
87
- // return specialRate;
88
- // }
89
- // function specialRateConvertRatesToDB(
90
- // specialRate: Partial<ServiceSpecialRatesExt>
91
- // ): Partial<ServiceSpecialRatesExt> {
92
- // if (specialRate.serviceRate) {
93
- // specialRate.serviceRate = generalRatesConvertRatesToDB(
94
- // specialRate.serviceRate
95
- // ) as ServiceRate;
96
- // }
97
- // return specialRate;
98
- // }
99
- // function specialRateConvertRatesFromDB(
100
- // specialRate: ServiceSpecialRatesExt
101
- // ): ServiceSpecialRatesExt {
102
- // if (specialRate.serviceRate) {
103
- // specialRate.serviceRate = generalRatesConvertRatesFromDB(
104
- // specialRate.serviceRate
105
- // );
106
- // }
107
- // return specialRate;
108
- // }
109
- // export function generalRatesConvertRatesToDB(
110
- // generalRate: ServiceRate
111
- // ): ServiceRate {
112
- // return generalRatesConvertRatesToDBHelper(structuredClone(generalRate));
113
- // }
114
- // export function generalRatesConvertRatesToDBHelper(
115
- // generalRate: ServiceRate
116
- // ): ServiceRate {
117
- // // console.log(
118
- // // `generalRatesConvertRatesToDBHelper A: ${JSON.stringify(generalRate)}`
119
- // // );
120
- // if (generalRate?.dailyRate) {
121
- // generalRate.dailyRate = convertDollarsToCents(generalRate.dailyRate);
122
- // }
123
- // if (generalRate?.hourlyRate) {
124
- // generalRate.hourlyRate = convertDollarsToCents(generalRate.hourlyRate);
125
- // }
126
- // if (generalRate?.cleaningFeePerBooking) {
127
- // generalRate.cleaningFeePerBooking = convertDollarsToCents(
128
- // generalRate.cleaningFeePerBooking
129
- // );
130
- // }
131
- // // console.log(
132
- // // `generalRatesConvertRatesToDBHelper B: ${JSON.stringify(generalRate)}`
133
- // // );
134
- // return generalRate;
135
- // }
136
- // export function generalRatesConvertRatesFromDB(
137
- // generalRate: ServiceRate
138
- // ): ServiceRate {
139
- // // console.log(
140
- // // `generalRatesConvertRatesFromDB A: ${JSON.stringify(generalRate)}`
141
- // // );
142
- // // console.log(`specialRateConvertRatesFromDB`);
143
- // if (generalRate?.dailyRate) {
144
- // generalRate.dailyRate = convertCentsToDollars(generalRate.dailyRate);
145
- // }
146
- // if (generalRate?.hourlyRate) {
147
- // generalRate.hourlyRate = convertCentsToDollars(generalRate.hourlyRate);
148
- // }
149
- // if (generalRate?.cleaningFeePerBooking) {
150
- // generalRate.cleaningFeePerBooking = convertCentsToDollars(
151
- // generalRate.cleaningFeePerBooking
152
- // );
153
- // }
154
- // // console.log(
155
- // // `generalRatesConvertRatesFromDB B: ${JSON.stringify(generalRate)}`
156
- // // );
157
- // return generalRate;
158
- // }
159
- //# sourceMappingURL=serviceRateDBUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serviceRateDBUtils.js","sourceRoot":"","sources":["../../../src/utils/service/serviceRateDBUtils.ts"],"names":[],"mappings":";AAAA,gDAAgD;AAChD,iDAAiD;AACjD,kEAAkE;AAClE,kFAAkF;AAElF,0CAA0C;AAC1C,iDAAiD;AACjD,uCAAuC;AACvC,wCAAwC;AACxC,sEAAsE;AACtE,OAAO;AACP,IAAI;AAEJ,4CAA4C;AAC5C,wCAAwC;AACxC,8BAA8B;AAC9B,gDAAgD;AAChD,0CAA0C;AAC1C,uDAAuD;AACvD,OAAO;AACP,IAAI;AAEJ,8CAA8C;AAC9C,iDAAiD;AACjD,uCAAuC;AACvC,0DAA0D;AAC1D,sDAAsD;AAEtD,+EAA+E;AAC/E,2EAA2E;AAC3E,sEAAsE;AACtE,kEAAkE;AAElE,sFAAsF;AACtF,kFAAkF;AAElF,oBAAoB;AACpB,+EAA+E;AAC/E,UAAU;AACV,oBAAoB;AACpB,2EAA2E;AAC3E,UAAU;AACV,oBAAoB;AACpB,yGAAyG;AACzG,UAAU;AACV,oBAAoB;AACpB,qGAAqG;AACrG,UAAU;AACV,oBAAoB;AACpB,mFAAmF;AACnF,UAAU;AACV,oBAAoB;AACpB,+EAA+E;AAC/E,UAAU;AAEV,wBAAwB;AAExB,oEAAoE;AACpE,gEAAgE;AAChE,2BAA2B;AAC3B,wBAAwB;AACxB,IAAI;AAEJ,gDAAgD;AAChD,wCAAwC;AACxC,8BAA8B;AAC9B,gFAAgF;AAChF,4EAA4E;AAE5E,6HAA6H;AAC7H,8DAA8D;AAC9D,yCAAyC;AACzC,mBAAmB;AACnB,4DAA4D;AAC5D,uCAAuC;AACvC,mBAAmB;AAEnB,6DAA6D;AAC7D,yDAAyD;AAEzD,0DAA0D;AAC1D,sDAAsD;AAEtD,yDAAyD;AACzD,yCAAyC;AACzC,UAAU;AACV,sFAAsF;AAEtF,iEAAiE;AACjE,4CAA4C;AAC5C,sBAAsB;AACtB,+DAA+D;AAC/D,0CAA0C;AAC1C,sBAAsB;AAEtB,mFAAmF;AACnF,+EAA+E;AAE/E,4DAA4D;AAC5D,0DAA0D;AAE1D,wBAAwB;AACxB,wBAAwB;AACxB,IAAI;AAEJ,wCAAwC;AACxC,iDAAiD;AACjD,uCAAuC;AACvC,mCAAmC;AACnC,8DAA8D;AAC9D,gCAAgC;AAChC,wBAAwB;AACxB,MAAM;AACN,wBAAwB;AACxB,IAAI;AAEJ,0CAA0C;AAC1C,wCAAwC;AACxC,8BAA8B;AAC9B,mCAAmC;AACnC,gEAAgE;AAChE,gCAAgC;AAChC,SAAS;AACT,MAAM;AACN,wBAAwB;AACxB,IAAI;AAEJ,gDAAgD;AAChD,6BAA6B;AAC7B,mBAAmB;AACnB,6EAA6E;AAC7E,IAAI;AAEJ,sDAAsD;AACtD,6BAA6B;AAC7B,mBAAmB;AACnB,sBAAsB;AACtB,kFAAkF;AAClF,YAAY;AACZ,kCAAkC;AAClC,4EAA4E;AAC5E,MAAM;AACN,mCAAmC;AACnC,8EAA8E;AAC9E,MAAM;AACN,8CAA8C;AAC9C,iEAAiE;AACjE,0CAA0C;AAC1C,SAAS;AACT,MAAM;AACN,sBAAsB;AACtB,kFAAkF;AAClF,YAAY;AACZ,wBAAwB;AACxB,IAAI;AAEJ,kDAAkD;AAClD,6BAA6B;AAC7B,mBAAmB;AACnB,sBAAsB;AACtB,8EAA8E;AAC9E,YAAY;AACZ,qDAAqD;AACrD,kCAAkC;AAClC,4EAA4E;AAC5E,MAAM;AACN,mCAAmC;AACnC,8EAA8E;AAC9E,MAAM;AACN,8CAA8C;AAC9C,iEAAiE;AACjE,0CAA0C;AAC1C,SAAS;AACT,MAAM;AACN,sBAAsB;AACtB,8EAA8E;AAC9E,YAAY;AACZ,wBAAwB;AACxB,IAAI"}