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.shipping.server.logic;
018
019import com.echothree.control.user.shipping.common.spec.ShippingMethodUniversalSpec;
020import com.echothree.model.control.core.common.ComponentVendors;
021import com.echothree.model.control.core.common.EntityTypes;
022import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
023import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
024import com.echothree.model.control.selector.common.SelectorKinds;
025import com.echothree.model.control.selector.common.SelectorTypes;
026import com.echothree.model.control.selector.server.evaluator.SelectorCache;
027import com.echothree.model.control.selector.server.evaluator.SelectorCacheFactory;
028import com.echothree.model.control.selector.server.evaluator.ShippingMethodItemSelectorEvaluator;
029import com.echothree.model.control.shipping.common.exception.DuplicateShippingMethodNameException;
030import com.echothree.model.control.shipping.common.exception.ItemNotAcceptibleForShippingMethodException;
031import com.echothree.model.control.shipping.common.exception.UnknownShippingMethodNameException;
032import com.echothree.model.control.shipping.server.control.ShippingControl;
033import com.echothree.model.data.item.server.entity.Item;
034import com.echothree.model.data.party.server.entity.Language;
035import com.echothree.model.data.selector.server.entity.Selector;
036import com.echothree.model.data.shipping.server.entity.ShippingMethod;
037import com.echothree.model.data.shipping.server.value.ShippingMethodDetailValue;
038import com.echothree.util.common.message.ExecutionErrors;
039import com.echothree.util.common.persistence.BasePK;
040import com.echothree.util.server.control.BaseLogic;
041import com.echothree.util.server.message.ExecutionErrorAccumulator;
042import com.echothree.util.server.persistence.EntityPermission;
043import com.echothree.util.server.persistence.Session;
044import java.util.Set;
045import javax.enterprise.context.ApplicationScoped;
046import javax.enterprise.inject.spi.CDI;
047
048@ApplicationScoped
049public class ShippingMethodLogic
050    extends BaseLogic {
051
052    protected ShippingMethodLogic() {
053        super();
054    }
055
056    public static ShippingMethodLogic getInstance() {
057        return CDI.current().select(ShippingMethodLogic.class).get();
058    }
059
060    public ShippingMethod createShippingMethod(final ExecutionErrorAccumulator eea, final String shippingMethodName,
061            final Selector geoCodeSelector, final Selector itemSelector, final Integer sortOrder, final Language language,
062            final String description, final BasePK createdBy) {
063        var shippingControl = Session.getModelController(ShippingControl.class);
064        var shippingMethod = shippingControl.getShippingMethodByName(shippingMethodName);
065
066        if(shippingMethod == null) {
067            shippingMethod = shippingControl.createShippingMethod(shippingMethodName, geoCodeSelector, itemSelector,
068                    sortOrder, createdBy);
069
070            if(description != null) {
071                shippingControl.createShippingMethodDescription(shippingMethod, language, description, createdBy);
072            }
073        } else {
074            handleExecutionError(DuplicateShippingMethodNameException.class, eea, ExecutionErrors.DuplicateShippingMethodName.name(), shippingMethodName);
075        }
076
077        return shippingMethod;
078    }
079    
080    private ShippingMethod getShippingMethodByName(final ExecutionErrorAccumulator eea, final String shippingMethodName,
081            final EntityPermission entityPermission) {
082        var shippingControl = Session.getModelController(ShippingControl.class);
083        var shippingMethod = shippingControl.getShippingMethodByName(shippingMethodName, entityPermission);
084
085        if(shippingMethod == null) {
086            handleExecutionError(UnknownShippingMethodNameException.class, eea, ExecutionErrors.UnknownShippingMethodName.name(), shippingMethodName);
087        }
088
089        return shippingMethod;
090    }
091
092    public ShippingMethod getShippingMethodByName(final ExecutionErrorAccumulator eea, final String shippingMethodName) {
093        return getShippingMethodByName(eea, shippingMethodName, EntityPermission.READ_ONLY);
094    }
095
096    public ShippingMethod getShippingMethodByNameForUpdate(final ExecutionErrorAccumulator eea, final String shippingMethodName) {
097        return getShippingMethodByName(eea, shippingMethodName, EntityPermission.READ_WRITE);
098    }
099
100    public ShippingMethod getShippingMethodByUniversalSpec(final ExecutionErrorAccumulator eea, final ShippingMethodUniversalSpec universalSpec,
101            final EntityPermission entityPermission) {
102        ShippingMethod shippingMethod = null;
103        var shippingControl = Session.getModelController(ShippingControl.class);
104        var shippingMethodName = universalSpec.getShippingMethodName();
105        var parameterCount = (shippingMethodName == null ? 0 : 1) + EntityInstanceLogic.getInstance().countPossibleEntitySpecs(universalSpec);
106
107        switch(parameterCount) {
108            case 1 -> {
109                if(shippingMethodName == null) {
110                    var entityInstance = EntityInstanceLogic.getInstance().getEntityInstance(eea, universalSpec,
111                            ComponentVendors.ECHO_THREE.name(), EntityTypes.ShippingMethod.name());
112
113                    if(!eea.hasExecutionErrors()) {
114                        shippingMethod = shippingControl.getShippingMethodByEntityInstance(entityInstance, entityPermission);
115                    }
116                } else {
117                    shippingMethod = getShippingMethodByName(eea, shippingMethodName, entityPermission);
118                }
119            }
120            default ->
121                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
122        }
123
124        return shippingMethod;
125    }
126
127    public ShippingMethod getShippingMethodByUniversalSpec(final ExecutionErrorAccumulator eea,
128            final ShippingMethodUniversalSpec universalSpec) {
129        return getShippingMethodByUniversalSpec(eea, universalSpec, EntityPermission.READ_ONLY);
130    }
131
132    public ShippingMethod getShippingMethodByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea,
133            final ShippingMethodUniversalSpec universalSpec) {
134        return getShippingMethodByUniversalSpec(eea, universalSpec, EntityPermission.READ_WRITE);
135    }
136
137    public void checkAcceptanceOfItem(final Session session, final ExecutionErrorAccumulator eea, final SelectorCache selectorCache,
138            final ShippingMethod shippingMethod, final Item item, final BasePK evaluatedBy) {
139        var selector = shippingMethod.getLastDetail().getItemSelector();
140        
141        if(selector != null) {
142            var cachedSelector = selectorCache.getSelector(selector);
143            
144            if(!new ShippingMethodItemSelectorEvaluator(session, evaluatedBy).evaluate(cachedSelector, item)) {
145                handleExecutionError(ItemNotAcceptibleForShippingMethodException.class, eea, ExecutionErrors.ItemNotAcceptibleForShippingMethod.name(),
146                        shippingMethod.getLastDetail().getShippingMethodName(), item.getLastDetail().getItemName());
147            }
148        }
149    }
150    
151    public void checkAcceptanceOfItem(final Session session, final ExecutionErrorAccumulator eea, final ShippingMethod shippingMethod, final Item item,
152            final BasePK evaluatedBy) {
153        var selector = shippingMethod.getLastDetail().getItemSelector();
154        
155        if(selector != null) {
156            var selectorCache = SelectorCacheFactory.getInstance().getSelectorCache(session, SelectorKinds.ITEM.name(),
157                    SelectorTypes.SHIPPING_METHOD.name());
158            
159            checkAcceptanceOfItem(session, eea, selectorCache, shippingMethod, item, evaluatedBy);
160        }
161    }
162    
163    public void checkAcceptanceOfItems(final Session session, final ExecutionErrorAccumulator eea, final ShippingMethod shippingMethod, final Set<Item> items,
164            final BasePK evaluatedBy) {
165        var selector = shippingMethod.getLastDetail().getItemSelector();
166        
167        if(selector != null) {
168            var selectorCache = SelectorCacheFactory.getInstance().getSelectorCache(session, SelectorKinds.ITEM.name(),
169                    SelectorTypes.SHIPPING_METHOD.name());
170            
171            items.forEach((item) -> {
172                checkAcceptanceOfItem(session, eea, selectorCache, shippingMethod, item, evaluatedBy);
173            });
174        }
175    }
176
177    public void updateShippingMethodFromValue(final ExecutionErrorAccumulator eea, final ShippingMethodDetailValue shippingMethodDetailValue,
178            final BasePK updatedBy) {
179        var shippingControl = Session.getModelController(ShippingControl.class);
180
181        shippingControl.updateShippingMethodFromValue(shippingMethodDetailValue, updatedBy);
182    }
183
184    public void deleteShippingMethod(final ExecutionErrorAccumulator eea, final ShippingMethod shippingMethod, final BasePK deletedBy) {
185        var shippingControl = Session.getModelController(ShippingControl.class);
186
187        shippingControl.deleteShippingMethod(shippingMethod, deletedBy);
188    }
189    
190}