rez_core 6.5.83 → 6.5.84
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.
- package/dist/module/filter/service/filter.service.js +2 -2
- package/dist/module/filter/service/filter.service.js.map +1 -1
- package/dist/module/listmaster/service/list-master-item.service.js +113 -39
- package/dist/module/listmaster/service/list-master-item.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/filter/service/filter.service.ts +12 -11
- package/src/module/listmaster/service/list-master-item.service.ts +150 -56
package/package.json
CHANGED
|
@@ -1245,18 +1245,19 @@ export class FilterService {
|
|
|
1245
1245
|
}
|
|
1246
1246
|
|
|
1247
1247
|
if (op === 'equal') {
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1248
|
+
return {
|
|
1249
|
+
query: `e.${attr}::text = ANY(:${key})`,
|
|
1250
|
+
params: { [key]: arr },
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (op === 'not_equal') {
|
|
1255
|
+
return {
|
|
1256
|
+
query: `NOT (e.${attr}::text = ANY(:${key}))`,
|
|
1257
|
+
params: { [key]: arr },
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1253
1260
|
|
|
1254
|
-
if (op === 'not_equal') {
|
|
1255
|
-
return {
|
|
1256
|
-
query: `e.${attr}::text NOT IN (:...${key})`,
|
|
1257
|
-
params: { [key]: arr },
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
1261
|
|
|
1261
1262
|
if (op === 'contains') {
|
|
1262
1263
|
return {
|
|
@@ -60,84 +60,177 @@ export class ListMasterItemService extends EntityServiceImpl {
|
|
|
60
60
|
loggedInUser,
|
|
61
61
|
): Promise<any> {
|
|
62
62
|
const entId = loggedInUser.enterprise_id;
|
|
63
|
-
|
|
64
63
|
const errors: any[] = [];
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
// Step 1: Validate and prepare items
|
|
66
|
+
const processedItems = items.map((item, index) => ({
|
|
67
|
+
...item,
|
|
68
|
+
index,
|
|
69
|
+
name: item.name?.trim(),
|
|
70
|
+
code: item.code?.trim(),
|
|
71
|
+
itemId: item.id,
|
|
72
|
+
}));
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// Step 2: Fetch all existing items for this list type in one query
|
|
75
|
+
const existingItems = await this.listItemsRepo.findAllItemsByListType(
|
|
76
|
+
listType,
|
|
77
|
+
'asc',
|
|
78
|
+
entId,
|
|
79
|
+
);
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
enterprise_id: entId,
|
|
84
|
-
});
|
|
81
|
+
// Create lookup maps for efficient validation
|
|
82
|
+
const existingItemsById = new Map(existingItems.map(item => [item.id, item]));
|
|
83
|
+
const existingItemsByName = new Map(existingItems.map(item => [item.name?.toLowerCase(), item]));
|
|
84
|
+
const existingItemsByCode = new Map(
|
|
85
|
+
existingItems.filter(item => item.code).map(item => [item.code?.toLowerCase(), item])
|
|
86
|
+
);
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
`list item with id ${itemId} not found`,
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
88
|
+
// Step 3: Validate all items and collect errors
|
|
89
|
+
const validItems: any[] = [];
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
for (const processedItem of processedItems) {
|
|
92
|
+
const { index, name, code, itemId } = processedItem;
|
|
93
|
+
const itemErrors: any[] = [];
|
|
94
|
+
|
|
95
|
+
// Validate required fields - both name and code are required
|
|
96
|
+
if (!name) {
|
|
97
|
+
itemErrors.push({
|
|
98
|
+
field: 'name',
|
|
99
|
+
message: 'Name is required',
|
|
98
100
|
});
|
|
101
|
+
}
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
if (!code) {
|
|
104
|
+
itemErrors.push({
|
|
105
|
+
field: 'code',
|
|
106
|
+
message: 'Code is required',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Determine if this is an update by checking for existing item
|
|
111
|
+
let existingItem: any = null;
|
|
112
|
+
let effectiveItemId = itemId; // Track the ID we'll use for this item
|
|
113
|
+
|
|
114
|
+
// First, check if ID is provided and exists
|
|
115
|
+
if (itemId) {
|
|
116
|
+
existingItem = existingItemsById.get(itemId) || null;
|
|
117
|
+
if (!existingItem) {
|
|
118
|
+
itemErrors.push({
|
|
119
|
+
field: 'id',
|
|
120
|
+
message: `List item with id ${itemId} not found`,
|
|
121
|
+
});
|
|
122
|
+
} else if (existingItem.listtype !== listType) {
|
|
123
|
+
itemErrors.push({
|
|
124
|
+
field: 'id',
|
|
125
|
+
message: `List item with id ${itemId} does not belong to list type ${listType}`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// If no ID provided, check if item exists by name or code (for upsert)
|
|
130
|
+
const existingByName = name ? existingItemsByName.get(name.toLowerCase()) : null;
|
|
131
|
+
const existingByCode = code ? existingItemsByCode.get(code.toLowerCase()) : null;
|
|
132
|
+
|
|
133
|
+
// If both name and code match the same item, it's an update - use that item's ID
|
|
134
|
+
if (existingByName && existingByCode && existingByName.id === existingByCode.id) {
|
|
135
|
+
existingItem = existingByName;
|
|
136
|
+
effectiveItemId = existingItem.id; // Automatically use the existing item's ID
|
|
104
137
|
}
|
|
138
|
+
// If name matches one item and code matches a different item, it's a conflict
|
|
139
|
+
else if (existingByName && existingByCode && existingByName.id !== existingByCode.id) {
|
|
140
|
+
itemErrors.push({
|
|
141
|
+
field: 'name',
|
|
142
|
+
message: `Name "${name}" belongs to item with code "${existingByName.code}"`,
|
|
143
|
+
});
|
|
144
|
+
itemErrors.push({
|
|
145
|
+
field: 'code',
|
|
146
|
+
message: `Code "${code}" belongs to item with name "${existingByCode.name}"`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// If only name matches, it's a conflict (trying to create with existing name but different code)
|
|
150
|
+
else if (existingByName) {
|
|
151
|
+
itemErrors.push({
|
|
152
|
+
field: 'name',
|
|
153
|
+
message: `List item with name "${name}" already exists with code "${existingByName.code}"`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// If only code matches, it's a conflict (trying to create with existing code but different name)
|
|
157
|
+
else if (existingByCode) {
|
|
158
|
+
itemErrors.push({
|
|
159
|
+
field: 'code',
|
|
160
|
+
message: `List item with code "${code}" already exists with name "${existingByCode.name}"`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
105
164
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
165
|
+
// Check for duplicates within the current batch
|
|
166
|
+
if (name) {
|
|
167
|
+
const duplicateInBatch = processedItems.find(
|
|
168
|
+
(other, otherIndex) =>
|
|
169
|
+
otherIndex < index &&
|
|
170
|
+
other.name?.toLowerCase() === name.toLowerCase() &&
|
|
171
|
+
(!effectiveItemId || other.itemId !== effectiveItemId)
|
|
172
|
+
);
|
|
173
|
+
if (duplicateInBatch) {
|
|
174
|
+
itemErrors.push({
|
|
175
|
+
field: 'name',
|
|
176
|
+
message: `Duplicate name "${name}" found in batch at row ${duplicateInBatch.index}`,
|
|
112
177
|
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
113
180
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
181
|
+
if (code) {
|
|
182
|
+
const duplicateCodeInBatch = processedItems.find(
|
|
183
|
+
(other, otherIndex) =>
|
|
184
|
+
otherIndex < index &&
|
|
185
|
+
other.code?.toLowerCase() === code.toLowerCase() &&
|
|
186
|
+
(!effectiveItemId || other.itemId !== effectiveItemId)
|
|
187
|
+
);
|
|
188
|
+
if (duplicateCodeInBatch) {
|
|
189
|
+
itemErrors.push({
|
|
190
|
+
field: 'code',
|
|
191
|
+
message: `Duplicate code "${code}" found in batch at row ${duplicateCodeInBatch.index}`,
|
|
192
|
+
});
|
|
119
193
|
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// If there are validation errors, add to errors array
|
|
197
|
+
if (itemErrors.length > 0) {
|
|
198
|
+
errors.push({
|
|
199
|
+
row: index,
|
|
200
|
+
errors: itemErrors,
|
|
201
|
+
});
|
|
202
|
+
} else {
|
|
203
|
+
validItems.push({
|
|
204
|
+
...processedItem,
|
|
205
|
+
existingItem,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
120
209
|
|
|
121
|
-
|
|
210
|
+
// Step 4: Process valid items (create or update)
|
|
211
|
+
for (const validItem of validItems) {
|
|
212
|
+
const { index, name, code, itemId, existingItem, ...restOfItem } = validItem;
|
|
213
|
+
|
|
214
|
+
try {
|
|
122
215
|
if (existingItem) {
|
|
123
|
-
// Update
|
|
216
|
+
// Update existing item
|
|
124
217
|
await this.updateEntity(
|
|
125
218
|
{
|
|
126
|
-
...
|
|
127
|
-
id:
|
|
219
|
+
...restOfItem,
|
|
220
|
+
id: existingItem.id, // Use the existing item's ID
|
|
128
221
|
name,
|
|
129
|
-
code
|
|
222
|
+
code,
|
|
130
223
|
listtype: listType,
|
|
131
224
|
},
|
|
132
225
|
loggedInUser,
|
|
133
226
|
);
|
|
134
227
|
} else {
|
|
135
|
-
//
|
|
228
|
+
// Create new item
|
|
136
229
|
await this.createEntity(
|
|
137
230
|
{
|
|
138
|
-
...
|
|
231
|
+
...restOfItem,
|
|
139
232
|
name,
|
|
140
|
-
code
|
|
233
|
+
code,
|
|
141
234
|
listtype: listType,
|
|
142
235
|
value: '',
|
|
143
236
|
},
|
|
@@ -145,19 +238,20 @@ export class ListMasterItemService extends EntityServiceImpl {
|
|
|
145
238
|
);
|
|
146
239
|
}
|
|
147
240
|
} catch (error) {
|
|
241
|
+
// Catch any runtime errors during create/update
|
|
148
242
|
errors.push({
|
|
149
|
-
row:
|
|
243
|
+
row: index,
|
|
150
244
|
errors: [
|
|
151
245
|
{
|
|
152
|
-
field: '
|
|
153
|
-
message:
|
|
154
|
-
error.message || 'An error occurred while processing the item',
|
|
246
|
+
field: 'general',
|
|
247
|
+
message: error.message || 'An error occurred while processing the item',
|
|
155
248
|
},
|
|
156
249
|
],
|
|
157
250
|
});
|
|
158
251
|
}
|
|
159
252
|
}
|
|
160
253
|
|
|
254
|
+
// Step 5: Fetch updated items and return response
|
|
161
255
|
const updatedItems = await this.listItemsRepo.findAllItemsByListType(
|
|
162
256
|
listType,
|
|
163
257
|
'asc',
|