@things-factory/operato-hub 4.0.9 → 4.0.13
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/config.development.js +49 -0
- package/dist-server/controllers/bizplace-initializer/dataset/codes.js +28 -4
- package/dist-server/controllers/bizplace-initializer/dataset/codes.js.map +1 -1
- package/dist-server/controllers/bizplace-initializer/dataset/menus.js +22 -0
- package/dist-server/controllers/bizplace-initializer/dataset/menus.js.map +1 -1
- package/dist-server/controllers/bizplace-initializer/dataset/roles-privileges.js +49 -0
- package/dist-server/controllers/bizplace-initializer/dataset/roles-privileges.js.map +1 -1
- package/dist-server/controllers/bizplace-initializer/dataset/settings.js +5 -0
- package/dist-server/controllers/bizplace-initializer/dataset/settings.js.map +1 -1
- package/dist-server/graphql/resolvers/synchronization/fetch-sync-invoices.js +1 -1
- package/dist-server/graphql/resolvers/synchronization/fetch-sync-invoices.js.map +1 -1
- package/dist-server/graphql/resolvers/synchronization/fetch-sync-purchase-orders.js +23 -10
- package/dist-server/graphql/resolvers/synchronization/fetch-sync-purchase-orders.js.map +1 -1
- package/dist-server/graphql/types/synchronization/index.js +1 -1
- package/dist-server/routers/api/restful-apis/unstable/add-inbound-order.js +9 -9
- package/dist-server/routers/api/restful-apis/unstable/add-inbound-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/unstable/add-release-order.js +396 -306
- package/dist-server/routers/api/restful-apis/unstable/add-release-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/unstable/get-marketplace-order-shipping-list.js +11 -19
- package/dist-server/routers/api/restful-apis/unstable/get-marketplace-order-shipping-list.js.map +1 -1
- package/dist-server/routers/api/restful-apis/unstable/index.js +1 -0
- package/dist-server/routers/api/restful-apis/unstable/index.js.map +1 -1
- package/dist-server/routers/api/restful-apis/unstable/update-release-order-details.js +82 -0
- package/dist-server/routers/api/restful-apis/unstable/update-release-order-details.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/add-release-order.js +394 -307
- package/dist-server/routers/api/restful-apis/v1/add-release-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/get-marketplace-order-shipping-list.js +13 -22
- package/dist-server/routers/api/restful-apis/v1/get-marketplace-order-shipping-list.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/index.js +1 -0
- package/dist-server/routers/api/restful-apis/v1/index.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/update-release-order-details.js +82 -0
- package/dist-server/routers/api/restful-apis/v1/update-release-order-details.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v2/add-release-order.js +394 -307
- package/dist-server/routers/api/restful-apis/v2/add-release-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v2/get-marketplace-order-shipping-list.js +13 -22
- package/dist-server/routers/api/restful-apis/v2/get-marketplace-order-shipping-list.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v2/index.js +1 -0
- package/dist-server/routers/api/restful-apis/v2/index.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v2/update-release-order-details.js +82 -0
- package/dist-server/routers/api/restful-apis/v2/update-release-order-details.js.map +1 -0
- package/openapi/unstable/outbound.yaml +85 -0
- package/openapi/v1/outbound.yaml +85 -0
- package/openapi/v2/outbound.yaml +85 -0
- package/package.json +67 -67
- package/server/controllers/bizplace-initializer/dataset/codes.ts +28 -4
- package/server/controllers/bizplace-initializer/dataset/menus.ts +22 -0
- package/server/controllers/bizplace-initializer/dataset/roles-privileges.ts +49 -0
- package/server/controllers/bizplace-initializer/dataset/settings.ts +5 -0
- package/server/graphql/resolvers/synchronization/fetch-sync-invoices.ts +1 -1
- package/server/graphql/resolvers/synchronization/fetch-sync-purchase-orders.ts +33 -9
- package/server/graphql/types/synchronization/index.ts +1 -1
- package/server/routers/api/restful-apis/unstable/add-inbound-order.ts +7 -7
- package/server/routers/api/restful-apis/unstable/add-release-order.ts +447 -336
- package/server/routers/api/restful-apis/unstable/get-marketplace-order-shipping-list.ts +12 -12
- package/server/routers/api/restful-apis/unstable/index.ts +1 -0
- package/server/routers/api/restful-apis/unstable/update-release-order-details.ts +94 -0
- package/server/routers/api/restful-apis/v1/add-release-order.ts +444 -339
- package/server/routers/api/restful-apis/v1/get-marketplace-order-shipping-list.ts +14 -15
- package/server/routers/api/restful-apis/v1/index.ts +1 -0
- package/server/routers/api/restful-apis/v1/update-release-order-details.ts +94 -0
- package/server/routers/api/restful-apis/v2/add-release-order.ts +444 -339
- package/server/routers/api/restful-apis/v2/get-marketplace-order-shipping-list.ts +14 -15
- package/server/routers/api/restful-apis/v2/index.ts +1 -0
- package/server/routers/api/restful-apis/v2/update-release-order-details.ts +94 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import gql from 'graphql-tag'
|
|
2
|
-
import {
|
|
2
|
+
import { EntityManager, getConnection, SelectQueryBuilder } from 'typeorm'
|
|
3
3
|
|
|
4
4
|
import { restfulApiRouter as router } from '@things-factory/api'
|
|
5
5
|
import { Bizplace, getCompanyBizplace } from '@things-factory/biz-base'
|
|
6
6
|
import { Product, ProductBundle, ProductDetail } from '@things-factory/product-base'
|
|
7
7
|
import { ORDER_TYPES, OrderInventory } from '@things-factory/sales-base'
|
|
8
8
|
import { Setting } from '@things-factory/setting-base'
|
|
9
|
-
import { Inventory, INVENTORY_STATUS } from '@things-factory/warehouse-base'
|
|
9
|
+
import { Inventory, INVENTORY_STATUS, LOCATION_TYPE } from '@things-factory/warehouse-base'
|
|
10
10
|
import { WorksheetDetail } from '@things-factory/worksheet-base'
|
|
11
11
|
|
|
12
12
|
import { businessMiddleware } from '../../../../middlewares/business-middleware'
|
|
@@ -19,386 +19,486 @@ router.post(
|
|
|
19
19
|
businessMiddleware,
|
|
20
20
|
warehouseMiddleware,
|
|
21
21
|
async (context, next) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
return await getConnection().transaction(async (tx: EntityManager) => {
|
|
23
|
+
const { client, domain } = context.state
|
|
24
|
+
const { warehouseId: customerBizplaceId } = context.params
|
|
25
|
+
const { t } = context
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
if (!customerBizplaceId) context.throw(404, t('error.warehouse id not found'))
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
let bodyReq = context.request.body
|
|
30
|
+
if (typeof bodyReq === undefined || !Object.keys(bodyReq)?.length) {
|
|
31
|
+
context.throw(400, t('error.invalid body request format'))
|
|
32
|
+
}
|
|
33
|
+
debug('post:/add-release-order request.body', bodyReq)
|
|
34
|
+
await checkMandatoryKey(context, bodyReq)
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
const custCompanyBizplace: Bizplace = await getCompanyBizplace(null, null, customerBizplaceId)
|
|
37
|
-
const customerBizplace: Bizplace = await getRepository(Bizplace).findOne({
|
|
38
|
-
where: { id: customerBizplaceId }
|
|
39
|
-
})
|
|
36
|
+
const isAutoAssign: Boolean = bodyReq.hasOwnProperty('isAutoAssign') ? bodyReq.isAutoAssign : true
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
// get customer company's bizplace
|
|
39
|
+
const custCompanyBizplace: Bizplace = await getCompanyBizplace(null, null, customerBizplaceId, tx)
|
|
40
|
+
const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
41
|
+
where: { id: customerBizplaceId }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
45
|
+
where: { domain, name: 'rule-for-picking-product' }
|
|
46
|
+
})
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
let locationSortingRules = []
|
|
49
|
+
if (pickingProductSetting) {
|
|
50
|
+
let locationSetting = JSON.parse(pickingProductSetting.value)
|
|
51
|
+
for (const key in locationSetting) {
|
|
52
|
+
locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
|
-
}
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
const orderInventories: OrderInventory[] = bodyReq.orderInventories
|
|
57
|
+
let newOrderInventories: OrderInventory[] = []
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
await Promise.all(
|
|
60
|
+
orderInventories.map(async orderInventory => {
|
|
61
|
+
const sku: string = orderInventory.product?.sku
|
|
62
|
+
const refCode: string = orderInventory.product?.refCode
|
|
63
|
+
const packingType: string = orderInventory.packingType
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
const qb: SelectQueryBuilder<ProductDetail> = tx
|
|
66
|
+
.getRepository(ProductDetail)
|
|
67
|
+
.createQueryBuilder('PD')
|
|
68
|
+
.innerJoinAndSelect('PD.product', 'PROD')
|
|
69
|
+
.where('PROD.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
if (!sku && !refCode) {
|
|
72
|
+
context.throw(404, t('error.sku or refCode not found'))
|
|
73
|
+
}
|
|
69
74
|
|
|
70
|
-
if (
|
|
71
|
-
qb.andWhere('PD.
|
|
75
|
+
if (refCode) {
|
|
76
|
+
qb.andWhere('PD.ref_code = :refCode', { refCode })
|
|
72
77
|
}
|
|
73
|
-
}
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
if (sku) {
|
|
80
|
+
qb.andWhere('PROD.sku = :sku', { sku })
|
|
81
|
+
}
|
|
77
82
|
|
|
78
83
|
if (packingType) {
|
|
79
84
|
qb.andWhere('PD.packing_type = :packingType', { packingType })
|
|
80
85
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const productDetail: ProductDetail = await qb.getOne()
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
|
|
87
|
+
const productDetail: ProductDetail = await qb.getOne()
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
newOrderInventory.packingType = productDetail.packingType
|
|
91
|
-
newOrderInventory.uomValue = productDetail.uomValue
|
|
92
|
-
newOrderInventories.push(newOrderInventory)
|
|
93
|
-
}
|
|
89
|
+
if (productDetail) {
|
|
90
|
+
let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
.where('PB.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
92
|
+
newOrderInventory.product.sku = productDetail.product.sku
|
|
93
|
+
newOrderInventory.product = productDetail.product
|
|
94
|
+
newOrderInventory.packingType = productDetail.packingType
|
|
95
|
+
newOrderInventory.uomValue = productDetail.uomValue
|
|
96
|
+
newOrderInventories.push(newOrderInventory)
|
|
97
|
+
}
|
|
102
98
|
|
|
103
|
-
if (
|
|
104
|
-
qb
|
|
99
|
+
if (!productDetail) {
|
|
100
|
+
const qb: SelectQueryBuilder<ProductDetail> = tx
|
|
101
|
+
.getRepository(ProductBundle)
|
|
102
|
+
.createQueryBuilder('PB')
|
|
103
|
+
.innerJoinAndSelect('PB.productBundleSettings', 'PBS')
|
|
104
|
+
.innerJoinAndSelect('PBS.productDetail', 'PBD')
|
|
105
|
+
.innerJoinAndSelect('PBD.product', 'PROD')
|
|
106
|
+
.where('PB.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
107
|
+
|
|
108
|
+
if (!sku && !refCode) {
|
|
109
|
+
context.throw(404, t('error.sku or refCode not found'))
|
|
110
|
+
}
|
|
105
111
|
|
|
106
|
-
if (
|
|
107
|
-
qb.andWhere('PB.
|
|
112
|
+
if (refCode) {
|
|
113
|
+
qb.andWhere('PB.ref_code = :refCode', { refCode })
|
|
108
114
|
}
|
|
109
|
-
}
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
if (sku) {
|
|
117
|
+
qb.andWhere('PB.sku = :sku', { sku })
|
|
118
|
+
}
|
|
113
119
|
|
|
114
120
|
if (packingType) {
|
|
115
121
|
qb.andWhere('PB.packing_type = :packingType', { packingType })
|
|
116
122
|
}
|
|
117
|
-
}
|
|
118
123
|
|
|
119
|
-
|
|
124
|
+
const foundProductBundle: ProductBundle = await qb.getOne()
|
|
125
|
+
|
|
126
|
+
if (foundProductBundle) {
|
|
127
|
+
const bundleProductSettings: any[] = foundProductBundle.productBundleSettings
|
|
128
|
+
bundleProductSettings.map(bundleProductSetting => {
|
|
129
|
+
const productDetailBundle: ProductDetail = bundleProductSetting.productDetail
|
|
130
|
+
|
|
131
|
+
let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
|
|
132
|
+
newOrderInventory.product.sku = productDetailBundle.product.sku
|
|
133
|
+
newOrderInventory.packingType = productDetailBundle.packingType
|
|
134
|
+
newOrderInventory.uomValue = productDetailBundle.uomValue
|
|
135
|
+
newOrderInventory.releaseQty = orderInventory.releaseQty * bundleProductSetting.bundleQty
|
|
136
|
+
newOrderInventory.product = productDetailBundle.product
|
|
137
|
+
newOrderInventories.push(newOrderInventory)
|
|
138
|
+
})
|
|
139
|
+
} else {
|
|
140
|
+
if (sku && refCode) {
|
|
141
|
+
context.throw(404, t(`error.sku ${sku} and refCode ${refCode} not exist in product / bundle master`))
|
|
142
|
+
}
|
|
120
143
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const productDetailBundle: ProductDetail = bundleProductSetting.productDetail
|
|
144
|
+
if (sku) {
|
|
145
|
+
context.throw(404, t(`error.sku ${sku} not exist in product / bundle master`))
|
|
146
|
+
}
|
|
125
147
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
newOrderInventory.uomValue = productDetailBundle.uomValue
|
|
130
|
-
newOrderInventory.releaseQty = orderInventory.releaseQty * bundleProductSetting.bundleQty
|
|
131
|
-
newOrderInventory.product = productDetailBundle.product
|
|
132
|
-
newOrderInventories.push(newOrderInventory)
|
|
133
|
-
})
|
|
134
|
-
} else {
|
|
135
|
-
context.throw(404, t(`error.${orderInventory.product?.sku} not exist in product / bundle master`))
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
})
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
let finalOrderInventories: OrderInventory[] = []
|
|
142
|
-
|
|
143
|
-
// Case 1. Every order inventories has specified batch id
|
|
144
|
-
if (newOrderInventories.every((orderInventory: OrderInventory) => orderInventory.batchId)) {
|
|
145
|
-
finalOrderInventories = await Promise.all(
|
|
146
|
-
newOrderInventories.map(async (orderInventory: OrderInventory) => {
|
|
147
|
-
let filters: any = [
|
|
148
|
-
{
|
|
149
|
-
name: 'batchId',
|
|
150
|
-
operator: 'eq',
|
|
151
|
-
value: orderInventory.batchId
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
name: 'productName',
|
|
155
|
-
operator: 'eq',
|
|
156
|
-
value: orderInventory.product.sku
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: 'bizplace',
|
|
160
|
-
operator: 'in',
|
|
161
|
-
value: [customerBizplaceId]
|
|
148
|
+
if (refCode) {
|
|
149
|
+
context.throw(404, t(`error.refCode ${refCode} not exist in product / bundle master`))
|
|
150
|
+
}
|
|
162
151
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
let finalOrderInventories: OrderInventory[] = []
|
|
157
|
+
|
|
158
|
+
// Case 1. Every order inventories has specified batch id
|
|
159
|
+
if (newOrderInventories.every((orderInventory: OrderInventory) => orderInventory.batchId)) {
|
|
160
|
+
finalOrderInventories = await Promise.all(
|
|
161
|
+
newOrderInventories.map(async (orderInventory: OrderInventory) => {
|
|
162
|
+
let filters: any = [
|
|
163
|
+
{
|
|
164
|
+
name: 'batchId',
|
|
165
|
+
operator: 'eq',
|
|
166
|
+
value: orderInventory.batchId
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'productName',
|
|
170
|
+
operator: 'eq',
|
|
171
|
+
value: orderInventory.product.sku
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'bizplace',
|
|
175
|
+
operator: 'in',
|
|
176
|
+
value: [customerBizplaceId]
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
// 2. get all inventory data according to SKU and batchId
|
|
181
|
+
const response = await client.query({
|
|
182
|
+
query: gql`
|
|
183
|
+
query inventoriesByPallet($filters: [Filter]) {
|
|
184
|
+
inventoriesByPallet(filters: $filters) {
|
|
185
|
+
items {
|
|
186
|
+
product {
|
|
187
|
+
id
|
|
188
|
+
name
|
|
189
|
+
description
|
|
190
|
+
}
|
|
191
|
+
batchId
|
|
192
|
+
packingType
|
|
193
|
+
remainQty
|
|
194
|
+
remainWeight
|
|
195
|
+
remainUomValue
|
|
175
196
|
}
|
|
176
|
-
|
|
177
|
-
packingType
|
|
178
|
-
remainQty
|
|
179
|
-
remainWeight
|
|
180
|
-
remainUomValue
|
|
197
|
+
total
|
|
181
198
|
}
|
|
182
|
-
|
|
199
|
+
}
|
|
200
|
+
`,
|
|
201
|
+
variables: { filters, locationSortingRules },
|
|
202
|
+
context: {
|
|
203
|
+
...context,
|
|
204
|
+
state: {
|
|
205
|
+
...context.state,
|
|
206
|
+
bizplace: customerBizplace,
|
|
207
|
+
domain
|
|
183
208
|
}
|
|
184
209
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
210
|
+
} as any)
|
|
211
|
+
|
|
212
|
+
if (!response.errors) {
|
|
213
|
+
const items = response.data.inventoriesByPallet.items || []
|
|
214
|
+
if (!items?.length)
|
|
215
|
+
context.throw(
|
|
216
|
+
404,
|
|
217
|
+
t(
|
|
218
|
+
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
items.forEach(item => {
|
|
223
|
+
if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
|
|
224
|
+
context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 3. add more information to orderInventory
|
|
228
|
+
orderInventory.product.id = item.product.id
|
|
229
|
+
orderInventory.packingType = item.packingType
|
|
230
|
+
orderInventory.batchId = item.batchId
|
|
231
|
+
orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
|
|
232
|
+
orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
|
|
233
|
+
orderInventory.uom = item.uom
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return orderInventory
|
|
237
|
+
} else context.throw(404, t('error.failed to fetch inventory'))
|
|
238
|
+
})
|
|
239
|
+
)
|
|
240
|
+
} else {
|
|
241
|
+
// Case 2. Some of order inventories doesn't have specified batch id
|
|
242
|
+
// MMS order doesn't have batch ID field.
|
|
243
|
+
// To cover this case first result of found inventory will be a target of RO
|
|
244
|
+
|
|
245
|
+
for (let i: number = 0; i < newOrderInventories.length; i++) {
|
|
246
|
+
const orderInventory: OrderInventory = newOrderInventories[i]
|
|
247
|
+
const product: Product = orderInventory.product
|
|
248
|
+
const packingType: string = orderInventory.packingType
|
|
249
|
+
|
|
250
|
+
if (isAutoAssign) {
|
|
251
|
+
let qb: SelectQueryBuilder<Inventory> = tx.getRepository(Inventory).createQueryBuilder('iv')
|
|
252
|
+
qb.leftJoinAndSelect('iv.location', 'loc')
|
|
253
|
+
.andWhere('"iv"."domain_id" = :domainId')
|
|
254
|
+
.andWhere('"iv"."bizplace_id" = :bizplaceId')
|
|
255
|
+
.andWhere('"iv"."packing_type" = :packingType')
|
|
256
|
+
.andWhere('"iv"."product_id" = :productId')
|
|
257
|
+
.andWhere('"iv"."status" = :status')
|
|
258
|
+
.andWhere('"loc"."type" NOT IN (:...locationTypes)')
|
|
259
|
+
.setParameters({
|
|
260
|
+
domainId: domain.id,
|
|
261
|
+
bizplaceId: customerBizplace.id,
|
|
262
|
+
packingType: packingType,
|
|
263
|
+
productId: product.id,
|
|
264
|
+
status: INVENTORY_STATUS.STORED,
|
|
265
|
+
locationTypes: [LOCATION_TYPE.QUARANTINE, LOCATION_TYPE.RESERVE]
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
if (locationSortingRules?.length > 0) {
|
|
269
|
+
locationSortingRules.forEach((rule: { name: string; desc: boolean }, idx: number) => {
|
|
270
|
+
idx === 0
|
|
271
|
+
? qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
272
|
+
: qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
273
|
+
})
|
|
274
|
+
} else {
|
|
275
|
+
qb.addOrderBy('"iv"."created_at"', 'ASC')
|
|
194
276
|
}
|
|
195
|
-
} as any)
|
|
196
277
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (!items?.length)
|
|
200
|
-
context.throw(
|
|
201
|
-
404,
|
|
202
|
-
t(
|
|
203
|
-
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
204
|
-
)
|
|
205
|
-
)
|
|
278
|
+
let inventories: Inventory[] = await qb.getMany()
|
|
279
|
+
if (!inventories?.length) context.throw(404, t(`error.no inventories found for ${product.sku}`))
|
|
206
280
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
281
|
+
inventories = inventories.map(inventory => {
|
|
282
|
+
return {
|
|
283
|
+
...inventory,
|
|
284
|
+
remainQty: inventory.qty - inventory.lockedQty,
|
|
285
|
+
remainUomValue: inventory.uomValue - inventory.lockedUomValue
|
|
210
286
|
}
|
|
287
|
+
})
|
|
211
288
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
orderInventory
|
|
216
|
-
|
|
217
|
-
|
|
289
|
+
const targetInventories: WorksheetDetail[] = _composeTargetInventories(
|
|
290
|
+
context,
|
|
291
|
+
product,
|
|
292
|
+
orderInventory,
|
|
293
|
+
inventories
|
|
294
|
+
)
|
|
295
|
+
targetInventories.map(item => {
|
|
296
|
+
finalOrderInventories.push(item.targetInventory)
|
|
218
297
|
})
|
|
298
|
+
} else {
|
|
299
|
+
let filters: any = [
|
|
300
|
+
{
|
|
301
|
+
name: 'productName',
|
|
302
|
+
operator: 'eq',
|
|
303
|
+
value: orderInventory.product.sku
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: 'bizplace_id',
|
|
307
|
+
operator: 'eq',
|
|
308
|
+
value: customerBizplaceId
|
|
309
|
+
}
|
|
310
|
+
]
|
|
311
|
+
|
|
312
|
+
// 2. get all inventory data according to SKU and batchId
|
|
313
|
+
const response = await client.query({
|
|
314
|
+
query: gql`
|
|
315
|
+
query inventoryProductGroup($filters: [Filter]) {
|
|
316
|
+
inventoryProductGroup(filters: $filters) {
|
|
317
|
+
items {
|
|
318
|
+
productId
|
|
319
|
+
productSKU
|
|
320
|
+
productName
|
|
321
|
+
batchId
|
|
322
|
+
packingType
|
|
323
|
+
remainQty
|
|
324
|
+
remainWeight
|
|
325
|
+
remainUomValue
|
|
326
|
+
}
|
|
327
|
+
total
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
`,
|
|
331
|
+
variables: { filters },
|
|
332
|
+
context: {
|
|
333
|
+
...context,
|
|
334
|
+
state: {
|
|
335
|
+
...context.state,
|
|
336
|
+
bizplace: customerBizplace,
|
|
337
|
+
domain
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} as any)
|
|
341
|
+
|
|
342
|
+
if (!response.errors) {
|
|
343
|
+
const items = response.data.inventoryProductGroup.items || []
|
|
344
|
+
if (!items?.length)
|
|
345
|
+
context.throw(
|
|
346
|
+
404,
|
|
347
|
+
t(
|
|
348
|
+
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
349
|
+
)
|
|
350
|
+
)
|
|
219
351
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
} else {
|
|
225
|
-
// Case 2. Some of order inventories doesn't have specified batch id
|
|
226
|
-
// MMS order doesn't have batch ID field.
|
|
227
|
-
// To cover this case first result of found inventory will be a target of RO
|
|
228
|
-
|
|
229
|
-
for (let i: number = 0; i < newOrderInventories.length; i++) {
|
|
230
|
-
const orderInventory: OrderInventory = newOrderInventories[i]
|
|
231
|
-
const product: Product = orderInventory.product
|
|
232
|
-
const packingType: string = orderInventory.packingType
|
|
233
|
-
|
|
234
|
-
let qb: SelectQueryBuilder<Inventory> = getRepository(Inventory).createQueryBuilder('iv')
|
|
235
|
-
qb.leftJoinAndSelect('iv.location', 'loc')
|
|
236
|
-
.andWhere('"iv"."domain_id" = :domainId')
|
|
237
|
-
.andWhere('"iv"."bizplace_id" = :bizplaceId')
|
|
238
|
-
.andWhere('"iv"."packing_type" = :packingType')
|
|
239
|
-
.andWhere('"iv"."product_id" = :productId')
|
|
240
|
-
.andWhere('"iv"."status" = :status')
|
|
241
|
-
.setParameters({
|
|
242
|
-
domainId: domain.id,
|
|
243
|
-
bizplaceId: customerBizplace.id,
|
|
244
|
-
packingType: packingType,
|
|
245
|
-
productId: product.id,
|
|
246
|
-
status: INVENTORY_STATUS.STORED
|
|
247
|
-
})
|
|
352
|
+
items.forEach(item => {
|
|
353
|
+
if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
|
|
354
|
+
context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
|
|
355
|
+
}
|
|
248
356
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
357
|
+
// 3. add more information to orderInventory
|
|
358
|
+
orderInventory.product = { id: item.productId }
|
|
359
|
+
orderInventory.packingType = item.packingType
|
|
360
|
+
orderInventory.batchId = item.batchId
|
|
361
|
+
orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
|
|
362
|
+
orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
|
|
363
|
+
orderInventory.uom = item.uom
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
delete orderInventory.uomValue
|
|
367
|
+
finalOrderInventories.push(orderInventory)
|
|
368
|
+
} else context.throw(404, t('error.failed to fetch inventory'))
|
|
369
|
+
}
|
|
257
370
|
}
|
|
258
|
-
|
|
259
|
-
const inventories: Inventory[] = await qb.getMany()
|
|
260
|
-
if (!inventories?.length) context.throw(404, t(`error.no inventories found for ${product.sku}`))
|
|
261
|
-
|
|
262
|
-
const targetInventories: WorksheetDetail[] = _composeTargetInventories(
|
|
263
|
-
context,
|
|
264
|
-
product,
|
|
265
|
-
orderInventory,
|
|
266
|
-
inventories
|
|
267
|
-
)
|
|
268
|
-
targetInventories.map(item => {
|
|
269
|
-
finalOrderInventories.push(item.targetInventory)
|
|
270
|
-
})
|
|
271
371
|
}
|
|
272
|
-
}
|
|
273
372
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
name
|
|
282
|
-
refNo
|
|
283
|
-
status
|
|
284
|
-
truckNo
|
|
285
|
-
ownTransport
|
|
286
|
-
crossDocking
|
|
287
|
-
marketplaceOrderStatus
|
|
288
|
-
billingAddress
|
|
289
|
-
deliveryAddress1
|
|
290
|
-
deliveryAddress2
|
|
291
|
-
deliveryAddress3
|
|
292
|
-
deliveryAddress4
|
|
293
|
-
deliveryAddress5
|
|
294
|
-
attentionTo
|
|
295
|
-
attentionCompany
|
|
296
|
-
city
|
|
297
|
-
state
|
|
298
|
-
postalCode
|
|
299
|
-
country
|
|
300
|
-
phone1
|
|
301
|
-
phone2
|
|
302
|
-
email
|
|
303
|
-
transporter
|
|
304
|
-
trackingNo
|
|
305
|
-
airwayBill
|
|
306
|
-
invoice
|
|
307
|
-
type
|
|
308
|
-
arrivalNotice {
|
|
373
|
+
context.body = {
|
|
374
|
+
result: (
|
|
375
|
+
await client.mutate({
|
|
376
|
+
mutation: gql`
|
|
377
|
+
mutation addReleaseGood($releaseGood: NewReleaseGood, $shippingOrder: ShippingOrderPatch, $file: Upload) {
|
|
378
|
+
addReleaseGood(releaseGood: $releaseGood, shippingOrder: $shippingOrder, file: $file) {
|
|
379
|
+
id
|
|
309
380
|
name
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
381
|
+
refNo
|
|
382
|
+
status
|
|
383
|
+
truckNo
|
|
384
|
+
ownTransport
|
|
385
|
+
crossDocking
|
|
386
|
+
marketplaceOrderStatus
|
|
387
|
+
billingAddress
|
|
388
|
+
deliveryAddress1
|
|
389
|
+
deliveryAddress2
|
|
390
|
+
deliveryAddress3
|
|
391
|
+
deliveryAddress4
|
|
392
|
+
deliveryAddress5
|
|
393
|
+
attentionTo
|
|
394
|
+
attentionCompany
|
|
395
|
+
city
|
|
396
|
+
state
|
|
397
|
+
postalCode
|
|
398
|
+
country
|
|
399
|
+
phone1
|
|
400
|
+
phone2
|
|
401
|
+
email
|
|
402
|
+
transporter
|
|
403
|
+
trackingNo
|
|
404
|
+
airwayBill
|
|
405
|
+
invoice
|
|
406
|
+
type
|
|
407
|
+
arrivalNotice {
|
|
320
408
|
name
|
|
321
|
-
description
|
|
322
409
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
releaseUomValue
|
|
328
|
-
}
|
|
329
|
-
orderVass {
|
|
330
|
-
vas {
|
|
410
|
+
exportOption
|
|
411
|
+
releaseDate
|
|
412
|
+
collectionOrderNo
|
|
413
|
+
bizplace {
|
|
331
414
|
name
|
|
332
|
-
operationGuide
|
|
333
|
-
operationGuideType
|
|
334
415
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
416
|
+
orderInventories {
|
|
417
|
+
product {
|
|
418
|
+
sku
|
|
419
|
+
name
|
|
420
|
+
description
|
|
421
|
+
}
|
|
422
|
+
batchId
|
|
423
|
+
packingType
|
|
424
|
+
packingSize
|
|
425
|
+
releaseQty
|
|
426
|
+
releaseUomValue
|
|
427
|
+
}
|
|
428
|
+
orderVass {
|
|
429
|
+
vas {
|
|
430
|
+
name
|
|
431
|
+
operationGuide
|
|
432
|
+
operationGuideType
|
|
433
|
+
}
|
|
434
|
+
set
|
|
435
|
+
targetType
|
|
436
|
+
targetBatchId
|
|
437
|
+
targetProduct {
|
|
438
|
+
name
|
|
439
|
+
description
|
|
440
|
+
}
|
|
441
|
+
packingType
|
|
442
|
+
qty
|
|
443
|
+
uomValue
|
|
444
|
+
otherTarget
|
|
340
445
|
description
|
|
446
|
+
remark
|
|
447
|
+
status
|
|
448
|
+
operationGuide
|
|
341
449
|
}
|
|
342
|
-
packingType
|
|
343
|
-
qty
|
|
344
|
-
uomValue
|
|
345
|
-
otherTarget
|
|
346
|
-
description
|
|
347
|
-
remark
|
|
348
|
-
status
|
|
349
|
-
operationGuide
|
|
350
450
|
}
|
|
351
451
|
}
|
|
452
|
+
`,
|
|
453
|
+
variables: {
|
|
454
|
+
releaseGood: {
|
|
455
|
+
customerBizplaceId: customerBizplace.id,
|
|
456
|
+
courierOption: bodyReq.courierOption,
|
|
457
|
+
collectionOrderNo: bodyReq.collectionOrderNo,
|
|
458
|
+
exportOption: bodyReq.exportOption,
|
|
459
|
+
orderInventories: finalOrderInventories,
|
|
460
|
+
ownTransport: bodyReq.ownTransport,
|
|
461
|
+
packingOption: bodyReq.packingOption,
|
|
462
|
+
refNo: bodyReq.refNo,
|
|
463
|
+
refNo2: bodyReq?.refNo2,
|
|
464
|
+
releaseDate: bodyReq.releaseDate,
|
|
465
|
+
type: bodyReq.type,
|
|
466
|
+
marketplaceOrderStatus: bodyReq?.marketplaceOrderStatus,
|
|
467
|
+
billingAddress: bodyReq?.billTo?.billingAddress || null,
|
|
468
|
+
deliveryAddress1: bodyReq?.deliverTo?.deliveryAddress1 || null,
|
|
469
|
+
deliveryAddress2: bodyReq?.deliverTo?.deliveryAddress2 || null,
|
|
470
|
+
deliveryAddress3: bodyReq?.deliverTo?.deliveryAddress3 || null,
|
|
471
|
+
deliveryAddress4: bodyReq?.deliverTo?.deliveryAddress4 || null,
|
|
472
|
+
deliveryAddress5: bodyReq?.deliverTo?.deliveryAddress5 || null,
|
|
473
|
+
attentionTo: bodyReq?.deliverTo?.attentionTo || null,
|
|
474
|
+
attentionCompany: bodyReq?.deliverTo?.attentionCompany || null,
|
|
475
|
+
city: bodyReq?.deliverTo?.city || null,
|
|
476
|
+
state: bodyReq?.deliverTo?.state || null,
|
|
477
|
+
postalCode: bodyReq?.deliverTo?.postalCode || null,
|
|
478
|
+
country: bodyReq?.deliverTo?.country || null,
|
|
479
|
+
phone1: bodyReq?.deliverTo?.phone1 || null,
|
|
480
|
+
phone2: bodyReq?.deliverTo?.phone2 || null,
|
|
481
|
+
email: bodyReq?.deliverTo?.email || null,
|
|
482
|
+
transporter: bodyReq?.transporter,
|
|
483
|
+
trackingNo: bodyReq?.trackingNo,
|
|
484
|
+
airwayBill: bodyReq?.airwayBill,
|
|
485
|
+
invoice: bodyReq?.invoice
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
context: {
|
|
489
|
+
...context,
|
|
490
|
+
hasUpload: true,
|
|
491
|
+
state: {
|
|
492
|
+
...context.state,
|
|
493
|
+
customerBizplace,
|
|
494
|
+
domain,
|
|
495
|
+
type: 'api'
|
|
496
|
+
}
|
|
352
497
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
courierOption: bodyReq.courierOption,
|
|
358
|
-
collectionOrderNo: bodyReq.collectionOrderNo,
|
|
359
|
-
exportOption: bodyReq.exportOption,
|
|
360
|
-
orderInventories: finalOrderInventories,
|
|
361
|
-
ownTransport: bodyReq.ownTransport,
|
|
362
|
-
packingOption: bodyReq.packingOption,
|
|
363
|
-
refNo: bodyReq.refNo,
|
|
364
|
-
refNo2: bodyReq?.refNo2,
|
|
365
|
-
releaseDate: bodyReq.releaseDate,
|
|
366
|
-
type: bodyReq.type,
|
|
367
|
-
marketplaceOrderStatus: bodyReq?.marketplaceOrderStatus,
|
|
368
|
-
billingAddress: bodyReq?.billTo?.billingAddress || null,
|
|
369
|
-
deliveryAddress1: bodyReq?.deliverTo?.deliveryAddress1 || null,
|
|
370
|
-
deliveryAddress2: bodyReq?.deliverTo?.deliveryAddress2 || null,
|
|
371
|
-
deliveryAddress3: bodyReq?.deliverTo?.deliveryAddress3 || null,
|
|
372
|
-
deliveryAddress4: bodyReq?.deliverTo?.deliveryAddress4 || null,
|
|
373
|
-
deliveryAddress5: bodyReq?.deliverTo?.deliveryAddress5 || null,
|
|
374
|
-
attentionTo: bodyReq?.deliverTo?.attentionTo || null,
|
|
375
|
-
attentionCompany: bodyReq?.deliverTo?.attentionCompany || null,
|
|
376
|
-
city: bodyReq?.deliverTo?.city || null,
|
|
377
|
-
state: bodyReq?.deliverTo?.state || null,
|
|
378
|
-
postalCode: bodyReq?.deliverTo?.postalCode || null,
|
|
379
|
-
country: bodyReq?.deliverTo?.country || null,
|
|
380
|
-
phone1: bodyReq?.deliverTo?.phone1 || null,
|
|
381
|
-
phone2: bodyReq?.deliverTo?.phone2 || null,
|
|
382
|
-
email: bodyReq?.deliverTo?.email || null,
|
|
383
|
-
transporter: bodyReq?.transporter,
|
|
384
|
-
trackingNo: bodyReq?.trackingNo,
|
|
385
|
-
airwayBill: bodyReq?.airwayBill,
|
|
386
|
-
invoice: bodyReq?.invoice
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
context: {
|
|
390
|
-
...context,
|
|
391
|
-
hasUpload: true,
|
|
392
|
-
state: {
|
|
393
|
-
...context.state,
|
|
394
|
-
customerBizplace,
|
|
395
|
-
domain,
|
|
396
|
-
type: 'api'
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
} as any)
|
|
400
|
-
).data
|
|
401
|
-
}
|
|
498
|
+
} as any)
|
|
499
|
+
).data
|
|
500
|
+
}
|
|
501
|
+
})
|
|
402
502
|
}
|
|
403
503
|
)
|
|
404
504
|
|
|
@@ -429,9 +529,18 @@ export async function checkMandatoryKey(context, params) {
|
|
|
429
529
|
}
|
|
430
530
|
|
|
431
531
|
if ('orderInventories' in params) {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
532
|
+
params.orderInventories.forEach((param, key) => {
|
|
533
|
+
let noSubParams = []
|
|
534
|
+
|
|
535
|
+
if (!param?.releaseQty) noSubParams.push('releaseQty')
|
|
536
|
+
|
|
537
|
+
if (!param?.product) noSubParams.push('product')
|
|
538
|
+
|
|
539
|
+
if (noSubParams?.length)
|
|
540
|
+
context.throw(400, context.t('error.required param x not found', { x: `${noSubParams.join(', ')}` }))
|
|
541
|
+
})
|
|
542
|
+
} else {
|
|
543
|
+
noparams.push('orderInventories')
|
|
435
544
|
}
|
|
436
545
|
|
|
437
546
|
if (noparams?.length) {
|
|
@@ -450,7 +559,7 @@ export function _composeTargetInventories(context, product, record, inventories)
|
|
|
450
559
|
let totalInventoryQty: number = 0
|
|
451
560
|
|
|
452
561
|
inventories.map(inventory => {
|
|
453
|
-
totalInventoryQty += inventory.
|
|
562
|
+
totalInventoryQty += inventory.remainQty
|
|
454
563
|
})
|
|
455
564
|
|
|
456
565
|
if (totalInventoryQty < record.releaseQty) {
|
|
@@ -462,7 +571,7 @@ export function _composeTargetInventories(context, product, record, inventories)
|
|
|
462
571
|
while (compReleaseQty < record.releaseQty) {
|
|
463
572
|
const inv = inventories[idx]
|
|
464
573
|
|
|
465
|
-
if (inv.
|
|
574
|
+
if (inv.remainQty > leftReleaseQty) {
|
|
466
575
|
compReleaseQty += leftReleaseQty
|
|
467
576
|
compReleaseUomValue += leftReleaseUomValue
|
|
468
577
|
|
|
@@ -473,23 +582,25 @@ export function _composeTargetInventories(context, product, record, inventories)
|
|
|
473
582
|
batchId: inv.batchId,
|
|
474
583
|
releaseQty: leftReleaseQty,
|
|
475
584
|
releaseUomValue: leftReleaseQty * record.uomValue,
|
|
585
|
+
uom: inv.uom,
|
|
476
586
|
product: { id: product.id },
|
|
477
587
|
type: ORDER_TYPES.RELEASE_OF_GOODS
|
|
478
588
|
}
|
|
479
589
|
})
|
|
480
590
|
} else {
|
|
481
|
-
compReleaseQty += inv.
|
|
482
|
-
compReleaseUomValue += inv.
|
|
483
|
-
leftReleaseQty -= inv.
|
|
484
|
-
leftReleaseUomValue -= inv.
|
|
591
|
+
compReleaseQty += inv.remainQty
|
|
592
|
+
compReleaseUomValue += inv.remainUomValue
|
|
593
|
+
leftReleaseQty -= inv.remainQty
|
|
594
|
+
leftReleaseUomValue -= inv.remainUomValue
|
|
485
595
|
|
|
486
596
|
targetInventories.push({
|
|
487
597
|
targetInventory: {
|
|
488
598
|
inventory: { id: inv.id },
|
|
489
599
|
packingType: inv.packingType,
|
|
490
600
|
batchId: inv.batchId,
|
|
491
|
-
releaseQty: inv.
|
|
492
|
-
releaseUomValue: inv.
|
|
601
|
+
releaseQty: inv.remainQty,
|
|
602
|
+
releaseUomValue: inv.remainUomValue,
|
|
603
|
+
uom: inv.uom,
|
|
493
604
|
product: { id: product.id },
|
|
494
605
|
type: ORDER_TYPES.RELEASE_OF_GOODS
|
|
495
606
|
}
|