fc-landmark 2.1.3 → 3.0.0

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.
@@ -0,0 +1,179 @@
1
+ import { xml2js } from 'xml-js';
2
+ import Shipment from './shipment';
3
+
4
+ const address = (country: string) => ({
5
+ name: 'Jane Doe',
6
+ attention_name: 'Jane',
7
+ address_line_1: '1 Main St',
8
+ address_line_2: '',
9
+ address_line_3: '',
10
+ city: 'Berlin',
11
+ state: 'BE',
12
+ zip: '10115',
13
+ country,
14
+ phone: 5551234,
15
+ email: 'jane@example.com',
16
+ });
17
+
18
+ const shipmentInput = (pieceOverrides: Record<string, unknown> = {}) => ({
19
+ reference: 'REF-1',
20
+ shipto_address: address('DE'),
21
+ shipfrom_address: address('US'),
22
+ targetToCountry: 'DE',
23
+ _carrierRateObj: { servicecode: 'LGINTSTD' },
24
+ shipment_total_usd: 10,
25
+ currency: 'USD',
26
+ label_format: 'PDF',
27
+ weight_unit: 'LB',
28
+ dimension_unit: 'IN',
29
+ package: { weight: 1, length: 1, width: 1, height: 1 },
30
+ b2b: false,
31
+ pieces: [
32
+ {
33
+ sku: 'SKU-1',
34
+ description: 'T-shirt',
35
+ quantity: 1,
36
+ sale_price: 10,
37
+ hs_code: '610910',
38
+ origin_country_code: 'US',
39
+ weight: 1,
40
+ ...pieceOverrides,
41
+ },
42
+ ],
43
+ });
44
+
45
+ const buildXml = (pieceOverrides?: Record<string, unknown>, dangerousGoodsDetails: unknown = '') =>
46
+ new Shipment().buildShipmentRequest(
47
+ shipmentInput(pieceOverrides),
48
+ dangerousGoodsDetails,
49
+ 'user',
50
+ 'pass',
51
+ true,
52
+ 1766,
53
+ 'EORI',
54
+ 'IOSS',
55
+ '',
56
+ );
57
+
58
+ const itemXml = (xml: string): string => {
59
+ const start = xml.indexOf('<Item>');
60
+ const end = xml.indexOf('</Item>') + '</Item>'.length;
61
+
62
+ return xml.slice(start, end);
63
+ };
64
+
65
+ const itemChildNames = (xml: string): string[] => {
66
+ const parsed = xml2js(itemXml(xml), { compact: false }) as { elements: { elements: { name: string }[] }[] };
67
+
68
+ return parsed.elements[0].elements.map((element) => element.name);
69
+ };
70
+
71
+ const productIdentifiers = (xml: string): Record<string, string> | undefined => {
72
+ const parsed = xml2js(itemXml(xml), { compact: true }) as {
73
+ Item: { ProductIdentifiers?: Record<string, { _text: string }> };
74
+ };
75
+ const identifiers = parsed.Item.ProductIdentifiers;
76
+ if (!identifiers) return undefined;
77
+
78
+ return Object.fromEntries(Object.entries(identifiers).map(([name, value]) => [name, value._text]));
79
+ };
80
+
81
+ const productIdentifierNames = (xml: string): string[] => {
82
+ const parsed = xml2js(itemXml(xml), { compact: false }) as {
83
+ elements: { elements: { name: string; elements?: { name: string }[] }[] }[];
84
+ };
85
+ const block = parsed.elements[0].elements.find((element) => element.name === 'ProductIdentifiers');
86
+
87
+ return (block?.elements ?? []).map((element) => element.name);
88
+ };
89
+
90
+ describe('buildShipmentRequest items', () => {
91
+ it("builds today's item when a piece has no PIDs", () => {
92
+ expect(itemXml(buildXml())).toBe(
93
+ [
94
+ '<Item>',
95
+ ' <Sku>SKU-1</Sku>',
96
+ ' <Description>T-shirt</Description>',
97
+ ' <Quantity>1</Quantity>',
98
+ ' <UnitPrice>10</UnitPrice>',
99
+ ' <HSCode>610910</HSCode>',
100
+ ' <CountryOfOrigin>US</CountryOfOrigin>',
101
+ ' </Item>',
102
+ ].join('\n'),
103
+ );
104
+ });
105
+
106
+ it('writes the PIDs into ProductIdentifiers, in the spec order, after CountryOfOrigin', () => {
107
+ const xml = buildXml({
108
+ merchant_pid: 'MPID-1',
109
+ ns_manufacturer_pid: 'MX-2024-BLK-L',
110
+ std_manufacturer_pid: '8712345678901',
111
+ });
112
+
113
+ expect(productIdentifiers(xml)).toStrictEqual({
114
+ MerchantProductID: 'MPID-1',
115
+ ManufacturerProductID: 'MX-2024-BLK-L',
116
+ HasStandardizedProductID: '1',
117
+ StandardizedProductID: '8712345678901',
118
+ });
119
+ expect(productIdentifierNames(xml)).toEqual([
120
+ 'MerchantProductID',
121
+ 'ManufacturerProductID',
122
+ 'HasStandardizedProductID',
123
+ 'StandardizedProductID',
124
+ ]);
125
+ expect(itemChildNames(xml).slice(-2)).toEqual(['CountryOfOrigin', 'ProductIdentifiers']);
126
+ });
127
+
128
+ it('declares no standardised code for Y081, without a StandardizedProductID', () => {
129
+ const xml = buildXml({ ns_manufacturer_pid: 'MX-1', std_manufacturer_pid: 'Y081' });
130
+
131
+ expect(productIdentifiers(xml)).toStrictEqual({
132
+ ManufacturerProductID: 'MX-1',
133
+ HasStandardizedProductID: '0',
134
+ });
135
+ });
136
+
137
+ it('sends only MerchantProductID when the piece has only a merchant PID', () => {
138
+ expect(productIdentifiers(buildXml({ merchant_pid: 'MPID-1' }))).toStrictEqual({
139
+ MerchantProductID: 'MPID-1',
140
+ });
141
+ });
142
+
143
+ it('sends only ManufacturerProductID when the piece has only an NS PID', () => {
144
+ expect(productIdentifiers(buildXml({ ns_manufacturer_pid: 'MX-1' }))).toStrictEqual({
145
+ ManufacturerProductID: 'MX-1',
146
+ });
147
+ });
148
+
149
+ it('never sends StandardizedProductIDType, whatever the piece type', () => {
150
+ const xml = buildXml({ std_manufacturer_pid: '8712345678901', std_manufacturer_pid_type: 'EAN13' });
151
+
152
+ expect(xml).not.toContain('StandardizedProductIDType');
153
+ expect(productIdentifiers(xml)).toStrictEqual({
154
+ HasStandardizedProductID: '1',
155
+ StandardizedProductID: '8712345678901',
156
+ });
157
+ });
158
+
159
+ it('escapes XML special characters in a PID', () => {
160
+ const xml = buildXml({ ns_manufacturer_pid: 'Model: A&B <X>' });
161
+
162
+ expect(xml).toContain('<ManufacturerProductID>Model: A&amp;B &lt;X&gt;</ManufacturerProductID>');
163
+ expect(productIdentifiers(xml)).toStrictEqual({ ManufacturerProductID: 'Model: A&B <X>' });
164
+ });
165
+
166
+ it('keeps leading zeros', () => {
167
+ expect(productIdentifiers(buildXml({ std_manufacturer_pid: '0012345678905' }))).toStrictEqual({
168
+ HasStandardizedProductID: '1',
169
+ StandardizedProductID: '0012345678905',
170
+ });
171
+ });
172
+
173
+ it('puts ProductIdentifiers before DangerousGoodsInformation', () => {
174
+ const dangerousGoodsDetails = { 'SKU-1': { UNCode: 'UN3481', CategoryCode: 'II', PackingInstructions: 'PI967' } };
175
+ const xml = buildXml({ merchant_pid: 'MPID-1' }, dangerousGoodsDetails);
176
+
177
+ expect(itemChildNames(xml).slice(-2)).toEqual(['ProductIdentifiers', 'DangerousGoodsInformation']);
178
+ });
179
+ });
package/src/shipment.ts CHANGED
@@ -1,193 +1,213 @@
1
- import { FlavorcloudShipmentResponse } from "./types";
2
- import { MyGlobal as app } from './globals';
3
- import { js2xml , xml2json} from 'xml-js';
4
-
5
- export default class Shipment {
6
- constructor() {
7
-
8
- }
9
- getConsignee(shipto_address: any,targetToCountry:any): any {
10
-
11
- const combinedAddress = shipto_address.address_line_1 + shipto_address.address_line_2 + shipto_address.address_line_3;
12
- let consignee: any = {
13
- "Name": shipto_address.name.slice(0, 50) ,
14
- "Attention": shipto_address.attention_name.slice(0, 50) ,
15
- "Address1": combinedAddress.substring(0,60),
16
- "Address2": combinedAddress.substring(61,120),
17
- "Address3": combinedAddress.substring(121,180),
18
- "City": shipto_address.city,
19
- "State": shipto_address.state,
20
- "PostalCode": shipto_address.zip,
21
- "Country": targetToCountry ? targetToCountry : shipto_address.country,
22
- "Phone": shipto_address.phone.toString(),
23
- "Email": shipto_address.email,
24
- "ConsigneeTaxID": shipto_address.federal_tax_id ? shipto_address.federal_tax_id : ""
25
- };
26
- return consignee;
27
- }
28
-
29
- getShipperInfo(shipfrom_address: any,targetFromCountry:any) {
30
- const combinedAddress = shipfrom_address.address_line_1 + shipfrom_address.address_line_2 + shipfrom_address.address_line_3;
31
- let shipper: any = {
32
- "Name": shipfrom_address.name.slice(0, 50) ,
33
- "Attention": shipfrom_address.attention_name.slice(0, 50) ,
34
- "Address1": combinedAddress.substring(0,60),
35
- "Address2": combinedAddress.substring(61,120),
36
- "Address3": combinedAddress.substring(121,180),
37
- "City": shipfrom_address.city,
38
- "State": shipfrom_address.state,
39
- "PostalCode": shipfrom_address.zip,
40
- "Country": targetFromCountry ? targetFromCountry : shipfrom_address.country,
41
- "Phone": shipfrom_address.phone.toString(),
42
- "Email": shipfrom_address.email
43
- };
44
- return shipper;
45
- }
46
-
47
- getVendorInfo(shipfrom_address: any,targetFromCountry:any,eroiNumber:any,iossNumber:any) {
48
- const combinedAddress = shipfrom_address.address_line_1 + shipfrom_address.address_line_2 + shipfrom_address.address_line_3;
49
- let shipper: any = {
50
- "VendorName": shipfrom_address.name.slice(0, 50) ,
51
- "Attention": shipfrom_address.attention_name.slice(0, 50) ,
52
- "VendorAddress1": combinedAddress.substring(0,60),
53
- "VendorAddress2": combinedAddress.substring(61,120),
54
- "VendorAddress3": combinedAddress.substring(121,180),
55
- "VendorCity": shipfrom_address.city,
56
- "VendorState": shipfrom_address.state,
57
- "VendorPostalCode": shipfrom_address.zip,
58
- "VendorCountry": targetFromCountry ? targetFromCountry : shipfrom_address.country,
59
- "VendorPhone": shipfrom_address.phone.toString(),
60
- "VendorEmail": shipfrom_address.email,
61
- "VendorBusinessNumber": "",
62
- "VendorRGRNumber":"",
63
- "VendorIOSSNumber":iossNumber,
64
- "VendorEORINumber":eroiNumber
65
- };
66
- return shipper;
67
- }
68
-
69
- buildShipmentRequest(args: any, dangerousGoodsDeatils: any = "", username:string,password:string,test:boolean,clientId:number,vendorEORINumber:any,vendorIOSSNumber:any,reqRegionValue:string): string{
70
- try {
71
- const EUCountries = ["BE", "BG", "CZ", "DK", "DE", "EE", "IE", "EL", "ES", "FR", "HR", "IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL", "PT", "RO", "SI", "SK", "FI", "SE", "GR"];
72
- let iossNumber=""
73
- let regionValue = (reqRegionValue && reqRegionValue != "") ? reqRegionValue : "Landmark BUF"
74
- if( EUCountries.indexOf(args.shipto_address.country.toUpperCase()) != -1 || EUCountries.indexOf(args.targetToCountry.toUpperCase()) != -1 ){
75
- iossNumber = vendorIOSSNumber
76
- }
77
- let eroiNumber=""
78
- if(args.shipto_address.country.toUpperCase() == "GB" || args.shipto_address.country.toUpperCase() == "UK"){
79
- eroiNumber = vendorEORINumber
80
- }
81
- let importRequest :any = {
82
- "Login": {
83
- "Username": username,
84
- "Password": password
85
- },
86
- "Test": test,
87
- "ClientID": clientId ,
88
- "Reference": args.reference,
89
- "ShipTo": this.getConsignee(args.shipto_address,args.targetToCountry),
90
- "ShippingLane": {
91
- "Region" : regionValue
92
- },
93
- "ShipMethod": args._carrierRateObj.servicecode,
94
- "OrderTotal": args.shipment_total_usd,
95
- "ItemsCurrency": args.currency,
96
- "ProduceLabel": true,
97
- "LabelFormat": args.label_format,
98
- "LabelEncoding": args.label_format.toLowerCase() == "zpl" ? "ZPL" : "LINKS" ,
99
- "Packages":{
100
- "Package": {
101
- "WeightUnit":args.weight_unit,
102
- "Weight":args.package.weight,
103
- "DimensionsUnit":args.dimension_unit,
104
- "Length":args.package.length,
105
- "Width":args.package.width,
106
- "Height":args.package.height,
107
- "PackageReference":args.reference
108
- }
109
- },
110
- "SendReturnToAddress": this.getShipperInfo(args.shipfrom_address,args.targetFromCountry),
111
- "VendorInformation": this.getVendorInfo(args.shipfrom_address,args.targetFromCountry,eroiNumber,iossNumber),
112
- "IsCommercialShipment": args.b2b ? 1 : 0,
113
- }
114
- // let items = args.pieces.map((item:any)=>{
115
- // return {"Item":{
116
- // "Sku": item.sku || 12345,
117
- // "Description": item.description.substr(0,100),
118
- // "Quantity": item.quantity,
119
- // "UnitPrice": (item.sale_price == 0) ? 0.01 : item.sale_price,
120
- // "HSCode": item.hs_code,
121
- // "CountryOfOrigin": item.origin_country_code
122
- // }
123
- // }
124
- // })
125
- let items = args.pieces.map((item:any) => {
126
- let itemObj: any = {
127
- "Sku": item.sku || 12345,
128
- "Description": item.description.substr(0, 100),
129
- "Quantity": item.quantity,
130
- "UnitPrice": (item.sale_price == 0) ? 0.01 : item.sale_price,
131
- "HSCode": item.hs_code,
132
- "CountryOfOrigin": item.origin_country_code
133
- };
134
- if(dangerousGoodsDeatils && dangerousGoodsDeatils[item.sku] && dangerousGoodsDeatils[item.sku]['UNCode']){
135
- let dangerousGoodInformation = {
136
- "ContainsDangerousGoods": 1,
137
- "UNCode": dangerousGoodsDeatils[item.sku]['UNCode'] || "",
138
- "PackingGroup": dangerousGoodsDeatils[item.sku]['CategoryCode'] || "",
139
- "PackingInstructions": dangerousGoodsDeatils[item.sku]['PackingInstructions'] || "",
140
- "ItemWeight": item.weight,
141
- "ItemWeightUnit": args.weight_unit
142
- }
143
- itemObj["DangerousGoodsInformation"] = dangerousGoodInformation;
144
- }
145
- return itemObj;
146
- });
147
- importRequest["Items"] = { "Item": items };
148
- let request :any = {
149
- "ImportRequest": importRequest
150
- }
151
- const xmlData = js2xml(request, { compact: true, ignoreComment: true, spaces: 4 });
152
- return xmlData;
153
- } catch(e) {
154
- throw app.FlclError?.create({className: 'Shipment', methodName: '_buildRequest', message: 'Exception while building the LandMark shipment request', cause: e, appendChildMsg: true}) || e;
155
- }
156
- }
157
-
158
- async createShipment(ShipmentRequest: string): Promise<any> {
159
- try {
160
- let configs = {
161
- headers: {
162
- 'Content-Type' : 'application/xml'
163
- }
164
- };
165
- let resp = await app.axios!.post(app.ship_url, ShipmentRequest, configs);
166
- console.log(resp.data)
167
- app.logger?.info({npm: 'fc-landmark', className: 'Landmark', methodName: 'createShipmet', propertyName: 'Landmark-RAW-RESPOSNE', propertyValue: resp.data});
168
- let responsejson= xml2json(resp.data,{compact: true, spaces: 4}) ;
169
- return JSON.parse(responsejson) ;
170
- } catch(e) {
171
- app.logger?.info({npm: 'fc-landmark', className: 'Landmark', methodName: 'createShipmet', propertyName: 'Landmark-RAW-RESPOSNE', data: {error: e}});
172
- app.logger?.error(app.flclError!.create({npm: 'fc-landmark', className: 'Shipment', methodName: 'createShipment', propertyName: 'CREDITS_ERROR', cause: e}));
173
- throw e;
174
- }
175
- }
176
-
177
- buildResponse(resp: any, args: any): FlavorcloudShipmentResponse{
178
- let response: FlavorcloudShipmentResponse = {
179
- provider_name: 'Landmark',
180
- shipping_provider: 'Landmark',
181
- carrier : 'Landmark',
182
- tracking_number: resp['ImportResponse']['Result']['Packages']['Package']['TrackingNumber']['_text'],
183
- provider_tracking_number: resp['ImportResponse']['Result']['Packages']['Package']['TrackingNumber']['_text'],
184
- shipping_label: args.label_format.toLowerCase() == "zpl" ? resp['ImportResponse']['Result']['Packages']['Package']['LabelImages']['LabelImage']['_text'] : resp['ImportResponse']['Result']['ShipmentLabelLink']['_text'],
185
- label_type: args.label_format.toLowerCase() == "zpl" ? "zplenc" : "url",
186
- gross_weight: args.total_weight,
187
- gross_weight_unit: args.weight_unit,
188
- submitted_electronically: true
189
- };
190
- return response;
191
- }
192
-
193
- }
1
+ import { FlavorcloudShipmentResponse, LandmarkProductIdentifiers } from "./types";
2
+ import { MyGlobal as app } from './globals';
3
+ import { js2xml , xml2json} from 'xml-js';
4
+
5
+ const NO_STANDARDISED_CODE_DECLARATION = "Y081";
6
+
7
+ export default class Shipment {
8
+ constructor() {
9
+
10
+ }
11
+ getConsignee(shipto_address: any,targetToCountry:any): any {
12
+
13
+ const combinedAddress = shipto_address.address_line_1 + shipto_address.address_line_2 + shipto_address.address_line_3;
14
+ let consignee: any = {
15
+ "Name": shipto_address.name.slice(0, 50) ,
16
+ "Attention": shipto_address.attention_name.slice(0, 50) ,
17
+ "Address1": combinedAddress.substring(0,60),
18
+ "Address2": combinedAddress.substring(61,120),
19
+ "Address3": combinedAddress.substring(121,180),
20
+ "City": shipto_address.city,
21
+ "State": shipto_address.state,
22
+ "PostalCode": shipto_address.zip,
23
+ "Country": targetToCountry ? targetToCountry : shipto_address.country,
24
+ "Phone": shipto_address.phone.toString(),
25
+ "Email": shipto_address.email,
26
+ "ConsigneeTaxID": shipto_address.federal_tax_id ? shipto_address.federal_tax_id : ""
27
+ };
28
+ return consignee;
29
+ }
30
+
31
+ getShipperInfo(shipfrom_address: any,targetFromCountry:any) {
32
+ const combinedAddress = shipfrom_address.address_line_1 + shipfrom_address.address_line_2 + shipfrom_address.address_line_3;
33
+ let shipper: any = {
34
+ "Name": shipfrom_address.name.slice(0, 50) ,
35
+ "Attention": shipfrom_address.attention_name.slice(0, 50) ,
36
+ "Address1": combinedAddress.substring(0,60),
37
+ "Address2": combinedAddress.substring(61,120),
38
+ "Address3": combinedAddress.substring(121,180),
39
+ "City": shipfrom_address.city,
40
+ "State": shipfrom_address.state,
41
+ "PostalCode": shipfrom_address.zip,
42
+ "Country": targetFromCountry ? targetFromCountry : shipfrom_address.country,
43
+ "Phone": shipfrom_address.phone.toString(),
44
+ "Email": shipfrom_address.email
45
+ };
46
+ return shipper;
47
+ }
48
+
49
+ getVendorInfo(shipfrom_address: any,targetFromCountry:any,eroiNumber:any,iossNumber:any) {
50
+ const combinedAddress = shipfrom_address.address_line_1 + shipfrom_address.address_line_2 + shipfrom_address.address_line_3;
51
+ let shipper: any = {
52
+ "VendorName": shipfrom_address.name.slice(0, 50) ,
53
+ "Attention": shipfrom_address.attention_name.slice(0, 50) ,
54
+ "VendorAddress1": combinedAddress.substring(0,60),
55
+ "VendorAddress2": combinedAddress.substring(61,120),
56
+ "VendorAddress3": combinedAddress.substring(121,180),
57
+ "VendorCity": shipfrom_address.city,
58
+ "VendorState": shipfrom_address.state,
59
+ "VendorPostalCode": shipfrom_address.zip,
60
+ "VendorCountry": targetFromCountry ? targetFromCountry : shipfrom_address.country,
61
+ "VendorPhone": shipfrom_address.phone.toString(),
62
+ "VendorEmail": shipfrom_address.email,
63
+ "VendorBusinessNumber": "",
64
+ "VendorRGRNumber":"",
65
+ "VendorIOSSNumber":iossNumber,
66
+ "VendorEORINumber":eroiNumber
67
+ };
68
+ return shipper;
69
+ }
70
+
71
+ getProductIdentifiers(item: any): LandmarkProductIdentifiers | undefined {
72
+ const identifiers: LandmarkProductIdentifiers = {};
73
+ if (item.merchant_pid) identifiers.MerchantProductID = item.merchant_pid;
74
+ if (item.ns_manufacturer_pid) identifiers.ManufacturerProductID = item.ns_manufacturer_pid;
75
+
76
+ const isNoStandardisedCodeDeclared = item.std_manufacturer_pid === NO_STANDARDISED_CODE_DECLARATION;
77
+ if (isNoStandardisedCodeDeclared) {
78
+ identifiers.HasStandardizedProductID = 0;
79
+ } else if (item.std_manufacturer_pid) {
80
+ identifiers.HasStandardizedProductID = 1;
81
+ identifiers.StandardizedProductID = item.std_manufacturer_pid;
82
+ }
83
+
84
+ return Object.keys(identifiers).length ? identifiers : undefined;
85
+ }
86
+
87
+ buildShipmentRequest(args: any, dangerousGoodsDeatils: any = "", username:string,password:string,test:boolean,clientId:number,vendorEORINumber:any,vendorIOSSNumber:any,reqRegionValue:string): string{
88
+ try {
89
+ const EUCountries = ["BE", "BG", "CZ", "DK", "DE", "EE", "IE", "EL", "ES", "FR", "HR", "IT", "CY", "LV", "LT", "LU", "HU", "MT", "NL", "AT", "PL", "PT", "RO", "SI", "SK", "FI", "SE", "GR"];
90
+ let iossNumber=""
91
+ let regionValue = (reqRegionValue && reqRegionValue != "") ? reqRegionValue : "Landmark BUF"
92
+ if( EUCountries.indexOf(args.shipto_address.country.toUpperCase()) != -1 || EUCountries.indexOf(args.targetToCountry.toUpperCase()) != -1 ){
93
+ iossNumber = vendorIOSSNumber
94
+ }
95
+ let eroiNumber=""
96
+ if(args.shipto_address.country.toUpperCase() == "GB" || args.shipto_address.country.toUpperCase() == "UK"){
97
+ eroiNumber = vendorEORINumber
98
+ }
99
+ let importRequest :any = {
100
+ "Login": {
101
+ "Username": username,
102
+ "Password": password
103
+ },
104
+ "Test": test,
105
+ "ClientID": clientId ,
106
+ "Reference": args.reference,
107
+ "ShipTo": this.getConsignee(args.shipto_address,args.targetToCountry),
108
+ "ShippingLane": {
109
+ "Region" : regionValue
110
+ },
111
+ "ShipMethod": args._carrierRateObj.servicecode,
112
+ "OrderTotal": args.shipment_total_usd,
113
+ "ItemsCurrency": args.currency,
114
+ "ProduceLabel": true,
115
+ "LabelFormat": args.label_format,
116
+ "LabelEncoding": args.label_format.toLowerCase() == "zpl" ? "ZPL" : "LINKS" ,
117
+ "Packages":{
118
+ "Package": {
119
+ "WeightUnit":args.weight_unit,
120
+ "Weight":args.package.weight,
121
+ "DimensionsUnit":args.dimension_unit,
122
+ "Length":args.package.length,
123
+ "Width":args.package.width,
124
+ "Height":args.package.height,
125
+ "PackageReference":args.reference
126
+ }
127
+ },
128
+ "SendReturnToAddress": this.getShipperInfo(args.shipfrom_address,args.targetFromCountry),
129
+ "VendorInformation": this.getVendorInfo(args.shipfrom_address,args.targetFromCountry,eroiNumber,iossNumber),
130
+ "IsCommercialShipment": args.b2b ? 1 : 0,
131
+ }
132
+ // let items = args.pieces.map((item:any)=>{
133
+ // return {"Item":{
134
+ // "Sku": item.sku || 12345,
135
+ // "Description": item.description.substr(0,100),
136
+ // "Quantity": item.quantity,
137
+ // "UnitPrice": (item.sale_price == 0) ? 0.01 : item.sale_price,
138
+ // "HSCode": item.hs_code,
139
+ // "CountryOfOrigin": item.origin_country_code
140
+ // }
141
+ // }
142
+ // })
143
+ let items = args.pieces.map((item:any) => {
144
+ const productIdentifiers = this.getProductIdentifiers(item);
145
+ let itemObj: any = {
146
+ "Sku": item.sku || 12345,
147
+ "Description": item.description.substr(0, 100),
148
+ "Quantity": item.quantity,
149
+ "UnitPrice": (item.sale_price == 0) ? 0.01 : item.sale_price,
150
+ "HSCode": item.hs_code,
151
+ "CountryOfOrigin": item.origin_country_code,
152
+ ...(productIdentifiers && { "ProductIdentifiers": productIdentifiers })
153
+ };
154
+ if(dangerousGoodsDeatils && dangerousGoodsDeatils[item.sku] && dangerousGoodsDeatils[item.sku]['UNCode']){
155
+ let dangerousGoodInformation = {
156
+ "ContainsDangerousGoods": 1,
157
+ "UNCode": dangerousGoodsDeatils[item.sku]['UNCode'] || "",
158
+ "PackingGroup": dangerousGoodsDeatils[item.sku]['CategoryCode'] || "",
159
+ "PackingInstructions": dangerousGoodsDeatils[item.sku]['PackingInstructions'] || "",
160
+ "ItemWeight": item.weight,
161
+ "ItemWeightUnit": args.weight_unit
162
+ }
163
+ itemObj["DangerousGoodsInformation"] = dangerousGoodInformation;
164
+ }
165
+ return itemObj;
166
+ });
167
+ importRequest["Items"] = { "Item": items };
168
+ let request :any = {
169
+ "ImportRequest": importRequest
170
+ }
171
+ const xmlData = js2xml(request, { compact: true, ignoreComment: true, spaces: 4 });
172
+ return xmlData;
173
+ } catch(e) {
174
+ throw app.FlclError?.create({className: 'Shipment', methodName: '_buildRequest', message: 'Exception while building the LandMark shipment request', cause: e, appendChildMsg: true}) || e;
175
+ }
176
+ }
177
+
178
+ async createShipment(ShipmentRequest: string): Promise<any> {
179
+ try {
180
+ let configs = {
181
+ headers: {
182
+ 'Content-Type' : 'application/xml'
183
+ }
184
+ };
185
+ let resp = await app.axios!.post(app.ship_url, ShipmentRequest, configs);
186
+ console.log(resp.data)
187
+ app.logger?.info({npm: 'fc-landmark', className: 'Landmark', methodName: 'createShipmet', propertyName: 'Landmark-RAW-RESPOSNE', propertyValue: resp.data});
188
+ let responsejson= xml2json(resp.data,{compact: true, spaces: 4}) ;
189
+ return JSON.parse(responsejson) ;
190
+ } catch(e) {
191
+ app.logger?.info({npm: 'fc-landmark', className: 'Landmark', methodName: 'createShipmet', propertyName: 'Landmark-RAW-RESPOSNE', data: {error: e}});
192
+ app.logger?.error(app.flclError!.create({npm: 'fc-landmark', className: 'Shipment', methodName: 'createShipment', propertyName: 'CREDITS_ERROR', cause: e}));
193
+ throw e;
194
+ }
195
+ }
196
+
197
+ buildResponse(resp: any, args: any): FlavorcloudShipmentResponse{
198
+ let response: FlavorcloudShipmentResponse = {
199
+ provider_name: 'Landmark',
200
+ shipping_provider: 'Landmark',
201
+ carrier : 'Landmark',
202
+ tracking_number: resp['ImportResponse']['Result']['Packages']['Package']['TrackingNumber']['_text'],
203
+ provider_tracking_number: resp['ImportResponse']['Result']['Packages']['Package']['TrackingNumber']['_text'],
204
+ shipping_label: args.label_format.toLowerCase() == "zpl" ? resp['ImportResponse']['Result']['Packages']['Package']['LabelImages']['LabelImage']['_text'] : resp['ImportResponse']['Result']['ShipmentLabelLink']['_text'],
205
+ label_type: args.label_format.toLowerCase() == "zpl" ? "zplenc" : "url",
206
+ gross_weight: args.total_weight,
207
+ gross_weight_unit: args.weight_unit,
208
+ submitted_electronically: true
209
+ };
210
+ return response;
211
+ }
212
+
213
+ }