import { groupBy, memoize, isEmpty, omit, camelCase } from 'lodash'; import { __ } from '@wordpress/i18n'; import { camelCaseKeys } from './common'; import { Hazmat, LabelRequestPackages, Rate, RatesResponse, RateWithParent, RequestPackage, ShipmentRatesResponse, LabelRateType, SnakeToCamelCase, ExtraOptionCharges, } from 'types'; import { getRatesForShipment } from 'data/label-purchase/selectors'; const groupByServiceId = memoize( ( rates ) => groupBy( rates, 'serviceId' ) ); export const getExtraOptionRate = ( serviceId: string, optionRates: Rate[], baseCost: number, type: SnakeToCamelCase< LabelRateType > = 'signatureRequired' ): ( Rate & { type: typeof type } ) | null => { const serviceRates = groupByServiceId( optionRates )[ serviceId ]; // Skip if there was no rate for this service type. if ( ! serviceRates || serviceRates.length === 0 ) { return null; } const serviceRate = serviceRates[ 0 ]; /** * USPS returns signature rates that are not valid. These can be identified * by the fact that the price with signature required is the same as the * base cost. Priority Express service is the exception because signature * can be required free-of-charge. */ if ( serviceRate.rate === baseCost && serviceId !== 'Express' ) { return null; } return { ...serviceRate, type, }; }; export const groupRatesByCarrier = ( allRates: RatesResponse ) => Object.entries( allRates ).reduce( ( acc, [ shipmentId, shipmentRates ] ) => ( { [ shipmentId ]: Object.entries( shipmentRates ).reduce( ( ratesAcc, [ key, { rates } ] ) => ( { ...ratesAcc, [ key as LabelRateType ]: { ...( ratesAcc[ key as LabelRateType ] || {} ), ...groupBy( rates.map( camelCaseKeys ), 'carrierId' ), }, } ), {} as ShipmentRatesResponse ), } ), {} ); export const applyShipmentHazmat = ( shipmentPackage: RequestPackage | LabelRequestPackages, shipmentHazmat: Hazmat ) => { if ( shipmentHazmat?.isHazmat && ! isEmpty( shipmentHazmat.category ) ) { return { ...shipmentPackage, hazmat: shipmentHazmat.category, }; } return shipmentPackage; }; export const extraRateTypeToTitle = ( extraType: SnakeToCamelCase< Exclude< LabelRateType, 'default' > > ) => { const mapping: Record< SnakeToCamelCase< Exclude< LabelRateType, 'default' > >, string > = { signatureRequired: __( 'Signature Required', 'woocommerce-shipping' ), adultSignatureRequired: __( 'Adult Signature Required', 'woocommerce-shipping' ), carbonNeutral: __( 'Carbon Neutral', 'woocommerce-shipping' ), additionalHandling: __( 'Additional Handling', 'woocommerce-shipping' ), saturdayDelivery: __( 'Saturday Delivery', 'woocommerce-shipping' ), }; return mapping[ extraType ]; }; export const filterToNonSignatureExtraOptions = < T >( options: ExtraOptionCharges< T > ): ExtraOptionCharges< T > => omit( options, 'signature' ); export const getExtraOptionSurcharge = ( option: LabelRateType, extraOption: ReturnType< typeof getRatesForShipment >, selectedRate?: RateWithParent ) => { const extraOptionRate = selectedRate ? getExtraOptionRate( selectedRate.rate.serviceId, extraOption?.[ selectedRate.rate.carrierId ] ?? [], selectedRate.rate.rate ?? 0, camelCase( option ) as SnakeToCamelCase< LabelRateType > )?.rate ?? 0 : 0; if ( extraOptionRate === 0 ) { return 0; } return ( extraOptionRate - ( selectedRate?.parent?.rate ?? selectedRate?.rate.rate ?? 0 ) ); };