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