From 46c7c112607b5e3e01e3bb26bbb0d19bab6c5f4b Mon Sep 17 00:00:00 2001 From: joddyabott Date: Tue, 29 Apr 2025 16:50:55 +0330 Subject: [PATCH] creat controller model,migration,factory,sedder.request resourse,web for 4item . such as event call,callhistory,category --- .../app/Http/Controllers/CallController.php | 140 ++++++++++++++++++ .../Http/Controllers/CategoryController.php | 20 +++ .../app/Http/Requests/Call/ListRequest.php | 30 ++++ .../app/Http/Requests/Call/StoreRequest.php | 30 ++++ .../app/Http/Requests/Call/UpdateRequest.php | 80 ++++++++++ .../app/Http/Resources/Call/CallResource.php | 32 ++++ laravel/app/Models/Call.php | 23 +++ laravel/app/Models/CallHistory.php | 27 ++++ laravel/app/Models/Category.php | 13 ++ laravel/app/Models/Event.php | 12 ++ laravel/database/factories/CallFactory.php | 44 ++++++ .../database/factories/CallHistoryFactory.php | 31 ++++ .../database/factories/CategoryFactory.php | 26 ++++ laravel/database/factories/EventFactory.php | 23 +++ .../2025_04_29_113252_create_calls_table.php | 49 ++++++ ...5_04_29_113931_create_categories_table.php | 33 +++++ ..._29_125524_create_call_histories_table.php | 37 +++++ .../2025_04_29_130015_create_events_table.php | 28 ++++ .../database/seeders/CallHistorySeeder.php | 17 +++ laravel/database/seeders/CallSeeder.php | 17 +++ laravel/database/seeders/CategorySeeder.php | 117 +++++++++++++++ laravel/database/seeders/EventSeeder.php | 49 ++++++ laravel/routes/web.php | 14 ++ 23 files changed, 892 insertions(+) create mode 100644 laravel/app/Http/Controllers/CallController.php create mode 100644 laravel/app/Http/Controllers/CategoryController.php create mode 100644 laravel/app/Http/Requests/Call/ListRequest.php create mode 100644 laravel/app/Http/Requests/Call/StoreRequest.php create mode 100644 laravel/app/Http/Requests/Call/UpdateRequest.php create mode 100644 laravel/app/Http/Resources/Call/CallResource.php create mode 100644 laravel/app/Models/Call.php create mode 100644 laravel/app/Models/CallHistory.php create mode 100644 laravel/app/Models/Category.php create mode 100644 laravel/app/Models/Event.php create mode 100644 laravel/database/factories/CallFactory.php create mode 100644 laravel/database/factories/CallHistoryFactory.php create mode 100644 laravel/database/factories/CategoryFactory.php create mode 100644 laravel/database/factories/EventFactory.php create mode 100644 laravel/database/migrations/2025_04_29_113252_create_calls_table.php create mode 100644 laravel/database/migrations/2025_04_29_113931_create_categories_table.php create mode 100644 laravel/database/migrations/2025_04_29_125524_create_call_histories_table.php create mode 100644 laravel/database/migrations/2025_04_29_130015_create_events_table.php create mode 100644 laravel/database/seeders/CallHistorySeeder.php create mode 100644 laravel/database/seeders/CallSeeder.php create mode 100644 laravel/database/seeders/CategorySeeder.php create mode 100644 laravel/database/seeders/EventSeeder.php diff --git a/laravel/app/Http/Controllers/CallController.php b/laravel/app/Http/Controllers/CallController.php new file mode 100644 index 0000000..eae5c18 --- /dev/null +++ b/laravel/app/Http/Controllers/CallController.php @@ -0,0 +1,140 @@ +where('telephone_id', $request->telephone_id)->first(); + + $call = Call::query()->create([ + 'telephone_id' => $request->telephone_id, + 'caller_phone_number' => $request->caller_phone_number, + 'operator_id' => $operator->id, + 'operator_username' => $operator->username, + 'operator_full_name' => $operator->full_name + ]); + + CallHistory::recordHistory($call, CallEvents::CALL_CREATED); + + return $call; + }); + + $data = [ + 'telephone_id' => $call->telephone_id, + 'phone_number' => $call->caller_phone_number, + 'call_id' => $call->id, + ]; + + $notificationService->deliverDataToNotificationServer($data); + + return $this->successResponse(); + } + catch (NotificationServerNotRespondingException $exception) + { + CallHistory::recordHistory($call, CallEvents::NOTIFICATION_SERVER_NOT_RESPONDING); + throw $exception; + } + catch (OperatorOfflineException $exception) + { + CallHistory::recordHistory($call, CallEvents::OPERATOR_IS_OFFLINE); + throw $exception; + } + catch (OperatorNotConnectedException $exception) + { + CallHistory::recordHistory($call, CallEvents::OPERATOR_COULD_NOT_CONNECT); + throw $exception; + } + } + + + public function show(string $id) + { + // + } + + public function update(UpdateRequest $request, Call $call): JsonResponse + { + DB::transaction(function () use ($request, $call) { + $operator = User::query()->where('telephone_id', $call->telephone_id)->first(); + + $category = Category::query()->where([ + ['category_id', $request->category_id], + ['subcategory_id', $request->subcategory_id] + ])->first(); + + $call->update([ + 'province_id' => $operator->province_id, + 'province_fa' => $operator->province_fa, + 'operator_id' => $operator->id, + 'operator_username' => $operator->username, + 'operator_full_name' => $operator->full_name, + 'category_id' => $request->category_id, + 'category_name' => $category->category_name, + 'subcategory_id' => $request->subcategory_id, + 'subcategory_name' => $category->subcategory_name, + 'description' => $request->description, + ]); + + $event_id = CallEvents::OPERATOR_STORED_CALL_DATA; + + $event_name = Event::query()->find($event_id)->first()->name; + + CallHistory::create([ + 'call_id' => $call->id, + 'telephone_id' => $call->telephone_id, + 'caller_phone_number' => $call->caller_phone_number, + 'event_id' => $event_id, + 'event_name' => $event_name, + ]); + }); + + return $this->successResponse(); + } + + public function list(ListRequest $request): JsonResponse + { + $phone_number = $request->phone_number; + $size = $request->size ?? config('global_variables.MAX_RECORDS_COUNT'); + + $calls_data = Call::query() + ->when($phone_number, function ($query) use ($phone_number) { + return $query->where('caller_phone_number', $phone_number); + })->orderBy('created_at', 'DESC') + ->limit($size) + ->get(); + + return $this->successResponse(CallResource::collection($calls_data)); + } +} diff --git a/laravel/app/Http/Controllers/CategoryController.php b/laravel/app/Http/Controllers/CategoryController.php new file mode 100644 index 0000000..9a078dd --- /dev/null +++ b/laravel/app/Http/Controllers/CategoryController.php @@ -0,0 +1,20 @@ +successResponse($data); + } +} diff --git a/laravel/app/Http/Requests/Call/ListRequest.php b/laravel/app/Http/Requests/Call/ListRequest.php new file mode 100644 index 0000000..664a005 --- /dev/null +++ b/laravel/app/Http/Requests/Call/ListRequest.php @@ -0,0 +1,30 @@ + + */ + public function rules(): array + { + return [ + 'phone_number' => 'regex:/^09\d{9}$/', + 'size' => 'integer' + ]; + } +} diff --git a/laravel/app/Http/Requests/Call/StoreRequest.php b/laravel/app/Http/Requests/Call/StoreRequest.php new file mode 100644 index 0000000..2d47c25 --- /dev/null +++ b/laravel/app/Http/Requests/Call/StoreRequest.php @@ -0,0 +1,30 @@ + + */ + public function rules(): array + { + return [ + 'telephone_id' => 'required|string|exists:users,telephone_id', + 'caller_phone_number' => 'required|numeric|regex:/^09\d{9}$/', + ]; + } +} diff --git a/laravel/app/Http/Requests/Call/UpdateRequest.php b/laravel/app/Http/Requests/Call/UpdateRequest.php new file mode 100644 index 0000000..39a1b4e --- /dev/null +++ b/laravel/app/Http/Requests/Call/UpdateRequest.php @@ -0,0 +1,80 @@ +user()->telephone_id; + + if ($operator_telephone_id == $this->call->telephone_id) { + return true; + } + return false; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules(): array + { + return [ + 'category_id' => 'required|integer', + 'subcategory_id' => 'required|integer', + 'description' => 'string', + ]; + } + + public function after(): array + { + return [ + function (Validator $validator) { + if ($this->somethingElseIsInvalid()) { + $validator->errors()->add( + 'category', + __('messages.combination_of_category_and_subcategory_does_not_exist') + ); + } + } + ]; + } + + private function somethingElseIsInvalid(): bool + { + $category_id = $this->category_id; + $subcategory_id = $this->subcategory_id; + + if ($category_id && $subcategory_id) { + return !Category::query()->where([ + ['category_id', $category_id], + ['subcategory_id', $subcategory_id] + ])->exists(); + } + + return false; + } +} diff --git a/laravel/app/Http/Resources/Call/CallResource.php b/laravel/app/Http/Resources/Call/CallResource.php new file mode 100644 index 0000000..455997e --- /dev/null +++ b/laravel/app/Http/Resources/Call/CallResource.php @@ -0,0 +1,32 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'operator_id' => $this->operator_id, + 'operator_full_name' => $this->operator_full_name, + 'operator_username' => $this->operator_username, + 'telephone_id' => $this->telephone_id, + 'caller_phone_number' => $this->caller_phone_number, + 'description' => $this->description, + 'category_id' => $this->category_id, + 'category_name' => $this->category_name, + 'subcategory_id' => $this->subcategory_id, + 'subcategory_name' => $this->subcategory_name, + 'created_at' => $this->created_at, + ]; + } +} diff --git a/laravel/app/Models/Call.php b/laravel/app/Models/Call.php new file mode 100644 index 0000000..0eb0b3b --- /dev/null +++ b/laravel/app/Models/Call.php @@ -0,0 +1,23 @@ + */ + use HasFactory; + protected $guarded = [ + 'call_id', + 'created_at', + 'updated_at' + ]; + +// public function histories(): HasMany +// { +// return $this->hasMany(CallHistory::class); +// } +} diff --git a/laravel/app/Models/CallHistory.php b/laravel/app/Models/CallHistory.php new file mode 100644 index 0000000..4f5f01e --- /dev/null +++ b/laravel/app/Models/CallHistory.php @@ -0,0 +1,27 @@ + */ + use HasFactory; + protected $guarded = ['id']; + + public static function recordHistory(Call $call, $event_id): void + { + $event = Event::query()->where('id', $event_id)->first(); + + self::create([ + 'call_id' => $call->id, + 'telephone_id' => $call->telephone_id, + 'caller_phone_number' => $call->caller_phone_number, + 'event_id' => $event->id, + 'event_name' => $event->name + ]); + } + +} diff --git a/laravel/app/Models/Category.php b/laravel/app/Models/Category.php new file mode 100644 index 0000000..b57bcab --- /dev/null +++ b/laravel/app/Models/Category.php @@ -0,0 +1,13 @@ + */ + use HasFactory; + protected $guarded = ['id']; +} diff --git a/laravel/app/Models/Event.php b/laravel/app/Models/Event.php new file mode 100644 index 0000000..9dce7e8 --- /dev/null +++ b/laravel/app/Models/Event.php @@ -0,0 +1,12 @@ + */ + use HasFactory; +} diff --git a/laravel/database/factories/CallFactory.php b/laravel/database/factories/CallFactory.php new file mode 100644 index 0000000..1f7d4cd --- /dev/null +++ b/laravel/database/factories/CallFactory.php @@ -0,0 +1,44 @@ + + */ +class CallFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'telephone_id' => $this->faker->numerify('tel-####'), + 'caller_phone_number' => '09' . $this->faker->unique()->randomNumber(9, true), + 'operator_id' => User::factory(), + 'operator_username' => function (array $attributes) { + return User::find($attributes['operator_id'])->username; + }, + 'operator_full_name' => function (array $attributes) { + return User::find($attributes['operator_id'])->full_name; + }, + 'description' => $this->faker->text, + 'category_id' => Category::factory(), + 'category_name' => function (array $attributes) { + return Category::find($attributes['category_id'])->category_name; + }, + 'subcategory_id' => function (array $attributes) { + return Category::find($attributes['category_id'])->subcategory_id; + }, + 'subcategory_name' => function (array $attributes) { + return Category::find($attributes['category_id'])->subcategory_name; + }, + ]; + } +} diff --git a/laravel/database/factories/CallHistoryFactory.php b/laravel/database/factories/CallHistoryFactory.php new file mode 100644 index 0000000..8c0ef62 --- /dev/null +++ b/laravel/database/factories/CallHistoryFactory.php @@ -0,0 +1,31 @@ + + */ +class CallHistoryFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'call_id' => Call::factory(), + 'telephone_id' => $this->faker->numerify('tel-####'), + 'caller_phone_number' => '09' . $this->faker->randomNumber(9, true), + 'event_id' => Event::factory(), + 'event_name' => function (array $attributes) { + return Event::query()->find($attributes['event_id'])->name; + } + ]; + } +} diff --git a/laravel/database/factories/CategoryFactory.php b/laravel/database/factories/CategoryFactory.php new file mode 100644 index 0000000..dd77e6f --- /dev/null +++ b/laravel/database/factories/CategoryFactory.php @@ -0,0 +1,26 @@ + + */ +class CategoryFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'category_id' => $this->faker->randomNumber(3, true), + 'category_name' => $this->faker->words(3, true), + 'subcategory_id' => $this->faker->randomNumber(4, true), + 'subcategory_name' => $this->faker->words(3, true) + ]; + } +} diff --git a/laravel/database/factories/EventFactory.php b/laravel/database/factories/EventFactory.php new file mode 100644 index 0000000..3138f50 --- /dev/null +++ b/laravel/database/factories/EventFactory.php @@ -0,0 +1,23 @@ + + */ +class EventFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => $this->faker->sentence, + ]; + } +} diff --git a/laravel/database/migrations/2025_04_29_113252_create_calls_table.php b/laravel/database/migrations/2025_04_29_113252_create_calls_table.php new file mode 100644 index 0000000..a8086e4 --- /dev/null +++ b/laravel/database/migrations/2025_04_29_113252_create_calls_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('telephone_id'); + $table->string('caller_phone_number'); + + $table->foreignId('province_id') + ->nullable() + ->constrained(); + $table->string('province_fa')->nullable(); + + $table->foreignId('operator_id') + ->nullable() + ->constrained('users'); + + $table->string('operator_username')->nullable(); + $table->string('operator_full_name')->nullable(); + + $table->unsignedSmallInteger('category_id')->nullable(); + $table->string('category_name')->nullable(); + + $table->unsignedSmallInteger('subcategory_id')->nullable(); + $table->string('subcategory_name')->nullable(); + + $table->text('description')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('calls'); + } +}; diff --git a/laravel/database/migrations/2025_04_29_113931_create_categories_table.php b/laravel/database/migrations/2025_04_29_113931_create_categories_table.php new file mode 100644 index 0000000..6ba142c --- /dev/null +++ b/laravel/database/migrations/2025_04_29_113931_create_categories_table.php @@ -0,0 +1,33 @@ +id(); + $table->unsignedSmallInteger('category_id'); + $table->string('category_name'); + + $table->unsignedSmallInteger('subcategory_id')->nullable(); + $table->string('subcategory_name')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/laravel/database/migrations/2025_04_29_125524_create_call_histories_table.php b/laravel/database/migrations/2025_04_29_125524_create_call_histories_table.php new file mode 100644 index 0000000..1a6c7ec --- /dev/null +++ b/laravel/database/migrations/2025_04_29_125524_create_call_histories_table.php @@ -0,0 +1,37 @@ +id(); + $table->foreignId('call_id') + ->constrained('calls'); + + $table->string('telephone_id'); + $table->string('caller_phone_number'); + + $table->foreignId('event_id') + ->constrained(); + $table->string('event_name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('call_histories'); + } +}; diff --git a/laravel/database/migrations/2025_04_29_130015_create_events_table.php b/laravel/database/migrations/2025_04_29_130015_create_events_table.php new file mode 100644 index 0000000..538f11f --- /dev/null +++ b/laravel/database/migrations/2025_04_29_130015_create_events_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('events'); + } +}; diff --git a/laravel/database/seeders/CallHistorySeeder.php b/laravel/database/seeders/CallHistorySeeder.php new file mode 100644 index 0000000..87d0a13 --- /dev/null +++ b/laravel/database/seeders/CallHistorySeeder.php @@ -0,0 +1,17 @@ + 1, + 'category_name' => 'اطلاعات راه', + 'subcategory_id' => 1, + 'subcategory_name' => 'اطلاعات باز و بسته', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 1, + 'category_name' => 'اطلاعات راه', + 'subcategory_id' => 2, + 'subcategory_name' => 'پرس و جو دلیل ترافیک', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 1, + 'category_name' => 'اطلاعات راه', + 'subcategory_id' => 3, + 'subcategory_name' => 'آب و هوا', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 1, + 'category_name' => 'اطلاعات راه', + 'subcategory_id' => 4, + 'subcategory_name' => 'یک طرفه دو طرفه', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 1, + 'category_name' => 'اطلاعات راه', + 'subcategory_id' => 5, + 'subcategory_name' => 'مسیر مسافت', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 2, + 'category_name' => 'شکایت', + 'subcategory_id' => 1, + 'subcategory_name' => 'شکایت از راه', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 2, + 'category_name' => 'شکایت', + 'subcategory_id' => 2, + 'subcategory_name' => 'شکایت از اتوبوس', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 2, + 'category_name' => 'شکایت', + 'subcategory_id' => 3, + 'subcategory_name' => 'شکایت از حمل و نقل عمومی', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 2, + 'category_name' => 'شکایت', + 'subcategory_id' => 4, + 'subcategory_name' => 'نیاز به برف روبی', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 3, + 'category_name' => 'سایر', + 'subcategory_id' => 1, + 'subcategory_name' => 'اشتباه', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 3, + 'category_name' => 'سایر', + 'subcategory_id' => 2, + 'subcategory_name' => 'مزاحم', + 'created_at' => now(), + 'updated_at'=> now() + ], + [ + 'category_id' => 3, + 'category_name' => 'سایر', + 'subcategory_id' => 3, + 'subcategory_name' => 'اختلال در ارتباط', + 'created_at' => now(), + 'updated_at'=> now() + ], + ]; + + DB::table('categories')->insert($data); + } +} diff --git a/laravel/database/seeders/EventSeeder.php b/laravel/database/seeders/EventSeeder.php new file mode 100644 index 0000000..c08c80c --- /dev/null +++ b/laravel/database/seeders/EventSeeder.php @@ -0,0 +1,49 @@ +insert([ + [ + 'id' => 1, + 'name' => 'تماس ساخته شد', + 'created_at' => now(), + 'updated_at' => now() + ], + [ + 'id' => 2, + 'name' => 'اپراتور آفلاین بود', + 'created_at' => now(), + 'updated_at' => now() + ], + [ + 'id' => 3, + 'name' => 'مشکل در ارتباط با اپراتور (نقص فنی)', + 'created_at' => now(), + 'updated_at' => now() + ], + [ + 'id' => 4, + 'name' => 'اپراتور اطلاعات تماس را ثبت کرد', + 'created_at' => now(), + 'updated_at' => now() + ], + [ + 'id' => 5, + 'name' => 'سرور پیام رسان قطع میباشد', + 'created_at' => now(), + 'updated_at' => now() + ], + ]); + } +} diff --git a/laravel/routes/web.php b/laravel/routes/web.php index fa91e35..32e2663 100644 --- a/laravel/routes/web.php +++ b/laravel/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Admin\UserManagementController; use App\Http\Controllers\AuthController; +use App\Http\Controllers\CallController; use App\Http\Controllers\ProfileController; use App\Http\Middleware\SuperAdminCheck; use Illuminate\Support\Facades\Route; @@ -35,3 +36,16 @@ Route::prefix('users') Route::delete('/{user}', 'destroy')->middleware([SuperAdminCheck::class])->name('destroy'); }); + +Route::prefix('calls') + ->name('calls.') + ->controller(CallController::class) + ->group(function () { + Route::post('/', 'store')->name('store'); + Route::get('/list', 'list')->name('list')->middleware(['auth', 'permission:manage_calls']); + Route::post('/{call}', 'update')->name('update')->middleware(['auth', 'permission:manage_calls']); + }); + +Route::middleware('auth')->get('/categories', [CategoryController::class, 'list'])->name('categories.list'); + +