@things-factory/operato-hub 4.3.561 → 4.3.563

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.
Files changed (42) hide show
  1. package/dist-server/graphql/resolvers/email/send-emails.js +3 -2
  2. package/dist-server/graphql/resolvers/email/send-emails.js.map +1 -1
  3. package/dist-server/graphql/resolvers/reports/admiral-asn-report.js +127 -0
  4. package/dist-server/graphql/resolvers/reports/admiral-asn-report.js.map +1 -0
  5. package/dist-server/graphql/resolvers/reports/aging-report.js +146 -0
  6. package/dist-server/graphql/resolvers/reports/aging-report.js.map +1 -0
  7. package/dist-server/graphql/resolvers/reports/asn-report.js +126 -0
  8. package/dist-server/graphql/resolvers/reports/asn-report.js.map +1 -0
  9. package/dist-server/graphql/resolvers/reports/custom-elccl-fn-dispatch-report.js +1 -1
  10. package/dist-server/graphql/resolvers/reports/index.js +4 -1
  11. package/dist-server/graphql/resolvers/reports/index.js.map +1 -1
  12. package/dist-server/graphql/types/reports/admiral-asn-report-list.js +14 -0
  13. package/dist-server/graphql/types/reports/admiral-asn-report-list.js.map +1 -0
  14. package/dist-server/graphql/types/reports/admiral-asn-report.js +21 -0
  15. package/dist-server/graphql/types/reports/admiral-asn-report.js.map +1 -0
  16. package/dist-server/graphql/types/reports/aging-report-list.js +14 -0
  17. package/dist-server/graphql/types/reports/aging-report-list.js.map +1 -0
  18. package/dist-server/graphql/types/reports/aging-report.js +29 -0
  19. package/dist-server/graphql/types/reports/aging-report.js.map +1 -0
  20. package/dist-server/graphql/types/reports/asn-report-list.js +14 -0
  21. package/dist-server/graphql/types/reports/asn-report-list.js.map +1 -0
  22. package/dist-server/graphql/types/reports/asn-report.js +21 -0
  23. package/dist-server/graphql/types/reports/asn-report.js.map +1 -0
  24. package/dist-server/graphql/types/reports/index.js +16 -1
  25. package/dist-server/graphql/types/reports/index.js.map +1 -1
  26. package/dist-server/routers/support-router.js +116 -2
  27. package/dist-server/routers/support-router.js.map +1 -1
  28. package/package.json +31 -31
  29. package/server/graphql/resolvers/email/send-emails.ts +3 -2
  30. package/server/graphql/resolvers/reports/admiral-asn-report.ts +142 -0
  31. package/server/graphql/resolvers/reports/aging-report.ts +161 -0
  32. package/server/graphql/resolvers/reports/asn-report.ts +141 -0
  33. package/server/graphql/resolvers/reports/custom-elccl-fn-dispatch-report.ts +1 -1
  34. package/server/graphql/resolvers/reports/index.ts +7 -1
  35. package/server/graphql/types/reports/admiral-asn-report-list.ts +8 -0
  36. package/server/graphql/types/reports/admiral-asn-report.ts +15 -0
  37. package/server/graphql/types/reports/aging-report-list.ts +8 -0
  38. package/server/graphql/types/reports/aging-report.ts +23 -0
  39. package/server/graphql/types/reports/asn-report-list.ts +8 -0
  40. package/server/graphql/types/reports/asn-report.ts +15 -0
  41. package/server/graphql/types/reports/index.ts +16 -1
  42. package/server/routers/support-router.ts +143 -8
