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.inventory.server.command;
018
019import com.echothree.control.user.inventory.common.edit.InventoryEditFactory;
020import com.echothree.control.user.inventory.common.edit.PartyInventoryLevelEdit;
021import com.echothree.control.user.inventory.common.result.EditPartyInventoryLevelResult;
022import com.echothree.control.user.inventory.common.result.InventoryResultFactory;
023import com.echothree.control.user.inventory.common.spec.PartyInventoryLevelSpec;
024import com.echothree.control.user.inventory.server.command.common.PartyInventoryLevelUtil;
025import com.echothree.model.control.inventory.server.control.InventoryConditionControl;
026import com.echothree.model.control.inventory.server.control.InventoryLevelControl;
027import com.echothree.model.control.item.server.control.ItemControl;
028import com.echothree.model.control.party.common.PartyTypes;
029import com.echothree.model.control.security.common.SecurityRoleGroups;
030import com.echothree.model.control.security.common.SecurityRoles;
031import com.echothree.model.control.uom.server.control.UomControl;
032import com.echothree.model.control.uom.server.logic.UnitOfMeasureTypeLogic;
033import com.echothree.model.control.uom.server.util.Conversion;
034import com.echothree.model.data.inventory.server.entity.PartyInventoryLevel;
035import com.echothree.model.data.item.server.entity.Item;
036import com.echothree.model.data.uom.server.entity.UnitOfMeasureKind;
037import com.echothree.util.common.command.EditMode;
038import com.echothree.util.common.message.ExecutionErrors;
039import com.echothree.util.common.validation.FieldDefinition;
040import com.echothree.util.common.validation.FieldType;
041import com.echothree.util.server.control.BaseAbstractEditCommand;
042import com.echothree.util.server.control.CommandSecurityDefinition;
043import com.echothree.util.server.control.PartyTypeDefinition;
044import com.echothree.util.server.control.SecurityRoleDefinition;
045import java.util.List;
046import javax.enterprise.context.Dependent;
047import javax.inject.Inject;
048
049@Dependent
050public class EditPartyInventoryLevelCommand
051        extends BaseAbstractEditCommand<PartyInventoryLevelSpec, PartyInventoryLevelEdit, EditPartyInventoryLevelResult, PartyInventoryLevel, Item> {
052
053    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
054    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
055    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
056
057    static {
058        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
059                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
060                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
061                        new SecurityRoleDefinition(SecurityRoleGroups.PartyInventoryLevel.name(), SecurityRoles.Edit.name())
062                ))
063        ));
064
065        SPEC_FIELD_DEFINITIONS = List.of(
066                new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null),
067                new FieldDefinition("CompanyName", FieldType.ENTITY_NAME, false, null, null),
068                new FieldDefinition("WarehouseName", FieldType.ENTITY_NAME, false, null, null),
069                new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null),
070                new FieldDefinition("InventoryConditionName", FieldType.ENTITY_NAME, true, null, null)
071        );
072
073        EDIT_FIELD_DEFINITIONS = List.of(
074                new FieldDefinition("MinimumInventoryUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
075                new FieldDefinition("MinimumInventory", FieldType.UNSIGNED_LONG, false, null, null),
076                new FieldDefinition("MaximumInventoryUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
077                new FieldDefinition("MaximumInventory", FieldType.UNSIGNED_LONG, false, null, null),
078                new FieldDefinition("ReorderQuantityUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
079                new FieldDefinition("ReorderQuantity", FieldType.UNSIGNED_LONG, false, null, null)
080        );
081    }
082
083    @Inject
084    InventoryConditionControl inventoryConditionControl;
085
086    @Inject
087    InventoryLevelControl inventoryLevelControl;
088
089    @Inject
090    ItemControl itemControl;
091
092    @Inject
093    UomControl uomControl;
094
095    @Inject
096    UnitOfMeasureTypeLogic unitOfMeasureTypeLogic;
097
098    @Inject
099    PartyInventoryLevelUtil partyInventoryLevelUtil;
100
101    /** Creates a new instance of EditPartyInventoryLevelCommand */
102    public EditPartyInventoryLevelCommand() {
103        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
104    }
105
106    @Override
107    public EditPartyInventoryLevelResult getResult() {
108        return InventoryResultFactory.getEditPartyInventoryLevelResult();
109    }
110
111    @Override
112    public PartyInventoryLevelEdit getEdit() {
113        return InventoryEditFactory.getPartyInventoryLevelEdit();
114    }
115
116    UnitOfMeasureKind unitOfMeasureKind;
117
118    @Override
119    public PartyInventoryLevel getEntity(EditPartyInventoryLevelResult result) {
120        PartyInventoryLevel partyInventoryLevel = null;
121        var party = partyInventoryLevelUtil.getParty(this, spec);
122
123        if(party != null) {
124            var itemName = spec.getItemName();
125            var item = itemControl.getItemByName(itemName);
126
127            if(item != null) {
128                var partyTypeName = partyInventoryLevelUtil.getPartyTypeName(party);
129
130                if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.UPDATE)) {
131                    unitOfMeasureKind = item.getLastDetail().getUnitOfMeasureKind();
132                }
133
134                if(partyTypeName.equals(PartyTypes.COMPANY.name())) {
135                    if(!party.equals(item.getLastDetail().getCompanyParty())) {
136                        addExecutionError(ExecutionErrors.InvalidCompany.name());
137                    }
138                }
139
140                if(!hasExecutionErrors()) {
141                    var inventoryConditionName = spec.getInventoryConditionName();
142                    var inventoryCondition = inventoryConditionControl.getInventoryConditionByName(inventoryConditionName);
143
144                    if(inventoryCondition != null) {
145                        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
146                            partyInventoryLevel = inventoryLevelControl.getPartyInventoryLevel(party, item, inventoryCondition);
147                        } else { // EditMode.UPDATE
148                            partyInventoryLevel = inventoryLevelControl.getPartyInventoryLevelForUpdate(party, item, inventoryCondition);
149                        }
150
151                        if(partyInventoryLevel == null) {
152                            addExecutionError(ExecutionErrors.UnknownPartyInventoryLevel.name(), party.getLastDetail().getPartyName(), itemName, inventoryConditionName);
153                        }
154                    } else {
155                        addExecutionError(ExecutionErrors.UnknownInventoryConditionName.name(), inventoryConditionName);
156                    }
157                }
158            } else {
159                addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName);
160            }
161        }
162
163        return partyInventoryLevel;
164    }
165
166    @Override
167    public Item getLockEntity(PartyInventoryLevel partyInventoryLevel) {
168        return partyInventoryLevel.getItem();
169    }
170
171    @Override
172    public void fillInResult(EditPartyInventoryLevelResult result, PartyInventoryLevel partyInventoryLevel) {
173        result.setPartyInventoryLevel(inventoryLevelControl.getPartyInventoryLevelTransfer(getUserVisit(), partyInventoryLevel));
174    }
175
176    @Override
177    public void doLock(PartyInventoryLevelEdit edit, PartyInventoryLevel partyInventoryLevel) {
178        minimumInventory = partyInventoryLevel.getMinimumInventory();
179        var minimumInventoryConversion = minimumInventory == null ? null : new Conversion(uomControl, unitOfMeasureKind, minimumInventory).convertToHighestUnitOfMeasureType();
180
181        maximumInventory = partyInventoryLevel.getMaximumInventory();
182        var maximumInventoryConversion = maximumInventory == null ? null : new Conversion(uomControl, unitOfMeasureKind, maximumInventory).convertToHighestUnitOfMeasureType();
183
184        reorderQuantity = partyInventoryLevel.getReorderQuantity();
185        var reorderQuantityConversion = reorderQuantity == null ? null : new Conversion(uomControl, unitOfMeasureKind, reorderQuantity).convertToHighestUnitOfMeasureType();
186
187        edit.setMinimumInventory(minimumInventoryConversion.getQuantity().toString());
188        edit.setMinimumInventoryUnitOfMeasureTypeName(minimumInventoryConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
189        edit.setMaximumInventory(maximumInventoryConversion.getQuantity().toString());
190        edit.setMaximumInventoryUnitOfMeasureTypeName(maximumInventoryConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
191        edit.setReorderQuantity(reorderQuantityConversion.getQuantity().toString());
192        edit.setReorderQuantityUnitOfMeasureTypeName(reorderQuantityConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
193    }
194
195    Long minimumInventory;
196    Long maximumInventory;
197    Long reorderQuantity;
198
199    @Override
200    public void canUpdate(PartyInventoryLevel partyInventoryLevel) {
201        minimumInventory = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
202                edit.getMinimumInventory(), edit.getMinimumInventoryUnitOfMeasureTypeName(),
203                null, ExecutionErrors.MissingRequiredMinimumInventory.name(), null, ExecutionErrors.MissingRequiredMinimumInventoryUnitOfMeasureTypeName.name(),
204                null, ExecutionErrors.UnknownMinimumInventoryUnitOfMeasureTypeName.name());
205
206        if(!hasExecutionErrors()) {
207            maximumInventory = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
208                    edit.getMaximumInventory(), edit.getMaximumInventoryUnitOfMeasureTypeName(),
209                    null, ExecutionErrors.MissingRequiredMaximumInventory.name(), null, ExecutionErrors.MissingRequiredMaximumInventoryUnitOfMeasureTypeName.name(),
210                    null, ExecutionErrors.UnknownMaximumInventoryUnitOfMeasureTypeName.name());
211
212            if(!hasExecutionErrors()) {
213                reorderQuantity = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
214                        edit.getReorderQuantity(), edit.getReorderQuantityUnitOfMeasureTypeName(),
215                        null, ExecutionErrors.MissingRequiredReorderQuantity.name(), null, ExecutionErrors.MissingRequiredReorderQuantityUnitOfMeasureTypeName.name(),
216                        null, ExecutionErrors.UnknownReorderQuantityUnitOfMeasureTypeName.name());
217            }
218        }
219    }
220
221    @Override
222    public void doUpdate(PartyInventoryLevel partyInventoryLevel) {
223        var partyInventoryLevelValue = inventoryLevelControl.getPartyInventoryLevelValue(partyInventoryLevel);
224
225        partyInventoryLevelValue.setMinimumInventory(minimumInventory);
226        partyInventoryLevelValue.setMaximumInventory(maximumInventory);
227        partyInventoryLevelValue.setReorderQuantity(reorderQuantity);
228
229        inventoryLevelControl.updatePartyInventoryLevelFromValue(partyInventoryLevelValue, getPartyPK());
230    }
231
232}