applications permissions and notifications major update

master
Константин 2023-09-11 01:03:31 +03:00
parent bb340b7a81
commit abae7d79b7
13 changed files with 204 additions and 8 deletions

View File

@ -0,0 +1,26 @@
<?php
namespace App\Events\Applications;
use App\Models\Applications\Application;
use App\Models\Companies\CompanyMember;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ApplicationExpertChanged {
use Dispatchable, InteractsWithSockets, SerializesModels;
public Application $application;
public ?CompanyMember $previousExpert;
public function __construct(Application $application, ?CompanyMember $previousExpert = null) {
$this->application = $application;
$this->previousExpert = $previousExpert;
}
public function broadcastOn(): PrivateChannel {
return new PrivateChannel('channel-name');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Listeners\Applications;
use App\Events\Applications\ApplicationExpertChanged;
use App\Mail\Applications\NotifyApplicationExpertChanged;
use App\Models\Applications\Application;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
class SendApplicationExpertChangedNotifications {
public function __construct() {
}
public function handle(ApplicationExpertChanged $event) {
if ($v = $event->application->submitter) $this->notify($v, $event->application);
if ($v = $event->application->expert()->first()) $this->notify($v->user, $event->application);
if ($v = $event->previousExpert) $this->notify($v->user, $event->application);
}
public function notify(User $recipient, Application $application) {
try {
Mail::to($recipient->email)->send(new NotifyApplicationExpertChanged($application, $recipient));
} catch (\Exception $exception) {}
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Mail\Applications;
use App\Models\Applications\Application;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class NotifyApplicationExpertChanged extends Mailable implements ShouldQueue {
use Queueable, SerializesModels;
public Application $application;
public User $recipient;
public function __construct(Application $application, User $recipient) {
$this->application = $application;
$this->recipient = $recipient;
}
public function build(): NotifyApplicationExpertChanged {
$expert = $this->application->expert()->first();
$subject = "Назначен эксперт по заявке №{$this->application->number}";
if ($this->recipient->id === ($expert->user->id ?? null)) $subject = "Вы назначены экспертом по заявке №{$this->application->number}";
return $this->subject($subject)->view("mail.applications.expert-changed");
}
}

View File

@ -2,6 +2,7 @@
namespace App\Models\Applications; namespace App\Models\Applications;
use App\Events\Applications\ApplicationExpertChanged;
use App\Events\Applications\ApplicationStatusChanged; use App\Events\Applications\ApplicationStatusChanged;
use App\Models\Companies\CompanyMember; use App\Models\Companies\CompanyMember;
use App\Models\Objects\Field; use App\Models\Objects\Field;
@ -95,6 +96,14 @@ class Application extends Model {
if (!$this->number) $this->update(['number' => self::generateNumber()]); if (!$this->number) $this->update(['number' => self::generateNumber()]);
} }
public function setExpert(CompanyMember $expert) {
if ($this->expert->id !== $expert->id) {
$previousExpert = $this->expert;
$this->update(['expert_id' => $expert->id]);
event(new ApplicationExpertChanged($this, $previousExpert));
}
}
public static function generateNumber($start = 100, $digits = 5): string { public static function generateNumber($start = 100, $digits = 5): string {
$res = intval(static::query()->max('number') ?? $start) + 1; $res = intval(static::query()->max('number') ?? $start) + 1;
while (strlen($res) < $digits) { while (strlen($res) < $digits) {

View File

@ -121,6 +121,7 @@ class User extends Authenticatable {
'super_admin' => $this->isSuperAdmin, 'super_admin' => $this->isSuperAdmin,
'admin' => $this->isAdmin, 'admin' => $this->isAdmin,
'expert' => $this->isExpert, 'expert' => $this->isExpert,
'applications_manager' => $this->isApplicationsManager,
'main_company_member' => $this->isMainCompanyMember 'main_company_member' => $this->isMainCompanyMember
]; ];
} }

View File

@ -53,8 +53,7 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() { public function boot() {
Carbon::setLocale(config('app.locale')); Carbon::setLocale(config('app.locale'));
if ($v = env('MAIL_ALWAYS_TO')) Mail::alwaysTo($v);
if ($this->app->environment('local')) Mail::alwaysTo('test@nirgroup.ru');
Relation::enforceMorphMap([ Relation::enforceMorphMap([
'asset' => Asset::class, 'asset' => Asset::class,

View File

@ -2,10 +2,12 @@
namespace App\Providers; namespace App\Providers;
use App\Events\Applications\ApplicationExpertChanged;
use App\Events\Applications\ApplicationStatusChanged; use App\Events\Applications\ApplicationStatusChanged;
use App\Events\FeedbackSender; use App\Events\FeedbackSender;
use App\Events\PasswordRecovered; use App\Events\PasswordRecovered;
use App\Events\UserRegistered; use App\Events\UserRegistered;
use App\Listeners\Applications\SendApplicationExpertChangedNotifications;
use App\Listeners\Applications\SendApplicationStatusChangedNotifications; use App\Listeners\Applications\SendApplicationStatusChangedNotifications;
use App\Listeners\SendFeedbackMessage; use App\Listeners\SendFeedbackMessage;
use App\Listeners\SendPasswordRecoveredNotification; use App\Listeners\SendPasswordRecoveredNotification;
@ -31,6 +33,9 @@ class EventServiceProvider extends ServiceProvider {
ApplicationStatusChanged::class => [ ApplicationStatusChanged::class => [
SendApplicationStatusChangedNotifications::class SendApplicationStatusChangedNotifications::class
],
ApplicationExpertChanged::class => [
SendApplicationExpertChangedNotifications::class
] ]
]; ];

View File

@ -98,7 +98,11 @@ class ApplicationFilters extends FiltersService {
public function applyPermissionsFilters(Builder $query) { public function applyPermissionsFilters(Builder $query) {
$user = Auth::user(); $user = Auth::user();
if (!$user->isExpert && !$user->isAdmin) $query->where(['submitter_id' => $user->id ?? null]); if (!$user->isApplicationsManager && !$user->isAdmin) $query->where(function($query) use($user) {
$query->where(['submitter_id' => $user->id ?? null])->orWhereHas('expert', function($query) use($user) {
$query->where(['user_id' => $user->id ?? null]);
});
});
} }
} }

View File

@ -5,6 +5,7 @@ namespace App\Services\Forms\Applications;
class ApplicationFormsServices { class ApplicationFormsServices {
public static array $services = [ public static array $services = [
'application' => ApplicationForms::class, 'application' => ApplicationForms::class,
'applicationConclusion' => ConclusionForms::class 'applicationConclusion' => ConclusionForms::class,
'applicationExpert' => ExpertForms::class
]; ];
} }

View File

@ -47,14 +47,18 @@ class ConclusionForms extends FormsService {
public function store(array $data): ?JsonResponse { public function store(array $data): ?JsonResponse {
$application = Application::byUuid($data['application'] ?? null)->firstOrFail(); $application = Application::byUuid($data['application'] ?? null)->firstOrFail();
$model = $application->conclusions()->create(['author_id' => Auth::user()->id, 'message' => $data['message'] ?? null]); $user = Auth::user();
$application->complete(); if (($application->expert->user->id ?? null) === ($user->id ?? null)) {
$model = $application->conclusions()->create(['author_id' => $user->id ?? null , 'message' => $data['message'] ?? null]);
$application->complete();
}
return fractal($model, new ConclusionTransformer())->respond(); return fractal($model, new ConclusionTransformer())->respond();
} }
public function update(string $id, array $data): ?JsonResponse { public function update(string $id, array $data): ?JsonResponse {
$model = Conclusion::byUuid($id)->firstOrFail(); $model = Conclusion::byUuid($id)->firstOrFail();
$model->update(['message' => $data['message'] ?? null]); $user = Auth::user();
if (($model->application->expert->user->id ?? null) === ($user->id ?? null)) $model->update(['message' => $data['message'] ?? null]);
return fractal($model, new ConclusionTransformer())->respond(); return fractal($model, new ConclusionTransformer())->respond();
} }

View File

@ -0,0 +1,69 @@
<?php
namespace App\Services\Forms\Applications;
use App\Models\Applications\Application;
use App\Models\Applications\ApplicationStatus;
use App\Models\Companies\CompanyMember;
use App\Models\Objects\Field;
use App\Models\Objects\FieldType;
use App\Models\Products\Product;
use App\Services\Forms\FormsService;
use App\Transformers\Applications\ApplicationTransformer;
use App\Transformers\Assets\AssetTransformer;
use App\Transformers\Companies\CompanyMemberTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Spatie\Fractal\Fractal;
class ExpertForms extends FormsService {
public array $formTitles = ['create' => 'Назначение эксперта', 'update' => 'Назначение эксперта'];
public function form(?string $id = null, array $data = []): array {
$model = Application::byUuid($id)->first();
return [
'title' => $this->formTitle($model),
'frames' => [
['title' => 'Общие сведения', 'groups' => $this->form1Groups($model)]
]
];
}
public function form1Groups(?Application $model): array {
$groups = [
['name' => 'common', 'title' => '', 'fields' => $this->commonGroupFields($model)]
];
return ['data' => $groups];
}
public function commonGroupFields(?Application $model): array {
$fields = [
[
'name' => 'expert',
'title' => 'Эксперт',
'type' => FieldType::RELATION,
'required' => true,
'options' => $this->getExperts(),
'value' => ($v = $model->expert ?? null) ? fractal($v, new CompanyMemberTransformer()) : null
]
];
return ['data' => $fields];
}
public function getExperts(): Fractal {
return fractal(CompanyMember::query()->mainCompany()->whereHas('objects', function($query) {
Field::applyFilters($query, collect(['types' => 'company-member-properties', 'moderate-permissions' => 'applications']));
})->get(), new CompanyMemberTransformer());
}
public function store(array $data) {
}
public function update(string $id, array $data): ?JsonResponse {
$model = Application::byUuid($id)->firstOrFail();
if ($expert = CompanyMember::byUuid($data['expert'] ?? null)->first()) $model->setExpert($expert);
return fractal($model, new ApplicationTransformer())->respond();
}
}

View File

@ -0,0 +1,18 @@
@extends('mail.layouts.layout')
@php
$expert = $application->expert()->first();
@endphp
@section('content')
@if(($expert->user->id ?? null) === ($recipient->id ?? null))
<p>Вы назначены экспертом по заявке {{$application->number}} от {{$application->created_at->format('d.m.Y')}}</p>
<p><b>Заявитель</b>: {{$application->applicant ?? 'не указано'}}</p>
<p><b>Наименование продукции</b>: {{$application->product->name ?? 'не указано'}}</p>
<p><b>Назначение продукции</b>: {{$application->product->purpose ?? 'не указано'}}</p>
@else
<p>Назначен эксперт по заявке {{$application->number}} от {{$application->created_at->format('d.m.Y')}}</p>
<p><b>Эксперт</b>: {{$application->expert->user->name ?? ''}}. {{$application->expert->position ?? ''}}</p>
@endif
<p><a href="{{url('/applications')}}">Перейти к журналу заявок</a></p>
@endsection

View File

@ -9,6 +9,8 @@
@elseif($status === \App\Models\Applications\ApplicationStatus::COMPLETED) @elseif($status === \App\Models\Applications\ApplicationStatus::COMPLETED)
<p><b>{{$application->title}} выполнена.</b></p> <p><b>{{$application->title}} выполнена.</b></p>
<p><b>Эксперт</b>: {{$application->conclusion->author->name ?? 'не указан'}}</p> <p><b>Эксперт</b>: {{$application->conclusion->author->name ?? 'не указан'}}</p>
<p><b>Мнение эксперта</b>: {{$application->conclusion->message ?? 'не указано'}}</p> <p><b>Мнение эксперта</b>:</p>
{!! $application->conclusion->message ?? 'не указано' !!}
@endif @endif
<p><a href="{{url('/applications')}}">Перейти к журналу заявок</a></p>
@endsection @endsection