@bash-app/bash-common 30.260.1 → 30.263.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 (89) hide show
  1. package/dist/__tests__/serviceCheckoutPaymentMethods.test.d.ts +2 -0
  2. package/dist/__tests__/serviceCheckoutPaymentMethods.test.d.ts.map +1 -0
  3. package/dist/__tests__/serviceCheckoutPaymentMethods.test.js +41 -0
  4. package/dist/__tests__/serviceCheckoutPaymentMethods.test.js.map +1 -0
  5. package/dist/__tests__/ticketBnplPaymentMethods.bankTransfer.test.d.ts +2 -0
  6. package/dist/__tests__/ticketBnplPaymentMethods.bankTransfer.test.d.ts.map +1 -0
  7. package/dist/__tests__/ticketBnplPaymentMethods.bankTransfer.test.js +30 -0
  8. package/dist/__tests__/ticketBnplPaymentMethods.bankTransfer.test.js.map +1 -0
  9. package/dist/__tests__/ticketBnplPaymentMethods.cashapp.test.d.ts +2 -0
  10. package/dist/__tests__/ticketBnplPaymentMethods.cashapp.test.d.ts.map +1 -0
  11. package/dist/__tests__/ticketBnplPaymentMethods.cashapp.test.js +33 -0
  12. package/dist/__tests__/ticketBnplPaymentMethods.cashapp.test.js.map +1 -0
  13. package/dist/__tests__/ticketBnplPaymentMethods.test.d.ts +2 -0
  14. package/dist/__tests__/ticketBnplPaymentMethods.test.d.ts.map +1 -0
  15. package/dist/__tests__/ticketBnplPaymentMethods.test.js +46 -0
  16. package/dist/__tests__/ticketBnplPaymentMethods.test.js.map +1 -0
  17. package/dist/definitions.d.ts +7 -1
  18. package/dist/definitions.d.ts.map +1 -1
  19. package/dist/definitions.js.map +1 -1
  20. package/dist/index.d.ts +6 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +6 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/ticketBnplPaymentMethods.d.ts +61 -0
  25. package/dist/ticketBnplPaymentMethods.d.ts.map +1 -0
  26. package/dist/ticketBnplPaymentMethods.js +83 -0
  27. package/dist/ticketBnplPaymentMethods.js.map +1 -0
  28. package/dist/utils/__tests__/featuredDiscoveryGeo.test.d.ts +2 -0
  29. package/dist/utils/__tests__/featuredDiscoveryGeo.test.d.ts.map +1 -0
  30. package/dist/utils/__tests__/featuredDiscoveryGeo.test.js +98 -0
  31. package/dist/utils/__tests__/featuredDiscoveryGeo.test.js.map +1 -0
  32. package/dist/utils/__tests__/flyerUtils.test.js +7 -1
  33. package/dist/utils/__tests__/flyerUtils.test.js.map +1 -1
  34. package/dist/utils/__tests__/guestSurface.test.d.ts +2 -0
  35. package/dist/utils/__tests__/guestSurface.test.d.ts.map +1 -0
  36. package/dist/utils/__tests__/guestSurface.test.js +94 -0
  37. package/dist/utils/__tests__/guestSurface.test.js.map +1 -0
  38. package/dist/utils/__tests__/ticketTierSchedule.test.d.ts +2 -0
  39. package/dist/utils/__tests__/ticketTierSchedule.test.d.ts.map +1 -0
  40. package/dist/utils/__tests__/ticketTierSchedule.test.js +84 -0
  41. package/dist/utils/__tests__/ticketTierSchedule.test.js.map +1 -0
  42. package/dist/utils/featuredDiscoveryGeo.d.ts +30 -0
  43. package/dist/utils/featuredDiscoveryGeo.d.ts.map +1 -0
  44. package/dist/utils/featuredDiscoveryGeo.js +47 -0
  45. package/dist/utils/featuredDiscoveryGeo.js.map +1 -0
  46. package/dist/utils/flyerUtils.d.ts +5 -0
  47. package/dist/utils/flyerUtils.d.ts.map +1 -1
  48. package/dist/utils/flyerUtils.js +24 -0
  49. package/dist/utils/flyerUtils.js.map +1 -1
  50. package/dist/utils/guestSurface.d.ts +114 -0
  51. package/dist/utils/guestSurface.d.ts.map +1 -0
  52. package/dist/utils/guestSurface.js +164 -0
  53. package/dist/utils/guestSurface.js.map +1 -0
  54. package/dist/utils/promotionBlastUtils.d.ts +38 -0
  55. package/dist/utils/promotionBlastUtils.d.ts.map +1 -0
  56. package/dist/utils/promotionBlastUtils.js +88 -0
  57. package/dist/utils/promotionBlastUtils.js.map +1 -0
  58. package/dist/utils/service/__tests__/defaultOfferAmountUtils.test.d.ts +2 -0
  59. package/dist/utils/service/__tests__/defaultOfferAmountUtils.test.d.ts.map +1 -0
  60. package/dist/utils/service/__tests__/defaultOfferAmountUtils.test.js +65 -0
  61. package/dist/utils/service/__tests__/defaultOfferAmountUtils.test.js.map +1 -0
  62. package/dist/utils/service/defaultOfferAmountUtils.d.ts +32 -0
  63. package/dist/utils/service/defaultOfferAmountUtils.d.ts.map +1 -0
  64. package/dist/utils/service/defaultOfferAmountUtils.js +115 -0
  65. package/dist/utils/service/defaultOfferAmountUtils.js.map +1 -0
  66. package/dist/utils/ticketTierSchedule.d.ts +58 -0
  67. package/dist/utils/ticketTierSchedule.d.ts.map +1 -0
  68. package/dist/utils/ticketTierSchedule.js +279 -0
  69. package/dist/utils/ticketTierSchedule.js.map +1 -0
  70. package/package.json +5 -2
  71. package/prisma/schema.prisma +340 -1
  72. package/src/__tests__/serviceCheckoutPaymentMethods.test.ts +59 -0
  73. package/src/__tests__/ticketBnplPaymentMethods.bankTransfer.test.ts +42 -0
  74. package/src/__tests__/ticketBnplPaymentMethods.cashapp.test.ts +45 -0
  75. package/src/__tests__/ticketBnplPaymentMethods.test.ts +66 -0
  76. package/src/definitions.ts +7 -1
  77. package/src/index.ts +6 -0
  78. package/src/ticketBnplPaymentMethods.ts +177 -0
  79. package/src/utils/__tests__/featuredDiscoveryGeo.test.ts +120 -0
  80. package/src/utils/__tests__/flyerUtils.test.ts +10 -0
  81. package/src/utils/__tests__/guestSurface.test.ts +128 -0
  82. package/src/utils/__tests__/ticketTierSchedule.test.ts +131 -0
  83. package/src/utils/featuredDiscoveryGeo.ts +75 -0
  84. package/src/utils/flyerUtils.ts +33 -0
  85. package/src/utils/guestSurface.ts +315 -0
  86. package/src/utils/promotionBlastUtils.ts +127 -0
  87. package/src/utils/service/__tests__/defaultOfferAmountUtils.test.ts +102 -0
  88. package/src/utils/service/defaultOfferAmountUtils.ts +170 -0
  89. package/src/utils/ticketTierSchedule.ts +387 -0
