Browse Source

fatture in cloud

Roberto Santini 3 weeks ago
parent
commit
cae78f55a0

+ 23
- 3
app/Http/Controllers/FatturazioneController.php View File

@@ -7,6 +7,7 @@ use App\Models\Config;
7 7
 use App\Models\Fattura;
8 8
 use App\Models\FatturaRiga;
9 9
 use App\Services\FatturaFicService;
10
+use App\Services\FatturaReportTicketPdfService;
10 11
 use App\Services\FatturazioneGeneraService;
11 12
 use Carbon\Carbon;
12 13
 use Illuminate\Http\Request;
@@ -32,7 +33,7 @@ class FatturazioneController extends Controller implements HasMiddleware
32 33
   public static function middleware(): array
33 34
   {
34 35
     return [
35
-      new Middleware('permission:view-fatturazione', only: ['admin_index', 'admin_genera', 'admin_show']),
36
+      new Middleware('permission:view-fatturazione', only: ['admin_index', 'admin_genera', 'admin_show', 'admin_report_ticket']),
36 37
       new Middleware('permission:genera-fatturazione', only: ['admin_genera']),
37 38
       new Middleware('permission:create-fattura', only: ['admin_crea']),
38 39
       new Middleware('permission:edit-fattura', only: ['admin_update', 'admin_emetti', 'admin_annulla', 'admin_invia_fic']),
@@ -70,6 +71,7 @@ class FatturazioneController extends Controller implements HasMiddleware
70 71
       'mese' => 'nullable|date_format:Y-m',
71 72
       'data_da' => 'nullable|date',
72 73
       'data_a' => 'nullable|date|after_or_equal:data_da',
74
+      'accorpa_segnalazioni' => 'nullable|boolean',
73 75
     ]);
74 76
 
75 77
     [$from, $to] = $this->periodoDaRequest($request);
@@ -79,7 +81,8 @@ class FatturazioneController extends Controller implements HasMiddleware
79 81
         $request->input('cliente_key'),
80 82
         $from,
81 83
         $to,
82
-        Auth::user()
84
+        Auth::user(),
85
+        $request->boolean('accorpa_segnalazioni')
83 86
       );
84 87
     } catch (RuntimeException $e) {
85 88
       return redirect()
@@ -225,7 +228,7 @@ class FatturazioneController extends Controller implements HasMiddleware
225 228
       ->with('success', 'Fattura aggiornata.');
226 229
   }
227 230
 
228
-  public function admin_emetti($id)
231
+  public function admin_emetti($id, FatturaReportTicketPdfService $report)
229 232
   {
230 233
     $fattura = Fattura::findOrFail($id);
231 234
     if (! $fattura->isBozza()) {
@@ -236,10 +239,27 @@ class FatturazioneController extends Controller implements HasMiddleware
236 239
       $fattura->data = now()->toDateString();
237 240
     }
238 241
     $fattura->save();
242
+    $report->store($fattura);
239 243
 
240 244
     return redirect()->back()->with('success', 'Fattura emessa.');
241 245
   }
242 246
 
247
+  public function admin_report_ticket($id, FatturaReportTicketPdfService $report)
248
+  {
249
+    $fattura = Fattura::findOrFail($id);
250
+    $binary = $report->binary($fattura);
251
+    if ($binary === null) {
252
+      return redirect()->back()->with('error', 'Nessun ticket collegato da riportare.');
253
+    }
254
+
255
+    $filename = str_replace(['/', '\\'], '-', $report->filename($fattura));
256
+
257
+    return response($binary, 200, [
258
+      'Content-Type' => 'application/pdf',
259
+      'Content-Disposition' => 'inline; filename="'.$filename.'"',
260
+    ]);
261
+  }
262
+
243 263
   public function admin_invia_fic($id, FatturaFicService $fic)
