@bash-app/bash-common 30.236.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.
Files changed (180) hide show
  1. package/dist/__tests__/statusEnums.test.js +88 -7
  2. package/dist/__tests__/statusEnums.test.js.map +1 -1
  3. package/dist/definitions.d.ts +39 -8
  4. package/dist/definitions.d.ts.map +1 -1
  5. package/dist/definitions.js +31 -10
  6. package/dist/definitions.js.map +1 -1
  7. package/dist/extendedSchemas.d.ts +6 -0
  8. package/dist/extendedSchemas.d.ts.map +1 -1
  9. package/dist/extendedSchemas.js.map +1 -1
  10. package/dist/index.d.ts +13 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +16 -4
  13. package/dist/index.js.map +1 -1
  14. package/dist/mirroredPrismaEnums.d.ts +145 -0
  15. package/dist/mirroredPrismaEnums.d.ts.map +1 -0
  16. package/dist/mirroredPrismaEnums.js +136 -0
  17. package/dist/mirroredPrismaEnums.js.map +1 -0
  18. package/dist/utils/__tests__/nonprofitUtils.test.d.ts +2 -0
  19. package/dist/utils/__tests__/nonprofitUtils.test.d.ts.map +1 -0
  20. package/dist/utils/__tests__/nonprofitUtils.test.js +84 -0
  21. package/dist/utils/__tests__/nonprofitUtils.test.js.map +1 -0
  22. package/dist/utils/__tests__/paymentUtils.test.js +87 -0
  23. package/dist/utils/__tests__/paymentUtils.test.js.map +1 -1
  24. package/dist/utils/nonprofitUtils.d.ts +21 -0
  25. package/dist/utils/nonprofitUtils.d.ts.map +1 -0
  26. package/dist/utils/nonprofitUtils.js +29 -0
  27. package/dist/utils/nonprofitUtils.js.map +1 -0
  28. package/dist/utils/paymentUtils.d.ts +23 -0
  29. package/dist/utils/paymentUtils.d.ts.map +1 -1
  30. package/dist/utils/paymentUtils.js +24 -7
  31. package/dist/utils/paymentUtils.js.map +1 -1
  32. package/dist/utils/service/__tests__/billingCapUtils.test.d.ts +2 -0
  33. package/dist/utils/service/__tests__/billingCapUtils.test.d.ts.map +1 -0
  34. package/dist/utils/service/__tests__/billingCapUtils.test.js +120 -0
  35. package/dist/utils/service/__tests__/billingCapUtils.test.js.map +1 -0
  36. package/dist/utils/service/__tests__/cancellationPolicyRefundResolver.test.js +1 -1
  37. package/dist/utils/service/__tests__/cancellationPolicyRefundResolver.test.js.map +1 -1
  38. package/dist/utils/service/__tests__/eventPromoterPhase3.test.d.ts +2 -0
  39. package/dist/utils/service/__tests__/eventPromoterPhase3.test.d.ts.map +1 -0
  40. package/dist/utils/service/__tests__/eventPromoterPhase3.test.js +243 -0
  41. package/dist/utils/service/__tests__/eventPromoterPhase3.test.js.map +1 -0
  42. package/dist/utils/service/__tests__/eventPromoterUtils.test.d.ts +2 -0
  43. package/dist/utils/service/__tests__/eventPromoterUtils.test.d.ts.map +1 -0
  44. package/dist/utils/service/__tests__/eventPromoterUtils.test.js +333 -0
  45. package/dist/utils/service/__tests__/eventPromoterUtils.test.js.map +1 -0
  46. package/dist/utils/service/__tests__/offerAllowListUtils.test.d.ts +2 -0
  47. package/dist/utils/service/__tests__/offerAllowListUtils.test.d.ts.map +1 -0
  48. package/dist/utils/service/__tests__/offerAllowListUtils.test.js +52 -0
  49. package/dist/utils/service/__tests__/offerAllowListUtils.test.js.map +1 -0
  50. package/dist/utils/service/__tests__/offerComparisonUtils.test.d.ts +2 -0
  51. package/dist/utils/service/__tests__/offerComparisonUtils.test.d.ts.map +1 -0
  52. package/dist/utils/service/__tests__/offerComparisonUtils.test.js +111 -0
  53. package/dist/utils/service/__tests__/offerComparisonUtils.test.js.map +1 -0
  54. package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.d.ts +2 -0
  55. package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.d.ts.map +1 -0
  56. package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.js +155 -0
  57. package/dist/utils/service/__tests__/serviceBookingExposureUtils.test.js.map +1 -0
  58. package/dist/utils/service/__tests__/unifiedPricingResolver.test.d.ts +2 -0
  59. package/dist/utils/service/__tests__/unifiedPricingResolver.test.d.ts.map +1 -0
  60. package/dist/utils/service/__tests__/unifiedPricingResolver.test.js +77 -0
  61. package/dist/utils/service/__tests__/unifiedPricingResolver.test.js.map +1 -0
  62. package/dist/utils/service/__tests__/venueFBSettlementUtils.test.d.ts +2 -0
  63. package/dist/utils/service/__tests__/venueFBSettlementUtils.test.d.ts.map +1 -0
  64. package/dist/utils/service/__tests__/venueFBSettlementUtils.test.js +157 -0
  65. package/dist/utils/service/__tests__/venueFBSettlementUtils.test.js.map +1 -0
  66. package/dist/utils/service/__tests__/venueSettlementUtils.test.d.ts +2 -0
  67. package/dist/utils/service/__tests__/venueSettlementUtils.test.d.ts.map +1 -0
  68. package/dist/utils/service/__tests__/venueSettlementUtils.test.js +175 -0
  69. package/dist/utils/service/__tests__/venueSettlementUtils.test.js.map +1 -0
  70. package/dist/utils/service/__tests__/volunteerCompensationUtils.test.d.ts +2 -0
  71. package/dist/utils/service/__tests__/volunteerCompensationUtils.test.d.ts.map +1 -0
  72. package/dist/utils/service/__tests__/volunteerCompensationUtils.test.js +118 -0
  73. package/dist/utils/service/__tests__/volunteerCompensationUtils.test.js.map +1 -0
  74. package/dist/utils/service/apiServiceBookingApiUtils.d.ts.map +1 -1
  75. package/dist/utils/service/apiServiceBookingApiUtils.js +4 -0
  76. package/dist/utils/service/apiServiceBookingApiUtils.js.map +1 -1
  77. package/dist/utils/service/billingCapUtils.d.ts +86 -0
  78. package/dist/utils/service/billingCapUtils.d.ts.map +1 -0
  79. package/dist/utils/service/billingCapUtils.js +96 -0
  80. package/dist/utils/service/billingCapUtils.js.map +1 -0
  81. package/dist/utils/service/cancellationPolicyRefundResolver.d.ts +1 -1
  82. package/dist/utils/service/cancellationPolicyRefundResolver.d.ts.map +1 -1
  83. package/dist/utils/service/cancellationPolicyRefundResolver.js +1 -1
  84. package/dist/utils/service/cancellationPolicyRefundResolver.js.map +1 -1
  85. package/dist/utils/service/eventPromoterUtils.d.ts +319 -0
  86. package/dist/utils/service/eventPromoterUtils.d.ts.map +1 -0
  87. package/dist/utils/service/eventPromoterUtils.js +372 -0
  88. package/dist/utils/service/eventPromoterUtils.js.map +1 -0
  89. package/dist/utils/service/offerAllowListUtils.d.ts +42 -0
  90. package/dist/utils/service/offerAllowListUtils.d.ts.map +1 -0
  91. package/dist/utils/service/offerAllowListUtils.js +49 -0
  92. package/dist/utils/service/offerAllowListUtils.js.map +1 -0
  93. package/dist/utils/service/offerComparisonUtils.d.ts +69 -0
  94. package/dist/utils/service/offerComparisonUtils.d.ts.map +1 -0
  95. package/dist/utils/service/offerComparisonUtils.js +110 -0
  96. package/dist/utils/service/offerComparisonUtils.js.map +1 -0
  97. package/dist/utils/service/serviceBookingExposureUtils.d.ts +111 -0
  98. package/dist/utils/service/serviceBookingExposureUtils.d.ts.map +1 -0
  99. package/dist/utils/service/serviceBookingExposureUtils.js +133 -0
  100. package/dist/utils/service/serviceBookingExposureUtils.js.map +1 -0
  101. package/dist/utils/service/serviceBookingTypes.d.ts +1 -1
  102. package/dist/utils/service/serviceBookingTypes.d.ts.map +1 -1
  103. package/dist/utils/service/serviceUtils.d.ts +2 -1
  104. package/dist/utils/service/serviceUtils.d.ts.map +1 -1
  105. package/dist/utils/service/serviceUtils.js +17 -16
  106. package/dist/utils/service/serviceUtils.js.map +1 -1
  107. package/dist/utils/service/unifiedPricingResolver.d.ts +67 -0
  108. package/dist/utils/service/unifiedPricingResolver.d.ts.map +1 -0
  109. package/dist/utils/service/unifiedPricingResolver.js +75 -0
  110. package/dist/utils/service/unifiedPricingResolver.js.map +1 -0
  111. package/dist/utils/service/venueFBSettlementUtils.d.ts +122 -0
  112. package/dist/utils/service/venueFBSettlementUtils.d.ts.map +1 -0
  113. package/dist/utils/service/venueFBSettlementUtils.js +106 -0
  114. package/dist/utils/service/venueFBSettlementUtils.js.map +1 -0
  115. package/dist/utils/service/venueSettlementUtils.d.ts +107 -0
  116. package/dist/utils/service/venueSettlementUtils.d.ts.map +1 -0
  117. package/dist/utils/service/venueSettlementUtils.js +117 -0
  118. package/dist/utils/service/venueSettlementUtils.js.map +1 -0
  119. package/dist/utils/service/volunteerCompensationUtils.d.ts +75 -0
  120. package/dist/utils/service/volunteerCompensationUtils.d.ts.map +1 -0
  121. package/dist/utils/service/volunteerCompensationUtils.js +88 -0
  122. package/dist/utils/service/volunteerCompensationUtils.js.map +1 -0
  123. package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.d.ts +2 -0
  124. package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.d.ts.map +1 -0
  125. package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.js +67 -0
  126. package/dist/utils/venueLoyalty/__tests__/eligibilityUtils.test.js.map +1 -0
  127. package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.d.ts +2 -0
  128. package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.d.ts.map +1 -0
  129. package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.js +71 -0
  130. package/dist/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.js.map +1 -0
  131. package/dist/utils/venueLoyalty/eligibilityUtils.d.ts +33 -0
  132. package/dist/utils/venueLoyalty/eligibilityUtils.d.ts.map +1 -0
  133. package/dist/utils/venueLoyalty/eligibilityUtils.js +49 -0
  134. package/dist/utils/venueLoyalty/eligibilityUtils.js.map +1 -0
  135. package/dist/utils/venueLoyalty/redemptionCodeUtils.d.ts +35 -0
  136. package/dist/utils/venueLoyalty/redemptionCodeUtils.d.ts.map +1 -0
  137. package/dist/utils/venueLoyalty/redemptionCodeUtils.js +74 -0
  138. package/dist/utils/venueLoyalty/redemptionCodeUtils.js.map +1 -0
  139. package/dist/venueLoyaltyRedemption.d.ts +146 -1
  140. package/dist/venueLoyaltyRedemption.d.ts.map +1 -1
  141. package/dist/venueLoyaltyRedemption.js +18 -2
  142. package/dist/venueLoyaltyRedemption.js.map +1 -1
  143. package/package.json +1 -1
  144. package/prisma/schema.prisma +609 -214
  145. package/src/__tests__/statusEnums.test.ts +119 -11
  146. package/src/definitions.ts +57 -14
  147. package/src/extendedSchemas.ts +6 -0
  148. package/src/index.ts +16 -6
  149. package/src/mirroredPrismaEnums.ts +181 -0
  150. package/src/utils/__tests__/nonprofitUtils.test.ts +117 -0
  151. package/src/utils/__tests__/paymentUtils.test.ts +93 -0
  152. package/src/utils/nonprofitUtils.ts +44 -0
  153. package/src/utils/paymentUtils.ts +33 -7
  154. package/src/utils/service/__tests__/billingCapUtils.test.ts +175 -0
  155. package/src/utils/service/__tests__/cancellationPolicyRefundResolver.test.ts +1 -1
  156. package/src/utils/service/__tests__/eventPromoterPhase3.test.ts +296 -0
  157. package/src/utils/service/__tests__/eventPromoterUtils.test.ts +396 -0
  158. package/src/utils/service/__tests__/offerAllowListUtils.test.ts +76 -0
  159. package/src/utils/service/__tests__/offerComparisonUtils.test.ts +124 -0
  160. package/src/utils/service/__tests__/serviceBookingExposureUtils.test.ts +171 -0
  161. package/src/utils/service/__tests__/unifiedPricingResolver.test.ts +83 -0
  162. package/src/utils/service/__tests__/venueSettlementUtils.test.ts +219 -0
  163. package/src/utils/service/__tests__/volunteerCompensationUtils.test.ts +172 -0
  164. package/src/utils/service/apiServiceBookingApiUtils.ts +4 -0
  165. package/src/utils/service/billingCapUtils.ts +145 -0
  166. package/src/utils/service/cancellationPolicyRefundResolver.ts +1 -1
  167. package/src/utils/service/eventPromoterUtils.ts +644 -0
  168. package/src/utils/service/offerAllowListUtils.ts +81 -0
  169. package/src/utils/service/offerComparisonUtils.ts +197 -0
  170. package/src/utils/service/serviceBookingExposureUtils.ts +218 -0
  171. package/src/utils/service/serviceBookingTypes.ts +4 -0
  172. package/src/utils/service/serviceUtils.ts +18 -21
  173. package/src/utils/service/unifiedPricingResolver.ts +149 -0
  174. package/src/utils/service/venueSettlementUtils.ts +198 -0
  175. package/src/utils/service/volunteerCompensationUtils.ts +145 -0
  176. package/src/utils/venueLoyalty/__tests__/eligibilityUtils.test.ts +103 -0
  177. package/src/utils/venueLoyalty/__tests__/redemptionCodeUtils.test.ts +92 -0
  178. package/src/utils/venueLoyalty/eligibilityUtils.ts +84 -0
  179. package/src/utils/venueLoyalty/redemptionCodeUtils.ts +94 -0
  180. package/src/venueLoyaltyRedemption.ts +177 -2
