Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 639
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
FacturasService
0.00% covered (danger)
0.00%
0 / 639
0.00% covered (danger)
0.00%
0 / 16
13110
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
 getInvoices
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 loopInvoices
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 1
210
 loopNextRemindersInvoices
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
42
 loopNextRemindersClients
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
240
 sendInvoice
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 1
600
 getAllInvoices
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
6
 getAllInvoicesExceptions
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 sendCyCInvoices
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
110
 setAllMonthAdministratorsInvoices
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
110
 sendAdministratorsInvoices
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 1
20
 addToSheets
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
56
 getGoogleSheetsService
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 writeToGoogleSheet
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
 handleGoogleAuthCallback
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
42
 getVencimientosFormateados
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Services;
4
5use App\Models\TblCompanies;
6use App\Models\TblInvoiceAdministrators;
7use App\Models\TblInvoiceReminders;
8use App\Models\TblInvoiceRemindersEmailTemplate;
9use App\Models\TblInvoicesExceptions;
10use App\Models\TblInvoicesNextReminders;
11use App\Services\GestionaService;
12use Carbon\Carbon;
13use Google\Service\Sheets;
14use Google\Service\Sheets\ValueRange;
15use Illuminate\Http\Request;
16use Illuminate\Support\Facades\Log;
17use Mockery\Exception;
18use PhpOffice\PhpSpreadsheet\Spreadsheet;
19use PhpOffice\PhpSpreadsheet\Style\Fill;
20use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
21
22class FacturasService extends GestionaService
23{
24    public function __construct()
25    {
26        parent::__construct();
27    }
28
29    public function getInvoices($region = "Cataluña"){
30        try{
31            if(!TblCompanies::where('region', $region)->where('invoice_reminder_active', 1)->exists()){
32                throw new Exception("Sincronizacion no activa para $region");
33            }
34
35            $today = date("Y-m-d");
36            $next10days = date("Y-m-d", strtotime("+10 days"));
37            $lastWeek = date("Y-m-d", strtotime("-1 week"));
38
39            $counter = 1;
40
41            $nextWeekInvoices = $this->request('get', 'factura/vence/' . $next10days, $region, []);
42            //$todayInvoices = $this->request('get', 'factura/vence/' . $today, $region, []);
43            $lastWeekInvoices = $this->request('get', 'factura/vence/' . $lastWeek, $region, []);
44
45            $resultNextWeekInvoices = $this->loopInvoices($nextWeekInvoices, 1, $region, $counter, $next10days);
46            /*$counter = $resultNextWeekInvoices["counter"] - 1;
47            if($counter >= 30){
48                return ['success' => true];
49            }*/
50
51            //$resultTodayInvoices = $this->loopInvoices($todayInvoices, 2, $region, $counter);
52            /*$counter = $resultTodayInvoices["counter"] - 1;
53            if($counter >= 30){
54                return ['success' => true];
55            }*/
56
57            $this->loopInvoices($lastWeekInvoices, 3, $region, $counter, $lastWeek);
58
59            $this->loopNextRemindersInvoices($region);
60
61            $this->loopNextRemindersClients($region, $next10days, $lastWeek);
62
63            return ['success' => true];
64        } catch (\Exception $e) {
65            Log::channel('g3w_invoices')->error($e->getMessage());
66            Log::error("Trace: " . $e->getTraceAsString());
67            return ['success' => false, 'error' => $e->getMessage()];
68        }
69    }
70
71    public function loopInvoices($invoices, $reminder_type, $region, $counter, $date=null){
72        foreach ($invoices["facturas"] as $invoice) {
73            // Continue if region is Comunidad Valenciana and the invoice starts with M
74            if(
75                $region == "Comunidad Valenciana"
76                && strpos($invoice["ID"], 'M') === 0
77            ){
78                continue;
79            }
80
81            //Check if exist a next reminder and jump the loop then
82            $existNextReminderInvoice = TblInvoicesNextReminders::where("invoice_number", $invoice["ID"])
83                ->where('region', $region)
84                ->exists();
85
86            if ($existNextReminderInvoice) {
87                continue;
88            }
89
90            $dataInvoice = $this->request('get', "factura/" . $invoice["ID"], $region, []);
91
92            if(!isset($dataInvoice["factura"])){
93                continue;
94            }
95
96            $cobrada = $dataInvoice["factura"]["cobrada"];
97            $formaPago = $dataInvoice["factura"]["forma_pago_factura"];
98
99            //Invoice already paied
100            //Invoice that the payment method is not "transferencia"
101            if (
102                $cobrada !== "NO"
103                || stripos($formaPago, "tr") === false
104            ) {
105                continue;
106            }
107
108            $existNextReminderClient = TblInvoicesNextReminders::where("id_client", $dataInvoice['factura']['cod_cliente'])
109                ->where('region', $region)
110                ->exists();
111
112            if($existNextReminderClient){
113                $this->addToSheets($dataInvoice['factura']['cod_cliente'], $dataInvoice['factura']['n_factura'], $region);
114
115                TblInvoicesNextReminders::create([
116                    "id_client" => $dataInvoice['factura']['cod_cliente'],
117                    "region" => $region,
118                    "invoice_number" => $dataInvoice['factura']['n_factura']
119                ]);
120
121                continue;
122            }
123
124            $dataClient = null;
125
126            if ($dataInvoice["factura"]["cod_cliente"]) {
127                $dataClient = $this->request('get', "cliente/" . $dataInvoice["factura"]["cod_cliente"], $region, []);
128                $dataClient = $dataClient["cliente"];
129            }
130
131            if($dataClient["tipo_cliente"] == "Administrador"){
132                $codService = $dataInvoice['factura']["lineas"][0]["cod_servicio"];
133                $dataService = $this->request('get', "servicio/" . $codService, $region, []);
134
135                TblInvoiceAdministrators::create(array(
136                    'invoice_number' => $dataInvoice['factura']['n_factura'],
137                    'region' => $region,
138                    'name' => $dataClient['cliente']['empresa'],
139                    'CIF' => $dataClient['cliente']["cliente_cif"],
140                    'email' => $dataClient['cliente']["email"],
141                    'service_name' => $dataService["servicio"]["nombre_servicio"],
142                    'service_addres' => $dataService["servicio"]["direccion"],
143                    'send_date' => $date,
144                    'expiration_date' => $date,
145                    'amount' => $dataInvoice["factura"]["importe_total_factura"],
146                ));
147                continue;
148            }
149
150            $exists = TblInvoicesExceptions::where('cif', $dataClient['cliente']['cliente_cif'])
151                ->orWhere('name', $dataClient['cliente']['empresa'])
152                ->orWhere('administrator', $dataClient['cliente']['empresa'])
153                ->orWhere('id_admin_g3w', $invoice['ID'])
154                ->orWhere('invoice_number', $dataInvoice['factura']['n_factura'])
155                ->exists();
156
157            if ($exists) {
158                continue;
159            }
160
161            $invoice_number = $dataInvoice["factura"]["n_factura"] ?? null;
162            $client_name = $dataClient["cliente"]["empresa"] ?? null;
163            $client_email = $dataClient["cliente"]["email"] ?? $dataClient["cliente"]["email_facturacion"] ?? null;
164            $cif = $dataClient["cliente"]["cliente_cif"] ?? null;
165            $issued_date = $dataInvoice["factura"]["fecha_emision"] ?? null;
166            $expiration_date = $date?? $dataInvoice["factura"]["vencimientos"][0]["fecha_vencimiento"];
167            $amount = $dataInvoice["factura"]["importe_total_factura"] ?? null;
168            $collection_date = null;
169            $document = $dataInvoice["factura"]["documento"] ?? null;
170
171            if(env("APP_ENV") === "production"){
172                $resultSend = $this->sendInvoice($invoice_number, $client_name, $client_email, $issued_date, $expiration_date, $document, $amount, $reminder_type);
173
174                if (!$resultSend["success"]) {
175                    continue;
176                }
177            }
178
179            TblInvoiceReminders::create([
180                "invoice_number" => $invoice_number,
181                "client_name" => $client_name,
182                "client_email" => $client_email,
183                "cif" => $cif,
184                "issued_date" => $issued_date,
185                "expiration_date" => $expiration_date,
186                "amount" => $amount,
187                "collection_date" => $collection_date,
188                "region" => $region,
189                "reminder_type" => $reminder_type
190            ]);
191            $counter++;
192        }
193
194        return [
195            'success' => true,
196            'counter' => $counter,
197        ];
198    }
199
200    private function loopNextRemindersInvoices($region){
201        $nextReminders = TblInvoicesNextReminders::where('region', $region)
202            ->where('next_reminders', date("Y-m-d"))
203            ->pluck('invoice_number');
204
205        foreach ($nextReminders as $nextReminder) {
206            $dataInvoice = $this->request('get', 'factura/' . $nextReminder, $region, []);
207
208            $cobrada = $dataInvoice["factura"]["cobrada"];
209            $formaPago = $dataInvoice["factura"]["forma_pago_factura"];
210
211            //Invoice already paied
212            //Invoice that the payment method is not "transferencia"
213            if (
214                $cobrada !== "NO"
215                || stripos($formaPago, "tr") === false
216            ) {
217                continue;
218            }
219
220            $invoice_number = $dataInvoice["factura"]["n_factura"] ?? null;
221            $client_name = $dataClient["cliente"]["empresa"] ?? null;
222            $client_email = $dataClient["cliente"]["email"] ?? $dataClient["cliente"]["email_facturacion"] ?? null;
223            $cif = $dataClient["cliente"]["cliente_cif"] ?? null;
224            $issued_date = $dataInvoice["factura"]["fecha_emision"] ?? null;
225            $expiration_date = $this->getVencimientosFormateados($dataInvoice);
226            $amount = $dataInvoice["factura"]["importe_total_factura"] ?? null;
227            $collection_date = null;
228            $document = $dataInvoice["factura"]["documento"] ?? null;
229
230            if (env("APP_ENV") === "production") {
231                $resultSend = $this->sendInvoice($invoice_number, $client_name, $client_email, $issued_date, $expiration_date, $document, $amount, 2);
232
233                if (!$resultSend["success"]) {
234                    continue;
235                }
236            }
237
238            TblInvoiceReminders::create(array(
239                "invoice_number" => $invoice_number,
240                "client_name" => $client_name,
241                "client_email" => $client_email,
242                "cif" => $cif,
243                "issued_date" => $issued_date,
244                "expiration_date" => $expiration_date,
245                "amount" => $amount,
246                "collection_date" => $collection_date,
247                "region" => $region,
248                "reminder_type" => 2
249            ));
250            }
251    }
252
253    private function loopNextRemindersClients($region, $next10days, $lastWeek){
254        $diaNext10 = date("j", strtotime($next10days));
255        $diaLastWeek = date("j", strtotime($lastWeek));
256
257        $nextWeekInvoices = TblInvoicesNextReminders::where("payment_day", $diaNext10)->get()->pluck('invoice_number');
258        $lastWeekInvoices = TblInvoicesNextReminders::where("payment_day", $diaLastWeek)->get()->pluck('invoice_number');
259
260        //type 1
261        foreach ($nextWeekInvoices as $reminder) {
262            if(!$reminder || is_null($reminder)){
263                continue;
264            }
265            $dataInvoice = $this->request('get', 'factura/' . $reminder, $region, []);
266            $cobrada = $dataInvoice["factura"]["cobrada"];
267            $formaPago = $dataInvoice["factura"]["forma_pago_factura"];
268
269            //Invoice already paied
270            //Invoice that the payment method is not "transferencia"
271            if (
272                $cobrada !== "NO"
273                || stripos($formaPago, "tr") === false
274            ) {
275                continue;
276            }
277
278            $invoice_number = $dataInvoice["factura"]["n_factura"] ?? null;
279            $client_name = $dataClient["cliente"]["empresa"] ?? null;
280            $client_email = $dataClient["cliente"]["email"] ?? $dataClient["cliente"]["email_facturacion"] ?? null;
281            $cif = $dataClient["cliente"]["cliente_cif"] ?? null;
282            $issued_date = $dataInvoice["factura"]["fecha_emision"] ?? null;
283            $expiration_date = $this->getVencimientosFormateados($dataInvoice);
284            $amount = $dataInvoice["factura"]["importe_total_factura"] ?? null;
285            $collection_date = null;
286            $document = $dataInvoice["factura"]["documento"] ?? null;
287
288            if (env("APP_ENV") === "production") {
289                $resultSend = $this->sendInvoice($invoice_number, $client_name, $client_email, $issued_date, $expiration_date, $document, $amount, 1);
290
291                if (!$resultSend["success"]) {
292                    continue;
293                }
294            }
295
296            TblInvoiceReminders::create(array(
297                "invoice_number" => $invoice_number,
298                "client_name" => $client_name,
299                "client_email" => $client_email,
300                "cif" => $cif,
301                "issued_date" => $issued_date,
302                "expiration_date" => $expiration_date,
303                "amount" => $amount,
304                "collection_date" => $collection_date,
305                "region" => $region,
306                "reminder_type" => 1
307            ));
308        }
309
310        //type 3
311        foreach ($lastWeekInvoices as $reminder) {
312            if(!$reminder || is_null($reminder)){
313                continue;
314            }
315            $dataInvoice = $this->request('get', 'factura/' . $reminder, $region, []);
316
317            $cobrada = $dataInvoice["factura"]["cobrada"];
318            $formaPago = $dataInvoice["factura"]["forma_pago_factura"];
319
320            //Invoice already paied
321            //Invoice that the payment method is not "transferencia"
322            if (
323                $cobrada !== "NO"
324                || stripos($formaPago, "tr") === false
325            ) {
326                continue;
327            }
328
329            $invoice_number = $dataInvoice["factura"]["n_factura"] ?? null;
330            $client_name = $dataClient["cliente"]["empresa"] ?? null;
331            $client_email = $dataClient["cliente"]["email"] ?? $dataClient["cliente"]["email_facturacion"] ?? null;
332            $cif = $dataClient["cliente"]["cliente_cif"] ?? null;
333            $issued_date = $dataInvoice["factura"]["fecha_emision"] ?? null;
334            $expiration_date = $this->getVencimientosFormateados($dataInvoice);
335            $amount = $dataInvoice["factura"]["importe_total_factura"] ?? null;
336            $collection_date = null;
337            $document = $dataInvoice["factura"]["documento"] ?? null;
338
339            if (env("APP_ENV") === "production") {
340                $resultSend = $this->sendInvoice($invoice_number, $client_name, $client_email, $issued_date, $expiration_date, $document, $amount,  3);
341
342                if (!$resultSend["success"]) {
343                    continue;
344                }
345            }
346
347            TblInvoiceReminders::create(array(
348                "invoice_number" => $invoice_number,
349                "client_name" => $client_name,
350                "client_email" => $client_email,
351                "cif" => $cif,
352                "issued_date" => $issued_date,
353                "expiration_date" => $expiration_date,
354                "amount" => $amount,
355                "collection_date" => $collection_date,
356                "region" => $region,
357                "reminder_type" => 3
358            ));
359        }
360
361    }
362
363    public function sendInvoice($invoice_number, $client_name, $client_email, $issued_date, $expiration_date, $document, $amount, $reminder_type, $table = null, $month = null) {
364        if (
365            empty($invoice_number) ||
366            empty($client_name) ||
367            empty($client_email) ||
368            empty($issued_date) ||
369            empty($expiration_date) ||
370            empty($document) ||
371            empty($reminder_type)
372        ) {
373            Log::channel('g3w_invoices_not_send')->error("$invoice_number => {
374            'client_name': $client_name,
375            'client_email': $client_email,
376            'issued_date': $issued_date,
377            'expiration_date': $expiration_date,
378            'reminder_type': $reminder_type
379        }");
380
381            return ['success' => false, 'message' => 'Campos obligatorios faltantes'];
382        }
383
384        try {
385            $emailTemplate = TblInvoiceRemindersEmailTemplate::where('type', $reminder_type)->first();
386
387            if (!$emailTemplate) {
388                throw new \Exception('No se encontró la plantilla de correo para este tipo de recordatorio');
389            }
390
391            $clientEmails = preg_split('/\s*[,;\-\s]\s*/', $client_email, -1, PREG_SPLIT_NO_EMPTY);
392            $clientEmails = array_map('trim', $clientEmails);
393            $validEmails = [];
394
395            foreach ($clientEmails as $email) {
396                if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
397                    $validEmails[] = $email;
398                } else {
399                    Log::channel('g3w_invoices_not_send')->warning("Email inválido omitido: $email para factura $invoice_number");
400                }
401            }
402
403            if (empty($validEmails)) {
404                Log::channel('g3w_invoices_not_send')->error("No hay emails válidos para enviar factura $invoice_number");
405                return ['success' => false, 'message' => 'No hay direcciones de correo válidas'];
406            }
407
408            $sendgrid = new \SendGrid(env('SENDGRID_API_KEY', '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'));
409            $successCount = 0;
410            $failCount = 0;
411
412            foreach ($validEmails as $toEmail) {
413                try {
414                    $email = new \SendGrid\Mail\Mail();
415
416                    $fromEmail = 'recordatorio.factura@fire.es';
417                    $fromName = 'Recordatorio Facturas Grupo Fire';
418                    $email->setFrom($fromEmail, $fromName);
419                    $email->setReplyTo('recordatorio.facturas@fire.es', 'Recordatorio Facturas Grupo Fire');
420                    
421                    if($reminder_type != 4){
422                        $subject = str_replace(
423                            //['{{invoice_number}}', '{{expiration_date}}', '{{amount}}'],
424                            ['{{invoice_number}}', '{{expiration_date}}'],
425                            [$invoice_number, $expiration_date, $amount],
426                            $emailTemplate->subject
427                        );
428                    } else {
429                        $subject = str_replace(
430                            //['{{invoice_number}}', '{{expiration_date}}', '{{amount}}'],
431                            ['{{expiration_date}}'],
432                            [$month],
433                            $emailTemplate->subject
434                        );
435                    }
436                    
437
438                    Carbon::setLocale('es');
439
440                    if($reminder_type != 4){
441                        $body = str_replace(
442                            ['{{invoice_number}}', '{{client_name}}', '{{issued_date}}', '{{expiration_date}}', '{{amount}}'],
443                            [
444                                $invoice_number,
445                                $client_name,
446                                Carbon::createFromFormat('Y-m-d', $issued_date)->isoFormat('D [de] MMMM [de] YYYY'),
447                                $expiration_date,
448                                $amount
449                            ],
450                            $emailTemplate->html_content
451                        );
452                    }else{
453                        $body = str_replace(
454                        ['{{table}}'],
455                        [$table],
456                        $emailTemplate->html_content
457                    );
458                    }
459
460                    
461
462                    $email->setSubject($subject);
463                    $email->addContent("text/html", $body);
464                    $email->addTo($toEmail, $client_name);                    
465
466                    if(is_array($document)){
467                        foreach ($document as $doc) {
468                            if (!base64_decode($doc["content"], true)) {
469                                throw new \Exception('El documento no es un base64 válido');
470                            }
471
472                            $attachment = new \SendGrid\Mail\Attachment();
473                            $attachment->setContent($doc["content"]);
474                            $attachment->setType("application/pdf");
475                            $attachment->setFilename($doc["filename"]);
476                            $attachment->setDisposition("attachment");
477                            $attachment->setContentId("factura_" . uniqid());
478                            $email->addAttachment($attachment);
479                            
480                        }
481                    }
482
483                    if (!is_array($document)) {
484                        if (!base64_decode($document, true)) {
485                            throw new \Exception('El documento no es un base64 válido');
486                        }
487
488                        $attachment = new \SendGrid\Mail\Attachment();
489                        $attachment->setContent($document);
490                        $attachment->setType("application/pdf");
491                        $attachment->setFilename("Factura_{$invoice_number}.pdf");
492                        $attachment->setDisposition("attachment");
493                        $attachment->setContentId("factura_" . uniqid());
494                        $email->addAttachment($attachment);
495                    }
496
497                    $response = $sendgrid->send($email);
498
499                    if ($response->statusCode() == 202) {
500                        $successCount++;
501                        Log::channel('g3w_invoices_sent')->info("Factura $invoice_number enviada exitosamente a: $toEmail");
502                    } else {
503                        $failCount++;
504                        Log::channel('g3w_invoices_not_send')->error("Error enviando a $toEmail" . $response->body());
505                    }
506
507                } catch (\Exception $e) {
508                    $failCount++;
509                    Log::channel('g3w_invoices_not_send')->error("Error enviando a $toEmail" . $e->getMessage());
510                    continue;
511                }
512            }
513
514            if ($successCount > 0) {
515                return [
516                    'success' => true,
517                    'message' => "Enviados: $successCount, Fallidos: $failCount",
518                    'sent_count' => $successCount,
519                    'failed_count' => $failCount
520                ];
521            } else {
522                return [
523                    'success' => false,
524                    'message' => "Todos los envíos fallaron",
525                    'sent_count' => $successCount,
526                    'failed_count' => $failCount
527                ];
528            }
529
530        } catch (\Exception $e) {
531            Log::channel('g3w_invoices_not_send')->error("Error general enviando factura $invoice_number" . $e->getMessage());
532            return ['success' => false, 'message' => $e->getMessage()];
533        }
534    }
535
536    public function getAllInvoices($region = "Cataluña"){
537        if($region === "All"){
538            $invoices = TblInvoiceReminders::orderBy('id', 'desc')
539                ->paginate(50);
540        } else {
541            $invoices = TblInvoiceReminders::where('region', $region)
542                ->orderBy('id', 'desc')
543                ->paginate(50);
544        }
545
546        return response()->json([
547            'invoices' => $invoices->items(),
548            'pagination' => [
549                'total' => $invoices->total(),
550                'current_page' => $invoices->currentPage(),
551                'per_page' => $invoices->perPage(),
552                'last_page' => $invoices->lastPage()
553            ]
554        ]);
555    }
556
557    public function getAllInvoicesExceptions(){
558        $invoices = TblInvoicesExceptions::orderBy('id', 'desc')->paginate(50);
559
560        return response()->json([
561            'invoices' => $invoices->items(),
562            'pagination' => [
563                'total' => $invoices->total(),
564                'current_page' => $invoices->currentPage(),
565                'per_page' => $invoices->perPage(),
566                'last_page' => $invoices->lastPage()
567            ]
568        ]);
569    }
570
571    public function sendCyCInvoices($region){
572        try{
573            if(!$region){
574                throw new Exception("No region provided");
575            }
576
577            $fromDay = 45;
578            $toDay = 35;
579            $today = Carbon::createFromDate(date('Y'), date('m'), date('d'));
580            $todayFormatted = Carbon::now()->format('Y-m-d');
581
582
583            $documentName =  $todayFormatted . '.csv';
584
585            $filePath = storage_path('app/public/uploads/CyC/' . $todayFormatted . '/' . $region .'/' . $documentName);
586
587            if (!file_exists(dirname($filePath))) {
588                mkdir(dirname($filePath), 0777, true);
589            }
590
591            $file = fopen($filePath, 'w');
592
593            fputcsv($file, [
594                'Service',
595                'Language',
596                'Cyc Poliza',
597                'SP Tax Idenfication Number',
598                'SP Country',
599                'BP TaxIdentificationNumber',
600                'SP Corporate Name',
601                'BP Country',
602                'Invoice Number',
603                'Invoice Issue Date',
604                'PD Installment Due Date',
605                'PD Payment Means',
606                'Total Amount',
607                'Taxable Base',
608                'Tax Rate',
609                'Tax Amount'
610            ], ";");
611
612            while ($fromDay > $toDay) {
613                $date = $today->copy()->subDays($fromDay)->format('Y-m-d');
614                $invoices = $this->request('get', 'factura/vence/' . $date, $region, []);
615                foreach ($invoices["facturas"] as $invoice) {
616                    $invoiceData = $this->request('get', 'factura/' . $invoice["ID"], $region, []);
617                    $invoiceData = $invoiceData["factura"];
618
619                    $dataClient = $this->request('get', "cliente/" . $invoiceData["cod_cliente"], $region, []);
620                    $invoiceCobrada = $invoiceData["cobrada"];
621                    $invoiceDocument = $invoiceData["documento"];
622                    $invoiceNumber = $invoiceData["n_factura"];
623
624                    if(
625                        !$invoiceDocument ||
626                        $invoiceCobrada !== "NO"){
627                        continue;
628                    }
629
630                    if($region === "Cataluña" && stripos($invoiceNumber, "R") === false){
631                        continue;
632                    }
633
634                    fputcsv($file, [
635                        'grabacionFacturas',
636                        'ESP',
637                        '156547',
638                        'B67795088',
639                        'ESP',
640                        $dataClient['cliente']['cliente_cif'],
641                        $dataClient['cliente']['empresa'],
642                        'ESP',
643                        $invoiceNumber,
644                        $invoiceData["fecha_creacion"],
645                        $invoiceData["vencimientos"][0]["fecha_vencimiento"],
646                        $invoiceData["forma_pago_factura"],
647                        $invoiceData["importe_total_factura"],
648                        $invoiceData["base_imponible_factura"],
649                        $invoiceData["iva_factura"]*100,
650                        $invoiceData["importe_iva_factura"]
651                    ],";");
652
653                }
654                --$fromDay;
655            }
656
657            fclose($file);
658
659            return ['success' => true];
660        } catch (\Exception $e) {
661            Log::channel('g3w_invoices')->error($e->getMessage());
662            return ['success' => false, 'error' => $e->getMessage()];
663        }
664    }
665    public function setAllMonthAdministratorsInvoices($region){
666        if(!$region){
667            return ['success'=> false,'error'=> 'No region provided'];
668        }
669        
670        try {
671            $now = Carbon::now();
672            $month = $now->format('m');
673        } catch (\Exception $e) {
674            Log::channel('g3w_invoices')->error("Formato de fecha de mes no válido (esperado YYYY-mm)");
675            return ['success'=> false, 'error'=> 'Formato de fecha de mes no válido (esperado YYYY-mm)'];
676        }
677
678        $invoices = $this->request('get', 'factura/vencemesadministrador/' . $month, $region, []);
679        
680        foreach ($invoices["facturas"] as $invoice) {
681            $invoiceData = $this->request('get', 'factura/' . $invoice["ID"], $region, []);
682            $invoiceData = $invoiceData["factura"];
683
684            // Continue if region is Comunidad Valenciana and the invoice starts with M
685            if(
686                $region == "Comunidad Valenciana"
687                && strpos($invoice["ID"], 'M') === 0
688            ){
689                continue;
690            }
691
692            $cobrada = $invoiceData["cobrada"];
693            $formaPago = $invoiceData["forma_pago_factura"];
694            //Invoice already paied
695            //Invoice that the payment method is not "transferencia"
696            if (
697                $cobrada !== "NO"
698                || stripos($formaPago, "tr") === false
699            ) {
700                continue;
701            }
702
703            if ($invoiceData["cod_cliente"]) {
704                $dataClient = $this->request('get', "cliente/" . $invoiceData["cod_cliente"], $region, []);
705                $dataClient = $dataClient["cliente"];
706            }
707
708            if (
709                $dataClient["tipo_cliente"] !== "Administrador"
710                ){
711                continue;
712            }
713
714            $codService = $invoiceData["lineas"][0]["cod_servicio"];
715            $dataService = $this->request('get', "servicio/" . $codService, $region, []);
716            $dataService = $dataService["servicio"];
717
718            TblInvoiceAdministrators::create(array(
719                'invoice_number' => $invoiceData['n_factura'],
720                'region' => $region,
721                'name' => $dataClient['empresa'],
722                'CIF' => $dataClient["cliente_cif"],
723                'email' => $dataClient["email"],
724                'service_name' => $dataService["nombre_servicio"],
725                'service_addres' => $dataService["direccion"],
726                'send_date' => Carbon::now('Europe/Madrid')->toDateString(),
727                'expiration_date' => Carbon::parse($invoice["fecha_vencimiento"])->toDateString(),
728                'amount' => $invoiceData["importe_total_factura"],
729            ));
730        }
731
732
733        return [
734            'success' => true,
735            'message' => "Proceso completado para el mes $month en la región $region.",
736        ];
737    }
738
739    public function sendAdministratorsInvoices($region){
740        if (!$region) {
741            return ['success' => false, 'error' => 'No region provided'];
742        }
743
744        $month = [
745            1 => "Enero",
746            2 => "Febrero",
747            3 => "Marzo",
748            4 => "Abril",
749            5 => "Mayo",
750            6 => "Junio",
751            7 => "Julio",
752            8 => "Agosto",
753            9 => "Septiembre",
754            10 => "Octubre",
755            11 => "Noviembre",
756            12 => "Diciembre",
757        ];
758
759        $startOfMonth = Carbon::now()->startOfMonth()->toDateString();
760        $endOfMonth = Carbon::now()->endOfMonth()->toDateString();
761
762        $currentMonthInvoices = TblInvoiceAdministrators::where('region', $region)
763            ->where('paid', 0)
764            ->whereBetween('expiration_date', [$startOfMonth, $endOfMonth])
765            ->orderBy('expiration_date', 'asc')
766            ->get();
767
768        $invoicesGroupedByAdministrator = $currentMonthInvoices->groupBy('CIF');
769
770        foreach ($invoicesGroupedByAdministrator as $administratorCIF => $administratorInvoices) {
771            $table = "<table style='border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;'>
772            <tr>
773                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Número Factura</th>
774                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Nombre cliente de servicio</th>
775                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Dirección del servicio</th>
776                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Fecha de emisión</th>
777                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Fecha de vencimiento</th>
778                <th style='border: 1px solid #999; padding: 8px; background-color: #f2f2f2; text-align: left;'>Importe</th>
779            </tr>";
780
781            $documentsBase64 = [];
782
783            foreach ($administratorInvoices as $invoice) {
784                $invoiceNumber = $invoice->invoice_number;
785                $table .= "<tr>
786                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoiceNumber . "</td>
787                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoice->service_name . "</td>
788                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoice->service_addres . "</td>
789                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoice->send_date . "</td>
790                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoice->expiration_date . "</td>
791                    <td style='border: 1px solid #999; padding: 8px;'>" . $invoice->amount . "€</td>
792                </tr>";
793
794
795                $invoice = $this->request('get', 'factura/' . $invoiceNumber, $region, []);
796                $invoiceData = $invoice["factura"];
797
798                $documentsBase64[] = [
799                    'content' => $invoiceData["documento"], 
800                    'filename' => "Factura_{$invoiceNumber}.pdf"
801                ];
802            }
803
804            $table .= "</table>";
805
806            $monthText = $month[Carbon::now()->format('n')];
807            
808            $invoiceSendData = $this->sendInvoice(
809                $administratorInvoices->first()->invoice_number, 
810                $administratorInvoices->first()->name, 
811                $administratorInvoices->first()->email, 
812                $administratorInvoices->first()->send_date, 
813                $administratorInvoices->first()->expiration_date, 
814                $documentsBase64, 
815                $administratorInvoices->first()->amount, 
816                4, 
817                $table,
818                $monthText . " de " . Carbon::now()->format('Y')
819            );
820            
821
822        }
823        
824        return ['success' => true, 'message' => 'Processing complete'];
825    }
826        
827
828    //Google sheets
829    public function addToSheets($codCliente, $invoice, $region){
830        $spreadsheetId = '15Lc9tJnHDOGp33V9RH86mXtIybJBAWWlW4fe7knhDZY';
831        $sheetName = 'Hoja 1';
832        $googleSheetsService = null;
833        $nextRow = 1;
834
835        try {
836            $googleSheetsService = $this->getGoogleSheetsService();
837            $range = $sheetName . '!A:A';
838            $response = $googleSheetsService->spreadsheets_values->get($spreadsheetId, $range);
839            $values = $response->getValues();
840            $nextRow = $values ? count($values) + 1 : 1;
841
842        } catch (\Exception $e) {
843            if (strpos($e->getMessage(), 'Primera configuración requerida') !== false) {
844                return [
845                    'success' => false,
846                    'message' => $e->getMessage(),
847                    'requires_auth' => true
848                ];
849            }
850
851            return [
852                'success' => false,
853                'message' => 'Error de conexión con Google Sheets: ' . $e->getMessage(),
854            ];
855        }
856
857        if ($googleSheetsService && $nextRow === 1) {
858            $this->writeToGoogleSheet($googleSheetsService, $spreadsheetId, $sheetName, [
859                ['ID Cliente', 'Número de Factura', 'Fecha de Compromiso de Pago', 'Fecha de Compromiso de Pago + 10 días', 'Region']
860            ], 1);
861            $nextRow = 2;
862        }
863
864        $fechaCompromiso = date('Y-m-d');
865        $fechaCompromisoMas10 = date('Y-m-d', strtotime('+10 days'));
866
867        $data = [
868            $codCliente,
869            $invoice,
870            $fechaCompromiso,
871            $fechaCompromisoMas10,
872            $region
873        ];
874
875        if ($googleSheetsService) {
876            $this->writeToGoogleSheet($googleSheetsService, $spreadsheetId, $sheetName, [$data], $nextRow);
877            $nextRow++;
878        }
879
880    }
881
882    private function getGoogleSheetsService()
883    {
884
885        $redirectUrl = "";
886        if(env("APP_ENV") === "production"){
887            $redirectUrl = "https://fireservicetitan.com/api/google-sheets-callback";
888        }
889
890        if(env("APP_ENV") === "staging"){
891            $redirectUrl = "https://stg.fireservicetitan.com/api/google-sheets-callback";
892        }
893
894        if(env("APP_ENV") === "local"){
895            $redirectUrl = "http://localhost:8000/api/google-sheets-callback";
896        }
897
898        $client = new \Google\Client();
899        $client->setAuthConfig(storage_path('app/credentials.json'));
900        $client->addScope(\Google\Service\Sheets::SPREADSHEETS);
901        $client->setAccessType('offline');
902        $client->setPrompt('select_account consent');
903        $client->setRedirectUri($redirectUrl);
904
905        $tokenPath = storage_path('app/token.json');
906
907        if (file_exists($tokenPath)) {
908            $accessToken = json_decode(file_get_contents($tokenPath), true);
909            $client->setAccessToken($accessToken);
910        }
911
912        if ($client->isAccessTokenExpired()) {
913            if ($client->getRefreshToken()) {
914                $newToken = $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
915                file_put_contents($tokenPath, json_encode($newToken));
916            } else {
917                $authUrl = $client->createAuthUrl();
918                throw new \Exception("Initial setup required. Visit this URL to authorize: " . $authUrl);
919            }
920        }
921
922        return new \Google\Service\Sheets($client);
923    }
924
925    private function writeToGoogleSheet($service, $spreadsheetId, $sheetName, $data, $rowNumber)
926    {
927        try {
928            $range = $sheetName . '!A' . $rowNumber . ':E' . $rowNumber;
929
930            $body = new \Google\Service\Sheets\ValueRange([
931                'values' => $data
932            ]);
933
934            $params = [
935                'valueInputOption' => 'USER_ENTERED'
936            ];
937
938            $result = $service->spreadsheets_values->update(
939                $spreadsheetId,
940                $range,
941                $body,
942                $params
943            );
944
945            Log::info('✅ Datos escritos en Google Sheets - Fila: ' . $rowNumber);
946            return $result;
947
948        } catch (\Exception $e) {
949            Log::error('❌ Error escribiendo en Google Sheets: ' . $e->getMessage());
950            throw $e;
951        }
952    }
953
954    public function handleGoogleAuthCallback(Request $request)
955    {
956        try {
957            // Verificar que el código existe
958            if (!$request->get('code')) {
959                Log::error('❌ No code parameter found');
960                return response()->json([
961                    'success' => false,
962                    'message' => 'No authorization code provided'
963                ], 400);
964            }
965
966            $redirectUrl = "";
967
968            if(env("APP_ENV") === "production"){
969                $redirectUrl = "https://fireservicetitan.com/api/google-sheets-callback";
970            }
971
972            if(env("APP_ENV") === "staging"){
973                $redirectUrl = "https://stg.fireservicetitan.com/api/google-sheets-callback";
974            }
975
976            if(env("APP_ENV") === "local"){
977                $redirectUrl = "http://localhost:8000/api/google-sheets-callback";
978            }
979
980            $client = new \Google\Client();
981            $client->setAuthConfig(storage_path('app/credentials.json'));
982            $client->addScope(\Google\Service\Sheets::SPREADSHEETS);
983            $client->setRedirectUri($redirectUrl);
984
985            $token = $client->fetchAccessTokenWithAuthCode($request->get('code'));
986
987            file_put_contents(storage_path('app/token.json'), json_encode($token));
988
989            return response()->json([
990                'success' => true,
991                'message' => 'Google Sheets authentication complete! You can now run the invoicing function.'
992            ]);
993
994        } catch (\Exception $e) {
995            Log::error('Error on Google sheets callback: ' . $e->getMessage());
996            Log::error('Error details: ' . $e->getTraceAsString());
997            return response()->json([
998                'success' => false,
999                'message' => 'Error: ' . $e->getMessage()
1000            ], 400);
1001        }
1002    }
1003
1004    private function getVencimientosFormateados($dataInvoice)
1005    {
1006        $vencimientos = $dataInvoice["factura"]["vencimientos"] ?? [];
1007
1008        if (count($vencimientos) === 0) {
1009            return null;
1010        }
1011
1012        $fechasFormateadas = array_map(function($vencimiento) {
1013            return Carbon::createFromFormat('Y-m-d', $vencimiento['fecha_vencimiento'])
1014                ->isoFormat('D [de] MMMM [de] YYYY');
1015        }, $vencimientos);
1016
1017        return implode(' ó ', $fechasFormateadas);
1018    }
1019
1020}