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.model.control.item.server.logic;
018
019import com.echothree.model.control.core.server.control.CoreControl;
020import com.echothree.model.control.item.common.exception.DuplicateItemNameException;
021import com.echothree.model.control.item.common.exception.UnknownItemNameException;
022import com.echothree.model.control.item.common.exception.UnknownItemNameOrAliasException;
023import com.echothree.model.control.item.common.exception.UnknownItemStatusChoiceException;
024import com.echothree.model.control.item.common.exception.UnknownItemTypeNameException;
025import com.echothree.model.control.item.common.exception.UnknownItemUseTypeNameException;
026import com.echothree.model.control.item.common.workflow.ItemStatusConstants;
027import com.echothree.model.control.item.server.control.ItemControl;
028import com.echothree.model.control.sequence.common.SequenceTypes;
029import com.echothree.model.control.sequence.common.exception.MissingDefaultSequenceException;
030import com.echothree.model.control.sequence.server.logic.SequenceGeneratorLogic;
031import com.echothree.model.control.workflow.server.control.WorkflowControl;
032import com.echothree.model.control.workflow.server.logic.WorkflowDestinationLogic;
033import com.echothree.model.control.workflow.server.logic.WorkflowLogic;
034import com.echothree.model.data.accounting.server.entity.ItemAccountingCategory;
035import com.echothree.model.data.cancellationpolicy.server.entity.CancellationPolicy;
036import com.echothree.model.data.item.server.entity.Item;
037import com.echothree.model.data.item.server.entity.ItemCategory;
038import com.echothree.model.data.item.server.entity.ItemDeliveryType;
039import com.echothree.model.data.item.server.entity.ItemInventoryType;
040import com.echothree.model.data.item.server.entity.ItemPriceType;
041import com.echothree.model.data.item.server.entity.ItemType;
042import com.echothree.model.data.item.server.entity.ItemUseType;
043import com.echothree.model.data.party.common.pk.PartyPK;
044import com.echothree.model.data.party.server.entity.Party;
045import com.echothree.model.data.returnpolicy.server.entity.ReturnPolicy;
046import com.echothree.model.data.sequence.server.entity.Sequence;
047import com.echothree.model.data.style.server.entity.StylePath;
048import com.echothree.model.data.uom.server.entity.UnitOfMeasureKind;
049import com.echothree.model.data.vendor.server.entity.ItemPurchasingCategory;
050import com.echothree.util.common.message.ExecutionErrors;
051import com.echothree.util.common.persistence.BasePK;
052import com.echothree.util.server.control.BaseLogic;
053import com.echothree.util.server.message.ExecutionErrorAccumulator;
054import com.echothree.util.server.persistence.Session;
055
056public class ItemLogic
057        extends BaseLogic {
058
059    private ItemLogic() {
060        super();
061    }
062
063    private static class ItemLogicHolder {
064        static ItemLogic instance = new ItemLogic();
065    }
066
067    public static ItemLogic getInstance() {
068        return ItemLogicHolder.instance;
069    }
070    
071    public ItemType getItemTypeByName(final ExecutionErrorAccumulator eea, final String itemTypeName) {
072        var itemControl = Session.getModelController(ItemControl.class);
073        var itemType = itemControl.getItemTypeByName(itemTypeName);
074
075        if(itemType == null) {
076            handleExecutionError(UnknownItemTypeNameException.class, eea, ExecutionErrors.UnknownItemTypeName.name(), itemTypeName);
077        }
078
079        return itemType;
080    }
081
082    public ItemUseType getItemUseTypeByName(final ExecutionErrorAccumulator eea, final String itemUseTypeName) {
083        var itemControl = Session.getModelController(ItemControl.class);
084        var itemUseType = itemControl.getItemUseTypeByName(itemUseTypeName);
085
086        if(itemUseType == null) {
087            handleExecutionError(UnknownItemUseTypeNameException.class, eea, ExecutionErrors.UnknownItemUseTypeName.name(), itemUseTypeName);
088        }
089
090        return itemUseType;
091    }
092
093    public Item getItemByName(final ExecutionErrorAccumulator eea, final String itemName) {
094        var itemControl = Session.getModelController(ItemControl.class);
095        var item = itemControl.getItemByName(itemName);
096
097        if(item == null) {
098            handleExecutionError(UnknownItemNameException.class, eea, ExecutionErrors.UnknownItemName.name(), itemName);
099        }
100
101        return item;
102    }
103
104    public Item getItemByNameThenAlias(final ExecutionErrorAccumulator eea, final String itemNameOrAlias) {
105        var itemControl = Session.getModelController(ItemControl.class);
106        var item = itemControl.getItemByNameThenAlias(itemNameOrAlias);
107
108        if(item == null) {
109            handleExecutionError(UnknownItemNameOrAliasException.class, eea, ExecutionErrors.UnknownItemNameOrAlias.name(), itemNameOrAlias);
110        }
111
112        return item;
113    }
114
115    public Item createItem(final ExecutionErrorAccumulator eea, String itemName, final ItemType itemType, final ItemUseType itemUseType,
116            ItemCategory itemCategory, final ItemAccountingCategory itemAccountingCategory, final ItemPurchasingCategory itemPurchasingCategory,
117            final Party companyParty, final ItemDeliveryType itemDeliveryType, final ItemInventoryType itemInventoryType,
118            final Boolean inventorySerialized, final Sequence serialNumberSequence, final Boolean shippingChargeExempt,
119            final Long shippingStartTime, final Long shippingEndTime, final Long salesOrderStartTime, final Long salesOrderEndTime,
120            final Long purchaseOrderStartTime, final Long purchaseOrderEndTime, final Boolean allowClubDiscounts, final Boolean allowCouponDiscounts,
121            final Boolean allowAssociatePayments, final UnitOfMeasureKind unitOfMeasureKind, final ItemPriceType itemPriceType,
122            final CancellationPolicy cancellationPolicy, final ReturnPolicy returnPolicy, final StylePath stylePath, final BasePK createdBy) {
123        var itemControl = Session.getModelController(ItemControl.class);
124        Item item = null;
125        
126        if(itemCategory == null) {
127            itemCategory = ItemCategoryLogic.getInstance().getDefaultItemCategory(eea);
128        }
129        
130        if(itemName == null && !hasExecutionErrors(eea)) {
131            itemName = getItemName(eea, itemCategory);
132        }
133        
134        if(itemControl.getItemByNameThenAlias(itemName) != null) {
135            handleExecutionError(DuplicateItemNameException.class, eea, ExecutionErrors.DuplicateItemName.name(),
136                    itemName);
137        }
138        
139        if(!hasExecutionErrors(eea)) {
140            item = itemControl.createItem(itemName, itemType, itemUseType, itemCategory, itemAccountingCategory,
141                    itemPurchasingCategory, companyParty, itemDeliveryType, itemInventoryType, inventorySerialized,
142                    serialNumberSequence, shippingChargeExempt, shippingStartTime, shippingEndTime, salesOrderStartTime,
143                    salesOrderEndTime, purchaseOrderStartTime, purchaseOrderEndTime, allowClubDiscounts, allowCouponDiscounts,
144                    allowAssociatePayments, unitOfMeasureKind, itemPriceType, cancellationPolicy, returnPolicy, stylePath,
145                    createdBy);
146        }
147            
148        return item;
149    }
150
151    private String getItemName(final ExecutionErrorAccumulator eea, final ItemCategory itemCategory) {
152        String itemName = null;
153        var itemSequence = itemCategory.getLastDetail().getItemSequence();
154        
155        if(itemSequence == null) {
156            itemSequence = SequenceGeneratorLogic.getInstance().getDefaultSequence(eea, SequenceTypes.ITEM.name());
157        }
158        
159        if(!hasExecutionErrors(eea)) {
160            itemName = SequenceGeneratorLogic.getInstance().getNextSequenceValue(eea, itemSequence);
161        } else {
162            handleExecutionError(MissingDefaultSequenceException.class, eea, ExecutionErrors.MissingDefaultSequence.name(),
163                    SequenceTypes.ITEM.name());
164        }
165        
166        return itemName;
167    }
168
169    public void setItemStatus(final Session session, final ExecutionErrorAccumulator eea, final Item item, final String itemStatusChoice, final PartyPK modifiedBy) {
170        var coreControl = Session.getModelController(CoreControl.class);
171        var workflowControl = Session.getModelController(WorkflowControl.class);
172        var workflow = WorkflowLogic.getInstance().getWorkflowByName(eea, ItemStatusConstants.Workflow_ITEM_STATUS);
173        var entityInstance = coreControl.getEntityInstanceByBasePK(item.getPrimaryKey());
174        var workflowEntityStatus = workflowControl.getWorkflowEntityStatusByEntityInstanceForUpdate(workflow, entityInstance);
175        var workflowDestination = itemStatusChoice == null ? null : workflowControl.getWorkflowDestinationByName(workflowEntityStatus.getWorkflowStep(), itemStatusChoice);
176
177        if(workflowDestination != null || itemStatusChoice == null) {
178            var workflowDestinationLogic = WorkflowDestinationLogic.getInstance();
179            var currentWorkflowStepName = workflowEntityStatus.getWorkflowStep().getLastDetail().getWorkflowStepName();
180            var map = workflowDestinationLogic.getWorkflowDestinationsAsMap(workflowDestination);
181            var handled = false;
182            Long triggerTime = null;
183            
184            if(currentWorkflowStepName.equals(ItemStatusConstants.WorkflowStep_ITEM_STATUS_ACTIVE)) {
185                if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_DISCONTINUED)) {
186                    // TODO
187                    handled = true;
188                } else if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_CANCEL_IF_NOT_IN_STOCK)) {
189                    // TODO
190                    handled = true;
191                }
192            } else if(currentWorkflowStepName.equals(ItemStatusConstants.WorkflowStep_ITEM_STATUS_DISCONTINUED)) {
193                if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_ACTIVE)) {
194                    // TODO
195                    handled = true;
196                } else if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_CANCEL_IF_NOT_IN_STOCK)) {
197                    // TODO
198                    handled = true;
199                }
200            } else if(currentWorkflowStepName.equals(ItemStatusConstants.WorkflowStep_ITEM_STATUS_CANCEL_IF_NOT_IN_STOCK)) {
201                if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_ACTIVE)) {
202                    // TODO
203                    handled = true;
204                } else if(workflowDestinationLogic.workflowDestinationMapContainsStep(map, ItemStatusConstants.Workflow_ITEM_STATUS, ItemStatusConstants.WorkflowStep_ITEM_STATUS_DISCONTINUED)) {
205                    // TODO
206                    handled = true;
207                }
208            }
209            
210            if(eea == null || !eea.hasExecutionErrors()) {
211                if(handled) {
212                    workflowControl.transitionEntityInWorkflow(eea, workflowEntityStatus, workflowDestination, triggerTime, modifiedBy);
213                } else {
214                    // TODO: An error of some sort.
215                }
216            }
217        } else {
218            handleExecutionError(UnknownItemStatusChoiceException.class, eea, ExecutionErrors.UnknownItemStatusChoice.name(), itemStatusChoice);
219        }
220    }
221    
222}