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.control.user.offer.server.command;
018
019import com.echothree.control.user.offer.common.edit.OfferEditFactory;
020import com.echothree.control.user.offer.common.edit.OfferItemPriceEdit;
021import com.echothree.control.user.offer.common.form.EditOfferItemPriceForm;
022import com.echothree.control.user.offer.common.result.OfferResultFactory;
023import com.echothree.control.user.offer.common.spec.OfferItemPriceSpec;
024import com.echothree.model.control.accounting.server.control.AccountingControl;
025import com.echothree.model.control.accounting.server.logic.CurrencyLogic;
026import com.echothree.model.control.inventory.server.logic.InventoryConditionLogic;
027import com.echothree.model.control.item.common.ItemPriceTypes;
028import com.echothree.model.control.item.server.logic.ItemLogic;
029import com.echothree.model.control.offer.server.control.OfferItemControl;
030import com.echothree.model.control.offer.server.logic.OfferItemLogic;
031import com.echothree.model.control.offer.server.logic.OfferLogic;
032import com.echothree.model.control.party.common.PartyTypes;
033import com.echothree.model.control.security.common.SecurityRoleGroups;
034import com.echothree.model.control.security.common.SecurityRoles;
035import com.echothree.model.control.uom.server.logic.UnitOfMeasureTypeLogic;
036import com.echothree.model.data.user.common.pk.UserVisitPK;
037import com.echothree.util.common.command.BaseResult;
038import com.echothree.util.common.command.EditMode;
039import com.echothree.util.common.form.BaseForm;
040import com.echothree.util.common.message.ExecutionErrors;
041import com.echothree.util.common.validation.FieldDefinition;
042import com.echothree.util.common.validation.FieldType;
043import com.echothree.util.server.control.BaseEditCommand;
044import com.echothree.util.server.control.CommandSecurityDefinition;
045import com.echothree.util.server.control.PartyTypeDefinition;
046import com.echothree.util.server.control.SecurityRoleDefinition;
047import com.echothree.util.server.persistence.Session;
048import com.echothree.util.server.string.AmountUtils;
049import com.echothree.util.server.validation.Validator;
050import java.util.List;
051import javax.enterprise.context.Dependent;
052
053@Dependent
054public class EditOfferItemPriceCommand
055        extends BaseEditCommand<OfferItemPriceSpec, OfferItemPriceEdit> {
056    
057    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
058    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
059    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
060    
061    static {
062        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
063                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
064                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
065                        new SecurityRoleDefinition(SecurityRoleGroups.OfferItemPrice.name(), SecurityRoles.Edit.name())
066                        ))
067                ));
068        
069        SPEC_FIELD_DEFINITIONS = List.of(
070                new FieldDefinition("OfferName", FieldType.ENTITY_NAME, true, null, 20L),
071                new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null),
072                new FieldDefinition("InventoryConditionName", FieldType.ENTITY_NAME, true, null, null),
073                new FieldDefinition("UnitOfMeasureTypeName", FieldType.ENTITY_NAME, true, null, null),
074                new FieldDefinition("CurrencyIsoName", FieldType.ENTITY_NAME, true, null, null)
075                );
076        
077        EDIT_FIELD_DEFINITIONS = List.of(
078                new FieldDefinition("UnitPrice", FieldType.UNSIGNED_PRICE_UNIT, false, null, null),
079                new FieldDefinition("MinimumUnitPrice", FieldType.UNSIGNED_PRICE_UNIT, false, null, null),
080                new FieldDefinition("MaximumUnitPrice", FieldType.UNSIGNED_PRICE_UNIT, false, null, null),
081                new FieldDefinition("UnitPriceIncrement", FieldType.UNSIGNED_PRICE_UNIT, false, null, null)
082                );
083    }
084    
085    /** Creates a new instance of EditOfferItemPriceCommand */
086    public EditOfferItemPriceCommand() {
087        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
088    }
089    
090    @Override
091    protected void setupValidatorForEdit(Validator validator, BaseForm specForm) {
092        var accountingControl = Session.getModelController(AccountingControl.class);
093        var currencyIsoName = spec.getCurrencyIsoName();
094        
095        validator.setCurrency(accountingControl.getCurrencyByIsoName(currencyIsoName));
096    }
097    
098    @Override
099    protected BaseResult execute() {
100        var result = OfferResultFactory.getEditOfferItemPriceResult();
101        var offerName = spec.getOfferName();
102        var offer = OfferLogic.getInstance().getOfferByName(this, offerName);
103
104        if(!hasExecutionErrors()) {
105            final var offerDetail = offer.getLastDetail();
106
107            if(offerDetail.getOfferItemPriceFilter() == null) {
108            var itemName = spec.getItemName();
109            var inventoryConditionName = spec.getInventoryConditionName();
110            var unitOfMeasureTypeName = spec.getUnitOfMeasureTypeName();
111            var currencyIsoName = spec.getCurrencyIsoName();
112            var item = ItemLogic.getInstance().getItemByName(this, itemName);
113            var inventoryCondition = InventoryConditionLogic.getInstance().getInventoryConditionByName(this, inventoryConditionName);
114            var currency = CurrencyLogic.getInstance().getCurrencyByName(this, currencyIsoName);
115
116            if(!hasExecutionErrors()) {
117                var offerItemControl = Session.getModelController(OfferItemControl.class);
118                var offerItem = offerItemControl.getOfferItem(offer, item);
119
120                if(offerItem != null) {
121                    var itemDetail = item.getLastDetail();
122                    var unitOfMeasureKind = item.getLastDetail().getUnitOfMeasureKind();
123                    var unitOfMeasureType = UnitOfMeasureTypeLogic.getInstance().getUnitOfMeasureTypeByName(this,
124                            unitOfMeasureKind, unitOfMeasureTypeName);
125
126                    if(!hasExecutionErrors()) {
127                        var offerItemPrice = offerItemControl.getOfferItemPrice(offerItem, inventoryCondition,
128                                unitOfMeasureType, currency);
129
130                        if(offerItemPrice != null) {
131                            var itemPriceTypeName = itemDetail.getItemPriceType().getItemPriceTypeName();
132
133                            if(editMode.equals(EditMode.LOCK)) {
134                                result.setOfferItemPrice(offerItemControl.getOfferItemPriceTransfer(getUserVisit(), offerItemPrice));
135
136                                if(lockEntity(offerItem)) {
137                                    var edit = OfferEditFactory.getOfferItemPriceEdit();
138
139                                    result.setEdit(edit);
140
141                                    if(itemPriceTypeName.equals(ItemPriceTypes.FIXED.name())) {
142                                        var offerItemFixedPrice = offerItemControl.getOfferItemFixedPrice(offerItemPrice);
143
144                                        edit.setUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemFixedPrice.getUnitPrice()));
145                                    } else if(itemPriceTypeName.equals(ItemPriceTypes.VARIABLE.name())) {
146                                        var offerItemVariablePrice = offerItemControl.getOfferItemVariablePrice(offerItemPrice);
147
148                                        edit.setMinimumUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getMinimumUnitPrice()));
149                                        edit.setMaximumUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getMaximumUnitPrice()));
150                                        edit.setUnitPriceIncrement(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getUnitPriceIncrement()));
151                                    } else {
152                                        addExecutionError(ExecutionErrors.UnknownItemPriceType.name(), itemPriceTypeName);
153                                    }
154                                } else {
155                                    addExecutionError(ExecutionErrors.EntityLockFailed.name());
156                                }
157
158                                result.setEntityLock(getEntityLockTransfer(offerItem));
159                            } else if(editMode.equals(EditMode.UPDATE)) {
160                                if(itemPriceTypeName.equals(ItemPriceTypes.FIXED.name())) {
161                                    var strUnitPrice = edit.getUnitPrice();
162
163                                    if(strUnitPrice != null) {
164                                        var unitPrice = Long.valueOf(strUnitPrice);
165
166                                        if(lockEntityForUpdate(offerItem)) {
167                                            try {
168                                                var offerItemFixedPriceValue = offerItemControl.getOfferItemFixedPriceValueForUpdate(offerItemPrice);
169
170                                                offerItemFixedPriceValue.setUnitPrice(unitPrice);
171
172                                                OfferItemLogic.getInstance().updateOfferItemFixedPriceFromValue(offerItemFixedPriceValue, getPartyPK());
173                                            } finally {
174                                                unlockEntity(offerItem);
175                                            }
176                                        } else {
177                                            addExecutionError(ExecutionErrors.EntityLockStale.name());
178                                        }
179                                    } else {
180                                        addExecutionError(ExecutionErrors.MissingUnitPrice.name());
181                                    }
182                                } else if(itemPriceTypeName.equals(ItemPriceTypes.VARIABLE.name())) {
183                                    var strMinimumUnitPrice = edit.getMinimumUnitPrice();
184                                    Long minimumUnitPrice = null;
185                                    var strMaximumUnitPrice = edit.getMaximumUnitPrice();
186                                    Long maximumUnitPrice = null;
187                                    var strUnitPriceIncrement = edit.getUnitPriceIncrement();
188                                    Long unitPriceIncrement = null;
189
190                                    if(strMinimumUnitPrice != null) {
191                                        minimumUnitPrice = Long.valueOf(strMinimumUnitPrice);
192                                    } else {
193                                        addExecutionError(ExecutionErrors.MissingMinimumUnitPrice.name());
194                                    }
195
196                                    if(strMaximumUnitPrice != null) {
197                                        maximumUnitPrice = Long.valueOf(strMaximumUnitPrice);
198                                    } else {
199                                        addExecutionError(ExecutionErrors.MissingMaximumUnitPrice.name());
200                                    }
201
202                                    if(strUnitPriceIncrement != null) {
203                                        unitPriceIncrement = Long.valueOf(strUnitPriceIncrement);
204                                    } else {
205                                        addExecutionError(ExecutionErrors.MissingUnitPriceIncrement.name());
206                                    }
207
208                                    if(minimumUnitPrice != null && maximumUnitPrice != null && unitPriceIncrement != null) {
209                                        if(lockEntityForUpdate(offerItem)) {
210                                            try {
211                                                var offerItemVariablePriceValue = offerItemControl.getOfferItemVariablePriceValueForUpdate(offerItemPrice);
212
213                                                offerItemVariablePriceValue.setMinimumUnitPrice(minimumUnitPrice);
214                                                offerItemVariablePriceValue.setMaximumUnitPrice(maximumUnitPrice);
215                                                offerItemVariablePriceValue.setUnitPriceIncrement(unitPriceIncrement);
216
217                                                OfferItemLogic.getInstance().updateOfferItemVariablePriceFromValue(offerItemVariablePriceValue, getPartyPK());
218                                            } finally {
219                                                unlockEntity(offerItem);
220                                            }
221                                        } else {
222                                            addExecutionError(ExecutionErrors.EntityLockStale.name());
223                                        }
224                                    }
225                                } else {
226                                    addExecutionError(ExecutionErrors.UnknownItemPriceType.name(), itemPriceTypeName);
227                                }
228                            }
229                        } else {
230                            addExecutionError(ExecutionErrors.DuplicateOfferItemPrice.name());
231                        }
232                    }
233                } else {
234                    addExecutionError(ExecutionErrors.UnknownOfferItem.name(), offerName, itemName);
235                }
236            }
237            } else {
238                addExecutionError(ExecutionErrors.CannotManuallyEditOfferItemPriceWhenOfferItemPriceFilterSet.name(),
239                        offerDetail.getOfferName());
240            }
241        }
242        
243        return result;
244    }
245    
246}