HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/vebon.komma.pro/app/KommaApp/Audit/AuditService.php
<?php

namespace KommaApp\Audit;

use App\Helpers\KommaHelpers;
use Carbon\Carbon;
use Illuminate\Support\MessageBag;
use KommaApp\Audit\Models\Audit;
use KommaApp\Audit\Models\DocumentGroup;
use KommaApp\Audit\Models\Document;
use KommaApp\BaseDocumentGroups\Models\BaseDocumentGroup;
use KommaApp\EndUsers\Models\EndUser;
use PhpParser\Comment\Doc;

/**
 * All the functions for the audit.
 *
 * @author      Tim Van Samang <timvansamang@komma.pro>
 * @copyright   (c) 2012-2015, Komma Mediadesign
 */
class AuditService
{


    /*----------------------------|
    |                             |
    |      Global functions       |
    |                             |
    |----------------------------*/


    /**
     * This will check if the current endUser
     * is allowed to see the current audit
     *
     * @param Audit $audit
     * @return bool
     */
    public function isUserAllowed(EndUser $endUser, Audit $audit)
    {

        //If the user is an member, and the audit belongs to this member, return true;
        if ($endUser->role == EndUser::$member && $endUser->memberAudits->contains($audit)) return true;

        //If the user is an auditor, and the audit belongs to this auditor, return true;
        if ($endUser->role == EndUser::$auditor && $endUser->auditorAudits->contains($audit)) return true;
        return false;

    }


    /**
     * This will check if the document can be downloaded
     *
     * @param EndUser $endUser
     * @param Document $document
     * @return bool
     */
    public function isUserAllowedToDocument(EndUser $endUser, Document $document)
    {
        //Get the audit
        $audit = $document->documentGroup->audit;
        //Check if the is user is allowed
        return $this->isUserAllowed($endUser, $audit);

    }


    /**
     * This will check if the documentGroup can be downloaded
     * @param EndUser $endUser
     * @param DocumentGroup $documentGroup
     * @return bool
     */
    public function isUserAllowedToDocumentGroup(EndUser $endUser, DocumentGroup $documentGroup)
    {
        //Get the audit
        $audit = $documentGroup->audit;
        //Check if the is user is allowed
        return $this->isUserAllowed($endUser, $audit);
    }

    /**
     * Update the documentGroup
     * based on the key value data
     *
     * @param $documentGroup
     * @param $data
     */
    public function updateDocumentGroup($documentGroup, $data)
    {
        //Loop trough the data
        foreach ($data as $key => $value) {
            //If the docuemntGroup doesnt have the given key, skip to the next
            if (!isset($documentGroup->$key)) continue;
            //Set the value to the given key
            $documentGroup->$key = $value;
        }
        //Save the documentGroup
        $documentGroup->save();

    }


    /**
     * This method changes the status of the given audit
     * with the given status
     *
     * @param Audit $audit
     * @param $status
     */
    public function changeAuditStatus(Audit $audit, $status)
    {

        switch ($status) {
            /**
             * When an audit is rejected by the auditor, its status will be changed to open
             * After an rejection the deadline is extended by one month from the status change
             * This is only valid on the first rejection hence the rejected_count
             * And when one month from now is larger then the initial deadline
             *
             */
            case Audit::$open:
                //Check rejected count and if one month from now i
                if ($audit->rejected_count == 0 && Carbon::now()->addMonth() > $audit->deadline) {
                    $audit->deadline = Carbon::now()->addMonth();
                }

                $audit->rejected_count = $audit->rejected_count + 1;

                break;
            /**
             * When an audit is set to be judged the filed date stamp will be set
             * Only the first time, so the rejected_count should be 0
             */
            case Audit::$judged:
                //Reject count is not 0, so stop,
                //Todo: should we mail again?
                if ($audit->rejected_count != 0) {

                    //Email that the files are filed in again
                    $this->notifyAuditor($audit, 'filed-again');
                    break;
                }

                //Set the file to now
                $audit->filed = Carbon::now();
                break;
            /**
             * When an audit is closed, set the closing_date
             */
            case Audit::$closed:
                $audit->closing_date = Carbon::now();
                break;
            /**
             * When an audit is reviewed:
             * update all documents,
             * set the closing_date
             * notify the user
             */
            case Audit::$reviewedInPractice:

                // Set all document statuses to reviewedInPractice
                $data = ['status' => Document::$reviewedInPractice];
                foreach($audit->documentGroups as $documentGroup)
                {
                    $this->updateDocuments($documentGroup->documents, $data);
                }

                // Set closing date
                $audit->closing_date = Carbon::now();

                // Notify the user
                $this->notifyReviewedInPractice($audit);

                break;
        }


        //Set the status
        $audit->status = $status;
        //And save
        $audit->save();
    }


