001// --------------------------------------------------------------------------------
002// Copyright 2002-2025 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.order.server.logic;
018
019import com.echothree.model.control.order.common.exception.DuplicateOrderLineSequenceException;
020import com.echothree.model.control.order.common.exception.UnknownOrderLineSequenceException;
021import com.echothree.model.control.order.server.control.OrderAdjustmentControl;
022import com.echothree.model.control.order.server.control.OrderControl;
023import com.echothree.model.control.order.server.control.OrderLineAdjustmentControl;
024import com.echothree.model.control.order.server.control.OrderLineControl;
025import com.echothree.model.data.cancellationpolicy.server.entity.CancellationPolicy;
026import com.echothree.model.data.inventory.server.entity.InventoryCondition;
027import com.echothree.model.data.item.server.entity.Item;
028import com.echothree.model.data.order.server.entity.Order;
029import com.echothree.model.data.order.server.entity.OrderLine;
030import com.echothree.model.data.order.server.entity.OrderShipmentGroup;
031import com.echothree.model.data.returnpolicy.server.entity.ReturnPolicy;
032import com.echothree.model.data.uom.server.entity.UnitOfMeasureType;
033import com.echothree.util.common.message.ExecutionErrors;
034import com.echothree.util.common.persistence.BasePK;
035import com.echothree.util.server.control.BaseLogic;
036import com.echothree.util.server.message.ExecutionErrorAccumulator;
037import com.echothree.util.server.persistence.EntityPermission;
038import com.echothree.util.server.persistence.Session;
039
040public class BaseOrderLineLogic
041        extends BaseLogic {
042
043    protected BaseOrderLineLogic() {
044        super();
045    }
046
047    public OrderLine createOrderLine(final Session session, final ExecutionErrorAccumulator eea, final Order order, Integer orderLineSequence,
048            final OrderLine parentOrderLine, final OrderShipmentGroup orderShipmentGroup, final Item item, final InventoryCondition inventoryCondition,
049            final UnitOfMeasureType unitOfMeasureType, final Long quantity, final Long unitAmount, final String description,
050            final CancellationPolicy cancellationPolicy, final ReturnPolicy returnPolicy, final Boolean taxable, final BasePK createdBy) {
051        var orderLogic = OrderLogic.getInstance();
052        OrderLine orderLine = null;
053
054        // Make sure any OrderPaymentPreferences associated with this order are OK with this Item.
055        orderLogic.checkItemAgainstOrderPaymentPreferences(session, eea, order, item, createdBy);
056        
057        if(orderShipmentGroup != null) {
058            // Make sure the ShippingMethod associated with the OrderShipmentGroup is OK with this Item.
059            orderLogic.checkItemAgainstShippingMethod(session, eea, orderShipmentGroup, item, createdBy);
060        }
061        
062        if(eea == null || !eea.hasExecutionErrors()) {
063            var orderControl = Session.getModelController(OrderControl.class);
064            var orderLineControl = Session.getModelController(OrderLineControl.class);
065            var orderStatus = orderControl.getOrderStatusForUpdate(order);
066
067            if(orderLineSequence == null) {
068                orderLineSequence = orderStatus.getOrderLineSequence() + 1;
069                orderStatus.setOrderLineSequence(orderLineSequence);
070            } else {
071                orderLine = orderLineControl.getOrderLineBySequence(order, orderLineSequence);
072
073                if(orderLine == null) {
074                    // If the orderLineSequence is > the last one that was recorded in the OrderStatus, jump the
075                    // one in OrderStatus forward - it should always record the greatest orderLineSequence used.
076                    if(orderLineSequence > orderStatus.getOrderLineSequence()) {
077                        orderStatus.setOrderLineSequence(orderLineSequence);
078                    }
079                } else {
080                    handleExecutionError(DuplicateOrderLineSequenceException.class, eea, ExecutionErrors.DuplicateOrderLineSequence.name(),
081                            order.getLastDetail().getOrderName(), orderLineSequence.toString());
082                }
083            }
084
085            if(orderLine == null) {
086                orderLine = orderLineControl.createOrderLine(order, orderLineSequence, parentOrderLine, orderShipmentGroup, item, inventoryCondition,
087                        unitOfMeasureType, quantity, unitAmount, description, cancellationPolicy, returnPolicy, taxable, createdBy);
088            }
089        }
090
091        return orderLine;
092    }
093
094    private OrderLine getOrderLineByName(final ExecutionErrorAccumulator eea, final String orderTypeName, final String orderName, final String orderLineSequence,
095            final EntityPermission entityPermission) {
096        var order = OrderLogic.getInstance().getOrderByName(eea, orderTypeName, orderName);
097        OrderLine orderLine = null;
098        
099        if(eea == null || !eea.hasExecutionErrors()) {
100            var orderLineControl = Session.getModelController(OrderLineControl.class);
101
102            orderLine = orderLineControl.getOrderLineBySequence(order, Integer.valueOf(orderLineSequence), entityPermission);
103            
104            if(orderLine == null) {
105                handleExecutionError(UnknownOrderLineSequenceException.class, eea, ExecutionErrors.UnknownOrderLineSequence.name(), orderTypeName, orderName, orderLineSequence);
106            }
107        }
108
109        return orderLine;
110    }
111
112    public OrderLine getOrderLineByName(final ExecutionErrorAccumulator eea, final String orderTypeName, final String orderName, final String orderLineSequence) {
113        return getOrderLineByName(eea, orderTypeName, orderName, orderLineSequence, EntityPermission.READ_ONLY);
114    }
115
116    public OrderLine getOrderLineByNameForUpdate(final ExecutionErrorAccumulator eea, final String orderTypeName, final String orderName, final String orderLineSequence) {
117        return getOrderLineByName(eea, orderTypeName, orderName, orderLineSequence, EntityPermission.READ_WRITE);
118    }
119    
120    public Long getOrderTotalWithAdjustments(final Order order) {
121        var orderAdjustmentControl = Session.getModelController(OrderAdjustmentControl.class);
122        long total = 0;
123        var orderAdjustments = orderAdjustmentControl.getOrderAdjustmentsByOrder(order);
124
125        total = orderAdjustments.stream().map((orderAdjustment) -> orderAdjustment.getLastDetail().getAmount()).reduce(total, (accumulator, _item) -> accumulator + _item);
126
127        return total + getOrderLineTotalsWithAdjustments(order);
128    }
129
130    public Long getOrderLineTotalsWithAdjustments(final Order order) {
131        var orderLineControl = Session.getModelController(OrderLineControl.class);
132        var orderLines = orderLineControl.getOrderLinesByOrder(order);
133        long total = 0;
134
135        total = orderLines.stream().map((orderLine) -> getOrderLineTotalWithAdjustments(orderLine)).reduce(total, (accumulator, _item) -> accumulator + _item);
136
137        return total;
138    }
139
140    public Long getOrderLineTotalWithAdjustments(final OrderLine orderLine) {
141        var orderLineAdjustmentControl = Session.getModelController(OrderLineAdjustmentControl.class);
142        var orderLineDetail = orderLine.getLastDetail();
143        var total = orderLineDetail.getQuantity() * orderLineDetail.getUnitAmount();
144        var orderLineAdjustments = orderLineAdjustmentControl.getOrderLineAdjustmentsByOrderLine(orderLine);
145
146        total = orderLineAdjustments.stream().map((orderLineAdjustment) -> orderLineAdjustment.getLastDetail().getAmount()).reduce(total, (accumulator, _item) -> accumulator + _item);
147
148        return total;
149    }
150
151}