@things-factory/integration-sftp 8.0.0-beta.0 → 8.0.0-beta.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/integration-sftp",
3
- "version": "8.0.0-beta.0",
3
+ "version": "8.0.0-beta.2",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -24,13 +24,13 @@
24
24
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
25
25
  },
26
26
  "dependencies": {
27
- "@things-factory/auth-base": "^8.0.0-beta.0",
28
- "@things-factory/biz-base": "^8.0.0-beta.0",
29
- "@things-factory/env": "^8.0.0-beta.0",
30
- "@things-factory/integration-fulfillment": "^8.0.0-beta.0",
31
- "@things-factory/shell": "^8.0.0-beta.0",
27
+ "@things-factory/auth-base": "^8.0.0-beta.2",
28
+ "@things-factory/biz-base": "^8.0.0-beta.2",
29
+ "@things-factory/env": "^8.0.0-beta.2",
30
+ "@things-factory/integration-fulfillment": "^8.0.0-beta.2",
31
+ "@things-factory/shell": "^8.0.0-beta.2",
32
32
  "aws-sdk": "^2.960.0",
33
33
  "xml-js": "^1.6.11"
34
34
  },
35
- "gitHead": "add6fb8224b2cb19cbea47bed6a5ecb0424c9a28"
35
+ "gitHead": "f03431a09435511b2595515658f9cb8f78ba4ebb"
36
36
  }
