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.string.AmountUtils;
048import com.echothree.util.server.validation.Validator;
049import java.util.List;
050import javax.enterprise.context.Dependent;
051import javax.inject.Inject;
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    @Inject
086    AccountingControl accountingControl;
087
088    @Inject
089    OfferItemControl offerItemControl;
090
091    @Inject
092    CurrencyLogic currencyLogic;
093
094    @Inject
095    InventoryConditionLogic inventoryConditionLogic;
096
097    @Inject
098    ItemLogic itemLogic;
099
100    @Inject
101    OfferItemLogic offerItemLogic;
102
103    @Inject
104    OfferLogic offerLogic;
105
106    @Inject
107    UnitOfMeasureTypeLogic unitOfMeasureTypeLogic;
108
109    
110    /** Creates a new instance of EditOfferItemPriceCommand */
111    public EditOfferItemPriceCommand() {
112        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
113    }
114    
115    @Override
116    protected void setupValidatorForEdit(Validator validator, BaseForm specForm) {
117        var currencyIsoName = spec.getCurrencyIsoName();
118        
119        validator.setCurrency(accountingControl.getCurrencyByIsoName(currencyIsoName));
120    }
121    
122    @Override
123    protected BaseResult execute() {
124        var result = OfferResultFactory.getEditOfferItemPriceResult();
125        var offerName = spec.getOfferName();
126        var offer = offerLogic.getOfferByName(this, offerName);
127
128        if(!hasExecutionErrors()) {
129            final var offerDetail = offer.getLastDetail();
130
131            if(offerDetail.getOfferItemPriceFilter() == null) {
132            var itemName = spec.getItemName();
133            var inventoryConditionName = spec.getInventoryConditionName();
134            var unitOfMeasureTypeName = spec.getUnitOfMeasureTypeName();
135            var currencyIsoName = spec.getCurrencyIsoName();
136            var item = itemLogic.getItemByName(this, itemName);
137            var inventoryCondition = inventoryConditionLogic.getInventoryConditionByName(this, inventoryConditionName);
138            var currency = currencyLogic.getCurrencyByName(this, currencyIsoName);
139
140            if(!hasExecutionErrors()) {
141                var offerItem = offerItemControl.getOfferItem(offer, item);
142
143                if(offerItem != null) {
144                    var itemDetail = item.getLastDetail();
145                    var unitOfMeasureKind = item.getLastDetail().getUnitOfMeasureKind();
146                    var unitOfMeasureType = unitOfMeasureTypeLogic.getUnitOfMeasureTypeByName(this,
147                            unitOfMeasureKind, unitOfMeasureTypeName);
148
149                    if(!hasExecutionErrors()) {
150                        var offerItemPrice = offerItemControl.getOfferItemPrice(offerItem, inventoryCondition,
151                                unitOfMeasureType, currency);
152
153                        if(offerItemPrice != null) {
154                            var itemPriceTypeName = itemDetail.getItemPriceType().getItemPriceTypeName();
155
156                            if(editMode.equals(EditMode.LOCK)) {
157                                result.setOfferItemPrice(offerItemControl.getOfferItemPriceTransfer(getUserVisit(), offerItemPrice));
158
159                                if(lockEntity(offerItem)) {
160                                    var edit = OfferEditFactory.getOfferItemPriceEdit();
161
162                                    result.setEdit(edit);
163
164                                    if(itemPriceTypeName.equals(ItemPriceTypes.FIXED.name())) {
165                                        var offerItemFixedPrice = offerItemControl.getOfferItemFixedPrice(offerItemPrice);
166
167                                        edit.setUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemFixedPrice.getUnitPrice()));
168                                    } else if(itemPriceTypeName.equals(ItemPriceTypes.VARIABLE.name())) {
169                                        var offerItemVariablePrice = offerItemControl.getOfferItemVariablePrice(offerItemPrice);
170
171                                        edit.setMinimumUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getMinimumUnitPrice()));
172                                        edit.setMaximumUnitPrice(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getMaximumUnitPrice()));
173                                        edit.setUnitPriceIncrement(AmountUtils.getInstance().formatPriceUnit(currency, offerItemVariablePrice.getUnitPriceIncrement()));
174                                    } else {
175                                        addExecutionError(ExecutionErrors.UnknownItemPriceType.name(), itemPriceTypeName);
176                                    }
177                                } else {
178                                    addExecutionError(ExecutionErrors.EntityLockFailed.name());
179                                }
180
181                                result.setEntityLock(getEntityLockTransfer(offerItem));
182                            } else if(editMode.equals(EditMode.UPDATE)) {
183                                if(itemPriceTypeName.equals(ItemPriceTypes.FIXED.name())) {
184                                    var strUnitPrice = edit.getUnitPrice();
185
186                                    if(strUnitPrice != null) {
187                                        var unitPrice = Long.valueOf(strUnitPrice);
188
189                                        if(lockEntityForUpdate(offerItem)) {
190                                            try {
191                                                var offerItemFixedPriceValue = offerItemControl.getOfferItemFixedPriceValueForUpdate(offerItemPrice);
192
193                                                offerItemFixedPriceValue.setUnitPrice(unitPrice);
194
195                                                offerItemLogic.updateOfferItemFixedPriceFromValue(offerItemFixedPriceValue, getPartyPK());
196                                            } finally {
197                                                unlockEntity(offerItem);
198                                            }
199                                        } else {
200                                            addExecutionError(ExecutionErrors.EntityLockStale.name());
201                                        }
202                                    } else {
203                                        addExecutionError(ExecutionErrors.MissingUnitPrice.name());
204                                    }
205                                } else if(itemPriceTypeName.equals(ItemPriceTypes.VARIABLE.name())) {
206                                    var strMinimumUnitPrice = edit.getMinimumUnitPrice();
207                                    Long minimumUnitPrice = null;
208                                    var strMaximumUnitPrice = edit.getMaximumUnitPrice();
209                                    Long maximumUnitPrice = null;
210                                    var strUnitPriceIncrement = edit.getUnitPriceIncrement();
211                                    Long unitPriceIncrement = null;
212
213                                    if(strMinimumUnitPrice != null) {
214                                        minimumUnitPrice = Long.valueOf(strMinimumUnitPrice);
215                                    } else {
216                                        addExecutionError(ExecutionErrors.MissingMinimumUnitPrice.name());
217                                    }
218
219                                    if(strMaximumUnitPrice != null) {
220                                        maximumUnitPrice = Long.valueOf(strMaximumUnitPrice);
221                                    } else {
222                                        addExecutionError(ExecutionErrors.MissingMaximumUnitPrice.name());
223                                    }
224
225                                    if(strUnitPriceIncrement != null) {
226                                        unitPriceIncrement = Long.valueOf(strUnitPriceIncrement);
227                                    } else {
228                                        addExecutionError(ExecutionErrors.MissingUnitPriceIncrement.name());
229                                    }
230
231                                    if(minimumUnitPrice != null && maximumUnitPrice != null && unitPriceIncrement != null) {
232                                        if(lockEntityForUpdate(offerItem)) {
233                                            try {
234                                                var offerItemVariablePriceValue = offerItemControl.getOfferItemVariablePriceValueForUpdate(offerItemPrice);
235
236                                                offerItemVariablePriceValue.setMinimumUnitPrice(minimumUnitPrice);
237                                                offerItemVariablePriceValue.setMaximumUnitPrice(maximumUnitPrice);
238                                                offerItemVariablePriceValue.setUnitPriceIncrement(unitPriceIncrement);
239
240                                                offerItemLogic.updateOfferItemVariablePriceFromValue(offerItemVariablePriceValue, getPartyPK());
241                                            } finally {
242                                                unlockEntity(offerItem);
243                                            }
244                                        } else {
245                                            addExecutionError(ExecutionErrors.EntityLockStale.name());
246                                        }
247                                    }
248                                } else {
249                                    addExecutionError(ExecutionErrors.UnknownItemPriceType.name(), itemPriceTypeName);
250                                }
251                            }
252                        } else {
253                            addExecutionError(ExecutionErrors.DuplicateOfferItemPrice.name());
254                        }
255                    }
256                } else {
257                    addExecutionError(ExecutionErrors.UnknownOfferItem.name(), offerName, itemName);
258                }
259            }
260            } else {
261                addExecutionError(ExecutionErrors.CannotManuallyEditOfferItemPriceWhenOfferItemPriceFilterSet.name(),
262                        offerDetail.getOfferName());
263            }
264        }
265        
266        return result;
267    }
268    
269}