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