    /**
     * Get all the audits with the given status and operator
     * for the given endUser
     *
     *
     * @param EndUser $EndUser
     * @param $status
     * @param string $operator
     * @return mixed
     */
    public function getEndUserAuditsByStatus(EndUser $EndUser, $status, $operator = '=')
    {
        //Set the enduser id based on the role
        $audits = Audit::where($EndUser->role . '_id', '=', $EndUser->id)
            //Set the status and operator
            ->where('status', $operator, $status)
            //Get
            ->get();
        return $audits;
    }


    /**
     * Get all the audits with the given status and operator
     * for the given endUser
     *
     *
     * @param EndUser $EndUser
     * @return mixed
     */
    public function getEndUserActiveAudits(EndUser $EndUser)
    {
        //Set the enduser id based on the role
        $audits = Audit::where($EndUser->role . '_id', '=', $EndUser->id)
            //Set the status and operator
            ->where('status', '!=', Audit::$closed)
            ->where('status', '!=', Audit::$reviewedInPractice)
            ->orderBy('updated_at','desc')
            //Get
            ->get();
        return $audits;
    }


    /**
     * Get all the audits with the given status and operator
     * for the given endUser
     *
     * @param EndUser $EndUser
     * @return mixed
     */
    public function getEndUserClosedAudits(EndUser $EndUser)
    {
        //Set the enduser id based on the role
        $audits = Audit::where($EndUser->role . '_id', '=', $EndUser->id)
            //Set the status and operator
            ->where(function ($query) {
                $query->where('status', '=', Audit::$closed)
                      ->orWhere('status', '=', Audit::$reviewedInPractice);
            })
            ->orderBy('closing_date','desc')
            //Get
            ->get();

        return $audits;
    }


    /**
     * Check if the documentGroup of the document
     * is the same as the given documentGroup.
     *
     * @param Document $document
     * @param DocumentGroup $documentGroup
     * @return bool
     */
    public function isDocumentPartOfDocumentGroup(Document $document, DocumentGroup $documentGroup)
    {
        //If it is not the same, return false
        if ($document->documentGroup != $documentGroup) return false;
        //If it is the same, return true
        return true;

    }

    /**
     * Update the document
     * based on the key value data
     *
     * @param Document $document
     * @param $data
     * @return Document
     */
    public function updateDocument(Document $document, $data)
    {
        //Loop trough the data
        foreach ($data as $key => $value) {
            //If the document doesn't have the given key, skip to the next
            if (!isset($document->$key)) continue;
            //Set the value to the given key
            $document->$key = $value;
        }
        //Save the documentGroup
        $document->save();

        return $document;
    }

    /**
     * Update the collection of documents
     * based on the key value data
     *
     * @param $documents
     * @param $data
     * @return mixed
     */
    public function updateDocuments($documents, $data)
    {
        //Loop trough each document
        $documents->each(function ($document) use ($data) {
            //Update this
            $this->updateDocument($document, $data);
        });

        return $documents;
    }

    /*----------------------------|
    |                             |
    |      Member functions       |
    |                             |
    |----------------------------*/