@@ -682,6 +682,11 @@ model BashEvent {
682
682
  donationDetails String?
683
683
  absorbDonationFees Boolean @default(false)
684
684
  absorbTicketFees Boolean @default(false)
685
+ /// Phase 1 of unified-pricing roadmap: governs where PER_BASHPOINTS_ATTENDEE
686
+ /// settlements are paid from. `HostWallet` (default) pays directly from the
687
+ /// host's BP balance; `BashBpPool` taps a per-bash pool funded by
688
+ /// BashPoints-priced ticket sales before falling back to the host wallet.
689
+ bashPointsPayoutSource BashPointsPayoutSource @default(HostWallet)
685
690
  /// When true, attendees may request a refund from the app/email (host approves in Tickets → Refunds). When false, self-serve refund CTAs are hidden.
686
691
  allowAttendeeRefundRequests Boolean @default(true)
687
692
  // GuestPays / Split: Stripe processing + Bash platform fee presentation (see platformFeeEnabled).
@@ -697,7 +702,7 @@ model BashEvent {
697
702
  /// Host uses Tap to Pay on a supported device (no separate reader). Door flow when enabled.
698
703
  hasTapToPay Boolean @default(true)
699
704
  /// Optional Stripe Terminal Location id on the host's connected account.
700
- stripeTerminalLocationId String?
705
+ stripeTerminalLocationId String?
701
706
  /// Optional: attendees can tag which act they came to see; drives attribution reports and future payouts.
702
707
  artistAttributionEnabled Boolean @default(false)
703
708
  /// "percentage" | "flat" — how artistPayoutRate is interpreted for suggested splits (display/export).
@@ -890,6 +895,8 @@ model BashEvent {
890
895
  /// SHA-256 of the snapshot fed to the AI; lets us skip a re-run when nothing changed.
891
896
  aiApprovalContentHash String?
892
897
 
898
+ bookingOffers ServiceBookingOffer[]
899
+
893
900
  @@index([templateId])
894
901
  @@index([parentEventId])
895
902
  @@index([organizationId])
@@ -992,9 +999,9 @@ model FlyerCampaign {
992
999
  fulfillmentType FlyerFulfillmentType @default(DONE_FOR_YOU)
993
1000
 
994
1001
  /// EDDM: route map + tier pricing. LOB: recipient list + lobFlyerUtils pricing.
995
- mailChannel FlyerMailChannel @default(EDDM_ROUTES)
1002
+ mailChannel FlyerMailChannel @default(EDDM_ROUTES)
996
1003
  /// Used when `mailChannel` is LOB_ADDRESS_LIST. Ignored for pure EDDM campaigns.
997
- lobPostcardSize LobPostcardSize @default(LOB_6X11)
1004
+ lobPostcardSize LobPostcardSize @default(LOB_6X11)
998
1005
  lastVendorStatusSyncAt DateTime?
999
1006
  lastLobWebhookId String?
1000
1007
 
@@ -1008,8 +1015,8 @@ model FlyerCampaign {
1008
1015
  campaignQrSlug String @unique
1009
1016
  campaignPromoCode String?
1010
1017
 
1011
- ctaLabel String?
1012
- templateVariant String @default("default")
1018
+ ctaLabel String?
1019
+ templateVariant String @default("default")
1013
1020
  excludedSponsorCategories String[] @default([])
1014
1021
 
1015
1022
  status FlyerCampaignStatus @default(DRAFT)
@@ -1017,13 +1024,13 @@ model FlyerCampaign {
1017
1024
  vendorOrderRef String?
1018
1025
  vendorStatus String?
1019
1026
 
1020
- bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1021
- host User @relation(fields: [hostUserId], references: [id], onDelete: Cascade)
1022
- routes FlyerMailingRoute[]
1023
- mailingAddresses FlyerMailingAddress[]
1024
- artworkVersions FlyerArtwork[]
1025
- sponsors FlyerCampaignSponsor[]
1026
- conversions FlyerConversion[]
1027
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
1028
+ host User @relation(fields: [hostUserId], references: [id], onDelete: Cascade)
1029
+ routes FlyerMailingRoute[]
1030
+ mailingAddresses FlyerMailingAddress[]
1031
+ artworkVersions FlyerArtwork[]
1032
+ sponsors FlyerCampaignSponsor[]
1033
+ conversions FlyerConversion[]
1027
1034
 
1028
1035
  createdAt DateTime @default(now())
1029
1036
  updatedAt DateTime @updatedAt
@@ -1058,18 +1065,18 @@ model FlyerMailingAddress {
1058
1065
  campaignId String
1059
1066
  campaign FlyerCampaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
1060
1067
 
1061
- name String?
1062
- line1 String
1063
- line2 String?
1064
- city String
1065
- state String
1068
+ name String?
1069
+ line1 String
1070
+ line2 String?
1071
+ city String
1072
+ state String
1066
1073
  /// ZIP or ZIP+4 as a single string (normalized server-side for Lob)
1067
1074
  zipCode String
1068
1075
 
1069
- source FlyerMailingAddressSource @default(CSV_IMPORT)
1076
+ source FlyerMailingAddressSource @default(CSV_IMPORT)
1070
1077
  /// pending | valid | failed
1071
- validationStatus String @default("pending")
1072
- validationError String?
1078
+ validationStatus String @default("pending")
1079
+ validationError String?
1073
1080
  /// Lob `adr_…` after creating a saved address, optional
1074
1081
  lobAddressId String?
1075
1082
 
@@ -1099,9 +1106,9 @@ model FlyerArtwork {
1099
1106
  }
1100
1107
 
1101
1108
  model FlyerCampaignSponsor {
1102
- id String @id @default(cuid())
1103
- campaignId String
1104
- campaign FlyerCampaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
1109
+ id String @id @default(cuid())
1110
+ campaignId String
1111
+ campaign FlyerCampaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
1105
1112
  sponsorProfileId String?
1106
1113
  sponsorProfile SponsorProfile? @relation(fields: [sponsorProfileId], references: [id], onDelete: SetNull)
1107
1114
 
@@ -1115,8 +1122,8 @@ model FlyerCampaignSponsor {
1115
1122
 
1116
1123
  slotPriceCents Int @default(0)
1117
1124
  stripePaymentIntentId String?
1118
- stripeRefundId String?
1119
- refundedAt DateTime?
1125
+ stripeRefundId String?
1126
+ refundedAt DateTime?
1120
1127
  paidAt DateTime?
1121
1128
 
1122
1129
  hostPayoutCents Int?
@@ -1139,9 +1146,9 @@ model FlyerCampaignSponsor {
1139
1146
  }
1140
1147
 
1141
1148
  model SponsorProfile {
1142
- id String @id @default(cuid())
1149
+ id String @id @default(cuid())
1143
1150
  ownerUserId String
1144
- owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
1151
+ owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
1145
1152
  businessName String
1146
1153
  normalizedBusinessName String
1147
1154
  contactName String?
@@ -1153,11 +1160,11 @@ model SponsorProfile {
1153
1160
  logoAltText String?
1154
1161
  defaultCtaText String?
1155
1162
  description String?
1156
- preferredCities String[] @default([])
1163
+ preferredCities String[] @default([])
1157
1164
  budgetRange String?
1158
1165
  flyerSponsors FlyerCampaignSponsor[]
1159
- createdAt DateTime @default(now())
1160
- updatedAt DateTime @updatedAt
1166
+ createdAt DateTime @default(now())
1167
+ updatedAt DateTime @updatedAt
1161
1168
 
1162
1169
  @@unique([ownerUserId, normalizedBusinessName])
1163
1170
  @@index([ownerUserId])
@@ -1576,26 +1583,6 @@ model BashCreditTransaction {
1576
1583
  @@index([type])
1577
1584
  }
1578
1585
 
1579
- model PendingBashPointsGift {
1580
- id String @id @default(cuid())
1581
- senderId String
1582
- sender User @relation("SentPendingGifts", fields: [senderId], references: [id], onDelete: Cascade)
1583
- recipientEmail String
1584
- amount Int
1585
- message String?
1586
- status PendingGiftStatus @default(Pending)
1587
- claimedAt DateTime?
1588
- claimedByUserId String?
1589
- claimedBy User? @relation("ClaimedPendingGifts", fields: [claimedByUserId], references: [id], onDelete: SetNull)
1590
- returnedAt DateTime?
1591
- expiresAt DateTime
1592
- createdAt DateTime @default(now())
1593
-
1594
- @@index([recipientEmail, status])
1595
- @@index([senderId])
1596
- @@index([expiresAt, status])
1597
- }
1598
-
1599
1586
  model UserReferralCode {
1600
1587
  id String @id @default(cuid())
1601
1588
  userId String @unique
@@ -1810,11 +1797,11 @@ model Ticket {
1810
1797
  qrToken String?
1811
1798
 
1812
1799
  // BashPoints Purchase Tracking
1813
- purchaseType String? // "USD", "BashPoints", "Free", "Comp", "BashPass", "PayAtDoor", "Cash"
1800
+ purchaseType String? // "USD", "BashPoints", "Free", "Comp", "BashPass", "PayAtDoor", "Cash"
1814
1801
  /// Promo entered at Pay-at-Door reservation; discount applied when they pay at the door (analytics: unpaid rows with code set).
1815
1802
  payAtDoorPromoCode String?
1816
- pointsPaid Int? // BashPoints amount paid (if purchaseType="BashPoints")
1817
- stripePurchaseId String? // Stripe payment ID (if purchaseType="USD")
1803
+ pointsPaid Int? // BashPoints amount paid (if purchaseType="BashPoints")
1804
+ stripePurchaseId String? // Stripe payment ID (if purchaseType="USD")
1818
1805
 
1819
1806
  /// When set, this ticket was created from a host `TicketGiftGrant` (comp block for distribution).
1820
1807
  giftGrantId String?
@@ -2103,18 +2090,19 @@ model Link {
2103
2090
  }
2104
2091
 
2105
2092
  model Media {
2106
- id String @id @default(cuid())
2107
- url String @unique
2108
- type MediaType
2109
- mimetype String?
2110
- volunteerServiceId String?
2111
- serviceRatesAssociationId String?
2112
- serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
2113
- volunteerService VolunteerService? @relation(fields: [volunteerServiceId], references: [id])
2114
- stripeAccount StripeAccount[]
2115
- bashEventsReferencingMe BashEvent[] @relation("BashEventToMedia")
2116
- serviceReferencingMe Service[] @relation("MediaToService")
2117
- sponsoredEventsReferencingMe SponsoredEvent[] @relation("MediaToSponsoredEvent")
2093
+ id String @id @default(cuid())
2094
+ url String @unique
2095
+ type MediaType
2096
+ mimetype String?
2097
+ volunteerServiceId String?
2098
+ serviceRatesAssociationId String?
2099
+ serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
2100
+ volunteerService VolunteerService? @relation(fields: [volunteerServiceId], references: [id])
2101
+ stripeAccount StripeAccount[]
2102
+ bashEventsReferencingMe BashEvent[] @relation("BashEventToMedia")
2103
+ serviceReferencingMe Service[] @relation("MediaToService")
2104
+ sponsoredEventsReferencingMe SponsoredEvent[] @relation("MediaToSponsoredEvent")
2105
+ organizationsNonprofitDeterminationDoc Organization[] @relation("OrganizationNonprofitDeterminationDoc")
2118
2106
  }
2119
2107
 
2120
2108
  model Prize {
@@ -2245,16 +2233,16 @@ model SocialMediaProfile {
2245
2233
  }
2246
2234
 
2247
2235
  model User {
2248
- id String @id @default(cuid())
2249
- username String? @unique
2250
- email String @unique
2251
- createdOn DateTime @default(now())
2252
- stripeCustomerId String? @unique
2253
- stripeAccountId String? @unique
2236
+ id String @id @default(cuid())
2237
+ username String? @unique
2238
+ email String @unique
2239
+ createdOn DateTime @default(now())
2240
+ stripeCustomerId String? @unique
2241
+ stripeAccountId String? @unique
2254
2242
  /// Preferred processor for dual-rail onboarding (optional; legacy Stripe fields remain source of truth until fully migrated).
2255
- paymentProvider PaymentProvider @default(STRIPE)
2256
- isSuperUser Boolean @default(false)
2257
- isSuspended Boolean @default(false)
2243
+ paymentProvider PaymentProvider @default(STRIPE)
2244
+ isSuperUser Boolean @default(false)
2245
+ isSuspended Boolean @default(false)
2258
2246
  intent UserIntent?
2259
2247
  signupSource String? // e.g. 'jamwith', 'mixlog', 'organic' for attribution
2260
2248
  googleCalendarAccess String?
@@ -2454,8 +2442,7 @@ model User {
2454
2442
  bashEventMessagesRead BashEventMessageRead[] @relation("BashMessageReader")
2455
2443
  transferRequestsFrom BashEventTransferRequest[] @relation("TransferRequestsFrom")
2456
2444
  transferRequestsTo BashEventTransferRequest[] @relation("TransferRequestsTo")
2457
- sentPendingGifts PendingBashPointsGift[] @relation("SentPendingGifts")
2458
- claimedPendingGifts PendingBashPointsGift[] @relation("ClaimedPendingGifts")
2445
+ venueFBCarryoverCredits VenueFBCarryoverCredit[] @relation("VenueFBCarryoverHost")
2459
2446
  biometricCredentials BiometricCredential[]
2460
2447
  blocksReceived BlockedUser[] @relation("UserBlocksReceived")
2461
2448
  blocksCreated BlockedUser[] @relation("UserBlocksMade")
@@ -2509,6 +2496,8 @@ model User {
2509
2496
  serviceBookingForUser ServiceBooking[] @relation("BookingForUser")
2510
2497
  serviceBookingCheckout ServiceBookingCheckout[]
2511
2498
  serviceBookingMessages ServiceBookingMessage[] @relation("ServiceMessageSender")
2499
+ sentBookingOffers ServiceBookingOffer[] @relation("OfferSender")
2500
+ receivedBookingOffers ServiceBookingOffer[] @relation("OfferRecipient")
2512
2501
  sessions Session[]
2513
2502
  socialMediaProfiles SocialMediaProfile[]
2514
2503
  sponsorBookingRequestsAsHost SponsorBookingRequest[] @relation("SponsorBookingHost")
@@ -2608,17 +2597,19 @@ model User {
2608
2597
  ideaInterests IdeaInterest[]
2609
2598
 
2610
2599
  // Organization Relations
2611
- ownedOrganizations Organization[] @relation("OrganizationOwner")
2612
- organizationMemberships OrganizationMember[] @relation("OrganizationMemberUser")
2613
- organizationEventRSVPs EventRSVP[] @relation("OrganizationEventRSVP")
2614
- submittedExpenses Expense[] @relation("ExpenseSubmitter")
2615
- approvedExpenses Expense[] @relation("ExpenseApprover")
2616
- approvedBudgets Budget[] @relation("BudgetApprover")
2617
- submittedBudgets Budget[] @relation("BudgetSubmitter")
2618
- ownedBudgets Budget[] @relation("UserBudgets")
2619
- departmentsHeaded Department[] @relation("DepartmentHead")
2620
- favoriteOrganizations Organization[] @relation("FavoriteOrganizations")
2621
- eventSeriesCreated EventSeries[] @relation("EventSeriesCreator")
2600
+ ownedOrganizations Organization[] @relation("OrganizationOwner")
2601
+ /// Organizations this admin user has verified as a nonprofit.
2602
+ verifiedNonprofitOrganizations Organization[] @relation("OrganizationNonprofitVerifier")
2603
+ organizationMemberships OrganizationMember[] @relation("OrganizationMemberUser")
2604
+ organizationEventRSVPs EventRSVP[] @relation("OrganizationEventRSVP")
2605
+ submittedExpenses Expense[] @relation("ExpenseSubmitter")
2606
+ approvedExpenses Expense[] @relation("ExpenseApprover")
2607
+ approvedBudgets Budget[] @relation("BudgetApprover")
2608
+ submittedBudgets Budget[] @relation("BudgetSubmitter")
2609
+ ownedBudgets Budget[] @relation("UserBudgets")
2610
+ departmentsHeaded Department[] @relation("DepartmentHead")
2611
+ favoriteOrganizations Organization[] @relation("FavoriteOrganizations")
2612
+ eventSeriesCreated EventSeries[] @relation("EventSeriesCreator")
2622
2613
 
2623
2614
  // Service Includes & Add-On Requests
2624
2615
  suggestedIncludes ServiceInclude[] @relation("SuggestedIncludes")
@@ -3067,6 +3058,7 @@ model Service {
3067
3058
  pocBusinessEmail String?
3068
3059
  additionalInfo String?
3069
3060
  coverPhoto String?
3061
+ backgroundImage String? // Custom or curated background image URL for the service/org profile page
3070
3062
  mission String?
3071
3063
  communityInvolvement String?
3072
3064
  emergencyContact String?
@@ -3105,9 +3097,6 @@ model Service {
3105
3097
  verifiedAt DateTime? // When verification was approved
3106
3098
  licenseNumber String? // License/registration number
3107
3099
  certifications String[] @default([]) // Array of certification names
3108
- /// Custom scope pricing — admin-gated flag for providers who need variable/quote-based pricing
3109
- customScopeStatus CustomScopeStatus @default(None)
3110
- customScopeRequestNote String? // Provider's explanation of why they need custom scope
3111
3100
  bashFeedPosts BashFeedPost[]
3112
3101
  bashEventArtists BashEventArtist[]
3113
3102
  bashCreativeSubmissions BashCreativeSubmission[]
@@ -3147,6 +3136,7 @@ model Service {
3147
3136
  includes ServiceInclude[]
3148
3137
  addonRequests ServiceAddonRequest[]
3149
3138
  serviceBudgets Budget[] @relation("ServiceBudgets")
3139
+ bookingOffers ServiceBookingOffer[]
3150
3140
 
3151
3141
  @@index([serviceListingStripeSubscriptionId])
3152
3142
  @@index([paymentAccountId])
@@ -3173,24 +3163,24 @@ model StripeAccount {
3173
3163
 
3174
3164
  /// Connects a user to Stripe and/or Square rails for provider payouts (dual-processor layer).
3175
3165
  model PaymentProviderAccount {
3176
- id String @id @default(cuid())
3177
- userId String
3178
- provider PaymentProvider @default(STRIPE)
3179
- stripeAccountId String? @unique
3180
- stripeCustomerId String? @unique
3181
- squareMerchantId String? @unique
3182
- squareLocationId String?
3183
- squareAccessToken String? @db.Text
3184
- squareRefreshToken String? @db.Text
3185
- squareTokenExpiresAt DateTime?
3186
- accountVerified Boolean @default(false)
3187
- payoutsEnabled Boolean @default(false)
3188
- accountStatus String?
3189
- createdAt DateTime @default(now())
3190
- updatedAt DateTime @updatedAt
3191
- lastVerifiedAt DateTime?
3192
- user User @relation(fields: [userId], references: [id], onDelete: Restrict, onUpdate: Cascade)
3193
- services Service[]
3166
+ id String @id @default(cuid())
3167
+ userId String
3168
+ provider PaymentProvider @default(STRIPE)
3169
+ stripeAccountId String? @unique
3170
+ stripeCustomerId String? @unique
3171
+ squareMerchantId String? @unique
3172
+ squareLocationId String?
3173
+ squareAccessToken String? @db.Text
3174
+ squareRefreshToken String? @db.Text
3175
+ squareTokenExpiresAt DateTime?
3176
+ accountVerified Boolean @default(false)
3177
+ payoutsEnabled Boolean @default(false)
3178
+ accountStatus String?
3179
+ createdAt DateTime @default(now())
3180
+ updatedAt DateTime @updatedAt
3181
+ lastVerifiedAt DateTime?
3182
+ user User @relation(fields: [userId], references: [id], onDelete: Restrict, onUpdate: Cascade)
3183
+ services Service[]
3194
3184
 
3195
3185
  @@unique([userId, provider])
3196
3186
  @@index([userId])
@@ -3211,32 +3201,47 @@ model StripeDispute {
3211
3201
  }
3212
3202
 
3213
3203
  model VolunteerService {
3214
- id String @id @default(cuid())
3204
+ id String @id @default(cuid())
3215
3205
  userId String
3216
3206
  serviceRangeId String?
3217
3207
  fullName String?
3218
3208
  address String?
3219
3209
  email String?
3220
3210
  phone String?
3221
- agreedToAgreement Boolean @default(false)
3222
- description String @default("")
3223
- status VolunteerServiceStatus @default(Draft)
3211
+ agreedToAgreement Boolean @default(false)
3212
+ description String @default("")
3213
+ status VolunteerServiceStatus @default(Draft)
3224
3214
  skills String?
3225
3215
  experienceLevel String?
3226
- preferredEventTypes String[] @default([])
3227
- availability String[] @default([])
3216
+ preferredEventTypes String[] @default([])
3217
+ availability String[] @default([])
3228
3218
  physicalCapabilities String?
3229
3219
  equipment String?
3230
3220
  transportation String?
3231
3221
  emergencyContactName String?
3232
3222
  emergencyContactPhone String?
3233
- serviceId String @unique
3234
- links Link[] @relation("VolunteerServiceLinks")
3223
+ serviceId String @unique
3224
+ // Volunteer compensation block — intentionally NARROWER than the unified
3225
+ // pricing block used by paid verticals. Volunteers are not employees or
3226
+ // contractors, so this surface deliberately excludes USD rates,
3227
+ // PER_ATTENDEE, revenue share, etc. See
3228
+ // `bash-common/src/utils/service/volunteerCompensationUtils.ts` and
3229
+ // `docs/help-center/pricing-models/volunteer-stipend.md`.
3230
+ compensationType VolunteerCompensationType @default(None)
3231
+ /// BashPoints amount per `rateUnit`. Closed-loop: only redeemable on Bash.
3232
+ bashPointsStipend Int?
3233
+ /// `"shift" | "hour"` — kept as a String for forward flexibility.
3234
+ rateUnit String?
3235
+ /// Free-form description of any perks ("Comp ticket + drink wristband + tee").
3236
+ perksDescription String?
3237
+ /// Host-facing notes ("Free swag bag if you stay through breakdown").
3238
+ compensationNotes String?
3239
+ links Link[] @relation("VolunteerServiceLinks")
3235
3240
  media Media[]
3236
3241
  serviceRatesAssociation ServiceRatesAssociation?
3237
- service Service @relation("ServiceToVolunteer", fields: [serviceId], references: [id])
3238
- serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3239
- user User @relation(fields: [userId], references: [id])
3242
+ service Service @relation("ServiceToVolunteer", fields: [serviceId], references: [id])
3243
+ serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3244
+ user User @relation(fields: [userId], references: [id])
3240
3245
 
3241
3246
  @@index([userId])
3242
3247
  }
@@ -3255,6 +3260,18 @@ model EventService {
3255
3260
  menuItems String?
3256
3261
  venueTypes String[]
3257
3262
  secondaryVenueTypes String[] @default([])
3263
+ // Pricing Model Fields — Event Promoter subtype is locked to PER_ATTENDEE
3264
+ // by `validateEventPromoterPricing` in bash-common/eventPromoterUtils.ts.
3265
+ pricingModel PricingModel? @default(CUSTOM)
3266
+ baseRateCents Int?
3267
+ // BashPoints unit rate, used when pricingModel = PER_BASHPOINTS_ATTENDEE
3268
+ // or for BP-priced tiered packages. Kept alongside baseRateCents so a single
3269
+ // service can quote in either currency. See Phase 1 of the unified-pricing
3270
+ // roadmap.
3271
+ baseRateBashPoints Int?
3272
+ rateUnit String?
3273
+ minimumChargeCents Int?
3274
+ minimumQuantity Int?
3258
3275
  crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
3259
3276
  serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3260
3277
  service Service?
@@ -3292,9 +3309,19 @@ model EntertainmentService {
3292
3309
  notifyOnMatchingVenues Boolean @default(true)
3293
3310
  lastMatchNotificationSent DateTime?
3294
3311
 
3295
- crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
3296
- serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3297
- service Service?
3312
+ // Phase 1 unified pricing block — adds parity with EventService/Vendor/etc.
3313
+ // so EntertainmentService can quote PER_ATTENDEE, PER_PAID_ATTENDEE, etc.
3314
+ pricingModel PricingModel? @default(CUSTOM)
3315
+ baseRateCents Int?
3316
+ baseRateBashPoints Int?
3317
+ rateUnit String?
3318
+ minimumChargeCents Int?
3319
+ minimumQuantity Int?
3320
+ tierPricing Json?
3321
+ pricingNotes String?
3322
+ crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
3323
+ serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3324
+ service Service?
3298
3325
  }
3299
3326
 
3300
3327
  model Vendor {
@@ -3325,6 +3352,7 @@ model Vendor {
3325
3352
  // Pricing Model Fields
3326
3353
  pricingModel PricingModel? @default(CUSTOM)
3327
3354
  baseRateCents Int? // Base rate in cents
3355
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3328
3356
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3329
3357
  minimumChargeCents Int? // Minimum booking amount in cents
3330
3358
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3445,6 +3473,7 @@ model Exhibitor {
3445
3473
  // Pricing Model Fields
3446
3474
  pricingModel PricingModel? @default(CUSTOM)
3447
3475
  baseRateCents Int? // Base rate in cents
3476
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3448
3477
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3449
3478
  minimumChargeCents Int? // Minimum booking amount in cents
3450
3479
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3472,6 +3501,7 @@ model Sponsor {
3472
3501
  // Pricing Model Fields
3473
3502
  pricingModel PricingModel? @default(CUSTOM)
3474
3503
  baseRateCents Int? // Base rate in cents
3504
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3475
3505
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3476
3506
  minimumChargeCents Int? // Minimum booking amount in cents
3477
3507
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3519,42 +3549,187 @@ model Venue {
3519
3549
  notifyOnMatchingMusicians Boolean @default(true)
3520
3550
  lastMatchNotificationSent DateTime?
3521
3551
 
3522
- /// Venue loyalty program intent (wizard + profile; redemption is future work)
3552
+ /// Venue loyalty program. Per-offer structured configuration lives on
3553
+ /// VenueLoyaltyOffer. `loyaltyTemplateIds[]` and `loyaltyNotes` are deprecated
3554
+ /// (kept for backward compat through one release); new wizards write offers.
3523
3555
  loyaltyEnabled Boolean @default(false)
3524
3556
  loyaltyTemplateIds String[] @default([])
3525
3557
  loyaltyNotes String?
3526
3558
 
3527
3559
  bashEvents BashEvent[]
3528
3560
  service Service?
3561
+ venueLoyaltyOffers VenueLoyaltyOffer[]
3529
3562
  venueLoyaltyRedemptions VenueLoyaltyRedemption[]
3530
3563
 
3531
3564
  // Pricing model — what the venue charges the host
3532
3565
  pricingModel PricingModel? @default(CUSTOM)
3533
3566
  baseRateCents Int?
3567
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3534
3568
  rateUnit String?
3535
3569
  minimumChargeCents Int?
3536
3570
  minimumQuantity Int?
3537
3571
  tierPricing Json?
3538
3572
  pricingNotes String?
3573
+
3574
+ // Phase 2 of the unified-pricing roadmap — F&B minimum spend + revenue share.
3575
+ // All snapshot fields are copied onto `ServiceBooking` at confirmation time
3576
+ // so subsequent policy edits don't move historical bookings.
3577
+ fbMinimumEnabled Boolean @default(false)
3578
+ /// Per-day-of-week minimums in cents. JSON shape:
3579
+ /// `{ Mon: 800000, Tue: 800000, Wed: 800000, Thu: 800000, Fri: 4000000, Sat: 4000000, Sun: 2000000 }`.
3580
+ /// Missing keys → no minimum that day. Date-specific overrides live in
3581
+ /// `VenueFBMinimumOverride` and beat the schedule.
3582
+ fbMinimumSchedule Json?
3583
+ /// ISO 4217 code. Only USD is supported in Phase 2; field reserved for future.
3584
+ fbMinimumCurrency String? @default("USD")
3585
+ /// Does the stated minimum already credit service charge as part of the
3586
+ /// covered amount? Industry default = TRUE.
3587
+ fbServiceChargeCountsTowardMinimum Boolean @default(true)
3588
+ /// Does the stated minimum include tax in the spend it counts? Industry
3589
+ /// default = FALSE.
3590
+ fbMinimumIncludesTax Boolean @default(false)
3591
+ /// Free-form policy notes ("Minimum waived for non-profit events", etc.).
3592
+ fbMinimumNotes String?
3593
+ /// Default resolution when a shortfall occurs at settlement. Venue can
3594
+ /// override on a per-booking basis when uploading the invoice.
3595
+ defaultFBShortfallResolution FBShortfallResolution? @default(ChargeDelta)
3596
+
3597
+ /// Revenue-share split with the host.
3598
+ revenueShareEnabled Boolean @default(false)
3599
+ /// 0..100 — the percentage of `revenueShareBasis` the HOST keeps. Venue
3600
+ /// share is `100 - revenueShareHostPercentage`. Single source of truth.
3601
+ revenueShareHostPercentage Int?
3602
+ /// `"FB_SALES" | "TICKET_REVENUE" | "TOTAL_GROSS"` — what the % is taken on.
3603
+ revenueShareBasis String?
3604
+ /// Free-form notes shown next to the rev-share split.
3605
+ revenueShareNotes String?
3606
+
3607
+ fbCarryoverCredits VenueFBCarryoverCredit[]
3608
+ fbMinimumOverrides VenueFBMinimumOverride[]
3609
+ }
3610
+
3611
+ /// Date-based override of the per-day-of-week F&B schedule. Use cases: NYE,
3612
+ /// Halloween, holiday weekends, special-event nights. Wizard surfaces these
3613
+ /// as a small calendar/list.
3614
+ model VenueFBMinimumOverride {
3615
+ id String @id @default(cuid())
3616
+ venueId String
3617
+ startDate DateTime
3618
+ endDate DateTime
3619
+ /// Override amount in cents. Replaces the schedule's day-of-week minimum
3620
+ /// for any bash whose start falls inside `[startDate, endDate]`.
3621
+ minimumCents Int
3622
+ /// Optional human label ("NYE 2026").
3623
+ note String?
3624
+ createdAt DateTime @default(now())
3625
+ updatedAt DateTime @updatedAt
3626
+ venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3627
+
3628
+ @@index([venueId])
3629
+ @@index([venueId, startDate])
3630
+ }
3631
+
3632
+ /// F&B credit a host accumulated either by exceeding the minimum at a prior
3633
+ /// bash OR by the venue choosing `CreditFutureBooking` on a shortfall. Applies
3634
+ /// as a discount on the next bash at the same venue. Default expiry: 12 months
3635
+ /// from `issuedAt` (per Phase 2 calibration).
3636
+ model VenueFBCarryoverCredit {
3637
+ id String @id @default(cuid())
3638
+ venueId String
3639
+ hostUserId String
3640
+ /// Booking that generated the credit (excess spend, or shortfall converted
3641
+ /// to a future credit).
3642
+ originatingServiceBookingId String?
3643
+ creditCents Int
3644
+ issuedAt DateTime @default(now())
3645
+ /// Default: `issuedAt + 12 months`.
3646
+ expiresAt DateTime?
3647
+ consumedAt DateTime?
3648
+ consumedByServiceBookingId String?
3649
+ venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3650
+ host User @relation("VenueFBCarryoverHost", fields: [hostUserId], references: [id], onDelete: Cascade)
3651
+
3652
+ @@index([venueId])
3653
+ @@index([hostUserId])
3654
+ @@index([hostUserId, venueId, expiresAt])
3539
3655
  }
3540
3656
 
3541
- /// Guest-requested perk aligned with Venue.loyaltyTemplateIds; host marks redeemedAt when fulfilled.
3542
- model VenueLoyaltyRedemption {
3543
- id String @id @default(cuid())
3544
- venueId String
3545
- userId String
3546
- templateId String
3547
- claimedAt DateTime @default(now())
3548
- redeemedAt DateTime?
3549
- guestNotes String?
3550
- hostNotes String?
3657
+ /// Structured per-offer loyalty configuration for a venue. Replaces the flat
3658
+ /// Venue.loyaltyTemplateIds[] (which now lives on as legacy/deprecated config).
3659
+ /// Each row is one perk the venue offers: BashPoints price (optional), eligibility
3660
+ /// gates (optional), cooldown, and claim expiry.
3661
+ model VenueLoyaltyOffer {
3662
+ id String @id @default(cuid())
3663
+ venueId String
3664
+ /// One of VENUE_LOYALTY_TEMPLATE_IDS — used for default copy + categorization.
3665
+ templateId String
3666
+ /// Title shown to guests on the public loyalty section. Defaults to template copy
3667
+ /// when the venue creates an offer from a template.
3668
+ title String
3669
+ description String?
3670
+ /// Optional BashPoints price. Null = free request (legacy "polite-request" mode).
3671
+ bashPointsCost Int?
3672
+ /// Optional guest-side gate. Counts distinct BashEvents at this venue where the
3673
+ /// user has a non-refunded paid ticket.
3674
+ minTicketedEventsAttended Int?
3675
+ /// Optional host-side gate. Counts confirmed ServiceBookings where the user is
3676
+ /// the booker and the service is this venue.
3677
+ minBookingsAsHost Int?
3678
+ /// Days a guest must wait after redeeming/declining/expiring before claiming
3679
+ /// the same offer again. 0 = no cooldown.
3680
+ cooldownDays Int @default(0)
3681
+ /// How many days a generated redemption code stays valid before auto-refund.
3682
+ claimExpiryDays Int @default(30)
3683
+ /// Soft-disable so codes-in-flight still resolve cleanly.
3684
+ enabled Boolean @default(true)
3685
+ createdAt DateTime @default(now())
3686
+ updatedAt DateTime @updatedAt
3551
3687
 
3552
- venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3553
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
3688
+ venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3689
+ redemptions VenueLoyaltyRedemption[]
3690
+
3691
+ @@index([venueId, enabled])
3692
+ }
3554
3693
 
3694
+ /// Guest claim against a VenueLoyaltyOffer. BashPoints are escrowed at claim time
3695
+ /// (when bashPointsCost > 0), credited to the venue owner on redemption, or refunded
3696
+ /// to the guest on decline/expire. Every transition writes a BashCreditTransaction
3697
+ /// row tagged CreditSourceType.VenueLoyaltyRedemption.
3698
+ model VenueLoyaltyRedemption {
3699
+ id String @id @default(cuid())
3700
+ venueId String
3701
+ /// Nullable so legacy rows (pre-offer migration) still resolve. New claims always set it.
3702
+ offerId String?
3703
+ userId String
3704
+ /// Copy of offer.templateId at claim time (for legacy display compat).
3705
+ templateId String
3706
+ /// BashPoints cost snapshotted at claim time so later offer edits don't shift accounting.
3707
+ bashPointsCost Int @default(0)
3708
+ /// 8-char alphanumeric code generated server-side; null on legacy rows.
3709
+ redemptionCode String?
3710
+ /// claimedAt + offer.claimExpiryDays. Null on legacy rows.
3711
+ expiresAt DateTime?
3712
+ claimedAt DateTime @default(now())
3713
+ redeemedAt DateTime?
3714
+ declinedAt DateTime?
3715
+ expiredAt DateTime?
3716
+ /// "host_declined" | "expired" | other freeform reasons.
3717
+ cancelReason String?
3718
+ guestNotes String?
3719
+ hostNotes String?
3720
+ /// { ticketedEventsAttended: number, bookingsAsHost: number } captured at claim time.
3721
+ eligibilitySnapshot Json?
3722
+
3723
+ venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3724
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
3725
+ offer VenueLoyaltyOffer? @relation(fields: [offerId], references: [id], onDelete: SetNull)
3726
+
3727
+ @@unique([venueId, redemptionCode])
3555
3728
  @@index([venueId])
3556
3729
  @@index([userId])
3730
+ @@index([offerId])
3557
3731
  @@index([venueId, redeemedAt])
3732
+ @@index([expiresAt])
3558
3733
  }
3559
3734
 
3560
3735
  model UserPromoCodeRedemption {
@@ -3632,9 +3807,25 @@ model Organization {
3632
3807
  awayTeamGames Game[] @relation("AwayTeamGames")
3633
3808
  products OrgProduct[]
3634
3809
 
3810
+ /// Verified-nonprofit fields. Verification is a Bash-side admin action driven by
3811
+ /// the host's uploaded determination letter (nonprofitDeterminationDocId). These
3812
+ /// are the ONLY signals fee-math is allowed to read — `BashEvent.nonProfit` is
3813
+ /// user-entered and MUST NOT drive money. Country-agnostic shape so the first
3814
+ /// non-US charity doesn't require a re-model.
3815
+ nonprofitCountry String? // ISO-3166-1 alpha-2 (US, CA, GB, ...)
3816
+ nonprofitRegistrationNumber String? // EIN in US / charity number elsewhere; not unique because countries collide
3817
+ nonprofitDeterminationDocId String? // Media FK — uploaded 501(c)(3) determination letter or equivalent
3818
+ nonprofitDeterminationDoc Media? @relation("OrganizationNonprofitDeterminationDoc", fields: [nonprofitDeterminationDocId], references: [id], onDelete: SetNull)
3819
+ nonprofitVerifiedAt DateTime?
3820
+ nonprofitVerifiedByUserId String?
3821
+ nonprofitVerifiedByUser User? @relation("OrganizationNonprofitVerifier", fields: [nonprofitVerifiedByUserId], references: [id], onDelete: SetNull)
3822
+ /// Recorded for analytics — informational only, NOT a gate for verification or fee waivers.
3823
+ stripeNonprofitPricingStatus StripeNonprofitPricingStatus @default(NotApplied)
3824
+
3635
3825
  @@index([ownerId])
3636
3826
  @@index([slug])
3637
3827
  @@index([parentOrganizationId])
3828
+ @@index([nonprofitVerifiedAt])
3638
3829
  }
3639
3830
 
3640
3831
  /// Sports-specific metadata for league or team organizations (1:1 with Organization).
@@ -3946,23 +4137,23 @@ model ServiceRange {
3946
4137
  }
3947
4138
 
3948
4139
  model ServiceAddon {
3949
- id String @id @default(cuid())
3950
- name String
3951
- description String
3952
- priceCents Int
3953
- quantity Int
4140
+ id String @id @default(cuid())
4141
+ name String
4142
+ description String
4143
+ priceCents Int
4144
+ quantity Int
3954
4145
  /// Booking-time add-ons vs merchandise sold at events (same CRUD; UI filters by kind)
3955
- catalogKind ServiceAddonCatalogKind @default(BookingAddOn)
3956
- status ServiceAddonStatus @default(Enabled)
3957
- imageUrl String? // Add-on image URL
3958
- imageAlt String? // Alt text for accessibility
3959
- servicePackageId String?
3960
- serviceRatesAssociationId String?
3961
- servicePackage ServicePackage? @relation(fields: [servicePackageId], references: [id], onDelete: Cascade)
3962
- serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
3963
- ServiceBookingAddOn ServiceBookingAddOn[]
3964
- convertedFromInclude ServiceInclude[] @relation("IncludeConvertedToAddon")
3965
- convertedFromRequest ServiceAddonRequest[] @relation("RequestConvertedToAddon")
4146
+ catalogKind ServiceAddonCatalogKind @default(BookingAddOn)
4147
+ status ServiceAddonStatus @default(Enabled)
4148
+ imageUrl String? // Add-on image URL
4149
+ imageAlt String? // Alt text for accessibility
4150
+ servicePackageId String?
4151
+ serviceRatesAssociationId String?
4152
+ servicePackage ServicePackage? @relation(fields: [servicePackageId], references: [id], onDelete: Cascade)
4153
+ serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
4154
+ ServiceBookingAddOn ServiceBookingAddOn[]
4155
+ convertedFromInclude ServiceInclude[] @relation("IncludeConvertedToAddon")
4156
+ convertedFromRequest ServiceAddonRequest[] @relation("RequestConvertedToAddon")
3966
4157
  serviceMerchSquareFulfillments ServiceMerchSquareFulfillment[]
3967
4158
 
3968
4159
  @@index([imageUrl])
@@ -4206,48 +4397,116 @@ model ServiceBookingCheckout {
4206
4397
  }
4207
4398
 
4208
4399
  model ServiceBooking {
4209
- id String @id @default(cuid())
4210
- creatorId String
4211
- forUserId String
4212
- daysTotalATBCents Int
4213
- serviceId String
4214
- rateOption ServiceBookingRateOption @default(TimeBased)
4215
- flatRateCents Int?
4216
- status ServiceBookingStatus @default(Pending)
4217
- bookingType ServiceBookingType @default(Request)
4218
- timezone String
4219
- requestedOn DateTime?
4220
- requestDecisionOn DateTime?
4221
- bookedOn DateTime?
4222
- canceledOn DateTime?
4223
- isFreeGuest Boolean @default(false)
4224
- allowPromiseToPay Boolean @default(false)
4225
- totalATBCents Int
4226
- subtotalATBCents Int @default(0)
4227
- bashEventId String?
4228
- isVendorBid Boolean @default(false)
4229
- vendorBidAmountCents Int?
4230
- vendorEventDetails String?
4231
- bashPointsApplied Int? // BashPoints credits applied to this booking
4232
- bashPointsTransactionId String? // Link to BashCreditTransaction
4400
+ id String @id @default(cuid())
4401
+ creatorId String
4402
+ forUserId String
4403
+ daysTotalATBCents Int
4404
+ serviceId String
4405
+ rateOption ServiceBookingRateOption @default(TimeBased)
4406
+ flatRateCents Int?
4407
+ status ServiceBookingStatus @default(Pending)
4408
+ bookingType ServiceBookingType @default(Request)
4409
+ timezone String
4410
+ requestedOn DateTime?
4411
+ requestDecisionOn DateTime?
4412
+ bookedOn DateTime?
4413
+ canceledOn DateTime?
4414
+ isFreeGuest Boolean @default(false)
4415
+ allowPromiseToPay Boolean @default(false)
4416
+ totalATBCents Int
4417
+ subtotalATBCents Int @default(0)
4418
+ bashEventId String?
4419
+ isVendorBid Boolean @default(false)
4420
+ vendorBidAmountCents Int?
4421
+ vendorEventDetails String?
4422
+ bashPointsApplied Int? // BashPoints credits applied to this booking
4423
+ bashPointsTransactionId String? // Link to BashCreditTransaction
4233
4424
  // Settlement fields for percentage-based bookings (populated at event close)
4234
- settlementBasis ServiceBookingSettlementBasis?
4235
- settlementPercentage Decimal?
4236
- settlementAmountCents Int?
4237
- settledAt DateTime?
4238
- notification Notification[]
4239
- bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4240
- creator User @relation("BookingCreator", fields: [creatorId], references: [id])
4241
- forUser User @relation("BookingForUser", fields: [forUserId], references: [id])
4242
- service Service @relation(fields: [serviceId], references: [id])
4243
- addOns ServiceBookingAddOn[]
4244
- checkout ServiceBookingCheckout?
4245
- bookedDays ServiceBookingDay[]
4246
- additionalFees ServiceBookingFee[]
4247
- messages ServiceBookingMessage[]
4248
- packages ServiceBookingPackage[]
4249
- commissions BookingCommission[] @relation("BookingCommissions")
4250
- sentReminders SentReminder[]
4425
+ settlementBasis ServiceBookingSettlementBasis?
4426
+ settlementPercentage Decimal?
4427
+ settlementAmountCents Int?
4428
+ settledAt DateTime?
4429
+ // Event Promoter / `AttendeeCount` settlement fields (see eventPromoterUtils.ts).
4430
+ // expectedAttendeesAtBooking is snapshotted from `bashEvent.expectedAttendees`
4431
+ // at booking time so the post-event true-up has a stable baseline even if
4432
+ // the host later edits the bash. `maxAttendeesAttributable` is the host-set
4433
+ // per-booking ceiling on billable check-ins (multi-promoter risk control).
4434
+ expectedAttendeesAtBooking Int?
4435
+ maxAttendeesAttributable Int?
4436
+ checkedInAttendeesAtSettle Int?
4437
+ settlementDeltaCents Int?
4438
+ deltaChargeStripePaymentIntentId String?
4439
+ deltaRefundStripeRefundId String?
4440
+ // Phase 0 adoption guardrails (see bash-common/src/utils/service/billingCapUtils.ts).
4441
+ // `maxBillableCents` is the host-set per-booking dollar ceiling for any
4442
+ // variable-pricing booking — defaults to 1.5x expectedAttendees * baseRateCents
4443
+ // at booking time. Snapshotted so policy changes don't move history.
4444
+ // `maxBillableBashPoints` is the parallel cap for PER_BASHPOINTS_ATTENDEE bookings.
4445
+ // `payoutTimingNote` snapshots the provider-facing copy ("Final settlement ~3
4446
+ // business days after the bash") so the booking detail keeps showing the
4447
+ // right expectation even after platform defaults change.
4448
+ maxBillableCents Int?
4449
+ maxBillableBashPoints Int?
4450
+ payoutTimingNote String?
4451
+ // Phase 3 — PER_PAID_ATTENDEE / PER_BASHPOINTS_ATTENDEE settlement snapshots.
4452
+ /// Checked-in attendees with `isFreeGuest = false` and ticket tier
4453
+ /// pricingType = USD. Populated at settlement time. PER_PAID_ATTENDEE.
4454
+ paidAttendeesAtSettle Int?
4455
+ /// Checked-in attendees with `isFreeGuest = false` and ticket tier
4456
+ /// pricingType = BASHPOINTS. Populated at settlement time.
4457
+ /// PER_BASHPOINTS_ATTENDEE.
4458
+ paidInBashPointsAttendeesAtSettle Int?
4459
+ /// When true on a `PER_PAID_ATTENDEE` booking, BP-paid tickets ALSO count
4460
+ /// toward the head count. Defaults to false (providers must explicitly opt
4461
+ /// in to mixed-currency settlement).
4462
+ countsBashPointsTickets Boolean @default(false)
4463
+ /// Snapshot of the per-attendee BashPoints rate. Mirrors `baseRateCents`
4464
+ /// snapshot semantics for PER_BASHPOINTS_ATTENDEE.
4465
+ baseRateBashPointsSnapshot Int?
4466
+ // Phase 2 — Venue F&B + revenue-share settlement snapshots. All fields are
4467
+ // snapshots taken at booking confirmation time so policy changes don't move
4468
+ // history.
4469
+ /// Effective F&B minimum after applying day-of-week schedule + overrides.
4470
+ fbMinimumCents Int?
4471
+ /// Final F&B spend (cents) from the venue-uploaded invoice.
4472
+ fbActualSpendCents Int?
4473
+ /// FK to the uploaded `Media` row (PDF/image of the F&B invoice).
4474
+ fbInvoiceMediaId String?
4475
+ fbInvoiceUploadedAt DateTime?
4476
+ /// Resolution applied at settlement (ChargeDelta | CreditFutureBooking | Forgiven).
4477
+ fbShortfallResolution FBShortfallResolution?
4478
+ /// Snapshot of `Venue.fbServiceChargeCountsTowardMinimum`.
4479
+ fbServiceChargeIncludedSnapshot Boolean?
4480
+ /// Snapshot of `Venue.fbMinimumIncludesTax`.
4481
+ fbMinimumIncludesTaxSnapshot Boolean?
4482
+ /// Snapshot of `Venue.revenueShareHostPercentage` (0..100).
4483
+ revenueShareHostPctSnapshot Int?
4484
+ /// Snapshot of `Venue.revenueShareBasis`.
4485
+ revenueShareBasisSnapshot String?
4486
+ /// Computed venue rev-share owed (cents) at settlement.
4487
+ revenueShareCalculatedCents Int?
4488
+ // Settlement lifecycle state (drives dunning, retries, dispute window).
4489
+ settlementStatus ServiceBookingSettlementStatus @default(Pending)
4490
+ settlementAttempts Int @default(0)
4491
+ lastSettlementAttemptAt DateTime?
4492
+ // When the host clicks "Dispute" during the window, we pause auto-settle.
4493
+ settlementDisputedAt DateTime?
4494
+ // When the delta refund actually lands at the issuing bank.
4495
+ refundedOn DateTime?
4496
+ notification Notification[]
4497
+ bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4498
+ creator User @relation("BookingCreator", fields: [creatorId], references: [id])
4499
+ forUser User @relation("BookingForUser", fields: [forUserId], references: [id])
4500
+ service Service @relation(fields: [serviceId], references: [id])
4501
+ addOns ServiceBookingAddOn[]
4502
+ checkout ServiceBookingCheckout?
4503
+ bookedDays ServiceBookingDay[]
4504
+ additionalFees ServiceBookingFee[]
4505
+ messages ServiceBookingMessage[]
4506
+ packages ServiceBookingPackage[]
4507
+ commissions BookingCommission[] @relation("BookingCommissions")
4508
+ sentReminders SentReminder[]
4509
+ offers ServiceBookingOffer[]
4251
4510
 
4252
4511
  @@index([status])
4253
4512
  @@index([creatorId])
@@ -4288,6 +4547,10 @@ model VendorBookingRequest {
4288
4547
  permitRequirements String
4289
4548
  weatherContingency String
4290
4549
  cancellationPolicy String
4550
+ /// Phase 4 — pricing models this host will accept bids in. Empty array =
4551
+ /// no host-side restriction (provider may bid in any of their supported
4552
+ /// models). Validated in `bash-common/src/utils/service/offerAllowListUtils.ts`.
4553
+ pricingModelAllowList String[] @default([])
4291
4554
  status VendorBookingStatus @default(PENDING)
4292
4555
  paymentAmount Float?
4293
4556
  paymentStatus String?
@@ -4300,6 +4563,7 @@ model VendorBookingRequest {
4300
4563
  bashEvent BashEvent? @relation("VendorBookingEvent", fields: [bashEventId], references: [id])
4301
4564
  hostUser User @relation("VendorBookingHost", fields: [hostUserId], references: [id], onDelete: Cascade)
4302
4565
  vendorService Service @relation("VendorBookingService", fields: [vendorServiceId], references: [id], onDelete: Cascade)
4566
+ offers ServiceBookingOffer[]
4303
4567
 
4304
4568
  @@index([hostUserId])
4305
4569
  @@index([vendorServiceId])
@@ -4391,6 +4655,8 @@ model ExhibitorBookingRequest {
4391
4655
  leadGenerationExpected Boolean @default(false)
4392
4656
  materialDistribution String
4393
4657
  demonstrationNeeds String
4658
+ /// Phase 4 — see VendorBookingRequest.pricingModelAllowList.
4659
+ pricingModelAllowList String[] @default([])
4394
4660
  status ExhibitorBookingStatus @default(PENDING)
4395
4661
  paymentAmount Float?
4396
4662
  paymentStatus String?
@@ -4440,6 +4706,8 @@ model SponsorBookingRequest {
4440
4706
  cancellationPolicy String
4441
4707
  mentionRequirements String
4442
4708
  socialMediaRequirements String
4709
+ /// Phase 4 — see VendorBookingRequest.pricingModelAllowList.
4710
+ pricingModelAllowList String[] @default([])
4443
4711
  status SponsorBookingStatus @default(PENDING)
4444
4712
  paymentAmount Float?
4445
4713
  paymentStatus String?
@@ -4485,23 +4753,23 @@ model ServiceLink {
4485
4753
  }
4486
4754
 
4487
4755
  model UserReport {
4488
- id String @id @default(cuid())
4756
+ id String @id @default(cuid())
4489
4757
  reporterId String
4490
4758
  reportedId String
4491
4759
  bashEventId String?
4492
4760
  reason String
4493
4761
  details String
4494
- createdAt DateTime @default(now())
4495
- status ReportStatus @default(Pending)
4762
+ createdAt DateTime @default(now())
4763
+ status ReportStatus @default(Pending)
4496
4764
  reviewerId String?
4497
4765
  reviewedAt DateTime?
4498
4766
  reviewNotes String?
4499
4767
  demerits Demerit[]
4500
4768
  evidence UserReportEvidence[]
4501
- bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4502
- reported User @relation("ReportsReceived", fields: [reportedId], references: [id], onDelete: Cascade)
4503
- reporter User @relation("ReportsMade", fields: [reporterId], references: [id], onDelete: Cascade)
4504
- reviewer User? @relation("ReportsReviewed", fields: [reviewerId], references: [id])
4769
+ bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4770
+ reported User @relation("ReportsReceived", fields: [reportedId], references: [id], onDelete: Cascade)
4771
+ reporter User @relation("ReportsMade", fields: [reporterId], references: [id], onDelete: Cascade)
4772
+ reviewer User? @relation("ReportsReviewed", fields: [reviewerId], references: [id])
4505
4773
 
4506
4774
  @@index([reporterId])
4507
4775
  @@index([reportedId])
@@ -4847,6 +5115,7 @@ enum NotificationType {
4847
5115
  ServiceBookingDeclined
4848
5116
  ServiceBookingCancelled
4849
5117
  ServiceBookingConfirmed
5118
+ ServiceOfferReceived
4850
5119
  Message
4851
5120
  ConnectionRequest
4852
5121
  ConnectionAccepted
@@ -5217,14 +5486,6 @@ enum SchoolNameSource {
5217
5486
  UserConfirmed
5218
5487
  }
5219
5488
 
5220
- /// Admin-gated custom-scope pricing flag for service providers needing variable/quote-based pricing
5221
- enum CustomScopeStatus {
5222
- None
5223
- Pending
5224
- Approved
5225
- Rejected
5226
- }
5227
-
5228
5489
  /// AI bash-approval reviewer verdict (see `bashApprovalAiService`).
5229
5490
  /// `Approve` and `Reject` are recommendations; whether the system acts on them
5230
5491
  /// vs. queues for a human depends on confidence + AI_BASH_APPROVAL_MODE.
@@ -5292,6 +5553,21 @@ enum VolunteerServiceStatus {
5292
5553
  Created
5293
5554
  }
5294
5555
 
5556
+ /// How a host thanks a volunteer for their time on a bash. Intentionally
5557
+ /// narrower than `PricingModel` — volunteers are not employees or contractors,
5558
+ /// so USD wages / per-attendee / revenue share are out of scope by design.
5559
+ enum VolunteerCompensationType {
5560
+ /// Pure volunteer — appreciation only, no stipend or perks recorded.
5561
+ None
5562
+ /// Closed-loop BashPoints stipend per shift or per hour. BP redeems on
5563
+ /// Bash; never cashed out, never a wage.
5564
+ BashPointsStipend
5565
+ /// Comped ticket + on-site perks (food, drink wristband, swag). No BP.
5566
+ PerksOnly
5567
+ /// Both a BashPoints stipend AND on-site perks.
5568
+ BashPointsAndPerks
5569
+ }
5570
+
5295
5571
  enum Gender {
5296
5572
  Male
5297
5573
  Female
@@ -6704,6 +6980,105 @@ enum ServiceBookingRateOption {
6704
6980
  enum ServiceBookingSettlementBasis {
6705
6981
  TicketRevenue // Venue takes % of ticket sales (Bash auto-calculates from held revenue)
6706
6982
  ProductSales // Host takes % of vendor product sales through Bash checkout
6983
+ AttendeeCount // Event Promoter: host pays per checked-in attendee with deposit + delta true-up
6984
+ FBMinimumShortfall // Venue F&B minimum (Phase 2) — host owes the gap between actualFbSpend and the minimum
6985
+ RevenueShare // Venue revenue-share + optional minimum floor (Phase 2)
6986
+ }
6987
+
6988
+ /// How an F&B minimum shortfall on a venue booking was resolved at settlement.
6989
+ /// Default venue policy lives at `Venue.defaultFBShortfallResolution`; the
6990
+ /// venue can override on the invoice-upload step.
6991
+ enum FBShortfallResolution {
6992
+ /// Host's card is charged the shortfall delta via the existing
6993
+ /// `ServiceBookingSettlementStatus` flow.
6994
+ ChargeDelta
6995
+ /// Venue chooses to bank the shortfall as a `VenueFBCarryoverCredit` against
6996
+ /// the host's next bash at the same venue.
6997
+ CreditFutureBooking
6998
+ /// Venue waives the shortfall — no charge, no credit.
6999
+ Forgiven
7000
+ }
7001
+
7002
+ /// Lifecycle state for `AttendeeCount` settlement (Event Promoter bookings).
7003
+ /// Drives Stripe webhook handlers, dunning, dispute window, retry logic.
7004
+ enum ServiceBookingSettlementStatus {
7005
+ Pending // Bash not yet ended, or within dispute window
7006
+ Settled // Charged or refunded successfully; `settledAt` populated
7007
+ SettlementPaymentFailed // Off-session delta charge failed after Stripe Smart Retries
7008
+ SettlementHeld // Awaiting host action (dispute, no check-in data, promoter Connect issue)
7009
+ SettlementDisputed // Host clicked "Dispute" during the dispute window
7010
+ }
7011
+
7012
+ /// Direction of a booking offer — derived from service type, not chosen by the user.
7013
+ /// Vendors/Exhibitors/Sponsors use ProviderToHost; all other service types use HostToProvider.
7014
+ enum ServiceBookingOfferDirection {
7015
+ HostToProvider
7016
+ ProviderToHost
7017
+ }
7018
+
7019
+ enum ServiceBookingOfferStatus {
7020
+ Pending
7021
+ Accepted
7022
+ Declined
7023
+ Countered // superseded by a child counter offer
7024
+ Expired
7025
+ }
7026
+
7027
+ /// Structured negotiation offer attached to a service + bash event.
7028
+ /// Max 3 rounds per thread (1 initial + 1 counter per side).
7029
+ model ServiceBookingOffer {
7030
+ id String @id @default(cuid())
7031
+ createdAt DateTime @default(now())
7032
+
7033
+ serviceId String
7034
+ bashEventId String
7035
+ serviceBookingId String? // set once attached to a Pending booking or after accept
7036
+ vendorBookingRequestId String? // for Vendor/Exhibitor/Sponsor flow
7037
+
7038
+ parentOfferId String? // the offer this is countering
7039
+ roundNumber Int // 1, 2, or 3 — server-enforced cap of 3
7040
+
7041
+ senderId String
7042
+ recipientId String
7043
+ direction ServiceBookingOfferDirection
7044
+ amountCents Int
7045
+ note String?
7046
+
7047
+ // Phase 5 — offers carry the pricing model so negotiation can cross models.
7048
+ // `amountCents` is kept as the denormalized **expected total** for legacy
7049
+ // sorting/AI; the fields below capture the full per-unit pricing block so
7050
+ // the recipient can counter on any axis.
7051
+ pricingModel PricingModel?
7052
+ baseRateCents Int?
7053
+ baseRateBashPoints Int?
7054
+ rateUnit String?
7055
+ minimumChargeCents Int?
7056
+ minimumQuantity Int?
7057
+ maxBillableCents Int?
7058
+
7059
+ aiSuggestedLowCents Int?
7060
+ aiSuggestedMidCents Int?
7061
+ aiSuggestedHighCents Int?
7062
+ aiReasoning String?
7063
+ acceptedAiSuggestion Boolean @default(false)
7064
+
7065
+ status ServiceBookingOfferStatus @default(Pending)
7066
+ decidedAt DateTime?
7067
+ expiresAt DateTime?
7068
+
7069
+ service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
7070
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
7071
+ serviceBooking ServiceBooking? @relation(fields: [serviceBookingId], references: [id], onDelete: SetNull)
7072
+ vendorBookingRequest VendorBookingRequest? @relation(fields: [vendorBookingRequestId], references: [id], onDelete: SetNull)
7073
+ parentOffer ServiceBookingOffer? @relation("OfferCounters", fields: [parentOfferId], references: [id], onDelete: SetNull)
7074
+ counters ServiceBookingOffer[] @relation("OfferCounters")
7075
+ sender User @relation("OfferSender", fields: [senderId], references: [id])
7076
+ recipient User @relation("OfferRecipient", fields: [recipientId], references: [id])
7077
+
7078
+ @@index([serviceId, bashEventId])
7079
+ @@index([serviceBookingId])
7080
+ @@index([recipientId, status])
7081
+ @@index([senderId])
6707
7082
  }
6708
7083
 
6709
7084
  enum VendorBookingStatus {
@@ -6805,7 +7180,9 @@ enum PaymentProvider {
6805
7180
 
6806
7181
  enum PricingModel {
6807
7182
  FLAT_FEE // Fixed amount: "$500 for vendor booth"
6808
- PER_ATTENDEE // Per person: "$50 per expected attendee"
7183
+ PER_ATTENDEE // Per person: "$50 per expected attendee" — counts every checked-in attendee
7184
+ PER_PAID_ATTENDEE // Like PER_ATTENDEE but only revenue-generating tickets count (no comps)
7185
+ PER_BASHPOINTS_ATTENDEE // Per attendee who paid in BashPoints (host wallet or BP pool)
6809
7186
  HOURLY // Per hour: "$200/hour, 4-hour minimum"
6810
7187
  PER_DAY // Per day: "$1,000/day"
6811
7188
  TIERED // Multiple options: "Bronze $1K, Silver $2.5K, Gold $5K"
@@ -6814,6 +7191,20 @@ enum PricingModel {
6814
7191
  PRODUCT_SALES_PERCENTAGE // Host takes a % of vendor/exhibitor product sales through Bash checkout
6815
7192
  }
6816
7193
 
7194
+ /**
7195
+ * Where the BashPoints for a PER_BASHPOINTS_ATTENDEE settlement come from.
7196
+ * - `HostWallet` (default): host's BP balance pays the provider directly.
7197
+ * - `BashBpPool`: BP collected from BashPoints-priced ticket sales for this
7198
+ * bash form a per-bash pool; the provider is paid from that pool first.
7199
+ * Refund of a BP ticket after settlement debits the host's wallet so Bash
7200
+ * never goes negative.
7201
+ * See `eventPromoterUtils` / Phase 3 of the unified-pricing roadmap.
7202
+ */
7203
+ enum BashPointsPayoutSource {
7204
+ HostWallet
7205
+ BashBpPool
7206
+ }
7207
+
6817
7208
  enum PricingType {
6818
7209
  USD // Ticket priced in USD (paid with credit card, earns BashPoints cashback)
6819
7210
  BASHPOINTS // Ticket priced in BashPoints (peer-to-peer loyalty points transfer)
@@ -6924,12 +7315,7 @@ enum CreditSourceType {
6924
7315
  PostBeforeEvent // First BashFeed post linked to event before it ends
6925
7316
  PostAfterEvent // First BashFeed post linked to event after it ends
6926
7317
  ReferralCodeUsed // Flat bonus for referrer when code drives a ticket/signup
6927
- }
6928
-
6929
- enum PendingGiftStatus {
6930
- Pending
6931
- Claimed
6932
- Returned
7318
+ VenueLoyaltyRedemption // BashPoints moved through a VenueLoyaltyRedemption claim/redeem/refund
6933
7319
  }
6934
7320
 
6935
7321
  enum ReferralTier {
@@ -8452,3 +8838,12 @@ enum OrgProductStatus {
8452
8838
  Active
8453
8839
  Archived
8454
8840
  }
8841
+
8842
+ /// Lifecycle of a host's external Stripe nonprofit-pricing application. Recorded
8843
+ /// for analytics; does NOT gate Bash-side verification or platform-fee waivers.
8844
+ enum StripeNonprofitPricingStatus {
8845
+ NotApplied
8846
+ Pending
8847
+ Approved
8848
+ Declined
8849
+ }