@nuxt-customer-portal/timesheets 0.3.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 (141) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +5 -0
  4. package/app/assets/timesheets.css +368 -0
  5. package/app/components/TimesheetsActivityForm.vue +61 -0
  6. package/app/components/TimesheetsAdminActivities.vue +323 -0
  7. package/app/components/TimesheetsAdminApprovals.vue +449 -0
  8. package/app/components/TimesheetsAdminEmptyState.vue +28 -0
  9. package/app/components/TimesheetsAdminListToolbar.vue +19 -0
  10. package/app/components/TimesheetsAdminPaginatedList.vue +95 -0
  11. package/app/components/TimesheetsAdminProjects.vue +234 -0
  12. package/app/components/TimesheetsAdminRates.vue +83 -0
  13. package/app/components/TimesheetsAdminReports.vue +123 -0
  14. package/app/components/TimesheetsAdminSectionPage.vue +135 -0
  15. package/app/components/TimesheetsAdminSettings.vue +15 -0
  16. package/app/components/TimesheetsAdministrationOrganizationPanel.vue +26 -0
  17. package/app/components/TimesheetsClientSettingsPanel.vue +52 -0
  18. package/app/components/TimesheetsClientTimesheetBrowser.vue +439 -0
  19. package/app/components/TimesheetsDashboardCard.vue +260 -0
  20. package/app/components/TimesheetsDashboardClientApprovals.vue +1 -0
  21. package/app/components/TimesheetsDashboardInternalApprovals.vue +1 -0
  22. package/app/components/TimesheetsDashboardMyTimesheets.vue +1 -0
  23. package/app/components/TimesheetsDashboardMyWeek.vue +1 -0
  24. package/app/components/TimesheetsDashboardSupplierTimesheets.vue +47 -0
  25. package/app/components/TimesheetsOrganizationFeaturesCard.vue +66 -0
  26. package/app/components/TimesheetsPageShell.vue +48 -0
  27. package/app/components/TimesheetsProjectDetail.vue +338 -0
  28. package/app/components/TimesheetsProjectForm.vue +215 -0
  29. package/app/components/TimesheetsSetupChecklist.vue +48 -0
  30. package/app/components/TimesheetsSubmissionMessages.vue +30 -0
  31. package/app/components/TimesheetsSubmissionTimeline.vue +89 -0
  32. package/app/components/TimesheetsWorkspaceSettingsForm.vue +80 -0
  33. package/app/composables/useTimesheetMenu.ts +69 -0
  34. package/app/composables/useTimesheetMutationError.ts +35 -0
  35. package/app/composables/useTimesheets.ts +248 -0
  36. package/app/composables/useTimesheetsAdminList.ts +165 -0
  37. package/app/composables/useTimesheetsDashboard.ts +8 -0
  38. package/app/pages/admin/timesheets/activities.vue +3 -0
  39. package/app/pages/admin/timesheets/approvals.vue +3 -0
  40. package/app/pages/admin/timesheets/index.vue +7 -0
  41. package/app/pages/admin/timesheets/internal-approvals.vue +131 -0
  42. package/app/pages/admin/timesheets/projects/[id].vue +57 -0
  43. package/app/pages/admin/timesheets/projects.vue +8 -0
  44. package/app/pages/admin/timesheets/rates.vue +3 -0
  45. package/app/pages/admin/timesheets/reports.vue +3 -0
  46. package/app/pages/admin/timesheets/settings.vue +3 -0
  47. package/app/pages/timesheets/approvals/reviewers.vue +96 -0
  48. package/app/pages/timesheets/approvals.vue +11 -0
  49. package/app/pages/timesheets/client-approvals.vue +108 -0
  50. package/app/pages/timesheets/client.vue +17 -0
  51. package/app/pages/timesheets/index.vue +1458 -0
  52. package/app/pages/timesheets/internal-approvals.vue +100 -0
  53. package/app/pages/timesheets/suppliers.vue +23 -0
  54. package/app/plugins/timesheets-feature.ts +122 -0
  55. package/i18n/locales/en.json +455 -0
  56. package/i18n/locales/nl.json +455 -0
  57. package/migrations/0000_baseline.sql +409 -0
  58. package/migrations/0001_remove_unused_legacy_invoice_schema.sql +31 -0
  59. package/migrations/0002_submission_batches.sql +47 -0
  60. package/migrations/0003_sync_provider_clients.sql +26 -0
  61. package/migrations/0004_client_reply.sql +1 -0
  62. package/migrations/0005_timer_rounding.sql +1 -0
  63. package/migrations/meta/0000_snapshot.json +3178 -0
  64. package/migrations/meta/_journal.json +13 -0
  65. package/nuxt.config.ts +20 -0
  66. package/package.json +61 -0
  67. package/portal.manifest.mjs +10 -0
  68. package/server/api/timesheets/admin/activities/[id]/deletion.get.ts +18 -0
  69. package/server/api/timesheets/admin/activities/[id].delete.ts +20 -0
  70. package/server/api/timesheets/admin/activities/[id].patch.ts +19 -0
  71. package/server/api/timesheets/admin/activities/index.get.ts +19 -0
  72. package/server/api/timesheets/admin/activities/index.post.ts +19 -0
  73. package/server/api/timesheets/admin/approvals/[id].post.ts +19 -0
  74. package/server/api/timesheets/admin/bootstrap.get.ts +73 -0
  75. package/server/api/timesheets/admin/client-settings/[clientId]/index.get.ts +25 -0
  76. package/server/api/timesheets/admin/client-settings/[clientId]/index.put.ts +28 -0
  77. package/server/api/timesheets/admin/clients/[id]/deletion.get.ts +18 -0
  78. package/server/api/timesheets/admin/clients/[id].delete.ts +20 -0
  79. package/server/api/timesheets/admin/clients/[id].patch.ts +14 -0
  80. package/server/api/timesheets/admin/clients/index.get.ts +18 -0
  81. package/server/api/timesheets/admin/clients/index.post.ts +25 -0
  82. package/server/api/timesheets/admin/internal-approvals/[userId].put.ts +11 -0
  83. package/server/api/timesheets/admin/internal-approvals/index.get.ts +8 -0
  84. package/server/api/timesheets/admin/internal-approvals/index.patch.ts +11 -0
  85. package/server/api/timesheets/admin/organization-capabilities/[organizationId].get.ts +19 -0
  86. package/server/api/timesheets/admin/organization-capabilities/[organizationId].patch.ts +23 -0
  87. package/server/api/timesheets/admin/projects/[id]/deletion.get.ts +18 -0
  88. package/server/api/timesheets/admin/projects/[id].delete.ts +20 -0
  89. package/server/api/timesheets/admin/projects/[id].get.ts +22 -0
  90. package/server/api/timesheets/admin/projects/[id].patch.ts +19 -0
  91. package/server/api/timesheets/admin/projects/index.get.ts +18 -0
  92. package/server/api/timesheets/admin/projects/index.post.ts +19 -0
  93. package/server/api/timesheets/admin/report.get.ts +26 -0
  94. package/server/api/timesheets/admin/settings.patch.ts +19 -0
  95. package/server/api/timesheets/admin/tariffs/index.put.ts +20 -0
  96. package/server/api/timesheets/admin/team/[userId].put.ts +24 -0
  97. package/server/api/timesheets/bootstrap.get.ts +24 -0
  98. package/server/api/timesheets/capabilities.get.ts +58 -0
  99. package/server/api/timesheets/client/[workspaceClientId]/index.get.ts +12 -0
  100. package/server/api/timesheets/client/[workspaceClientId]/reviewers.get.ts +10 -0
  101. package/server/api/timesheets/client/[workspaceClientId]/reviewers.put.ts +18 -0
  102. package/server/api/timesheets/client/[workspaceClientId]/reviews/[submissionId].post.ts +18 -0
  103. package/server/api/timesheets/client/approval-members.get.ts +11 -0
  104. package/server/api/timesheets/client/approval-suppliers.get.ts +8 -0
  105. package/server/api/timesheets/client/approvals.get.ts +14 -0
  106. package/server/api/timesheets/client/reviewer-suppliers.get.ts +10 -0
  107. package/server/api/timesheets/client/supplier-options.get.ts +14 -0
  108. package/server/api/timesheets/client/supplier-timesheets.get.ts +17 -0
  109. package/server/api/timesheets/client/workspaces.get.ts +11 -0
  110. package/server/api/timesheets/client-approvals.get.ts +18 -0
  111. package/server/api/timesheets/dashboard.get.ts +191 -0
  112. package/server/api/timesheets/entries/[id].delete.ts +18 -0
  113. package/server/api/timesheets/entries/[id].patch.ts +23 -0
  114. package/server/api/timesheets/entries/index.post.ts +22 -0
  115. package/server/api/timesheets/internal-approvals/[id].post.ts +9 -0
  116. package/server/api/timesheets/internal-approvals/index.get.ts +37 -0
  117. package/server/api/timesheets/internal-approvals/list.get.ts +12 -0
  118. package/server/api/timesheets/setup-status.get.ts +21 -0
  119. package/server/api/timesheets/submissions/[id]/client-reply.post.ts +20 -0
  120. package/server/api/timesheets/submissions/[id]/request-client-approval.post.ts +21 -0
  121. package/server/api/timesheets/submissions/[id]/resubmit.post.ts +10 -0
  122. package/server/api/timesheets/timer/index.delete.ts +18 -0
  123. package/server/api/timesheets/timer/index.post.ts +23 -0
  124. package/server/api/timesheets/weeks/[id]/submissions.post.ts +19 -0
  125. package/server/db/schema/timesheets.ts +383 -0
  126. package/server/plugins/client-sync.ts +30 -0
  127. package/server/plugins/openapi-contracts.ts +57 -0
  128. package/server/utils/timesheet-admin-listing.ts +281 -0
  129. package/server/utils/timesheet-email.ts +221 -0
  130. package/server/utils/timesheet-repository.ts +3096 -0
  131. package/server/utils/timesheet-validation.ts +231 -0
  132. package/shared/client-approval-dashboard.ts +17 -0
  133. package/shared/emails.ts +403 -0
  134. package/shared/feature.ts +184 -0
  135. package/shared/period-lock.ts +8 -0
  136. package/shared/submission-reply.ts +3 -0
  137. package/shared/timer-rounding.ts +2 -0
  138. package/shared/timesheet-dates.ts +23 -0
  139. package/shared/timesheet-errors.ts +13 -0
  140. package/shared/types/timesheet.ts +424 -0
  141. package/tokens.css +25 -0
