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.accounting.server.command;
018
019import com.echothree.control.user.accounting.common.edit.AccountingEditFactory;
020import com.echothree.control.user.accounting.common.edit.TransactionGlAccountCategoryEdit;
021import com.echothree.control.user.accounting.common.form.EditTransactionGlAccountCategoryForm;
022import com.echothree.control.user.accounting.common.result.AccountingResultFactory;
023import com.echothree.control.user.accounting.common.spec.TransactionGlAccountCategorySpec;
024import com.echothree.model.control.accounting.server.control.AccountingControl;
025import com.echothree.model.control.party.common.PartyTypes;
026import com.echothree.model.control.security.common.SecurityRoleGroups;
027import com.echothree.model.control.security.common.SecurityRoles;
028import com.echothree.model.data.user.common.pk.UserVisitPK;
029import com.echothree.util.common.message.ExecutionErrors;
030import com.echothree.util.common.validation.FieldDefinition;
031import com.echothree.util.common.validation.FieldType;
032import com.echothree.util.common.command.BaseResult;
033import com.echothree.util.common.command.EditMode;
034import com.echothree.util.server.control.BaseEditCommand;
035import com.echothree.util.server.control.CommandSecurityDefinition;
036import com.echothree.util.server.control.PartyTypeDefinition;
037import com.echothree.util.server.control.SecurityRoleDefinition;
038import java.util.List;
039import javax.enterprise.context.Dependent;
040import javax.inject.Inject;
041
042@Dependent
043public class EditTransactionGlAccountCategoryCommand
044        extends BaseEditCommand<TransactionGlAccountCategorySpec, TransactionGlAccountCategoryEdit> {
045    
046    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
047    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
048    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
049    
050    static {
051        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
052                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
053                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
054                        new SecurityRoleDefinition(SecurityRoleGroups.TransactionGlAccountCategory.name(), SecurityRoles.Edit.name())
055                ))
056        ));
057        
058        SPEC_FIELD_DEFINITIONS = List.of(
059                new FieldDefinition("TransactionTypeName", FieldType.ENTITY_NAME, true, null, null),
060                new FieldDefinition("TransactionGlAccountCategoryName", FieldType.ENTITY_NAME, true, null, null)
061        );
062        
063        EDIT_FIELD_DEFINITIONS = List.of(
064                new FieldDefinition("TransactionGlAccountCategoryName", FieldType.ENTITY_NAME, true, null, null),
065                new FieldDefinition("GlAccountCategoryName", FieldType.ENTITY_NAME, false, null, null),
066                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
067                new FieldDefinition("GlAccountName", FieldType.ENTITY_NAME, false, null, null),
068                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L)
069        );
070    }
071
072    @Inject
073    AccountingControl accountingControl;
074
075    
076    /** Creates a new instance of EditTransactionGlAccountCategoryCommand */
077    public EditTransactionGlAccountCategoryCommand() {
078        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
079    }
080    
081    @Override
082    protected BaseResult execute() {
083        var result = AccountingResultFactory.getEditTransactionGlAccountCategoryResult();
084        var transactionTypeName = spec.getTransactionTypeName();
085        var transactionType = accountingControl.getTransactionTypeByNameForUpdate(transactionTypeName);
086        
087        if(transactionType != null) {
088            var transactionGlAccountCategoryName = spec.getTransactionGlAccountCategoryName();
089
090            if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
091                var transactionGlAccountCategory = accountingControl.getTransactionGlAccountCategoryByName(transactionType, transactionGlAccountCategoryName);
092
093                if(transactionGlAccountCategory != null) {
094                    if(editMode.equals(EditMode.LOCK)) {
095                        if(lockEntity(transactionGlAccountCategory)) {
096                            var transactionGlAccountCategoryDescription = accountingControl.getTransactionGlAccountCategoryDescription(transactionGlAccountCategory, getPreferredLanguage());
097                            var transactionGlAccount = accountingControl.getTransactionGlAccount(transactionGlAccountCategory);
098                            var edit = AccountingEditFactory.getTransactionGlAccountCategoryEdit();
099                            var transactionGlAccountCategoryDetail = transactionGlAccountCategory.getLastDetail();
100                            var glAccountCategory = transactionGlAccountCategoryDetail.getGlAccountCategory();
101
102                            result.setTransactionGlAccountCategory(accountingControl.getTransactionGlAccountCategoryTransfer(getUserVisit(), transactionGlAccountCategory));
103
104                            result.setEdit(edit);
105                            edit.setTransactionGlAccountCategoryName(transactionGlAccountCategoryDetail.getTransactionGlAccountCategoryName());
106                            edit.setGlAccountCategoryName(glAccountCategory == null? null: glAccountCategory.getLastDetail().getGlAccountCategoryName());
107                            edit.setSortOrder(transactionGlAccountCategoryDetail.getSortOrder().toString());
108                            edit.setGlAccountName(transactionGlAccount == null? null: transactionGlAccount.getGlAccount().getLastDetail().getGlAccountName());
109
110                            if(transactionGlAccountCategoryDescription != null) {
111                                edit.setDescription(transactionGlAccountCategoryDescription.getDescription());
112                            }
113                        } else {
114                            addExecutionError(ExecutionErrors.EntityLockFailed.name());
115                        }
116
117                        result.setEntityLock(getEntityLockTransfer(transactionGlAccountCategory));
118                    } else { // EditMode.ABANDON
119                        unlockEntity(transactionGlAccountCategory);
120                    }
121                } else {
122                    addExecutionError(ExecutionErrors.UnknownTransactionGlAccountCategoryName.name(), transactionTypeName, transactionGlAccountCategoryName);
123                }
124            } else if(editMode.equals(EditMode.UPDATE)) {
125                var transactionGlAccountCategory = accountingControl.getTransactionGlAccountCategoryByNameForUpdate(transactionType, transactionGlAccountCategoryName);
126
127                if(transactionGlAccountCategory != null) {
128                    transactionGlAccountCategoryName = edit.getTransactionGlAccountCategoryName();
129                    var duplicateTransactionGlAccountCategory = accountingControl.getTransactionGlAccountCategoryByName(transactionType, transactionGlAccountCategoryName);
130
131                    if(duplicateTransactionGlAccountCategory == null || transactionGlAccountCategory.equals(duplicateTransactionGlAccountCategory)) {
132                        var glAccountCategoryName = edit.getGlAccountCategoryName();
133                        var glAccountCategory = glAccountCategoryName == null? null: accountingControl.getGlAccountCategoryByName(glAccountCategoryName);
134
135                        if(glAccountCategoryName == null || glAccountCategory != null) {
136                            var glAccountName = edit.getGlAccountName();
137                            var glAccount = glAccountName == null? null: accountingControl.getGlAccountByName(glAccountName);
138
139                            if(glAccountName == null || glAccount != null) {
140                                if(glAccountCategory == null || glAccount == null? true: glAccountCategory.equals(glAccount.getLastDetail().getGlAccountCategory())) {
141                                    if(lockEntityForUpdate(transactionGlAccountCategory)) {
142                                        try {
143                                            var partyPK = getPartyPK();
144                                            var transactionGlAccountCategoryDetailValue = accountingControl.getTransactionGlAccountCategoryDetailValueForUpdate(transactionGlAccountCategory);
145                                            var transactionGlAccountCategoryDescription = accountingControl.getTransactionGlAccountCategoryDescriptionForUpdate(transactionGlAccountCategory, getPreferredLanguage());
146                                            var transactionGlAccount = accountingControl.getTransactionGlAccount(transactionGlAccountCategory);
147                                            var description = edit.getDescription();
148
149                                            transactionGlAccountCategoryDetailValue.setTransactionGlAccountCategoryName(edit.getTransactionGlAccountCategoryName());
150                                            transactionGlAccountCategoryDetailValue.setGlAccountCategoryPK(glAccountCategory == null? null: glAccountCategory.getPrimaryKey());
151                                            transactionGlAccountCategoryDetailValue.setSortOrder(Integer.valueOf(edit.getSortOrder()));
152
153                                            accountingControl.updateTransactionGlAccountCategoryFromValue(transactionGlAccountCategoryDetailValue, partyPK);
154
155                                            if(transactionGlAccountCategoryDescription == null && description != null) {
156                                                accountingControl.createTransactionGlAccountCategoryDescription(transactionGlAccountCategory, getPreferredLanguage(), description, partyPK);
157                                            } else if(transactionGlAccountCategoryDescription != null && description == null) {
158                                                accountingControl.deleteTransactionGlAccountCategoryDescription(transactionGlAccountCategoryDescription, partyPK);
159                                            } else if(transactionGlAccountCategoryDescription != null && description != null) {
160                                                var transactionGlAccountCategoryDescriptionValue = accountingControl.getTransactionGlAccountCategoryDescriptionValue(transactionGlAccountCategoryDescription);
161
162                                                transactionGlAccountCategoryDescriptionValue.setDescription(description);
163                                                accountingControl.updateTransactionGlAccountCategoryDescriptionFromValue(transactionGlAccountCategoryDescriptionValue, partyPK);
164                                            }
165
166                                            if(transactionGlAccount == null && glAccount != null) {
167                                                accountingControl.createTransactionGlAccount(transactionGlAccountCategory, glAccount, partyPK);
168                                            } else if(transactionGlAccount != null && glAccount == null) {
169                                                accountingControl.deleteTransactionGlAccount(transactionGlAccount, partyPK);
170                                            } else if(transactionGlAccount != null && glAccount != null) {
171                                                var transactionGlAccountValue = accountingControl.getTransactionGlAccountValue(transactionGlAccount);
172
173                                                transactionGlAccountValue.setGlAccountPK(glAccount.getPrimaryKey());
174                                                accountingControl.updateTransactionGlAccountFromValue(transactionGlAccountValue, partyPK);
175                                            }
176                                        } finally {
177                                            unlockEntity(transactionGlAccountCategory);
178                                        }
179                                    } else {
180                                        addExecutionError(ExecutionErrors.EntityLockStale.name());
181                                    }
182                                } else {
183                                    addExecutionError(ExecutionErrors.InvalidGlAccountCategory.name());
184                                }
185                            } else {
186                                addExecutionError(ExecutionErrors.UnknownGlAccountName.name(), glAccountName);
187                            }
188                        } else {
189                            addExecutionError(ExecutionErrors.UnknownGlAccountCategoryName.name(), glAccountCategoryName);
190                        }
191                    } else {
192                        addExecutionError(ExecutionErrors.DuplicateTransactionGlAccountCategoryName.name(), transactionTypeName, transactionGlAccountCategoryName);
193                    }
194
195                    if(hasExecutionErrors()) {
196                        result.setTransactionGlAccountCategory(accountingControl.getTransactionGlAccountCategoryTransfer(getUserVisit(), transactionGlAccountCategory));
197                        result.setEntityLock(getEntityLockTransfer(transactionGlAccountCategory));
198                    }
199                } else {
200                    addExecutionError(ExecutionErrors.UnknownTransactionGlAccountCategoryName.name(), transactionTypeName, transactionGlAccountCategoryName);
201                }
202            }
203        } else {
204            addExecutionError(ExecutionErrors.UnknownTransactionTypeName.name(), transactionTypeName);
205        }
206        
207        return result;
208    }
209    
210}