diff --git a/app/Modules/Docs/Routes/web.php b/app/Modules/Docs/Routes/web.php
index 6ed87de..000df14 100644
--- a/app/Modules/Docs/Routes/web.php
+++ b/app/Modules/Docs/Routes/web.php
@@ -5,8 +5,6 @@
Route::middleware(['auth'])->group(function ()
{
-
Route::get('/docs', [DocsController::class, 'index'])->name('docs.index');
Route::get('/docs/{document}/download', [DocsController::class, 'download'])->name('docs.download');
-
});
\ No newline at end of file
diff --git a/app/Modules/Invite/Config/config.php b/app/Modules/Invite/Config/config.php
new file mode 100644
index 0000000..ce09543
--- /dev/null
+++ b/app/Modules/Invite/Config/config.php
@@ -0,0 +1,5 @@
+id();
+ $table->uuid('hash');
+ $table->foreignId('company_id')->references('id')->on('companies')->onDelete('cascade');
+ $table->timestamps();
+ $table->softDeletes();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('invites');
+ }
+};
diff --git a/app/Modules/Invite/Database/Migrations/2026_04_27_000002_create_invite_agents_table.php b/app/Modules/Invite/Database/Migrations/2026_04_27_000002_create_invite_agents_table.php
new file mode 100644
index 0000000..6913731
--- /dev/null
+++ b/app/Modules/Invite/Database/Migrations/2026_04_27_000002_create_invite_agents_table.php
@@ -0,0 +1,30 @@
+id();
+ $table->foreignId('invite_id')->references('id')->on('invites');
+ $table->foreignId('agent_id')->references('id')->on('agents');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('invite_agents');
+ }
+};
diff --git a/app/Modules/Invite/Http/Controllers/InviteController.php b/app/Modules/Invite/Http/Controllers/InviteController.php
new file mode 100644
index 0000000..e93f9c8
--- /dev/null
+++ b/app/Modules/Invite/Http/Controllers/InviteController.php
@@ -0,0 +1,125 @@
+user()->id)->pluck('company_id')->toArray();
+ if (!$company) {
+ if (auth()->user()->hasRole(Role::CITY_MANAGER)) {
+ $citiesIds = CityManager::where('user_id', auth()->user()->id)->pluck('city_id')->toArray();
+ foreach (Company::whereIn('city_id', $citiesIds)->get() as $company) {
+ $companies[] = $company;
+ }
+ }
+ if (auth()->user()->hasRole(Role::COMPANY_ADMIN)) {
+ $companyAdmin = CompanyAdmin::where('user_id', auth()->user()->id)->first();
+ $companies[] = $companyAdmin->company;
+ }
+ if (count($companies) > 1) {
+ return view('invite::companies', [
+ 'companies' => $companies
+ ]);
+ } else {
+ return to_route('company.invites', [
+ 'company' => $companies[0]
+ ]);
+ }
+ }
+ return view('invite::index', [
+ 'company' => $company,
+ 'invites' => Invite::where('company_id', $company->id)->get()
+ ]);
+ }
+ public function create(Request $request, Company $company) {
+ Invite::create([
+ 'hash' => Uuid::uuid4(),
+ 'company_id' => $company->id
+ ]);
+ return back();
+ }
+ public function open(Request $request, $hash) {
+ if (!$invite = Invite::where('hash', $hash)->first()) {
+ return back();
+ }
+ return view('invite::form', [
+ 'invite' => $invite
+ ]);
+ return back();
+ }
+
+ public function process(Request $request, $hash) {
+ if (!$invite = Invite::where('hash', $hash)->first()) {
+ return back();
+ }
+ $user = User::where('email', $request->email)->orWhere('phone', $request->phone)->first();
+
+ if ($user) {
+ if (UserRole::where('user_id', Role::AGENT)->get()) {
+ return back()->withInput()->withErrors('Агент с данным телефоном или электронной почтой уже зарегистрирован');
+ }
+ } else {
+ $user = User::create([
+ 'name' => $request->name,
+ 'email' => $request->email,
+ 'phone' => $request->phone
+ ]);
+ }
+ $agent = Agent::create([
+ 'company_id' => $invite->company_id,
+ 'user_id' => $user->id
+ ]);
+ if (!$agent && $user->wasRecentlyCreated) {
+ $user->delete();
+ return back()->withInput()->withErrors('При создании учетной записи возникла ошибка. Попробуйте сделать это немного позже');
+ }
+ $registration = InviteAgent::create([
+ 'invite_id' => $invite->id,
+ 'agent_id' => $agent->id
+ ]);
+ if (!$registration) {
+ $agent->forceDelete();
+ return back()->withInput()->withErrors('При создании учетной записи возникла ошибка. Попробуйте сделать это немного позже');
+ }
+ $user->setForcedPassword();
+ return to_route('company.invite.success', [
+ 'hash' => $invite->hash
+ ]);
+ }
+
+ public function success(Request $request, $hash) {
+ if (!$invite = Invite::where('hash', $hash)->first()) {
+ return back();
+ }
+ return view('invite::success', [
+ 'invite' => $invite
+ ]);
+ }
+ public function delete (Invite $invite) {
+ $invite->delete();
+ return back()->withSuccess('Ссылка-приглашение была успешно удалена');
+ }
+ public function agents(Invite $invite) {
+ return view('invite::agents', [
+ 'invite' => $invite
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Modules/Invite/Models/Invite.php b/app/Modules/Invite/Models/Invite.php
new file mode 100644
index 0000000..91aff65
--- /dev/null
+++ b/app/Modules/Invite/Models/Invite.php
@@ -0,0 +1,26 @@
+belongsTo(Company::class, 'company_id');
+ }
+
+ public function registrations()
+ {
+ return $this->HasMany(InviteAgent::class, 'invite_id');
+ }
+}
diff --git a/app/Modules/Invite/Models/InviteAgent.php b/app/Modules/Invite/Models/InviteAgent.php
new file mode 100644
index 0000000..9e6f747
--- /dev/null
+++ b/app/Modules/Invite/Models/InviteAgent.php
@@ -0,0 +1,27 @@
+belongsTo(Agent::class, 'agent_id');
+ }
+
+ public function invite()
+ {
+ return $this->belongsTo(Invite::class, 'invite_id');
+ }
+}
diff --git a/app/Modules/Invite/Providers/ModuleServiceProvider.php b/app/Modules/Invite/Providers/ModuleServiceProvider.php
new file mode 100644
index 0000000..61c5dc3
--- /dev/null
+++ b/app/Modules/Invite/Providers/ModuleServiceProvider.php
@@ -0,0 +1,71 @@
+app->register(RouteServiceProvider::class);
+ }
+
+ public function boot()
+ {
+ $this->registerViews();
+ $this->registerLivewireViews();
+ $this->registerMigrations();
+ $this->registerConfig();
+ $this->registerComponent();
+ $this->registerLivewire();
+ }
+
+ protected function registerViews()
+ {
+ $moduleViewsPath = __DIR__ . '/../Views';
+ $this->loadViewsFrom(
+ $moduleViewsPath,
+ strtolower($this->moduleName)
+ );
+ }
+
+ protected function registerLivewireViews()
+ {
+ $moduleViewsPath = __DIR__ . '/../Views/livewire';
+ $this->loadViewsFrom(
+ $moduleViewsPath,
+ strtolower($this->moduleName)
+ );
+ }
+
+ protected function registerMigrations()
+ {
+ $this->loadMigrationsFrom(
+ app_path('Modules/' . $this->moduleName . '/Database/Migrations')
+ );
+ }
+
+ protected function registerConfig()
+ {
+ $path = app_path('Modules/' . $this->moduleName . '/Config/config.php');
+ $this->mergeConfigFrom(
+ $path,
+ strtolower($this->moduleName)
+ );
+ }
+
+ protected function registerLivewire()
+ {
+ //Livewire::component('
', \Modules\\Http\Livewire\::class);
+ }
+
+ protected function registerComponent()
+ {
+ //Blade::component('document', \Modules\Docs\Http\Components\DocumentComponent::class);
+ }
+}
\ No newline at end of file
diff --git a/app/Modules/Invite/Providers/RouteServiceProvider.php b/app/Modules/Invite/Providers/RouteServiceProvider.php
new file mode 100644
index 0000000..2aed1e6
--- /dev/null
+++ b/app/Modules/Invite/Providers/RouteServiceProvider.php
@@ -0,0 +1,24 @@
+registerWebRoutes();
+ }
+
+ protected function registerWebRoutes()
+ {
+ //Add Web Routes with web Guard
+ Route::middleware('web')
+ //Set Default Controllers Namespace
+ ->namespace('Modules\\Invite\\Http\\Controllers')
+ ->group(app_path('Modules/Invite/Routes/web.php'));
+ }
+}
\ No newline at end of file
diff --git a/app/Modules/Invite/Routes/web.php b/app/Modules/Invite/Routes/web.php
new file mode 100644
index 0000000..48ed732
--- /dev/null
+++ b/app/Modules/Invite/Routes/web.php
@@ -0,0 +1,17 @@
+group(function ()
+{
+ Route::get('company/{company}/invites', [InviteController::class, 'index'])->name('company.invites');
+ Route::get('company/invites', [InviteController::class, 'index'])->name('company.invites.select');
+
+ Route::post('company/{company}/create', [InviteController::class, 'create'])->name('company.invites.create');
+ Route::get('company/invite/{hash}', [InviteController::class, 'open'])->name('company.invite.open');
+ Route::post('company/invite/{hash}', [InviteController::class, 'process'])->name('company.invite.process');
+ Route::get('company/invite/{hash}/success', [InviteController::class, 'success'])->name('company.invite.success');
+ Route::get('company/invite/{invite}/agents', [InviteController::class, 'agents'])->name('company.invite.agents');
+ Route::post('company/invite/{invite}/delete', [InviteController::class, 'delete'])->name('company.invite.delete');
+});
\ No newline at end of file
diff --git a/app/Modules/Invite/Views/agents.blade.php b/app/Modules/Invite/Views/agents.blade.php
new file mode 100644
index 0000000..48db33f
--- /dev/null
+++ b/app/Modules/Invite/Views/agents.blade.php
@@ -0,0 +1,40 @@
+@php($title = 'Зарегистрированные по приглашению агенты')
+@extends('layouts.app')
+@section('content')
+ {{ $invite->company->name }}
+
+
+ Зарегистрированные по приглашению агенты
+
+ @foreach ($invite->registrations()->orderBy('created_at', 'desc')->get() as $inviteRegistration)
+
+
+ {{ $inviteRegistration->agent->user?->name }}
+
+
+ {{ $inviteRegistration->created_at->diffForHumans() }}
+
+
+
+ @endforeach
+
+
+@endsection
\ No newline at end of file
diff --git a/app/Modules/Invite/Views/companies.blade.php b/app/Modules/Invite/Views/companies.blade.php
new file mode 100644
index 0000000..1c00e50
--- /dev/null
+++ b/app/Modules/Invite/Views/companies.blade.php
@@ -0,0 +1,45 @@
+@php($title = 'Приглашения агентов')
+@extends('layouts.app')
+@section('content')
+