@primocaredentgroup/elettromedicali 0.1.0 → 0.1.1

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 (150) hide show
  1. package/dist/client/index.d.ts +0 -2
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +2 -28
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/api.d.ts +4 -4
  6. package/dist/component/_generated/api.d.ts.map +1 -1
  7. package/dist/component/_generated/component.d.ts +165 -218
  8. package/dist/component/_generated/component.d.ts.map +1 -1
  9. package/dist/component/contracts.d.ts +9 -9
  10. package/dist/component/contracts.d.ts.map +1 -1
  11. package/dist/component/contracts.js +7 -13
  12. package/dist/component/contracts.js.map +1 -1
  13. package/dist/component/crons.d.ts.map +1 -1
  14. package/dist/component/crons.js +1 -2
  15. package/dist/component/crons.js.map +1 -1
  16. package/dist/component/dashboardStats.d.ts +8 -3
  17. package/dist/component/dashboardStats.d.ts.map +1 -1
  18. package/dist/component/dashboardStats.js +24 -39
  19. package/dist/component/dashboardStats.js.map +1 -1
  20. package/dist/component/dashboardStatsCache.d.ts +5 -11
  21. package/dist/component/dashboardStatsCache.d.ts.map +1 -1
  22. package/dist/component/dashboardStatsCache.js +12 -53
  23. package/dist/component/dashboardStatsCache.js.map +1 -1
  24. package/dist/component/deviceCategories.d.ts +22 -15
  25. package/dist/component/deviceCategories.d.ts.map +1 -1
  26. package/dist/component/deviceCategories.js +10 -4
  27. package/dist/component/deviceCategories.js.map +1 -1
  28. package/dist/component/deviceQuestions.d.ts +36 -27
  29. package/dist/component/deviceQuestions.d.ts.map +1 -1
  30. package/dist/component/deviceQuestions.js +22 -5
  31. package/dist/component/deviceQuestions.js.map +1 -1
  32. package/dist/component/deviceRepairHistory.d.ts +3 -3
  33. package/dist/component/deviceRepairHistory.js +1 -1
  34. package/dist/component/deviceRepairHistory.js.map +1 -1
  35. package/dist/component/deviceStatus.d.ts +8 -57
  36. package/dist/component/deviceStatus.d.ts.map +1 -1
  37. package/dist/component/deviceStatus.js +32 -30
  38. package/dist/component/deviceStatus.js.map +1 -1
  39. package/dist/component/devices.d.ts +39 -22
  40. package/dist/component/devices.d.ts.map +1 -1
  41. package/dist/component/devices.js +85 -96
  42. package/dist/component/devices.js.map +1 -1
  43. package/dist/component/emailHelpers.d.ts +10 -3
  44. package/dist/component/emailHelpers.d.ts.map +1 -1
  45. package/dist/component/emailHelpers.js +9 -20
  46. package/dist/component/emailHelpers.js.map +1 -1
  47. package/dist/component/emails.d.ts +5 -5
  48. package/dist/component/emails.js +2 -2
  49. package/dist/component/emails.js.map +1 -1
  50. package/dist/component/http.d.ts.map +1 -1
  51. package/dist/component/http.js +3 -108
  52. package/dist/component/http.js.map +1 -1
  53. package/dist/component/migrationHelpers.d.ts +29 -0
  54. package/dist/component/migrationHelpers.d.ts.map +1 -0
  55. package/dist/component/migrationHelpers.js +84 -0
  56. package/dist/component/migrationHelpers.js.map +1 -0
  57. package/dist/component/roles.d.ts +1 -0
  58. package/dist/component/roles.d.ts.map +1 -1
  59. package/dist/component/roles.js +5 -6
  60. package/dist/component/roles.js.map +1 -1
  61. package/dist/component/schema.d.ts +69 -150
  62. package/dist/component/schema.d.ts.map +1 -1
  63. package/dist/component/schema.js +35 -88
  64. package/dist/component/schema.js.map +1 -1
  65. package/dist/component/slaMonitoring.d.ts +16 -30
  66. package/dist/component/slaMonitoring.d.ts.map +1 -1
  67. package/dist/component/slaMonitoring.js +48 -99
  68. package/dist/component/slaMonitoring.js.map +1 -1
  69. package/dist/component/spareParts.d.ts +11 -48
  70. package/dist/component/spareParts.d.ts.map +1 -1
  71. package/dist/component/spareParts.js +41 -11
  72. package/dist/component/spareParts.js.map +1 -1
  73. package/dist/component/suppliers.d.ts +38 -19
  74. package/dist/component/suppliers.d.ts.map +1 -1
  75. package/dist/component/suppliers.js +63 -44
  76. package/dist/component/suppliers.js.map +1 -1
  77. package/dist/component/ticketComments.d.ts +18 -12
  78. package/dist/component/ticketComments.d.ts.map +1 -1
  79. package/dist/component/ticketComments.js +28 -59
  80. package/dist/component/ticketComments.js.map +1 -1
  81. package/dist/component/ticketDeviceData.d.ts +63 -0
  82. package/dist/component/ticketDeviceData.d.ts.map +1 -0
  83. package/dist/component/ticketDeviceData.js +103 -0
  84. package/dist/component/ticketDeviceData.js.map +1 -0
  85. package/dist/component/ticketExport.d.ts +22 -40
  86. package/dist/component/ticketExport.d.ts.map +1 -1
  87. package/dist/component/ticketExport.js +43 -109
  88. package/dist/component/ticketExport.js.map +1 -1
  89. package/dist/component/ticketHistory.d.ts +4 -4
  90. package/dist/component/ticketHistory.d.ts.map +1 -1
  91. package/dist/component/ticketHistory.js +6 -9
  92. package/dist/component/ticketHistory.js.map +1 -1
  93. package/dist/component/ticketMacros.d.ts +19 -18
  94. package/dist/component/ticketMacros.d.ts.map +1 -1
  95. package/dist/component/ticketMacros.js +24 -30
  96. package/dist/component/ticketMacros.js.map +1 -1
  97. package/dist/component/ticketStatuses.d.ts +1 -0
  98. package/dist/component/ticketStatuses.d.ts.map +1 -1
  99. package/dist/component/ticketStatuses.js +5 -6
  100. package/dist/component/ticketStatuses.js.map +1 -1
  101. package/dist/component/ticketTriggers.d.ts +36 -16
  102. package/dist/component/ticketTriggers.d.ts.map +1 -1
  103. package/dist/component/ticketTriggers.js +115 -153
  104. package/dist/component/ticketTriggers.js.map +1 -1
  105. package/dist/component/userProfiles.d.ts +25 -120
  106. package/dist/component/userProfiles.d.ts.map +1 -1
  107. package/dist/component/userProfiles.js +73 -384
  108. package/dist/component/userProfiles.js.map +1 -1
  109. package/dist/test.d.ts +69 -150
  110. package/dist/test.d.ts.map +1 -1
  111. package/package.json +12 -3
  112. package/src/client/index.ts +2 -30
  113. package/src/component/_generated/api.ts +4 -4
  114. package/src/component/_generated/component.ts +228 -350
  115. package/src/component/contracts.ts +7 -14
  116. package/src/component/crons.ts +2 -7
  117. package/src/component/dashboardStats.ts +24 -41
  118. package/src/component/dashboardStatsCache.ts +12 -61
  119. package/src/component/deviceCategories.ts +12 -4
  120. package/src/component/deviceQuestions.ts +28 -5
  121. package/src/component/deviceRepairHistory.ts +1 -1
  122. package/src/component/deviceStatus.ts +43 -45
  123. package/src/component/devices.ts +87 -106
  124. package/src/component/emailHelpers.ts +9 -19
  125. package/src/component/emails.ts +2 -2
  126. package/src/component/http.ts +3 -108
  127. package/src/component/migrationHelpers.ts +96 -0
  128. package/src/component/roles.ts +5 -6
  129. package/src/component/schema.ts +35 -93
  130. package/src/component/slaMonitoring.ts +52 -107
  131. package/src/component/spareParts.ts +46 -12
  132. package/src/component/suppliers.ts +71 -48
  133. package/src/component/ticketComments.ts +28 -71
  134. package/src/component/ticketDeviceData.ts +113 -0
  135. package/src/component/ticketExport.ts +52 -137
  136. package/src/component/ticketHistory.ts +6 -9
  137. package/src/component/ticketMacros.ts +25 -37
  138. package/src/component/ticketStatuses.ts +5 -6
  139. package/src/component/ticketTriggers.ts +121 -217
  140. package/src/component/userProfiles.ts +67 -451
  141. package/dist/component/clinics.d.ts +0 -103
  142. package/dist/component/clinics.d.ts.map +0 -1
  143. package/dist/component/clinics.js +0 -126
  144. package/dist/component/clinics.js.map +0 -1
  145. package/dist/component/maintenanceTasks.d.ts +0 -733
  146. package/dist/component/maintenanceTasks.d.ts.map +0 -1
  147. package/dist/component/maintenanceTasks.js +0 -937
  148. package/dist/component/maintenanceTasks.js.map +0 -1
  149. package/src/component/clinics.ts +0 -136
  150. package/src/component/maintenanceTasks.ts +0 -1003
