Files
homaroma/apps/backend/prisma/schema.prisma
T
2026-10-01 05:28:31 +07:00

909 lines
32 KiB
Plaintext

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
model ProductBrand {
id Int @id @default(autoincrement())
name String @unique
products Product[]
translations ProductBrandTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ProductBrandTranslation {
id Int @id @default(autoincrement())
brandId Int
brand ProductBrand @relation(fields: [brandId], references: [id], onDelete: Cascade)
langCode String
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([brandId, langCode])
}
model Category {
id Int @id @default(autoincrement())
name String @unique
imageUrl String?
layoutType String @default("split_showcase")
products Product[]
attributes AttributeDefinition[]
translations CategoryTranslation[]
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([deletedAt])
}
model CategoryTranslation {
id Int @id @default(autoincrement())
categoryId Int
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
langCode String
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([categoryId, langCode])
}
model Product {
id Int @id @default(autoincrement())
categoryId Int
category Category @relation(fields: [categoryId], references: [id])
name String?
description String?
details String?
brandId Int
brand ProductBrand @relation(fields: [brandId], references: [id])
options Json? @default("[]") // Expected shape: [{ name: "Color", values: ["Red", "Blue"] }, ...]
variants ProductVariant[]
images ProductImage[]
attributes ProductAttribute[]
reviews Review[]
detailSections ProductDetailSection[]
translations ProductTranslation[]
isDeleted Boolean @default(false)
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([isDeleted])
@@index([categoryId, isDeleted])
}
model ProductTranslation {
id Int @id @default(autoincrement())
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
langCode String
name String
description String?
details String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([productId, langCode])
}
model ProductImage {
id Int @id @default(autoincrement())
url String
order Int @default(0)
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
}
model ProductVariant {
id Int @id @default(autoincrement())
sku String? @unique
barcode String?
price Float? @default(0)
stock Int @default(0)
option1 String @default("") // Maps to Product.options[0]
option2 String @default("") // Maps to Product.options[1]
option3 String @default("") // Maps to Product.options[2]
productId Int
product Product @relation(fields: [productId], references: [id])
bomItems BomItem[]
marketplaceProducts MarketplaceProduct[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([productId, option1, option2, option3])
}
model AttributeDefinition {
id Int @id @default(autoincrement())
code String @unique
label String
description String?
type String // TEXT, NUMBER, BOOLEAN, SELECT, JSON
unit String?
options Json? // Expected shape: [{ value: "floral", label: { th: "ดอกไม้", en: "Floral" } }]
isRequired Boolean @default(false)
isFilterable Boolean @default(false)
sortOrder Int @default(0)
categoryId Int?
category Category? @relation(fields: [categoryId], references: [id], onDelete: Cascade)
products ProductAttribute[]
translations AttributeDefinitionTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([categoryId])
@@index([sortOrder])
}
model AttributeDefinitionTranslation {
id Int @id @default(autoincrement())
attributeDefinitionId Int
attributeDefinition AttributeDefinition @relation(fields: [attributeDefinitionId], references: [id], onDelete: Cascade)
langCode String
label String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([attributeDefinitionId, langCode])
}
model ProductAttribute {
id Int @id @default(autoincrement())
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
attributeDefinitionId Int
attributeDefinition AttributeDefinition @relation(fields: [attributeDefinitionId], references: [id], onDelete: Cascade)
valueText String?
valueNumber Float?
valueBoolean Boolean?
valueJson Json?
translations ProductAttributeTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([productId, attributeDefinitionId])
@@index([productId])
@@index([attributeDefinitionId])
}
model ProductAttributeTranslation {
id Int @id @default(autoincrement())
productAttributeId Int
productAttribute ProductAttribute @relation(fields: [productAttributeId], references: [id], onDelete: Cascade)
langCode String
valueText String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([productAttributeId, langCode])
@@index([productAttributeId])
}
model User {
id Int @id @default(autoincrement())
username String @unique
password String
role String @default("ADMIN")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Customer {
id Int @id @default(autoincrement())
lineUserId String @unique
displayName String?
pictureUrl String?
email String?
phone String?
points Int @default(0)
orders Order[]
reviews Review[]
addresses CustomerAddress[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model CustomerAddress {
id Int @id @default(autoincrement())
customerId Int
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
recipientName String
phone String
addressLine String // บ้านเลขที่ หมู่บ้าน ถนน ซอย
subdistrict String // แขวง/ตำบล
district String // เขต/อำเภอ
province String // จังหวัด
zipcode String // รหัสไปรษณีย์
isDefault Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Coupon {
id Int @id @default(autoincrement())
code String @unique
type String // "PERCENTAGE", "FIXED_AMOUNT", "FREE_SHIPPING"
value Float
minPurchase Float @default(0)
maxDiscount Float?
usageLimit Int?
usedCount Int @default(0)
expiresAt DateTime?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Promotion {
id Int @id @default(autoincrement())
name String
level Int
type String
value Float
minPurchase Float @default(0)
isActive Boolean @default(true)
startDate DateTime?
endDate DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model StoreSettings {
id Int @id @default(1)
brandName String @default("HomAroma")
logoUrl String?
themePreset String @default("default")
themeTokens Json?
shippingFee Float @default(35)
bankName String @default("KASIKORNBANK (KBANK)")
bankAccountName String @default("HomAroma Co., Ltd.")
bankAccountNumber String @default("012-3-45678-9")
pointsEarnRate Float @default(1.0)
facebookUrl String?
footerDescription String?
instagramUrl String?
tiktokUrl String?
newsletterTitle String?
newsletterDescription String?
newsletterPlaceholder String?
newsletterButtonText String?
footerSupportHeading Json?
footerCopyrightText Json?
scrollRevealEnabled Boolean @default(true)
scrollRevealStyle String @default("fade-up")
scrollRevealDuration Int @default(700)
headerStyle String @default("single_line")
defaultSeoTitle String?
defaultSeoDescription String?
defaultOgImage String?
brandPrompt String?
translations StoreSettingsTranslation[]
updatedAt DateTime @updatedAt
}
model StoreSettingsTranslation {
id Int @id @default(autoincrement())
storeSettingsId Int
storeSettings StoreSettings @relation(fields: [storeSettingsId], references: [id], onDelete: Cascade)
langCode String
footerDescription String?
newsletterTitle String?
newsletterDescription String?
newsletterPlaceholder String?
newsletterButtonText String?
defaultSeoTitle String?
defaultSeoDescription String?
brandPrompt String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([storeSettingsId, langCode])
}
model NewsletterSubscriber {
id Int @id @default(autoincrement())
email String @unique
isActive Boolean @default(true)
createdAt DateTime @default(now())
}
model BrandKnowledge {
id Int @id @default(1)
brandName String @default("AKÉRIA")
tagline String?
story String?
targetAudience String?
toneOfVoice String?
visualArtPrompt String?
productUsps String?
marketingGuidelines String?
customRules String?
masterPromptOverride String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Order {
id Int @id @default(autoincrement())
channel String @default("ONLINE") // "ONLINE" | "POS"
customerName String?
customerEmail String?
customerPhone String?
shippingAddress String?
subtotal Float @default(0)
promoLevel1Name String?
promoLevel1Disc Float @default(0)
promoLevel2Name String?
promoLevel2Disc Float @default(0)
couponCode String?
discountAmount Float @default(0)
pointsUsed Int @default(0)
pointsDiscount Float @default(0)
pointsEarned Int @default(0)
shippingFee Float @default(0)
totalAmount Float
status String @default("PENDING_PAYMENT")
paymentMethod String? @default("CASH")
receivedAmount Float?
changeAmount Float?
cashierId Int?
paymentSlipUrl String?
trackingNo String?
customerId Int?
customer Customer? @relation(fields: [customerId], references: [id])
items OrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([channel])
@@index([createdAt])
}
model OrderItem {
id Int @id @default(autoincrement())
orderId Int
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
productId Int
variantId Int?
quantity Int
priceAtPurchase Float
productName String
variantName String?
productImage String?
}
model Article {
id Int @id @default(autoincrement())
slug String @unique
title String
coverImage String?
content String
isPublished Boolean @default(false)
translations ArticleTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ArticleTranslation {
id Int @id @default(autoincrement())
articleId Int
article Article @relation(fields: [articleId], references: [id], onDelete: Cascade)
langCode String
title String?
content String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([articleId, langCode])
}
model TiktokIncome {
id String @id // Order/adjustment ID
type String
orderCreatedTime String?
orderSettledTime String?
currency String
totalSettlementAmount Float
totalRevenue Float
totalFees Float
rawData Json // Stores all other 50+ columns
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model TiktokProduct {
id String @id // Product ID
productName String
status String
gmv Float
itemsSold Int
orders Int
rawData Json // Stores remaining tab/live/video metrics
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model TiktokProductSku {
id String @id // SKU ID
productId String
skuName String
status String
gmv Float
skuOrders Int
itemsSold Int
rawData Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model RawMaterial {
id Int @id @default(autoincrement())
name String @unique
unit String // e.g., 'kg', 'liter', 'piece'
pricePerUnit Float
bomItems BomItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model BomItem {
id Int @id @default(autoincrement())
productVariantId Int
productVariant ProductVariant @relation(fields: [productVariantId], references: [id], onDelete: Cascade)
rawMaterialId Int
rawMaterial RawMaterial @relation(fields: [rawMaterialId], references: [id], onDelete: Cascade)
quantity Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([productVariantId, rawMaterialId])
}
model ShopeeOrder {
orderId String @id
shop String @default("hom-aroma")
status String
buyerUsername String?
orderCreatedAt String?
paymentTime String?
paymentMethod String?
trackingNo String?
totalAmount Float @default(0)
buyerPaidAmount Float @default(0)
shippingFee Float @default(0)
commission Float @default(0)
completedAt String?
items ShopeeOrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ShopeeOrderItem {
id Int @id @default(autoincrement())
orderId String
order ShopeeOrder @relation(fields: [orderId], references: [orderId], onDelete: Cascade)
parentSku String?
productName String
skuRef String?
variantName String?
originalPrice Float @default(0)
dealPrice Float @default(0)
quantity Int @default(1)
totalPayment Float @default(0)
rawData Json
}
// ── TikTok Orders ──────────────────────────────────────────────────────────────
model TiktokOrder {
id Int @id @default(autoincrement())
orderId String @unique
shop String @default("hom-aroma")
status String // Order Status (Thai)
subStatus String? // Order Substatus
orderType String? // Normal / Pre-order
cancelBy String?
cancelReason String?
fulfillmentType String?
warehouseName String?
trackingId String?
deliveryOption String?
shippingProvider String?
buyerUsername String?
paymentMethod String?
// Financials (order-level)
orderAmount Float @default(0) // Total paid by buyer
refundAmount Float @default(0)
shippingFee Float @default(0) // Shipping Fee After Discount
originalShipping Float @default(0)
taxes Float @default(0)
// Settlement Financials
commissionFee Float @default(0) // ค่าคอมมิชชั่น TikTok
affiliateFee Float @default(0) // ค่าคอมมิชชั่นแอฟฟิลิเอต
netSettlement Float @default(0) // ยอดเงินโอนจริงสุทธิ
settledAt String? // วันที่โอนเงิน
isSettled Boolean @default(false)
// Geography
province String?
district String?
country String?
// Timestamps
createdTime String?
paidTime String?
rtsTime String?
shippedTime String?
deliveredTime String?
cancelledTime String?
items TiktokOrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([shop])
@@index([status])
@@index([createdTime])
}
model TiktokOrderItem {
id Int @id @default(autoincrement())
orderId String
order TiktokOrder @relation(fields: [orderId], references: [orderId], onDelete: Cascade)
skuId String?
sellerSku String?
productName String
variation String?
quantity Int @default(1)
skuQtyReturn Int @default(0)
unitOriginalPrice Float @default(0)
subtotalBeforeDiscount Float @default(0)
platformDiscount Float @default(0)
sellerDiscount Float @default(0)
subtotalAfterDiscount Float @default(0) // Revenue ระดับ SKU
productCategory String?
weight Float @default(0)
}
model TiktokSettlement {
id Int @id @default(autoincrement())
orderId String @unique // หมายเลขคำสั่งซื้อ/การปรับ
shop String @default("hom-aroma")
transactionType String? // ประเภทธุรกรรม (คำสั่งซื้อ / การปรับยอด)
orderCreatedTime String? // เวลาที่สร้างคำสั่งซื้อ
orderSettledTime String? // เวลาที่ชำระคำสั่งซื้อ / วันที่โอนเงิน
currency String @default("THB")
// Financial breakdowns
settlementAmount Float @default(0) // ยอดการชำระเงินทั้งหมด (Net Payout)
grossRevenue Float @default(0) // รายได้ทั้งหมด
subtotalAfterSellerDiscount Float @default(0) // ยอดรวมค่าสินค้าหลังหักส่วนลดจากผู้ขาย
subtotalBeforeDiscount Float @default(0) // ยอดรวมค่าสินค้าก่อนหักส่วนลด
sellerDiscount Float @default(0) // ส่วนลดจากร้านค้า
refundAmount Float @default(0) // ยอดรวมเงินคืน
// Fees
totalFee Float @default(0) // ค่าธรรมเนียมทั้งหมด
orderFee Float @default(0) // ค่าธรรมเนียมคำสั่งซื้อ
commissionFee Float @default(0) // ค่าคอมมิชชั่น TikTok Shop
affiliateCommission Float @default(0) // ค่าคอมมิชชั่นแอฟฟิลิเอต
affiliatePartnerFee Float @default(0) // ค่าคอมมิชชั่นของพาร์ทเนอร์แอฟฟิลิเอต
growthSupportFee Float @default(0) // ค่าธรรมเนียมสนับสนุนการเติบโตของร้านค้า
shippingFeeActual Float @default(0) // ค่าธรรมเนียมการจัดส่งจริง
platformShippingDiscount Float @default(0) // ส่วนลดค่าธรรมเนียมการจัดส่งจากแพลตฟอร์ม
customerPayment Float @default(0) // การชำระเงินของลูกค้า
rawData Json? // Full raw row data for audit
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([shop])
@@index([orderSettledTime])
@@index([orderId])
}
// ── Lazada Orders ──────────────────────────────────────────────────────────────
model LazadaOrder {
id Int @id @default(autoincrement())
orderNumber String @unique
shop String @default("hom-aroma")
createTime String?
updateTime String?
deliveredDate String?
customerName String?
shippingCity String?
shippingPostCode String?
shippingRegion String?
payMethod String?
status String? // Based on items or first item
trackingCode String?
shippingProvider String?
// Aggregate from items
orderAmount Float @default(0) // sum(paidPrice)
shippingFee Float @default(0) // sum(shippingFee)
items LazadaOrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([shop])
@@index([status])
@@index([createTime])
}
model LazadaOrderItem {
id Int @id @default(autoincrement())
orderNumber String
order LazadaOrder @relation(fields: [orderNumber], references: [orderNumber], onDelete: Cascade)
orderItemId String @unique
sellerSku String?
lazadaSku String?
itemName String
variation String?
unitPrice Float @default(0)
paidPrice Float @default(0)
sellerDiscountTotal Float @default(0)
platformDiscountTotal Float @default(0)
shippingFee Float @default(0)
status String?
}
// ── Reviews ────────────────────────────────────────────────────────────────
model Review {
id Int @id @default(autoincrement())
rating Int @default(5)
comment String?
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
customerId Int?
customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
customerName String?
isPublished Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId])
@@index([customerId])
}
model Page {
id Int @id @default(autoincrement())
slug String @unique // e.g., "home", "about-us"
title String
seoTitle String?
seoDescription String?
seoKeywords String?
ogImageUrl String?
sections PageSection[]
translations PageTranslation[]
isPublished Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model PageTranslation {
id Int @id @default(autoincrement())
pageId Int
page Page @relation(fields: [pageId], references: [id], onDelete: Cascade)
langCode String
title String
seoTitle String?
seoDescription String?
seoKeywords String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([pageId, langCode])
}
model PageSection {
id Int @id @default(autoincrement())
pageId Int
page Page @relation(fields: [pageId], references: [id], onDelete: Cascade)
type String // e.g., "HERO", "CATEGORIES", "PRODUCTS", "BANNER", "TEXT"
order Int // Display order
payload Json // Dynamic JSON payload
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ProductDetailSection {
id Int @id @default(autoincrement())
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
type String
order Int
payload Json
isActive Boolean @default(true)
isLocked Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId, order])
@@index([productId, isActive])
}
model NewsletterSubscription {
id Int @id @default(autoincrement())
email String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Menu {
id Int @id @default(autoincrement())
name String @unique // e.g., "header", "footer"
payload Json?
rootImage String?
isActive Boolean @default(true)
items MenuItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model MenuItem {
id Int @id @default(autoincrement())
menuId Int
menu Menu @relation(fields: [menuId], references: [id], onDelete: Cascade)
label String
url String
order Int @default(0)
columnImage String?
hoverImage String?
translations MenuItemTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model MenuItemTranslation {
id Int @id @default(autoincrement())
menuItemId Int
menuItem MenuItem @relation(fields: [menuItemId], references: [id], onDelete: Cascade)
langCode String
label String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([menuItemId, langCode])
}
model Media {
id Int @id @default(autoincrement())
filename String
path String
mimeType String
sizeBytes Int
createdAt DateTime @default(now())
}
// ── Contact Messages ────────────────────────────────────────────────────────
model ContactMessage {
id Int @id @default(autoincrement())
name String
email String
message String
isRead Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// ── Marketplace Products & SKU Mapping ──────────────────────────────────────────
model MarketplaceProduct {
id Int @id @default(autoincrement())
channel String // "tiktok" | "shopee" | "lazada"
shop String @default("hom-aroma")
marketplaceSku String @default("") // sellerSku / skuRef / skuId
productName String // Item name on marketplace
variation String @default("") // Variation / flavor / size
avgPrice Float @default(0)
totalSoldQty Int @default(0)
totalRevenue Float @default(0)
firstSoldAt String?
lastSoldAt String?
// Link to Master Core Catalog
masterVariantId Int?
masterVariant ProductVariant? @relation(fields: [masterVariantId], references: [id], onDelete: SetNull)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([channel, shop, productName, variation, marketplaceSku])
@@index([channel])
@@index([shop])
@@index([marketplaceSku])
@@index([masterVariantId])
@@index([totalRevenue])
}
// ── Marketplace Customers & CRM ───────────────────────────────────────────────
model MarketplaceCustomer {
id Int @id @default(autoincrement())
channel String // "tiktok" | "shopee" | "lazada"
shop String @default("hom-aroma")
identifier String // Unique identifier per channel (username or name+postcode)
displayName String // Display name on UI
location String? // District, Province
province String?
district String?
// Aggregated buyer stats
orderCount Int @default(0)
totalSpent Float @default(0)
avgIntervalDays Float @default(0)
firstOrderDate String?
lastOrderDate String?
predictedNextOrderDate String?
topProducts Json? // Stored as JSON array: string[]
// CRM Relationship
crm MarketplaceCustomerCrm?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([channel, identifier])
@@index([channel])
@@index([totalSpent])
@@index([orderCount])
}
model MarketplaceCustomerCrm {
id Int @id @default(autoincrement())
customerId Int @unique
customer MarketplaceCustomer @relation(fields: [customerId], references: [id], onDelete: Cascade)
// Tracking status
status String @default("pending") // "pending" | "contacted" | "converted" | "unresponsive" | "do_not_disturb"
strategyType String @default("due_restock") // "due_restock" | "win_back" | "vip_reward" | "nurture"
// Campaign & contact details
promoCodeSent String? // e.g., "REPEAT10"
discountOffered String? // e.g., "ส่วนลด 10%"
lastContactedAt DateTime?
nextFollowUpDate DateTime?
notes String?
assignedTo String?
activities CustomerCrmActivity[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([status])
@@index([strategyType])
@@index([nextFollowUpDate])
}
model CustomerCrmActivity {
id Int @id @default(autoincrement())
crmId Int
crm MarketplaceCustomerCrm @relation(fields: [crmId], references: [id], onDelete: Cascade)
action String // "STATUS_CHANGE" | "SENT_PROMO" | "CALL_NOTE" | "CHAT_NOTE"
content String
author String?
createdAt DateTime @default(now())
@@index([crmId])
}