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