@fleetbase/fleetops-engine
Version:
Fleet & Transport Management Extension for Fleetbase
266 lines (237 loc) • 9.68 kB
JavaScript
import ResourceActionService from '@fleetbase/ember-core/services/resource-action';
import { task } from 'ember-concurrency';
import { isNone } from '@ember/utils';
import serializePayload from '../utils/serialize-payload';
export default class ServiceRateActionsService extends ResourceActionService {
modelNamePath = 'service_name';
get defaultCurrency() {
return this.currentUser?.company?.currency || this.currentUser.currency || 'USD';
}
constructor() {
super(...arguments);
this.initialize('service-rate', {
defaultAttributes: {
rate_calculation_method: 'per_meter',
per_meter_unit: 'm',
currency: this.defaultCurrency,
parcel_fees: this.#getDefaultParcelFees(),
},
});
}
transition = {
view: (serviceRate) => this.transitionTo('operations.service-rates.index.details', serviceRate),
edit: (serviceRate) => this.transitionTo('operations.service-rates.index.edit', serviceRate),
create: () => this.transitionTo('operations.service-rates.index.new'),
};
panel = {
create: (attributes = {}) => {
const serviceRate = this.createNewInstance(attributes);
return this.resourceContextPanel.open({
content: 'service-rate/form',
title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.service rate')?.toLowerCase() }),
useDefaultSaveTask: true,
saveOptions: {
callback: this.refresh,
},
serviceRate,
});
},
edit: (serviceRate) => {
return this.resourceContextPanel.open({
content: 'service-rate/form',
title: this.intl.t('common.edit-resource-name', { resourceName: serviceRate.name }),
useDefaultSaveTask: true,
serviceRate,
});
},
view: (serviceRate) => {
return this.resourceContextPanel.open({
serviceRate,
tabs: [
{
label: this.intl.t('common.overview'),
component: 'service-rate/details',
},
],
});
},
};
modal = {
create: (attributes = {}, options = {}, saveOptions = {}) => {
const serviceRate = this.createNewInstance(attributes);
return this.modalsManager.show('modals/resource', {
resource: serviceRate,
title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.service rate')?.toLowerCase() }),
acceptButtonText: this.intl.t('common.create-resource', { resource: this.intl.t('resource.service-rate') }),
component: 'service-rate/form',
confirm: (modal) => this.modalTask.perform(modal, 'saveTask', serviceRate, { refresh: true, ...saveOptions }),
...options,
});
},
edit: (serviceRate, options = {}, saveOptions = {}) => {
return this.modalsManager.show('modals/resource', {
resource: serviceRate,
title: this.intl.t('common.edit-resource-name', { resourceName: serviceRate.name }),
acceptButtonText: this.intl.t('common.save-changes'),
saveButtonIcon: 'save',
component: 'service-rate/form',
confirm: (modal) => this.modalTask.perform(modal, 'saveTask', serviceRate, { refresh: true, ...saveOptions }),
...options,
});
},
view: (serviceRate, options = {}) => {
return this.modalsManager.show('modals/resource', {
resource: serviceRate,
title: serviceRate.name,
component: 'service-rate/details',
...options,
});
},
};
*queryServiceRatesForOrder(order, params = {}) {
const payloadCoordinates = order.payload?.payloadCoordinates ?? [];
const routeCoordinates = payloadCoordinates.map((coordinate) => this.#serializeRouteCoordinate(coordinate)).filter(Boolean);
if (routeCoordinates.length < 2) {
return [];
}
const queryParams = {
coordinates: routeCoordinates.join(';'),
facilitator: order.facilitator?.get('isIntegratedVendor') ? order.facilitator.get('public_id') : null,
service_type: order.order_config?.get('key'),
...params,
};
try {
const serviceRates = yield this.fetch.get('service-rates/for-route', queryParams, { normalizeToEmberData: true, normalizeModelType: 'service-rate' });
serviceRates.unshiftObject({
service_name: 'Quote from all Service Rates',
id: 'all',
});
return serviceRates;
} catch (err) {
console.error(err);
this.notifications.serverError(err);
}
}
#serializeRouteCoordinate(coordinate) {
if (Array.isArray(coordinate)) {
const [longitude, latitude] = coordinate;
if (!this.#isValidCoordinate(latitude) || !this.#isValidCoordinate(longitude)) {
return null;
}
return `${latitude},${longitude}`;
}
if (typeof coordinate === 'string') {
const parts = coordinate
.split(',')
.map((part) => part.trim())
.filter(Boolean);
if (parts.length !== 2 || !parts.every((part) => this.#isValidCoordinate(part))) {
return null;
}
return parts.join(',');
}
return null;
}
#isValidCoordinate(value) {
return value !== null && value !== undefined && value !== '' && Number.isFinite(Number(value));
}
*getServiceQuotes(serviceRate, order) {
if (order.payload.payloadCoordinates.length < 2) return;
const hasFacilitator = !isNone(order.facilitator);
const facilitatorServiceType = order.facilitator?.get('service_types.firstObject.key') ?? order.type;
const routeSummary = order.route?.summary ?? order.route?.details?.summary ?? {};
try {
const serviceQuotes = yield this.fetch.post('service-quotes/preliminary', {
payload: serializePayload(order.payload),
distance: routeSummary.totalDistance,
time: routeSummary.totalTime,
service_type: hasFacilitator ? facilitatorServiceType : order.type,
facilitator: order.facilitator?.public_id,
scheduled_at: order.scheduled_at,
is_route_optimized: order.optimized,
service: serviceRate.id,
meta: order.meta,
});
return serviceQuotes;
} catch (err) {
console.error(err);
this.notifications.serverError(err);
}
}
generateFixedRateFees(serviceRate) {
if (!serviceRate.isFixedRate) return;
const maxDistance = Number(serviceRate.max_distance) || 0;
const existing = serviceRate.rate_fees.toArray();
const byDistance = new Map(existing.map((f) => [f.distance, f]));
// Remove fees beyond max_distance
existing.forEach((fee) => {
if (fee.distance >= maxDistance) {
serviceRate.rate_fees.removeObject(fee);
if (!fee.isNew) {
fee.deleteRecord();
}
}
});
// Add missing fees
for (let d = 0; d < maxDistance; d++) {
if (!byDistance.has(d)) {
const fee = this.store.createRecord('service-rate-fee', {
distance: d,
distance_unit: serviceRate.max_distance_unit,
fee: 0,
currency: serviceRate.currency,
});
serviceRate.rate_fees.pushObject(fee);
}
}
}
#getDefaultParcelFees() {
const defaults = [
{
size: 'small',
length: 34,
width: 18,
height: 10,
dimensions_unit: 'cm',
weight: 2,
weight_unit: 'kg',
fee: 0,
currency: this.currentUser.currency,
},
{
size: 'medium',
length: 34,
width: 32,
height: 10,
dimensions_unit: 'cm',
weight: 4,
weight_unit: 'kg',
fee: 0,
currency: this.currentUser.currency,
},
{
size: 'large',
length: 34,
width: 32,
height: 18,
dimensions_unit: 'cm',
weight: 8,
weight_unit: 'kg',
fee: 0,
currency: this.currentUser.currency,
},
{
size: 'x-large',
length: 34,
width: 32,
height: 34,
dimensions_unit: 'cm',
weight: 13,
weight_unit: 'kg',
fee: 0,
currency: this.currentUser.currency,
},
];
return defaults.map((fee) => this.store.createRecord('service-rate-parcel-fee', fee));
}
}