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