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