// 杜康好客 · 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 } enum ActorType { USER STORE PARTNER HQ SYSTEM } enum TicketType { REFUND RESHIPMENT ALERT } 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 { DRAFT CONFIRMED PAID REJECTED } enum StoreStatus { OPEN PAUSED CLOSED } enum StoreAuditStatus { PENDING APPROVED REJECTED } enum UserSourceType { ORGANIC PROMO_CODE SHARE_LINK FRIEND_REFERRAL OFFLINE_EVENT 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 } enum FreightPayType { FREE COD } enum DeliveryProvider { XFX LOGISTICS MANUAL } enum BenefitCouponStatus { ACTIVE USED_UP VOID } enum StorePayoutStatus { PENDING 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") } 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") } 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") 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[] @@index([status, aromaType]) @@map("common_product_item") } 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) stores Store[] @@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 createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) warehouses CityWarehouse[] deliveries OrderDelivery[] @@map("common_fulfillment_provider") } 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(DRAFT) confirmedAt DateTime? @map("confirmed_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]) @@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[] 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 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) settlementRate Decimal @default(0.60) @map("settlement_rate") @db.Decimal(5, 4) 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[] @@index([cityId, status]) @@index([partnerAccountId]) @@index([auditStatus, createdAt]) @@map("store_store") } 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[] @@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) fulfillmentWarehouseId BigInt? @map("fulfillment_warehouse_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) 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? @@index([userId, status]) @@index([cityId, createdAt]) @@index([productId]) @@index([barcode69]) @@index([payExternalNo]) @@index([ipCity]) @@index([gpsCity]) @@index([fulfillmentWarehouseId]) @@map("user_order") } 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[] @@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? @@index([storeId, createdAt]) @@map("user_redeem_record") } 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 StorePayout { id BigInt @id @default(autoincrement()) @db.UnsignedBigInt redeemRecordId BigInt @unique @map("redeem_record_id") @db.UnsignedBigInt storeId BigInt @map("store_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) @@index([storeId, status]) @@map("store_payout") } // ─── 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") }