    /**
     * Create a new Audit for the given  member
     * and the given year
     *
     * @param EndUser $member
     * @param $year
     * @return mixed
     */
    public function createNewAudit(EndUser $member, $year)
    {
        //Check if there the Audit for this member and year exist, or create a new
        $audit = Audit::firstOrNew(['member_id' => $member->id, 'year' => $year]);

        //If it has an id, the audit already exist, skip creation of documentGroups and return the audit
        if ($audit->id) return $audit;

        //Set the deadline to the first day of april of the audit year
        $audit->deadline = Carbon::createFromDate($year, 4, 1);

        //Save the audit
        $audit->save();


        $documentGroups = BaseDocumentGroup::all();

        //Add the documentGroups to the audit, use the array from the config and the given year
        $this->addDocumentGroupsToAudit($audit, $documentGroups, $year);

        //Return the audit
        return $audit;

    }


    /**
     * Create document groups for the given audit
     * based on the given array of documentGroups
     * for the given year
     *
     * @param Audit $audit
     * @param $documentGroups
     * @param $year
     * @return bool
     */
    private function addDocumentGroupsToAudit(Audit $audit, $documentGroups, $year)
    {
        //Loop trough the documentGroups
        foreach ($documentGroups as $baseDocumentGroup) {

            //Replace the last_year and year strings
            $documentGroupName = KommaHelpers::makeReplacements($baseDocumentGroup->name, ['last_year' => $year - 1, 'year' => $year]);

            //Check if the documentGroup already exist for this audit or create a new
            $documentGroup = DocumentGroup::firstOrNew(['audit_id' => $audit->id, 'name' => $documentGroupName]);

            //If it has an id, it already exists, skip to the next (this makes it possible to add new documents to existing audit)
            if ($documentGroup->id) continue;

            //Add the required form the config
            $documentGroup->required = $baseDocumentGroup->required;
            $documentGroup->description = $baseDocumentGroup->description;

            //Save the documentGroup
            $documentGroup->save();
        }
        return true;

    }


    /**
     * Get the oldest audit based on the year field
     * for the given member
     *
     * @param EndUser $member
     * @return bool
     */
    public function getMemberFirstAudit(EndUser $member)
    {
        //Get all the audits for the given member_id, order by year and get the first, if fails return false
        if (!$audit = Audit::where('member_id', '=', $member->id)->orderBy('year')->first()) return false;

        //return audit
        return $audit;
    }

    /**
     * @param $member_id
     * @return mixed
     */
    public function getMemberAudits($member_id)
    {
        $audits = Audit::where('member_id', '=', $member_id)->orderBy('year', 'desc')->get();
        return $audits;
    }


    /**
     * This will bind the multiple files to the given DocumentGroup
     *
     * @param DocumentGroup $documentGroup
     * @param $filesData
     * @return mixed
     */
    public function bindFilesToDocumentGroup(DocumentGroup $documentGroup, $filesData)
    {
        $documents = [];
        //Loop trough the filesData
        foreach ($filesData as $file) {
            //Bind one file to the documentGroup
            $document = $this->bindFileToDocumentGroup($documentGroup, $file);
            //Set the document to the documents array
            $documents[] = $document;
        }
        return $documents;
    }

    /**
     * This will bind one file to the given documentGroup
     *
     * @param DocumentGroup $documentGroup
     * @param $file ]
     * @return mixed
     */
    public function bindFileToDocumentGroup(DocumentGroup $documentGroup, $file)
    {
        //Check if the document already exist based on the file name
        if (!$document = $documentGroup->documents()->where('file_name', $file['file_name'])->first()) {
            //If not create it
            $document = Document::create([
                'file_name' => $file['file_name'],
                'document_group_id' => $documentGroup->id
            ]);
        }
        //Reset the status to notJudged
        $document->status = Document::$notJudged;
        //Set the relative path (without public_path()) to full_path
        $document->full_path = $file['relative_path'];
        //Save
        $document->save();

        return $document;
    }


