Broadleaf Microservices
  • v1.0.0-latest-prod

Unified Admin Release Notes for 1.9.3

Important Updates

  • Now supports Node 18. Node 14 has reached end-of-life and we recommend upgrading to Node 18 as soon as possible since Node 16 reaches end of life in September 2023.

    • Upgrading Node is not required to use this update.

Features & Enhancements

  • Added new custom form actions for updating Order Fulfillment properties.

New Modal Form Action for Fulfillments

We introduced a new form action to allow defining custom actions against an Order Fulfillment. Examples are defining in metadata an action to update the Shipment info on the Fulfillment or updating a Fulfillment’s Address. This can be referenced for the FulfillmentView (type FULFILLMENT) or ItemsOrderViewSection (type ORDER_ITEM) using the action type of MODAL_FORM.

Example configuration for an action to add Shipment info to Order Fulfillment
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.broadleafcommerce.metadata.dsl.core.OperationType;
import com.broadleafcommerce.metadata.dsl.core.extension.fields.DateField;
import com.broadleafcommerce.metadata.dsl.core.utils.Actions;
import com.broadleafcommerce.metadata.dsl.core.utils.Conditionals;
import com.broadleafcommerce.metadata.dsl.core.utils.Endpoints;
import com.broadleafcommerce.metadata.dsl.core.utils.Fields;
import com.broadleafcommerce.metadata.dsl.core.utils.ValidationMethods;
import com.broadleafcommerce.metadata.dsl.core.utils.ValidationSchemas;
import com.broadleafcommerce.metadata.dsl.registry.ComponentSource;
import com.broadleafcommerce.order.metadata.autoconfigure.OrderServicesMetadataAutoConfiguration;
import com.broadleafcommerce.order.metadata.dsl.extension.views.FulfillmentView;
import com.broadleafcommerce.order.metadata.dsl.extension.views.OrderView;
import com.broadleafcommerce.order.metadata.support.OrderFulfillmentStatuses;
import com.broadleafcommerce.order.metadata.support.OrderIds;
import com.broadleafcommerce.order.metadata.support.OrderPaths;
import com.broadleafcommerce.order.metadata.support.OrderProps;
import com.broadleafcommerce.order.metadata.support.OrderScopes;

import java.util.List;

import lombok.RequiredArgsConstructor;
import lombok.experimental.UtilityClass;

@Configuration
@RequiredArgsConstructor
@AutoConfigureAfter(OrderServicesMetadataAutoConfiguration.class)
public class OrderMetadataAutoConfiguration {

    @UtilityClass
    static class ShipmentProps {
        public final String SHIPMENT = "shipment";
        public final String TRACKING_NUMBER = SHIPMENT +  ".trackingNumber";
        public final String TRACKING_URL = SHIPMENT + ".trackingUrl";
        public final String SHIP_DATE = SHIPMENT + ".shipDate";
        public final String SHIPPER_TYPE = SHIPMENT + ".shipperType";
    }

