@things-factory/operato-hub 4.3.543 → 4.3.544
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/routers/api/restful-apis/v1/company/get-webhook-details.js +58 -0
- package/dist-server/routers/api/restful-apis/v1/company/get-webhook-details.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/company/index.js +2 -0
- package/dist-server/routers/api/restful-apis/v1/company/index.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/company/upsert-webhooks.js +146 -0
- package/dist-server/routers/api/restful-apis/v1/company/upsert-webhooks.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/utils/params.js +43 -0
- package/dist-server/routers/api/restful-apis/v1/utils/params.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-inventory-adjustment-details.js +108 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-inventory-adjustment-details.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/index.js +1 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/index.js.map +1 -1
- package/openapi/v1/Inventory.yaml +221 -0
- package/openapi/v1/webhook.yaml +281 -0
- package/openapi/v1.yaml +2 -0
- package/package.json +14 -14
- package/server/routers/api/restful-apis/v1/company/get-webhook-details.ts +64 -0
- package/server/routers/api/restful-apis/v1/company/index.ts +2 -0
- package/server/routers/api/restful-apis/v1/company/upsert-webhooks.ts +176 -0
- package/server/routers/api/restful-apis/v1/utils/params.ts +43 -0
- package/server/routers/api/restful-apis/v1/warehouse/get-inventory-adjustment-details.ts +112 -0
- package/server/routers/api/restful-apis/v1/warehouse/index.ts +1 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { EntityManager, getConnection, SelectQueryBuilder } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import { restfulApiRouter as router } from '@things-factory/api'
|
|
4
|
+
import { Bizplace, getPartnersBizplaces } from '@things-factory/biz-base'
|
|
5
|
+
import { Webhook, WebhookEvent, WebhookEventsEnum } from '@things-factory/integration-base'
|
|
6
|
+
|
|
7
|
+
import { businessMiddleware, loggingMiddleware, validationMiddleware } from '../middlewares'
|
|
8
|
+
import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
|
|
9
|
+
|
|
10
|
+
router.post(
|
|
11
|
+
'/v1/company/upsert-webhooks',
|
|
12
|
+
businessMiddleware,
|
|
13
|
+
validationMiddleware,
|
|
14
|
+
loggingMiddleware,
|
|
15
|
+
async (context, next) => {
|
|
16
|
+
try {
|
|
17
|
+
await getConnection().transaction(async (tx: EntityManager) => {
|
|
18
|
+
const { domain, user } = context.state
|
|
19
|
+
const webhooks = context.request.body.data
|
|
20
|
+
const webhookIds: string[] = []
|
|
21
|
+
|
|
22
|
+
if (!Array.isArray(webhooks)) throw new ApiError('E01', 'data field is not an array')
|
|
23
|
+
|
|
24
|
+
for (const wb of webhooks) {
|
|
25
|
+
const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
26
|
+
where: { id: wb.warehouseBizplaceId },
|
|
27
|
+
relations: ['domain']
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
if (!wb?.events || wb?.events?.length < 1)
|
|
31
|
+
throw new ApiError('E01', 'The "events" field is required and must contain at least one event.')
|
|
32
|
+
const partnerBizplaces: any[] = await getPartnersBizplaces(bizplace.domain, user, tx)
|
|
33
|
+
|
|
34
|
+
const validatedPartnerBiz = validatePartnerBizplaces(partnerBizplaces, wb.partnerBizplaceIds)
|
|
35
|
+
|
|
36
|
+
if (!wb.id) {
|
|
37
|
+
let data = await generateWebook(tx, wb, validatedPartnerBiz, bizplace.domain)
|
|
38
|
+
webhookIds.push(data)
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
webhookIds.push(wb.id)
|
|
43
|
+
await updateWebhook(tx, wb, validatedPartnerBiz)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const qb: SelectQueryBuilder<Webhook> = await tx
|
|
47
|
+
.getRepository(Webhook)
|
|
48
|
+
.createQueryBuilder('webhook')
|
|
49
|
+
.innerJoinAndSelect('webhook.bizplaces', 'bz')
|
|
50
|
+
.innerJoinAndSelect('webhook.webhookEvents', 'webhookEvent')
|
|
51
|
+
.where('webhook.id in (:...webhookIds)', { webhookIds })
|
|
52
|
+
|
|
53
|
+
const result = await qb.getMany()
|
|
54
|
+
|
|
55
|
+
let data = []
|
|
56
|
+
for (const wb of result) {
|
|
57
|
+
let datapoint = {}
|
|
58
|
+
datapoint = {
|
|
59
|
+
id: wb.id,
|
|
60
|
+
name: wb.name,
|
|
61
|
+
active: wb.active,
|
|
62
|
+
targetUrl: wb.targetUrl,
|
|
63
|
+
extensionUrl: wb.extensionUrl,
|
|
64
|
+
events: wb.webhookEvents.map(e => e.name),
|
|
65
|
+
partnerBizplaces: wb.bizplaces.map(b => ({ id: b.id, name: b.name }))
|
|
66
|
+
}
|
|
67
|
+
data.push(datapoint)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
context.body = {
|
|
71
|
+
data
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
} catch (e) {
|
|
75
|
+
if (e instanceof ApiError) ApiErrorHandler(context, e)
|
|
76
|
+
else throwInternalServerError(context, e)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
function validatePartnerBizplaces(partnerBizplacesIdsDb, partnerBizplaceIds: any[]) {
|
|
82
|
+
const partnerBizplaceIdsSet = new Set(partnerBizplacesIdsDb.map(itm => itm.id))
|
|
83
|
+
const payloadPartnerBizplaceIds = new Set(partnerBizplaceIds.map(itm => itm.id))
|
|
84
|
+
|
|
85
|
+
const notPartnerBizplaces: Bizplace[] = partnerBizplaceIds.filter(itm => !partnerBizplaceIdsSet.has(itm.id))
|
|
86
|
+
|
|
87
|
+
if (notPartnerBizplaces.length > 0) {
|
|
88
|
+
throw new ApiError('E01', `partner bizplaces not found for ${notPartnerBizplaces.join(',')} `)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return partnerBizplacesIdsDb.filter(itm => payloadPartnerBizplaceIds.has(itm.id))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function generateInsertQuery(tableName: string) {
|
|
95
|
+
return `
|
|
96
|
+
INSERT INTO ${tableName} (name, webhook_id, created_at)
|
|
97
|
+
SELECT e.name, e.webhook_id, e.created_at
|
|
98
|
+
FROM jsonb_to_recordset($1) AS e(name webhook_events_enum, webhook_id UUID, created_at TIMESTAMP)
|
|
99
|
+
RETURNING *;
|
|
100
|
+
`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function eventsToInsert(events: WebhookEventsEnum[], webhook: Webhook) {
|
|
104
|
+
const filteredEvents = []
|
|
105
|
+
|
|
106
|
+
for (const [key, values] of Object.entries(WebhookEventsEnum)) {
|
|
107
|
+
if (events.includes(values)) {
|
|
108
|
+
filteredEvents.push(values)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return filteredEvents.map(e => ({
|
|
113
|
+
name: e,
|
|
114
|
+
webhook_id: webhook.id,
|
|
115
|
+
created_at: new Date()
|
|
116
|
+
}))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function generateWebook(tx: EntityManager, webhook: Webhook, bizplaces: Bizplace[], warehouseDomain: any) {
|
|
120
|
+
const data = {
|
|
121
|
+
name: webhook.name,
|
|
122
|
+
targetUrl: webhook.targetUrl,
|
|
123
|
+
extensionUrl: webhook.extensionUrl,
|
|
124
|
+
active: webhook.active,
|
|
125
|
+
bizplaces: bizplaces,
|
|
126
|
+
domain: warehouseDomain,
|
|
127
|
+
updatedAt: new Date()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const addedWebhook: Webhook = await tx.getRepository(Webhook).save(data)
|
|
131
|
+
|
|
132
|
+
if (webhook.events.length > 0) {
|
|
133
|
+
await tx
|
|
134
|
+
.getRepository(WebhookEvent)
|
|
135
|
+
.query(generateInsertQuery('webhook_events'), [JSON.stringify(eventsToInsert(webhook.events, addedWebhook))])
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const newWebhook: Webhook = await tx.getRepository(Webhook).findOne({ where: { id: addedWebhook.id } })
|
|
139
|
+
|
|
140
|
+
return newWebhook.id
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function updateWebhook(tx: EntityManager, webhook: Webhook, bizplace: Bizplace[]) {
|
|
144
|
+
await tx.getRepository(Webhook).update(webhook.id, {
|
|
145
|
+
name: webhook.name,
|
|
146
|
+
targetUrl: webhook.targetUrl,
|
|
147
|
+
extensionUrl: webhook.extensionUrl,
|
|
148
|
+
active: webhook.active,
|
|
149
|
+
updatedAt: new Date()
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const webhookEvents: WebhookEvent = await tx
|
|
153
|
+
.getRepository(WebhookEvent)
|
|
154
|
+
.find({ where: { webhook: { id: webhook.id } } })
|
|
155
|
+
|
|
156
|
+
const payloadEvents = new Set(webhook?.events)
|
|
157
|
+
const dbEvents = new Set(webhookEvents.map(itm => itm.name))
|
|
158
|
+
|
|
159
|
+
const { addEvents, removeEvents } = {
|
|
160
|
+
addEvents: webhook?.events.filter(event => !dbEvents.has(event)),
|
|
161
|
+
removeEvents: webhookEvents.filter(event => !payloadEvents.has(event.name))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (addEvents.length > 0) {
|
|
165
|
+
await tx
|
|
166
|
+
.getRepository(WebhookEvent)
|
|
167
|
+
.query(generateInsertQuery('webhook_events'), [JSON.stringify(eventsToInsert(addEvents, { id: webhook.id }))])
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (removeEvents.length > 0) {
|
|
171
|
+
const removeEventNames = removeEvents.map(itm => `'${itm.name}'`).join(',')
|
|
172
|
+
await tx
|
|
173
|
+
.getRepository(WebhookEvent)
|
|
174
|
+
.query(`DELETE FROM webhook_events where webhook_id = '${webhook.id}' and name in (${removeEventNames})`)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -27,8 +27,10 @@ export const params = {
|
|
|
27
27
|
'get-delivery-order-list': ['bizplaceId', 'doNo', 'vehicleNo', ...fromToDate, ...limitOffset],
|
|
28
28
|
'get-onhand-inventory-list': ['bizplaceId', 'sku', 'batchId', 'fromDate', 'toDate', ...limitOffset],
|
|
29
29
|
'get-inventory-product-group-list': ['bizplaceId', 'sku', 'batchId', ...fromToDate, ...limitOffset],
|
|
30
|
+
'get-inventory-adjustment-details': ['bizplaceId', 'id'],
|
|
30
31
|
'get-inventory-adjustment-list': ['bizplaceId', ...fromToDate, ...limitOffset, 'sku', 'adjustmentStatus'],
|
|
31
32
|
'get-manifest-details': ['bizplaceId', 'name', 'id'],
|
|
33
|
+
'get-webhook-details': ['warehouseBizplaceId', 'webhookId'],
|
|
32
34
|
'add-contact-points': [
|
|
33
35
|
'bizplaceId',
|
|
34
36
|
'name',
|
|
@@ -170,6 +172,17 @@ export const params = {
|
|
|
170
172
|
'marketplaceProducts.marketplaceProductVariations.inventoryItemId',
|
|
171
173
|
'marketplaceProducts.marketplaceProductVariations.locationId'
|
|
172
174
|
],
|
|
175
|
+
'upsert-webhooks': [
|
|
176
|
+
'id',
|
|
177
|
+
'name',
|
|
178
|
+
'warehouseBizplaceId',
|
|
179
|
+
'partnerBizplaceIds',
|
|
180
|
+
'partnerBizplaceIds.id',
|
|
181
|
+
'active',
|
|
182
|
+
'targetUrl',
|
|
183
|
+
'extensionUrl',
|
|
184
|
+
'events'
|
|
185
|
+
],
|
|
173
186
|
'update-marketplace-product': [
|
|
174
187
|
'storeId',
|
|
175
188
|
'id',
|
|
@@ -580,7 +593,9 @@ export const reqParams = {
|
|
|
580
593
|
'get-onhand-inventory-list': ['bizplaceId'],
|
|
581
594
|
'get-inventory-product-group-list': ['bizplaceId'],
|
|
582
595
|
'get-manifest-details': ['bizplaceId'],
|
|
596
|
+
'get-webhook-details': ['warehouseBizplaceId'],
|
|
583
597
|
'get-warehouse-bizplace-onhand-inventories': ['bizplaceId'],
|
|
598
|
+
'get-inventory-adjustment-details': ['id'],
|
|
584
599
|
'get-inventory-adjustment-list': ['bizplaceId', 'fromDate', 'toDate'],
|
|
585
600
|
'upsert-product': [
|
|
586
601
|
{
|
|
@@ -611,6 +626,34 @@ export const reqParams = {
|
|
|
611
626
|
]
|
|
612
627
|
}
|
|
613
628
|
],
|
|
629
|
+
'upsert-webhooks': [
|
|
630
|
+
{
|
|
631
|
+
name: 'warehouseBizplaceId',
|
|
632
|
+
required: true,
|
|
633
|
+
type: 'field'
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
name: 'partnerBizplaceIds',
|
|
637
|
+
required: true,
|
|
638
|
+
type: 'array',
|
|
639
|
+
data: [{ name: 'id', required: true, type: 'field' }]
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: 'active',
|
|
643
|
+
required: true,
|
|
644
|
+
type: 'field'
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
name: 'name',
|
|
648
|
+
required: true,
|
|
649
|
+
type: 'field'
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
name: 'targetUrl',
|
|
653
|
+
required: true,
|
|
654
|
+
type: 'field'
|
|
655
|
+
}
|
|
656
|
+
],
|
|
614
657
|
'upsert-products': [
|
|
615
658
|
{
|
|
616
659
|
name: 'sku',
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { getRepository } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { restfulApiRouter as router } from '@things-factory/api'
|
|
5
|
+
import { InventoryChange } from '@things-factory/warehouse-base'
|
|
6
|
+
|
|
7
|
+
import { businessMiddleware, loggingMiddleware, validationMiddleware } from '../middlewares'
|
|
8
|
+
import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
|
|
9
|
+
|
|
10
|
+
router.get(
|
|
11
|
+
'/v1/warehouse/get-inventory-adjustment-details',
|
|
12
|
+
businessMiddleware,
|
|
13
|
+
validationMiddleware,
|
|
14
|
+
loggingMiddleware,
|
|
15
|
+
async (context, next) => {
|
|
16
|
+
try {
|
|
17
|
+
// get contact points for that bizplace
|
|
18
|
+
// optional query parameter filter
|
|
19
|
+
const { domain } = context.state
|
|
20
|
+
let filter = { ...context.query, domain: domain.id }
|
|
21
|
+
if (_.has(filter, 'bizplaceId')) {
|
|
22
|
+
filter['bizplace'] = filter['bizplaceId']
|
|
23
|
+
delete filter['bizplaceId']
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const inventoryChange: InventoryChange = await getRepository(InventoryChange).findOne({
|
|
27
|
+
where: filter,
|
|
28
|
+
relations: ['product', 'productDetail', 'bizplace', 'lastInventoryHistory']
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
if (!inventoryChange) {
|
|
32
|
+
throw new ApiError('E04', 'inventory adjustment not found')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// create and format data response
|
|
36
|
+
const data = {
|
|
37
|
+
id: inventoryChange.id,
|
|
38
|
+
current: {
|
|
39
|
+
productDetails: {
|
|
40
|
+
refCode: inventoryChange.productDetail.refCode,
|
|
41
|
+
packingType: inventoryChange.productDetail.packingType,
|
|
42
|
+
packingSize: inventoryChange.productDetail.packingSize,
|
|
43
|
+
uom: inventoryChange.productDetail.uom,
|
|
44
|
+
uomValue: inventoryChange.productDetail.uomValue
|
|
45
|
+
},
|
|
46
|
+
product: {
|
|
47
|
+
sku: inventoryChange.product.sku,
|
|
48
|
+
name: inventoryChange.product.name,
|
|
49
|
+
descrtiption: inventoryChange.product.description
|
|
50
|
+
},
|
|
51
|
+
bizplace: {
|
|
52
|
+
name: inventoryChange.bizplace.name
|
|
53
|
+
},
|
|
54
|
+
qty: inventoryChange.qty,
|
|
55
|
+
uom: inventoryChange.uom,
|
|
56
|
+
uomValue: inventoryChange.uomValue,
|
|
57
|
+
packingType: inventoryChange.packingType,
|
|
58
|
+
packingSize: inventoryChange.packingSize,
|
|
59
|
+
batchId: inventoryChange.batchId,
|
|
60
|
+
batchIdRef: inventoryChange.batchIdRef,
|
|
61
|
+
expirationDate: inventoryChange.expirationDate,
|
|
62
|
+
manufactureYear: inventoryChange.manufactureYear,
|
|
63
|
+
manufactureDate: inventoryChange.manufactureDate,
|
|
64
|
+
palletId: inventoryChange.palletId,
|
|
65
|
+
cartonId: inventoryChange.cartonId,
|
|
66
|
+
},
|
|
67
|
+
previous: {
|
|
68
|
+
productDetails: {
|
|
69
|
+
refCode: inventoryChange.productDetail.refCode,
|
|
70
|
+
packingType: inventoryChange.productDetail.packingType,
|
|
71
|
+
packingSize: inventoryChange.productDetail.packingSize,
|
|
72
|
+
uom: inventoryChange.productDetail.uom,
|
|
73
|
+
uomValue: inventoryChange.productDetail.uomValue
|
|
74
|
+
},
|
|
75
|
+
product: {
|
|
76
|
+
sku: inventoryChange.product.sku,
|
|
77
|
+
name: inventoryChange.product.name,
|
|
78
|
+
descrtiption: inventoryChange.product.description
|
|
79
|
+
},
|
|
80
|
+
bizplace: {
|
|
81
|
+
name: inventoryChange.bizplace.name
|
|
82
|
+
},
|
|
83
|
+
qty: inventoryChange.lastInventoryHistory.qty,
|
|
84
|
+
uom: inventoryChange.lastInventoryHistory.uom,
|
|
85
|
+
uomValue: inventoryChange.lastInventoryHistory.uomValue,
|
|
86
|
+
packingType: inventoryChange.lastInventoryHistory.packingType,
|
|
87
|
+
packingSize: inventoryChange.lastInventoryHistory.packingSize,
|
|
88
|
+
batchId: inventoryChange.lastInventoryHistory.batchId,
|
|
89
|
+
batchIdRef: inventoryChange.lastInventoryHistory.batchIdRef,
|
|
90
|
+
expirationDate: inventoryChange.lastInventoryHistory.expirationDate,
|
|
91
|
+
manufactureYear: inventoryChange.lastInventoryHistory.manufactureYear,
|
|
92
|
+
manufactureDate: inventoryChange.lastInventoryHistory.manufactureDate,
|
|
93
|
+
palletId: inventoryChange.lastInventoryHistory.palletId,
|
|
94
|
+
cartonId: inventoryChange.lastInventoryHistory.cartonId,
|
|
95
|
+
},
|
|
96
|
+
adjustmentCode: inventoryChange.adjustmentCode,
|
|
97
|
+
adjustmentNote: inventoryChange.adjustmentNote,
|
|
98
|
+
type: inventoryChange.transactionType,
|
|
99
|
+
status: inventoryChange.status,
|
|
100
|
+
createdAt: inventoryChange.createdAt,
|
|
101
|
+
updatedAt: inventoryChange.updatedAt
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
context.body = {
|
|
105
|
+
data
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
if (e instanceof ApiError) ApiErrorHandler(context, e)
|
|
109
|
+
else throwInternalServerError(context, e)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
)
|
|
@@ -20,5 +20,6 @@ import './dispatch-delivery-order'
|
|
|
20
20
|
import './update-gan-to-arrived'
|
|
21
21
|
import './complete-delivery-order'
|
|
22
22
|
import './get-inventory-adjustment-list'
|
|
23
|
+
import './get-inventory-adjustment-details'
|
|
23
24
|
import './get-manifest-details'
|
|
24
25
|
import './update-order-package-details'
|