    /**
     * This method will check if the documentGroup
     * is ready to handed in.
     *
     * @param Audit $audit
     * @return bool|MessageBag
     */
    public function checkDocumentGroup(Audit $audit)
    {
        $errors = new MessageBag();

        $minimimFilesPerGroup = 1;

        foreach ($audit->documentGroups as $documentGroup) {
            //Documents with status false
            if ($documentGroup->documents->where('status', Document::$rejected)->count() > 0) $errors->add($documentGroup->id, \Lang::get('audit.still_rejected_files'));

            //Check if required is false and applicable is false, if this is the case, skip this group (no files needed)
            if (!$documentGroup->required && !$documentGroup->applicable) continue;

            //We need to have at least (one) document in each documentGroup
            if ($documentGroup->documents->count() >= $minimimFilesPerGroup) continue;

            //Not enough documents check if required is true
            if ($documentGroup->required) $errors->add($documentGroup->id, \Lang::get('audit.min_files_required', ['min' => $minimimFilesPerGroup]));
            else if (!$documentGroup->required) $errors->add($documentGroup->id, \Lang::get('audit.min_files_required_or_applicable', ['min' => $minimimFilesPerGroup]));

        }

        if ($errors->any()) return $errors;

        return false;


    }


    /**
     * This method will check if the audit is ready to be clased
     *
     * @param Audit $audit
     * @return bool|MessageBag
     */
    public function checkAuditForApproval(Audit $audit)
    {
        $errors = new MessageBag();

        //Loop trough each documentGroup
        foreach ($audit->documentGroups as $documentGroup) {
            //Check if there are documents where the status is approved
            if ($documentGroup->documents()->where('status', '!=', Document::$approved)->get()->count() > 0) $errors->add($documentGroup->id, \Lang::get('audit.not_all_files_approved'));
        }
        //Return the faults, if there are any
        if ($errors->any()) return $errors;

        return false;
    }


    /**
     * Get the first open audits for a given member
     *
     * @param $member
     * @return bool
     */
    public function getOpenAudit($member)
    {
        if (!$audit = $member->memberAudits()->where('status', '!=', Audit::$closed)->orderBy('year', 'desc')->first()) return false;

        return $audit;

    }

    /*----------------------------|
    |                             |
    |      Auditor functions      |
    |                             |
    |----------------------------*/


    /**
     * This checks if an auditor can reject the audit
     *
     * @param Audit $audit
     * @return bool|MessageBag
     */
    public function checkAuditForRejection(Audit $audit)
    {
        $errors = new MessageBag();
        //Loop trough each documentGroup
        foreach ($audit->documentGroups as $documentGroup) {
            //Check if there are documents where the status is is not judged
            if ($documentGroup->documents()->where('status', '==', Document::$notJudged)->get()->count() > 0) $errors->add($documentGroup->id, \Lang::get('audit.not_all_files_judged'));

        }
        //Return the faults, if there are any
        if ($errors->any()) return $errors;

        return false;
    }


    /**
     * Get all the audits that can be claimed
     *
     * @return mixed
     */
    public function getAuditsReadyToBeJudged()
    {
        //Get all the audits where there is no auditor coupled
        $audits = Audit::whereNull('auditor_id')->orderBy('updated_at','desc')->get();
        return $audits;
    }

    /**
     * Get all unclosed the audits for the given auditor
     * This is a wrapper function for getEndUserAuditsByStatus
     *
     * @param EndUser $auditor
     * @return mixed
     */
    public function getActiveAuditsForAuditor(EndUser $auditor)
    {
        return $this->getEndUserActiveAudits($auditor);
    }

    /**
     * Get all the closed audits for an auditor
     * This is a wrapper function for getEndUserAuditsByStatus
     *
     * @param EndUser $auditor
     * @return mixed
     */
    public function getClosedAuditsForAuditor(EndUser $auditor)
    {
        return $this->getEndUserClosedAudits($auditor);
    }


    /**
     * Bind an auditor to an Audit
     *
     * @param EndUser $auditor
     * @param Audit $audit
     * @return bool
     */
    public function bindAuditorToAudit(EndUser $auditor, Audit $audit)
    {
        $audit->auditor_id = $auditor->id;
        $audit->save();
        return true;
    }

