<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd">
    <!-- Shipment services -->
    <simple-method method-name="createShipment" short-description="Create Shipment">
        <make-value entity-name="Shipment" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>

        <if-not-empty field="parameters.shipmentId">
            <set-pk-fields map="parameters" value-field="newEntity"/>
        <else>
            <sequenced-id sequence-name="Shipment" field="newEntity.shipmentId"/>
        </else>
        </if-not-empty>
        <field-to-result field="newEntity.shipmentId" result-name="shipmentId"/>
        <set field="shipmentTypeId" from-field="parameters.shipmentTypeId"/>
        <!-- set the created and lastModified info -->
        <now-timestamp field="newEntity.createdDate"/>
        <set from-field="userLogin.userLoginId" field="newEntity.createdByUserLogin"/>
        <now-timestamp field="newEntity.lastModifiedDate"/>
        <set from-field="userLogin.userLoginId" field="newEntity.lastModifiedByUserLogin"/>
        <!-- if needed create some WorkEfforts and remember their IDs:
            estimatedShipDate: estimatedShipWorkEffId
            estimatedArrivalDate: estimatedArrivalWorkEffId
        -->
        <if-not-empty field="parameters.estimatedShipDate">
            <set field="shipWorkEffortMap.workEffortName" value="Shipment #${newEntity.shipmentId} ${newEntity.primaryOrderId} Ship"/>
            <if>
                <condition>
                    <or>
                        <if-compare field="shipmentTypeId" operator="equals" value="OUTGOING_SHIPMENT"/>
                        <if-compare field="shipmentTypeId" operator="equals" value="SALES_SHIPMENT"/>
                        <if-compare field="shipmentTypeId" operator="equals" value="PURCHASE_RETURN"/>
                    </or>
                </condition>
                <then><set field="shipWorkEffortMap.workEffortTypeId" value="SHIPMENT_OUTBOUND"/></then>
            </if>
            <set value="CAL_TENTATIVE" field="shipWorkEffortMap.currentStatusId"/>
            <set value="WEPT_WAREHOUSING" field="shipWorkEffortMap.workEffortPurposeTypeId"/>
            <set from-field="parameters.estimatedShipDate" field="shipWorkEffortMap.estimatedStartDate"/>
            <set from-field="parameters.estimatedShipDate" field="shipWorkEffortMap.estimatedCompletionDate"/>
            <set from-field="parameters.originFacilityId" field="shipWorkEffortMap.facilityId"/>
            <set from-field="userLogin.partyId" field="shipWorkEffortMap.quickAssignPartyId"/>
            <call-service service-name="createWorkEffort" in-map-name="shipWorkEffortMap">
                <result-to-field result-name="workEffortId" field="newEntity.estimatedShipWorkEffId"/>
            </call-service>
            <if-not-empty field="newEntity.partyIdFrom">
                <set from-field="newEntity.estimatedShipWorkEffId" field="assignPartyToWorkEffortShip.workEffortId"/>
                <set from-field="newEntity.partyIdFrom" field="assignPartyToWorkEffortShip.partyId"/>
                <set value="CAL_ATTENDEE" field="assignPartyToWorkEffortShip.roleTypeId"/>
                <set value="CAL_SENT" field="assignPartyToWorkEffortShip.statusId"/>
                <call-service service-name="assignPartyToWorkEffort" in-map-name="assignPartyToWorkEffortShip"/>
            </if-not-empty>
        </if-not-empty>
        <if-not-empty field="parameters.estimatedArrivalDate">
            <set field="arrivalWorkEffortMap.workEffortName" value="Shipment #${newEntity.shipmentId} ${newEntity.primaryOrderId} Arrival" />
            <if>
                <condition>
                    <or>
                        <if-compare field="shipmentTypeId" operator="equals" value="INCOMING_SHIPMENT"/>
                        <if-compare field="shipmentTypeId" operator="equals" value="PURCHASE_SHIPMENT"/>
                        <if-compare field="shipmentTypeId" operator="equals" value="SALES_RETURN"/>
                    </or>
                </condition>
                <then><set field="arrivalWorkEffortMap.workEffortTypeId" value="SHIPMENT_INBOUND"/></then>
            </if>
            <set value="CAL_TENTATIVE" field="arrivalWorkEffortMap.currentStatusId"/>
            <set value="WEPT_WAREHOUSING" field="arrivalWorkEffortMap.workEffortPurposeTypeId"/>
            <set from-field="parameters.estimatedArrivalDate" field="arrivalWorkEffortMap.estimatedStartDate"/>
            <set from-field="parameters.estimatedArrivalDate" field="arrivalWorkEffortMap.estimatedCompletionDate"/>
            <set from-field="parameters.destinationFacilityId" field="arrivalWorkEffortMap.facilityId"/>
            <set from-field="userLogin.partyId" field="arrivalWorkEffortMap.quickAssignPartyId"/>
            <call-service service-name="createWorkEffort" in-map-name="arrivalWorkEffortMap">
                <result-to-field result-name="workEffortId" field="newEntity.estimatedArrivalWorkEffId"/>
            </call-service>
            <if-not-empty field="newEntity.partyIdTo">
                <set from-field="newEntity.estimatedArrivalWorkEffId" field="assignPartyToWorkEffortArrival.workEffortId"/>
                <set from-field="newEntity.partyIdTo" field="assignPartyToWorkEffortArrival.partyId"/>
                <set value="CAL_ATTENDEE" field="assignPartyToWorkEffortArrival.roleTypeId"/>
                <set value="CAL_SENT" field="assignPartyToWorkEffortArrival.statusId"/>
                <call-service service-name="assignPartyToWorkEffort" in-map-name="assignPartyToWorkEffortArrival"/>
            </if-not-empty>
        </if-not-empty>

        <create-value value-field="newEntity"/>

        <!-- get the ShipmentStatus history started -->
        <if-not-empty field="newEntity.statusId">
            <set field="createShipmentStatusMap.shipmentId" from-field="newEntity.shipmentId" />
            <set field="createShipmentStatusMap.statusId" from-field="newEntity.statusId" />
            <call-service service-name="createShipmentStatus" in-map-name="createShipmentStatusMap"/>
        </if-not-empty>
    </simple-method>
    
    <simple-method method-name="updateShipment" short-description="Update Shipment">
        <set value="Update Shipment" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusDelivered"/>
        <check-errors/>

        <make-value entity-name="Shipment" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key map="lookupPKMap" value-field="lookedUpValue"/>

        <!-- put the type in return map so that service consumer knows what type of shipment was updated -->
        <field-to-result field="lookedUpValue.shipmentTypeId" result-name="shipmentTypeId"/>

        <if-not-empty field="parameters.statusId">
            <if-compare-field field="parameters.statusId" to-field="lookedUpValue.statusId" operator="not-equals">
                <!-- make sure a StatusValidChange record exists, if not return error -->
                <entity-one entity-name="StatusValidChange" value-field="checkStatusValidChange" auto-field-map="false">
                    <field-map field-name="statusId" from-field="lookedUpValue.statusId"/>
                    <field-map field-name="statusIdTo" from-field="parameters.statusId"/>
                </entity-one>
                <if-empty field="checkStatusValidChange">
                    <string-to-list string="ERROR: Changing the status from ${lookedUpValue.statusId} to ${parameters.statusId} is not allowed." list="error_list"/>
                </if-empty>
                <set field="createShipmentStatusMap.shipmentId" from-field="parameters.shipmentId" />
                <set field="createShipmentStatusMap.statusId" from-field="parameters.statusId" />
                <if-not-empty field="parameters.eventDate">
                    <set field="createShipmentStatusMap.statusDate" from-field="parameters.eventDate"/>
                </if-not-empty>
                <call-service service-name="createShipmentStatus" in-map-name="createShipmentStatusMap"/>
            </if-compare-field>
        </if-not-empty>

        <!-- now finally check for errors -->
        <check-errors/>

        <!-- Check the pickup and delivery dates for changes and update the corresponding WorkEfforts -->
        <if>
            <condition>
                <or>
                    <and>
                        <not><if-empty field="parameters.estimatedShipDate"/></not>
                        <if-compare-field field="parameters.estimatedShipDate" to-field="lookedUpValue.estimatedShipDate" operator="not-equals"/>
                    </and>
                    <and>
                        <not><if-empty field="parameters.originFacilityId"/></not>
                        <if-compare-field field="parameters.originFacilityId" to-field="lookedUpValue.originFacilityId" operator="not-equals"/>
                    </and>
                    <and>
                        <not><if-empty field="parameters.statusId"/></not>
                        <if-compare-field field="parameters.statusId" to-field="lookedUpValue.statusId" operator="not-equals"/>
                        <or>
                            <if-compare field="parameters.statusId" value="SHIPMENT_CANCELLED" operator="equals"/>
                            <if-compare field="parameters.statusId" value="SHIPMENT_PACKED" operator="equals"/>
                            <if-compare field="parameters.statusId" value="SHIPMENT_SHIPPED" operator="equals"/>
                        </or>
                    </and>
                </or>
            </condition>
            <then>
                <entity-one entity-name="WorkEffort" value-field="estShipWe" auto-field-map="false">
                    <field-map field-name="workEffortId" from-field="lookedUpValue.estimatedShipWorkEffId"/>
                </entity-one>
                <if-not-empty field="estShipWe">
                    <set from-field="parameters.estimatedShipDate" field="estShipWe.estimatedStartDate"/>
                    <set from-field="parameters.estimatedShipDate" field="estShipWe.estimatedCompletionDate"/>
                    <set from-field="parameters.originFacilityId" field="estShipWe.facilityId"/>
                    <if>
                        <condition>
                            <and>
                                <not><if-empty field="parameters.statusId"/></not>
                                <if-compare-field field="parameters.statusId" to-field="lookedUpValue.statusId" operator="not-equals"/>
                            </and>
                        </condition>
                        <then>
                            <if-compare field="parameters.statusId" value="SHIPMENT_CANCELLED" operator="equals">
                                <set value="CAL_CANCELLED" field="estShipWe.currentStatusId"/>
                            </if-compare>
                            <if-compare field="parameters.statusId" value="SHIPMENT_PACKED" operator="equals">
                                <set value="CAL_CONFIRMED" field="estShipWe.currentStatusId"/>
                            </if-compare>
                            <if-compare field="parameters.statusId" value="SHIPMENT_SHIPPED" operator="equals">
                                <set value="CAL_COMPLETED" field="estShipWe.currentStatusId"/>
                            </if-compare>
                        </then>
                    </if>
                    <set-service-fields service-name="updateWorkEffort" map="estShipWe" to-map="estShipWeUpdMap"/>
                    <call-service service-name="updateWorkEffort" in-map-name="estShipWeUpdMap"/>
                </if-not-empty>
            </then>
        </if>
        <if>
            <condition>
                <or>
                    <and>
                        <not><if-empty field="parameters.estimatedArrivalDate"/></not>
                        <if-compare-field field="parameters.estimatedArrivalDate" to-field="lookedUpValue.estimatedArrivalDate" operator="not-equals"/>
                    </and>
                    <and>
                        <not><if-empty field="parameters.destinationFacilityId"/></not>
                        <if-compare-field field="parameters.destinationFacilityId" to-field="lookedUpValue.destinationFacilityId" operator="not-equals"/>
                    </and>
                </or>
            </condition>
            <then>
                <entity-one entity-name="WorkEffort" value-field="estimatedArrivalWorkEffort" auto-field-map="false">
                    <field-map field-name="workEffortId" from-field="lookedUpValue.estimatedArrivalWorkEffId"/>
                </entity-one>
                <if-not-empty field="estimatedArrivalWorkEffort">
                    <set from-field="parameters.estimatedArrivalDate" field="estimatedArrivalWorkEffort.estimatedStartDate"/>
                    <set from-field="parameters.estimatedArrivalDate" field="estimatedArrivalWorkEffort.estimatedCompletionDate"/>
                    <set from-field="parameters.destinationFacilityId" field="estimatedArrivalWorkEffort.facilityId"/>
                    <set-service-fields service-name="updateWorkEffort" map="estimatedArrivalWorkEffort" to-map="estimatedArrivalWorkEffortUpdMap"/>
                    <call-service service-name="updateWorkEffort" in-map-name="estimatedArrivalWorkEffortUpdMap"/>
                </if-not-empty>
            </then>
        </if>

        <!-- if the partyIdTo or partyIdFrom has changed, add WEPAs -->
        <if>
            <condition>
                <and>
                    <not><if-empty field="parameters.partyIdFrom"/></not>
                    <if-compare-field field="parameters.partyIdFrom" to-field="lookedUpValue.partyIdFrom" operator="not-equals"/>
                    <not><if-empty field="lookedUpValue.estimatedShipWorkEffId"/></not>
                </and>
            </condition>
            <then>
                <set field="assignPartyToWorkEffortShip.workEffortId" from-field="lookedUpValue.estimatedShipWorkEffId"/>
                <set field="assignPartyToWorkEffortShip.partyId" from-field="parameters.partyIdFrom"/>
                <find-by-and entity-name="WorkEffortPartyAssignment" list="existingShipWepas" map="assignPartyToWorkEffortShip"/>
                <filter-list-by-date list="existingShipWepas"/>
                <if-empty field="existingShipWepas">
                    <set field="assignPartyToWorkEffortShip.roleTypeId" value="CAL_ATTENDEE"/>
                    <set field="assignPartyToWorkEffortShip.statusId" value="CAL_SENT"/>
                    <call-service service-name="assignPartyToWorkEffort" in-map-name="assignPartyToWorkEffortShip"/>
                </if-empty>
            </then>
        </if>
        <if>
            <condition>
                <and>
                    <not><if-empty field="parameters.partyIdTo"/></not>
                    <if-compare-field field="parameters.partyIdTo" to-field="lookedUpValue.partyIdTo" operator="not-equals"/>
                    <not><if-empty field="lookedUpValue.estimatedArrivalWorkEffId"/></not>
                </and>
            </condition>
            <then>
                <set field="assignPartyToWorkEffortArrival.workEffortId" from-field="lookedUpValue.estimatedArrivalWorkEffId"/>
                <set field="assignPartyToWorkEffortArrival.partyId" from-field="parameters.partyIdTo"/>
                <find-by-and entity-name="WorkEffortPartyAssignment" list="existingArrivalWepas" map="assignPartyToWorkEffortArrival"/>
                <filter-list-by-date list="existingArrivalWepas"/>
                <if-empty field="existingArrivalWepas">
                    <set field="assignPartyToWorkEffortArrival.roleTypeId" value="CAL_ATTENDEE"/>
                    <set field="assignPartyToWorkEffortArrival.statusId" value="CAL_SENT"/>
                    <call-service service-name="assignPartyToWorkEffort" in-map-name="assignPartyToWorkEffortArrival"/>
                </if-empty>
            </then>
        </if>

        <!-- finally before setting nonpk fields, set the oldStatusId, oldPrimaryOrderId, oldOriginFacilityId, oldDestinationFacilityId -->
        <field-to-result field="lookedUpValue.statusId" result-name="oldStatusId"/>
        <field-to-result field="lookedUpValue.primaryOrderId" result-name="oldPrimaryOrderId"/>
        <field-to-result field="lookedUpValue.originFacilityId" result-name="oldOriginFacilityId"/>
        <field-to-result field="lookedUpValue.destinationFacilityId" result-name="oldDestinationFacilityId"/>

        <!-- now that all changes have been checked, set the nonpks -->
        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
        <now-timestamp field="lookedUpValue.lastModifiedDate"/>
        <set from-field="userLogin.userLoginId" field="lookedUpValue.lastModifiedByUserLogin"/>
        <field-to-result field="lookedUpValue.shipmentId" result-name="shipmentId"/>
        <store-value value-field="lookedUpValue"/>
    </simple-method>

    <simple-method method-name="deleteShipment" short-description="Delete Shipment">
        <set value="Delete Shipment" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>
        <entity-one entity-name="Shipment" value-field="lookedUpValue"/>
        <remove-value value-field="lookedUpValue"/>
    </simple-method>

    <simple-method method-name="createShipmentForReturn" short-description="Create Shipment based on ReturnHeader">
        <entity-one entity-name="ReturnHeader" value-field="returnHeader">
            <field-map field-name="returnId" from-field="parameters.returnId"/>
        </entity-one>

        <set from-field="returnHeader.fromPartyId" field="shipmentCtx.partyIdFrom"/>
        <set from-field="returnHeader.toPartyId" field="shipmentCtx.partyIdTo"/>
        <set from-field="returnHeader.originContactMechId" field="shipmentCtx.originContactMechId"/>
        <set from-field="returnHeader.destinationFacilityId" field="shipmentCtx.destinationFacilityId"/>
        <set from-field="returnHeader.returnId" field="shipmentCtx.primaryReturnId"/>
        <!-- later different behavior for customer vs. returns would happen here -->
        <if>
            <condition>
                <if-compare field="returnHeader.returnHeaderTypeId" operator="contains" value="CUSTOMER_"/>
            </condition>
            <then>
                <set field="shipmentCtx.shipmentTypeId" value="SALES_RETURN"/>
                <set field="shipmentCtx.statusId" value="PURCH_SHIP_CREATED"/>  <!-- we may later need different status codes for return shipments -->
            </then>
        <else-if>
            <condition>
                <if-compare field="returnHeader.returnHeaderTypeId" operator="equals" value="VENDOR_RETURN"/>
            </condition>
            <then>
                <set field="shipmentCtx.shipmentTypeId" value="PURCHASE_RETURN"/>
                <set field="shipmentCtx.statusId" value="SHIPMENT_INPUT"/>
            </then>
        </else-if>
        <else>
             <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityReturnHeaderTypeNotSupported"/>
            </add-error>
            <check-errors/>
        </else>
        </if>

        <call-service service-name="createShipment" in-map-name="shipmentCtx">
            <result-to-field result-name="shipmentId"/>
        </call-service>

        <field-to-result field="shipmentId"/>
    </simple-method>

    <simple-method method-name="createShipmentAndItemsForReturn" short-description="Create Shipment and ShipmentItems based on ReturnHeader and ReturnItems">
        <entity-condition entity-name="ReturnItem" list="returnItems">
            <condition-expr field-name="returnId" operator="equals" from-field="parameters.returnId"/>
        </entity-condition>

       <!-- The return shipment is created if the return contains one or more physical products -->
        <set field="isPhysicalProductAvailable" value="false" type="Boolean"/>
        <iterate list="returnItems" entry="returnItem">
            <get-related-one value-field="returnItem" relation-name="Product" to-value-field="product"/>
            <if-not-empty field="product">
                <call-class-method class-name="org.apache.ofbiz.product.product.ProductWorker" method-name="isPhysical" ret-field="isPhysicalProduct">
                    <field field="product" type="GenericValue"/>
                </call-class-method>
                <if-compare field="isPhysicalProduct" operator="equals" value="true" type="Boolean">
                    <set field="isPhysicalProductAvailable" value="true" type="Boolean"/>
                </if-compare>
            </if-not-empty>
        </iterate>

        <if-compare field="isPhysicalProductAvailable" operator="equals" value="true" type="Boolean">
        <set-service-fields service-name="createShipmentForReturn" map="parameters" to-map="shipmentCtx"/>
        <call-service service-name="createShipmentForReturn" in-map-name="shipmentCtx">
            <result-to-field result-name="shipmentId"/>
        </call-service>
        <check-errors/>
        <log level="info" message="Created new shipment ${shipmentId}"/>

        <iterate list="returnItems" entry="returnItem">

            <!-- Shipment items are created only for physical products -->
            <set field="isPhysicalProduct" value="false" type="Boolean"/>
            <get-related-one value-field="returnItem" relation-name="Product" to-value-field="product"/>
            <if-not-empty field="product">
                <call-class-method class-name="org.apache.ofbiz.product.product.ProductWorker" method-name="isPhysical" ret-field="isPhysicalProduct">
                    <field field="product" type="GenericValue"/>
                </call-class-method>
            </if-not-empty>

            <if-compare field="isPhysicalProduct" operator="equals" value="true" type="Boolean">
            <clear-field field="shipItemCtx"/>
            <set from-field="shipmentId" field="shipItemCtx.shipmentId"/>
            <set from-field="returnItem.productId" field="shipItemCtx.productId"/>
            <set from-field="returnItem.returnQuantity" field="shipItemCtx.quantity"/>
            <log level="info" message="calling create shipment item with ${shipItemCtx}"/>
            <call-service service-name="createShipmentItem" in-map-name="shipItemCtx">
                <result-to-field result-name="shipmentItemSeqId"/>
            </call-service>
            <clear-field field="shipItemCtx"/>
            <set from-field="shipmentId" field="shipItemCtx.shipmentId"/>
            <set from-field="shipmentItemSeqId" field="shipItemCtx.shipmentItemSeqId"/>
            <set from-field="returnItem.returnId" field="shipItemCtx.returnId"/>
            <set from-field="returnItem.returnItemSeqId" field="shipItemCtx.returnItemSeqId"/>
            <set from-field="returnItem.returnQuantity" field="shipItemCtx.quantity"/>
            <call-service service-name="createReturnItemShipment" in-map-name="shipItemCtx"/>
            </if-compare>
        </iterate>

        <field-to-result field="shipmentId"/>
        </if-compare>
    </simple-method>

    <simple-method method-name="createShipmentAndItemsForVendorReturn" short-description="Create Shipment and ShipmentItems based on primaryReturnId for Vendor return">
        <set-service-fields service-name="createShipment" map="parameters" to-map="shipmentCtx"/>
        <call-service service-name="createShipment" in-map-name="shipmentCtx">
            <result-to-field result-name="shipmentId"/>
        </call-service>
        <check-errors/>
        <log level="info" message="Created new shipment ${shipmentId}"/>

        <entity-condition entity-name="ReturnItem" list="returnItems">
            <condition-expr field-name="returnId" operator="equals" from-field="parameters.primaryReturnId"/>
        </entity-condition>
        <iterate list="returnItems" entry="returnItem">
            <clear-field field="shipItemCtx"/>
            <set from-field="shipmentId" field="shipItemCtx.shipmentId"/>
            <set from-field="returnItem.productId" field="shipItemCtx.productId"/>
            <set from-field="returnItem.returnQuantity" field="shipItemCtx.quantity"/>
            <log level="info" message="calling create shipment item with ${shipItemCtx}"/>
            <call-service service-name="createShipmentItem" in-map-name="shipItemCtx">
                <result-to-field result-name="shipmentItemSeqId"/>
            </call-service>
            <clear-field field="shipItemCtx"/>
            <set from-field="shipmentId" field="shipItemCtx.shipmentId"/>
            <set from-field="shipmentItemSeqId" field="shipItemCtx.shipmentItemSeqId"/>
            <set from-field="returnItem.returnId" field="shipItemCtx.returnId"/>
            <set from-field="returnItem.returnItemSeqId" field="shipItemCtx.returnItemSeqId"/>
            <set from-field="returnItem.returnQuantity" field="shipItemCtx.quantity"/>
            <call-service service-name="createReturnItemShipment" in-map-name="shipItemCtx"/>
        </iterate>

        <field-to-result field="shipmentId"/>
    </simple-method>

    <simple-method method-name="setShipmentSettingsFromPrimaryOrder" short-description="Set Shipment Settings From Primary Order">
        <set value="Set Shipment Settings From Primary Order" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <!-- on Shipment set partyIdFrom, partyIdTo (vendorPartyId), originContactMechId, destinationContactMechId, estimatedShipCost -->
        <entity-one entity-name="Shipment" value-field="shipment"/>

        <if-empty field="shipment.primaryOrderId">
            <!-- No primaryOrderId specified, don't do anything -->
            <log level="info" message="Not running setShipmentSettingsFromPrimaryOrder, primaryOrderId is empty for shipmentId [${shipment.shipmentId}]"/>
            <return response-code="success"/>
        </if-empty>

        <!-- TODO: we may not want to check this if, for example, Purchase Orders don't have any OrderItemShipGroups -->
        <if-empty field="shipment.primaryShipGroupSeqId">
            <!-- No primaryShipGroupSeqId specified, don't do anything -->
            <log level="info" message="Not running setShipmentSettingsFromPrimaryOrder, primaryShipGroupSeqId is empty for shipmentId [${parameters.shipmentId}]"/>
            <return response-code="success"/>
        </if-empty>

        <entity-one entity-name="OrderHeader" value-field="orderHeader" auto-field-map="false">
            <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
        </entity-one>
        <if-not-empty field="shipment.primaryShipGroupSeqId">
            <entity-one entity-name="OrderItemShipGroup" value-field="orderItemShipGroup" auto-field-map="false">
                <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
                <field-map field-name="shipGroupSeqId" from-field="shipment.primaryShipGroupSeqId"/>
            </entity-one>
        </if-not-empty>

        <if-compare field="orderHeader.orderTypeId" operator="equals" value="SALES_ORDER">
            <set value="SALES_SHIPMENT" field="shipment.shipmentTypeId"/>
        </if-compare>
        <if-compare field="orderHeader.orderTypeId" operator="equals" value="PURCHASE_ORDER">
            <if-compare field="shipment.shipmentTypeId" operator="not-equals" value="DROP_SHIPMENT">
                <set value="PURCHASE_SHIPMENT" field="shipment.shipmentTypeId"/>
            </if-compare>
        </if-compare>

        <!-- set the facility if we are from a store with a single facility -->
        <if>
            <condition>
                <and>
                    <if-empty field="shipment.originFacilityId"/>
                    <if-compare field="shipment.shipmentTypeId" operator="equals" value="SALES_SHIPMENT"/>
                    <not><if-empty field="orderHeader.productStoreId"/></not>
                </and>
            </condition>
            <then>
                <entity-one entity-name="ProductStore" value-field="productStore" auto-field-map="false">
                    <field-map field-name="productStoreId" from-field="orderHeader.productStoreId"/>
                </entity-one>
                <if-compare field="productStore.oneInventoryFacility" operator="equals" value="Y">
                    <set from-field="productStore.inventoryFacilityId" field="shipment.originFacilityId"/>
                </if-compare>
            </then>
        </if>


        <!-- partyIdFrom, partyIdTo (vendorPartyId) - NOTE: these work the same for Purchase and Sales Orders... -->
        <entity-and entity-name="OrderRole" list="orderRoles">
            <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
        </entity-and>

        <!-- From: SHIP_FROM_VENDOR -->
        <if-empty field="shipment.partyIdFrom">
            <set value="SHIP_FROM_VENDOR" field="limitRoleMap.roleTypeId"/>
            <filter-list-by-and list="orderRoles" map="limitRoleMap" to-list="limitOrderRoles"/>
            <first-from-list list="limitOrderRoles" entry="limitOrderRole"/>
            <if-not-empty field="limitOrderRole">
                <set from-field="limitOrderRole.partyId" field="shipment.partyIdFrom"/>
            </if-not-empty>
            <clear-field field="limitRoleMap"/><clear-field field="limitOrderRoles"/><clear-field field="limitOrderRole"/>
        </if-empty>
        <!-- From: VENDOR -->
        <if-empty field="shipment.partyIdFrom">
            <set value="VENDOR" field="limitRoleMap.roleTypeId"/>
            <filter-list-by-and list="orderRoles" map="limitRoleMap" to-list="limitOrderRoles"/>
            <first-from-list list="limitOrderRoles" entry="limitOrderRole"/>
            <if-not-empty field="limitOrderRole">
                <set from-field="limitOrderRole.partyId" field="shipment.partyIdFrom"/>
            </if-not-empty>
            <clear-field field="limitRoleMap"/><clear-field field="limitOrderRoles"/><clear-field field="limitOrderRole"/>
        </if-empty>

        <!-- To: SHIP_TO_CUSTOMER -->
        <if-empty field="shipment.partyIdTo">
            <set value="SHIP_TO_CUSTOMER" field="limitRoleMap.roleTypeId"/>
            <filter-list-by-and list="orderRoles" map="limitRoleMap" to-list="limitOrderRoles"/>
            <first-from-list list="limitOrderRoles" entry="limitOrderRole"/>
            <if-not-empty field="limitOrderRole">
                <set from-field="limitOrderRole.partyId" field="shipment.partyIdTo"/>
            </if-not-empty>
            <clear-field field="limitRoleMap"/><clear-field field="limitOrderRoles"/><clear-field field="limitOrderRole"/>
        </if-empty>
        <!-- To: CUSTOMER -->
        <if-empty field="shipment.partyIdTo">
            <set value="CUSTOMER" field="limitRoleMap.roleTypeId"/>
            <filter-list-by-and list="orderRoles" map="limitRoleMap" to-list="limitOrderRoles"/>
            <first-from-list list="limitOrderRoles" entry="limitOrderRole"/>
            <if-not-empty field="limitOrderRole">
                <set from-field="limitOrderRole.partyId" field="shipment.partyIdTo"/>
            </if-not-empty>
            <clear-field field="limitRoleMap"/><clear-field field="limitOrderRoles"/><clear-field field="limitOrderRole"/>
        </if-empty>

        <entity-and entity-name="OrderContactMech" list="orderContactMechs">
            <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
        </entity-and>
        <!-- destinationContactMechId -->
        <if-empty field="shipment.destinationContactMechId">
            <!-- first try from orderContactMechs -->
            <set value="SHIPPING_LOCATION" field="destinationContactMap.contactMechPurposeTypeId"/>
            <filter-list-by-and list="orderContactMechs" map="destinationContactMap" to-list="destinationOrderContactMechs"/>
            <first-from-list list="destinationOrderContactMechs" entry="destinationOrderContactMech"/>
            <if-not-empty field="destinationOrderContactMech">
                <set from-field="destinationOrderContactMech.contactMechId" field="shipment.destinationContactMechId"/>
               <else>
                  <log level="warning" message="Cannot find a shipping destination address for ${shipment.primaryOrderId}"/>
                </else>
            </if-not-empty>
        </if-empty>
        <!-- originContactMechId.  Only do this if it is not a purchase shipment -->
        <if-compare field="shipment.shipmentTypeId" operator="not-equals" value="PURCHASE_SHIPMENT">
            <if-empty field="shipment.originContactMechId">
                <set value="SHIP_ORIG_LOCATION" field="originContactMap.contactMechPurposeTypeId"/>
                <filter-list-by-and list="orderContactMechs" map="originContactMap" to-list="originOrderContactMechs"/>
                <first-from-list list="originOrderContactMechs" entry="originOrderContactMech"/>
                <if-not-empty field="originOrderContactMech">
                    <set from-field="originOrderContactMech.contactMechId" field="shipment.originContactMechId"/>
                    <else>
                        <log level="warning" message="Cannot find a shipping origin address for ${shipment.primaryOrderId}"/>
                    </else>
                </if-not-empty>
            </if-empty>
        </if-compare>

        <!-- destinationTelecomNumberId -->
        <if-empty field="shipment.destinationTelecomNumberId">
            <set value="PHONE_SHIPPING" field="destTelecomOrderContactMechMap.contactMechPurposeTypeId"/>
            <filter-list-by-and list="orderContactMechs" map="destTelecomOrderContactMechMap" to-list="destTelecomOrderContactMechs"/>
            <first-from-list list="destTelecomOrderContactMechs" entry="destTelecomOrderContactMech"/>
            <if-not-empty field="destTelecomOrderContactMech">
                <set from-field="destTelecomOrderContactMech.contactMechId" field="shipment.destinationTelecomNumberId"/>
                <else>
                    <!-- use the first unexpired phone number of the shipment partyIdTo -->
                    <entity-and entity-name="PartyAndTelecomNumber" list="phoneNumbers" filter-by-date="true">
                        <field-map field-name="partyId" from-field="shipment.partyIdTo"/>
                    </entity-and>
                    <first-from-list list="phoneNumbers" entry="phoneNumber"/>
                    <if-not-empty field="phoneNumber">
                        <set from-field="phoneNumber.contactMechId" field="shipment.destinationTelecomNumberId"/>
                        <else>
                            <log level="warning" message="Cannot find a shipping destination phone number for ${shipment.primaryOrderId}"/>
                        </else>
                    </if-not-empty>
                </else>
            </if-not-empty>
        </if-empty>
        <!-- originTelecomNumberId -->
        <if-empty field="shipment.originTelecomNumberId">
            <set value="PHONE_SHIP_ORIG" field="originTelecomOrderContactMechMap.contactMechPurposeTypeId"/>
            <filter-list-by-and list="orderContactMechs" map="originTelecomOrderContactMechMap" to-list="originTelecomOrderContactMechs"/>
            <first-from-list list="originTelecomOrderContactMechs" entry="originTelecomOrderContactMech"/>
            <if-not-empty field="originTelecomOrderContactMech">
                <set from-field="originTelecomOrderContactMech.contactMechId" field="shipment.originTelecomNumberId"/>
                <else>
                    <log level="warning" message="Cannot find a shipping origin phone number for ${shipment.primaryOrderId}"/>
                </else>
            </if-not-empty>
        </if-empty>

        <!-- set the destination facility if it is a purchase order -->
        <if-empty field="shipment.destinationFacilityId">
            <if-compare field="shipment.shipmentTypeId" operator="equals" value="PURCHASE_SHIPMENT">
                <set from-field="shipment.destinationContactMechId" field="facilityLookup.contactMechId"/>
                <find-by-and entity-name="FacilityContactMech" map="facilityLookup" list="facilities"/>
                <first-from-list list="facilities" entry="destinationFacility"/>
                <set from-field="destinationFacility.facilityId" field="shipment.destinationFacilityId"/>
            </if-compare>
        </if-empty>

        <!-- NOTE: use new place to find source/destination location/addresses for new OrderItemShipGroup.contactMechId (destination address for sales orders, source address for purchase orders) -->
        <!-- do this second so it will override the orderContactMech -->
        <!-- TODO: maybe we should add a new entity for OrderItemShipGroup ContactMechs? -->
        <if-not-empty field="orderItemShipGroup">
            <if-compare field="orderHeader.orderTypeId" operator="equals" value="SALES_ORDER">
                <set from-field="orderItemShipGroup.contactMechId" field="shipment.destinationContactMechId"/>
                <set from-field="orderItemShipGroup.telecomContactMechId" field="shipment.destinationTelecomNumberId"/>
            </if-compare>
        </if-not-empty>

        <if-empty field="shipment.estimatedShipCost">
            <script>groovy:
                    import java.math.BigDecimal
                    import org.apache.ofbiz.order.order.OrderReadHelper

                    orderReadHelper = new OrderReadHelper(orderHeader)
                    orderItems = orderReadHelper.getValidOrderItems()
                    orderAdjustments = orderReadHelper.getAdjustments()
                    orderHeaderAdjustments = orderReadHelper.getOrderHeaderAdjustments()
                    orderSubTotal = orderReadHelper.getOrderItemsSubTotal()

                    shippingAmount = OrderReadHelper.getAllOrderItemsAdjustmentsTotal(orderItems, orderAdjustments, false, false, true)
                    shippingAmount = shippingAmount.add(OrderReadHelper.calcOrderAdjustments(orderHeaderAdjustments, orderSubTotal, false, false, true))
                    //org.apache.ofbiz.base.util.Debug.log("shippingAmmount=" + shippingAmount)
                    shipment.put("estimatedShipCost", shippingAmount)
            </script>
        </if-empty>

        <!-- create a ShipmentRouteSegment with originFacilityId (if set on Shipment), destContactMechId,
            and from OrderItemShipGroup shipmentMethodTypeId, carrierPartyId, etc -->
            <set from-field="shipment.shipmentId" field="shipmentRouteSegmentMap.shipmentId"/>
        <find-by-and entity-name="ShipmentRouteSegment" map="shipmentRouteSegmentMap" list="shipmentRouteSegments"/>
        <if-empty field="shipmentRouteSegments">
            <!-- estimatedShipDate, estimatedArrivalDate -->
            <set from-field="shipment.estimatedShipDate" field="shipmentRouteSegmentMap.estimatedStartDate"/>
            <set from-field="shipment.estimatedArrivalDate" field="shipmentRouteSegmentMap.estimatedArrivalDate"/>

            <set from-field="shipment.originFacilityId" field="shipmentRouteSegmentMap.originFacilityId"/>
            <set from-field="shipment.originContactMechId" field="shipmentRouteSegmentMap.originContactMechId"/>
            <set from-field="shipment.originTelecomNumberId" field="shipmentRouteSegmentMap.originTelecomNumberId"/>
            <set from-field="shipment.destinationFacilityId" field="shipmentRouteSegmentMap.destFacilityId"/>
            <set from-field="shipment.destinationContactMechId" field="shipmentRouteSegmentMap.destContactMechId"/>
            <set from-field="shipment.destinationTelecomNumberId" field="shipmentRouteSegmentMap.destTelecomNumberId"/>

            <entity-one entity-name="OrderItemShipGroup" value-field="orderItemShipGroup">
                <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
                <field-map field-name="shipGroupSeqId" from-field="shipment.primaryShipGroupSeqId"/>
            </entity-one>
            <if-not-empty field="orderItemShipGroup">
                <set from-field="orderItemShipGroup.carrierPartyId" field="shipmentRouteSegmentMap.carrierPartyId"/>
                <set from-field="orderItemShipGroup.shipmentMethodTypeId" field="shipmentRouteSegmentMap.shipmentMethodTypeId"/>
            </if-not-empty>
            <call-service service-name="createShipmentRouteSegment" in-map-name="shipmentRouteSegmentMap"/>
        </if-empty>

        <set-service-fields service-name="updateShipment" map="shipment" to-map="shipmentUpdateMap"/>
        <call-service service-name="updateShipment" in-map-name="shipmentUpdateMap"/>
    </simple-method>

    <simple-method method-name="setShipmentSettingsFromFacilities" short-description="Set Shipment Settings From Facilities">
        <set value="Set Shipment Settings From Facilities" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <entity-one entity-name="Shipment" value-field="shipment"/>

        <clone-value value-field="shipment" new-value-field="shipmentCopy"/>

        <string-to-list string="-fromDate" list="descendingFromDateOrder"/>
        <if-not-empty field="shipment.originFacilityId">
            <if-empty field="shipment.originContactMechId">
                <script>groovy:
                    facilityContactMech = org.apache.ofbiz.party.contact.ContactMechWorker.getFacilityContactMechByPurpose(
                                delegator, shipment.get("originFacilityId"), 
                                org.apache.ofbiz.base.util.UtilMisc.toList("SHIP_ORIG_LOCATION", "PRIMARY_LOCATION"))
                    if (facilityContactMech != null) {
                        shipment.put("originContactMechId", facilityContactMech.get("contactMechId"));
                    }
                </script>
            </if-empty>
            <if-empty field="shipment.originTelecomNumberId">
                <script>groovy:
                    facilityContactMech = org.apache.ofbiz.party.contact.ContactMechWorker.getFacilityContactMechByPurpose(
                                delegator, shipment.get("originFacilityId"), 
                                org.apache.ofbiz.base.util.UtilMisc.toList("PHONE_SHIP_ORIG", "PRIMARY_PHONE"))
                    if (facilityContactMech != null) {
                        shipment.put("originTelecomNumberId", facilityContactMech.get("contactMechId"))
                    }
                </script>
            </if-empty>
        </if-not-empty>
        <if-not-empty field="shipment.destinationFacilityId">
            <if-empty field="shipment.destinationContactMechId">
                <script>groovy:
                    facilityContactMech = org.apache.ofbiz.party.contact.ContactMechWorker.getFacilityContactMechByPurpose(
                                delegator, shipment.get("destinationFacilityId"), 
                                org.apache.ofbiz.base.util.UtilMisc.toList("SHIPPING_LOCATION", "PRIMARY_LOCATION"))
                    if (facilityContactMech != null) {
                        shipment.put("destinationContactMechId", facilityContactMech.get("contactMechId"))
                    }
                </script>
            </if-empty>
            <if-empty field="shipment.destinationTelecomNumberId">
                <script>groovy:
                    facilityContactMech = org.apache.ofbiz.party.contact.ContactMechWorker.getFacilityContactMechByPurpose(
                                delegator, shipment.get("destinationFacilityId"), 
                                org.apache.ofbiz.base.util.UtilMisc.toList("PHONE_SHIPPING", "PRIMARY_PHONE"))
                    if (facilityContactMech != null) {
                        shipment.put("destinationTelecomNumberId", facilityContactMech.get("contactMechId"))
                    }
                </script>
            </if-empty>
        </if-not-empty>

        <if-compare-field field="shipment" to-field="shipmentCopy" operator="not-equals">
            <set-service-fields service-name="updateShipment" map="shipment" to-map="shipmentUpdateMap"/>
            <call-service service-name="updateShipment" in-map-name="shipmentUpdateMap"/>
        </if-compare-field>
    </simple-method>

    <simple-method method-name="sendShipmentScheduledNotification" short-description="Send Shipment Scheduled Notification">
        <entity-one entity-name="Shipment" value-field="shipment"/>

        <!-- find email address for currently logged in user, set as sendFrom -->
        <entity-and entity-name="PartyAndContactMech" list="curUserPartyAndContactMechs">
            <field-map field-name="partyId" from-field="userLogin.partyId"/>
            <field-map field-name="contactMechTypeId" value="EMAIL_ADDRESS"/>
        </entity-and>

        <first-from-list list="curUserPartyAndContactMechs" entry="curUserPartyAndContactMech"/>
        <string-append field="sendEmailMap.sendFrom" string="${curUserPartyAndContactMech.infoString}"/>

        <!-- find email addresses of partyIdFrom, set as sendTo -->
        <set from-field="shipment.partyIdFrom" field="sendToPartyIdMap.${shipment.partyIdFrom}"/>

        <!-- find email addresses of all parties not equal to partyIdFrom in SUPPLIER_AGENT roleTypeId associated with primary order, set as sendTo -->
        <entity-and entity-name="OrderRole" list="supplierAgentOrderRoles">
            <field-map field-name="orderId" from-field="shipment.primaryOrderId"/>
            <field-map field-name="roleTypeId" value="SUPPLIER_AGENT"/>
        </entity-and>

        <iterate list="supplierAgentOrderRoles" entry="supplierAgentOrderRole">
            <set from-field="supplierAgentOrderRole.partyId" field="sendToPartyIdMap[supplierAgentOrderRole.partyId]"/>
        </iterate>

        <!-- go through all send to parties and get email addresses -->
        <iterate-map key="sendToPartyId" value="sendToPartyIdValue" map="sendToPartyIdMap">
            <entity-and entity-name="PartyAndContactMech" list="sendToPartyPartyAndContactMechs">
                <field-map field-name="partyId" from-field="sendToPartyId"/>
                <field-map field-name="contactMechTypeId" value="EMAIL_ADDRESS"/>
            </entity-and>

            <iterate list="sendToPartyPartyAndContactMechs" entry="sendToPartyPartyAndContactMech">
                <string-append field="sendEmailMap.sendTo" string="${sendToPartyPartyAndContactMech.infoString}" prefix=","/>
            </iterate>
        </iterate-map>

        <!-- set subject, contentType, templateName, templateData -->
        <set value="Scheduled Notification for Shipment ${shipment.shipmentId}" field="sendEmailMap.subject"/>
        <if-not-empty field="shipment.primaryOrderId">
            <string-append string=" for Primary Order ${shipment.primaryOrderId}" field="sendEmailMap.subject"/>
        </if-not-empty>
        <set value="text/html" field="sendEmailMap.contentType"/>
        <set value="component://product/template/shipment/ShipmentScheduledNotice.ftl" field="sendEmailMap.templateName"/>
        <set from-field="shipment" field="sendEmailMap.templateData.shipment"/>

        <!-- call sendGenericNotificationEmail service, if enough information was found -->
        <log level="info" message="Sending generic notification email (if all info is in place): ${sendEmailMap}"/>
        <if>
            <condition>
                <and>
                    <not><if-empty field="sendEmailMap.sendTo"/></not>
                    <not><if-empty field="sendEmailMap.sendFrom"/></not>
                </and>
            </condition>
            <then>
                <call-service service-name="sendGenericNotificationEmail" in-map-name="sendEmailMap"/>
            </then>
            <else>
                <log level="error" message="Insufficient data to send notice email: ${sendEmailMap}"/>
            </else>
        </if>
    </simple-method>

    <simple-method method-name="balanceItemIssuancesForShipment" short-description="Release the purchase order's items assigned to the shipment but not actually received">
        <entity-one entity-name="Shipment" value-field="shipment"/>
        <get-related value-field="shipment" relation-name="ItemIssuance" list="issuances"/>
        <iterate list="issuances" entry="issuance">
            <entity-and entity-name="ShipmentReceipt" list="receipts">
                <field-map field-name="shipmentId" from-field="shipment.shipmentId"/>
                <field-map field-name="orderId" from-field="issuance.orderId"/>
                <field-map field-name="orderItemSeqId" from-field="issuance.orderItemSeqId"/>
            </entity-and>
            <iterate list="receipts" entry="receipt">
                <calculate field="issuanceQuantity">
                    <calcop operator="get" field="receipt.quantityAccepted"/>
                    <calcop operator="get" field="receipt.quantityRejected"/>
                    <calcop operator="get" field="issuanceQuantity"/>
                </calculate>
            </iterate>
            <set field="issuance.quantity" from-field="issuanceQuantity"/>
            <store-value value-field="issuance"/>
            <clear-field field="issuanceQuantity"/>
        </iterate>
    </simple-method>

    <!-- ShipmentItem services -->
    <simple-method method-name="createShipmentItem" short-description="Create ShipmentItem">
        <set value="Create ShipmentItem" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentItem" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>
        <!-- if no shipmentItemSeqId, generate one based on existing items, ie one greater than the current higher number -->
        <make-next-seq-id value-field="newEntity" seq-field-name="shipmentItemSeqId"/>
        <field-to-result field="newEntity.shipmentItemSeqId" result-name="shipmentItemSeqId"/>
        <create-value value-field="newEntity"/>
    </simple-method>
    <simple-method method-name="updateShipmentItem" short-description="Update ShipmentItem">
        <set value="Update ShipmentItem" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentItem" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key entity-name="ShipmentItem" map="lookupPKMap" value-field="lookedUpValue"/>
        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
        <store-value value-field="lookedUpValue"/>
    </simple-method>
    <simple-method method-name="deleteShipmentItem" short-description="Delete ShipmentItem">
        <set value="Delete ShipmentItem" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>
        <!-- If there is any Shipment Package Content available for this Shipment Item then it cannot be deleted as it require 
                Shipment Package content to be deleted first -->
        <entity-and entity-name="ShipmentPackageContent" list="shipmentPackageContents">
            <field-map field-name="shipmentId" from-field="parameters.shipmentId"/>
            <field-map field-name="shipmentItemSeqId" from-field="parameters.shipmentItemSeqId"/>
        </entity-and>
        <if-not-empty field="shipmentPackageContents">
            <add-error>
                <fail-property resource="ProductErrorUiLabels" property="ProductErrorShipmentItemCannotBeDeleted"/>
            </add-error>
            <check-errors/>
        <else>
            <make-value entity-name="ShipmentItem" value-field="lookupPKMap"/>
            <set-pk-fields map="parameters" value-field="lookupPKMap"/>
            <find-by-primary-key entity-name="ShipmentItem" map="lookupPKMap" value-field="lookedUpValue"/>
            <remove-value value-field="lookedUpValue"/>
        </else>
        </if-not-empty>
    </simple-method>

    <simple-method method-name="splitShipmentItemByQuantity" short-description="splitShipmentItemByQuantity">
        <entity-one entity-name="ShipmentItem" value-field="originalShipmentItem"/>

        <!-- create new ShipmentItem -->
        <clear-field field="inputMap"/>
        <set field="inputMap.shipmentId" from-field="originalShipmentItem.shipmentId"/>
        <set field="inputMap.productId" from-field="originalShipmentItem.productId"/>
        <set field="inputMap.quantity" from-field="parameters.newItemQuantity"/>
        <call-service service-name="createShipmentItem" in-map-name="inputMap">
            <result-to-field result-name="shipmentItemSeqId" field="newShipmentItemSeqId"/>
        </call-service>

        <!-- reduce the originalShipmentItem.quantity  -->
        <calculate field="originalShipmentItem.quantity">
            <calcop operator="add" field="originalShipmentItem.quantity">
                <calcop operator="negative" field="parameters.newItemQuantity"/>
            </calcop>
        </calculate>
        <!-- update the original ShipmentItem -->
        <set-service-fields service-name="updateShipmentItem" map="originalShipmentItem" to-map="updateOriginalShipmentItemMap"/>
        <call-service service-name="updateShipmentItem" in-map-name="updateOriginalShipmentItemMap"/>

        <!-- split the OrderShipment record(s) as well for the new quantities,
            from originalShipmentItem.shipmentItemSeqId to newShipmentItemSeqId -->
        <entity-and entity-name="OrderShipment" list="itemOrderShipmentList">
            <field-map field-name="shipmentId" from-field="originalShipmentItem.shipmentId"/>
            <field-map field-name="shipmentItemSeqId" from-field="originalShipmentItem.shipmentItemSeqId"/>
        </entity-and>

        <set field="orderShipmentQuantityLeft" from-field="parameters.newItemQuantity"/>
        <iterate list="itemOrderShipmentList" entry="itemOrderShipment">
            <if-compare field="orderShipmentQuantityLeft" operator="greater" value="0" type="BigDecimal">
                <if-compare-field field="itemOrderShipment.quantity" to-field="orderShipmentQuantityLeft" operator="greater" type="BigDecimal">
                    <!-- there is enough in this OrderShipment record, so just adjust it and move on -->
                    <clear-field field="updateOrderShipmentMap"/>
                    <set-service-fields service-name="updateOrderShipment" map="itemOrderShipment" to-map="updateOrderShipmentMap"/>
                    <calculate field="updateOrderShipmentMap.quantity">
                        <calcop operator="add" field="itemOrderShipment.quantity">
                            <calcop operator="negative" field="orderShipmentQuantityLeft"/>
                        </calcop>
                    </calculate>
                    <call-service service-name="updateOrderShipment" in-map-name="updateOrderShipmentMap"/>

                    <clear-field field="createOrderShipmentMap"/>
                    <set field="createOrderShipmentMap.orderId" from-field="itemOrderShipment.orderId"/>
                    <set field="createOrderShipmentMap.orderItemSeqId" from-field="itemOrderShipment.orderItemSeqId"/>
                    <set field="createOrderShipmentMap.shipmentId" from-field="itemOrderShipment.shipmentId"/>
                    <set field="createOrderShipmentMap.shipmentItemSeqId" from-field="newShipmentItemSeqId"/>
                    <set field="createOrderShipmentMap.quantity" from-field="orderShipmentQuantityLeft"/>
                    <call-service service-name="createOrderShipment" in-map-name="createOrderShipmentMap"/>

                    <set field="orderShipmentQuantityLeft" value="0" type="BigDecimal"/>

                    <else>
                        <!-- not enough on this one, create a new one for the new item and delete this one -->
                        <clear-field field="deleteOrderShipmentMap"/>
                        <set-service-fields service-name="deleteOrderShipment" map="itemOrderShipment" to-map="deleteOrderShipmentMap"/>
                        <call-service service-name="deleteOrderShipment" in-map-name="deleteOrderShipmentMap"/>

                        <clear-field field="createOrderShipmentMap"/>
                        <set field="createOrderShipmentMap.orderId" from-field="itemOrderShipment.orderId"/>
                        <set field="createOrderShipmentMap.orderItemSeqId" from-field="itemOrderShipment.orderItemSeqId"/>
                        <set field="createOrderShipmentMap.shipmentId" from-field="itemOrderShipment.shipmentId"/>
                        <set field="createOrderShipmentMap.shipmentItemSeqId" from-field="newShipmentItemSeqId"/>
                        <set field="createOrderShipmentMap.quantity" from-field="itemOrderShipment.quantity"/>
                        <call-service service-name="createOrderShipment" in-map-name="createOrderShipmentMap"/>

                        <calculate field="orderShipmentQuantityLeft">
                            <calcop operator="get" field="orderShipmentQuantityLeft"/>
                            <calcop operator="negative" field="itemOrderShipment.quantity"/>
                        </calculate>
                    </else>
                </if-compare-field>
            </if-compare>
        </iterate>

        <field-to-result field="newShipmentItemSeqId"/>
    </simple-method>

    <!-- ShipmentPackage services -->
    <simple-method method-name="createShipmentPackage" short-description="Create ShipmentPackage">
        <set value="Create ShipmentPackage" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackage" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>

        <if-compare value="New" operator="equals" field="newEntity.shipmentPackageSeqId">
            <clear-field field="newEntity.shipmentPackageSeqId"/>
        </if-compare>

        <!-- if no shipmentPackageSeqId, generate one based on existing items, ie one greater than the current higher number -->
        <make-next-seq-id value-field="newEntity" seq-field-name="shipmentPackageSeqId"/>
        <field-to-result field="newEntity.shipmentPackageSeqId" result-name="shipmentPackageSeqId"/>

        <now-timestamp field="newEntity.dateCreated"/>

        <create-value value-field="newEntity"/>

        <set from-field="newEntity.shipmentId" field="shipmentId"/>
        <set from-field="newEntity.shipmentPackageSeqId" field="shipmentPackageSeqId"/>
        <call-simple-method method-name="ensurePackageRouteSeg"/>
    </simple-method>
    <simple-method method-name="updateShipmentPackage" short-description="Update ShipmentPackage">
        <set value="Update ShipmentPackage" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusShipped"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackage" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key entity-name="ShipmentPackage" map="lookupPKMap" value-field="lookedUpValue"/>
        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
        <store-value value-field="lookedUpValue"/>

        <set from-field="lookedUpValue.shipmentId" field="shipmentId"/>
        <set from-field="lookedUpValue.shipmentPackageSeqId" field="shipmentPackageSeqId"/>
        <call-simple-method method-name="ensurePackageRouteSeg"/>
    </simple-method>
    <simple-method method-name="deleteShipmentPackage" short-description="Delete ShipmentPackage">
        <set value="Delete ShipmentPackage" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>
        <!-- If there is any Shipment Package Content available for this shipment than Shipment Package cannot be deleted as it require
             Shipment Package Content to be deleted first -->
        <entity-and entity-name="ShipmentPackageContent" list="shipmentPackageContents">
            <field-map field-name="shipmentId" from-field="parameters.shipmentId"/>
            <field-map field-name="shipmentPackageSeqId" from-field="parameters.shipmentPackageSeqId"/>
        </entity-and>
        <if-not-empty field="shipmentPackageContents">
            <add-error>
                <fail-property resource="ProductErrorUiLabels" property="ProductErrorShipmentPackageCannotBeDeleted"/>
            </add-error>
            <check-errors/>
        <else>
            <entity-one entity-name="ShipmentPackage" value-field="lookedUpValue"/>
            <remove-value value-field="lookedUpValue"/>
        </else>
        </if-not-empty>
    </simple-method>
    <simple-method method-name="ensurePackageRouteSeg" short-description="Ensure ShipmentPackageRouteSeg exists for all RouteSegments for this Package">
        <entity-and entity-name="ShipmentRouteSegment" list="shipmentRouteSegments">
            <field-map field-name="shipmentId" from-field="shipmentId"/>
        </entity-and>

        <iterate list="shipmentRouteSegments" entry="shipmentRouteSegment">
            <entity-one entity-name="ShipmentPackageRouteSeg" value-field="checkShipmentPackageRouteSeg" auto-field-map="false">
                <field-map field-name="shipmentId" from-field="shipmentId"/>
                <field-map field-name="shipmentPackageSeqId" from-field="shipmentPackageSeqId"/>
                <field-map field-name="shipmentRouteSegmentId" from-field="shipmentRouteSegment.shipmentRouteSegmentId"/>
            </entity-one>

            <if-empty field="checkShipmentPackageRouteSeg">
               <set field="checkShipmentPackageRouteSegMap.shipmentRouteSegmentId" from-field="shipmentRouteSegment.shipmentRouteSegmentId"/>
               <set field="checkShipmentPackageRouteSegMap.shipmentPackageSeqId" from-field="shipmentPackageSeqId"/>
               <set field="checkShipmentPackageRouteSegMap.shipmentId" from-field="shipmentId"/>
               <call-service service-name="createShipmentPackageRouteSeg" in-map-name="checkShipmentPackageRouteSegMap">
               </call-service>
            </if-empty>
        </iterate>
    </simple-method>

    <!-- ShipmentPackageContent services -->
    <simple-method method-name="createShipmentPackageContent" short-description="Create ShipmentPackageContent">
        <set value="Create ShipmentPackageContent" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackageContent" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>

        <create-value value-field="newEntity"/>
        <field-to-result field="newEntity.shipmentPackageSeqId" result-name="shipmentPackageSeqId"/>
    </simple-method>
    <simple-method method-name="updateShipmentPackageContent" short-description="Update ShipmentPackageContent">
        <set value="Update ShipmentPackageContent" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackageContent" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key entity-name="ShipmentPackageContent" map="lookupPKMap" value-field="lookedUpValue"/>
        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
        <store-value value-field="lookedUpValue"/>
    </simple-method>
    <simple-method method-name="deleteShipmentPackageContent" short-description="Delete ShipmentPackageContent">
        <set value="Delete ShipmentPackageContent" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackageContent" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key entity-name="ShipmentPackageContent" map="lookupPKMap" value-field="lookedUpValue"/>
        <remove-value value-field="lookedUpValue"/>
    </simple-method>
    <simple-method method-name="addShipmentContentToPackage" short-description="Add Shipment Content To Package">
        <set value="Create ShipmentPackageContent" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>
        <make-value entity-name="ShipmentPackageContent" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <find-by-primary-key value-field="shipmentPackageContent" map="newEntity"/>
        <log level="verbose" message="In addShipmentContentToPackage trying values: ${newEntity}"/>
        <if-empty field="shipmentPackageContent">
            <set-service-fields service-name="createShipmentPackageContent" map="parameters" to-map="createSPCMap"/>
            <call-service service-name="createShipmentPackageContent" in-map-name="createSPCMap">
                <result-to-field result-name="shipmentPackageSeqId" field="newEntity.shipmentPackageSeqId"/>
            </call-service>
        <else>
            <!-- add the quantities and store it -->
            <calculate field="shipmentPackageContent.quantity">
                <calcop operator="add" field="shipmentPackageContent.quantity"/>
                <calcop operator="get" field="parameters.quantity"/>
            </calculate>
            <set-service-fields service-name="updateShipmentPackageContent" map="shipmentPackageContent" to-map="updateSPCMap"/>
            <call-service service-name="updateShipmentPackageContent" in-map-name="updateSPCMap"/>
        </else>
        </if-empty>
        <log level="info" message="Shipment package: ${newEntity}"/>
        <field-to-result field="newEntity.shipmentPackageSeqId" result-name="shipmentPackageSeqId"/>
    </simple-method>

    <!-- ShipmentPackageRouteSeg services -->
    <simple-method method-name="createShipmentPackageRouteSeg" short-description="Create ShipmentPackageRouteSeg">
        <make-value entity-name="ShipmentPackageRouteSeg" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>

        <create-value value-field="newEntity"/>
    </simple-method>
    <simple-method method-name="deleteShipmentPackageRouteSeg" short-description="Delete ShipmentPackageRouteSeg">
        <set value="Delete ShipmentPackageRouteSeg" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentPackageRouteSeg" value-field="lookupPKMap"/>
        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
        <find-by-primary-key entity-name="ShipmentPackageRouteSeg" map="lookupPKMap" value-field="lookedUpValue"/>
        <remove-value value-field="lookedUpValue"/>
    </simple-method>

    <!-- ShipmentRouteSegment services -->
    <simple-method method-name="createShipmentRouteSegment" short-description="Create ShipmentRouteSegment">
        <set value="Create ShipmentRouteSegment" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <make-value entity-name="ShipmentRouteSegment" value-field="newEntity"/>
        <set-pk-fields map="parameters" value-field="newEntity"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>

        <!-- if no shipmentRouteSegmentSeqId, generate one based on existing items, ie one greater than the current higher number -->
        <make-next-seq-id value-field="newEntity" seq-field-name="shipmentRouteSegmentId"/>
        <field-to-result field="newEntity.shipmentRouteSegmentId" result-name="shipmentRouteSegmentId"/>

        <if-empty field="newEntity.carrierServiceStatusId">
            <set value="SHRSCS_NOT_STARTED" field="newEntity.carrierServiceStatusId"/>
        </if-empty>

        <create-value value-field="newEntity"/>

        <set from-field="newEntity.shipmentId" field="shipmentId"/>
        <set from-field="newEntity.shipmentRouteSegmentId" field="shipmentRouteSegmentId"/>
        <call-simple-method method-name="ensureRouteSegPackage"/>
    </simple-method>
    <simple-method method-name="updateShipmentRouteSegment" short-description="Update ShipmentRouteSegment">
        <set value="Update ShipmentRouteSegment" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusDelivered"/>
        <check-errors/>

        <entity-one entity-name="ShipmentRouteSegment" value-field="lookedUpValue"/>
        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>

        <if-empty field="newEntity.carrierServiceStatusId">
            <set value="SHRSCS_NOT_STARTED" field="newEntity.carrierServiceStatusId"/>
        </if-empty>


        <set from-field="userLogin.userLoginId" field="lookedUpValue.updatedByUserLoginId"/>
        <now-timestamp field="lookedUpValue.lastUpdatedDate"/>
        <store-value value-field="lookedUpValue"/>

        <set from-field="lookedUpValue.shipmentId" field="shipmentId"/>
        <set from-field="lookedUpValue.shipmentRouteSegmentId" field="shipmentRouteSegmentId"/>
        <call-simple-method method-name="ensureRouteSegPackage"/>
    </simple-method>
    <simple-method method-name="deleteShipmentRouteSegment" short-description="Delete ShipmentRouteSegment">
        <set value="Delete ShipmentRouteSegment" field="operationName"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusPacked"/>
        <check-errors/>

        <entity-one entity-name="ShipmentRouteSegment" value-field="lookedUpValue"/>
        <remove-value value-field="lookedUpValue"/>
    </simple-method>
    <simple-method method-name="ensureRouteSegPackage" short-description="Ensure ShipmentPackageRouteSeg exists for all Packages for this RouteSegment">
        <entity-and entity-name="ShipmentPackage" list="shipmentPackages">
            <field-map field-name="shipmentId" from-field="shipmentId"/>
        </entity-and>
        <iterate list="shipmentPackages" entry="shipmentPackage">
            <entity-one entity-name="ShipmentPackageRouteSeg" value-field="checkShipmentPackageRouteSeg" auto-field-map="false">
                <field-map field-name="shipmentId" from-field="shipmentId"/>
                <field-map field-name="shipmentRouteSegmentId" from-field="shipmentRouteSegmentId"/>
                <field-map field-name="shipmentPackageSeqId" from-field="shipmentPackage.shipmentPackageSeqId"/>
            </entity-one>
            <if-empty field="checkShipmentPackageRouteSeg">
                <set field="createShipmentPackageRouteSegMap.shipmentId" from-field="shipmentId"/>
                <set field="createShipmentPackageRouteSegMap.shipmentRouteSegmentId" from-field="shipmentRouteSegmentId"/>
                <set field="createShipmentPackageRouteSegMap.shipmentPackageSeqId" from-field="shipmentPackage.shipmentPackageSeqId"/>
                <call-service service-name="createShipmentPackageRouteSeg" in-map-name="createShipmentPackageRouteSegMap"/>
            </if-empty>
        </iterate>
    </simple-method>

    <!-- Check the Status of a Shipment to see if it can be changed - meant to be called in-line -->
    <simple-method method-name="checkCanChangeShipmentStatusPacked" short-description="Check the Status of a Shipment to see if it can be changed - meant to be called in-line">
        <set value="SHIPMENT_PACKED" field="fromStatusId"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusGeneral"/>
    </simple-method>
    <simple-method method-name="checkCanChangeShipmentStatusShipped" short-description="Check the Status of a Shipment to see if it can be changed - meant to be called in-line">
        <set value="SHIPMENT_SHIPPED" field="fromStatusId"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusGeneral"/>
    </simple-method>
    <simple-method method-name="checkCanChangeShipmentStatusDelivered" short-description="Check the Status of a Shipment to see if it can be changed - meant to be called in-line">
        <set value="SHIPMENT_DELIVERED" field="fromStatusId"/>
        <call-simple-method method-name="checkCanChangeShipmentStatusGeneral"/>
    </simple-method>
    <simple-method method-name="checkCanChangeShipmentStatusGeneral" short-description="Check the Status of a Shipment to see if it can be changed - meant to be called in-line">
        <entity-one entity-name="Shipment" value-field="testShipment"/>
        <if>
            <condition>
                <or>
                    <and>
                        <or>
                            <if-empty field="fromStatusId"/>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_PACKED"/>
                        </or>
                        <if-compare field="testShipment.statusId" operator="equals" value="SHIPMENT_PACKED"/>
                    </and>
                    <and>
                        <or>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_PACKED"/>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_SHIPPED"/>
                        </or>
                        <if-compare field="testShipment.statusId" operator="equals" value="SHIPMENT_SHIPPED"/>
                    </and>
                    <and>
                        <or>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_PACKED"/>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_SHIPPED"/>
                            <if-compare field="fromStatusId" operator="equals" value="SHIPMENT_DELIVERED"/>
                        </or>
                        <if-compare field="testShipment.statusId" operator="equals" value="SHIPMENT_DELIVERED"/>
                    </and>
                    <if-compare field="testShipment.statusId" operator="equals" value="SHIPMENT_CANCELLED"/>
                </or>
            </condition>
            <then>
                <get-related-one relation-name="StatusItem" value-field="testShipment" to-value-field="testShipmentStatus"/>
                <string-to-list string="Cannot perform operation ${operationName} when the shipment is in the ${testShipmentStatus.description} [${testShipment.statusId}] status." list="error_list"/>
            </then>
        </if>
    </simple-method>

    <!-- quick ship entire order in one package per facility & ship group -->
    <simple-method method-name="quickShipEntireOrder" short-description="Quick ships an entire order from multiple facilities">
        <!-- first get the order header; make sure we have a product store -->
        <entity-one entity-name="OrderHeader" value-field="orderHeader"/>
        <if-empty field="orderHeader.productStoreId">
            <!-- no store cannot use quick ship; throw error -->
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityShipmentMissingProductStore"/>
            </add-error>
            <check-errors/>
        </if-empty>

        <!-- get the product store entity -->
        <entity-one entity-name="ProductStore" value-field="productStore" auto-field-map="false">
            <field-map field-name="productStoreId" from-field="orderHeader.productStoreId"/>
        </entity-one>

        <if-compare field="productStore.reserveInventory" operator="not-equals" value="Y">
            <!-- no reservations; no shipment; cannot use quick ship -->
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityShipmentNotCreatedForNotReserveInventory"/>
            </add-error>
        </if-compare>
        <if-compare field="productStore.explodeOrderItems" operator="equals" value="Y">
            <!-- can't insert duplicate rows in shipmentPackageContent -->
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityShipmentNotCreatedForExplodesOrderItems"/>
            </add-error>
        </if-compare>
        <check-errors/>

        <!-- locate shipping facilities associated with order item rez's -->
        <entity-condition entity-name="OrderItemAndShipGrpInvResAndItem" list="orderItemAndShipGrpInvResAndItemList">
            <condition-list>
                <condition-expr field-name="orderId" from-field="orderHeader.orderId"/>
                <condition-expr field-name="statusId" value="ITEM_APPROVED"/>
            </condition-list>
        </entity-condition>
        <iterate list="orderItemAndShipGrpInvResAndItemList" entry="orderItemAndShipGrpInvResAndItem">
            <if>
                <condition><not><if-compare-field field="orderItemShipGrpInvResFacilityIds" to-field="orderItemAndShipGrpInvResAndItem.facilityId" operator="contains"/></not></condition>
                <then><field-to-list field="orderItemAndShipGrpInvResAndItem.facilityId" list="orderItemShipGrpInvResFacilityIds"/></then>
            </if>
        </iterate>

        <call-simple-method method-name="getOrderItemShipGroupLists"/>

        <!-- traverse facilities, instantiate shipment for each -->
        <iterate list="orderItemShipGrpInvResFacilityIds" entry="orderItemShipGrpInvResFacilityId">
            <!-- sanity check for valid facility -->
            <entity-one entity-name="Facility" value-field="facility">
                <field-map field-name="facilityId" from-field="orderItemShipGrpInvResFacilityId"/>
            </entity-one>
            <!-- should never be empty - referential integrity enforced -->

            <set field="eventDate" from-field="parameters.eventDate"/>
            <set field="setPackedOnly" from-field="parameters.setPackedOnly"/>
            <call-simple-method method-name="createShipmentForFacilityAndShipGroup"/>
        </iterate>

        <log level="info" message="Finished quickShipEntireOrder:\nshipmentShipGroupFacilityList=${shipmentShipGroupFacilityList}\nsuccessMessageList=${successMessageList}"/>
        <field-to-result field="shipmentShipGroupFacilityList"/>
        <field-to-result field="successMessageList"/>

        <if-empty field="shipmentShipGroupFacilityList">
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityShipmentNotCreated"/>
            </add-error>
        </if-empty>
        <check-errors/>
    </simple-method>

    <simple-method method-name="quickDropShipOrder" short-description="Create and complete a drop shipment for a ship group">
        <entity-one entity-name="OrderHeader" value-field="orderHeader"/>
        <if-compare field="orderHeader.statusId" operator="equals" value="ORDER_CREATED">
            <add-error>
                <fail-property resource="OrderErrorUiLabels" property="OrderApproveOrderBeforeQuickDropShip"/>
            </add-error>
            <check-errors/>
        </if-compare>
        <set from-field="parameters.orderId" field="shipmentContext.primaryOrderId"/>
        <set from-field="parameters.shipGroupSeqId" field="shipmentContext.primaryShipGroupSeqId"/>
        <set value="PURCH_SHIP_CREATED" field="shipmentContext.statusId"/>
        <set value="DROP_SHIPMENT" field="shipmentContext.shipmentTypeId"/>
        <call-service service-name="createShipment" in-map-name="shipmentContext">
            <result-to-field result-name="shipmentId" field="shipmentId"/>
        </call-service>
        <check-errors/>
        <set from-field="shipmentId" field="updateShipmentContext.shipmentId"/>
        <set value="PURCH_SHIP_SHIPPED" field="updateShipmentContext.statusId"/>
        <call-service service-name="updateShipment" in-map-name="updateShipmentContext"/>
        <check-errors/>
        <set value="PURCH_SHIP_RECEIVED" field="updateShipmentContext.statusId"/>
        <call-service service-name="updateShipment" in-map-name="updateShipmentContext"/>
        <check-errors/>
        <field-to-result field="shipmentId" result-name="shipmentId"/>

        <!-- Iterate through the order items in the ship group -->
        <entity-and entity-name="OrderItemShipGroupAssoc" list="orderItemShipGroupAssocs">
            <field-map field-name="orderId" from-field="parameters.orderId"/>
            <field-map field-name="shipGroupSeqId" from-field="parameters.shipGroupSeqId"/>
        </entity-and>
        <iterate list="orderItemShipGroupAssocs" entry="orderItemShipGroupAssoc">
            <get-related-one relation-name="OrderItem" value-field="orderItemShipGroupAssoc" to-value-field="orderItem"/>

            <!-- Set the item status to completed -->
            <set field="itemStatusContext.orderId" from-field="parameters.orderId"/>
            <set field="itemStatusContext.orderItemSeqId" from-field="orderItem.orderItemSeqId"/>
            <set field="itemStatusContext.statusId" value="ITEM_COMPLETED"/>
            <call-service service-name="changeOrderItemStatus" in-map-name="itemStatusContext"/>
            <check-errors/>

            <!-- Set the status of any linked sales order items to completed as well -->
            <entity-and entity-name="OrderItemAssoc" list="orderItemAssocs">
                <field-map field-name="toOrderId" from-field="parameters.orderId"/>
                <field-map field-name="toOrderItemSeqId" from-field="orderItem.orderItemSeqId"/>
                <field-map field-name="orderItemAssocTypeId" value="DROP_SHIPMENT"/>
            </entity-and>
            <if-not-empty field="orderItemAssocs">
                <iterate list="orderItemAssocs" entry="orderItemAssoc">
                    <set field="itemStatusContext.orderId" from-field="orderItemAssoc.orderId"/>
                    <set field="itemStatusContext.orderItemSeqId" from-field="orderItemAssoc.orderItemSeqId"/>
                    <call-service service-name="changeOrderItemStatus" in-map-name="itemStatusContext"/>
                    <check-errors/>
                </iterate>
            </if-not-empty>
        </iterate>
    </simple-method>

    <simple-method method-name="quickReceivePurchaseOrder" short-description="Quick receives an entire purchase order in a facility">
        <entity-one entity-name="OrderHeader" value-field="orderHeader"/>
        <entity-one entity-name="Facility" value-field="facility"/>
        <call-simple-method method-name="getOrderItemShipGroupLists"/>
        <call-simple-method method-name="createShipmentForFacilityAndShipGroup"/>
        <log level="info" message="Finished quickReceivePurchaseOrder for orderId ${parameters.orderId} and destination facilityId ${parameters.facilityId} shipment created ${shipmentIds}"/>
        <field-to-result field="shipmentIds" result-name="shipmentIds"/>
    </simple-method>

    <simple-method method-name="getOrderItemShipGroupLists"
        short-description="Sub-method used by quickShip methods to get a list of OrderItemAndShipGroupAssoc and a Map of shipGroupId -> OrderItemAndShipGroupAssoc">

        <!-- lookup all the approved items, doing by item because the item must be approved before shipping -->
        <entity-and entity-name="OrderItemAndShipGroupAssoc" list="orderItemAndShipGroupAssocList">
            <field-map field-name="orderId" from-field="orderHeader.orderId"/>
            <field-map field-name="statusId" value="ITEM_APPROVED"/>
        </entity-and>

        <!-- make sure we have something to ship -->
        <if-empty field="orderItemAndShipGroupAssocList">
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityNoItemsAvailableToShip"/>
            </add-error>
            <check-errors/>
        </if-empty>

        <get-related relation-name="OrderItemShipGroup" value-field="orderHeader" list="orderItemShipGroupList"/>

        <!-- group orderItems (actually OrderItemAndShipGroupAssocs) by shipGroupSeqId in a Map with List values
             This Map is actually used only for sales orders' shipments right now.  -->
        <iterate list="orderItemAndShipGroupAssocList" entry="orderItemAndShipGroupAssoc">
            <field-to-list field="orderItemAndShipGroupAssoc" list="orderItemListByShGrpMap[orderItemAndShipGroupAssoc.shipGroupSeqId]"/>
        </iterate>
    </simple-method>

    <simple-method method-name="createShipmentForFacilityAndShipGroup" short-description="Sub-method used by quickShip methods to create a shipment">

        <!-- for OrderItemShipGroup need to split all OISGIRs into their ship groups and create a shipment for each -->
        <iterate list="orderItemShipGroupList" entry="orderItemShipGroup">
            <!-- lookup all the approved items -->
            <entity-and entity-name="OrderItemAndShipGroupAssoc" list="orderItems">
                <field-map field-name="orderId" from-field="orderHeader.orderId"/>
                <field-map field-name="shipGroupSeqId" from-field="orderItemShipGroup.shipGroupSeqId"/>
                <field-map field-name="statusId" value="ITEM_APPROVED"/>
            </entity-and>

            <set from-field="orderItemListByShGrpMap[orderItemShipGroup.shipGroupSeqId]" field="perShipGroupItemList"/>

            <!-- make sure we have something to ship -->
            <if-empty field="perShipGroupItemList">
                <set field="argListNames[]" from-field="orderItemShipGroup.shipGroupSeqId"/>
                <property-to-field property="FacilityShipmentNoItemsAvailableToShip" resource="ProductUiLabels" field="successMessage" arg-list-name="argListNames"/>
            <else>
                <!-- create the shipment for this facility and ship group combination -->
                <set from-field="orderHeader.orderId" field="shipmentContext.primaryOrderId"/>
                <set from-field="orderItemShipGroup.shipGroupSeqId" field="shipmentContext.primaryShipGroupSeqId"/>
                <!-- for Sales Shipment, order items' reservation facilityId is the originFacilityId, and the initial status is "INPUT"
                     for Purchase Shipment, the facilityId parameter is the destinationFacilityId, and the initial status is "CREATED" -->
                <if><condition><if-compare field="orderHeader.orderTypeId" operator="equals" value="SALES_ORDER"/></condition>
                  <then>
                    <if-not-empty field="orderItemShipGroup.vendorPartyId">
                      <set field="partyIdFrom" from-field="orderItemShipGroup.vendorPartyId"/>
                    <else>
                      <entity-one entity-name="Facility" value-field="facility" auto-field-map="false">
                        <field-map field-name="facilityId" from-field="orderItemShipGrpInvResFacilityId"/>
                      </entity-one>
                      <if-not-empty field="facility.ownerPartyId">
                        <set field="partyIdFrom" from-field="facility.ownerPartyId"/>
                      </if-not-empty>
                      <if-empty field="partyIdFrom">
                        <entity-and entity-name="OrderRole" list="orderRoles">
                          <field-map field-name="orderId" from-field="orderHeader.orderId"/>
                          <field-map field-name="roleTypeId" value="SHIP_FROM_VENDOR"/>
                        </entity-and>
                        <if-not-empty field="orderRoles">
                          <first-from-list list="orderRoles" entry="orderRole"/>
                          <set field="partyIdFrom" from-field="orderRole.partyId"/>
                        <else>
                          <entity-and entity-name="OrderRole" list="orderRoles">
                            <field-map field-name="orderId" from-field="orderHeader.orderId"/>
                            <field-map field-name="roleTypeId" value="BILL_FROM_VENDOR"/>
                          </entity-and>
                          <first-from-list list="orderRoles" entry="orderRole"/>
                          <set field="partyIdFrom" from-field="orderRole.partyId"/>
                        </else>
                        </if-not-empty>
                      </if-empty>
                    </else>
                    </if-not-empty>
                    <set field="shipmentContext.partyIdFrom" from-field="partyIdFrom"/>
                    <set from-field="orderItemShipGrpInvResFacilityId" field="shipmentContext.originFacilityId"/>
                    <set value="SHIPMENT_INPUT" field="shipmentContext.statusId"/>
                  </then>
                  <else>
                    <set from-field="facility.facilityId" field="shipmentContext.destinationFacilityId"/>
                    <set value="PURCH_SHIP_CREATED" field="shipmentContext.statusId"/>
                  </else>
                </if>
                <call-service service-name="createShipment" in-map-name="shipmentContext">
                    <result-to-field result-name="shipmentId" field="shipmentLookupMap.shipmentId"/>
                </call-service>
                <find-by-primary-key entity-name="Shipment" map="shipmentLookupMap" value-field="shipment"/>

                <if><condition><if-compare field="orderHeader.orderTypeId" operator="equals" value="SALES_ORDER"/></condition>
                  <then>
                    <iterate list="perShipGroupItemList" entry="orderItemAndShipGroupAssoc">
                      <!-- just get the OrderItemShipGrpInvResAndItem records for this facility and this ship group, since that is what this shipment is for -->
                      <clear-field field="itemResFindMap"/>
                      <set from-field="orderItemShipGrpInvResFacilityId" field="itemResFindMap.facilityId"/>
                      <get-related value-field="orderItemAndShipGroupAssoc" relation-name="OrderItemShipGrpInvResAndItem" map="itemResFindMap" list="itemResList"/>
                      <iterate list="itemResList" entry="itemRes">
                        <set from-field="shipment.shipmentId" field="issueContext.shipmentId"/>
                        <set from-field="itemRes.orderId" field="issueContext.orderId"/>
                        <set from-field="itemRes.orderItemSeqId" field="issueContext.orderItemSeqId"/>
                        <set from-field="itemRes.shipGroupSeqId" field="issueContext.shipGroupSeqId"/>
                        <set from-field="itemRes.inventoryItemId" field="issueContext.inventoryItemId"/>
                        <set from-field="itemRes.quantity" field="issueContext.quantity"/>
                        <set from-field="eventDate" field="issueContext.eventDate"/>
                        <call-service service-name="issueOrderItemShipGrpInvResToShipment" in-map-name="issueContext"/>
                      </iterate>
                    </iterate>
                  </then>
                  <else> <!-- Issue all purchase order items -->
                    <clear-field field="itemResFindMap"/>
                    <set from-field="facilityId" field="itemResFindMap.facilityId"/>
                    <iterate list="orderItemAndShipGroupAssocList" entry="item">
                      <set from-field="shipment.shipmentId" field="issueContext.shipmentId"/>
                      <set from-field="item.orderId" field="issueContext.orderId"/>
                      <set from-field="item.orderItemSeqId" field="issueContext.orderItemSeqId"/>
                      <set from-field="item.shipGroupSeqId" field="issueContext.shipGroupSeqId"/>
                      <set from-field="item.quantity" field="issueContext.quantity"/>
                      <call-service service-name="issueOrderItemToShipment" in-map-name="issueContext"/>
                    </iterate>
                  </else>
                </if>

                <!-- place all issued items into a single package -->
                <entity-and entity-name="ItemIssuance" list="itemIssuances">
                    <field-map field-name="orderId" from-field="orderHeader.orderId"/>
                    <field-map field-name="shipGroupSeqId" from-field="orderItemShipGroup.shipGroupSeqId"/>
                    <field-map field-name="shipmentId" from-field="shipment.shipmentId"/>
                </entity-and>

                <set value="New" field="shipmentPackageSeqId"/>
                <iterate list="itemIssuances" entry="itemIssuance">
                    <log level="verbose" message="In quick ship adding item to package: ${shipmentPackageSeqId}"/>
                    <clear-field field="shipItemContext"/>
                    <set from-field="itemIssuance.shipmentId" field="shipItemContext.shipmentId"/>
                    <set from-field="itemIssuance.shipmentItemSeqId" field="shipItemContext.shipmentItemSeqId"/>
                    <set from-field="itemIssuance.quantity" field="shipItemContext.quantity"/>
                    <set from-field="shipmentPackageSeqId" field="shipItemContext.shipmentPackageSeqId"/>
                    <call-service service-name="addShipmentContentToPackage" in-map-name="shipItemContext">
                        <result-to-field result-name="shipmentPackageSeqId" field="shipmentPackageSeqId"/>
                    </call-service>
                </iterate>

                <if><condition><if-compare field="orderHeader.orderTypeId" operator="equals" value="SALES_ORDER"/></condition>
                  <then>
                    <!-- update the shipment status to packed -->
                    <set from-field="shipment.shipmentId" field="packedContext.shipmentId"/>
                    <set from-field="eventDate" field="packedContext.eventDate"/>
                    <set value="SHIPMENT_PACKED" field="packedContext.statusId"/>
                    <call-service service-name="updateShipment" in-map-name="packedContext"/>
                    <!-- update the shipment status to shipped (if setPackedOnly has NOT been set) -->
                    <if-empty field="setPackedOnly">
                        <set from-field="shipment.shipmentId" field="packedContext.shipmentId"/>
                        <set value="SHIPMENT_SHIPPED" field="packedContext.statusId"/>
                        <call-service service-name="updateShipment" in-map-name="packedContext"/>
                    </if-empty>
                  </then>
                  <else> <!-- PURCHASE_ORDER -->
                    <!-- update the shipment status to shipped -->
                    <set from-field="shipment.shipmentId" field="packedContext.shipmentId"/>
                    <set value="PURCH_SHIP_SHIPPED" field="packedContext.statusId"/>
                    <call-service service-name="updateShipment" in-map-name="packedContext"/>
                  </else>
                </if>

                <set from-field="shipment.shipmentId" field="shipmentShipGroupFacility.shipmentId"/>
                <set from-field="facility.facilityId" field="shipmentShipGroupFacility.facilityId"/>
                <set from-field="orderItemShipGroup.shipGroupSeqId" field="shipmentShipGroupFacility.shipGroupSeqId"/>
                <field-to-list field="shipmentShipGroupFacility" list="shipmentShipGroupFacilityList"/>
                <set field="argListNames[]" from-field="shipmentShipGroupFacility.shipmentId"/>
                <set field="argListNames[]" from-field="shipmentShipGroupFacility.shipGroupSeqId"/>
                <set field="argListNames[]" from-field="shipmentShipGroupFacility.facilityId"/>
                <property-to-field property="FacilityShipmentIdCreated" resource="ProductUiLabels" field="successMessage" arg-list-name="argListNames"/>
                <clear-field field="shipmentShipGroupFacility"/>
                <set field="shipmentIds[]" from-field="shipment.shipmentId"/>
            </else>
            </if-empty>
        </iterate>
        <field-to-result field="shipmentIds" result-name="shipmentIds"/>
    </simple-method>

    <simple-method method-name="createOrderShipmentPlan" short-description="Create Shipment, ShipmentItems and OrderShipment">
        <!-- first get the order header; make sure we have a product store -->
        <entity-one entity-name="OrderHeader" value-field="orderHeader"/>
        <if-empty field="orderHeader.productStoreId">
            <!-- no store cannot use quick ship; throw error -->
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityNoQuickShip"/>
            </add-error>
            <check-errors/>
        </if-empty>

        <!-- get the product store entity -->
        <entity-one entity-name="ProductStore" value-field="productStore" auto-field-map="false">
            <field-map field-name="productStoreId" from-field="orderHeader.productStoreId"/>
        </entity-one>
        <get-related relation-name="OrderItemShipGroup" value-field="orderHeader" list="orderItemShipGroupList"/>

        <iterate list="orderItemShipGroupList" entry="orderItemShipGroup">
            <!-- For each shipGroup create Shipment -->
            <clear-field field="createShipmentContext"/>
            <set field="createShipmentContext.primaryOrderId" from-field="orderHeader.orderId"/>
            <set field="createShipmentContext.primaryShipGroupSeqId" from-field="orderItemShipGroup.shipGroupSeqId"/>
            <set field="createShipmentContext.statusId" value="SHIPMENT_INPUT"/>
            <set field="createShipmentContext.originFacilityId" from-field="productStore.inventoryFacilityId"/>
            <set field="createShipmentContext.userLogin" from-field="parameters.userLogin"/>
            <call-service service-name="createShipment" in-map-name="createShipmentContext">
                <result-to-field result-name="shipmentId" field="parameters.shipmentId"/>
            </call-service>
            <entity-one entity-name="Shipment" value-field="shipment"/>
            <get-related value-field="orderHeader" relation-name="OrderItem" list="orderItems"/>
            <iterate list="orderItems" entry="orderItem">
                <entity-one entity-name="Product" value-field="itemProduct" auto-field-map="false" use-cache="true">
                    <field-map field-name="productId" from-field="orderItem.productId"/>
                </entity-one>

                <!-- make sure the OrderItem is for a Product that has a ProductType with isPhysical=Y -->
                <if-not-empty field="itemProduct">
                    <get-related-one value-field="itemProduct" relation-name="ProductType" to-value-field="itemProductType" use-cache="true"/>
                    <if-compare field="itemProductType.isPhysical" operator="equals" value="Y">
                        <!-- Create shipment item -->
                        <clear-field field="addOrderShipmentToShipmentCtx"/>
                        <set field="addOrderShipmentToShipmentCtx.orderId" from-field="orderHeader.orderId"/>
                        <set field="addOrderShipmentToShipmentCtx.orderItemSeqId" from-field="orderItem.orderItemSeqId"/>
                        <set field="addOrderShipmentToShipmentCtx.shipmentId" from-field="parameters.shipmentId"/>
                        <set field="addOrderShipmentToShipmentCtx.quantity" from-field="orderItem.quantity"/>
                        <set field="addOrderShipmentToShipmentCtx.userLogin" from-field="parameters.userLogin"/>
                        <call-service service-name="addOrderShipmentToShipment" in-map-name="addOrderShipmentToShipmentCtx"/>
                    </if-compare>
                </if-not-empty>
            </iterate>
            <field-to-result field="parameters.shipmentId" result-name="shipmentId"/>
        </iterate>
    </simple-method>

    <simple-method method-name="issueSerializedInvToShipmentPackageAndSetTracking" short-description="">
        <!-- If serialNumber is provided, Then compare it with the serialNumber of inventoryItem on reservation. If they don't match,
            We'll have to reReserve specific inventory that is shiped. -->
        <!-- If serialNumber exist then run reserveAnInventoryItem for serialisedInventory.There is no need to check
             this condition for the non-serialized inventory (Non serialized Inventory will directly issued).
        -->
        <if-not-empty field="parameters.serialNumber">
        <make-value entity-name="OrderItemShipGrpInvRes" value-field="orderItemShipGrpInvResLookupPk"/>
        <set-pk-fields value-field="orderItemShipGrpInvResLookupPk" map="parameters"/>
        <find-by-primary-key entity-name="OrderItemShipGrpInvRes" map="orderItemShipGrpInvResLookupPk" value-field="orderItemShipGrpInvRes"/>
        <get-related-one to-value-field="inventoryItem" relation-name="InventoryItem" value-field="orderItemShipGrpInvRes"/>
        <if-compare-field field="inventoryItem.serialNumber" operator="not-equals" to-field="parameters.serialNumber">
            <!-- The inventory that we have reserved is not what we shipped. Lets reReserve, this time we'll get what we want -->
            <set-service-fields service-name="reserveAnInventoryItem" map="parameters" to-map="reserveAnInventoryItemCtx"/>
            <call-service service-name="reserveAnInventoryItem" in-map-name="reserveAnInventoryItemCtx">
                <result-to-field result-name="inventoryItemId" field="parameters.inventoryItemId"/>
            </call-service>
        </if-compare-field>
        </if-not-empty>
        <!-- get InventoryItem issued to shipment -->
        <clear-field field="issueContext"/>
        <set from-field="parameters.shipmentId" field="issueContext.shipmentId"/>
        <set from-field="parameters.inventoryItemId" field="issueContext.inventoryItemId"/>
        <set from-field="parameters.orderId" field="issueContext.orderId"/>
        <set from-field="parameters.shipGroupSeqId" field="issueContext.shipGroupSeqId"/>
        <set from-field="parameters.orderItemSeqId" field="issueContext.orderItemSeqId"/>
        <set from-field="parameters.inventoryItemId" field="issueContext.inventoryItemId"/>
        <set from-field="parameters.quantity" field="issueContext.quantity"/>
        <call-service service-name="issueOrderItemShipGrpInvResToShipment" in-map-name="issueContext">
            <result-to-field result-name="itemIssuanceId" field="parameters.itemIssuanceId"/>
        </call-service>
        <!-- place all issued items into a package for tracking num -->
        <log level="info" message="QuickShipOrderByItem grouping by tracking number : ${parameters.trackingNum}"/>
        <entity-one entity-name="ItemIssuance" value-field="itemIssuance">
            <field-map field-name="itemIssuanceId" from-field="parameters.itemIssuanceId"/>
        </entity-one>
        <clear-field field="shipItemContext"/>
        <set from-field="parameters.shipmentPackageSeqId" field="shipItemContext.shipmentPackageSeqId"/>
        <if-empty field="shipItemContext.shipmentPackageSeqId">
            <set value="New" field="shipItemContext.shipmentPackageSeqId"/>
        </if-empty>
        <log level="info" message="Package SeqID : ${shipItemContext.shipmentPackageSeqId}"/>
        <make-value entity-name="ShipmentPackage" value-field="shipmentPackageLookupPk"/>
        <set-pk-fields value-field="shipmentPackageLookupPk" map="parameters"/>
        <find-by-primary-key entity-name="ShipmentPackage" map="shipmentPackageLookupPk" value-field="shipmentPackage"/>
        <if-empty field="shipmentPackage">
            <set from-field="itemIssuance.shipmentId" field="shipPackageContext.shipmentId"/>
            <set from-field="shipItemContext.shipmentPackageSeqId" field="shipPackageContext.shipmentPackageSeqId"/>
            <call-service service-name="createShipmentPackage" in-map-name="shipPackageContext"/>
        </if-empty>

        <set from-field="itemIssuance.shipmentId" field="shipItemContext.shipmentId"/>
        <set from-field="itemIssuance.shipmentItemSeqId" field="shipItemContext.shipmentItemSeqId"/>
        <set from-field="itemIssuance.quantity" field="shipItemContext.quantity"/>
        <call-service service-name="addShipmentContentToPackage" in-map-name="shipItemContext">
            <result-to-field result-name="shipmentPackageSeqId" field="packageMap.${parameters.trackingNum}"/>
            <result-to-field result-name="shipmentPackageSeqId" field="routeSegLookup.shipmentPackageSeqId"/>
        </call-service>

        <if-not-empty field="routeSegLookup.shipmentPackageSeqId">
            <set from-field="itemIssuance.shipmentId" field="routeSegLookup.shipmentId"/>
            <!-- quick ship orders should only have one route segment -->
            <set value="00001" field="routeSegLookup.shipmentRouteSegmentId"/>
            <find-by-primary-key entity-name="ShipmentPackageRouteSeg" map="routeSegLookup" value-field="packageRouteSegment"/>
            <if-not-empty field="packageRouteSegment">
                <set from-field="parameters.trackingNum" field="packageRouteSegment.trackingCode"/>
                <store-value value-field="packageRouteSegment"/>
            </if-not-empty>
            <if-empty field="packageRouteSegment">
                <log level="warning" message="No route segment found : ${routeSegLookup}"/>
            </if-empty>
        </if-not-empty>
        <if-empty field="routeSegLookup.shipmentPackageSeqId">
            <log level="warning" message="No shipment package ID found; cannot update RouteSegment"/>
        </if-empty>

    </simple-method>

    <simple-method  method-name="setShipmentStatusPackedAndShipped" short-description="Move a shipment into Packed status and then to Shipped status">
        <!--update the shipment status to packed -->
        <set from-field="parameters.shipmentId" field="packedContext.shipmentId"/>
        <set value="SHIPMENT_PACKED" field="packedContext.statusId"/>
        <call-service service-name="updateShipment" in-map-name="packedContext"/>
        <!--update the shipment status to shipped -->
        <if-empty field="parameters.setPackedOnly">
            <set from-field="parameters.shipmentId" field="packedContext.shipmentId"/>
            <set value="SHIPMENT_SHIPPED" field="packedContext.statusId"/>
            <call-service service-name="updateShipment" in-map-name="packedContext"/>
        </if-empty>
    </simple-method>

    <simple-method method-name="quickShipOrderByItem" short-description="Quick ships order based on item list">
        <!-- quick ship order using multiple packages per tracking number -->
        <!-- Parameters coming in: orderId, shipGroupSeqId,itemShipList, originFacilityId, setPackedOnly -->
        <!-- The input list contains Maps with four keys: orderItemSeqId, inventoryItemId, qtyShipped, trackingNum -->
        <!-- Parameters going out: shipmentId -->

        <!-- first get the order header; make sure we have a product store -->
        <entity-one entity-name="OrderHeader" value-field="orderHeader"/>

        <if-empty field="parameters.originFacilityId">
            <if-empty field="orderHeader.productStoreId">
                <!-- no store cannot use quick ship; throw error -->
                <add-error>
                    <fail-property resource="ProductUiLabels" property="FacilityNoQuickShip"/>
                </add-error>
                <check-errors/>
            </if-empty>
            <if-not-empty field="orderHeader.productStoreId">
                <!-- get the product store entity -->
                <entity-one entity-name="ProductStore" value-field="productStore">
                    <field-map field-name="productStoreId" from-field="orderHeader.productStoreId"/>
                </entity-one>

                <if-compare field="productStore.reserveInventory" operator="not-equals" value="Y">
                    <!-- no reservations; no shipment; cannot use quick ship -->
                    <add-error>
                        <fail-property resource="ProductUiLabels" property="FacilityNoQuickShipForNotReserveInventory"/>
                    </add-error>
                </if-compare>
                <if-compare field="productStore.oneInventoryFacility" operator="not-equals" value="Y">
                    <!-- if we allow multiple facilities we cannot use quick ship; throw error -->
                    <add-error>
                        <fail-property resource="ProductUiLabels" property="FacilityNoQuickShipForMultipleFacilities"/>
                    </add-error>
                </if-compare>
                <if-empty field="productStore.inventoryFacilityId">
                    <!-- if no inventoryFacility is defined we cannot use quick ship; throw error -->
                    <add-error>
                        <fail-property resource="ProductUiLabels" property="FacilityNoQuickShipForNotInventoryFacility"/>
                    </add-error>
                </if-empty>
                <check-errors/>
            </if-not-empty>
        </if-empty>

        <!-- make sure we have items to issue -->
        <if-empty field="parameters.itemShipList">
            <add-error>
                <fail-property resource="ProductUiLabels" property="FacilityNoItemsAvailableToShip"/>
            </add-error>
            <check-errors/>
        </if-empty>

        <!-- move the itemMap to the envrironment -->
        <set from-field="parameters.itemShipList" field="itemMapList"/>

        <!-- we are all good to go; create the shipment -->
        <if-not-empty field="parameters.originFacilityId">
            <set from-field="parameters.originFacilityId" field="shipmentContext.originFacilityId"/>
        </if-not-empty>
        <set from-field="parameters.orderId" field="shipmentContext.primaryOrderId"/>
        <set from-field="parameters.shipGroupSeqId" field="shipmentContext.primaryShipGroupSeqId"/>
        <set value="SHIPMENT_INPUT" field="shipmentContext.statusId"/>
        <call-service service-name="createShipment" in-map-name="shipmentContext">
            <result-to-field result-name="shipmentId" field="shipmentLookupMap.shipmentId"/>
        </call-service>
        <find-by-primary-key entity-name="Shipment" map="shipmentLookupMap" value-field="shipment"/>

        <!-- issue the passed in order items -->
        <log level="verbose" message="ShipMap List : ${itemMapList}  /  ${parameters.itemShipList}"/>
        <iterate list="itemMapList" entry="itemMap">
            <log level="verbose" message="Item Map : ${itemMap}"/>
            <clear-field field="issueContext"/>
            <set from-field="shipment.shipmentId" field="issueContext.shipmentId"/>
            <set from-field="parameters.orderId" field="issueContext.orderId"/>
            <set from-field="parameters.shipGroupSeqId" field="issueContext.shipGroupSeqId"/>
            <set from-field="itemMap.orderItemSeqId" field="issueContext.orderItemSeqId"/>
            <set from-field="itemMap.inventoryItemId" field="issueContext.inventoryItemId"/>
            <set from-field="itemMap.qtyShipped" field="issueContext.quantity"/>
            <call-service service-name="issueOrderItemShipGrpInvResToShipment" in-map-name="issueContext">
                <result-to-field result-name="itemIssuanceId" field="itemMap.itemIssuanceId"/>
            </call-service>
        </iterate>

        <!-- place all issued items into a unique package per tracking num -->
        <iterate list="itemMapList" entry="itemMap">
            <log level="info" message="QuickShipOrderByItem grouping by tracking number : ${itemMap.trackingNum}"/>

            <entity-one entity-name="ItemIssuance" value-field="itemIssuance">
                <field-map field-name="itemIssuanceId" from-field="itemMap.itemIssuanceId"/>
            </entity-one>

            <clear-field field="shipItemContext"/>
            <set from-field="packageMap.${itemMap.trackingNum}" field="shipItemContext.shipmentPackageSeqId"/>
            <if-empty field="shipItemContext.shipmentPackageSeqId">
                <set value="New" field="shipItemContext.shipmentPackageSeqId"/>
            </if-empty>
            <log level="info" message="Package SeqID : ${shipItemContext.shipmentPackageSeqId}"/>

            <set from-field="itemIssuance.shipmentId" field="shipItemContext.shipmentId"/>
            <set from-field="itemIssuance.shipmentItemSeqId" field="shipItemContext.shipmentItemSeqId"/>
            <set from-field="itemIssuance.quantity" field="shipItemContext.quantity"/>
            <call-service service-name="addShipmentContentToPackage" in-map-name="shipItemContext">
                <result-to-field result-name="shipmentPackageSeqId" field="packageMap.${itemMap.trackingNum}"/>
                <result-to-field result-name="shipmentPackageSeqId" field="routeSegLookup.shipmentPackageSeqId"/>
            </call-service>

            <if-not-empty field="routeSegLookup.shipmentPackageSeqId">
                <set from-field="itemIssuance.shipmentId" field="routeSegLookup.shipmentId"/>
                <!-- quick ship orders should only have one route segment -->
                <set value="00001" field="routeSegLookup.shipmentRouteSegmentId"/>
                <find-by-primary-key entity-name="ShipmentPackageRouteSeg" map="routeSegLookup" value-field="packageRouteSegment"/>

                <if-not-empty field="packageRouteSegment">
                    <set from-field="itemMap.trackingNum" field="packageRouteSegment.trackingCode"/>
                    <store-value value-field="packageRouteSegment"/>
                </if-not-empty>
                <if-empty field="packageRouteSegment">
                    <log level="warning" message="No route segment found : ${routeSegLookup}"/>
                </if-empty>
            </if-not-empty>
            <if-empty field="routeSegLookup.shipmentPackageSeqId">
                <log level="warning" message="No shipment package ID found; cannot update RouteSegment"/>
            </if-empty>
        </iterate>

        <!-- update the shipment status to packed -->
        <set from-field="shipment.shipmentId" field="packedContext.shipmentId"/>
        <set value="SHIPMENT_PACKED" field="packedContext.statusId"/>
        <call-service service-name="updateShipment" in-map-name="packedContext"/>

        <!-- update the shipment status to shipped -->
        <if-empty field="parameters.setPackedOnly">
            <set from-field="shipment.shipmentId" field="packedContext.shipmentId"/>
            <set value="SHIPMENT_SHIPPED" field="packedContext.statusId"/>
            <call-service service-name="updateShipment" in-map-name="packedContext"/>
        </if-empty>

        <field-to-result field="shipment.shipmentId" result-name="shipmentId"/>
    </simple-method>

    <simple-method method-name="removeOrderShipmentFromShipment" short-description="Delete an OrderShipment and updates the ShipmentItem">
        <make-value entity-name="OrderShipment" value-field="lookupPk"/>
        <set-pk-fields value-field="lookupPk" map="parameters"/>
        <find-by-primary-key entity-name="OrderShipment" map="lookupPk" value-field="orderShipment"/>
        <clear-field field="lookupPk"/>
        <make-value entity-name="ShipmentItem" value-field="lookupPk"/>
        <set-pk-fields value-field="lookupPk" map="parameters"/>
        <find-by-primary-key entity-name="ShipmentItem" map="lookupPk" value-field="shipmentItem"/>

        <set from-field="parameters.userLogin" field="inMap.userLogin"/>
        <set from-field="parameters.shipmentId" field="inMap.shipmentId"/>
        <set from-field="parameters.shipmentItemSeqId" field="inMap.shipmentItemSeqId"/>
        <set from-field="parameters.orderId" field="inMap.orderId"/>
        <set from-field="parameters.orderItemSeqId" field="inMap.orderItemSeqId"/>
        <set from-field="parameters.shipGroupSeqId" field="inMap.shipGroupSeqId"/>
        <call-service service-name="deleteOrderShipment" in-map-name="inMap"/>

        <calculate field="shipmentItem.quantity">
            <calcop operator="subtract" field="shipmentItem.quantity">
                <calcop operator="get" field="orderShipment.quantity"/>
            </calcop>
        </calculate>
        <clear-field field="inMap"/>
        <if-compare field="shipmentItem.quantity" operator="greater" value="0.0" type="BigDecimal">
            <set from-field="parameters.userLogin" field="inMap.userLogin"/>
            <set from-field="parameters.shipmentId" field="inMap.shipmentId"/>
            <set from-field="parameters.shipmentItemSeqId" field="inMap.shipmentItemSeqId"/>
            <set from-field="shipmentItem.quantity" field="inMap.quantity"/>
            <call-service service-name="updateShipmentItem" in-map-name="inMap"/>
        <else>
            <set from-field="parameters.userLogin" field="inMap.userLogin"/>
            <set from-field="parameters.shipmentId" field="inMap.shipmentId"/>
            <set from-field="parameters.shipmentItemSeqId" field="inMap.shipmentItemSeqId"/>
            <call-service service-name="deleteShipmentItem" in-map-name="inMap"/>
        </else>
        </if-compare>
    </simple-method>

    <!-- for a given order item and quantity it creates (or updates if already exists) an -->
    <!-- entry in the ShipmentPlan. -->
    <simple-method method-name="addOrderShipmentToShipment" short-description="Add or update a ShipmentPlan entry">
        <!-- if quantity is greater than 0 we add or update the ShipmentPlan -->
        <if-compare field="parameters.quantity" operator="greater" value="0" type="BigDecimal">

            <!-- get orderHeader -->
            <make-value entity-name="OrderHeader" value-field="orderHeaderLookupPk"/>
            <set-pk-fields value-field="orderHeaderLookupPk" map="parameters"/>
            <find-by-primary-key map="orderHeaderLookupPk" value-field="orderHeader"/>

            <!-- get orderItem -->
            <make-value entity-name="OrderItem" value-field="orderItemLookupPk"/>
            <set-pk-fields value-field="orderItemLookupPk" map="parameters"/>
            <find-by-primary-key map="orderItemLookupPk" value-field="orderItem"/>

            <!-- make sure the orderItem is not already present in this shipment -->
            <make-value entity-name="OrderShipment" value-field="orderShipmentLookup"/>
            <set-pk-fields value-field="orderShipmentLookup" map="parameters"/>
            <find-by-and entity-name="OrderShipment" map="orderShipmentLookup" list="existingOrderShipments"/>
            <if-not-empty field="existingOrderShipments">
                <string-to-list string="Not adding Order Item to plan for shipment [${parameters.shipmentId}] because the order item is already in the shipment (order [${parameters.orderId}], order item [${parameters.orderItemSeqId}])" list="error_list"/>
            </if-not-empty>

            <set from-field="parameters.orderId" field="inputMap.orderId"/>
            <set from-field="parameters.orderItemSeqId" field="inputMap.orderItemSeqId"/>
            <call-service service-name="getQuantityForShipment" in-map-name="inputMap">
                <result-to-field result-name="remainingQuantity" field="remainingQuantity"/>
            </call-service>

            <if-compare-field field="parameters.quantity" to-field="remainingQuantity" operator="greater" type="BigDecimal">
                <string-to-list string="Not adding Order Item to plan for shipment [${parameters.shipmentId}] because the quantity is greater than the remaining quantity (order [${parameters.orderId}], order item [${parameters.orderItemSeqId}])" list="error_list"/>
            </if-compare-field>
            <check-errors/>
            <clear-field field="inputMap"/>
            <set from-field="parameters.userLogin" field="inputMap.userLogin"/>
            <set from-field="parameters.shipmentId" field="inputMap.shipmentId"/>
            <set from-field="orderItem.productId" field="inputMap.productId"/>
            <set from-field="parameters.quantity" field="inputMap.quantity"/>
            <call-service service-name="createShipmentItem" in-map-name="inputMap">
                <result-to-field result-name="shipmentItemSeqId" field="parameters.shipmentItemSeqId"/>
                <result-to-result result-name="shipmentItemSeqId" service-result-name="shipmentItemSeqId"/>
            </call-service>
            <clear-field field="inputMap"/>
            <set from-field="parameters.userLogin" field="inputMap.userLogin"/>
            <set from-field="parameters.shipmentId" field="inputMap.shipmentId"/>
            <set from-field="parameters.shipmentItemSeqId" field="inputMap.shipmentItemSeqId"/>
            <set from-field="parameters.orderId" field="inputMap.orderId"/>
            <set from-field="parameters.orderItemSeqId" field="inputMap.orderItemSeqId"/>
            <set from-field="parameters.quantity" field="inputMap.quantity"/>
            <call-service service-name="createOrderShipment" in-map-name="parameters"/>
        </if-compare>
    </simple-method>
    <simple-method method-name="getQuantityForShipment" short-description="get the order item quantity still not put in shipments">
        <!-- get orderItem -->
        <make-value entity-name="OrderItem" value-field="orderItemLookupPk"/>
        <set-pk-fields value-field="orderItemLookupPk" map="parameters"/>
        <find-by-primary-key map="orderItemLookupPk" value-field="orderItem"/>

        <set from-field="parameters.orderId" field="orderShipmentLookup.orderId"/>
        <set from-field="parameters.orderItemSeqId" field="orderShipmentLookup.orderItemSeqId"/>
        <find-by-and entity-name="OrderShipment" map="orderShipmentLookup" list="existingOrderShipments"/>
        <iterate list="existingOrderShipments" entry="orderShipment">
            <calculate field="plannedQuantity">
                <calcop operator="add" field="plannedQuantity">
                    <calcop operator="get" field="orderShipment.quantity"/>
                </calcop>
            </calculate>
        </iterate>
        <clear-field field="existingOrderShipments"/>
        <find-by-and entity-name="ItemIssuance" map="orderShipmentLookup" list="existingOrderShipments"/>
        <iterate list="existingOrderShipments" entry="itemIssuance">
            <calculate field="issuedQuantity">
                <calcop operator="get" field="issuedQuantity"/>
                <calcop operator="get" field="itemIssuance.quantity"/>
                <calcop operator="negative" field="itemIssuance.cancelQuantity"/>
            </calculate>
        </iterate>

        <calculate field="totPlannedOrIssuedQuantity">
            <calcop operator="get" field="issuedQuantity"/>
            <calcop operator="get" field="plannedQuantity"/>
        </calculate>
        <calculate field="remainingQuantity">
            <calcop operator="subtract" field="orderItem.quantity">
                <calcop operator="get" field="orderItem.cancelQuantity"/>
                <calcop operator="get" field="totPlannedOrIssuedQuantity"/>
            </calcop>
        </calculate>
        <field-to-result field="remainingQuantity"/>
    </simple-method>

    <simple-method method-name="checkCancelItemIssuanceAndOrderShipmentFromShipment" short-description="Check Shipment Items and Cancel Item Issuance and Order Shipment">
        <entity-and entity-name="OrderShipment" list="orderShipmentList">
            <field-map field-name="shipmentId" from-field="parameters.shipmentId"/>
        </entity-and>
        <iterate list="orderShipmentList" entry="orderShipment">
            <clear-field field="deleteOrderShipmentMap"/>
            <set-service-fields service-name="deleteOrderShipment" map="orderShipment" to-map="deleteOrderShipmentMap"/>
            <call-service service-name="deleteOrderShipment" in-map-name="deleteOrderShipmentMap"/>
        </iterate>

        <log level="info" message="Cancelling Item Issuances for shimpentId: ${parameters.shipmentId}"/>
        <entity-one entity-name="Shipment" value-field="shipment"/>
        <get-related value-field="shipment" relation-name="ItemIssuance" list="issuances"/>
        <iterate list="issuances" entry="issuance">
            <set from-field="issuance.itemIssuanceId" field="inputMap.itemIssuanceId"/>
            <call-service service-name="cancelOrderItemIssuanceFromSalesShipment" in-map-name="inputMap"/>
        </iterate>
    </simple-method>

    <!-- QuantityBreak services -->
    <!-- create a new QuantityBreak -->
    <simple-method method-name="createQuantityBreak" short-description="Create a QuoteAttribute">
        <make-value entity-name="QuantityBreak" value-field="quantityBreak"/>
        <set-nonpk-fields map="parameters" value-field="quantityBreak"/>
        <sequenced-id sequence-name="QuantityBreak" field="quantityBreak.quantityBreakId"/>
        <create-value value-field="quantityBreak"/>
        <check-errors/>
    </simple-method>

    <!-- remove an existing QuantityBreak -->
    <simple-method method-name="deleteQuantityBreak" short-description="Remove an existing QuantityBreak">
        <entity-one entity-name="QuantityBreak" value-field="quantityBreak" auto-field-map="true"/>
        <check-errors/>
        <remove-value value-field="quantityBreak"/>
        <check-errors/>
    </simple-method>
</simple-methods>

