From 9f0f5cee3e84af3551034898c475f28913d7d12b Mon Sep 17 00:00:00 2001 From: panabonic Date: Mon, 24 Jul 2023 22:15:52 +0300 Subject: [PATCH 1/2] registries and registry filters --- .../Api/Registries/EntriesController.php | 8 +- app/Models/Objects/Field.php | 6 +- app/Models/Objects/NirObject.php | 5 + app/Models/Registries/Entry.php | 54 +++++++- app/Models/Registries/RegistryType.php | 23 +++- .../Filters/Registries/EntryFilters.php | 78 ++++++++++-- .../Forms/Registries/OperationForms.php | 2 + .../Dictionaries/DictionariesTableSeeder.php | 8 ++ .../seeders/Objects/FieldsTableSeeder.php | 119 ++++++++++++++++-- .../Objects/ObjectTypeFieldsTableSeeder.php | 31 +++-- .../Objects/ObjectTypesTableSeeder.php | 15 +++ database/seeders/Pages/PagesTableSeeder.php | 12 +- 12 files changed, 310 insertions(+), 51 deletions(-) diff --git a/app/Http/Controllers/Api/Registries/EntriesController.php b/app/Http/Controllers/Api/Registries/EntriesController.php index d52d097..f872b1c 100644 --- a/app/Http/Controllers/Api/Registries/EntriesController.php +++ b/app/Http/Controllers/Api/Registries/EntriesController.php @@ -20,10 +20,10 @@ class EntriesController extends Controller { public function index(Request $request): JsonResponse { $filters = collect($request->has('filters') ? json_decode($request->get('filters'), true) : [])->filter(function($val) {return $val;}); - $registry = Registry::byUuid($request->get('registry'))->first(); - $category = Category::byUuid($request->get('category'))->first(); - $query = $this->model->query()->where(['registry_id' => $registry->id ?? 0]); - if ($filters->isEmpty()) $query->where(['category_id' => $category->id ?? 0]); + //$registry = Registry::byUuid($request->get('registry'))->first(); + //$category = Category::byUuid($request->get('category'))->first(); + $query = $this->model->query(); + //if ($filters->except('registry')->isEmpty()) $query->where(['category_id' => $category->id ?? 0]); $service = FiltersService::getService('registryEntries'); $service->applyFilters($query, $filters); $paginator = $query->paginate(config('app.pagination_limit')); diff --git a/app/Models/Objects/Field.php b/app/Models/Objects/Field.php index 47f9126..56f1186 100644 --- a/app/Models/Objects/Field.php +++ b/app/Models/Objects/Field.php @@ -178,9 +178,9 @@ class Field extends Model { public function applyOrder(Builder $query, $dir) { if ($table = FieldType::TABLES[$this->type] ?? null) { - $query->leftJoin("{$table} as {$this->name}", function(JoinClause $join) use($table) { - $join->on('objects.id', '=', "{$this->name}.object_id"); - })->where(["{$this->name}.field_id" => $this->id])->orderBy("{$this->name}.value", $dir); + $query->leftJoin("{$table} as prop-{$this->name}", function(JoinClause $join) use($table) { + $join->on('objects.id', '=', "prop-{$this->name}.object_id"); + })->where(["prop-{$this->name}.field_id" => $this->id])->orderBy("prop-{$this->name}.value", $dir); } } diff --git a/app/Models/Objects/NirObject.php b/app/Models/Objects/NirObject.php index ec3044d..9c443fd 100644 --- a/app/Models/Objects/NirObject.php +++ b/app/Models/Objects/NirObject.php @@ -11,6 +11,7 @@ use App\Models\Objects\Values\IntegerValue; use App\Models\Objects\Values\RelationValue; use App\Models\Objects\Values\StringValue; use App\Models\Objects\Values\TextValue; +use App\Models\Registries\Entry; use App\Models\User; use App\Support\UuidScopeTrait; use Illuminate\Database\Eloquent\Builder; @@ -41,6 +42,10 @@ class NirObject extends Model { ]; + public function entries(): MorphToMany { + return $this->morphedByMany(Entry::class, 'objectable'); + } + public function objects(): MorphToMany { return $this->morphToMany(NirObject::class, 'objectable'); } diff --git a/app/Models/Registries/Entry.php b/app/Models/Registries/Entry.php index d7722ca..8c8c542 100644 --- a/app/Models/Registries/Entry.php +++ b/app/Models/Registries/Entry.php @@ -6,6 +6,7 @@ use App\Models\Asset; use App\Support\HasObjectsTrait; use App\Support\RelationValuesTrait; use App\Support\UuidScopeTrait; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphToMany; @@ -56,10 +57,54 @@ class Entry extends Model { } public function operations(): MorphToMany { - return $this->objectsByGroup('operations')->reorder()->applyOrders(['order-date' => 'desc']); + return $this->objectsByGroup('operations'); } + public function scopeByStates($query, $states) { + $query->where(function($query) use($states) { + collect($states)->each(function($state) use($query) { + $query->orWhere(function($query) use($state) { + $query->$state(); + }); + }); + }); + } + + public function scopeAwaiting($query) { + $query->where('active_since', '>', now()); + } + public function scopeActive($query) { + $query->where('active_since', '<=', now())->where(function($query) { + $query->whereNull('active_till')->orWhere('active_till', '>', now()); + })->notCancelled()->notSuspended(); + } + public function scopeExpired($query) { + $query->where('active_till', '<=', now()); + } + public function scopeSuspended($query) { + $query->where('suspended_since', '<=', now())->where(function($query) { + $query->whereNull('suspended_till')->orWhere('suspended_till', '>', now()); + })->notCancelled(); + } + public function scopeNotSuspended($query) { + $query->where(function($query) { + $query->whereNull('suspended_since')->orWhere('suspended_since', '>', now()); + })->where(function($query) { + $query->whereNull('suspended_till')->orWhere('suspended_till', '<', now()); + }); + } + public function scopeCancelled($query) { + $query->where('cancelled_at', '<=', now()); + } + public function scopeNotCancelled($query) { + $query->where(function($query) { + $query->whereNull('cancelled_at')->orWhere('cancelled_at', '>', now()); + }); + } + + + public function getPropertiesAttribute(): ?Model { return ($type = $this->registry->parsedType['options']['properties'] ?? null) ? $this->getObject($type, 'properties') : null; } @@ -76,5 +121,12 @@ class Entry extends Model { } + public function sortOperations() { + $this->operations()->reorder()->applyOrders(['order-date' => 'desc'])->get()->each(function($operation, $ord) { + $this->objects()->updateExistingPivot($operation, ['ord' => $ord]); + }); + } + + } diff --git a/app/Models/Registries/RegistryType.php b/app/Models/Registries/RegistryType.php index 45fb8d0..ba07e76 100644 --- a/app/Models/Registries/RegistryType.php +++ b/app/Models/Registries/RegistryType.php @@ -4,11 +4,17 @@ namespace App\Models\Registries; class RegistryType { public const SIMPLE = 'simple'; + public const CATEGORIZED = 'categorized'; public const RULESET = 'ruleset'; public const LABORATORIES = 'laboratories'; public const CERTIFIERS = 'certifiers'; public const EXPERTS = 'experts'; public const CERTIFICATES = 'certificates'; + public const COMPANIES = 'companies'; + public const DEVELOPMENTS = 'developments'; + public const DISCUSSIONS = 'discussions'; + public const RESEARCHES = 'researches'; + public const TECHNICAL_CERTIFICATES = 'technical-certificates'; public const TITLES = [ self::SIMPLE => 'Простой реестр', @@ -16,15 +22,26 @@ class RegistryType { self::LABORATORIES => 'Реестр испытательных лабораторий', self::CERTIFIERS => 'Реестр органов по сертификации', self::EXPERTS => 'Реестр экспертов', - self::CERTIFICATES => 'Реестр сертификатов соответствия' + self::CERTIFICATES => 'Реестр сертификатов соответствия', + self::COMPANIES => 'Реестр организаций', + self::DEVELOPMENTS => 'Реестр планов разработки', + self::DISCUSSIONS => 'Реестр публичных обсуждений', + self::RESEARCHES => 'Реестр исследований', + self::TECHNICAL_CERTIFICATES => 'Реестр технических свидетельств' ]; public const OPTIONS = [ self::SIMPLE => [], + self::CATEGORIZED => ['categories' => true], self::RULESET => ['categories' => true, 'operations' => 'entry-operation-ruleset', 'states' => true], self::LABORATORIES => ['properties' => 'entry-properties-laboratory', 'states' => true], self::CERTIFIERS => ['properties' => 'entry-properties-certifier', 'states' => true], - self::EXPERTS => ['categories' => true, 'properties' => 'entry-properties-expert', 'states' => true], - self::CERTIFICATES => ['categories' => true, 'properties' => 'entry-properties-certificate', 'states' => true] + self::EXPERTS => ['categories' => true, 'states' => true], + self::CERTIFICATES => ['categories' => true, 'properties' => 'entry-properties-certificate', 'states' => true], + self::COMPANIES => ['properties' => 'entry-properties-company'], + self::DEVELOPMENTS => ['categorized' => true, 'properties' => 'entry-properties-development'], + self::DISCUSSIONS => ['properties' => 'entry-properties-discussion'], + self::RESEARCHES => ['categories' => true, 'properties' => 'entry-properties-research'], + self::TECHNICAL_CERTIFICATES => ['properties' => 'entry-properties-technical-certificate', 'states' => true] ]; } \ No newline at end of file diff --git a/app/Services/Filters/Registries/EntryFilters.php b/app/Services/Filters/Registries/EntryFilters.php index f1ae739..c6c79b9 100644 --- a/app/Services/Filters/Registries/EntryFilters.php +++ b/app/Services/Filters/Registries/EntryFilters.php @@ -3,17 +3,30 @@ namespace App\Services\Filters\Registries; use App\Models\Dictionaries\Dictionary; -use App\Models\Dictionaries\DictionaryItem; +use App\Models\Objects\Field; use App\Models\Objects\FieldType; +use App\Models\Objects\ObjectType; +use App\Models\Registries\Category; use App\Models\Registries\Entry; +use App\Models\Registries\EntryState; +use App\Models\Registries\Registry; use App\Services\Filters\FiltersService; use App\Transformers\Dictionaries\DictionaryItemTransformer; +use App\Transformers\Objects\FieldTransformer; +use App\Transformers\Objects\ObjectTypeTransformer; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Spatie\Fractal\Fractal; class EntryFilters extends FiltersService { + public string $objectRelationName = 'entries'; + public function get(Collection $filters): array { + $registry = Registry::byUuid($filters->get('registry'))->firstOrFail(); + $types = []; + if ($v = ObjectType::byName($registry->options['operations'] ?? null)->first()) $types[] = $v->uuid; + if ($v = ObjectType::byName($registry->options['properties'] ?? null)->first()) $types[] = $v->uuid; + if ($types) $filters->put('types', $types); $groups = [ [ 'name' => 'common', @@ -21,29 +34,43 @@ class EntryFilters extends FiltersService { 'fields' => $this->nativeFields($filters) ] ]; + if ($types) $groups[] = ['name' => 'properties', 'title' => 'Дополнительные характеристики', 'fields' => $this->objectFields($filters)]; + //if ($v = $registry->options['properties'] ?? null) $groups[] = ['name' => 'properties', 'title' => 'Особые характеристики', 'fields' => $this->propertiesFields($v, $filters)]; $query = Entry::query(); - $this->applyFilters($query, $filters); + $this->applyFilters($query, $filters->put('fake', 'zzz')); return ['groups' => ['data' => $groups], 'total' => $query->count()]; } public function nativeFields(Collection $filters): array { return [ [ - 'name' => 'listings', - 'title' => 'Вхождение в перечень ПП', + 'name' => 'registry', + 'title' => 'Реестр', + 'type' => FieldType::STRING, + 'hidden' => true, + 'value' => $filters->get('registry') + ], + [ + 'name' => 'types', + 'title' => 'Типы связанных объектов', 'type' => FieldType::RELATION, - 'represented' => $this->getListings($filters), - 'value' => ($val = $filters->get('listings')) ? fractal(DictionaryItem::byUuids($val)->get(), new DictionaryItemTransformer()) : null - ] + 'hidden' => true, + 'value' => $filters->get('types') ? fractal(ObjectType::whereIn('uuid', $filters->get('types'))->get(), new ObjectTypeTransformer()) : null + ], + [ + 'name' => 'state', + 'title' => 'Статус', + 'type' => FieldType::RELATION, + 'represented' => $this->getRelationItems(EntryState::TITLES), + 'value' => $this->getRelationValue($filters->get('state'), EntryState::TITLES) + ], ]; } - public function operationsFields(Collection $filters): array { - return []; - } - - public function propertiesFilters(Collection $filters): array { - return []; + public function objectFields(Collection $filters): array { + return fractal(Field::query()->whereHas('groups.objectType', function($query) use($filters) { + $query->whereIn('uuid', $filters->get('types') ?? []); + })->whereIn('type', [FieldType::RELATION, FieldType::DATE, FieldType::STRING])->get(), new FieldTransformer($filters->all(), $this))->toArray(); } @@ -53,7 +80,9 @@ class EntryFilters extends FiltersService { public function applyFilters(Builder $query, Collection $filters) { + $this->applyCategoryFilter($query, $filters); $this->applyNativeFilters($query, $filters); + $this->applyObjectFilters($query, $filters); $this->applyPermissionsFilters($query); } @@ -66,14 +95,37 @@ class EntryFilters extends FiltersService { public function applyNativeFilter(Builder $query, $prop, $value) { if ($value) { if ($prop === 'search') $this->applySearchFilter($query, $value, ['name', 'number']); + elseif ($prop === 'registry') $this->applyRelationFilter($query, 'registry', $value); + elseif ($prop === 'state') $query->byStates($value); } } + public function applyObjectFilters(Builder $query, Collection $filters) { + if ($filters->get('types') && !$this->isFiltersEmpty($filters, true)) $query->whereHas('objects', function($query) use($filters) { + Field::applyFilters($query, $filters); + }); + } + + + + public function applyCategoryFilter(Builder $query, Collection $filters) { + if ($this->isFiltersEmpty($filters)) $query->where(['category_id' => Category::byUuid($filters->get('category'))->first()->id ?? 0]); + } + public function applyPermissionsFilters(Builder $query) { } + public function isFiltersEmpty(Collection $filters, $exceptNative = false): bool { + if ($exceptNative) $filters = $filters->filter(function($val, $prop) { + return Field::byName($prop)->exists(); + }); + return $filters->except('registry', 'category', 'types', 'state')->filter(function($val) { + return collect($val)->filter(function($val) {return $val;})->isNotEmpty(); + })->isEmpty(); + } + } diff --git a/app/Services/Forms/Registries/OperationForms.php b/app/Services/Forms/Registries/OperationForms.php index 69fc5f3..d3edad5 100644 --- a/app/Services/Forms/Registries/OperationForms.php +++ b/app/Services/Forms/Registries/OperationForms.php @@ -35,12 +35,14 @@ class OperationForms extends FormsService { $entry = Entry::byUuid($data['entry'] ?? null)->firstOrFail(); $model = $entry->createObject($entry->registry->options['operations'] ?? null, null, 'operations'); $model->setValues($data); + $entry->sortOperations(); return fractal($model, new ObjectTransformer())->respond(); } public function update(string $id, array $data): ?JsonResponse { $model = NirObject::byUuid($id)->firstOrFail(); $model->setValues($data); + $model->entries()->first()->sortOperations(); return fractal($model->fresh(), new ObjectTransformer())->respond(); } } diff --git a/database/seeders/Dictionaries/DictionariesTableSeeder.php b/database/seeders/Dictionaries/DictionariesTableSeeder.php index c094979..bd1a5f2 100644 --- a/database/seeders/Dictionaries/DictionariesTableSeeder.php +++ b/database/seeders/Dictionaries/DictionariesTableSeeder.php @@ -32,6 +32,14 @@ class DictionariesTableSeeder extends Seeder { 'listings' => [ 'title' => 'Перечни ПП', 'items' => ['pp1521' => 'ПП №1521 от 26.12.2014 г.', 'pp985' => 'ПП № 985 от 04.07.2020 г.', 'pp815' => 'ПП № 815 от 28.05.2021 г.'] + ], + 'activities' => [ + 'title' => 'Направления деятельности', + 'items' => ['products' => 'Продукция', 'services' => 'Работы и услуги', 'management' => 'СМК'] + ], + 'research-types' => [ + 'title' => 'Виды исследовательских работ', + 'items' => ['nir' => 'НИР', 'niokr' => 'НИОКР'] ] ]; diff --git a/database/seeders/Objects/FieldsTableSeeder.php b/database/seeders/Objects/FieldsTableSeeder.php index a558c06..4433651 100644 --- a/database/seeders/Objects/FieldsTableSeeder.php +++ b/database/seeders/Objects/FieldsTableSeeder.php @@ -169,25 +169,122 @@ class FieldsTableSeeder extends Seeder { 'required' => true, ], - 'laboratory-name' => [ - 'title' => 'Наименование лаборатории', + 'company-name' => [ + 'title' => 'Наименование организации', 'type' => FieldType::STRING, 'required' => true ], - 'certifier-name' => [ - 'title' => 'Наименование органа по сертификации', + 'activities' => [ + 'title' => 'Виды деятельности', + 'type' => FieldType::RELATION, + 'required' => true, + 'multiple' => true, + 'params' => [ + 'related' => DictionaryItem::class, 'transformer' => DictionaryItemTransformer::class, + 'options' => ['show' => true, 'whereHas' => ['dictionary' => ['name' => 'activities']]], + ] + ], + + 'applicant-name' => [ + 'title' => 'Заявитель', 'type' => FieldType::STRING, 'required' => true ], - 'expert-name' => [ - 'title' => 'ФИО эксперта', - 'type' => FieldType::STRING, + 'applicant-address' => [ + 'title' => 'Адрес заявителя', + 'type' => FieldType::STRING + ], + 'applicant-email' => [ + 'title' => 'Электронная почта заявителя', + 'type' => FieldType::STRING + ], + 'applicant-phone' => [ + 'title' => 'Телефон заявителя', + 'type' => FieldType::STRING + ], + 'producer-name' => [ + 'title' => 'Производитель', + 'type' => FieldType::STRING + ], + 'producer-address' => [ + 'title' => 'Адрес производителя', + 'type' => FieldType::STRING + ], + 'producer-email' => [ + 'title' => 'Электронная почта производителя', + 'type' => FieldType::STRING + ], + 'producer-phone' => [ + 'title' => 'Телефон производителя', + 'type' => FieldType::STRING + ], + + 'company-address' => [ + 'title' => 'Адрес', + 'type' => FieldType::STRING + ], + 'company-site' => [ + 'title' => 'Сайт', + 'type' => FieldType::STRING + ], + 'company-email' => [ + 'title' => 'Электронная почта', + 'type' => FieldType::STRING + ], + 'company-phone' => [ + 'title' => 'Телефон', + 'type' => FieldType::STRING + ], + + 'primary-developer' => [ + 'title'=> 'Основной исполнитель', + 'type' => FieldType::STRING + ], + 'funding-source' => [ + 'title' => 'Источник финансирования', + 'type' => FieldType::STRING + ], + 'plan-year' => [ + 'title' => 'Год плана', + 'type' => FieldType::INTEGER + ], + + 'discussion-start-date' => [ + 'title' => 'Дата начала обсуждения', + 'type' => FieldType::DATE + ], + 'discussion-finish-date' => [ + 'title' => 'Дата окончания обсуждения', + 'type' => FieldType::DATE + ], + + 'research-type' => [ + 'title' => 'Вид работы', + 'type' => FieldType::RELATION, + 'required' => true, + 'params' => [ + 'appearance' => 'radio', + 'related' => DictionaryItem::class, 'transformer' => DictionaryItemTransformer::class, + 'options' => ['show' => true, 'whereHas' => ['dictionary' => ['name' => 'research-types']]] + ] + ], + 'research-objective' => [ + 'title' => 'Цель исследования', + 'type' => FieldType::TEXT + ], + + 'technical-conclusion' => [ + 'title' => 'Техническое заключение', + 'type' => FieldType::DOCUMENT, 'required' => true ], - 'certificate-number' => [ - 'title' => 'Номер сертификата', - 'type' => FieldType::STRING, - 'required' => true + 'developer-name' => [ + 'title' => 'Разработчик', + 'type' => FieldType::STRING + ], + 'developer-address' => [ + 'title' => 'Адрес разработчика', + 'type' => FieldType::STRING ], 'operation-type' => [ diff --git a/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php b/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php index b9ba854..6ba6242 100644 --- a/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php +++ b/database/seeders/Objects/ObjectTypeFieldsTableSeeder.php @@ -77,23 +77,34 @@ class ObjectTypeFieldsTableSeeder extends Seeder { ], 'entry-properties-laboratory' => [ - 'common' => [ - 'fields' => ['laboratory-name'] - ] + 'common' => ['fields' => ['company-name', 'activities']] ], 'entry-properties-certifier' => [ - 'common' => [ - 'fields' => ['certifier-name'] - ] + 'common' => ['fields' => ['company-name', 'activities']] ], 'entry-properties-expert' => [ - 'common' => [ - 'fields' => ['expert-name'] - ] + 'common' => ['fields' => []] ], 'entry-properties-certificate' => [ 'common' => [ - 'fields' => ['certificate-number'] + 'fields' => ['applicant-name', 'applicant-address', 'applicant-email', 'applicant-phone', 'producer-name', 'producer-address', 'producer-email', 'producer-phone'] + ] + ], + 'entry-properties-company' => [ + 'common' => ['fields' => ['company-address', 'company-email', 'company-phone']] + ], + 'entry-properties-development' => [ + 'common' => ['fields' => ['operation-type', 'primary-developer', 'funding-source', 'plan-year']] + ], + 'entry-properties-discussion' => [ + 'common' => ['fields' => ['discussion-start-date', 'discussion-finish-date', 'funding-source']] + ], + 'entry-properties-research' => [ + 'common' => ['fields' => ['research-type', 'research-objective', 'plan-year']] + ], + 'entry-properties-technical-certificate' => [ + 'common' => [ + 'fields' => ['technical-conclusion', 'developer-name', 'developer-address', 'company-site', 'company-email', 'company-phone', 'producer-name', 'producer-address'] ] ], diff --git a/database/seeders/Objects/ObjectTypesTableSeeder.php b/database/seeders/Objects/ObjectTypesTableSeeder.php index 42eb712..bab991d 100644 --- a/database/seeders/Objects/ObjectTypesTableSeeder.php +++ b/database/seeders/Objects/ObjectTypesTableSeeder.php @@ -73,6 +73,21 @@ class ObjectTypesTableSeeder extends Seeder { ], 'entry-properties-certificate' => [ 'title' => 'Сертификат соответствия' + ], + 'entry-properties-company' => [ + 'title' => 'Организация' + ], + 'entry-properties-development' => [ + 'title' => 'Разработка' + ], + 'entry-properties-discussion' => [ + 'title' => 'Обсуждение' + ], + 'entry-properties-research' => [ + 'title' => 'Исследование' + ], + 'entry-properties-technical-certificate' => [ + 'title' => 'Техническое свидетельство' ] ] ], diff --git a/database/seeders/Pages/PagesTableSeeder.php b/database/seeders/Pages/PagesTableSeeder.php index f2a1a7f..bea3911 100644 --- a/database/seeders/Pages/PagesTableSeeder.php +++ b/database/seeders/Pages/PagesTableSeeder.php @@ -37,8 +37,8 @@ class PagesTableSeeder extends Seeder 'Закупки' => [], 'Противодействие коррупции' => [ 'children' => [ - 'ФЗ, указы, постановления' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], - 'Ведомственные нормативные правовые акты' => [], + 'ФЗ, указы, постановления' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CATEGORIZED], + 'Ведомственные нормативные правовые акты' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], 'Внутренние нормативные документы' => [], 'Антикоррупционная экспертиза' => [], 'Методические материалы' => [], @@ -56,15 +56,15 @@ class PagesTableSeeder extends Seeder 'Нормирование и стандартизация' => [ 'children' => [ 'Реестр сводов правил' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::RULESET], - 'Разработка сводов правил' => [], - 'Прикладные исследования' => [], + 'Разработка сводов правил' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::DEVELOPMENTS], + 'Прикладные исследования' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::RESEARCHES], 'Реестр нормативно-технической документации' => [], 'Методические материалы' => [], ] ], 'Оценка пригодности' => [ 'children' => [ - 'Реестр технических свидетельств' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], + 'Реестр технических свидетельств' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::TECHNICAL_CERTIFICATES], 'Заявка на оформление' => [], 'Предварительная заявка' => [], ] @@ -75,7 +75,7 @@ class PagesTableSeeder extends Seeder 'Секретариат' => [], 'Структура' => [], 'Состав' => [], - 'Документы' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], + 'Документы' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CATEGORIZED], 'АИС ТК 465 «Строительство»' => [], ] ], From 4d7e3a558300fb08337dfdb949d305db453a2e52 Mon Sep 17 00:00:00 2001 From: panabonic Date: Mon, 31 Jul 2023 12:39:47 +0300 Subject: [PATCH 2/2] companies and advisories modules added --- .../Api/Advisories/AdvisoriesController.php | 72 ++++++ .../AdvisoryCompaniesController.php | 43 ++++ .../Advisories/AdvisoryMembersController.php | 42 ++++ .../Api/Assets/UploadFileController.php | 6 + .../Api/Companies/CompaniesController.php | 81 +++++++ .../Api/Companies/DepartmentsController.php | 39 ++++ .../Api/Companies/MembersController.php | 70 ++++++ app/Models/Advisories/Advisory.php | 162 +++++++++++++ app/Models/Advisories/AdvisoryCompany.php | 68 ++++++ app/Models/Advisories/AdvisoryMember.php | 61 +++++ app/Models/Advisories/AdvisoryMemberRank.php | 39 ++++ app/Models/Advisories/AdvisoryType.php | 13 ++ app/Models/Companies/Address.php | 57 +++++ app/Models/Companies/BankDetails.php | 38 +++ app/Models/Companies/Company.php | 220 ++++++++++++++++++ app/Models/Companies/CompanyMember.php | 115 +++++++++ app/Models/Companies/CompanyMemberRank.php | 21 ++ app/Models/Companies/CompanyMemberRole.php | 15 ++ app/Models/Companies/CompanyType.php | 38 +++ app/Models/Companies/Contact.php | 33 +++ app/Models/Companies/ContactType.php | 19 ++ app/Models/Companies/Department.php | 89 +++++++ app/Models/Pages/PageType.php | 4 +- app/Models/User.php | 3 + app/Providers/AppServiceProvider.php | 22 +- .../Companies/CompanyFiltersServices.php | 9 + .../Companies/CompanyMemberFilters.php | 58 +++++ app/Services/Filters/FiltersService.php | 4 +- .../Advisories/AdvisoryCompaniesForms.php | 53 +++++ .../AdvisoryCompanyMembersForms.php | 64 +++++ .../Forms/Advisories/AdvisoryForms.php | 188 +++++++++++++++ .../Advisories/AdvisoryFormsServices.php | 13 ++ .../Forms/Advisories/AdvisoryGroupForms.php | 71 ++++++ .../Forms/Advisories/AdvisoryInfoForms.php | 92 ++++++++ app/Services/Forms/Companies/CompanyForms.php | 91 ++++++++ .../Forms/Companies/CompanyFormsServices.php | 11 + .../Forms/Companies/CompanyMemberForms.php | 147 ++++++++++++ .../Forms/Companies/DepartmentForms.php | 56 +++++ app/Services/Forms/FormsService.php | 4 + app/Support/ParticipatableTrait.php | 12 - .../Advisories/AdvisoryCompanyTransformer.php | 53 +++++ .../Advisories/AdvisoryMemberTransformer.php | 34 +++ .../Advisories/AdvisoryTransformer.php | 80 +++++++ .../Companies/AddressTransformer.php | 38 +++ .../Companies/BankDetailsTransformer.php | 34 +++ .../Companies/CompanyMemberTransformer.php | 56 +++++ .../Companies/CompanyTransformer.php | 100 ++++++++ .../Companies/CompanyTypeTransformer.php | 31 +++ .../Companies/ContactTransformer.php | 30 +++ .../Companies/DepartmentTransformer.php | 41 ++++ ...21_08_23_111709_create_companies_table.php | 44 ++++ ...23_154821_create_company_members_table.php | 43 ++++ ..._194429_create_company_addresses_table.php | 45 ++++ ...1659_create_company_bank_details_table.php | 39 ++++ ...1_204328_create_company_contacts_table.php | 34 +++ ...04528_create_company_departments_table.php | 38 +++ ...7_01_204530_create_company_types_table.php | 33 +++ ...> 2022_07_01_204700_create_jobs_table.php} | 0 ...2_09_19_211521_create_advisories_table.php | 45 ++++ ...9_211544_create_advisory_members_table.php | 37 +++ ...211700_create_advisory_companies_table.php | 34 +++ .../Advisories/AdvisoriesTableSeeder.php | 83 +++++++ .../Advisories/AdvisoriesTablesSeeder.php | 11 + .../Companies/CompaniesTableSeeder.php | 56 +++++ .../Companies/CompaniesTablesSeeder.php | 11 + database/seeders/DatabaseSeeder.php | 4 + .../Dictionaries/DictionariesTableSeeder.php | 2 +- .../seeders/Objects/FieldsTableSeeder.php | 2 +- database/seeders/Pages/PagesTableSeeder.php | 10 +- routes/api.php | 10 + storage/app/dadata/7736151499.json | 1 + 71 files changed, 3300 insertions(+), 22 deletions(-) create mode 100644 app/Http/Controllers/Api/Advisories/AdvisoriesController.php create mode 100644 app/Http/Controllers/Api/Advisories/AdvisoryCompaniesController.php create mode 100644 app/Http/Controllers/Api/Advisories/AdvisoryMembersController.php create mode 100644 app/Http/Controllers/Api/Companies/CompaniesController.php create mode 100644 app/Http/Controllers/Api/Companies/DepartmentsController.php create mode 100644 app/Http/Controllers/Api/Companies/MembersController.php create mode 100644 app/Models/Advisories/Advisory.php create mode 100644 app/Models/Advisories/AdvisoryCompany.php create mode 100644 app/Models/Advisories/AdvisoryMember.php create mode 100644 app/Models/Advisories/AdvisoryMemberRank.php create mode 100644 app/Models/Advisories/AdvisoryType.php create mode 100644 app/Models/Companies/Address.php create mode 100644 app/Models/Companies/BankDetails.php create mode 100644 app/Models/Companies/Company.php create mode 100644 app/Models/Companies/CompanyMember.php create mode 100644 app/Models/Companies/CompanyMemberRank.php create mode 100644 app/Models/Companies/CompanyMemberRole.php create mode 100644 app/Models/Companies/CompanyType.php create mode 100644 app/Models/Companies/Contact.php create mode 100644 app/Models/Companies/ContactType.php create mode 100644 app/Models/Companies/Department.php create mode 100644 app/Services/Filters/Companies/CompanyFiltersServices.php create mode 100644 app/Services/Filters/Companies/CompanyMemberFilters.php create mode 100644 app/Services/Forms/Advisories/AdvisoryCompaniesForms.php create mode 100644 app/Services/Forms/Advisories/AdvisoryCompanyMembersForms.php create mode 100644 app/Services/Forms/Advisories/AdvisoryForms.php create mode 100644 app/Services/Forms/Advisories/AdvisoryFormsServices.php create mode 100644 app/Services/Forms/Advisories/AdvisoryGroupForms.php create mode 100644 app/Services/Forms/Advisories/AdvisoryInfoForms.php create mode 100644 app/Services/Forms/Companies/CompanyForms.php create mode 100644 app/Services/Forms/Companies/CompanyFormsServices.php create mode 100644 app/Services/Forms/Companies/CompanyMemberForms.php create mode 100644 app/Services/Forms/Companies/DepartmentForms.php delete mode 100644 app/Support/ParticipatableTrait.php create mode 100644 app/Transformers/Advisories/AdvisoryCompanyTransformer.php create mode 100644 app/Transformers/Advisories/AdvisoryMemberTransformer.php create mode 100644 app/Transformers/Advisories/AdvisoryTransformer.php create mode 100644 app/Transformers/Companies/AddressTransformer.php create mode 100644 app/Transformers/Companies/BankDetailsTransformer.php create mode 100644 app/Transformers/Companies/CompanyMemberTransformer.php create mode 100644 app/Transformers/Companies/CompanyTransformer.php create mode 100644 app/Transformers/Companies/CompanyTypeTransformer.php create mode 100644 app/Transformers/Companies/ContactTransformer.php create mode 100644 app/Transformers/Companies/DepartmentTransformer.php create mode 100644 database/migrations/2021_08_23_111709_create_companies_table.php create mode 100644 database/migrations/2021_08_23_154821_create_company_members_table.php create mode 100644 database/migrations/2021_09_16_194429_create_company_addresses_table.php create mode 100644 database/migrations/2021_09_16_201659_create_company_bank_details_table.php create mode 100644 database/migrations/2022_07_01_204328_create_company_contacts_table.php create mode 100644 database/migrations/2022_07_01_204528_create_company_departments_table.php create mode 100644 database/migrations/2022_07_01_204530_create_company_types_table.php rename database/migrations/{2022_07_01_191111_create_jobs_table.php => 2022_07_01_204700_create_jobs_table.php} (100%) create mode 100644 database/migrations/2022_09_19_211521_create_advisories_table.php create mode 100644 database/migrations/2022_09_19_211544_create_advisory_members_table.php create mode 100644 database/migrations/2022_09_19_211700_create_advisory_companies_table.php create mode 100644 database/seeders/Advisories/AdvisoriesTableSeeder.php create mode 100644 database/seeders/Advisories/AdvisoriesTablesSeeder.php create mode 100644 database/seeders/Companies/CompaniesTableSeeder.php create mode 100644 database/seeders/Companies/CompaniesTablesSeeder.php create mode 100644 storage/app/dadata/7736151499.json diff --git a/app/Http/Controllers/Api/Advisories/AdvisoriesController.php b/app/Http/Controllers/Api/Advisories/AdvisoriesController.php new file mode 100644 index 0000000..5cd6021 --- /dev/null +++ b/app/Http/Controllers/Api/Advisories/AdvisoriesController.php @@ -0,0 +1,72 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $query = $this->model->query(); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new AdvisoryTransformer())->respond(); + } + + public function show(Request $request, $id): JsonResponse { + $query = $this->model->query(); + $model = ($id === 'main') ? $query->where(['is_main' => 1])->firstOrFail() : $query->byUuid($id)->firstOrFail(); + return fractal($model, new AdvisoryTransformer())->respond(); + } + + public function siblings(Request $request, $id): JsonResponse { + $filters = collect($request->has('filters') ? json_decode($request->get('filters'), true) : []); + $query = $this->model->query(); + $model = ($id === 'main') ? $query->where(['is_main' => 1])->firstOrFail() : $query->byUuid($id)->firstOrFail(); + $query = $model->siblings(); + $service = FiltersService::getService('advisories'); + $service->applyFilters($query, $filters); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new AdvisoryTransformer())->respond(); + } + + public function store(Request $request): JsonResponse { + $this->validate($request, [ + 'parent' => 'required|exists:advisories,uuid', + 'title' => 'required', + 'number' => 'required', + 'type' => 'required' + ]); + + $model = $this->model->create($request->all()); + return fractal($model, new AdvisoryTransformer())->respond(201); + } + + public function update(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $this->validate($request, [ + 'title' => 'required', + 'number' => 'required', + 'type' => 'required' + ]); + $model->update($request->all()); + return fractal($model->fresh(), new AdvisoryTransformer())->respond(); + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } + + +} diff --git a/app/Http/Controllers/Api/Advisories/AdvisoryCompaniesController.php b/app/Http/Controllers/Api/Advisories/AdvisoryCompaniesController.php new file mode 100644 index 0000000..8a1116a --- /dev/null +++ b/app/Http/Controllers/Api/Advisories/AdvisoryCompaniesController.php @@ -0,0 +1,43 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $query = $this->model->query(); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new AdvisoryCompanyTransformer())->respond(); + } + + public function show(Request $request, $id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + return fractal($model, new AdvisoryCompanyTransformer())->respond(); + } + + public function store(Request $request): void { + } + + public function update(Request $request, $uuid): void { + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->advisoryMembers()->delete(); + $model->delete(); + return response()->json(null, 204); + } + + +} diff --git a/app/Http/Controllers/Api/Advisories/AdvisoryMembersController.php b/app/Http/Controllers/Api/Advisories/AdvisoryMembersController.php new file mode 100644 index 0000000..3891f3f --- /dev/null +++ b/app/Http/Controllers/Api/Advisories/AdvisoryMembersController.php @@ -0,0 +1,42 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $query = $this->model->query(); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new AdvisoryMemberTransformer())->respond(); + } + + public function show(Request $request, $id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + return fractal($model, new AdvisoryMemberTransformer())->respond(); + } + + public function store(Request $request): void { + } + + public function update(Request $request, $uuid): void { + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } + + +} diff --git a/app/Http/Controllers/Api/Assets/UploadFileController.php b/app/Http/Controllers/Api/Assets/UploadFileController.php index 24844f6..71606c8 100644 --- a/app/Http/Controllers/Api/Assets/UploadFileController.php +++ b/app/Http/Controllers/Api/Assets/UploadFileController.php @@ -30,6 +30,12 @@ class UploadFileController extends Controller { 'type' => 'image', 'extension' => 'png', ], + /* + 'image/svg+xml' => [ + 'type' => 'image', + 'extension' => 'svg' + ], + */ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => [ 'type' => 'document', 'extension' => 'xlsx' diff --git a/app/Http/Controllers/Api/Companies/CompaniesController.php b/app/Http/Controllers/Api/Companies/CompaniesController.php new file mode 100644 index 0000000..1b42763 --- /dev/null +++ b/app/Http/Controllers/Api/Companies/CompaniesController.php @@ -0,0 +1,81 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $filters = collect(json_decode($request->get('filters'), true) ?? []); + $query = $this->model->query()->orderBy('updated_at', 'desc'); + if ($val = $filters->get('search')) { + $query->where(function($query) use($val) { + $query->where('name', 'like', "%{$val}%")->orWhere('full_name', 'like', "%{$val}%")->orWhere('inn', 'like', "%{$val}%"); + }); + } + if ($val = $filters->get('type')) $query->whereHas('types', function($query) use($val) { + $query->where(['name' => $val]); + }); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new CompanyTransformer())->respond(); + } + + public function show($id): JsonResponse { + $query = ($id === 'main') ? $this->model->where(['is_main' => 1]) : $this->model->byUuid($id); + return fractal($query->firstOrFail(), new CompanyTransformer())->respond(); + } + + public function store(Request $request): JsonResponse { + $this->validate($request, [ + 'inn' => 'required', + 'name' => 'required', + 'address' => 'required', + ]); + $model = $this->model->getByData($request->all()); + return fractal($model, new CompanyTransformer())->respond(201); + } + + public function update(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $this->validate($request, [ + 'name' => 'required', + 'address' => 'required', + ]); + $model->update(['name' => $request->get('name')]); + $address = [ + 'full' => $request->get('address') + ]; + $model->legalAddress->update($address); + $model->actualAddress->update($address); + foreach(['phone', 'email'] as $key) { + if ($request->has($key)) { + $model->$key->update(['value' => $request->get($key)]); + } + } + + return fractal($model->fresh(), new CompanyTransformer())->respond(); + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } + + + + public function getDataByInn(Request $request, $inn) { + return (new DaDataService($inn))->getCompanyData(); + } +} diff --git a/app/Http/Controllers/Api/Companies/DepartmentsController.php b/app/Http/Controllers/Api/Companies/DepartmentsController.php new file mode 100644 index 0000000..33bce08 --- /dev/null +++ b/app/Http/Controllers/Api/Companies/DepartmentsController.php @@ -0,0 +1,39 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $query = $this->model->query(); + $paginator = $query->paginate(config('app.pagination_limit')); + return fractal($paginator, new DepartmentTransformer())->respond(); + } + + public function show($id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + return fractal($model, new DepartmentTransformer())->respond(); + } + + public function my(Request $request): JsonResponse { + return fractal($request->user()->selectedMember->department, new DepartmentTransformer())->respond(); + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } + +} diff --git a/app/Http/Controllers/Api/Companies/MembersController.php b/app/Http/Controllers/Api/Companies/MembersController.php new file mode 100644 index 0000000..a84afa4 --- /dev/null +++ b/app/Http/Controllers/Api/Companies/MembersController.php @@ -0,0 +1,70 @@ +model = $model; + } + + public function index(Request $request): JsonResponse { + $filters = collect($request->has('filters') ? json_decode($request->get('filters'), true) : [])->filter(function($val) {return $val;}); + $query = $this->model->query(); + $service = FiltersService::getService('companyMembers'); + $service->applyFilters($query, $filters); + $paginator = $query->paginate(2); + return fractal($paginator, new CompanyMemberTransformer())->respond(); + } + + public function show($id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + return fractal($model, new CompanyMemberTransformer())->respond(); + } + + public function store(Request $request): JsonResponse { + $this->validate($request, [ + 'name' => 'required', + 'position' => 'required', + 'company' => 'required|exists:companies,uuid', + ]); + $user = User::getByData($request->only('name', 'email', 'phone')); + $company = Company::byUuid($request->get('company'))->first(); + $department = Department::byUuid($request->get('department')); + $model = $company->addMember($user, $request->get('position'), $department->id ?? null, $request->get('rank')); + return fractal($model, new CompanyMemberTransformer())->respond(201); + } + + public function update(Request $request, $uuid): JsonResponse { + $this->validate($request, [ + 'name' => 'required' + ]); + + $model = $this->model->byUuid($uuid)->firstOrFail(); + foreach (['name', 'phone'] as $key) { + if ($request->has($key)) { + $model->user->update([$key => $request->get($key)]); + } + } + + $model->update($request->all()); + return fractal($model->fresh(), new CompanyMemberTransformer())->respond(); + } + + public function destroy(Request $request, $uuid): JsonResponse { + $model = $this->model->byUuid($uuid)->firstOrFail(); + $model->delete(); + return response()->json(null, 204); + } +} diff --git a/app/Models/Advisories/Advisory.php b/app/Models/Advisories/Advisory.php new file mode 100644 index 0000000..ad44872 --- /dev/null +++ b/app/Models/Advisories/Advisory.php @@ -0,0 +1,162 @@ +belongsTo(Asset::class); + } + + public function document(): BelongsTo { + return $this->belongsTo(Asset::class); + } + + public function advisoryCompanies(): HasMany { + return $this->hasMany(AdvisoryCompany::class); + } + + public function companies(): BelongsToMany { + return $this->belongsToMany(Company::class, 'advisory_companies'); + } + + public function members(): HasMany { + return $this->hasMany(AdvisoryMember::class); + } + + public function companyMembers(): BelongsToMany { + return $this->belongsToMany(CompanyMember::class, 'advisory_members')->wherePivotNull('deleted_at'); + } + + public function parent(): BelongsTo { + return $this->belongsTo(self::class, 'parent_id'); + } + + public function children(): HasMany { + return $this->hasMany(self::class, 'parent_id'); + } + + public function siblings(): HasMany { + return $this->hasMany(Advisory::class, 'parent_id', 'parent_id')->where('id', '!=', $this->id); + } + + + + public function getParsedTypeAttribute(): array { + return ['name' => $this->type, 'title' => AdvisoryType::TITLES[$this->type] ?? null]; + } + + public function getCaptionAttribute(): string { + return "{$this->number} «{$this->title}»"; + } + + public function getPathTitleAttribute(): string { + $advisory = $this; + $result = [$advisory->number]; + while ($advisory = $advisory->parent) $result[] = $advisory->number; + return implode(' / ', $result); + } + + /* + public function getSecretaryAttribute() { + return $this->companyMembers()->wherePivot('rank', '=', AdvisoryMemberRank::SECRETARY)->first(); + } + */ + public function getSecretaryAssistantsAttribute(): Collection { + return $this->companyMembers()->wherePivot('rank', '=', AdvisoryMemberRank::SECRETARY_ASSISTANT)->get(); + } + public function getSecretaryAndAssistantsAttribute(): Collection { + return $this->companyMembers()->wherePivotIn('rank', [AdvisoryMemberRank::SECRETARY, AdvisoryMemberRank::SECRETARY_ASSISTANT])->get(); + } + public function getChairmanAttribute() { + return $this->companyMembers()->wherePivot('rank', '=', AdvisoryMemberRank::CHAIRMAN)->first(); + } + public function getChairmanVicesAttribute(): Collection { + return $this->companyMembers()->wherePivot('rank', '=', AdvisoryMemberRank::VICE_CHAIRMAN)->get(); + } + public function getOrdinaryMembersAttribute(): Collection { + return $this->companyMembers()->wherePivot('rank', '=', AdvisoryMemberRank::ORDINARY)->get(); + } + + + + public function setLogo($val) { + $asset = Asset::byUuid($val)->first(); + $this->update(['logo_id' => $asset->id ?? null]); + } + public function setDocument($val) { + $asset = Asset::byUuid($val)->first(); + $this->update(['document_id' => $asset->id ?? null]); + } + + + public function addMember(CompanyMember $companyMember, $rank = null): Model { + $member = $this->members()->firstOrCreate(['company_member_id' => $companyMember->id]); + $member->update(['rank' => $rank ?? AdvisoryMemberRank::ORDINARY]); + return $member; + } + + + public function syncMembers(Collection $companyMembers, $rank, ?Company $company = null) { + $exists = $companyMembers->map(function(CompanyMember $companyMember) use($rank) { + return $this->members()->firstOrCreate(['company_member_id' => $companyMember->id, 'rank' => $rank]); + }); + $this->deleteDisappearedMembers($exists, $rank, $company); + } + public function deleteDisappearedMembers(Collection $exists, $rank, ?Company $company) { + $query = $this->members()->where(['rank' => $rank])->whereNotIn('id', $exists->pluck('id')->all()); + if ($company && in_array($rank, [AdvisoryMemberRank::ORDINARY, AdvisoryMemberRank::VOTER])) $query->whereHas('companyMember', function($query) use($company) { + $query->where(['company_id' => $company->id]); + }); + $query->delete(); + } + + + + public static function main() { + return self::query()->where(['is_main' => 1])->first(); + } + + public static function root() { + return self::query()->where(['parent_id' => 0])->get(); + } + +} diff --git a/app/Models/Advisories/AdvisoryCompany.php b/app/Models/Advisories/AdvisoryCompany.php new file mode 100644 index 0000000..050e360 --- /dev/null +++ b/app/Models/Advisories/AdvisoryCompany.php @@ -0,0 +1,68 @@ +belongsTo(Advisory::class); + } + + public function company(): BelongsTo { + return $this->belongsTo(Company::class); + } + + public function advisoryMembers() { + return $this->advisory->members()->whereHas('companyMember', function($query) { + $query->where(['company_id' => $this->company_id]); + }); + } + + public function companyMembers(): BelongsToMany { + return $this->advisory->companyMembers()->where(['company_id' => $this->company_id]); + } + + + + public function getTitleAttribute(): string { + return "Член {$this->advisory->number} {$this->company->name}"; + } + + public function getSubtitleAttribute(): string { + return "Член {$this->advisory->number}"; + } + + public function getVoterAttribute(): ?Model { + return $this->advisoryMembers()->where(['rank' => AdvisoryMemberRank::VOTER])->first(); + } + + + public function getCompanyMembers($rank): BelongsToMany { + return $this->companyMembers()->wherePivot('rank', '=', $rank); + } + + +} diff --git a/app/Models/Advisories/AdvisoryMember.php b/app/Models/Advisories/AdvisoryMember.php new file mode 100644 index 0000000..e3258d3 --- /dev/null +++ b/app/Models/Advisories/AdvisoryMember.php @@ -0,0 +1,61 @@ +belongsTo(Advisory::class); + } + + public function companyMember(): BelongsTo { + return $this->belongsTo(CompanyMember::class); + } + + + + public function getTitleAttribute(): string { + $rank = AdvisoryMemberRank::CATEGORIES[$this->rank] ?? 'Член'; + return "{$rank} {$this->advisory->number} {$this->companyMember->company->name}"; + } + + public function getParsedRankAttribute(): array { + return ['name' => AdvisoryMemberRank::NAMES[$this->rank] ?? null, 'title' => AdvisoryMemberRank::TITLES[$this->rank] ?? null, 'level' => $this->rank]; + } + + public function getAdvisoryCompanyAttribute(): ?Model { + return ($this->advisory && $this->companyMember) ? $this->advisory->advisoryCompanies()->where(['company_id' => $this->companyMember->company_id])->first() : null; + } + + + + public function setRank($rank = null) { + $this->update(['rank' => $rank ?? AdvisoryMemberRank::ORDINARY]); + } + + +} diff --git a/app/Models/Advisories/AdvisoryMemberRank.php b/app/Models/Advisories/AdvisoryMemberRank.php new file mode 100644 index 0000000..0287a44 --- /dev/null +++ b/app/Models/Advisories/AdvisoryMemberRank.php @@ -0,0 +1,39 @@ + 'Член', + self::VOTER => 'Член с правом голоса', + self::SECRETARY_ASSISTANT => 'Помощник секретаря', + self::SECRETARY => 'Секретарь', + self::VICE_CHAIRMAN => 'Заместитель руководителя', + self::CHAIRMAN => 'Руководитель' + ]; + + public const NAMES = [ + self::ORDINARY => 'ordinary', + self::VOTER => 'voter', + self::SECRETARY_ASSISTANT => 'secretary-assistant', + self::SECRETARY => 'secretary', + self::VICE_CHAIRMAN => 'vice-chairman', + self::CHAIRMAN => 'chairman' + ]; + + public const CATEGORIES = [ + self::ORDINARY => 'Член', + self::VOTER => 'Член', + self::SECRETARY_ASSISTANT => 'Секретариат', + self::SECRETARY => 'Секретариат', + self::VICE_CHAIRMAN => 'Руководство', + self::CHAIRMAN => 'Руководство' + ]; +} \ No newline at end of file diff --git a/app/Models/Advisories/AdvisoryType.php b/app/Models/Advisories/AdvisoryType.php new file mode 100644 index 0000000..f24af2d --- /dev/null +++ b/app/Models/Advisories/AdvisoryType.php @@ -0,0 +1,13 @@ + 'Комитет', + self::WORKGROUP => 'Рабочая группа' + ]; +} \ No newline at end of file diff --git a/app/Models/Companies/Address.php b/app/Models/Companies/Address.php new file mode 100644 index 0000000..9535061 --- /dev/null +++ b/app/Models/Companies/Address.php @@ -0,0 +1,57 @@ +belongsTo(Company::class); + } + + + + public function setFullAddress($val) { + $address = ['full' => $val, 'postcode' => '', 'country' => '', 'region' => '', 'city' => '', + 'district' => '', 'street' => '', 'house' => '', 'block' => '', 'office' => '']; + $this->update($address); + } + +} diff --git a/app/Models/Companies/BankDetails.php b/app/Models/Companies/BankDetails.php new file mode 100644 index 0000000..d2ee433 --- /dev/null +++ b/app/Models/Companies/BankDetails.php @@ -0,0 +1,38 @@ +belongsTo(Company::class); + } +} diff --git a/app/Models/Companies/Company.php b/app/Models/Companies/Company.php new file mode 100644 index 0000000..0becc5d --- /dev/null +++ b/app/Models/Companies/Company.php @@ -0,0 +1,220 @@ +belongsTo(Asset::class); + } + + public function types(): HasMany { + return $this->hasMany(CompanyType::class); + } + + public function departments(): HasMany { + return $this->hasMany(Department::class); + } + + public function members(): HasMany { + return $this->hasMany(CompanyMember::class); + } + public function rootMembers(): HasMany { + return $this->members()->whereNull('department_id'); + } + public function management(): HasMany { + return $this->members()->whereIn('status', [CompanyMemberRank::VICE, CompanyMemberRank::CHIEF]); + } + public function vices(): HasMany { + return $this->members()->where(['status' => CompanyMemberRank::VICE]); + } + public function employees(): HasMany { + return $this->members()->where(['status' => CompanyMemberRank::EMPLOYEE]); + } + + public function addresses(): HasMany { + return $this->hasMany(Address::class); + } + + public function bankDetails(): HasOne { + return $this->hasOne(BankDetails::class); + } + + public function contacts(): HasMany { + return $this->hasMany(Contact::class); + } + public function phones(): HasMany { + return $this->contacts()->where(['type' => ContactType::PHONE]); + } + public function emails(): HasMany { + return $this->contacts()->where(['type' => ContactType::EMAIL]); + } + + public function advisoryCompanies(): HasMany { + return $this->hasMany(AdvisoryCompany::class); + } + + + + public function scopeByTypes($query, $types) { + return $query->whereHas('types', function($query) use($types) { + $query->whereIn('name', is_array($types) ? $types : [$types]); + }); + } + + + public function getLegalAddressAttribute(): Model { + return $this->addresses()->firstOrCreate(['type' => Address::$TYPE_LEGAL]); + } + public function getActualAddressAttribute(): Model { + return $this->addresses()->firstOrCreate(['type' => Address::$TYPE_ACTUAL]); + } + public function getPhoneAttribute(): Model { + return $this->phones()->firstOrCreate(['type' => ContactType::PHONE]); + } + public function getEmailAttribute(): Model { + return $this->emails()->firstOrCreate(['type' => ContactType::EMAIL]); + } + public function getRootDepartmentAttribute(): Model { + $res = $this->departments()->whereNull('parent_id')->firstOrCreate(['name' => 'root']); + if (!$res->title) $res->update(['title' => 'Дирекция']); + return $res; + } + public function getRepresentativeMemberAttribute() { + return $this->members()->where(['representative' => true])->first(); + } + public function getResponsibleMemberAttribute() { + return $this->members()->orderBy('representative', 'desc')->first(); + } + + + public static function getByData($data) { + $result = false; + if (!empty($data['inn'])) { + $result = self::firstOrCreate(['inn' => $data['inn']]); + (new DaDataService($data['inn']))->saveToCompany($result); + if ($val = $data['name'] ?? null) $result->update(['name' => $val, 'full_name' => $val]); + if (($val = $data['address'] ?? null) && $result->legalAddress->full !== $val) $result->setAddress($val); + if ($val = $data['phone'] ?? null) $result->setPhone($val); + if ($val = $data['email'] ?? null) $result->setEmail($val); + if ($val = $data['contacts'] ?? null) $result->setContacts($val); + if ($val = $data['types'] ?? null) $result->setTypes($val); + if ($val = $data['logo'] ?? null) $result->setLogo($val); + if (!$result->name && !is_numeric($result->inn)) $result->update(['name' => $result->inn, 'full_name' => $result->inn]); + } + return $result; + } + + public function addMember(User $user, $position, $departmentId = null, $rank = null): Model { + if ($member = $this->members()->where(['user_id' => $user->id, 'position' => $position])->first()) { + if ($departmentId) $member->update(['department_id' => $departmentId]); + if (!is_null($rank)) $member->update(['rank' => $rank]); + } elseif ($member = $this->members()->create(['user_id' => $user->id, 'position' => $position])) { + $member->update(['department_id' => $departmentId ?? $this->rootDepartment->id ?? null, 'rank' => $rank ?? CompanyMemberRank::EMPLOYEE]); + } + return $member; + } + + public function isMember(CompanyMember $member): bool { + return $this->members()->where('id', $member->id)->exists(); + } + + + public function findDepartments($search): Collection { + return $this->departments()->where('title', 'like', "%{$search}%")->get(); + } + public function findMembers($search): Collection { + return $this->members()->where('position', 'like', "%{$search}%")->orWhereHas('user', function($query) use($search) { + $query->where('name', 'like', "%{$search}%"); + })->get(); + } + + + public function setTypes(array $types) { + $exists = collect($types)->map(function($item) { + $name = (is_string($item)) ? $item : $item['id'] ?? null; + return $name ? $this->types()->firstOrCreate(['name' => $name]) : null; + }); + $this->types()->whereNotIn('name', $exists->pluck('name')->all())->delete(); + } + + public function setLogo($val) { + $asset = Asset::byUuid($val)->first(); + $this->update(['logo_id' => $asset->id ?? null]); + } + + public function setAddress($val) { + $this->legalAddress->setFullAddress($val); + $this->actualAddress->setFullAddress($val); + } + public function setEmail($val): ?Model { + $this->emails()->delete(); + return $val ? $this->contacts()->create(['type' => ContactType::EMAIL, 'value' => $val]) : null; + } + public function setPhone($val): ?Model { + $this->phones()->delete(); + return $val ? $this->contacts()->create(['type' => ContactType::PHONE, 'value' => $val]) : null; + } + public function setContacts($val) { + $this->contacts()->firstOrCreate(['type' => ContactType::MIXED, 'value' => $val]); + collect(explode(';', $val))->each(function($contact) { + $type = (Str::contains($contact, '@')) ? ContactType::EMAIL : ContactType::PHONE; + $this->contacts()->firstOrCreate(['type' => $type, 'value' => trim($contact)]); + }); + } + + + public function getPermissions(User $user): array { + $result = ['view' => false, 'edit' => false]; + if ($user->isAdmin) $result = ['view' => true, 'edit' => true]; + elseif ($user->isCompanyMember($this)) { + $result['view'] = true; + if ($this->members()->where(['user_id' => $user->id, 'representative' => 1])->exists()) $result['edit'] = true; + } + return $result; + } + + +} diff --git a/app/Models/Companies/CompanyMember.php b/app/Models/Companies/CompanyMember.php new file mode 100644 index 0000000..cd76a5f --- /dev/null +++ b/app/Models/Companies/CompanyMember.php @@ -0,0 +1,115 @@ +belongsTo(Company::class); + } + + public function user(): BelongsTo { + return $this->belongsTo(User::class); + } + + public function department(): BelongsTo { + return $this->belongsTo(Department::class); + } + + public function advisoryMembership(): HasMany { + return $this->hasMany(AdvisoryMember::class); + } + + + + public function getIsMeAttribute(): ?bool { + return ($user = Auth::user()) ? ($user->id === $this->user_id) : null; + } + + public function getSubordinatesAttribute() { + $query = $this->department ? $this->department->members() : $this->company->members()->whereNull('department_id'); + return $query->where('role', '<', $this->role)->get(); + } + + public function getSuperiorsAttribute() { + $query = $this->department ? $this->department->members() : $this->company->members()->whereNull('department_id'); + return $query->where('role', '>', $this->role)->get(); + } + + public function getIsChiefAttribute(): bool { + return $this->role === CompanyMemberRank::CHIEF; + } + + public function getIsViceAttribute(): bool { + return $this->role === CompanyMemberRank::VICE; + } + + public function getIsManagementAttribute(): bool { + return in_array($this->role, [CompanyMemberRank::VICE, CompanyMemberRank::CHIEF]); + } + + public function getParsedRankAttribute(): array { + return [ + 'name' => CompanyMemberRank::NAMES[$this->rank] ?? null, + 'title' => CompanyMemberRank::TITLES[$this->rank] ?? null, + 'level' => $this->rank + ]; + } + + public function getParsedRoleAttribute(): array { + return ['name' => $this->role, 'title' => CompanyMemberRole::TITLES[$this->role] ?? null]; + } + + public function isSubordinateFor(User $user): bool { + $members = $user->membership()->where(['company_id' => $this->company_id])->where('rank', '>', CompanyMemberRank::EMPLOYEE)->get(); + foreach ($members->all() as $member) { + if ($this->department->isMember($member)) return ($member->rank > $this->rank); + elseif ($member->department->level < $this->department->level) return $member->department->isParentFor($this->department); + } + return false; + } + + + + public function setRank($rank): bool { + if (!empty(CompanyMemberRank::TITLES[$rank])) { + if (($rank === CompanyMemberRank::CHIEF) && ($chief = $this->department->chief)) $chief->setRank(CompanyMemberRank::EMPLOYEE); + return $this->update(['rank' => $rank]); + } + return false; + } +} diff --git a/app/Models/Companies/CompanyMemberRank.php b/app/Models/Companies/CompanyMemberRank.php new file mode 100644 index 0000000..8ceab6b --- /dev/null +++ b/app/Models/Companies/CompanyMemberRank.php @@ -0,0 +1,21 @@ + 'Руководитель структурного подразделения', + self::VICE => 'Заместитель руководителя структурного подразделения', + self::EMPLOYEE => 'Сотрудник структурного подразделения' + ]; + + public const NAMES = [ + self::EMPLOYEE => 'employee', + self::VICE => 'vice', + self::CHIEF => 'chief' + ]; +} \ No newline at end of file diff --git a/app/Models/Companies/CompanyMemberRole.php b/app/Models/Companies/CompanyMemberRole.php new file mode 100644 index 0000000..004cd39 --- /dev/null +++ b/app/Models/Companies/CompanyMemberRole.php @@ -0,0 +1,15 @@ + 'Пользователь', + self::MODERATOR => 'Редактор', + self::ADMINISTRATOR => 'Администратор' + ]; +} \ No newline at end of file diff --git a/app/Models/Companies/CompanyType.php b/app/Models/Companies/CompanyType.php new file mode 100644 index 0000000..b75e99a --- /dev/null +++ b/app/Models/Companies/CompanyType.php @@ -0,0 +1,38 @@ + 'Заявитель', + self::PRODUCER => 'Изготовитель продукции' + ]; + + protected $dates = [ + ]; + + protected $fillable = [ + 'company_id', + 'name' + ]; + + protected $hidden = [ + ]; + + public function company(): BelongsTo { + return $this->belongsTo(Company::class); + } + + + public function getTitleAttribute(): ?string { + return self::TITLES[$this->name] ?? null; + } + + +} \ No newline at end of file diff --git a/app/Models/Companies/Contact.php b/app/Models/Companies/Contact.php new file mode 100644 index 0000000..fab10a8 --- /dev/null +++ b/app/Models/Companies/Contact.php @@ -0,0 +1,33 @@ +belongsTo(Company::class); + } + + public function getParsedTypeAttribute(): array { + return ['name' => $this->type, 'title' => ContactType::TITLES[$this->type] ?? null]; + } + +} diff --git a/app/Models/Companies/ContactType.php b/app/Models/Companies/ContactType.php new file mode 100644 index 0000000..abae8e2 --- /dev/null +++ b/app/Models/Companies/ContactType.php @@ -0,0 +1,19 @@ + 'телефон', + self::EMAIL => 'электронная почта', + self::SITE => 'сайт', + self::FAX => 'факс', + self::MIXED => 'смешанное' + ]; +} \ No newline at end of file diff --git a/app/Models/Companies/Department.php b/app/Models/Companies/Department.php new file mode 100644 index 0000000..7ee3dfd --- /dev/null +++ b/app/Models/Companies/Department.php @@ -0,0 +1,89 @@ +belongsTo(Company::class); + } + + public function parent(): BelongsTo { + return $this->belongsTo(self::class, 'parent_id'); + } + + public function children(): HasMany { + return $this->hasMany(self::class, 'parent_id'); + } + + public function members(): HasMany { + return $this->hasMany(CompanyMember::class); + } + public function management(): HasMany { + return $this->members()->whereIn('rank', [CompanyMemberRank::VICE, CompanyMemberRank::CHIEF]); + } + public function vices(): HasMany { + return $this->members()->where(['rank' => CompanyMemberRank::VICE]); + } + public function employees(): HasMany { + return $this->members()->where(['rank' => CompanyMemberRank::EMPLOYEE]); + } + + + public function getChiefAttribute() { + return $this->members()->where(['rank' => CompanyMemberRank::CHIEF])->first(); + } + + + public function addChildren($name, $title): ?Department { + $result = null; + if (($name = trim($name)) && ($title = trim($title))) { + $result = $this->company->departments()->firstOrCreate(['name' => $name]); + $result->update(['title' => $title, 'parent_id' => $this->id, 'level' => ++$this->level]); + } + return $result; + } + + public function addMember(User $user, $position = null): Model { + return $this->members()->firstOrCreate(['company_id' => $this->company_id, 'user_id' => $user->id, 'position' => $position]); + } + + public function isMember(CompanyMember $member): bool { + return $this->members()->where(['id' => $member->id])->exists(); + } + + public function isParentFor(Department $department): bool { + while ($parent = $department->parent) { + if ($parent->id === $this->id) return true; + $department = $department->parent; + } + return false; + } + +} diff --git a/app/Models/Pages/PageType.php b/app/Models/Pages/PageType.php index cd888a4..f867fca 100644 --- a/app/Models/Pages/PageType.php +++ b/app/Models/Pages/PageType.php @@ -6,10 +6,12 @@ class PageType { public const CONTENT = 'content'; public const PUBLICATIONS = 'publications'; public const REGISTRY = 'registry'; + public const TK_STRUCTURE = 'tk-structure'; public const TITLES = [ self::CONTENT => 'Контентная страница', self::PUBLICATIONS => 'Страница публикаций', - self::REGISTRY => 'Страница реестра' + self::REGISTRY => 'Страница реестра', + self::TK_STRUCTURE => 'Структура ТК' ]; } \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 22f2085..22470d5 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -70,6 +70,9 @@ class User extends Authenticatable { return $this->hasRole('Administrator'); } + public function getIsPrivilegedAttribute() { + return $this->isAdmin; + } public static function getByData($data, $triggerEvent = false) { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 87b5596..30aeedb 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,7 +2,16 @@ namespace App\Providers; +use App\Models\Advisories\Advisory; +use App\Models\Advisories\AdvisoryCompany; +use App\Models\Advisories\AdvisoryMember; use App\Models\Asset; +use App\Models\Companies\Address; +use App\Models\Companies\BankDetails; +use App\Models\Companies\Company; +use App\Models\Companies\CompanyMember; +use App\Models\Companies\Contact; +use App\Models\Companies\Department; use App\Models\Dictionaries\Dictionary; use App\Models\Dictionaries\DictionaryItem; use App\Models\Objects\Field; @@ -64,7 +73,18 @@ class AppServiceProvider extends ServiceProvider 'registry' => Registry::class, 'registry-category' => Category::class, - 'registry-entry' => Entry::class + 'registry-entry' => Entry::class, + + 'company' => Company::class, + 'company-address' => Address::class, + 'company-member' => CompanyMember::class, + 'company-contact' => Contact::class, + 'company-department' => Department::class, + 'bank-details' => BankDetails::class, + + 'advisory' => Advisory::class, + 'advisory-member' => AdvisoryMember::class, + 'advisory-company' => AdvisoryCompany::class ]); } } diff --git a/app/Services/Filters/Companies/CompanyFiltersServices.php b/app/Services/Filters/Companies/CompanyFiltersServices.php new file mode 100644 index 0000000..edb345f --- /dev/null +++ b/app/Services/Filters/Companies/CompanyFiltersServices.php @@ -0,0 +1,9 @@ + CompanyMemberFilters::class + ]; +} diff --git a/app/Services/Filters/Companies/CompanyMemberFilters.php b/app/Services/Filters/Companies/CompanyMemberFilters.php new file mode 100644 index 0000000..754c8d7 --- /dev/null +++ b/app/Services/Filters/Companies/CompanyMemberFilters.php @@ -0,0 +1,58 @@ + 'common', + 'title' => 'Общие параметры', + 'fields' => $this->nativeFields($filters) + ] + ]; + $query = CompanyMember::query(); + $this->applyFilters($query, $filters); + return ['groups' => ['data' => $groups], 'total' => $query->count()]; + } + + public function nativeFields(Collection $filters): array { + return [ + ]; + } + + + public function applyFilters(Builder $query, Collection $filters) { + $this->applyNativeFilters($query, $filters); + $this->applyPermissionsFilters($query); + } + + public function applyNativeFilters(Builder $query, Collection $filters) { + $filters->each(function($value, $prop) use($query) { + $this->applyNativeFilter($query, $prop, $value); + }); + } + + public function applyNativeFilter(Builder $query, $prop, $value) { + if ($value) { + if ($prop === 'search') $this->applySearchFilter($query, $value, ['position', 'room', 'intercom', ['user' => ['name', 'email', 'phone']], ['department' => ['title']]]); + elseif ($prop === 'company') $this->applyCompanyFilter($query, $value); + } + } + + public function applyCompanyFilter(Builder $query, $value) { + $query->whereHas('company', function($query) use($value) { + ($value === 'main') ? $query->where(['is_main' => 1]) : $query->whereIn('uuid', is_array($value) ? $value : [$value]); + }); + } + + + public function applyPermissionsFilters(Builder $query) { + } + +} diff --git a/app/Services/Filters/FiltersService.php b/app/Services/Filters/FiltersService.php index be6e76c..3a11212 100644 --- a/app/Services/Filters/FiltersService.php +++ b/app/Services/Filters/FiltersService.php @@ -2,6 +2,7 @@ namespace App\Services\Filters; +use App\Services\Filters\Companies\CompanyFiltersServices; use App\Services\Filters\Registries\RegistryFiltersServices; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; @@ -9,7 +10,8 @@ use Illuminate\Support\Facades\Date; class FiltersService { public static array $services = [ - RegistryFiltersServices::class + RegistryFiltersServices::class, + CompanyFiltersServices::class ]; diff --git a/app/Services/Forms/Advisories/AdvisoryCompaniesForms.php b/app/Services/Forms/Advisories/AdvisoryCompaniesForms.php new file mode 100644 index 0000000..29115a9 --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryCompaniesForms.php @@ -0,0 +1,53 @@ + 'Добавление организаций-участников', 'update' => 'Редактирование организаций-участников']; + + public function form(?string $id = null, array $data = []): array { + $model = Advisory::byUuid($id)->first(); + $groups = [ + ['name' => 'common', 'fields' => $this->commonGroupFields($model)] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'companies', + 'title' => 'Организации-участники', + 'type' => FieldType::RELATION, + 'multiple' => true, + 'options' => fractal(Company::all(), new CompanyTransformer()), + 'value' => $model ? fractal($model->companies, new CompanyTransformer()) : null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): ?JsonResponse { + } + + public function update(string $id, array $data): ?JsonResponse { + $model = Advisory::byUuid($id)->firstOrFail(); + $exists = Company::byUuids($data['companies'] ?? [])->get()->map(function($company) use($model) { + return $model->advisoryCompanies()->firstOrCreate(['company_id' => $company->id]); + }); + $model->advisoryCompanies()->whereNotIn('id', $exists->pluck('id')->all())->delete(); + return fractal($model->fresh(), new AdvisoryTransformer())->respond(); + } + + +} diff --git a/app/Services/Forms/Advisories/AdvisoryCompanyMembersForms.php b/app/Services/Forms/Advisories/AdvisoryCompanyMembersForms.php new file mode 100644 index 0000000..a4e0e3d --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryCompanyMembersForms.php @@ -0,0 +1,64 @@ + '', 'update' => 'Добавление сотрудников-участников']; + + public function form(?string $id = null, array $data = []): array { + $model = AdvisoryCompany::byUuid($id)->first(); + $groups = [ + ['name' => 'common', 'fields' => $this->commonGroupFields($model)] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?AdvisoryCompany $model): array { + $fields = [ + [ + 'name' => 'voter', + 'title' => 'Сотрудник с правом голоса', + 'type' => FieldType::RELATION, + 'required' => true, + 'options' => $model ? fractal($model->company->members, new CompanyMemberTransformer()) : null, + 'value' => $model ? fractal($model->getCompanyMembers(AdvisoryMemberRank::VOTER)->get(), new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'members', + 'title' => 'Сотрудники', + 'type' => FieldType::RELATION, + 'multiple' => true, + 'options' => $model ? fractal($model->company->members, new CompanyMemberTransformer()) : null, + 'value' => $model ? fractal($model->getCompanyMembers(AdvisoryMemberRank::ORDINARY)->get(), new CompanyMemberTransformer()) : null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): void { + } + + public function update(string $id, array $data): ?JsonResponse { + $model = AdvisoryCompany::byUuid($id)->firstOrFail(); + $voter = $data['voter'] ?? null; + $members = collect($data['members'] ?? [])->filter(function($member_id) use($voter) { + return $member_id !== $voter; + })->all(); + $model->advisory->syncMembers(CompanyMember::byUuids($members)->get(), AdvisoryMemberRank::ORDINARY, $model->company); + $model->advisory->syncMembers(CompanyMember::byUuids([$voter])->get(), AdvisoryMemberRank::VOTER, $model->company); + return fractal($model->fresh(), new AdvisoryCompanyTransformer())->respond(); + } + + +} diff --git a/app/Services/Forms/Advisories/AdvisoryForms.php b/app/Services/Forms/Advisories/AdvisoryForms.php new file mode 100644 index 0000000..492d814 --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryForms.php @@ -0,0 +1,188 @@ + 'Добавление подразделения', 'update' => 'Редактирование подразделения']; + + public function form(?string $id = null, array $data = []): array { + $model = Advisory::byUuid($id)->first(); + return [ + 'title' => $this->formTitle($model), + 'frames' => [ + ['title' => 'Общие сведения', 'groups' => $this->form1Groups($model)], + // ['title' => 'Руководство', 'groups' => $this->form2Groups($model)] + ] + ]; + } + + public function form1Groups(?Advisory $model): array { + $groups = [ + ['name' => 'common', 'title' => '', 'fields' => $this->commonGroupFields($model)] + ]; + return ['data' => $groups]; + } + + public function form2Groups(?Advisory $model): array { + $groups = [ + ['name' => 'management', 'title' => '', 'fields' => $this->managementGroupFields($model)] + ]; + return ['data' => $groups]; + } + + public function commonGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'type', + 'title' => 'Тип подразделения', + 'type' => FieldType::RELATION, + 'required' => true, + 'appearance' => 'radio', + 'options' => $this->getRelationItems(AdvisoryType::TITLES), + 'value' => $this->getRelationValue(AdvisoryType::TITLES, $model->type ?? null) + ], + [ + 'name' => 'title', + 'title' => 'Название подразделения', + 'type' => FieldType::TEXT, + 'required' => true, + 'value' => $model->title ?? null + ], + [ + 'name' => 'number', + 'title' => 'Обозначение подразделения', + 'type' => FieldType::STRING, + 'required' => true, + 'value' => $model->number ?? null + ], + [ + 'name' => 'email', + 'title' => 'Электронная почта', + 'type' => FieldType::STRING, + 'value' => $model->email ?? null + ], + [ + 'name' => 'phone', + 'title' => 'Телефон', + 'type' => FieldType::STRING, + 'value' => $model->phone ?? null + ], + [ + 'name' => 'director_name', + 'title' => 'Руководитель', + 'type' => FieldType::STRING, + 'value' => $model->director_name ?? null + ], + [ + 'name' => 'secretary_name', + 'title' => 'Секретарь', + 'type' => FieldType::STRING, + 'value' => $model->secretary_name ?? null + ], + [ + 'name' => 'document', + 'title' => 'Списочный состав', + 'type' => FieldType::DOCUMENT, + 'value' => ($model->document ?? null) ? fractal($model->document, new AssetTransformer()) : null + ], + /* + [ + 'name' => 'logo', + 'title' => 'Логотип', + 'type' => FieldType::IMAGE, + 'value' => ($model->logo ?? null) ? fractal($model->logo, new AssetTransformer()) : null + ] + */ + ]; + return ['data' => $fields]; + } + + public function managementGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'chairman', + 'title' => 'Руководитель', + 'type' => FieldType::RELATION, + //'required' => true, + 'options' => fractal(CompanyMember::all(), new CompanyMemberTransformer()), + 'value' => ($val = $model->chairman ?? null) ? fractal($val, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'vices', + 'title' => 'Заместители', + 'type' => FieldType::RELATION, + 'multiple' => true, + 'options' => fractal(CompanyMember::all(), new CompanyMemberTransformer()), + 'value' => $model ? fractal($model->chairmanVices, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'secretary', + 'title' => 'Ответственный секретарь', + 'type' => FieldType::RELATION, + //'required' => true, + 'options' => fractal(CompanyMember::all(), new CompanyMemberTransformer()), + 'value' => ($val = $model->secretary ?? null) ? fractal($val, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'assistants', + 'title' => 'Помощники секретаря', + 'type' => FieldType::RELATION, + 'multiple' => true, + 'options' => fractal(CompanyMember::all(), new CompanyMemberTransformer()), + 'value' => $model ? fractal($model->secretaryAssistants, new CompanyMemberTransformer()) : null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): JsonResponse { + $parent = Advisory::byUuid($data['parent'] ?? null)->firstOrFail(); + $model = $parent->children()->create(); + $this->updateData($model, $data); + return fractal($model, new AdvisoryTransformer())->respond(201); + } + + public function update(string $id, array $data): JsonResponse { + $model = Advisory::byUuid($id)->firstOrFail(); + $this->updateData($model, $data); + return fractal($model->fresh(), new AdvisoryTransformer())->respond(); + } + + public function updateData(Advisory $model, $data) { + $data['name'] = $this->makeName($data); + $model->update(collect($data)->only('type', 'name', 'title', 'number', 'email', 'phone', 'director_name', 'secretary_name')->all()); + $this->syncMembers($model, $data); + $model->setLogo($data['logo'] ?? null); + $model->setDocument($data['document'] ?? null); + } + + public function makeName($data): string { + $val = $data['number'] ?? $data['title'] ?? ''; + return Str::lower(Str::replace(' ', '', Str::transliterate($val))); + } + + + public function syncMembers(Advisory $model, $data) { + $ranksByFields = ['chairman' => AdvisoryMemberRank::CHAIRMAN, 'vices' => AdvisoryMemberRank::VICE_CHAIRMAN, + 'secretary' => AdvisoryMemberRank::SECRETARY, 'assistants' => AdvisoryMemberRank::SECRETARY_ASSISTANT, 'ordinary' => AdvisoryMemberRank::ORDINARY]; + collect($ranksByFields)->each(function($rank, $field) use($model, $data) { + if (array_key_exists($field, $data)) $model->syncMembers(CompanyMember::byUuids($data[$field])->get(), $rank); + }); + } + + +} diff --git a/app/Services/Forms/Advisories/AdvisoryFormsServices.php b/app/Services/Forms/Advisories/AdvisoryFormsServices.php new file mode 100644 index 0000000..d3b60ce --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryFormsServices.php @@ -0,0 +1,13 @@ + AdvisoryCompaniesForms::class, + 'advisoryCompanyMembers' => AdvisoryCompanyMembersForms::class, + 'advisory' => AdvisoryForms::class, + 'advisoryInfo' => AdvisoryInfoForms::class, + 'advisoryGroup' => AdvisoryGroupForms::class + ]; +} diff --git a/app/Services/Forms/Advisories/AdvisoryGroupForms.php b/app/Services/Forms/Advisories/AdvisoryGroupForms.php new file mode 100644 index 0000000..e64e120 --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryGroupForms.php @@ -0,0 +1,71 @@ + 'Добавление направления', 'update' => 'Редактирование направления']; + + public function form(?string $id = null, array $data = []): array { + $model = Advisory::byUuid($id)->first(); + return [ + 'title' => $this->formTitle($model), + 'frames' => [ + ['title' => 'Общие сведения', 'groups' => $this->form1Groups($model)] + ] + ]; + } + + public function form1Groups(?Advisory $model): array { + $groups = [ + ['name' => 'common', 'title' => '', 'fields' => $this->commonGroupFields($model)] + ]; + return ['data' => $groups]; + } + + public function commonGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'title', + 'title' => 'Название подразделения', + 'type' => FieldType::TEXT, + 'required' => true, + 'value' => $model->title ?? null + ] + ]; + return ['data' => $fields]; + } + + + public function store(array $data): JsonResponse { + $parent = Advisory::byUuid($data['parent'] ?? null)->firstOrFail(); + $data['name'] = $this->makeName($data); + $model = $parent->children()->create(collect($data)->only('name', 'title')->all()); + $model->setLogo($data['logo'] ?? null); + return fractal($model, new AdvisoryTransformer())->respond(201); + } + + public function update(string $id, array $data): JsonResponse { + $model = Advisory::byUuid($id)->firstOrFail(); + $data['name'] = $this->makeName($data); + $model->update(collect($data)->only('name', 'title')->all()); + $model->setLogo($data['logo'] ?? null); + return fractal($model->fresh(), new AdvisoryTransformer())->respond(); + } + + public function makeName($data): string { + return Str::slug(Str::transliterate($data['title'] ?? '')); + } + +} diff --git a/app/Services/Forms/Advisories/AdvisoryInfoForms.php b/app/Services/Forms/Advisories/AdvisoryInfoForms.php new file mode 100644 index 0000000..2bdeef1 --- /dev/null +++ b/app/Services/Forms/Advisories/AdvisoryInfoForms.php @@ -0,0 +1,92 @@ + '', 'update' => 'Профиль подкомитета']; + + public function form(?string $id = null, array $data = []): array { + $model = Advisory::byUuid($id)->first(); + $groups = [ + ['name' => 'contacts', 'title' => 'Контакты', 'fields' => $this->contactsGroupFields($model)], + ['name' => 'management', 'title' => 'Руководители и секретариат', 'fields' => $this->managementGroupFields($model)] + ]; + return ['title' => $this->formTitle($model), 'btnSaveHidden' => true, 'data' => $groups]; + } + + public function contactsGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'caption', + 'title' => 'Наименование', + 'type' => FieldType::STRING, + 'readonly' => true, + 'value' => $model->caption ?? null + ], + [ + 'name' => 'email', + 'title' => 'Электронная почта', + 'type' => FieldType::STRING, + 'readonly' => true, + 'value' => $model->email ?? null + ], + [ + 'name' => 'phone', + 'title' => 'Телефон', + 'type' => FieldType::STRING, + 'readonly' => true, + 'value' => $model->phone ?? null + ] + ]; + return ['data' => $fields]; + } + + public function managementGroupFields(?Advisory $model): array { + $fields = [ + [ + 'name' => 'chairman', + 'title' => 'Руководитель', + 'type' => FieldType::RELATION, + 'readonly' => true, + 'value' => ($val = $model->chairman ?? null) ? fractal($val, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'vices', + 'title' => 'Заместители', + 'type' => FieldType::RELATION, + 'readonly' => true, + 'value' => $model ? fractal($model->chairmanVices, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'secretary', + 'title' => 'Ответственный секретарь', + 'type' => FieldType::RELATION, + 'readonly' => true, + 'value' => ($val = $model->secretary ?? null) ? fractal($val, new CompanyMemberTransformer()) : null + ], + [ + 'name' => 'assistants', + 'title' => 'Помощники секретаря', + 'type' => FieldType::RELATION, + 'readonly' => true, + 'value' => $model ? fractal($model->secretaryAssistants, new CompanyMemberTransformer()) : null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): void { + } + + public function update(string $id, array $data): void { + } + + +} diff --git a/app/Services/Forms/Companies/CompanyForms.php b/app/Services/Forms/Companies/CompanyForms.php new file mode 100644 index 0000000..d3baa40 --- /dev/null +++ b/app/Services/Forms/Companies/CompanyForms.php @@ -0,0 +1,91 @@ + 'Создание новой организации', 'update' => 'Редактирование организации']; + + public function form(?string $id = null, array $data = []): array { + $model = Company::byUuid($id)->first(); + $groups = [ + ['name' => 'common', 'fields' => $this->commonGroupFields($model)] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?Company $model): array { + $fields = [ + [ + 'name' => 'inn', + 'title' => 'ИНН', + 'type' => FieldType::STRING, + 'required' => true, + 'readonly' => !!$model, + 'value' => $model->inn ?? null + ], + [ + 'name' => 'name', + 'title' => 'Наименование организации', + 'type' => FieldType::STRING, + 'required' => true, + 'value' => $model->name ?? null + ], + [ + 'name' => 'address', + 'title' => 'Юридический адрес', + 'type' => FieldType::STRING, + 'required' => true, + 'value' => $model->legalAddress->full ?? null + ], + [ + 'name' => 'phone', + 'title' => 'Телефон', + 'type' => FieldType::STRING, + 'required' => false, + 'value' => $model->phone->value ?? null + ], + [ + 'name' => 'email', + 'title' => 'Email', + 'type' => FieldType::STRING, + 'required' => false, + 'value' => $model->email->value ?? null + ], + [ + 'name' => 'logo', + 'title' => 'Логотип', + 'type' => FieldType::IMAGE, + 'value' => ($model->logo ?? null) ? fractal($model->logo, new AssetTransformer()) : null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): ?JsonResponse { + if (!empty($data['inn']) && ($model = Company::getByData($data))) { + return fractal($model, new CompanyTransformer())->respond(); + } + } + + public function update(string $id, array $data): ?JsonResponse { + $model = Company::byUuid($id)->firstOrFail(); + if ($val = trim($data['name'] ?? null)) $model->update(['name' => $val]); + if ($val = trim($data['address'] ?? null)) $model->setAddress($val); + if ($val = trim($data['phone'] ?? null)) $model->setPhone($val); + if ($val = trim($data['email'] ?? null)) $model->setEmail($val); + $model->setTypes($data['types'] ?? []); + $model->setLogo($data['logo'] ?? null); + return fractal($model->fresh(), new CompanyTransformer())->respond(); + } + + +} diff --git a/app/Services/Forms/Companies/CompanyFormsServices.php b/app/Services/Forms/Companies/CompanyFormsServices.php new file mode 100644 index 0000000..a20acc8 --- /dev/null +++ b/app/Services/Forms/Companies/CompanyFormsServices.php @@ -0,0 +1,11 @@ + CompanyForms::class, + 'companyMember' => CompanyMemberForms::class, + 'department' => DepartmentForms::class + ]; +} diff --git a/app/Services/Forms/Companies/CompanyMemberForms.php b/app/Services/Forms/Companies/CompanyMemberForms.php new file mode 100644 index 0000000..fdb00f2 --- /dev/null +++ b/app/Services/Forms/Companies/CompanyMemberForms.php @@ -0,0 +1,147 @@ + 'Добавление сотрудника организации', 'update' => 'Редактирование сотрудника']; + + public function form(?string $id = null, array $data = []): array { + $model = CompanyMember::byUuid($id)->first(); + $groups = [ + [ + 'name' => 'common', + 'fields' => $this->commonGroupFields($model), + 'dynamic' => [ + ['field' => 'role', 'hide' => ['pages']], + ['field' => 'role', 'value' => CompanyMemberRole::MODERATOR, 'show' => ['pages']] + ] + ] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?CompanyMember $model): array { + $fields = [ + [ + 'name' => 'email', + 'title' => 'Email', + 'type' => FieldType::STRING, + 'required' => true, + 'readonly' => !!$model && !Auth::user()->isPrivileged, + 'value' => $model->user->email ?? null + ], + [ + 'name' => 'name', + 'title' => 'ФИО', + 'type' => FieldType::TEXT, + 'required' => true, + 'value' => $model->user->name ?? null + ], + [ + 'name' => 'position', + 'title' => 'Должность', + 'type' => FieldType::TEXT, + 'required' => true, + 'value' => $model->position ?? null + ], + [ + 'name' => 'phone', + 'title' => 'Телефон', + 'type' => FieldType::STRING, + 'value' => $model->user->phone ?? null + ], + [ + 'name' => 'room', + 'title' => 'Кабинет', + 'type' => FieldType::STRING, + 'value' => $model->room ?? null + ], + [ + 'name' => 'intercom', + 'title' => 'Внутренний телефон', + 'type' => FieldType::STRING, + 'value' => $model->intercom ?? null + ], + [ + 'name' => 'role', + 'title' => 'Роль', + 'type' => FieldType::RELATION, + 'required' => true, + 'appearance' => 'radio', + 'options' => $this->getRelationItems(CompanyMemberRole::TITLES), + 'value' => $this->getRelationValue(CompanyMemberRole::TITLES, $model->role ?? null) + ], + [ + 'name' => 'pages', + 'title' => 'Разделы сайта', + 'type' => FieldType::RELATION, + 'multiple' => true, + 'options' => fractal(Page::all(), new PageTransformer()), + 'value' => null + ] + /* + [ + 'name' => 'rank', + 'title' => 'Ранг сотрудника', + 'type' => FieldType::RELATION, + 'required' => true, + 'appearance' => 'radio', + 'options' => $this->getRelationItems(CompanyMemberRank::TITLES), + 'value' => $model ? $model->parsedRank + ['id' => $model->rank] : null + ], + [ + 'name' => 'representative', + 'title' => 'Назначить администратором', + 'type' => FieldType::BOOLEAN, + 'value' => $model->representative ?? null + ] + */ + ]; + /* + if ($model) $fields[] = [ + 'name' => 'department', + 'title' => 'Отдел', + 'type' => FieldType::RELATION, + 'options' => fractal($model->company->departments ?? [], new DepartmentTransformer()), + 'value' => $model ? fractal($model->department, new DepartmentTransformer()) : null + ]; + */ + + return ['data' => $fields]; + } + + + + public function store(array $data): ?JsonResponse { + if (($department = Department::byUuid($data['department'] ?? null)->first()) && ($user = User::getByData(collect($data)->except('role')->all(), true))) { + $model = $department->addMember($user, $data['position'] ?? null); + $model->update(['position' => $data['position'] ?? null, 'role' => $data['role'] ?? null, 'room' => $data['room'] ?? null, 'intercom' => $data['intercom'] ?? null]); + return fractal($model, new CompanyMemberTransformer())->respond(); + } + } + + public function update(string $id, array $data): ?JsonResponse { + $model = CompanyMember::byUuid($id)->firstOrFail(); + $model->update(['position' => $data['position'] ?? null, 'role' => $data['role'] ?? null, 'room' => $data['room'] ?? null, 'intercom' => $data['intercom'] ?? null]); + if ($department = Department::byUuid($data['department'] ?? null)->first()) $model->update(['department_id' => $department->id]); + $model->user->update(['name' => $data['name'] ?? null, 'phone' => $data['phone'] ?? null]); + if (($email = $data['email'] ?? null) && !User::query()->where(['email' => $email])->exists()) $model->user->update(['email' => $data['email']]); + return fractal($model->fresh(), new CompanyMemberTransformer())->respond(); + } + + +} diff --git a/app/Services/Forms/Companies/DepartmentForms.php b/app/Services/Forms/Companies/DepartmentForms.php new file mode 100644 index 0000000..94f8bf8 --- /dev/null +++ b/app/Services/Forms/Companies/DepartmentForms.php @@ -0,0 +1,56 @@ + 'Создание подразделение организации', 'update' => 'Редактирование подразделения']; + + public function form(?string $id = null, array $data = []): array { + $model = Department::byUuid($id)->first(); + $groups = [ + ['name' => 'common', 'fields' => $this->commonGroupFields($model)] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?Department $model): array { + $fields = [ + [ + 'name' => 'title', + 'title' => 'Название подразделения', + 'type' => FieldType::STRING, + 'required' => true, + 'value' => $model->title ?? null + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): ?JsonResponse { + $parent = Department::byUuid($data['department'] ?? null)->firstOrFail(); + if ($title = trim($data['title'] ?? null)) { + $model = $parent->addChildren(Str::transliterate($title), $title); + return fractal($model, new DepartmentTransformer())->respond(); + } + } + + public function update(string $id, array $data): ?JsonResponse { + $model = Department::byUuid($id)->firstOrFail(); + if ($val = trim($data['title'] ?? null)) { + $model->update(['title' => $val]); + if ($model->name !== 'root') $model->update(['name' => Str::transliterate($val)]); + } + return fractal($model, new DepartmentTransformer())->respond(); + } + + +} diff --git a/app/Services/Forms/FormsService.php b/app/Services/Forms/FormsService.php index 7dfcfe0..d14ece8 100644 --- a/app/Services/Forms/FormsService.php +++ b/app/Services/Forms/FormsService.php @@ -2,6 +2,8 @@ namespace App\Services\Forms; +use App\Services\Forms\Advisories\AdvisoryFormsServices; +use App\Services\Forms\Companies\CompanyFormsServices; use App\Services\Forms\Feedback\FeedbackFormsServices; use App\Services\Forms\Pages\PageFormsServices; use App\Services\Forms\Publications\PublicationFormsServices; @@ -17,6 +19,8 @@ class FormsService { RegistryFormsServices::class, UserFormsServices::class, FeedbackFormsServices::class, + AdvisoryFormsServices::class, + CompanyFormsServices::class ]; public function __construct() { diff --git a/app/Support/ParticipatableTrait.php b/app/Support/ParticipatableTrait.php deleted file mode 100644 index 06afbe5..0000000 --- a/app/Support/ParticipatableTrait.php +++ /dev/null @@ -1,12 +0,0 @@ -morphMany(Participant::class, 'participatable'); - } -} diff --git a/app/Transformers/Advisories/AdvisoryCompanyTransformer.php b/app/Transformers/Advisories/AdvisoryCompanyTransformer.php new file mode 100644 index 0000000..d8e394c --- /dev/null +++ b/app/Transformers/Advisories/AdvisoryCompanyTransformer.php @@ -0,0 +1,53 @@ + $model->uuid, + 'title' => $model->title + ]; + } + + public function includeAdvisory(AdvisoryCompany $model): ?Item { + return $model->advisory ? $this->item($model->advisory, new AdvisoryTransformer()) : null; + } + + public function includeCompany(AdvisoryCompany $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + public function includeVoter(AdvisoryCompany $model): ?Item { + return $model->voter ? $this->item($model->voter, new AdvisoryMemberTransformer()) : null; + } + + public function includeAdvisoryMembers(AdvisoryCompany $model): Collection { + return $this->collection($model->advisoryMembers()->whereIn('rank', [AdvisoryMemberRank::ORDINARY, AdvisoryMemberRank::VOTER])->get(), new AdvisoryMemberTransformer()); + } + + public function includeCompanyMembers(AdvisoryCompany $model): Collection { + return $this->collection($model->companyMembers, new CompanyMemberTransformer()); + } + + public function includePermissions(AdvisoryCompany $model): Primitive { + return $this->primitive((new PermissionsService($model))->get()); + } + +} \ No newline at end of file diff --git a/app/Transformers/Advisories/AdvisoryMemberTransformer.php b/app/Transformers/Advisories/AdvisoryMemberTransformer.php new file mode 100644 index 0000000..4e94b63 --- /dev/null +++ b/app/Transformers/Advisories/AdvisoryMemberTransformer.php @@ -0,0 +1,34 @@ + $model->uuid, + 'rank' => $model->parsedRank, + 'title' => $model->title + ]; + } + + public function includeAdvisory(AdvisoryMember $model): ?Item { + return $model->advisory ? $this->item($model->advisory, new AdvisoryTransformer()) : null; + } + + public function includeCompanyMember(AdvisoryMember $model): ?Item { + return $model->companyMember ? $this->item($model->companyMember, new CompanyMemberTransformer()) : null; + } + + +} \ No newline at end of file diff --git a/app/Transformers/Advisories/AdvisoryTransformer.php b/app/Transformers/Advisories/AdvisoryTransformer.php new file mode 100644 index 0000000..356a228 --- /dev/null +++ b/app/Transformers/Advisories/AdvisoryTransformer.php @@ -0,0 +1,80 @@ + $model->uuid, + 'type' => $model->parsedType, + 'name' => $model->name, + 'title' => $model->title, + 'number' => $model->number, + 'email' => $model->email, + 'phone' => $model->phone, + 'director_name' => $model->director_name, + 'secretary_name' => $model->secretary_name, + 'is_main' => boolval($model->is_main), + 'caption' => $model->caption + ]; + } + + public function includeLogo(Advisory $model): ?Item { + return $model->logo ? $this->item($model->logo, new AssetTransformer()) : null; + } + + public function includeDocument(Advisory $model): ?Item { + return $model->document ? $this->item($model->document, new AssetTransformer()) : null; + } + + public function includeCompanies(Advisory $model): Collection { + return $this->collection($model->companies, new CompanyTransformer()); + } + + public function includeAdvisoryCompanies(Advisory $model): Collection { + return $this->collection($model->advisoryCompanies, new AdvisoryCompanyTransformer()); + } + + public function includeMembers(Advisory $model): Collection { + return $this->collection($model->members, new AdvisoryMemberTransformer()); + } + + public function includeSecretary(Advisory $model): ?Item { + return $model->secretary ? $this->item($model->secretary, new CompanyMemberTransformer()) : null; + } + + public function includeParent(Advisory $model): ?Item { + return $model->parent ? $this->item($model->parent, new AdvisoryTransformer()) : null; + } + + public function includeChildren(Advisory $model): Collection { + return $this->collection($model->children, new AdvisoryTransformer()); + } + + public function includeObject(Advisory $model): ?Item { + return $model->object ? $this->item($model->object, new ObjectTransformer()) : null; + } + + public function includePermissions(Advisory $model): Primitive { + return $this->primitive((new PermissionsService($model))->get()); + } + + +} \ No newline at end of file diff --git a/app/Transformers/Companies/AddressTransformer.php b/app/Transformers/Companies/AddressTransformer.php new file mode 100644 index 0000000..a30fd35 --- /dev/null +++ b/app/Transformers/Companies/AddressTransformer.php @@ -0,0 +1,38 @@ + $model->uuid, + 'type' => $model->type, + 'full' => $model->full, + 'postcode' => $model->postcode, + 'country' => $model->country, + 'region' => $model->region, + 'city' => $model->city, + 'district' => $model->district, + 'street' => $model->street, + 'house' => $model->house, + 'block' => $model->block, + 'office' => $model->office + ]; + } + + public function includeCompany(Address $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + +} diff --git a/app/Transformers/Companies/BankDetailsTransformer.php b/app/Transformers/Companies/BankDetailsTransformer.php new file mode 100644 index 0000000..8b660b9 --- /dev/null +++ b/app/Transformers/Companies/BankDetailsTransformer.php @@ -0,0 +1,34 @@ + $model->uuid, + 'bik' => $model->bik, + 'bank' => $model->bank, + 'address' => $model->address, + 'checking_account' => $model->checking_account, + 'correspondent_account' => $model->correspondent_account + ]; + } + + public function includeCompany(BankDetails $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + +} diff --git a/app/Transformers/Companies/CompanyMemberTransformer.php b/app/Transformers/Companies/CompanyMemberTransformer.php new file mode 100644 index 0000000..ea39d2f --- /dev/null +++ b/app/Transformers/Companies/CompanyMemberTransformer.php @@ -0,0 +1,56 @@ + $model->uuid, + 'position' => $model->position, + 'rank' => $model->parsedRank, + 'role' => $model->parsedRole, + 'caption' => $model->user->name, + 'subtitle' => "{$model->company->name}, {$model->position}", + 'room' => $model->room, + 'intercom' => $model->intercom + ]; + } + + public function includeUser(CompanyMember $model): ?Item { + return $model->user ? $this->item($model->user, new UserTransformer()) : null; + } + + public function includeCompany(CompanyMember $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + public function includeDepartment(CompanyMember $model): ?Item { + return $model->department ? $this->item($model->department, new DepartmentTransformer()) : null; + } + + public function includeAdvisoryMembership(CompanyMember $model): Collection { + return $this->collection($model->advisoryMembership, new AdvisoryMemberTransformer()); + } + + public function includeIsSubordinate(CompanyMember $model): ?Primitive { + return $this->primitive($model->isSubordinateFor(Auth::user())); + } + + +} diff --git a/app/Transformers/Companies/CompanyTransformer.php b/app/Transformers/Companies/CompanyTransformer.php new file mode 100644 index 0000000..1d54e18 --- /dev/null +++ b/app/Transformers/Companies/CompanyTransformer.php @@ -0,0 +1,100 @@ + $model->uuid, + 'name' => $model->name, + 'full_name' => $model->full_name, + 'inn' => $model->inn, + 'kpp' => $model->kpp, + 'ogrn' => $model->ogrn, + 'okved' => $model->okved, + 'okato' => $model->okato, + 'tax_registration_date' => $model->tax_registration_date ? $model->tax_registration_date->toIso8601String() : null + ]; + } + + public function includeLogo(Company $model): ?Item { + return $model->logo ? $this->item($model->logo, new AssetTransformer()) : null; + } + + public function includeTypes(Company $model): Collection { + return $this->collection($model->types, new CompanyTypeTransformer()); + } + + public function includeDepartments(Company $model): Collection { + return $this->collection($model->departments, new DepartmentTransformer()); + } + + public function includeRootDepartment(Company $model): ?Item { + return $model->rootDepartment ? $this->item($model->rootDepartment, new DepartmentTransformer()) : null; + } + + public function includeMembers(Company $model): Collection { + return $this->collection($model->members, new CompanyMemberTransformer()); + } + + public function includeRootMembers(Company $model): Collection { + return $this->collection($model->rootMembers, new CompanyMemberTransformer()); + } + + public function includeRepresentativeMember(Company $model): ?Item { + return $model->representativeMember ? $this->item($model->representativeMember, new CompanyMemberTransformer()) : null; + } + + public function includeAddresses(Company $model): Collection { + return $this->collection($model->addresses, new AddressTransformer()); + } + + public function includeLegalAddress(Company $model): Item { + return $this->item($model->legalAddress, new AddressTransformer()); + } + + public function includeActualAddress(Company $model): Item { + return $this->item($model->actualAddress, new AddressTransformer()); + } + + public function includeBankDetails(Company $model): Item { + return $this->item($model->bankDetails, new BankDetailsTransformer()); + } + + public function includeContacts(Company $model): Collection { + return $this->collection($model->contacts, new ContactTransformer()); + } + + public function includePhones(Company $model): Collection { + return $this->collection($model->phones, new ContactTransformer()); + } + + public function includeEmails(Company $model): Collection { + return $this->collection($model->emails, new ContactTransformer()); + } + + public function includePermissions(Company $model): Primitive { + return $this->primitive((new PermissionsService($model))->get()); + } + + public function includeAdvisoryCompanies(Company $model): Collection { + return $this->collection($model->advisoryCompanies, new AdvisoryCompanyTransformer()); + } +} \ No newline at end of file diff --git a/app/Transformers/Companies/CompanyTypeTransformer.php b/app/Transformers/Companies/CompanyTypeTransformer.php new file mode 100644 index 0000000..44c0721 --- /dev/null +++ b/app/Transformers/Companies/CompanyTypeTransformer.php @@ -0,0 +1,31 @@ + $model->name, + 'name' => $model->name, + 'title' => $model->title + ]; + } + + public function includeCompany(CompanyType $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + +} diff --git a/app/Transformers/Companies/ContactTransformer.php b/app/Transformers/Companies/ContactTransformer.php new file mode 100644 index 0000000..791670e --- /dev/null +++ b/app/Transformers/Companies/ContactTransformer.php @@ -0,0 +1,30 @@ + $model->parsedType, + 'value' => $model->value + ]; + } + + public function includeCompany(Contact $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + +} diff --git a/app/Transformers/Companies/DepartmentTransformer.php b/app/Transformers/Companies/DepartmentTransformer.php new file mode 100644 index 0000000..2c5a929 --- /dev/null +++ b/app/Transformers/Companies/DepartmentTransformer.php @@ -0,0 +1,41 @@ + $model->uuid, + 'name' => $model->name, + 'title' => $model->title + ]; + } + + public function includeCompany(Department $model): ?Item { + return $model->company ? $this->item($model->company, new CompanyTransformer()) : null; + } + + public function includeParent(Department $model): ?Item { + return $model->parent ? $this->item($model->parent, new DepartmentTransformer()) : null; + } + + public function includeChildren(Department $model): Collection { + return $this->collection($model->children, new DepartmentTransformer()); + } + + public function includeMembers(Department $model): Collection { + return $this->collection($model->members, new CompanyMemberTransformer()); + } + +} \ No newline at end of file diff --git a/database/migrations/2021_08_23_111709_create_companies_table.php b/database/migrations/2021_08_23_111709_create_companies_table.php new file mode 100644 index 0000000..5465eec --- /dev/null +++ b/database/migrations/2021_08_23_111709_create_companies_table.php @@ -0,0 +1,44 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('logo_id')->nullable(); + $table->string('name')->nullable(); + $table->string('full_name', 500)->nullable(); + $table->string('inn')->index()->unique(); + $table->string('kpp', 20)->nullable(); + $table->string('ogrn', 20)->nullable(); + $table->string('okpo', 20)->nullable(); + $table->string('okved', 20)->nullable(); + $table->string('okato', 20)->nullable(); + $table->timestamp('tax_registration_date')->nullable(); + $table->boolean('is_main')->index()->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('companies'); + } +} diff --git a/database/migrations/2021_08_23_154821_create_company_members_table.php b/database/migrations/2021_08_23_154821_create_company_members_table.php new file mode 100644 index 0000000..c60d3d9 --- /dev/null +++ b/database/migrations/2021_08_23_154821_create_company_members_table.php @@ -0,0 +1,43 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('user_id')->index()->nullable(); + $table->integer('company_id')->index()->nullable(); + $table->integer('department_id')->index()->nullable(); + $table->smallInteger('rank')->index()->default(CompanyMemberRank::EMPLOYEE); + $table->string('role')->index()->nullable(); + $table->string('position')->index()->nullable(); + $table->string('room')->index()->nullable(); + $table->string('intercom')->index()->nullable(); + $table->boolean('selected')->index()->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_members'); + } +} diff --git a/database/migrations/2021_09_16_194429_create_company_addresses_table.php b/database/migrations/2021_09_16_194429_create_company_addresses_table.php new file mode 100644 index 0000000..4267e5f --- /dev/null +++ b/database/migrations/2021_09_16_194429_create_company_addresses_table.php @@ -0,0 +1,45 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('company_id')->index(); + $table->string('type')->index(); + $table->string('full', 500)->nullable(); + $table->string('postcode')->nullable(); + $table->string('country')->nullable(); + $table->string('region')->nullable(); + $table->string('city')->nullable(); + $table->string('district')->nullable(); + $table->string('street')->nullable(); + $table->string('house')->nullable(); + $table->string('block')->nullable(); + $table->string('office')->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_addresses'); + } +} diff --git a/database/migrations/2021_09_16_201659_create_company_bank_details_table.php b/database/migrations/2021_09_16_201659_create_company_bank_details_table.php new file mode 100644 index 0000000..e6a6f0a --- /dev/null +++ b/database/migrations/2021_09_16_201659_create_company_bank_details_table.php @@ -0,0 +1,39 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('company_id')->index(); + $table->string('bik')->nullable(); + $table->string('bank')->nullable(); + $table->string('address')->nullable(); + $table->string('checking_account')->nullable(); + $table->string('correspondent_account')->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_bank_details'); + } +} diff --git a/database/migrations/2022_07_01_204328_create_company_contacts_table.php b/database/migrations/2022_07_01_204328_create_company_contacts_table.php new file mode 100644 index 0000000..7322cde --- /dev/null +++ b/database/migrations/2022_07_01_204328_create_company_contacts_table.php @@ -0,0 +1,34 @@ +id(); + $table->integer('company_id')->index(); + $table->string('type', 20)->index(); + $table->string('value')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_contacts'); + } +} diff --git a/database/migrations/2022_07_01_204528_create_company_departments_table.php b/database/migrations/2022_07_01_204528_create_company_departments_table.php new file mode 100644 index 0000000..7963057 --- /dev/null +++ b/database/migrations/2022_07_01_204528_create_company_departments_table.php @@ -0,0 +1,38 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('company_id')->nullable()->index(); + $table->integer('parent_id')->nullable()->index(); + $table->string('name')->index()->nullable(); + $table->string('title')->index()->nullable(); + $table->smallInteger('level')->index()->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_departments'); + } +} diff --git a/database/migrations/2022_07_01_204530_create_company_types_table.php b/database/migrations/2022_07_01_204530_create_company_types_table.php new file mode 100644 index 0000000..df1cca4 --- /dev/null +++ b/database/migrations/2022_07_01_204530_create_company_types_table.php @@ -0,0 +1,33 @@ +id(); + $table->integer('company_id')->index()->nullable(); + $table->string('name')->index()->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_types'); + } +} diff --git a/database/migrations/2022_07_01_191111_create_jobs_table.php b/database/migrations/2022_07_01_204700_create_jobs_table.php similarity index 100% rename from database/migrations/2022_07_01_191111_create_jobs_table.php rename to database/migrations/2022_07_01_204700_create_jobs_table.php diff --git a/database/migrations/2022_09_19_211521_create_advisories_table.php b/database/migrations/2022_09_19_211521_create_advisories_table.php new file mode 100644 index 0000000..8c47f19 --- /dev/null +++ b/database/migrations/2022_09_19_211521_create_advisories_table.php @@ -0,0 +1,45 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('parent_id')->index()->default(0); + $table->integer('logo_id')->nullable(); + $table->integer('document_id')->nullable(); + $table->string('type')->index()->nullable(); + $table->string('name')->index()->nullable(); + $table->string('title')->index()->nullable(); + $table->string('number')->index()->nullable(); + $table->string('email')->index()->nullable(); + $table->string('phone')->index()->nullable(); + $table->string('director_name')->index()->nullable(); + $table->string('secretary_name')->index()->nullable(); + $table->boolean('is_main')->index()->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('advisories'); + } +} diff --git a/database/migrations/2022_09_19_211544_create_advisory_members_table.php b/database/migrations/2022_09_19_211544_create_advisory_members_table.php new file mode 100644 index 0000000..7236bc5 --- /dev/null +++ b/database/migrations/2022_09_19_211544_create_advisory_members_table.php @@ -0,0 +1,37 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('advisory_id')->index()->nullable(); + $table->integer('company_member_id')->index()->nullable(); + $table->integer('rank')->index()->default(AdvisoryMemberRank::ORDINARY); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('advisory_members'); + } +} diff --git a/database/migrations/2022_09_19_211700_create_advisory_companies_table.php b/database/migrations/2022_09_19_211700_create_advisory_companies_table.php new file mode 100644 index 0000000..1127162 --- /dev/null +++ b/database/migrations/2022_09_19_211700_create_advisory_companies_table.php @@ -0,0 +1,34 @@ +id(); + $table->char('uuid', 36)->index()->unique(); + $table->integer('advisory_id')->index()->nullable(); + $table->integer('company_id')->index()->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('advisory_companies'); + } +} diff --git a/database/seeders/Advisories/AdvisoriesTableSeeder.php b/database/seeders/Advisories/AdvisoriesTableSeeder.php new file mode 100644 index 0000000..8cee69c --- /dev/null +++ b/database/seeders/Advisories/AdvisoriesTableSeeder.php @@ -0,0 +1,83 @@ + [ + 'number' => 'ТК 465', + 'title' => 'Строительство', + 'type' => AdvisoryType::COMMITTEE, + 'is_main' => true, + //'members' => ['import' => 'import/advisories/tk465_members.xlsx'], + 'children' => [ + 'group1' => [ + 'title' => 'Организационно-методические и общетехнические вопросы в строительстве', + 'children' => [ + 'pk2' => [ + 'title' => 'Проектирование. Основные положения нормирования', + 'number' => 'ПК 2', + 'type' => AdvisoryType::COMMITTEE + ], + 'pk4' => [ + 'title' => 'Обследование и мониторинг технического состояния зданий и сооружений. Ремонт, восстановление и усиление конструкций зданий и сооружений', + 'number' => 'ПК 4', + 'type' => AdvisoryType::COMMITTEE + ], + 'pk6' => [ + 'title' => 'Пожаробезопасность в строительстве', + 'number' => 'ПК 6', + 'type' => AdvisoryType::COMMITTEE + ] + ] + ], + 'group2' => [ + 'title' => 'Здания и сооружения', + 'children' => [ + 'pk10' => [ + 'title' => 'Жилые, общественные и производственные здания и сооружения', + 'number' => 'ПК 2', + 'type' => AdvisoryType::COMMITTEE + ] + ] + ], + 'group3' => [ + 'title' => 'Наружные и внутренние инженерные сети и оборудование', + 'children' => [] + ], + 'group4' => [ + 'title' => 'Строительные конструкции и основания', + 'children' => [] + ] + ] + ] + ]; + + public function run() { + collect($this->advisories)->each(function($data, $name) { + $this->importAdvisory($name, $data); + }); + } + + public function importAdvisory($name, $data, $parent = null) { + $query = $parent ? $parent->children() : Advisory::query(); + $advisory = $query->firstOrCreate(['name' => $name]); + $advisory->update(collect($data)->except('members', 'children')->all()); + $this->importAdvisoryMembers($advisory, $data['members'] ?? []); + collect($data['children'] ?? [])->each(function($data, $name) use($advisory) { + $this->importAdvisory($name, $data, $advisory); + }); + } + + public function importAdvisoryMembers(Advisory $advisory, $data) { + if ($path = $data['import'] ?? null) Excel::import(new AdvisoryMembersImport($advisory), Storage::path($path)); + } + +} diff --git a/database/seeders/Advisories/AdvisoriesTablesSeeder.php b/database/seeders/Advisories/AdvisoriesTablesSeeder.php new file mode 100644 index 0000000..b810c3f --- /dev/null +++ b/database/seeders/Advisories/AdvisoriesTablesSeeder.php @@ -0,0 +1,11 @@ +call(AdvisoriesTableSeeder::class); + } +} diff --git a/database/seeders/Companies/CompaniesTableSeeder.php b/database/seeders/Companies/CompaniesTableSeeder.php new file mode 100644 index 0000000..5473797 --- /dev/null +++ b/database/seeders/Companies/CompaniesTableSeeder.php @@ -0,0 +1,56 @@ + [ + 'is_main' => 1, + 'members' => [ + 'test1@testnir.ru' => ['name' => 'Иванов Иван Иванович', 'position' => 'Генеральный директор', 'rank' => CompanyMemberRank::CHIEF], + 'test2@testnir.ru' => ['name' => 'Петров Петр Петрович', 'position' => 'Заместитель генерального директора', 'rank' => CompanyMemberRank::VICE] + ] + ] + ]; + public string $import = ''; + + public function run() { + collect($this->companies)->each(function($data, $inn) { + $company = Company::query()->firstOrCreate(['inn' => $inn]); + (new DaDataService($inn))->saveToCompany($company); + $company->update(collect($data)->except('departments', 'members', 'phone', 'email')->all()); + $company->setEmail($data['email'] ?? null); + $company->setPhone($data['phone'] ?? null); + $this->syncMembers($company->rootDepartment, $data['members'] ?? []); + $this->syncDepartments($company->rootDepartment, $data['departments'] ?? []); + }); + if ($this->import && Storage::exists($this->import)) Excel::import(new CompaniesImport(), Storage::path($this->import)); + } + + public function syncDepartments(Department $parent, $data) { + collect($data)->each(function($data, $name) use($parent) { + if ($department = $parent->addChildren($name, $data['title'] ?? null)) { + $this->syncMembers($department, $data['members'] ?? []); + $this->syncDepartments($department, $data['departments'] ?? []); + } + }); + } + + public function syncMembers(Department $department, $data) { + collect($data)->each(function($data, $email) use($department) { + $user = User::getByData(['email' => $email, 'name' => $data['name'] ?? '']); + $member = $department->addMember($user, $data['position'] ?? ''); + $member->update(['rank' => $data['rank'] ?? CompanyMemberRank::EMPLOYEE]); + }); + } +} diff --git a/database/seeders/Companies/CompaniesTablesSeeder.php b/database/seeders/Companies/CompaniesTablesSeeder.php new file mode 100644 index 0000000..68454f3 --- /dev/null +++ b/database/seeders/Companies/CompaniesTablesSeeder.php @@ -0,0 +1,11 @@ +call(CompaniesTableSeeder::class); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 9c0e792..d520623 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,6 +2,8 @@ namespace Database\Seeders; +use Database\Seeders\Advisories\AdvisoriesTablesSeeder; +use Database\Seeders\Companies\CompaniesTablesSeeder; use Database\Seeders\Dictionaries\DictionariesTablesSeeder; use Database\Seeders\Objects\ObjectsTablesSeeder; use Database\Seeders\Pages\PagesTableSeeder; @@ -17,5 +19,7 @@ class DatabaseSeeder extends Seeder { $this->call(ObjectsTablesSeeder::class); $this->call(DictionariesTablesSeeder::class); $this->call(PagesTableSeeder::class); + $this->call(CompaniesTablesSeeder::class); + $this->call(AdvisoriesTablesSeeder::class); } } diff --git a/database/seeders/Dictionaries/DictionariesTableSeeder.php b/database/seeders/Dictionaries/DictionariesTableSeeder.php index bd1a5f2..f806181 100644 --- a/database/seeders/Dictionaries/DictionariesTableSeeder.php +++ b/database/seeders/Dictionaries/DictionariesTableSeeder.php @@ -35,7 +35,7 @@ class DictionariesTableSeeder extends Seeder { ], 'activities' => [ 'title' => 'Направления деятельности', - 'items' => ['products' => 'Продукция', 'services' => 'Работы и услуги', 'management' => 'СМК'] + 'items' => ['products' => 'Продукция в строительстве', 'services' => 'Работы и услуги', 'management' => 'СМК'] ], 'research-types' => [ 'title' => 'Виды исследовательских работ', diff --git a/database/seeders/Objects/FieldsTableSeeder.php b/database/seeders/Objects/FieldsTableSeeder.php index 4433651..c16cb9a 100644 --- a/database/seeders/Objects/FieldsTableSeeder.php +++ b/database/seeders/Objects/FieldsTableSeeder.php @@ -175,7 +175,7 @@ class FieldsTableSeeder extends Seeder { 'required' => true ], 'activities' => [ - 'title' => 'Виды деятельности', + 'title' => 'Объект сертификации', 'type' => FieldType::RELATION, 'required' => true, 'multiple' => true, diff --git a/database/seeders/Pages/PagesTableSeeder.php b/database/seeders/Pages/PagesTableSeeder.php index bea3911..58c2c9e 100644 --- a/database/seeders/Pages/PagesTableSeeder.php +++ b/database/seeders/Pages/PagesTableSeeder.php @@ -73,7 +73,7 @@ class PagesTableSeeder extends Seeder 'children' => [ 'Руководство' => [], 'Секретариат' => [], - 'Структура' => [], + 'Структура' => ['type' => PageType::TK_STRUCTURE], 'Состав' => [], 'Документы' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CATEGORIZED], 'АИС ТК 465 «Строительство»' => [], @@ -95,14 +95,14 @@ class PagesTableSeeder extends Seeder 'Добровольная сертификация' => [ 'children' => [ 'О системе' => [], - 'Основополагающие документы' => [], - 'Решения ЦОС' => [], - 'Руководящие документы' => [], + 'Основополагающие документы' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CATEGORIZED], + 'Решения ЦОС' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], + 'Руководящие документы' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], 'Реестр органов по сертификации' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CERTIFIERS], 'Реестр испытательных лабораторий' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::LABORATORIES], 'Реестр экспертов' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::EXPERTS], 'Реестр сертификатов соответствия' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::CERTIFICATES], - 'Бланки документов' => [], + 'Бланки документов' => ['type' => PageType::REGISTRY, 'registry_type' => RegistryType::SIMPLE], ] ], 'Международная деятельность' => [ diff --git a/routes/api.php b/routes/api.php index 192ca75..6e6d6e9 100644 --- a/routes/api.php +++ b/routes/api.php @@ -78,4 +78,14 @@ Route::group(['middleware' => ['auth:api']], function() { Route::put('publications/published/{id}', 'Api\Publications\PublicationsController@published'); Route::delete('publications/{id}', 'Api\Publications\PublicationsController@destroy'); + + Route::apiResource('companies', 'Api\Companies\CompaniesController'); + Route::apiResource('members', 'Api\Companies\MembersController'); + Route::apiResource('departments', 'Api\Companies\DepartmentsController'); + + Route::apiResource('advisories', 'Api\Advisories\AdvisoriesController'); + Route::get('advisories/{id}/siblings', 'Api\Advisories\AdvisoriesController@siblings'); + Route::apiResource('advisory-companies', 'Api\Advisories\AdvisoryCompaniesController'); + Route::apiResource('advisory-members', 'Api\Advisories\AdvisoryMembersController'); + }); \ No newline at end of file diff --git a/storage/app/dadata/7736151499.json b/storage/app/dadata/7736151499.json new file mode 100644 index 0000000..2b6ec5f --- /dev/null +++ b/storage/app/dadata/7736151499.json @@ -0,0 +1 @@ +{"suggestions":[{"value":"\u0424\u0410\u0423 \"\u0424\u0426\u0421\"","unrestricted_value":"\u0424\u0410\u0423 \"\u0424\u0426\u0421\"","data":{"kpp":"770801001","capital":null,"invalid":null,"management":{"name":"\u041a\u043e\u043f\u044b\u0442\u0438\u043d \u0410\u043d\u0434\u0440\u0435\u0439 \u0412\u0438\u043a\u0442\u043e\u0440\u043e\u0432\u0438\u0447","post":"\u0414\u0418\u0420\u0415\u041a\u0422\u041e\u0420","disqualified":null},"founders":null,"managers":null,"predecessors":null,"successors":null,"branch_type":"MAIN","branch_count":0,"source":null,"qc":null,"hid":"bacefd9d49767cf886bc3b7490aefb4becd210a8095100abdd25a4da407775ec","type":"LEGAL","state":{"status":"ACTIVE","code":null,"actuality_date":1669248000000,"registration_date":827193600000,"liquidation_date":null},"opf":{"type":"2014","code":"75101","full":"\u0424\u0435\u0434\u0435\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e\u0435 \u0443\u0447\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435","short":"\u0424\u0413\u0410\u0423"},"name":{"full_with_opf":"\u0424\u0415\u0414\u0415\u0420\u0410\u041b\u042c\u041d\u041e\u0415 \u0410\u0412\u0422\u041e\u041d\u041e\u041c\u041d\u041e\u0415 \u0423\u0427\u0420\u0415\u0416\u0414\u0415\u041d\u0418\u0415 \"\u0424\u0415\u0414\u0415\u0420\u0410\u041b\u042c\u041d\u042b\u0419 \u0426\u0415\u041d\u0422\u0420 \u041d\u041e\u0420\u041c\u0418\u0420\u041e\u0412\u0410\u041d\u0418\u042f, \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422\u0418\u0417\u0410\u0426\u0418\u0418 \u0418 \u0422\u0415\u0425\u041d\u0418\u0427\u0415\u0421\u041a\u041e\u0419 \u041e\u0426\u0415\u041d\u041a\u0418 \u0421\u041e\u041e\u0422\u0412\u0415\u0422\u0421\u0422\u0412\u0418\u042f \u0412 \u0421\u0422\u0420\u041e\u0418\u0422\u0415\u041b\u042c\u0421\u0422\u0412\u0415\"","short_with_opf":"\u0424\u0410\u0423 \"\u0424\u0426\u0421\"","latin":null,"full":"\u0424\u0415\u0414\u0415\u0420\u0410\u041b\u042c\u041d\u041e\u0415 \u0410\u0423 \u0424\u0415\u0414\u0415\u0420\u0410\u041b\u042c\u041d\u042b\u0419 \u0426\u0415\u041d\u0422\u0420 \u041d\u041e\u0420\u041c\u0418\u0420\u041e\u0412\u0410\u041d\u0418\u042f, \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422\u0418\u0417\u0410\u0426\u0418\u0418 \u0418 \u0422\u0415\u0425\u041d\u0418\u0427\u0415\u0421\u041a\u041e\u0419 \u041e\u0426\u0415\u041d\u041a\u0418 \u0421\u041e\u041e\u0422\u0412\u0415\u0422\u0421\u0422\u0412\u0418\u042f \u0412 \u0421\u0422\u0420\u041e\u0418\u0422\u0415\u041b\u042c\u0421\u0422\u0412\u0415","short":"\u0424\u0410\u0423 \u0424\u0426\u0421"},"inn":"7736151499","ogrn":"1027739860818","okpo":"44416204","okato":"45286565000","oktmo":"45378000000","okogu":"1325800","okfs":"12","okved":"63.11.1","okveds":null,"authorities":null,"documents":null,"licenses":null,"finance":null,"address":{"value":"\u0433 \u041c\u043e\u0441\u043a\u0432\u0430, \u0424\u0443\u0440\u043a\u0430\u0441\u043e\u0432\u0441\u043a\u0438\u0439 \u043f\u0435\u0440, \u0434 6","unrestricted_value":"101000, \u0433 \u041c\u043e\u0441\u043a\u0432\u0430, \u041a\u0440\u0430\u0441\u043d\u043e\u0441\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0440-\u043d, \u0424\u0443\u0440\u043a\u0430\u0441\u043e\u0432\u0441\u043a\u0438\u0439 \u043f\u0435\u0440, \u0434 6","invalidity":null,"data":{"postal_code":"101000","country":"\u0420\u043e\u0441\u0441\u0438\u044f","country_iso_code":"RU","federal_district":"\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439","region_fias_id":"0c5b2444-70a0-4932-980c-b4dc0d3f02b5","region_kladr_id":"7700000000000","region_iso_code":"RU-MOW","region_with_type":"\u0433 \u041c\u043e\u0441\u043a\u0432\u0430","region_type":"\u0433","region_type_full":"\u0433\u043e\u0440\u043e\u0434","region":"\u041c\u043e\u0441\u043a\u0432\u0430","area_fias_id":null,"area_kladr_id":null,"area_with_type":null,"area_type":null,"area_type_full":null,"area":null,"city_fias_id":"0c5b2444-70a0-4932-980c-b4dc0d3f02b5","city_kladr_id":"7700000000000","city_with_type":"\u0433 \u041c\u043e\u0441\u043a\u0432\u0430","city_type":"\u0433","city_type_full":"\u0433\u043e\u0440\u043e\u0434","city":"\u041c\u043e\u0441\u043a\u0432\u0430","city_area":"\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439","city_district_fias_id":null,"city_district_kladr_id":null,"city_district_with_type":"\u041a\u0440\u0430\u0441\u043d\u043e\u0441\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0440-\u043d","city_district_type":"\u0440-\u043d","city_district_type_full":"\u0440\u0430\u0439\u043e\u043d","city_district":"\u041a\u0440\u0430\u0441\u043d\u043e\u0441\u0435\u043b\u044c\u0441\u043a\u0438\u0439","settlement_fias_id":null,"settlement_kladr_id":null,"settlement_with_type":null,"settlement_type":null,"settlement_type_full":null,"settlement":null,"street_fias_id":"010b8526-eed1-445c-88b2-ff0223c58b89","street_kladr_id":"77000000000069400","street_with_type":"\u0424\u0443\u0440\u043a\u0430\u0441\u043e\u0432\u0441\u043a\u0438\u0439 \u043f\u0435\u0440","street_type":"\u043f\u0435\u0440","street_type_full":"\u043f\u0435\u0440\u0435\u0443\u043b\u043e\u043a","street":"\u0424\u0443\u0440\u043a\u0430\u0441\u043e\u0432\u0441\u043a\u0438\u0439","stead_fias_id":null,"stead_cadnum":null,"stead_type":null,"stead_type_full":null,"stead":null,"house_fias_id":"ead5df73-7aec-4341-ac22-e54d0daec91a","house_kladr_id":"7700000000006940001","house_cadnum":"77:00:0000000:41682","house_type":"\u0434","house_type_full":"\u0434\u043e\u043c","house":"6","block_type":null,"block_type_full":null,"block":null,"entrance":null,"floor":null,"flat_fias_id":null,"flat_cadnum":null,"flat_type":null,"flat_type_full":null,"flat":null,"flat_area":null,"square_meter_price":null,"flat_price":null,"room_fias_id":null,"room_cadnum":null,"room_type":null,"room_type_full":null,"room":null,"postal_box":null,"fias_id":"ead5df73-7aec-4341-ac22-e54d0daec91a","fias_code":"77000000000000006940001","fias_level":"8","fias_actuality_state":"0","kladr_id":"7700000000006940001","geoname_id":"524901","capital_marker":"0","okato":"45286565000","oktmo":"45378000","tax_office":"7708","tax_office_legal":"7708","timezone":"UTC+3","geo_lat":"55.7604818","geo_lon":"37.6300517","beltway_hit":"IN_MKAD","beltway_distance":null,"metro":[{"name":"\u041b\u0443\u0431\u044f\u043d\u043a\u0430","line":"\u0421\u043e\u043a\u043e\u043b\u044c\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f","distance":0.3},{"name":"\u041a\u0443\u0437\u043d\u0435\u0446\u043a\u0438\u0439 \u043c\u043e\u0441\u0442","line":"\u0422\u0430\u0433\u0430\u043d\u0441\u043a\u043e-\u041a\u0440\u0430\u0441\u043d\u043e\u043f\u0440\u0435\u0441\u043d\u0435\u043d\u0441\u043a\u0430\u044f","distance":0.4},{"name":"\u041a\u0438\u0442\u0430\u0439-\u0433\u043e\u0440\u043e\u0434","line":"\u041a\u0430\u043b\u0443\u0436\u0441\u043a\u043e-\u0420\u0438\u0436\u0441\u043a\u0430\u044f","distance":0.5}],"divisions":null,"qc_geo":"0","qc_complete":null,"qc_house":null,"history_values":null,"unparsed_parts":null,"source":"101000, \u0413.\u041c\u043e\u0441\u043a\u0432\u0430, \u0412\u041d.\u0422\u0415\u0420.\u0413. \u041c\u0423\u041d\u0418\u0426\u0418\u041f\u0410\u041b\u042c\u041d\u042b\u0419 \u041e\u041a\u0420\u0423\u0413 \u041a\u0420\u0410\u0421\u041d\u041e\u0421\u0415\u041b\u042c\u0421\u041a\u0418\u0419, \u041f\u0415\u0420 \u0424\u0423\u0420\u041a\u0410\u0421\u041e\u0412\u0421\u041a\u0418\u0419, \u0414. 6","qc":"0"}},"phones":null,"emails":null,"ogrn_date":1040601600000,"okved_type":"2014","employee_count":null}}]} \ No newline at end of file