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.model.control.party.server.logic;
018
019import com.echothree.model.control.party.common.PartyRelationshipTypes;
020import com.echothree.model.control.party.common.PartyTypes;
021import com.echothree.model.control.party.common.RoleTypes;
022import com.echothree.model.control.party.common.exception.DuplicatePartyRelationshipException;
023import com.echothree.model.control.party.common.exception.NotAnEmployeeOfDepartmentsDivisionException;
024import com.echothree.model.control.party.common.exception.NotAnEmployeeOfDivisionsCompanyException;
025import com.echothree.model.control.party.common.exception.UnknownPartyRelationshipException;
026import com.echothree.model.control.party.common.exception.UnknownPartyRelationshipTypeNameException;
027import com.echothree.model.control.party.common.exception.UnknownRoleTypeNameException;
028import com.echothree.model.control.party.server.control.PartyControl;
029import com.echothree.model.control.user.server.logic.UserKeyLogic;
030import com.echothree.model.control.user.server.logic.UserSessionLogic;
031import com.echothree.model.data.party.server.entity.Party;
032import com.echothree.model.data.party.server.entity.PartyCompany;
033import com.echothree.model.data.party.server.entity.PartyDepartment;
034import com.echothree.model.data.party.server.entity.PartyDivision;
035import com.echothree.model.data.party.server.entity.PartyRelationship;
036import com.echothree.model.data.party.server.entity.PartyRelationshipType;
037import com.echothree.model.data.party.server.entity.RoleType;
038import com.echothree.util.common.message.ExecutionErrors;
039import com.echothree.util.common.persistence.BasePK;
040import com.echothree.util.server.control.BaseLogic;
041import com.echothree.util.server.message.ExecutionErrorAccumulator;
042import com.echothree.util.server.persistence.Session;
043import java.util.List;
044
045public class PartyRelationshipLogic
046        extends BaseLogic {
047    
048    private PartyRelationshipLogic() {
049        super();
050    }
051    
052    private static class PartyRelationshipLogicHolder {
053        static PartyRelationshipLogic instance = new PartyRelationshipLogic();
054    }
055    
056    public static PartyRelationshipLogic getInstance() {
057        return PartyRelationshipLogicHolder.instance;
058    }
059
060    public PartyRelationshipType getPartyRelationshipTypeByName(final ExecutionErrorAccumulator eea, final String partyRelationshipTypeName) {
061        var partyControl = Session.getModelController(PartyControl.class);
062        PartyRelationshipType partyRelationshipType = partyControl.getPartyRelationshipTypeByName(partyRelationshipTypeName);
063
064        if(partyRelationshipType == null) {
065            handleExecutionError(UnknownPartyRelationshipTypeNameException.class, eea, ExecutionErrors.UnknownPartyRelationshipTypeName.name(), partyRelationshipTypeName);
066        }
067
068        return partyRelationshipType;
069    }
070
071    public RoleType getRoleTypeByName(final ExecutionErrorAccumulator eea, final String roleTypeName) {
072        var partyControl = Session.getModelController(PartyControl.class);
073        RoleType roleType = partyControl.getRoleTypeByName(roleTypeName);
074
075        if(roleType == null) {
076            handleExecutionError(UnknownRoleTypeNameException.class, eea, ExecutionErrors.UnknownRoleTypeName.name(), roleTypeName);
077        }
078
079        return roleType;
080    }
081
082    public PartyRelationship createPartyRelationship(final ExecutionErrorAccumulator eea, final PartyRelationshipType partyRelationshipType,
083            final Party fromParty, final RoleType fromRoleType, final Party toParty, final RoleType toRoleType, final BasePK createdBy) {
084        var partyControl = Session.getModelController(PartyControl.class);
085        PartyRelationship partyRelationship = partyControl.getPartyRelationship(partyRelationshipType, fromParty, fromRoleType, toParty, toRoleType);
086
087        if(partyRelationship == null) {
088            partyControl.createPartyRelationship(partyRelationshipType, fromParty, fromRoleType, toParty, toRoleType, createdBy);
089        } else {
090            handleExecutionError(DuplicatePartyRelationshipException.class, eea, ExecutionErrors.DuplicatePartyRelationship.name(),
091                    partyRelationshipType.getPartyRelationshipTypeName(),
092                    fromParty.getLastDetail().getPartyName(), fromRoleType.getRoleTypeName(),
093                    toParty.getLastDetail().getPartyName(), toRoleType.getRoleTypeName());
094        }
095
096        return partyRelationship;
097    }
098
099    public void deletePartyRelationship(final ExecutionErrorAccumulator eea, final PartyRelationshipType partyRelationshipType, final Party fromParty,
100            final RoleType fromRoleType, final Party toParty, final RoleType toRoleType, final BasePK deletedBy) {
101        var partyControl = Session.getModelController(PartyControl.class);
102        PartyRelationship partyRelationship = partyControl.getPartyRelationshipForUpdate(partyRelationshipType, fromParty, fromRoleType, toParty, toRoleType);
103
104        if(partyRelationship == null) {
105            handleExecutionError(UnknownPartyRelationshipException.class, eea, ExecutionErrors.UnknownPartyRelationship.name(),
106                    partyRelationshipType.getPartyRelationshipTypeName(),
107                    fromParty.getLastDetail().getPartyName(), fromRoleType.getRoleTypeName(),
108                    toParty.getLastDetail().getPartyName(), toRoleType.getRoleTypeName());
109        } else {
110            UserKeyLogic.getInstance().clearUserKeysByPartyRelationship(partyRelationship);
111            UserSessionLogic.getInstance().deleteUserSessionsByPartyRelationship(partyRelationship);
112            partyControl.deletePartyRelationship(partyRelationship, deletedBy);
113        }
114    }
115
116    public boolean isEmployeeOfCompany(final ExecutionErrorAccumulator eea, final Party company, final Party employee) {
117        boolean result = false;
118
119        PartyLogic.getInstance().checkPartyType(eea, company, PartyTypes.COMPANY.name());
120        PartyLogic.getInstance().checkPartyType(eea, employee, PartyTypes.EMPLOYEE.name());
121
122        if(!hasExecutionErrors(eea)) {
123            var partyControl = Session.getModelController(PartyControl.class);
124
125            result = partyControl.countPartyRelationships(getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
126                    company, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
127                    employee, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name())) == 1;
128        }
129
130        return result;
131    }
132
133    public PartyRelationship addEmployeeToCompany(final ExecutionErrorAccumulator eea, final Party companyParty, final Party employeeParty, final BasePK createdBy) {
134        PartyRelationship partyRelationship = null;
135
136        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
137        PartyLogic.getInstance().checkPartyType(eea, companyParty, PartyTypes.COMPANY.name());
138
139        if(!hasExecutionErrors(eea)) {
140            partyRelationship = createPartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
141                        companyParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
142                        employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), createdBy);
143        }
144
145        return partyRelationship;
146    }
147
148    public void removeEmployeeFromCompany(final ExecutionErrorAccumulator eea, final Party companyParty, final Party employeeParty, final BasePK deletedBy) {
149        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
150        PartyLogic.getInstance().checkPartyType(eea, companyParty, PartyTypes.COMPANY.name());
151
152        if(!hasExecutionErrors(eea)) {
153            removeEmployeeFromCompanysDivisions(eea, companyParty, employeeParty, deletedBy);
154
155            deletePartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
156                        companyParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
157                        employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), deletedBy);
158        }
159    }
160
161    public boolean isEmployeeOfDivision(final ExecutionErrorAccumulator eea, final Party division, final Party employee) {
162        boolean result = false;
163
164        PartyLogic.getInstance().checkPartyType(eea, division, PartyTypes.DIVISION.name());
165        PartyLogic.getInstance().checkPartyType(eea, employee, PartyTypes.EMPLOYEE.name());
166
167        if(!hasExecutionErrors(eea)) {
168            var partyControl = Session.getModelController(PartyControl.class);
169
170            result = partyControl.countPartyRelationships(getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
171                    division, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
172                    employee, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name())) == 1;
173        }
174
175        return result;
176    }
177
178    public PartyRelationship addEmployeeToDivision(final ExecutionErrorAccumulator eea, final Party divisionParty, final Party employeeParty, final BasePK createdBy) {
179        PartyRelationship partyRelationship = null;
180
181        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
182        PartyLogic.getInstance().checkPartyType(eea, divisionParty, PartyTypes.DIVISION.name());
183
184        if(!hasExecutionErrors(eea)) {
185            var partyControl = Session.getModelController(PartyControl.class);
186            PartyDivision partyDivision = partyControl.getPartyDivision(divisionParty);
187            PartyCompany partyCompany = partyControl.getPartyCompany(partyDivision.getCompanyParty());
188            Party companyParty = partyCompany.getParty();
189
190            if(isEmployeeOfCompany(eea, companyParty, employeeParty)) {
191                partyRelationship = createPartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
192                            divisionParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
193                            employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), createdBy);
194            } else {
195                handleExecutionError(NotAnEmployeeOfDivisionsCompanyException.class, eea, ExecutionErrors.NotAnEmployeeOfDivisionsCompany.name(),
196                        partyCompany.getPartyCompanyName(), employeeParty.getLastDetail().getPartyName());
197            }
198        }
199
200        return partyRelationship;
201    }
202
203    public void removeEmployeeFromCompanysDivisions(final ExecutionErrorAccumulator eea, final Party companyParty, final Party employeeParty, final BasePK deletedBy) {
204        var partyControl = Session.getModelController(PartyControl.class);
205        List<PartyDivision> partyDivisions = partyControl.getDivisionsByCompany(companyParty);
206
207        partyDivisions.stream().map((partyDivision) -> partyDivision.getParty()).filter((divisionParty) -> isEmployeeOfDivision(eea, divisionParty, employeeParty)).forEach((divisionParty) -> {
208            removeEmployeeFromDivisionsDepartments(eea, employeeParty, employeeParty, deletedBy);
209            removeEmployeeFromDivision(eea, divisionParty, employeeParty, deletedBy);
210        });
211    }
212
213    public void removeEmployeeFromDivision(final ExecutionErrorAccumulator eea, final Party divisionParty, final Party employeeParty, final BasePK deletedBy) {
214        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
215        PartyLogic.getInstance().checkPartyType(eea, divisionParty, PartyTypes.DIVISION.name());
216
217        if(!hasExecutionErrors(eea)) {
218            removeEmployeeFromDivisionsDepartments(eea, divisionParty, employeeParty, deletedBy);
219
220            deletePartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
221                        divisionParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
222                        employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), deletedBy);
223        }
224    }
225
226    public boolean isEmployeeOfDepartment(final ExecutionErrorAccumulator eea, final Party department, final Party employee) {
227        boolean result = false;
228
229        PartyLogic.getInstance().checkPartyType(eea, department, PartyTypes.DEPARTMENT.name());
230        PartyLogic.getInstance().checkPartyType(eea, employee, PartyTypes.EMPLOYEE.name());
231
232        if(!hasExecutionErrors(eea)) {
233            var partyControl = Session.getModelController(PartyControl.class);
234
235            result = partyControl.countPartyRelationships(getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
236                    department, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
237                    employee, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name())) == 1;
238        }
239
240        return result;
241    }
242
243    public PartyRelationship addEmployeeToDepartment(final ExecutionErrorAccumulator eea, final Party departmentParty, final Party employeeParty, final BasePK createdBy) {
244        PartyRelationship partyRelationship = null;
245
246        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
247        PartyLogic.getInstance().checkPartyType(eea, departmentParty, PartyTypes.DEPARTMENT.name());
248
249        if(!hasExecutionErrors(eea)) {
250            var partyControl = Session.getModelController(PartyControl.class);
251            PartyDepartment partyDepartment = partyControl.getPartyDepartment(departmentParty);
252            PartyDivision partyDivision = partyControl.getPartyDivision(partyDepartment.getDivisionParty());
253            PartyCompany partyCompany = partyControl.getPartyCompany(partyDivision.getCompanyParty());
254            Party divisionParty = partyDivision.getParty();
255
256            if(isEmployeeOfDivision(eea, divisionParty, employeeParty)) {
257                partyRelationship = createPartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
258                            departmentParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
259                            employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), createdBy);
260            } else {
261                handleExecutionError(NotAnEmployeeOfDepartmentsDivisionException.class, eea, ExecutionErrors.NotAnEmployeeOfDepartmentsDivision.name(),
262                        partyCompany.getPartyCompanyName(), partyDivision.getPartyDivisionName(), employeeParty.getLastDetail().getPartyName());
263            }
264        }
265
266        return partyRelationship;
267    }
268
269    public void removeEmployeeFromDivisionsDepartments(final ExecutionErrorAccumulator eea, final Party divisionParty, final Party employeeParty, final BasePK deletedBy) {
270        var partyControl = Session.getModelController(PartyControl.class);
271        List<PartyDepartment> partyDepartments = partyControl.getDepartmentsByDivision(divisionParty);
272
273        partyDepartments.stream().map((partyDepartment) -> partyDepartment.getParty()).filter((departmentParty) -> isEmployeeOfDepartment(eea, departmentParty, employeeParty)).forEach((departmentParty) -> {
274            removeEmployeeFromDepartment(eea, departmentParty, employeeParty, deletedBy);
275        });
276    }
277
278    public void removeEmployeeFromDepartment(final ExecutionErrorAccumulator eea, final Party departmentParty, final Party employeeParty, final BasePK deletedBy) {
279        PartyLogic.getInstance().checkPartyType(eea, employeeParty, PartyTypes.EMPLOYEE.name());
280        PartyLogic.getInstance().checkPartyType(eea, departmentParty, PartyTypes.DEPARTMENT.name());
281
282        if(!hasExecutionErrors(eea)) {
283            deletePartyRelationship(eea, getPartyRelationshipTypeByName(eea, PartyRelationshipTypes.EMPLOYMENT.name()),
284                        departmentParty, getRoleTypeByName(eea, RoleTypes.EMPLOYER.name()),
285                        employeeParty, getRoleTypeByName(eea, PartyTypes.EMPLOYEE.name()), deletedBy);
286        }
287    }
288
289}