@@ -58,6 +58,17 @@ enum InviteReferralStatus {
|
||||
QUALIFIED
|
||||
}
|
||||
|
||||
enum MembershipContractStatus {
|
||||
PENDING_SIGN
|
||||
SIGNED
|
||||
VOIDED
|
||||
}
|
||||
|
||||
enum MembershipContractSource {
|
||||
PURCHASE
|
||||
LEGACY
|
||||
}
|
||||
|
||||
// ===== Models =====
|
||||
|
||||
model User {
|
||||
@@ -95,6 +106,7 @@ model User {
|
||||
trainingPlans TrainingPlan[]
|
||||
reassessmentTodos ReassessmentTodo[]
|
||||
growthShareCards GrowthShareCard[]
|
||||
membershipContracts MembershipContract[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@@ -163,6 +175,7 @@ model Membership {
|
||||
bookings Booking[]
|
||||
orders Order[]
|
||||
inviteRewardGrants InviteRewardGrant[]
|
||||
contracts MembershipContract[]
|
||||
|
||||
@@index([userId])
|
||||
@@index([userId, cardTypeId])
|
||||
@@ -273,6 +286,7 @@ model Order {
|
||||
status OrderStatus @default(PENDING)
|
||||
wxTransactionId String? @map("wx_transaction_id")
|
||||
paidAt DateTime? @map("paid_at")
|
||||
contractAcceptedAt DateTime? @map("contract_accepted_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@ -280,6 +294,7 @@ model Order {
|
||||
cardType CardType @relation(fields: [cardTypeId], references: [id])
|
||||
membership Membership? @relation(fields: [membershipId], references: [id])
|
||||
inviteReferrals InviteReferral[]
|
||||
contract MembershipContract?
|
||||
|
||||
@@index([userId])
|
||||
@@index([status])
|
||||
@@ -287,6 +302,84 @@ model Order {
|
||||
@@map("orders")
|
||||
}
|
||||
|
||||
// Single-row party B profile; signed contracts keep their own snapshot.
|
||||
model ContractParty {
|
||||
id String @id @default(uuid())
|
||||
businessName String @default("") @map("business_name") @db.VarChar(100)
|
||||
brandName String @default("") @map("brand_name") @db.VarChar(60)
|
||||
creditCode String @default("") @map("credit_code") @db.VarChar(18)
|
||||
operatorName String @default("") @map("operator_name") @db.VarChar(30)
|
||||
phone String @default("") @db.VarChar(20)
|
||||
address String @default("") @db.VarChar(200)
|
||||
premisesType String @default("LEASED") @map("premises_type") @db.VarChar(10)
|
||||
leaseEndDate DateTime? @map("lease_end_date") @db.Date
|
||||
standardLessonPrice Int @default(0) @map("standard_lesson_price")
|
||||
signatureImage Bytes? @map("signature_image") @db.MediumBlob
|
||||
signatureSha256 String? @map("signature_sha256") @db.VarChar(64)
|
||||
signatureUpdatedAt DateTime? @map("signature_updated_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@map("contract_parties")
|
||||
}
|
||||
|
||||
// terms is frozen at issuance; document, hashes and signatures are frozen at signing.
|
||||
model MembershipContract {
|
||||
id String @id @default(uuid())
|
||||
contractNo String @unique @map("contract_no") @db.VarChar(32)
|
||||
userId String @map("user_id")
|
||||
membershipId String @map("membership_id")
|
||||
orderId String? @unique @map("order_id")
|
||||
source MembershipContractSource
|
||||
status MembershipContractStatus @default(PENDING_SIGN)
|
||||
requireBeforeBooking Boolean @default(false) @map("require_before_booking")
|
||||
templateVersion String @map("template_version") @db.VarChar(32)
|
||||
terms Json
|
||||
partyName String? @map("party_name") @db.VarChar(30)
|
||||
partyPhone String? @map("party_phone") @db.VarChar(20)
|
||||
document Json?
|
||||
contentSha256 String? @map("content_sha256") @db.VarChar(64)
|
||||
signatureImage Bytes? @map("signature_image") @db.MediumBlob
|
||||
signatureSha256 String? @map("signature_sha256") @db.VarChar(64)
|
||||
partyBSignatureImage Bytes? @map("party_b_signature_image") @db.MediumBlob
|
||||
partyBName String? @map("party_b_name") @db.VarChar(100)
|
||||
signedAt DateTime? @map("signed_at")
|
||||
signerIp String? @map("signer_ip") @db.VarChar(64)
|
||||
signerUserAgent String? @map("signer_user_agent") @db.VarChar(300)
|
||||
signerDevice String? @map("signer_device") @db.VarChar(200)
|
||||
voidedAt DateTime? @map("voided_at")
|
||||
voidedBy String? @map("voided_by")
|
||||
voidReason String? @map("void_reason") @db.VarChar(200)
|
||||
createdBy String? @map("created_by")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
membership Membership @relation(fields: [membershipId], references: [id])
|
||||
order Order? @relation(fields: [orderId], references: [id])
|
||||
events ContractEvent[]
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([membershipId, status])
|
||||
@@index([status, createdAt])
|
||||
@@map("membership_contracts")
|
||||
}
|
||||
|
||||
model ContractEvent {
|
||||
id String @id @default(uuid())
|
||||
contractId String @map("contract_id")
|
||||
action String @db.VarChar(20)
|
||||
actorId String? @map("actor_id")
|
||||
ip String? @db.VarChar(64)
|
||||
userAgent String? @map("user_agent") @db.VarChar(300)
|
||||
detail Json?
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
contract MembershipContract @relation(fields: [contractId], references: [id])
|
||||
|
||||
@@index([contractId, createdAt])
|
||||
@@map("contract_events")
|
||||
}
|
||||
|
||||
model InviteReferral {
|
||||
id String @id @default(uuid())
|
||||
inviterId String @map("inviter_id")
|
||||
|
||||
Reference in New Issue
Block a user