Files
dukang/server/dukang-api/prisma/schema.prisma
T

1603 lines
68 KiB
Plaintext

// 杜康好客 · V3.1 数据模型(由 init_v3.sql 生成)
// 激活方式:确认后替换 schema.prisma,执行 prisma migrate / db push + seed-v31
// 旧版备份:schema.legacy-v21.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
// ─── 枚举(与 init_v3.sql COMMENT 对齐)────────────────
enum ClientApp {
USER_MINI
USER_H5
PARTNER_MINI
PARTNER_H5
HQ_MINI
HQ_WEB
SHOP_H5
}
enum ResourceOwnerType {
PRODUCT
STORE
PARTNER
USER
ORDER
PROMO
HQ
}
enum ResourceBizType {
COVER
ENV
CONTRACT
CAROUSEL
DETAIL
AVATAR
QRCODE
SIGN_PHOTO
VIDEO
REDEEM_PENDING_PHOTO
}
enum RedeemPendingStatus {
PENDING
COMPLETED
REJECTED
}
enum ResourceMediaType {
IMAGE
VIDEO
FILE
}
enum ResourceStatus {
ACTIVE
DELETED
}
enum EventType {
STORE_AUDIT
ORDER_STATUS
BENEFIT_LEDGER
HQ_OPERATION
PROMO_TOUCH
TICKET_COLLAB
}
enum ActorType {
USER
STORE
PARTNER
HQ
SYSTEM
}
enum TicketType {
REFUND
RESHIPMENT
ALERT
DAMAGE_RETURN
RETURN_REFUND
}
enum SupportTicketType {
BUG
SUGGESTION
OTHER
}
enum SupportTicketStatus {
PENDING_REVIEW
REJECTED
DEVELOPING
TESTING
PASSED
}
enum InvoiceTitleType {
PERSONAL
ENTERPRISE
}
enum InvoiceKind {
NORMAL
SPECIAL
}
enum InvoiceStatus {
PENDING
ISSUED
REJECTED
}
enum AromaType {
QINGXIANG
JIANGXIANG
NONGXIANG
}
enum ProductStatus {
DRAFT
ON_SALE
OFF_SALE
}
enum DetailTemplateStatus {
ACTIVE
DISABLED
}
enum PromoCodeStatus {
ACTIVE
DISABLED
}
enum PromoCodeScene {
ONLINE_LINK
OFFLINE_PICKUP
PARTNER_CHANNEL
EVENT
OTHER
}
enum CityStatus {
PENDING
ACTIVE
PAUSED
}
enum CityPartnerScopeType {
CITY_WIDE
DISTRICT
}
enum CityPartnerStatus {
ACTIVE
PAUSED
}
enum WarehouseManagerType {
HQ
PARTNER
}
enum WarehouseStatus {
ACTIVE
PAUSED
}
enum FulfillmentProviderType {
API
MANUAL
}
enum FulfillmentProviderStatus {
ACTIVE
DISABLED
}
enum WarehouseFulfillmentMode {
API_AUTO
MANUAL
}
enum PartnerStaffRole {
PARTNER
INTERNAL
PROMOTER
}
enum StoreStaffRole {
MANAGER
CASHIER
}
enum AccountStatus {
ACTIVE
DISABLED
}
enum HqAdminRole {
SUPER_ADMIN
OPS
FINANCE
CUSTOMER_SERVICE
}
enum PartnerBillStatus {
PENDING_REVIEW
AWAITING_CONFIRM
UNPAID
PAID
REJECTED
}
// 酒厂/门店对账单打款状态
enum FinancePayStatus {
UNPAID
PAID
}
// 物流承运商结算方式:前期充值,后期挂账月结
enum LogisticsSettlementMethod {
PREPAID
MONTHLY_CREDIT
}
enum LogisticsPrepaidLedgerType {
RECHARGE
DEDUCT
ADJUST
}
enum StoreStatus {
OPEN
PAUSED
CLOSED
}
enum StoreAuditStatus {
PENDING
APPROVED
REJECTED
}
enum UserSourceType {
ORGANIC
PROMO_CODE
SHARE_LINK
FRIEND_REFERRAL
OFFLINE_EVENT
PARTNER_PROXY
OTHER
}
enum OrderType {
NORMAL
RESHIPMENT
PROXY
}
enum OrderStatus {
PENDING_PAY
PENDING_SHIP
OUT_WAREHOUSE
SHIPPING
PENDING_RECEIVE
COMPLETED
CANCELLED
REFUNDING
REFUNDED
}
enum PayStatus {
UNPAID
PAYING
PAID
REFUNDING
REFUNDED
}
enum DeliveryType {
LOCAL
CROSS_CITY
ON_SITE_PICKUP
}
enum FreightPayType {
FREE
COD
}
enum DeliveryProvider {
XFX
LOGISTICS
MANUAL
}
enum BenefitCouponStatus {
ACTIVE
USED_UP
VOID
}
enum StorePayoutStatus {
PENDING
PAID
}
enum StoreWithdrawStatus {
PENDING_REVIEW
REJECTED
PAID
}
enum ThirdPartyProvider {
WECHAT_PAY
WECHAT_REFUND
WECHAT_AUTH
WECHAT_MAP
ALIYUN_OSS
XFX
SMS
LOGISTICS
}
enum ThirdPartyLogStatus {
PENDING
SUCCESS
FAILED
}
enum BenefitLedgerType {
GRANT
REDEEM
REFUND_VOID
ADJUST
}
// ─── COMMON ───────────────────────────────────────────
model SystemVersion {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
gitTag String? @map("git_tag") @db.VarChar(128)
commitId String @map("commit_id") @db.VarChar(64)
commitMessage String @map("commit_message") @db.VarChar(512)
branch String? @db.VarChar(64)
deployedBy String? @map("deployed_by") @db.VarChar(32)
deployedAt DateTime @default(now()) @map("deployed_at") @db.DateTime(3)
@@index([deployedAt])
@@map("system_version")
}
model SystemConfig {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
configKey String @unique @map("config_key") @db.VarChar(128)
value String @db.Text
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
@@map("system_config")
}
/// 企业微信智能机器人(HQ 可创建多实例,长连接)
model WecomBot {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
name String @db.VarChar(64)
role String @db.VarChar(32)
botId String @unique @map("bot_id") @db.VarChar(128)
secret String @db.VarChar(256)
avatarUrl String? @map("avatar_url") @db.VarChar(512)
welcome String? @db.VarChar(1024)
/// JSON 字符串数组,如 ["ticket.create","user.view_sms"]
permissions String @db.Text
/// 未匹配指令时是否调用语言模型
aiEnabled Boolean @default(false) @map("ai_enabled")
llmConfigId BigInt? @map("llm_config_id") @db.UnsignedBigInt
knowledgeBaseId BigInt? @map("knowledge_base_id") @db.UnsignedBigInt
enabled Boolean @default(true)
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
llmConfig LlmApiConfig? @relation(fields: [llmConfigId], references: [id], onDelete: SetNull)
knowledgeBase KnowledgeBase? @relation(fields: [knowledgeBaseId], references: [id], onDelete: SetNull)
@@index([enabled, sortOrder])
@@index([llmConfigId])
@@index([knowledgeBaseId])
@@map("wecom_bot")
}
/// HQ 语言模型 API 配置(非超管仅可见/可开关自己创建的)
model LlmApiConfig {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
name String @db.VarChar(64)
provider String @db.VarChar(32)
baseUrl String @map("base_url") @db.VarChar(512)
apiKey String @map("api_key") @db.VarChar(512)
modelName String @map("model_name") @db.VarChar(128)
temperature Decimal? @db.Decimal(3, 2)
maxTokens Int? @map("max_tokens")
systemPrompt String? @map("system_prompt") @db.Text
enabled Boolean @default(true)
createdByHqAccountId BigInt @map("created_by_hq_account_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
wecomBots WecomBot[]
@@index([createdByHqAccountId, enabled])
@@map("llm_api_config")
}
/// HQ 知识库
model KnowledgeBase {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
name String @db.VarChar(128)
description String? @db.VarChar(512)
enabled Boolean @default(true)
createdByHqAccountId BigInt @map("created_by_hq_account_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
documents KnowledgeDocument[]
wecomBots WecomBot[]
@@index([createdByHqAccountId, enabled])
@@map("knowledge_base")
}
model KnowledgeDocument {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
knowledgeBaseId BigInt @map("knowledge_base_id") @db.UnsignedBigInt
title String @db.VarChar(256)
fileName String? @map("file_name") @db.VarChar(256)
fileUrl String? @map("file_url") @db.VarChar(1024)
mimeType String? @map("mime_type") @db.VarChar(128)
sizeBytes Int? @map("size_bytes")
contentText String? @map("content_text") @db.LongText
status String @default("READY") @db.VarChar(16)
errorMessage String? @map("error_message") @db.VarChar(512)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
@@index([knowledgeBaseId])
@@map("knowledge_document")
}
model MockSmsCode {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
phone String @db.VarChar(20)
scene String @db.VarChar(64)
code String @db.VarChar(8)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([createdAt])
@@map("mock_sms_code")
}
model CommonWxAppConfig {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
clientApp ClientApp @unique @map("client_app")
appId String @map("app_id") @db.VarChar(64)
appSecret String @map("app_secret") @db.VarChar(128)
mchId String? @map("mch_id") @db.VarChar(32)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
@@map("common_wx_app_config")
}
model CommonResource {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
ownerType ResourceOwnerType @map("owner_type")
ownerId BigInt @map("owner_id") @db.UnsignedBigInt
bizType ResourceBizType @map("biz_type")
mediaType ResourceMediaType @default(IMAGE) @map("media_type")
ossBucket String @map("oss_bucket") @db.VarChar(64)
ossKey String @map("oss_key") @db.VarChar(256)
url String @db.VarChar(512)
fileName String? @map("file_name") @db.VarChar(128)
fileSize BigInt? @map("file_size") @db.UnsignedBigInt
mimeType String? @map("mime_type") @db.VarChar(64)
sortOrder Int @default(0) @map("sort_order")
status ResourceStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
productCovers CommonProductItem[] @relation("ProductCover")
promoQrcodes CommonPromoCode[] @relation("PromoQrcode")
userAvatars User[] @relation("UserAvatar")
storeCovers Store[] @relation("StoreCover")
orderImages Order[] @relation("OrderProductImage")
deliveryPhotos OrderDelivery[] @relation("DeliverySignPhoto")
redeemPendingPhotos RedeemPendingRecord[] @relation("RedeemPendingPhoto")
@@index([ownerType, ownerId, bizType])
@@index([status])
@@map("common_resource")
}
model CommonEvent {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
eventType EventType @map("event_type")
refType String @map("ref_type") @db.VarChar(32)
refId BigInt @map("ref_id") @db.UnsignedBigInt
actorType ActorType? @map("actor_type")
actorId BigInt? @map("actor_id") @db.UnsignedBigInt
status String? @db.VarChar(32)
param1 String? @db.VarChar(128)
param1Desc String? @map("param1_desc") @db.VarChar(64)
param2 String? @db.VarChar(128)
param2Desc String? @map("param2_desc") @db.VarChar(64)
param3 String? @db.VarChar(128)
param3Desc String? @map("param3_desc") @db.VarChar(64)
amount1 Decimal? @db.Decimal(10, 2)
amount2 Decimal? @db.Decimal(10, 2)
remark String? @db.VarChar(512)
extraJson Json? @map("extra_json")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([refType, refId, eventType])
@@index([eventType, createdAt])
@@index([actorType, actorId])
@@map("common_event")
}
model CommonTicket {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
ticketNo String @unique @map("ticket_no") @db.VarChar(32)
ticketType TicketType @map("ticket_type")
status String @default("PENDING") @db.VarChar(32)
refType String @map("ref_type") @db.VarChar(32)
refId BigInt @map("ref_id") @db.UnsignedBigInt
operatorType ActorType? @map("operator_type")
operatorId BigInt? @map("operator_id") @db.UnsignedBigInt
param1 String? @db.VarChar(128)
param1Desc String? @map("param1_desc") @db.VarChar(64)
param2 String? @db.VarChar(128)
param2Desc String? @map("param2_desc") @db.VarChar(64)
param3 String? @db.VarChar(128)
param3Desc String? @map("param3_desc") @db.VarChar(64)
remark String? @db.VarChar(512)
extraJson Json? @map("extra_json")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
completedAt DateTime? @map("completed_at") @db.DateTime(3)
@@index([refType, refId])
@@index([ticketType, status])
@@map("common_ticket")
}
/// HQ 内部技术支持工单(BUG / 建议 / 其他)
model CommonSupportTicket {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
ticketNo String @unique @map("ticket_no") @db.VarChar(32)
ticketType SupportTicketType @map("ticket_type")
status SupportTicketStatus @default(PENDING_REVIEW)
title String @db.VarChar(128)
content String? @db.Text
rejectReason String? @map("reject_reason") @db.VarChar(512)
creatorId BigInt @map("creator_id") @db.UnsignedBigInt
creatorName String @map("creator_name") @db.VarChar(64)
reviewerId BigInt? @map("reviewer_id") @db.UnsignedBigInt
reviewerName String? @map("reviewer_name") @db.VarChar(64)
reviewedAt DateTime? @map("reviewed_at") @db.DateTime(3)
remark String? @db.VarChar(512)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
completedAt DateTime? @map("completed_at") @db.DateTime(3)
@@index([status, createdAt])
@@index([ticketType, status])
@@index([creatorId])
@@map("common_support_ticket")
}
model CommonProductItem {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
skuCode String @unique @map("sku_code") @db.VarChar(32)
barcode69 String @unique @map("barcode_69") @db.VarChar(32)
name String @db.VarChar(128)
subtitle String? @db.VarChar(256)
aromaType AromaType @map("aroma_type")
spec String @db.VarChar(128)
price Decimal @db.Decimal(10, 2)
benefitAmount Decimal? @map("benefit_amount") @db.Decimal(10, 2)
status ProductStatus @default(DRAFT)
sortOrder Int @default(0) @map("sort_order")
allowOnSitePickup Boolean @default(false) @map("allow_on_site_pickup")
/// 允许配送到址(同城线上购买)
allowOnlinePurchase Boolean @default(true) @map("allow_online_purchase")
/// 允许跨城配送(依附线上购买)
allowCrossCityDelivery Boolean @default(true) @map("allow_cross_city_delivery")
/// Online test: only listed phones can see/buy when enabled
visibilityWhitelistEnabled Boolean @default(false) @map("visibility_whitelist_enabled")
coverResourceId BigInt? @map("cover_resource_id") @db.UnsignedBigInt
detailContent Json? @map("detail_content")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
coverResource CommonResource? @relation("ProductCover", fields: [coverResourceId], references: [id], onDelete: SetNull)
orders Order[]
visibilityPhones CommonProductVisibilityPhone[]
@@index([status, aromaType])
@@map("common_product_item")
}
/// Product visibility whitelist phones (match by bound phone)
model CommonProductVisibilityPhone {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
productId BigInt @map("product_id") @db.UnsignedBigInt
phone String @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
product CommonProductItem @relation(fields: [productId], references: [id], onDelete: Cascade)
@@unique([productId, phone])
@@index([phone])
@@map("common_product_visibility_phone")
}
model CommonProductDetailTemplate {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
code String @unique @db.VarChar(32)
name String @db.VarChar(64)
description String? @db.VarChar(256)
aromaType AromaType? @map("aroma_type")
storyTitle String? @map("story_title") @db.VarChar(128)
storyText String? @map("story_text") @db.Text
features Json?
detailImageUrls Json? @map("detail_image_urls")
suggestedDetailImageCount Int @default(1) @map("suggested_detail_image_count")
sortOrder Int @default(0) @map("sort_order")
status DetailTemplateStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
@@index([status, sortOrder])
@@map("common_product_detail_template")
}
model CommonStoreCategory {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
code String @unique @db.VarChar(32)
name String @db.VarChar(64)
sort Int @default(0)
parentId BigInt? @map("parent_id") @db.UnsignedBigInt
status String @default("ACTIVE") @db.VarChar(16)
parent CommonStoreCategory? @relation("StoreCategoryTree", fields: [parentId], references: [id], onDelete: Restrict)
children CommonStoreCategory[] @relation("StoreCategoryTree")
stores Store[]
@@index([parentId, sort])
@@index([status])
@@map("common_store_category")
}
model CommonPromoCode {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
code String @unique @db.VarChar(32)
name String @db.VarChar(128)
scene PromoCodeScene @default(ONLINE_LINK)
qrcodeId String @unique @map("qrcode_id") @db.VarChar(64)
status PromoCodeStatus @default(ACTIVE)
ownerUserId BigInt? @map("owner_user_id") @db.UnsignedBigInt
remark String? @db.VarChar(256)
qrcodeResourceId BigInt? @map("qrcode_resource_id") @db.UnsignedBigInt
scanCount Int @default(0) @map("scan_count")
orderCount Int @default(0) @map("order_count")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
ownerUser User? @relation("PromoOwnerUser", fields: [ownerUserId], references: [id], onDelete: SetNull)
qrcodeResource CommonResource? @relation("PromoQrcode", fields: [qrcodeResourceId], references: [id], onDelete: SetNull)
attributions UserPromoAttribution[]
orders Order[]
@@index([ownerUserId])
@@index([scene, status])
@@map("common_promo_code")
}
model CommonCity {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
code String @unique @db.VarChar(16)
name String @db.VarChar(64)
province String @db.VarChar(32)
status CityStatus @default(PENDING)
localMinQty Int @default(2) @map("local_min_qty")
crossMinQty Int @default(6) @map("cross_min_qty")
maxPartnerCommissionRate Decimal @default(0.05) @map("max_partner_commission_rate") @db.Decimal(5, 4)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
warehouses CityWarehouse[]
partnerAccounts PartnerAccount[] @relation("PartnerAccountCity")
stores Store[]
orders Order[]
@@map("common_city")
}
model FulfillmentProvider {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
code String @unique @db.VarChar(32)
name String @db.VarChar(128)
type FulfillmentProviderType
status FulfillmentProviderStatus @default(ACTIVE)
configJson String? @map("config_json") @db.Text
capabilitiesJson String? @map("capabilities_json") @db.Text
bankAccountName String? @map("bank_account_name") @db.VarChar(64)
bankName String? @map("bank_name") @db.VarChar(64)
bankBranch String? @map("bank_branch") @db.VarChar(128)
bankAccountNo String? @map("bank_account_no") @db.VarChar(64)
settlementMethod LogisticsSettlementMethod @default(PREPAID) @map("settlement_method")
pricingRulesJson String? @map("pricing_rules_json") @db.Text
prepaidBalance Decimal @default(0) @map("prepaid_balance") @db.Decimal(12, 2)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
warehouses CityWarehouse[]
deliveries OrderDelivery[]
logisticsBills LogisticsBill[]
prepaidLedgers LogisticsPrepaidLedger[]
@@map("common_fulfillment_provider")
}
// 物流对账月账单(按承运商汇总)
model LogisticsBill {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
billNo String @unique @map("bill_no") @db.VarChar(32)
fulfillmentProviderId BigInt @map("fulfillment_provider_id") @db.UnsignedBigInt
periodStart DateTime @map("period_start") @db.DateTime(3)
periodEnd DateTime @map("period_end") @db.DateTime(3)
orderCount Int @default(0) @map("order_count")
bottleCount Int @default(0) @map("bottle_count")
logisticsAmount Decimal @map("logistics_amount") @db.Decimal(12, 2)
settlementMethod LogisticsSettlementMethod @map("settlement_method")
pricingSnapshotJson String? @map("pricing_snapshot_json") @db.Text
status FinancePayStatus @default(UNPAID)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
fulfillmentProvider FulfillmentProvider @relation(fields: [fulfillmentProviderId], references: [id], onDelete: Restrict)
items LogisticsBillItem[]
prepaidLedgers LogisticsPrepaidLedger[]
@@unique([fulfillmentProviderId, periodStart])
@@index([status, periodStart])
@@map("logistics_bill")
}
model LogisticsBillItem {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
logisticsBillId BigInt @map("logistics_bill_id") @db.UnsignedBigInt
orderId BigInt @map("order_id") @db.UnsignedBigInt
orderNo String @map("order_no") @db.VarChar(32)
quantity Int
logisticsAmount Decimal @map("logistics_amount") @db.Decimal(10, 2)
shippedAt DateTime @map("shipped_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
logisticsBill LogisticsBill @relation(fields: [logisticsBillId], references: [id], onDelete: Cascade)
@@unique([logisticsBillId, orderId])
@@index([logisticsBillId])
@@map("logistics_bill_item")
}
model LogisticsPrepaidLedger {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
fulfillmentProviderId BigInt @map("fulfillment_provider_id") @db.UnsignedBigInt
type LogisticsPrepaidLedgerType
amount Decimal @db.Decimal(12, 2)
balanceAfter Decimal @map("balance_after") @db.Decimal(12, 2)
logisticsBillId BigInt? @map("logistics_bill_id") @db.UnsignedBigInt
remark String? @db.VarChar(256)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
fulfillmentProvider FulfillmentProvider @relation(fields: [fulfillmentProviderId], references: [id], onDelete: Restrict)
logisticsBill LogisticsBill? @relation(fields: [logisticsBillId], references: [id], onDelete: SetNull)
@@index([fulfillmentProviderId, createdAt])
@@map("logistics_prepaid_ledger")
}
model CityWarehouse {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
cityId BigInt @map("city_id") @db.UnsignedBigInt
name String @db.VarChar(128)
address String @db.VarChar(256)
contactName String @map("contact_name") @db.VarChar(64)
contactPhone String @map("contact_phone") @db.VarChar(20)
managerType WarehouseManagerType @map("manager_type")
partnerAccountId BigInt? @map("partner_account_id") @db.UnsignedBigInt
status WarehouseStatus @default(ACTIVE)
fulfillmentMode WarehouseFulfillmentMode @default(MANUAL) @map("fulfillment_mode")
fulfillmentProviderId BigInt? @map("fulfillment_provider_id") @db.UnsignedBigInt
manualCarrierLabel String? @map("manual_carrier_label") @db.VarChar(64)
manualQueryUrlTemplate String? @map("manual_query_url_template") @db.VarChar(512)
lng Decimal? @db.Decimal(10, 7)
lat Decimal? @db.Decimal(10, 7)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
city CommonCity @relation(fields: [cityId], references: [id], onDelete: Cascade)
partnerAccount PartnerAccount? @relation("WarehouseManager", fields: [partnerAccountId], references: [id], onDelete: SetNull)
managedBy PartnerAccount? @relation("ManagedWarehouse")
fulfillmentProvider FulfillmentProvider? @relation(fields: [fulfillmentProviderId], references: [id], onDelete: SetNull)
fulfilledOrders Order[] @relation("OrderFulfillmentWarehouse")
@@index([cityId])
@@index([partnerAccountId])
@@index([fulfillmentProviderId])
@@map("common_city_warehouse")
}
// ─── PARTNER ──────────────────────────────────────────
model PartnerAccount {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
phone String @unique @db.VarChar(20)
name String @db.VarChar(64)
wxOpenId String? @map("wx_open_id") @db.VarChar(64)
wxUnionId String? @map("wx_union_id") @db.VarChar(64)
wxNickname String? @map("wx_nickname") @db.VarChar(64)
wxAvatarUrl String? @map("wx_avatar_url") @db.VarChar(512)
isPrimary Int @default(0) @map("is_primary") @db.TinyInt
parentAccountId BigInt? @map("parent_account_id") @db.UnsignedBigInt
staffRole PartnerStaffRole? @map("staff_role")
permissions Json?
status AccountStatus @default(ACTIVE)
lastLoginAt DateTime? @map("last_login_at") @db.DateTime(3)
cityId BigInt? @map("city_id") @db.UnsignedBigInt
scopeType CityPartnerScopeType? @map("scope_type")
districtCodes Json? @map("district_codes")
orderCommissionRate Decimal? @default(0) @map("order_commission_rate") @db.Decimal(5, 4)
redeemCommissionRate Decimal? @default(0.03) @map("redeem_commission_rate") @db.Decimal(5, 4)
bindingStatus CityPartnerStatus? @default(ACTIVE) @map("binding_status")
companyName String? @map("company_name") @db.VarChar(128)
address String? @db.VarChar(256)
contactPhone String? @map("contact_phone") @db.VarChar(20)
contractNo String? @map("contract_no") @db.VarChar(64)
contractSignedAt DateTime? @map("contract_signed_at") @db.DateTime(3)
contractExpireAt DateTime? @map("contract_expire_at") @db.DateTime(3)
bankAccountName String? @map("bank_account_name") @db.VarChar(64)
bankAccountNo String? @map("bank_account_no") @db.VarChar(32)
bankBranch String? @map("bank_branch") @db.VarChar(128)
weeklyStoreTarget Int? @default(20) @map("weekly_store_target")
managedWarehouseId BigInt? @unique @map("managed_warehouse_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
city CommonCity? @relation("PartnerAccountCity", fields: [cityId], references: [id], onDelete: Restrict)
managedWarehouse CityWarehouse? @relation("ManagedWarehouse", fields: [managedWarehouseId], references: [id], onDelete: SetNull)
managedWarehouses CityWarehouse[] @relation("WarehouseManager")
parent PartnerAccount? @relation("PartnerAccountHierarchy", fields: [parentAccountId], references: [id], onDelete: SetNull)
children PartnerAccount[] @relation("PartnerAccountHierarchy")
stores Store[]
bills PartnerBill[]
@@index([cityId, scopeType])
@@index([cityId, isPrimary])
@@index([parentAccountId])
@@index([wxOpenId])
@@index([contactPhone])
@@map("partner_account")
}
model PartnerBill {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
billNo String @unique @map("bill_no") @db.VarChar(32)
partnerAccountId BigInt @map("partner_account_id") @db.UnsignedBigInt
periodStart DateTime @map("period_start") @db.DateTime(3)
periodEnd DateTime @map("period_end") @db.DateTime(3)
orderCommission Decimal @default(0) @map("order_commission") @db.Decimal(10, 2)
redeemCommission Decimal @default(0) @map("redeem_commission") @db.Decimal(10, 2)
totalAmount Decimal @map("total_amount") @db.Decimal(10, 2)
status PartnerBillStatus @default(PENDING_REVIEW)
confirmedAt DateTime? @map("confirmed_at") @db.DateTime(3)
sentAt DateTime? @map("sent_at") @db.DateTime(3)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
rejectReason String? @map("reject_reason") @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
partnerAccount PartnerAccount @relation(fields: [partnerAccountId], references: [id], onDelete: Restrict)
@@index([partnerAccountId, status])
@@unique([partnerAccountId, periodStart])
@@map("partner_bill")
}
// ─── HQ ───────────────────────────────────────────────
model HqAccount {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
phone String @unique @db.VarChar(20)
loginName String? @unique @map("login_name") @db.VarChar(64)
passwordHash String? @map("password_hash") @db.VarChar(255)
name String @db.VarChar(64)
adminRole HqAdminRole @default(OPS) @map("admin_role")
wxOpenId String? @map("wx_open_id") @db.VarChar(64)
wxUnionId String? @map("wx_union_id") @db.VarChar(64)
status AccountStatus @default(ACTIVE)
lastLoginAt DateTime? @map("last_login_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
permissions HqAccountPermission[]
@@map("hq_account")
}
model HqRolePermission {
adminRole HqAdminRole @map("admin_role")
permissionKey String @map("permission_key") @db.VarChar(64)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@id([adminRole, permissionKey])
@@map("hq_role_permission")
}
model HqAccountPermission {
hqAccountId BigInt @map("hq_account_id") @db.UnsignedBigInt
permissionKey String @map("permission_key") @db.VarChar(64)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
hqAccount HqAccount @relation(fields: [hqAccountId], references: [id], onDelete: Cascade)
@@id([hqAccountId, permissionKey])
@@map("hq_account_permission")
}
// ─── USER ─────────────────────────────────────────────
model User {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
userNo String @unique @map("user_no") @db.VarChar(20)
deviceKey String? @unique @map("device_key") @db.VarChar(36)
phone String? @unique @db.VarChar(20)
phoneVerifiedAt DateTime? @map("phone_verified_at") @db.DateTime(3)
mergedIntoUserId BigInt? @map("merged_into_user_id") @db.UnsignedBigInt
wxOpenId String? @map("wx_open_id") @db.VarChar(64)
wxUnionId String? @map("wx_union_id") @db.VarChar(64)
nickname String? @db.VarChar(64)
avatarResourceId BigInt? @map("avatar_resource_id") @db.UnsignedBigInt
status Int @default(1) @db.TinyInt
sourceType UserSourceType @default(ORGANIC) @map("source_type")
sourceRefId BigInt? @map("source_ref_id") @db.UnsignedBigInt
sourceLabel String? @map("source_label") @db.VarChar(128)
referrerUserId BigInt? @map("referrer_user_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
mergedInto User? @relation("UserMerge", fields: [mergedIntoUserId], references: [id], onDelete: SetNull)
mergedFrom User[] @relation("UserMerge")
referrer User? @relation("UserReferrer", fields: [referrerUserId], references: [id], onDelete: SetNull)
referrers User[] @relation("UserReferrer")
avatar CommonResource? @relation("UserAvatar", fields: [avatarResourceId], references: [id], onDelete: SetNull)
addresses UserAddress[]
cityPreference UserCityPreference?
promoTouch UserPromoAttribution?
ownedPromoCodes CommonPromoCode[] @relation("PromoOwnerUser")
orders Order[]
invoices UserInvoice[]
benefitCoupons BenefitCoupon[]
redeemRecords RedeemRecord[]
redeemPendingRecords RedeemPendingRecord[]
@@index([sourceType, sourceRefId])
@@index([referrerUserId])
@@index([mergedIntoUserId])
@@index([wxOpenId])
@@map("user_user")
}
model UserAddress {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
userId BigInt @map("user_id") @db.UnsignedBigInt
receiverName String @map("receiver_name") @db.VarChar(32)
phone String @db.VarChar(20)
province String @db.VarChar(32)
city String @db.VarChar(32)
district String @db.VarChar(32)
detail String @db.VarChar(256)
latitude Decimal? @db.Decimal(10, 7)
longitude Decimal? @db.Decimal(10, 7)
isDefault Int @default(0) @map("is_default") @db.TinyInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@map("user_address")
}
model UserCityPreference {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
userId BigInt @unique @map("user_id") @db.UnsignedBigInt
selectedCityCode String? @map("selected_city_code") @db.VarChar(16)
selectedDistrict String? @map("selected_district") @db.VarChar(32)
locateCityCode String? @map("locate_city_code") @db.VarChar(16)
locateDistrict String? @map("locate_district") @db.VarChar(32)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("user_city_preference")
}
model UserPromoAttribution {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
userId BigInt @unique @map("user_id") @db.UnsignedBigInt
promoCodeId BigInt @map("promo_code_id") @db.UnsignedBigInt
channelName String @map("channel_name") @db.VarChar(128)
firstTouchAt DateTime @map("first_touch_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
promoCode CommonPromoCode @relation(fields: [promoCodeId], references: [id], onDelete: Restrict)
@@index([promoCodeId])
@@map("user_promo_attribution")
}
// ─── STORE ────────────────────────────────────────────
model Store {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
cityId BigInt @map("city_id") @db.UnsignedBigInt
partnerAccountId BigInt @map("partner_account_id") @db.UnsignedBigInt
categoryId BigInt? @map("category_id") @db.UnsignedBigInt
name String @db.VarChar(128)
phone String @db.VarChar(20)
province String @db.VarChar(32)
cityName String @map("city_name") @db.VarChar(32)
district String @db.VarChar(32)
address String @db.VarChar(256)
latitude Decimal? @db.Decimal(10, 7)
longitude Decimal? @db.Decimal(10, 7)
intro String? @db.Text
// 好客权益券使用规则(C 端门店详情展示)
benefitUsageRule String? @map("benefit_usage_rule") @db.Text
coverResourceId BigInt? @map("cover_resource_id") @db.UnsignedBigInt
avgPrice Decimal? @map("avg_price") @db.Decimal(10, 2)
rating Decimal? @db.Decimal(3, 2)
tags Json?
status StoreStatus @default(PAUSED)
auditStatus StoreAuditStatus @default(APPROVED) @map("audit_status")
rejectReason String? @map("reject_reason") @db.VarChar(512)
auditedAt DateTime? @map("audited_at") @db.DateTime(3)
openTime String? @map("open_time") @db.VarChar(8)
closeTime String? @map("close_time") @db.VarChar(8)
openTime2 String? @map("open_time_2") @db.VarChar(8)
closeTime2 String? @map("close_time_2") @db.VarChar(8)
settlementRate Decimal @default(0.60) @map("settlement_rate") @db.Decimal(5, 4)
/// Online test: only listed phones can see store on C-end when enabled
visibilityWhitelistEnabled Boolean @default(false) @map("visibility_whitelist_enabled")
/// FIN-001:允许未出账手动提现的白名单门店
withdrawWhitelistEnabled Boolean @default(false) @map("withdraw_whitelist_enabled")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
cityRef CommonCity @relation(fields: [cityId], references: [id], onDelete: Restrict)
partnerAccount PartnerAccount @relation(fields: [partnerAccountId], references: [id], onDelete: Restrict)
category CommonStoreCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
coverResource CommonResource? @relation("StoreCover", fields: [coverResourceId], references: [id], onDelete: SetNull)
bindings StoreAccountStore[]
redeemRecords RedeemRecord[]
redeemPendingRecords RedeemPendingRecord[]
ratings StoreRating[]
payouts StorePayout[]
storeBills StoreBill[]
withdrawRequests StoreWithdrawRequest[]
visibilityPhones StoreVisibilityPhone[]
@@index([cityId, status])
@@index([partnerAccountId])
@@index([auditStatus, createdAt])
@@map("store_store")
}
/// Store visibility whitelist phones (match by bound user phone)
model StoreVisibilityPhone {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
phone String @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
@@unique([storeId, phone])
@@index([phone])
@@map("store_visibility_phone")
}
model StoreAccount {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
phone String @unique @db.VarChar(20)
name String @db.VarChar(64)
wxOpenId String? @map("wx_open_id") @db.VarChar(64)
wxUnionId String? @map("wx_union_id") @db.VarChar(64)
isPrimary Int @default(1) @map("is_primary") @db.TinyInt
parentAccountId BigInt? @map("parent_account_id") @db.UnsignedBigInt
staffRole StoreStaffRole? @map("staff_role")
permissions Json?
bankAccountName String? @map("bank_account_name") @db.VarChar(64)
bankAccountNo String? @map("bank_account_no") @db.VarChar(32)
bankBranch String? @map("bank_branch") @db.VarChar(128)
status AccountStatus @default(ACTIVE)
lastLoginAt DateTime? @map("last_login_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
parentAccount StoreAccount? @relation("StoreAccountHierarchy", fields: [parentAccountId], references: [id], onDelete: Restrict)
childAccounts StoreAccount[] @relation("StoreAccountHierarchy")
bindings StoreAccountStore[]
redeemPendingRecords RedeemPendingRecord[]
withdrawRequests StoreWithdrawRequest[]
@@index([parentAccountId])
@@map("store_account")
}
model StoreAccountStore {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
storeAccountId BigInt @map("store_account_id") @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
storeAccount StoreAccount @relation(fields: [storeAccountId], references: [id], onDelete: Cascade)
store Store @relation(fields: [storeId], references: [id], onDelete: Cascade)
@@unique([storeAccountId, storeId])
@@index([storeId])
@@map("store_account_store")
}
// ─── ORDER ────────────────────────────────────────────
model Order {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
orderNo String @unique @map("order_no") @db.VarChar(32)
orderType OrderType @default(NORMAL) @map("order_type")
userId BigInt @map("user_id") @db.UnsignedBigInt
cityId BigInt @map("city_id") @db.UnsignedBigInt
status OrderStatus @default(PENDING_PAY)
payStatus PayStatus @default(UNPAID) @map("pay_status")
deliveryType DeliveryType @map("delivery_type")
originOrderId BigInt? @map("origin_order_id") @db.UnsignedBigInt
promoCodeId BigInt? @map("promo_code_id") @db.UnsignedBigInt
channelSource String? @map("channel_source") @db.VarChar(128)
productId BigInt @map("product_id") @db.UnsignedBigInt
barcode69 String @map("barcode_69") @db.VarChar(32)
productName String @map("product_name") @db.VarChar(128)
productSpec String @map("product_spec") @db.VarChar(128)
imageResourceId BigInt? @map("image_resource_id") @db.UnsignedBigInt
quantity Int
listUnitPrice Decimal @map("list_unit_price") @db.Decimal(10, 2)
listAmount Decimal @map("list_amount") @db.Decimal(10, 2)
discountAmount Decimal @default(0) @map("discount_amount") @db.Decimal(10, 2)
productAmount Decimal @map("product_amount") @db.Decimal(10, 2)
freightAmount Decimal @default(0) @map("freight_amount") @db.Decimal(10, 2)
freightPayType FreightPayType? @map("freight_pay_type")
payAmount Decimal @map("pay_amount") @db.Decimal(10, 2)
benefitAmount Decimal @default(0) @map("benefit_amount") @db.Decimal(10, 2)
receiverName String @map("receiver_name") @db.VarChar(32)
receiverPhone String @map("receiver_phone") @db.VarChar(20)
receiverAddress String @map("receiver_address") @db.Text
receiverProvince String @map("receiver_province") @db.VarChar(32)
receiverCity String @map("receiver_city") @db.VarChar(32)
receiverDistrict String @map("receiver_district") @db.VarChar(32)
clientIp String? @map("client_ip") @db.VarChar(45)
ipProvince String? @map("ip_province") @db.VarChar(32)
ipCity String? @map("ip_city") @db.VarChar(32)
ipDistrict String? @map("ip_district") @db.VarChar(32)
gpsProvince String? @map("gps_province") @db.VarChar(32)
gpsCity String? @map("gps_city") @db.VarChar(32)
gpsDistrict String? @map("gps_district") @db.VarChar(32)
gpsLatitude Decimal? @map("gps_latitude") @db.Decimal(10, 7)
gpsLongitude Decimal? @map("gps_longitude") @db.Decimal(10, 7)
gpsAddress String? @map("gps_address") @db.VarChar(256)
payExternalNo String? @map("pay_external_no") @db.VarChar(64)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
shippedAt DateTime? @map("shipped_at") @db.DateTime(3)
completedAt DateTime? @map("completed_at") @db.DateTime(3)
cancelledAt DateTime? @map("cancelled_at") @db.DateTime(3)
payExpireAt DateTime? @map("pay_expire_at") @db.DateTime(3)
partnerAccountIdAtPay BigInt? @map("partner_account_id_at_pay") @db.UnsignedBigInt
orderCommissionRateAtPay Decimal? @map("order_commission_rate_at_pay") @db.Decimal(5, 4)
/// 代下单操作人(与佣金归属 partnerAccountIdAtPay 分离)
proxyPartnerAccountId BigInt? @map("proxy_partner_account_id") @db.UnsignedBigInt
proxyPartnerName String? @map("proxy_partner_name") @db.VarChar(64)
proxyPartnerPhone String? @map("proxy_partner_phone") @db.VarChar(20)
fulfillmentWarehouseId BigInt? @map("fulfillment_warehouse_id") @db.UnsignedBigInt
/// 大单等场景拦截自动推承运商,待总部确认后推单或自配送
fulfillmentHold Boolean @default(false) @map("fulfillment_hold")
fulfillmentHoldReason String? @map("fulfillment_hold_reason") @db.VarChar(64)
remark String? @db.VarChar(512)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
city CommonCity @relation(fields: [cityId], references: [id], onDelete: Restrict)
fulfillmentWarehouse CityWarehouse? @relation("OrderFulfillmentWarehouse", fields: [fulfillmentWarehouseId], references: [id], onDelete: SetNull)
originOrder Order? @relation("OrderReshipment", fields: [originOrderId], references: [id], onDelete: SetNull)
reshipments Order[] @relation("OrderReshipment")
promoCode CommonPromoCode? @relation(fields: [promoCodeId], references: [id], onDelete: SetNull)
product CommonProductItem @relation(fields: [productId], references: [id], onDelete: Restrict)
imageResource CommonResource? @relation("OrderProductImage", fields: [imageResourceId], references: [id], onDelete: SetNull)
delivery OrderDelivery?
benefitCoupon BenefitCoupon?
invoices UserInvoice[]
@@index([userId, status])
@@index([cityId, createdAt])
@@index([productId])
@@index([barcode69])
@@index([payExternalNo])
@@index([ipCity])
@@index([gpsCity])
@@index([fulfillmentWarehouseId])
@@index([proxyPartnerAccountId])
@@map("user_order")
}
model UserInvoice {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
invoiceNo String @unique @map("invoice_no") @db.VarChar(32)
orderId BigInt @map("order_id") @db.UnsignedBigInt
userId BigInt @map("user_id") @db.UnsignedBigInt
titleType InvoiceTitleType @map("title_type")
invoiceKind InvoiceKind @map("invoice_kind")
titleName String @map("title_name") @db.VarChar(128)
taxNo String? @map("tax_no") @db.VarChar(32)
addressPhone String? @map("address_phone") @db.VarChar(256)
bankAccount String? @map("bank_account") @db.VarChar(256)
email String @db.VarChar(128)
phone String @db.VarChar(20)
status InvoiceStatus @default(PENDING)
fileUrl String? @map("file_url") @db.VarChar(512)
resourceId BigInt? @map("resource_id") @db.UnsignedBigInt
issuedAt DateTime? @map("issued_at") @db.DateTime(3)
operatorId BigInt? @map("operator_id") @db.UnsignedBigInt
remark String? @db.VarChar(512)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
order Order @relation(fields: [orderId], references: [id], onDelete: Restrict)
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
@@index([userId, status])
@@index([orderId])
@@index([status, createdAt])
@@map("user_invoice")
}
model OrderDelivery {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
orderId BigInt @unique @map("order_id") @db.UnsignedBigInt
provider DeliveryProvider
fulfillmentProviderId BigInt? @map("fulfillment_provider_id") @db.UnsignedBigInt
providerOrderNo String? @map("provider_order_no") @db.VarChar(64)
trackingNo String? @map("tracking_no") @db.VarChar(64)
logisticsCompany String? @map("logistics_company") @db.VarChar(64)
manualQueryUrl String? @map("manual_query_url") @db.VarChar(512)
outWarehouseAt DateTime? @map("out_warehouse_at") @db.DateTime(3)
shippingAt DateTime? @map("shipping_at") @db.DateTime(3)
deliveredAt DateTime? @map("delivered_at") @db.DateTime(3)
signPhotoResourceId BigInt? @map("sign_photo_resource_id") @db.UnsignedBigInt
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
fulfillmentProvider FulfillmentProvider? @relation(fields: [fulfillmentProviderId], references: [id], onDelete: SetNull)
signPhotoResource CommonResource? @relation("DeliverySignPhoto", fields: [signPhotoResourceId], references: [id], onDelete: SetNull)
@@index([fulfillmentProviderId])
@@map("user_order_delivery")
}
// ─── BENEFIT & REDEEM ─────────────────────────────────
model BenefitCoupon {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
couponNo String @unique @map("coupon_no") @db.VarChar(32)
userId BigInt @map("user_id") @db.UnsignedBigInt
orderId BigInt? @unique @map("order_id") @db.UnsignedBigInt
totalAmount Decimal @map("total_amount") @db.Decimal(10, 2)
usedAmount Decimal @default(0) @map("used_amount") @db.Decimal(10, 2)
balance Decimal @db.Decimal(10, 2)
status BenefitCouponStatus @default(ACTIVE)
sourceProduct String @map("source_product") @db.VarChar(128)
version Int @default(0)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
order Order? @relation(fields: [orderId], references: [id], onDelete: Restrict)
redeemRecords RedeemRecord[]
redeemAllocations RedeemRecordAllocation[]
@@index([userId, status])
@@map("user_benefit_coupon")
}
model RedeemRecord {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
redeemNo String @unique @map("redeem_no") @db.VarChar(32)
userId BigInt @map("user_id") @db.UnsignedBigInt
couponId BigInt @map("coupon_id") @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
amount Decimal @db.Decimal(10, 2)
settleAmount Decimal @map("settle_amount") @db.Decimal(10, 2)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
coupon BenefitCoupon @relation(fields: [couponId], references: [id], onDelete: Restrict)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
rating StoreRating?
payout StorePayout?
pending RedeemPendingRecord?
allocations RedeemRecordAllocation[]
@@index([storeId, createdAt])
@@map("user_redeem_record")
}
// 核销单跨券 FIFO 分摊明细(含次券可追溯)
model RedeemRecordAllocation {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
redeemRecordId BigInt @map("redeem_record_id") @db.UnsignedBigInt
couponId BigInt @map("coupon_id") @db.UnsignedBigInt
amount Decimal @db.Decimal(10, 2)
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
redeemRecord RedeemRecord @relation(fields: [redeemRecordId], references: [id], onDelete: Cascade)
coupon BenefitCoupon @relation(fields: [couponId], references: [id], onDelete: Restrict)
@@unique([redeemRecordId, couponId])
@@index([couponId])
@@index([redeemRecordId])
@@map("user_redeem_record_allocation")
}
model RedeemPendingRecord {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
pendingNo String @unique @map("pending_no") @db.VarChar(32)
redeemToken String @map("redeem_token") @db.VarChar(64)
storeId BigInt @map("store_id") @db.UnsignedBigInt
storeAccountId BigInt @map("store_account_id") @db.UnsignedBigInt
userId BigInt @map("user_id") @db.UnsignedBigInt
amount Decimal @db.Decimal(10, 2)
redeemType String @default("DIRECT") @map("redeem_type") @db.VarChar(16)
allocationsJson Json @map("allocations_json")
photoResourceId BigInt @map("photo_resource_id") @db.UnsignedBigInt
failCount Int @default(5) @map("fail_count")
status RedeemPendingStatus @default(PENDING)
redeemRecordId BigInt? @unique @map("redeem_record_id") @db.UnsignedBigInt
processedAt DateTime? @map("processed_at") @db.DateTime(3)
processedByHqId BigInt? @map("processed_by_hq_id") @db.UnsignedBigInt
rejectReason String? @map("reject_reason") @db.VarChar(256)
remark String? @db.VarChar(256)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
storeAccount StoreAccount @relation(fields: [storeAccountId], references: [id], onDelete: Restrict)
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
photoResource CommonResource @relation("RedeemPendingPhoto", fields: [photoResourceId], references: [id], onDelete: Restrict)
redeemRecord RedeemRecord? @relation(fields: [redeemRecordId], references: [id], onDelete: SetNull)
@@index([storeId, status, createdAt])
@@index([redeemToken])
@@index([status, createdAt])
@@map("user_redeem_pending")
}
model StoreRating {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
redeemRecordId BigInt @unique @map("redeem_record_id") @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
serviceScore Int @map("service_score") @db.TinyInt
envScore Int @map("env_score") @db.TinyInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
redeemRecord RedeemRecord @relation(fields: [redeemRecordId], references: [id], onDelete: Cascade)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
@@map("user_store_rating")
}
model StoreBill {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
billNo String @unique @map("bill_no") @db.VarChar(32)
storeId BigInt @map("store_id") @db.UnsignedBigInt
billDate DateTime @map("bill_date") @db.DateTime(3)
redeemCount Int @default(0) @map("redeem_count")
redeemAmount Decimal @map("redeem_amount") @db.Decimal(10, 2)
settlementRate Decimal @map("settlement_rate") @db.Decimal(5, 4)
payoutAmount Decimal @map("payout_amount") @db.Decimal(10, 2)
status FinancePayStatus @default(UNPAID)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
payouts StorePayout[]
@@unique([storeId, billDate])
@@index([status, billDate])
@@map("store_bill")
}
model StorePayout {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
redeemRecordId BigInt @unique @map("redeem_record_id") @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
storeBillId BigInt? @map("store_bill_id") @db.UnsignedBigInt
redeemAmount Decimal @map("redeem_amount") @db.Decimal(10, 2)
payoutAmount Decimal @map("payout_amount") @db.Decimal(10, 2)
settlementRate Decimal @map("settlement_rate") @db.Decimal(5, 4)
status StorePayoutStatus @default(PENDING)
expectedPayAt DateTime @map("expected_pay_at") @db.DateTime(3)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
batchNo String? @map("batch_no") @db.VarChar(32)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
redeemRecord RedeemRecord @relation(fields: [redeemRecordId], references: [id], onDelete: Restrict)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
storeBill StoreBill? @relation(fields: [storeBillId], references: [id], onDelete: SetNull)
withdrawItem StoreWithdrawPayoutItem?
@@index([storeId, status])
@@index([storeBillId])
@@map("store_payout")
}
model StoreWithdrawRequest {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
withdrawNo String @unique @map("withdraw_no") @db.VarChar(32)
storeId BigInt @map("store_id") @db.UnsignedBigInt
storeAccountId BigInt @map("store_account_id") @db.UnsignedBigInt
amount Decimal @db.Decimal(10, 2)
payoutCount Int @default(0) @map("payout_count")
status StoreWithdrawStatus @default(PENDING_REVIEW)
rejectReason String? @map("reject_reason") @db.VarChar(512)
appliedAt DateTime @default(now()) @map("applied_at") @db.DateTime(3)
reviewedAt DateTime? @map("reviewed_at") @db.DateTime(3)
reviewedByHqId BigInt? @map("reviewed_by_hq_id") @db.UnsignedBigInt
paidAt DateTime? @map("paid_at") @db.DateTime(3)
paymentRef String? @map("payment_ref") @db.VarChar(128)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
store Store @relation(fields: [storeId], references: [id], onDelete: Restrict)
storeAccount StoreAccount @relation(fields: [storeAccountId], references: [id], onDelete: Restrict)
items StoreWithdrawPayoutItem[]
@@index([storeId, status])
@@index([status, appliedAt])
@@map("store_withdraw_request")
}
model StoreWithdrawPayoutItem {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
withdrawRequestId BigInt @map("withdraw_request_id") @db.UnsignedBigInt
storePayoutId BigInt @unique @map("store_payout_id") @db.UnsignedBigInt
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
withdrawRequest StoreWithdrawRequest @relation(fields: [withdrawRequestId], references: [id], onDelete: Cascade)
storePayout StorePayout @relation(fields: [storePayoutId], references: [id], onDelete: Restrict)
@@index([withdrawRequestId])
@@map("store_withdraw_payout_item")
}
model WineryBill {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
billNo String @unique @map("bill_no") @db.VarChar(32)
billDate DateTime @map("bill_date") @db.DateTime(3)
orderCount Int @default(0) @map("order_count")
orderAmount Decimal @map("order_amount") @db.Decimal(10, 2)
wineryRate Decimal @map("winery_rate") @db.Decimal(5, 4)
wineryAmount Decimal @map("winery_amount") @db.Decimal(10, 2)
status FinancePayStatus @default(UNPAID)
paidAt DateTime? @map("paid_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
items WineryBillItem[]
@@unique([billDate])
@@index([status, billDate])
@@map("winery_bill")
}
model WineryBillItem {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
wineryBillId BigInt @map("winery_bill_id") @db.UnsignedBigInt
orderId BigInt @unique @map("order_id") @db.UnsignedBigInt
orderNo String @map("order_no") @db.VarChar(32)
deliveryType String @map("delivery_type") @db.VarChar(16)
payAmount Decimal @map("pay_amount") @db.Decimal(10, 2)
wineryAmount Decimal @map("winery_amount") @db.Decimal(10, 2)
paidAt DateTime @map("paid_at") @db.DateTime(3)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
wineryBill WineryBill @relation(fields: [wineryBillId], references: [id], onDelete: Cascade)
@@index([wineryBillId])
@@map("winery_bill_item")
}
// ─── LOG ──────────────────────────────────────────────
model LogThirdParty {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
provider ThirdPartyProvider
scene String @db.VarChar(64)
refType String? @map("ref_type") @db.VarChar(32)
refId BigInt? @map("ref_id") @db.UnsignedBigInt
requestUrl String? @map("request_url") @db.VarChar(512)
requestBody Json? @map("request_body")
responseBody Json? @map("response_body")
externalNo String? @map("external_no") @db.VarChar(128)
amount Decimal? @db.Decimal(10, 2)
status ThirdPartyLogStatus @default(PENDING)
errorMessage String? @map("error_message") @db.VarChar(512)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([refType, refId])
@@index([provider, scene, createdAt])
@@index([externalNo])
@@map("log_third_party")
}
model LogUserAnalytics {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
userId BigInt? @map("user_id") @db.UnsignedBigInt
sessionId String? @map("session_id") @db.VarChar(64)
eventName String @map("event_name") @db.VarChar(64)
clientApp ClientApp? @map("client_app")
pagePath String? @map("page_path") @db.VarChar(128)
refType String? @map("ref_type") @db.VarChar(32)
refId BigInt? @map("ref_id") @db.UnsignedBigInt
keyword String? @db.VarChar(128)
sourceType String? @map("source_type") @db.VarChar(32)
sourceRefId BigInt? @map("source_ref_id") @db.UnsignedBigInt
extraJson Json? @map("extra_json")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([userId, createdAt])
@@index([eventName, createdAt])
@@index([sessionId])
@@index([refType, refId])
@@map("log_user_analytics")
}
model LogStoreAnalytics {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
storeAccountId BigInt? @map("store_account_id") @db.UnsignedBigInt
storeId BigInt @map("store_id") @db.UnsignedBigInt
eventName String @map("event_name") @db.VarChar(64)
clientApp ClientApp? @map("client_app")
refType String? @map("ref_type") @db.VarChar(32)
refId BigInt? @map("ref_id") @db.UnsignedBigInt
extraJson Json? @map("extra_json")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([storeId, createdAt])
@@index([storeAccountId, createdAt])
@@index([eventName, createdAt])
@@map("log_store_analytics")
}
model LogPartnerAnalytics {
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
partnerAccountId BigInt @map("partner_account_id") @db.UnsignedBigInt
eventName String @map("event_name") @db.VarChar(64)
clientApp ClientApp? @map("client_app")
refType String? @map("ref_type") @db.VarChar(32)
refId BigInt? @map("ref_id") @db.UnsignedBigInt
extraJson Json? @map("extra_json")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
@@index([partnerAccountId, createdAt])
@@index([eventName, createdAt])
@@map("log_partner_analytics")
}