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.offer.server.logic;
018
019import com.echothree.control.user.offer.common.spec.OfferUniversalSpec;
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.offer.common.exception.CannotDeleteOfferInUseException;
025import com.echothree.model.control.offer.common.exception.DuplicateOfferNameException;
026import com.echothree.model.control.offer.common.exception.UnknownDefaultOfferException;
027import com.echothree.model.control.offer.common.exception.UnknownOfferNameException;
028import com.echothree.model.control.offer.server.control.OfferControl;
029import com.echothree.model.control.offer.server.control.OfferItemControl;
030import com.echothree.model.control.offer.server.control.OfferUseControl;
031import com.echothree.model.data.filter.server.entity.Filter;
032import com.echothree.model.data.offer.server.entity.Offer;
033import com.echothree.model.data.offer.server.factory.OfferFactory;
034import com.echothree.model.data.offer.server.value.OfferDetailValue;
035import com.echothree.model.data.party.server.entity.Language;
036import com.echothree.model.data.party.server.entity.Party;
037import com.echothree.model.data.selector.server.entity.Selector;
038import com.echothree.model.data.sequence.server.entity.Sequence;
039import com.echothree.util.common.message.ExecutionErrors;
040import com.echothree.util.common.persistence.BasePK;
041import com.echothree.util.server.control.BaseLogic;
042import com.echothree.util.server.message.ExecutionErrorAccumulator;
043import com.echothree.util.server.persistence.EntityPermission;
044import com.echothree.util.server.persistence.Session;
045import javax.enterprise.context.ApplicationScoped;
046import javax.enterprise.inject.spi.CDI;
047
048@ApplicationScoped
049public class OfferLogic
050        extends BaseLogic {
051
052    protected OfferLogic() {
053        super();
054    }
055
056    public static OfferLogic getInstance() {
057        return CDI.current().select(OfferLogic.class).get();
058    }
059
060    public Offer createOffer(final ExecutionErrorAccumulator eea, final String offerName, final Sequence salesOrderSequence,
061            final Party departmentParty, final Selector offerItemSelector, final Filter offerItemPriceFilter, final Boolean isDefault,
062            final Integer sortOrder, final Language language, final String description, final BasePK createdBy) {
063        var offerControl = Session.getModelController(OfferControl.class);
064        var offer = offerControl.getOfferByName(offerName);
065
066        if(offer == null) {
067            offer = offerControl.createOffer(offerName, salesOrderSequence, departmentParty, offerItemSelector,
068                    offerItemPriceFilter, isDefault, sortOrder, createdBy);
069
070            if(description != null) {
071                offerControl.createOfferDescription(offer, language, description, createdBy);
072            }
073        } else {
074            handleExecutionError(DuplicateOfferNameException.class, eea, ExecutionErrors.DuplicateOfferName.name(), offerName);
075        }
076
077        return offer;
078    }
079
080    public Offer getOfferByName(final ExecutionErrorAccumulator eea, final String offerName,
081            final EntityPermission entityPermission) {
082        var offerControl = Session.getModelController(OfferControl.class);
083        var offer = offerControl.getOfferByName(offerName, entityPermission);
084
085        if(offer == null) {
086            handleExecutionError(UnknownOfferNameException.class, eea, ExecutionErrors.UnknownOfferName.name(), offerName);
087        }
088
089        return offer;
090    }
091
092    public Offer getOfferByName(final ExecutionErrorAccumulator eea, final String offerName) {
093        return getOfferByName(eea, offerName, EntityPermission.READ_ONLY);
094    }
095
096    public Offer getOfferByNameForUpdate(final ExecutionErrorAccumulator eea, final String offerName) {
097        return getOfferByName(eea, offerName, EntityPermission.READ_WRITE);
098    }
099
100    public Offer getOfferByUniversalSpec(final ExecutionErrorAccumulator eea,
101            final OfferUniversalSpec universalSpec, boolean allowDefault, final EntityPermission entityPermission) {
102        Offer offer = null;
103        var offerControl = Session.getModelController(OfferControl.class);
104        var offerName = universalSpec.getOfferName();
105        var parameterCount = (offerName == null ? 0 : 1) + EntityInstanceLogic.getInstance().countPossibleEntitySpecs(universalSpec);
106
107        switch(parameterCount) {
108            case 0 -> {
109                if(allowDefault) {
110                    offer = offerControl.getDefaultOffer(entityPermission);
111
112                    if(offer == null) {
113                        handleExecutionError(UnknownDefaultOfferException.class, eea, ExecutionErrors.UnknownDefaultOffer.name());
114                    }
115                } else {
116                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
117                }
118            }
119            case 1 -> {
120                if(offerName == null) {
121                    var entityInstance = EntityInstanceLogic.getInstance().getEntityInstance(eea, universalSpec,
122                            ComponentVendors.ECHO_THREE.name(), EntityTypes.Offer.name());
123
124                    if(!eea.hasExecutionErrors()) {
125                        offer = offerControl.getOfferByEntityInstance(entityInstance, entityPermission);
126                    }
127                } else {
128                    offer = getOfferByName(eea, offerName, entityPermission);
129                }
130            }
131            default ->
132                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
133        }
134
135        return offer;
136    }
137
138    public Offer getOfferByUniversalSpec(final ExecutionErrorAccumulator eea,
139            final OfferUniversalSpec universalSpec, boolean allowDefault) {
140        return getOfferByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY);
141    }
142
143    public Offer getOfferByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea,
144            final OfferUniversalSpec universalSpec, boolean allowDefault) {
145        return getOfferByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE);
146    }
147
148    public void updateOfferFromValue(OfferDetailValue offerDetailValue, BasePK updatedBy) {
149        var offerControl = Session.getModelController(OfferControl.class);
150
151        if(offerDetailValue.getOfferItemSelectorPKHasBeenModified() && offerDetailValue.getOfferItemSelectorPK() != null) {
152            var offer = OfferFactory.getInstance().getEntityFromPK(EntityPermission.READ_WRITE, offerDetailValue.getOfferPK());
153
154            OfferItemLogic.getInstance().deleteOfferItemsByOffer(offer, updatedBy);
155        } else if(offerDetailValue.getOfferItemPriceFilterPKHasBeenModified() && offerDetailValue.getOfferItemPriceFilterPK() != null) {
156            var offerItemControl = Session.getModelController(OfferItemControl.class);
157            var offer = OfferFactory.getInstance().getEntityFromPK(EntityPermission.READ_WRITE, offerDetailValue.getOfferPK());
158
159            var offerItems = offerItemControl.getOfferItemsByOffer(offer);
160            for(var offerItem : offerItems) {
161                var offerItemPrices = offerItemControl.getOfferItemPricesByOfferItemForUpdate(offerItem);
162
163                for(var offerItemPrice : offerItemPrices) {
164                    offerItemControl.deleteOfferItemPrice(offerItemPrice, updatedBy);
165                }
166            }
167        }
168
169        offerControl.updateOfferFromValue(offerDetailValue, updatedBy);
170    }
171
172    public void deleteOffer(final ExecutionErrorAccumulator eea, final Offer offer, final BasePK deletedBy) {
173        var offerUseControl = Session.getModelController(OfferUseControl.class);
174
175        if(offerUseControl.countOfferUsesByOffer(offer) == 0) {
176            var offerControl = Session.getModelController(OfferControl.class);
177
178            offerControl.deleteOffer(offer, deletedBy);
179        } else {
180            handleExecutionError(CannotDeleteOfferInUseException.class, eea, ExecutionErrors.CannotDeleteOfferInUse.name());
181        }
182    }
183
184}