@@ -1,51 +0,0 @@
1
- import { BACKUPPATH, SNSUBMITDATAPATH } from '../../../sftp-const'
2
-
3
- export function createSerialNumber() {
4
- return {
5
- method: 'post',
6
- path: '{folderPath}/{folderType}{snPath}',
7
- denormalize(req) {
8
- let { releaseGood, inventoryItems, sftp } = req
9
- let { folderPath, platform } = sftp
10
- const folderType: string = sftp.isDevelopment ? `dev` : `prd`
11
- const snPath: string = SNSUBMITDATAPATH
12
- const backupPath: string = `${BACKUPPATH}${platform}/${folderType}`
13
-
14
- let responseFilePattern: any = JSON.parse(sftp.responseFilePattern)
15
- const { snSuffix, fileExtension, snRunningNumberDigit, snSequence } = responseFilePattern
16
- let newSeq: number = parseFloat(snSequence) + 1
17
- let newSequence = newSeq.toString().padStart(snRunningNumberDigit, '0')
18
- let newResponseFilePattern: string = JSON.stringify({
19
- ...responseFilePattern,
20
- snSequence: newSeq.toString()
21
- })
22
- sftp = { ...sftp, responseFilePattern: newResponseFilePattern }
23
-
24
- const today = new Date()
25
- const year = today.getFullYear().toString()
26
- const month = (today.getMonth() + 1).toString().padStart(2, '0')
27
- const day = today.getDate().toString().padStart(2, '0')
28
- const newDate = day + month + year
29
-
30
- let title: string = snSuffix ? snSuffix : ``
31
- title += `_` + newDate
32
- title += `_` + newSequence
33
- title += fileExtension ? `.` + fileExtension : ``
34
-
35
- let content: string = ''
36
- const orderNo: string = releaseGood.refNo
37
- for (let i = 0; i < inventoryItems.length; i++) {
38
- let serialNumber: string = inventoryItems[i].serialNumber
39
- content += orderNo + '|' + serialNumber + '\n'
40
- }
41
-
42
- return {
43
- resource: { folderPath, folderType, snPath },
44
- payload: { title, content, sftp, backupPath }
45
- }
46
- },
47
- normalize(res) {
48
- return res
49
- }
50
- }
51
- }
@@ -1,88 +0,0 @@
1
- import { BACKUPPATH, COMPLETEDATAPATH } from '../../../sftp-const'
2
-
3
- export function createShipment() {
4
- return {
5
- method: 'post',
6
- path: '{folderPath}/{folderType}{shipmentCompletePath}',
7
- denormalize(req) {
8
- let { releaseGoods, sftp } = req
9
- let { folderPath, platform } = sftp
10
- const folderType: string = sftp.isDevelopment ? `dev` : `prd`
11
- const shipmentCompletePath: string = COMPLETEDATAPATH
12
- const backupPath: string = `${BACKUPPATH}${platform}/${folderType}`
13
-
14
- let responseFilePattern: any = JSON.parse(sftp.responseFilePattern)
15
- const { suffix, fileExtension, runningNumberDigit, sequence } = responseFilePattern
16
- let newSeq: number = parseFloat(sequence) + 1
17
- let newSequence = newSeq.toString().padStart(runningNumberDigit, '0')
18
- let newResponseFilePattern: string = JSON.stringify({
19
- ...responseFilePattern,
20
- sequence: newSeq.toString()
21
- })
22
- sftp = { ...sftp, responseFilePattern: newResponseFilePattern }
23
-
24
- const warehouseNumber: string = releaseGoods[0].refNo2
25
- let title: string = suffix ? suffix : ``
26
- title += newSequence
27
- title += warehouseNumber ? `_` + warehouseNumber : ``
28
- title += fileExtension ? `.` + fileExtension : ``
29
-
30
- let backupTitle: string = releaseGoods[0].refNo + '_' + title
31
- const orderNoColumn: number = 15
32
- const shipmentColumn: number = 27
33
- const trackingNoColumn: number = 20
34
- let bulkContent = ''
35
- for (let releaseGood of releaseGoods) {
36
- const refNoLength: number = releaseGood.refNo.length
37
- let content: string = `1710` + releaseGood.refNo
38
- let spaceNeeded: number = orderNoColumn - refNoLength
39
- for (let i = 0; i < spaceNeeded; i++) {
40
- content += ` `
41
- }
42
- content += warehouseNumber
43
- content += `001000001`
44
- for (let i = 0; i < shipmentColumn; i++) {
45
- content += ` `
46
- }
47
- content += `000000 `
48
- for (let i = 0; i < trackingNoColumn; i++) {
49
- content += ` `
50
- }
51
- content += `000000000000 `
52
- const today = new Date()
53
- const year = today.getFullYear().toString()
54
- const month = (today.getMonth() + 1).toString().padStart(2, '0')
55
- const day = today.getDate().toString().padStart(2, '0')
56
- const newDate = year + month + day
57
- content += newDate + '\n'
58
-
59
- for (let i = 0; i < releaseGood.orderInventories.length; i++) {
60
- const orderInventory: any = releaseGood.orderInventories[i]
61
- let sku: string = orderInventory.product.brandSku
62
- content += `1810` + releaseGood.refNo
63
- for (let i = 0; i < spaceNeeded; i++) {
64
- content += ` `
65
- }
66
- const idx = (i + 1).toString().padStart(2, '0')
67
- const productCode: string = sku.substring(0, 4)
68
- content += idx + `000000` + productCode
69
- let productCodeSpaceNeeded = 7 - productCode.length
70
- for (let i = 0; i < productCodeSpaceNeeded; i++) {
71
- content += ` `
72
- }
73
- const orderedQty = orderInventory.releaseQty.toString().padStart(4, '0')
74
- const pickedQty = orderInventory.pickedQty.toString().padStart(4, '0')
75
- content += orderedQty + pickedQty + '\n'
76
- }
77
- bulkContent += content
78
- }
79
- return {
80
- resource: { folderPath, folderType, shipmentCompletePath },
81
- payload: { title, backupTitle, content: bulkContent, sftp, backupPath }
82
- }
83
- },
84
- normalize(res) {
85
- return res
86
- }
87
- }
88
- }
@@ -1,14 +0,0 @@
1
- export function echo() {
2
- return {
3
- path: '/echo',
4
- denormalize(req) {
5
- return { ...req }
6
- },
7
- normalize(res) {
8
- return { ...res }
9
- },
10
- action({ store, method, path, request, platformAction }) {
11
- return { ...request }
12
- }
13
- }
14
- }
@@ -1,119 +0,0 @@
1
- export function getOutboundOrder() {
2
- return {
3
- method: 'get',
4
- path: '{folderPath}/{folderType}/sob/data/{fileKey}',
5
- denormalize(req) {
6
- const { folderPath, folderType, fileKey } = req
7
- return {
8
- resource: { folderPath, folderType, fileKey }
9
- }
10
- },
11
- normalize(res, { sftp }) {
12
- const { Order } = res
13
- let isAccept: boolean = false
14
-
15
- const responseFilePattern = JSON.parse(sftp.responseFilePattern)
16
- const acceptOrderTypes = responseFilePattern.acceptOrderTypes // ['RSO', 'MSO', 'MSBO']
17
- const acceptNTSStatuses = responseFilePattern.acceptNTSStatuses //['', 'BACKORDER']
18
- const acceptWarehouseNumber = responseFilePattern.acceptWarehouseNumber //['NK']
19
- const acceptCommand = responseFilePattern.acceptCommand //['NTS', '']
20
- const acceptFreightCode = responseFilePattern.acceptFreightCode // ['PU']
21
-
22
- let orderHeader: any = Order.OrderHeader
23
- let generalInfo: any = orderHeader.General
24
- let distributorDetails: any = orderHeader.DistributorDetails
25
- let shippingInstructions: any = Order.ShippingInstructions
26
-
27
- let orderType: string = generalInfo.OrderType._text
28
- let ntsStatus: string = generalInfo.NTSStatus._text || ''
29
- let command: string = generalInfo.Command._text || ''
30
- let warehouseNumber: string = generalInfo.WarehouseNumber._text
31
- let freightCode: string = shippingInstructions.FreightCode._text
32
-
33
- if (
34
- acceptWarehouseNumber.includes(warehouseNumber) &&
35
- acceptOrderTypes.includes(orderType) &&
36
- acceptNTSStatuses.includes(ntsStatus) &&
37
- acceptCommand.includes(command) &&
38
- acceptFreightCode.includes(freightCode)
39
- ) {
40
- isAccept = true
41
- }
42
-
43
- let shippingInstruction: string = shippingInstructions.ShippingInstructions._text
44
- let ntsDateParts = generalInfo.NTS_Date._text.split('/')
45
- let releaseDate: string = ntsDateParts[2] + '-' + ntsDateParts[1] + '-' + ntsDateParts[0]
46
- let orderInfo: any = {
47
- refNo: generalInfo.OrderNumber._text,
48
- refNo2: warehouseNumber,
49
- type: 'b2b',
50
- releaseDate,
51
- collectionOrderNo: generalInfo.OrderNumber._text,
52
- marketplaceOrderStatus: ntsStatus,
53
- ownTransport: true,
54
- exportOption: false,
55
- packingOption: false,
56
- remark: shippingInstruction,
57
- billTo: {
58
- billingAddress: distributorDetails.BillTo.BillToAddress._text
59
- },
60
- deliverTo: {
61
- deliveryAddress1: distributorDetails.ShipTo.Address1._text,
62
- deliveryAddress2: distributorDetails.ShipTo.Address2._text,
63
- deliveryAddress3: distributorDetails.ShipTo.Address3._text,
64
- attentionTo: distributorDetails.ShipTo.Name._text,
65
- city: distributorDetails.ShipTo.City._text,
66
- state: distributorDetails.ShipTo.ShipToState._text,
67
- postalCode: distributorDetails.ShipTo.Zipcode._text,
68
- country: distributorDetails.ShipTo.Country._text,
69
- phone1: distributorDetails.ShipTo.Phone._text
70
- }
71
- }
72
-
73
- let OrderLine = Order.PickList
74
- let totalItems: number = parseFloat(Order.PickList.LinesInPickList._text)
75
- let itemsToPick: any[] = []
76
- let checkDuplicationValidation
77
- if (totalItems == 1) {
78
- if (parseFloat(OrderLine.Item.QuantityReleased._text) > 0) {
79
- itemsToPick.push({
80
- product: {
81
- sku: OrderLine.Item.StockingSKU._text
82
- },
83
- releaseQty: parseFloat(OrderLine.Item.QuantityReleased._text)
84
- })
85
- }
86
- } else {
87
- OrderLine.Item.map(line => {
88
- if (parseFloat(line.QuantityReleased._text) > 0) {
89
- itemsToPick.push({
90
- product: {
91
- sku: line.StockingSKU._text
92
- },
93
- releaseQty: parseFloat(line.QuantityReleased._text)
94
- })
95
- }
96
- })
97
- }
98
-
99
- if (ntsStatus == 'BACKORDER' && OrderLine.Item.some(itm => itm.QuantityReleased._text == 0)) {
100
- checkDuplicationValidation = false
101
- }
102
-
103
- if (itemsToPick.length == 0) {
104
- isAccept = false
105
- }
106
-
107
- let orderItems: any[] = itemsToPick
108
-
109
- let result: any = {
110
- ...orderInfo,
111
- orderInventories: orderItems,
112
- isAccept,
113
- checkDuplicationValidation
114
- }
115
-
116
- return result
117
- }
118
- }
119
- }
@@ -1,4 +0,0 @@
1
- export * from './echo'
2
- export * from './get-outbound-order'
3
- export * from './create-shipment'
4
- export * from './create-serial-number'
@@ -1,53 +0,0 @@
1
- import '../../sftp-s3'
2
-
3
- import { xml2js } from 'xml-js'
4
-
5
- import { Sftp } from '../../service'
6
- import { SFTPFILESTORAGE } from '../../sftp-const'
7
- import { generateFiles } from '../../util/generate-files'
8
-
9
- const debug = require('debug')('things-factory:integration-sftp:herbalife')
10
-
11
- export type HerbalifeConfig = {}
12
-
13
- export class Herbalife {
14
- constructor() {}
15
-
16
- async get(path: string, data: any = {}) {
17
- const fileResult: any = await SFTPFILESTORAGE.readFile(path, 'utf-8')
18
- const item: any = xml2js(fileResult, {
19
- compact: true
20
- })
21
- const result: any = { ...item }
22
- return result
23
- }
24
-
25
- async post(path: string, data: any = {}) {
26
- const {
27
- title,
28
- backupTitle,
29
- content,
30
- sftp,
31
- backupPath
32
- }: { title: string; backupTitle: string; content: string; sftp: Sftp; backupPath: string } = data
33
-
34
- let params: any[] = [
35
- {
36
- title,
37
- uploadPath: path,
38
- content
39
- }
40
- ]
41
-
42
- if (backupPath) {
43
- params.push({
44
- title: backupTitle,
45
- uploadPath: backupPath,
46
- content
47
- })
48
- }
49
- await generateFiles(params)
50
-
51
- return sftp
52
- }
53
- }
@@ -1,7 +0,0 @@
1
- import { SftpAPI } from '../sftp-api'
2
- import * as APIS from './apis'
3
- import { action } from './platform-action'
4
-
5
- export * from './herbalife'
6
-
7
- SftpAPI.registerPlatform('herbalife', action, APIS)
@@ -1,34 +0,0 @@
1
- import { Herbalife } from './herbalife'
2
-
3
- function substitute(path, obj) {
4
- var props = []
5
- var re = /{([^}]+)}/g
6
- var text
7
-
8
- while ((text = re.exec(path))) {
9
- props.push(text[1])
10
- }
11
-
12
- var result = path
13
- props.forEach(prop => {
14
- let value = obj[prop.trim()]
15
- result = result.replace(`{${prop}}`, value === undefined ? '' : value)
16
- })
17
-
18
- return result
19
- }
20
-
21
- export const action = async ({ method = 'get', path, request }) => {
22
- const client = new Herbalife()
23
-
24
- const { resource = {}, payload = {} } = request
25
-
26
- path = substitute(path, resource)
27
-
28
- var response = await client[method](path, payload)
29
- if (response.errors) {
30
- throw response
31
- }
32
-
33
- return response
34
- }
@@ -1,3 +0,0 @@
1
- import './herbalife'
2
-
3
- export * from './sftp-api'
@@ -1,43 +0,0 @@
1
- import Debug from 'debug'
2
-
3
- import { Sftp } from '../../service'
4
-
5
- const debug = Debug('things-factory:integration-sftp:sftp-api-decorator')
6
-
7
- const NOOP = v => v
8
-
9
- export const api = (target: Object, property: string, descriptor: TypedPropertyDescriptor<any>): any => {
10
- const method = descriptor.value
11
-
12
- descriptor.value = async function (sftp: Sftp, request) {
13
- const SftpAPI = this
14
-
15
- var { platform } = sftp
16
-
17
- var { action: platformAction, apis } = SftpAPI.getPlatform(platform)
18
-
19
- var m = apis[method.name]
20
- if (!m) {
21
- throw Error(`SFTP doesn't have API ${method.name}`)
22
- }
23
-
24
- var {
25
- path,
26
- method: httpMethod = 'post',
27
- denormalize = NOOP,
28
- normalize = NOOP,
29
- action = platformAction
30
- } = m.apply(this, [request])
31
-
32
- var denormalized = await denormalize(request || {}, { sftp })
33
- debug('request', denormalized)
34
-
35
- var response = await action.apply(this, [{ sftp, method: httpMethod, path, request: denormalized, platformAction }])
36
-
37
- debug('response', response)
38
-
39
- return await normalize(response, { sftp })
40
- }
41
-
42
- return descriptor
43
- }
@@ -1,39 +0,0 @@
1
- import { getRepository } from '@things-factory/shell'
2
-
3
- import { Sftp } from '../../service'
4
- import { api } from './decorators'
5
-
6
- export class SftpAPI {
7
- static platforms = {}
8
-
9
- static registerPlatform(name, action, apis) {
10
- SftpAPI.platforms[name] = {
11
- action,
12
- apis
13
- }
14
- }
15
-
16
- static getPlatform(name) {
17
- return SftpAPI.platforms[name]
18
- }
19
-
20
- static async getSftp(id) {
21
- const repository = getRepository(Sftp)
22
- return await repository.findOne({
23
- where: { id },
24
- relations: ['domain']
25
- })
26
- }
27
-
28
- @api
29
- static echo(sftp, req): any {}
30
-
31
- @api
32
- static getOutboundOrder(sftp, req): any {}
33
-
34
- @api
35
- static createShipment(sftp, req): any {}
36
-
37
- @api
38
- static createSerialNumber(sftp, req): any {}
39
- }
File without changes
package/server/index.ts DELETED
@@ -1,7 +0,0 @@
1
- import './routes'
2
-
3
- export * from './middlewares'
4
- export * from './service'
5
- export * from './sftp-const'
6
- export * from './controllers'
7
- export * from './util'
@@ -1,3 +0,0 @@
1
- export function initMiddlewares(app) {
2
- /* can add middlewares into app */
3
- }
package/server/routes.ts DELETED
@@ -1,28 +0,0 @@
1
- const debug = require('debug')('things-factory:integration-sftp:routes')
2
-
3
- process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
4
- /*
5
- * can add global public routes to application (auth not required, tenancy not required)
6
- *
7
- * ex) routes.get('/path', async(context, next) => {})
8
- * ex) routes.post('/path', async(context, next) => {})
9
- */
10
- })
11
-
12
- process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
13
- /*
14
- * can add global private routes to application (auth required, tenancy not required)
15
- */
16
- })
17
-
18
- process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
19
- /*
20
- * can add domain public routes to application (auth not required, tenancy required)
21
- */
22
- })
23
-
24
- process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
25
- /*
26
- * can add domain private routes to application (auth required, tenancy required)
27
- */
28
- })
@@ -1,18 +0,0 @@
1
- /* EXPORT ENTITY TYPES */
2
- export * from './sftp/sftp'
3
-
4
- /* IMPORT ENTITIES AND RESOLVERS */
5
- import { entities as SftpEntities, resolvers as SftpResolvers } from './sftp'
6
-
7
- export const entities = [
8
- /* ENTITIES */
9
- ...SftpEntities,
10
- ]
11
-
12
-
13
- export const schema = {
14
- resolverClasses: [
15
- /* RESOLVER CLASSES */
16
- ...SftpResolvers,
17
- ]
18
- }
@@ -1,6 +0,0 @@
1
- import { Sftp } from './sftp'
2
- import { SftpQuery } from './sftp-query'
3
- import { SftpMutation } from './sftp-mutation'
4
-
5
- export const entities = [Sftp]
6
- export const resolvers = [SftpQuery, SftpMutation]
@@ -1,241 +0,0 @@
1
- import '../../sftp-s3'
2
-
3
- import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
4
- import { EntityManager, getConnection, In } from 'typeorm'
5
-
6
- import { Bizplace } from '@things-factory/biz-base'
7
- import { FulfillmentAPI, FulfillmentCenter } from '@things-factory/integration-fulfillment'
8
- import { Domain } from '@things-factory/shell'
9
-
10
- import { SftpAPI } from '../../controllers'
11
- import { FAILEDDATAPATH, SFTPFILESTORAGE, SUBMITDATAPATH, SUCCESSDATAPATH } from '../../sftp-const'
12
- import { getPermittedDirectories } from '../../util'
13
- import { Sftp, SftpStatus } from './sftp'
14
- import { NewSftp, SftpPatch } from './sftp-type'
15
-
16
- @Resolver(Sftp)
17
- export class SftpMutation {
18
- @Directive('@transaction')
19
- @Mutation(returns => Sftp, { description: 'To create new Sftp' })
20
- async createSftp(@Arg('sftp') sftp: NewSftp, @Ctx() context: ResolverContext): Promise<Sftp> {
21
- const { domain, user, tx } = context.state
22
-
23
- return await tx.getRepository(Sftp).save({
24
- ...sftp,
25
- domain,
26
- creator: user,
27
- updater: user
28
- })
29
- }
30
-
31
- @Directive('@transaction')
32
- @Mutation(returns => Sftp, { description: 'To modify Sftp information' })
33
- async updateSftp(
34
- @Arg('id') id: string,
35
- @Arg('patch') patch: SftpPatch,
36
- @Ctx() context: ResolverContext
37
- ): Promise<Sftp> {
38
- const { domain, user, tx } = context.state
39
-
40
- const repository = tx.getRepository(Sftp)
41
- const sftp = await repository.findOne({
42
- where: { domain: { id: domain.id }, id }
43
- })
44
-
45
- return await repository.save({
46
- ...sftp,
47
- ...patch,
48
- updater: user
49
- })
50
- }
51
-
52
- @Directive('@transaction')
53
- @Mutation(returns => [Sftp], { description: "To modify multiple Sftps' information" })
54
- async updateMultipleSftp(
55
- @Arg('patches', type => [SftpPatch]) patches: SftpPatch[],
56
- @Ctx() context: ResolverContext
57
- ): Promise<Sftp[]> {
58
- const { domain, user, tx } = context.state
59
-
60
- let results = []
61
- const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
62
- const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
63
- const sftpRepo = tx.getRepository(Sftp)
64
-
65
- if (_createRecords.length > 0) {
66
- for (let i = 0; i < _createRecords.length; i++) {
67
- const newRecord = _createRecords[i]
68
-
69
- const result = await sftpRepo.save({
70
- ...newRecord,
71
- domain,
72
- creator: user,
73
- updater: user
74
- })
75
-
76
- results.push({ ...result, cuFlag: '+' })
77
- }
78
- }
79
-
80
- if (_updateRecords.length > 0) {
81
- for (let i = 0; i < _updateRecords.length; i++) {
82
- const newRecord = _updateRecords[i]
83
- const sftp = await sftpRepo.findOneBy({ id: newRecord.id })
84
-
85
- const result = await sftpRepo.save({
86
- ...sftp,
87
- ...newRecord,
88
- updater: user
89
- })
90
-
91
- results.push({ ...result, cuFlag: 'M' })
92
- }
93
- }
94
-
95
- return results
96
- }
97
-
98
- @Directive('@transaction')
99
- @Mutation(returns => Boolean, { description: 'To delete Sftp' })
100
- async deleteSftp(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
101
- const { domain, tx } = context.state
102
-
103
- await tx.getRepository(Sftp).delete({ domain: { id: domain.id }, id })
104
- return true
105
- }
106
-
107
- @Directive('@transaction')
108
- @Mutation(returns => Boolean, { description: 'To delete multiple sftps' })
109
- async deleteSftps(@Arg('ids', type => [String]) ids: string[], @Ctx() context: ResolverContext): Promise<boolean> {
110
- const { domain, tx } = context.state
111
-
112
- await tx.getRepository(Sftp).delete({
113
- domain: { id: domain.id },
114
- id: In(ids)
115
- })
116
-
117
- return true
118
- }
119
-
120
- @Mutation(returns => Boolean, { description: 'To sync all orders from sftp' })
121
- async syncSftpOrders(
122
- @Arg('customerDomainId', type => String) customerDomainId: string,
123
- @Ctx() context: ResolverContext
124
- ): Promise<boolean> {
125
- await getConnection().transaction(async (tx: EntityManager) => {
126
- const customerDomain: Domain = await tx.getRepository(Domain).findOneBy({ id: customerDomainId })
127
-
128
- const customerBizplace: Bizplace = await getCustomerBizplace(customerDomainId, tx)
129
-
130
- const sftpUsers: Sftp[] = await tx.getRepository(Sftp).find({
131
- where: { domain: { id: customerDomainId }, status: SftpStatus.ACTIVE },
132
- relations: ['fulfillmentCenter']
133
- })
134
-
135
- for (var i = 0; i < sftpUsers.length; i++) {
136
- const sftpUser: Sftp = sftpUsers[i]
137
- processSftp(sftpUser, context, customerBizplace.id)
138
- }
139
- })
140
-
141
- return true
142
- }
143
-
144
- @Directive('@transaction')
145
- @Mutation(returns => Boolean, { description: 'Calls syncSftpOrders for all domain Ids' })
146
- async syncAllSftpOrders(@Ctx() context: ResolverContext): Promise<Boolean> {
147
- try {
148
- await getConnection().transaction(async tx => {
149
- const sftps = await tx
150
- .getRepository(Sftp)
151
- .createQueryBuilder('s')
152
- .where('s.status = :status', { status: 'ACTIVE' })
153
- .getMany()
154
-
155
- if (sftps.length === 0) return
156
- for (const sftp of sftps) {
157
- const customerBizplace = await getCustomerBizplace(sftp.domainId, tx)
158
- await processSftp(sftp, context, customerBizplace.id)
159
- }
160
- })
161
- } catch (e) {
162
- console.log(e)
163
- }
164
- return true
165
- }
166
- }
167
-
168
- export async function processSftp(sftpUser, context, customerBizplaceId) {
169
- const fulfilmentCenter: FulfillmentCenter = sftpUser.fulfillmentCenter
170
- const isDevelopment: boolean = sftpUser.isDevelopment
171
- const folderPath: string = sftpUser.folderPath
172
- const folderType: string = isDevelopment ? 'dev' : 'prd'
173
- let initialDataPath: string = `${sftpUser.folderPath}/${folderType}${SUBMITDATAPATH}/`
174
- const results: any[] = await getPermittedDirectories({ path: initialDataPath }, context)
175
- const filesDirectories: any[] = results.filter(result => result.Size > 0)
176
-
177
- for await (let fileDirectory of filesDirectories) {
178
- let dataPath: string = `${sftpUser.folderPath}/${folderType}${SUBMITDATAPATH}/`
179
- let successPath: string = `${sftpUser.folderPath}/${folderType}${SUCCESSDATAPATH}/`
180
- let failedPath: string = `${sftpUser.folderPath}/${folderType}${FAILEDDATAPATH}/`
181
- const fileKey: string = fileDirectory.Key
182
- const lastSlashIdx = fileKey.lastIndexOf('/')
183
- const fileString: string = fileKey.substring(lastSlashIdx + 1, fileKey.length)
184
- try {
185
- const sftp: any = sftpUser
186
- let result: any = await SftpAPI.getOutboundOrder(sftp, { folderPath, folderType, fileKey: fileString })
187
- let isAccept: boolean = result.isAccept
188
-
189
- if (isAccept) {
190
- delete result.isAccept
191
- if (result) {
192
- let { items: releaseOrders }: any = await FulfillmentAPI.getOutboundOrders(fulfilmentCenter, {
193
- customerBizplaceId,
194
- refNo: result.refNo
195
- })
196
-
197
- if (releaseOrders) {
198
- result.collectionOrderNo = result.collectionOrderNo + ' - ' + (releaseOrders.length + 1)
199
- }
200
-
201
- result.requiredDraft = false
202
-
203
- const releaseOrder: any = await FulfillmentAPI.createOutboundOrder(fulfilmentCenter, {
204
- customerBizplaceId,
205
- releaseOrder: result
206
- })
207
-
208
- if (releaseOrder) {
209
- let movePaths = {
210
- source: (dataPath += fileString),
211
- destination: (successPath += fileString)
212
- }
213
- await SFTPFILESTORAGE.moveFile(movePaths)
214
- }
215
- }
216
- } else {
217
- let movePaths = {
218
- source: (dataPath += fileString),
219
- destination: (failedPath += fileString)
220
- }
221
- await SFTPFILESTORAGE.moveFile(movePaths)
222
- }
223
- } catch (e) {
224
- let movePaths = {
225
- source: (dataPath += fileString),
226
- destination: (failedPath += fileString)
227
- }
228
- await SFTPFILESTORAGE.moveFile(movePaths)
229
- }
230
- }
231
- }
232
-
233
- export async function getCustomerBizplace(customerDomainId, tx): Promise<Bizplace> {
234
- const customerDomain: Domain = await tx.getRepository(Domain).findOneBy({ id: customerDomainId })
235
-
236
- const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
237
- where: { domain: { id: customerDomain.id } }
238
- })
239
-
240
- return customerBizplace
241
- }
@@ -1,44 +0,0 @@
1
- import { Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
-
3
- import { User } from '@things-factory/auth-base'
4
- import { convertListParams, Domain, getRepository, ListParam } from '@things-factory/shell'
5
-
6
- import { Sftp } from './sftp'
7
- import { SftpList } from './sftp-type'
8
-
9
- @Resolver(Sftp)
10
- export class SftpQuery {
11
- @Query(returns => Sftp, { description: 'To fetch a Sftp' })
12
- async sftp(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Sftp> {
13
- const { domain } = context.state
14
-
15
- return await getRepository(Sftp).findOne({
16
- where: { domain: { id: domain.id }, id }
17
- })
18
- }
19
-
20
- @Query(returns => SftpList, { description: 'To fetch multiple Sftps' })
21
- async sftps(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<SftpList> {
22
- const { domain } = context.state
23
-
24
- const convertedParams = convertListParams(params, { domain })
25
- const [items, total] = await getRepository(Sftp).findAndCount(convertedParams)
26
-
27
- return { items, total }
28
- }
29
-
30
- @FieldResolver(type => Domain)
31
- async domain(@Root() sftp: Sftp): Promise<Domain> {
32
- return await getRepository(Domain).findOneBy({ id: sftp.domainId })
33
- }
34
-
35
- @FieldResolver(type => User)
36
- async updater(@Root() sftp: Sftp): Promise<User> {
37
- return await getRepository(User).findOneBy({ id: sftp.updaterId })
38
- }
39
-
40
- @FieldResolver(type => User)
41
- async creator(@Root() sftp: Sftp): Promise<User> {
42
- return await getRepository(User).findOneBy({ id: sftp.creatorId })
43
- }
44
- }
@@ -1,78 +0,0 @@
1
- import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
2
-
3
- import { Sftp, SftpStatus } from './sftp'
4
-
5
- @InputType()
6
- export class NewSftp {
7
- @Field()
8
- name: string
9
-
10
- @Field({ nullable: true })
11
- description?: string
12
-
13
- @Field(type => SftpStatus, { nullable: true })
14
- status?: SftpStatus
15
-
16
- @Field({ nullable: true })
17
- username?: string
18
-
19
- @Field({ nullable: true })
20
- publicKey?: string
21
-
22
- @Field({ nullable: true })
23
- privateKey?: string
24
-
25
- @Field({ nullable: true })
26
- folderPath?: string
27
-
28
- @Field({ nullable: true })
29
- isDevelopment?: boolean
30
-
31
- @Field({ nullable: true })
32
- platform?: string
33
- }
34
-
35
- @InputType()
36
- export class SftpPatch {
37
- @Field(type => ID, { nullable: true })
38
- id?: string
39
-
40
- @Field({ nullable: true })
41
- name?: string
42
-
43
- @Field({ nullable: true })
44
- description?: string
45
-
46
- @Field(type => SftpStatus, { nullable: true })
47
- status?: SftpStatus
48
-
49
- @Field({ nullable: true })
50
- username?: string
51
-
52
- @Field({ nullable: true })
53
- publicKey?: string
54
-
55
- @Field({ nullable: true })
56
- privateKey?: string
57
-
58
- @Field({ nullable: true })
59
- folderPath?: string
60
-
61
- @Field({ nullable: true })
62
- isDevelopment?: boolean
63
-
64
- @Field({ nullable: true })
65
- platform?: string
66
-
67
- @Field()
68
- cuFlag: string
69
- }
70
-
71
- @ObjectType()
72
- export class SftpList {
73
- @Field(type => [Sftp])
74
- items: Sftp[]
75
-
76
- @Field(type => Int)
77
- total: number
78
- }
@@ -1,143 +0,0 @@
1
- import { Field, ID, ObjectType, registerEnumType } from 'type-graphql'
2
- import {
3
- Column,
4
- CreateDateColumn,
5
- Entity,
6
- Index,
7
- ManyToOne,
8
- PrimaryGeneratedColumn,
9
- RelationId,
10
- UpdateDateColumn
11
- } from 'typeorm'
12
-
13
- import { User } from '@things-factory/auth-base'
14
- import { FulfillmentCenter } from '@things-factory/integration-fulfillment'
15
- import { Domain } from '@things-factory/shell'
16
-
17
- export enum SftpStatus {
18
- ACTIVE = 'ACTIVE',
19
- INACTIVE = 'INACTIVE',
20
- TERMINATED = 'TERMINATED'
21
- }
22
-
23
- registerEnumType(SftpStatus, {
24
- name: 'SftpStatus',
25
- description: 'state enumeration of a sftp'
26
- })
27
-
28
- @Entity()
29
- @Index('ix_sftp_0', (sftp: Sftp) => [sftp.domain, sftp.name], { unique: true })
30
- @ObjectType({ description: 'Entity for Sftp' })
31
- export class Sftp {
32
- @PrimaryGeneratedColumn('uuid')
33
- @Field(type => ID)
34
- readonly id: string
35
-
36
- @ManyToOne(type => Domain)
37
- @Field(type => Domain)
38
- domain?: Domain
39
-
40
- @RelationId((sftp: Sftp) => sftp.domain)
41
- domainId?: string
42
-
43
- @Column()
44
- @Field()
45
- name: string
46
-
47
- @Column({
48
- nullable: true
49
- })
50
- @Field({ nullable: true })
51
- description?: string
52
-
53
- @Column({ nullable: true })
54
- @Field({ nullable: true })
55
- status?: SftpStatus
56
-
57
- @Column({
58
- nullable: true
59
- })
60
- @Field({ nullable: true })
61
- username?: string
62
-
63
- @Column({
64
- nullable: true
65
- })
66
- @Field({ nullable: true })
67
- publicKey?: string
68
-
69
- @Column({
70
- nullable: true
71
- })
72
- @Field({ nullable: true })
73
- privateKey?: string
74
-
75
- @Column({
76
- nullable: true
77
- })
78
- @Field({ nullable: true })
79
- folderPath?: string
80
-
81
- @Column({
82
- nullable: true
83
- })
84
- @Field({ nullable: true })
85
- isDevelopment?: boolean
86
-
87
- @Column({
88
- nullable: true
89
- })
90
- @Field({ nullable: true })
91
- platform?: string
92
-
93
- @ManyToOne(type => FulfillmentCenter, { nullable: true })
94
- fulfillmentCenter: FulfillmentCenter
95
-
96
- @Column({
97
- nullable: true
98
- })
99
- @Field({ nullable: true })
100
- responseType: string
101
-
102
- @Column({
103
- nullable: true
104
- })
105
- @Field({ nullable: true })
106
- responseFilePattern: string
107
-
108
- @Column({
109
- nullable: true
110
- })
111
- @Field({ nullable: true })
112
- responseFileTypes: string
113
-
114
- @Column({ nullable: true })
115
- @Field({ nullable: true })
116
- lastTimeSync?: Date
117
-
118
- @CreateDateColumn()
119
- @Field({ nullable: true })
120
- createdAt?: Date
121
-
122
- @UpdateDateColumn()
123
- @Field({ nullable: true })
124
- updatedAt?: Date
125
-
126
- @ManyToOne(type => User, {
127
- nullable: true
128
- })
129
- @Field(type => User, { nullable: true })
130
- creator?: User
131
-
132
- @RelationId((sftp: Sftp) => sftp.creator)
133
- creatorId?: string
134
-
135
- @ManyToOne(type => User, {
136
- nullable: true
137
- })
138
- @Field(type => User, { nullable: true })
139
- updater?: User
140
-
141
- @RelationId((sftp: Sftp) => sftp.updater)
142
- updaterId?: string
143
- }
@@ -1,13 +0,0 @@
1
- import { config } from '@things-factory/env'
2
-
3
- export var SFTPFILESTORAGE: any = config.get('sftpFileStorage')
4
- export var SUBMITDATAPATH: string = '/sob/data'
5
- export var SUCCESSDATAPATH: string = '/sob/success'
6
- export var FAILEDDATAPATH: string = '/sob/failed'
7
- export var COMPLETEDATAPATH: string = '/oc/data01'
8
- export var COMPLETESUCCESSDATAPATH: string = '/oc/success'
9
- export var COMPLETEFAILEDDATAPATH: string = '/oc/failed'
10
- export var SNSUBMITDATAPATH: string = '/sn/data'
11
- export var SNSUCCESSDATAPATH: string = '/sn/success'
12
- export var SNFAILEDDATAPATH: string = '/sn/failed'
13
- export var BACKUPPATH: string = 'hatiosea/'
package/server/sftp-s3.ts DELETED
@@ -1,92 +0,0 @@
1
- import AWS from 'aws-sdk'
2
-
3
- import { logger } from '@things-factory/env'
4
-
5
- import { SFTPFILESTORAGE } from './sftp-const'
6
-
7
- const crypto = require('crypto')
8
-
9
- const { PassThrough } = require('stream')
10
-
11
- if (SFTPFILESTORAGE && SFTPFILESTORAGE.type == 's3') {
12
- const S3 = new AWS.S3({
13
- accessKeyId: SFTPFILESTORAGE.accessKeyId,
14
- secretAccessKey: SFTPFILESTORAGE.secretAccessKey
15
- })
16
-
17
- SFTPFILESTORAGE.readFolders = async (params, encoding) => {
18
- let S3params = {
19
- Bucket: SFTPFILESTORAGE.bucketName,
20
- Delimiter: '/',
21
- Prefix: params.path
22
- }
23
-
24
- const result = await S3.listObjects(S3params).promise()
25
-
26
- let body = result.Contents
27
-
28
- return body
29
- }
30
-
31
- SFTPFILESTORAGE.readFile = async (path, encoding) => {
32
- const result = await S3.getObject({
33
- Bucket: SFTPFILESTORAGE.bucketName,
34
- Key: path
35
- }).promise()
36
-
37
- var body = result.Body
38
-
39
- if (encoding) {
40
- return body.toString(encoding)
41
- }
42
-
43
- return body
44
- }
45
-
46
- SFTPFILESTORAGE.moveFile = async (path, encoding) => {
47
- const copyResult = await S3.copyObject({
48
- Bucket: SFTPFILESTORAGE.bucketName,
49
- CopySource: SFTPFILESTORAGE.bucketName + '/' + path.source,
50
- Key: path.destination
51
- }).promise()
52
-
53
- const copyBody = copyResult.CopyObjectResult
54
-
55
- const deleteResult = await S3.deleteObject({
56
- Bucket: SFTPFILESTORAGE.bucketName,
57
- Key: path.source
58
- }).promise()
59
-
60
- return true
61
- }
62
-
63
- /* upload file */
64
- SFTPFILESTORAGE.uploadFile = ({ stream, filename, uploadPath }) => {
65
- const id = crypto.randomUUID()
66
- let size: number = 0
67
-
68
- return new Promise<{ id: string; path: string; size: number }>((resolve, reject) =>
69
- stream
70
- .pipe(
71
- (() => {
72
- var pass = new PassThrough()
73
-
74
- S3.upload(
75
- {
76
- Bucket: SFTPFILESTORAGE.bucketName,
77
- Key: uploadPath + '/' + filename,
78
- Body: pass
79
- },
80
- (err, data) => (err ? reject(err) : resolve({ id, path: uploadPath, size }))
81
- )
82
-
83
- return pass
84
- })()
85
- )
86
- .on('error', error => reject(error))
87
- .on('data', chunk => (size += chunk.length))
88
- )
89
- }
90
-
91
- logger.info('S3 Bucket Storage is Ready.')
92
- }
@@ -1,33 +0,0 @@
1
- import '../sftp-s3'
2
-
3
- import { SFTPFILESTORAGE } from '../sftp-const'
4
-
5
- const fs = require('fs')
6
-
7
- export async function generateFiles(params: any[]) {
8
- const fileDirectory = './uploaded-files'
9
- for (let i = 0; i < params.length; i++) {
10
- let param: any = params[i]
11
- const { uploadPath, content, title } = param
12
-
13
- if (!fs.existsSync(fileDirectory)) {
14
- fs.mkdirSync(fileDirectory)
15
- }
16
-
17
- const filePath = fileDirectory + '/' + title
18
-
19
- fs.writeFile(filePath, content, function (err) {
20
- if (err) throw err
21
- console.log('File is created successfully.')
22
- })
23
-
24
- if (uploadPath) {
25
- const stream = fs.createReadStream(filePath)
26
- await SFTPFILESTORAGE.uploadFile({ stream, filename: title, uploadPath })
27
- }
28
- }
29
-
30
- fs.rm(fileDirectory, { recursive: true })
31
-
32
- return true
33
- }
@@ -1,15 +0,0 @@
1
- import '../sftp-s3'
2
-
3
- import { SFTPFILESTORAGE } from '../sftp-const'
4
-
5
- export async function getPermittedDirectories(params: any, context: ResolverContext) {
6
- const sftpDirectories: any[] = await SFTPFILESTORAGE.readFolders(params)
7
-
8
- return sftpDirectories
9
- }
10
-
11
- export async function readFile(fileKey: any) {
12
- const file: any = await SFTPFILESTORAGE.readFile(fileKey, 'utf-8')
13
-
14
- return file
15
- }
@@ -1,2 +0,0 @@
1
- export * from './get-permitted-directories'
2
- export * from './generate-files'
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../tsconfig-base.json",
3
- "compilerOptions": {
4
- "outDir": "./dist-server",
5
- "baseUrl": "./"
6
- },
7
- "include": ["./server/**/*"],
8
- "exclude": ["**/*.spec.ts"]
9
- }