@@ -723,7 +723,27 @@ model BashEvent {
723
723
  allowPublicInterestRsvp Boolean @default(false)
724
724
  /// When true, guests can join a waitlist (activated automatically when amountOfGuests.allowWaitlistAtMax is set and max capacity is reached)
725
725
  waitlistEnabled Boolean @default(false)
726
- attendeeDisplayMode String @default("All") // "All" | "NetworkOnly" | "Hidden"
726
+ /// High-demand on-sale: virtual waiting room before checkout (requires queue worker when enabled).
727
+ queueEnabled Boolean @default(false)
728
+ /// When the waiting room opens (optional; null = opens at first paid checkout attempt).
729
+ queueOpensAt DateTime?
730
+ /// Target admits per second when queue is active.
731
+ queueAdmitRatePerSecond Int?
732
+ /// Stripe BNPL (Afterpay/Klarna) on eligible paid checkout.
733
+ installmentsEnabled Boolean @default(false)
734
+ /// Stripe Cash App Pay on eligible paid checkout (not Square OAuth).
735
+ cashAppEnabled Boolean @default(false)
736
+ /// Stripe US bank transfer (customer_balance) on eligible paid checkout.
737
+ bankTransferEnabled Boolean @default(false)
738
+ /// Send confirmation SMS for this event when user opted in and env allows.
739
+ smsConfirmationsEnabled Boolean @default(false)
740
+ /// Collect named holder per seat at checkout.
741
+ namedTicketsEnabled Boolean @default(false)
742
+ attendeeDisplayMode String @default("All") // "All" | "CountOnly" | "NetworkOnly" | "Hidden"
743
+ /// Optional headline above featured guests on bash detail (curated guest visibility).
744
+ featuredGuestsHeadline String?
745
+ /// When true, bash detail shows the full privacy-filtered guest list to everyone (not just tier holders).
746
+ attendeeListPublic Boolean @default(false)
727
747
  showOrganizerTitles Boolean @default(false)
728
748
  servicePreferences Json? // New tiered status: { "Entertainment": "need", "Sponsors": "booked_closed", ... }
729
749
  bookedServices Json? // Booked service details: { "Entertainment": { serviceId: "...", providerId: "...", bookedAt: "..." }, ... }
@@ -822,6 +842,7 @@ model BashEvent {
822
842
  tickets Ticket[]
823
843
  ticketGiftGrants TicketGiftGrant[]
824
844
  ticketTiers TicketTier[]
845
+ tierReleaseReminders TierReleaseReminder[]
825
846
  favoritedBy UserFavorite[]
826
847
  userPromoCodeRedemption UserPromoCodeRedemption[]
827
848
  userReport UserReport[]
@@ -887,6 +908,8 @@ model BashEvent {
887
908
  bashEventArtists BashEventArtist[]
888
909
  vanityPaths EventVanityPath[]
889
910
  flyerCampaigns FlyerCampaign[]
911
+ featuredGuests EventFeaturedGuest[]
912
+ attendeeVisibilities EventAttendeeVisibility[]
890
913
 
891
914
  /// Latest AI moderator verdict (see `bashApprovalAiService` + `mapAiResultToDecision`).
892
915
  /// Null = never reviewed by AI. Recomputed each time the bash transitions to Pending
@@ -903,6 +926,8 @@ model BashEvent {
903
926
  aiApprovalContentHash String?
904
927
 
905
928
  bookingOffers ServiceBookingOffer[]
929
+ promotionBlastEntitlements PromotionBlastEntitlement[]
930
+ promotionBlasts PromotionBlast[]
906
931
 
907
932
  @@index([templateId])
908
933
  @@index([parentEventId])
@@ -975,6 +1000,7 @@ enum FlyerSponsorSlot {
975
1000
 
976
1001
  enum FlyerSponsorReviewStatus {
977
1002
  DRAFT
1003
+ INVITE_PENDING
978
1004
  PAYMENT_PENDING
979
1005
  PAID
980
1006
  REVIEW_PENDING
@@ -1038,6 +1064,7 @@ model FlyerCampaign {
1038
1064
  artworkVersions FlyerArtwork[]
1039
1065
  sponsors FlyerCampaignSponsor[]
1040
1066
  conversions FlyerConversion[]
1067
+ bookingOffers ServiceBookingOffer[]
1041
1068
 
1042
1069
  createdAt DateTime @default(now())
1043
1070
  updatedAt DateTime @updatedAt
@@ -1121,6 +1148,7 @@ model FlyerCampaignSponsor {
1121
1148
 
1122
1149
  slotType FlyerSponsorSlot
1123
1150
  businessName String
1151
+ contactEmail String?
1124
1152
  logoS3Key String?
1125
1153
  logoAltText String?
1126
1154
  ctaText String?
@@ -1200,6 +1228,199 @@ model FlyerConversion {
1200
1228
  @@index([ticketId])
1201
1229
  }
1202
1230
 
1231
+ // --- Promotion Blast (on-site partner promos: time-boxed + geofence) ---
1232
+
1233
+ enum PromotionBlastTriggerType {
1234
+ TIME_BOXED
1235
+ GEOFENCE
1236
+ }
1237
+
1238
+ enum PromotionBlastTemplateReviewStatus {
1239
+ REVIEW_PENDING
1240
+ APPROVED
1241
+ FLAGGED
1242
+ }
1243
+
1244
+ enum PromotionBlastEntitlementStatus {
1245
+ PENDING_PAYMENT
1246
+ ACTIVE
1247
+ EXHAUSTED
1248
+ REVOKED
1249
+ REFUNDED
1250
+ }
1251
+
1252
+ enum PromotionBlastStatus {
1253
+ DRAFT
1254
+ SCHEDULED
1255
+ LIVE
1256
+ PAUSED
1257
+ ENDED
1258
+ CANCELLED
1259
+ }
1260
+
1261
+ enum PromotionBlastRedemptionMethod {
1262
+ QR
1263
+ MANUAL
1264
+ }
1265
+
1266
+ /// Reusable promo template saved on a partner service profile (How wizard).
1267
+ model PromotionBlastTemplate {
1268
+ id String @id @default(cuid())
1269
+ createdAt DateTime @default(now())
1270
+ updatedAt DateTime @updatedAt
1271
+
1272
+ serviceId String
1273
+ service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
1274
+
1275
+ name String
1276
+ triggerType PromotionBlastTriggerType @default(TIME_BOXED)
1277
+ headline String
1278
+ body String?
1279
+ ctaLabel String @default("Show at booth")
1280
+ imageUrl String?
1281
+
1282
+ defaultDurationMinutes Int?
1283
+ defaultRadiusFeet Int?
1284
+ defaultMaxRedemptions Int?
1285
+
1286
+ serviceAddonId String?
1287
+ specialOfferId String?
1288
+
1289
+ reviewStatus PromotionBlastTemplateReviewStatus @default(REVIEW_PENDING)
1290
+ reviewNotes String?
1291
+ reviewedAt DateTime?
1292
+ reviewedByUserId String?
1293
+ reviewedBy User? @relation("PromotionBlastTemplateReviewedBy", fields: [reviewedByUserId], references: [id], onDelete: SetNull)
1294
+ isActive Boolean @default(true)
1295
+ sortOrder Int @default(0)
1296
+
1297
+ blasts PromotionBlast[]
1298
+
1299
+ @@index([serviceId])
1300
+ @@index([serviceId, isActive])
1301
+ }
1302
+
1303
+ /// Paid package granting blast activations for a booking at an event.
1304
+ model PromotionBlastEntitlement {
1305
+ id String @id @default(cuid())
1306
+ createdAt DateTime @default(now())
1307
+ updatedAt DateTime @updatedAt
1308
+
1309
+ serviceBookingId String @unique
1310
+ serviceBooking ServiceBooking @relation(fields: [serviceBookingId], references: [id], onDelete: Cascade)
1311
+ bashEventId String
1312
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1313
+ serviceId String
1314
+ service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
1315
+ partnerUserId String
1316
+ partnerUser User @relation("PromotionBlastPartner", fields: [partnerUserId], references: [id], onDelete: Cascade)
1317
+
1318
+ maxBlasts Int @default(3)
1319
+ maxPushRecipients Int?
1320
+ maxRadiusFeet Int @default(500)
1321
+ allowedTriggerTypes PromotionBlastTriggerType[] @default([TIME_BOXED, GEOFENCE])
1322
+
1323
+ hostAccessFeeCents Int @default(0)
1324
+ bashPlatformFeeCents Int @default(0)
1325
+ paidAt DateTime?
1326
+ stripePaymentIntentId String?
1327
+
1328
+ blastsUsed Int @default(0)
1329
+ status PromotionBlastEntitlementStatus @default(PENDING_PAYMENT)
1330
+
1331
+ packageTier String?
1332
+
1333
+ blasts PromotionBlast[]
1334
+
1335
+ @@index([bashEventId])
1336
+ @@index([serviceId])
1337
+ @@index([partnerUserId])
1338
+ @@index([status])
1339
+ }
1340
+
1341
+ /// Runtime promo instance activated at an event.
1342
+ model PromotionBlast {
1343
+ id String @id @default(cuid())
1344
+ createdAt DateTime @default(now())
1345
+ updatedAt DateTime @updatedAt
1346
+
1347
+ entitlementId String
1348
+ entitlement PromotionBlastEntitlement @relation(fields: [entitlementId], references: [id], onDelete: Cascade)
1349
+ templateId String?
1350
+ template PromotionBlastTemplate? @relation(fields: [templateId], references: [id], onDelete: SetNull)
1351
+ bashEventId String
1352
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1353
+ serviceId String
1354
+ service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
1355
+ partnerUserId String
1356
+ partnerUser User @relation("PromotionBlastOwner", fields: [partnerUserId], references: [id], onDelete: Cascade)
1357
+
1358
+ triggerType PromotionBlastTriggerType
1359
+ startsAt DateTime
1360
+ endsAt DateTime?
1361
+ radiusFeet Int?
1362
+ centerLat Float?
1363
+ centerLng Float?
1364
+
1365
+ headline String
1366
+ body String?
1367
+ ctaLabel String @default("Show at booth")
1368
+ imageUrl String?
1369
+
1370
+ status PromotionBlastStatus @default(DRAFT)
1371
+
1372
+ pushSentCount Int @default(0)
1373
+ impressionCount Int @default(0)
1374
+ redemptionCount Int @default(0)
1375
+
1376
+ pausedAt DateTime?
1377
+ pausedByUserId String?
1378
+ pausedBy User? @relation("PromotionBlastPausedBy", fields: [pausedByUserId], references: [id], onDelete: SetNull)
1379
+
1380
+ redemptions PromotionBlastRedemption[]
1381
+ pushDeliveries PromotionBlastPushDelivery[]
1382
+
1383
+ @@index([bashEventId, status])
1384
+ @@index([entitlementId])
1385
+ @@index([serviceId])
1386
+ @@index([partnerUserId])
1387
+ @@index([status, endsAt])
1388
+ }
1389
+
1390
+ model PromotionBlastRedemption {
1391
+ id String @id @default(cuid())
1392
+ createdAt DateTime @default(now())
1393
+
1394
+ promotionBlastId String
1395
+ promotionBlast PromotionBlast @relation(fields: [promotionBlastId], references: [id], onDelete: Cascade)
1396
+ userId String
1397
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1398
+
1399
+ confirmationCode String?
1400
+ redeemedAt DateTime?
1401
+ method PromotionBlastRedemptionMethod @default(MANUAL)
1402
+
1403
+ @@unique([promotionBlastId, userId])
1404
+ @@index([promotionBlastId])
1405
+ @@index([userId])
1406
+ }
1407
+
1408
+ /// Tracks push sends for dedupe and global event caps.
1409
+ model PromotionBlastPushDelivery {
1410
+ id String @id @default(cuid())
1411
+ createdAt DateTime @default(now())
1412
+
1413
+ promotionBlastId String
1414
+ promotionBlast PromotionBlast @relation(fields: [promotionBlastId], references: [id], onDelete: Cascade)
1415
+ userId String
1416
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1417
+ bashEventId String
1418
+
1419
+ @@unique([promotionBlastId, userId])
1420
+ @@index([userId, bashEventId, createdAt])
1421
+ @@index([bashEventId])
1422
+ }
1423
+
1203
1424
  /// USPS carrier-route catalog (Utah MVP; expand for national rollout).
1204
1425
  model PostalCarrierRoute {
1205
1426
  id String @id @default(cuid())
@@ -1714,13 +1935,26 @@ model TicketTier {
1714
1935
  // Availability rules
1715
1936
  availabilityType String @default("Immediate") // "Immediate" | "OnDate" | "EngagedUsersOnly" | "UnlockWhenInterestReached" | "UnlockWhenTicketsSold"
1716
1937
  availableAt DateTime? // OnDate: when tier unlocks
1938
+ expiresAt DateTime? // Hide + block purchase after this instant
1939
+ preReleaseDisplay String @default("Tease") // "Tease" | "Hidden" before availableAt when OnDate
1940
+ isManuallySoldOut Boolean @default(false)
1941
+ notifyOnRelease Boolean @default(true)
1942
+ tierReleaseNotifiedAt DateTime?
1717
1943
  availableWhenInterestReached Int? // UnlockWhenInterestReached: min IdeaInterest count
1718
1944
  unlockWhenTicketsSold Int? // UnlockWhenTicketsSold: min tickets sold across event to unlock this tier
1719
1945
  maxTicketsPerUser Int? // Optional per-user purchase cap
1946
+ /// Presale audience gate (PR7): "Public" | "Ambashador" | "BashInsider" | "Promoters"
1947
+ presaleAudience String @default("Public")
1948
+ /// When presaleAudience != Public, public sale opens at this time (optional; falls back to availableAt)
1949
+ publicAvailableAt DateTime?
1720
1950
 
1721
1951
  // Privacy: "Public" | "LinkOnly" | "InviteOnly"
1722
1952
  tierPrivacy String @default("Public")
1723
1953
 
1954
+ /// Guest list visibility depth for ticket holders: "None" | "Partial" | "Full"
1955
+ guestListDepth String @default("None")
1956
+ partialRosterLimit Int?
1957
+
1724
1958
  // Checkout timer: host-configurable per-tier timeout (minutes). null = no timer.
1725
1959
  checkoutTimeoutMinutes Int?
1726
1960
 
@@ -1729,8 +1963,10 @@ model TicketTier {
1729
1963
  /// Max BashPass redemptions for this tier (null = unlimited within tier capacity).
1730
1964
  bashPassMaxRedemptions Int?
1731
1965
  ticketGiftGrants TicketGiftGrant[]
1966
+ tierReleaseReminders TierReleaseReminder[]
1732
1967
 
1733
1968
  @@unique([bashEventId, title])
1969
+ @@index([availableAt])
1734
1970
  }
1735
1971
 
1736
1972
  enum TicketGiftGrantStatus {
@@ -1805,6 +2041,14 @@ model Ticket {
1805
2041
  /// Rotated when ticket is transferred; QR payload must match for check-in (null = legacy tickets, no strict check).
1806
2042
  qrToken String?
1807
2043
 
2044
+ /// P2P Venmo/Zelle off-platform payment flow
2045
+ p2pPaymentMethod String?
2046
+ p2pTransactionId String?
2047
+ p2pRequestedAt DateTime?
2048
+ p2pConfirmedAt DateTime?
2049
+ /// Set when we send the ~24h-before-event P2P reminder to the host (once per ticket).
2050
+ p2pHostReminderSentAt DateTime?
2051
+
1808
2052
  // BashPoints Purchase Tracking
1809
2053
  purchaseType String? // "USD", "BashPoints", "Free", "Comp", "BashPass", "PayAtDoor", "Cash"
1810
2054
  /// Promo entered at Pay-at-Door reservation; discount applied when they pay at the door (analytics: unpaid rows with code set).
@@ -1845,6 +2089,37 @@ model Ticket {
1845
2089
  @@index([giftGrantId])
1846
2090
  }
1847
2091
 
2092
+ /// Host-curated spotlight row on bash detail (image + name only).
2093
+ model EventFeaturedGuest {
2094
+ id String @id @default(cuid())
2095
+ bashEventId String
2096
+ userId String
2097
+ sortOrder Int @default(0)
2098
+ featuredAt DateTime @default(now())
2099
+ featuredBy String
2100
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2101
+ user User @relation("FeaturedGuestOnEvent", fields: [userId], references: [id], onDelete: Cascade)
2102
+
2103
+ @@unique([bashEventId, userId])
2104
+ @@index([bashEventId, sortOrder])
2105
+ }
2106
+
2107
+ /// Per-guest visibility for an event (user × event).
2108
+ model EventAttendeeVisibility {
2109
+ id String @id @default(cuid())
2110
+ bashEventId String
2111
+ userId String
2112
+ visibility String @default("Visible") // Visible | Hidden | FeaturedPending | FeaturedInvited
2113
+ priorVisibility String? // Visible | Hidden — snapshot when host sends featured invite
2114
+ setAt DateTime @default(now())
2115
+ setBy String?
2116
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2117
+ user User @relation("AttendeeVisibilityOnEvent", fields: [userId], references: [id], onDelete: Cascade)
2118
+
2119
+ @@unique([bashEventId, userId])
2120
+ @@index([bashEventId, visibility])
2121
+ }
2122
+
1848
2123
  model TicketTransfer {
1849
2124
  id String @id @default(cuid())
1850
2125
  ticketId String
@@ -2515,6 +2790,12 @@ model User {
2515
2790
  serviceBookingMessages ServiceBookingMessage[] @relation("ServiceMessageSender")
2516
2791
  sentBookingOffers ServiceBookingOffer[] @relation("OfferSender")
2517
2792
  receivedBookingOffers ServiceBookingOffer[] @relation("OfferRecipient")
2793
+ promotionBlastEntitlements PromotionBlastEntitlement[] @relation("PromotionBlastPartner")
2794
+ promotionBlastsOwned PromotionBlast[] @relation("PromotionBlastOwner")
2795
+ promotionBlastsPaused PromotionBlast[] @relation("PromotionBlastPausedBy")
2796
+ promotionBlastRedemptions PromotionBlastRedemption[]
2797
+ promotionBlastPushDeliveries PromotionBlastPushDelivery[]
2798
+ promotionBlastTemplatesReviewed PromotionBlastTemplate[] @relation("PromotionBlastTemplateReviewedBy")
2518
2799
  sessions Session[]
2519
2800
  socialMediaProfiles SocialMediaProfile[]
2520
2801
  sponsorBookingRequestsAsHost SponsorBookingRequest[] @relation("SponsorBookingHost")
@@ -2523,6 +2804,8 @@ model User {
2523
2804
  paymentProviderAccounts PaymentProviderAccount[]
2524
2805
  ticketsISent Ticket[] @relation("TicketsISent")
2525
2806
  ticketsIOwn Ticket[] @relation("TicketsIOwn")
2807
+ eventFeaturedGuestSpots EventFeaturedGuest[] @relation("FeaturedGuestOnEvent")
2808
+ eventAttendeeVisibilities EventAttendeeVisibility[] @relation("AttendeeVisibilityOnEvent")
2526
2809
  bashEventDonations BashEventDonation[]
2527
2810
  bashCreativeSubmissions BashCreativeSubmission[]
2528
2811
  ticketsOnWaitlist Ticket[] @relation("TicketsOnWaitlist")
@@ -2572,6 +2855,7 @@ model User {
2572
2855
  redeemedVouchers Voucher[]
2573
2856
  bashEventPromoCodesIUsed BashEventPromoCode[] @relation("BashEventPromoCodeToUser")
2574
2857
  ticketTiersWaitListsIveJoined TicketTier[] @relation("TicketTierToUser")
2858
+ tierReleaseReminders TierReleaseReminder[]
2575
2859
  scoutReferralsMade ScoutReferral[] @relation("ScoutReferrer")
2576
2860
  eventReferralsMade EventReferral[] @relation("EventReferralsMade")
2577
2861
  eventReferralsReceived EventReferral[] @relation("EventReferralsReceived")
@@ -2683,6 +2967,8 @@ model UserPreferences {
2683
2967
  invitationNotify Boolean @default(true)
2684
2968
  commentNotify Boolean @default(true)
2685
2969
  servicePromotionsNotify Boolean @default(true)
2970
+ locationPromotionsOptIn Boolean @default(false)
2971
+ ticketTierUpdatesNotify Boolean @default(true)
2686
2972
  profileVisibility String @default("public")
2687
2973
  eventHistoryVisibility Boolean @default(true)
2688
2974
  servicesVisibility Boolean @default(true)
@@ -3101,6 +3387,10 @@ model Service {
3101
3387
  cancellationPolicy ServiceCancellationPolicy? @default(None)
3102
3388
  availableHours String?
3103
3389
  allowsInstantBooking Boolean @default(false)
3390
+ /// US bank transfer (Stripe `customer_balance`) on service booking Checkout.
3391
+ bankTransferEnabled Boolean @default(false)
3392
+ /// ACH Direct Debit (Stripe `us_bank_account`) on service booking Checkout.
3393
+ achDebitEnabled Boolean @default(false)
3104
3394
  instantBookingLeadTimeHours Int @default(0)
3105
3395
  displayGoogleReviewsOnDetailPage Boolean @default(true)
3106
3396
  displayBashReviewsOnDetailPage Boolean @default(true)
@@ -3179,6 +3469,9 @@ model Service {
3179
3469
  addonRequests ServiceAddonRequest[]
3180
3470
  serviceBudgets Budget[] @relation("ServiceBudgets")
3181
3471
  bookingOffers ServiceBookingOffer[]
3472
+ promotionBlastTemplates PromotionBlastTemplate[]
3473
+ promotionBlastEntitlements PromotionBlastEntitlement[]
3474
+ promotionBlasts PromotionBlast[]
3182
3475
 
3183
3476
  @@index([serviceListingStripeSubscriptionId])
3184
3477
  @@index([paymentAccountId])
@@ -3193,6 +3486,12 @@ model StripeAccount {
3193
3486
  ownerId String
3194
3487
  stripeAccountId String @unique
3195
3488
  stripeCustomerId String? @unique
3489
+ /// Cached from Stripe account.updated webhook — Connect BNPL eligibility.
3490
+ stripeKlarnaPaymentsActive Boolean?
3491
+ stripeCashappPaymentsActive Boolean?
3492
+ stripeUsBankTransferPaymentsActive Boolean?
3493
+ stripeUsBankAccountAchPaymentsActive Boolean?
3494
+ stripeCardPaymentsActive Boolean?
3196
3495
  logoId String?
3197
3496
  createdAt DateTime @default(now())
3198
3497
  updatedAt DateTime @updatedAt
@@ -4575,6 +4874,7 @@ model ServiceBooking {
4575
4874
  commissions BookingCommission[] @relation("BookingCommissions")
4576
4875
  sentReminders SentReminder[]
4577
4876
  offers ServiceBookingOffer[]
4877
+ promotionBlastEntitlement PromotionBlastEntitlement?
4578
4878
 
4579
4879
  @@index([status])
4580
4880
  @@index([creatorId])
@@ -5224,6 +5524,33 @@ enum NotificationType {
5224
5524
  BudgetInvoiceDueToday // Host/organizer: invoice due today
5225
5525
  BudgetInvoicePastDue // Host/organizer: invoice 1 day past due
5226
5526
  BudgetInvoicePastDueFinal // Host/organizer: invoice 15+ days past due
5527
+ TicketTierReleased // Tier scheduled release went live
5528
+ TicketTierExpiringSoon // Tier sale window closing soon
5529
+ TicketTierRestocked // Host reopened sold-out tier or added capacity
5530
+ FeaturedGuestInvited // Host invited ticket holder to be a featured guest
5531
+ FeaturedGuestInviteAccepted // Host: guest accepted featured guest invite
5532
+ FeaturedGuestInviteDeclined // Host: guest declined featured guest invite
5533
+ PartnerPromotionBlast // Attendee: partner on-site promo deal at an event
5534
+ }
5535
+
5536
+ /// Opt-in reminder for a scheduled tier release (v1.5).
5537
+ model TierReleaseReminder {
5538
+ id String @id @default(cuid())
5539
+ userId String
5540
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5541
+ ticketTierId String
5542
+ ticketTier TicketTier @relation(fields: [ticketTierId], references: [id], onDelete: Cascade)
5543
+ bashEventId String
5544
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
5545
+ reminded24hAt DateTime?
5546
+ reminded1hAt DateTime?
5547
+ remindedAtReleaseAt DateTime?
5548
+ expiryReminded1hAt DateTime?
5549
+ createdAt DateTime @default(now())
5550
+
5551
+ @@unique([userId, ticketTierId])
5552
+ @@index([bashEventId])
5553
+ @@index([ticketTierId])
5227
5554
  }
5228
5555
 
5229
5556
  enum NotificationPriority {
@@ -5263,6 +5590,9 @@ enum TicketStatus {
5263
5590
  Pending
5264
5591
  WaitlistPending // Requested a spot on a host-approval waitlist; awaiting decision
5265
5592
  RefundPending // Refund requested; held while next waitlister is given a claim window
5593
+ P2PPending // Venmo/Zelle payment requested; awaiting host confirmation
5594
+ P2PConfirmed // Host confirmed P2P payment; valid for admission
5595
+ P2PExpired // Event ended with unconfirmed P2P request (cleanup job)
5266
5596
  }
5267
5597
 
5268
5598
  enum DayOfWeek {
@@ -7112,6 +7442,13 @@ model ServiceBookingOffer {
7112
7442
  serviceBookingId String? // set once attached to a Pending booking or after accept
7113
7443
  vendorBookingRequestId String? // for Vendor/Exhibitor/Sponsor flow
7114
7444
 
7445
+ /// Flyer Blast sponsor slot offer — when set, accept materializes FlyerCampaignSponsor.
7446
+ flyerCampaignId String?
7447
+ flyerSlotType FlyerSponsorSlot?
7448
+
7449
+ /// Promotion Blast package terms during negotiation (JSON).
7450
+ promotionBlastPackageJson Json?
7451
+
7115
7452
  parentOfferId String? // the offer this is countering
7116
7453
  roundNumber Int // 1, 2, or 3 — server-enforced cap of 3
7117
7454
 
@@ -7147,6 +7484,7 @@ model ServiceBookingOffer {
7147
7484
  bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
7148
7485
  serviceBooking ServiceBooking? @relation(fields: [serviceBookingId], references: [id], onDelete: SetNull)
7149
7486
  vendorBookingRequest VendorBookingRequest? @relation(fields: [vendorBookingRequestId], references: [id], onDelete: SetNull)
7487
+ flyerCampaign FlyerCampaign? @relation(fields: [flyerCampaignId], references: [id], onDelete: SetNull)
7150
7488
  parentOffer ServiceBookingOffer? @relation("OfferCounters", fields: [parentOfferId], references: [id], onDelete: SetNull)
7151
7489
  counters ServiceBookingOffer[] @relation("OfferCounters")
7152
7490
  sender User @relation("OfferSender", fields: [senderId], references: [id])
@@ -7156,6 +7494,7 @@ model ServiceBookingOffer {
7156
7494
  @@index([serviceBookingId])
7157
7495
  @@index([recipientId, status])
7158
7496
  @@index([senderId])
7497
+ @@index([flyerCampaignId, flyerSlotType])
7159
7498
  }
7160
7499
 
7161
7500
  enum VendorBookingStatus {
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+
3
+ import {
4
+ resolveServiceCheckoutPaymentMethodTypes,
5
+ serviceCheckoutOffersAchDebit,
6
+ serviceCheckoutOffersBankTransfer,
7
+ } from "../ticketBnplPaymentMethods.js";
8
+
9
+ describe("resolveServiceCheckoutPaymentMethodTypes", () => {
10
+ it("includes customer_balance when bank transfer enabled", () => {
11
+ expect(
12
+ resolveServiceCheckoutPaymentMethodTypes({
13
+ bankTransferEnabled: true,
14
+ totalChargedCents: 250_000,
15
+ currency: "usd",
16
+ })
17
+ ).toContain("customer_balance");
18
+ });
19
+
20
+ it("includes us_bank_account when ACH enabled", () => {
21
+ expect(
22
+ resolveServiceCheckoutPaymentMethodTypes({
23
+ achDebitEnabled: true,
24
+ totalChargedCents: 250_000,
25
+ currency: "usd",
26
+ })
27
+ ).toContain("us_bank_account");
28
+ });
29
+
30
+ it("excludes async methods when globally disabled", () => {
31
+ expect(
32
+ resolveServiceCheckoutPaymentMethodTypes({
33
+ bankTransferEnabled: true,
34
+ achDebitEnabled: true,
35
+ totalChargedCents: 250_000,
36
+ currency: "usd",
37
+ bankTransferGloballyEnabled: false,
38
+ achDebitGloballyEnabled: false,
39
+ })
40
+ ).toEqual(["card", "link"]);
41
+ });
42
+
43
+ it("serviceCheckoutOffers* reflects resolver", () => {
44
+ expect(
45
+ serviceCheckoutOffersBankTransfer({
46
+ bankTransferEnabled: true,
47
+ totalChargedCents: 10_000,
48
+ currency: "usd",
49
+ })
50
+ ).toBe(true);
51
+ expect(
52
+ serviceCheckoutOffersAchDebit({
53
+ achDebitEnabled: true,
54
+ totalChargedCents: 10_000,
55
+ currency: "usd",
56
+ })
57
+ ).toBe(true);
58
+ });
59
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+
3
+ import {
4
+ resolveTicketCheckoutPaymentMethodTypes,
5
+ ticketCheckoutOffersBankTransfer,
6
+ } from "../ticketBnplPaymentMethods.js";
7
+
8
+ describe("resolveTicketCheckoutPaymentMethodTypes bank transfer", () => {
9
+ it("includes customer_balance when host toggle and USD order", () => {
10
+ expect(
11
+ resolveTicketCheckoutPaymentMethodTypes({
12
+ installmentsEnabled: false,
13
+ bankTransferEnabled: true,
14
+ totalChargedCents: 50_000,
15
+ currency: "usd",
16
+ })
17
+ ).toContain("customer_balance");
18
+ });
19
+
20
+ it("excludes customer_balance when globally disabled", () => {
21
+ expect(
22
+ resolveTicketCheckoutPaymentMethodTypes({
23
+ installmentsEnabled: false,
24
+ bankTransferEnabled: true,
25
+ totalChargedCents: 50_000,
26
+ currency: "usd",
27
+ bankTransferGloballyEnabled: false,
28
+ })
29
+ ).not.toContain("customer_balance");
30
+ });
31
+
32
+ it("ticketCheckoutOffersBankTransfer reflects resolver", () => {
33
+ expect(
34
+ ticketCheckoutOffersBankTransfer({
35
+ installmentsEnabled: false,
36
+ bankTransferEnabled: true,
37
+ totalChargedCents: 10_000,
38
+ currency: "usd",
39
+ })
40
+ ).toBe(true);
41
+ });
42
+ });
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+ import { describe, expect, it } from "@jest/globals";
5
+
6
+ import {
7
+ resolveTicketCheckoutPaymentMethodTypes,
8
+ ticketCheckoutOffersCashApp,
9
+ } from "../ticketBnplPaymentMethods.js";
10
+
11
+ describe("resolveTicketCheckoutPaymentMethodTypes cashapp", () => {
12
+ it("includes cashapp when host toggle and USD order", () => {
13
+ expect(
14
+ resolveTicketCheckoutPaymentMethodTypes({
15
+ installmentsEnabled: false,
16
+ cashAppEnabled: true,
17
+ totalChargedCents: 1500,
18
+ currency: "usd",
19
+ })
20
+ ).toContain("cashapp");
21
+ });
22
+
23
+ it("excludes cashapp when globally disabled", () => {
24
+ expect(
25
+ resolveTicketCheckoutPaymentMethodTypes({
26
+ installmentsEnabled: false,
27
+ cashAppEnabled: true,
28
+ totalChargedCents: 1500,
29
+ currency: "usd",
30
+ cashAppGloballyEnabled: false,
31
+ })
32
+ ).not.toContain("cashapp");
33
+ });
34
+
35
+ it("ticketCheckoutOffersCashApp reflects resolver", () => {
36
+ expect(
37
+ ticketCheckoutOffersCashApp({
38
+ cashAppEnabled: true,
39
+ installmentsEnabled: false,
40
+ totalChargedCents: 500,
41
+ currency: "usd",
42
+ })
43
+ ).toBe(true);
44
+ });
45
+ });