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.training.server.trigger;
018
019import com.echothree.model.control.core.common.EventTypes;
020import com.echothree.model.control.core.server.control.EventControl;
021import com.echothree.model.control.security.server.control.SecurityControl;
022import com.echothree.model.control.training.common.training.PartyTrainingClassStatusConstants;
023import com.echothree.model.control.training.server.control.TrainingControl;
024import com.echothree.model.control.training.server.logic.PartyTrainingClassLogic;
025import com.echothree.model.control.workflow.server.control.WorkflowControl;
026import com.echothree.model.control.workflow.server.trigger.BaseTrigger;
027import com.echothree.model.control.workflow.server.trigger.EntityTypeTrigger;
028import com.echothree.model.data.party.common.pk.PartyPK;
029import com.echothree.model.data.party.server.entity.Party;
030import com.echothree.model.data.training.server.entity.PartyTrainingClass;
031import com.echothree.model.data.training.server.entity.TrainingClass;
032import com.echothree.model.data.workflow.server.entity.WorkflowEntityStatus;
033import com.echothree.util.server.message.ExecutionErrorAccumulator;
034import com.echothree.util.server.persistence.Session;
035
036public class PartyTrainingClassTrigger
037        extends BaseTrigger
038        implements EntityTypeTrigger {
039
040    private void expireCurrentPartyTrainingClass(final Session session, final ExecutionErrorAccumulator eea, final WorkflowEntityStatus workflowEntityStatus,
041            final PartyTrainingClass partyTrainingClass, final PartyPK triggeredBy) {
042        var eventControl = Session.getModelController(EventControl.class);
043        var trainingControl = Session.getModelController(TrainingControl.class);
044        var workflowControl = Session.getModelController(WorkflowControl.class);
045        var partyTrainingClassDetail = partyTrainingClass.getLastDetail();
046        var party = partyTrainingClassDetail.getParty();
047        var trainingClass = partyTrainingClassDetail.getTrainingClass();
048
049        workflowControl.transitionEntityInWorkflowUsingNames(null, workflowEntityStatus, PartyTrainingClassStatusConstants.WorkflowDestination_PASSED_TO_EXPIRED,
050                trainingClass.getLastDetail().getExpiredRetentionTime(), triggeredBy);
051        eventControl.sendEvent(partyTrainingClassDetail.getParty().getPrimaryKey(), EventTypes.TOUCH, partyTrainingClass.getPrimaryKey(), EventTypes.MODIFY, triggeredBy);
052
053        // If it is required, then consider creating a new PartyTrainingClass that's assigned to them.
054        if(checkTrainingRequired(party, trainingClass)) {
055            // Check to see if the TrainingClass is in one of the listed statuses for the Party. If it is, then we do not create a
056            // new instance of a PartyTrainingClass for it.
057            var partyTrainingClasses = trainingControl.getPartyTrainingClassesByStatuses(party, trainingClass,
058                    PartyTrainingClassStatusConstants.WorkflowStep_ASSIGNED, PartyTrainingClassStatusConstants.WorkflowStep_TRAINING,
059                    PartyTrainingClassStatusConstants.WorkflowStep_PASSED);
060
061            if(partyTrainingClasses.isEmpty()) {
062                var partyTrainingClassLogic = PartyTrainingClassLogic.getInstance();
063                var preparedPartyTrainingClass = partyTrainingClassLogic.preparePartyTrainingClass(eea, party, trainingClass, null, null);
064
065                if(!eea.hasExecutionErrors()) {
066                    partyTrainingClassLogic.createPartyTrainingClass(session, preparedPartyTrainingClass, triggeredBy);
067                }
068            }
069        }
070    }
071    
072    private boolean checkTrainingRequired(final Party party, final TrainingClass trainingClass) {
073        var trainingRequired = false;
074
075        // Check AlwaysReassignOnExpiration on the TrainingClass, and if that isn't set, check to see if the Party has a
076        // PartySecurityRoleTemplateUse. If the PartySecurityRoleTemplate lists this TrainingClass, then it will be required.
077        if(trainingClass.getLastDetail().getAlwaysReassignOnExpiration()) {
078            trainingRequired = true;
079        } else {
080            var securityControl = Session.getModelController(SecurityControl.class);
081            var partySecurityRoleTemplateUse = securityControl.getPartySecurityRoleTemplateUse(party);
082            if(partySecurityRoleTemplateUse != null) {
083                if(securityControl.getPartySecurityRoleTemplateTrainingClass(partySecurityRoleTemplateUse.getPartySecurityRoleTemplate(), trainingClass) != null) {
084                    trainingRequired = true;
085                }
086            }
087        }
088        
089        return trainingRequired;
090    }
091    
092    @Override
093    public void handleTrigger(final Session session, final ExecutionErrorAccumulator eea, final WorkflowEntityStatus workflowEntityStatus, final PartyPK triggeredBy) {
094        var trainingControl = Session.getModelController(TrainingControl.class);
095        var partyTrainingClass = trainingControl.convertEntityInstanceToPartyTrainingClassForUpdate(getEntityInstance(workflowEntityStatus));
096        var workflowStepName = getWorkflowStepName(workflowEntityStatus);
097        
098        if(workflowStepName.equals(PartyTrainingClassStatusConstants.WorkflowStep_PASSED)) {
099            expireCurrentPartyTrainingClass(session, eea, workflowEntityStatus, partyTrainingClass, triggeredBy);
100        } else if(workflowStepName.equals(PartyTrainingClassStatusConstants.WorkflowStep_EXPIRED)) {
101            trainingControl.deletePartyTrainingClass(partyTrainingClass, triggeredBy);
102        }
103    }
104
105}