    @Bean
    public ComponentSource addCustomFulfillmentAction() {
        return registry -> {
            FulfillmentView<?> fulfillmentView =
                    (FulfillmentView<?>) registry.get(OrderIds.FULFILLMENT_DETAILS);
            fulfillmentView
                    .addAction("MODAL_FORM", Actions.action()
                            .label("order.actions.add-shipment.label")
                            .operationType(OperationType.UPDATE)
                            .placement("PRIMARY")
                            .type("MODAL_FORM")
                            // since actions don't normally have conditionals, they need to be
                            // as an attribute if needed added
                            .attribute("conditionals", List.of(
                                    Conditionals.when(OrderProps.OrderFulfillment.STATUS)
                                            .equalTo(OrderFulfillmentStatuses.FULFILLED)))
                            .addEndpoint("UPDATE", Endpoints.put()
                                    .uri(OrderPaths.ORDER_FULFILLMENTS + "/${fulfillment.id}")
                                    .scope(OrderScopes.ORDER_FULFILLMENT))
                            .addComponent(ShipmentProps.TRACKING_NUMBER, Fields.string()
                                    .name(ShipmentProps.TRACKING_NUMBER)
                                    .label("order.fields.shipment.tracking-number.label")
                                    .order(1))
                            .addComponent(ShipmentProps.TRACKING_URL, Fields.string()
                                    .name(ShipmentProps.TRACKING_URL)
                                    .label("order.fields.shipment.tracking-url.label")
                                    .order(2)
                                    .validationSchema(ValidationSchemas.string()
                                            .method(ValidationMethods.urlAbsoluteOrRelative(
                                                    "order.fields.shipment.tracking-url.valid"))))
                            .addComponent(ShipmentProps.SHIP_DATE, Fields.date()
                                    .name(ShipmentProps.SHIP_DATE)
                                    .label("order.fields.shipment.ship-date.label")
                                    .defaultStartOf(DateField.DateStartUnit.DAY)
                                    .order(3))
                            .addComponent(ShipmentProps.SHIPPER_TYPE, Fields.string()
                                    .name(ShipmentProps.SHIPPER_TYPE)
                                    .label("order.fields.shipment.shipper-type.label")
                                    .order(4)));
        };
    }

    @Bean
    public ComponentSource addCustomItemOrderAction() {
        return registry -> {
            OrderView<?> orderView =
                    (OrderView<?>) registry.get(OrderIds.DETAILS);
            orderView
                    .getItemsSection()
                    .addAction("MODAL_FORM", Actions.action()
                            .label("order.actions.add-shipment.label")
                            .operationType(OperationType.UPDATE)
                            .placement("CARD")
                            .type("MODAL_FORM")
                            // since actions don't normally have conditionals, they need to be added
                            // as an attribute if needed
                            .attribute("conditionals", List.of(
                                    Conditionals.when(OrderProps.OrderFulfillment.STATUS)
                                            .equalTo(OrderFulfillmentStatuses.FULFILLED)))
                            .addEndpoint("UPDATE", Endpoints.put()
                                    .uri(OrderPaths.ORDER_FULFILLMENTS + "/${fulfillment.id}")
                                    .scope(OrderScopes.ORDER_FULFILLMENT))
                            .addComponent(ShipmentProps.TRACKING_NUMBER, Fields.string()
                                    .name(ShipmentProps.TRACKING_NUMBER)
                                    .label("order.fields.shipment.tracking-number.label")
                                    .order(1))
                            .addComponent(ShipmentProps.TRACKING_URL, Fields.string()
                                    .name(ShipmentProps.TRACKING_URL)
                                    .label("order.fields.shipment.tracking-url.label")
                                    .order(2)
                                    .validationSchema(ValidationSchemas.string()
                                            .method(ValidationMethods.urlAbsoluteOrRelative(
                                                    "order.fields.shipment.tracking-url.valid"))))
                            .addComponent(ShipmentProps.SHIP_DATE, Fields.date()
                                    .name(ShipmentProps.SHIP_DATE)
                                    .label("order.fields.shipment.ship-date.label")
                                    .defaultStartOf(DateField.DateStartUnit.DAY)
                                    .order(3))
                            .addComponent(ShipmentProps.SHIPPER_TYPE, Fields.string()
                                    .name(ShipmentProps.SHIPPER_TYPE)
                                    .label("order.fields.shipment.shipper-type.label")
                                    .order(4)));
        };
    }

}
Example translatable text
order.fields.shipment.tracking-number.label=Tracking Number
order.fields.shipment.tracking-url.label=Tracking URL
order.fields.shipment.tracking-url.valid=Must be a valid url
order.fields.shipment.ship-date.label=Ship Date
order.fields.shipment.shipper-type.label=Carrier

order.actions.add-shipment.label=Add Shipping Info

Bug Fixes

  • Fixed issue with implicit filters not applying introduced in 1.9.2.

  • Addressed some typescript type import issues and access to the useContextParams hook for the Fulfillment and Order Items view components

  • Fixed validation of URLs that can be absolute or relative. Before, we were not validating that relative paths had to start with a slash.