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