@@ -3,183 +3,97 @@ import { query } from './_generated/server';
3
3
 
4
4
  export const exportTickets = query({
5
5
  args: {
6
- statuses: v.optional(v.array(v.string())),
7
- priorities: v.optional(v.array(v.string())),
8
- clinicIds: v.optional(v.array(v.id('clinics'))),
9
- supplierIds: v.optional(v.array(v.id('suppliers'))),
10
- createdByEmail: v.optional(v.string()),
11
- ticketNumber: v.optional(v.string()),
12
- dateFrom: v.optional(v.number()),
13
- dateTo: v.optional(v.number()),
14
- slaBreached: v.optional(v.boolean()),
15
- isExternal: v.optional(v.boolean()),
16
- needsAssignment: v.optional(v.boolean()),
17
- hasDevice: v.optional(v.boolean()),
18
- deviceCategory: v.optional(v.string()),
19
- deviceBrand: v.optional(v.string()),
6
+ tickets: v.array(v.any()),
7
+ clinicDataMap: v.optional(v.any()),
20
8
  },
21
9
  handler: async (ctx, args) => {
22
- let tickets = await ctx.db.query('maintenance_tasks').order('desc').take(1500);
10
+ const tickets = args.tickets;
23
11
 
24
- if (args.statuses && args.statuses.length > 0) {
25
- tickets = tickets.filter(t => args.statuses!.includes(t.status));
26
- }
27
-
28
- if (args.priorities && args.priorities.length > 0) {
29
- tickets = tickets.filter(t => t.priority && args.priorities!.includes(t.priority));
30
- }
31
-
32
- if (args.clinicIds && args.clinicIds.length > 0) {
33
- tickets = tickets.filter(t => args.clinicIds!.includes(t.clinicId));
34
- }
35
-
36
- if (args.supplierIds && args.supplierIds.length > 0) {
37
- tickets = tickets.filter(t => t.supplierId && args.supplierIds!.includes(t.supplierId));
38
- }
39
-
40
- if (args.createdByEmail) {
41
- const emailLower = args.createdByEmail.toLowerCase();
42
- tickets = tickets.filter(t =>
43
- t.createdByEmail?.toLowerCase().includes(emailLower)
44
- );
45
- }
46
-
47
- if (args.ticketNumber) {
48
- const numLower = args.ticketNumber.toLowerCase();
49
- tickets = tickets.filter(t =>
50
- t.ticketNumber?.toLowerCase().includes(numLower)
51
- );
52
- }
53
-
54
- if (args.dateFrom) {
55
- tickets = tickets.filter(t => t.created_at >= args.dateFrom!);
56
- }
57
-
58
- if (args.dateTo) {
59
- tickets = tickets.filter(t => t.created_at <= args.dateTo!);
60
- }
61
-
62
- if (args.slaBreached !== undefined) {
63
- tickets = tickets.filter(t => t.slaBreached === args.slaBreached);
64
- }
65
-
66
- if (args.isExternal !== undefined) {
67
- tickets = tickets.filter(t => t.isExternal === args.isExternal);
68
- }
69
-
70
- if (args.needsAssignment !== undefined) {
71
- tickets = tickets.filter(t => t.needsAssignment === args.needsAssignment);
72
- }
73
-
74
- if (args.hasDevice !== undefined) {
75
- if (args.hasDevice) {
76
- tickets = tickets.filter(t => t.deviceId);
77
- } else {
78
- tickets = tickets.filter(t => !t.deviceId);
79
- }
80
- }
81
-
82
- const clinicIds = [...new Set(tickets.map(t => t.clinicId))].slice(0, 300);
83
- const supplierIds = [...new Set(tickets.filter(t => t.supplierId).map(t => t.supplierId!))].slice(0, 300);
84
- const deviceIds = [...new Set(tickets.filter(t => t.deviceId).map(t => t.deviceId!))].slice(0, 500);
85
-
86
- const clinicsMap = new Map();
87
- for (const id of clinicIds) {
88
- const clinic = await ctx.db.get(id);
89
- if (clinic) clinicsMap.set(id, clinic);
90
- }
12
+ const supplierIds = [...new Set(tickets.filter((t: any) => t.supplierId).map((t: any) => t.supplierId))].slice(0, 300);
91
13
 
92
14
  const suppliersMap = new Map();
93
15
  for (const id of supplierIds) {
94
- const supplier = await ctx.db.get(id);
95
- if (supplier) suppliersMap.set(id, supplier);
96
- }
16
+ try {
17
+ const supplier = await ctx.db.get(id);
18
+ if (supplier) suppliersMap.set(id, supplier);
19
+ } catch { /* skip invalid IDs */ }
20
+ }
21
+
22
+ const ticketIds = tickets.map((t: any) => t._id?.toString() || t.ticketId);
23
+ const deviceDataEntries = await Promise.all(
24
+ ticketIds.map(async (tid: string) =>
25
+ ctx.db.query('ticket_device_data')
26
+ .withIndex('by_ticketId', q => q.eq('ticketId', tid))
27
+ .first()
28
+ )
29
+ );
30
+ const validDeviceData = deviceDataEntries.filter(Boolean);
31
+ const deviceDataMap = new Map(validDeviceData.map(d => [d!.ticketId, d!]));
32
+
33
+ const deviceIds = [...new Set(
34
+ validDeviceData.filter((d): d is NonNullable<typeof d> => d != null && !!d.deviceId).map(d => d.deviceId!)
35
+ )].slice(0, 500);
97
36
 
98
37
  const devicesMap = new Map();
99
38
  for (const id of deviceIds) {
100
39
  const device = await ctx.db.get(id);
101
- if (device) devicesMap.set(id, device);
40
+ if (device) devicesMap.set(id.toString(), device);
102
41
  }
103
42
 
104
- if (args.deviceCategory || args.deviceBrand) {
105
- tickets = tickets.filter(t => {
106
- if (!t.deviceId) return false;
107
- const device = devicesMap.get(t.deviceId);
108
- if (!device) return false;
109
-
110
- if (args.deviceCategory && device.category !== args.deviceCategory) {
111
- return false;
112
- }
113
- if (args.deviceBrand && device.brand !== args.deviceBrand) {
114
- return false;
115
- }
116
- return true;
117
- });
43
+ const clinicsMap = new Map();
44
+ if (args.clinicDataMap && typeof args.clinicDataMap === 'object') {
45
+ for (const [id, data] of Object.entries(args.clinicDataMap)) {
46
+ clinicsMap.set(id, data);
47
+ }
118
48
  }
119
49
 
120
50
  const statuses = await ctx.db.query('ticket_statuses').collect();
121
51
  const statusMap = new Map(statuses.map(s => [s.name, s.label]));
122
52
 
123
- const enrichedTickets = tickets.map(t => {
53
+ const enrichedTickets = tickets.map((t: any) => {
124
54
  const clinic = clinicsMap.get(t.clinicId);
125
55
  const supplier = t.supplierId ? suppliersMap.get(t.supplierId) : null;
126
- const device = t.deviceId ? devicesMap.get(t.deviceId) : null;
56
+ const dd = deviceDataMap.get(t._id?.toString() || t.ticketId);
57
+ const device = dd?.deviceId ? devicesMap.get(dd.deviceId.toString()) : null;
127
58
 
128
59
  return {
129
- _id: t._id,
60
+ _id: t._id || t.ticketId,
130
61
  ticketNumber: t.ticketNumber || '-',
131
-
132
62
  title: t.title || '-',
133
63
  description: t.description,
134
64
  status: t.status,
135
65
  statusLabel: statusMap.get(t.status) || t.status,
136
66
  priority: t.priority || '-',
137
-
138
67
  createdByEmail: t.createdByEmail || '-',
139
- created_by: t.created_by,
140
-
141
- created_at: t.created_at,
142
- createdAtFormatted: new Date(t.created_at).toLocaleString('it-IT'),
143
- updated_at: t.updated_at,
144
- updatedAtFormatted: new Date(t.updated_at).toLocaleString('it-IT'),
145
-
68
+ created_at: t.created_at || t.lastActivityAt,
69
+ createdAtFormatted: t.created_at ? new Date(t.created_at).toLocaleString('it-IT') : '-',
70
+ updated_at: t.updated_at || t.lastActivityAt,
71
+ updatedAtFormatted: t.updated_at ? new Date(t.updated_at).toLocaleString('it-IT') : '-',
146
72
  clinicId: t.clinicId,
147
- clinicName: clinic?.name || '-',
148
- clinicAddress: clinic?.address || '-',
149
- clinicRegion: clinic?.region || '-',
150
-
73
+ clinicName: (clinic as any)?.name || '-',
74
+ clinicAddress: (clinic as any)?.address || '-',
75
+ clinicRegion: (clinic as any)?.region || '-',
151
76
  supplierId: t.supplierId || null,
152
77
  supplierName: supplier?.name || '-',
153
78
  supplierEmail: supplier?.contact_email || '-',
154
-
155
- deviceId: t.deviceId || null,
79
+ deviceId: dd?.deviceId || null,
156
80
  deviceName: device?.name || '-',
157
81
  deviceCategory: device?.category || '-',
158
82
  deviceBrand: device?.brand || '-',
159
83
  deviceModel: device?.model || '-',
160
84
  deviceSerialNumber: device?.serial_number || '-',
161
-
162
85
  slaDeadline: t.slaDeadline || null,
163
86
  slaDeadlineFormatted: t.slaDeadline ? new Date(t.slaDeadline).toLocaleString('it-IT') : '-',
164
87
  slaBreached: t.slaBreached || false,
165
-
166
- isExternal: t.isExternal || false,
167
- needsAssignment: t.needsAssignment || false,
168
-
88
+ isExternal: t.isExternalApi || false,
169
89
  notes: t.notes || '-',
170
90
  customFields: t.customFields || {},
171
-
172
- externalTicketId: t.externalTicketId || '-',
173
- externalTicketNumber: t.externalTicketNumber || '-',
174
- importSource: t.importSource || '-',
175
-
176
- photosCount: t.photos?.length || 0,
177
-
178
- deviceQuestionAnswers: t.deviceQuestionAnswers || [],
91
+ photosCount: dd?.photoStorageIds?.length || 0,
92
+ deviceQuestionAnswers: dd?.deviceQuestionAnswers || [],
179
93
  };
180
94
  });
181
95
 
182
- enrichedTickets.sort((a, b) => b.created_at - a.created_at);
96
+ enrichedTickets.sort((a: any, b: any) => (b.created_at || 0) - (a.created_at || 0));
183
97
 
184
98
  return {
185
99
  tickets: enrichedTickets,
@@ -189,13 +103,14 @@ export const exportTickets = query({
189
103
  });
190
104
 
191
105
  export const getFilterOptions = query({
192
- args: {},
193
- handler: async (ctx) => {
106
+ args: {
107
+ clinics: v.optional(v.array(v.any())),
108
+ },
109
+ handler: async (ctx, args) => {
194
110
  const statuses = await ctx.db.query('ticket_statuses').collect();
195
111
  const statusOptions = statuses.map(s => ({ value: s.name, label: s.label }));
196
112
 
197
- const clinics = await ctx.db.query('clinics').collect();
198
- const clinicOptions = clinics.map(c => ({ value: c._id, label: c.name }));
113
+ const clinicOptions = args.clinics || [];
199
114
 
200
115
  const suppliers = await ctx.db.query('suppliers').collect();
201
116
  const supplierOptions = suppliers.map(s => ({ value: s._id, label: s.name }));
@@ -211,7 +126,7 @@ export const getFilterOptions = query({
211
126
  { value: 'medium', label: 'Media' },
212
127
  { value: 'high', label: 'Alta' },
213
128
  ],
214
- clinics: clinicOptions.sort((a, b) => a.label.localeCompare(b.label)),
129
+ clinics: clinicOptions,
215
130
  suppliers: supplierOptions.sort((a, b) => a.label.localeCompare(b.label)),
216
131
  deviceCategories: categories.sort(),
217
132
  deviceBrands: brands.sort(),
@@ -1,24 +1,22 @@
1
1
  import { v } from 'convex/values';
2
2
  import { query, mutation, internalMutation } from './_generated/server';
3
3
 
4
- // Get ticket history (admin only)
5
4
  export const getTicketHistory = query({
6
- args: { ticketId: v.id('maintenance_tasks') },
5
+ args: { ticketId: v.string() },
7
6
  handler: async (ctx, args) => {
8
7
  const history = await ctx.db
9
8
  .query('ticket_history')
10
- .withIndex('by_ticketId', (q: any) => q.eq('ticketId', args.ticketId))
9
+ .withIndex('by_ticketId_timestamp', (q: any) => q.eq('ticketId', args.ticketId))
10
+ .order('desc')
11
11
  .take(200);
12
12
 
13
- // Sort by timestamp descending (most recent first)
14
- return history.sort((a, b) => b.timestamp - a.timestamp);
13
+ return history;
15
14
  },
16
15
  });
17
16
 
18
- // Add history entry (internal mutation - called by other functions)
19
17
  export const addHistoryEntry = internalMutation({
20
18
  args: {
21
- ticketId: v.id('maintenance_tasks'),
19
+ ticketId: v.string(),
22
20
  eventType: v.union(
23
21
  v.literal('created'),
24
22
  v.literal('status_change'),
@@ -53,10 +51,9 @@ export const addHistoryEntry = internalMutation({
53
51
  },
54
52
  });
55
53
 
56
- // Public mutation to add history (for use from frontend/other mutations)
57
54
  export const recordHistoryEvent = mutation({
58
55
  args: {
59
- ticketId: v.id('maintenance_tasks'),
56
+ ticketId: v.string(),
60
57
  eventType: v.union(
61
58
  v.literal('created'),
62
59
  v.literal('status_change'),
@@ -1,10 +1,9 @@
1
1
  import { v } from 'convex/values';
2
2
  import { query, mutation } from './_generated/server';
3
- import type { Id } from './_generated/dataModel';
4
3
 
5
4
  export const listMacros = query({
6
5
  args: {
7
- userProfileId: v.optional(v.id('user_profiles')),
6
+ userProfileId: v.optional(v.string()),
8
7
  },
9
8
  handler: async (ctx, args) => {
10
9
  const allMacros = await ctx.db.query('ticket_macros').collect();
@@ -13,25 +12,18 @@ export const listMacros = query({
13
12
  m.isGlobal || (args.userProfileId && m.createdBy === args.userProfileId)
14
13
  );
15
14
 
16
- const macrosWithCreator = await Promise.all(
17
- filteredMacros.map(async (macro) => {
18
- const creator = await ctx.db.get(macro.createdBy);
19
- return {
20
- ...macro,
21
- creatorName: creator?.name || creator?.email || 'Sconosciuto',
22
- creatorEmail: creator?.email,
23
- isOwner: args.userProfileId ? macro.createdBy === args.userProfileId : false,
24
- };
25
- })
26
- );
27
-
28
- return macrosWithCreator;
15
+ return filteredMacros.map((macro) => ({
16
+ ...macro,
17
+ creatorName: macro.createdBy,
18
+ creatorEmail: undefined,
19
+ isOwner: args.userProfileId ? macro.createdBy === args.userProfileId : false,
20
+ }));
29
21
  },
30
22
  });
31
23
 
32
24
  export const listActiveMacros = query({
33
25
  args: {
34
- userProfileId: v.optional(v.id('user_profiles')),
26
+ userProfileId: v.optional(v.string()),
35
27
  },
36
28
  handler: async (ctx, args) => {
37
29
  const allMacros = await ctx.db
@@ -53,7 +45,7 @@ export const listActiveMacros = query({
53
45
  export const getMacro = query({
54
46
  args: {
55
47
  macroId: v.id('ticket_macros'),
56
- userProfileId: v.optional(v.id('user_profiles')),
48
+ userProfileId: v.optional(v.string()),
57
49
  },
58
50
  handler: async (ctx, args) => {
59
51
  const macro = await ctx.db.get(args.macroId);
@@ -77,7 +69,7 @@ export const createMacro = mutation({
77
69
  actions: v.object({
78
70
  changeStatus: v.optional(v.string()),
79
71
  assignSupplier: v.optional(v.id('suppliers')),
80
- assignUser: v.optional(v.id('user_profiles')),
72
+ assignUser: v.optional(v.string()),
81
73
  setSlaHours: v.optional(v.number()),
82
74
  applySlaRule: v.optional(v.boolean()),
83
75
  addNote: v.optional(v.string()),
@@ -87,7 +79,7 @@ export const createMacro = mutation({
87
79
  })),
88
80
  setPriority: v.optional(v.string()),
89
81
  }),
90
- createdBy: v.id('user_profiles'),
82
+ createdBy: v.string(),
91
83
  },
92
84
  handler: async (ctx, args) => {
93
85
  const macroId = await ctx.db.insert('ticket_macros', {
@@ -115,7 +107,7 @@ export const updateMacro = mutation({
115
107
  actions: v.optional(v.object({
116
108
  changeStatus: v.optional(v.string()),
117
109
  assignSupplier: v.optional(v.id('suppliers')),
118
- assignUser: v.optional(v.id('user_profiles')),
110
+ assignUser: v.optional(v.string()),
119
111
  setSlaHours: v.optional(v.number()),
120
112
  applySlaRule: v.optional(v.boolean()),
121
113
  addNote: v.optional(v.string()),
@@ -181,7 +173,7 @@ export const duplicateMacro = mutation({
181
173
  args: {
182
174
  macroId: v.id('ticket_macros'),
183
175
  newName: v.string(),
184
- createdBy: v.id('user_profiles'),
176
+ createdBy: v.string(),
185
177
  },
186
178
  handler: async (ctx, args) => {
187
179
  const macro = await ctx.db.get(args.macroId);
@@ -207,8 +199,8 @@ export const duplicateMacro = mutation({
207
199
  export const executeMacro = mutation({
208
200
  args: {
209
201
  macroId: v.id('ticket_macros'),
210
- ticketId: v.id('maintenance_tasks'),
211
- userProfileId: v.optional(v.id('user_profiles')),
202
+ ticketId: v.string(),
203
+ userProfileId: v.optional(v.string()),
212
204
  userAuth0Id: v.optional(v.string()),
213
205
  userName: v.optional(v.string()),
214
206
  userEmail: v.optional(v.string()),
@@ -227,13 +219,8 @@ export const executeMacro = mutation({
227
219
  throw new Error('Non hai accesso a questa macro');
228
220
  }
229
221
 
230
- const ticket = await ctx.db.get(args.ticketId);
231
- if (!ticket) {
232
- throw new Error('Ticket non trovato');
233
- }
234
-
235
222
  const actions = macro.actions;
236
- const updates: any = { updated_at: Date.now() };
223
+ const updates: any = {};
237
224
  const executedActions: string[] = [];
238
225
 
239
226
  if (actions.changeStatus) {
@@ -247,16 +234,18 @@ export const executeMacro = mutation({
247
234
  }
248
235
 
249
236
  if (actions.assignUser) {
250
- const user = await ctx.db.get(actions.assignUser);
251
- if (user?.supplierId) {
252
- updates.supplierId = user.supplierId;
237
+ const userSettings = await ctx.db
238
+ .query('user_profiles')
239
+ .withIndex('by_auth0Id', (q: any) => q.eq('auth0Id', actions.assignUser))
240
+ .first();
241
+ if (userSettings?.supplierId) {
242
+ updates.supplierId = userSettings.supplierId;
253
243
  }
254
244
  executedActions.push('Utente assegnato');
255
245
  }
256
246
 
257
247
  if (actions.setSlaHours) {
258
- updates.slaHours = actions.setSlaHours;
259
- updates.slaDueDate = Date.now() + (actions.setSlaHours * 60 * 60 * 1000);
248
+ updates.slaDeadline = Date.now() + (actions.setSlaHours * 60 * 60 * 1000);
260
249
  executedActions.push(`SLA impostato a ${actions.setSlaHours} ore`);
261
250
  }
262
251
 
@@ -265,11 +254,9 @@ export const executeMacro = mutation({
265
254
  executedActions.push(`Priorità impostata a: ${actions.setPriority}`);
266
255
  }
267
256
 
268
- await ctx.db.patch(args.ticketId, updates);
269
-
270
257
  if (actions.addNote) {
271
258
  await ctx.db.insert('ticket_comments', {
272
- taskId: args.ticketId,
259
+ ticketId: args.ticketId,
273
260
  authorId: args.userAuth0Id || 'system',
274
261
  authorName: args.userName || args.userEmail || 'Sistema',
275
262
  authorEmail: args.userEmail || 'system@app',
@@ -286,6 +273,7 @@ export const executeMacro = mutation({
286
273
  ticketId: args.ticketId,
287
274
  macroName: macro.name,
288
275
  executedActions,
276
+ ticketUpdates: updates,
289
277
  };
290
278
  },
291
279
  });
@@ -74,15 +74,14 @@ export const updateTicketStatus = mutation({
74
74
  });
75
75
 
76
76
  export const deleteTicketStatus = mutation({
77
- args: { statusId: v.id('ticket_statuses') },
77
+ args: {
78
+ statusId: v.id('ticket_statuses'),
79
+ hasLinkedTickets: v.optional(v.boolean()),
80
+ },
78
81
  handler: async (ctx, args) => {
79
82
  const status = await ctx.db.get(args.statusId);
80
83
  if (!status) throw new Error('Status not found');
81
- const ticketsWithStatus = await ctx.db
82
- .query('maintenance_tasks')
83
- .withIndex('by_status', (q: any) => q.eq('status', status.name))
84
- .first();
85
- if (ticketsWithStatus) {
84
+ if (args.hasLinkedTickets) {
86
85
  throw new Error('Cannot delete status: tickets are using it. Deactivate it instead.');
87
86
  }
88
87
  await ctx.db.delete(args.statusId);