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.item.server.command;
018
019import com.echothree.control.user.item.common.edit.ItemEdit;
020import com.echothree.control.user.item.common.edit.ItemEditFactory;
021import com.echothree.control.user.item.common.result.EditItemResult;
022import com.echothree.control.user.item.common.result.ItemResultFactory;
023import com.echothree.control.user.item.common.spec.ItemSpec;
024import com.echothree.model.control.accounting.server.control.AccountingControl;
025import com.echothree.model.control.cancellationpolicy.common.CancellationKinds;
026import com.echothree.model.control.cancellationpolicy.server.control.CancellationPolicyControl;
027import com.echothree.model.control.item.common.ItemTypes;
028import com.echothree.model.control.item.server.control.ItemControl;
029import com.echothree.model.control.party.common.PartyTypes;
030import com.echothree.model.control.returnpolicy.common.ReturnKinds;
031import com.echothree.model.control.returnpolicy.server.control.ReturnPolicyControl;
032import com.echothree.model.control.security.common.SecurityRoleGroups;
033import com.echothree.model.control.security.common.SecurityRoles;
034import com.echothree.model.control.vendor.server.control.VendorControl;
035import com.echothree.model.data.accounting.server.entity.ItemAccountingCategory;
036import com.echothree.model.data.cancellationpolicy.server.entity.CancellationPolicy;
037import com.echothree.model.data.item.server.entity.Item;
038import com.echothree.model.data.item.server.entity.ItemCategory;
039import com.echothree.model.data.returnpolicy.server.entity.ReturnPolicy;
040import com.echothree.model.data.vendor.server.entity.ItemPurchasingCategory;
041import com.echothree.util.common.command.EditMode;
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.server.control.BaseAbstractEditCommand;
046import com.echothree.util.server.control.CommandSecurityDefinition;
047import com.echothree.util.server.control.PartyTypeDefinition;
048import com.echothree.util.server.control.SecurityRoleDefinition;
049import com.echothree.util.server.persistence.Session;
050import com.echothree.util.server.string.DateUtils;
051import java.util.List;
052import javax.enterprise.context.Dependent;
053
054@Dependent
055public class EditItemCommand
056        extends BaseAbstractEditCommand<ItemSpec, ItemEdit, EditItemResult, Item, Item> {
057    
058    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
059    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
060    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
061    
062    static {
063        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
064                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
065                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
066                        new SecurityRoleDefinition(SecurityRoleGroups.ItemCategory.name(), SecurityRoles.Edit.name())
067                        ))
068                ));
069
070        SPEC_FIELD_DEFINITIONS = List.of(
071                new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null)
072                );
073        
074        EDIT_FIELD_DEFINITIONS = List.of(
075                new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null),
076                new FieldDefinition("ItemCategoryName", FieldType.ENTITY_NAME, true, null, null),
077                new FieldDefinition("ItemAccountingCategoryName", FieldType.ENTITY_NAME, false, null, null),
078                new FieldDefinition("ItemPurchasingCategoryName", FieldType.ENTITY_NAME, false, null, null),
079                new FieldDefinition("ShippingChargeExempt", FieldType.BOOLEAN, true, null, null),
080                new FieldDefinition("ShippingStartTime", FieldType.DATE_TIME, false, null, null),
081                new FieldDefinition("ShippingEndTime", FieldType.DATE_TIME, false, null, null),
082                new FieldDefinition("SalesOrderStartTime", FieldType.DATE_TIME, false, null, null),
083                new FieldDefinition("SalesOrderEndTime", FieldType.DATE_TIME, false, null, null),
084                new FieldDefinition("PurchaseOrderStartTime", FieldType.DATE_TIME, false, null, null),
085                new FieldDefinition("PurchaseOrderEndTime", FieldType.DATE_TIME, false, null, null),
086                new FieldDefinition("AllowClubDiscounts", FieldType.BOOLEAN, true, null, null),
087                new FieldDefinition("AllowCouponDiscounts", FieldType.BOOLEAN, true, null, null),
088                new FieldDefinition("AllowAssociatePayments", FieldType.BOOLEAN, true, null, null),
089                new FieldDefinition("CancellationPolicyName", FieldType.ENTITY_NAME, false, null, null),
090                new FieldDefinition("ReturnPolicyName", FieldType.ENTITY_NAME, false, null, null)
091                );
092    }
093    
094    /** Creates a new instance of EditItemCommand */
095    public EditItemCommand() {
096        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
097    }
098
099    @Override
100    public EditItemResult getResult() {
101        return ItemResultFactory.getEditItemResult();
102    }
103
104    @Override
105    public ItemEdit getEdit() {
106        return ItemEditFactory.getItemEdit();
107    }
108
109    @Override
110    public Item getEntity(EditItemResult result) {
111        var itemControl = Session.getModelController(ItemControl.class);
112        Item item;
113        var itemName = spec.getItemName();
114
115        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
116            item = itemControl.getItemByName(itemName);
117        } else { // EditMode.UPDATE
118            item = itemControl.getItemByNameForUpdate(itemName);
119        }
120
121        if(item != null) {
122            result.setItem(itemControl.getItemTransfer(getUserVisit(), item));
123        } else {
124            addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName);
125        }
126
127        return item;
128    }
129
130    @Override
131    public Item getLockEntity(Item item) {
132        return item;
133    }
134
135    @Override
136    public void fillInResult(EditItemResult result, Item item) {
137        var itemControl = Session.getModelController(ItemControl.class);
138
139        result.setItem(itemControl.getItemTransfer(getUserVisit(), item));
140    }
141
142    @Override
143    public void doLock(ItemEdit edit, Item item) {
144        var dateUtils = DateUtils.getInstance();
145        var itemDetail = item.getLastDetail();
146        var userVisit = getUserVisit();
147        var preferredDateTimeFormat = getPreferredDateTimeFormat();
148
149        itemAccountingCategory = itemDetail.getItemAccountingCategory();
150        itemPurchasingCategory = itemDetail.getItemPurchasingCategory();
151        cancellationPolicy = itemDetail.getCancellationPolicy();
152        returnPolicy = itemDetail.getReturnPolicy();
153
154        edit.setItemName(itemDetail.getItemName());
155        edit.setItemName(edit.getItemName());
156        edit.setItemCategoryName(itemDetail.getItemCategory().getLastDetail().getItemCategoryName());
157        edit.setItemAccountingCategoryName(itemAccountingCategory == null? null: itemAccountingCategory.getLastDetail().getItemAccountingCategoryName());
158        edit.setItemPurchasingCategoryName(itemPurchasingCategory == null? null: itemPurchasingCategory.getLastDetail().getItemPurchasingCategoryName());
159        edit.setShippingChargeExempt(itemDetail.getShippingChargeExempt().toString());
160        edit.setShippingStartTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getShippingStartTime()));
161        edit.setShippingEndTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getShippingEndTime()));
162        edit.setSalesOrderStartTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getSalesOrderStartTime()));
163        edit.setSalesOrderEndTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getSalesOrderEndTime()));
164        edit.setPurchaseOrderStartTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getPurchaseOrderStartTime()));
165        edit.setPurchaseOrderEndTime(dateUtils.formatTypicalDateTime(userVisit, preferredDateTimeFormat, itemDetail.getPurchaseOrderEndTime()));
166        edit.setAllowClubDiscounts(itemDetail.getAllowClubDiscounts().toString());
167        edit.setAllowCouponDiscounts(itemDetail.getAllowCouponDiscounts().toString());
168        edit.setAllowAssociatePayments(itemDetail.getAllowAssociatePayments().toString());
169        edit.setCancellationPolicyName(cancellationPolicy == null? null: cancellationPolicy.getLastDetail().getCancellationPolicyName());
170        edit.setReturnPolicyName(returnPolicy == null? null: returnPolicy.getLastDetail().getReturnPolicyName());
171    }
172
173    ItemCategory itemCategory;
174    boolean isKit;
175    ItemAccountingCategory itemAccountingCategory;
176    ItemPurchasingCategory itemPurchasingCategory;
177    CancellationPolicy cancellationPolicy;
178    ReturnPolicy returnPolicy;
179
180    @Override
181    public void canUpdate(Item item) {
182        var itemControl = Session.getModelController(ItemControl.class);
183        var itemName = edit.getItemName();
184        var duplicateItem = itemControl.getItemByName(itemName);
185
186        if(duplicateItem == null || item.equals(duplicateItem)) {
187            var itemCategoryName = edit.getItemCategoryName();
188            var itemTypeName = item.getLastDetail().getItemType().getItemTypeName();
189
190            itemCategory = itemControl.getItemCategoryByName(itemCategoryName);
191
192            if(itemCategory != null) {
193                var itemAccountingCategoryName = edit.getItemAccountingCategoryName();
194
195                isKit = itemTypeName.equals(ItemTypes.KIT.name());
196
197                if(isKit) {
198                    if(itemAccountingCategoryName != null) {
199                        addExecutionError(ExecutionErrors.NotPermittedItemAccountingCategory.name(), itemAccountingCategoryName);
200                    }
201                } else {
202                    var accountingControl = Session.getModelController(AccountingControl.class);
203
204                    itemAccountingCategory = itemAccountingCategoryName == null? null: accountingControl.getItemAccountingCategoryByName(itemAccountingCategoryName);
205
206                    if(itemAccountingCategoryName == null) {
207                        addExecutionError(ExecutionErrors.MissingItemAccountingCategoryName.name());
208                    } else if(itemAccountingCategory == null) {
209                        addExecutionError(ExecutionErrors.UnknownItemAccountingCategoryName.name(), itemAccountingCategoryName);
210                    }
211                }
212
213                if(!hasExecutionErrors()) {
214                    var itemPurchasingCategoryName = edit.getItemPurchasingCategoryName();
215
216                    if(isKit) {
217                        if(itemPurchasingCategoryName != null) {
218                            addExecutionError(ExecutionErrors.NotPermittedItemPurchasingCategory.name(), itemPurchasingCategoryName);
219                        }
220                    } else {
221                        var vendorControl = Session.getModelController(VendorControl.class);
222
223                        itemPurchasingCategory = itemPurchasingCategoryName == null? null: vendorControl.getItemPurchasingCategoryByName(itemPurchasingCategoryName);
224
225                        if(itemPurchasingCategoryName == null) {
226                            addExecutionError(ExecutionErrors.MissingItemPurchasingCategoryName.name());
227                        } else if(itemPurchasingCategory == null) {
228                            addExecutionError(ExecutionErrors.UnknownItemPurchasingCategoryName.name(), itemPurchasingCategoryName);
229                        }
230                    }
231
232                    if(!hasExecutionErrors()) {
233                        var cancellationPolicyName = edit.getCancellationPolicyName();
234
235                        if(cancellationPolicyName != null) {
236                            var cancellationPolicyControl = Session.getModelController(CancellationPolicyControl.class);
237                            var cancellationKind = cancellationPolicyControl.getCancellationKindByName(CancellationKinds.CUSTOMER_CANCELLATION.name());
238
239                            cancellationPolicy = cancellationPolicyControl.getCancellationPolicyByName(cancellationKind, cancellationPolicyName);
240                        }
241
242                        if(cancellationPolicyName == null || cancellationPolicy != null) {
243                            var returnPolicyName = edit.getReturnPolicyName();
244
245                            if(returnPolicyName != null) {
246                                var returnPolicyControl = Session.getModelController(ReturnPolicyControl.class);
247                                var returnKind = returnPolicyControl.getReturnKindByName(ReturnKinds.CUSTOMER_RETURN.name());
248
249                                returnPolicy = returnPolicyControl.getReturnPolicyByName(returnKind, returnPolicyName);
250                            }
251
252                            if(returnPolicyName != null && returnPolicy == null) {
253                                addExecutionError(ExecutionErrors.UnknownReturnPolicyName.name(), returnPolicyName);
254                            }
255                        } else {
256                            addExecutionError(ExecutionErrors.UnknownCancellationPolicyName.name(), cancellationPolicyName);
257                        }
258                    }
259                }
260            } else {
261                addExecutionError(ExecutionErrors.UnknownItemCategoryName.name(), itemCategoryName);
262            }
263        } else {
264            addExecutionError(ExecutionErrors.DuplicateItemName.name(), itemName);
265        }
266    }
267
268    @Override
269    public void doUpdate(Item item) {
270        var itemControl = Session.getModelController(ItemControl.class);
271        var partyPK = getPartyPK();
272        var itemDetailValue = itemControl.getItemDetailValueForUpdate(item);
273        var shippingChargeExempt = Boolean.valueOf(edit.getShippingChargeExempt());
274        var strShippingStartTime = edit.getShippingStartTime();
275        var shippingStartTime = strShippingStartTime == null? session.getStartTime(): Long.valueOf(strShippingStartTime);
276        var strShippingEndTime = edit.getShippingEndTime();
277        var shippingEndTime = strShippingEndTime == null? null: Long.valueOf(strShippingEndTime);
278        var strSalesOrderStartTime = edit.getSalesOrderStartTime();
279        var salesOrderStartTime = strSalesOrderStartTime == null? session.getStartTime(): Long.valueOf(strSalesOrderStartTime);
280        var strSalesOrderEndTime = edit.getSalesOrderEndTime();
281        var salesOrderEndTime = strSalesOrderEndTime == null? null: Long.valueOf(strSalesOrderEndTime);
282        var strPurchaseOrderStartTime = edit.getPurchaseOrderStartTime();
283        var purchaseOrderStartTime = isKit? null: strPurchaseOrderStartTime == null? session.getStartTime(): Long.valueOf(strPurchaseOrderStartTime);
284        var strPurchaseOrderEndTime = edit.getPurchaseOrderEndTime();
285        var purchaseOrderEndTime = isKit? null: strPurchaseOrderEndTime == null? null: Long.valueOf(strPurchaseOrderEndTime);
286        var allowClubDiscounts = Boolean.valueOf(edit.getAllowClubDiscounts());
287        var allowCouponDiscounts = Boolean.valueOf(edit.getAllowCouponDiscounts());
288        var allowAssociatePayments = Boolean.valueOf(edit.getAllowAssociatePayments());
289
290        itemDetailValue.setItemName(edit.getItemName());
291        itemDetailValue.setItemCategoryPK(itemCategory.getPrimaryKey());
292        itemDetailValue.setItemAccountingCategoryPK(itemAccountingCategory == null? null: itemAccountingCategory.getPrimaryKey());
293        itemDetailValue.setItemPurchasingCategoryPK(itemPurchasingCategory == null? null: itemPurchasingCategory.getPrimaryKey());
294        itemDetailValue.setShippingChargeExempt(shippingChargeExempt);
295        itemDetailValue.setShippingStartTime(shippingStartTime);
296        itemDetailValue.setShippingEndTime(shippingEndTime);
297        itemDetailValue.setSalesOrderStartTime(salesOrderStartTime);
298        itemDetailValue.setSalesOrderEndTime(salesOrderEndTime);
299        itemDetailValue.setPurchaseOrderStartTime(purchaseOrderStartTime);
300        itemDetailValue.setPurchaseOrderEndTime(purchaseOrderEndTime);
301        itemDetailValue.setAllowClubDiscounts(allowClubDiscounts);
302        itemDetailValue.setAllowCouponDiscounts(allowCouponDiscounts);
303        itemDetailValue.setAllowAssociatePayments(allowAssociatePayments);
304        itemDetailValue.setCancellationPolicyPK(cancellationPolicy == null? null: cancellationPolicy.getPrimaryKey());
305        itemDetailValue.setReturnPolicyPK(returnPolicy == null? null: returnPolicy.getPrimaryKey());
306
307        itemControl.updateItemFromValue(itemDetailValue, partyPK);
308    }
309    
310}