Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 398
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
GestionaController
0.00% covered (danger)
0.00%
0 / 398
0.00% covered (danger)
0.00%
0 / 14
4830
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
2
 updateApiCredentials
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getApiDetails
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 getLastUpdate
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 getAcceptanceWarnings
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
42
 getSyncStatus
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getG3wActive
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 updateG3wActive
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 getMappings
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 setMappings
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
156
 deleteMappings
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 getAllBudgetMonitor
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 1
132
 syncAllBudgetMonitor
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
42
 getDuplicatedValues
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2namespace App\Http\Controllers;
3
4use App\Models\TblCompanies;
5use App\Models\TblG3wLastUpdate;
6use App\Models\TblQuotations;
7use App\Models\TblSegmentG3wMapping;
8use App\Models\TblSourceG3wMapping;
9use App\Models\TblSources;
10use App\Models\TblStatusG3wMapping;
11use App\Models\TblTypeG3wMapping;
12use App\Models\TblUserG3wMapping;
13use App\Models\TblUsers;
14use App\Services\PresupuestosService;
15use Illuminate\Http\Request;
16use App\Services\GestionaService;
17use Illuminate\Support\Carbon;
18use Illuminate\Support\Facades\Log;
19use Illuminate\Support\Facades\DB;
20use Illuminate\Support\Facades\Schema;
21use function Illuminate\Events\queueable;
22
23class GestionaController extends Controller
24{
25    protected $gestionaService;
26    protected $presupuestoService;
27    protected $tables;
28
29    public function __construct(GestionaService $gestionaService, PresupuestosService $presupuestoService)
30    {
31        $this->gestionaService = $gestionaService;
32        $this->presupuestoService = $presupuestoService;
33        $this->tables = [
34            "status" => [
35                "model" => TblStatusG3wMapping::class,
36                "index" => "budget_status_id",
37                "relation" => "budgetStatus",
38                "tblQuotationsG3wNameColumn" => "status_by_g3w",
39                "tblMappingNameColumn" => "name_g3w",
40                "tblQuotationsNameColumn" => "budget_status_id",
41                "requestNameKey" => "budget_status_id"
42            ],
43            "segment" => [
44                "model" => TblSegmentG3wMapping::class,
45                "index" => "segment_id",
46                "relation" => "segment",
47                "tblQuotationsG3wNameColumn" => "segment_by_g3w",
48                "tblMappingNameColumn" => "name_g3w",
49                "tblQuotationsNameColumn" => "segment_id",
50                "requestNameKey" => "segment_id"
51            ],
52            "type" => [
53                "model" => TblTypeG3wMapping::class,
54                "index" => "budget_type_name",
55                "relation" => "budgetType",
56                "tblQuotationsG3wNameColumn" => "type_by_g3w",
57                "tblMappingNameColumn" => "id_g3w",
58                "tblQuotationsNameColumn" => "budget_type_id",
59                "requestNameKey" => "id_g3w"
60            ],
61            "source" => [
62                "model" => TblSourceG3wMapping::class,
63                "index" => "source_name",
64                "relation" => "source",
65                "tblQuotationsG3wNameColumn" => "source_by_g3w",
66                "tblMappingNameColumn" => "id_g3w",
67                "tblQuotationsNameColumn" => "source_id",
68                "requestNameKey" => "id_g3w"
69            ],
70            "user" => [
71                "model" => TblUserG3wMapping::class,
72                "index" => "id_fst",
73                "relation" => "user",
74                "tblQuotationsG3wNameColumn" => "G3W_code",
75                "tblMappingNameColumn" => "id_fst",
76                "tblQuotationsNameColumn" => "G3W_code",
77                "requestNameKey" => "id_fst"
78            ],
79        ];
80    }
81
82    /**
83     * Sincroniza un presupuesto por su ID.
84     *
85     * @param $id
86     * @return \Illuminate\Http\JsonResponse
87     */
88    public function updateApiCredentials(Request $request)
89    {
90        try {
91            $region = @getallheaders()["Region"];
92
93            if($region == "Catalunya"){
94                $region = "Cataluña";
95            }
96
97            $params = $request->only(['url', 'user', 'password', 'user_id']);
98            $this->gestionaService->updateApiCredentials($params, $region);
99            return response()->json(['message' => 'Credentials updated successfully'], 200);
100        } catch (\Exception $e) {
101            /** @disregard P1014 */
102            $e->exceptionCode = 'UPDATE_API_CREDENTIALS_EXCEPTION'; 
103            report($e);
104            return response()->json(['error' => $e->getMessage()], 400);
105        }
106    }
107
108    /**
109     * @return \Illuminate\Http\JsonResponse
110     * @throws \Exception
111     */
112    public function getApiDetails(){
113        try {
114            $region = @getallheaders()["Region"];
115
116            if($region === "Catalunya"){
117                $region="Cataluña";
118            }
119
120            $apiDetailsResponse = $this->gestionaService->getApiDetails($region);
121
122            if(!$apiDetailsResponse){
123                throw new \Exception('Api details not found');
124            }
125
126            $apiDetails = json_decode($apiDetailsResponse->getContent(), true);
127
128            return response()->json([
129                'url' => $apiDetails['url'] ?? null,
130                'user' => $apiDetails['user'] ?? null,
131            ], 200);
132
133        } catch (\Illuminate\Database\QueryException $e) {
134            /** @disregard P1014 */
135            $e->exceptionCode = 'GET_API_DETAILS_EXCEPTION'; 
136            report($e);
137            return response()->json(['error' => $e->getMessage()], 400);
138        }
139    }
140
141    public function getLastUpdate(){
142        try {
143            $region = @getallheaders()["Region"];
144
145            if($region === "Catalunya"){
146                $region="Cataluña";
147            }
148
149            $apiLastUpdateResponse = $this->gestionaService->getLastUpdate($region);
150
151            if(!$apiLastUpdateResponse){
152                throw new \Exception('Last update not found');
153            }
154
155            $apiLastUpdate = json_decode($apiLastUpdateResponse->getContent(), true);
156
157            return response()->json([
158                'lastUpdate' => $apiLastUpdate['lastUpdate'] ?? null,
159                'updatingNow' => $apiLastUpdate['updatingNow'] ?? null,
160            ], 200);
161
162        } catch (\Illuminate\Database\QueryException $e) {
163            /** @disregard P1014 */
164            $e->exceptionCode = 'GET_LAST_UPDATE_EXCEPTION'; 
165            report($e);
166            Log::error('Error en getLastUpdate: ' . $e->getMessage());
167            return response()->json(['error' => $e->getMessage()], 400);
168        }
169    }
170
171    public function getAcceptanceWarnings(Request $request)
172    {
173        try {
174            $region = @getallheaders()["Region"] ?? null;
175
176            if (!$region) {
177                return response()->json(['error' => 'Region header is missing'], 400);
178            }
179
180            if ($region == "Catalunya") {
181                $region = "Cataluña";
182            }
183
184            $commercial = $request->input('commercial', null);
185
186            $company = TblCompanies::where('region', $region)->first();
187            if (!$company) {
188                return response()->json([
189                    'countWarnings' => 0
190                ], 200);
191            }
192
193            $companyId = $company->company_id;
194
195            /*$countWarnings = TblQuotations::where('sync_import', 1)
196                ->where('company_id', $companyId)
197                ->when(!empty($commercial) && $commercial !== "All", function ($query) use ($commercial) {
198                    return $query->where('commercial', $commercial);
199                })
200                ->where(function ($query) {
201                    $query->WhereIn('budget_status_id', [13, 14])
202                        ->orWhere(function ($subQuery) {
203                            $subQuery->whereNull('commercial')
204                                ->orWhereNotExists(function ($subQuery) {
205                                    $subQuery->select(DB::raw(1))
206                                        ->from('tbl_users')
207                                        ->whereColumn('tbl_users.name', 'tbl_quotations.commercial');
208                                });
209                        })
210                        ->orWhereNull('phone_number')
211                        ->orWhereNull('source_id')
212                        ->orWhereNull('budget_type_id')
213                        ->orWhere(function ($subQuery) {
214                            $subQuery->whereNull('client')
215                                ->orWhere(DB::raw('TRIM(client)'), '');
216                        })
217                        ->orWhere(function ($subQuery) {
218                            $subQuery->whereNull('email')
219                                ->orWhere(DB::raw('TRIM(email)'), '');
220                        });
221                })
222                ->count();*/
223
224            $countWarnings = TblQuotations::where('sync_import', 1)
225                ->where('company_id', $companyId)
226                ->where('g3w_warning', 1)
227                ->when(!empty($commercial) && $commercial !== "All", function ($query) use ($commercial) {
228                    return $query->where('commercial', $commercial);
229                })
230                ->count();
231
232
233            return response()->json([
234                'countWarnings' => $countWarnings
235            ], 200);
236
237        } catch (\Illuminate\Database\QueryException $e) {
238            /** @disregard P1014 */
239            $e->exceptionCode = 'ADD_WORK_STATUS_EXCEPTION'; 
240            report($e);
241            Log::error('Error en getAcceptanceWarnings: ' . $e->getMessage());
242            return response()->json(['error' => $e->getMessage()], 400);
243        }
244    }
245
246    public function getSyncStatus(){
247        try {
248            $region = @getallheaders()["Region"];
249
250            if($region === "Catalunya"){
251                $region="Cataluña";
252            }
253
254            return response()->json([
255                'status' => $this->gestionaService->getSyncStatus($region)
256            ], 200);
257
258        } catch (\Illuminate\Database\QueryException $e) {
259            /** @disregard P1014 */
260            $e->exceptionCode = 'GET_SYNC_STATUS_EXCEPTION'; 
261            report($e);
262            return response()->json(['error' => $e->getMessage()], 400);
263        }
264    }
265
266    public function getG3wActive(){
267        try {
268            $region = @getallheaders()["Region"];
269
270            if($region === "Catalunya"){
271                $region="Cataluña";
272            }
273
274            return response()->json([
275                'active' => $this->gestionaService->getG3wActive($region)
276            ], 200);
277
278        } catch (\Illuminate\Database\QueryException $e) {
279            /** @disregard P1014 */
280            $e->exceptionCode = 'GET_G3W_ACTIVE_EXCEPTION'; 
281            report($e);
282            Log::error('Error en getG3wActive: ' . $e->getMessage());
283            return response()->json(['error' => $e->getMessage()], 400);
284        }
285    }
286
287    public function updateG3wActive(Request $request){
288        try {
289            $region = @getallheaders()["Region"];
290
291            if($region === "Catalunya"){
292                $region="Cataluña";
293            }
294
295            $active = $request->input('active');
296
297            $this->gestionaService->updateG3wActive($active, $region);
298
299            return response()->json([
300                'success' => 1
301            ], 200);
302
303        } catch (\Illuminate\Database\QueryException $e) {
304            /** @disregard P1014 */
305            $e->exceptionCode = 'UPDATE_G3W_ACTIVE_EXCEPTION'; 
306            report($e);
307            return response()->json(['error' => $e->getMessage()], 400);
308        }
309    }
310
311    public function getMappings(Request $request)
312    {
313        try {
314
315            if (!$request->has("type") || !array_key_exists($request->type, $this->tables)) {
316                throw new \Exception('Type parameter is missing or invalid');
317            }
318
319            $tableConfig = $this->tables[$request->type];
320
321            if (isset($tableConfig['model'])) {
322                $mappings = $tableConfig['model']::with([$tableConfig['relation'] => function ($query) use ($tableConfig) {
323                    $relatedModel = (new $tableConfig['model'])->{$tableConfig['relation']}()->getRelated();
324                    $relatedTable = $relatedModel->getTable();
325
326                    if (Schema::hasColumn($relatedTable, 'priority')) {
327                        $query->orderBy('priority', 'desc');
328                    }
329                }])->get();
330            }
331            else {
332                $mappings = DB::table($tableConfig['table'])->get();
333            }
334
335            return response()->json($mappings);
336
337        } catch (\Exception $e) {
338            /** @disregard P1014 */
339            $e->exceptionCode = 'GET_MAPPINGS_EXCEPTION'; 
340            report($e);
341            return response()->json(['error' => $e->getMessage()], 400);
342        }
343    }
344
345    public function setMappings(Request $request)
346    {
347        try{
348            if(!$request->has('type')){
349                return response()->json(['message' => 'Not type especified']);
350            }
351
352            $tableConfig = $this->tables[$request->type];
353
354            if (!isset($tableConfig['tblQuotationsG3wNameColumn'], $tableConfig['tblMappingNameColumn'], $tableConfig['tblQuotationsNameColumn'], $tableConfig['requestNameKey'])) {
355                return response()->json(['message' => 'Missing configuration keys'], 500);
356            }
357
358            $data = $request->except('type');
359
360            if(!$request->has('id')){
361                $tableConfig['model']::create($data);
362                return response()->json(['message' => $request->type . ' created successfully']);
363            }
364
365            if ($tableConfig['relation'] === "user") {
366                if(is_numeric($request["id"])){
367                    $rowMapping = $tableConfig['model']::where("id_fst", $request["id"])->first();
368                    $data = $request->except('id');
369
370                    if (!$rowMapping) {
371                        $tableConfig['model']::create($data);
372                        return response()->json(['error' => 'User mapping not found'], 404);
373                    }
374
375                    $userName = TblUsers::where('id', $rowMapping->id_fst)->first()->name;
376                    $nameG3w = $rowMapping->name_g3w;
377
378                    TblQuotations::where("user_create_by_g3w", $nameG3w)
379                        ->update(['created_by' => $userName]);
380
381                    TblQuotations::where("user_commercial_by_g3w", $nameG3w)
382                        ->update(['commercial' => $userName]);
383
384                    TblQuotations::where("user_create_by_g3w", $nameG3w)
385                        ->whereNull('commercial')
386                        ->whereNull('user_commercial_by_g3w')
387                        ->update(['commercial' => $nameG3w]);
388
389
390                    $rowMapping->update($data);
391
392                } else {
393                    $rowMapping = $tableConfig['model']::where("name_g3w", $request["id"])->first();
394
395                    if (!$rowMapping) {
396                        return response()->json(['error' => 'User mapping not found'], 404);
397                    }
398
399                    $rowMapping->update(array('id_fst' => $request["id_fst"]));
400
401                    $userName = TblUsers::where('id', $request["id_fst"])->first();
402
403                    if(!$userName){
404                        return response()->json(['error' => 'User mapping not found'], 404);
405                    }
406
407                    TblQuotations::where("user_create_by_g3w", $request["id"])
408                        ->update(['created_by' => $userName->name]);
409
410                    TblQuotations::where("user_commercial_by_g3w", $request["id"])
411                        ->update(['commercial' => $userName->name]);
412
413                    TblQuotations::where("user_create_by_g3w", $request["id"])
414                        ->whereNull('commercial')
415                        ->whereNull('user_commercial_by_g3w')
416                        ->update(['commercial' => $userName->name]);
417
418                }
419
420                return response()->json(['message' => $request->type . ' edited successfully']);
421            }
422
423            $rowMapping = $tableConfig['model']::where("id", $request["id"])->first();
424
425            if ($tableConfig['relation'] === "source") {
426                $data = [];
427                $sourceRow = TblSources::where('source_id', $request["id_fst"])->first();
428                if(!$sourceRow){
429                    return response()->json(['error' => 'Source mapping not found'], 404);
430                }
431
432                $data["source_name"] = $sourceRow->name;
433            }
434
435            $rowMapping->update($data);
436
437            TblQuotations::where($tableConfig['tblQuotationsG3wNameColumn'], $rowMapping[$tableConfig['tblMappingNameColumn']])
438                            ->update([$tableConfig['tblQuotationsNameColumn'] => $rowMapping[$tableConfig['requestNameKey']]]);
439
440            return response()->json(['message' => $request->type . ' edited successfully']);
441
442        }catch (\Illuminate\Database\QueryException $e) {
443            /** @disregard P1014 */
444            $e->exceptionCode = 'SET_MAPPING_EXCEPTION'; 
445            report($e);
446            return response()->json(['error' => $e->getMessage()], 400);
447        }
448    }
449
450    public function deleteMappings(Request $request)
451    {
452        try{
453            if(!$request->has('id')){
454                return response()->json(['message' => 'Can`t be deleted without ID']);
455            }
456
457            if(!$request->has('type')){
458                return response()->json(['message' => 'Not type especified']);
459            }
460
461            $tableConfig = $this->tables[$request->type];
462
463            if($tableConfig['relation'] === "user"){
464                $tableConfig['model']::where("id_fst", $request["id"])->delete();
465                return response()->json(['message' => $request->type . ' deleted successfully']);
466            }
467
468            $tableConfig['model']::where("id", $request["id"])->delete();
469            return response()->json(['message' => $request->type . ' deleted successfully']);
470
471        }catch (\Illuminate\Database\QueryException $e) {
472            /** @disregard P1014 */
473            $e->exceptionCode = 'DELETE_MAPPING_EXCEPTION'; 
474            report($e);
475            return response()->json(['error' => $e->getMessage()], 400);
476        }
477    }
478
479    public function getAllBudgetMonitor(Request $request)
480    {
481        try {
482            $data = $request->all();
483            $region = urldecode(@getallheaders()["Region"]);
484            $page = $data["page"];
485
486            $daysOffset = $page * 10;
487            $endDate = Carbon::today()->subDays($daysOffset);
488            $startDate = $endDate->copy()->addDays(10);
489
490            $dataResponse = [];
491            $currentDate = $startDate->copy();
492            $companyId = TblCompanies::where("region", $region)->first()->company_id;
493            $alreadyG3wBudgets = [];
494
495            while ($currentDate > $endDate) {
496                $dateStr = $currentDate->format('Y-m-d');
497
498                $g3wBudgets = $this->gestionaService->getBudgetsByDay($dateStr, $region);
499                if (is_string($g3wBudgets)) {
500                    $g3wBudgets = json_decode($g3wBudgets, true);
501                }
502
503                $g3wBudgetIds = array_map(function($item) {
504                    return $item["ID"];
505                }, $g3wBudgets);
506
507                $newG3wBudgetIds = array_diff($g3wBudgetIds, $alreadyG3wBudgets);
508                $alreadyG3wBudgets = array_merge($alreadyG3wBudgets, $newG3wBudgetIds);
509                $countG3wBudgets = count($newG3wBudgetIds);
510
511                $fstBudgets = TblQuotations::where("company_id", $companyId)
512                    ->where(function($query) {
513                        $query->where("sync_import", 1)
514                            ->orWhere("sync_import_edited", 1);
515                    })
516                    ->whereDate("created_at", $dateStr)
517                    ->pluck("internal_quote_id")
518                    ->toArray();
519
520                if ($companyId == 18 || $companyId == 22){
521                    $fstBudgets = TblQuotations::whereIn("company_id", [18, 22])
522                        ->where(function($query) {
523                            $query->where("sync_import", 1)
524                                ->orWhere("sync_import_edited", 1);
525                        })
526                        ->whereDate("created_at", $dateStr)
527                        ->pluck("internal_quote_id")
528                        ->toArray();
529                }
530
531                $countFstBudgets = count($fstBudgets);
532
533                $missingIds = array_diff($newG3wBudgetIds, $fstBudgets);
534
535                $existingIds = TblQuotations::where("company_id", $companyId)
536                    ->where(function($query) {
537                        $query->where("sync_import", 1)
538                            ->orWhere("sync_import_edited", 1);
539                    })
540                    ->whereIn("internal_quote_id", $missingIds)
541                    ->pluck("internal_quote_id")
542                    ->toArray();
543
544                if($companyId == 18 || $companyId == 22){
545                    $existingIds = TblQuotations::where("company_id", $companyId)
546                        ->where(function($query) {
547                            $query->where("sync_import", 1)
548                                ->orWhere("sync_import_edited", 1);
549                        })
550                        ->whereIn("internal_quote_id", $missingIds)
551                        ->pluck("internal_quote_id")
552                        ->toArray();
553                }
554
555                $finalMissingIds = array_diff($missingIds, $existingIds);
556
557                $duplicatedFst = $this->getDuplicatedValues($fstBudgets);
558
559                $deletedIds = array_diff($fstBudgets, $newG3wBudgetIds);
560                foreach ($deletedIds as $key => $id){
561                    $deleted = $this->gestionaService->checkDeleted($id, $region);
562                    if(!$deleted){
563                        unset($deletedIds[$key]);
564                    }
565                }
566
567                $dataResponse[] = [
568                    'date' => $dateStr,
569                    'g3wBudgets' => array_values($newG3wBudgetIds),
570                    'countG3wBudgets' => $countG3wBudgets,
571                    'fstBudgets' => $fstBudgets,
572                    'countfstBudgets' => $countFstBudgets,
573                    'missingIds' => array_values($finalMissingIds),
574                    'duplicatedFst' => $duplicatedFst,
575                    'deletedIds' => array_values($deletedIds)
576                ];
577
578                $currentDate->subDay();
579
580            }
581
582            usort($dataResponse, function($a, $b) {
583                return strtotime($b['date']) - strtotime($a['date']);
584            });
585
586            return response()->json([
587                'data' => $dataResponse,
588                'meta' => [
589                    'current_page' => (int)$page,
590                    'date_range' => [
591                        'start' => $startDate->format('Y-m-d'),
592                        'end' => $endDate->format('Y-m-d')
593                    ]
594                ]]);
595        } catch (\Exception $e){
596            /** @disregard P1014 */
597            $e->exceptionCode = 'GET_ALL_BUDGET_MONITOR_EXCEPTION'; 
598            report($e);
599            Log::error('Error en getAllBudgetMonitor: ' . $e->getMessage());
600
601            if($e->getMessage() == "API URL is not defined."){
602                return response()->json([
603                    'error' => 'KO',
604                    'message' => 'La conexión con la API de G3W no está configurada. Por favor, configúrala en los ajustes de la empresa.'
605                ], 200);
606            }
607
608            return response()->json([
609                'message' => 'Error interno del servidor'
610            ], 500);
611        }
612    }
613
614    public function syncAllBudgetMonitor(Request $request)
615    {
616        try {
617            $data = $request->all();
618            if (app()->runningInConsole()) {
619                $region = $request->header('Region');
620            } else {
621                $headers = getallheaders();
622                $region = urldecode($headers["Region"] ?? '');
623            }
624            $day = $data["day"];
625            $dataResponse = [];
626            $companyId = TblCompanies::where("region", $region)->first()->company_id;
627            $alreadyG3wBudgets = [];
628
629            $g3wBudgets = $this->gestionaService->getBudgetsByDay($day, $region);
630
631            if (is_string($g3wBudgets)) {
632                $g3wBudgets = json_decode($g3wBudgets, true);
633            }
634
635            $g3wBudgetIds = array_map(function($item) {
636                return $item["ID"];
637            }, $g3wBudgets);
638
639            $newG3wBudgetIds = array_diff($g3wBudgetIds, $alreadyG3wBudgets);
640            $alreadyG3wBudgets = array_merge($alreadyG3wBudgets, $newG3wBudgetIds);
641
642            $fstBudgets = TblQuotations::where("company_id", $companyId)
643                ->where("sync_import", 1)
644                ->whereDate("created_at", $day)
645                ->pluck("internal_quote_id")
646                ->toArray();
647
648            $missingIds = array_diff($newG3wBudgetIds, $fstBudgets);
649
650            $existingIds = TblQuotations::where("company_id", $companyId)
651                ->where("sync_import", 1)
652                ->whereIn("internal_quote_id", $missingIds)
653                ->pluck("internal_quote_id")
654                ->toArray();
655
656            $finalMissingIds = array_diff($missingIds, $existingIds);
657
658            $duplicatedFst = $this->getDuplicatedValues($fstBudgets);
659
660            $deletedIds = array_diff($fstBudgets, $newG3wBudgetIds);
661
662            foreach ($deletedIds as $key => $id){
663                $deleted = $this->gestionaService->checkDeleted($id, $region);
664                if(!$deleted){
665                    unset($deletedIds[$key]);
666                }
667            }
668
669            $this->presupuestoService->syncByIds(implode(',', $finalMissingIds), $region, $day);
670
671            $dataResponse[] = [
672                'missingIds' => array_values($finalMissingIds),
673                'deletedIds' => array_values($deletedIds)
674            ];
675
676            return response()->json([
677                'success' => true,
678                'message' => "Presupuestos que faltan sincronizados correctamente",
679            ]);
680        } catch (\Exception $e){
681            /** @disregard P1014 */
682            $e->exceptionCode = 'SYNC_ALL_BUDGET_MONITOR_EXCEPTION'; 
683            report($e);
684            Log::error('Error en getAllBudgetMonitor: ' . $e->getMessage());
685
686            return response()->json([
687                'message' => 'Error interno del servidor'
688            ], 500);
689        }
690    }
691
692    private function getDuplicatedValues($fstBudgets) {
693        $filteredValues = array_filter($fstBudgets, function($value) {
694            return $value !== null;
695        });
696
697        if (empty($filteredValues)) {
698            return [];
699        }
700
701        $counts = array_count_values($filteredValues);
702        $duplicates = array_filter($counts, function($count) {
703            return $count > 1;
704        });
705
706        return array_keys($duplicates);
707    }
708}