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;
}
}