'tag_task'] ]; protected $fillable_relations = [ 'tags' ]; protected $casts = [ 'work_start' => 'datetime:Y-m-d H:i', 'work_finish' => 'datetime:Y-m-d H:i', 'watchers' => 'array', ]; public function rules() { // dd(\request('_business_info')['info']['workflows']->toArray()); $validations = [ 'assignee_id' => ['nullable', 'numeric', function ($attribute, $value, $fail) { //check assignee at least guest in project if (!can('isProjectGuest', ['project_id' => request()->route('project'), 'user_id' => $value])) { $fail('The selected '.$attribute.' is invalid.'); } if (request()->method() === 'PUT' && ($this->assignee_id != $value && Work::where('task_id', $this->id)->exists())) { //when update execute //check if change assignee then should be on task not work set $fail('The selected '.$attribute.' is invalid.'); } }], 'system_id' => ['nullable', 'numeric', Rule::in(\request('_business_info')['info']['projects'][request()->route('project')]['systems'])], 'sprint_id' => ['nullable', 'numeric', Rule::in(\request('_business_info')['info']['projects'][request()->route('project')]['sprints'])], 'workflow_id' => ['required', 'numeric', Rule::in(array_keys(\request('_business_info')['info']['workflows']->toArray()))], 'status_id' => 'required|numeric', 'approver_id' => ['nullable', 'numeric', function ($attribute, $value, $fail) { //check approval at least colleague in project if (!can('isProjectColleague', ['project_id' => request()->route('project'), 'user_id' => $value])) { $fail('The selected '.$attribute.' is invalid.'); } }], 'title' => 'required|string|min:3|max:254', 'description' => 'nullable|string|min:2|max:1000', 'priority' => 'nullable|numeric|between:1,10', 'estimated_time' => 'bail|nullable|numeric', 'due_date' => 'bail|nullable|date|date_format:Y-m-d|after_or_equal:'. ((request()->method() === 'POST') ? date('yy-m-d') : $this->created_at->toDateString()), 'tags' => 'nullable|array', 'tags.*' => [new RequiredIf(isset($request->tags)), 'numeric', Rule::in(\request('_business_info')['info']['tags'])], ] ; $workflow_id = $this->workflow_id; if (request()->filled('workflow_id') && isset(request('_business_info')['info']['workflows'][request()->workflow_id])) { $workflow_id = request()->workflow_id; } if (isset($workflow_id)) { $validations['status_id'] = ['bail', 'required', 'numeric', //check status exists in status list Rule::in(\request('_business_info')['info']['workflows'][$workflow_id]['statuses']), function ($attribute, $value, $fail) use ($workflow_id) { //check not close or done $state = \request('_business_info')['workflows'][$workflow_id]['statuses'][$value]['state']; if (request()->method() == 'POST' && ($state == enum('status.states.close.id') || $state == enum('status.states.done.id'))) { $fail('The selected '.$attribute.' is invalid.'); } if ((request()->method() == 'PUT') && !can('projectTasks', ['project_id' => request()->route('project')]) && $state != enum('status.states.active.id')) { $fail('The selected '.$attribute.' is invalid.'); } }]; } return $validations; } public function updateRelations() { // tags relations $this->dirties['tags'] = $this->tags()->sync($this->filled_relations['tags']); //old code // if (!empty($this->filled_relations['tags'])) { // $this->dirties['tags'] = $this->tags()->sync($this->filled_relations['tags']); // } } public function getValueOf(?string $key) { $values = [ 'business_id' => $this->business_id, 'project_id' => $this->project_id, 'sprint_id' => $this->sprint_id, 'workflow_id' => $this->workflow_id, 'status_id' => $this->status_id, 'system_id' => $this->system_id, 'task_id' => $this->id, 'subject_id' => $this->id, 'user_id' => $this->assignee_id, ]; if ($key && isset($values, $key)) { return $values[$key]; } return $values; } public function business() { return $this->belongsTo(Business::class, 'business_id', 'id', __FUNCTION__); } public function creator() { return $this->belongsTo(User::class, 'creator_id', 'id', __FUNCTION__); } public function user() { return $this->belongsTo(User::class, 'user_id', 'id', __FUNCTION__); } public function project() { return $this->belongsTo(Project::class, 'project_id', 'id', __FUNCTION__); } public function tags() { return $this->belongsToMany(Tag::class)->using(ReportableRelation::class); } // Todo: are we need this relation???? public function tagTask() { return $this->hasMany(TagTask::class, 'task_id', 'id'); } public function works() { return $this->hasMany(Work::class, 'task_id', 'id'); } public function comments() { return $this->hasMany(Comment::class, 'task_id', 'id'); } public function scopePriorityMin($query, $min) { return $query->where('tasks.priority', '>=', $min); } public function scopePriorityMax($query, $max) { return $query->where('tasks.priority', '<=', $max); } public function scopeCreatesBefore($query, $date) { //ToDo: comment lines have better performance but should be test // return $query->whereDate('tasks.created_at', '<=', Carbon::parse($date.' 23:59:59')); // return $query->where('tasks.created_at', '<', (new DateTime('2014-07-10'))->modify('+1 day')->format('Y-m-d')); return $query->whereDate('tasks.created_at', '<=', Carbon::parse($date)); } public function scopeCreatesAfter($query, $date) { return $query->whereDate('tasks.created_at', '>=', Carbon::parse($date)); } public function scopeCreatesIn($query, $days) { return $query->whereDate('tasks.created_at', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeUpdatesBefore($query, $date) { return $query->whereDate('tasks.updated_at', '<=', Carbon::parse($date)); } public function scopeUpdatesAfter($query, $date) { return $query->whereDate('tasks.updated_at', '>=', Carbon::parse($date)); } public function scopeUpdatesIn($query, $days) { return $query->whereDate('tasks.updated_at', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeSpentFrom($query, $minute) { return $query->where('tasks.spent_time', '>=', $minute); } public function scopeSpentTo($query, $minute) { return $query->where('tasks.spent_time', '<=', $minute); } public function scopeEstimatedFrom($query, $minute) { return $query->where('tasks.estimated_time', '>=', $minute); } public function scopeEstimatedTo($query, $minute) { return $query->where('tasks.estimated_time', '<=', $minute); } public function scopeStartsBefore($query, $date) { return $query->whereDate('tasks.work_start', '<=', Carbon::parse($date)); } public function scopeStartsAfter($query, $date) { return $query->whereDate('tasks.work_start', '>=', Carbon::parse($date)); } public function scopeStartsIn($query, $days) { return $query->whereDate('tasks.work_start', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeFinishBefore($query, $date) { return $query->whereDate('tasks.work_finish', '<=', Carbon::parse($date)); } public function scopeFinishAfter($query, $date) { return $query->whereDate('tasks.work_finish', '>=', Carbon::parse($date)); } public function scopeFinishIn($query, $days) { return $query->whereDate('tasks.work_finish', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeCompletesBefore($query, $date) { return $query->where('tasks.completed_at', '<=', $date); } public function scopeCompletesAfter($query, $date) { return $query->where('tasks.completed_at', '>=', $date); } public function scopeCompletesIn($query, $days) { return $query->whereDate('tasks.completed_at', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeDueDateBefore($query, $date) { return $query->where('tasks.due_date', '<=', $date); } public function scopeDueDateAfter($query, $date) { return $query->where('tasks.due_date', '>=', $date); } public function scopeDueDateIn($query, $days) { return $query->whereDate('tasks.due_date', '>=', Carbon::now()->modify('-'.$days.' day')->toDate()); } public function scopeOverSpentFrom($query, $minute) { return $query->whereColumn('spent_time', '>', 'estimated_time') ->having('over_spent', '>=', $minute); } public function scopeOverSpentTo($query, $minute) { return $query->whereColumn('spent_time', '>', 'estimated_time') ->having('over_spent', '<=', $minute); } public function scopeMyWatching($query) { return $query->whereJsonContains('watchers', auth()->id()); } public function scopeOverDue($query) { return $query->whereColumn('due_date', '<', 'completed_at'); } public function scopeReport($query, $group_field) { return $query->select(DB::raw($group_field.' , status_id, COUNT(*) as total, SUM(spent_time) as spent_sum, SUM(estimated_time) as estimated_sum,SUM(ready_to_test) as test_sum, COUNT(completed_at) as completed_total, SUM(on_time) as on_time_total, SUM(Case When spent_time > estimated_time Then (spent_time - estimated_time) Else 0 End) as over_spent_sum, SUM(Case When (spent_time <= estimated_time) And (completed_at) Then (estimated_time - spent_time) Else 0 End) as under_spent_sum')) ->groupBy($group_field, 'status_id'); } }