create-crm-tmp 1.1.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/package.json +1 -1
  2. package/template/.prettierignore +2 -0
  3. package/template/README.md +1 -1
  4. package/template/components.json +22 -0
  5. package/template/exemple-contacts.csv +54 -0
  6. package/template/next.config.ts +27 -1
  7. package/template/package.json +51 -16
  8. package/template/prisma/schema.prisma +807 -58
  9. package/template/skills-lock.json +25 -0
  10. package/template/src/app/(auth)/invite/[token]/page.tsx +21 -24
  11. package/template/src/app/(auth)/reset-password/complete/page.tsx +12 -21
  12. package/template/src/app/(auth)/reset-password/page.tsx +12 -8
  13. package/template/src/app/(auth)/reset-password/verify/page.tsx +12 -8
  14. package/template/src/app/(auth)/signin/page.tsx +20 -17
  15. package/template/src/app/(dashboard)/agenda/page.tsx +2232 -2189
  16. package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
  17. package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +680 -323
  18. package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
  19. package/template/src/app/(dashboard)/automatisation/page.tsx +473 -180
  20. package/template/src/app/(dashboard)/closing/page.tsx +500 -468
  21. package/template/src/app/(dashboard)/contacts/[id]/page.tsx +5049 -4110
  22. package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1703 -0
  23. package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
  24. package/template/src/app/(dashboard)/contacts/page.tsx +3776 -2064
  25. package/template/src/app/(dashboard)/dashboard/page.tsx +37 -519
  26. package/template/src/app/(dashboard)/error.tsx +37 -0
  27. package/template/src/app/(dashboard)/layout.tsx +1 -1
  28. package/template/src/app/(dashboard)/loading.tsx +5 -0
  29. package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
  30. package/template/src/app/(dashboard)/settings/page.tsx +2685 -2489
  31. package/template/src/app/(dashboard)/templates/page.tsx +500 -300
  32. package/template/src/app/(dashboard)/users/list/page.tsx +356 -350
  33. package/template/src/app/(dashboard)/users/page.tsx +279 -310
  34. package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
  35. package/template/src/app/(dashboard)/users/roles/page.tsx +164 -137
  36. package/template/src/app/api/audit-logs/route.ts +1 -1
  37. package/template/src/app/api/auth/google/callback/route.ts +8 -5
  38. package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
  39. package/template/src/app/api/companies/[id]/activities/route.ts +131 -0
  40. package/template/src/app/api/companies/[id]/route.ts +195 -0
  41. package/template/src/app/api/companies/export/route.ts +206 -0
  42. package/template/src/app/api/companies/route.ts +166 -0
  43. package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
  44. package/template/src/app/api/contact-views/[id]/route.ts +197 -0
  45. package/template/src/app/api/contact-views/route.ts +146 -0
  46. package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +77 -0
  47. package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +7 -17
  48. package/template/src/app/api/contacts/[id]/files/route.ts +83 -44
  49. package/template/src/app/api/contacts/[id]/interactions/route.ts +37 -0
  50. package/template/src/app/api/contacts/[id]/kyc/route.ts +71 -0
  51. package/template/src/app/api/contacts/[id]/meet/route.ts +38 -29
  52. package/template/src/app/api/contacts/[id]/route.ts +111 -20
  53. package/template/src/app/api/contacts/[id]/send-email/route.ts +6 -0
  54. package/template/src/app/api/contacts/[id]/workflows/run/route.ts +61 -0
  55. package/template/src/app/api/contacts/export/route.ts +13 -18
  56. package/template/src/app/api/contacts/import/route.ts +22 -19
  57. package/template/src/app/api/contacts/import-preview/route.ts +139 -0
  58. package/template/src/app/api/contacts/route.ts +202 -49
  59. package/template/src/app/api/dashboard/stats/route.ts +9 -292
  60. package/template/src/app/api/integrations/google-sheet/sync/route.ts +203 -185
  61. package/template/src/app/api/invite/complete/route.ts +20 -23
  62. package/template/src/app/api/reminders/route.ts +1 -0
  63. package/template/src/app/api/reset-password/complete/route.ts +11 -13
  64. package/template/src/app/api/send/route.ts +9 -43
  65. package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
  66. package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
  67. package/template/src/app/api/settings/company/route.ts +19 -26
  68. package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
  69. package/template/src/app/api/settings/google-ads/route.ts +20 -23
  70. package/template/src/app/api/settings/google-sheet/[id]/route.ts +20 -23
  71. package/template/src/app/api/settings/google-sheet/auto-map/route.ts +23 -32
  72. package/template/src/app/api/settings/google-sheet/preview/route.ts +104 -0
  73. package/template/src/app/api/settings/google-sheet/route.ts +20 -23
  74. package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -23
  75. package/template/src/app/api/settings/meta-leads/route.ts +20 -23
  76. package/template/src/app/api/settings/statuses/[id]/route.ts +29 -32
  77. package/template/src/app/api/settings/statuses/route.ts +24 -22
  78. package/template/src/app/api/statuses/route.ts +2 -5
  79. package/template/src/app/api/tasks/[id]/attendees/route.ts +14 -7
  80. package/template/src/app/api/tasks/[id]/route.ts +173 -137
  81. package/template/src/app/api/tasks/meet/route.ts +11 -8
  82. package/template/src/app/api/tasks/route.ts +155 -95
  83. package/template/src/app/api/templates/[id]/route.ts +22 -13
  84. package/template/src/app/api/templates/route.ts +22 -5
  85. package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
  86. package/template/src/app/api/users/[id]/route.ts +2 -2
  87. package/template/src/app/api/users/commercials/route.ts +38 -0
  88. package/template/src/app/api/users/for-agenda/route.ts +1 -2
  89. package/template/src/app/api/users/route.ts +89 -34
  90. package/template/src/app/api/webhooks/google-ads/route.ts +20 -1
  91. package/template/src/app/api/webhooks/meta-leads/route.ts +18 -1
  92. package/template/src/app/api/workflows/[id]/route.ts +33 -6
  93. package/template/src/app/api/workflows/process/route.ts +510 -146
  94. package/template/src/app/api/workflows/route.ts +46 -4
  95. package/template/src/app/globals.css +243 -101
  96. package/template/src/app/layout.tsx +19 -8
  97. package/template/src/app/page.tsx +37 -7
  98. package/template/src/components/address-autocomplete.tsx +232 -0
  99. package/template/src/components/contacts/filter-bar.tsx +181 -0
  100. package/template/src/components/contacts/filter-builder.tsx +589 -0
  101. package/template/src/components/contacts/save-view-dialog.tsx +160 -0
  102. package/template/src/components/contacts/views-tab-bar.tsx +440 -0
  103. package/template/src/components/dashboard/activity-chart.tsx +31 -39
  104. package/template/src/components/dashboard/dashboard-content.tsx +79 -0
  105. package/template/src/components/dashboard/stat-card.tsx +40 -42
  106. package/template/src/components/dashboard/tasks-pie-chart.tsx +34 -37
  107. package/template/src/components/dashboard/upcoming-tasks-list.tsx +78 -72
  108. package/template/src/components/date-picker.tsx +396 -0
  109. package/template/src/components/editor.tsx +27 -13
  110. package/template/src/components/email-template.tsx +4 -2
  111. package/template/src/components/global-search.tsx +358 -0
  112. package/template/src/components/header.tsx +57 -62
  113. package/template/src/components/invitation-email-template.tsx +4 -2
  114. package/template/src/components/lazy-editor.tsx +11 -0
  115. package/template/src/components/meet-cancellation-email-template.tsx +11 -3
  116. package/template/src/components/meet-confirmation-email-template.tsx +10 -3
  117. package/template/src/components/meet-update-email-template.tsx +10 -3
  118. package/template/src/components/page-header.tsx +19 -15
  119. package/template/src/components/protected-page.tsx +94 -0
  120. package/template/src/components/reset-password-email-template.tsx +4 -2
  121. package/template/src/components/sidebar.tsx +92 -94
  122. package/template/src/components/skeleton.tsx +128 -42
  123. package/template/src/components/ui/accordion.tsx +64 -0
  124. package/template/src/components/ui/alert-dialog.tsx +139 -0
  125. package/template/src/components/ui/button.tsx +60 -0
  126. package/template/src/components/view-as-banner.tsx +1 -1
  127. package/template/src/components/view-as-modal.tsx +21 -16
  128. package/template/src/config/nav-pages.ts +108 -0
  129. package/template/src/contexts/app-toast-context.tsx +174 -0
  130. package/template/src/contexts/sidebar-context.tsx +16 -47
  131. package/template/src/contexts/task-reminder-context.tsx +6 -6
  132. package/template/src/contexts/view-as-context.tsx +11 -16
  133. package/template/src/hooks/use-alert.tsx +65 -0
  134. package/template/src/hooks/use-confirm.tsx +87 -0
  135. package/template/src/hooks/use-contact-views.ts +140 -0
  136. package/template/src/hooks/use-contacts.ts +69 -0
  137. package/template/src/hooks/use-fetch.ts +17 -0
  138. package/template/src/hooks/use-focus-trap.ts +73 -0
  139. package/template/src/hooks/use-statuses.ts +22 -0
  140. package/template/src/lib/address-api.ts +155 -0
  141. package/template/src/lib/cache.ts +73 -0
  142. package/template/src/lib/check-permission.ts +12 -177
  143. package/template/src/lib/contact-interactions.ts +3 -1
  144. package/template/src/lib/contact-view-filters.ts +341 -0
  145. package/template/src/lib/dashboard-stats.ts +224 -0
  146. package/template/src/lib/date-utils.ts +49 -0
  147. package/template/src/lib/get-auth-user.ts +25 -0
  148. package/template/src/lib/google-calendar.ts +54 -12
  149. package/template/src/lib/google-drive.ts +796 -75
  150. package/template/src/lib/google-fetch.ts +63 -0
  151. package/template/src/lib/local-storage.ts +34 -0
  152. package/template/src/lib/permissions.ts +245 -47
  153. package/template/src/lib/prisma.ts +11 -11
  154. package/template/src/lib/roles.ts +12 -15
  155. package/template/src/lib/template-variables.ts +67 -33
  156. package/template/src/lib/utils.ts +26 -11
  157. package/template/src/lib/workflow-executor.ts +445 -228
  158. package/template/src/proxy.ts +34 -73
  159. package/template/src/types/contact-views.ts +351 -0
  160. package/template/src/types/yousign.ts +52 -0
  161. package/template/vercel.json +12 -0
  162. package/template/WORKFLOWS_CRON.md +0 -185
  163. package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
  164. package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
  165. package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
  166. package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
  167. package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
  168. package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
  169. package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
  170. package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
  171. package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
  172. package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
  173. package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
  174. package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
  175. package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
  176. package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
  177. package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
  178. package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
  179. package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
  180. package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
  181. package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
  182. package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
  183. package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
  184. package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
  185. package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
  186. package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
  187. package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
  188. package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
  189. package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
  190. package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
  191. package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
  192. package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
  193. package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
  194. package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
  195. package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
  196. package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
  197. package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
  198. package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
  199. package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
  200. package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
  201. package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
  202. package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
  203. package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
  204. package/template/prisma/migrations/20260226093949_fix_cascade_on_user_delete/migration.sql +0 -69
  205. package/template/prisma/migrations/migration_lock.toml +0 -3
  206. package/template/src/app/(dashboard)/users/layout.tsx +0 -30
  207. package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -47
  208. package/template/src/app/api/dashboard/widgets/route.ts +0 -181
  209. package/template/src/components/dashboard/add-widget-dialog.tsx +0 -161
  210. package/template/src/components/dashboard/color-picker.tsx +0 -65
  211. package/template/src/components/dashboard/contacts-chart.tsx +0 -69
  212. package/template/src/components/dashboard/interactions-by-type-chart.tsx +0 -121
  213. package/template/src/components/dashboard/recent-activity.tsx +0 -157
  214. package/template/src/components/dashboard/status-distribution-chart.tsx +0 -82
  215. package/template/src/components/dashboard/top-contacts-list.tsx +0 -119
  216. package/template/src/components/dashboard/widget-wrapper.tsx +0 -39
  217. package/template/src/contexts/dashboard-theme-context.tsx +0 -58
  218. package/template/src/lib/dashboard-themes.ts +0 -140
  219. package/template/src/lib/default-widgets.ts +0 -14
  220. package/template/src/lib/widget-registry.ts +0 -177
