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