@bash-app/bash-common 30.235.0 → 30.237.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +45 -14
  4. package/dist/definitions.d.ts.map +1 -1
  5. package/dist/definitions.js +38 -17
  6. package/dist/definitions.js.map +1 -1
  7. package/dist/extendedSchemas.d.ts +8 -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 +638 -214
  145. package/src/__tests__/statusEnums.test.ts +119 -11
  146. package/src/definitions.ts +65 -22
  147. package/src/extendedSchemas.ts +8 -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,9 +1797,11 @@ model Ticket {
1810
1797
  qrToken String?
1811
1798
 
1812
1799
  // BashPoints Purchase Tracking
1813
- purchaseType String? // "USD", "BashPoints", "Free", "Comp", "BashPass"
1814
- pointsPaid Int? // BashPoints amount paid (if purchaseType="BashPoints")
1815
- stripePurchaseId String? // Stripe payment ID (if purchaseType="USD")
1800
+ purchaseType String? // "USD", "BashPoints", "Free", "Comp", "BashPass", "PayAtDoor", "Cash"
1801
+ /// Promo entered at Pay-at-Door reservation; discount applied when they pay at the door (analytics: unpaid rows with code set).
1802
+ payAtDoorPromoCode String?
1803
+ pointsPaid Int? // BashPoints amount paid (if purchaseType="BashPoints")
1804
+ stripePurchaseId String? // Stripe payment ID (if purchaseType="USD")
1816
1805
 
1817
1806
  /// When set, this ticket was created from a host `TicketGiftGrant` (comp block for distribution).
1818
1807
  giftGrantId String?
@@ -2101,18 +2090,19 @@ model Link {
2101
2090
  }
2102
2091
 
2103
2092
  model Media {
2104
- id String @id @default(cuid())
2105
- url String @unique
2106
- type MediaType
2107
- mimetype String?
2108
- volunteerServiceId String?
2109
- serviceRatesAssociationId String?
2110
- serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
2111
- volunteerService VolunteerService? @relation(fields: [volunteerServiceId], references: [id])
2112
- stripeAccount StripeAccount[]
2113
- bashEventsReferencingMe BashEvent[] @relation("BashEventToMedia")
2114
- serviceReferencingMe Service[] @relation("MediaToService")
2115
- 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")
2116
2106
  }
2117
2107
 
2118
2108
  model Prize {
@@ -2243,16 +2233,16 @@ model SocialMediaProfile {
2243
2233
  }
2244
2234
 
2245
2235
  model User {
2246
- id String @id @default(cuid())
2247
- username String? @unique
2248
- email String @unique
2249
- createdOn DateTime @default(now())
2250
- stripeCustomerId String? @unique
2251
- 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
2252
2242
  /// Preferred processor for dual-rail onboarding (optional; legacy Stripe fields remain source of truth until fully migrated).
2253
- paymentProvider PaymentProvider @default(STRIPE)
2254
- isSuperUser Boolean @default(false)
2255
- isSuspended Boolean @default(false)
2243
+ paymentProvider PaymentProvider @default(STRIPE)
2244
+ isSuperUser Boolean @default(false)
2245
+ isSuspended Boolean @default(false)
2256
2246
  intent UserIntent?
2257
2247
  signupSource String? // e.g. 'jamwith', 'mixlog', 'organic' for attribution
2258
2248
  googleCalendarAccess String?
@@ -2452,8 +2442,7 @@ model User {
2452
2442
  bashEventMessagesRead BashEventMessageRead[] @relation("BashMessageReader")
2453
2443
  transferRequestsFrom BashEventTransferRequest[] @relation("TransferRequestsFrom")
2454
2444
  transferRequestsTo BashEventTransferRequest[] @relation("TransferRequestsTo")
2455
- sentPendingGifts PendingBashPointsGift[] @relation("SentPendingGifts")
2456
- claimedPendingGifts PendingBashPointsGift[] @relation("ClaimedPendingGifts")
2445
+ venueFBCarryoverCredits VenueFBCarryoverCredit[] @relation("VenueFBCarryoverHost")
2457
2446
  biometricCredentials BiometricCredential[]
2458
2447
  blocksReceived BlockedUser[] @relation("UserBlocksReceived")
2459
2448
  blocksCreated BlockedUser[] @relation("UserBlocksMade")
@@ -2507,6 +2496,8 @@ model User {
2507
2496
  serviceBookingForUser ServiceBooking[] @relation("BookingForUser")
2508
2497
  serviceBookingCheckout ServiceBookingCheckout[]
2509
2498
  serviceBookingMessages ServiceBookingMessage[] @relation("ServiceMessageSender")
2499
+ sentBookingOffers ServiceBookingOffer[] @relation("OfferSender")
2500
+ receivedBookingOffers ServiceBookingOffer[] @relation("OfferRecipient")
2510
2501
  sessions Session[]
2511
2502
  socialMediaProfiles SocialMediaProfile[]
2512
2503
  sponsorBookingRequestsAsHost SponsorBookingRequest[] @relation("SponsorBookingHost")
@@ -2606,17 +2597,19 @@ model User {
2606
2597
  ideaInterests IdeaInterest[]
2607
2598
 
2608
2599
  // Organization Relations
2609
- ownedOrganizations Organization[] @relation("OrganizationOwner")
2610
- organizationMemberships OrganizationMember[] @relation("OrganizationMemberUser")
2611
- organizationEventRSVPs EventRSVP[] @relation("OrganizationEventRSVP")
2612
- submittedExpenses Expense[] @relation("ExpenseSubmitter")
2613
- approvedExpenses Expense[] @relation("ExpenseApprover")
2614
- approvedBudgets Budget[] @relation("BudgetApprover")
2615
- submittedBudgets Budget[] @relation("BudgetSubmitter")
2616
- ownedBudgets Budget[] @relation("UserBudgets")
2617
- departmentsHeaded Department[] @relation("DepartmentHead")
2618
- favoriteOrganizations Organization[] @relation("FavoriteOrganizations")
2619
- 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")
2620
2613
 
2621
2614
  // Service Includes & Add-On Requests
2622
2615
  suggestedIncludes ServiceInclude[] @relation("SuggestedIncludes")
@@ -3065,6 +3058,7 @@ model Service {
3065
3058
  pocBusinessEmail String?
3066
3059
  additionalInfo String?
3067
3060
  coverPhoto String?
3061
+ backgroundImage String? // Custom or curated background image URL for the service/org profile page
3068
3062
  mission String?
3069
3063
  communityInvolvement String?
3070
3064
  emergencyContact String?
@@ -3103,9 +3097,6 @@ model Service {
3103
3097
  verifiedAt DateTime? // When verification was approved
3104
3098
  licenseNumber String? // License/registration number
3105
3099
  certifications String[] @default([]) // Array of certification names
3106
- /// Custom scope pricing — admin-gated flag for providers who need variable/quote-based pricing
3107
- customScopeStatus CustomScopeStatus @default(None)
3108
- customScopeRequestNote String? // Provider's explanation of why they need custom scope
3109
3100
  bashFeedPosts BashFeedPost[]
3110
3101
  bashEventArtists BashEventArtist[]
3111
3102
  bashCreativeSubmissions BashCreativeSubmission[]
@@ -3145,6 +3136,7 @@ model Service {
3145
3136
  includes ServiceInclude[]
3146
3137
  addonRequests ServiceAddonRequest[]
3147
3138
  serviceBudgets Budget[] @relation("ServiceBudgets")
3139
+ bookingOffers ServiceBookingOffer[]
3148
3140
 
3149
3141
  @@index([serviceListingStripeSubscriptionId])
3150
3142
  @@index([paymentAccountId])
@@ -3171,24 +3163,24 @@ model StripeAccount {
3171
3163
 
3172
3164
  /// Connects a user to Stripe and/or Square rails for provider payouts (dual-processor layer).
3173
3165
  model PaymentProviderAccount {
3174
- id String @id @default(cuid())
3175
- userId String
3176
- provider PaymentProvider @default(STRIPE)
3177
- stripeAccountId String? @unique
3178
- stripeCustomerId String? @unique
3179
- squareMerchantId String? @unique
3180
- squareLocationId String?
3181
- squareAccessToken String? @db.Text
3182
- squareRefreshToken String? @db.Text
3183
- squareTokenExpiresAt DateTime?
3184
- accountVerified Boolean @default(false)
3185
- payoutsEnabled Boolean @default(false)
3186
- accountStatus String?
3187
- createdAt DateTime @default(now())
3188
- updatedAt DateTime @updatedAt
3189
- lastVerifiedAt DateTime?
3190
- user User @relation(fields: [userId], references: [id], onDelete: Restrict, onUpdate: Cascade)
3191
- 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[]
3192
3184
 
3193
3185
  @@unique([userId, provider])
3194
3186
  @@index([userId])
@@ -3209,32 +3201,47 @@ model StripeDispute {
3209
3201
  }
3210
3202
 
3211
3203
  model VolunteerService {
3212
- id String @id @default(cuid())
3204
+ id String @id @default(cuid())
3213
3205
  userId String
3214
3206
  serviceRangeId String?
3215
3207
  fullName String?
3216
3208
  address String?
3217
3209
  email String?
3218
3210
  phone String?
3219
- agreedToAgreement Boolean @default(false)
3220
- description String @default("")
3221
- status VolunteerServiceStatus @default(Draft)
3211
+ agreedToAgreement Boolean @default(false)
3212
+ description String @default("")
3213
+ status VolunteerServiceStatus @default(Draft)
3222
3214
  skills String?
3223
3215
  experienceLevel String?
3224
- preferredEventTypes String[] @default([])
3225
- availability String[] @default([])
3216
+ preferredEventTypes String[] @default([])
3217
+ availability String[] @default([])
3226
3218
  physicalCapabilities String?
3227
3219
  equipment String?
3228
3220
  transportation String?
3229
3221
  emergencyContactName String?
3230
3222
  emergencyContactPhone String?
3231
- serviceId String @unique
3232
- 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")
3233
3240
  media Media[]
3234
3241
  serviceRatesAssociation ServiceRatesAssociation?
3235
- service Service @relation("ServiceToVolunteer", fields: [serviceId], references: [id])
3236
- serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3237
- 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])
3238
3245
 
3239
3246
  @@index([userId])
3240
3247
  }
@@ -3253,6 +3260,18 @@ model EventService {
3253
3260
  menuItems String?
3254
3261
  venueTypes String[]
3255
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?
3256
3275
  crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
3257
3276
  serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3258
3277
  service Service?
@@ -3290,9 +3309,19 @@ model EntertainmentService {
3290
3309
  notifyOnMatchingVenues Boolean @default(true)
3291
3310
  lastMatchNotificationSent DateTime?
3292
3311
 
3293
- crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
3294
- serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
3295
- 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?
3296
3325
  }
3297
3326
 
3298
3327
  model Vendor {
@@ -3323,6 +3352,7 @@ model Vendor {
3323
3352
  // Pricing Model Fields
3324
3353
  pricingModel PricingModel? @default(CUSTOM)
3325
3354
  baseRateCents Int? // Base rate in cents
3355
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3326
3356
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3327
3357
  minimumChargeCents Int? // Minimum booking amount in cents
3328
3358
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3443,6 +3473,7 @@ model Exhibitor {
3443
3473
  // Pricing Model Fields
3444
3474
  pricingModel PricingModel? @default(CUSTOM)
3445
3475
  baseRateCents Int? // Base rate in cents
3476
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3446
3477
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3447
3478
  minimumChargeCents Int? // Minimum booking amount in cents
3448
3479
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3470,6 +3501,7 @@ model Sponsor {
3470
3501
  // Pricing Model Fields
3471
3502
  pricingModel PricingModel? @default(CUSTOM)
3472
3503
  baseRateCents Int? // Base rate in cents
3504
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3473
3505
  rateUnit String? // "per_person", "per_hour", "per_day", "flat"
3474
3506
  minimumChargeCents Int? // Minimum booking amount in cents
3475
3507
  minimumQuantity Int? // Minimum attendees/hours/days
@@ -3517,42 +3549,187 @@ model Venue {
3517
3549
  notifyOnMatchingMusicians Boolean @default(true)
3518
3550
  lastMatchNotificationSent DateTime?
3519
3551
 
3520
- /// 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.
3521
3555
  loyaltyEnabled Boolean @default(false)
3522
3556
  loyaltyTemplateIds String[] @default([])
3523
3557
  loyaltyNotes String?
3524
3558
 
3525
3559
  bashEvents BashEvent[]
3526
3560
  service Service?
3561
+ venueLoyaltyOffers VenueLoyaltyOffer[]
3527
3562
  venueLoyaltyRedemptions VenueLoyaltyRedemption[]
3528
3563
 
3529
3564
  // Pricing model — what the venue charges the host
3530
3565
  pricingModel PricingModel? @default(CUSTOM)
3531
3566
  baseRateCents Int?
3567
+ baseRateBashPoints Int? // BashPoints unit rate (for PER_BASHPOINTS_ATTENDEE etc.)
3532
3568
  rateUnit String?
3533
3569
  minimumChargeCents Int?
3534
3570
  minimumQuantity Int?
3535
3571
  tierPricing Json?
3536
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])
3537
3655
  }
3538
3656
 
3539
- /// Guest-requested perk aligned with Venue.loyaltyTemplateIds; host marks redeemedAt when fulfilled.
3540
- model VenueLoyaltyRedemption {
3541
- id String @id @default(cuid())
3542
- venueId String
3543
- userId String
3544
- templateId String
3545
- claimedAt DateTime @default(now())
3546
- redeemedAt DateTime?
3547
- guestNotes String?
3548
- 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
3687
+
3688
+ venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3689
+ redemptions VenueLoyaltyRedemption[]
3549
3690
 
3550
- venue Venue @relation(fields: [venueId], references: [id], onDelete: Cascade)
3551
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
3691
+ @@index([venueId, enabled])
3692
+ }
3552
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])
3553
3728
  @@index([venueId])
3554
3729
  @@index([userId])
3730
+ @@index([offerId])
3555
3731
  @@index([venueId, redeemedAt])
3732
+ @@index([expiresAt])
3556
3733
  }
3557
3734
 
3558
3735
  model UserPromoCodeRedemption {
@@ -3608,6 +3785,7 @@ model Organization {
3608
3785
  stripeSubscriptionId String? @unique
3609
3786
  stripeCustomerId String?
3610
3787
  stripeConnectedAccountId String? // Org-level Stripe account for wallet display
3788
+ accentColor String? // Hex color for org page branding (e.g. "#6366f1")
3611
3789
  inheritBrandingFromParent Boolean @default(true)
3612
3790
  latitude Float?
3613
3791
  longitude Float?
@@ -3627,10 +3805,27 @@ model Organization {
3627
3805
  seasons Season[]
3628
3806
  homeTeamGames Game[] @relation("HomeTeamGames")
3629
3807
  awayTeamGames Game[] @relation("AwayTeamGames")
3808
+ products OrgProduct[]
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)
3630
3824
 
3631
3825
  @@index([ownerId])
3632
3826
  @@index([slug])
3633
3827
  @@index([parentOrganizationId])
3828
+ @@index([nonprofitVerifiedAt])
3634
3829
  }
3635
3830
 
3636
3831
  /// Sports-specific metadata for league or team organizations (1:1 with Organization).
@@ -3648,6 +3843,26 @@ model SportsProfile {
3648
3843
  updatedAt DateTime @updatedAt
3649
3844
  }
3650
3845
 
3846
+ /// Merchandise or digital products sold by an organization on their public profile.
3847
+ model OrgProduct {
3848
+ id String @id @default(cuid())
3849
+ organizationId String
3850
+ name String
3851
+ description String?
3852
+ priceCents Int
3853
+ imageUrl String?
3854
+ /// null = unlimited stock
3855
+ inventory Int?
3856
+ status OrgProductStatus @default(Active)
3857
+ /// shipping | pickup | digital
3858
+ fulfillment String @default("shipping")
3859
+ createdAt DateTime @default(now())
3860
+ updatedAt DateTime @updatedAt
3861
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
3862
+
3863
+ @@index([organizationId])
3864
+ }
3865
+
3651
3866
  /// A competition season owned by a league organization.
3652
3867
  model Season {
3653
3868
  id String @id @default(cuid())
@@ -3922,23 +4137,23 @@ model ServiceRange {
3922
4137
  }
3923
4138
 
3924
4139
  model ServiceAddon {
3925
- id String @id @default(cuid())
3926
- name String
3927
- description String
3928
- priceCents Int
3929
- quantity Int
4140
+ id String @id @default(cuid())
4141
+ name String
4142
+ description String
4143
+ priceCents Int
4144
+ quantity Int
3930
4145
  /// Booking-time add-ons vs merchandise sold at events (same CRUD; UI filters by kind)
3931
- catalogKind ServiceAddonCatalogKind @default(BookingAddOn)
3932
- status ServiceAddonStatus @default(Enabled)
3933
- imageUrl String? // Add-on image URL
3934
- imageAlt String? // Alt text for accessibility
3935
- servicePackageId String?
3936
- serviceRatesAssociationId String?
3937
- servicePackage ServicePackage? @relation(fields: [servicePackageId], references: [id], onDelete: Cascade)
3938
- serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
3939
- ServiceBookingAddOn ServiceBookingAddOn[]
3940
- convertedFromInclude ServiceInclude[] @relation("IncludeConvertedToAddon")
3941
- 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")
3942
4157
  serviceMerchSquareFulfillments ServiceMerchSquareFulfillment[]
3943
4158
 
3944
4159
  @@index([imageUrl])
@@ -4182,48 +4397,116 @@ model ServiceBookingCheckout {
4182
4397
  }
4183
4398
 
4184
4399
  model ServiceBooking {
4185
- id String @id @default(cuid())
4186
- creatorId String
4187
- forUserId String
4188
- daysTotalATBCents Int
4189
- serviceId String
4190
- rateOption ServiceBookingRateOption @default(TimeBased)
4191
- flatRateCents Int?
4192
- status ServiceBookingStatus @default(Pending)
4193
- bookingType ServiceBookingType @default(Request)
4194
- timezone String
4195
- requestedOn DateTime?
4196
- requestDecisionOn DateTime?
4197
- bookedOn DateTime?
4198
- canceledOn DateTime?
4199
- isFreeGuest Boolean @default(false)
4200
- allowPromiseToPay Boolean @default(false)
4201
- totalATBCents Int
4202
- subtotalATBCents Int @default(0)
4203
- bashEventId String?
4204
- isVendorBid Boolean @default(false)
4205
- vendorBidAmountCents Int?
4206
- vendorEventDetails String?
4207
- bashPointsApplied Int? // BashPoints credits applied to this booking
4208
- 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
4209
4424
  // Settlement fields for percentage-based bookings (populated at event close)
4210
- settlementBasis ServiceBookingSettlementBasis?
4211
- settlementPercentage Decimal?
4212
- settlementAmountCents Int?
4213
- settledAt DateTime?
4214
- notification Notification[]
4215
- bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4216
- creator User @relation("BookingCreator", fields: [creatorId], references: [id])
4217
- forUser User @relation("BookingForUser", fields: [forUserId], references: [id])
4218
- service Service @relation(fields: [serviceId], references: [id])
4219
- addOns ServiceBookingAddOn[]
4220
- checkout ServiceBookingCheckout?
4221
- bookedDays ServiceBookingDay[]
4222
- additionalFees ServiceBookingFee[]
4223
- messages ServiceBookingMessage[]
4224
- packages ServiceBookingPackage[]
4225
- commissions BookingCommission[] @relation("BookingCommissions")
4226
- 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[]
4227
4510
 
4228
4511
  @@index([status])
4229
4512
  @@index([creatorId])
@@ -4264,6 +4547,10 @@ model VendorBookingRequest {
4264
4547
  permitRequirements String
4265
4548
  weatherContingency String
4266
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([])
4267
4554
  status VendorBookingStatus @default(PENDING)
4268
4555
  paymentAmount Float?
4269
4556
  paymentStatus String?
@@ -4276,6 +4563,7 @@ model VendorBookingRequest {
4276
4563
  bashEvent BashEvent? @relation("VendorBookingEvent", fields: [bashEventId], references: [id])
4277
4564
  hostUser User @relation("VendorBookingHost", fields: [hostUserId], references: [id], onDelete: Cascade)
4278
4565
  vendorService Service @relation("VendorBookingService", fields: [vendorServiceId], references: [id], onDelete: Cascade)
4566
+ offers ServiceBookingOffer[]
4279
4567
 
4280
4568
  @@index([hostUserId])
4281
4569
  @@index([vendorServiceId])
@@ -4367,6 +4655,8 @@ model ExhibitorBookingRequest {
4367
4655
  leadGenerationExpected Boolean @default(false)
4368
4656
  materialDistribution String
4369
4657
  demonstrationNeeds String
4658
+ /// Phase 4 — see VendorBookingRequest.pricingModelAllowList.
4659
+ pricingModelAllowList String[] @default([])
4370
4660
  status ExhibitorBookingStatus @default(PENDING)
4371
4661
  paymentAmount Float?
4372
4662
  paymentStatus String?
@@ -4416,6 +4706,8 @@ model SponsorBookingRequest {
4416
4706
  cancellationPolicy String
4417
4707
  mentionRequirements String
4418
4708
  socialMediaRequirements String
4709
+ /// Phase 4 — see VendorBookingRequest.pricingModelAllowList.
4710
+ pricingModelAllowList String[] @default([])
4419
4711
  status SponsorBookingStatus @default(PENDING)
4420
4712
  paymentAmount Float?
4421
4713
  paymentStatus String?
@@ -4461,23 +4753,23 @@ model ServiceLink {
4461
4753
  }
4462
4754
 
4463
4755
  model UserReport {
4464
- id String @id @default(cuid())
4756
+ id String @id @default(cuid())
4465
4757
  reporterId String
4466
4758
  reportedId String
4467
4759
  bashEventId String?
4468
4760
  reason String
4469
4761
  details String
4470
- createdAt DateTime @default(now())
4471
- status ReportStatus @default(Pending)
4762
+ createdAt DateTime @default(now())
4763
+ status ReportStatus @default(Pending)
4472
4764
  reviewerId String?
4473
4765
  reviewedAt DateTime?
4474
4766
  reviewNotes String?
4475
4767
  demerits Demerit[]
4476
4768
  evidence UserReportEvidence[]
4477
- bashEvent BashEvent? @relation(fields: [bashEventId], references: [id])
4478
- reported User @relation("ReportsReceived", fields: [reportedId], references: [id], onDelete: Cascade)
4479
- reporter User @relation("ReportsMade", fields: [reporterId], references: [id], onDelete: Cascade)
4480
- 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])
4481
4773
 
4482
4774
  @@index([reporterId])
4483
4775
  @@index([reportedId])
@@ -4823,6 +5115,7 @@ enum NotificationType {
4823
5115
  ServiceBookingDeclined
4824
5116
  ServiceBookingCancelled
4825
5117
  ServiceBookingConfirmed
5118
+ ServiceOfferReceived
4826
5119
  Message
4827
5120
  ConnectionRequest
4828
5121
  ConnectionAccepted
@@ -5193,14 +5486,6 @@ enum SchoolNameSource {
5193
5486
  UserConfirmed
5194
5487
  }
5195
5488
 
5196
- /// Admin-gated custom-scope pricing flag for service providers needing variable/quote-based pricing
5197
- enum CustomScopeStatus {
5198
- None
5199
- Pending
5200
- Approved
5201
- Rejected
5202
- }
5203
-
5204
5489
  /// AI bash-approval reviewer verdict (see `bashApprovalAiService`).
5205
5490
  /// `Approve` and `Reject` are recommendations; whether the system acts on them
5206
5491
  /// vs. queues for a human depends on confidence + AI_BASH_APPROVAL_MODE.
@@ -5268,6 +5553,21 @@ enum VolunteerServiceStatus {
5268
5553
  Created
5269
5554
  }
5270
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
+
5271
5571
  enum Gender {
5272
5572
  Male
5273
5573
  Female
@@ -6680,6 +6980,105 @@ enum ServiceBookingRateOption {
6680
6980
  enum ServiceBookingSettlementBasis {
6681
6981
  TicketRevenue // Venue takes % of ticket sales (Bash auto-calculates from held revenue)
6682
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])
6683
7082
  }
6684
7083
 
6685
7084
  enum VendorBookingStatus {
@@ -6781,7 +7180,9 @@ enum PaymentProvider {
6781
7180
 
6782
7181
  enum PricingModel {
6783
7182
  FLAT_FEE // Fixed amount: "$500 for vendor booth"
6784
- 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)
6785
7186
  HOURLY // Per hour: "$200/hour, 4-hour minimum"
6786
7187
  PER_DAY // Per day: "$1,000/day"
6787
7188
  TIERED // Multiple options: "Bronze $1K, Silver $2.5K, Gold $5K"
@@ -6790,6 +7191,20 @@ enum PricingModel {
6790
7191
  PRODUCT_SALES_PERCENTAGE // Host takes a % of vendor/exhibitor product sales through Bash checkout
6791
7192
  }
6792
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
+
6793
7208
  enum PricingType {
6794
7209
  USD // Ticket priced in USD (paid with credit card, earns BashPoints cashback)
6795
7210
  BASHPOINTS // Ticket priced in BashPoints (peer-to-peer loyalty points transfer)
@@ -6900,12 +7315,7 @@ enum CreditSourceType {
6900
7315
  PostBeforeEvent // First BashFeed post linked to event before it ends
6901
7316
  PostAfterEvent // First BashFeed post linked to event after it ends
6902
7317
  ReferralCodeUsed // Flat bonus for referrer when code drives a ticket/signup
6903
- }
6904
-
6905
- enum PendingGiftStatus {
6906
- Pending
6907
- Claimed
6908
- Returned
7318
+ VenueLoyaltyRedemption // BashPoints moved through a VenueLoyaltyRedemption claim/redeem/refund
6909
7319
  }
6910
7320
 
6911
7321
  enum ReferralTier {
@@ -8423,3 +8833,17 @@ enum VanityPathStatus {
8423
8833
  Active
8424
8834
  Revoked
8425
8835
  }
8836
+
8837
+ enum OrgProductStatus {
8838
+ Active
8839
+ Archived
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
+ }