    /**
     * Mail the auditor that the files are handed in
     *
     * @param $audit
     * @param string $type
     */
    public function notifyAuditor($audit, $type = 'filed')
    {
        //If there is no auditor for this audit , don't sent a mail
        if(!$audit->auditor) return;

        // If the audit is filed before the deadline, don't send a mail
        if( $type == 'filed' && Carbon::now() < $audit->deadline) return;

        //Queue the mail
        \Mail::queue('emails.' . $type, ['audit' => $audit], function ($m) use ($audit, $type) {
            $m->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));

            $m->to($audit->auditor->email)->subject(
                \Lang::get('email/' . $type . '.subject', [
                    'member' => $audit->member->company
                ])
            );
        });

    }

    /**
     * Mail the member that the files are reviewed in practice
     *
     * @param $audit
     * @param string $type
     */
    public function notifyReviewedInPractice($audit)
    {
        //If there is no auditor for this audit , don't sent a mail
        if(!$audit->auditor) return;

        //Queue the mail
        \Mail::queue('emails.reviewedInPractice', ['audit' => $audit], function ($m) use ($audit) {
            $m->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));

            $m->to($audit->member->email)->subject(
                \Lang::get('email/reviewedInPractice.subject')
            );
        });
    }


    /*----------------------------|
    |                             |
    |      Console functions      |
    |                             |
    |----------------------------*/

    /**
     * Get all the open audits
     * When $withRejected is false, don't include rejected
     * When $withRejected is true, include rejected
     *
     * @param $year
     * @param bool $withRejected
     * @return mixed
     */
    public function getOpenAudits($year, $withRejected = false)
    {

        $audits = Audit::where('status', '=', Audit::$open)
            ->where('year', '=', $year);

        if ($withRejected === false) {
            $audits->where('rejected_count', '=', 0);
        }

        $audits = $audits->get();

        return $audits;

    }


    /**
     * Send each audit-member from the list a reminder email
     * Switched by the $type parameter
     *
     * @param $audits
     * @param string $type
     */
    public function sendReminderEmails($audits, $type = 'first-reminder')
    {


        //Loop trough the given audit
        foreach ($audits as $audit) {

            switch ($type) {

                case 'rejected':
                    /**
                     * This email is send as a reminder that the auditor rejected the audit and the deadline is coming near
                     */
                    //Queue the mail
                    \Mail::queue('emails.rejected-reminder', ['audit' => $audit], function ($m) use ($audit) {
                        $m->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));
                        $m->to($audit->member->email)->subject(
                            \Lang::get('email/rejected-reminder.subject', [
                                'date' => KommaHelpers::localize_date($audit->deadline, 'd-m-y')
                            ])
                        );
                    });
                    break;

                case 'first-reminder':
                    /**
                     * This email is send as a reminder that the deadline is coming near
                     *
                     */
                    //Queue the mail
                    \Mail::queue('emails.first-reminder', ['audit' => $audit], function ($m) use ($audit) {
                        $m->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));

                        $m->to($audit->member->email)->subject(
                            \Lang::get('email/first-reminder.subject', [
                                'date' => KommaHelpers::localize_date($audit->deadline, 'd-m-y')
                            ])
                        );
                    });
                    break;
                case 'second-reminder':
                    /**
                     * This email is send as a reminder that the deadline is coming near
                     *
                     */
                    //Queue the mail
                    \Mail::queue('emails.second-reminder', ['audit' => $audit], function ($m) use ($audit) {
                        $m->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));

                        $m->to($audit->member->email)->subject(
                            \Lang::get('email/second-reminder.subject', [
                                'date' => KommaHelpers::localize_date($audit->deadline, 'd-m-y')
                            ])
                        );
                    });
                    break;
            }
        }
    }

    /**
     * Get all the rejected audits, with status open
     * With the given deadline
     *
     * @param Carbon $deadline
     * @return mixed
     */
    public function getRejectedAuditsByDeadline(Carbon $deadline)
    {
        \Log::info($deadline);
        $audits = Audit::where('status', '=', Audit::$open)
            ->where('rejected_count', '!=', 0)
            //Start of the day, is greater than or equals the deadline
            ->where('deadline', '>=', $deadline->toDateTimeString())
            //End of the day, is smaller than the deadline+ 1 day
            ->where('deadline', '<', $deadline->addDay()->toDateTimeString())
            ->get();
        return $audits;
    }


}