@things-factory/sales-base 4.3.108 → 4.3.110
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-server/service/arrival-notice/arrival-notice-mutation.js +5 -6
- package/dist-server/service/arrival-notice/arrival-notice-mutation.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js +0 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js.map +1 -1
- package/dist-server/service/delivery-order/delivery-order-mutation.js +30 -3
- package/dist-server/service/delivery-order/delivery-order-mutation.js.map +1 -1
- package/dist-server/service/draft-release-good/draft-release-good-mutation.js +4 -3
- package/dist-server/service/draft-release-good/draft-release-good-mutation.js.map +1 -1
- package/dist-server/service/draft-release-good/draft-release-good-query.js +15 -11
- package/dist-server/service/draft-release-good/draft-release-good-query.js.map +1 -1
- package/dist-server/service/goods-receival-note/goods-receival-note-mutation.js +32 -4
- package/dist-server/service/goods-receival-note/goods-receival-note-mutation.js.map +1 -1
- package/dist-server/service/invoice-product/invoice-product.js +3 -8
- package/dist-server/service/invoice-product/invoice-product.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory-query.js +1 -2
- package/dist-server/service/order-inventory/order-inventory-query.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory-types.js +10 -18
- package/dist-server/service/order-inventory/order-inventory-types.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory.js +3 -12
- package/dist-server/service/order-inventory/order-inventory.js.map +1 -1
- package/dist-server/service/order-product/order-product-query.js +0 -1
- package/dist-server/service/order-product/order-product-query.js.map +1 -1
- package/dist-server/service/order-product/order-product-types.js +10 -18
- package/dist-server/service/order-product/order-product-types.js.map +1 -1
- package/dist-server/service/order-product/order-product.js +5 -0
- package/dist-server/service/order-product/order-product.js.map +1 -1
- package/dist-server/service/order-vas/order-vas.js +3 -8
- package/dist-server/service/order-vas/order-vas.js.map +1 -1
- package/dist-server/service/others/other-query.js +177 -196
- package/dist-server/service/others/other-query.js.map +1 -1
- package/dist-server/service/others/other-types.js +1 -9
- package/dist-server/service/others/other-types.js.map +1 -1
- package/dist-server/service/purchase-order/purchase-order-mutation.js +2 -10
- package/dist-server/service/purchase-order/purchase-order-mutation.js.map +1 -1
- package/dist-server/service/purchase-order/purchase-order-query.js +0 -1
- package/dist-server/service/purchase-order/purchase-order-query.js.map +1 -1
- package/dist-server/service/release-good/release-good-mutation.js +8 -18
- package/dist-server/service/release-good/release-good-mutation.js.map +1 -1
- package/dist-server/service/release-good/release-good-query.js +2 -3
- package/dist-server/service/release-good/release-good-query.js.map +1 -1
- package/dist-server/service/release-good/release-good-types.js +4 -8
- package/dist-server/service/release-good/release-good-types.js.map +1 -1
- package/dist-server/service/return-order/return-order-mutation.js +0 -3
- package/dist-server/service/return-order/return-order-mutation.js.map +1 -1
- package/dist-server/service/return-order/return-order-types.js.map +1 -1
- package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.js +3 -8
- package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.js.map +1 -1
- package/dist-server/utils/inventory-util.js +104 -39
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +14 -13
- package/server/service/arrival-notice/arrival-notice-mutation.ts +3 -6
- package/server/service/arrival-notice/arrival-notice-query.ts +0 -1
- package/server/service/delivery-order/delivery-order-mutation.ts +49 -19
- package/server/service/draft-release-good/draft-release-good-mutation.ts +4 -3
- package/server/service/draft-release-good/draft-release-good-query.ts +21 -17
- package/server/service/goods-receival-note/goods-receival-note-mutation.ts +38 -4
- package/server/service/invoice-product/invoice-product.ts +1 -5
- package/server/service/order-inventory/order-inventory-query.ts +0 -2
- package/server/service/order-inventory/order-inventory-types.ts +0 -6
- package/server/service/order-inventory/order-inventory.ts +1 -8
- package/server/service/order-product/order-product-query.ts +0 -1
- package/server/service/order-product/order-product-types.ts +0 -6
- package/server/service/order-product/order-product.ts +4 -0
- package/server/service/order-vas/order-vas.ts +1 -6
- package/server/service/others/other-query.ts +219 -231
- package/server/service/others/other-types.ts +1 -7
- package/server/service/purchase-order/purchase-order-mutation.ts +1 -10
- package/server/service/purchase-order/purchase-order-query.ts +0 -1
- package/server/service/release-good/release-good-mutation.ts +8 -21
- package/server/service/release-good/release-good-query.ts +2 -3
- package/server/service/release-good/release-good-types.ts +3 -4
- package/server/service/return-order/return-order-mutation.ts +1 -4
- package/server/service/return-order/return-order-types.ts +0 -1
- package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.ts +1 -5
- package/server/utils/inventory-util.ts +149 -75
- package/translations/en.json +0 -1
- package/translations/ko.json +1 -2
- package/translations/ms.json +1 -2
- package/translations/zh.json +0 -25
|
@@ -17,7 +17,7 @@ import { MarketplaceStore } from '@things-factory/integration-marketplace'
|
|
|
17
17
|
import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
|
|
18
18
|
import { MarketplaceOrder, MarketplaceProductVariation } from '@things-factory/marketplace-base'
|
|
19
19
|
// import { sendNotification } from '@things-factory/notification'
|
|
20
|
-
import { Product, ProductBundleSetting
|
|
20
|
+
import { Product, ProductBundleSetting } from '@things-factory/product-base'
|
|
21
21
|
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
22
22
|
import { Domain } from '@things-factory/shell'
|
|
23
23
|
import { Inventory } from '@things-factory/warehouse-base'
|
|
@@ -676,7 +676,7 @@ export async function generateReleaseGoodFunction(
|
|
|
676
676
|
|
|
677
677
|
const pbSettings: ProductBundleSetting[] = await tx.getRepository(ProductBundleSetting).find({
|
|
678
678
|
where: { productBundle: oi.product.id },
|
|
679
|
-
relations: ['product', 'productBundle'
|
|
679
|
+
relations: ['product', 'productBundle']
|
|
680
680
|
})
|
|
681
681
|
|
|
682
682
|
pbSettings.forEach(pbs => {
|
|
@@ -690,9 +690,6 @@ export async function generateReleaseGoodFunction(
|
|
|
690
690
|
id: pbs.product.id,
|
|
691
691
|
name: pbs.product.name,
|
|
692
692
|
groupType: PRODUCT_GROUP_TYPE.SINGLE
|
|
693
|
-
},
|
|
694
|
-
productDetail: {
|
|
695
|
-
id: pbs.productDetail.id
|
|
696
693
|
}
|
|
697
694
|
}
|
|
698
695
|
splitBundleOIs.push(splitOI)
|
|
@@ -707,10 +704,6 @@ export async function generateReleaseGoodFunction(
|
|
|
707
704
|
newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
|
|
708
705
|
|
|
709
706
|
for (let oi of orderInventories) {
|
|
710
|
-
let productDetail: any = await tx
|
|
711
|
-
.getRepository(ProductDetail)
|
|
712
|
-
.findOne(oi.productDetail.id, { relations: ['product'] })
|
|
713
|
-
|
|
714
707
|
let newOrderInv: OrderInventory = Object.assign({}, oi)
|
|
715
708
|
newOrderInv = {
|
|
716
709
|
...newOrderInv,
|
|
@@ -719,8 +712,7 @@ export async function generateReleaseGoodFunction(
|
|
|
719
712
|
status: ORDER_INVENTORY_STATUS.PENDING,
|
|
720
713
|
name: OrderNoGenerator.orderInventory(),
|
|
721
714
|
releaseGood: newReleaseGood,
|
|
722
|
-
product:
|
|
723
|
-
productDetail,
|
|
715
|
+
product: await tx.getRepository(Product).findOne(oi.product.id),
|
|
724
716
|
creator: user,
|
|
725
717
|
updater: user
|
|
726
718
|
}
|
|
@@ -758,9 +750,9 @@ export async function generateReleaseGoodFunction(
|
|
|
758
750
|
}
|
|
759
751
|
|
|
760
752
|
let assignedOrderInventories: OrderInventory[] = await InventoryUtil.autoAssignInventoryForRelease(
|
|
753
|
+
newOrderInv.product,
|
|
761
754
|
oi,
|
|
762
|
-
|
|
763
|
-
productDetail,
|
|
755
|
+
oi.packingType,
|
|
764
756
|
locationSortingRules,
|
|
765
757
|
bizplace,
|
|
766
758
|
warehouseDomain,
|
|
@@ -1387,17 +1379,12 @@ export async function bulkGenerateReleaseGood(
|
|
|
1387
1379
|
}
|
|
1388
1380
|
}
|
|
1389
1381
|
|
|
1390
|
-
|
|
1391
|
-
let product = oi.orderProduct?.product
|
|
1392
|
-
if (!productDetail) {
|
|
1393
|
-
productDetail = await tx.getRepository(ProductDetail).findOne(oi.productDetailId, { relations: ['product'] })
|
|
1394
|
-
product = productDetail.product
|
|
1395
|
-
}
|
|
1382
|
+
const product: Product = await tx.getRepository(Product).findOne(oi.productId)
|
|
1396
1383
|
|
|
1397
1384
|
let assignedResult = await InventoryUtil.autoAssignInventoryForRelease(
|
|
1398
|
-
oi,
|
|
1399
1385
|
product,
|
|
1400
|
-
|
|
1386
|
+
oi,
|
|
1387
|
+
oi.packingType,
|
|
1401
1388
|
locationSortingRules,
|
|
1402
1389
|
bizplace,
|
|
1403
1390
|
warehouseDomain,
|
|
@@ -133,6 +133,7 @@ export class ReleaseGoodQuery {
|
|
|
133
133
|
'orderInventories.product',
|
|
134
134
|
'orderInventories.inventory',
|
|
135
135
|
'orderInventories.inventory.product',
|
|
136
|
+
'orderInventories.inventory.product.productDetails',
|
|
136
137
|
'orderVass',
|
|
137
138
|
'orderVass.vas',
|
|
138
139
|
'creator',
|
|
@@ -196,7 +197,6 @@ export class ReleaseGoodQuery {
|
|
|
196
197
|
.createQueryBuilder('oi')
|
|
197
198
|
.leftJoinAndSelect('oi.inventory', 'inventory')
|
|
198
199
|
.leftJoinAndSelect('oi.product', 'product')
|
|
199
|
-
.leftJoinAndSelect('oi.productDetail', 'productDetail')
|
|
200
200
|
.leftJoinAndSelect('inventory.location', 'location')
|
|
201
201
|
.where('oi.domain_id = :domainId', { domainId: domain.id })
|
|
202
202
|
.andWhere('oi.release_good_id = :releaseGoodId', { releaseGoodId: releaseGood.id })
|
|
@@ -227,7 +227,6 @@ export class ReleaseGoodQuery {
|
|
|
227
227
|
batchIdRef: inventory.batchIdRef,
|
|
228
228
|
palletId: inventory.palletId,
|
|
229
229
|
product: orderInv.product,
|
|
230
|
-
productDetail: orderInv.productDetail,
|
|
231
230
|
productIdRef: orderInv.product.id,
|
|
232
231
|
productName: `${orderInv.product.name} (${orderInv.product.description})`,
|
|
233
232
|
packingType: orderInv.packingType,
|
|
@@ -935,7 +934,7 @@ function _extractData(rawData, validatedData) {
|
|
|
935
934
|
errorMsg:
|
|
936
935
|
!raw.productId || !raw.productDetailId
|
|
937
936
|
? 'inventory or product not found'
|
|
938
|
-
: raw.releaseQty <= 0
|
|
937
|
+
: raw.releaseQty <= 0
|
|
939
938
|
? 'invalid release qty'
|
|
940
939
|
: raw.assignedQty < raw.releaseQty
|
|
941
940
|
? 'insufficient stock'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Field, Float, InputType, Int, ObjectType } from 'type-graphql'
|
|
2
2
|
|
|
3
|
-
import { Product
|
|
3
|
+
import { Product } from '@things-factory/product-base'
|
|
4
4
|
import { ObjectRef } from '@things-factory/shell'
|
|
5
5
|
import { Location } from '@things-factory/warehouse-base'
|
|
6
6
|
|
|
@@ -77,9 +77,6 @@ export class InventoryInfos {
|
|
|
77
77
|
@Field(type => Product, { nullable: true })
|
|
78
78
|
product?: Product
|
|
79
79
|
|
|
80
|
-
@Field(type => ProductDetail, { nullable: true })
|
|
81
|
-
productDetail?: ProductDetail
|
|
82
|
-
|
|
83
80
|
@Field({ nullable: true })
|
|
84
81
|
packingType?: string
|
|
85
82
|
|
|
@@ -188,6 +185,8 @@ export class NewReleaseGood {
|
|
|
188
185
|
@Field({ nullable: true })
|
|
189
186
|
orderMethod: string
|
|
190
187
|
|
|
188
|
+
|
|
189
|
+
|
|
191
190
|
@Field({ nullable: true })
|
|
192
191
|
collectionOrderNo: string
|
|
193
192
|
|
|
@@ -6,7 +6,7 @@ import { Attachment, createAttachments } from '@things-factory/attachment-base'
|
|
|
6
6
|
import { Role, User } from '@things-factory/auth-base'
|
|
7
7
|
import { Bizplace, getDomainUsers } from '@things-factory/biz-base'
|
|
8
8
|
import { sendNotification } from '@things-factory/notification'
|
|
9
|
-
import { Product
|
|
9
|
+
import { Product } from '@things-factory/product-base'
|
|
10
10
|
import { Domain } from '@things-factory/shell'
|
|
11
11
|
import { Inventory } from '@things-factory/warehouse-base'
|
|
12
12
|
|
|
@@ -59,7 +59,6 @@ export class ReturnOrderMutation {
|
|
|
59
59
|
itm =>
|
|
60
60
|
itm.product.id === curr.product.id &&
|
|
61
61
|
itm.packingType === curr.packingType &&
|
|
62
|
-
itm.productDetailId === curr.product.productDetailId &&
|
|
63
62
|
itm.batchId === curr.batchId &&
|
|
64
63
|
itm.packingSize === curr.packingSize
|
|
65
64
|
)
|
|
@@ -69,7 +68,6 @@ export class ReturnOrderMutation {
|
|
|
69
68
|
} else {
|
|
70
69
|
existingItem.returnQty = existingItem.returnQty + curr.returnQty
|
|
71
70
|
existingItem.returnUomValue = existingItem.returnUomValue + curr.returnUomValue
|
|
72
|
-
existingItem.remark = `${existingItem.remark} | ${curr.remark}`
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
return acc
|
|
@@ -101,7 +99,6 @@ export class ReturnOrderMutation {
|
|
|
101
99
|
newOrderInv.name = OrderNoGenerator.orderInventory()
|
|
102
100
|
newOrderInv.returnOrder = createdReturnOrder
|
|
103
101
|
newOrderInv.product = await tx.getRepository(Product).findOne(moi.product.id)
|
|
104
|
-
newOrderInv.productDetail = await tx.getRepository(ProductDetail).findOne(moi.productDetail.id)
|
|
105
102
|
newOrderInv.creator = user
|
|
106
103
|
newOrderInv.updater = user
|
|
107
104
|
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
|
|
13
13
|
import { User } from '@things-factory/auth-base'
|
|
14
14
|
import { Bizplace } from '@things-factory/biz-base'
|
|
15
|
-
import { Product
|
|
15
|
+
import { Product } from '@things-factory/product-base'
|
|
16
16
|
import { Domain } from '@things-factory/shell'
|
|
17
17
|
import { Inventory } from '@things-factory/warehouse-base'
|
|
18
18
|
|
|
@@ -127,10 +127,6 @@ export class ReverseKittingOrderInventory {
|
|
|
127
127
|
@Field({ nullable: true })
|
|
128
128
|
updatedAt?: Date
|
|
129
129
|
|
|
130
|
-
@ManyToOne(type => ProductDetail, { nullable: true })
|
|
131
|
-
@Field({ nullable: true })
|
|
132
|
-
productDetail: ProductDetail
|
|
133
|
-
|
|
134
130
|
@ManyToOne(type => User, { nullable: true })
|
|
135
131
|
@Field({ nullable: true })
|
|
136
132
|
creator?: User
|
|
@@ -2,7 +2,7 @@ import { EntityManager, Equal, getRepository, In, Not, Raw, Repository, SelectQu
|
|
|
2
2
|
|
|
3
3
|
import { User } from '@things-factory/auth-base'
|
|
4
4
|
import { Bizplace } from '@things-factory/biz-base'
|
|
5
|
-
import { Product, ProductBundle
|
|
5
|
+
import { Product, ProductBundle } from '@things-factory/product-base'
|
|
6
6
|
import { Domain, ListParam } from '@things-factory/shell'
|
|
7
7
|
import {
|
|
8
8
|
Inventory,
|
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
Location,
|
|
13
13
|
LOCATION_STATUS,
|
|
14
14
|
LOCATION_TYPE,
|
|
15
|
-
Pallet
|
|
16
|
-
generateInventoryHistory
|
|
15
|
+
Pallet
|
|
17
16
|
} from '@things-factory/warehouse-base'
|
|
18
17
|
|
|
19
18
|
import { ORDER_TYPES } from '../constants'
|
|
@@ -103,7 +102,6 @@ export const InventoryUtil = {
|
|
|
103
102
|
coalesce(p.sku, '') AS "productSKU",
|
|
104
103
|
coalesce(p.brand, '') AS "productBrand",
|
|
105
104
|
p.id AS "productId",
|
|
106
|
-
pd.id AS "productDetailId",
|
|
107
105
|
COALESCE(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)),0) AS "remainQty",
|
|
108
106
|
COALESCE(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)),0) AS "remainUomValue",
|
|
109
107
|
concat(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)), ' ', pd.uom) AS "remainUomValueWithUom",
|
|
@@ -116,7 +114,10 @@ export const InventoryUtil = {
|
|
|
116
114
|
WHERE l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
|
|
117
115
|
AND i.domain_id = $1 AND i.status = 'STORED'
|
|
118
116
|
${inventoryBizplaceFilter ? `AND i.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
|
|
119
|
-
) i ON i.
|
|
117
|
+
) i ON i.product_id = pd.product_id
|
|
118
|
+
AND i.packing_type = pd.packing_type
|
|
119
|
+
and i.packing_size = pd.packing_size
|
|
120
|
+
and i.uom = pd.uom
|
|
120
121
|
LEFT JOIN oi ON i.batch_id = oi.batch_id AND p.name = oi.product_name AND i.packing_type = oi.packing_type AND i.packing_size = oi.packing_size AND i.uom = oi.uom
|
|
121
122
|
LEFT JOIN (
|
|
122
123
|
SELECT pbs.product_id, SUM(pbs.bundle_qty * src.release_qty) AS bundle_product_release_qty, SUM(pbs.bundle_qty * src.release_uom_value) AS bundle_product_release_uom_value
|
|
@@ -124,26 +125,24 @@ export const InventoryUtil = {
|
|
|
124
125
|
INNER JOIN json_populate_recordset(NULL::order_inventories, '${batchBundle}') src ON src.product_id = pbs.product_bundle_id
|
|
125
126
|
GROUP BY pbs.product_id
|
|
126
127
|
) bp on i.product_id = bp.product_id
|
|
127
|
-
WHERE
|
|
128
|
+
WHERE p.bizplace_id IN (${bizplaceIds})
|
|
128
129
|
${productDetailWhereClause}
|
|
129
|
-
${
|
|
130
|
-
|
|
131
|
-
? `AND (
|
|
130
|
+
${productFilter
|
|
131
|
+
? `AND (
|
|
132
132
|
lower(p.sku) ilike '${productFilter.value}'
|
|
133
133
|
OR lower(p.name) ilike '${productFilter.value}'
|
|
134
134
|
OR lower(p.description) ilike '${productFilter.value}'
|
|
135
135
|
)
|
|
136
136
|
`
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
: ``
|
|
138
|
+
}
|
|
139
139
|
GROUP BY
|
|
140
140
|
p.id,
|
|
141
|
-
pd.id,
|
|
142
141
|
pd.packing_type,
|
|
143
142
|
pd.packing_size,
|
|
144
143
|
pd.uom
|
|
145
144
|
UNION
|
|
146
|
-
SELECT packing_type, packing_size,'UNIT' AS "uom", name AS "productName", sku AS "productSKU", '-' AS "productBrand", id AS "productId",
|
|
145
|
+
SELECT packing_type, packing_size,'UNIT' AS "uom", name AS "productName", sku AS "productSKU", '-' AS "productBrand", id AS "productId",
|
|
147
146
|
COALESCE(MIN(FLOOR(pbs."availableQty")),0) AS "remainQty",
|
|
148
147
|
COALESCE(MIN(FLOOR(pbs."availableUomValue")),0) AS "remainUomValue",
|
|
149
148
|
CONCAT(COALESCE(MIN(FLOOR(pbs."availableUomValue")),0),' UNIT') AS "remainUomValueWithUom",
|
|
@@ -152,8 +151,7 @@ export const InventoryUtil = {
|
|
|
152
151
|
LEFT JOIN (
|
|
153
152
|
SELECT pbs.product_id, pbs.product_bundle_id, min(pbs.bundle_qty),
|
|
154
153
|
(SUM(COALESCE(i2.qty, 0)) - SUM(COALESCE(i2.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
|
|
155
|
-
(SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue"
|
|
156
|
-
pbs.product_detail_id
|
|
154
|
+
(SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue"
|
|
157
155
|
FROM product_bundle_settings pbs
|
|
158
156
|
LEFT JOIN inventories i2 ON i2.product_id = pbs.product_id AND i2.domain_id = $1 AND i2.status = 'STORED'
|
|
159
157
|
INNER JOIN locations l2 ON i2.location_id = l2.id
|
|
@@ -162,28 +160,25 @@ export const InventoryUtil = {
|
|
|
162
160
|
${inventoryBizplaceFilter ? `AND i2.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
|
|
163
161
|
GROUP BY
|
|
164
162
|
pbs.product_id,
|
|
165
|
-
pbs.product_bundle_id
|
|
166
|
-
pbs.product_detail_id
|
|
163
|
+
pbs.product_bundle_id
|
|
167
164
|
) pbs ON pbs.product_bundle_id = pb.id
|
|
168
165
|
${bundleWhereClause}
|
|
169
166
|
AND pb.bizplace_id IN (${bizplaceIds})
|
|
170
|
-
${
|
|
171
|
-
|
|
172
|
-
? `AND (
|
|
167
|
+
${productFilter
|
|
168
|
+
? `AND (
|
|
173
169
|
lower(pb.sku) ilike '${productFilter.value}'
|
|
174
170
|
OR lower(pb.name) ilike '${productFilter.value}'
|
|
175
171
|
OR lower(pb.description) ilike '${productFilter.value}'
|
|
176
172
|
)
|
|
177
173
|
`
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
: ``
|
|
175
|
+
}
|
|
180
176
|
GROUP BY
|
|
181
177
|
pb.packing_type,
|
|
182
178
|
pb.packing_size,
|
|
183
179
|
pb.name,
|
|
184
180
|
pb.sku,
|
|
185
|
-
pb.id
|
|
186
|
-
pbs.product_detail_id
|
|
181
|
+
pb.id
|
|
187
182
|
)
|
|
188
183
|
AS inv_prod_grp
|
|
189
184
|
${whereClause}
|
|
@@ -278,7 +273,6 @@ export const InventoryUtil = {
|
|
|
278
273
|
coalesce(p.sku, '') AS "productSKU",
|
|
279
274
|
coalesce(p.brand, '') AS "productBrand",
|
|
280
275
|
p.id AS "productId",
|
|
281
|
-
i.product_detail_id AS "productDetailId",
|
|
282
276
|
SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)) AS "remainQty",
|
|
283
277
|
SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)) AS "remainUomValue",
|
|
284
278
|
concat(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)), ' ', i.uom) AS "remainUomValueWithUom",
|
|
@@ -298,7 +292,6 @@ export const InventoryUtil = {
|
|
|
298
292
|
AND l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
|
|
299
293
|
${productWhereClause}
|
|
300
294
|
GROUP BY
|
|
301
|
-
i.product_detail_id,
|
|
302
295
|
i.batch_id,
|
|
303
296
|
i.batch_id_ref,
|
|
304
297
|
p.id,
|
|
@@ -306,7 +299,7 @@ export const InventoryUtil = {
|
|
|
306
299
|
i.packing_size,
|
|
307
300
|
i.uom
|
|
308
301
|
UNION
|
|
309
|
-
SELECT 'BUNDLE' AS "batchId", null as "batchIdRef", packing_type, packing_size,'UNIT' AS "uom", name AS "productName", sku AS "productSKU", 'brand' AS "productBrand", id AS "productId",
|
|
302
|
+
SELECT 'BUNDLE' AS "batchId", null as "batchIdRef", packing_type, packing_size,'UNIT' AS "uom", name AS "productName", sku AS "productSKU", 'brand' AS "productBrand", id AS "productId",
|
|
310
303
|
MIN(FLOOR(pbs."availableQty")) AS "remainQty",
|
|
311
304
|
MIN(FLOOR(pbs."availableUomValue")) AS "remainUomValue",
|
|
312
305
|
CONCAT(MIN(FLOOR(pbs."availableUomValue")),' UNIT') AS "remainUomValueWithUom",
|
|
@@ -315,17 +308,16 @@ export const InventoryUtil = {
|
|
|
315
308
|
INNER JOIN (
|
|
316
309
|
SELECT pbs.product_id, pbs.product_bundle_id, min(pbs.bundle_qty),
|
|
317
310
|
(SUM(COALESCE(i2.qty, 0)) - SUM(COALESCE(i2.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
|
|
318
|
-
(SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue"
|
|
319
|
-
pbs.product_detail_id
|
|
311
|
+
(SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue"
|
|
320
312
|
FROM product_bundle_settings pbs
|
|
321
313
|
LEFT JOIN inventories i2 ON i2.product_id = pbs.product_id AND i2.domain_id = $1
|
|
322
314
|
AND i2.bizplace_id IN (${bizplaceIds})
|
|
323
315
|
AND i2.status = 'STORED'
|
|
324
316
|
LEFT JOIN oi ON oi.product_id = i2.product_id
|
|
325
|
-
GROUP BY pbs.product_id, pbs.product_bundle_id
|
|
317
|
+
GROUP BY pbs.product_id, pbs.product_bundle_id
|
|
326
318
|
) pbs ON pbs.product_bundle_id = pb.id
|
|
327
319
|
${bundleWhereClause}
|
|
328
|
-
GROUP BY pb.packing_type, pb.packing_size, pb.name, pb.sku, pb.id
|
|
320
|
+
GROUP BY pb.packing_type, pb.packing_size, pb.name, pb.sku, pb.id
|
|
329
321
|
)
|
|
330
322
|
AS inv_prod_grp
|
|
331
323
|
${whereClause}
|
|
@@ -365,15 +357,13 @@ export const InventoryUtil = {
|
|
|
365
357
|
|
|
366
358
|
if (params?.pagination) {
|
|
367
359
|
items = await trxMgr.query(
|
|
368
|
-
`select * from temp_inventory_product_group ${filterGroupTypeQuery ? filterGroupTypeQuery : ''} ${
|
|
369
|
-
sortingArr.length > 0 ? ' Order by ' + sortedBy.toString() : ''
|
|
360
|
+
`select * from temp_inventory_product_group ${filterGroupTypeQuery ? filterGroupTypeQuery : ''} ${sortingArr.length > 0 ? ' Order by ' + sortedBy.toString() : ''
|
|
370
361
|
} OFFSET $1 LIMIT $2`,
|
|
371
362
|
[(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
|
|
372
363
|
)
|
|
373
364
|
} else {
|
|
374
365
|
items = await trxMgr.query(
|
|
375
|
-
`select * from temp_inventory_product_group ${filterGroupTypeQuery ? filterGroupTypeQuery : ''} ${
|
|
376
|
-
sortingArr.length > 0 ? ' Order by ' + sortedBy.toString() : ''
|
|
366
|
+
`select * from temp_inventory_product_group ${filterGroupTypeQuery ? filterGroupTypeQuery : ''} ${sortingArr.length > 0 ? ' Order by ' + sortedBy.toString() : ''
|
|
377
367
|
}`
|
|
378
368
|
)
|
|
379
369
|
}
|
|
@@ -493,17 +483,12 @@ export const InventoryUtil = {
|
|
|
493
483
|
context: any,
|
|
494
484
|
trxMgr?: EntityManager
|
|
495
485
|
): Promise<Inventory> {
|
|
496
|
-
let validOrderInventories = orderInventories.filter(oi => oi.isError == false)
|
|
497
|
-
|
|
498
|
-
if (!validOrderInventories.length) {
|
|
499
|
-
return
|
|
500
|
-
}
|
|
501
|
-
|
|
502
486
|
let json_oi = JSON.stringify(
|
|
503
|
-
|
|
487
|
+
orderInventories.map(x => {
|
|
504
488
|
return {
|
|
505
|
-
|
|
489
|
+
product_id: x.product.id,
|
|
506
490
|
batch_id: x.batchId,
|
|
491
|
+
packing_type: x.packingType,
|
|
507
492
|
release_qty: x.releaseQty,
|
|
508
493
|
uom: x.uom
|
|
509
494
|
}
|
|
@@ -512,14 +497,15 @@ export const InventoryUtil = {
|
|
|
512
497
|
|
|
513
498
|
let resultQb = await trxMgr.query(
|
|
514
499
|
`
|
|
515
|
-
select joi.
|
|
500
|
+
select joi.product_id as "productId", joi.batch_id as "batchId", joi.packing_type as "packingType", joi.uom as "uom", joi.release_qty as "releaseQty",
|
|
516
501
|
sum(i.qty - coalesce(i.locked_qty,0)) - coalesce(
|
|
517
502
|
(
|
|
518
503
|
select sum(oi.release_qty) from order_inventories oi
|
|
519
504
|
where (oi.status = 'PENDING' or oi.status = 'PENDING_RECEIVE' or oi.status = 'PENDING_WORKSHEET' or oi.status = 'PENDING_SPLIT')
|
|
520
505
|
and oi.inventory_id IS null
|
|
521
|
-
and oi.
|
|
506
|
+
and oi.product_id = joi.product_id
|
|
522
507
|
and oi.batch_id = joi.batch_id
|
|
508
|
+
and oi.packing_type = joi.packing_type
|
|
523
509
|
and oi.uom = joi.uom
|
|
524
510
|
and oi.domain_id = $1
|
|
525
511
|
and oi.bizplace_id = $2
|
|
@@ -529,20 +515,21 @@ export const InventoryUtil = {
|
|
|
529
515
|
select sum(oi.release_uom_value) from order_inventories oi
|
|
530
516
|
where (oi.status = 'PENDING' or oi.status = 'PENDING_RECEIVE' or oi.status = 'PENDING_WORKSHEET' or oi.status = 'PENDING_SPLIT')
|
|
531
517
|
and oi.inventory_id IS null
|
|
532
|
-
and oi.
|
|
518
|
+
and oi.product_id = joi.product_id
|
|
533
519
|
and oi.batch_id = joi.batch_id
|
|
520
|
+
and oi.packing_type = joi.packing_type
|
|
534
521
|
and oi.uom = joi.uom
|
|
535
522
|
and oi.domain_id = $1
|
|
536
523
|
and oi.bizplace_id = $2
|
|
537
524
|
),0) as "availableUomValue"
|
|
538
525
|
from json_populate_recordset(NULL::order_inventories,'${json_oi}') joi
|
|
539
|
-
left join inventories i on joi.
|
|
526
|
+
left join inventories i on joi.product_id = i.product_id
|
|
540
527
|
and joi.batch_id = i.batch_id
|
|
541
|
-
and i.status ='STORED'
|
|
528
|
+
and joi.packing_type = i.packing_type and i.status ='STORED'
|
|
542
529
|
and joi.uom = i.uom
|
|
543
530
|
and i.domain_id = $1
|
|
544
531
|
and i.bizplace_id = $2
|
|
545
|
-
group by joi.
|
|
532
|
+
group by joi.product_id, joi.batch_id, joi.packing_type, joi.release_qty, joi.uom
|
|
546
533
|
`,
|
|
547
534
|
[warehouseDomain.id, partnerBizplace.id]
|
|
548
535
|
)
|
|
@@ -588,9 +575,9 @@ export const InventoryUtil = {
|
|
|
588
575
|
* @returns orderInventories
|
|
589
576
|
*/
|
|
590
577
|
async autoAssignInventoryForRelease(
|
|
591
|
-
orderInventory: OrderInventory,
|
|
592
578
|
product: Product,
|
|
593
|
-
|
|
579
|
+
orderInventory: OrderInventory,
|
|
580
|
+
packingType: string,
|
|
594
581
|
locationSortingRules: any = [],
|
|
595
582
|
customerBizplace: Bizplace,
|
|
596
583
|
domain: Domain,
|
|
@@ -601,14 +588,16 @@ export const InventoryUtil = {
|
|
|
601
588
|
qb.leftJoinAndSelect('iv.location', 'loc')
|
|
602
589
|
.andWhere('"iv"."domain_id" = :domainId')
|
|
603
590
|
.andWhere('"iv"."bizplace_id" = :bizplaceId')
|
|
604
|
-
.andWhere('"iv"."
|
|
591
|
+
.andWhere('"iv"."packing_type" = :packingType')
|
|
592
|
+
.andWhere('"iv"."product_id" = :productId')
|
|
605
593
|
.andWhere('"iv"."status" = :status')
|
|
606
594
|
.andWhere('"iv"."qty" - COALESCE("iv"."locked_qty", 0) > 0')
|
|
607
595
|
.andWhere('"loc"."type" NOT IN (:...locationTypes)')
|
|
608
596
|
.setParameters({
|
|
609
597
|
domainId: domain.id,
|
|
610
598
|
bizplaceId: customerBizplace.id,
|
|
611
|
-
|
|
599
|
+
packingType: packingType,
|
|
600
|
+
productId: product.id,
|
|
612
601
|
status: INVENTORY_STATUS.STORED,
|
|
613
602
|
locationTypes: [LOCATION_TYPE.QUARANTINE, LOCATION_TYPE.RESERVE]
|
|
614
603
|
})
|
|
@@ -670,7 +659,7 @@ export const InventoryUtil = {
|
|
|
670
659
|
}
|
|
671
660
|
})
|
|
672
661
|
|
|
673
|
-
return _composeTargetInventories(
|
|
662
|
+
return _composeTargetInventories(product, orderInventory, inventories)
|
|
674
663
|
},
|
|
675
664
|
|
|
676
665
|
/**
|
|
@@ -862,32 +851,31 @@ async function getConditions(
|
|
|
862
851
|
case 'batch_product':
|
|
863
852
|
productWhereClause += `
|
|
864
853
|
AND (i.batch_id, p.id, i.packing_type, i.packing_size) ${operator === 'in' ? 'IN' : 'NOT IN'} (${value
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
854
|
+
.map(
|
|
855
|
+
(v: { batchId: string; productId: string; packingType: string; packingSize: string }) =>
|
|
856
|
+
`('${v.batchId}', '${v.productId}', '${v.packingType}', '${v.packingSize}')`
|
|
857
|
+
)
|
|
858
|
+
.join()})
|
|
870
859
|
`
|
|
871
860
|
break
|
|
872
861
|
|
|
873
862
|
case 'batch_bundle':
|
|
874
863
|
bundleWhereClause += `
|
|
875
864
|
${bundleWhereClause == '' ? 'WHERE' : 'AND'} pb.id ${operator === 'in' ? 'IN' : 'NOT IN'} (${value
|
|
876
|
-
|
|
877
|
-
|
|
865
|
+
.map((v: { productId: string }) => `('${v.productId}')`)
|
|
866
|
+
.join()})
|
|
878
867
|
`
|
|
879
868
|
break
|
|
880
869
|
|
|
881
870
|
case 'product':
|
|
882
871
|
productDetailWhereClause += `
|
|
883
|
-
AND (pd.product_id, pd.packing_type, pd.packing_size, pd.uom) ${
|
|
884
|
-
operator === 'in' ? 'IN' : 'NOT IN'
|
|
872
|
+
AND (pd.product_id, pd.packing_type, pd.packing_size, pd.uom) ${operator === 'in' ? 'IN' : 'NOT IN'
|
|
885
873
|
} (${value
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
874
|
+
.map(
|
|
875
|
+
(v: { productId: string; packingType: string; packingSize: string; uom: string }) =>
|
|
876
|
+
`('${v.productId}', '${v.packingType}', '${v.packingSize}', '${v.uom}')`
|
|
877
|
+
)
|
|
878
|
+
.join()})
|
|
891
879
|
`
|
|
892
880
|
break
|
|
893
881
|
}
|
|
@@ -939,6 +927,98 @@ async function updateInventory(
|
|
|
939
927
|
return await trxMgr.getRepository(Inventory).save(inventory)
|
|
940
928
|
}
|
|
941
929
|
|
|
930
|
+
async function generateInventoryHistory(
|
|
931
|
+
inventory: Inventory,
|
|
932
|
+
refOrder: any,
|
|
933
|
+
transactionType: string,
|
|
934
|
+
qty: number,
|
|
935
|
+
uomValue: number,
|
|
936
|
+
user: User,
|
|
937
|
+
trxMgr?: EntityManager
|
|
938
|
+
): Promise<InventoryHistory> {
|
|
939
|
+
const invHistoryRepo: Repository<InventoryHistory> =
|
|
940
|
+
trxMgr?.getRepository(InventoryHistory) || getRepository(InventoryHistory)
|
|
941
|
+
const invRepo: Repository<Inventory> = trxMgr?.getRepository(Inventory) || getRepository(Inventory)
|
|
942
|
+
|
|
943
|
+
if (!inventory?.id) throw new Error(`Can't find out ID of inventory.`)
|
|
944
|
+
if (!refOrder?.id || !refOrder.name) throw new Error(`Can't find out ID or Name of Reference Order`)
|
|
945
|
+
if (
|
|
946
|
+
!inventory?.domain ||
|
|
947
|
+
!inventory?.bizplace ||
|
|
948
|
+
!inventory?.product?.id ||
|
|
949
|
+
!inventory?.warehouse?.id ||
|
|
950
|
+
!inventory?.location?.id
|
|
951
|
+
) {
|
|
952
|
+
inventory = await invRepo.findOne({
|
|
953
|
+
where: { id: inventory.id },
|
|
954
|
+
relations: ['domain', 'bizplace', 'product', 'warehouse', 'location']
|
|
955
|
+
})
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const domain: Domain = inventory.domain
|
|
959
|
+
const location: Location = inventory.location
|
|
960
|
+
|
|
961
|
+
const seq: number = await invHistoryRepo.count({ domain: inventory.domain, palletId: inventory.palletId })
|
|
962
|
+
let openingQty: number = 0
|
|
963
|
+
let openingUomValue: number = 0
|
|
964
|
+
|
|
965
|
+
if (seq) {
|
|
966
|
+
const lastInvHistory: InventoryHistory = await invHistoryRepo.findOne({
|
|
967
|
+
domain: inventory.domain,
|
|
968
|
+
palletId: inventory.palletId,
|
|
969
|
+
seq: seq - 1
|
|
970
|
+
})
|
|
971
|
+
openingQty = lastInvHistory.openingQty + lastInvHistory.qty
|
|
972
|
+
openingUomValue = lastInvHistory.openingUomValue + lastInvHistory.uomValue
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
let inventoryHistory: InventoryHistory = new InventoryHistory()
|
|
976
|
+
inventoryHistory.name = InventoryNoGenerator.inventoryHistoryName()
|
|
977
|
+
inventoryHistory.description = inventory.description
|
|
978
|
+
inventoryHistory.seq = seq
|
|
979
|
+
inventoryHistory.palletId = inventory.palletId
|
|
980
|
+
inventoryHistory.cartonId = inventory.cartonId
|
|
981
|
+
inventoryHistory.batchId = inventory.batchId
|
|
982
|
+
inventoryHistory.batchIdRef = inventory.batchIdRef
|
|
983
|
+
inventoryHistory.status = inventory.status
|
|
984
|
+
inventoryHistory.transactionType = transactionType
|
|
985
|
+
inventoryHistory.refOrderId = refOrder?.id || null
|
|
986
|
+
inventoryHistory.orderNo = refOrder?.name || null
|
|
987
|
+
inventoryHistory.orderRefNo = refOrder?.refNo || null
|
|
988
|
+
inventoryHistory.inventory = inventory
|
|
989
|
+
inventoryHistory.product = inventory.product
|
|
990
|
+
inventoryHistory.reusablePallet = inventory.reusablePallet
|
|
991
|
+
inventoryHistory.zone = inventory.zone
|
|
992
|
+
inventoryHistory.warehouse = inventory.warehouse
|
|
993
|
+
inventoryHistory.location = inventory.location
|
|
994
|
+
inventoryHistory.expirationDate = inventory.expirationDate
|
|
995
|
+
inventoryHistory.packingType = inventory.packingType
|
|
996
|
+
inventoryHistory.packingSize = inventory.packingSize
|
|
997
|
+
inventoryHistory.uom = inventory.uom
|
|
998
|
+
inventoryHistory.qty = qty
|
|
999
|
+
inventoryHistory.openingQty = openingQty
|
|
1000
|
+
inventoryHistory.uomValue = uomValue
|
|
1001
|
+
inventoryHistory.openingUomValue = openingUomValue
|
|
1002
|
+
inventoryHistory.unitCost = inventory.unitCost
|
|
1003
|
+
inventoryHistory.domain = inventory.domain
|
|
1004
|
+
inventoryHistory.bizplace = inventory.bizplace
|
|
1005
|
+
inventoryHistory.creator = user
|
|
1006
|
+
inventoryHistory.updater = user
|
|
1007
|
+
|
|
1008
|
+
inventoryHistory = await invHistoryRepo.save(inventoryHistory)
|
|
1009
|
+
|
|
1010
|
+
if (inventory.lastSeq !== seq) {
|
|
1011
|
+
await invRepo.save({
|
|
1012
|
+
...inventory,
|
|
1013
|
+
lastSeq: inventoryHistory.seq,
|
|
1014
|
+
updater: user
|
|
1015
|
+
})
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
await switchLocationStatus(domain, location, user, trxMgr)
|
|
1019
|
+
return inventoryHistory
|
|
1020
|
+
}
|
|
1021
|
+
|
|
942
1022
|
/**
|
|
943
1023
|
* @description: Check location emptiness and update status of location
|
|
944
1024
|
* @param domain
|
|
@@ -977,17 +1057,12 @@ export async function switchLocationStatus(
|
|
|
977
1057
|
return location
|
|
978
1058
|
}
|
|
979
1059
|
|
|
980
|
-
export function _composeTargetInventories(
|
|
981
|
-
productDetail: ProductDetail,
|
|
982
|
-
record: any,
|
|
983
|
-
inventories: Inventory[]
|
|
984
|
-
): OrderInventory[] {
|
|
1060
|
+
export function _composeTargetInventories(product: Product, record: any, inventories: Inventory[]): OrderInventory[] {
|
|
985
1061
|
let leftReleaseQty: number = record.releaseQty
|
|
986
1062
|
let leftReleaseUomValue: number = record.releaseUomValue
|
|
987
1063
|
let compReleaseQty: number = 0
|
|
988
1064
|
let compReleaseUomValue: number = 0
|
|
989
1065
|
let totalInventoryQty: number = inventories.reduce((total, inventory) => total + inventory.remainQty, 0)
|
|
990
|
-
let product = productDetail.product
|
|
991
1066
|
|
|
992
1067
|
if (totalInventoryQty < record.releaseQty) {
|
|
993
1068
|
throw new Error(`invalid release qty for ${product?.sku}`)
|
|
@@ -1040,7 +1115,6 @@ export function _composeTargetInventories(
|
|
|
1040
1115
|
batchIdRef,
|
|
1041
1116
|
uom,
|
|
1042
1117
|
product,
|
|
1043
|
-
productDetail,
|
|
1044
1118
|
type: ORDER_TYPES.RELEASE_OF_GOODS
|
|
1045
1119
|
})
|
|
1046
1120
|
|
package/translations/en.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"error.Manifest(s) (x) already in open status": "Manifest(s) ({x}) already in open status",
|
|
3
|
-
"error.product_not_found": "product not found",
|
|
4
3
|
"error.release_order_not_found": "release order not found",
|
|
5
4
|
"error.tracking_no_already_scanned_before": "tracking no already scanned before",
|
|
6
5
|
"error.tracking_no_belongs_to_x": "tracking no belongs to {x}",
|