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