Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 269
0.00% covered (danger)
0.00%
0 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
FinanceController
0.00% covered (danger)
0.00%
0 / 269
0.00% covered (danger)
0.00%
0 / 18
2862
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCompany
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 list_regions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 list_sedes
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 list_budget
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 upsert_budget
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 bulk_upsert_budget
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 list_prevision
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 upsert_prevision
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 bulk_upsert_prevision
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 list_resumen
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 load_resumen
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
90
 list_report_semanal
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
6
 load_report_semanal
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
156
 list_recipients
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 create_recipient
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 update_recipient
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 delete_recipient
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Http\Controllers;
4
5use App\Models\TblCompanies;
6use App\Models\TblFinanceBudgetAnual;
7use App\Models\TblFinancePrevisionAnual;
8use App\Models\TblFinanceRegions;
9use App\Models\TblFinanceReportRecipients;
10use App\Models\TblFinanceReportSemanal;
11use App\Models\TblFinanceResumenAnual;
12use App\Models\TblFinanceSedes;
13use Illuminate\Http\Request;
14use Illuminate\Support\Facades\App;
15use Illuminate\Support\Facades\DB;
16use Illuminate\Support\Facades\Log;
17
18class FinanceController extends Controller
19{
20    public function __construct()
21    {
22        App::setLocale(@getallheaders()['Locale-ID']);
23    }
24
25    // -------------------------------------------------------
26    // Helpers
27    // -------------------------------------------------------
28    private function getCompany(Request $request)
29    {
30        $region = urldecode($request->header('Region'));
31
32        return TblCompanies::where('region', $region)->firstOrFail();
33    }
34
35    // -------------------------------------------------------
36    // SEDES & REGIONES
37    // -------------------------------------------------------
38    public function list_regions(Request $request)
39    {
40        try {
41            $company = $this->getCompany($request);
42            $data = TblFinanceRegions::where('company_id', $company->company_id)
43                ->where('is_active', 1)
44                ->with('sedes')
45                ->orderBy('name')
46                ->get();
47
48            return response(['message' => 'OK', 'data' => $data]);
49        } catch (\Exception $e) {
50            /** @disregard P1014 */
51            $e->exceptionCode = 'LIST_FINANCE_REGIONS_EXCEPTION';
52            report($e);
53
54            return response(['message' => 'KO', 'error' => $e->getMessage()]);
55        }
56    }
57
58    public function list_sedes(Request $request)
59    {
60        try {
61            $company = $this->getCompany($request);
62            $data = TblFinanceSedes::where('company_id', $company->company_id)
63                ->where('is_active', 1)
64                ->with('region')
65                ->orderBy('name')
66                ->get();
67
68            return response(['message' => 'OK', 'data' => $data]);
69        } catch (\Exception $e) {
70            /** @disregard P1014 */
71            $e->exceptionCode = 'LIST_FINANCE_SEDES_EXCEPTION';
72            report($e);
73
74            return response(['message' => 'KO', 'error' => $e->getMessage()]);
75        }
76    }
77
78    // -------------------------------------------------------
79    // BUDGET ANUAL
80    // -------------------------------------------------------
81
82    /**
83     * GET /finance/budget?year=2025
84     * Devuelve todas las filas de Budget para el año dado,
85     * agrupadas por sede y región.
86     */
87    public function list_budget(Request $request)
88    {
89        try {
90            $company = $this->getCompany($request);
91            Log::info($company);
92            $year = $request->query('year', date('Y'));
93
94            $data = TblFinanceBudgetAnual::where('company_id', $company->company_id)
95                ->where('year', $year)
96                ->with(['sede.region'])
97                ->orderBy('sede_id')
98                ->orderBy('month')
99                ->get();
100
101            return response(['message' => 'OK', 'data' => $data]);
102        } catch (\Exception $e) {
103            /** @disregard P1014 */
104            $e->exceptionCode = 'LIST_BUDGET_EXCEPTION';
105            report($e);
106
107            return response(['message' => 'KO', 'error' => $e->getMessage()]);
108        }
109    }
110
111    /**
112     * POST /finance/budget
113     * Crea o actualiza (upsert) una fila de Budget.
114     * Body: { sede_id, year, month, amount }
115     */
116    public function upsert_budget(Request $request)
117    {
118        try {
119            $company = $this->getCompany($request);
120            $data = $request->all();
121
122            TblFinanceBudgetAnual::updateOrCreate(
123                [
124                    'company_id' => $company->company_id,
125                    'sede_id' => $data['sede_id'],
126                    'year' => $data['year'],
127                    'month' => $data['month'],
128                ],
129                ['amount' => $data['amount']]
130            );
131
132            return response(['message' => 'OK']);
133        } catch (\Exception $e) {
134            /** @disregard P1014 */
135            $e->exceptionCode = 'UPSERT_BUDGET_EXCEPTION';
136            report($e);
137
138            return response(['message' => 'KO', 'error' => $e->getMessage()]);
139        }
140    }
141
142    /**
143     * POST /finance/budget/bulk
144     * Guarda múltiples filas de Budget en una sola llamada.
145     * Body: { year, rows: [{ sede_id, month, amount }, ...] }
146     */
147    public function bulk_upsert_budget(Request $request)
148    {
149        try {
150            $company = $this->getCompany($request);
151            $year = $request->input('year');
152            $rows = $request->input('rows', []);
153
154            DB::transaction(function () use ($company, $year, $rows) {
155                foreach ($rows as $row) {
156                    TblFinanceBudgetAnual::updateOrCreate(
157                        [
158                            'company_id' => $company->company_id,
159                            'sede_id' => $row['sede_id'],
160                            'year' => $year,
161                            'month' => $row['month'],
162                        ],
163                        ['amount' => $row['amount']]
164                    );
165                }
166            });
167
168            return response(['message' => 'OK']);
169        } catch (\Exception $e) {
170            /** @disregard P1014 */
171            $e->exceptionCode = 'BULK_UPSERT_BUDGET_EXCEPTION';
172            report($e);
173
174            return response(['message' => 'KO', 'error' => $e->getMessage()]);
175        }
176    }
177
178    // -------------------------------------------------------
179    // PREVISIÓN ANUAL
180    // -------------------------------------------------------
181
182    public function list_prevision(Request $request)
183    {
184        try {
185            $company = $this->getCompany($request);
186            $year = $request->query('year', date('Y'));
187
188            $data = TblFinancePrevisionAnual::where('company_id', $company->company_id)
189                ->where('year', $year)
190                ->with(['sede.region'])
191                ->orderBy('sede_id')
192                ->orderBy('month')
193                ->get();
194
195            return response(['message' => 'OK', 'data' => $data]);
196        } catch (\Exception $e) {
197            /** @disregard P1014 */
198            $e->exceptionCode = 'LIST_PREVISION_EXCEPTION';
199            report($e);
200
201            return response(['message' => 'KO', 'error' => $e->getMessage()]);
202        }
203    }
204
205    public function upsert_prevision(Request $request)
206    {
207        try {
208            $company = $this->getCompany($request);
209            $data = $request->all();
210
211            TblFinancePrevisionAnual::updateOrCreate(
212                [
213                    'company_id' => $company->company_id,
214                    'sede_id' => $data['sede_id'],
215                    'year' => $data['year'],
216                    'month' => $data['month'],
217                ],
218                ['amount' => $data['amount']]
219            );
220
221            return response(['message' => 'OK']);
222        } catch (\Exception $e) {
223            /** @disregard P1014 */
224            $e->exceptionCode = 'UPSERT_PREVISION_EXCEPTION';
225            report($e);
226
227            return response(['message' => 'KO', 'error' => $e->getMessage()]);
228        }
229    }
230
231    public function bulk_upsert_prevision(Request $request)
232    {
233        try {
234            $company = $this->getCompany($request);
235            $year = $request->input('year');
236            $rows = $request->input('rows', []);
237
238            DB::transaction(function () use ($company, $year, $rows) {
239                foreach ($rows as $row) {
240                    TblFinancePrevisionAnual::updateOrCreate(
241                        [
242                            'company_id' => $company->company_id,
243                            'sede_id' => $row['sede_id'],
244                            'year' => $year,
245                            'month' => $row['month'],
246                        ],
247                        ['amount' => $row['amount']]
248                    );
249                }
250            });
251
252            return response(['message' => 'OK']);
253        } catch (\Exception $e) {
254            /** @disregard P1014 */
255            $e->exceptionCode = 'BULK_UPSERT_PREVISION_EXCEPTION';
256            report($e);
257
258            return response(['message' => 'KO', 'error' => $e->getMessage()]);
259        }
260    }
261
262    // -------------------------------------------------------
263    // RESUMEN ANUAL (solo lectura desde front, escritura automática)
264    // -------------------------------------------------------
265
266    /**
267     * GET /finance/resumen?year=2025
268     */
269    public function list_resumen(Request $request)
270    {
271        try {
272            $company = $this->getCompany($request);
273            $year = $request->query('year', date('Y'));
274
275            $data = TblFinanceResumenAnual::where('company_id', $company->company_id)
276                ->where('year', $year)
277                ->with(['sede.region'])
278                ->orderBy('sede_id')
279                ->orderBy('month')
280                ->get();
281
282            return response(['message' => 'OK', 'data' => $data]);
283        } catch (\Exception $e) {
284            /** @disregard P1014 */
285            $e->exceptionCode = 'LIST_RESUMEN_EXCEPTION';
286            report($e);
287
288            return response(['message' => 'KO', 'error' => $e->getMessage()]);
289        }
290    }
291
292    /**
293     * POST /finance/resumen/load
294     * Llamado desde el job automático del día 1 de cada mes.
295     * Body: { year, month, rows: [{ sede_id, actuals, actuals_n1, actuals_n2 }] }
296     */
297    public function load_resumen(Request $request)
298    {
299        try {
300            $company = $this->getCompany($request);
301            $year = $request->input('year');
302            $month = $request->input('month');
303            $rows = $request->input('rows', []);
304
305            DB::transaction(function () use ($company, $year, $month, $rows) {
306                foreach ($rows as $row) {
307                    $budget = TblFinanceBudgetAnual::where([
308                        'company_id' => $company->company_id,
309                        'sede_id' => $row['sede_id'],
310                        'year' => $year,
311                        'month' => $month,
312                    ])->value('amount');
313
314                    $actuals = $row['actuals'];
315                    $n1 = $row['actuals_n1'] ?? null;
316                    $n2 = $row['actuals_n2'] ?? null;
317
318                    TblFinanceResumenAnual::updateOrCreate(
319                        [
320                            'company_id' => $company->company_id,
321                            'sede_id' => $row['sede_id'],
322                            'year' => $year,
323                            'month' => $month,
324                        ],
325                        [
326                            'actuals' => $actuals,
327                            'actuals_n1' => $n1,
328                            'actuals_n2' => $n2,
329                            'budget' => $budget,
330                            'deviation_vs_n1' => ($n1 && $n1 != 0) ? (($actuals - $n1) / $n1) : null,
331                            'deviation_vs_n2' => ($n2 && $n2 != 0) ? (($actuals - $n2) / $n2) : null,
332                            'deviation_vs_budget' => ($budget && $budget != 0) ? (($actuals - $budget) / $budget) : null,
333                            'loaded_at' => now(),
334                        ]
335                    );
336                }
337            });
338
339            return response(['message' => 'OK']);
340        } catch (\Exception $e) {
341            /** @disregard P1014 */
342            $e->exceptionCode = 'LOAD_RESUMEN_EXCEPTION';
343            report($e);
344
345            return response(['message' => 'KO', 'error' => $e->getMessage()]);
346        }
347    }
348
349    // -------------------------------------------------------
350    // REPORT SEMANAL (solo lectura desde front, escritura automática)
351    // -------------------------------------------------------
352
353    /**
354     * GET /finance/report-semanal?year=2025&month=10
355     */
356    public function list_report_semanal(Request $request)
357    {
358        try {
359            $company = $this->getCompany($request);
360            $year = $request->query('year', date('Y'));
361            $month = $request->query('month', date('n'));
362
363            $data = TblFinanceReportSemanal::where('company_id', $company->company_id)
364                ->where('year', $year)
365                ->where('month', $month)
366                ->with(['sede.region'])
367                ->orderBy('week_date', 'desc')
368                ->orderBy('sede_id')
369                ->get();
370
371            return response(['message' => 'OK', 'data' => $data]);
372        } catch (\Exception $e) {
373            /** @disregard P1014 */
374            $e->exceptionCode = 'LIST_REPORT_SEMANAL_EXCEPTION';
375            report($e);
376
377            return response(['message' => 'KO', 'error' => $e->getMessage()]);
378        }
379    }
380
381    /**
382     * POST /finance/report-semanal/load
383     * Llamado desde el job automático de cada sábado.
384     * Body: { week_date, year, month, rows: [{ sede_id, actuals, actuals_n1, budget, prevision }] }
385     */
386    public function load_report_semanal(Request $request)
387    {
388        try {
389            $company = $this->getCompany($request);
390            $weekDate = $request->input('week_date');
391            $year = $request->input('year');
392            $month = $request->input('month');
393            $rows = $request->input('rows', []);
394
395            DB::transaction(function () use ($company, $weekDate, $year, $month, $rows) {
396                foreach ($rows as $row) {
397                    $actuals = $row['actuals'];
398                    $n1 = $row['actuals_n1'] ?? null;
399                    $budget = $row['budget'] ?? null;
400                    $prevision = $row['prevision'] ?? null;
401
402                    TblFinanceReportSemanal::updateOrCreate(
403                        [
404                            'company_id' => $company->company_id,
405                            'sede_id' => $row['sede_id'],
406                            'week_date' => $weekDate,
407                        ],
408                        [
409                            'year' => $year,
410                            'month' => $month,
411                            'actuals' => $actuals,
412                            'actuals_n1' => $n1,
413                            'budget' => $budget,
414                            'prevision' => $prevision,
415                            'deviation_vs_n1' => ($n1 !== null) ? ($actuals - $n1) : null,
416                            'deviation_pct_vs_n1' => ($n1 && $n1 != 0) ? (($actuals - $n1) / $n1) : null,
417                            'deviation_vs_budget' => ($budget !== null) ? ($actuals - $budget) : null,
418                            'deviation_pct_vs_budget' => ($budget && $budget != 0) ? (($actuals - $budget) / $budget) : null,
419                            'deviation_vs_prevision' => ($prevision !== null) ? ($actuals - $prevision) : null,
420                            'deviation_pct_vs_prevision' => ($prevision && $prevision != 0) ? (($actuals - $prevision) / $prevision) : null,
421                            'loaded_at' => now(),
422                        ]
423                    );
424                }
425            });
426
427            return response(['message' => 'OK']);
428        } catch (\Exception $e) {
429            /** @disregard P1014 */
430            $e->exceptionCode = 'LOAD_REPORT_SEMANAL_EXCEPTION';
431            report($e);
432
433            return response(['message' => 'KO', 'error' => $e->getMessage()]);
434        }
435    }
436
437    // -------------------------------------------------------
438    // DESTINATARIOS REPORTE SEMANAL
439    // -------------------------------------------------------
440
441    public function list_recipients(Request $request)
442    {
443        try {
444            $company = $this->getCompany($request);
445            $data = TblFinanceReportRecipients::where('company_id', $company->company_id)
446                ->orderBy('name')
447                ->get();
448
449            return response(['message' => 'OK', 'data' => $data]);
450        } catch (\Exception $e) {
451            /** @disregard P1014 */
452            $e->exceptionCode = 'LIST_RECIPIENTS_EXCEPTION';
453            report($e);
454
455            return response(['message' => 'KO', 'error' => $e->getMessage()]);
456        }
457    }
458
459    public function create_recipient(Request $request)
460    {
461        try {
462            $company = $this->getCompany($request);
463            $data = $request->all();
464
465            $recipient = TblFinanceReportRecipients::create([
466                'company_id' => $company->company_id,
467                'name' => $data['name'],
468                'email' => $data['email'],
469                'is_active' => $data['is_active'] ?? 1,
470                'days_before_delete_errors' => $data['days_before_delete_errors'] ?? 7,
471            ]);
472
473            return response(['message' => 'OK', 'data' => $recipient]);
474        } catch (\Exception $e) {
475            /** @disregard P1014 */
476            $e->exceptionCode = 'CREATE_RECIPIENT_EXCEPTION';
477            report($e);
478
479            return response(['message' => 'KO', 'error' => $e->getMessage()]);
480        }
481    }
482
483    public function update_recipient(Request $request, $id)
484    {
485        try {
486            $company = $this->getCompany($request);
487            $data = $request->all();
488
489            TblFinanceReportRecipients::where('id', $id)
490                ->where('company_id', $company->company_id)
491                ->update($data);
492
493            return response(['message' => 'OK']);
494        } catch (\Exception $e) {
495            /** @disregard P1014 */
496            $e->exceptionCode = 'UPDATE_RECIPIENT_EXCEPTION';
497            report($e);
498
499            return response(['message' => 'KO', 'error' => $e->getMessage()]);
500        }
501    }
502
503    public function delete_recipient($id)
504    {
505        try {
506            TblFinanceReportRecipients::where('id', $id)->delete();
507
508            return response(['message' => 'OK']);
509        } catch (\Exception $e) {
510            /** @disregard P1014 */
511            $e->exceptionCode = 'DELETE_RECIPIENT_EXCEPTION';
512            report($e);
513
514            return response(['message' => 'KO', 'error' => $e->getMessage()]);
515        }
516    }
517}