@things-factory/operato-wms 4.3.822 → 4.3.824
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/client/pages/order/arrival-notice/create-arrival-notice.js +9 -0
- package/client/pages/order/release-order/release-order-detail.js +15 -3
- package/client/pages/outbound/packing-product.js +10 -2
- package/config.development.js +141 -71
- package/dist-server/graphql/resolvers/outbound/get-loading-task.js +15 -5
- package/dist-server/graphql/resolvers/outbound/get-loading-task.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js +17 -2
- package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js +13 -2
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js.map +1 -1
- package/dist-server/graphql/types/zone-worksheet/index.js +5 -1
- package/dist-server/graphql/types/zone-worksheet/index.js.map +1 -1
- package/package.json +10 -10
- package/server/graphql/resolvers/outbound/get-loading-task.ts +15 -5
- package/server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts +17 -2
- package/server/graphql/resolvers/zone-worksheet/zone-worksheet.ts +17 -6
- package/server/graphql/types/zone-worksheet/index.ts +5 -1
|
@@ -1878,6 +1878,13 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
|
|
|
1878
1878
|
},
|
|
1879
1879
|
...(this.enableDirectInbound
|
|
1880
1880
|
? [
|
|
1881
|
+
{
|
|
1882
|
+
type: 'date',
|
|
1883
|
+
name: 'expDate',
|
|
1884
|
+
header: i18next.t('field.exp_date'),
|
|
1885
|
+
imex: { header: i18next.t('field.exp_date'), key: 'expDate', width: 25, type: 'string' },
|
|
1886
|
+
width: 120
|
|
1887
|
+
},
|
|
1881
1888
|
{
|
|
1882
1889
|
type: 'object',
|
|
1883
1890
|
name: 'location',
|
|
@@ -1966,6 +1973,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
|
|
|
1966
1973
|
palletQty
|
|
1967
1974
|
palletId
|
|
1968
1975
|
manufactureDate
|
|
1976
|
+
expDate
|
|
1969
1977
|
batchId
|
|
1970
1978
|
batchIdRef
|
|
1971
1979
|
unitPrice
|
|
@@ -1992,6 +2000,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
|
|
|
1992
2000
|
primaryUnit
|
|
1993
2001
|
primaryValue
|
|
1994
2002
|
costPrice
|
|
2003
|
+
isRequiredCheckExpiry
|
|
1995
2004
|
}
|
|
1996
2005
|
productDetail {
|
|
1997
2006
|
id
|
|
@@ -508,10 +508,12 @@ class ReleaseOrderDetail extends connect(store)(localize(i18next)(PageView)) {
|
|
|
508
508
|
<label ?hidden="${!this._ownTransport}">${i18next.t('label.co_no')}</label>
|
|
509
509
|
<input name="collectionOrderNo" ?hidden="${!this._ownTransport}" ?readonly="${!this?._editable}" />
|
|
510
510
|
|
|
511
|
-
<label ?hidden="${this.roType === 'b2b'}"
|
|
511
|
+
<label ?hidden="${this.roType === 'b2b' && !this._beforeRemark}"
|
|
512
|
+
>${i18next.t('label.order_remark')}</label
|
|
513
|
+
>
|
|
512
514
|
<textarea
|
|
513
515
|
name="remark"
|
|
514
|
-
?hidden="${this.roType === 'b2b'}"
|
|
516
|
+
?hidden="${this.roType === 'b2b' && !this._beforeRemark}"
|
|
515
517
|
rows="5"
|
|
516
518
|
?readonly="${!this?._editable}"
|
|
517
519
|
></textarea>
|
|
@@ -1216,7 +1218,9 @@ class ReleaseOrderDetail extends connect(store)(localize(i18next)(PageView)) {
|
|
|
1216
1218
|
this.inventoryGristConfig = {
|
|
1217
1219
|
pagination: { infinite: true },
|
|
1218
1220
|
rows: { selectable: { multiple: true }, appendable: false },
|
|
1219
|
-
list: {
|
|
1221
|
+
list: {
|
|
1222
|
+
fields: ['sku', 'productName', 'batchId', 'invStatus', 'packingType', 'releaseQty', 'releaseUomValue', 'remark']
|
|
1223
|
+
},
|
|
1220
1224
|
columns: [
|
|
1221
1225
|
{ name: 'releaseUomValue', hidden: true },
|
|
1222
1226
|
{ name: 'remainUomValue', hidden: true },
|
|
@@ -1288,6 +1292,12 @@ class ReleaseOrderDetail extends connect(store)(localize(i18next)(PageView)) {
|
|
|
1288
1292
|
name: 'batchIdRef',
|
|
1289
1293
|
header: i18next.t('field.batch_no_ref'),
|
|
1290
1294
|
width: 100
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
type: 'string',
|
|
1298
|
+
name: 'remark',
|
|
1299
|
+
header: i18next.t('field.remark'),
|
|
1300
|
+
width: 200
|
|
1291
1301
|
}
|
|
1292
1302
|
]
|
|
1293
1303
|
}
|
|
@@ -1617,6 +1627,7 @@ class ReleaseOrderDetail extends connect(store)(localize(i18next)(PageView)) {
|
|
|
1617
1627
|
releaseQty
|
|
1618
1628
|
releaseUomValue
|
|
1619
1629
|
status
|
|
1630
|
+
remark
|
|
1620
1631
|
}
|
|
1621
1632
|
inventoryInfos {
|
|
1622
1633
|
id
|
|
@@ -1650,6 +1661,7 @@ class ReleaseOrderDetail extends connect(store)(localize(i18next)(PageView)) {
|
|
|
1650
1661
|
}
|
|
1651
1662
|
status
|
|
1652
1663
|
refWorksheetId
|
|
1664
|
+
remark
|
|
1653
1665
|
}
|
|
1654
1666
|
shippingOrderInfo {
|
|
1655
1667
|
id
|
|
@@ -722,11 +722,11 @@ class PackingProduct extends connect(store)(localize(i18next)(PageView)) {
|
|
|
722
722
|
this.focusOnReleaseQtyInput()
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
if (worksheetInfo.source == 'POWRUP') {
|
|
725
|
+
if (worksheetInfo.source == 'POWRUP' && !releaseGood.lmdOption) {
|
|
726
726
|
this.fetchPowrupOrderDocument(worksheetInfo.orderPackage.id)
|
|
727
727
|
}
|
|
728
728
|
|
|
729
|
-
if (worksheetInfo.source == 'WEBSPERT') {
|
|
729
|
+
if (worksheetInfo.source == 'WEBSPERT' && !releaseGood.lmdOption) {
|
|
730
730
|
this.fetchWebspertOrderDocument(worksheetInfo.orderPackage.id)
|
|
731
731
|
}
|
|
732
732
|
|
|
@@ -1536,6 +1536,14 @@ class PackingProduct extends connect(store)(localize(i18next)(PageView)) {
|
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
1538
|
async complete() {
|
|
1539
|
+
if (this._isLmdOption && (!this.airwayBill || String(this.airwayBill).trim() === '')) {
|
|
1540
|
+
this.showToast({
|
|
1541
|
+
message:
|
|
1542
|
+
'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
|
|
1543
|
+
})
|
|
1544
|
+
return
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1539
1547
|
if (this._enablePackingGrossWeight) {
|
|
1540
1548
|
const grossWeightValue = this.grossWeightInput.value
|
|
1541
1549
|
|
package/config.development.js
CHANGED
|
@@ -6,18 +6,29 @@ module.exports = {
|
|
|
6
6
|
subdomainOffset: 2,
|
|
7
7
|
port: 4000,
|
|
8
8
|
inspect: '9330',
|
|
9
|
-
|
|
10
|
-
storage: {
|
|
11
|
-
type: 's3',
|
|
12
|
-
accessKeyId: 'AKIAUQEOPWEJHCE4MTH4',
|
|
13
|
-
secretAccessKey: 'HkQ1engoFOhduKltXF4j6OakRmLY/9JhvyTWbc8b',
|
|
14
|
-
bucketName: 'opa-one',
|
|
15
|
-
region: 'ap-southeast-1'
|
|
16
|
-
},
|
|
17
|
-
// arif
|
|
18
9
|
// ormconfig: {
|
|
19
10
|
// name: 'default',
|
|
20
11
|
// type: 'postgres',
|
|
12
|
+
// database: 'postgres',
|
|
13
|
+
// username: 'izzah',
|
|
14
|
+
// password: 'hatio1234',
|
|
15
|
+
// host: 'my-operato-pg.cjcso4qmeuq0.ap-southeast-5.rds.amazonaws.com',
|
|
16
|
+
// port: 55432,
|
|
17
|
+
// synchronize: false,
|
|
18
|
+
// logging: true
|
|
19
|
+
// },
|
|
20
|
+
// postgres2
|
|
21
|
+
// ormconfig: {
|
|
22
|
+
// name: 'default',
|
|
23
|
+
// type: 'postgres',
|
|
24
|
+
// database: 'postgres',
|
|
25
|
+
// username: 'postgres',
|
|
26
|
+
// password: 'hatio',
|
|
27
|
+
// host: '192.168.0.151',
|
|
28
|
+
// port: 15432,
|
|
29
|
+
// synchronize: false,debug
|
|
30
|
+
// name: 'default',
|
|
31
|
+
// type: 'postgres',
|
|
21
32
|
// database: 'arif',
|
|
22
33
|
// username: 'postgres',
|
|
23
34
|
// password: 'hatio',
|
|
@@ -26,7 +37,51 @@ module.exports = {
|
|
|
26
37
|
// synchronize: false,
|
|
27
38
|
// logging: true
|
|
28
39
|
// },
|
|
29
|
-
|
|
40
|
+
// ormconfig: {
|
|
41
|
+
// name: 'default',
|
|
42
|
+
// type: 'postgres',
|
|
43
|
+
// database: 'operato-eric',
|
|
44
|
+
// username: 'postgres',
|
|
45
|
+
// password: 'hatio',
|
|
46
|
+
// host: '192.168.0.248',
|
|
47
|
+
// port: 15432,
|
|
48
|
+
// synchronize: false,
|
|
49
|
+
// logging: true
|
|
50
|
+
// },
|
|
51
|
+
//operato
|
|
52
|
+
// ormconfig: {
|
|
53
|
+
// name: 'default',
|
|
54
|
+
// type: 'postgres',
|
|
55
|
+
// database: 'operato',
|
|
56
|
+
// username: 'postgres',
|
|
57
|
+
// password: 'hatio',
|
|
58
|
+
// host: '192.168.0.151',
|
|
59
|
+
// port: 15432,
|
|
60
|
+
// synchronize: false,
|
|
61
|
+
// logging: true
|
|
62
|
+
// },
|
|
63
|
+
//153 - operatodebug
|
|
64
|
+
// type: 'postgres',
|
|
65
|
+
// database: 'operato',
|
|
66
|
+
// username: 'postgres',
|
|
67
|
+
// password: 'hatio',
|
|
68
|
+
// host: '192.168.0.153',
|
|
69
|
+
// port: 15432,
|
|
70
|
+
// synchronize: false,
|
|
71
|
+
// logging: true
|
|
72
|
+
// },
|
|
73
|
+
//eric2
|
|
74
|
+
// ormconfig: {
|
|
75
|
+
// name: 'default',
|
|
76
|
+
// type: 'postgres',
|
|
77
|
+
// database: 'eric2',
|
|
78
|
+
// username: 'postgres',
|
|
79
|
+
// password: 'hatio',
|
|
80
|
+
// host: '192.168.0.153',
|
|
81
|
+
// port: 15432,
|
|
82
|
+
// synchronize: false,
|
|
83
|
+
// logging: true
|
|
84
|
+
// },
|
|
30
85
|
// STAGING DATABASE
|
|
31
86
|
ormconfig: {
|
|
32
87
|
name: 'default',
|
|
@@ -39,46 +94,30 @@ module.exports = {
|
|
|
39
94
|
synchronize: false,
|
|
40
95
|
logging: true
|
|
41
96
|
},
|
|
42
|
-
|
|
97
|
+
//EMS
|
|
43
98
|
// ormconfig: {
|
|
44
99
|
// name: 'default',
|
|
45
100
|
// type: 'postgres',
|
|
46
|
-
//
|
|
47
|
-
// port: 55432,
|
|
48
|
-
// database: 'postgres',
|
|
49
|
-
// username: 'postgres',
|
|
50
|
-
// password: 'abcd1234',
|
|
51
|
-
// synchronize: false,
|
|
52
|
-
// logging: true,
|
|
53
|
-
// connectTimeoutMS: 30000,
|
|
54
|
-
// extra: { poolSize: 30 }
|
|
55
|
-
// },
|
|
56
|
-
|
|
57
|
-
//db izzah
|
|
58
|
-
// ormconfig: {
|
|
59
|
-
// name: 'default',
|
|
60
|
-
// type: 'postgres',
|
|
61
|
-
// database: '06072023',
|
|
101
|
+
// database: 'EMS',
|
|
62
102
|
// username: 'postgres',
|
|
63
103
|
// password: 'hatio',
|
|
64
|
-
// host: '192.168.0.
|
|
65
|
-
// port: 15432,
|
|
66
|
-
// synchronize:
|
|
104
|
+
// host: '192.168.0.161',
|
|
105
|
+
// port: 15432,
|
|
106
|
+
// synchronize: false,
|
|
67
107
|
// logging: true
|
|
68
108
|
// },
|
|
109
|
+
//db nora
|
|
69
110
|
// ormconfig: {
|
|
70
111
|
// name: 'default',
|
|
71
112
|
// type: 'postgres',
|
|
72
113
|
// database: 'postgres',
|
|
73
114
|
// username: 'postgres',
|
|
74
115
|
// password: 'hatio',
|
|
75
|
-
// host: '192.168.0.
|
|
116
|
+
// host: '192.168.0.36',
|
|
76
117
|
// port: 15432,
|
|
77
|
-
// synchronize:
|
|
118
|
+
// synchronize: true,
|
|
78
119
|
// logging: true
|
|
79
120
|
// },
|
|
80
|
-
|
|
81
|
-
// //ERIC
|
|
82
121
|
// ormconfig: {
|
|
83
122
|
// name: 'default',
|
|
84
123
|
// type: 'postgres',
|
|
@@ -87,15 +126,14 @@ module.exports = {
|
|
|
87
126
|
// password: 'hatio',
|
|
88
127
|
// host: '192.168.0.153',
|
|
89
128
|
// port: 15432,
|
|
90
|
-
// synchronize:
|
|
129
|
+
// synchronize: true,
|
|
91
130
|
// logging: true
|
|
92
131
|
// },
|
|
93
|
-
|
|
94
|
-
//eric 2
|
|
132
|
+
//db izzah
|
|
95
133
|
// ormconfig: {
|
|
96
134
|
// name: 'default',
|
|
97
135
|
// type: 'postgres',
|
|
98
|
-
// database: '
|
|
136
|
+
// database: '06072023',
|
|
99
137
|
// username: 'postgres',
|
|
100
138
|
// password: 'hatio',
|
|
101
139
|
// host: '192.168.0.153',
|
|
@@ -103,21 +141,20 @@ module.exports = {
|
|
|
103
141
|
// synchronize: false,
|
|
104
142
|
// logging: true
|
|
105
143
|
// },
|
|
106
|
-
|
|
107
144
|
// ormconfig: {
|
|
108
145
|
// name: 'default',
|
|
109
146
|
// type: 'postgres',
|
|
110
|
-
// host: '
|
|
111
|
-
// port:
|
|
147
|
+
// host: 'a6cf0bb5671f54555985dede599d5a87-649005352.ap-southeast-1.elb.amazonaws.com',
|
|
148
|
+
// port: 15432,
|
|
112
149
|
// database: 'postgres',
|
|
113
|
-
// username: '
|
|
114
|
-
// password: '
|
|
150
|
+
// username: 'operato-hub-app',
|
|
151
|
+
// password: 'a5Z(7|6n$Zti',
|
|
115
152
|
// synchronize: false,
|
|
116
153
|
// logging: true,
|
|
117
154
|
// connectTimeoutMS: 30000,
|
|
118
155
|
// extra: { poolSize: 30 }
|
|
119
156
|
// },
|
|
120
|
-
//ormconfig: {
|
|
157
|
+
// //ormconfig: {
|
|
121
158
|
// name: 'default',
|
|
122
159
|
// type: 'postgres',
|
|
123
160
|
// database: 'dev2',
|
|
@@ -145,16 +182,7 @@ module.exports = {
|
|
|
145
182
|
},
|
|
146
183
|
uploads: 'uploads',
|
|
147
184
|
attachmentsPath: 'attachments',
|
|
148
|
-
logger: {
|
|
149
|
-
file: {
|
|
150
|
-
filename: 'logs/application-%DATE%.log',
|
|
151
|
-
datePattern: 'YYYY-MM-DD-HH',
|
|
152
|
-
zippedArchive: true,
|
|
153
|
-
maxSize: '200m',
|
|
154
|
-
maxFiles: '1m',
|
|
155
|
-
level: 'info'
|
|
156
|
-
}
|
|
157
|
-
},
|
|
185
|
+
logger: {},
|
|
158
186
|
email: {
|
|
159
187
|
host: 'smtp.office365.com',
|
|
160
188
|
port: 587,
|
|
@@ -192,30 +220,72 @@ module.exports = {
|
|
|
192
220
|
// privateKey: '4pmlt3Wk019u7nqU3Q_oGZE6LbUDjjf8DpmAcn9-iss'
|
|
193
221
|
// }
|
|
194
222
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
223
|
+
fulfillmentIntegrationOperato: {
|
|
224
|
+
host: '192.168.0.161:3000',
|
|
225
|
+
protocol: 'http',
|
|
226
|
+
platform: 'operato',
|
|
227
|
+
application: 'Operato MMS',
|
|
228
|
+
appKey: 'a9bf751e622bf146662b240d58971051',
|
|
229
|
+
appSecret: '1c385935dc131c4b902b9bbf6a4798af',
|
|
230
|
+
callback: 'http://192.168.0.161:5000/callback-operato'
|
|
231
|
+
},
|
|
232
|
+
lmdIntegrationNinjavan: {
|
|
233
|
+
clientId: 'P8WCEwMo0FHNlPECwTLetwN3diAmt5KF',
|
|
234
|
+
secretKey: '1D0yNZGseOjhxnwri29xmuZiiuRp131L',
|
|
235
|
+
refreshThreshold: 43200
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
lmdIntegrationEms: { refreshThreshold: 43200 },
|
|
239
|
+
marketplaceIntegrationShopee: {
|
|
240
|
+
platform: 'shopee',
|
|
241
|
+
isUAT: false,
|
|
242
|
+
application: 'Operato MMS',
|
|
243
|
+
partnerId: 846025,
|
|
244
|
+
partnerKey: 'd34cfd85a603f196a0d74ebe08043280c1a27788bb36bdffd61e7e0bb1c90b64',
|
|
245
|
+
v2: true
|
|
246
|
+
},
|
|
247
|
+
marketplaceIntegrationLazada: {
|
|
248
|
+
platform: 'lazada',
|
|
249
|
+
application: 'operato-mms',
|
|
250
|
+
appKey: '120961',
|
|
251
|
+
appSecret: 'HB3RTNEXHlVSlBr9SmWF8AjbSUT7a825',
|
|
252
|
+
callback: 'https://maybank.operato-m.com/lazada-callback'
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
//testinglazada
|
|
256
|
+
// marketplaceIntegrationLazada: {
|
|
257
|
+
// platform: 'lazada',
|
|
258
|
+
// application: 'powrup_bi',
|
|
259
|
+
// appKey: '117890',
|
|
260
|
+
// appSecret: 'tQVllnUa7irAHoNxAwXEVxoP1we1bUjE',
|
|
261
|
+
// callback: 'https://73c5-175-141-30-142.ngrok-free.app/lazada-callback'
|
|
262
|
+
// },
|
|
263
|
+
reportApiUrl: 'http://localhost:8090/rest/report/show_html',
|
|
264
|
+
// reportApiUrl: 'http://192.168.0.153:8888/rest/report/show_html'
|
|
199
265
|
// reportApiUrl: 'http://10.100.109.66:8090/rest/report/show_html',
|
|
200
266
|
awbFileStorage: {
|
|
201
267
|
type: 's3',
|
|
202
|
-
accessKeyId: '
|
|
203
|
-
secretAccessKey: '
|
|
268
|
+
accessKeyId: 'AKIAUQEOPWEJPXIVER74',
|
|
269
|
+
secretAccessKey: 'I6uuS+6CMzIQlqBS9i+G8AYIeYj5RR7wb4fxjbLq',
|
|
204
270
|
bucketName: 'operato-awb',
|
|
205
271
|
region: 'ap-southeast-1'
|
|
206
272
|
},
|
|
207
|
-
invoiceFileStorage: {
|
|
208
|
-
type: 's3',
|
|
209
|
-
accessKeyId: 'AKIAUQEOPWEJKL43OMZA',
|
|
210
|
-
secretAccessKey: 'OG2qS0Usg4wyjPWbfv1ahPZzP80/w8z4i8MYHl+e',
|
|
211
|
-
invoiceBucket: 'operato-invoice',
|
|
212
|
-
region: 'ap-southeast-1'
|
|
213
|
-
},
|
|
214
273
|
lambda: {
|
|
215
274
|
region: 'ap-southeast-1',
|
|
216
|
-
accessKeyId: '
|
|
217
|
-
secretAccessKey: '
|
|
275
|
+
accessKeyId: 'AKIAUQEOPWEJPXIVER74',
|
|
276
|
+
secretAccessKey: 'I6uuS+6CMzIQlqBS9i+G8AYIeYj5RR7wb4fxjbLq'
|
|
218
277
|
},
|
|
219
|
-
|
|
220
|
-
|
|
278
|
+
lmdIntegrationConfig: {
|
|
279
|
+
version: {
|
|
280
|
+
v1: 'lmdMiddleware',
|
|
281
|
+
v2: 'lmdMiddlewareV2'
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
awsSesEmail: {
|
|
285
|
+
accessKeyId: 'AKIAUQEOPWEJPXIVER74',
|
|
286
|
+
secretAccessKey: 'I6uuS+6CMzIQlqBS9i+G8AYIeYj5RR7wb4fxjbLq',
|
|
287
|
+
email: 'support@hatio.asia'
|
|
288
|
+
}
|
|
289
|
+
// reportApiUrl:
|
|
290
|
+
// 'http://k8s-default-operator-2fd6178d98-66c66a0f76c09575.elb.ap-southeast-1.amazonaws.com/rest/report/show_html'
|
|
221
291
|
}
|
|
@@ -31,28 +31,38 @@ exports.getLoadingTask = {
|
|
|
31
31
|
.andWhere('wsd.status NOT IN (:...status)', { status: [worksheet_base_1.WORKSHEET_STATUS.DONE, worksheet_base_1.WORKSHEET_STATUS.DEACTIVATED] })
|
|
32
32
|
.getOne();
|
|
33
33
|
// 2. If no assigned worksheet, find and assign next available one
|
|
34
|
+
// FOR UPDATE OF ws SKIP LOCKED: under concurrent clicks, two callers
|
|
35
|
+
// used to SELECT the same row and the second UPDATE would re-evaluate,
|
|
36
|
+
// find sorter_id no longer NULL, update zero rows, and the user would
|
|
37
|
+
// see a confusing "no suitable worksheet found" error even though other
|
|
38
|
+
// unassigned rows existed. SKIP LOCKED makes concurrent callers pick
|
|
39
|
+
// different rows. `OF ws` scopes the row lock to the worksheets table
|
|
40
|
+
// only (not the joined release_goods / worksheet_details rows). Inner
|
|
41
|
+
// transaction is independent so the row lock is released as soon as
|
|
42
|
+
// the UPDATE commits.
|
|
34
43
|
if (!worksheet) {
|
|
35
44
|
let updatedWorksheets = await (0, typeorm_1.getConnection)().transaction(async (tx2) => {
|
|
36
45
|
let x = await tx2.query(`
|
|
37
|
-
UPDATE worksheets ws SET
|
|
46
|
+
UPDATE worksheets ws SET
|
|
38
47
|
sorter_id = $2,
|
|
39
48
|
updated_at = NOW(),
|
|
40
49
|
updater_id = $2
|
|
41
50
|
FROM (
|
|
42
|
-
SELECT ws.id
|
|
51
|
+
SELECT ws.id
|
|
43
52
|
FROM worksheets ws
|
|
44
53
|
INNER JOIN release_goods rg ON rg.id = ws.release_good_id
|
|
45
54
|
INNER JOIN worksheet_details wsd ON wsd.worksheet_id = ws.id
|
|
46
|
-
WHERE ws.domain_id = $1
|
|
55
|
+
WHERE ws.domain_id = $1
|
|
47
56
|
AND ws.type = 'LOADING'
|
|
48
57
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
49
58
|
AND ws.sorter_id IS NULL
|
|
50
59
|
AND rg.status IN ('LOADING', 'PROCESSING', 'PARTIAL_PROCESSING')
|
|
51
60
|
AND wsd.status NOT IN ('DONE', 'DEACTIVATED')
|
|
52
61
|
AND (rg.sorted_by_id = $2 OR rg.sorted_by_id IS NULL)
|
|
53
|
-
ORDER BY rg.created_at
|
|
62
|
+
ORDER BY rg.created_at
|
|
54
63
|
LIMIT 1
|
|
55
|
-
|
|
64
|
+
FOR UPDATE OF ws SKIP LOCKED
|
|
65
|
+
) src
|
|
56
66
|
WHERE src.id = ws.id
|
|
57
67
|
RETURNING ws.id
|
|
58
68
|
`, [domain.id, user.id]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-loading-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/get-loading-task.ts"],"names":[],"mappings":";;;AAAA,qCAA0D;AAI1D,2DAAsE;AACtE,mEAA4F;AAC5F,iEAA2D;AAE9C,QAAA,cAAc,GAAG;IAC5B,KAAK,CAAC,cAAc,CAAC,CAAM,EAAE,EAAE,EAAE,OAAY;QAC3C,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAsD,OAAO,CAAC,KAAK,CAAA;QAE7F,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,EAAE;YACzC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;SAC/B;QACD,IAAI;YACF,6BAA6B;YAC7B,IAAI,SAAS,GAAc,MAAM,EAAE;iBAChC,aAAa,CAAC,0BAAS,CAAC;iBACxB,kBAAkB,CAAC,IAAI,CAAC;iBACxB,kBAAkB,CAAC,aAAa,EAAE,KAAK,CAAC;iBACxC,kBAAkB,CAAC,gBAAgB,EAAE,IAAI,CAAC;iBAC1C,SAAS,CAAC,qBAAqB,EAAE,KAAK,CAAC;iBACvC,KAAK,CAAC;gBACL,MAAM;gBACN,IAAI,EAAE,+BAAc,CAAC,OAAO;gBAC5B,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAA,YAAE,EAAC,CAAC,iCAAgB,CAAC,SAAS,EAAE,iCAAgB,CAAC,WAAW,CAAC,CAAC;aACvE,CAAC;iBACD,QAAQ,CAAC,2BAA2B,EAAE;gBACrC,MAAM,EAAE,CAAC,yBAAY,CAAC,OAAO,EAAE,yBAAY,CAAC,UAAU,EAAE,yBAAY,CAAC,kBAAkB,CAAC;aACzF,CAAC;iBACD,QAAQ,CAAC,gCAAgC,EAAE,EAAE,MAAM,EAAE,CAAC,iCAAgB,CAAC,IAAI,EAAE,iCAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;iBAC7G,MAAM,EAAE,CAAA;YAEX,kEAAkE;YAClE,IAAI,CAAC,SAAS,EAAE;gBACd,IAAI,iBAAiB,GAAG,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAkB,EAAE,EAAE;oBACrF,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,KAAK,CACrB
|
|
1
|
+
{"version":3,"file":"get-loading-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/get-loading-task.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,19 +35,34 @@ exports.getZonePickingTask = {
|
|
|
35
35
|
worksheet = await worksheetQb.getOne();
|
|
36
36
|
if (!worksheet) {
|
|
37
37
|
//find a worksheet and update assignee to user
|
|
38
|
+
// Claim a single oldest unassigned worksheet. The LIMIT 1 + FOR UPDATE
|
|
39
|
+
// SKIP LOCKED inside the subquery makes this safe under concurrent clicks:
|
|
40
|
+
// - LIMIT 1 prevents bulk-claiming every unassigned worksheet for one user
|
|
41
|
+
// (the previous version assigned ALL of them to the clicker and only
|
|
42
|
+
// returned x[0], silently mis-assigning the rest to whoever clicked first).
|
|
43
|
+
// - FOR UPDATE SKIP LOCKED makes concurrent callers pick different rows
|
|
44
|
+
// instead of waiting on each other and then failing with "no suitable
|
|
45
|
+
// worksheet found" because the first user already grabbed everything.
|
|
46
|
+
//
|
|
47
|
+
// Use an independent inner transaction (not the outer `tx`) so the UPDATE
|
|
48
|
+
// commits before the surrounding resolver transaction finishes. Otherwise
|
|
49
|
+
// the row lock acquired by the UPDATE would persist for the whole resolver,
|
|
50
|
+
// defeating SKIP LOCKED for any concurrent click that arrives mid-flight.
|
|
38
51
|
let updatedWorksheets = await (0, typeorm_1.getConnection)().transaction(async (tx2) => {
|
|
39
52
|
let x = await tx2.getRepository(worksheet_base_1.Worksheet).query(`
|
|
40
|
-
UPDATE worksheets ws SET
|
|
53
|
+
UPDATE worksheets ws SET
|
|
41
54
|
assignee_id = $2,
|
|
42
55
|
updated_at = NOW(),
|
|
43
56
|
updater_id = $2
|
|
44
57
|
FROM (
|
|
45
|
-
SELECT ws.id
|
|
58
|
+
SELECT ws.id FROM worksheets ws
|
|
46
59
|
WHERE ws.domain_id = $1
|
|
47
60
|
AND ws.type = 'ZONE_PICKING'
|
|
48
61
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
49
62
|
AND ws.assignee_id IS NULL
|
|
50
63
|
ORDER BY ws.created_at
|
|
64
|
+
LIMIT 1
|
|
65
|
+
FOR UPDATE SKIP LOCKED
|
|
51
66
|
) src where src.id = ws.id
|
|
52
67
|
RETURNING ws.id;
|
|
53
68
|
`, [domain.id, assignee.id]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-zone-picking-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts"],"names":[],"mappings":";;;AAAA,qCAA0D;AAE1D,yDAAgD;AAEhD,2DAA8G;AAE9G,mEAA6G;AAC7G,+DAAsD;AACtD,qDAAuD;AAE1C,QAAA,kBAAkB,GAAG;IAChC,KAAK,CAAC,kBAAkB,CAAC,CAAM,EAAE,EAAE,EAAE,OAAY;QAC/C,IAAI;YACF,IAAI,SAAoB,CAAA;YACxB,IAAI,oBAA6B,CAAA;YACjC,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAiB,EAAE,EAAE;gBAC5D,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAmC,OAAO,CAAC,KAAK,CAAA;gBACtE,MAAM,QAAQ,GAAS,MAAM,EAAE,CAAC,aAAa,CAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;gBAChG,IAAI,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,KAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;oBACtF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;gBAEhE,IAAI,CAAC,QAAQ;oBAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;gBAE5D,IAAI,WAAW,GAAG,MAAM,EAAE;qBACvB,aAAa,CAAC,0BAAS,CAAC;qBACxB,kBAAkB,CAAC,IAAI,CAAC;qBACxB,MAAM,CAAC,OAAO,CAAC;qBACf,SAAS,CAAC,SAAS,CAAC;qBACpB,SAAS,CAAC,WAAW,CAAC;qBACtB,KAAK,CACJ,mIAAmI,EACnI;oBACE,SAAS,EAAE,MAAM,CAAC,EAAE;oBACpB,IAAI,EAAE,+BAAc,CAAC,YAAY;oBACjC,QAAQ,EAAE,QAAQ,CAAC,EAAE;oBACrB,OAAO,EAAE,iCAAgB,CAAC,SAAS;oBACnC,OAAO,EAAE,iCAAgB,CAAC,WAAW;iBACtC,CACF,CAAA;gBACH,SAAS,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAA;gBAEtC,IAAI,CAAC,SAAS,EAAE;oBACd,8CAA8C;oBAC9C,IAAI,iBAAiB,GAAG,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAkB,EAAE,EAAE;wBACrF,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAS,CAAC,CAAC,KAAK,CAC9C
|
|
1
|
+
{"version":3,"file":"get-zone-picking-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,15 @@ exports.zonePickingWorksheet = {
|
|
|
55
55
|
zoneWorksheet.worksheetDetail = await (0, typeorm_1.getRepository)(worksheet_base_1.WorksheetDetail).find({
|
|
56
56
|
where: { worksheet }
|
|
57
57
|
});
|
|
58
|
+
// Lightweight pre-pass: only the columns needed to compute invIds, roIds, and
|
|
59
|
+
// isCompletable. Avoids running the heavy joined SELECT (product/inventory/
|
|
60
|
+
// location/productDetail/...) twice — the second, filtered getMany() below
|
|
61
|
+
// produces the rows actually returned to the client.
|
|
62
|
+
const orderInventories = await (0, typeorm_1.getRepository)(sales_base_1.OrderInventory)
|
|
63
|
+
.createQueryBuilder('oi')
|
|
64
|
+
.select(['oi.id', 'oi.inventoryId', 'oi.releaseGoodId', 'oi.status'])
|
|
65
|
+
.where('oi.ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id })
|
|
66
|
+
.getMany();
|
|
58
67
|
//fetch order inventories
|
|
59
68
|
let qb = (0, typeorm_1.getRepository)(sales_base_1.OrderInventory)
|
|
60
69
|
.createQueryBuilder('oi')
|
|
@@ -66,8 +75,6 @@ exports.zonePickingWorksheet = {
|
|
|
66
75
|
.leftJoinAndSelect('pd.childProductDetail', 'cpd')
|
|
67
76
|
.leftJoinAndSelect('pd.parentProductDetails', 'ppd')
|
|
68
77
|
.where('ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id });
|
|
69
|
-
//get all oi to find inventory changes and determine if the worksheet is completable
|
|
70
|
-
const orderInventories = await qb.getMany();
|
|
71
78
|
//item assigned to obsolete inventories will not be displayed during picking
|
|
72
79
|
if (filter) {
|
|
73
80
|
qb.andWhere('rg.status != :orderStatus', { orderStatus: sales_base_1.ORDER_STATUS.OBSOLETE });
|
|
@@ -136,6 +143,10 @@ exports.zonePickingWorksheet = {
|
|
|
136
143
|
}
|
|
137
144
|
};
|
|
138
145
|
function isCompletable(oi, ic) {
|
|
146
|
+
// NOTE: callers may pass a partial OrderInventory with only id/inventoryId/
|
|
147
|
+
// releaseGoodId/status populated (see the lightweight pre-pass in
|
|
148
|
+
// zonePickingWorksheet). Don't reference other fields here without first
|
|
149
|
+
// widening that SELECT.
|
|
139
150
|
//find processing oi and check if there is any pending inventory adjustment
|
|
140
151
|
let processingOi = oi.filter(item => item.status === sales_base_1.ORDER_INVENTORY_STATUS.PROCESSING);
|
|
141
152
|
processingOi = processingOi.filter(item => !ic.filter(change => change.status === 'APPROVED').some(change => change.inventory.id === item.inventoryId));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zone-worksheet.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/zone-worksheet.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"zone-worksheet.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/zone-worksheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,11 @@ exports.Mutation = `
|
|
|
16
16
|
assignSorter(releaseGoodId: [String]!, userId: String): Boolean @transaction
|
|
17
17
|
completeZonePicking(worksheetId: String!): Boolean @transaction
|
|
18
18
|
completeZonePickingPartially(worksheetId: String!): Boolean @transaction
|
|
19
|
-
|
|
19
|
+
# Intentionally NOT @transaction — the resolver opens its own
|
|
20
|
+
# getConnection().transaction() and uses an independent inner transaction
|
|
21
|
+
# to commit the worksheet-claim UPDATE early (releases the row lock so
|
|
22
|
+
# SKIP LOCKED works for concurrent clicks). See get-zone-picking-task.ts.
|
|
23
|
+
getZonePickingTask: ZonePickingWorksheet @privilege(category: "worksheet_control", privilege: "mutation")
|
|
20
24
|
`;
|
|
21
25
|
exports.Types = [zone_worksheet_overview_1.ZoneWorksheetOverview, zone_worksheet_overview_list_1.ZoneWorksheetOverviewList, zone_picking_worksheet_1.ZonePickingWorksheet];
|
|
22
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,uEAAiE;AACjE,iFAA0E;AAC1E,qEAA+D;AAElD,QAAA,KAAK,GAAG;;;CAGpB,CAAA;AAEY,QAAA,QAAQ,GAAG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,uEAAiE;AACjE,iFAA0E;AAC1E,qEAA+D;AAElD,QAAA,KAAK,GAAG;;;CAGpB,CAAA;AAEY,QAAA,QAAQ,GAAG;;;;;;;;;;;;;CAavB,CAAA;AAEY,QAAA,KAAK,GAAG,CAAC,+CAAqB,EAAE,wDAAyB,EAAE,6CAAoB,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/operato-wms",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.824",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@things-factory/attachment-ui": "^4.3.815",
|
|
67
67
|
"@things-factory/auth-ui": "^4.3.815",
|
|
68
68
|
"@things-factory/barcode-ui": "^4.3.815",
|
|
69
|
-
"@things-factory/biz-ui": "^4.3.
|
|
69
|
+
"@things-factory/biz-ui": "^4.3.823",
|
|
70
70
|
"@things-factory/board-service": "^4.3.815",
|
|
71
71
|
"@things-factory/board-ui": "^4.3.815",
|
|
72
72
|
"@things-factory/code-ui": "^4.3.815",
|
|
@@ -81,17 +81,17 @@
|
|
|
81
81
|
"@things-factory/help": "^4.3.815",
|
|
82
82
|
"@things-factory/i18n-base": "^4.3.815",
|
|
83
83
|
"@things-factory/id-rule-base": "^4.3.815",
|
|
84
|
-
"@things-factory/import-ui": "^4.3.
|
|
85
|
-
"@things-factory/import-ui-excel": "^4.3.
|
|
84
|
+
"@things-factory/import-ui": "^4.3.823",
|
|
85
|
+
"@things-factory/import-ui-excel": "^4.3.823",
|
|
86
86
|
"@things-factory/menu-ui": "^4.3.815",
|
|
87
87
|
"@things-factory/more-ui": "^4.3.815",
|
|
88
88
|
"@things-factory/notification": "^4.3.815",
|
|
89
89
|
"@things-factory/pdf": "^4.3.815",
|
|
90
90
|
"@things-factory/print-proxy-service": "^4.3.815",
|
|
91
91
|
"@things-factory/print-ui": "^4.3.815",
|
|
92
|
-
"@things-factory/product-base": "^4.3.
|
|
93
|
-
"@things-factory/resource-ui": "^4.3.
|
|
94
|
-
"@things-factory/sales-ui": "^4.3.
|
|
92
|
+
"@things-factory/product-base": "^4.3.824",
|
|
93
|
+
"@things-factory/resource-ui": "^4.3.823",
|
|
94
|
+
"@things-factory/sales-ui": "^4.3.824",
|
|
95
95
|
"@things-factory/scene-data-transform": "^4.3.815",
|
|
96
96
|
"@things-factory/scene-excel": "^4.3.815",
|
|
97
97
|
"@things-factory/scene-firebase": "^4.3.815",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"@things-factory/system-ui": "^4.3.815",
|
|
108
108
|
"@things-factory/transport-base": "^4.3.819",
|
|
109
109
|
"@things-factory/tutorial-ui": "^4.3.815",
|
|
110
|
-
"@things-factory/warehouse-base": "^4.3.
|
|
111
|
-
"@things-factory/worksheet-base": "^4.3.
|
|
110
|
+
"@things-factory/warehouse-base": "^4.3.824",
|
|
111
|
+
"@things-factory/worksheet-base": "^4.3.824"
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
114
|
"@things-factory/builder": "^4.3.815",
|
|
@@ -117,5 +117,5 @@
|
|
|
117
117
|
"cypress-localstorage-commands": "^1.6.1",
|
|
118
118
|
"eslint-plugin-cypress": "^2.12.1"
|
|
119
119
|
},
|
|
120
|
-
"gitHead": "
|
|
120
|
+
"gitHead": "7c6aa626b0ce0ce8ab988710b0e8fc2ed0bba5c2"
|
|
121
121
|
}
|
|
@@ -34,29 +34,39 @@ export const getLoadingTask = {
|
|
|
34
34
|
.getOne()
|
|
35
35
|
|
|
36
36
|
// 2. If no assigned worksheet, find and assign next available one
|
|
37
|
+
// FOR UPDATE OF ws SKIP LOCKED: under concurrent clicks, two callers
|
|
38
|
+
// used to SELECT the same row and the second UPDATE would re-evaluate,
|
|
39
|
+
// find sorter_id no longer NULL, update zero rows, and the user would
|
|
40
|
+
// see a confusing "no suitable worksheet found" error even though other
|
|
41
|
+
// unassigned rows existed. SKIP LOCKED makes concurrent callers pick
|
|
42
|
+
// different rows. `OF ws` scopes the row lock to the worksheets table
|
|
43
|
+
// only (not the joined release_goods / worksheet_details rows). Inner
|
|
44
|
+
// transaction is independent so the row lock is released as soon as
|
|
45
|
+
// the UPDATE commits.
|
|
37
46
|
if (!worksheet) {
|
|
38
47
|
let updatedWorksheets = await getConnection().transaction(async (tx2: EntityManager) => {
|
|
39
48
|
let x = await tx2.query(
|
|
40
49
|
`
|
|
41
|
-
UPDATE worksheets ws SET
|
|
50
|
+
UPDATE worksheets ws SET
|
|
42
51
|
sorter_id = $2,
|
|
43
52
|
updated_at = NOW(),
|
|
44
53
|
updater_id = $2
|
|
45
54
|
FROM (
|
|
46
|
-
SELECT ws.id
|
|
55
|
+
SELECT ws.id
|
|
47
56
|
FROM worksheets ws
|
|
48
57
|
INNER JOIN release_goods rg ON rg.id = ws.release_good_id
|
|
49
58
|
INNER JOIN worksheet_details wsd ON wsd.worksheet_id = ws.id
|
|
50
|
-
WHERE ws.domain_id = $1
|
|
59
|
+
WHERE ws.domain_id = $1
|
|
51
60
|
AND ws.type = 'LOADING'
|
|
52
61
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
53
62
|
AND ws.sorter_id IS NULL
|
|
54
63
|
AND rg.status IN ('LOADING', 'PROCESSING', 'PARTIAL_PROCESSING')
|
|
55
64
|
AND wsd.status NOT IN ('DONE', 'DEACTIVATED')
|
|
56
65
|
AND (rg.sorted_by_id = $2 OR rg.sorted_by_id IS NULL)
|
|
57
|
-
ORDER BY rg.created_at
|
|
66
|
+
ORDER BY rg.created_at
|
|
58
67
|
LIMIT 1
|
|
59
|
-
|
|
68
|
+
FOR UPDATE OF ws SKIP LOCKED
|
|
69
|
+
) src
|
|
60
70
|
WHERE src.id = ws.id
|
|
61
71
|
RETURNING ws.id
|
|
62
72
|
`,
|
|
@@ -41,20 +41,35 @@ export const getZonePickingTask = {
|
|
|
41
41
|
|
|
42
42
|
if (!worksheet) {
|
|
43
43
|
//find a worksheet and update assignee to user
|
|
44
|
+
// Claim a single oldest unassigned worksheet. The LIMIT 1 + FOR UPDATE
|
|
45
|
+
// SKIP LOCKED inside the subquery makes this safe under concurrent clicks:
|
|
46
|
+
// - LIMIT 1 prevents bulk-claiming every unassigned worksheet for one user
|
|
47
|
+
// (the previous version assigned ALL of them to the clicker and only
|
|
48
|
+
// returned x[0], silently mis-assigning the rest to whoever clicked first).
|
|
49
|
+
// - FOR UPDATE SKIP LOCKED makes concurrent callers pick different rows
|
|
50
|
+
// instead of waiting on each other and then failing with "no suitable
|
|
51
|
+
// worksheet found" because the first user already grabbed everything.
|
|
52
|
+
//
|
|
53
|
+
// Use an independent inner transaction (not the outer `tx`) so the UPDATE
|
|
54
|
+
// commits before the surrounding resolver transaction finishes. Otherwise
|
|
55
|
+
// the row lock acquired by the UPDATE would persist for the whole resolver,
|
|
56
|
+
// defeating SKIP LOCKED for any concurrent click that arrives mid-flight.
|
|
44
57
|
let updatedWorksheets = await getConnection().transaction(async (tx2: EntityManager) => {
|
|
45
58
|
let x = await tx2.getRepository(Worksheet).query(
|
|
46
59
|
`
|
|
47
|
-
UPDATE worksheets ws SET
|
|
60
|
+
UPDATE worksheets ws SET
|
|
48
61
|
assignee_id = $2,
|
|
49
62
|
updated_at = NOW(),
|
|
50
63
|
updater_id = $2
|
|
51
64
|
FROM (
|
|
52
|
-
SELECT ws.id
|
|
65
|
+
SELECT ws.id FROM worksheets ws
|
|
53
66
|
WHERE ws.domain_id = $1
|
|
54
67
|
AND ws.type = 'ZONE_PICKING'
|
|
55
68
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
56
69
|
AND ws.assignee_id IS NULL
|
|
57
70
|
ORDER BY ws.created_at
|
|
71
|
+
LIMIT 1
|
|
72
|
+
FOR UPDATE SKIP LOCKED
|
|
58
73
|
) src where src.id = ws.id
|
|
59
74
|
RETURNING ws.id;
|
|
60
75
|
`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { EntityManager, getRepository, In
|
|
1
|
+
import { EntityManager, getRepository, In } from 'typeorm'
|
|
2
2
|
import { Domain } from '@things-factory/biz-base'
|
|
3
|
-
import { Worksheet, WorksheetDetail,
|
|
4
|
-
import {
|
|
3
|
+
import { Worksheet, WorksheetDetail, computeConversionString } from '@things-factory/worksheet-base'
|
|
4
|
+
import { InventoryChange } from '@things-factory/warehouse-base'
|
|
5
5
|
import { OrderInventory, ReleaseGood, ORDER_STATUS, ORDER_INVENTORY_STATUS } from '@things-factory/sales-base'
|
|
6
6
|
|
|
7
7
|
export const zoneWorksheetOverview = {
|
|
@@ -75,6 +75,16 @@ export const zonePickingWorksheet = {
|
|
|
75
75
|
where: { worksheet }
|
|
76
76
|
})
|
|
77
77
|
|
|
78
|
+
// Lightweight pre-pass: only the columns needed to compute invIds, roIds, and
|
|
79
|
+
// isCompletable. Avoids running the heavy joined SELECT (product/inventory/
|
|
80
|
+
// location/productDetail/...) twice — the second, filtered getMany() below
|
|
81
|
+
// produces the rows actually returned to the client.
|
|
82
|
+
const orderInventories: OrderInventory[] = await getRepository(OrderInventory)
|
|
83
|
+
.createQueryBuilder('oi')
|
|
84
|
+
.select(['oi.id', 'oi.inventoryId', 'oi.releaseGoodId', 'oi.status'])
|
|
85
|
+
.where('oi.ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id })
|
|
86
|
+
.getMany()
|
|
87
|
+
|
|
78
88
|
//fetch order inventories
|
|
79
89
|
let qb = getRepository(OrderInventory)
|
|
80
90
|
.createQueryBuilder('oi')
|
|
@@ -87,9 +97,6 @@ export const zonePickingWorksheet = {
|
|
|
87
97
|
.leftJoinAndSelect('pd.parentProductDetails', 'ppd')
|
|
88
98
|
.where('ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id })
|
|
89
99
|
|
|
90
|
-
//get all oi to find inventory changes and determine if the worksheet is completable
|
|
91
|
-
const orderInventories: OrderInventory[] = await qb.getMany()
|
|
92
|
-
|
|
93
100
|
//item assigned to obsolete inventories will not be displayed during picking
|
|
94
101
|
if (filter) {
|
|
95
102
|
qb.andWhere('rg.status != :orderStatus', { orderStatus: ORDER_STATUS.OBSOLETE })
|
|
@@ -174,6 +181,10 @@ export const zonePickingWorksheet = {
|
|
|
174
181
|
}
|
|
175
182
|
|
|
176
183
|
function isCompletable(oi: OrderInventory[], ic: InventoryChange[]): String {
|
|
184
|
+
// NOTE: callers may pass a partial OrderInventory with only id/inventoryId/
|
|
185
|
+
// releaseGoodId/status populated (see the lightweight pre-pass in
|
|
186
|
+
// zonePickingWorksheet). Don't reference other fields here without first
|
|
187
|
+
// widening that SELECT.
|
|
177
188
|
//find processing oi and check if there is any pending inventory adjustment
|
|
178
189
|
let processingOi = oi.filter(item => item.status === ORDER_INVENTORY_STATUS.PROCESSING)
|
|
179
190
|
|
|
@@ -15,7 +15,11 @@ export const Mutation = `
|
|
|
15
15
|
assignSorter(releaseGoodId: [String]!, userId: String): Boolean @transaction
|
|
16
16
|
completeZonePicking(worksheetId: String!): Boolean @transaction
|
|
17
17
|
completeZonePickingPartially(worksheetId: String!): Boolean @transaction
|
|
18
|
-
|
|
18
|
+
# Intentionally NOT @transaction — the resolver opens its own
|
|
19
|
+
# getConnection().transaction() and uses an independent inner transaction
|
|
20
|
+
# to commit the worksheet-claim UPDATE early (releases the row lock so
|
|
21
|
+
# SKIP LOCKED works for concurrent clicks). See get-zone-picking-task.ts.
|
|
22
|
+
getZonePickingTask: ZonePickingWorksheet @privilege(category: "worksheet_control", privilege: "mutation")
|
|
19
23
|
`
|
|
20
24
|
|
|
21
25
|
export const Types = [ZoneWorksheetOverview, ZoneWorksheetOverviewList, ZonePickingWorksheet]
|