@@ -0,0 +1,409 @@
1
+ CREATE SCHEMA "timesheets";
2
+ --> statement-breakpoint
3
+ CREATE TYPE "timesheets"."approval_action" AS ENUM('SUBMITTED', 'APPROVED', 'REJECTED', 'REOPENED');--> statement-breakpoint
4
+ CREATE TYPE "timesheets"."client_access_mode" AS ENUM('DISABLED', 'VIEW', 'REVIEW');--> statement-breakpoint
5
+ CREATE TYPE "timesheets"."client_review_action" AS ENUM('APPROVED', 'DISPUTED');--> statement-breakpoint
6
+ CREATE TYPE "timesheets"."client_review_status" AS ENUM('PENDING', 'APPROVED', 'DISPUTED');--> statement-breakpoint
7
+ CREATE TYPE "timesheets"."invoice_email_delivery_status" AS ENUM('PENDING', 'SENT', 'FAILED');--> statement-breakpoint
8
+ CREATE TYPE "timesheets"."invoice_email_purpose" AS ENUM('INVOICE', 'REMINDER');--> statement-breakpoint
9
+ CREATE TYPE "timesheets"."invoice_status" AS ENUM('DRAFT', 'ISSUED', 'PAID', 'VOID');--> statement-breakpoint
10
+ CREATE TYPE "timesheets"."project_status" AS ENUM('ACTIVE', 'ARCHIVED');--> statement-breakpoint
11
+ CREATE TYPE "timesheets"."timesheet_status" AS ENUM('DRAFT', 'SUBMITTED', 'APPROVED', 'REJECTED');--> statement-breakpoint
12
+ CREATE TABLE "timesheets"."activity_type" (
13
+ "id" text PRIMARY KEY NOT NULL,
14
+ "organization_id" text NOT NULL,
15
+ "name" text NOT NULL,
16
+ "billable" boolean DEFAULT true NOT NULL,
17
+ "active" boolean DEFAULT true NOT NULL,
18
+ "created_at" timestamp DEFAULT now() NOT NULL,
19
+ "updated_at" timestamp DEFAULT now() NOT NULL
20
+ );
21
+ --> statement-breakpoint
22
+ CREATE TABLE "timesheets"."internal_approver_assignment" (
23
+ "id" text PRIMARY KEY NOT NULL,
24
+ "organization_id" text NOT NULL,
25
+ "submitter_user_id" text NOT NULL,
26
+ "approver_user_id" text NOT NULL,
27
+ "created_by_id" text NOT NULL,
28
+ "created_at" timestamp DEFAULT now() NOT NULL
29
+ );
30
+ --> statement-breakpoint
31
+ CREATE TABLE "timesheets"."invoice" (
32
+ "id" text PRIMARY KEY NOT NULL,
33
+ "organization_id" text NOT NULL,
34
+ "client_organization_id" text,
35
+ "number" text NOT NULL,
36
+ "status" "timesheets"."invoice_status" DEFAULT 'DRAFT' NOT NULL,
37
+ "currency" text NOT NULL,
38
+ "issue_date" date NOT NULL,
39
+ "due_date" date NOT NULL,
40
+ "subject" text,
41
+ "notes" text,
42
+ "sender_name" text NOT NULL,
43
+ "sender_logo" text,
44
+ "sender_address" text NOT NULL,
45
+ "sender_registration" text,
46
+ "sender_vat_number" text,
47
+ "sender_iban" text,
48
+ "sender_bic" text,
49
+ "recipient_name" text NOT NULL,
50
+ "recipient_address" text NOT NULL,
51
+ "recipient_contact_name" text,
52
+ "recipient_email" text,
53
+ "recipient_locale" text DEFAULT 'nl' NOT NULL,
54
+ "created_by_id" text NOT NULL,
55
+ "issued_at" timestamp,
56
+ "created_at" timestamp DEFAULT now() NOT NULL,
57
+ "updated_at" timestamp DEFAULT now() NOT NULL
58
+ );
59
+ --> statement-breakpoint
60
+ CREATE TABLE "timesheets"."invoice_attachment" (
61
+ "id" text PRIMARY KEY NOT NULL,
62
+ "invoice_id" text NOT NULL,
63
+ "file_name" text NOT NULL,
64
+ "content_type" text NOT NULL,
65
+ "size" integer NOT NULL,
66
+ "content_base64" text NOT NULL,
67
+ "uploaded_by_id" text NOT NULL,
68
+ "created_at" timestamp DEFAULT now() NOT NULL
69
+ );
70
+ --> statement-breakpoint
71
+ CREATE TABLE "timesheets"."invoice_email_delivery" (
72
+ "id" text PRIMARY KEY NOT NULL,
73
+ "invoice_id" text NOT NULL,
74
+ "status" "timesheets"."invoice_email_delivery_status" DEFAULT 'PENDING' NOT NULL,
75
+ "purpose" "timesheets"."invoice_email_purpose" DEFAULT 'INVOICE' NOT NULL,
76
+ "recipient_email" text NOT NULL,
77
+ "cc_emails" text DEFAULT '[]' NOT NULL,
78
+ "locale" text NOT NULL,
79
+ "subject" text NOT NULL,
80
+ "body" text NOT NULL,
81
+ "actor_user_id" text NOT NULL,
82
+ "provider_message_id" text,
83
+ "provider_last_event" text,
84
+ "provider_status_checked_at" timestamp,
85
+ "error_message" text,
86
+ "payload_hash" text NOT NULL,
87
+ "created_at" timestamp DEFAULT now() NOT NULL,
88
+ "updated_at" timestamp DEFAULT now() NOT NULL,
89
+ "sent_at" timestamp
90
+ );
91
+ --> statement-breakpoint
92
+ CREATE TABLE "timesheets"."invoice_history" (
93
+ "id" text PRIMARY KEY NOT NULL,
94
+ "invoice_id" text NOT NULL,
95
+ "action" text NOT NULL,
96
+ "actor_user_id" text NOT NULL,
97
+ "amount_minor" integer,
98
+ "attachment_name" text,
99
+ "created_at" timestamp DEFAULT now() NOT NULL
100
+ );
101
+ --> statement-breakpoint
102
+ CREATE TABLE "timesheets"."invoice_line" (
103
+ "id" text PRIMARY KEY NOT NULL,
104
+ "invoice_id" text NOT NULL,
105
+ "position" integer NOT NULL,
106
+ "description" text NOT NULL,
107
+ "quantity_milli" integer NOT NULL,
108
+ "unit" text DEFAULT 'hour' NOT NULL,
109
+ "unit_price_minor" integer NOT NULL,
110
+ "vat_rate_basis_points" integer DEFAULT 2100 NOT NULL
111
+ );
112
+ --> statement-breakpoint
113
+ CREATE TABLE "timesheets"."invoice_payment" (
114
+ "id" text PRIMARY KEY NOT NULL,
115
+ "invoice_id" text NOT NULL,
116
+ "paid_on" date NOT NULL,
117
+ "amount_minor" integer NOT NULL,
118
+ "reference" text,
119
+ "note" text,
120
+ "created_by_id" text NOT NULL,
121
+ "created_at" timestamp DEFAULT now() NOT NULL
122
+ );
123
+ --> statement-breakpoint
124
+ CREATE TABLE "timesheets"."invoice_time_entry" (
125
+ "id" text PRIMARY KEY NOT NULL,
126
+ "invoice_id" text NOT NULL,
127
+ "invoice_line_id" text NOT NULL,
128
+ "time_entry_id" text NOT NULL
129
+ );
130
+ --> statement-breakpoint
131
+ CREATE TABLE "timesheets"."organization_contact" (
132
+ "id" text PRIMARY KEY NOT NULL,
133
+ "organization_id" text NOT NULL,
134
+ "user_id" text,
135
+ "name" text NOT NULL,
136
+ "email" text NOT NULL,
137
+ "phone" text,
138
+ "job_title" text,
139
+ "created_at" timestamp DEFAULT now() NOT NULL,
140
+ "updated_at" timestamp DEFAULT now() NOT NULL
141
+ );
142
+ --> statement-breakpoint
143
+ CREATE TABLE "timesheets"."organization_invoice_profile" (
144
+ "organization_id" text PRIMARY KEY NOT NULL,
145
+ "address" text DEFAULT '' NOT NULL,
146
+ "registration_number" text,
147
+ "vat_number" text,
148
+ "iban" text,
149
+ "bic" text,
150
+ "invoice_email" text,
151
+ "invoice_email_template" text,
152
+ "preferred_locale" text DEFAULT 'nl' NOT NULL,
153
+ "created_at" timestamp DEFAULT now() NOT NULL,
154
+ "updated_at" timestamp DEFAULT now() NOT NULL
155
+ );
156
+ --> statement-breakpoint
157
+ CREATE TABLE "timesheets"."project" (
158
+ "id" text PRIMARY KEY NOT NULL,
159
+ "organization_id" text NOT NULL,
160
+ "client_organization_id" text NOT NULL,
161
+ "name" text NOT NULL,
162
+ "code" text,
163
+ "status" "timesheets"."project_status" DEFAULT 'ACTIVE' NOT NULL,
164
+ "starts_on" date,
165
+ "ends_on" date,
166
+ "budget_minutes" integer,
167
+ "budget_minor" integer,
168
+ "created_at" timestamp DEFAULT now() NOT NULL,
169
+ "updated_at" timestamp DEFAULT now() NOT NULL
170
+ );
171
+ --> statement-breakpoint
172
+ CREATE TABLE "timesheets"."project_activity" (
173
+ "id" text PRIMARY KEY NOT NULL,
174
+ "project_id" text NOT NULL,
175
+ "activity_type_id" text NOT NULL
176
+ );
177
+ --> statement-breakpoint
178
+ CREATE TABLE "timesheets"."project_person_tariff" (
179
+ "id" text PRIMARY KEY NOT NULL,
180
+ "project_id" text NOT NULL,
181
+ "user_id" text NOT NULL,
182
+ "hourly_rate_minor" integer NOT NULL,
183
+ "created_at" timestamp DEFAULT now() NOT NULL,
184
+ "updated_at" timestamp DEFAULT now() NOT NULL
185
+ );
186
+ --> statement-breakpoint
187
+ CREATE TABLE "timesheets"."team_member_settings" (
188
+ "id" text PRIMARY KEY NOT NULL,
189
+ "organization_id" text NOT NULL,
190
+ "user_id" text NOT NULL,
191
+ "can_enter_time" boolean DEFAULT true NOT NULL,
192
+ "internal_approval_required" boolean DEFAULT true NOT NULL,
193
+ "created_at" timestamp DEFAULT now() NOT NULL,
194
+ "updated_at" timestamp DEFAULT now() NOT NULL
195
+ );
196
+ --> statement-breakpoint
197
+ CREATE TABLE "timesheets"."team_tariff" (
198
+ "id" text PRIMARY KEY NOT NULL,
199
+ "organization_id" text NOT NULL,
200
+ "user_id" text NOT NULL,
201
+ "hourly_rate_minor" integer NOT NULL,
202
+ "created_at" timestamp DEFAULT now() NOT NULL,
203
+ "updated_at" timestamp DEFAULT now() NOT NULL
204
+ );
205
+ --> statement-breakpoint
206
+ CREATE TABLE "timesheets"."time_entry" (
207
+ "id" text PRIMARY KEY NOT NULL,
208
+ "organization_id" text NOT NULL,
209
+ "weekly_timesheet_id" text NOT NULL,
210
+ "user_id" text NOT NULL,
211
+ "project_id" text NOT NULL,
212
+ "client_organization_id" text NOT NULL,
213
+ "activity_type_id" text NOT NULL,
214
+ "entry_date" date NOT NULL,
215
+ "duration_minutes" integer DEFAULT 0 NOT NULL,
216
+ "note" text,
217
+ "billable_snapshot" boolean NOT NULL,
218
+ "hourly_rate_minor_snapshot" integer NOT NULL,
219
+ "currency_snapshot" text NOT NULL,
220
+ "timer_started_at" timestamp,
221
+ "created_at" timestamp DEFAULT now() NOT NULL,
222
+ "updated_at" timestamp DEFAULT now() NOT NULL
223
+ );
224
+ --> statement-breakpoint
225
+ CREATE TABLE "timesheets"."approval_history" (
226
+ "id" text PRIMARY KEY NOT NULL,
227
+ "weekly_timesheet_id" text NOT NULL,
228
+ "action" "timesheets"."approval_action" NOT NULL,
229
+ "actor_user_id" text NOT NULL,
230
+ "comment" text,
231
+ "created_at" timestamp DEFAULT now() NOT NULL
232
+ );
233
+ --> statement-breakpoint
234
+ CREATE TABLE "timesheets"."client_review" (
235
+ "id" text PRIMARY KEY NOT NULL,
236
+ "weekly_timesheet_id" text NOT NULL,
237
+ "client_organization_id" text NOT NULL,
238
+ "status" "timesheets"."client_review_status" DEFAULT 'PENDING' NOT NULL,
239
+ "reviewer_user_id" text,
240
+ "comment" text,
241
+ "version" integer DEFAULT 1 NOT NULL,
242
+ "reviewed_at" timestamp,
243
+ "created_at" timestamp DEFAULT now() NOT NULL,
244
+ "updated_at" timestamp DEFAULT now() NOT NULL
245
+ );
246
+ --> statement-breakpoint
247
+ CREATE TABLE "timesheets"."client_review_history" (
248
+ "id" text PRIMARY KEY NOT NULL,
249
+ "weekly_timesheet_id" text NOT NULL,
250
+ "client_organization_id" text NOT NULL,
251
+ "action" "timesheets"."client_review_action" NOT NULL,
252
+ "actor_user_id" text NOT NULL,
253
+ "comment" text,
254
+ "created_at" timestamp DEFAULT now() NOT NULL
255
+ );
256
+ --> statement-breakpoint
257
+ CREATE TABLE "timesheets"."weekly_timesheet" (
258
+ "id" text PRIMARY KEY NOT NULL,
259
+ "organization_id" text NOT NULL,
260
+ "user_id" text NOT NULL,
261
+ "week_starts_on" date NOT NULL,
262
+ "status" timesheet_status DEFAULT 'DRAFT' NOT NULL,
263
+ "submitted_at" timestamp,
264
+ "reviewed_at" timestamp,
265
+ "reviewed_by_id" text,
266
+ "rejection_comment" text,
267
+ "created_at" timestamp DEFAULT now() NOT NULL,
268
+ "updated_at" timestamp DEFAULT now() NOT NULL
269
+ );
270
+ --> statement-breakpoint
271
+ CREATE TABLE "timesheets"."workspace_client" (
272
+ "id" text PRIMARY KEY NOT NULL,
273
+ "workspace_organization_id" text NOT NULL,
274
+ "client_organization_id" text NOT NULL,
275
+ "access_mode" "timesheets"."client_access_mode" DEFAULT 'DISABLED' NOT NULL,
276
+ "invoice_access_enabled" boolean DEFAULT false NOT NULL,
277
+ "created_at" timestamp DEFAULT now() NOT NULL,
278
+ "updated_at" timestamp DEFAULT now() NOT NULL
279
+ );
280
+ --> statement-breakpoint
281
+ CREATE TABLE "timesheets"."workspace_client_invoice_viewer" (
282
+ "id" text PRIMARY KEY NOT NULL,
283
+ "workspace_client_id" text NOT NULL,
284
+ "user_id" text NOT NULL,
285
+ "created_by_id" text NOT NULL,
286
+ "created_at" timestamp DEFAULT now() NOT NULL
287
+ );
288
+ --> statement-breakpoint
289
+ CREATE TABLE "timesheets"."workspace_client_reviewer" (
290
+ "id" text PRIMARY KEY NOT NULL,
291
+ "workspace_client_id" text NOT NULL,
292
+ "user_id" text NOT NULL,
293
+ "created_by_id" text NOT NULL,
294
+ "created_at" timestamp DEFAULT now() NOT NULL
295
+ );
296
+ --> statement-breakpoint
297
+ CREATE TABLE "timesheets"."workspace_settings" (
298
+ "organization_id" text PRIMARY KEY NOT NULL,
299
+ "currency" text DEFAULT 'EUR' NOT NULL,
300
+ "timezone" text DEFAULT 'Europe/Amsterdam' NOT NULL,
301
+ "default_vat_rate_basis_points" integer DEFAULT 2100 NOT NULL,
302
+ "week_starts_on" integer DEFAULT 1 NOT NULL,
303
+ "workspace_enabled" boolean DEFAULT false NOT NULL,
304
+ "invoicing_enabled" boolean DEFAULT false NOT NULL,
305
+ "internal_approvals_enabled" boolean DEFAULT true NOT NULL,
306
+ "created_at" timestamp DEFAULT now() NOT NULL,
307
+ "updated_at" timestamp DEFAULT now() NOT NULL
308
+ );
309
+ --> statement-breakpoint
310
+ ALTER TABLE "timesheets"."activity_type" ADD CONSTRAINT "activity_type_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
311
+ ALTER TABLE "timesheets"."internal_approver_assignment" ADD CONSTRAINT "internal_approver_assignment_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
312
+ ALTER TABLE "timesheets"."internal_approver_assignment" ADD CONSTRAINT "internal_approver_assignment_submitter_user_id_user_id_fk" FOREIGN KEY ("submitter_user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
313
+ ALTER TABLE "timesheets"."internal_approver_assignment" ADD CONSTRAINT "internal_approver_assignment_approver_user_id_user_id_fk" FOREIGN KEY ("approver_user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
314
+ ALTER TABLE "timesheets"."internal_approver_assignment" ADD CONSTRAINT "internal_approver_assignment_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
315
+ ALTER TABLE "timesheets"."invoice" ADD CONSTRAINT "invoice_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
316
+ ALTER TABLE "timesheets"."invoice" ADD CONSTRAINT "invoice_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
317
+ ALTER TABLE "timesheets"."invoice" ADD CONSTRAINT "invoice_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
318
+ ALTER TABLE "timesheets"."invoice_attachment" ADD CONSTRAINT "invoice_attachment_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
319
+ ALTER TABLE "timesheets"."invoice_attachment" ADD CONSTRAINT "invoice_attachment_uploaded_by_id_user_id_fk" FOREIGN KEY ("uploaded_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
320
+ ALTER TABLE "timesheets"."invoice_email_delivery" ADD CONSTRAINT "invoice_email_delivery_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
321
+ ALTER TABLE "timesheets"."invoice_email_delivery" ADD CONSTRAINT "invoice_email_delivery_actor_user_id_user_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
322
+ ALTER TABLE "timesheets"."invoice_history" ADD CONSTRAINT "invoice_history_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
323
+ ALTER TABLE "timesheets"."invoice_history" ADD CONSTRAINT "invoice_history_actor_user_id_user_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
324
+ ALTER TABLE "timesheets"."invoice_line" ADD CONSTRAINT "invoice_line_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
325
+ ALTER TABLE "timesheets"."invoice_payment" ADD CONSTRAINT "invoice_payment_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
326
+ ALTER TABLE "timesheets"."invoice_payment" ADD CONSTRAINT "invoice_payment_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
327
+ ALTER TABLE "timesheets"."invoice_time_entry" ADD CONSTRAINT "invoice_time_entry_invoice_id_invoice_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "timesheets"."invoice"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
328
+ ALTER TABLE "timesheets"."invoice_time_entry" ADD CONSTRAINT "invoice_time_entry_invoice_line_id_invoice_line_id_fk" FOREIGN KEY ("invoice_line_id") REFERENCES "timesheets"."invoice_line"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
329
+ ALTER TABLE "timesheets"."invoice_time_entry" ADD CONSTRAINT "invoice_time_entry_time_entry_id_time_entry_id_fk" FOREIGN KEY ("time_entry_id") REFERENCES "timesheets"."time_entry"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
330
+ ALTER TABLE "timesheets"."organization_contact" ADD CONSTRAINT "organization_contact_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
331
+ ALTER TABLE "timesheets"."organization_contact" ADD CONSTRAINT "organization_contact_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
332
+ ALTER TABLE "timesheets"."organization_invoice_profile" ADD CONSTRAINT "organization_invoice_profile_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
333
+ ALTER TABLE "timesheets"."project" ADD CONSTRAINT "project_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
334
+ ALTER TABLE "timesheets"."project" ADD CONSTRAINT "project_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
335
+ ALTER TABLE "timesheets"."project_activity" ADD CONSTRAINT "project_activity_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "timesheets"."project"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
336
+ ALTER TABLE "timesheets"."project_activity" ADD CONSTRAINT "project_activity_activity_type_id_activity_type_id_fk" FOREIGN KEY ("activity_type_id") REFERENCES "timesheets"."activity_type"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
337
+ ALTER TABLE "timesheets"."project_person_tariff" ADD CONSTRAINT "project_person_tariff_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "timesheets"."project"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
338
+ ALTER TABLE "timesheets"."project_person_tariff" ADD CONSTRAINT "project_person_tariff_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
339
+ ALTER TABLE "timesheets"."team_member_settings" ADD CONSTRAINT "team_member_settings_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
340
+ ALTER TABLE "timesheets"."team_member_settings" ADD CONSTRAINT "team_member_settings_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
341
+ ALTER TABLE "timesheets"."team_tariff" ADD CONSTRAINT "team_tariff_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
342
+ ALTER TABLE "timesheets"."team_tariff" ADD CONSTRAINT "team_tariff_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
343
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
344
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_weekly_timesheet_id_weekly_timesheet_id_fk" FOREIGN KEY ("weekly_timesheet_id") REFERENCES "timesheets"."weekly_timesheet"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
345
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
346
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "timesheets"."project"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
347
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
348
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_activity_type_id_activity_type_id_fk" FOREIGN KEY ("activity_type_id") REFERENCES "timesheets"."activity_type"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
349
+ ALTER TABLE "timesheets"."approval_history" ADD CONSTRAINT "approval_history_weekly_timesheet_id_weekly_timesheet_id_fk" FOREIGN KEY ("weekly_timesheet_id") REFERENCES "timesheets"."weekly_timesheet"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
350
+ ALTER TABLE "timesheets"."approval_history" ADD CONSTRAINT "approval_history_actor_user_id_user_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
351
+ ALTER TABLE "timesheets"."client_review" ADD CONSTRAINT "client_review_weekly_timesheet_id_weekly_timesheet_id_fk" FOREIGN KEY ("weekly_timesheet_id") REFERENCES "timesheets"."weekly_timesheet"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
352
+ ALTER TABLE "timesheets"."client_review" ADD CONSTRAINT "client_review_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
353
+ ALTER TABLE "timesheets"."client_review" ADD CONSTRAINT "client_review_reviewer_user_id_user_id_fk" FOREIGN KEY ("reviewer_user_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
354
+ ALTER TABLE "timesheets"."client_review_history" ADD CONSTRAINT "client_review_history_weekly_timesheet_id_weekly_timesheet_id_fk" FOREIGN KEY ("weekly_timesheet_id") REFERENCES "timesheets"."weekly_timesheet"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
355
+ ALTER TABLE "timesheets"."client_review_history" ADD CONSTRAINT "client_review_history_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
356
+ ALTER TABLE "timesheets"."client_review_history" ADD CONSTRAINT "client_review_history_actor_user_id_user_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
357
+ ALTER TABLE "timesheets"."weekly_timesheet" ADD CONSTRAINT "weekly_timesheet_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
358
+ ALTER TABLE "timesheets"."weekly_timesheet" ADD CONSTRAINT "weekly_timesheet_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
359
+ ALTER TABLE "timesheets"."weekly_timesheet" ADD CONSTRAINT "weekly_timesheet_reviewed_by_id_user_id_fk" FOREIGN KEY ("reviewed_by_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
360
+ ALTER TABLE "timesheets"."workspace_client" ADD CONSTRAINT "workspace_client_workspace_organization_id_organization_id_fk" FOREIGN KEY ("workspace_organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
361
+ ALTER TABLE "timesheets"."workspace_client" ADD CONSTRAINT "workspace_client_client_organization_id_organization_id_fk" FOREIGN KEY ("client_organization_id") REFERENCES "public"."organization"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
362
+ ALTER TABLE "timesheets"."workspace_client_invoice_viewer" ADD CONSTRAINT "workspace_client_invoice_viewer_workspace_client_id_workspace_client_id_fk" FOREIGN KEY ("workspace_client_id") REFERENCES "timesheets"."workspace_client"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
363
+ ALTER TABLE "timesheets"."workspace_client_invoice_viewer" ADD CONSTRAINT "workspace_client_invoice_viewer_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
364
+ ALTER TABLE "timesheets"."workspace_client_invoice_viewer" ADD CONSTRAINT "workspace_client_invoice_viewer_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
365
+ ALTER TABLE "timesheets"."workspace_client_reviewer" ADD CONSTRAINT "workspace_client_reviewer_workspace_client_id_workspace_client_id_fk" FOREIGN KEY ("workspace_client_id") REFERENCES "timesheets"."workspace_client"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
366
+ ALTER TABLE "timesheets"."workspace_client_reviewer" ADD CONSTRAINT "workspace_client_reviewer_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
367
+ ALTER TABLE "timesheets"."workspace_client_reviewer" ADD CONSTRAINT "workspace_client_reviewer_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
368
+ ALTER TABLE "timesheets"."workspace_settings" ADD CONSTRAINT "workspace_settings_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
369
+ CREATE UNIQUE INDEX "activity_type_org_name_uidx" ON "timesheets"."activity_type" USING btree ("organization_id","name");--> statement-breakpoint
370
+ CREATE INDEX "activity_type_org_idx" ON "timesheets"."activity_type" USING btree ("organization_id");--> statement-breakpoint
371
+ CREATE UNIQUE INDEX "internal_approver_assignment_org_submitter_approver_uidx" ON "timesheets"."internal_approver_assignment" USING btree ("organization_id","submitter_user_id","approver_user_id");--> statement-breakpoint
372
+ CREATE INDEX "internal_approver_assignment_approver_idx" ON "timesheets"."internal_approver_assignment" USING btree ("organization_id","approver_user_id");--> statement-breakpoint
373
+ CREATE INDEX "internal_approver_assignment_submitter_idx" ON "timesheets"."internal_approver_assignment" USING btree ("organization_id","submitter_user_id");--> statement-breakpoint
374
+ CREATE UNIQUE INDEX "invoice_org_number_uidx" ON "timesheets"."invoice" USING btree ("organization_id","number");--> statement-breakpoint
375
+ CREATE INDEX "invoice_org_status_idx" ON "timesheets"."invoice" USING btree ("organization_id","status");--> statement-breakpoint
376
+ CREATE INDEX "invoice_client_idx" ON "timesheets"."invoice" USING btree ("client_organization_id");--> statement-breakpoint
377
+ CREATE INDEX "invoice_attachment_invoice_idx" ON "timesheets"."invoice_attachment" USING btree ("invoice_id");--> statement-breakpoint
378
+ CREATE INDEX "invoice_email_delivery_invoice_idx" ON "timesheets"."invoice_email_delivery" USING btree ("invoice_id","created_at");--> statement-breakpoint
379
+ CREATE UNIQUE INDEX "invoice_email_delivery_pending_invoice_uidx" ON "timesheets"."invoice_email_delivery" USING btree ("invoice_id") WHERE "timesheets"."invoice_email_delivery"."status" = 'PENDING';--> statement-breakpoint
380
+ CREATE INDEX "invoice_history_invoice_idx" ON "timesheets"."invoice_history" USING btree ("invoice_id");--> statement-breakpoint
381
+ CREATE INDEX "invoice_line_invoice_idx" ON "timesheets"."invoice_line" USING btree ("invoice_id");--> statement-breakpoint
382
+ CREATE INDEX "invoice_payment_invoice_idx" ON "timesheets"."invoice_payment" USING btree ("invoice_id");--> statement-breakpoint
383
+ CREATE INDEX "invoice_time_entry_entry_idx" ON "timesheets"."invoice_time_entry" USING btree ("time_entry_id");--> statement-breakpoint
384
+ CREATE INDEX "invoice_time_entry_invoice_idx" ON "timesheets"."invoice_time_entry" USING btree ("invoice_id");--> statement-breakpoint
385
+ CREATE INDEX "organization_contact_org_idx" ON "timesheets"."organization_contact" USING btree ("organization_id");--> statement-breakpoint
386
+ CREATE UNIQUE INDEX "organization_contact_org_email_uidx" ON "timesheets"."organization_contact" USING btree ("organization_id","email");--> statement-breakpoint
387
+ CREATE UNIQUE INDEX "project_org_name_uidx" ON "timesheets"."project" USING btree ("organization_id","name");--> statement-breakpoint
388
+ CREATE INDEX "project_org_status_idx" ON "timesheets"."project" USING btree ("organization_id","status");--> statement-breakpoint
389
+ CREATE INDEX "project_client_idx" ON "timesheets"."project" USING btree ("client_organization_id");--> statement-breakpoint
390
+ CREATE UNIQUE INDEX "project_activity_project_activity_uidx" ON "timesheets"."project_activity" USING btree ("project_id","activity_type_id");--> statement-breakpoint
391
+ CREATE UNIQUE INDEX "project_person_tariff_project_user_uidx" ON "timesheets"."project_person_tariff" USING btree ("project_id","user_id");--> statement-breakpoint
392
+ CREATE UNIQUE INDEX "team_member_settings_org_user_uidx" ON "timesheets"."team_member_settings" USING btree ("organization_id","user_id");--> statement-breakpoint
393
+ CREATE UNIQUE INDEX "team_tariff_org_user_uidx" ON "timesheets"."team_tariff" USING btree ("organization_id","user_id");--> statement-breakpoint
394
+ CREATE INDEX "time_entry_org_user_date_idx" ON "timesheets"."time_entry" USING btree ("organization_id","user_id","entry_date");--> statement-breakpoint
395
+ CREATE INDEX "time_entry_week_idx" ON "timesheets"."time_entry" USING btree ("weekly_timesheet_id");--> statement-breakpoint
396
+ CREATE INDEX "time_entry_project_idx" ON "timesheets"."time_entry" USING btree ("project_id");--> statement-breakpoint
397
+ CREATE INDEX "time_entry_client_idx" ON "timesheets"."time_entry" USING btree ("client_organization_id");--> statement-breakpoint
398
+ CREATE INDEX "approval_history_week_idx" ON "timesheets"."approval_history" USING btree ("weekly_timesheet_id");--> statement-breakpoint
399
+ CREATE UNIQUE INDEX "client_review_week_client_uidx" ON "timesheets"."client_review" USING btree ("weekly_timesheet_id","client_organization_id");--> statement-breakpoint
400
+ CREATE INDEX "client_review_client_status_idx" ON "timesheets"."client_review" USING btree ("client_organization_id","status");--> statement-breakpoint
401
+ CREATE INDEX "client_review_history_week_client_idx" ON "timesheets"."client_review_history" USING btree ("weekly_timesheet_id","client_organization_id","created_at");--> statement-breakpoint
402
+ CREATE UNIQUE INDEX "weekly_timesheet_org_user_week_uidx" ON "timesheets"."weekly_timesheet" USING btree ("organization_id","user_id","week_starts_on");--> statement-breakpoint
403
+ CREATE INDEX "weekly_timesheet_org_status_idx" ON "timesheets"."weekly_timesheet" USING btree ("organization_id","status");--> statement-breakpoint
404
+ CREATE UNIQUE INDEX "workspace_client_workspace_client_uidx" ON "timesheets"."workspace_client" USING btree ("workspace_organization_id","client_organization_id");--> statement-breakpoint
405
+ CREATE INDEX "workspace_client_workspace_idx" ON "timesheets"."workspace_client" USING btree ("workspace_organization_id");--> statement-breakpoint
406
+ CREATE UNIQUE INDEX "workspace_client_invoice_viewer_link_user_uidx" ON "timesheets"."workspace_client_invoice_viewer" USING btree ("workspace_client_id","user_id");--> statement-breakpoint
407
+ CREATE INDEX "workspace_client_invoice_viewer_user_idx" ON "timesheets"."workspace_client_invoice_viewer" USING btree ("user_id");--> statement-breakpoint
408
+ CREATE UNIQUE INDEX "workspace_client_reviewer_link_user_uidx" ON "timesheets"."workspace_client_reviewer" USING btree ("workspace_client_id","user_id");--> statement-breakpoint
409
+ CREATE INDEX "workspace_client_reviewer_user_idx" ON "timesheets"."workspace_client_reviewer" USING btree ("user_id");
@@ -0,0 +1,31 @@
1
+ DO $$
2
+ BEGIN
3
+ -- A clean Timesheets-only installation must not retain invoice objects from the
4
+ -- historical combined baseline. Preserve any populated legacy installation so
5
+ -- the Invoices migration can copy and verify it transactionally first.
6
+ IF to_regclass('timesheets.invoice') IS NOT NULL
7
+ AND NOT EXISTS (SELECT 1 FROM timesheets.invoice)
8
+ AND NOT EXISTS (SELECT 1 FROM timesheets.organization_invoice_profile)
9
+ AND NOT EXISTS (SELECT 1 FROM timesheets.organization_contact)
10
+ AND NOT EXISTS (SELECT 1 FROM timesheets.workspace_client_invoice_viewer)
11
+ AND NOT EXISTS (SELECT 1 FROM timesheets.workspace_client WHERE invoice_access_enabled)
12
+ AND NOT EXISTS (SELECT 1 FROM timesheets.workspace_settings WHERE invoicing_enabled)
13
+ THEN
14
+ DROP TABLE timesheets.invoice_time_entry;
15
+ DROP TABLE timesheets.invoice_email_delivery;
16
+ DROP TABLE timesheets.invoice_attachment;
17
+ DROP TABLE timesheets.invoice_history;
18
+ DROP TABLE timesheets.invoice_payment;
19
+ DROP TABLE timesheets.invoice_line;
20
+ DROP TABLE timesheets.invoice;
21
+ DROP TABLE timesheets.workspace_client_invoice_viewer;
22
+ DROP TABLE timesheets.organization_contact;
23
+ DROP TABLE timesheets.organization_invoice_profile;
24
+ ALTER TABLE timesheets.workspace_client DROP COLUMN invoice_access_enabled;
25
+ ALTER TABLE timesheets.workspace_settings DROP COLUMN invoicing_enabled;
26
+ ALTER TABLE timesheets.workspace_settings DROP COLUMN default_vat_rate_basis_points;
27
+ DROP TYPE timesheets.invoice_email_purpose;
28
+ DROP TYPE timesheets.invoice_email_delivery_status;
29
+ DROP TYPE timesheets.invoice_status;
30
+ END IF;
31
+ END $$;
@@ -0,0 +1,47 @@
1
+ CREATE TABLE "timesheets"."submission" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "weekly_timesheet_id" text NOT NULL,
4
+ "organization_id" text NOT NULL,
5
+ "user_id" text NOT NULL,
6
+ "period_starts_on" date NOT NULL,
7
+ "period_ends_on" date NOT NULL,
8
+ "status" "timesheets"."timesheet_status" DEFAULT 'DRAFT' NOT NULL,
9
+ "submitted_at" timestamp,
10
+ "reviewed_at" timestamp,
11
+ "reviewed_by_id" text,
12
+ "rejection_comment" text,
13
+ "version" integer DEFAULT 1 NOT NULL,
14
+ "created_at" timestamp DEFAULT now() NOT NULL,
15
+ "updated_at" timestamp DEFAULT now() NOT NULL
16
+ );
17
+ --> statement-breakpoint
18
+ ALTER TABLE "timesheets"."submission" ADD CONSTRAINT "submission_weekly_timesheet_id_weekly_timesheet_id_fk" FOREIGN KEY ("weekly_timesheet_id") REFERENCES "timesheets"."weekly_timesheet"("id") ON DELETE cascade;--> statement-breakpoint
19
+ ALTER TABLE "timesheets"."submission" ADD CONSTRAINT "submission_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade;--> statement-breakpoint
20
+ ALTER TABLE "timesheets"."submission" ADD CONSTRAINT "submission_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade;--> statement-breakpoint
21
+ ALTER TABLE "timesheets"."submission" ADD CONSTRAINT "submission_reviewed_by_id_user_id_fk" FOREIGN KEY ("reviewed_by_id") REFERENCES "public"."user"("id") ON DELETE set null;--> statement-breakpoint
22
+ ALTER TABLE "timesheets"."time_entry" ADD COLUMN "submission_id" text;--> statement-breakpoint
23
+ ALTER TABLE "timesheets"."client_review" ADD COLUMN "submission_id" text;--> statement-breakpoint
24
+ ALTER TABLE "timesheets"."client_review_history" ADD COLUMN "submission_id" text;--> statement-breakpoint
25
+ ALTER TABLE "timesheets"."approval_history" ADD COLUMN "submission_id" text;--> statement-breakpoint
26
+ INSERT INTO "timesheets"."submission" ("id", "weekly_timesheet_id", "organization_id", "user_id", "period_starts_on", "period_ends_on", "status", "submitted_at", "reviewed_at", "reviewed_by_id", "rejection_comment", "created_at", "updated_at")
27
+ SELECT 'legacy_' || w."id", w."id", w."organization_id", w."user_id", w."week_starts_on", w."week_starts_on" + 6, w."status", w."submitted_at", w."reviewed_at", w."reviewed_by_id", w."rejection_comment", w."created_at", w."updated_at"
28
+ FROM "timesheets"."weekly_timesheet" w
29
+ WHERE w."status" <> 'DRAFT';--> statement-breakpoint
30
+ UPDATE "timesheets"."time_entry" e SET "submission_id" = 'legacy_' || e."weekly_timesheet_id"
31
+ FROM "timesheets"."weekly_timesheet" w WHERE w."id" = e."weekly_timesheet_id" AND w."status" <> 'DRAFT';--> statement-breakpoint
32
+ UPDATE "timesheets"."client_review" r SET "submission_id" = 'legacy_' || r."weekly_timesheet_id"
33
+ FROM "timesheets"."weekly_timesheet" w WHERE w."id" = r."weekly_timesheet_id" AND w."status" <> 'DRAFT';--> statement-breakpoint
34
+ UPDATE "timesheets"."client_review_history" h SET "submission_id" = 'legacy_' || h."weekly_timesheet_id"
35
+ FROM "timesheets"."weekly_timesheet" w WHERE w."id" = h."weekly_timesheet_id" AND w."status" <> 'DRAFT';--> statement-breakpoint
36
+ UPDATE "timesheets"."approval_history" h SET "submission_id" = 'legacy_' || h."weekly_timesheet_id"
37
+ FROM "timesheets"."weekly_timesheet" w WHERE w."id" = h."weekly_timesheet_id" AND w."status" <> 'DRAFT';--> statement-breakpoint
38
+ ALTER TABLE "timesheets"."time_entry" ADD CONSTRAINT "time_entry_submission_id_submission_id_fk" FOREIGN KEY ("submission_id") REFERENCES "timesheets"."submission"("id") ON DELETE restrict;--> statement-breakpoint
39
+ ALTER TABLE "timesheets"."client_review" ADD CONSTRAINT "client_review_submission_id_submission_id_fk" FOREIGN KEY ("submission_id") REFERENCES "timesheets"."submission"("id") ON DELETE cascade;--> statement-breakpoint
40
+ ALTER TABLE "timesheets"."client_review_history" ADD CONSTRAINT "client_review_history_submission_id_submission_id_fk" FOREIGN KEY ("submission_id") REFERENCES "timesheets"."submission"("id") ON DELETE cascade;--> statement-breakpoint
41
+ ALTER TABLE "timesheets"."approval_history" ADD CONSTRAINT "approval_history_submission_id_submission_id_fk" FOREIGN KEY ("submission_id") REFERENCES "timesheets"."submission"("id") ON DELETE cascade;--> statement-breakpoint
42
+ DROP INDEX IF EXISTS "timesheets"."client_review_week_client_uidx";--> statement-breakpoint
43
+ CREATE UNIQUE INDEX "client_review_submission_client_uidx" ON "timesheets"."client_review" USING btree ("submission_id", "client_organization_id");--> statement-breakpoint
44
+ CREATE INDEX "submission_week_idx" ON "timesheets"."submission" USING btree ("weekly_timesheet_id");--> statement-breakpoint
45
+ CREATE INDEX "submission_org_status_idx" ON "timesheets"."submission" USING btree ("organization_id", "status");--> statement-breakpoint
46
+ CREATE INDEX "submission_user_period_idx" ON "timesheets"."submission" USING btree ("user_id", "period_starts_on", "period_ends_on");--> statement-breakpoint
47
+ CREATE INDEX "time_entry_submission_idx" ON "timesheets"."time_entry" USING btree ("submission_id");
@@ -0,0 +1,26 @@
1
+ INSERT INTO "timesheets"."workspace_client" (
2
+ "id",
3
+ "workspace_organization_id",
4
+ "client_organization_id",
5
+ "access_mode",
6
+ "created_at",
7
+ "updated_at"
8
+ )
9
+ SELECT
10
+ md5(provider."id" || ':' || client."id" || ':timesheets'),
11
+ provider."id",
12
+ client."id",
13
+ 'DISABLED',
14
+ now(),
15
+ now()
16
+ FROM "organization" provider
17
+ CROSS JOIN "organization" client
18
+ INNER JOIN "clients"."client_profile" profile ON profile."organization_id" = client."id"
19
+ INNER JOIN "clients"."client_module" module
20
+ ON module."organization_id" = client."id"
21
+ AND module."module_id" = 'timesheets'
22
+ AND module."enabled" = true
23
+ WHERE provider."organization_type" = 'PROVIDER'
24
+ AND client."organization_type" = 'CLIENT'
25
+ AND profile."archived_at" IS NULL
26
+ ON CONFLICT ("workspace_organization_id", "client_organization_id") DO NOTHING;
@@ -0,0 +1 @@
1
+ ALTER TYPE "timesheets"."client_review_action" ADD VALUE IF NOT EXISTS 'SUBMITTED';
@@ -0,0 +1 @@
1
+ ALTER TABLE "timesheets"."workspace_settings" ADD COLUMN IF NOT EXISTS "timer_rounding_minutes" integer DEFAULT 1 NOT NULL CHECK ("timer_rounding_minutes" BETWEEN 1 AND 60);