diff --git a/package-lock.json b/package-lock.json index de6b3c15ae113565ae660a059b39753df9dec805..dd806c8e2b7b1a4d99d33a404c246c8f86bb21a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,10 @@ "dependencies": { "@prisma/client": "^5.5.2", "@types/express": "^4.17.20", + "axios": "^1.6.2", "cors": "^2.8.5", - "express": "^4.18.2" + "express": "^4.18.2", + "xml-js": "^1.6.11" }, "devDependencies": { "@types/cors": "^2.8.16", @@ -274,6 +276,21 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -382,6 +399,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -459,6 +487,14 @@ "node": ">= 0.4" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -581,6 +617,38 @@ "node": ">= 0.8" } }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1037,6 +1105,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -1115,6 +1188,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -1377,6 +1455,17 @@ "node": ">= 0.8" } }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 0034c3db938190090d8978538fca6d8c6aa33dd6..740886520f02e3d0d43ae70dc7bb4dcba5678eef 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,10 @@ "dependencies": { "@prisma/client": "^5.5.2", "@types/express": "^4.17.20", + "axios": "^1.6.2", "cors": "^2.8.5", - "express": "^4.18.2" + "express": "^4.18.2", + "xml-js": "^1.6.11" }, "devDependencies": { "@types/cors": "^2.8.16", diff --git a/src/handler/soap-caller/DetailPesananSoapCaller.ts b/src/handler/soap-caller/DetailPesananSoapCaller.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3b61c45ab920e10b83533a3f2ca169b00f5ec6a --- /dev/null +++ b/src/handler/soap-caller/DetailPesananSoapCaller.ts @@ -0,0 +1,9 @@ +import { DETAIL_PESANAN_URL, SoapApiCall } from "./SoapCaller"; + +export async function getDetailPesanan(id_pesanan : number) { + const args = { + arg0 : id_pesanan, + }; + + return await SoapApiCall(DETAIL_PESANAN_URL, "getDetailPesanan", args); +} diff --git a/src/handler/soap-caller/PesananSoapCaller.ts b/src/handler/soap-caller/PesananSoapCaller.ts new file mode 100644 index 0000000000000000000000000000000000000000..780c00d73220c9104e1a833dd89182e76698691e --- /dev/null +++ b/src/handler/soap-caller/PesananSoapCaller.ts @@ -0,0 +1,56 @@ +import { PESANAN_URL, SoapApiCall } from "./SoapCaller" + + +export async function getPesananByKurir(id_kurir : number) { + const args = { + arg0 : id_kurir, + }; + + return await SoapApiCall(PESANAN_URL, "getPesananByKurir", args); +} + +export async function getPesananNoKurir() { + return await SoapApiCall(PESANAN_URL, "getPesananNoKurir"); +} + +export async function addPesanan(idPemesan : number, + alamat : string, + nama_penerima : string, + keterangan : string, + harga : string, + biaya_pengiriman : number, + nama_product : string, + quantity : string) { + const args = { + arg0 : idPemesan, + arg1 : alamat, + arg2 : nama_penerima, + arg3 : keterangan, + arg4 : harga, + arg5 : biaya_pengiriman, + arg6 : nama_product, + arg7 : quantity, + }; + + return await SoapApiCall(PESANAN_URL, "addPesanan", args); +} + +export async function ambilPesanan(id_pesanan : number, id_kurir : number) { + const args = { + arg0 : id_pesanan, + arg1 : id_kurir, + }; + + return await SoapApiCall(PESANAN_URL, "ambilPesanan", args); +} + +export async function updatePesanan(id_pesanan : number, id_kurir : number, status : string, keterangan : string) { + const args = { + arg0 : id_pesanan, + arg1 : id_kurir, + arg2 : status, + arg3 : keterangan, + }; + + return await SoapApiCall(PESANAN_URL, "updatePesanan", args); +} diff --git a/src/handler/soap-caller/SoapCaller.ts b/src/handler/soap-caller/SoapCaller.ts new file mode 100644 index 0000000000000000000000000000000000000000..b18eac7e9146000edbbfbd2601cc7be9f5604ace --- /dev/null +++ b/src/handler/soap-caller/SoapCaller.ts @@ -0,0 +1,57 @@ +import axios from "axios"; +import { parseXML } from "../../utils/XMLConverter"; + +export const PESANAN_URL = "http://localhost:6001/ws/pesanan?wsdl"; +export const DETAIL_PESANAN_URL = "http://host.docker.internal:6001/ws/detailPesanan?wsdl"; +const REST_API_KEY = "mZHA8N63GOH88EnQW3hJ6zcJQhzY79WnuM+UnVG/e1k="; + +type Header = { + [key: string]: string | undefined +} + +export async function SoapApiCall(url : string, method : string, params? : Object) { + const headers: Header = { + 'Content-Type': 'text/xml;charset=UTF-8', + SOAPAction: '#POST', + 'api-key': REST_API_KEY + }; + + const XMLRequest = buildXMLRequest(method, params); + console.log("url", url); + console.log("XMLRequest", XMLRequest); + console.log("headers", headers); + + const response = await axios.post(url, XMLRequest, {headers}); + console.log("response", response); + + return parseXML(response.data, method); +} + +function buildXMLRequest(method : string, params? : Object) { + const XMLParams = buildXMLParams(params); + + const XMLRequest = ` + <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> + <Body> + <${method} xmlns="http://ws/"> + ${XMLParams} + </${method}> + </Body> + </Envelope>`; + + return XMLRequest; +} + +function buildXMLParams(params?: Object) { + if (!params) { + return ''; + } + + const XMLParamsBuilder = Object.keys(params).map((key) => { + return `<${key} xmlns="">${params[key as keyof typeof params]}</${key}>`; + }) + + const XMLParams = XMLParamsBuilder.join(''); + + return XMLParams; +} \ No newline at end of file diff --git a/src/utils/XMLConverter.ts b/src/utils/XMLConverter.ts new file mode 100644 index 0000000000000000000000000000000000000000..09e5adbe21ea0dcab0f588deedc3ab5afee426ef --- /dev/null +++ b/src/utils/XMLConverter.ts @@ -0,0 +1,32 @@ +import converter from 'xml-js' + + +export function parseXML(xml: string, method: string) { + const json = JSON.parse(converter.xml2json(xml, { compact: true, spaces: 4 })) + const returnVal = json['S:Envelope']['S:Body']['ns2:' + method + 'Response']['return'] + + if (!returnVal) { + return null + } + + return buildResponseJSON(returnVal) +} + +function buildResponseJSON(json: JSON) { + if (Array.isArray(json)) { + return json.map((item) => flatten(item)) + } + + return flatten(json) +} + +function flatten(json: JSON): JSON { + const response: any = {} + + Object.keys(json).forEach((key) => { + const value = json[key as keyof typeof json] + response[key] = value['_text' as keyof typeof value] + }) + + return response +}