@bash-app/bash-common 30.117.0 → 30.118.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extendedSchemas.d.ts +54 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +10 -1
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/__tests__/paymentUtils.test.d.ts +6 -0
- package/dist/utils/__tests__/paymentUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/paymentUtils.test.js +77 -0
- package/dist/utils/__tests__/paymentUtils.test.js.map +1 -0
- package/dist/utils/discountEngine/__tests__/bestPriceResolver.test.d.ts +2 -0
- package/dist/utils/discountEngine/__tests__/bestPriceResolver.test.d.ts.map +1 -0
- package/dist/utils/discountEngine/__tests__/bestPriceResolver.test.js +457 -0
- package/dist/utils/discountEngine/__tests__/bestPriceResolver.test.js.map +1 -0
- package/dist/utils/discountEngine/__tests__/eligibilityValidator.test.d.ts +2 -0
- package/dist/utils/discountEngine/__tests__/eligibilityValidator.test.d.ts.map +1 -0
- package/dist/utils/discountEngine/__tests__/eligibilityValidator.test.js +480 -0
- package/dist/utils/discountEngine/__tests__/eligibilityValidator.test.js.map +1 -0
- package/package.json +2 -2
- package/prisma/COMPREHENSIVE-MIGRATION-README.md +295 -0
- package/prisma/MIGRATION-FILES-GUIDE.md +76 -0
- package/prisma/comprehensive-migration-20260120.sql +5751 -0
- package/prisma/delta-migration-20260120.sql +302 -0
- package/prisma/schema.prisma +486 -147
- package/prisma/verify-migration.sql +132 -0
- package/src/extendedSchemas.ts +10 -1
- package/src/index.ts +4 -0
- package/src/utils/__tests__/paymentUtils.test.ts +95 -0
- package/src/utils/discountEngine/__tests__/bestPriceResolver.test.ts +558 -0
- package/src/utils/discountEngine/__tests__/eligibilityValidator.test.ts +655 -0
package/prisma/schema.prisma
CHANGED
|
@@ -16,6 +16,7 @@ model Club {
|
|
|
16
16
|
events BashEvent[]
|
|
17
17
|
admin ClubAdmin[]
|
|
18
18
|
members ClubMember[]
|
|
19
|
+
budgets Budget[] @relation("ClubBudgets")
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
model ClubAdmin {
|
|
@@ -56,7 +57,8 @@ model BashComment {
|
|
|
56
57
|
model BashFeedPost {
|
|
57
58
|
id String @id @default(cuid())
|
|
58
59
|
userId String
|
|
59
|
-
bashId String
|
|
60
|
+
bashId String?
|
|
61
|
+
serviceId String?
|
|
60
62
|
content String? @db.Text
|
|
61
63
|
mediaIds String[] // Array of Media IDs
|
|
62
64
|
mentionedUserIds String[] // Array of User IDs mentioned in post
|
|
@@ -71,7 +73,8 @@ model BashFeedPost {
|
|
|
71
73
|
|
|
72
74
|
// Relationships
|
|
73
75
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
74
|
-
bash BashEvent
|
|
76
|
+
bash BashEvent? @relation(fields: [bashId], references: [id], onDelete: Cascade)
|
|
77
|
+
service Service? @relation(fields: [serviceId], references: [id], onDelete: Cascade)
|
|
75
78
|
likes BashFeedLike[]
|
|
76
79
|
comments BashFeedComment[]
|
|
77
80
|
ratings BashFeedRating[]
|
|
@@ -80,6 +83,7 @@ model BashFeedPost {
|
|
|
80
83
|
reposts BashFeedRepost[]
|
|
81
84
|
|
|
82
85
|
@@index([bashId])
|
|
86
|
+
@@index([serviceId])
|
|
83
87
|
@@index([userId])
|
|
84
88
|
@@index([createdAt])
|
|
85
89
|
@@index([isAnonymous])
|
|
@@ -338,6 +342,7 @@ model EventTask {
|
|
|
338
342
|
neededCount Int? // Number of volunteers needed
|
|
339
343
|
estimatedDuration Int? // Estimated duration in minutes
|
|
340
344
|
createdAt DateTime? @default(now())
|
|
345
|
+
organizationId String? // Organization association
|
|
341
346
|
assignedTo User? @relation("TasksAssignedToMe", fields: [assignedToId], references: [id], onDelete: Cascade)
|
|
342
347
|
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
343
348
|
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
|
|
@@ -547,89 +552,99 @@ model Invitation {
|
|
|
547
552
|
}
|
|
548
553
|
|
|
549
554
|
model BashEvent {
|
|
550
|
-
id
|
|
551
|
-
source
|
|
552
|
-
title
|
|
553
|
-
slug
|
|
554
|
-
creatorId
|
|
555
|
-
createdAt
|
|
556
|
-
isApproved
|
|
557
|
-
description
|
|
558
|
-
eventType
|
|
559
|
-
timezone
|
|
560
|
-
startDateTime
|
|
561
|
-
endDateTime
|
|
562
|
-
waiverUrl
|
|
563
|
-
waiverRequired
|
|
564
|
-
waiverDisplayType
|
|
565
|
-
targetAudienceId
|
|
566
|
-
amountOfGuestsId
|
|
567
|
-
vibe
|
|
568
|
-
occasion
|
|
569
|
-
dress
|
|
570
|
-
allowed
|
|
571
|
-
notAllowed
|
|
572
|
-
eventFormat
|
|
573
|
-
nonProfit
|
|
574
|
-
nonProfitId
|
|
575
|
-
privacy
|
|
576
|
-
capacity
|
|
577
|
-
location
|
|
578
|
-
street
|
|
579
|
-
city
|
|
580
|
-
state
|
|
581
|
-
zipCode
|
|
582
|
-
country
|
|
583
|
-
status
|
|
584
|
-
tags
|
|
585
|
-
coverPhoto
|
|
586
|
-
clubId
|
|
587
|
-
dateTimePublished
|
|
588
|
-
includedItems
|
|
589
|
-
videoLink
|
|
590
|
-
subtitle
|
|
591
|
-
isFeatured
|
|
592
|
-
isTrending
|
|
593
|
-
venueId
|
|
594
|
-
averageRating
|
|
595
|
-
totalRatings
|
|
596
|
-
totalReviews
|
|
597
|
-
totalFeedRatings
|
|
598
|
-
allowDonations
|
|
599
|
-
suggestedDonationAmount
|
|
600
|
-
donationDetails
|
|
601
|
-
absorbDonationFees
|
|
602
|
-
absorbTicketFees
|
|
603
|
-
showAttendees
|
|
604
|
-
servicePreferences
|
|
605
|
-
bookedServices
|
|
606
|
-
serviceVisibility
|
|
607
|
-
originalCreatorId
|
|
608
|
-
transferredAt
|
|
609
|
-
transferredFromId
|
|
610
|
-
transferCount
|
|
611
|
-
startTimeLocked
|
|
612
|
-
p2pPaymentMethod
|
|
613
|
-
venmoUsername
|
|
614
|
-
venmoQRCodeUrl
|
|
615
|
-
zelleEmail
|
|
616
|
-
zellePhone
|
|
617
|
-
zelleQRCodeUrl
|
|
618
|
-
externalTicketUrl
|
|
619
|
-
externalPriceMin
|
|
620
|
-
externalPriceMax
|
|
621
|
-
externalPriceSummary
|
|
622
|
-
customTermsAndConditions
|
|
623
|
-
itinerary
|
|
624
|
-
|
|
555
|
+
id String @id @default(cuid())
|
|
556
|
+
source BashEventSource @default(Bash)
|
|
557
|
+
title String
|
|
558
|
+
slug String? @unique
|
|
559
|
+
creatorId String
|
|
560
|
+
createdAt DateTime? @default(now())
|
|
561
|
+
isApproved Boolean? @default(false)
|
|
562
|
+
description String?
|
|
563
|
+
eventType String @default("Other")
|
|
564
|
+
timezone String?
|
|
565
|
+
startDateTime DateTime?
|
|
566
|
+
endDateTime DateTime?
|
|
567
|
+
waiverUrl String?
|
|
568
|
+
waiverRequired Boolean @default(false)
|
|
569
|
+
waiverDisplayType String? @default("inline")
|
|
570
|
+
targetAudienceId String? @unique
|
|
571
|
+
amountOfGuestsId String? @unique
|
|
572
|
+
vibe String?
|
|
573
|
+
occasion String?
|
|
574
|
+
dress String?
|
|
575
|
+
allowed String?
|
|
576
|
+
notAllowed String?
|
|
577
|
+
eventFormat EventFormat? // Derived from location and videoLink: In-Person, Virtual, or Hybrid
|
|
578
|
+
nonProfit Boolean?
|
|
579
|
+
nonProfitId String?
|
|
580
|
+
privacy Privacy @default(Public)
|
|
581
|
+
capacity Int?
|
|
582
|
+
location String?
|
|
583
|
+
street String?
|
|
584
|
+
city String?
|
|
585
|
+
state String?
|
|
586
|
+
zipCode String?
|
|
587
|
+
country String?
|
|
588
|
+
status BashStatus @default(Draft)
|
|
589
|
+
tags String[]
|
|
590
|
+
coverPhoto String?
|
|
591
|
+
clubId String?
|
|
592
|
+
dateTimePublished DateTime?
|
|
593
|
+
includedItems String[]
|
|
594
|
+
videoLink String?
|
|
595
|
+
subtitle String?
|
|
596
|
+
isFeatured Boolean?
|
|
597
|
+
isTrending Boolean?
|
|
598
|
+
venueId String?
|
|
599
|
+
averageRating Float? @default(0)
|
|
600
|
+
totalRatings Int? @default(0) // Total count of all ratings (Review + BashFeedRating)
|
|
601
|
+
totalReviews Int? @default(0) // Count of Review records (anonymous quick ratings)
|
|
602
|
+
totalFeedRatings Int? @default(0) // Count of BashFeedRating records (from posts)
|
|
603
|
+
allowDonations Boolean? @default(true)
|
|
604
|
+
suggestedDonationAmount Int?
|
|
605
|
+
donationDetails String?
|
|
606
|
+
absorbDonationFees Boolean @default(false)
|
|
607
|
+
absorbTicketFees Boolean @default(false)
|
|
608
|
+
showAttendees Boolean @default(true)
|
|
609
|
+
servicePreferences Json? // New tiered status: { "Entertainment": "need", "Sponsors": "booked_closed", ... }
|
|
610
|
+
bookedServices Json? // Booked service details: { "Entertainment": { serviceId: "...", providerId: "...", bookedAt: "..." }, ... }
|
|
611
|
+
serviceVisibility Json? // DEPRECATED: Use servicePreferences instead. Kept for backward compatibility during migration.
|
|
612
|
+
originalCreatorId String?
|
|
613
|
+
transferredAt DateTime?
|
|
614
|
+
transferredFromId String?
|
|
615
|
+
transferCount Int @default(0)
|
|
616
|
+
startTimeLocked Boolean @default(false)
|
|
617
|
+
p2pPaymentMethod String?
|
|
618
|
+
venmoUsername String?
|
|
619
|
+
venmoQRCodeUrl String?
|
|
620
|
+
zelleEmail String?
|
|
621
|
+
zellePhone String?
|
|
622
|
+
zelleQRCodeUrl String?
|
|
623
|
+
externalTicketUrl String? // URL to external ticket purchase page (for imported events)
|
|
624
|
+
externalPriceMin Int? // Minimum ticket price in cents (for imported events)
|
|
625
|
+
externalPriceMax Int? // Maximum ticket price in cents (for imported events)
|
|
626
|
+
externalPriceSummary String? // Human-readable price summary e.g., "$50 - $150" or "$75"
|
|
627
|
+
customTermsAndConditions String?
|
|
628
|
+
itinerary Json? // Array of { id: string, title: string, startTime: string, endTime: string, description?: string }
|
|
629
|
+
|
|
625
630
|
// Idea-specific fields (only used when status = 'Idea')
|
|
626
|
-
ideaExpiresAt
|
|
627
|
-
ideaInterestThreshold
|
|
628
|
-
hideInterestCount
|
|
629
|
-
isAutoApprovable
|
|
630
|
-
autoApprovedAt
|
|
631
|
-
lastEngagementAt
|
|
632
|
-
|
|
631
|
+
ideaExpiresAt DateTime?
|
|
632
|
+
ideaInterestThreshold Int? @default(35)
|
|
633
|
+
hideInterestCount Boolean @default(false)
|
|
634
|
+
isAutoApprovable Boolean @default(false)
|
|
635
|
+
autoApprovedAt DateTime?
|
|
636
|
+
lastEngagementAt DateTime? // Track last interest/share for decay
|
|
637
|
+
|
|
638
|
+
// Organization field
|
|
639
|
+
organizationId String?
|
|
640
|
+
organization Organization? @relation("OrganizationBashEvents", fields: [organizationId], references: [id])
|
|
641
|
+
|
|
642
|
+
// Organization access controls (only apply when organizationId is set)
|
|
643
|
+
requiresOrgMembership Boolean @default(false) // Must be member to attend/RSVP
|
|
644
|
+
allowMemberGuests Boolean @default(false) // Members can bring +1s
|
|
645
|
+
maxGuestsPerMember Int? // Guest limit per member (null = unlimited)
|
|
646
|
+
restrictToOrgDepartments String[] @default([]) // Empty = all departments can see/join
|
|
647
|
+
|
|
633
648
|
associatedBashesReferencingMe AssociatedBash[]
|
|
634
649
|
comments BashComment[]
|
|
635
650
|
amountOfGuests AmountOfGuests? @relation(fields: [amountOfGuestsId], references: [id], onDelete: Cascade)
|
|
@@ -682,16 +697,21 @@ model BashEvent {
|
|
|
682
697
|
bashFeedPosts BashFeedPost[]
|
|
683
698
|
bashFeedRatings BashFeedRating[]
|
|
684
699
|
eventRankings EventRankings?
|
|
685
|
-
|
|
700
|
+
|
|
686
701
|
// Idea Relations
|
|
687
|
-
interests
|
|
688
|
-
configurations
|
|
702
|
+
interests IdeaInterest[]
|
|
703
|
+
configurations IdeaConfiguration[]
|
|
689
704
|
|
|
690
705
|
// Analytics Relations
|
|
691
706
|
analyticsPredictions AnalyticsPrediction[]
|
|
692
707
|
|
|
708
|
+
// Organization Relations
|
|
709
|
+
budgets Budget[] @relation("EventBudgets")
|
|
710
|
+
rsvps EventRSVP[] @relation("EventRSVPs")
|
|
711
|
+
|
|
693
712
|
@@index([templateId])
|
|
694
713
|
@@index([parentEventId])
|
|
714
|
+
@@index([organizationId])
|
|
695
715
|
}
|
|
696
716
|
|
|
697
717
|
// ============================================
|
|
@@ -699,22 +719,22 @@ model BashEvent {
|
|
|
699
719
|
// ============================================
|
|
700
720
|
|
|
701
721
|
model IdeaInterest {
|
|
702
|
-
id String
|
|
722
|
+
id String @id @default(cuid())
|
|
703
723
|
bashEventId String
|
|
704
724
|
email String
|
|
705
725
|
phone String?
|
|
706
|
-
source String?
|
|
707
|
-
ipAddress String?
|
|
726
|
+
source String? // 'tiktok_bio', 'bashfeed', 'share', 'direct'
|
|
727
|
+
ipAddress String? // For fraud prevention
|
|
708
728
|
userAgent String?
|
|
709
|
-
convertedToUserId String?
|
|
710
|
-
createdAt DateTime
|
|
711
|
-
updatedAt DateTime
|
|
712
|
-
|
|
729
|
+
convertedToUserId String? // If they later create account
|
|
730
|
+
createdAt DateTime @default(now())
|
|
731
|
+
updatedAt DateTime @updatedAt
|
|
732
|
+
|
|
713
733
|
// Relationships
|
|
714
|
-
bashEvent
|
|
715
|
-
user
|
|
716
|
-
responses
|
|
717
|
-
|
|
734
|
+
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
735
|
+
user User? @relation(fields: [convertedToUserId], references: [id])
|
|
736
|
+
responses IdeaInterestResponse[]
|
|
737
|
+
|
|
718
738
|
@@unique([bashEventId, email])
|
|
719
739
|
@@index([bashEventId])
|
|
720
740
|
@@index([email])
|
|
@@ -722,38 +742,38 @@ model IdeaInterest {
|
|
|
722
742
|
}
|
|
723
743
|
|
|
724
744
|
model IdeaInterestResponse {
|
|
725
|
-
id String
|
|
745
|
+
id String @id @default(cuid())
|
|
726
746
|
interestId String
|
|
727
|
-
questionType String
|
|
728
|
-
questionText String?
|
|
729
|
-
responseValue String
|
|
730
|
-
configurationId String?
|
|
731
|
-
createdAt DateTime
|
|
732
|
-
|
|
747
|
+
questionType String // 'base_price', 'configuration_price', 'preferred_date', 'must_have'
|
|
748
|
+
questionText String? // For custom host questions
|
|
749
|
+
responseValue String // JSON: {min: 20, max: 50} or "Yes" or date string
|
|
750
|
+
configurationId String? // Links to specific configuration if applicable
|
|
751
|
+
createdAt DateTime @default(now())
|
|
752
|
+
|
|
733
753
|
// Relationships
|
|
734
|
-
interest
|
|
735
|
-
configuration
|
|
736
|
-
|
|
754
|
+
interest IdeaInterest @relation(fields: [interestId], references: [id], onDelete: Cascade)
|
|
755
|
+
configuration IdeaConfiguration? @relation(fields: [configurationId], references: [id], onDelete: SetNull)
|
|
756
|
+
|
|
737
757
|
@@index([interestId])
|
|
738
758
|
@@index([configurationId])
|
|
739
759
|
@@index([questionType])
|
|
740
760
|
}
|
|
741
761
|
|
|
742
762
|
model IdeaConfiguration {
|
|
743
|
-
id
|
|
744
|
-
bashEventId
|
|
745
|
-
name
|
|
746
|
-
description
|
|
747
|
-
estimatedCost
|
|
748
|
-
isActive
|
|
749
|
-
sortOrder
|
|
750
|
-
createdAt
|
|
751
|
-
updatedAt
|
|
752
|
-
|
|
763
|
+
id String @id @default(cuid())
|
|
764
|
+
bashEventId String
|
|
765
|
+
name String // "Premium Open Bar", "Food Truck", "Live DJ"
|
|
766
|
+
description String?
|
|
767
|
+
estimatedCost Int? // In cents - helps host with pricing
|
|
768
|
+
isActive Boolean @default(true)
|
|
769
|
+
sortOrder Int @default(0)
|
|
770
|
+
createdAt DateTime @default(now())
|
|
771
|
+
updatedAt DateTime @updatedAt
|
|
772
|
+
|
|
753
773
|
// Relationships
|
|
754
|
-
bashEvent
|
|
755
|
-
responses
|
|
756
|
-
|
|
774
|
+
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
775
|
+
responses IdeaInterestResponse[]
|
|
776
|
+
|
|
757
777
|
@@index([bashEventId])
|
|
758
778
|
@@index([isActive])
|
|
759
779
|
}
|
|
@@ -925,6 +945,12 @@ model TicketTier {
|
|
|
925
945
|
specialOffers SpecialOffer[] // NEW - Special offers for this tier
|
|
926
946
|
appliedDiscounts AppliedDiscount[] // NEW - Discounts applied to this tier
|
|
927
947
|
|
|
948
|
+
// Organization member restrictions (for org events)
|
|
949
|
+
restrictedToRoles String[] @default([]) // ["Admin", "Owner"] - empty = all roles
|
|
950
|
+
restrictedToDepartments String[] @default([]) // [deptId1, deptId2] - empty = all departments
|
|
951
|
+
restrictedToMembershipTiers String[] @default([]) // ["Premium"] - empty = all membership tiers
|
|
952
|
+
isGuestTier Boolean @default(false) // Ticket for member +1s
|
|
953
|
+
|
|
928
954
|
@@unique([bashEventId, title])
|
|
929
955
|
}
|
|
930
956
|
|
|
@@ -1507,9 +1533,26 @@ model User {
|
|
|
1507
1533
|
nominationsGiven Nomination[] @relation("NominatingUser")
|
|
1508
1534
|
votesGiven NominationVote[]
|
|
1509
1535
|
categoriesCreated NominationCategory[]
|
|
1510
|
-
|
|
1536
|
+
|
|
1511
1537
|
// Idea Interest Relations
|
|
1512
1538
|
ideaInterests IdeaInterest[]
|
|
1539
|
+
|
|
1540
|
+
// Organization Relations
|
|
1541
|
+
ownedOrganizations Organization[] @relation("OrganizationOwner")
|
|
1542
|
+
organizationMemberships OrganizationMember[] @relation("OrganizationMemberUser")
|
|
1543
|
+
organizationEventRSVPs EventRSVP[] @relation("OrganizationEventRSVP")
|
|
1544
|
+
submittedExpenses Expense[] @relation("ExpenseSubmitter")
|
|
1545
|
+
approvedExpenses Expense[] @relation("ExpenseApprover")
|
|
1546
|
+
approvedBudgets Budget[] @relation("BudgetApprover")
|
|
1547
|
+
submittedBudgets Budget[] @relation("BudgetSubmitter")
|
|
1548
|
+
ownedBudgets Budget[] @relation("UserBudgets")
|
|
1549
|
+
departmentsHeaded Department[] @relation("DepartmentHead")
|
|
1550
|
+
favoriteOrganizations Organization[] @relation("FavoriteOrganizations")
|
|
1551
|
+
|
|
1552
|
+
// Service Includes & Add-On Requests
|
|
1553
|
+
suggestedIncludes ServiceInclude[] @relation("SuggestedIncludes")
|
|
1554
|
+
includeVotes ServiceIncludeVote[]
|
|
1555
|
+
requestedAddons ServiceAddonRequest[] @relation("RequestedAddons")
|
|
1513
1556
|
}
|
|
1514
1557
|
|
|
1515
1558
|
model UserPreferences {
|
|
@@ -1952,6 +1995,12 @@ model Service {
|
|
|
1952
1995
|
monthlyPrice Decimal @default(0)
|
|
1953
1996
|
serviceListingStripeSubscriptionId String?
|
|
1954
1997
|
acceptsBashCash Boolean @default(true) // NEW: Allow BashCash payments
|
|
1998
|
+
isVerified Boolean @default(false) // Service owner verified
|
|
1999
|
+
isLicensed Boolean @default(false) // Has required licenses
|
|
2000
|
+
verifiedAt DateTime? // When verification was approved
|
|
2001
|
+
licenseNumber String? // License/registration number
|
|
2002
|
+
certifications String[] @default([]) // Array of certification names
|
|
2003
|
+
bashFeedPosts BashFeedPost[]
|
|
1955
2004
|
associatedServicesReferencingMe AssociatedService[]
|
|
1956
2005
|
exhibitorBookingRequests ExhibitorBookingRequest[] @relation("ExhibitorBookingService")
|
|
1957
2006
|
notification Notification[]
|
|
@@ -1984,9 +2033,13 @@ model Service {
|
|
|
1984
2033
|
bookingCommissions BookingCommission[] @relation("CommissionServiceProfile")
|
|
1985
2034
|
venueMatches VenueEntertainmentMatch[] @relation("VenueMatches")
|
|
1986
2035
|
entertainerMatches VenueEntertainmentMatch[] @relation("EntertainerMatches")
|
|
2036
|
+
includes ServiceInclude[]
|
|
2037
|
+
addonRequests ServiceAddonRequest[]
|
|
1987
2038
|
|
|
1988
2039
|
@@index([serviceListingStripeSubscriptionId])
|
|
1989
2040
|
@@index([isFreeFirstListing])
|
|
2041
|
+
@@index([isVerified])
|
|
2042
|
+
@@index([isLicensed])
|
|
1990
2043
|
}
|
|
1991
2044
|
|
|
1992
2045
|
model StripeAccount {
|
|
@@ -2318,12 +2371,202 @@ model UserPromoCodeRedemption {
|
|
|
2318
2371
|
}
|
|
2319
2372
|
|
|
2320
2373
|
model Organization {
|
|
2321
|
-
id
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2374
|
+
id String @id @default(cuid())
|
|
2375
|
+
name String
|
|
2376
|
+
slug String @unique
|
|
2377
|
+
organizationType OrganizationType[]
|
|
2378
|
+
bio String?
|
|
2379
|
+
mission String?
|
|
2380
|
+
pocName String?
|
|
2381
|
+
pocEmail String?
|
|
2382
|
+
pocPhone String?
|
|
2383
|
+
street String?
|
|
2384
|
+
city String?
|
|
2385
|
+
state String?
|
|
2386
|
+
zipCode String?
|
|
2387
|
+
country String? @default("US")
|
|
2388
|
+
coverPhoto String?
|
|
2389
|
+
logoUrl String?
|
|
2390
|
+
websiteUrl String?
|
|
2391
|
+
socialLinks Json?
|
|
2392
|
+
goodsOrServices String[]
|
|
2393
|
+
venueTypes String[]
|
|
2394
|
+
secondaryVenueTypes String[] @default([])
|
|
2395
|
+
baseMembershipPriceCents Int?
|
|
2396
|
+
premiumMembershipPriceCents Int?
|
|
2397
|
+
allowGuestsByDefault Boolean @default(false)
|
|
2398
|
+
defaultGuestLimit Int @default(0)
|
|
2399
|
+
visibility String @default("Public")
|
|
2400
|
+
requiresApproval Boolean @default(true)
|
|
2401
|
+
memberAutoApproval Boolean @default(false)
|
|
2402
|
+
ownerId String
|
|
2403
|
+
parentOrganizationId String?
|
|
2404
|
+
departmentName String?
|
|
2405
|
+
hierarchyLevel Int @default(0)
|
|
2406
|
+
subscriptionTier String?
|
|
2407
|
+
subscriptionStatus String?
|
|
2408
|
+
stripeSubscriptionId String? @unique
|
|
2409
|
+
stripeCustomerId String?
|
|
2410
|
+
createdAt DateTime @default(now())
|
|
2411
|
+
updatedAt DateTime @updatedAt
|
|
2412
|
+
service Service?
|
|
2413
|
+
owner User @relation("OrganizationOwner", fields: [ownerId], references: [id], onDelete: Restrict)
|
|
2414
|
+
parentOrganization Organization? @relation("OrganizationHierarchy", fields: [parentOrganizationId], references: [id])
|
|
2415
|
+
childOrganizations Organization[] @relation("OrganizationHierarchy")
|
|
2416
|
+
members OrganizationMember[]
|
|
2417
|
+
budgets Budget[] @relation("OrganizationBudgets")
|
|
2418
|
+
departments Department[]
|
|
2419
|
+
bashEvents BashEvent[] @relation("OrganizationBashEvents")
|
|
2420
|
+
favoriteBy User[] @relation("FavoriteOrganizations")
|
|
2421
|
+
|
|
2422
|
+
@@index([ownerId])
|
|
2423
|
+
@@index([slug])
|
|
2424
|
+
@@index([parentOrganizationId])
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
model OrganizationMember {
|
|
2428
|
+
id String @id @default(cuid())
|
|
2429
|
+
organizationId String
|
|
2430
|
+
userId String
|
|
2431
|
+
role String @default("Member") // Owner, Admin, Coordinator, EventOrganizer, Treasurer, Member
|
|
2432
|
+
membershipTier String @default("Base") // Base, Premium
|
|
2433
|
+
status String @default("Pending") // Pending, Active, Suspended, Removed
|
|
2434
|
+
joinedAt DateTime @default(now())
|
|
2435
|
+
approvedAt DateTime?
|
|
2436
|
+
approvedBy String?
|
|
2437
|
+
paidUntil DateTime?
|
|
2438
|
+
paymentStatus String? @default("Current") // Current, Overdue, Cancelled
|
|
2439
|
+
guestLimit Int?
|
|
2440
|
+
canInvite Boolean @default(true)
|
|
2441
|
+
canCreateEvents Boolean @default(false)
|
|
2442
|
+
canManageBudgets Boolean @default(false)
|
|
2443
|
+
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
2444
|
+
user User @relation("OrganizationMemberUser", fields: [userId], references: [id], onDelete: Cascade)
|
|
2445
|
+
eventRSVPs EventRSVP[]
|
|
2446
|
+
|
|
2447
|
+
@@unique([organizationId, userId])
|
|
2448
|
+
@@index([organizationId])
|
|
2449
|
+
@@index([userId])
|
|
2450
|
+
@@index([status])
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
model Department {
|
|
2454
|
+
id String @id @default(cuid())
|
|
2455
|
+
organizationId String
|
|
2456
|
+
name String
|
|
2457
|
+
description String?
|
|
2458
|
+
parentDeptId String?
|
|
2459
|
+
headUserId String?
|
|
2460
|
+
budgetCents Int?
|
|
2461
|
+
createdAt DateTime @default(now())
|
|
2462
|
+
updatedAt DateTime @updatedAt
|
|
2463
|
+
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
2464
|
+
parentDept Department? @relation("DepartmentHierarchy", fields: [parentDeptId], references: [id])
|
|
2465
|
+
childDepts Department[] @relation("DepartmentHierarchy")
|
|
2466
|
+
head User? @relation("DepartmentHead", fields: [headUserId], references: [id])
|
|
2467
|
+
budgets Budget[] @relation("DepartmentBudgets")
|
|
2468
|
+
|
|
2469
|
+
@@index([organizationId])
|
|
2470
|
+
@@index([parentDeptId])
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
model EventRSVP {
|
|
2474
|
+
id String @id @default(cuid())
|
|
2475
|
+
eventId String
|
|
2476
|
+
memberId String
|
|
2477
|
+
userId String
|
|
2478
|
+
status String @default("Going") // Going, Maybe, NotGoing
|
|
2479
|
+
guestsCount Int @default(0)
|
|
2480
|
+
checkedIn Boolean @default(false)
|
|
2481
|
+
checkedInAt DateTime?
|
|
2482
|
+
createdAt DateTime @default(now())
|
|
2483
|
+
updatedAt DateTime @updatedAt
|
|
2484
|
+
event BashEvent @relation("EventRSVPs", fields: [eventId], references: [id], onDelete: Cascade)
|
|
2485
|
+
member OrganizationMember @relation(fields: [memberId], references: [id], onDelete: Cascade)
|
|
2486
|
+
user User @relation("OrganizationEventRSVP", fields: [userId], references: [id])
|
|
2487
|
+
|
|
2488
|
+
@@unique([eventId, userId])
|
|
2489
|
+
@@index([eventId])
|
|
2490
|
+
@@index([userId])
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
model Budget {
|
|
2494
|
+
id String @id @default(cuid())
|
|
2495
|
+
name String
|
|
2496
|
+
|
|
2497
|
+
// Flexible ownership - at least ONE should be set
|
|
2498
|
+
organizationId String?
|
|
2499
|
+
bashEventId String?
|
|
2500
|
+
clubId String?
|
|
2501
|
+
departmentId String?
|
|
2502
|
+
userId String? // For personal event budgets
|
|
2503
|
+
|
|
2504
|
+
// Budget details
|
|
2505
|
+
totalAllocatedCents Int
|
|
2506
|
+
totalBudgetCents Int? // Alias for backward compatibility
|
|
2507
|
+
spentCents Int @default(0)
|
|
2508
|
+
remainingCents Int? // Can be computed: totalAllocatedCents - spentCents
|
|
2509
|
+
|
|
2510
|
+
// Categorization
|
|
2511
|
+
category String? // "Marketing", "Catering", "Venue", "Annual", "Activities"
|
|
2512
|
+
fiscalYear String? // Keep as String for flexibility ("2026", "2026-Q1", "FY2026")
|
|
2513
|
+
|
|
2514
|
+
// Approval workflow
|
|
2515
|
+
status String? @default("Draft") // Draft, Submitted, Approved, Active, Closed, Archived
|
|
2516
|
+
submittedBy String?
|
|
2517
|
+
approverId String?
|
|
2518
|
+
approvedBy String? // Alias for approverId
|
|
2519
|
+
approvedAt DateTime?
|
|
2520
|
+
|
|
2521
|
+
// Date ranges
|
|
2522
|
+
startDate DateTime?
|
|
2523
|
+
endDate DateTime?
|
|
2524
|
+
|
|
2525
|
+
// Timestamps
|
|
2526
|
+
createdAt DateTime @default(now())
|
|
2527
|
+
updatedAt DateTime @updatedAt
|
|
2528
|
+
|
|
2529
|
+
// Relations
|
|
2530
|
+
organization Organization? @relation("OrganizationBudgets", fields: [organizationId], references: [id], onDelete: Cascade)
|
|
2531
|
+
bashEvent BashEvent? @relation("EventBudgets", fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
2532
|
+
club Club? @relation("ClubBudgets", fields: [clubId], references: [id], onDelete: Cascade)
|
|
2533
|
+
department Department? @relation("DepartmentBudgets", fields: [departmentId], references: [id], onDelete: Cascade)
|
|
2534
|
+
user User? @relation("UserBudgets", fields: [userId], references: [id], onDelete: Cascade)
|
|
2535
|
+
submitter User? @relation("BudgetSubmitter", fields: [submittedBy], references: [id])
|
|
2536
|
+
approver User? @relation("BudgetApprover", fields: [approverId], references: [id])
|
|
2537
|
+
expenses Expense[]
|
|
2538
|
+
|
|
2539
|
+
@@index([organizationId])
|
|
2540
|
+
@@index([bashEventId])
|
|
2541
|
+
@@index([clubId])
|
|
2542
|
+
@@index([departmentId])
|
|
2543
|
+
@@index([userId])
|
|
2544
|
+
@@index([status])
|
|
2545
|
+
@@index([fiscalYear])
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
model Expense {
|
|
2549
|
+
id String @id @default(cuid())
|
|
2550
|
+
budgetId String
|
|
2551
|
+
submittedBy String
|
|
2552
|
+
description String
|
|
2553
|
+
amountCents Int
|
|
2554
|
+
category String?
|
|
2555
|
+
receiptUrl String?
|
|
2556
|
+
expenseDate DateTime? // When the expense occurred
|
|
2557
|
+
status String @default("Pending") // Pending, Approved, Rejected
|
|
2558
|
+
approvedBy String?
|
|
2559
|
+
approvedAt DateTime?
|
|
2560
|
+
rejectionReason String?
|
|
2561
|
+
createdAt DateTime @default(now())
|
|
2562
|
+
updatedAt DateTime @updatedAt
|
|
2563
|
+
budget Budget @relation(fields: [budgetId], references: [id], onDelete: Cascade)
|
|
2564
|
+
submitter User @relation("ExpenseSubmitter", fields: [submittedBy], references: [id])
|
|
2565
|
+
approver User? @relation("ExpenseApprover", fields: [approvedBy], references: [id])
|
|
2566
|
+
|
|
2567
|
+
@@index([budgetId])
|
|
2568
|
+
@@index([submittedBy])
|
|
2569
|
+
@@index([status])
|
|
2327
2570
|
}
|
|
2328
2571
|
|
|
2329
2572
|
model ServiceRange {
|
|
@@ -2345,11 +2588,87 @@ model ServiceAddon {
|
|
|
2345
2588
|
priceCents Int
|
|
2346
2589
|
quantity Int
|
|
2347
2590
|
status ServiceAddonStatus @default(Enabled)
|
|
2591
|
+
imageUrl String? // Add-on image URL
|
|
2592
|
+
imageAlt String? // Alt text for accessibility
|
|
2348
2593
|
servicePackageId String?
|
|
2349
2594
|
serviceRatesAssociationId String?
|
|
2350
2595
|
servicePackage ServicePackage? @relation(fields: [servicePackageId], references: [id], onDelete: Cascade)
|
|
2351
2596
|
serviceRatesAssociation ServiceRatesAssociation? @relation(fields: [serviceRatesAssociationId], references: [id], onDelete: Cascade)
|
|
2352
2597
|
ServiceBookingAddOn ServiceBookingAddOn[]
|
|
2598
|
+
convertedFromInclude ServiceInclude[] @relation("IncludeConvertedToAddon")
|
|
2599
|
+
convertedFromRequest ServiceAddonRequest[] @relation("RequestConvertedToAddon")
|
|
2600
|
+
|
|
2601
|
+
@@index([imageUrl])
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
model ServiceInclude {
|
|
2605
|
+
id String @id @default(cuid())
|
|
2606
|
+
serviceId String
|
|
2607
|
+
suggestedByUserId String? // Who suggested it (null if anonymous)
|
|
2608
|
+
name String // e.g., "Tables and Chairs"
|
|
2609
|
+
description String? // Optional details
|
|
2610
|
+
status ServiceIncludeStatus @default(Pending)
|
|
2611
|
+
providerResponse ServiceIncludeResponse? // How provider responded
|
|
2612
|
+
responseNote String? // Optional note from provider
|
|
2613
|
+
convertedToAddonId String? // If converted to paid add-on
|
|
2614
|
+
voteCount Int @default(0) // Net votes (upvotes - downvotes)
|
|
2615
|
+
upvoteCount Int @default(0)
|
|
2616
|
+
downvoteCount Int @default(0)
|
|
2617
|
+
isActuallyIncluded Boolean @default(false) // Provider confirmed it IS included
|
|
2618
|
+
createdAt DateTime @default(now())
|
|
2619
|
+
updatedAt DateTime @updatedAt
|
|
2620
|
+
|
|
2621
|
+
service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
|
|
2622
|
+
suggestedBy User? @relation("SuggestedIncludes", fields: [suggestedByUserId], references: [id], onDelete: SetNull)
|
|
2623
|
+
convertedToAddon ServiceAddon? @relation("IncludeConvertedToAddon", fields: [convertedToAddonId], references: [id], onDelete: SetNull)
|
|
2624
|
+
votes ServiceIncludeVote[]
|
|
2625
|
+
|
|
2626
|
+
@@unique([serviceId, name]) // Prevent duplicate suggestions for same service
|
|
2627
|
+
@@index([serviceId])
|
|
2628
|
+
@@index([status])
|
|
2629
|
+
@@index([voteCount])
|
|
2630
|
+
@@index([createdAt])
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
model ServiceIncludeVote {
|
|
2634
|
+
id String @id @default(cuid())
|
|
2635
|
+
serviceIncludeId String
|
|
2636
|
+
userId String
|
|
2637
|
+
voteType VoteType // Upvote or Downvote
|
|
2638
|
+
createdAt DateTime @default(now())
|
|
2639
|
+
updatedAt DateTime @updatedAt
|
|
2640
|
+
|
|
2641
|
+
serviceInclude ServiceInclude @relation(fields: [serviceIncludeId], references: [id], onDelete: Cascade)
|
|
2642
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
2643
|
+
|
|
2644
|
+
@@unique([serviceIncludeId, userId]) // One vote per user per include
|
|
2645
|
+
@@index([serviceIncludeId])
|
|
2646
|
+
@@index([userId])
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
model ServiceAddonRequest {
|
|
2650
|
+
id String @id @default(cuid())
|
|
2651
|
+
serviceId String
|
|
2652
|
+
userId String? // null if anonymous
|
|
2653
|
+
name String // e.g., "Specialty Lighting Package"
|
|
2654
|
+
description String? // Optional details
|
|
2655
|
+
status ServiceAddonRequestStatus @default(Pending)
|
|
2656
|
+
providerNote String? // Provider's response/notes
|
|
2657
|
+
notifyOnAvailable Boolean @default(false) // Customer wants notification
|
|
2658
|
+
convertedToAddonId String? // Links to actual ServiceAddon if created
|
|
2659
|
+
requestCount Int @default(1) // How many customers requested this
|
|
2660
|
+
createdAt DateTime @default(now())
|
|
2661
|
+
updatedAt DateTime @updatedAt
|
|
2662
|
+
|
|
2663
|
+
service Service @relation(fields: [serviceId], references: [id], onDelete: Cascade)
|
|
2664
|
+
user User? @relation("RequestedAddons", fields: [userId], references: [id], onDelete: SetNull)
|
|
2665
|
+
convertedToAddon ServiceAddon? @relation("RequestConvertedToAddon", fields: [convertedToAddonId], references: [id], onDelete: SetNull)
|
|
2666
|
+
|
|
2667
|
+
@@index([serviceId])
|
|
2668
|
+
@@index([status])
|
|
2669
|
+
@@index([userId])
|
|
2670
|
+
@@index([requestCount])
|
|
2671
|
+
@@index([createdAt])
|
|
2353
2672
|
}
|
|
2354
2673
|
|
|
2355
2674
|
model ServicePackage {
|
|
@@ -3410,7 +3729,7 @@ enum UserIntent {
|
|
|
3410
3729
|
}
|
|
3411
3730
|
|
|
3412
3731
|
enum BashStatus {
|
|
3413
|
-
Idea
|
|
3732
|
+
Idea // Pre-event idea gauging interest
|
|
3414
3733
|
Draft
|
|
3415
3734
|
Pending
|
|
3416
3735
|
PreSale
|
|
@@ -3729,11 +4048,6 @@ enum AudioVisualSupportSubType {
|
|
|
3729
4048
|
ProjectorSetup
|
|
3730
4049
|
}
|
|
3731
4050
|
|
|
3732
|
-
enum HostingSupportSubType {
|
|
3733
|
-
Emcee
|
|
3734
|
-
Greeter
|
|
3735
|
-
}
|
|
3736
|
-
|
|
3737
4051
|
enum PromotionAndMarketingSubType {
|
|
3738
4052
|
Influencer
|
|
3739
4053
|
Promoter
|
|
@@ -3744,6 +4058,10 @@ enum StaffingSubType {
|
|
|
3744
4058
|
CrewHand
|
|
3745
4059
|
ParkingManagement
|
|
3746
4060
|
GuestRegistration
|
|
4061
|
+
Greeter
|
|
4062
|
+
Ushers
|
|
4063
|
+
CoatCheck
|
|
4064
|
+
DoorAttendant
|
|
3747
4065
|
Security
|
|
3748
4066
|
}
|
|
3749
4067
|
|
|
@@ -4770,21 +5088,14 @@ enum OrganizationType {
|
|
|
4770
5088
|
GreekLife
|
|
4771
5089
|
SocialClub
|
|
4772
5090
|
Nonprofit
|
|
4773
|
-
|
|
4774
|
-
|
|
5091
|
+
Other
|
|
5092
|
+
Professional
|
|
5093
|
+
RecordLabel
|
|
5094
|
+
School
|
|
5095
|
+
StudentClub
|
|
4775
5096
|
Sports
|
|
4776
|
-
Government
|
|
4777
|
-
Cultural
|
|
4778
|
-
Lifestyle
|
|
4779
|
-
Political
|
|
4780
|
-
Tourism
|
|
4781
5097
|
Youth
|
|
4782
|
-
|
|
4783
|
-
Tradeshow
|
|
4784
|
-
Conference
|
|
4785
|
-
FoodAndBeverage
|
|
4786
|
-
TechAndStartups
|
|
4787
|
-
Other
|
|
5098
|
+
Cultural
|
|
4788
5099
|
}
|
|
4789
5100
|
|
|
4790
5101
|
enum YearsOfExperience {
|
|
@@ -4805,6 +5116,34 @@ enum ServiceAddonStatus {
|
|
|
4805
5116
|
Disabled
|
|
4806
5117
|
}
|
|
4807
5118
|
|
|
5119
|
+
enum ServiceIncludeStatus {
|
|
5120
|
+
Pending // Customer suggested, awaiting provider review
|
|
5121
|
+
Approved // Provider confirmed it IS included
|
|
5122
|
+
Declined // Provider says not possible/won't include
|
|
5123
|
+
Duplicate // Same as another suggestion
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
enum ServiceIncludeResponse {
|
|
5127
|
+
NotPossible // Can't offer this
|
|
5128
|
+
Added // Now included in base package
|
|
5129
|
+
AlreadyIncluded // Was already included
|
|
5130
|
+
AvailableAsAddOn // Can offer but as paid add-on
|
|
5131
|
+
UnderConsideration // Thinking about it
|
|
5132
|
+
}
|
|
5133
|
+
|
|
5134
|
+
enum VoteType {
|
|
5135
|
+
Upvote
|
|
5136
|
+
Downvote
|
|
5137
|
+
}
|
|
5138
|
+
|
|
5139
|
+
enum ServiceAddonRequestStatus {
|
|
5140
|
+
Pending // New request
|
|
5141
|
+
Acknowledged // Provider saw it
|
|
5142
|
+
Added // Provider created the add-on
|
|
5143
|
+
Declined // Provider won't offer this
|
|
5144
|
+
Duplicate // Same as another request
|
|
5145
|
+
}
|
|
5146
|
+
|
|
4808
5147
|
enum ServiceBookingFeeType {
|
|
4809
5148
|
CleaningFee
|
|
4810
5149
|
ProcessingFee
|