|
|
@@ -18,9 +18,9 @@ class FatturaReportTicketPdfService
|
|
18
|
18
|
*/
|
|
19
|
19
|
public function righe(Fattura $fattura): array
|
|
20
|
20
|
{
|
|
21
|
|
- $daRighe = $this->righeDaFattura($fattura);
|
|
22
|
|
- if ($daRighe !== []) {
|
|
23
|
|
- return $daRighe;
|
|
|
21
|
+ $cronologia = $this->cronologia($fattura);
|
|
|
22
|
+ if ($cronologia !== []) {
|
|
|
23
|
+ return $cronologia;
|
|
24
|
24
|
}
|
|
25
|
25
|
|
|
26
|
26
|
$salvate = data_get($fattura->meta, 'dettaglio_ticket');
|
|
|
@@ -59,24 +59,41 @@ class FatturaReportTicketPdfService
|
|
59
|
59
|
}
|
|
60
|
60
|
|
|
61
|
61
|
/**
|
|
|
62
|
+ * Una riga per ogni tempo registrato sui ticket della fattura, nel periodo.
|
|
|
63
|
+ *
|
|
62
|
64
|
* @return array<int, array{titolo: string, data: string, minuti_ticket: int, minuti_fatturati: int, uscita: ?float}>
|
|
63
|
65
|
*/
|
|
64
|
|
- protected function righeDaFattura(Fattura $fattura): array
|
|
|
66
|
+ protected function cronologia(Fattura $fattura): array
|
|
65
|
67
|
{
|
|
66
|
68
|
$fattura->loadMissing('righe');
|
|
67
|
|
- $ids = $fattura->righe
|
|
|
69
|
+ $idsFatturati = $fattura->righe
|
|
68
|
70
|
->pluck('annotazione_id')
|
|
69
|
71
|
->filter()
|
|
70
|
72
|
->map(fn ($id) => (int) $id)
|
|
|
73
|
+ ->merge(collect(data_get($fattura->meta, 'annotazione_ids', []))->map(fn ($id) => (int) $id))
|
|
71
|
74
|
->unique()
|
|
72
|
75
|
->values();
|
|
73
|
|
- if ($ids->isEmpty()) {
|
|
|
76
|
+
|
|
|
77
|
+ $segnalazioneIds = $fattura->righe
|
|
|
78
|
+ ->pluck('segnalazione_id')
|
|
|
79
|
+ ->filter()
|
|
|
80
|
+ ->map(fn ($id) => (int) $id);
|
|
|
81
|
+ if ($idsFatturati->isNotEmpty()) {
|
|
|
82
|
+ $segnalazioneIds = $segnalazioneIds->merge(
|
|
|
83
|
+ Annotazione::query()->whereIn('id', $idsFatturati)->pluck('segnalazione_id')
|
|
|
84
|
+ );
|
|
|
85
|
+ }
|
|
|
86
|
+ $segnalazioneIds = $segnalazioneIds->filter()->map(fn ($id) => (int) $id)->unique()->values();
|
|
|
87
|
+ if ($segnalazioneIds->isEmpty()) {
|
|
74
|
88
|
return [];
|
|
75
|
89
|
}
|
|
76
|
90
|
|
|
|
91
|
+ $from = $fattura->periodo_da ? Carbon::parse($fattura->periodo_da)->startOfDay() : null;
|
|
|
92
|
+ $to = $fattura->periodo_a ? Carbon::parse($fattura->periodo_a)->endOfDay() : null;
|
|
|
93
|
+
|
|
77
|
94
|
$tipiOre = [FatturaRiga::TIPO_TEMPO, FatturaRiga::TIPO_EXTRA_CONTRATTO, FatturaRiga::TIPO_EXTRA_ORDINE];
|
|
78
|
95
|
$uscite = [];
|
|
79
|
|
- $minuti = [];
|
|
|
96
|
+ $minutiFatturati = [];
|
|
80
|
97
|
foreach ($fattura->righe as $riga) {
|
|
81
|
98
|
if (! $riga->annotazione_id) {
|
|
82
|
99
|
continue;
|
|
|
@@ -86,35 +103,93 @@ class FatturaReportTicketPdfService
|
|
86
|
103
|
$uscite[$id] = round(($uscite[$id] ?? 0) + (float) ($riga->importo ?? 0), 2);
|
|
87
|
104
|
}
|
|
88
|
105
|
if (in_array($riga->tipo, $tipiOre, true)) {
|
|
89
|
|
- $minuti[$id] = ($minuti[$id] ?? 0) + (int) ($riga->minuti ?? 0);
|
|
|
106
|
+ $minutiFatturati[$id] = ($minutiFatturati[$id] ?? 0) + (int) ($riga->minuti ?? 0);
|
|
90
|
107
|
}
|
|
91
|
108
|
}
|
|
92
|
109
|
|
|
93
|
|
- $annotazioni = Annotazione::query()->with('segnalazione')->whereIn('id', $ids)->get()->keyBy('id');
|
|
94
|
|
- $righe = [];
|
|
95
|
|
- foreach ($ids as $id) {
|
|
96
|
|
- $annotazione = $annotazioni->get($id);
|
|
97
|
|
- if (! $annotazione) {
|
|
|
110
|
+ $daSnapshot = [];
|
|
|
111
|
+ $daSnapshotData = [];
|
|
|
112
|
+ $usciteSnapshot = [];
|
|
|
113
|
+ $usciteSnapshotData = [];
|
|
|
114
|
+ foreach (data_get($fattura->meta, 'dettaglio_ticket', []) as $salvata) {
|
|
|
115
|
+ if (! is_array($salvata)) {
|
|
98
|
116
|
continue;
|
|
99
|
117
|
}
|
|
|
118
|
+ if (array_key_exists('minuti_fatturati', $salvata)) {
|
|
|
119
|
+ $minutiSalvati = (int) $salvata['minuti_fatturati'];
|
|
|
120
|
+ } elseif (array_key_exists('minuti', $salvata)) {
|
|
|
121
|
+ $minutiSalvati = (int) $salvata['minuti'];
|
|
|
122
|
+ } else {
|
|
|
123
|
+ $minutiSalvati = null;
|
|
|
124
|
+ }
|
|
|
125
|
+ $chiaveData = (string) ($salvata['data'] ?? '').'|'.(string) ($salvata['titolo'] ?? '');
|
|
|
126
|
+ if (! empty($salvata['annotazione_id']) && $minutiSalvati !== null) {
|
|
|
127
|
+ $daSnapshot[(int) $salvata['annotazione_id']] = $minutiSalvati;
|
|
|
128
|
+ }
|
|
|
129
|
+ if ($minutiSalvati !== null && $chiaveData !== '|') {
|
|
|
130
|
+ $daSnapshotData[$chiaveData] = $minutiSalvati;
|
|
|
131
|
+ }
|
|
|
132
|
+ if (! empty($salvata['uscita'])) {
|
|
|
133
|
+ if (! empty($salvata['annotazione_id'])) {
|
|
|
134
|
+ $usciteSnapshot[(int) $salvata['annotazione_id']] = (float) $salvata['uscita'];
|
|
|
135
|
+ }
|
|
|
136
|
+ if ($chiaveData !== '|') {
|
|
|
137
|
+ $usciteSnapshotData[$chiaveData] = (float) $salvata['uscita'];
|
|
|
138
|
+ }
|
|
|
139
|
+ }
|
|
|
140
|
+ }
|
|
|
141
|
+
|
|
|
142
|
+ $annotazioni = Annotazione::query()
|
|
|
143
|
+ ->with('segnalazione')
|
|
|
144
|
+ ->where(function ($q) use ($segnalazioneIds, $from, $to, $idsFatturati) {
|
|
|
145
|
+ $q->where(function ($q2) use ($segnalazioneIds, $from, $to) {
|
|
|
146
|
+ $q2->whereIn('segnalazione_id', $segnalazioneIds);
|
|
|
147
|
+ if ($from && $to) {
|
|
|
148
|
+ $q2->where(function ($q3) use ($from, $to) {
|
|
|
149
|
+ $q3->whereBetween('tempo_data', [$from, $to])
|
|
|
150
|
+ ->orWhere(function ($q4) use ($from, $to) {
|
|
|
151
|
+ $q4->whereNull('tempo_data')->whereBetween('created_at', [$from, $to]);
|
|
|
152
|
+ });
|
|
|
153
|
+ });
|
|
|
154
|
+ }
|
|
|
155
|
+ });
|
|
|
156
|
+ if ($idsFatturati->isNotEmpty()) {
|
|
|
157
|
+ $q->orWhereIn('id', $idsFatturati);
|
|
|
158
|
+ }
|
|
|
159
|
+ })
|
|
|
160
|
+ ->where(function ($q) {
|
|
|
161
|
+ $q->whereNull('non_fatturare')->orWhere('non_fatturare', false);
|
|
|
162
|
+ })
|
|
|
163
|
+ ->where(function ($q) {
|
|
|
164
|
+ $q->where('tempo_minuti', '>', 0)->orWhere('costo_uscita', true);
|
|
|
165
|
+ })
|
|
|
166
|
+ ->orderByRaw('COALESCE(tempo_data, created_at)')
|
|
|
167
|
+ ->orderBy('id')
|
|
|
168
|
+ ->get();
|
|
|
169
|
+
|
|
|
170
|
+ $righe = [];
|
|
|
171
|
+ foreach ($annotazioni as $annotazione) {
|
|
|
172
|
+ $id = (int) $annotazione->id;
|
|
100
|
173
|
$quando = $annotazione->tempo_data
|
|
101
|
174
|
? Carbon::parse($annotazione->tempo_data)
|
|
102
|
175
|
: Carbon::parse($annotazione->created_at);
|
|
103
|
|
- $minutiFattura = (int) ($minuti[$id] ?? 0);
|
|
|
176
|
+ $titolo = $annotazione->segnalazione?->titolo ?: 'Ticket';
|
|
|
177
|
+ $chiaveData = $quando->format('Y-m-d H:i').'|'.$titolo;
|
|
|
178
|
+ $minutiFattura = $minutiFatturati[$id] ?? $daSnapshot[$id] ?? $daSnapshotData[$chiaveData] ?? 0;
|
|
104
|
179
|
$minutiTicket = (int) $annotazione->tempo_minuti;
|
|
105
|
|
- $uscita = $uscite[$id] ?? null;
|
|
|
180
|
+ $uscita = $uscite[$id] ?? $usciteSnapshot[$id] ?? $usciteSnapshotData[$chiaveData] ?? null;
|
|
106
|
181
|
if ($minutiTicket <= 0 && $minutiFattura <= 0 && ! $uscita) {
|
|
107
|
182
|
continue;
|
|
108
|
183
|
}
|
|
|
184
|
+ $numero = $annotazione->segnalazione?->getNumeroLabel();
|
|
109
|
185
|
$righe[] = [
|
|
110
|
|
- 'titolo' => $annotazione->segnalazione?->titolo ?: 'Ticket',
|
|
|
186
|
+ 'titolo' => $numero ? $numero.' — '.$titolo : $titolo,
|
|
111
|
187
|
'data' => $quando->format('Y-m-d H:i'),
|
|
112
|
188
|
'minuti_ticket' => $minutiTicket,
|
|
113
|
|
- 'minuti_fatturati' => $minutiFattura,
|
|
|
189
|
+ 'minuti_fatturati' => (int) $minutiFattura,
|
|
114
|
190
|
'uscita' => $uscita,
|
|
115
|
191
|
];
|
|
116
|
192
|
}
|
|
117
|
|
- usort($righe, fn ($a, $b) => strcmp($a['data'], $b['data']));
|
|
118
|
193
|
|
|
119
|
194
|
return $righe;
|
|
120
|
195
|
}
|