244 264
   {
245 265
     try {

+ 21
- 2
app/Services/FatturaFicService.php View File

@@ -12,7 +12,10 @@ use RuntimeException;
12 12
 
13 13
 class FatturaFicService
14 14
 {
15
-    public function __construct(protected FattureInCloudClient $fic) {}
15
+    public function __construct(
16
+        protected FattureInCloudClient $fic,
17
+        protected FatturaReportTicketPdfService $report
18
+    ) {}
16 19
 
17 20
     public function invia(Fattura $fattura): string
18 21
     {
@@ -69,7 +72,23 @@ class FatturaFicService
69 72
         }
70 73
         $fattura->save();
71 74
 
72
-        return 'Fattura '.$fattura->numero_documento.' allineata a Fatture in Cloud. L\'invio allo SDI lo fai da lì.';
75
+        $allegato = '';
76
+        $path = $this->report->store($fattura);
77
+        if ($path !== null) {
78
+            try {
79
+                $nome = str_replace(['/', '\\'], '-', $this->report->filename($fattura));
80
+                $this->fic->uploadIssuedDocumentAttachment(
81
+                    (int) $document['id'],
82
+                    $nome,
83
+                    (string) \Illuminate\Support\Facades\Storage::disk('local')->get($path)
84
+                );
85
+                $allegato = ' Il dettaglio ticket è allegato.';
86
+            } catch (RuntimeException $e) {
87
+                $allegato = ' Il dettaglio ticket non è stato allegato: '.$this->conScope($e->getMessage());
88
+            }
89
+        }
90
+
91
+        return 'Fattura '.$fattura->numero_documento.' allineata a Fatture in Cloud.'.$allegato.' L\'invio allo SDI lo fai da lì.';
73 92
     }
74 93
 
75 94
     protected function collegamento(Fattura $fattura): ?FicCollegamento

+ 130
- 0
app/Services/FatturaReportTicketPdfService.php View File

@@ -0,0 +1,130 @@
1
+<?php
2
+
3
+namespace App\Services;
4
+
5
+use App\Models\Annotazione;
6
+use App\Models\Config;
7
+use App\Models\Fattura;
8
+use App\Models\FatturaRiga;
9
+use App\Support\PdfDocument;
10
+use Barryvdh\DomPDF\Facade\Pdf;
11
+use Carbon\Carbon;
12
+use Illuminate\Support\Facades\Storage;
13
+
14
+class FatturaReportTicketPdfService
15
+{
16
+    /**
17
+     * @return array<int, array{titolo: string, data: string, ore: float, uscita: ?float}>
18
+     */
19
+    public function righe(Fattura $fattura): array
20
+    {
21
+        $salvate = data_get($fattura->meta, 'dettaglio_ticket');
22
+        if (is_array($salvate) && $salvate !== []) {
23
+            return array_values($salvate);
24
+        }
25
+
26
+        $fattura->loadMissing('righe');
27
+        $ids = $fattura->righe
28
+            ->pluck('annotazione_id')
29
+            ->filter()
30
+            ->map(fn ($id) => (int) $id)
31
+            ->unique()
32
+            ->values();
33
+        if ($ids->isEmpty()) {
34
+            return [];
35
+        }
36
+
37
+        $uscite = [];
38
+        foreach ($fattura->righe as $riga) {
39
+            if ($riga->tipo !== FatturaRiga::TIPO_USCITA || ! $riga->annotazione_id) {
40
+                continue;
41
+            }
42
+            $id = (int) $riga->annotazione_id;
43
+            $uscite[$id] = round(($uscite[$id] ?? 0) + (float) ($riga->importo ?? 0), 2);
44
+        }
45
+
46
+        $annotazioni = Annotazione::query()->with('segnalazione')->whereIn('id', $ids)->get()->keyBy('id');
47
+        $righe = [];
48
+        foreach ($ids as $id) {
49
+            $annotazione = $annotazioni->get($id);
50
+            if (! $annotazione) {
51
+                continue;
52
+            }
53
+            $quando = $annotazione->tempo_data
54
+                ? Carbon::parse($annotazione->tempo_data)
55
+                : Carbon::parse($annotazione->created_at);
56
+            $ore = round(((int) $annotazione->tempo_minuti) / 60, 2);
57
+            $uscita = $uscite[$id] ?? null;
58
+            if ($ore <= 0 && ! $uscita) {
59
+                continue;
60
+            }
61
+            $righe[] = [
62
+                'titolo' => $annotazione->segnalazione?->titolo ?: 'Ticket',
63
+                'data' => $quando->format('Y-m-d H:i'),
64
+                'ore' => $ore,
65
+                'uscita' => $uscita,
66
+            ];
67
+        }
68
+        usort($righe, fn ($a, $b) => strcmp($a['data'], $b['data']));
69
+
70
+        return $righe;
71
+    }
72
+
73
+    public function haDettaglio(Fattura $fattura): bool
74
+    {
75
+        return $this->righe($fattura) !== [];
76
+    }
77
+
78
+    public function filename(Fattura $fattura): string
79
+    {
80
+        return 'Dettaglio-ticket-fattura-'.$fattura->numero_documento.'.pdf';
81
+    }
82
+
83
+    public function generateBinary(Fattura $fattura): string
84
+    {
85
+        $pdf = Pdf::loadView('fatturazione.report-ticket', [
86
+            'fattura' => $fattura,
87
+            'righe' => $this->righe($fattura),
88
+            'logoBase64' => PdfDocument::logoBase64(),
89
+            'azienda' => PdfDocument::azienda(),
90
+        ]);
91
+        $pdf->setPaper('a4', 'portrait');
92
+        $pdf->setOption('defaultFont', 'DejaVu Sans');
93
+        $pdf->setOption('isHtml5ParserEnabled', true);
94
+
95
+        return $pdf->output();
96
+    }
97
+
98
+    public function store(Fattura $fattura): ?string
99
+    {
100
+        if (! $this->haDettaglio($fattura)) {
101
+            return null;
102
+        }
103
+
104
+        $path = 'fatture/fattura-'.$fattura->id.'-dettaglio-ticket.pdf';
105
+        Storage::disk('local')->put($path, $this->generateBinary($fattura));
106
+        $fattura->path_file = $path;
107
+        $fattura->save();
108
+
109
+        return $path;
110
+    }
111
+
112
+    public function binary(Fattura $fattura): ?string
113
+    {
114
+        if ($fattura->path_file && Storage::disk('local')->exists($fattura->path_file)) {
115
+            return Storage::disk('local')->get($fattura->path_file);
116
+        }
117
+        if (! $this->haDettaglio($fattura)) {
118
+            return null;
119
+        }
120
+
121
+        $this->store($fattura);
122
+
123
+        return Storage::disk('local')->get($fattura->path_file);
124
+    }
125
+
126
+    public function formatOre(float $ore): string
127
+    {
128
+        return Config::formatTempo((int) round($ore * 60));
129
+    }
130
+}

+ 139
- 8
app/Services/FatturazioneGeneraService.php View File

@@ -105,7 +105,7 @@ class FatturazioneGeneraService
105 105
         ];
106 106
     }
