- Added support for uploading and compressing GLB models using Draco in the backoffice. - Implemented commands for importing and re-compressing 3D models. - Updated model resource to handle 3D model uploads and validations. - Introduced a new script for compressing GLB files with Draco. - Modified Vite configuration to remove GLB files from the build output. - Updated package dependencies to include GLTF-transform libraries for handling 3D models. - Added tests to ensure proper functionality of 3D model handling and compression.
237 lines
10 KiB
PHP
237 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Filament\Resources\ModelloResource\Pages\EditModello;
|
|
use App\Filament\Resources\ModelloResource\RelationManagers\ListinoRelationManager;
|
|
use App\Filament\Resources\SistemaResource\Pages\ListSistemi;
|
|
use App\Models\ListinoPrezzo;
|
|
use App\Models\Modello;
|
|
use App\Models\Sistema;
|
|
use App\Models\User;
|
|
use App\Support\Listini\ListinoExcelParser;
|
|
use App\Support\Listini\ListinoImporter;
|
|
use Database\Seeders\CatalogoSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Livewire\Livewire;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
use Tests\TestCase;
|
|
|
|
class ImportazioneListiniTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private Sistema $pvc;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Storage::fake('public');
|
|
$this->seed(CatalogoSeeder::class);
|
|
$this->pvc = Sistema::where('codice', 'pvc')->firstOrFail();
|
|
$this->actingAs(User::factory()->create(['is_superadmin' => true]));
|
|
}
|
|
|
|
/** Due tabelle nel formato del listino, separate da una riga vuota. */
|
|
private function righe(): array
|
|
{
|
|
return [
|
|
[null, null, null],
|
|
['finestra_1_anta', 400, 500],
|
|
[400, 367.2, 381.244],
|
|
[500, 381.24, null],
|
|
[null, null, null],
|
|
['PORTA 1 ANTA, CON SERRATURA', 500, 600],
|
|
[1800, 796.5, 820],
|
|
];
|
|
}
|
|
|
|
private function fileExcel(): UploadedFile
|
|
{
|
|
$spreadsheet = new Spreadsheet;
|
|
$spreadsheet->getActiveSheet()->fromArray($this->righe(), null, 'A1', true);
|
|
$path = tempnam(sys_get_temp_dir(), 'listino');
|
|
(new Xlsx($spreadsheet))->save($path);
|
|
|
|
return UploadedFile::fake()->createWithContent('listino.xlsx', file_get_contents($path));
|
|
}
|
|
|
|
public function test_il_parser_legge_le_tabelle_in_mm(): void
|
|
{
|
|
$blocchi = ListinoExcelParser::parseRighe($this->righe());
|
|
|
|
$this->assertSame(['finestra_1_anta', 'PORTA 1 ANTA, CON SERRATURA'], array_column($blocchi, 'codice'));
|
|
$this->assertSame([
|
|
['larghezza' => 400, 'altezza' => 400, 'prezzo' => 367.2],
|
|
['larghezza' => 500, 'altezza' => 400, 'prezzo' => 381.24],
|
|
['larghezza' => 400, 'altezza' => 500, 'prezzo' => 381.24],
|
|
], $blocchi[0]['prezzi']);
|
|
}
|
|
|
|
public function test_il_parser_gestisce_l_intestazione_sulla_riga_successiva(): void
|
|
{
|
|
$blocchi = ListinoExcelParser::parseRighe([
|
|
['CASSONETTO PVC', null, null],
|
|
['mm', 500, 600],
|
|
[300, 94.14, 104.59],
|
|
]);
|
|
|
|
$this->assertSame('CASSONETTO PVC', $blocchi[0]['codice']);
|
|
$this->assertCount(2, $blocchi[0]['prezzi']);
|
|
}
|
|
|
|
public function test_associazione_proposta_per_codice_alias_e_descrizione(): void
|
|
{
|
|
$associazioni = ListinoImporter::suggerisciAssociazioni($this->pvc, [
|
|
'finestra_1_anta', 'finestra_wasistas', 'BILICO ORIZZONTALE', 'ALZANTE 2ANTE_MANO SX',
|
|
]);
|
|
|
|
$id = fn (string $codice) => Modello::where('codice', $codice)->value('id');
|
|
$this->assertSame([
|
|
'finestra_1_anta' => $id('finestra_1_anta'),
|
|
'finestra_wasistas' => $id('finestra_vasistas'),
|
|
'BILICO ORIZZONTALE' => $id('bilico'),
|
|
'ALZANTE 2ANTE_MANO SX' => null,
|
|
], $associazioni);
|
|
}
|
|
|
|
public function test_l_azione_importa_i_listini_secondo_le_associazioni_scelte(): void
|
|
{
|
|
$finestra = Modello::where('codice', 'finestra_1_anta')->firstOrFail();
|
|
$porta = Modello::where('codice', 'porta_1_anta')->firstOrFail();
|
|
$bilico = Modello::where('codice', 'bilico')->firstOrFail();
|
|
// Listino preesistente di un modello non coinvolto: deve restare com'è.
|
|
ListinoPrezzo::create(['modello_id' => $bilico->id, 'larghezza' => 1000, 'altezza' => 1000, 'prezzo' => 1]);
|
|
ListinoPrezzo::create(['modello_id' => $finestra->id, 'larghezza' => 9990, 'altezza' => 9990, 'prezzo' => 1]);
|
|
|
|
Livewire::test(ListSistemi::class)
|
|
->callTableAction('importaListini', $this->pvc, data: [
|
|
'file' => $this->fileExcel(),
|
|
'associazioni' => [
|
|
'a' => ['codice' => 'finestra_1_anta', 'modello_id' => $finestra->id],
|
|
// Associazione corretta a mano dall'admin.
|
|
'b' => ['codice' => 'PORTA 1 ANTA, CON SERRATURA', 'modello_id' => $porta->id],
|
|
],
|
|
])
|
|
->assertHasNoTableActionErrors()
|
|
->assertNotified('Listini importati');
|
|
|
|
$this->assertSame(3, $finestra->listino()->count());
|
|
$this->assertFalse($finestra->listino()->where('larghezza', 9990)->exists());
|
|
$this->assertEquals(820, $porta->listino()->where('larghezza', 600)->value('prezzo'));
|
|
$this->assertSame(1, $bilico->listino()->count());
|
|
$this->assertNotNull($finestra->fresh()->listino_aggiornato_at);
|
|
}
|
|
|
|
/** Listino con un prezzo da Excel e due aggiunti a mano (uno su una misura presente nel file). */
|
|
private function finestraConPrezziPersonalizzati(): Modello
|
|
{
|
|
$finestra = Modello::where('codice', 'finestra_1_anta')->firstOrFail();
|
|
ListinoPrezzo::create(['modello_id' => $finestra->id, 'larghezza' => 400, 'altezza' => 400, 'prezzo' => 1]);
|
|
ListinoPrezzo::create(['modello_id' => $finestra->id, 'larghezza' => 500, 'altezza' => 400, 'prezzo' => 999, 'personalizzato' => true]);
|
|
ListinoPrezzo::create(['modello_id' => $finestra->id, 'larghezza' => 2000, 'altezza' => 2000, 'prezzo' => 888, 'personalizzato' => true]);
|
|
|
|
return $finestra;
|
|
}
|
|
|
|
private function importaFinestra(Modello $finestra, ?bool $sovrascriviTutto): void
|
|
{
|
|
$data = [
|
|
'file' => $this->fileExcel(),
|
|
'associazioni' => ['a' => ['codice' => 'finestra_1_anta', 'modello_id' => $finestra->id]],
|
|
];
|
|
if ($sovrascriviTutto !== null) {
|
|
$data['sovrascrivi_tutto'] = $sovrascriviTutto;
|
|
}
|
|
|
|
Livewire::test(ListSistemi::class)
|
|
->callTableAction('importaListini', $this->pvc, data: $data)
|
|
->assertHasNoTableActionErrors();
|
|
}
|
|
|
|
public function test_di_default_l_excel_sovrascrive_anche_i_prezzi_personalizzati(): void
|
|
{
|
|
$finestra = $this->finestraConPrezziPersonalizzati();
|
|
|
|
Livewire::test(ListSistemi::class)
|
|
->mountTableAction('importaListini', $this->pvc)
|
|
->assertTableActionDataSet(['sovrascrivi_tutto' => true]);
|
|
|
|
$this->importaFinestra($finestra, null);
|
|
|
|
$this->assertSame(3, $finestra->listino()->count());
|
|
$this->assertFalse($finestra->listino()->where('personalizzato', true)->exists());
|
|
$this->assertEquals(381.24, $finestra->listino()->where('larghezza', 500)->where('altezza', 400)->value('prezzo'));
|
|
}
|
|
|
|
public function test_si_possono_preservare_i_prezzi_personalizzati(): void
|
|
{
|
|
$finestra = $this->finestraConPrezziPersonalizzati();
|
|
|
|
$this->importaFinestra($finestra, false);
|
|
|
|
// 3 misure dal file (una sostituita dal prezzo personalizzato) + 1 personalizzata fuori file.
|
|
$this->assertSame(4, $finestra->listino()->count());
|
|
$this->assertEquals(367.2, $finestra->listino()->where('larghezza', 400)->where('altezza', 400)->value('prezzo'));
|
|
$this->assertEquals(999, $finestra->listino()->where('larghezza', 500)->where('altezza', 400)->value('prezzo'));
|
|
$this->assertEquals(888, $finestra->listino()->where('larghezza', 2000)->value('prezzo'));
|
|
$this->assertSame(2, $finestra->listino()->where('personalizzato', true)->count());
|
|
}
|
|
|
|
public function test_due_tabelle_non_possono_andare_sullo_stesso_modello(): void
|
|
{
|
|
$finestra = Modello::where('codice', 'finestra_1_anta')->firstOrFail();
|
|
|
|
Livewire::test(ListSistemi::class)
|
|
->callTableAction('importaListini', $this->pvc, data: [
|
|
'file' => $this->fileExcel(),
|
|
'associazioni' => [
|
|
'a' => ['codice' => 'finestra_1_anta', 'modello_id' => $finestra->id],
|
|
'b' => ['codice' => 'PORTA 1 ANTA, CON SERRATURA', 'modello_id' => $finestra->id],
|
|
],
|
|
])
|
|
->assertHasTableActionErrors();
|
|
|
|
$this->assertSame(0, $finestra->listino()->count());
|
|
}
|
|
|
|
public function test_il_listino_e_modificabile_dal_modello(): void
|
|
{
|
|
$finestra = Modello::where('codice', 'finestra_1_anta')->firstOrFail();
|
|
$prezzo = ListinoPrezzo::create(['modello_id' => $finestra->id, 'larghezza' => 400, 'altezza' => 400, 'prezzo' => 100]);
|
|
|
|
Livewire::test(ListinoRelationManager::class, ['ownerRecord' => $finestra, 'pageClass' => EditModello::class])
|
|
->assertCanSeeTableRecords([$prezzo])
|
|
->callTableAction('create', data: ['larghezza' => 500, 'altezza' => 400, 'prezzo' => 120])
|
|
->assertHasNoTableActionErrors()
|
|
->callTableAction('create', data: ['larghezza' => 400, 'altezza' => 400, 'prezzo' => 1])
|
|
->assertHasTableActionErrors(['larghezza' => 'unique']);
|
|
|
|
$this->assertSame(2, $finestra->listino()->count());
|
|
$this->assertTrue($finestra->listino()->where('larghezza', 500)->value('personalizzato'));
|
|
$this->assertFalse($prezzo->fresh()->personalizzato);
|
|
}
|
|
|
|
public function test_api_listino_restituisce_la_griglia_ordinata(): void
|
|
{
|
|
$finestra = Modello::where('codice', 'finestra_1_anta')->firstOrFail();
|
|
ListinoImporter::importa($this->pvc, ListinoExcelParser::parseRighe($this->righe()), ['finestra_1_anta' => $finestra->id]);
|
|
$this->conModelli3d();
|
|
|
|
$this->getJson('/api/sistemi/pvc/modelli/finestra_1_anta/listino')
|
|
->assertOk()
|
|
->assertExactJson([
|
|
['altezza' => 400, 'larghezza' => 400, 'prezzo' => 367.2],
|
|
['altezza' => 400, 'larghezza' => 500, 'prezzo' => 381.24],
|
|
['altezza' => 500, 'larghezza' => 400, 'prezzo' => 381.24],
|
|
]);
|
|
|
|
// Modello disattivo (senza asset 3D): non esposto.
|
|
$this->getJson('/api/sistemi/pvc/modelli/scorrevole_hst_4_ante/listino')->assertNotFound();
|
|
}
|
|
}
|