@@ -45,7 +45,6 @@ model User {
45
45
  role Role @default(USER)
46
46
  customRoleId String? // Profil personnalisé optionnel
47
47
  customRole CustomRole? @relation(fields: [customRoleId], references: [id], onDelete: SetNull)
48
- eventColor String? // Couleur pour les événements de l'utilisateur
49
48
  createdAt DateTime @default(now())
50
49
  updatedAt DateTime @updatedAt
51
50
  sessions Session[]
@@ -67,7 +66,24 @@ model User {
67
66
  auditLogsAsActor AuditLog[] @relation("AuditActor")
68
67
  auditLogsAsTargetUser AuditLog[] @relation("AuditTargetUser")
69
68
  workflows Workflow[] @relation("WorkflowOwner")
70
- dashboardWidgets DashboardWidget[]
69
+ toursManaged Tour[] @relation("TourCommercial")
70
+ transactionsCreated Transaction[] @relation("TransactionCreatedBy")
71
+ transactionsAssigned Transaction[] @relation("TransactionAssignedTo")
72
+ transactionAuditLogs TransactionAuditLog[]
73
+ unavailableDatesCreated UnavailableDate[]
74
+ distributionCampaignPayments DistributionCampaignPayment[]
75
+ metaAdsPayments MetaAdsPayment[]
76
+ contactViews ContactView[]
77
+ contactViewPins ContactViewPin[]
78
+ companiesAssignedCommercial Company[] @relation("CompanyAssignedCommercial")
79
+ companiesAssignedTelepro Company[] @relation("CompanyAssignedTelepro")
80
+ companiesCreatedBy Company[] @relation("CompanyCreatedBy")
81
+ companyActivities CompanyActivity[]
82
+ workflowActionsTaskAssigned WorkflowAction[] @relation("WorkflowActionTaskAssignedUser")
83
+ workflowActionsAssignCommercial WorkflowAction[] @relation("WorkflowActionAssignCommercial")
84
+ workflowActionsAssignTelepro WorkflowAction[] @relation("WorkflowActionAssignTelepro")
85
+ workflowActionsNotifyUser WorkflowAction[] @relation("WorkflowActionNotifyUser")
86
+ refinerSubmissions RefinerSubmission[] @relation("RefinerSubmissionCreatedBy")
71
87
 
72
88
  @@unique([email])
73
89
  @@index([customRoleId])
@@ -136,26 +152,80 @@ model Verification {
136
152
  updatedAt DateTime @updatedAt
137
153
 
138
154
  @@index([identifier])
155
+ @@index([value])
139
156
  @@map("verification")
140
157
  }
141
158
 
159
+ model Organization {
160
+ id String @id @default("company")
161
+ name String?
162
+ legalRepresentative String? // Nom du représentant légal ou statutaire
163
+ address String?
164
+ city String?
165
+ postalCode String?
166
+ country String?
167
+ phone String?
168
+ email String?
169
+ website String?
170
+ siret String?
171
+ vatNumber String?
172
+ logo String?
173
+ cerfaTemplateFileId String? // Google Drive File ID du template PDF Cerfa
174
+ contractTemplateFileId String? // Google Drive File ID du template PDF de contrat de rachat
175
+ yousignSignaturePosition Json? // Position de la signature Yousign {page, x, y, width, height}
176
+ yousignRetractionPosition Json? // Position de la signature Yousign pour le formulaire de rétractation (page 4)
177
+ createdAt DateTime @default(now())
178
+ updatedAt DateTime @updatedAt
179
+
180
+ @@map("company")
181
+ }
182
+
142
183
  model Company {
143
- id String @id @default("company")
144
- name String?
145
- address String?
146
- city String?
147
- postalCode String?
148
- country String?
149
- phone String?
150
- email String?
151
- website String?
152
- siret String?
153
- vatNumber String?
154
- logo String?
184
+ id String @id @default(cuid())
185
+ name String
186
+ phone String?
187
+ email String?
188
+ address String?
189
+ city String?
190
+ postalCode String?
191
+ website String?
192
+ siret String?
193
+ industry String?
194
+ notes String? @db.Text
195
+ assignedCommercialId String?
196
+ assignedCommercial User? @relation("CompanyAssignedCommercial", fields: [assignedCommercialId], references: [id], onDelete: SetNull)
197
+ assignedTeleproId String?
198
+ assignedTelepro User? @relation("CompanyAssignedTelepro", fields: [assignedTeleproId], references: [id], onDelete: SetNull)
199
+ createdById String?
200
+ createdBy User? @relation("CompanyCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
201
+ createdAt DateTime @default(now())
202
+ updatedAt DateTime @updatedAt
203
+ contacts Contact[]
204
+ activities CompanyActivity[]
205
+
206
+ @@index([assignedCommercialId])
207
+ @@index([assignedTeleproId])
208
+ @@index([createdById])
209
+ @@index([name])
210
+ @@map("companies")
211
+ }
212
+
213
+ model CompanyActivity {
214
+ id String @id @default(cuid())
215
+ companyId String
216
+ company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
217
+ type String // COMPANY_UPDATE, CONTACT_ADDED, NOTE
218
+ title String?
219
+ content String @db.Text
220
+ metadata Json? // Détails des changements (champs modifiés, etc.)
221
+ userId String?
222
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
155
223
  createdAt DateTime @default(now())
156
- updatedAt DateTime @updatedAt
157
224
 
158
- @@map("company")
225
+ @@index([companyId])
226
+ @@index([companyId, createdAt])
227
+ @@index([userId])
228
+ @@map("company_activity")
159
229
  }
160
230
 
161
231
  model SmtpConfig {
@@ -181,6 +251,8 @@ model Status {
181
251
  name String
182
252
  color String // Couleur au format hexadécimal (ex: #3B82F6)
183
253
  order Int @default(0) // Ordre d'affichage
254
+ isSystem Boolean @default(false)
255
+ requiresClosingReason Boolean @default(false)
184
256
  createdAt DateTime @default(now())
185
257
  updatedAt DateTime @updatedAt
186
258
  contacts Contact[]
@@ -222,11 +294,12 @@ enum InteractionType {
222
294
 
223
295
  enum TaskType {
224
296
  CALL
225
- MEETING
297
+ MEETING // Rendez-vous physique
226
298
  EMAIL
227
299
  VIDEO_CONFERENCE
228
300
  OTHER
229
301
  TASK
302
+ PHYSICAL_APPOINTMENT // Rendez-vous physique avec localisation
230
303
  }
231
304
 
232
305
  enum TaskPriority {
@@ -236,6 +309,133 @@ enum TaskPriority {
236
309
  URGENT
237
310
  }
238
311
 
312
+ enum PlaceType {
313
+ HOTEL
314
+ RESTAURANT
315
+ AUTRE
316
+ }
317
+
318
+ enum PaymentStatus {
319
+ PAYE
320
+ EN_ATTENTE
321
+ ACOMPTE_VERSE
322
+ }
323
+
324
+ enum CampaignPaymentStatus {
325
+ A_PAYER
326
+ PARTIEL
327
+ PAYE
328
+ }
329
+
330
+ enum CityHallStatus {
331
+ OUI
332
+ NON
333
+ EN_COURS
334
+ EN_ATTENTE
335
+ }
336
+
337
+ enum DistributionType {
338
+ FLYERS
339
+ COURRIERS
340
+ MIX
341
+ }
342
+
343
+ enum IdType {
344
+ CNI
345
+ PASSPORT
346
+ LICENSE
347
+ RESIDENCE_PERMIT
348
+ OTHER
349
+ }
350
+
351
+ enum TransactionStatus {
352
+ DRAFT
353
+ PENDING_ID_VERIFICATION
354
+ ID_VERIFIED
355
+ ITEMS_ENTERED
356
+ PENDING_SIGNATURE // En attente de signature électronique Yousign
357
+ SIGNED
358
+ LOCKED
359
+ PAYMENT_PENDING
360
+ COMPLETED
361
+ PENDING_RETRACTION // En attente de signature du formulaire de rétractation
362
+ CANCELLED_RETRACTION
363
+ CANCELLED
364
+ }
365
+
366
+ enum SignatureType {
367
+ TABLET
368
+ ELECTRONIC
369
+ PAPER
370
+ }
371
+
372
+ enum PaymentMethod {
373
+ CHECK
374
+ BANK_TRANSFER
375
+ }
376
+
377
+ enum TransactionItemCategory {
378
+ GOLD
379
+ PLATINUM
380
+ SILVER
381
+ WATCHES
382
+ COLLECTIBLES
383
+ DIAMONDS
384
+ SILVERED_METAL
385
+ GOLD_PLATED
386
+ TIN
387
+ }
388
+
389
+ enum TransactionItemProcessingStatus {
390
+ A_VERIFIER
391
+ TRAITE
392
+ }
393
+
394
+ enum StockDisposition {
395
+ IN_STOCK
396
+ EXCLUDED
397
+ SENT_TO_REFINER
398
+ SOLD
399
+ }
400
+
401
+ enum RefinerSubmissionStatus {
402
+ PENDING
403
+ PROVISIONAL_PAID
404
+ COMPLETED
405
+ }
406
+
407
+ enum GoldPurity {
408
+ P375
409
+ P585
410
+ P750
411
+ P900
412
+ P916
413
+ P999
414
+ }
415
+
416
+ enum PlatinumPurity {
417
+ P900
418
+ P950
419
+ }
420
+
421
+ enum SilverPurity {
422
+ P680
423
+ P800
424
+ P835
425
+ P900
426
+ P925
427
+ P999
428
+ }
429
+
430
+ enum GoldType {
431
+ JEWELRY
432
+ DEBRIS
433
+ COINS
434
+ INGOTS
435
+ TEETH
436
+ GOLD_WATCHES
437
+ }
438
+
239
439
  model Contact {
240
440
  id String @id @default(cuid())
241
441
  civility Civility?
@@ -248,11 +448,9 @@ model Contact {
248
448
  city String?
249
449
  postalCode String?
250
450
  origin String? // Origine du contact
251
- companyName String? // Nom de l'entreprise (texte brut)
252
- isCompany Boolean @default(false) // Indique si le contact est une entreprise
253
- companyId String? // ID de l'entreprise à laquelle ce contact est lié
254
- companyRelation Contact? @relation("ContactCompany", fields: [companyId], references: [id], onDelete: SetNull)
255
- contacts Contact[] @relation("ContactCompany") // Contacts liés à cette entreprise (via companyId)
451
+ companyId String?
452
+ company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
453
+ jobTitle String? // Intitulé du poste (pour hiérarchie dans l'entreprise)
256
454
  statusId String?
257
455
  status Status? @relation(fields: [statusId], references: [id], onDelete: SetNull)
258
456
  closingReason String? // Motif de fermeture (si statut Fermé)
@@ -268,13 +466,26 @@ model Contact {
268
466
  tasks Task[]
269
467
  files ContactFile[]
270
468
  scheduledWorkflowActions ScheduledWorkflowAction[]
469
+ tourLinks TourContact[]
470
+ // KYC fields
471
+ placeOfBirth String? // Lieu de naissance
472
+ dateOfBirth DateTime? // Date de naissance
473
+ idType IdType? // Type de pièce d'identité
474
+ idNumber String? // Numéro de pièce d'identité
475
+ idExpiryDate DateTime? // Date d'expiration de la pièce d'identité
476
+ idDocumentUrl String? // URL/lien vers le document d'identité dans Google Drive
477
+ idVerifiedByAdmin Boolean @default(false) // Vérifié par un admin
478
+ transactions Transaction[]
271
479
 
272
480
  @@index([statusId])
273
481
  @@index([assignedCommercialId])
274
482
  @@index([assignedTeleproId])
275
483
  @@index([createdById])
276
484
  @@index([companyId])
277
- @@index([isCompany])
485
+ @@index([phone])
486
+ @@index([createdAt])
487
+ @@index([updatedAt])
488
+ @@index([statusId, updatedAt])
278
489
  @@map("contact")
279
490
  }
280
491
 
@@ -295,6 +506,7 @@ model Interaction {
295
506
 
296
507
  @@index([contactId])
297
508
  @@index([userId])
509
+ @@index([contactId, createdAt])
298
510
  @@map("interaction")
299
511
  }
300
512
 
@@ -316,6 +528,8 @@ model Task {
316
528
  id String @id @default(cuid())
317
529
  contactId String? // Optionnel : peut être créée depuis un contact
318
530
  contact Contact? @relation(fields: [contactId], references: [id], onDelete: SetNull)
531
+ tourId String? // Optionnel : lien avec une tournée
532
+ tour Tour? @relation(fields: [tourId], references: [id], onDelete: SetNull)
319
533
  type TaskType
320
534
  title String?
321
535
  description String // Description HTML (avec Editor)
@@ -333,14 +547,23 @@ model Task {
333
547
  durationMinutes Int? // Durée de la réunion en minutes (pour Google Meet)
334
548
  internalNote String? // Note personnelle (non partagée dans les emails)
335
549
  notifyContact Boolean? // Si le contact a été prévenu lors de la création
550
+ // Champs pour les rendez-vous physiques
551
+ location String? // Adresse complète du lieu
552
+ locationAddress String? // Rue
553
+ locationCity String? // Ville
554
+ locationPostalCode String? // Code postal
555
+ isAtHome Boolean @default(false) // Rendez-vous au domicile du contact
336
556
  createdAt DateTime @default(now())
337
557
  updatedAt DateTime @updatedAt
338
558
 
339
559
  @@index([contactId])
560
+ @@index([tourId])
340
561
  @@index([assignedUserId])
341
562
  @@index([createdById])
342
563
  @@index([scheduledAt])
343
564
  @@index([googleEventId])
565
+ @@index([assignedUserId, completed, scheduledAt])
566
+ @@index([assignedUserId, createdAt])
344
567
  @@map("task")
345
568
  }
346
569
 
@@ -359,20 +582,22 @@ model UserGoogleAccount {
359
582
  }
360
583
 
361
584
  model ContactFile {
362
- id String @id @default(cuid())
363
- contactId String
364
- contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
365
- fileName String // Nom original du fichier
366
- fileSize Int // Taille en octets
367
- mimeType String // Type MIME du fichier
368
- googleDriveFileId String // ID du fichier dans Google Drive
369
- uploadedById String? // Utilisateur qui a uploadé le fichier
370
- uploadedBy User? @relation("ContactFileUploadedBy", fields: [uploadedById], references: [id], onDelete: SetNull)
371
- createdAt DateTime @default(now())
372
- updatedAt DateTime @updatedAt
585
+ id String @id @default(cuid())
586
+ contactId String
587
+ contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
588
+ fileName String // Nom original du fichier
589
+ fileSize Int // Taille en octets
590
+ mimeType String // Type MIME du fichier
591
+ googleDriveFileId String // ID du fichier dans Google Drive
592
+ isIdentityDocument Boolean @default(false) // Indique si c'est une pièce d'identité
593
+ uploadedById String? // Utilisateur qui a uploadé le fichier
594
+ uploadedBy User? @relation("ContactFileUploadedBy", fields: [uploadedById], references: [id], onDelete: SetNull)
595
+ createdAt DateTime @default(now())
596
+ updatedAt DateTime @updatedAt
373
597
 
374
598
  @@index([contactId])
375
599
  @@index([uploadedById])
600
+ @@index([contactId, isIdentityDocument])
376
601
  @@map("contact_file")
377
602
  }
378
603
 
@@ -460,6 +685,7 @@ model Template {
460
685
  userId String? // Utilisateur qui a créé le template
461
686
  user User? @relation("TemplateCreatedBy", fields: [userId], references: [id], onDelete: SetNull)
462
687
  workflowActions WorkflowAction[] @relation("WorkflowActionEmailTemplate")
688
+ placeReminderConfigs PlaceReminderConfig[]
463
689
  createdAt DateTime @default(now())
464
690
  updatedAt DateTime @updatedAt
465
691
 
@@ -468,19 +694,43 @@ model Template {
468
694
  @@map("template")
469
695
  }
470
696
 
697
+ model PlaceReminderConfig {
698
+ id String @id @default("place-reminder-config")
699
+ enabled Boolean @default(true)
700
+ delayDays Int @default(7)
701
+ templateId String?
702
+ template Template? @relation(fields: [templateId], references: [id], onDelete: SetNull)
703
+ updatedAt DateTime @updatedAt
704
+
705
+ @@map("place_reminder_config")
706
+ }
707
+
471
708
  enum WorkflowTriggerType {
472
- CONTACT_CREATED // Nouveau contact créé
473
- STATUS_CHANGED // Changement de statut
474
- TIME_BASED // Basé sur le temps
475
- MANUAL // Déclencheur manuel
709
+ CONTACT_CREATED // Nouveau contact créé
710
+ STATUS_CHANGED // Changement de statut
711
+ TIME_BASED // Basé sur le temps
712
+ MANUAL // Déclencheur manuel
713
+ TASK_COMPLETED // Tâche complétée
714
+ TRANSACTION_CREATED // Transaction créée
715
+ TRANSACTION_STATUS_CHANGED // Changement de statut de transaction
716
+ CONTACT_ASSIGNMENT_CHANGED // Changement d'assignation du contact
717
+ }
718
+
719
+ enum WorkflowTimeReference {
720
+ CONTACT_CREATED_DATE // Date de création du contact
721
+ LAST_STATUS_CHANGE // Dernier changement de statut
722
+ LAST_INTERACTION // Dernière interaction
476
723
  }
477
724
 
478
725
  enum WorkflowActionType {
479
726
  SEND_EMAIL // Envoyer un email
480
727
  SEND_SMS // Envoyer un SMS
481
- CHANGE_STATUS // Changer le statut
482
- CREATE_TASK // Créer une tâche
483
- WAIT // Attendre
728
+ CHANGE_STATUS // Changer le statut
729
+ CREATE_TASK // Créer une tâche
730
+ WAIT // Attendre
731
+ ASSIGN_CONTACT // Assigner le contact à un commercial/télépro
732
+ ADD_NOTE // Ajouter une note au contact
733
+ NOTIFY_USER // Notifier un utilisateur (créer une tâche pour lui)
484
734
  }
485
735
 
486
736
  enum WorkflowConditionOperator {
@@ -506,8 +756,16 @@ model Workflow {
506
756
  triggerToStatus Status? @relation("WorkflowTriggerToStatus", fields: [triggerToStatusId], references: [id], onDelete: SetNull)
507
757
 
508
758
  // Pour TIME_BASED
509
- triggerTimeDays Int? // Nombre de jours après un événement
510
- triggerTimeHours Int? // Nombre d'heures après un événement
759
+ triggerTimeDays Int? // Nombre de jours après un événement
760
+ triggerTimeHours Int? // Nombre d'heures après un événement
761
+ triggerTimeReference WorkflowTimeReference? // Événement de référence pour TIME_BASED
762
+
763
+ // Pour TASK_COMPLETED
764
+ triggerTaskType TaskType? // Type de tâche (optionnel, null = toutes)
765
+
766
+ // Pour TRANSACTION_STATUS_CHANGED
767
+ triggerTransactionFromStatus String? // Statut source de la transaction (ex: DRAFT, SIGNED)
768
+ triggerTransactionToStatus String? // Statut cible de la transaction
511
769
 
512
770
  actions WorkflowAction[]
513
771
  scheduledActions ScheduledWorkflowAction[]
@@ -515,7 +773,7 @@ model Workflow {
515
773
  updatedAt DateTime @updatedAt
516
774
 
517
775
  @@index([userId])
518
- @@index([active])
776
+ @@index([active, triggerType])
519
777
  @@map("workflow")
520
778
  }
521
779
 
@@ -547,13 +805,32 @@ model WorkflowAction {
547
805
  newStatus Status? @relation("WorkflowActionNewStatus", fields: [newStatusId], references: [id], onDelete: SetNull)
548
806
 
549
807
  // Pour CREATE_TASK
550
- taskTitle String? // Titre de la tâche
551
- taskDescription String? // Description de la tâche
808
+ taskTitle String? // Titre de la tâche
809
+ taskDescription String? // Description de la tâche
810
+ taskType TaskType? // Type de tâche (CALL, MEETING, etc.) — défaut OTHER
811
+ taskPriority TaskPriority? // Priorité (LOW, MEDIUM, HIGH, URGENT) — défaut MEDIUM
812
+ taskAssignedUserId String? // Utilisateur assigné à la tâche
813
+ taskAssignedUser User? @relation("WorkflowActionTaskAssignedUser", fields: [taskAssignedUserId], references: [id], onDelete: SetNull)
814
+
815
+ // Pour ASSIGN_CONTACT
816
+ assignCommercialId String? // Commercial à assigner
817
+ assignCommercial User? @relation("WorkflowActionAssignCommercial", fields: [assignCommercialId], references: [id], onDelete: SetNull)
818
+ assignTeleproId String? // Télépro à assigner
819
+ assignTelepro User? @relation("WorkflowActionAssignTelepro", fields: [assignTeleproId], references: [id], onDelete: SetNull)
820
+
821
+ // Pour ADD_NOTE
822
+ noteContent String? @db.Text // Contenu de la note (supporte les variables de template)
823
+
824
+ // Pour NOTIFY_USER
825
+ notifyUserId String? // Utilisateur à notifier
826
+ notifyUser User? @relation("WorkflowActionNotifyUser", fields: [notifyUserId], references: [id], onDelete: SetNull)
552
827
 
553
828
  // Condition (optionnelle)
554
- conditionOperator WorkflowConditionOperator? // Opérateur de condition
555
- conditionStatusId String? // Statut pour la condition
556
- conditionStatus Status? @relation("WorkflowActionConditionStatus", fields: [conditionStatusId], references: [id], onDelete: SetNull)
829
+ conditionOperator WorkflowConditionOperator? // Opérateur de condition
830
+ conditionStatusId String? // Statut pour la condition
831
+ conditionStatus Status? @relation("WorkflowActionConditionStatus", fields: [conditionStatusId], references: [id], onDelete: SetNull)
832
+ conditionOrigin String? // Origine du contact pour la condition
833
+ conditionHasCompany Boolean? // true = contact doit avoir une société, false = ne doit pas
557
834
 
558
835
  createdAt DateTime @default(now())
559
836
  updatedAt DateTime @updatedAt
@@ -585,18 +862,490 @@ model ScheduledWorkflowAction {
585
862
  @@map("scheduled_workflow_action")
586
863
  }
587
864
 
588
- model DashboardWidget {
865
+ /// Tournée commerciale (inclut infos tournée, lieu, mairie, campagnes de distribution)
866
+ model Tour {
867
+ id String @id @default(cuid())
868
+ number String // Numéro de tournée (#T_${année}${mois}${cp})
869
+ region String?
870
+ department String?
871
+ city String?
872
+ postalCode String?
873
+ isoWeek Int? // Semaine ISO
874
+
875
+ presenceStart DateTime? // Début de présence (créneau)
876
+ presenceEnd DateTime? // Fin de présence (créneau)
877
+
878
+ // Lieu
879
+ placeType PlaceType? // Hôtel / Restaurant / Autre
880
+ placeName String?
881
+ placeAddress String?
882
+ placePhone String?
883
+ placeEmail String?
884
+ placeContactName String?
885
+ placeContactRole String?
886
+ placeContacts Json? // Contacts sur place multiples [{name, role, email, phone}]
887
+ placeRentalPriceCents Int? // Prix location en centimes (TTC)
888
+ placePaymentDepositCents Int? // Acompte versé en centimes
889
+ placePaymentDate DateTime?
890
+ placePaymentStatus PaymentStatus? // Payé / En attente / Acompte versé
891
+ placeInvoiceRef String?
892
+ placeInvoiceFileId String? // ID fichier (PDF) éventuel
893
+
894
+ // Lieu – emails
895
+ placeEmailSentDate DateTime?
896
+ placeReminderSentDate DateTime?
897
+ placeEmailSentById String?
898
+
899
+ // Mairie
900
+ cityHallName String?
901
+ cityHallAddress String?
902
+ cityHallCity String?
903
+ cityHallPostalCode String?
904
+ cityHallPhone String?
905
+ cityHallEmail String?
906
+ cityHallContactName String?
907
+ cityHallContacts Json? // Contacts mairie multiples [{name, role, email, phone}]
908
+ cityHallStatus CityHallStatus? // Oui / Non / En cours
909
+ cityHallRequestDate DateTime?
910
+ cityHallReminderDate DateTime?
911
+ cityHallDecisionDate DateTime?
912
+ cityHallDecision String? // Validation / Refus
913
+ cityHallRequestFileId String?
914
+ cityHallResponseFileId String?
915
+ cityHallAuthorizationFileId String?
916
+
917
+ // Campagnes de distribution
918
+ distributionType DistributionType? // Flyers / Courriers / Mix
919
+ distributionFlyersQty Int? // nombre de flyers
920
+ distributionLettersQty Int? // nombre de courriers
921
+ distributionProvider String? // Prestataire (ex: Mediapost)
922
+ distributionCampaignRef String?
923
+ distributionWeek String? // Semaine de distribution (texte)
924
+ distributionEndDate DateTime?
925
+ distributionZones String? // Zones couvertes (CP, quartiers...)
926
+ distributionDailyCostCents Int?
927
+ distributionFlyersHTCents Int? // Prix HT flyers en centimes
928
+ distributionLettersHTCents Int? // Prix HT courriers en centimes
929
+ distributionTotalCostCents Int? // Prix total TTC calculé automatiquement
930
+ distributionInvoiceFileId String?
931
+
932
+ // Relations
933
+ commercialId String?
934
+ commercial User? @relation("TourCommercial", fields: [commercialId], references: [id], onDelete: SetNull)
935
+ contacts TourContact[]
936
+ tasks Task[] // Tâches liées à cette tournée
937
+ transactions Transaction[] @relation("TransactionTour") // Transactions liées à cette tournée
938
+
939
+ // Note / Instructions
940
+ note String?
941
+
942
+ // Compteur interactions manuelles
943
+ interactionCount Int @default(0)
944
+
945
+ createdAt DateTime @default(now())
946
+ updatedAt DateTime @updatedAt
947
+
948
+ @@index([number])
949
+ @@index([commercialId])
950
+ @@index([distributionWeek])
951
+ @@map("tour")
952
+ }
953
+
954
+ /// Liaison plusieurs contacts <-> tournée
955
+ model TourContact {
589
956
  id String @id @default(cuid())
590
- userId String
591
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
592
- type String // Identifiant du type de widget (ex: stat_total_contacts, contacts_chart, etc.)
593
- x Int @default(0)
594
- y Int @default(0)
595
- w Int @default(6) // Largeur sur grille de 12
596
- h Int @default(4) // Hauteur en unités
957
+ tourId String
958
+ contactId String
959
+
960
+ tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
961
+ contact Contact @relation(fields: [contactId], references: [id], onDelete: Cascade)
962
+
963
+ createdAt DateTime @default(now())
964
+
965
+ @@unique([tourId, contactId])
966
+ @@index([tourId])
967
+ @@index([contactId])
968
+ @@map("tour_contact")
969
+ }
970
+
971
+ /// Prestataires de distribution (configurés par l'admin)
972
+ model DistributionProvider {
973
+ id String @id @default(cuid())
974
+ name String
975
+ isDefault Boolean @default(false)
597
976
  createdAt DateTime @default(now())
598
977
  updatedAt DateTime @updatedAt
599
978
 
979
+ @@map("distribution_provider")
980
+ }
981
+
982
+ /// Documents requis pour la demande d'autorisation en mairie (configurés par l'admin)
983
+ model CityHallRequiredDocument {
984
+ id String @id @default(cuid())
985
+ name String // Nom du document (ex: "Plan d'implantation", "Demande d'autorisation", etc.)
986
+ fileId String // ID du fichier Google Drive
987
+ fileName String // Nom du fichier original
988
+ order Int @default(0) // Ordre d'affichage
989
+ createdAt DateTime @default(now())
990
+ updatedAt DateTime @updatedAt
991
+
992
+ @@index([order])
993
+ @@map("city_hall_required_document")
994
+ }
995
+
996
+ /// Transaction d'achat d'or/métaux précieux
997
+ model Transaction {
998
+ id String @id @default(cuid())
999
+ contactId String
1000
+ contact Contact @relation(fields: [contactId], references: [id], onDelete: Restrict)
1001
+ tourId String? // Optionnel : lié à une tournée
1002
+ tour Tour? @relation("TransactionTour", fields: [tourId], references: [id], onDelete: SetNull)
1003
+ salesRepId String? // Commercial assigné
1004
+ salesRep User? @relation("TransactionAssignedTo", fields: [salesRepId], references: [id], onDelete: SetNull)
1005
+ createdById String?
1006
+ createdBy User? @relation("TransactionCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
1007
+ status TransactionStatus @default(DRAFT)
1008
+ paymentMethod PaymentMethod?
1009
+ paymentReference String? // Numéro de chèque ou nom de la banque
1010
+ signedAt DateTime? // Date de signature
1011
+ retractionDeadline DateTime? // Date limite de rétractation (48 heures après signature)
1012
+ contractPdfFileId String? // ID du fichier PDF du contrat dans Google Drive
1013
+ signatureType SignatureType? // Type de signature : ELECTRONIC, TABLET, PAPER
1014
+ signatureData String? // Données de signature (pour tablet) ou URL du scan (pour papier)
1015
+ yousignSignatureRequestId String? @unique // ID de la demande de signature Yousign
1016
+ yousignSignatureUrl String? // URL de signature Yousign
1017
+ yousignRetractionRequestId String? @unique // ID de la demande de signature de rétractation Yousign
1018
+ retractionPdfFileId String? // ID du fichier PDF de rétractation signé dans Google Drive
1019
+ transactionAddress String? // Adresse du lieu de la transaction (si pas de tournée)
1020
+ totalAmountCents Int? // Montant total en centimes
1021
+ lockedAt DateTime? // Date de verrouillage
1022
+ lockedBy String? // ID de l'utilisateur qui a verrouillé
1023
+ completedAt DateTime? // Date de complétion
1024
+ cancelledAt DateTime? // Date d'annulation
1025
+ items TransactionItem[]
1026
+ auditLogs TransactionAuditLog[]
1027
+ createdAt DateTime @default(now())
1028
+ updatedAt DateTime @updatedAt
1029
+
1030
+ @@index([contactId])
1031
+ @@index([salesRepId])
1032
+ @@index([createdById])
1033
+ @@index([status])
1034
+ @@index([tourId])
1035
+ @@index([status, contactId])
1036
+ @@index([status, salesRepId])
1037
+ @@index([status, createdAt])
1038
+ @@index([signedAt])
1039
+ @@index([salesRepId, signedAt])
1040
+ @@map("transaction")
1041
+ }
1042
+
1043
+ /// Articles d'une transaction (polymorphique)
1044
+ model TransactionItem {
1045
+ id String @id @default(cuid())
1046
+ transactionId String
1047
+ transaction Transaction @relation(fields: [transactionId], references: [id], onDelete: Cascade)
1048
+ category TransactionItemCategory
1049
+ order Int @default(0)
1050
+ processingStatus TransactionItemProcessingStatus @default(A_VERIFIER)
1051
+
1052
+ // Disposition dans le stock (après traitement)
1053
+ stockDisposition StockDisposition @default(IN_STOCK)
1054
+ exclusionReason String? // "Pas en étain", "Contrefaçon", "Irréparable", "Sans intérêt"
1055
+
1056
+ // Vente manuelle (pour articles d'occasion)
1057
+ saleAmountCents Int?
1058
+ saleDate DateTime?
1059
+ saleNotes String?
1060
+
1061
+ // Pour les métaux (OR, PLATINE, ARGENT)
1062
+ purity Int?
1063
+ weightGross Float?
1064
+ weightNet Float?
1065
+ type String?
1066
+ tmpValueCents Int?
1067
+
1068
+ // Pour les unités (montres, collectibles, diamants)
1069
+ brand String?
1070
+ model String?
1071
+ state String?
1072
+ certificate Boolean?
1073
+ pricePerUnitCents Int?
1074
+ quantity Int?
1075
+
1076
+ // Pour les diamants (4C)
1077
+ carat Float?
1078
+ color String?
1079
+ clarity String?
1080
+ cut String?
1081
+
1082
+ // Pour métal argenté, plaqué or, étains
1083
+ weightKg Float?
1084
+
1085
+ // Fichiers/photos
1086
+ photoFileId String?
1087
+
1088
+ // Métadonnées JSON pour flexibilité
1089
+ metadata Json?
1090
+
1091
+ refinerSubmissionItems RefinerSubmissionItem[]
1092
+
1093
+ createdAt DateTime @default(now())
1094
+ updatedAt DateTime @updatedAt
1095
+
1096
+ @@index([transactionId])
1097
+ @@index([category])
1098
+ @@index([stockDisposition])
1099
+ @@map("transaction_item")
1100
+ }
1101
+
1102
+ /// Journal d'audit pour les transactions verrouillées
1103
+ model TransactionAuditLog {
1104
+ id String @id @default(cuid())
1105
+ transactionId String
1106
+ transaction Transaction @relation(fields: [transactionId], references: [id], onDelete: Cascade)
1107
+ userId String?
1108
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
1109
+ fieldChanged String // Nom du champ modifié
1110
+ oldValue String? // Ancienne valeur (JSON stringifié si nécessaire)
1111
+ newValue String? // Nouvelle valeur (JSON stringifié si nécessaire)
1112
+ createdAt DateTime @default(now())
1113
+
1114
+ @@index([transactionId])
600
1115
  @@index([userId])
601
- @@map("dashboard_widget")
1116
+ @@index([createdAt])
1117
+ @@map("transaction_audit_log")
1118
+ }
1119
+
1120
+ /// Types de récurrence pour les jours d'indisponibilité
1121
+ enum RecurrenceType {
1122
+ NONE // Pas de récurrence (date unique)
1123
+ PERIOD // Période (du... au...)
1124
+ WEEKLY // Récurrence hebdomadaire (tous les lundis, mardis, etc.)
1125
+ MONTHLY_DAY // Récurrence mensuelle par jour (tous les 5 du mois)
1126
+ YEARLY // Récurrence annuelle (tous les 25 décembre)
1127
+ }
1128
+
1129
+ /// Types de jour d'indisponibilité
1130
+ enum UnavailableDateType {
1131
+ PUBLIC_HOLIDAY // Jour férié national
1132
+ CUSTOM // Jour personnalisé par l'admin
1133
+ }
1134
+
1135
+ /// Jours d'indisponibilité pour les tournées
1136
+ model UnavailableDate {
1137
+ id String @id @default(cuid())
1138
+ name String // Nom/Description (ex: "Noël", "Fermeture estivale")
1139
+ type UnavailableDateType @default(CUSTOM)
1140
+ date DateTime? // Date spécifique (si pas de récurrence ou date de début de période)
1141
+ endDate DateTime? // Date de fin (pour les périodes, ex: du 7 au 22 janvier)
1142
+ recurrenceType RecurrenceType @default(NONE)
1143
+ // Pour WEEKLY : 0=Dimanche, 1=Lundi, 2=Mardi, etc.
1144
+ // Pour MONTHLY_DAY : jour du mois (1-31)
1145
+ // Pour YEARLY : null (utilise la date)
1146
+ recurrenceValue Int? // Valeur de la récurrence
1147
+ isActive Boolean @default(true) // Permet de désactiver temporairement
1148
+ createdById String?
1149
+ createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
1150
+ createdAt DateTime @default(now())
1151
+ updatedAt DateTime @updatedAt
1152
+
1153
+ @@index([type])
1154
+ @@index([isActive])
1155
+ @@index([createdById])
1156
+ @@map("unavailable_date")
1157
+ }
1158
+
1159
+ /// Mode de paiement
1160
+ enum PaymentMode {
1161
+ VIREMENT
1162
+ CHEQUE
1163
+ ESPECES
1164
+ CB
1165
+ }
1166
+
1167
+ /// Paiement de campagne de distribution
1168
+ model DistributionCampaignPayment {
1169
+ id String @id @default(cuid())
1170
+ paymentKey String @unique // Clé de paiement (ex: PV-2026-S02)
1171
+ year Int // Année
1172
+ isoWeek Int // Semaine ISO
1173
+ tourDate DateTime // Date tournée
1174
+ amountHT Float // Montant HT
1175
+ tva Float // TVA 20%
1176
+ amountTTC Float // Montant TTC
1177
+
1178
+ // Acompte 1
1179
+ deposit1Date DateTime? // Date acompte 1
1180
+ deposit1Amount Float? @default(0) // Acompte 1
1181
+
1182
+ // Acompte 2
1183
+ deposit2Date DateTime? // Date acompte 2
1184
+ deposit2Amount Float? @default(0) // Acompte 2
1185
+
1186
+ // Acompte 3
1187
+ deposit3Date DateTime? // Date acompte 3
1188
+ deposit3Amount Float? @default(0) // Acompte 3
1189
+
1190
+ // Solde 1
1191
+ balance1Date DateTime? // Date solde 1
1192
+ balance1Amount Float? @default(0) // Solde 1
1193
+
1194
+ // Solde 2
1195
+ balance2Date DateTime? // Date solde 2
1196
+ balance2Amount Float? @default(0) // Solde 2
1197
+
1198
+ // Solde 3
1199
+ balance3Date DateTime? // Date solde 3
1200
+ balance3Amount Float? @default(0) // Solde 3
1201
+
1202
+ totalPaid Float @default(0) // Montant total payé (calculé)
1203
+ remainingBalance Float // Solde restant (calculé)
1204
+ status CampaignPaymentStatus @default(A_PAYER) // Statut
1205
+
1206
+ createdById String?
1207
+ createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
1208
+ createdAt DateTime @default(now())
1209
+ updatedAt DateTime @updatedAt
1210
+
1211
+ @@index([year])
1212
+ @@index([isoWeek])
1213
+ @@index([status])
1214
+ @@index([createdById])
1215
+ @@map("distribution_campaign_payment")
1216
+ }
1217
+
1218
+ /// Paiement publicité Meta
1219
+ model MetaAdsPayment {
1220
+ id String @id @default(cuid())
1221
+ paymentKey String @unique // Clé paiement Meta (ex: META-2025-12-1)
1222
+ year Int // Année
1223
+ month String // Mois (ex: "décembre")
1224
+ periodCovered String? // Période couverte (ex: "S50 à S52")
1225
+ invoiceNumber String? // N° Facture Meta
1226
+ invoiceDate DateTime? // Date de Facture
1227
+ invoiceDueDate DateTime? // Date d'échéance Facture
1228
+ paymentDate DateTime? // Date de Paiement
1229
+ invoiceAmount Float // Montant facture META
1230
+ paymentMode PaymentMode @default(VIREMENT) // Mode de paiement
1231
+ paymentStatus CampaignPaymentStatus @default(A_PAYER) // Statut paiement
1232
+
1233
+ createdById String?
1234
+ createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
1235
+ createdAt DateTime @default(now())
1236
+ updatedAt DateTime @updatedAt
1237
+
1238
+ @@index([year])
1239
+ @@index([month])
1240
+ @@index([paymentStatus])
1241
+ @@index([createdById])
1242
+ @@map("meta_ads_payment")
1243
+ }
1244
+
1245
+ model ContactView {
1246
+ id String @id @default(cuid())
1247
+ name String
1248
+ userId String
1249
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1250
+ isPublic Boolean @default(false)
1251
+ isDefault Boolean @default(false)
1252
+ entityType String @default("contacts") // "contacts" | "companies"
1253
+ filters Json @default("[]")
1254
+ columns Json?
1255
+ sortConfig Json?
1256
+ createdAt DateTime @default(now())
1257
+ updatedAt DateTime @updatedAt
1258
+ pins ContactViewPin[]
1259
+
1260
+ @@index([userId])
1261
+ @@index([isPublic])
1262
+ @@index([entityType, isPublic])
1263
+ @@map("contact_view")
1264
+ }
1265
+
1266
+ model ContactViewPin {
1267
+ id String @id @default(cuid())
1268
+ userId String
1269
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1270
+ viewId String
1271
+ view ContactView @relation(fields: [viewId], references: [id], onDelete: Cascade)
1272
+ pinOrder Int @default(0)
1273
+
1274
+ @@unique([userId, viewId])
1275
+ @@index([userId])
1276
+ @@map("contact_view_pin")
1277
+ }
1278
+
1279
+ /// Remise affineur (lot envoyé à l'affineur pour rachat)
1280
+ model RefinerSubmission {
1281
+ id String @id @default(cuid())
1282
+ submissionDate DateTime
1283
+ category TransactionItemCategory
1284
+ purity Int?
1285
+ metalPricePerKgCents Int
1286
+ brokeragePercent Float
1287
+ refinerPricePerGramCents Int
1288
+ totalWeightGrams Float
1289
+ totalFineWeightGrams Float
1290
+ provisionalAmountCents Int?
1291
+ actualAmountCents Int?
1292
+ status RefinerSubmissionStatus @default(PENDING)
1293
+ notes String?
1294
+ createdById String?
1295
+ createdBy User? @relation("RefinerSubmissionCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
1296
+ items RefinerSubmissionItem[]
1297
+ documents RefinerDocument[]
1298
+ createdAt DateTime @default(now())
1299
+ updatedAt DateTime @updatedAt
1300
+
1301
+ @@index([category])
1302
+ @@index([status])
1303
+ @@index([submissionDate])
1304
+ @@index([createdById])
1305
+ @@map("refiner_submission")
1306
+ }
1307
+
1308
+ /// Article lié à une remise affineur (snapshot des valeurs au moment de la remise)
1309
+ model RefinerSubmissionItem {
1310
+ id String @id @default(cuid())
1311
+ submissionId String
1312
+ submission RefinerSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
1313
+ transactionItemId String
1314
+ transactionItem TransactionItem @relation(fields: [transactionItemId], references: [id], onDelete: Restrict)
1315
+ weightGrams Float
1316
+ purity Int?
1317
+ fineWeightGrams Float
1318
+ provisionalPaymentPercent Float?
1319
+ restitutionPercent Float?
1320
+ calculatedAmountCents Int
1321
+ createdAt DateTime @default(now())
1322
+
1323
+ @@index([submissionId])
1324
+ @@index([transactionItemId])
1325
+ @@map("refiner_submission_item")
1326
+ }
1327
+
1328
+ /// Document attaché à une remise affineur (facture, bordereau)
1329
+ model RefinerDocument {
1330
+ id String @id @default(cuid())
1331
+ submissionId String
1332
+ submission RefinerSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
1333
+ fileName String
1334
+ fileUrl String
1335
+ fileType String?
1336
+ uploadedAt DateTime @default(now())
1337
+
1338
+ @@index([submissionId])
1339
+ @@map("refiner_document")
1340
+ }
1341
+
1342
+ /// Configuration de la valorisation du stock (clé/valeur)
1343
+ model StockConfig {
1344
+ id String @id @default(cuid())
1345
+ key String @unique
1346
+ value String
1347
+ label String
1348
+ updatedAt DateTime @updatedAt
1349
+
1350
+ @@map("stock_config")
602
1351
  }