Skip to content

Commit

Permalink
feat(dhl_soap): add step price algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerald Baulig committed Oct 25, 2024
1 parent 299ebd7 commit b81ac26
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 36 deletions.
26 changes: 15 additions & 11 deletions src/services/fulfillment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export class FulfillmentService
message: 'SUCCESS',
},
PARTIAL: {
code: 208,
code: 207,
message: 'Patrial executed with errors!',
},
LIMIT_EXHAUSTED: {
Expand Down Expand Up @@ -890,13 +890,14 @@ export class FulfillmentService
);

if (evaluate) {
item.packaging?.parcels?.forEach(
p => {
await Promise.all(item.packaging?.parcels?.map(
async p => {
const product = product_map[p.product_id].payload;
const variant = product.variants.find(
v => v.id === p.variant_id
);
const price = variant?.price;
const courier = courier_map[product.courier_id]?.payload;
const stub = Stub.getInstance(courier);
const taxes = product.tax_ids.map(
id => tax_map[id]?.payload
).filter(
Expand All @@ -907,22 +908,25 @@ export class FulfillmentService
!!customer.payload.private?.user_id,
)
);
const gross = price.sale ? price.sale_price : price.regular_price;
const gross = await stub.calcGross(variant, p.package);
const vats = taxes.map((tax): VAT => ({
tax_id: tax.id,
vat: gross * tax.rate,
vat: gross.multipliedBy(tax.rate).decimalPlaces(2).toNumber(),
}));
const net = vats.reduce((a, b) => a + b.vat, gross);
const net = vats.reduce(
(a, b) => a.plus(b.vat),
gross
);

p.price = variant.price;
p.amount = {
currency_id: price.currency_id,
gross,
net,
currency_id: variant.price.currency_id,
gross: gross.decimalPlaces(2).toNumber(),
net: net.decimalPlaces(2).toNumber(),
vats,
};
}
);
));
}

