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