public virtual void SendToOtherParty(Party modifyingParty, string message, UserInfo userInfo, DateTime now)
        {
            CheckIsEmployerOrProvider(modifyingParty);
            CheckIsWithParty(modifyingParty);

            StartTrackingSession(UserAction.SendCohort, modifyingParty, EmployerAccountId, ProviderId, userInfo);
            ChangeTrackingSession.TrackUpdate(this);

            IsDraft                = false;
            EditStatus             = modifyingParty.GetOtherParty().ToEditStatus();
            WithParty              = modifyingParty.GetOtherParty();
            LastAction             = LastAction.Amend;
            CommitmentStatus       = CommitmentStatus.Active;
            TransferApprovalStatus = null;
            AddMessage(message, modifyingParty, userInfo);
            UpdatedBy(modifyingParty, userInfo);
            LastUpdatedOn = DateTime.UtcNow;

            switch (WithParty)
            {
            case Party.Employer:
                Publish(() => new CohortAssignedToEmployerEvent(Id, now, modifyingParty));
                break;

            case Party.Provider:
                Publish(() => new CohortAssignedToProviderEvent(Id, now));
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(EditStatus));
            }

            if (Approvals.HasFlag(Party.Provider))
            {
                Publish(() => new ApprovedCohortReturnedToProviderEvent(Id, now));
            }

            if (ChangeOfPartyRequestId.HasValue)
            {
                Publish(() => new CohortWithChangeOfPartyUpdatedEvent(Id, userInfo));
            }

            Approvals = Party.None;
            ChangeTrackingSession.CompleteTrackingSession();
        }
        public virtual void Approve(Party modifyingParty, string message, UserInfo userInfo, DateTime now)
        {
            CheckIsEmployerOrProviderOrTransferSender(modifyingParty);
            CheckIsWithParty(modifyingParty);
            CheckIsCompleteForParty(modifyingParty);

            StartTrackingSession(UserAction.ApproveCohort, modifyingParty, EmployerAccountId, ProviderId, userInfo);
            ChangeTrackingSession.TrackUpdate(this);

            switch (modifyingParty)
            {
            case Party.Employer:
            case Party.Provider:
            {
                var otherParty             = modifyingParty.GetOtherParty();
                var isApprovedByOtherParty = Approvals.HasFlag(otherParty);

                IsDraft    = false;
                EditStatus = isApprovedByOtherParty ? EditStatus.Both : otherParty.ToEditStatus();
                WithParty  = GetWithParty(otherParty, isApprovedByOtherParty);
                if (isApprovedByOtherParty)
                {
                    EmployerAndProviderApprovedOn = DateTime.UtcNow;
                }
                LastAction             = LastAction.Approve;
                CommitmentStatus       = CommitmentStatus.Active;
                TransferApprovalStatus = GetTransferApprovalStatus(isApprovedByOtherParty);
                Approvals |= modifyingParty;
                AddMessage(message, modifyingParty, userInfo);
                UpdatedBy(modifyingParty, userInfo);
                LastUpdatedOn = DateTime.UtcNow;

                switch (WithParty)
                {
                case Party.Employer:
                    Publish(() => new CohortAssignedToEmployerEvent(Id, now, modifyingParty));
                    break;

                case Party.Provider:
                    Publish(() => new CohortAssignedToProviderEvent(Id, now));
                    break;

                case Party.TransferSender:
                    Publish(() => new CohortTransferApprovalRequestedEvent(Id, now, modifyingParty));
                    break;
                }

                break;
            }

            case Party.TransferSender:
                TransferApprovalStatus     = Types.TransferApprovalStatus.Approved;
                TransferApprovalActionedOn = now;
                WithParty = Party.None;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(modifyingParty));
            }

            if (Approvals.HasFlag(Party.Provider) && modifyingParty == Party.Employer)
            {
                Publish(() => new CohortApprovedByEmployerEvent(Id, now));
            }

            if (IsApprovedByAllParties)
            {
                Publish(() => new CohortFullyApprovedEvent(Id, EmployerAccountId, ProviderId, now, modifyingParty, ChangeOfPartyRequestId, userInfo));

                if (ChangeOfPartyRequestId.HasValue)
                {
                    Publish(() => new CohortWithChangeOfPartyFullyApprovedEvent(Id, ChangeOfPartyRequestId.Value, now, modifyingParty, userInfo));
                }
            }

            ChangeTrackingSession.CompleteTrackingSession();
        }