@things-factory/sales-base 4.3.605 → 4.3.607

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.
@@ -1,19 +1,54 @@
1
- import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
- import { EntityManager, getConnection, getRepository, In, Repository } from 'typeorm'
1
+ import {
2
+ Arg,
3
+ Ctx,
4
+ Directive,
5
+ Mutation,
6
+ Resolver
7
+ } from 'type-graphql'
8
+ import {
9
+ EntityManager,
10
+ getConnection,
11
+ getRepository,
12
+ In,
13
+ Repository
14
+ } from 'typeorm'
3
15
 
4
16
  import { Bizplace } from '@things-factory/biz-base'
5
17
  import { logger } from '@things-factory/env'
18
+ import {
19
+ WebhookEventsEnum,
20
+ webhookHandler
21
+ } from '@things-factory/integration-base'
6
22
  import { ProductBundle } from '@things-factory/product-base'
7
- import { webhookHandler, WebhookEventsEnum } from '@things-factory/integration-base'
8
- import { PartnerSetting, Setting } from '@things-factory/setting-base'
23
+ import {
24
+ PartnerSetting,
25
+ Setting
26
+ } from '@things-factory/setting-base'
9
27
  import { Domain } from '@things-factory/shell'
10
- import { bulkReleaseGoodsAvailableItemsFunction, DraftReleaseGood, DraftReleaseGoodInfos, OrderProduct } from '../'
11
- import { DRAFT_RELEASE_ORDER_STATUS, ORDER_NUMBER_SETTING_KEY, ORDER_STATUS } from '../../constants'
28
+
29
+ import {
30
+ bulkReleaseGoodsAvailableItemsFunction,
31
+ DraftReleaseGood,
32
+ DraftReleaseGoodInfos,
33
+ OrderProduct
34
+ } from '../'
35
+ import {
36
+ DRAFT_RELEASE_ORDER_STATUS,
37
+ ORDER_NUMBER_SETTING_KEY,
38
+ ORDER_STATUS
39
+ } from '../../constants'
12
40
  import { ValidationError } from '../../errors'
13
- import { InventoryUtil, OrderNoGenerator } from '../../utils'
41
+ import {
42
+ InventoryUtil,
43
+ OrderNoGenerator
44
+ } from '../../utils'
14
45
  import { ReleaseGood } from '../release-good/release-good'
46
+ import {
47
+ bulkGenerateReleaseGood,
48
+ confirmReleaseGood,
49
+ receiveReleaseGood
50
+ } from '../release-good/release-good-mutation'
15
51
  import { SuccessReleasedDraftOrder } from './draft-release-good-type'
16
- import { bulkGenerateReleaseGood, confirmReleaseGood, receiveReleaseGood } from '../release-good/release-good-mutation'
17
52
 
18
53
  @Resolver(DraftReleaseGood)
19
54
  export class DraftReleaseGoodCreate {
@@ -71,6 +106,7 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
71
106
  relations: [
72
107
  'orderProducts',
73
108
  'orderProducts.product',
109
+ 'orderProducts.productDetail',
74
110
  'orderProducts.productBundle',
75
111
  'orderProducts.productBundle.productBundleSettings',
76
112
  'orderProducts.productBundle.productBundleSettings.product',
@@ -85,6 +121,7 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
85
121
  ]
86
122
  })
87
123
  let failReleaseOrder = []
124
+ let successReleaseOrder = []
88
125
 
89
126
  if (updatableDraftOrders.length > 0) {
90
127
  const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
@@ -142,7 +179,8 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
142
179
  name: 'productId',
143
180
  operator: 'in',
144
181
  value: productIds
145
- }
182
+ },
183
+ { name: 'deleted_at', operator: 'eq', value: true }
146
184
  ]
147
185
  },
148
186
  context,
@@ -178,8 +216,11 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
178
216
  }
179
217
  })
180
218
 
181
- let insufficient = draftOrder.orderProducts.find(op => op.status == 'insufficient')
182
- if (!insufficient) {
219
+ let failedInventory = draftOrder.orderProducts.find(
220
+ op => op.status == 'insufficient' || op.productDetail.deletedAt != null
221
+ )
222
+
223
+ if (!failedInventory) {
183
224
  //create RO
184
225
  let releaseGood = { ...draftOrder }
185
226
  delete releaseGood.id
@@ -266,6 +307,14 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
266
307
  context,
267
308
  innerTx2
268
309
  )
310
+
311
+ if (availableItems.some(item => item.orderProduct.productDetail.deletedAt != null)) {
312
+ throw new ValidationError({
313
+ ...ValidationError.ERROR_CODES.DELETED_PRODUCT_DETAIL,
314
+ detail: { data: JSON.stringify(availableItems) }
315
+ })
316
+ }
317
+
269
318
  if (availableItems.some(item => !item.releaseQty || item.releaseQty > item.assignedQty))
270
319
  throw new ValidationError({
271
320
  ...ValidationError.ERROR_CODES.INSUFFICIENT_STOCK,
@@ -303,6 +352,7 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
303
352
  if (existingReleaseGood.length > 1) {
304
353
  throw new Error('generating release orders')
305
354
  }
355
+ // successReleaseOrder.push({ draftName: draftOrder?.name, status: 'success' })
306
356
  })
307
357
 
308
358
  await innerTx2
@@ -332,6 +382,7 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
332
382
 
333
383
  createdReleaseGood = await confirmReleaseGood(createdReleaseGood.name, context, innerTx2)
334
384
 
385
+ successReleaseOrder.push({ draftName: draftOrder?.name, status: 'success' })
335
386
  if (settingValue > 1) {
336
387
  createdReleaseGood = await receiveReleaseGood(createdReleaseGood.name, context, innerTx2)
337
388
  }
@@ -340,8 +391,12 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
340
391
  webhookHandler(createdReleaseGood, createdReleaseGood.bizplace, WebhookEventsEnum.ReleaseOrderCreated)
341
392
  })