@@ -0,0 +1,141 @@
1
+ import { EntityManager } from 'typeorm'
2
+ import { Bizplace } from '@things-factory/biz-base'
3
+ import { ListParam } from '@things-factory/shell'
4
+
5
+ export const asnReport = {
6
+ async asnReport(_: any, params: ListParam, context: any) {
7
+ try {
8
+ const { tx }: { tx: EntityManager } = context.state
9
+
10
+ // Fetch all bizplace filters from params
11
+ let bizplaceFilters = params.filters.filter(data => data.name === 'bizplace')
12
+
13
+ if (!bizplaceFilters || bizplaceFilters.length === 0)
14
+ throw 'Invalid input: At least one Bizplace filter is required'
15
+
16
+ // Extract bizplace IDs from filters
17
+ const bizplaceIds = bizplaceFilters.map(filter => filter.value)
18
+
19
+ if (!bizplaceIds || bizplaceIds.length === 0) throw 'Invalid input: No Bizplace IDs provided'
20
+
21
+ // Query the database for matching Bizplaces to ensure they exist
22
+ const bizplaces: Bizplace[] = await tx.getRepository(Bizplace).findByIds(bizplaceIds)
23
+
24
+ if (!bizplaces || bizplaces.length === 0) throw 'Invalid input: None of the provided Bizplaces were found'
25
+
26
+ // Create temporary table for report
27
+ await tx.query(
28
+ `
29
+ create temp table temp_inbound_order_report on commit drop as (
30
+ select
31
+ to_char((grn.created_at + interval '8 hours')::date,'dd/mm/yyyy') as "date_received",
32
+ an.delivery_order_no as "do_number",
33
+ p.sku as "sku",
34
+ p.name as "descr",
35
+ coalesce(oi.actual_pack_qty, 0) as "qty",
36
+ i.pallet_id as "pallet_id",
37
+ to_char(i.manufacture_date, 'DD/MM/YYYY') as "mfg_date",
38
+ to_char(i.expiration_date, 'DD/MM/YYYY') as "expiry_date",
39
+ i.batch_id as "remark"
40
+ from arrival_notices an
41
+ inner join order_products op on an.id = op.arrival_notice_id
42
+ inner join order_inventories oi
43
+ on op.arrival_notice_id = oi.arrival_notice_id
44
+ and op.product_id = oi.product_id
45
+ and op.product_detail_id = oi.product_detail_id
46
+ and oi.batch_id = op.batch_id
47
+ inner join products p on p.id = op.product_id
48
+ inner join inventories i on i.id = oi.inventory_id
49
+ inner join goods_receival_notes grn on an.id = grn.arrival_notice_id
50
+ where i.bizplace_id = ANY($1)
51
+ and grn.created_at::date = (NOW()::date - interval '1 day')
52
+ order by "date_received", "pallet_id"
53
+ )
54
+ `,
55
+ [bizplaceIds]
56
+ )
57
+
58
+ // Fetch detailed results
59
+ const result: any = await tx.query(`
60
+ select *
61
+ from temp_inbound_order_report
62
+ `)
63
+
64
+ // Fetch aggregated totals grouped by D/O Number
65
+ const totals = await tx.query(`
66
+ select
67
+ do_number,
68
+ SUM(COALESCE(qty, 0)) as total_qty
69
+ from temp_inbound_order_report
70
+ group by do_number
71
+ order by do_number
72
+ `)
73
+
74
+ // Map detailed results
75
+ let items = result.map(itm => ({
76
+ dateReceived: itm.date_received,
77
+ doNumber: itm.do_number,
78
+ sku: itm.sku,
79
+ descr: itm.descr,
80
+ qty: itm.qty && !isNaN(itm.qty) ? parseInt(itm.qty, 10) : 0,
81
+ palletId: itm.pallet_id,
82
+ mfgDate: itm.mfg_date,
83
+ expiryDate: itm.expiry_date,
84
+ remark: itm.remark
85
+ }))
86
+
87
+ // Map aggregated totals
88
+ let totalItems = totals.map(total => ({
89
+ doNumber: total.do_number,
90
+ qty: total.total_qty && !isNaN(total.total_qty) ? parseInt(total.total_qty, 10) : 0
91
+ }))
92
+
93
+ // Insert total counts into the items array
94
+ totalItems.forEach(total => {
95
+ // Find the last index of items matching the current total description
96
+ const lastIndex = items.findLastIndex(item => item.doNumber === total.doNumber)
97
+
98
+ if (lastIndex !== -1) {
99
+ items.splice(lastIndex + 1, 0, {
100
+ dateReceived: null,
101
+ doNumber: `${total.doNumber} Total`,
102
+ sku: null,
103
+ descr: null,
104
+ qty: total.qty,
105
+ palletId: null,
106
+ mfgDate: null,
107
+ expiryDate: null,
108
+ remark: null
109
+ })
110
+ }
111
+ })
112
+
113
+ // Calculate grand total
114
+ const grandTotalQty = totalItems.reduce((sum, total) => {
115
+ const qty = !isNaN(total.qty) ? parseInt(total.qty, 10) : 0
116
+ return sum + qty
117
+ }, 0)
118
+
119
+ // Append the grand total row at the end
120
+ items.push({
121
+ dateReceived: null,
122
+ doNumber: 'Grand Total',
123
+ sku: null,
124
+ descr: null,
125
+ qty: grandTotalQty,
126
+ palletId: null,
127
+ mfgDate: null,
128
+ expiryDate: null,
129
+ remark: null
130
+ })
131
+
132
+ // Return the modified items with inserted totals
133
+ return {
134
+ items,
135
+ totals: totalItems
136
+ }
137
+ } catch (error) {
138
+ throw error
139
+ }
140
+ }
141
+ }
@@ -31,7 +31,7 @@ export const customElcclDispatchReport = {
31
31
  inner join products p on p.id = oi.product_id
32
32
  inner join delivery_orders do2 on rg.id = do2.release_good_id and do2.id = oi.delivery_order_id
33
33
  left join contact_points cp on cp.phone = do2.phone_1 and cp.address = do2.delivery_address_1
34
- where rg.bizplace_id in('f0848540-9d8f-4835-b744-2407db36a14e','157a9653-9f2b-4568-b245-ab8791db98ce')
34
+ where rg.bizplace_id in('f0848540-9d8f-4835-b744-2407db36a14e','226c9c9d-9685-403d-8f05-89b7d3b8691e','157a9653-9f2b-4568-b245-ab8791db98ce')
35
35
  and do2.status in('DELIVERING','DONE')
36
36
  and do2.delivery_date::date = (NOW()::date - interval '1 day')
37
37
  order by "creation_date" asc
@@ -2,10 +2,16 @@ import { inboundOrderDetailsReport } from './inbound-order-details-report'
2
2
  import { outboundOrderDetailsReport } from './outbound-order-details-report'
3
3
  import { shortageReport } from './shortage-report'
4
4
  import { customElcclDispatchReport } from './custom-elccl-fn-dispatch-report'
5
+ import { agingReport } from './aging-report'
6
+ import { asnReport } from './asn-report'
7
+ import { admiralAsnReport } from './admiral-asn-report'
5
8
 
6
9
  export const Query = {
7
10
  ...inboundOrderDetailsReport,
8
11
  ...outboundOrderDetailsReport,
9
12
  ...shortageReport,
10
- ...customElcclDispatchReport
13
+ ...customElcclDispatchReport,
14
+ ...agingReport,
15
+ ...asnReport,
16
+ ...admiralAsnReport
11
17
  }
@@ -0,0 +1,8 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AdmiralAsnReportList = gql`
4
+ type AdmiralAsnReportList {
5
+ items: [AdmiralAsnReport]
6
+ total: Int
7
+ }
8
+ `
@@ -0,0 +1,15 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AdmiralAsnReport = gql`
4
+ type AdmiralAsnReport {
5
+ dateReceived: String
6
+ doNumber: String
7
+ sku: String
8
+ descr: String
9
+ qty: Int
10
+ palletId: String
11
+ mfgDate: String
12
+ expiryDate: String
13
+ remark: String
14
+ }
15
+ `
@@ -0,0 +1,8 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AgingReportList = gql`
4
+ type AgingReportList {
5
+ items: [AgingReport]
6
+ total: Int
7
+ }
8
+ `
@@ -0,0 +1,23 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AgingReport = gql`
4
+ type AgingReport {
5
+ productSku: Int
6
+ productName: String
7
+ pallet: Int
8
+ qtyAvailable: Int
9
+ lotId: String
10
+ batchId: String
11
+ receiptDate: String
12
+ expDate: String
13
+ mfgDate: String
14
+ stockStatus: String
15
+ defaultUom: String
16
+ daysInWarehouse: Int
17
+ daysToExpire: Int
18
+ monthsInWarehouse: Int
19
+ monthsToExpire: Int
20
+ totalPallet: String
21
+ totalQtyAvailable: String
22
+ }
23
+ `
@@ -0,0 +1,8 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AsnReportList = gql`
4
+ type AsnReportList {
5
+ items: [AsnReport]
6
+ total: Int
7
+ }
8
+ `
@@ -0,0 +1,15 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ export const AsnReport = gql`
4
+ type AsnReport {
5
+ dateReceived: String
6
+ doNumber: String
7
+ sku: String
8
+ descr: String
9
+ qty: Int
10
+ palletId: String
11
+ mfgDate: String
12
+ expiryDate: String
13
+ remark: String
14
+ }
15
+ `
@@ -6,12 +6,21 @@ import { ShortageReportList } from './shortage-report-list'
6
6
  import { ShortageReport } from './shortage-report-type'
7
7
  import { CustomElcclDispatchReport } from './custom-elccl-fn-dispatch-report'
8
8
  import { CustomElcclDispatchReportList } from './custom-elccl-fn-dispatch-report-list'
9
+ import { AgingReport } from './aging-report'
10
+ import { AgingReportList } from './aging-report-list'
11
+ import { AsnReport } from './asn-report'
12
+ import { AsnReportList } from './asn-report-list'
13
+ import { AdmiralAsnReport } from './admiral-asn-report'
14
+ import { AdmiralAsnReportList } from './admiral-asn-report-list'
9
15
 
10
16
  export const Query = `
11
17
  inboundOrderDetailsReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): InboundOrderDetailsReportList @transaction
12
18
  outboundOrderDetailsReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): OutboundOrderDetailsReportList @transaction
13
19
  shortageReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]):ShortageReportList @transaction
14
20
  customElcclDispatchReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): CustomElcclDispatchReportList @transaction
21
+ agingReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): AgingReportList @transaction
22
+ asnReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): AsnReportList @transaction
23
+ admiralAsnReport(filters: [Filter!], pagination: Pagination, sortings: [Sorting!]): AdmiralAsnReportList @transaction
15
24
  `
16
25
 
17
26
  export const Types = [
@@ -22,5 +31,11 @@ export const Types = [
22
31
  ShortageReport,
23
32
  ShortageReportList,
24
33
  CustomElcclDispatchReport,
25
- CustomElcclDispatchReportList
34
+ CustomElcclDispatchReportList,
35
+ AgingReport,
36
+ AgingReportList,
37
+ AsnReport,
38
+ AsnReportList,
39
+ AdmiralAsnReport,
40
+ AdmiralAsnReportList
26
41
  ]
@@ -1,16 +1,17 @@
1
1
  import Router from 'koa-router'
2
- import { EntityManager, getConnection, getRepository, In, Not, SelectQueryBuilder } from 'typeorm'
3
- import { OrderPackage, ReleaseGood } from '@things-factory/sales-base'
4
- import { Domain } from '@things-factory/shell'
5
- import { processAwbAndTrackingNo } from '@things-factory/worksheet-base'
2
+ import { EntityManager, getConnection, getRepository, SelectQueryBuilder } from 'typeorm'
3
+
4
+ import { Account, AccountingAPI } from '@things-factory/integration-accounting'
5
+ import { MarketplaceStore, StoreAPI } from '@things-factory/integration-marketplace'
6
6
  import {
7
7
  MarketplaceOrder,
8
8
  MarketplaceOrderItem,
9
- MarketplaceOrderShippingItem,
10
- MarketplaceOrderShipping
9
+ MarketplaceOrderShipping,
10
+ MarketplaceOrderShippingItem
11
11
  } from '@things-factory/marketplace-base'
12
-
13
- import { MarketplaceStore, StoreAPI } from '@things-factory/integration-marketplace'
12
+ import { OrderPackage, OrderProduct, ReleaseGood } from '@things-factory/sales-base'
13
+ import { Domain } from '@things-factory/shell'
14
+ import { processAwbAndTrackingNo } from '@things-factory/worksheet-base'
14
15
 
15
16
  const debug = require('debug')('things-factory:integration-accounting:xilnex-router')
16
17
 
@@ -131,6 +132,140 @@ supportRouter.post('/update-magento-tracking-no', async (context, next) => {
131
132
  }
132
133
  })
133
134
 
135
+ supportRouter.post('/create-xilnex-sales-orders', async (context, next) => {
136
+ try {
137
+ let successRecords: { releaseGoodId: string; salesOrder: any }[] = []
138
+ let failRecords: { releaseGoodId: string; error: string }[] = []
139
+
140
+ const { id } = context.query
141
+ const { releaseGoodIds } = context.request.body
142
+
143
+ const account: Account = await getRepository(Account).findOne({ where: { id: id } })
144
+
145
+ const qb: SelectQueryBuilder<ReleaseGood> = getRepository(ReleaseGood)
146
+ .createQueryBuilder('rg')
147
+ .innerJoinAndSelect('rg.orderProducts', 'op')
148
+ .innerJoinAndSelect('op.product', 'p')
149
+ .where('rg.id IN (:...releaseGoodIds)', {
150
+ releaseGoodIds: releaseGoodIds
151
+ })
152
+
153
+ let releaseGoods = await qb.getMany()
154
+
155
+ for (let i = 0; i < releaseGoods.length; i++) {
156
+ let releaseGood = releaseGoods[i]
157
+ let orderProducts = releaseGood.orderProducts
158
+
159
+ delete releaseGood.orderProducts
160
+ try {
161
+ const salesOrder = await AccountingAPI.createSalesOrder(account, { releaseGood, orderProducts })
162
+
163
+ successRecords.push({ releaseGoodId: releaseGood.id, salesOrder: salesOrder })
164
+ } catch (e) {
165
+ failRecords.push({
166
+ releaseGoodId: releaseGood.id,
167
+ error: e
168
+ })
169
+ }
170
+ }
171
+
172
+ context.response.body = {
173
+ success: successRecords,
174
+ fail: failRecords
175
+ }
176
+ } catch (e) {
177
+ console.log(e)
178
+ }
179
+ })
180
+
181
+ supportRouter.post('/post-xilnex-so-to-si', async (context, next) => {
182
+ try {
183
+ let successRecords: { releaseGoodId: string; salesOrderId: string; salesInvoice: any }[] = []
184
+ let failRecords: { releaseGoodId: string; salesOrderId: string; error: string }[] = []
185
+
186
+ const { id } = context.query
187
+ const { data } = context.request.body
188
+
189
+ const account: Account = await getRepository(Account).findOne({ where: { id: id } })
190
+
191
+ if (data.length > 0) {
192
+ for (let i = 0; i < data.length; i++) {
193
+ let item = data[i]
194
+ try {
195
+ const { releaseGoodId, salesOrderId } = item
196
+
197
+ const salesInvoice = await AccountingAPI.postSalesOrderToSalesInvoice(account, { orderId: salesOrderId })
198
+
199
+ let releaseGood
200
+ let updatedOrderProducts
201
+ await getConnection().transaction(async (tx: EntityManager) => {
202
+ const qb: SelectQueryBuilder<ReleaseGood> = tx
203
+ .getRepository(ReleaseGood)
204
+ .createQueryBuilder('rg')
205
+ .innerJoinAndSelect('rg.orderProducts', 'op')
206
+ .innerJoinAndSelect('op.product', 'p')
207
+ .where('rg.id = :releaseGoodId', {
208
+ releaseGoodId: releaseGoodId
209
+ })
210
+
211
+ releaseGood = await qb.getOne()
212
+
213
+ await tx.getRepository(ReleaseGood).update({ id: releaseGood.id }, { refNo3: salesInvoice.sale.id })
214
+
215
+ releaseGood.refNo3 = salesInvoice.sale.id
216
+ let orderProducts = releaseGood.orderProducts
217
+ updatedOrderProducts = await Promise.all(
218
+ orderProducts.map(async op => {
219
+ let foundSalesItem = salesInvoice.sale.items.find(item => item.itemCode == op.product.sku)
220
+
221
+ await tx.getRepository(OrderProduct).update({ id: op.id }, { refItemId: foundSalesItem.id.toString() })
222
+
223
+ return {
224
+ id: op.id,
225
+ refItemId: foundSalesItem.id.toString(),
226
+ releaseQty: op.releaseQty
227
+ }
228
+ })
229
+ )
230
+ })
231
+
232
+ await AccountingAPI.createShipment(account, { releaseGood, orderProducts: updatedOrderProducts })
233
+
234
+ successRecords.push({
235
+ releaseGoodId: releaseGoodId,
236
+ salesOrderId: salesOrderId,
237
+ salesInvoice: {
238
+ salesId: salesInvoice.salesId,
239
+ shippingStatus: salesInvoice.sale.shippingStatus,
240
+ status: salesInvoice.sale.status,
241
+ paymentStatus: salesInvoice.sale.paymentStatus,
242
+ saleItems: salesInvoice.sale.items.map(item => {
243
+ return {
244
+ id: item.id,
245
+ quantity: item.quantity
246
+ }
247
+ })
248
+ }
249
+ })
250
+ } catch (e) {
251
+ failRecords.push({
252
+ releaseGoodId: item.releaseGoodId,
253
+ salesOrderId: item.salesOrderId,
254
+ error: JSON.stringify(e)
255
+ })
256
+ }
257
+ }
258
+ }
259
+
260
+ context.response.body = {
261
+ success: successRecords,
262
+ fail: failRecords
263
+ }
264
+ } catch (e) {
265
+ console.log(e)
266
+ }
267
+ })
268
+
134
269
  async function updateTrackingNo(tx, marketplaceOrder, marketplaceStore, orderPackage) {
135
270
  try {
136
271
  const companyDomain: Domain = marketplaceStore.domain