ModelType defines a formula with placeholders ({serie}{diametre}{type}).
ReferenceAutoGenerator resolves it from CustomFieldValues with trim+uppercase normalisation.
ReferenceAutoSubscriber (onFlush) recalculates on Piece/CFV insert/update/delete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
179 lines
7.0 KiB
PHP
179 lines
7.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Api\Entity;
|
|
|
|
use App\Enum\ModelCategory;
|
|
use App\Tests\AbstractApiTestCase;
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
class PieceReferenceAutoTest extends AbstractApiTestCase
|
|
{
|
|
public function testReferenceAutoGeneratedAfterAllCfvCreated(): void
|
|
{
|
|
$mt = $this->createModelType('Roulement', 'ROUL-010', ModelCategory::PIECE);
|
|
$mt->setReferenceFormula('{serie}{diametre}{type}');
|
|
$mt->setRequiredFieldsForReference(['serie', 'diametre', 'type']);
|
|
|
|
$em = $this->getEntityManager();
|
|
$em->flush();
|
|
|
|
$cfSerie = $this->createCustomField('serie', 'text', typePiece: $mt);
|
|
$cfDiametre = $this->createCustomField('diametre', 'text', typePiece: $mt);
|
|
$cfType = $this->createCustomField('type', 'text', typePiece: $mt);
|
|
|
|
$piece = $this->createPiece('Roulement Auto', null, $mt);
|
|
|
|
$this->createCustomFieldValue($cfSerie, '22', piece: $piece);
|
|
$this->createCustomFieldValue($cfDiametre, '07', piece: $piece);
|
|
$this->createCustomFieldValue($cfType, 'K', piece: $piece);
|
|
|
|
$client = $this->createViewerClient();
|
|
$client->request('GET', self::iri('pieces', $piece->getId()));
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
$this->assertJsonContains(['referenceAuto' => '2207K']);
|
|
}
|
|
|
|
public function testReferenceAutoNullWhenNoFormula(): void
|
|
{
|
|
$mt = $this->createModelType('Galet', 'GAL-010', ModelCategory::PIECE);
|
|
$piece = $this->createPiece('Galet Auto', null, $mt);
|
|
|
|
$client = $this->createViewerClient();
|
|
$response = $client->request('GET', self::iri('pieces', $piece->getId()));
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
$data = $response->toArray();
|
|
self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be serialized when null');
|
|
}
|
|
|
|
public function testReferenceAutoNullWhenRequiredFieldsMissing(): void
|
|
{
|
|
$mt = $this->createModelType('Palier', 'PAL-010', ModelCategory::PIECE);
|
|
$mt->setReferenceFormula('SNU {taille}');
|
|
$mt->setRequiredFieldsForReference(['taille']);
|
|
|
|
$em = $this->getEntityManager();
|
|
$em->flush();
|
|
|
|
$piece = $this->createPiece('Palier Sans Champ', null, $mt);
|
|
|
|
$client = $this->createViewerClient();
|
|
$response = $client->request('GET', self::iri('pieces', $piece->getId()));
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
$data = $response->toArray();
|
|
self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be serialized when required fields missing');
|
|
}
|
|
|
|
public function testReferenceAutoUpdatedWhenCustomFieldValueChanges(): void
|
|
{
|
|
$mt = $this->createModelType('Joint', 'JOINT-010', ModelCategory::PIECE);
|
|
$mt->setReferenceFormula('U{taille}');
|
|
|
|
$em = $this->getEntityManager();
|
|
$em->flush();
|
|
|
|
$cfTaille = $this->createCustomField('taille', 'text', typePiece: $mt);
|
|
$piece = $this->createPiece('Joint Upd', null, $mt);
|
|
$cfv = $this->createCustomFieldValue($cfTaille, '507', piece: $piece);
|
|
|
|
$client = $this->createViewerClient();
|
|
$client->request('GET', self::iri('pieces', $piece->getId()));
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
$this->assertJsonContains(['referenceAuto' => 'U507']);
|
|
|
|
// Update CFV value via API
|
|
$gClient = $this->createGestionnaireClient();
|
|
$gClient->request('PATCH', self::iri('custom_field_values', $cfv->getId()), [
|
|
'headers' => ['Content-Type' => 'application/merge-patch+json'],
|
|
'json' => ['value' => '608'],
|
|
]);
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
|
|
// Re-read the Piece to check updated referenceAuto
|
|
$viewer = $this->createViewerClient();
|
|
$viewer->request('GET', self::iri('pieces', $piece->getId()));
|
|
$this->assertJsonContains(['referenceAuto' => 'U608']);
|
|
}
|
|
|
|
public function testReferenceAutoNullAfterRequiredCfvDeleted(): void
|
|
{
|
|
$mt = $this->createModelType('Joint Del', 'JOINT-011', ModelCategory::PIECE);
|
|
$mt->setReferenceFormula('U{taille}');
|
|
$mt->setRequiredFieldsForReference(['taille']);
|
|
|
|
$em = $this->getEntityManager();
|
|
$em->flush();
|
|
|
|
$cfTaille = $this->createCustomField('taille', 'text', typePiece: $mt);
|
|
$piece = $this->createPiece('Joint Del', null, $mt);
|
|
$cfv = $this->createCustomFieldValue($cfTaille, '507', piece: $piece);
|
|
|
|
$client = $this->createViewerClient();
|
|
$client->request('GET', self::iri('pieces', $piece->getId()));
|
|
$this->assertJsonContains(['referenceAuto' => 'U507']);
|
|
|
|
// Delete the CFV
|
|
$gClient = $this->createGestionnaireClient();
|
|
$gClient->request('DELETE', self::iri('custom_field_values', $cfv->getId()));
|
|
$this->assertResponseStatusCodeSame(204);
|
|
|
|
// Re-read piece — referenceAuto should now be absent (null = not serialized)
|
|
$viewer = $this->createViewerClient();
|
|
$response = $viewer->request('GET', self::iri('pieces', $piece->getId()));
|
|
$data = $response->toArray();
|
|
self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should be null after required CFV deleted');
|
|
}
|
|
|
|
public function testReferenceAutoIsReadOnlyViaApi(): void
|
|
{
|
|
$piece = $this->createPiece('ReadOnly Test');
|
|
|
|
$client = $this->createGestionnaireClient();
|
|
$client->request('PATCH', self::iri('pieces', $piece->getId()), [
|
|
'headers' => ['Content-Type' => 'application/merge-patch+json'],
|
|
'json' => ['referenceAuto' => 'HACKED'],
|
|
]);
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
|
|
// referenceAuto should still be null (no formula) — subscriber overwrites
|
|
$viewer = $this->createViewerClient();
|
|
$response = $viewer->request('GET', self::iri('pieces', $piece->getId()));
|
|
$data = $response->toArray();
|
|
self::assertArrayNotHasKey('referenceAuto', $data, 'referenceAuto should not be settable via API');
|
|
}
|
|
|
|
public function testReferenceAutoNormalizesLowercaseValues(): void
|
|
{
|
|
$mt = $this->createModelType('Roulement Norm', 'ROUL-011', ModelCategory::PIECE);
|
|
$mt->setReferenceFormula('{serie}{diametre}{type}');
|
|
|
|
$em = $this->getEntityManager();
|
|
$em->flush();
|
|
|
|
$cfSerie = $this->createCustomField('serie', 'text', typePiece: $mt);
|
|
$cfDiametre = $this->createCustomField('diametre', 'text', typePiece: $mt);
|
|
$cfType = $this->createCustomField('type', 'text', typePiece: $mt);
|
|
|
|
$piece = $this->createPiece('Roulement Norm', null, $mt);
|
|
|
|
$this->createCustomFieldValue($cfSerie, '22', piece: $piece);
|
|
$this->createCustomFieldValue($cfDiametre, '07', piece: $piece);
|
|
$this->createCustomFieldValue($cfType, 'k', piece: $piece);
|
|
|
|
$client = $this->createViewerClient();
|
|
$client->request('GET', self::iri('pieces', $piece->getId()));
|
|
|
|
$this->assertResponseIsSuccessful();
|
|
$this->assertJsonContains(['referenceAuto' => '2207K']);
|
|
}
|
|
}
|