136 lines
5.1 KiB
PHP
136 lines
5.1 KiB
PHP
<?php
|
|
namespace App\Services\Consumi;
|
|
|
|
use Carbon\Carbon;
|
|
|
|
class GasLucePdfTextParser
|
|
{
|
|
/**
|
|
* @return array{
|
|
* codici: array{cliente: string|null, contratto: string|null, pdr: string|null, pod: string|null},
|
|
* pagamento: array{scadenza: string|null},
|
|
* consumi: array<int, array{dal: string|null, al: string|null, valore: float|null, unita: string, tipologia_lettura: string}>
|
|
* }
|
|
*/
|
|
public function parse(string $text): array
|
|
{
|
|
$text = str_replace("\r\n", "\n", $text);
|
|
$text = str_replace("\r", "\n", $text);
|
|
|
|
// Cliente
|
|
$cliente = $this->firstMatch($text, '/(?:Codice\s+Cliente|Cod\.\s*Cliente|Cliente\s*n\.|Client\s*code)\s*:?\s*([A-Z0-9_]{4,})/i');
|
|
|
|
// Contratto
|
|
$contratto = $this->firstMatch($text, '/(?:Contratto|Cod\.\s*Contratto|Codice\s+Contratto|Contract\s*n\.)\s*:?\s*([A-Z0-9_]{4,})/i');
|
|
|
|
// PDR / POD
|
|
$pdr = $this->firstMatch($text, '/\bPDR\b\s*:?\s*([0-9]{14})\b/i');
|
|
$pod = $this->firstMatch($text, '/\bPOD\b\s*:?\s*([A-Z0-9]{14,15})\b/i');
|
|
|
|
// Scadenza
|
|
$scadenza = $this->toIsoDate($this->firstMatch($text, '/(?:Scadenza|Entro\s+il|Data\s+scadenza)\s*:?\s*(\d{2}\/\d{2}\/\d{4})/i'));
|
|
|
|
// Cerca consumi del tipo: "Consumo Fatturato APRILE 2026 910 Smc"
|
|
// O genericamente "Consumo... [valore] Smc/kWh"
|
|
$consumi = [];
|
|
if (preg_match_all('/(?:Consumo\s+Fatturato|Consumo|Consumo\s+rilevato|Consumo\s+stimato)\s+(?:([A-Z]+)\s+(\d{4})\s+)?(\d+(?:[\.,]\d+)?)\s*(Smc|kWh)/i', $text, $matches, PREG_SET_ORDER)) {
|
|
foreach ($matches as $m) {
|
|
$monthName = !empty($m[1]) ? strtoupper(trim($m[1])) : null;
|
|
$yearVal = !empty($m[2]) ? (int) $m[2] : null;
|
|
$valore = $this->toFloatIt($m[3]);
|
|
$unita = trim($m[4]);
|
|
|
|
$dal = null;
|
|
$al = null;
|
|
if ($monthName && $yearVal) {
|
|
$months = [
|
|
'GENNAIO' => 1, 'FEBBRAIO' => 2, 'MARZO' => 3, 'APRILE' => 4,
|
|
'MAGGIO' => 5, 'GIUGNO' => 6, 'LUGLIO' => 7, 'AGOSTO' => 8,
|
|
'SETTEMBRE' => 9, 'OTTOBRE' => 10, 'NOVEMBRE' => 11, 'DICEMBRE' => 12,
|
|
'JANUARY' => 1, 'FEBRUARY' => 2, 'MARCH' => 3, 'APRIL' => 4,
|
|
'MAY' => 5, 'JUNE' => 6, 'JULY' => 7, 'AUGUST' => 8,
|
|
'SEPTEMBER' => 9, 'OCTOBER' => 10, 'NOVEMBER' => 11, 'DECEMBER' => 12
|
|
];
|
|
$mNum = $months[$monthName] ?? null;
|
|
if ($mNum) {
|
|
$dal = Carbon::create($yearVal, $mNum, 1)->startOfMonth()->format('Y-m-d');
|
|
$al = Carbon::create($yearVal, $mNum, 1)->endOfMonth()->format('Y-m-d');
|
|
}
|
|
}
|
|
|
|
$consumi[] = [
|
|
'dal' => $dal,
|
|
'al' => $al,
|
|
'valore' => $valore,
|
|
'unita' => $unita,
|
|
'tipologia_lettura' => 'fatturata',
|
|
];
|
|
}
|
|
}
|
|
|
|
// Se non troviamo date dai consumi ma c'è un intervallo di date nel testo, tipo "dal 01/04/2026 al 30/04/2026"
|
|
if (count($consumi) === 0 && preg_match('/dal\s+(\d{2}\/\d{2}\/\d{4})\s+al\s+(\d{2}\/\d{2}\/\d{4})/i', $text, $mDates)) {
|
|
$dal = $this->toIsoDate($mDates[1]);
|
|
$al = $this->toIsoDate($mDates[2]);
|
|
|
|
// Prova a estrarre il valore di consumo vicino a Smc o kWh
|
|
$val = null;
|
|
$uni = 'Smc';
|
|
if (preg_match('/(\d+(?:[\.,]\d+)?)\s*(Smc|kWh)/i', $text, $mVal)) {
|
|
$val = $this->toFloatIt($mVal[1]);
|
|
$uni = $mVal[2];
|
|
}
|
|
|
|
if ($val !== null) {
|
|
$consumi[] = [
|
|
'dal' => $dal,
|
|
'al' => $al,
|
|
'valore' => $val,
|
|
'unita' => $uni,
|
|
'tipologia_lettura' => 'rilevata',
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'codici' => [
|
|
'cliente' => $cliente,
|
|
'contratto' => $contratto,
|
|
'pdr' => $pdr,
|
|
'pod' => $pod,
|
|
],
|
|
'pagamento' => [
|
|
'scadenza' => $scadenza,
|
|
],
|
|
'consumi' => $consumi,
|
|
];
|
|
}
|
|
|
|
private function firstMatch(string $text, string $pattern): ?string
|
|
{
|
|
if (preg_match($pattern, $text, $matches)) {
|
|
return trim($matches[1]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private function toFloatIt(mixed $val): ?float
|
|
{
|
|
if ($val === null) return null;
|
|
$val = str_replace('.', '', $val);
|
|
$val = str_replace(',', '.', $val);
|
|
return is_numeric($val) ? (float) $val : null;
|
|
}
|
|
|
|
private function toIsoDate(?string $value): ?string
|
|
{
|
|
if (! $value) {
|
|
return null;
|
|
}
|
|
try {
|
|
return Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d');
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
} |