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

Sign up to get free protection for your applications and to get access to all the features.
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
- }