@bash-app/bash-common 30.275.0 → 30.276.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__/groupTicketUtils.test.d.ts +2 -0
- package/dist/__tests__/groupTicketUtils.test.d.ts.map +1 -0
- package/dist/__tests__/groupTicketUtils.test.js +38 -0
- package/dist/__tests__/groupTicketUtils.test.js.map +1 -0
- package/dist/competitionIdeas.d.ts +19 -0
- package/dist/competitionIdeas.d.ts.map +1 -0
- package/dist/competitionIdeas.js +405 -0
- package/dist/competitionIdeas.js.map +1 -0
- package/dist/competitionValidation.d.ts +10 -0
- package/dist/competitionValidation.d.ts.map +1 -0
- package/dist/competitionValidation.js +29 -0
- package/dist/competitionValidation.js.map +1 -0
- package/dist/definitions.d.ts +4 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +351 -1
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +15 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/groupTicketUtils.d.ts +19 -0
- package/dist/groupTicketUtils.d.ts.map +1 -0
- package/dist/groupTicketUtils.js +74 -0
- package/dist/groupTicketUtils.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/__tests__/paymentUtils.test.js +18 -0
- package/dist/utils/__tests__/paymentUtils.test.js.map +1 -1
- package/dist/utils/__tests__/ticketListUtils.test.js +10 -0
- package/dist/utils/__tests__/ticketListUtils.test.js.map +1 -1
- package/dist/utils/groupTicketCartUtils.d.ts +12 -0
- package/dist/utils/groupTicketCartUtils.d.ts.map +1 -0
- package/dist/utils/groupTicketCartUtils.js +30 -0
- package/dist/utils/groupTicketCartUtils.js.map +1 -0
- package/dist/utils/paymentUtils.d.ts +10 -0
- package/dist/utils/paymentUtils.d.ts.map +1 -1
- package/dist/utils/paymentUtils.js +37 -1
- package/dist/utils/paymentUtils.js.map +1 -1
- package/dist/utils/ticketListUtils.d.ts.map +1 -1
- package/dist/utils/ticketListUtils.js +15 -3
- package/dist/utils/ticketListUtils.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/competition-prize-catalog-entry-tier.sql +39 -0
- package/prisma/schema.prisma +90 -7
- package/src/__tests__/groupTicketUtils.test.ts +53 -0
- package/src/competitionIdeas.ts +429 -0
- package/src/competitionValidation.ts +42 -0
- package/src/definitions.ts +5 -0
- package/src/extendedSchemas.ts +47 -0
- package/src/groupTicketUtils.ts +101 -0
- package/src/index.ts +4 -0
- package/src/utils/__tests__/paymentUtils.test.ts +19 -0
- package/src/utils/__tests__/ticketListUtils.test.ts +12 -0
- package/src/utils/groupTicketCartUtils.ts +36 -0
- package/src/utils/paymentUtils.ts +42 -1
- package/src/utils/ticketListUtils.ts +19 -5
|
@@ -65,7 +65,10 @@ export function ticketListToString(ticketList) {
|
|
|
65
65
|
dateTimeStr = dateTime.toISO() || dateTimeStr;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
ticketArgs.push(`${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}
|
|
68
|
+
ticketArgs.push(`${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}${ticketNumAndDates.unitPriceCents != null &&
|
|
69
|
+
ticketNumAndDates.unitPriceCents > 0
|
|
70
|
+
? `${URL_PARAMS_TICKETS_DATE_DELIM}${ticketNumAndDates.unitPriceCents}`
|
|
71
|
+
: ""}`);
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
// Only include this tier if we found at least one ticket > 0
|
|
@@ -114,16 +117,25 @@ export function ticketListStrToTicketList(ticketListStr) {
|
|
|
114
117
|
.split(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM)
|
|
115
118
|
.filter((ticketNumAndDateStr) => !!ticketNumAndDateStr);
|
|
116
119
|
for (const ticketNumAndDateStr of ticketNumAndDates) {
|
|
117
|
-
// [numberOfTickets];;[date]
|
|
118
|
-
const
|
|
120
|
+
// [numberOfTickets];;[date];;[unitPriceCents?]
|
|
121
|
+
const segments = ticketNumAndDateStr.split(URL_PARAMS_TICKETS_DATE_DELIM);
|
|
122
|
+
const numberOfTickets = segments[0];
|
|
123
|
+
const ticketDateTimeStr = segments[1];
|
|
124
|
+
const unitPriceCentsRaw = segments[2];
|
|
119
125
|
const ticketDateTime = DateTime.fromISO(ticketDateTimeStr);
|
|
120
126
|
let ticketDateTimeFormattedStr = undefined;
|
|
121
127
|
if (ticketDateTime.isValid) {
|
|
122
128
|
ticketDateTimeFormattedStr = ticketDateTime.toISO() ?? undefined;
|
|
123
129
|
}
|
|
130
|
+
const unitPriceCents = unitPriceCentsRaw != null && unitPriceCentsRaw !== ""
|
|
131
|
+
? parseInt(unitPriceCentsRaw, 10)
|
|
132
|
+
: undefined;
|
|
124
133
|
ticketNumAndDatesArr.push({
|
|
125
134
|
numberOfTickets: parseInt(numberOfTickets),
|
|
126
135
|
ticketDateTime: ticketDateTimeFormattedStr,
|
|
136
|
+
...(unitPriceCents != null && !Number.isNaN(unitPriceCents)
|
|
137
|
+
? { unitPriceCents }
|
|
138
|
+
: {}),
|
|
127
139
|
});
|
|
128
140
|
}
|
|
129
141
|
ticketList.set(ticketTierId, ticketNumAndDatesArr);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticketListUtils.js","sourceRoot":"","sources":["../../src/utils/ticketListUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAEL,+CAA+C,EAC/C,4BAA4B,EAC5B,sDAAsD,EACtD,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACtC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,sBAAsB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC;aACb,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;aACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;aACnB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,mBAAmB;QACnB,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;aACpB,QAAQ,CAAC,QAAQ,CAAC;aAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;aACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;aACnB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACtC,mBAAmB;IACnB,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC;IAChB,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,sBAAsB;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,mBAAmB;QACnB,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAiD;IAEjD,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QAClE,MAAM,UAAU,GAAa;YAC3B,GAAG,YAAY,GAAG,sDAAsD,EAAE;SAC3E,CAAC;QACF,IAAI,aAAa,GAAG,KAAK,CAAC,CAAC,oDAAoD;QAE/E,KAAK,MAAM,iBAAiB,IAAI,cAAc,EAAE,CAAC;YAC/C,IAAI,iBAAiB,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;gBAC1C,aAAa,GAAG,IAAI,CAAC;gBAErB,oDAAoD;gBACpD,IAAI,WAAW,GAAG,iBAAiB,CAAC,cAAc,CAAC;gBACnD,IAAI,WAAW,EAAE,CAAC;oBAChB,2EAA2E;oBAC3E,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;oBAC/C,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;wBACrB,WAAW,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,WAAW,CAAC;oBAChD,CAAC;gBACH,CAAC;gBAED,UAAU,CAAC,IAAI,CACb,GAAG,iBAAiB,CAAC,eAAe,GAAG,6BAA6B,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"ticketListUtils.js","sourceRoot":"","sources":["../../src/utils/ticketListUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- Competition prize catalog + entry ticket tier link
|
|
2
|
+
-- Safe additive migration — preserves all data
|
|
3
|
+
BEGIN;
|
|
4
|
+
|
|
5
|
+
-- Prize catalog fields
|
|
6
|
+
ALTER TABLE "Prize" ADD COLUMN IF NOT EXISTS "sponsorLabel" TEXT;
|
|
7
|
+
ALTER TABLE "Prize" ADD COLUMN IF NOT EXISTS "imageUrl" TEXT;
|
|
8
|
+
|
|
9
|
+
-- Competition entry ticket tier + host promotions acknowledgment
|
|
10
|
+
ALTER TABLE "Competition" ADD COLUMN IF NOT EXISTS "entryTicketTierId" TEXT;
|
|
11
|
+
ALTER TABLE "Competition" ADD COLUMN IF NOT EXISTS "hostPromotionsAckAt" TIMESTAMP(3);
|
|
12
|
+
|
|
13
|
+
DO $$
|
|
14
|
+
BEGIN
|
|
15
|
+
IF NOT EXISTS (
|
|
16
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'Competition_entryTicketTierId_key'
|
|
17
|
+
) THEN
|
|
18
|
+
ALTER TABLE "Competition"
|
|
19
|
+
ADD CONSTRAINT "Competition_entryTicketTierId_key" UNIQUE ("entryTicketTierId");
|
|
20
|
+
END IF;
|
|
21
|
+
END $$;
|
|
22
|
+
|
|
23
|
+
DO $$
|
|
24
|
+
BEGIN
|
|
25
|
+
IF NOT EXISTS (
|
|
26
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'Competition_entryTicketTierId_fkey'
|
|
27
|
+
) THEN
|
|
28
|
+
ALTER TABLE "Competition"
|
|
29
|
+
ADD CONSTRAINT "Competition_entryTicketTierId_fkey"
|
|
30
|
+
FOREIGN KEY ("entryTicketTierId") REFERENCES "TicketTier"("id")
|
|
31
|
+
ON DELETE SET NULL ON UPDATE CASCADE;
|
|
32
|
+
END IF;
|
|
33
|
+
END $$;
|
|
34
|
+
|
|
35
|
+
COMMIT;
|
|
36
|
+
|
|
37
|
+
-- Verification
|
|
38
|
+
-- SELECT column_name FROM information_schema.columns WHERE table_name = 'Prize' AND column_name IN ('sponsorLabel', 'imageUrl');
|
|
39
|
+
-- SELECT column_name FROM information_schema.columns WHERE table_name = 'Competition' AND column_name IN ('entryTicketTierId', 'hostPromotionsAckAt');
|
package/prisma/schema.prisma
CHANGED
|
@@ -239,12 +239,25 @@ model Competition {
|
|
|
239
239
|
bracketData Json? // Store bracket structure/metadata
|
|
240
240
|
bracketVisible Boolean @default(true)
|
|
241
241
|
|
|
242
|
+
/// Optional ticket tier required for competition entry (participation fee / game entry)
|
|
243
|
+
entryTicketTierId String? @unique
|
|
244
|
+
entryTicketTier TicketTier? @relation("CompetitionEntryTicketTier", fields: [entryTicketTierId], references: [id], onDelete: SetNull)
|
|
245
|
+
/// When the host acknowledged contests/promotions Terms at setup
|
|
246
|
+
hostPromotionsAckAt DateTime?
|
|
247
|
+
/// Minimum event donation (cents) that qualifies for game entry when no linked tier (or OR with tier).
|
|
248
|
+
entryMinDonationCents Int?
|
|
249
|
+
/// Optional fundraising goal for public progress display (participation revenue + donations).
|
|
250
|
+
fundraiserGoalCents Int?
|
|
251
|
+
/// Host accepts inbound prize contributions from users/businesses.
|
|
252
|
+
seekingPrizes Boolean @default(false)
|
|
253
|
+
|
|
242
254
|
createdAt DateTime @default(now())
|
|
243
255
|
updatedAt DateTime @updatedAt
|
|
244
256
|
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
245
257
|
owner User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
246
258
|
sponsor CompetitionSponsor[]
|
|
247
259
|
prizes Prize[]
|
|
260
|
+
prizeOffers CompetitionPrizeOffer[]
|
|
248
261
|
participants CompetitionParticipant[]
|
|
249
262
|
votes CompetitionVote[]
|
|
250
263
|
matches CompetitionMatch[]
|
|
@@ -289,13 +302,46 @@ model CompetitionJudgeScore {
|
|
|
289
302
|
}
|
|
290
303
|
|
|
291
304
|
model CompetitionSponsor {
|
|
292
|
-
id
|
|
293
|
-
competitionId
|
|
294
|
-
userId
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
305
|
+
id String @id @default(cuid())
|
|
306
|
+
competitionId String
|
|
307
|
+
userId String?
|
|
308
|
+
/// Optional link to a Sponsor marketplace service for discovery/branding
|
|
309
|
+
sourceServiceId String?
|
|
310
|
+
/// Display name when sponsor is not a platform user
|
|
311
|
+
sponsorName String?
|
|
312
|
+
logoUrl String?
|
|
313
|
+
description String?
|
|
314
|
+
paidOn String?
|
|
315
|
+
competition Competition @relation(fields: [competitionId], references: [id], onDelete: Cascade)
|
|
316
|
+
sponsor User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
317
|
+
sourceService Service? @relation("CompetitionSponsorSourceService", fields: [sourceServiceId], references: [id], onDelete: SetNull)
|
|
318
|
+
|
|
319
|
+
@@index([sourceServiceId])
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/// Inbound prize contribution proposal (Bash matchmaker — host accepts → Prize row).
|
|
323
|
+
model CompetitionPrizeOffer {
|
|
324
|
+
id String @id @default(cuid())
|
|
325
|
+
competitionId String
|
|
326
|
+
offeredByUserId String
|
|
327
|
+
status CompetitionPrizeOfferStatus @default(PENDING)
|
|
328
|
+
name String
|
|
329
|
+
description String @db.Text
|
|
330
|
+
imageUrl String?
|
|
331
|
+
sponsorLabel String?
|
|
332
|
+
sourceServiceId String?
|
|
333
|
+
sourceSku String?
|
|
334
|
+
hostNote String?
|
|
335
|
+
createdAt DateTime @default(now())
|
|
336
|
+
updatedAt DateTime @updatedAt
|
|
337
|
+
respondedAt DateTime?
|
|
338
|
+
competition Competition @relation(fields: [competitionId], references: [id], onDelete: Cascade)
|
|
339
|
+
offeredBy User @relation("CompetitionPrizeOffersSubmitted", fields: [offeredByUserId], references: [id], onDelete: Cascade)
|
|
340
|
+
sourceService Service? @relation("CompetitionPrizeOfferSourceService", fields: [sourceServiceId], references: [id], onDelete: SetNull)
|
|
341
|
+
|
|
342
|
+
@@index([competitionId])
|
|
343
|
+
@@index([offeredByUserId])
|
|
344
|
+
@@index([status])
|
|
299
345
|
}
|
|
300
346
|
|
|
301
347
|
model CompetitionParticipant {
|
|
@@ -2034,8 +2080,13 @@ model TicketTier {
|
|
|
2034
2080
|
bashPassEligible Boolean @default(false)
|
|
2035
2081
|
/// Max BashPass redemptions for this tier (null = unlimited within tier capacity).
|
|
2036
2082
|
bashPassMaxRedemptions Int?
|
|
2083
|
+
/// One checkout buys a fixed package (e.g. table); price is package total, not per-person.
|
|
2084
|
+
isGroupTicket Boolean @default(false)
|
|
2085
|
+
/// Headcount included per package when isGroupTicket (e.g. 6). Required when isGroupTicket.
|
|
2086
|
+
groupTicketSeatCount Int?
|
|
2037
2087
|
ticketGiftGrants TicketGiftGrant[]
|
|
2038
2088
|
tierReleaseReminders TierReleaseReminder[]
|
|
2089
|
+
entryCompetition Competition? @relation("CompetitionEntryTicketTier")
|
|
2039
2090
|
|
|
2040
2091
|
@@unique([bashEventId, title])
|
|
2041
2092
|
@@index([availableAt])
|
|
@@ -2113,6 +2164,8 @@ model Ticket {
|
|
|
2113
2164
|
waitlistUserId String?
|
|
2114
2165
|
/// Rotated when ticket is transferred; QR payload must match for check-in (null = legacy tickets, no strict check).
|
|
2115
2166
|
qrToken String?
|
|
2167
|
+
/// Actual unit price paid at checkout in cents (PWYC tiers; null = use tier.price for legacy rows).
|
|
2168
|
+
paidUnitPriceCents Int?
|
|
2116
2169
|
|
|
2117
2170
|
/// P2P Venmo/Zelle off-platform payment flow
|
|
2118
2171
|
p2pPaymentMethod String?
|
|
@@ -2470,6 +2523,8 @@ model Prize {
|
|
|
2470
2523
|
prizeType PrizeType
|
|
2471
2524
|
name String // Prize name (e.g., "$100 Cash", "Backpack")
|
|
2472
2525
|
placeName String? // Display name (e.g., "1st Place", "Winner")
|
|
2526
|
+
sponsorLabel String? // e.g. "Contributed by Acme Co"
|
|
2527
|
+
imageUrl String? // Optional prize photo
|
|
2473
2528
|
prizeLevel Int
|
|
2474
2529
|
description String
|
|
2475
2530
|
competitionId String?
|
|
@@ -2477,6 +2532,16 @@ model Prize {
|
|
|
2477
2532
|
winnerUserId String?
|
|
2478
2533
|
wonAt DateTime? // When the prize was awarded
|
|
2479
2534
|
claimedAt DateTime? // When the prize was claimed
|
|
2535
|
+
/// Platform user who donated this prize (optional)
|
|
2536
|
+
contributorUserId String?
|
|
2537
|
+
/// Sponsor marketplace service the prize was picked from (optional)
|
|
2538
|
+
sourceServiceId String?
|
|
2539
|
+
sourceSku String?
|
|
2540
|
+
/// Contributor marked their in-kind commitment fulfilled (off-platform delivery via host)
|
|
2541
|
+
contributorFulfilledAt DateTime?
|
|
2542
|
+
contributorFulfilledNote String?
|
|
2543
|
+
/// Host marked prize handed to winner
|
|
2544
|
+
hostDeliveredAt DateTime?
|
|
2480
2545
|
|
|
2481
2546
|
// Automatic payment fields
|
|
2482
2547
|
autoPayEnabled Boolean @default(false)
|
|
@@ -2497,10 +2562,14 @@ model Prize {
|
|
|
2497
2562
|
|
|
2498
2563
|
competition Competition? @relation(fields: [competitionId], references: [id], onDelete: Cascade)
|
|
2499
2564
|
winner User? @relation(fields: [winnerUserId], references: [id], onDelete: Cascade)
|
|
2565
|
+
contributor User? @relation("PrizeContributor", fields: [contributorUserId], references: [id], onDelete: SetNull)
|
|
2566
|
+
sourceService Service? @relation("PrizeSourceService", fields: [sourceServiceId], references: [id], onDelete: SetNull)
|
|
2500
2567
|
bashPointsTransaction BashCreditTransaction? @relation(fields: [bashPointsTransactionId], references: [id], onDelete: SetNull)
|
|
2501
2568
|
|
|
2502
2569
|
@@index([competitionId])
|
|
2503
2570
|
@@index([winnerUserId]) // For fetching user's wins
|
|
2571
|
+
@@index([contributorUserId])
|
|
2572
|
+
@@index([sourceServiceId])
|
|
2504
2573
|
@@index([bashPointsTransactionId])
|
|
2505
2574
|
}
|
|
2506
2575
|
|
|
@@ -2819,6 +2888,8 @@ model User {
|
|
|
2819
2888
|
clubMembers ClubMember[]
|
|
2820
2889
|
competitions Competition[]
|
|
2821
2890
|
competitionSponsorships CompetitionSponsor[]
|
|
2891
|
+
competitionPrizeOffersSubmitted CompetitionPrizeOffer[] @relation("CompetitionPrizeOffersSubmitted")
|
|
2892
|
+
prizesContributed Prize[] @relation("PrizeContributor")
|
|
2822
2893
|
competitionParticipations CompetitionParticipant[]
|
|
2823
2894
|
competitionVotes CompetitionVote[]
|
|
2824
2895
|
competitionJudgeAssignments CompetitionJudgeAssignment[] @relation("CompetitionJudgeAssignments")
|
|
@@ -3555,6 +3626,9 @@ model Service {
|
|
|
3555
3626
|
promotionBlastTemplates PromotionBlastTemplate[]
|
|
3556
3627
|
promotionBlastEntitlements PromotionBlastEntitlement[]
|
|
3557
3628
|
promotionBlasts PromotionBlast[]
|
|
3629
|
+
competitionPrizesSourced Prize[] @relation("PrizeSourceService")
|
|
3630
|
+
competitionSponsorCredits CompetitionSponsor[] @relation("CompetitionSponsorSourceService")
|
|
3631
|
+
competitionPrizeOffersSourced CompetitionPrizeOffer[] @relation("CompetitionPrizeOfferSourceService")
|
|
3558
3632
|
|
|
3559
3633
|
@@index([serviceListingStripeSubscriptionId])
|
|
3560
3634
|
@@index([paymentAccountId])
|
|
@@ -6108,6 +6182,13 @@ enum PrizePaymentMethod {
|
|
|
6108
6182
|
Manual
|
|
6109
6183
|
}
|
|
6110
6184
|
|
|
6185
|
+
enum CompetitionPrizeOfferStatus {
|
|
6186
|
+
PENDING
|
|
6187
|
+
ACCEPTED
|
|
6188
|
+
DECLINED
|
|
6189
|
+
WITHDRAWN
|
|
6190
|
+
}
|
|
6191
|
+
|
|
6111
6192
|
enum PrizePaymentStatus {
|
|
6112
6193
|
Pending
|
|
6113
6194
|
AwaitingPayment
|
|
@@ -9171,6 +9252,8 @@ model GroupMember {
|
|
|
9171
9252
|
userId String
|
|
9172
9253
|
status GroupMemberStatus @default(Invited)
|
|
9173
9254
|
ticketId String? // Set when status = Going
|
|
9255
|
+
/// Group leader marked this member as having reimbursed their share off-platform (Venmo, etc.)
|
|
9256
|
+
reimbursedLeaderAt DateTime?
|
|
9174
9257
|
joinedAt DateTime @default(now())
|
|
9175
9258
|
|
|
9176
9259
|
group EventGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatGroupPackagePerPersonUsd,
|
|
3
|
+
groupPackageShareCents,
|
|
4
|
+
isGroupTicketTier,
|
|
5
|
+
packagesSoldFromTicketCount,
|
|
6
|
+
validateGroupTicketTierInput,
|
|
7
|
+
} from "../groupTicketUtils.js";
|
|
8
|
+
|
|
9
|
+
describe("isGroupTicketTier", () => {
|
|
10
|
+
it("returns true when flag and seat count are valid", () => {
|
|
11
|
+
expect(
|
|
12
|
+
isGroupTicketTier({ isGroupTicket: true, groupTicketSeatCount: 6 })
|
|
13
|
+
).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns false when seat count is below minimum", () => {
|
|
17
|
+
expect(
|
|
18
|
+
isGroupTicketTier({ isGroupTicket: true, groupTicketSeatCount: 1 })
|
|
19
|
+
).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("packagesSoldFromTicketCount", () => {
|
|
24
|
+
it("converts seat rows to package count", () => {
|
|
25
|
+
expect(packagesSoldFromTicketCount(12, 6)).toBe(2);
|
|
26
|
+
expect(packagesSoldFromTicketCount(7, 6)).toBe(2);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("groupPackageShareCents", () => {
|
|
31
|
+
it("splits package price evenly in cents", () => {
|
|
32
|
+
expect(groupPackageShareCents(60000, 6)).toBe(10000);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("formatGroupPackagePerPersonUsd", () => {
|
|
37
|
+
it("formats per-person USD", () => {
|
|
38
|
+
expect(formatGroupPackagePerPersonUsd(60000, 6)).toMatch(/\$100/);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("validateGroupTicketTierInput", () => {
|
|
43
|
+
it("rejects donation group packages", () => {
|
|
44
|
+
const result = validateGroupTicketTierInput({
|
|
45
|
+
isGroupTicket: true,
|
|
46
|
+
groupTicketSeatCount: 6,
|
|
47
|
+
isDonationTier: true,
|
|
48
|
+
isWaitlistTier: false,
|
|
49
|
+
pricingType: "USD",
|
|
50
|
+
});
|
|
51
|
+
expect(result.ok).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
});
|