quotes.prisma 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. model Quote {
  2. id String @id @default(cuid())
  3. quoteNumber String?
  4. title String
  5. description String?
  6. status String @default("draft")
  7. validUntil DateTime?
  8. subtotal Float @default(0)
  9. taxRate Float @default(0)
  10. taxAmount Float @default(0)
  11. taxInclusive Boolean @default(false)
  12. /// See ServiceRecord.taxComponents.
  13. taxComponents Json?
  14. discountType String?
  15. discountValue Float @default(0)
  16. discountAmount Float @default(0)
  17. totalAmount Float @default(0)
  18. notes String?
  19. publicToken String?
  20. sharedAt DateTime?
  21. viewCount Int @default(0)
  22. lastViewedAt DateTime?
  23. customerMessage String?
  24. convertedToId String?
  25. createdAt DateTime @default(now())
  26. updatedAt DateTime @updatedAt
  27. /// Most recent time this quote reached the customer, by email or share
  28. /// link. Exists so an unlock is spent when the quote is issued again; the
  29. /// status alone cannot show that, because re-sending an accepted quote does
  30. /// not change it.
  31. sentAt DateTime?
  32. /// See ServiceRecord.editUnlockedAt.
  33. editUnlockedAt DateTime?
  34. editUnlockedById String?
  35. userId String
  36. user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  37. organizationId String?
  38. organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  39. customerId String?
  40. customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
  41. /// The stored set this quote is about, when it came out of the tire hotel.
  42. /// SetNull rather than Cascade: a quote already sent is a document the
  43. /// customer holds, and deleting the set must not erase it.
  44. tireSetId String?
  45. tireSet TireSet? @relation(fields: [tireSetId], references: [id], onDelete: SetNull)
  46. vehicleId String?
  47. vehicle Vehicle? @relation(fields: [vehicleId], references: [id], onDelete: SetNull)
  48. inspectionId String?
  49. inspection Inspection? @relation(fields: [inspectionId], references: [id], onDelete: SetNull)
  50. partItems QuotePart[]
  51. laborItems QuoteLabor[]
  52. attachments QuoteAttachment[]
  53. @@index([organizationId])
  54. @@map("quotes")
  55. }
  56. model QuoteAttachment {
  57. id String @id @default(cuid())
  58. fileName String
  59. fileUrl String
  60. fileType String
  61. fileSize Int
  62. category String @default("image")
  63. description String?
  64. includeInInvoice Boolean @default(true)
  65. createdAt DateTime @default(now())
  66. quoteId String
  67. quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
  68. @@index([quoteId])
  69. @@map("quote_attachments")
  70. }
  71. model QuotePart {
  72. id String @id @default(cuid())
  73. partNumber String?
  74. name String
  75. quantity Float @default(1)
  76. /// Unit of measure snapshotted from InventoryPart at pick time; null for
  77. /// free-text lines and legacy rows.
  78. unit String?
  79. /// Internal purchase cost — never shown to customers (quote PDF/share
  80. /// render unitPrice only)
  81. unitCost Float @default(0)
  82. markupPercent Float @default(0)
  83. unitPrice Float @default(0)
  84. total Float @default(0)
  85. excluded Boolean @default(false)
  86. /// Optional link to the stocked part this line was picked from. Carried into
  87. /// ServicePart on conversion so the job deducts the right inventory item.
  88. inventoryPartId String?
  89. quoteId String
  90. quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
  91. @@index([quoteId])
  92. @@map("quote_parts")
  93. }
  94. model QuoteLabor {
  95. id String @id @default(cuid())
  96. description String
  97. hours Float @default(0)
  98. rate Float @default(0)
  99. total Float @default(0)
  100. pricingType String @default("hourly")
  101. excluded Boolean @default(false)
  102. quoteId String
  103. quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
  104. @@index([quoteId])
  105. @@map("quote_labor")
  106. }