const aggreagatedFulfillment: AggregatedFulfillment = {
Expand Down
2 changes: 1 addition & 1 deletion src/services/fulfillment_product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export class FulfillmentProductService
message: 'SUCCESS',
},
PARTIAL: {
code: 400,
code: 207,
message: 'Patrial executed with errors!',
},
LIMIT_EXHAUSTED: {
Expand Down
15 changes: 9 additions & 6 deletions src/stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import {
FlatAggregatedFulfillment,
extractCouriers,
} from './utils.js';
import { FulfillmentProduct, PackingSolutionQuery } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/fulfillment_product.js';
import {
FulfillmentProduct,
PackingSolutionQuery,
Variant
} from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/fulfillment_product.js';
import { BigNumber } from 'bignumber.js';
import { Package } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/product.js';

export abstract class Stub
{
Expand All @@ -22,15 +28,12 @@ export abstract class Stub
public logger?: Logger
) {}

public abstract matchesZone(
product: FulfillmentProduct,
query: PackingSolutionQuery,
helper?: any
): Promise<boolean>;
protected abstract evaluateImpl (fulfillments: FlatAggregatedFulfillment[]): Promise<FlatAggregatedFulfillment[]>;
protected abstract submitImpl (fulfillments: FlatAggregatedFulfillment[]): Promise<FlatAggregatedFulfillment[]>;
protected abstract trackImpl (fulfillments: FlatAggregatedFulfillment[]): Promise<FlatAggregatedFulfillment[]>;
protected abstract cancelImpl (fulfillments: FlatAggregatedFulfillment[]): Promise<FlatAggregatedFulfillment[]>;
public abstract matchesZone<T>(product: FulfillmentProduct, query: PackingSolutionQuery, helper?: T): Promise<boolean>;
public abstract calcGross(product: Variant, pack: Package): Promise<BigNumber>;

protected createStatusCode(
entity: string,
Expand Down
121 changes: 103 additions & 18 deletions src/stubs/dhl_soap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ import {
import {
Credential
} from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/credential.js';
import { OperationStatus, Status } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/status.js';
import {
FlatAggregatedFulfillment,
throwOperationStatusCode,
} from '../utils.js';
import { Stub } from '../stub.js';
import {
FulfillmentProduct,
PackingSolutionQuery
PackingSolutionQuery,
Variant
} from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/fulfillment_product.js';
import { BigNumber } from 'bignumber.js';
import { Package } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/product.js';

dayjs.extend(customParseFormat);

Expand Down Expand Up @@ -157,14 +159,16 @@ interface Config
},
}

const parseService = (attributes: any[]) => attributes.filter((att: any) =>
att.id.startsWith('urn:restorecommerce:fufs:names:service:attr:dhl')
).map((att: any) => ({
[att.value]: {
attributes: Object.assign({}, ...att.attribute.map((att: any) => ({
[att.id]: att.value
})))}
}));
const DefaultUrns = {
dhl_service: 'urn:restorecommerce:fulfillment:product:attribute:dhl:service',
dhl_productName: 'urn:restorecommerce:fulfillment:product:attribute:dhl:productName',
dhl_accountNumber: 'urn:restorecommerce:fulfillment:product:attribute:dhl:accountNumber',
dhl_roundWeightUp: 'urn:restorecommerce:fulfillment:product:attribute:dhl:roundWeightUp',
dhl_stepPrice: 'urn:restorecommerce:fulfillment:product:attribute:dhl:stepPrice',
dhl_stepWeight: 'urn:restorecommerce:fulfillment:product:attribute:dhl:stepWeightInKg',
};

type KnownUrns = typeof DefaultUrns;

const DHLEvent2FulfillmentEvent = (attributes: any): Event => ({
timestamp: dayjs(attributes['event-timestamp'], 'DD.MM.YYYY HH:mm').toDate(),
Expand Down Expand Up @@ -299,10 +303,11 @@ const DHLShipmentCancelResponse2AggregatedFulfillment = (
export class DHLSoap extends Stub {
public readonly version: number[];
protected readonly stub_defaults: any;
protected readonly urns: KnownUrns;
private _stub_config: Config;
private _soap_client: soap.Client;

protected readonly status_codes: { [key: string]: Status } = {
protected readonly status_codes = {
OK: {
id: '',
code: 200,
Expand All @@ -313,19 +318,29 @@ export class DHLSoap extends Stub {
code: 404,
message: '{entity} {id} not found! {details}',
},
WEAK_ERROR: {
id: '',
code: 207,
message: '{entity} {id} week validation error! {details}',
},
INVALID_ADDRESS: {
id: '',
code: 400,
message: '{entity} {id} address invalid! {details}',
},
INVALID_PRICE: {
id: '',
code: 500,
message: '{entity} {id} price calculation failed! {details}',
},
UNKNOWN_ERROR: {
id: '',
code: 500,
message: '{entity} {id} caused unknown error! {details}',
},
};

protected readonly operation_status_codes: { [key: string]: OperationStatus } = {
protected readonly operation_status_codes = {
SUCCESS: {
code: 200,
message: 'SUCCESS',
Expand Down Expand Up @@ -378,6 +393,59 @@ export class DHLSoap extends Stub {
...this.operation_status_codes,
...this.cfg?.get('operationStatusCodes'),
};

this.urns = {
...DefaultUrns,
...this.cfg?.get('urns'),
...this.cfg?.get('urns:authentication'),
};
}

public async calcGross(
product: Variant,
pack: Package
): Promise<BigNumber> {
try{
const step_weight = Number.parseFloat(
product.attributes.find(attr => attr.id === this.urns.dhl_stepWeight)?.value ?? '1'
);
const step_price = Number.parseFloat(
product.attributes.find(attr => attr.id === this.urns.dhl_stepPrice)?.value ?? '1'
);
const precision = Number.parseInt(
product.attributes.find(attr => attr.id === this.urns.dhl_stepPrice)?.value ?? '3'
);
const price = new BigNumber(
pack.weight_in_kg / step_weight * step_price
).plus(
product.price.sale ? product.price.sale_price : product.price.regular_price
).decimalPlaces(
precision, BigNumber.ROUND_UP
);
if (price.isNaN()) {
throw 'NaN detected!'
}
return price;
}
catch (e: any) {
this.throwStatusCode(
'FulfillmentProduct',
product?.id,
this.status_codes.INVALID_PRICE,
e?.message ?? e.details ?? JSON.stringify(e)
);
}
}

protected parseService (attributes: any[]) {
return attributes.filter((att: any) =>
att.id.startsWith(this.urns.dhl_service)
).map((att: any) => ({
[att.value]: {
attributes: Object.assign({}, ...att.attribute.map((att: any) => ({
[att.id]: att.value
})))}
}));
}

protected DHLCode2StatusCode(
Expand All @@ -392,10 +460,22 @@ export class DHLSoap extends Stub {
this.status_codes.OK,
details,
);
case 1101: return this.createStatusCode(
'Fulfillment',
id,
this.status_codes.INVALID_ADDRESS,
details,
);
case 207: return this.createStatusCode(
'Fulfillment',
id,
this.status_codes.WEAK_ERROR,
details,
);
default: return this.createStatusCode(
'Fulfillment',
id,
this.status_codes.UNKOWN_ERROR,
this.status_codes.UNKNOWN_ERROR,
details,
);
}
Expand Down Expand Up @@ -463,12 +543,13 @@ export class DHLSoap extends Stub {
if (response?.CreationState) {
return fulfillments.map((fulfillment, i) => {
const dhl_state = response.CreationState.find((state: any) => state.sequenceNumber === (i + 1).toString());
const code = dhl_state?.LabelData?.Status?.statusCode;
const weak = dhl_state?.Status?.statusText?.startsWith('Weak');
const code = weak ? 207 : dhl_state?.LabelData?.Status?.statusCode;
const state = code === 0 ? FulfillmentState.SUBMITTED : FulfillmentState.INVALID;
const status = this.DHLCode2StatusCode(
code,
fulfillment.payload?.id,
dhl_state?.LabelData?.Status?.statusMessage,
dhl_state?.LabelData?.Status?.statusMessage ?? dhl_state?.Status?.statusText,
);

if (state === FulfillmentState.INVALID) {
Expand All @@ -494,7 +575,8 @@ export class DHLSoap extends Stub {
else if (response?.ValidationState) {
return fulfillments.map((fulfillment, i) => {
const dhl_state = response.ValidationState.find((state: any) => state.sequenceNumber === (i + 1).toString());
const code = dhl_state?.Status?.statusCode;
const weak = dhl_state?.Status?.statusText?.startsWith('Weak');
const code = weak ? 207 : dhl_state?.Status?.statusCode;
const status = this.DHLCode2StatusCode(
code,
fulfillment.payload?.id,
Expand All @@ -505,6 +587,7 @@ export class DHLSoap extends Stub {
fulfillment.payload.fulfillment_state = FulfillmentState.INVALID;
}

this.logger.debug('DHLSoap Evaluation:', status);
fulfillment.status = status;
return fulfillment;
});
Expand Down Expand Up @@ -590,9 +673,11 @@ export class DHLSoap extends Stub {
shipmentDate: new Date().toISOString().slice(0,10),
costCenter: '',
customerReference: request.payload.id,
product: request.product.attributes.find(att => att.id === this.cfg.get('urns:productName'))?.value,
product: request.product.attributes.find(
att => att.id === this.urns.dhl_productName
)?.value,
accountNumber: request.product.attributes.find(
att => att.id === this.cfg.get('urns:accountNumber')
att => att.id === this.urns.dhl_accountNumber
)?.value ?? this.stub_config?.ordering?.account_number,
// Service: parseService(request.parcel.attributes),
ShipmentItem: {
Expand Down

0 comments on commit b81ac26

Please sign in to comment.