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