@things-factory/warehouse-base 4.2.12 → 4.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 (41) hide show
  1. package/dist-server/constants/index.js +1 -0
  2. package/dist-server/constants/index.js.map +1 -1
  3. package/dist-server/constants/tote.js +9 -0
  4. package/dist-server/constants/tote.js.map +1 -0
  5. package/dist-server/index.js +3 -1
  6. package/dist-server/index.js.map +1 -1
  7. package/dist-server/service/index.js +7 -2
  8. package/dist-server/service/index.js.map +1 -1
  9. package/dist-server/service/inventory/inventory-query.js +2 -1
  10. package/dist-server/service/inventory/inventory-query.js.map +1 -1
  11. package/dist-server/service/inventory-change/inventory-change-mutation.js +334 -273
  12. package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
  13. package/dist-server/service/inventory-history/inventory-history-query.js +23 -2
  14. package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
  15. package/dist-server/service/tote/index.js +9 -0
  16. package/dist-server/service/tote/index.js.map +1 -0
  17. package/dist-server/service/tote/tote-mutation.js +192 -0
  18. package/dist-server/service/tote/tote-mutation.js.map +1 -0
  19. package/dist-server/service/tote/tote-query.js +146 -0
  20. package/dist-server/service/tote/tote-query.js.map +1 -0
  21. package/dist-server/service/tote/tote-types.js +75 -0
  22. package/dist-server/service/tote/tote-types.js.map +1 -0
  23. package/dist-server/service/tote/tote.js +98 -0
  24. package/dist-server/service/tote/tote.js.map +1 -0
  25. package/dist-server/utils/inventory-util.js +5 -3
  26. package/dist-server/utils/inventory-util.js.map +1 -1
  27. package/package.json +8 -8
  28. package/server/constants/index.ts +1 -0
  29. package/server/constants/tote.ts +5 -0
  30. package/server/index.ts +2 -0
  31. package/server/service/index.ts +7 -2
  32. package/server/service/inventory/inventory-query.ts +2 -1
  33. package/server/service/inventory-change/index.ts +1 -1
  34. package/server/service/inventory-change/inventory-change-mutation.ts +471 -407
  35. package/server/service/inventory-history/inventory-history-query.ts +23 -2
  36. package/server/service/tote/index.ts +6 -0
  37. package/server/service/tote/tote-mutation.ts +200 -0
  38. package/server/service/tote/tote-query.ts +102 -0
  39. package/server/service/tote/tote-types.ts +44 -0
  40. package/server/service/tote/tote.ts +77 -0
  41. package/server/utils/inventory-util.ts +5 -3
@@ -12,13 +12,15 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.InventoryChangeMutation = void 0;
15
+ exports.approveInventoryChanges = exports.InventoryChangeMutation = void 0;
16
16
  const type_graphql_1 = require("type-graphql");
17
17
  const typeorm_1 = require("typeorm");
18
+ const auth_base_1 = require("@things-factory/auth-base");
18
19
  const biz_base_1 = require("@things-factory/biz-base");
19
20
  const id_rule_base_1 = require("@things-factory/id-rule-base");
20
21
  const integration_marketplace_1 = require("@things-factory/integration-marketplace");
21
22
  const integration_sellercraft_1 = require("@things-factory/integration-sellercraft");
23
+ const notification_1 = require("@things-factory/notification");
22
24
  const product_base_1 = require("@things-factory/product-base");
23
25
  const setting_base_1 = require("@things-factory/setting-base");
24
26
  const constants_1 = require("../../constants");
@@ -83,7 +85,7 @@ let InventoryChangeMutation = class InventoryChangeMutation {
83
85
  return true;
84
86
  }
85
87
  async submitInventoryChanges(patches, context) {
86
- var _a, _b, _c, _d, _e;
88
+ var _a, _b, _c, _d, _e, _f, _g, _h;
87
89
  const { domain, user, tx } = context.state;
88
90
  const _createRecords = [];
89
91
  const _updateRecords = [];
@@ -96,6 +98,10 @@ let InventoryChangeMutation = class InventoryChangeMutation {
96
98
  where: { id: (_b = patches[i]) === null || _b === void 0 ? void 0 : _b.id }
97
99
  });
98
100
  }
101
+ const invLockedQty = (foundExistingPallet === null || foundExistingPallet === void 0 ? void 0 : foundExistingPallet.lockedQty) == null ? 0 : foundExistingPallet === null || foundExistingPallet === void 0 ? void 0 : foundExistingPallet.lockedQty;
102
+ if (((_c = patches[i]) === null || _c === void 0 ? void 0 : _c.qty) < invLockedQty) {
103
+ throw new Error('Adjusted qty value should not be lower than released qty, kindly contact our support if you have difficulties');
104
+ }
99
105
  if (foundExistingPallet) {
100
106
  delete patches[i].serialNumbers;
101
107
  _updateRecords.push(patches[i]);
@@ -182,7 +188,7 @@ let InventoryChangeMutation = class InventoryChangeMutation {
182
188
  relations: ['location', 'warehouse', 'product', 'bizplace']
183
189
  });
184
190
  }
