feat(technique) : sous-ressources Contacts / Adresses / RIBs (ERP-135)
Expose les sous-collections du prestataire en #[ApiResource] (POST sur le
parent + PATCH/DELETE/GET unitaires), edition complete par onglet (pas de
POST-only, RETEX M1/M2) :
- ProviderContact : POST /providers/{id}/contacts, PATCH/DELETE
/provider_contacts/{id} (security technique.providers.manage).
ProviderContactProcessor : normalisation RG-3.11 (nom/prenom Title Case,
telephones chiffres, email lowercase) + RG-3.04 (au moins un champ parmi
prenom/nom/telephone/email, miroir du CHECK chk_provider_contact_name -> 422).
- ProviderAddress : POST /providers/{id}/addresses, PATCH/DELETE
/provider_addresses/{id} (security technique.providers.manage).
ProviderAddressProcessor : rattachement parent + cloisonnement d'ecriture des
sites de l'adresse (RG-3.05 / § 2.13 : site hors user_site -> 422 sur sites).
- ProviderRib : POST /providers/{id}/ribs, PATCH/DELETE /provider_ribs/{id}
(security technique.providers.accounting.manage). ProviderRibProcessor :
RG-3.08 (DELETE du dernier RIB sous LCR -> 409).
Tests : ProviderSubResourceApiTest (19 cas) — CRUD chaque sous-ressource, 403
selon permission (Contacts/Adresses=manage, RIB=accounting.manage), 409 dernier
RIB LCR, 422 cloisonnement site adresse. Helpers addContact/addRib/paymentType
ajoutes a AbstractProviderApiTestCase.
This commit is contained in:
@@ -7,11 +7,14 @@ namespace App\Tests\Module\Technique\Api;
|
||||
use ApiPlatform\Symfony\Bundle\Test\Client;
|
||||
use App\Module\Catalog\Domain\Entity\Category;
|
||||
use App\Module\Catalog\Domain\Entity\CategoryType;
|
||||
use App\Module\Commercial\Domain\Entity\PaymentType;
|
||||
use App\Module\Core\Domain\Entity\Permission;
|
||||
use App\Module\Core\Domain\Entity\Role;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Sites\Domain\Entity\Site;
|
||||
use App\Module\Technique\Domain\Entity\Provider;
|
||||
use App\Module\Technique\Domain\Entity\ProviderContact;
|
||||
use App\Module\Technique\Domain\Entity\ProviderRib;
|
||||
use App\Tests\Module\Core\Api\AbstractApiTestCase;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
@@ -48,6 +51,12 @@ abstract class AbstractProviderApiTestCase extends AbstractApiTestCase
|
||||
protected const string SITE_17 = '17400'; // Saint-Jean
|
||||
protected const string SITE_82 = '82400'; // Pommevic
|
||||
|
||||
/** IBAN / BIC valides (memes valeurs que les tests M2) pour les RIB. */
|
||||
protected const string VALID_IBAN = 'FR1420041010050500013M02606';
|
||||
protected const string VALID_BIC = 'BNPAFRPPXXX';
|
||||
/** BIC d'un autre pays (DE) : controle croise pays BIC/IBAN. */
|
||||
protected const string FOREIGN_BIC = 'DEUTDEFFXXX';
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$em = $this->getEm();
|
||||
@@ -268,6 +277,64 @@ abstract class AbstractProviderApiTestCase extends AbstractApiTestCase
|
||||
return ['username' => $username, 'password' => $password];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute un contact a un prestataire deja persiste (seed direct).
|
||||
*/
|
||||
protected function addContact(
|
||||
Provider $provider,
|
||||
?string $firstName = 'Marie',
|
||||
?string $lastName = 'Martin',
|
||||
?string $phonePrimary = null,
|
||||
?string $email = null,
|
||||
int $position = 0,
|
||||
): ProviderContact {
|
||||
$contact = new ProviderContact();
|
||||
$contact->setProvider($provider);
|
||||
$contact->setFirstName($firstName);
|
||||
$contact->setLastName($lastName);
|
||||
$contact->setPhonePrimary($phonePrimary);
|
||||
$contact->setEmail($email);
|
||||
$contact->setPosition($position);
|
||||
$provider->addContact($contact);
|
||||
$this->getEm()->persist($contact);
|
||||
$this->getEm()->flush();
|
||||
|
||||
return $contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute un RIB a un prestataire deja persiste (seed direct).
|
||||
*/
|
||||
protected function addRib(Provider $provider, string $label = 'Compte principal'): ProviderRib
|
||||
{
|
||||
$rib = new ProviderRib();
|
||||
$rib->setProvider($provider);
|
||||
$rib->setLabel($label);
|
||||
$rib->setBic(self::VALID_BIC);
|
||||
$rib->setIban(self::VALID_IBAN);
|
||||
$provider->addRib($rib);
|
||||
$this->getEm()->persist($rib);
|
||||
$this->getEm()->flush();
|
||||
|
||||
return $rib;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recupere un type de reglement seede (CommercialReferentialFixtures) par code
|
||||
* (ex. LCR, VIREMENT). Echoue explicitement si absent (fixtures non chargees).
|
||||
*/
|
||||
protected function paymentType(string $code): PaymentType
|
||||
{
|
||||
$paymentType = $this->getEm()->getRepository(PaymentType::class)->findOneBy(['code' => $code]);
|
||||
|
||||
self::assertNotNull(
|
||||
$paymentType,
|
||||
sprintf('Type de reglement "%s" introuvable : fixtures comptables chargees (make test-db-setup) ?', $code),
|
||||
);
|
||||
|
||||
return $paymentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexe les violations d'un corps 422 par propertyPath (assert ciblee).
|
||||
*
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Module\Technique\Api;
|
||||
|
||||
use App\Module\Technique\Domain\Entity\Provider;
|
||||
|
||||
/**
|
||||
* Tests fonctionnels des sous-ressources Contacts / Adresses / RIB du prestataire
|
||||
* (M3, spec § 4.5 — ERP-135). Couvrent : normalisation contact (RG-3.11), RG-3.04
|
||||
* (au moins un champ parmi prenom/nom/telephone/email), RG-3.05 (>= 1 site sur
|
||||
* l'adresse), RG-3.06 (code postal), RG-3.09 (categorie PRESTATAIRE sur adresse),
|
||||
* le cloisonnement d'ecriture des sites de l'adresse (§ 2.13 -> 422 sur `sites`),
|
||||
* RG-3.08 (DELETE dernier RIB sous LCR -> 409), DELETE contact libre au M3 (pas de
|
||||
* garde « dernier contact ») et le gating selon permission (Contacts/Adresses =
|
||||
* manage, RIB = accounting.manage). Jumeau de SupplierSubResourceApiTest.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ProviderSubResourceApiTest extends AbstractProviderApiTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
// seedProvider exige >= 1 site (RG-3.03) : le module Sites doit etre actif.
|
||||
$this->skipIfSitesModuleDisabled();
|
||||
}
|
||||
|
||||
// === Contacts (security: technique.providers.manage) ===
|
||||
|
||||
public function testPostContactNormalizesFields(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Contact Host');
|
||||
|
||||
$data = $client->request('POST', '/api/providers/'.$seed->getId().'/contacts', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'firstName' => 'JEAN',
|
||||
'lastName' => 'dupont',
|
||||
'phonePrimary' => '06.12.34.56.78',
|
||||
'email' => 'Jean.DUPONT@ACME.FR',
|
||||
],
|
||||
])->toArray();
|
||||
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
// RG-3.11 : prenom/nom Title Case, telephone chiffres seuls, email lowercase.
|
||||
self::assertSame('Jean', $data['firstName']);
|
||||
self::assertSame('Dupont', $data['lastName']);
|
||||
self::assertSame('0612345678', $data['phonePrimary']);
|
||||
self::assertSame('jean.dupont@acme.fr', $data['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* RG-3.04 : un bloc sans aucun champ du CHECK (prenom/nom/telephone/email) est
|
||||
* rejete avant la base (chk_provider_contact_name) -> 422 rattachee a firstName.
|
||||
* Ici seul jobTitle est fourni (hors CHECK).
|
||||
*/
|
||||
public function testPostContactWithoutNamedFieldReturns422OnFirstNamePath(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Contact No Name');
|
||||
|
||||
$response = $client->request('POST', '/api/providers/'.$seed->getId().'/contacts', [
|
||||
'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD],
|
||||
'json' => ['jobTitle' => 'Directeur'],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
self::assertArrayHasKey('firstName', $this->violationsByPath($response->toArray(false)));
|
||||
}
|
||||
|
||||
public function testPostContactOnMissingProviderReturns404(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
|
||||
$client->request('POST', '/api/providers/999999/contacts', [
|
||||
'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD],
|
||||
'json' => ['firstName' => 'Orphan'],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(404);
|
||||
}
|
||||
|
||||
public function testPatchContactNormalizesFields(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Contact Patch');
|
||||
$contact = $this->addContact($seed, 'Marie', 'Martin');
|
||||
|
||||
$data = $client->request('PATCH', '/api/provider_contacts/'.$contact->getId(), [
|
||||
'headers' => ['Content-Type' => self::MERGE],
|
||||
'json' => ['lastName' => 'durand'],
|
||||
])->toArray();
|
||||
|
||||
self::assertResponseStatusCodeSame(200);
|
||||
// Normalisation aussi sur PATCH : "durand" -> "Durand".
|
||||
self::assertSame('Durand', $data['lastName']);
|
||||
}
|
||||
|
||||
public function testDeleteLastContactReturns204(): void
|
||||
{
|
||||
// M3 : pas de garde « dernier contact » (RG-3.12 front-driven) — la
|
||||
// suppression du dernier contact est libre (204).
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Contact Solo');
|
||||
$contact = $this->addContact($seed, 'Unique', 'Contact');
|
||||
|
||||
$client->request('DELETE', '/api/provider_contacts/'.$contact->getId());
|
||||
|
||||
self::assertResponseStatusCodeSame(204);
|
||||
}
|
||||
|
||||
public function testContactWriteWithoutManageReturns403(): void
|
||||
{
|
||||
// Un user sans permission technique.providers.manage -> 403 sur la sous-ressource.
|
||||
$seed = $this->seedProvider('Contact Forbidden');
|
||||
$creds = $this->createUserWithPermission('core.users.view');
|
||||
$http = $this->authenticatedClient($creds['username'], $creds['password']);
|
||||
|
||||
$http->request('POST', '/api/providers/'.$seed->getId().'/contacts', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => ['firstName' => 'Nope'],
|
||||
]);
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
}
|
||||
|
||||
// === Adresses (security: technique.providers.manage) ===
|
||||
|
||||
public function testPostAddressWithValidPayloadReturns201(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Address Host');
|
||||
$category = $this->providerCategory('NETTOYAGE');
|
||||
|
||||
$data = $client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '86100',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_86)->getId()],
|
||||
'categories' => ['/api/categories/'.$category->getId()],
|
||||
],
|
||||
])->toArray();
|
||||
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
self::assertSame('Châtellerault', $data['city']);
|
||||
}
|
||||
|
||||
public function testPostAddressWithoutSiteReturns422(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Address No Site');
|
||||
|
||||
$client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '86100',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => [],
|
||||
'categories' => ['/api/categories/'.$this->providerCategory()->getId()],
|
||||
],
|
||||
]);
|
||||
|
||||
// RG-3.05 (Assert\Count min 1 sur sites).
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
}
|
||||
|
||||
public function testPostAddressWithInvalidPostalCodeReturns422(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Address Bad CP');
|
||||
|
||||
$client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '123',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_86)->getId()],
|
||||
'categories' => ['/api/categories/'.$this->providerCategory()->getId()],
|
||||
],
|
||||
]);
|
||||
|
||||
// RG-3.06 (Assert\Regex ^[0-9]{4,5}$).
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
}
|
||||
|
||||
public function testPostAddressWithNonPrestataireCategoryReturns422(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Address Bad Cat');
|
||||
$foreign = $this->foreignCategory(); // type CLIENT -> interdite (RG-3.09).
|
||||
|
||||
$response = $client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '86100',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_86)->getId()],
|
||||
'categories' => ['/api/categories/'.$foreign->getId()],
|
||||
],
|
||||
]);
|
||||
|
||||
// RG-3.09 -> 422 rattachee a categories.
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
self::assertArrayHasKey('categories', $this->violationsByPath($response->toArray(false)));
|
||||
}
|
||||
|
||||
public function testDeleteAddressReturns204(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Address Delete');
|
||||
$category = $this->providerCategory('NETTOYAGE');
|
||||
|
||||
$created = $client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '86100',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_86)->getId()],
|
||||
'categories' => ['/api/categories/'.$category->getId()],
|
||||
],
|
||||
])->toArray();
|
||||
|
||||
$client->request('DELETE', $created['@id']);
|
||||
self::assertResponseStatusCodeSame(204);
|
||||
}
|
||||
|
||||
public function testAddressWriteWithoutManageReturns403(): void
|
||||
{
|
||||
$seed = $this->seedProvider('Address Forbidden');
|
||||
$creds = $this->createUserWithPermission('core.users.view');
|
||||
$http = $this->authenticatedClient($creds['username'], $creds['password']);
|
||||
|
||||
$http->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '86100',
|
||||
'city' => 'Châtellerault',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_86)->getId()],
|
||||
],
|
||||
]);
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* § 2.13 / RG-3.05 (cloisonnement d'ECRITURE sur l'adresse) : un user non-bypass
|
||||
* `sites.read_ref` (qui peut resoudre n'importe quel IRI de site, sinon 400 en
|
||||
* amont) ne peut attacher a l'adresse que ses propres user_site. Site hors
|
||||
* perimetre -> 422 sur `sites` (garde ProviderAddressProcessor).
|
||||
*/
|
||||
public function testPostAddressWithOutOfScopeSiteReturns422OnSitesPath(): void
|
||||
{
|
||||
$seed = $this->seedProvider('Address Scope', [self::SITE_86]);
|
||||
$category = $this->providerCategory('NETTOYAGE');
|
||||
|
||||
$creds = $this->createScopedUser(
|
||||
['technique.providers.view', 'technique.providers.manage', 'sites.read_ref'],
|
||||
sitePostalCodes: [self::SITE_86],
|
||||
currentSitePostalCode: self::SITE_86,
|
||||
);
|
||||
$client = $this->authenticatedClient($creds['username'], $creds['password']);
|
||||
|
||||
$response = $client->request('POST', '/api/providers/'.$seed->getId().'/addresses', [
|
||||
'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD],
|
||||
'json' => [
|
||||
'postalCode' => '17400',
|
||||
'city' => 'Saint-Jean-d\'Angély',
|
||||
'street' => '1 rue du Test',
|
||||
'sites' => ['/api/sites/'.$this->site(self::SITE_17)->getId()], // hors user_site
|
||||
'categories' => ['/api/categories/'.$category->getId()],
|
||||
],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
self::assertArrayHasKey('sites', $this->violationsByPath($response->toArray(false)));
|
||||
}
|
||||
|
||||
// === RIBs (security: technique.providers.accounting.manage) ===
|
||||
|
||||
public function testPostRibByAdminReturns201(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Rib Host');
|
||||
|
||||
$data = $client->request('POST', '/api/providers/'.$seed->getId().'/ribs', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => [
|
||||
'label' => 'Compte principal',
|
||||
'bic' => self::VALID_BIC,
|
||||
'iban' => self::VALID_IBAN,
|
||||
],
|
||||
])->toArray();
|
||||
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
self::assertSame('Compte principal', $data['label']);
|
||||
}
|
||||
|
||||
public function testPostRibWithInvalidIbanReturns422(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Rib Bad Iban');
|
||||
|
||||
$client->request('POST', '/api/providers/'.$seed->getId().'/ribs', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => ['label' => 'Compte invalide', 'bic' => self::VALID_BIC, 'iban' => 'INVALID-IBAN'],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
}
|
||||
|
||||
/**
|
||||
* Controle croise pays BIC/IBAN (Assert\Bic ibanPropertyPath) : un BIC (DE) et
|
||||
* un IBAN (FR) valides isolement mais de pays differents -> 422 sur `bic`.
|
||||
*/
|
||||
public function testPostRibWithBicIbanCountryMismatchReturns422OnBic(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Rib Pays Mismatch');
|
||||
|
||||
$response = $client->request('POST', '/api/providers/'.$seed->getId().'/ribs', [
|
||||
'headers' => ['Content-Type' => self::LD, 'Accept' => self::LD],
|
||||
'json' => ['label' => 'Compte incoherent', 'bic' => self::FOREIGN_BIC, 'iban' => self::VALID_IBAN],
|
||||
]);
|
||||
|
||||
self::assertResponseStatusCodeSame(422);
|
||||
$byPath = $this->violationsByPath($response->toArray(false));
|
||||
self::assertArrayHasKey('bic', $byPath);
|
||||
self::assertSame('Le BIC ne correspond pas au pays de l\'IBAN.', $byPath['bic']);
|
||||
}
|
||||
|
||||
public function testDeleteRibNonLcrReturns204(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Rib Non LCR');
|
||||
$rib = $this->addRib($seed);
|
||||
|
||||
$client->request('DELETE', '/api/provider_ribs/'.$rib->getId());
|
||||
|
||||
self::assertResponseStatusCodeSame(204);
|
||||
}
|
||||
|
||||
public function testDeleteLastRibUnderLcrReturns409(): void
|
||||
{
|
||||
$client = $this->createAdminClient();
|
||||
$seed = $this->seedProvider('Rib LCR Solo');
|
||||
$rib = $this->addRib($seed);
|
||||
|
||||
// Passe le prestataire en LCR (seed direct).
|
||||
$em = $this->getEm();
|
||||
$managed = $em->getRepository(Provider::class)->find($seed->getId());
|
||||
$managed->setPaymentType($this->paymentType('LCR'));
|
||||
$em->flush();
|
||||
|
||||
$client->request('DELETE', '/api/provider_ribs/'.$rib->getId());
|
||||
|
||||
// RG-3.08 : LCR exige >= 1 RIB -> suppression du dernier refusee.
|
||||
self::assertResponseStatusCodeSame(409);
|
||||
}
|
||||
|
||||
public function testRibWriteWithoutAccountingManageReturns403(): void
|
||||
{
|
||||
// Un user portant seulement technique.providers.manage (sans accounting.manage)
|
||||
// ne peut ni creer, ni modifier, ni supprimer un RIB (gating renforce § 4.5).
|
||||
$seed = $this->seedProvider('Rib Forbidden');
|
||||
$rib = $this->addRib($seed);
|
||||
$creds = $this->createUserWithPermission('technique.providers.manage');
|
||||
$http = $this->authenticatedClient($creds['username'], $creds['password']);
|
||||
|
||||
$http->request('POST', '/api/providers/'.$seed->getId().'/ribs', [
|
||||
'headers' => ['Content-Type' => self::LD],
|
||||
'json' => ['label' => 'X', 'bic' => self::VALID_BIC, 'iban' => self::VALID_IBAN],
|
||||
]);
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
|
||||
$http->request('PATCH', '/api/provider_ribs/'.$rib->getId(), [
|
||||
'headers' => ['Content-Type' => self::MERGE],
|
||||
'json' => ['label' => 'Y'],
|
||||
]);
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
|
||||
$http->request('DELETE', '/api/provider_ribs/'.$rib->getId());
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user