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.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.form.EditPartyInventoryLevelForm;
022import com.echothree.control.user.inventory.common.result.EditPartyInventoryLevelResult;
023import com.echothree.control.user.inventory.common.result.InventoryResultFactory;
024import com.echothree.control.user.inventory.common.spec.PartyInventoryLevelSpec;
025import com.echothree.model.control.inventory.server.control.InventoryControl;
026import com.echothree.model.control.item.server.control.ItemControl;
027import com.echothree.model.control.party.common.PartyTypes;
028import com.echothree.model.control.party.server.control.PartyControl;
029import com.echothree.model.control.uom.server.control.UomControl;
030import com.echothree.model.control.uom.server.logic.UnitOfMeasureTypeLogic;
031import com.echothree.model.control.uom.server.util.Conversion;
032import com.echothree.model.control.warehouse.server.control.WarehouseControl;
033import com.echothree.model.data.inventory.server.entity.PartyInventoryLevel;
034import com.echothree.model.data.item.server.entity.Item;
035import com.echothree.model.data.party.server.entity.Party;
036import com.echothree.model.data.uom.server.entity.UnitOfMeasureKind;
037import com.echothree.model.data.user.common.pk.UserVisitPK;
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.common.command.EditMode;
042import com.echothree.util.server.control.BaseAbstractEditCommand;
043import com.echothree.util.server.persistence.Session;
044import java.util.Arrays;
045import java.util.Collections;
046import java.util.List;
047import javax.enterprise.context.RequestScoped;
048
049@RequestScoped
050public class EditPartyInventoryLevelCommand
051        extends BaseAbstractEditCommand<PartyInventoryLevelSpec, PartyInventoryLevelEdit, EditPartyInventoryLevelResult, PartyInventoryLevel, Item> {
052    
053    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
054    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
055    
056    static {
057        SPEC_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
058                new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null),
059                new FieldDefinition("CompanyName", FieldType.ENTITY_NAME, false, null, null),
060                new FieldDefinition("WarehouseName", FieldType.ENTITY_NAME, false, null, null),
061                new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null),
062                new FieldDefinition("InventoryConditionName", FieldType.ENTITY_NAME, true, null, null)
063                ));
064        
065        EDIT_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
066                new FieldDefinition("MinimumInventoryUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
067                new FieldDefinition("MinimumInventory", FieldType.UNSIGNED_LONG, false, null, null),
068                new FieldDefinition("MaximumInventoryUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
069                new FieldDefinition("MaximumInventory", FieldType.UNSIGNED_LONG, false, null, null),
070                new FieldDefinition("ReorderQuantityUnitOfMeasureTypeName", FieldType.ENTITY_NAME, false, null, null),
071                new FieldDefinition("ReorderQuantity", FieldType.UNSIGNED_LONG, false, null, null)
072                ));
073    }
074
075    /** Creates a new instance of EditPartyInventoryLevelCommand */
076    public EditPartyInventoryLevelCommand() {
077        super(null, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
078    }
079
080    @Override
081    public EditPartyInventoryLevelResult getResult() {
082        return InventoryResultFactory.getEditPartyInventoryLevelResult();
083    }
084
085    @Override
086    public PartyInventoryLevelEdit getEdit() {
087        return InventoryEditFactory.getPartyInventoryLevelEdit();
088    }
089
090    // TODO: Duplicated from BasePartyInventoryLevelCommand
091    protected String getPartyTypeName(final Party party) {
092        return party.getLastDetail().getPartyType().getPartyTypeName();
093    }
094
095    protected Party getParty(final String partyName, final String companyName, final String warehouseName) {
096        Party party = null;
097
098        if(partyName != null || companyName != null) {
099            var partyControl = Session.getModelController(PartyControl.class);
100
101            if(partyName != null) {
102                party = partyControl.getPartyByName(partyName);
103
104                if(party != null) {
105                    var partyTypeName = getPartyTypeName(party);
106
107                    if(!partyTypeName.equals(PartyTypes.COMPANY.name())
108                            && !partyTypeName.equals(PartyTypes.WAREHOUSE.name())) {
109                        party = null;
110                        addExecutionError(ExecutionErrors.InvalidPartyType.name());
111                    }
112                }  else {
113                    addExecutionError(ExecutionErrors.UnknownPartyName.name(), partyName);
114                }
115            } else if(companyName != null) {
116                var partyCompany = partyControl.getPartyCompanyByName(companyName);
117
118                if(partyCompany != null) {
119                    party = partyCompany.getParty();
120                } else {
121                    addExecutionError(ExecutionErrors.UnknownCompanyName.name(), companyName);
122                }
123            }
124        } else if(warehouseName != null) {
125            var warehouseControl = Session.getModelController(WarehouseControl.class);
126            var warehouse = warehouseControl.getWarehouseByName(warehouseName);
127
128            if(warehouse != null) {
129                party = warehouse.getParty();
130            } else {
131                addExecutionError(ExecutionErrors.UnknownWarehouseName.name(), warehouseName);
132            }
133        }
134        return party;
135    }
136
137    protected Party getParty(PartyInventoryLevelSpec spec) {
138        var partyName = spec.getPartyName();
139        var companyName = spec.getCompanyName();
140        var warehouseName = spec.getWarehouseName();
141        var parameterCount = (partyName == null ? 0 : 1) + (companyName == null ? 0 : 1) + (warehouseName == null ? 0 : 1);
142        Party party = null;
143
144        if(parameterCount == 1) {
145            party = getParty(partyName, companyName, warehouseName);
146        }  else {
147            addExecutionError(ExecutionErrors.InvalidParameterCount.name());
148        }
149
150        return party;
151    }
152
153    UnitOfMeasureKind unitOfMeasureKind;
154
155    @Override
156    public PartyInventoryLevel getEntity(EditPartyInventoryLevelResult result) {
157        var itemControl = Session.getModelController(ItemControl.class);
158        PartyInventoryLevel partyInventoryLevel = null;
159        var party = getParty(spec);
160
161        if(party != null) {
162            var itemName = spec.getItemName();
163            var item = itemControl.getItemByName(itemName);
164
165            if(item != null) {
166                var partyTypeName = getPartyTypeName(party);
167
168                if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.UPDATE)) {
169                    unitOfMeasureKind = item.getLastDetail().getUnitOfMeasureKind();
170                }
171
172                if(partyTypeName.equals(PartyTypes.COMPANY.name())) {
173                    if(!party.equals(item.getLastDetail().getCompanyParty())) {
174                        addExecutionError(ExecutionErrors.InvalidCompany.name());
175                    }
176                }
177
178                if(!hasExecutionErrors()) {
179                    var inventoryControl = Session.getModelController(InventoryControl.class);
180                    var inventoryConditionName = spec.getInventoryConditionName();
181                    var inventoryCondition = inventoryControl.getInventoryConditionByName(inventoryConditionName);
182
183                    if(inventoryCondition != null) {
184                        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
185                            partyInventoryLevel = inventoryControl.getPartyInventoryLevel(party, item, inventoryCondition);
186                        } else { // EditMode.UPDATE
187                            partyInventoryLevel = inventoryControl.getPartyInventoryLevelForUpdate(party, item, inventoryCondition);
188                        }
189
190                        if(partyInventoryLevel == null) {
191                            addExecutionError(ExecutionErrors.UnknownPartyInventoryLevel.name(), party.getLastDetail().getPartyName(), itemName, inventoryConditionName);
192                        }
193                    } else {
194                        addExecutionError(ExecutionErrors.UnknownInventoryConditionName.name(), inventoryConditionName);
195                    }
196                }
197            } else {
198                addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName);
199            }
200        }
201
202        return partyInventoryLevel;
203    }
204
205    @Override
206    public Item getLockEntity(PartyInventoryLevel partyInventoryLevel) {
207        return partyInventoryLevel.getItem();
208    }
209
210    @Override
211    public void fillInResult(EditPartyInventoryLevelResult result, PartyInventoryLevel partyInventoryLevel) {
212        var inventoryControl = Session.getModelController(InventoryControl.class);
213
214        result.setPartyInventoryLevel(inventoryControl.getPartyInventoryLevelTransfer(getUserVisit(), partyInventoryLevel));
215    }
216
217    @Override
218    public void doLock(PartyInventoryLevelEdit edit, PartyInventoryLevel partyInventoryLevel) {
219        var uomControl = Session.getModelController(UomControl.class);
220
221        minimumInventory = partyInventoryLevel.getMinimumInventory();
222        var minimumInventoryConversion = minimumInventory == null ? null : new Conversion(uomControl, unitOfMeasureKind, minimumInventory).convertToHighestUnitOfMeasureType();
223
224        maximumInventory = partyInventoryLevel.getMaximumInventory();
225        var maximumInventoryConversion = maximumInventory == null ? null : new Conversion(uomControl, unitOfMeasureKind, maximumInventory).convertToHighestUnitOfMeasureType();
226
227        reorderQuantity = partyInventoryLevel.getReorderQuantity();
228        var reorderQuantityConversion = reorderQuantity == null ? null : new Conversion(uomControl, unitOfMeasureKind, reorderQuantity).convertToHighestUnitOfMeasureType();
229
230        edit.setMinimumInventory(minimumInventoryConversion.getQuantity().toString());
231        edit.setMinimumInventoryUnitOfMeasureTypeName(minimumInventoryConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
232        edit.setMaximumInventory(maximumInventoryConversion.getQuantity().toString());
233        edit.setMaximumInventoryUnitOfMeasureTypeName(maximumInventoryConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
234        edit.setReorderQuantity(reorderQuantityConversion.getQuantity().toString());
235        edit.setReorderQuantityUnitOfMeasureTypeName(reorderQuantityConversion.getUnitOfMeasureType().getLastDetail().getUnitOfMeasureTypeName());
236    }
237
238    Long minimumInventory;
239    Long maximumInventory;
240    Long reorderQuantity;
241
242    @Override
243    public void canUpdate(PartyInventoryLevel partyInventoryLevel) {
244        var unitOfMeasureTypeLogic = UnitOfMeasureTypeLogic.getInstance();
245
246        minimumInventory = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
247                edit.getMinimumInventory(), edit.getMinimumInventoryUnitOfMeasureTypeName(),
248                null, ExecutionErrors.MissingRequiredMinimumInventory.name(), null, ExecutionErrors.MissingRequiredMinimumInventoryUnitOfMeasureTypeName.name(),
249                null, ExecutionErrors.UnknownMinimumInventoryUnitOfMeasureTypeName.name());
250
251        if(!hasExecutionErrors()) {
252            maximumInventory = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
253                    edit.getMaximumInventory(), edit.getMaximumInventoryUnitOfMeasureTypeName(),
254                    null, ExecutionErrors.MissingRequiredMaximumInventory.name(), null, ExecutionErrors.MissingRequiredMaximumInventoryUnitOfMeasureTypeName.name(),
255                    null, ExecutionErrors.UnknownMaximumInventoryUnitOfMeasureTypeName.name());
256
257            if(!hasExecutionErrors()) {
258                reorderQuantity = unitOfMeasureTypeLogic.checkUnitOfMeasure(this, unitOfMeasureKind,
259                        edit.getReorderQuantity(), edit.getReorderQuantityUnitOfMeasureTypeName(),
260                        null, ExecutionErrors.MissingRequiredReorderQuantity.name(), null, ExecutionErrors.MissingRequiredReorderQuantityUnitOfMeasureTypeName.name(),
261                        null, ExecutionErrors.UnknownReorderQuantityUnitOfMeasureTypeName.name());
262            }
263        }
264    }
265
266    @Override
267    public void doUpdate(PartyInventoryLevel partyInventoryLevel) {
268        var inventoryControl = Session.getModelController(InventoryControl.class);
269        var partyInventoryLevelValue = inventoryControl.getPartyInventoryLevelValue(partyInventoryLevel);
270
271        partyInventoryLevelValue.setMinimumInventory(minimumInventory);
272        partyInventoryLevelValue.setMaximumInventory(maximumInventory);
273        partyInventoryLevelValue.setReorderQuantity(reorderQuantity);
274
275        inventoryControl.updatePartyInventoryLevelFromValue(partyInventoryLevelValue, getPartyPK());
276    }
277
278}