107 107
 
108
-    public function creaFattura(string $clienteKey, Carbon $from, Carbon $to, User $author): Fattura
108
+    public function creaFattura(string $clienteKey, Carbon $from, Carbon $to, User $author, bool $accorpaSegnalazioni = false): Fattura
109 109
     {
110 110
         $esito = $this->genera($from, $to);
111 111
         $cliente = collect(array_merge($esito['aziende'], $esito['privati']))
@@ -126,7 +126,14 @@ class FatturazioneGeneraService
126 126
             throw new RuntimeException('Cliente non trovato.');
127 127
         }
128 128
 
129
-        return DB::transaction(function () use ($cliente, $from, $to, $author, $user) {
129
+        return DB::transaction(function () use ($cliente, $from, $to, $author, $user, $accorpaSegnalazioni) {
130
+            $voci = $cliente['voci'];
131
+            $dettaglio = $this->dettaglioTicket($voci);
132
+            $annotazioneIds = collect($voci)->pluck('annotazione_id')->filter()->map(fn ($id) => (int) $id)->unique()->values()->all();
133
+            if ($accorpaSegnalazioni) {
134
+                $voci = $this->accorpaVociSegnalazioni($voci);
135
+            }
136
+
130 137
             $fattura = new Fattura();
131 138
             $fattura->user_id = $user->id;
132 139
             $fattura->created_by_id = $author->id;
@@ -138,10 +145,15 @@ class FatturazioneGeneraService
138 145
             $fattura->periodo_a = $to->toDateString();
139 146
             $fattura->iva_percentuale = Config::ivaPercentualeDefault();
140 147
             $fattura->snapshotDaUser($user);
148
+            $fattura->meta = [
149
+                'annotazione_ids' => $annotazioneIds,
150
+                'dettaglio_ticket' => $dettaglio,
151
+                'accorpa_segnalazioni' => $accorpaSegnalazioni,
152
+            ];
141 153
             $fattura->save();
142 154
 
143 155
             $ordine = 0;
144
-            foreach ($cliente['voci'] as $voce) {
156
+            foreach ($voci as $voce) {
145 157
                 $ordine++;
146 158
                 FatturaRiga::create([
147 159
                     'fattura_id' => $fattura->id,
@@ -1102,14 +1114,133 @@ class FatturazioneGeneraService
1102 1114
      */
1103 1115
     protected function annotazioneIdsGiaFatturate(): array
1104 1116
     {
1105
-        return FatturaRiga::query()
1117
+        $daRighe = FatturaRiga::query()
1106 1118
             ->suFattureAttive()
1107 1119
             ->whereNotNull('annotazione_id')
1108 1120
             ->pluck('annotazione_id')
1109
-            ->map(fn ($id) => (int) $id)
1110
-            ->unique()
1111
-            ->values()
1112
-            ->all();
1121
+            ->map(fn ($id) => (int) $id);
1122
+
1123
+        $daMeta = Fattura::query()
1124
+            ->nonAnnullate()
1125
+            ->whereNotNull('meta')
1126
+            ->pluck('meta')
1127
+            ->flatMap(function ($meta) {
1128
+                $ids = is_array($meta) ? ($meta['annotazione_ids'] ?? []) : [];
1129
+
1130
+                return collect($ids)->map(fn ($id) => (int) $id);
1131
+            });
1132
+
1133
+        return $daRighe->merge($daMeta)->unique()->values()->all();
1134
+    }
1135
+
1136
+    /**
1137
+     * Una riga fattura per tipo (ore, extra, spese, uscite) al posto di una riga per ticket.
1138
+     *
1139
+     * @param  array<int, array<string, mixed>>  $voci
1140
+     * @return array<int, array<string, mixed>>
1141
+     */
1142
+    protected function accorpaVociSegnalazioni(array $voci): array
1143
+    {
1144
+        $accorpabili = [
1145
+            FatturaRiga::TIPO_TEMPO,
1146
+            FatturaRiga::TIPO_EXTRA_CONTRATTO,
1147
+            FatturaRiga::TIPO_EXTRA_ORDINE,
1148
+            FatturaRiga::TIPO_SPESA,
1149
+            FatturaRiga::TIPO_USCITA,
1150
+        ];
1151
+        $gruppi = [];
1152
+        $resto = [];
1153
+        foreach ($voci as $voce) {
1154
+            $tipo = (string) ($voce['tipo'] ?? '');
1155
+            if (empty($voce['segnalazione_id']) || ! in_array($tipo, $accorpabili, true)) {
1156
+                $resto[] = $voce;
1157
+                continue;
1158
+            }
1159
+            $gruppi[$tipo][] = $voce;
1160
+        }
1161
+
1162
+        foreach ($gruppi as $tipo => $items) {
1163
+            $importo = round(collect($items)->sum(fn ($v) => (float) ($v['importo'] ?? 0)), 2);
1164
+            $minuti = (int) collect($items)->sum(fn ($v) => (int) ($v['minuti'] ?? 0));
1165
+            $ore = in_array($tipo, [FatturaRiga::TIPO_TEMPO, FatturaRiga::TIPO_EXTRA_CONTRATTO, FatturaRiga::TIPO_EXTRA_ORDINE], true);
1166
+            $qty = $ore ? round($minuti / 60, 2) : (float) count($items);
1167
+            if ($qty <= 0) {
1168
+                $qty = 1;
1169
+            }
1170
+            $resto[] = [
1171
+                'tipo' => $tipo,
1172
+                'descrizione' => FatturaRiga::TIPI[$tipo] ?? $tipo,
1173
+                'quantita' => $qty,
1174
+                'unita_misura' => $ore ? 'ora' : 'forfait',
1175
+                'prezzo_unitario' => round($importo / $qty, 2),
1176
+                'importo' => $importo,
1177
+                'minuti' => $minuti > 0 ? $minuti : null,
1178
+                'annotazione_id' => null,
1179
+                'segnalazione_id' => null,
1180
+                'contratto_servizio_id' => null,
1181
+                'contratto_servizio_riga_id' => null,
1182
+                'ordine_lavoro_id' => null,
1183
+                'prodotto_id' => null,
1184
+                'periodo_da' => null,
1185
+                'periodo_a' => null,
1186
+                'nota' => null,
1187
+            ];
1188
+        }
1189
+
1190
+        return $resto;
1191
+    }
1192
+
1193
+    /**
1194
+     * @param  array<int, array<string, mixed>>  $voci
1195
+     * @return array<int, array{titolo: string, data: string, ore: float, uscita: ?float}>
1196
+     */
1197
+    protected function dettaglioTicket(array $voci): array
1198
+    {
1199
+        $ids = collect($voci)->pluck('annotazione_id')->filter()->map(fn ($id) => (int) $id)->unique()->values();
1200
+        if ($ids->isEmpty()) {
1201
+            return [];
1202
+        }
1203
+
1204
+        $uscite = [];
1205
+        foreach ($voci as $voce) {
1206
+            if (($voce['tipo'] ?? '') !== FatturaRiga::TIPO_USCITA || empty($voce['annotazione_id'])) {
1207
+                continue;
1208
+            }
1209
+            $id = (int) $voce['annotazione_id'];
1210
+            $uscite[$id] = round(($uscite[$id] ?? 0) + (float) ($voce['importo'] ?? 0), 2);
1211
+        }
1212
+
1213
+        $annotazioni = Annotazione::query()
1214
+            ->with('segnalazione')
1215
+            ->whereIn('id', $ids)
1216
+            ->get()
1217
+            ->keyBy('id');
1218
+
1219
+        $righe = [];
1220
+        foreach ($ids as $id) {
1221
+            $annotazione = $annotazioni->get($id);
1222
+            if (! $annotazione) {
1223
+                continue;
1224
+            }
1225
+            $quando = $annotazione->tempo_data
1226
+                ? Carbon::parse($annotazione->tempo_data)
1227
+                : Carbon::parse($annotazione->created_at);
1228
+            $ore = round(((int) $annotazione->tempo_minuti) / 60, 2);
1229
+            $uscita = $uscite[$id] ?? null;
1230
+            if ($ore <= 0 && ! $uscita) {
1231
+                continue;
1232
+            }
1233
+            $righe[] = [
1234
+                'titolo' => $annotazione->segnalazione?->titolo ?: 'Ticket',
1235
+                'data' => $quando->format('Y-m-d H:i'),
1236
+                'ore' => $ore,
1237
+                'uscita' => $uscita,
1238
+            ];
1239
+        }
1240
+
1241
+        usort($righe, fn ($a, $b) => strcmp($a['data'], $b['data']));
1242
+
1243
+        return $righe;
1113 1244
     }
1114 1245
 
1115 1246
     protected function canoneGiaFatturato(int $contrattoId, ?int $rigaId, Carbon $pDa, Carbon $pA): bool

+ 8
- 0
app/Services/FattureInCloudClient.php View File

@@ -405,6 +405,14 @@ class FattureInCloudClient
405 405
     /**
406 406
      * @return array<string, mixed>
407 407
      */
408
+    public function uploadIssuedDocumentAttachment(int $documentId, string $filename, string $binary): void
409
+    {
410
+        $this->decode($this->http()->post($this->url('/issued_documents/'.$documentId.'/attachment'), [
411
+            'filename' => $filename,
412
+            'attachment' => base64_encode($binary),
413
+        ]));
414
+    }
415
+
408 416
     public function getIssuedDocument(int $id): array
409 417
     {
410 418
         $json = $this->decode($this->http()->get($this->url('/issued_documents/'.$id)));

+ 5
- 1
resources/views/fatturazione/partials/cliente.blade.php View File

@@ -24,12 +24,16 @@
24 24
     <div class="accordion-body">
25 25
       @can('create-fattura')
26 26
       @if(($cliente['totale'] ?? 0) > 0 && !empty($cliente['user_id']) && count($cliente['voci'] ?? []) > 0)
27
-      <form method="POST" action="{{ route('admin.fatturazione.crea') }}" class="mb-4 d-print-none">
27
+      <form method="POST" action="{{ route('admin.fatturazione.crea') }}" class="mb-4 d-print-none d-flex flex-wrap align-items-center gap-2">
28 28
         @csrf
29 29
         <input type="hidden" name="cliente_key" value="{{ $cliente['key'] }}">
30 30
         <input type="hidden" name="mese" value="{{ $mese }}">
31 31
         <input type="hidden" name="data_da" value="{{ $data_da }}">
32 32
         <input type="hidden" name="data_a" value="{{ $data_a }}">
33
+        <label class="form-check form-check-inline mb-0 me-2">
34
+          <input class="form-check-input" type="checkbox" name="accorpa_segnalazioni" value="1">
35
+          <span class="form-check-label">Accorpa le voci dei ticket per tipo</span>
36
+        </label>
33 37
         <button type="submit" class="btn btn-primary btn-sm">
34 38
           <i class="bx bx-receipt me-1"></i>Crea fattura ({{ Config::formatCosto($cliente['totale']) }} imponibile)
35 39
         </button>

+ 52
- 0
resources/views/fatturazione/report-ticket.blade.php View File

@@ -0,0 +1,52 @@
1
+<!DOCTYPE html>
2
+<html lang="it">
3
+<head>
4
+  <meta charset="UTF-8">
5
+  @include('pdf.styles')
6
+</head>
7
+<body>
8
+  @include('pdf.header')
9
+
10
+  <div class="pdf-doc-title">Dettaglio ticket — Fattura {{ $fattura->numero_documento }}</div>
11
+
12
+  <table class="pdf-meta">
13
+    <tr>
14
+      <td style="width:50%">
15
+        <div class="label">Cliente</div>
16
+        <strong>{{ $fattura->ragione_sociale ?: '—' }}</strong>
17
+      </td>
18
+      <td style="width:50%">
19
+        <div class="label">Periodo</div>
20
+        {{ $fattura->periodo_da ? \Carbon\Carbon::parse($fattura->periodo_da)->format('d/m/Y') : '—' }}
21
+        –
22
+        {{ $fattura->periodo_a ? \Carbon\Carbon::parse($fattura->periodo_a)->format('d/m/Y') : '—' }}
23
+      </td>
24
+    </tr>
25
+  </table>
26
+
27
+  <table class="pdf-lines">
28
+    <thead>
29
+      <tr>
30
+        <th>Segnalazione</th>
31
+        <th>Data</th>
32
+        <th class="text-end">Ore</th>
33
+        <th class="text-end">Costo d'uscita</th>
34
+      </tr>
35
+    </thead>
36
+    <tbody>
37
+      @forelse($righe as $riga)
38
+      <tr>
39
+        <td>{{ $riga['titolo'] }}</td>
40
+        <td>{{ \Carbon\Carbon::parse($riga['data'])->format('d/m/Y') }}</td>
41
+        <td class="text-end">{{ $riga['ore'] > 0 ? \App\Models\Config::formatTempo((int) round($riga['ore'] * 60)) : '—' }}</td>
42
+        <td class="text-end">{{ !empty($riga['uscita']) ? \App\Models\Config::formatCosto($riga['uscita']) : '—' }}</td>
43
+      </tr>
44
+      @empty
45
+      <tr>
46
+        <td colspan="4" class="muted">Nessun ticket collegato.</td>
47
+      </tr>
48
+      @endforelse
49
+    </tbody>
50
+  </table>
51
+</body>
52
+</html>

+ 5
- 0
resources/views/fatturazione/show.blade.php View File

@@ -61,6 +61,11 @@
61 61
     <i class="bx bx-user me-1"></i>Scheda cliente
62 62
   </a>
63 63
   @endif
64
+  @if(collect(data_get($fattura->meta, 'dettaglio_ticket', []))->isNotEmpty() || $fattura->righe->contains(fn ($r) => filled($r->segnalazione_id)))
65
+  <a href="{{ route('admin.fatturazione.report_ticket', $fattura->id) }}" class="btn btn-label-secondary btn-sm" target="_blank">
66
+    <i class="bx bx-file me-1"></i>Report ticket
67
+  </a>
68
+  @endif
64 69
   <a href="{{ route('admin.fatturazione.index') }}" class="btn btn-label-secondary btn-sm">
65 70
     <i class="bx bx-list-ul me-1"></i>Elenco
66 71
   </a>

+ 1
- 0
routes/web.php View File

@@ -122,6 +122,7 @@ Route::middleware(['auth:sanctum', config('jetstream.auth_session')])->prefix('a
122 122
     Route::get('fatturazione/{id}', [FatturazioneController::class, 'admin_show'])->name('admin.fatturazione.show')->whereNumber('id');
123 123
     Route::put('fatturazione/{id}', [FatturazioneController::class, 'admin_update'])->name('admin.fatturazione.update')->whereNumber('id');
124 124
     Route::post('fatturazione/{id}/emetti', [FatturazioneController::class, 'admin_emetti'])->name('admin.fatturazione.emetti')->whereNumber('id');
125
+    Route::get('fatturazione/{id}/report-ticket', [FatturazioneController::class, 'admin_report_ticket'])->name('admin.fatturazione.report_ticket')->whereNumber('id');
125 126
     Route::post('fatturazione/{id}/fic', [FatturazioneController::class, 'admin_invia_fic'])->name('admin.fatturazione.fic')->whereNumber('id');
126 127
     Route::post('fatturazione/{id}/annulla', [FatturazioneController::class, 'admin_annulla'])->name('admin.fatturazione.annulla')->whereNumber('id');
127 128
     Route::delete('fatturazione/{id}', [FatturazioneController::class, 'admin_destroy'])->name('admin.fatturazione.destroy')->whereNumber('id');

Loading…
Cancel
Save