185
- if (!!((_c = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.location) === null || _c === void 0 ? void 0 : _c.id)) {
191
+ if (!!((_d = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.location) === null || _d === void 0 ? void 0 : _d.id)) {
186
192
  var location = await tx.getRepository(location_1.Location).findOne({
187
193
  where: { id: updateRecord.location.id },
188
194
  relations: ['warehouse']
@@ -191,18 +197,20 @@ let InventoryChangeMutation = class InventoryChangeMutation {
191
197
  updateRecord.zone = location.zone;
192
198
  updateRecord.warehouse = location.warehouse;
193
199
  }
194
- if (!!((_d = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.bizplace) === null || _d === void 0 ? void 0 : _d.id))
200
+ if (!!((_e = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.bizplace) === null || _e === void 0 ? void 0 : _e.id))
195
201
  updateRecord.bizplace = await tx.getRepository(biz_base_1.Bizplace).findOne(updateRecord.bizplace.id);
196
202
  let product;
197
- if (!!((_e = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.product) === null || _e === void 0 ? void 0 : _e.id)) {
203
+ if (!!((_f = updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.product) === null || _f === void 0 ? void 0 : _f.id)) {
198
204
  product = await tx.getRepository(product_base_1.Product).findOne(updateRecord.product.id);
199
205
  updateRecord.product = product;
200
206
  }
201
207
  else {
202
208
  product = existingRecord.product;
203
209
  }
210
+ updateRecord.transactionType == 'MISSING'
211
+ ? (updateRecord.transactionType = 'MISSING')
212
+ : (updateRecord.transactionType = 'CHANGES');
204
213
  updateRecord.status = 'PENDING';
205
- updateRecord.transactionType = 'CHANGES';
206
214
  updateRecord.expirationDate =
207
215
  (((updateRecord === null || updateRecord === void 0 ? void 0 : updateRecord.expirationDate) && new Date(updateRecord.expirationDate).getFullYear()) || 0) < 2000
208
216
  ? null
@@ -243,276 +251,52 @@ let InventoryChangeMutation = class InventoryChangeMutation {
243
251
  }
244
252
  }
245
253
  }
246
- return true;
247
- }
248
- async approveInventoryChanges(patches, context) {
249
- var _a, _b, _c, _d;
250
- const { domain, user, tx } = context.state;
251
- // Get Selected Inventory Change Data
252
- const _inventoryChanges = await tx.getRepository(inventory_change_1.InventoryChange).find({
253
- where: { id: (0, typeorm_1.In)(patches.map(item => item.id)) },
254
- relations: [
255
- 'inventory',
256
- 'inventory.bizplace',
257
- 'inventory.bizplace.domain',
258
- 'inventory.product',
259
- 'inventory.location',
260
- 'inventory.warehouse',
261
- 'bizplace',
262
- 'bizplace.domain',
263
- 'bizplace.company',
264
- 'bizplace.company.domain',
265
- 'product',
266
- 'product.productDetails',
267
- 'product.productDetails.childProductDetail',
268
- 'location'
269
- ],
270
- order: {
271
- createdAt: 'ASC'
254
+ const notificationApprover = await tx
255
+ .getRepository(auth_base_1.Privilege)
256
+ .createQueryBuilder('p')
257
+ .select('u.*')
258
+ .innerJoin('p.roles', 'r')
259
+ .innerJoin('r.users', 'u')
260
+ .where('p.name = :name', { name: 'mutation' })
261
+ .andWhere('p.category = :category', { category: 'inventory' })
262
+ .andWhere('r.domain_id = :domainId', { domainId: domain.id })
263
+ .groupBy('u.id')
264
+ .getRawMany();
265
+ if (_updateRecords.some(res => res.transactionType == 'MISSING')) {
266
+ if ((notificationApprover === null || notificationApprover === void 0 ? void 0 : notificationApprover.length) && ((_g = context.header) === null || _g === void 0 ? void 0 : _g.referer)) {
267
+ const receivers = notificationApprover.map(user => user.id);
268
+ const msg = {
269
+ title: `Missing stock identified. Review this transaction in Inventory Adjustment Approval.`,
270
+ body: ``,
271
+ url: context.header.referer,
272
+ data: { url: context.header.referer }
273
+ };
274
+ await (0, notification_1.sendNotification)({
275
+ receivers,
276
+ message: Object.assign({}, msg)
277
+ });
272
278
  }
273
- });
274
- let arrLockedInventory = [];
275
- if (_inventoryChanges.length > 0) {
276
- let today = new Date(), year = today.getFullYear(), month = today.getMonth(), date = today.getDate();
277
- for (let i = 0; i < _inventoryChanges.length; i++) {
278
- if (_inventoryChanges[i].status.toLocaleLowerCase() != 'pending')
279
- continue;
280
- const newRecord = Object.assign({}, _inventoryChanges[i]), newHistoryRecord = Object.assign({}, _inventoryChanges[i]);
281
- // Adjustment of existing Inventory
282
- if (_inventoryChanges[i].inventory != null) {
283
- let inventoryId = _inventoryChanges[i].inventory.id;
284
- let inventory = await tx.getRepository(inventory_1.Inventory).findOne({
285
- where: { id: inventoryId },
286
- relations: [
287
- 'domain',
288
- 'bizplace',
289
- 'bizplace.domain',
290
- 'bizplace.company',
291
- 'bizplace.company.domain',
292
- 'product',
293
- 'product.productDetails',
294
- 'product.productDetails.childProductDetail',
295
- 'warehouse',
296
- 'location',
297
- 'creator',
298
- 'updater'
299
- ]
300
- });
301
- const customerDomain = inventory.bizplace.domain;
302
- // Check for locked inventory, and stop from udpating inventory
303
- if (inventory.lockedQty > 0) {
304
- arrLockedInventory.push(_inventoryChanges[i]);
305
- continue;
306
- }
307
- // Check for Terminated inventory, then update InventoryChange entity, and stop from udpating inventory
308
- if (inventory.status == constants_1.INVENTORY_STATUS.TERMINATED) {
309
- _inventoryChanges[i] = Object.assign(Object.assign({}, _inventoryChanges[i]), { status: 'TERMINATED' });
310
- continue;
311
- }
312
- let lastSeq = inventory.lastSeq, transactionType = '';
313
- newHistoryRecord.openingQty = inventory.qty;
314
- newHistoryRecord.openingUomValue = inventory.uomValue;
315
- // Get last row of InventoryHistory
316
- let latestEntry = await tx.getRepository(inventory_history_1.InventoryHistory).findOne({
317
- where: { palletId: inventory.palletId, domain: domain },
318
- order: { seq: 'DESC' }
319
- });
320
- _inventoryChanges[i].lastInventoryHistory = latestEntry;
321
- // Check Change of existing inventory location
322
- if (newRecord.location && newRecord.location.id != inventory.location.id) {
323
- newRecord.zone = newRecord.location.zone;
324
- newRecord.warehouse = newRecord.location.warehouse;
325
- transactionType = 'ADJUSTMENT';
326
- // Check and set current location status
327
- let currentLocationInventoryCount = await tx.getRepository(inventory_1.Inventory).count({
328
- where: { location: inventory.location, status: 'STORED', id: (0, typeorm_1.Not)(inventory.id) }
329
- });
330
- if (currentLocationInventoryCount == 0) {
331
- let currentLocation = await tx.getRepository(location_1.Location).findOne({
332
- where: { id: inventory.location.id }
333
- });
334
- await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, currentLocation), { status: constants_1.LOCATION_STATUS.EMPTY }));
335
- }
336
- }
337
- // Check Change of existing inventory quantity
338
- if (newRecord.qty != null && newRecord.qty != inventory.qty) {
339
- newHistoryRecord.qty = newRecord.qty - inventory.qty;
340
- if (newRecord.qty < 1) {
341
- newRecord.qty = 0;
342
- newRecord.uomValue = 0;
343
- }
344
- transactionType = 'ADJUSTMENT';
345
- }
346
- else {
347
- newHistoryRecord.qty = 0;
348
- }
349
- // Check Change of existing inventory uomValue
350
- if (newRecord.uomValue != null && newRecord.uomValue != inventory.uomValue) {
351
- newHistoryRecord.uomValue = newRecord.uomValue - inventory.uomValue;
352
- Math.round(newHistoryRecord.uomValue * 100) / 100;
353
- transactionType = 'ADJUSTMENT';
354
- }
355
- else {
356
- newHistoryRecord.uomValue = 0;
357
- }
358
- // Terminate current inventory history if there is change of bizplace, product, batchId, packingType, or uom
359
- if ((newRecord.bizplace && inventory.bizplace.id !== newRecord.bizplace.id) ||
360
- (newRecord.product && inventory.product.id !== newRecord.product.id) ||
361
- (newRecord.batchId && inventory.batchId !== newRecord.batchId) ||
362
- (newRecord.packingType && inventory.packingType !== newRecord.packingType) ||
363
- (newRecord.uom && inventory.uom !== newRecord.uom)) {
364
- transactionType = 'ADJUSTMENT';
365
- lastSeq = lastSeq + 1;
366
- let inventoryHistory = Object.assign(Object.assign({}, inventory), { domain: domain, bizplace: inventory.bizplace.id, openingQty: inventory.qty, openingUomValue: inventory.uomValue, qty: -inventory.qty || 0, uom: inventory.uom, uomValue: -inventory.uomValue || 0, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), seq: lastSeq, transactionType: transactionType, status: constants_1.INVENTORY_STATUS.TERMINATED, productId: inventory.product.id, warehouseId: inventory.warehouse.id, locationId: inventory.location.id, packingType: inventory.packingType, creator: user, updater: user });
367
- delete inventoryHistory.id;
368
- delete inventoryHistory.createdAt;
369
- delete inventoryHistory.updatedAt;
370
- await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
371
- newHistoryRecord.qty = newRecord.qty != null ? newRecord.qty : inventory.qty || 0;
372
- newHistoryRecord.uomValue = newRecord.uomValue != null ? newRecord.uomValue : inventory.uomValue || 0;
373
- newHistoryRecord.openingQty = 0;
374
- newHistoryRecord.openingUomValue = 0;
375
- }
376
- // Set and update inventory and inventory history data
377
- lastSeq = lastSeq + 1;
378
- clean(newHistoryRecord);
379
- let inventoryHistory = Object.assign(Object.assign(Object.assign({}, inventory), newHistoryRecord), { domain: domain, creator: user, updater: user, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), status: 'STORED', seq: lastSeq, transactionType: transactionType == '' ? 'ADJUSTMENT' : transactionType, productId: newRecord.product ? newRecord.product.id : inventory.product.id, warehouseId: newRecord.warehouse ? newRecord.warehouse.id : inventory.warehouse.id, locationId: newRecord.location && newRecord.location.id != inventory.location.id
380
- ? newRecord.location.id
381
- : inventory.location.id, uom: newRecord.uom != null ? newRecord.uom : inventory.uom });
382
- delete inventoryHistory.id;
383
- delete inventoryHistory.createdAt;
384
- delete inventoryHistory.updatedAt;
385
- await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
386
- if (newRecord.qty != null && newRecord.qty == 0) {
387
- ++lastSeq;
388
- delete inventoryHistory.id;
389
- inventoryHistory = Object.assign(Object.assign({}, inventoryHistory), { name: utils_1.InventoryNoGenerator.inventoryHistoryName(), qty: 0, uomValue: 0, openingQty: 0, openingUomValue: 0, seq: lastSeq, transactionType: 'TERMINATED', status: 'TERMINATED' });
390
- await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
391
- }
392
- clean(newRecord);
393
- await tx.getRepository(inventory_1.Inventory).save(Object.assign(Object.assign(Object.assign({}, inventory), newRecord), { id: inventoryId, status: (newRecord.qty != null ? newRecord.qty : inventory.qty) > 0 ? 'STORED' : 'TERMINATED', updater: user, lastSeq: lastSeq }));
394
- //Check and set latest location status
395
- if (newRecord.qty != null ? newRecord.qty : inventory.qty > 0) {
396
- var location = await tx.getRepository(location_1.Location).findOne({
397
- where: { id: newRecord.location ? newRecord.location.id : inventory.location.id }
398
- });
399
- await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, location), { status: constants_1.LOCATION_STATUS.OCCUPIED }));
400
- }
401
- else {
402
- let latestLocationInventoryCount = await tx.getRepository(inventory_1.Inventory).count({
403
- where: {
404
- location: newRecord.location ? newRecord.location.id : inventory.location.id,
405
- status: 'STORED',
406
- id: (0, typeorm_1.Not)(inventory.id)
407
- }
408
- });
409
- if (latestLocationInventoryCount == 0) {
410
- let latestLocation = await tx.getRepository(location_1.Location).findOne({
411
- where: { id: newRecord.location ? newRecord.location.id : inventory.location.id }
412
- });
413
- await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, latestLocation), { status: constants_1.LOCATION_STATUS.EMPTY }));
414
- }
415
- }
416
- await upsertInventoryItems(context, _inventoryChanges[i], 'APPROVED', tx);
417
- const sellercraft = await tx
418
- .getRepository(integration_sellercraft_1.Sellercraft)
419
- .findOne({ domain: customerDomain, status: integration_sellercraft_1.SellercraftStatus.ACTIVE });
420
- const companyDomain = (_a = inventory.bizplace) === null || _a === void 0 ? void 0 : _a.company.domain;
421
- if (sellercraft) {
422
- const sellercraftCtrl = new controllers_1.SellercraftController(tx, domain, user);
423
- await sellercraftCtrl.updateSellercraftStock(sellercraft, inventory);
424
- }
425
- // check for any existing active marketplace connection, update marketplace selling qty
426
- const marketplaceStores = await tx.getRepository(integration_marketplace_1.MarketplaceStore).find({
427
- where: { domain: companyDomain, status: 'ACTIVE', isAutoUpdateStockQty: true },
428
- relations: ['marketplaceDistributors']
429
- });
430
- if ((marketplaceStores === null || marketplaceStores === void 0 ? void 0 : marketplaceStores.length) && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
431
- const ecommerceCtrl = new controllers_1.EcommerceController(tx, domain, user);
432
- await ecommerceCtrl.updateProductVariationStock(marketplaceStores, inventory.product.id, companyDomain);
433
- }
434
- }
435
- // Adding Inventory
436
- else {
437
- const total = await tx.getRepository(inventory_1.Inventory).count({
438
- createdAt: (0, typeorm_1.MoreThan)(new Date(year, month, date))
439
- });
440
- const yy = String(year).substr(String(year).length - 2);
441
- const mm = String(month + 1).padStart(2, '0');
442
- const dd = String(date).padStart(2, '0');
443
- const dateStr = yy + mm + dd;
444
- let palletId = newRecord.palletId;
445
- if (!((_b = newRecord.palletId) === null || _b === void 0 ? void 0 : _b.trim())) {
446
- palletId = await (0, id_rule_base_1.generateId)({
447
- domain: domain,
448
- type: 'adjustment_pallet_id',
449
- seed: {
450
- batchId: newRecord.batchId,
451
- date: dateStr
452
- }
453
- });
454
- if (!palletId)
455
- throw new Error('No adjustment pallet id setting rule found');
456
- }
457
- var location = await tx.getRepository(location_1.Location).findOne({
458
- where: { id: newRecord.location.id },
459
- relations: ['warehouse']
460
- });
461
- newRecord.location = location;
462
- newRecord.zone = location.zone;
463
- newRecord.warehouse = location.warehouse;
464
- newRecord.status = constants_1.INVENTORY_STATUS.STORED;
465
- newRecord.name = palletId;
466
- newRecord.palletId = palletId;
467
- const warehouseCartonSetting = await tx.getRepository(setting_base_1.Setting).findOne({
468
- where: { domain, category: 'id-rule', name: 'enable-carton-label' }
469
- });
470
- const partnerCartonSetting = await tx.getRepository(setting_base_1.PartnerSetting).findOne({
471
- where: { setting: warehouseCartonSetting, domain, partnerDomain: (_c = newRecord.bizplace) === null || _c === void 0 ? void 0 : _c.domain }
472
- });
473
- if (partnerCartonSetting === null || partnerCartonSetting === void 0 ? void 0 : partnerCartonSetting.value) {
474
- let cartonId = await (0, id_rule_base_1.generateId)({
475
- domain: domain,
476
- type: 'adjustment_carton_id',
477
- seed: { date: dateStr }
478
- });
479
- if (!cartonId)
480
- throw new Error('No adjustment carton id setting rule found');
481
- newRecord.cartonId = cartonId;
482
- }
483
- let expirationDate = (((newRecord === null || newRecord === void 0 ? void 0 : newRecord.expirationDate) && new Date(newRecord.expirationDate).getFullYear()) || 0) < 2000
484
- ? null
485
- : newRecord.expirationDate;
486
- let savedInventory = await tx.getRepository(inventory_1.Inventory).save(Object.assign(Object.assign({}, newRecord), { expirationDate, domain: domain, creator: user, updater: user, lastSeq: 0 }));
487
- await tx.getRepository(inventory_history_1.InventoryHistory).save(Object.assign(Object.assign({}, newRecord), { domain: domain, creator: user, updater: user, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), seq: 0, transactionType: 'NEW', productId: newRecord.product.id, warehouseId: newRecord.warehouse.id, locationId: newRecord.location.id, inventory: savedInventory, expirationDate: expirationDate }));
488
- await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, location), { status: constants_1.LOCATION_STATUS.OCCUPIED }));
489
- _inventoryChanges[i].inventory = savedInventory;
490
- _inventoryChanges[i].palletId = savedInventory.palletId;
491
- await upsertInventoryItems(context, _inventoryChanges[i], 'APPROVED', tx);
492
- const sellercraft = await tx
493
- .getRepository(integration_sellercraft_1.Sellercraft)
494
- .findOne({ domain: newRecord.bizplace.domain, status: integration_sellercraft_1.SellercraftStatus.ACTIVE });
495
- const companyDomain = (_d = newRecord.bizplace) === null || _d === void 0 ? void 0 : _d.company.domain;
496
- if (sellercraft) {
497
- const sellercraftCtrl = new controllers_1.SellercraftController(tx, domain, user);
498
- await sellercraftCtrl.updateSellercraftStock(sellercraft, newRecord);
499
- }
500
- // update marketplace store qty
501
- // check for any existing active marketplace connection, update marketplace selling qty
502
- const marketplaceStores = await tx.getRepository(integration_marketplace_1.MarketplaceStore).find({
503
- where: { domain: companyDomain, status: 'ACTIVE', isAutoUpdateStockQty: true },
504
- relations: ['marketplaceDistributors']
505
- });
506
- if ((marketplaceStores === null || marketplaceStores === void 0 ? void 0 : marketplaceStores.length) && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
507
- const ecommerceCtrl = new controllers_1.EcommerceController(tx, domain, user);
508
- await ecommerceCtrl.updateProductVariationStock(marketplaceStores, newRecord.product.id, companyDomain);
509
- }
510
- }
511
- _inventoryChanges[i].status = 'APPROVED';
279
+ }
280
+ else {
281
+ if ((notificationApprover === null || notificationApprover === void 0 ? void 0 : notificationApprover.length) && ((_h = context.header) === null || _h === void 0 ? void 0 : _h.referer)) {
282
+ const receivers = notificationApprover.map(user => user.id);
283
+ const msg = {
284
+ title: `There is an inventory adjustment pending for approval, kindly review within 1 hour to avoid any operation conflict.`,
285
+ body: ``,
286
+ url: context.header.referer,
287
+ data: { url: context.header.referer }
288
+ };
289
+ await (0, notification_1.sendNotification)({
290
+ receivers,
291
+ message: Object.assign({}, msg)
292
+ });
512
293
  }
513
- await tx.getRepository(inventory_change_1.InventoryChange).save(_inventoryChanges);
514
294
  }
