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