342
393
  } else {
343
- if (draftOrder.orderProducts.every(op => op.id === insufficient?.id)) {
344
- failReleaseOrder.push(draftOrder?.name)
394
+ if (
395
+ draftOrder.orderProducts.some(op => op.id === failedInventory?.id && op.productDetail.deletedAt != null)
396
+ ) {
397
+ failReleaseOrder.push({ draftName: draftOrder?.name, status: 'deleted' })
398
+ } else {
399
+ failReleaseOrder.push({ draftName: draftOrder?.name, status: 'insufficient' })
345
400
  }
346
401
  }
347
402
  } catch (e) {
@@ -352,12 +407,12 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
352
407
  })
353
408
  }
354
409
  }
355
- releasedOrders = updatableDraftOrders.filter(drg => !drg.name.includes(failReleaseOrder))
356
- releasedOrders = releasedOrders.map(item => {
357
- return {
358
- draftName: item.name
359
- }
410
+ releasedOrders.push({
411
+ successCount: successReleaseOrder.length,
412
+ insufficientCount: failReleaseOrder.filter(fro => fro.status === 'insufficient').length,
413
+ deletedCount: failReleaseOrder.filter(fro => fro.status === 'deleted').length
360
414
  })
415
+
361
416
  return releasedOrders
362
417
  } catch (e) {
363
418
  logger.error(`draft-release-good-mutation[generateReleaseGoodsFromDraft]: ${e?.message}`)
@@ -1,9 +1,4 @@
1
- import {
2
- Field,
3
- InputType,
4
- Int,
5
- ObjectType
6
- } from 'type-graphql'
1
+ import { Field, InputType, Int, ObjectType } from 'type-graphql'
7
2
 
8
3
  import { ObjectRef } from '@things-factory/shell'
9
4
 
@@ -287,6 +282,15 @@ export class SuccessReleasedDraftOrder {
287
282
 
288
283
  @Field({ nullable: true })
289
284
  isProductBundle?: Boolean
285
+
286
+ @Field({ nullable: true })
287
+ successCount?: number
288
+
289
+ @Field({ nullable: true })
290
+ insufficientCount?: number
291
+
292
+ @Field({ nullable: true })
293
+ deletedCount?: number
290
294
  }
291
295
 
292
296
  @InputType()
@@ -47,6 +47,7 @@ import {
47
47
  ORDER_STATUS,
48
48
  ORDER_VAS_STATUS
49
49
  } from '../../constants'
50
+ import { convertExcelDateToISO } from '../../utils/datetime-util'
50
51
  import { OrderInventory } from '../order-inventory/order-inventory'
51
52
  import { OrderPackage } from '../order-package/order-package'
52
53
  import { ShippingOrder } from '../shipping-order/shipping-order'
@@ -1105,6 +1106,8 @@ function _extractData(rawData, validatedData) {
1105
1106
  let errMsg
1106
1107
  let comparison = ['packingType', 'packingSize', 'uom']
1107
1108
  let data = validatedData
1109
+ raw.releaseDate = raw.releaseDate ? convertExcelDateToISO(raw.releaseDate) : null
1110
+ raw.expirationDate = raw.expirationDate ? convertExcelDateToISO(raw.expirationDate) : null
1108
1111
  if (raw.batchId) {
1109
1112
  data = data.filter(val => val.batchId === raw.batchId)
1110
1113
  comparison.push('batchId')
@@ -1176,7 +1179,8 @@ function _extractData(rawData, validatedData) {
1176
1179
  raw.productId = null
1177
1180
  }
1178
1181
 
1179
- let releaseDate = _getStdDateStr(new Date(raw.releaseDate || ''))
1182
+
1183
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/
1180
1184
 
1181
1185
  return {
1182
1186
  ...raw,
@@ -1196,17 +1200,19 @@ function _extractData(rawData, validatedData) {
1196
1200
  if (raw.assignedQty < raw.releaseQty) {
1197
1201
  errors.push('insufficient stock');
1198
1202
  }
1203
+ if(!dateRegex.test(raw.releaseDate)){
1204
+ errors.push('invalid release date format. please use dd/mm/yyyy')
1205
+ }
1199
1206
  if (raw.releaseDate === '') {
1200
1207
  errors.push('release date is empty');
1201
1208
  }
1202
- if (releaseDate < _getStdDateStr(new Date())) {
1209
+ if (raw.releaseDate < _getStdDateStr(new Date())) {
1203
1210
  errors.push('backdate is not allowed');
1204
1211
  }
1205
1212
  if (!raw.refNo || raw.refNo === '') {
1206
1213
  errors.push('ref no is empty');
1207
1214
  }
1208
-
1209
- if (raw?.type === 'b2c') {
1215
+ if (raw?.type === 'b2c') {
1210
1216
  if (!raw.attentionTo) errors.push('attention to is empty');
1211
1217
  if (!raw.postalCode) errors.push('postal code is empty');
1212
1218
  if (!raw.country) errors.push('country is empty');
@@ -1217,12 +1223,14 @@ function _extractData(rawData, validatedData) {
1217
1223
  if ((raw.codOption && !raw.paidAmount) || raw.paidAmount < 0 || raw.paidAmount == null) {
1218
1224
  errors.push('invalid paid amount');
1219
1225
  }
1226
+ if(raw?.expirationDate != null && !dateRegex.test(raw?.expirationDate)){
1227
+ errors.push('invalid expiration date format. please use dd/mm/yyyy')
1228
+ }
1220
1229
  if (raw.airwayBill && raw.lmdOption === true) {
1221
1230
  errors.push('kindly remove AWB as LMD is marked as true');
1222
1231
  }
1223
1232
  }
1224
-
1225
- return errors.length > 0 ? errors.join(', ') : ''; // Combine all errors into a single string
1233
+ return errors.length > 0 ? errors.join(', ') : ''// Combine all errors into a single string
1226
1234
  })(),
1227
1235
  };
1228
1236
 
@@ -1252,4 +1260,4 @@ function _getStdDateStr(date) {
1252
1260
  date.setHours(date.getHours() + 8)
1253
1261
  return date.toISOString().split('T')[0]
1254
1262
  }
1255
- }
1263
+ }
@@ -66,3 +66,26 @@ export class DateTimeDifference {
66
66
  return diffInSeconds
67
67
  }
68
68
  }
69
+
70
+ export function isValidExcelDate(excelSerial) {
71
+ // Check if the serial number is a valid positive number
72
+ if (isNaN(excelSerial) || excelSerial <= 0) {
73
+ return false;
74
+ }
75
+ const date = new Date((parseInt(excelSerial) - 25569) * 86400 * 1000)
76
+
77
+ return !isNaN(date.getTime());
78
+ }
79
+
80
+ export function convertExcelDateToISO(excelSerial) {
81
+ if (!isValidExcelDate(excelSerial)) {
82
+ return excelSerial; // Invalid date serial
83
+ }
84
+ const date = new Date((parseInt(excelSerial) - 25569) * 86400 * 1000)
85
+ // Format the date in YYYY-MM-DD format
86
+ const year = date.getFullYear();
87
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are zero-indexed
88
+ const day = String(date.getDate()).padStart(2, '0');
89
+
90
+ return `${year}-${month}-${day}`;
91
+ }
@@ -1,10 +1,29 @@
1
- import { EntityManager, Equal, getRepository, In, Not, Raw, Repository, SelectQueryBuilder } from 'typeorm'
1
+ import {
2
+ EntityManager,
3
+ Equal,
4
+ getRepository,
5
+ In,
6
+ Not,
7
+ Raw,
8
+ Repository,
9
+ SelectQueryBuilder
10
+ } from 'typeorm'
2
11
 
3
12
  import { User } from '@things-factory/auth-base'
4
13
  import { Bizplace } from '@things-factory/biz-base'
5
- import { Product, ProductBundle, ProductDetail } from '@things-factory/product-base'
6
- import { PartnerSetting, Setting } from '@things-factory/setting-base'
7
- import { Domain, ListParam } from '@things-factory/shell'
14
+ import {
15
+ Product,
16
+ ProductBundle,
17
+ ProductDetail
18
+ } from '@things-factory/product-base'
19
+ import {
20
+ PartnerSetting,
21
+ Setting
22
+ } from '@things-factory/setting-base'
23
+ import {
24
+ Domain,
25
+ ListParam
26
+ } from '@things-factory/shell'
8
27
  import {
9
28
  generateInventoryHistory,
10
29
  Inventory,
@@ -57,6 +76,7 @@ export const InventoryUtil = {
57
76
 
58
77
  let productFilter = filters.find(itm => itm.name == 'productName')
59
78
  let inventoryBizplaceFilter = filters.find(itm => itm.name == 'bizplaceId')
79
+ let deletedAt = filters.find(filter => filter.name == 'deleted_at')
60
80
 
61
81
  let queryStrings = `
62
82
  CREATE TEMP TABLE temp_inventory_product_group ON COMMIT DROP AS (
@@ -152,6 +172,7 @@ export const InventoryUtil = {
152
172
  `
153
173
  : ``
154
174
  }
175
+ ${deletedAt && deletedAt.value == true ? `AND pd.deleted_at isnull` : ``}
155
176
  GROUP BY
156
177
  i.lock_inventory,
157
178
  p.id,