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.GlAccountEdit;
021import com.echothree.control.user.accounting.common.form.EditGlAccountForm;
022import com.echothree.control.user.accounting.common.result.AccountingResultFactory;
023import com.echothree.control.user.accounting.common.spec.GlAccountUniversalSpec;
024import com.echothree.model.control.accounting.server.control.AccountingControl;
025import com.echothree.model.control.accounting.server.logic.GlAccountLogic;
026import com.echothree.model.control.party.common.PartyTypes;
027import com.echothree.model.control.security.common.SecurityRoleGroups;
028import com.echothree.model.control.security.common.SecurityRoles;
029import com.echothree.model.data.accounting.server.entity.GlAccount;
030import com.echothree.model.data.user.common.pk.UserVisitPK;
031import com.echothree.util.common.command.BaseResult;
032import com.echothree.util.common.command.EditMode;
033import com.echothree.util.common.message.ExecutionErrors;
034import com.echothree.util.common.validation.FieldDefinition;
035import com.echothree.util.common.validation.FieldType;
036import com.echothree.util.server.control.BaseEditCommand;
037import com.echothree.util.server.control.CommandSecurityDefinition;
038import com.echothree.util.server.control.PartyTypeDefinition;
039import com.echothree.util.server.control.SecurityRoleDefinition;
040import java.util.List;
041import javax.enterprise.context.Dependent;
042import javax.inject.Inject;
043
044@Dependent
045public class EditGlAccountCommand
046        extends BaseEditCommand<GlAccountUniversalSpec, GlAccountEdit> {
047    
048    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
049    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
050    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
051    
052    static {
053        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
054                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
055                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
056                        new SecurityRoleDefinition(SecurityRoleGroups.GlAccount.name(), SecurityRoles.Edit.name())
057                ))
058        ));
059        
060        SPEC_FIELD_DEFINITIONS = List.of(
061                new FieldDefinition("GlAccountName", FieldType.ENTITY_NAME, false, null, null),
062                new FieldDefinition("EntityRef", FieldType.ENTITY_REF, false, null, null),
063                new FieldDefinition("Uuid", FieldType.UUID, false, null, null)
064        );
065        
066        EDIT_FIELD_DEFINITIONS = List.of(
067                new FieldDefinition("GlAccountName", FieldType.ENTITY_NAME, true, null, null),
068                new FieldDefinition("ParentGlAccountName", FieldType.ENTITY_NAME, false, null, null),
069                new FieldDefinition("GlAccountClassName", FieldType.ENTITY_NAME, true, null, null),
070                new FieldDefinition("GlAccountCategoryName", FieldType.ENTITY_NAME, false, null, null),
071                new FieldDefinition("GlResourceTypeName", FieldType.ENTITY_NAME, true, null, null),
072                new FieldDefinition("IsDefault", FieldType.BOOLEAN, false, null, null),
073                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L)
074        );
075    }
076
077    @Inject
078    AccountingControl accountingControl;
079
080    @Inject
081    GlAccountLogic glAccountLogic;
082
083    
084    /** Creates a new instance of EditGlAccountCommand */
085    public EditGlAccountCommand() {
086        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
087    }
088    
089    @Override
090    protected BaseResult execute() {
091        var result = AccountingResultFactory.getEditGlAccountResult();
092        
093        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
094            var glAccount = glAccountLogic.getGlAccountByUniversalSpec(this, spec, false, null);
095
096            if(!hasExecutionErrors()) {
097                if(editMode.equals(EditMode.LOCK)) {
098                    if(lockEntity(glAccount)) {
099                        var glAccountDescription = accountingControl.getGlAccountDescription(glAccount, getPreferredLanguage());
100                        var edit = AccountingEditFactory.getGlAccountEdit();
101                        var glAccountDetail = glAccount.getLastDetail();
102                        var parentGlAccount = glAccountDetail.getParentGlAccount();
103                        var glAccountCategory = glAccountDetail.getGlAccountCategory();
104                        var isDefault = glAccountDetail.getIsDefault();
105
106                        result.setGlAccount(accountingControl.getGlAccountTransfer(getUserVisit(), glAccount));
107
108                        result.setEdit(edit);
109                        edit.setGlAccountName(glAccountDetail.getGlAccountName());
110                        edit.setParentGlAccountName(parentGlAccount == null? null: parentGlAccount.getLastDetail().getGlAccountName());
111                        edit.setGlAccountClassName(glAccountDetail.getGlAccountClass().getLastDetail().getGlAccountClassName());
112                        edit.setGlAccountCategoryName(glAccountCategory == null? null: glAccountCategory.getLastDetail().getGlAccountCategoryName());
113                        edit.setGlResourceTypeName(glAccountDetail.getGlResourceType().getLastDetail().getGlResourceTypeName());
114                        edit.setIsDefault(isDefault == null? null: isDefault.toString());
115
116                        if(glAccountDescription != null) {
117                            edit.setDescription(glAccountDescription.getDescription());
118                        }
119                    } else {
120                        addExecutionError(ExecutionErrors.EntityLockFailed.name());
121                    }
122
123                    result.setEntityLock(getEntityLockTransfer(glAccount));
124                } else { // EditMode.ABANDON
125                    unlockEntity(glAccount);
126                }
127            }
128        } else if(editMode.equals(EditMode.UPDATE)) {
129            var glAccount = glAccountLogic.getGlAccountByUniversalSpecForUpdate(this, spec, false, null);
130
131            if(!hasExecutionErrors()) {
132                var glAccountName = edit.getGlAccountName();
133                var duplicateGlAccount = accountingControl.getGlAccountByName(glAccountName);
134                
135                if(duplicateGlAccount == null || glAccount.equals(duplicateGlAccount)) {
136                    var parentGlAccountName = edit.getParentGlAccountName();
137                    GlAccount parentGlAccount = null;
138                    
139                    if(parentGlAccountName != null) {
140                        parentGlAccount = accountingControl.getGlAccountByName(parentGlAccountName);
141                    }
142                    
143                    if(parentGlAccountName == null || parentGlAccount != null) {
144                        if(accountingControl.isParentGlAccountSafe(glAccount, parentGlAccount)) {
145                            var glAccountClassName = edit.getGlAccountClassName();
146                            var glAccountClass = accountingControl.getGlAccountClassByName(glAccountClassName);
147                            
148                            if(glAccountClass != null) {
149                                var glAccountCategoryName = edit.getGlAccountCategoryName();
150                                var glAccountCategory = glAccountCategoryName == null? null: accountingControl.getGlAccountCategoryByName(glAccountCategoryName);
151                                
152                                if(glAccountCategoryName == null || glAccountCategory != null) {
153                                    var glResourceTypeName = edit.getGlResourceTypeName();
154                                    var glResourceType = accountingControl.getGlResourceTypeByName(glResourceTypeName);
155                                    
156                                    if(glResourceType != null) {
157                                        if(lockEntityForUpdate(glAccount)) {
158                                            try {
159                                                var partyPK = getPartyPK();
160                                                var glAccountDetailValue = accountingControl.getGlAccountDetailValueForUpdate(glAccount);
161                                                var glAccountDescription = accountingControl.getGlAccountDescriptionForUpdate(glAccount, getPreferredLanguage());
162                                                var isDefault = glAccountCategory == null? null: Boolean.valueOf(edit.getIsDefault());
163                                                var description = edit.getDescription();
164                                                
165                                                glAccountDetailValue.setGlAccountName(glAccountName);
166                                                glAccountDetailValue.setParentGlAccountPK(parentGlAccount == null? null: parentGlAccount.getPrimaryKey());
167                                                glAccountDetailValue.setGlAccountClassPK(glAccountClass.getPrimaryKey());
168                                                glAccountDetailValue.setGlAccountCategoryPK(glAccountCategory == null? null: glAccountCategory.getPrimaryKey());
169                                                glAccountDetailValue.setGlResourceTypePK(glResourceType.getPrimaryKey());
170                                                glAccountDetailValue.setIsDefault(isDefault);
171                                                
172                                                glAccountLogic.updateGlAccountFromValue(glAccountDetailValue, partyPK);
173                                                
174                                                if(glAccountDescription == null && description != null) {
175                                                    accountingControl.createGlAccountDescription(glAccount, getPreferredLanguage(), description, partyPK);
176                                                } else if(glAccountDescription != null && description == null) {
177                                                    accountingControl.deleteGlAccountDescription(glAccountDescription, partyPK);
178                                                } else if(glAccountDescription != null && description != null) {
179                                                    var glAccountDescriptionValue = accountingControl.getGlAccountDescriptionValue(glAccountDescription);
180                                                    
181                                                    glAccountDescriptionValue.setDescription(description);
182                                                    accountingControl.updateGlAccountDescriptionFromValue(glAccountDescriptionValue, partyPK);
183                                                }
184                                            } finally {
185                                                unlockEntity(glAccount);
186                                            }
187                                        } else {
188                                            addExecutionError(ExecutionErrors.EntityLockStale.name());
189                                        }
190                                    } else {
191                                        addExecutionError(ExecutionErrors.UnknownGlResourceTypeName.name(), glResourceTypeName);
192                                    }
193                                } else {
194                                    addExecutionError(ExecutionErrors.UnknownGlAccountCategoryName.name(), glAccountCategoryName);
195                                }
196                            } else {
197                                addExecutionError(ExecutionErrors.UnknownGlAccountClassName.name(), glAccountClassName);
198                            }
199                        } else {
200                            addExecutionError(ExecutionErrors.InvalidParentGlAccount.name());
201                        }
202                    } else {
203                        addExecutionError(ExecutionErrors.UnknownParentGlAccountName.name(), parentGlAccountName);
204                    }
205                } else {
206                    addExecutionError(ExecutionErrors.DuplicateGlAccountName.name(), glAccountName);
207                }
208            }
209            
210            if(hasExecutionErrors()) {
211                result.setGlAccount(accountingControl.getGlAccountTransfer(getUserVisit(), glAccount));
212                result.setEntityLock(getEntityLockTransfer(glAccount));
213            }
214        }
215        
216        return result;
217    }
218    
219}