515
- return { items: arrLockedInventory, total: arrLockedInventory.length };
295
+ return true;
296
+ }
297
+ async approveInventoryChanges(patches, context) {
298
+ const inventoryChangeList = await approveInventoryChanges(patches, context);
299
+ return inventoryChangeList;
516
300
  }
517
301
  async rejectInventoryChanges(patches, context) {
518
302
  const { domain, user, tx } = context.state;
@@ -679,4 +463,281 @@ async function upsertInventoryItems(context, inventoryChange, approvalStatus, tx
679
463
  .update({ id: inventoryItemChange.id }, { status: approvalStatus, inventoryItem });
680
464
  }));
681
465
  }
466
+ async function approveInventoryChanges(patches, context) {
467
+ var _a, _b, _c, _d;
468
+ const { domain, user, tx } = context.state;
469
+ // Get Selected Inventory Change Data
470
+ const _inventoryChanges = await tx.getRepository(inventory_change_1.InventoryChange).find({
471
+ where: { id: (0, typeorm_1.In)(patches.map(item => item.id)) },
472
+ relations: [
473
+ 'inventory',
474
+ 'inventory.bizplace',
475
+ 'inventory.bizplace.domain',
476
+ 'inventory.product',
477
+ 'inventory.location',
478
+ 'inventory.warehouse',
479
+ 'bizplace',
480
+ 'bizplace.domain',
481
+ 'bizplace.company',
482
+ 'bizplace.company.domain',
483
+ 'product',
484
+ 'product.productDetails',
485
+ 'product.productDetails.childProductDetail',
486
+ 'location'
487
+ ],
488
+ order: {
489
+ createdAt: 'ASC'
490
+ }
491
+ });
492
+ let arrLockedInventory = [];
493
+ if (_inventoryChanges.length > 0) {
494
+ let today = new Date(), year = today.getFullYear(), month = today.getMonth(), date = today.getDate();
495
+ for (let i = 0; i < _inventoryChanges.length; i++) {
496
+ if (_inventoryChanges[i].status.toLocaleLowerCase() != 'pending')
497
+ continue;
498
+ const newRecord = Object.assign({}, _inventoryChanges[i]), newHistoryRecord = Object.assign({}, _inventoryChanges[i]);
499
+ // Adjustment of existing Inventory
500
+ if (_inventoryChanges[i].inventory != null) {
501
+ let inventoryId = _inventoryChanges[i].inventory.id;
502
+ let inventory = await tx.getRepository(inventory_1.Inventory).findOne({
503
+ where: { id: inventoryId },
504
+ relations: [
505
+ 'domain',
506
+ 'bizplace',
507
+ 'bizplace.domain',
508
+ 'bizplace.company',
509
+ 'bizplace.company.domain',
510
+ 'product',
511
+ 'product.productDetails',
512
+ 'product.productDetails.childProductDetail',
513
+ 'warehouse',
514
+ 'location',
515
+ 'creator',
516
+ 'updater'
517
+ ]
518
+ });
519
+ const customerDomain = inventory.bizplace.domain;
520
+ // Check for locked inventory, and stop from udpating inventory
521
+ if (inventory.qty < inventory.lockedQty) {
522
+ arrLockedInventory.push(_inventoryChanges[i]);
523
+ continue;
524
+ }
525
+ // Check for Terminated inventory, then update InventoryChange entity, and stop from udpating inventory
526
+ if (inventory.status == constants_1.INVENTORY_STATUS.TERMINATED) {
527
+ _inventoryChanges[i] = Object.assign(Object.assign({}, _inventoryChanges[i]), { status: 'TERMINATED' });
528
+ continue;
529
+ }
530
+ let lastSeq = inventory.lastSeq, transactionType = '';
531
+ newHistoryRecord.openingQty = inventory.qty;
532
+ newHistoryRecord.openingUomValue = inventory.uomValue;
533
+ // Get last row of InventoryHistory
534
+ let latestEntry = await tx.getRepository(inventory_history_1.InventoryHistory).findOne({
535
+ where: { palletId: inventory.palletId, domain: domain },
536
+ order: { seq: 'DESC' }
537
+ });
538
+ _inventoryChanges[i].lastInventoryHistory = latestEntry;
539
+ // Check Change of existing inventory location
540
+ if (newRecord.location && newRecord.location.id != inventory.location.id) {
541
+ newRecord.zone = newRecord.location.zone;
542
+ newRecord.warehouse = newRecord.location.warehouse;
543
+ transactionType = 'ADJUSTMENT';
544
+ // Check and set current location status
545
+ let currentLocationInventoryCount = await tx.getRepository(inventory_1.Inventory).count({
546
+ where: { location: inventory.location, status: 'STORED', id: (0, typeorm_1.Not)(inventory.id) }
547
+ });
548
+ if (currentLocationInventoryCount == 0) {
549
+ let currentLocation = await tx.getRepository(location_1.Location).findOne({
550
+ where: { id: inventory.location.id }
551
+ });
552
+ await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, currentLocation), { status: constants_1.LOCATION_STATUS.EMPTY }));
553
+ }
554
+ }
555
+ // Check Change of existing inventory quantity
556
+ if (newRecord.qty != null && newRecord.qty != inventory.qty) {
557
+ newHistoryRecord.qty = newRecord.qty - inventory.qty;
558
+ if (newRecord.qty < 1) {
559
+ newRecord.qty = 0;
560
+ newRecord.uomValue = 0;
561
+ }
562
+ transactionType = 'ADJUSTMENT';
563
+ }
564
+ else {
565
+ newHistoryRecord.qty = 0;
566
+ }
567
+ // Check Change of existing inventory uomValue
568
+ if (newRecord.uomValue != null && newRecord.uomValue != inventory.uomValue) {
569
+ newHistoryRecord.uomValue = newRecord.uomValue - inventory.uomValue;
570
+ Math.round(newHistoryRecord.uomValue * 100) / 100;
571
+ transactionType = 'ADJUSTMENT';
572
+ }
573
+ else {
574
+ newHistoryRecord.uomValue = 0;
575
+ }
576
+ // Terminate current inventory history if there is change of bizplace, product, batchId, packingType, or uom
577
+ if ((newRecord.bizplace && inventory.bizplace.id !== newRecord.bizplace.id) ||
578
+ (newRecord.product && inventory.product.id !== newRecord.product.id) ||
579
+ (newRecord.batchId && inventory.batchId !== newRecord.batchId) ||
580
+ (newRecord.packingType && inventory.packingType !== newRecord.packingType) ||
581
+ (newRecord.uom && inventory.uom !== newRecord.uom)) {
582
+ transactionType = 'ADJUSTMENT';
583
+ lastSeq = lastSeq + 1;
584
+ let inventoryHistory = Object.assign(Object.assign({}, inventory), { domain: domain, bizplace: inventory.bizplace.id, openingQty: inventory.qty, openingUomValue: inventory.uomValue, qty: -inventory.qty || 0, uom: inventory.uom, uomValue: -inventory.uomValue || 0, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), seq: lastSeq, transactionType: transactionType, status: constants_1.INVENTORY_STATUS.TERMINATED, productId: inventory.product.id, warehouseId: inventory.warehouse.id, locationId: inventory.location.id, packingType: inventory.packingType, creator: user, updater: user });
585
+ delete inventoryHistory.id;
586
+ delete inventoryHistory.createdAt;
587
+ delete inventoryHistory.updatedAt;
588
+ await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
589
+ newHistoryRecord.qty = newRecord.qty != null ? newRecord.qty : inventory.qty || 0;
590
+ newHistoryRecord.uomValue = newRecord.uomValue != null ? newRecord.uomValue : inventory.uomValue || 0;
591
+ newHistoryRecord.openingQty = 0;
592
+ newHistoryRecord.openingUomValue = 0;
593
+ }
594
+ // Set and update inventory and inventory history data
595
+ lastSeq = lastSeq + 1;
596
+ clean(newHistoryRecord);
597
+ let inventoryHistory = Object.assign(Object.assign(Object.assign({}, inventory), newHistoryRecord), { domain: domain, creator: user, updater: user, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), status: newHistoryRecord.transactionType == 'MISSING' ? 'MISSING' : 'STORED', seq: lastSeq, transactionType: transactionType == '' ? 'ADJUSTMENT' : transactionType, productId: newRecord.product ? newRecord.product.id : inventory.product.id, warehouseId: newRecord.warehouse ? newRecord.warehouse.id : inventory.warehouse.id, locationId: newRecord.location && newRecord.location.id != inventory.location.id
598
+ ? newRecord.location.id
599
+ : inventory.location.id, uom: newRecord.uom != null ? newRecord.uom : inventory.uom });
600
+ delete inventoryHistory.id;
601
+ delete inventoryHistory.createdAt;
602
+ delete inventoryHistory.updatedAt;
603
+ await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
604
+ if (newRecord.qty != null && newRecord.qty == 0) {
605
+ ++lastSeq;
606
+ delete inventoryHistory.id;
607
+ inventoryHistory = Object.assign(Object.assign({}, inventoryHistory), { name: utils_1.InventoryNoGenerator.inventoryHistoryName(), qty: 0, uomValue: 0, openingQty: 0, openingUomValue: 0, seq: lastSeq, transactionType: 'TERMINATED', status: 'TERMINATED' });
608
+ await tx.getRepository(inventory_history_1.InventoryHistory).save(inventoryHistory);
609
+ }
610
+ clean(newRecord);
611
+ let statusFilter = '';
612
+ if (newRecord.transactionType == 'MISSING') {
613
+ statusFilter = 'MISSING';
614
+ }
615
+ else {
616
+ statusFilter = (newRecord.qty != null ? newRecord.qty : inventory.qty) > 0 ? 'STORED' : 'TERMINATED';
617
+ }
618
+ await tx.getRepository(inventory_1.Inventory).save(Object.assign(Object.assign(Object.assign({}, inventory), newRecord), { id: inventoryId, status: statusFilter, updater: user, lastSeq: lastSeq }));
619
+ //Check and set latest location status
620
+ if (newRecord.qty != null ? newRecord.qty : inventory.qty > 0) {
621
+ var location = await tx.getRepository(location_1.Location).findOne({
622
+ where: { id: newRecord.location ? newRecord.location.id : inventory.location.id }
623
+ });
624
+ await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, location), { status: constants_1.LOCATION_STATUS.OCCUPIED }));
625
+ }
626
+ else {
627
+ let latestLocationInventoryCount = await tx.getRepository(inventory_1.Inventory).count({
628
+ where: {
629
+ location: newRecord.location ? newRecord.location.id : inventory.location.id,
630
+ status: 'STORED',
631
+ id: (0, typeorm_1.Not)(inventory.id)
632
+ }
633
+ });
634
+ if (latestLocationInventoryCount == 0) {
635
+ let latestLocation = await tx.getRepository(location_1.Location).findOne({
636
+ where: { id: newRecord.location ? newRecord.location.id : inventory.location.id }
637
+ });
638
+ await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, latestLocation), { status: constants_1.LOCATION_STATUS.EMPTY }));
639
+ }
640
+ }
641
+ await upsertInventoryItems(context, _inventoryChanges[i], 'APPROVED', tx);
642
+ const sellercraft = await tx
643
+ .getRepository(integration_sellercraft_1.Sellercraft)
644
+ .findOne({ domain: customerDomain, status: integration_sellercraft_1.SellercraftStatus.ACTIVE });
645
+ const companyDomain = (_a = inventory.bizplace) === null || _a === void 0 ? void 0 : _a.company.domain;
646
+ if (sellercraft) {
647
+ const sellercraftCtrl = new controllers_1.SellercraftController(tx, domain, user);
648
+ await sellercraftCtrl.updateSellercraftStock(sellercraft, inventory);
649
+ }
650
+ // check for any existing active marketplace connection, update marketplace selling qty
651
+ const marketplaceStores = await tx.getRepository(integration_marketplace_1.MarketplaceStore).find({
652
+ where: { domain: companyDomain, status: 'ACTIVE', isAutoUpdateStockQty: true },
653
+ relations: ['marketplaceDistributors']
654
+ });
655
+ if ((marketplaceStores === null || marketplaceStores === void 0 ? void 0 : marketplaceStores.length) && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
656
+ const ecommerceCtrl = new controllers_1.EcommerceController(tx, domain, user);
657
+ await ecommerceCtrl.updateProductVariationStock(marketplaceStores, inventory.product.id, companyDomain);
658
+ }
659
+ }
660
+ // Adding Inventory
661
+ else {
662
+ const total = await tx.getRepository(inventory_1.Inventory).count({
663
+ createdAt: (0, typeorm_1.MoreThan)(new Date(year, month, date))
664
+ });
665
+ const yy = String(year).substr(String(year).length - 2);
666
+ const mm = String(month + 1).padStart(2, '0');
667
+ const dd = String(date).padStart(2, '0');
668
+ const dateStr = yy + mm + dd;
669
+ let palletId = newRecord.palletId;
670
+ if (!((_b = newRecord.palletId) === null || _b === void 0 ? void 0 : _b.trim())) {
671
+ palletId = await (0, id_rule_base_1.generateId)({
672
+ domain: domain,
673
+ type: 'adjustment_pallet_id',
674
+ seed: {
675
+ batchId: newRecord.batchId,
676
+ date: dateStr
677
+ }
678
+ });
679
+ if (!palletId)
680
+ throw new Error('No adjustment pallet id setting rule found');
681
+ }
682
+ var location = await tx.getRepository(location_1.Location).findOne({
683
+ where: { id: newRecord.location.id },
684
+ relations: ['warehouse']
685
+ });
686
+ newRecord.location = location;
687
+ newRecord.zone = location.zone;
688
+ newRecord.warehouse = location.warehouse;
689
+ newRecord.status = constants_1.INVENTORY_STATUS.STORED;
690
+ newRecord.name = palletId;
691
+ newRecord.palletId = palletId;
692
+ const warehouseCartonSetting = await tx.getRepository(setting_base_1.Setting).findOne({
693
+ where: { domain, category: 'id-rule', name: 'enable-carton-label' }
694
+ });
695
+ const partnerCartonSetting = await tx.getRepository(setting_base_1.PartnerSetting).findOne({
696
+ where: { setting: warehouseCartonSetting, domain, partnerDomain: (_c = newRecord.bizplace) === null || _c === void 0 ? void 0 : _c.domain }
697
+ });
698
+ if (partnerCartonSetting === null || partnerCartonSetting === void 0 ? void 0 : partnerCartonSetting.value) {
699
+ let cartonId = await (0, id_rule_base_1.generateId)({
700
+ domain: domain,
701
+ type: 'adjustment_carton_id',
702
+ seed: { date: dateStr }
703
+ });
704
+ if (!cartonId)
705
+ throw new Error('No adjustment carton id setting rule found');
706
+ newRecord.cartonId = cartonId;
707
+ }
708
+ let expirationDate = (((newRecord === null || newRecord === void 0 ? void 0 : newRecord.expirationDate) && new Date(newRecord.expirationDate).getFullYear()) || 0) < 2000
709
+ ? null
710
+ : newRecord.expirationDate;
711
+ let savedInventory = await tx.getRepository(inventory_1.Inventory).save(Object.assign(Object.assign({}, newRecord), { expirationDate, domain: domain, creator: user, updater: user, lastSeq: 0 }));
712
+ await tx.getRepository(inventory_history_1.InventoryHistory).save(Object.assign(Object.assign({}, newRecord), { domain: domain, creator: user, updater: user, name: utils_1.InventoryNoGenerator.inventoryHistoryName(), seq: 0, transactionType: 'NEW', productId: newRecord.product.id, warehouseId: newRecord.warehouse.id, locationId: newRecord.location.id, inventory: savedInventory, expirationDate: expirationDate }));
713
+ await tx.getRepository(location_1.Location).save(Object.assign(Object.assign({}, location), { status: constants_1.LOCATION_STATUS.OCCUPIED }));
714
+ _inventoryChanges[i].inventory = savedInventory;
715
+ _inventoryChanges[i].palletId = savedInventory.palletId;
716
+ await upsertInventoryItems(context, _inventoryChanges[i], 'APPROVED', tx);
717
+ const sellercraft = await tx
718
+ .getRepository(integration_sellercraft_1.Sellercraft)
719
+ .findOne({ domain: newRecord.bizplace.domain, status: integration_sellercraft_1.SellercraftStatus.ACTIVE });
720
+ const companyDomain = (_d = newRecord.bizplace) === null || _d === void 0 ? void 0 : _d.company.domain;
721
+ if (sellercraft) {
722
+ const sellercraftCtrl = new controllers_1.SellercraftController(tx, domain, user);
723
+ await sellercraftCtrl.updateSellercraftStock(sellercraft, newRecord);
724
+ }
725
+ // update marketplace store qty
726
+ // check for any existing active marketplace connection, update marketplace selling qty
727
+ const marketplaceStores = await tx.getRepository(integration_marketplace_1.MarketplaceStore).find({
728
+ where: { domain: companyDomain, status: 'ACTIVE', isAutoUpdateStockQty: true },
729
+ relations: ['marketplaceDistributors']
730
+ });
731
+ if ((marketplaceStores === null || marketplaceStores === void 0 ? void 0 : marketplaceStores.length) && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
732
+ const ecommerceCtrl = new controllers_1.EcommerceController(tx, domain, user);
733
+ await ecommerceCtrl.updateProductVariationStock(marketplaceStores, newRecord.product.id, companyDomain);
734
+ }
735
+ }
736
+ _inventoryChanges[i].status = 'APPROVED';
737
+ }
738
+ await tx.getRepository(inventory_change_1.InventoryChange).save(_inventoryChanges);
739
+ }
740
+ return { items: arrLockedInventory, total: arrLockedInventory.length };
741
+ }
742
+ exports.approveInventoryChanges = approveInventoryChanges;
682
743
  //# sourceMappingURL=inventory-change-mutation.js.map