diff --git a/Dockerfile b/Dockerfile index f3c4890..8c14e99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,10 +19,10 @@ RUN apk update && apk add --no-cache \ && docker-php-ext-install pdo_pgsql pdo_mysql gd zip # Set the working directory -WORKDIR /var/www/laravel +WORKDIR /var/www/crm/backend COPY . . -RUN chmod -R 777 /var/www/laravel/storage /var/www/laravel/bootstrap/cache +RUN chmod -R 777 /var/www/crm/backend/storage /var/www/crm/backend/bootstrap/cache # Install Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer diff --git a/app/Http/Controllers/Admin/UserManagementController.php b/app/Http/Controllers/Admin/UserManagementController.php index 55d639c..077cb55 100644 --- a/app/Http/Controllers/Admin/UserManagementController.php +++ b/app/Http/Controllers/Admin/UserManagementController.php @@ -27,8 +27,8 @@ class UserManagementController extends Controller User::query()->where('username', "<>", "witel"), $request, allowedFilters: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id'), - allowedSortings: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id'), - allowedRelations: array('roles:id,name_fa') + allowedRelations: array('roles:id,name_fa'), + allowedSortings: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id') ); return response()->json($data); diff --git a/app/Http/Controllers/CallController.php b/app/Http/Controllers/CallController.php index 6cf67ba..97580c2 100644 --- a/app/Http/Controllers/CallController.php +++ b/app/Http/Controllers/CallController.php @@ -123,7 +123,7 @@ class CallController extends Controller $size = $request->size ?? config('global_variables.MAX_RECORDS_COUNT'); $calls_data = Call::query() - ->when($phone_number, fn($query, $phone_number) => $query->where('phone_number', '=', $phone_number)) + ->when($phone_number, fn($query, $phone_number) => $query->where('caller_phone_number', '=', $phone_number)) ->orderBy('created_at', 'DESC') ->limit($size) ->get(); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 05b8c08..a2a7b75 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -52,7 +52,7 @@ class ProfileController extends Controller public function online(Request $request): JsonResponse { User::query() - ->firstWhere('telephone_id', '=', $request->telephone_id) + ->Where('telephone_id', '=', $request->telephone_id) ->update(['is_online' => true,]); return $this->successResponse(); diff --git a/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php b/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php index c3cdace..946bed1 100644 --- a/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php +++ b/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php @@ -22,14 +22,22 @@ class SupervisorController extends Controller return response()->json($dataTableService->index($request)); } - public function rate(RateRequest $request,OperatorDialogue $operatorDialogue): JsonResponse + public function rate(RateRequest $request): JsonResponse { - $operatorDialogue->update([ - 'supervisor_id' => auth()->user()->id, - 'is_good' => $request->is_good, - 'is_listen' => true, - 'description' => $request->description, - ]); + OperatorDialogue::query()->updateOrCreate( + [ + $request->cdr_unique_id + ], + [ + 'cdr_unique_id' => $request->cdr_unique_id, + 'date' => $request->date, + 'supervisor_id' => auth()->user()->id, + 'is_good' => $request->is_good, + 'is_listen' => true, + 'description' => $request->description, + ] + ); + return $this->successResponse(); } diff --git a/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php b/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php index f5150a1..1d7d447 100644 --- a/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php +++ b/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php @@ -22,6 +22,7 @@ class RateRequest extends FormRequest public function rules(): array { return [ + 'cdr_unique_id' => 'required|string', 'is_good' => 'required|in:0,1', 'description' => 'string', ]; diff --git a/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php b/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php index 4354160..d844d42 100644 --- a/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php +++ b/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php @@ -12,7 +12,7 @@ class DataTableService public function index(Request $request) { $query = DB::table('asteriskcdrdb.cdr') - ->leftJoin('crm_db.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'crm_db.operator_dialogues.cdr_unique_id') + ->leftJoin('roaddb.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'roaddb.operator_dialogues.cdr_unique_id') ->where('dst', '<>', '') ->where('lastapp', '=', 'Dial') ->where('duration', '>', 0) diff --git a/app/Services/Dashboard/Province/ReportService.php b/app/Services/Dashboard/Province/ReportService.php index bd804d6..bba6ddd 100644 --- a/app/Services/Dashboard/Province/ReportService.php +++ b/app/Services/Dashboard/Province/ReportService.php @@ -4,11 +4,12 @@ namespace App\Services\Dashboard\Province; use App\Facades\DataTable\DataTableFacade; use Illuminate\Http\Request; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; class ReportService { - public function cumulative(Request $request) + public function cumulative(Request $request): Collection { $query = DB::table('asteriskcdrdb.cdr') ->selectRaw(" @@ -23,13 +24,9 @@ class ReportService COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all_calls, AVG(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' THEN billsec END) AS avg - "); -// ->whereBetween('calldate', [$from, $to]) // use Carbon or date strings -// ->groupBy(DB::raw('DATE(calldate)')) -// ->orderByDesc(DB::raw('DATE(calldate)')) -// ->get(); + ")->groupByRaw('DATE(calldate)'); $data = DataTableFacade::run( $query, @@ -38,6 +35,9 @@ class ReportService allowedSortings: ['*'], allowedGroupBy: ['d'] ); + + $data = collect($data); + $totals = [ 'd' => 'TOTAL', 'total' => $data->sum('total'), @@ -66,8 +66,6 @@ class ReportService COUNT(CASE WHEN is_listen = 1 THEN 1 END) AS l, COUNT(CASE WHEN is_listen = 0 THEN 1 END) AS nl '); -// ->whereBetween('date', [$date_from, $date_to]) -// ->first(); return DataTableFacade::run( $query, @@ -81,57 +79,33 @@ class ReportService { $query = DB::table('asteriskcdrdb.cdr') ->where('recordingfile', '<>', ''); -// ->whereBetween('calldate', ["$date_from $time_from", "$date_to $time_to"]) -// ->when($cid, function ($query, $cid) { -// return $query->where('src', 'like', "%{$cid}%"); -// }) -// ->when($c_op, function ($query, $c_op) { -// return $query->where('dst', $c_op); -// }, function ($query) { -// return $query->whereBetween('dst', [100, 110]); -// }) -// ->orderByDesc('calldate'); return DataTableFacade::run( $query, $request, allowedFilters: ['*'], allowedSortings: ['*'], + allowedSelects: ['calldate', 'src', 'dst', 'disposition', 'duration'] ); } public function operatorPerformanceDaily(Request $request) { - $query = DB::table('asteriskcdrdb.cdr') + $query = DB::table(DB::raw("(SELECT *, CAST(dst AS UNSIGNED) AS dst_num FROM asteriskcdrdb.cdr) AS cdr")) ->selectRaw(" - * - (all - (ok + nok)) AS fail - FROM ( - SELECT - DATE(calldate) AS d, - dst, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END) AS ok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END) AS nok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, - COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, - COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all - FROM asteriskcdrdb.cdr - WHERE dst BETWEEN 101 AND 105 - GROUP BY d, dst - ORDER BY d, dst - ); - "); -// ->whereBetween('calldate', ["$date_from $time_from", "$date_to $time_to"]) -// ->when($cid, function ($query, $cid) { -// return $query->where('src', 'like', "%{$cid}%"); -// }) -// ->when($c_op, function ($query, $c_op) { -// return $query->where('dst', $c_op); -// }, function ($query) { -// return $query->whereBetween('dst', [100, 110]); -// }) -// ->orderByDesc('calldate'); + DATE(calldate) AS d, + dst, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 THEN 1 END) AS ok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst_num BETWEEN 1 AND 104 AND duration > 14 THEN 1 END) AS nok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 AND billsec > 9 THEN 1 END) AS b10, + COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, + COUNT(CASE WHEN dst_num BETWEEN 502 AND 599 THEN 1 END) AS trans, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst_num BETWEEN 1 AND 105 THEN 1 END) AS total_calls + ") + ->whereBetween('dst_num', [1, 105]) + ->groupBy(DB::raw('DATE(calldate)'), 'dst') + ->orderBy(DB::raw('DATE(calldate)')) + ->orderBy('dst'); return DataTableFacade::run( $query, @@ -143,25 +117,21 @@ class ReportService public function operatorPerformanceTotal(Request $request) { - $query = DB::table('asteriskcdrdb.cdr') + $query = DB::table(DB::raw("(SELECT *, CAST(dst AS UNSIGNED) AS dst_num FROM asteriskcdrdb.cdr) AS cdr")) ->selectRaw(" - * - (all - (ok + nok)) AS fail - FROM ( - SELECT - DATE(calldate) AS d, - dst, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END) AS ok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END) AS nok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, - COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, - COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all - FROM asteriskcdrdb.cdr - WHERE dst BETWEEN 101 AND 105 - GROUP BY dst - ORDER BY dst); - "); + DATE(calldate) AS d, + dst, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 THEN 1 END) AS ok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst_num BETWEEN 1 AND 104 AND duration > 14 THEN 1 END) AS nok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 AND billsec > 9 THEN 1 END) AS b10, + COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, + COUNT(CASE WHEN dst_num BETWEEN 502 AND 599 THEN 1 END) AS trans, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst_num BETWEEN 1 AND 105 THEN 1 END) AS total_calls + ") + ->whereBetween('dst_num', [1, 105]) + ->groupBy('dst') + ->orderBy(DB::raw('DATE(calldate)')) + ->orderBy('dst'); return DataTableFacade::run( $query, diff --git a/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php b/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php index 2a37667..61fe9ce 100644 --- a/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php +++ b/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('operator_dialogues', function (Blueprint $table) { $table->id(); - $table->string('cdr_unique_id'); + $table->string('cdr_unique_id', 32)->collation('utf8mb4_general_ci'); $table->dateTime('date'); $table->foreignId('supervisor_id')->constrained('users'); $table->boolean('is_listen')->default(false); diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 738fece..0a40f64 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -37,8 +37,15 @@ class PermissionSeeder extends Seeder 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() + ], + [ + 'id' => 4, + 'name' => 'teleport_to_province', + 'name_fa' => 'انتقال به استان ها', + 'guard_name' => 'api', + 'created_at' => now(), + 'updated_at' => now() ] ]); - } } diff --git a/routes/api.php b/routes/api.php index 0c62851..c68579a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -15,6 +15,7 @@ use App\Http\Controllers\ProfileController; use App\Http\Controllers\ProvinceController; use App\Http\Controllers\ProvinceDashboard\ReportController; use App\Http\Controllers\ProvinceDashboard\VerifyAuthenticationController; +use App\Http\Middleware\SuperAdminCheck; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route;