Commit 28abaf87 by Mathieu Poisbeau

#143: Gros débogage et nettoyage de l'import des prestataires

parent 078d9c8c
...@@ -18,6 +18,7 @@ use App\Entity\Siege; ...@@ -18,6 +18,7 @@ use App\Entity\Siege;
use App\Entity\User; use App\Entity\User;
use App\Entity\Usergroup; use App\Entity\Usergroup;
use App\Entity\Flux; use App\Entity\Flux;
use App\Entity\TypePrestataire;
use App\Enum\ImportEnum; use App\Enum\ImportEnum;
use App\Enum\MoyenEnum; use App\Enum\MoyenEnum;
use App\Events\MLCEvents; use App\Events\MLCEvents;
...@@ -81,6 +82,9 @@ class ImportController extends CRUDController ...@@ -81,6 +82,9 @@ class ImportController extends CRUDController
$this->sendemail = false; $this->sendemail = false;
} }
/**
* @TODO: manage the case of a fatal error (so catch the exception, and display a nice message)!
*/
public function createAction() public function createAction()
{ {
$this->siege = $this->em->getRepository(Siege::class)->findOneById(1); $this->siege = $this->em->getRepository(Siege::class)->findOneById(1);
...@@ -344,164 +348,153 @@ class ImportController extends CRUDController ...@@ -344,164 +348,153 @@ class ImportController extends CRUDController
{ {
$operateur = $this->getUser(); $operateur = $this->getUser();
$operateur_id = $operateur->getId(); $operateur_id = $operateur->getId();
// Iterate over the reader and write each row to the database $line = 0;
// groupe;adresse;cpostal;ville;raison;ecompte;metier;statut;responsable;iban;siret;web;horaires;description;rubriques;tags;tauxreconversion;cotisations;gestionnaire_email1;gestionnaire_nom1;gestionnaire_prenom1;gestionnaire_phone1;gestionnaire_mobile1;contact1;phone1;email1;contact2;phone2;email2
$line = 1; /**
* Iterate over the reader and write each row to the database.
* Each row has at least 6 required columns.
*
* Row format: groupe;adresse;cpostal;ville;raison;ecompte;metier;statut;responsable;iban;siret;web;horaires;...
* description;rubriques;tags;tauxreconversion;cotisations;...
* gestionnaire_email1;gestionnaire_nom1;gestionnaire_prenom1;gestionnaire_phone1;gestionnaire_mobile1;...
* contact1;phone1;email1;contact2;phone2;email2
*/
$requiredColumns = [
'groupe', 'raison', 'siret', 'adresse', 'cpostal', 'ville',
];
$warningColumns = [
'metier', 'statut', 'responsable', 'iban', 'web', 'horaires', 'description', 'ecompte',
];
$columns = array_fill_keys(
array_merge($requiredColumns, $warningColumns, ['rubriques', 'tags', 'tauxreconversion', 'cotisations']),
null
);
foreach ($csvRows as $row) { foreach ($csvRows as $row) {
$hasError = false; $hasError = false;
if ($line == 1) {
$line++; $line++;
// The header is ignored
if ($line === 1) {
continue; continue;
} }
if (!array_key_exists("groupe", $row)) {
$this->addError($row, $line, 'groupe', $this->translator->trans("La colonne 'groupe' est obligatoire !")); // Add the missing columns to the current row (with a null value).
} $row += $columns;
if (!array_key_exists("adresse", $row)) {
$this->addError($row, $line, 'adresse', $this->translator->trans("La colonne 'adresse' est obligatoire !")); /**
} * Check the required columns.
if (!array_key_exists("cpostal", $row)) { * If one is not present or empty => add an error and go to the next line.
$this->addError($row, $line, 'cpostal', $this->translator->trans("La colonne 'cpostal' est obligatoire !")); */
} foreach ($requiredColumns as $column) {
if (!array_key_exists("ville", $row)) { if (! $row[$column]) {
$this->addError($row, $line, 'ville', $this->translator->trans("La colonne 'ville' est obligatoire !")); $this->addError($row, $line, $column,
} $this->translator->trans('prestataire.column_required', [$column], 'import')
if (!array_key_exists("raison", $row)) { );
$this->addError($row, $line, 'raison', $this->translator->trans("La colonne 'raison' est obligatoire !")); $hasError = true;
}
if (!(array_key_exists("groupe", $row) && array_key_exists("adresse", $row) && array_key_exists("cpostal", $row) && array_key_exists("ville", $row) && array_key_exists("raison", $row))) {
$line++;
$this->nberrors++;
continue;
}
$groupe = array_key_exists("groupe", $row) ? $row['groupe'] : '';
$adresse = array_key_exists("adresse", $row) ? $row['adresse'] : '';
$cpostal = array_key_exists("cpostal", $row) ? $row['cpostal'] : '';
$ville = array_key_exists("ville", $row) ? $row['ville'] : '';
$raison = array_key_exists("raison", $row) ? $row['raison'] : '';
if (empty($groupe)) {
$this->addError($row, $line, 'groupe', $this->translator->trans("Le 'groupe' est obligatoire !"));
}
if (empty($adresse)) {
$this->addError($row, $line, 'adresse', $this->translator->trans("Le 'adresse' est obligatoire !"));
}
if (empty($cpostal)) {
$this->addError($row, $line, 'cpostal', $this->translator->trans("Le 'cpostal' est obligatoire !"));
}
if (empty($ville)) {
$this->addError($row, $line, 'ville', $this->translator->trans("Le 'ville' est obligatoire !"));
} }
if (empty($raison)) {
$this->addError($row, $line, 'raison', $this->translator->trans("Le 'raison' est obligatoire !"));
} }
if (empty($groupe) || empty($adresse) || empty($cpostal) || empty($ville) || empty($raison)) {
if ($hasError) {
$this->nberrors++; $this->nberrors++;
$line++;
continue; continue;
} }
$ecompte = array_key_exists("ecompte", $row) ? $row['ecompte'] : '';
$metier = array_key_exists("metier", $row) ? $row['metier'] : '';
$statut = array_key_exists("statut", $row) ? $row['statut'] : '';
$responsable = array_key_exists("responsable", $row) ? $row['responsable'] : '';
$iban = array_key_exists("iban", $row) ? $row['iban'] : '';
$siret = array_key_exists("siret", $row) ? $row['siret'] : '';
$web = array_key_exists("web", $row) ? $row['web'] : '';
$horaires = array_key_exists("horaires", $row) ? $row['horaires'] : '';
$description = array_key_exists("description", $row) ? $row['description'] : '';
$rubriques = array_key_exists("rubriques", $row) ? $row['rubriques'] : '';
$tags = array_key_exists("tags", $row) ? $row['tags'] : '';
$tauxreconversion = array_key_exists("tauxreconversion", $row) ? $row['tauxreconversion'] : '';
$cotisations = array_key_exists("cotisations", $row) ? $row['cotisations'] : '';
$prestataire = $this->em->getRepository(Prestataire::class)->findOneBy(array('slug' => $this->slugify($raison))); /**
if (empty($prestataire)) { * If it doesn't exist yet, create and fill a Prestataire.
* Otherwise => error!
*/
$prestataire = $this->em->getRepository(Prestataire::class)->findOneBy([
'slug' => $this->slugify($row['raison'])
]);
if (!$prestataire) {
$prestataire = new Prestataire(); $prestataire = new Prestataire();
if (!empty($raison)) { // Actually, each new Prestataire will have the 'prestataire' as TypePrestataire
$prestataire->setRaison($raison); // @TODO: add a column 'type' in the CSV file (to choose a TypePrestataire)?
} else { $prestataire->setTypePrestataire($this->em->getRepository(TypePrestataire::class)->findOneBy([
$this->addWarning($row, $line, 'raison', 'empty'); 'slug' => 'prestataire'
} ]));
if (!empty($metier)) {
$prestataire->setMetier($metier); foreach ($requiredColumns as $column) {
} else { // Special processings for these fields => so we skip them
$this->addWarning($row, $line, 'metier', 'empty'); if (in_array($column, ['groupe', 'adresse', 'cpostal', 'ville'])) continue;
}
if (!empty($statut)) { $prestataire->{'set'.ucfirst($column)}($row[$column]);
$prestataire->setStatut($statut);
} else {
$this->addWarning($row, $line, 'statut', 'empty');
} }
if (!empty($responsable)) {
$prestataire->setResponsable($responsable); // Special processing for the 'ecompte' field
} else { if ($e =& $row['ecompte']) {
$this->addWarning($row, $line, 'responsable', 'empty'); $e = $this->tofloat($e);
} }
if (!empty($iban)) {
$prestataire->setIban($iban); foreach ($warningColumns as $column) {
if ($row[$column]) {
$prestataire->{'set'.ucfirst($column)}($row[$column]);
} else { } else {
$this->addWarning($row, $line, 'iban', 'empty'); $this->addWarning($row, $line, $column, 'empty');
} }
if (!empty($siret)) {
$prestataire->setSiret($siret);
} else {
$this->addWarning($row, $line, 'siret', 'empty');
} }
if (!empty($web)) {
$prestataire->setWeb($web); /**
} else { * If one or many Contacts are present, we create them for the Prestataire.
$this->addWarning($row, $line, 'web', 'empty'); * If a phone or an email is defined, the associated 'contact' field must be defined too!
*/
for ($i = 1; $i < 10; $i++) {
$name = $row["contact$i"] ?? null;
$phone = $row["phone$i"] ?? null;
$email = $row["email$i"] ?? null;
if ($name) {
$contact = new ContactPrestataire();
$contact->setPrestataire($prestataire);
$contact->setEnabled(true);
$contact->setName($name);
$contact->setTel($row["phone$i"] ?? '');
$contact->setEmail($row["email$i"] ?? '');
$this->em->persist($contact);
} elseif ($phone || $email) {
$this->addError($row, $line, "contact$i",
$this->translator->trans('prestataire.column_required', ["contact$i"], 'import')
);
$hasError = true;
} }
if (!empty($horaires)) {
$prestataire->setHoraires($horaires);
} else {
$this->addWarning($row, $line, 'horaires', 'empty');
}
if (!empty($description)) {
$prestataire->setDescription($description);
} else {
$this->addWarning($row, $line, 'description', 'empty');
} }
$cptContact = 1; if ($hasError) {
while (array_key_exists("contact".$cptContact, $row) && $cptContact < 10) { $this->nberrors++;
$contact = array_key_exists('contact'.$cptContact, $row) ? $row['contact'.$cptContact] : ''; continue;
$phone = array_key_exists('phone'.$cptContact, $row) ? $row['phone'.$cptContact] : '';
$email = array_key_exists('email'.$cptContact, $row) ? $row['email'.$cptContact] : '';
$contactC = new ContactPrestataire();
$contactC->setPrestataire($prestataire);
$contactC->setEnabled(true);
$contactC->setName($contact);
$contactC->setTel($phone);
$contactC->setEmail($email);
$this->em->persist($contactC);
++$cptContact;
} }
// Importer les gestionnaires du prestataire s'ils existent // Importer les gestionnaires du prestataire s'ils existent
$groupeGestionnaire = $this->em->getRepository(Usergroup::class)->findOneByName('Prestataire'); $groupeGestionnaire = $this->em->getRepository(Usergroup::class)->findOneByName('Prestataire');
$gestionnaires = $this->importGestionnaires($row, $groupeGestionnaire); $gestionnaires = $this->importGestionnaires($row, $groupeGestionnaire);
$prestataire->setUsers($gestionnaires); $prestataire->setUsers($gestionnaires);
if (!empty($ecompte)) { /**
$prestataire->setEcompte($this->tofloat($ecompte)); * If no Groupe object exists for the 'groupe' field, we create one.
} else { * Note: at this point, the 'groupe' field is necessarily not empty (because it was required above).
$this->addWarning($row, $line, 'ecompte', 'empty'); */
} $groupe = $row['groupe'];
if (!empty($groupe)) { $groupeObj = $this->em->getRepository(Groupe::class)->findOneBy(['name' => $groupe]);
$groupeFound = $this->em->getRepository(Groupe::class)->findOneBy(array('name' => $groupe));
if (empty($groupeFound)) { if (! $groupeObj) {
$groupeFound = new Groupe(); $groupeObj = new Groupe();
$groupeFound->setName($groupe); $groupeObj->setName($groupe);
$groupeFound->setSiege($this->siege); $groupeObj->setSiege($this->siege);
$this->em->persist($groupeFound); $this->em->persist($groupeObj);
$this->addWarning($row, $line, 'groupe', $this->translator->trans('Groupe introuvable, création du groupe : ').$groupe); $this->addSuccess($row, $line, 'groupe',
} $this->translator->trans('prestataire.groupe_notfound_created', [$groupe], 'import')
$prestataire->setGroupe($groupeFound); );
} else {
$this->addWarning($row, $line, 'groupe', 'empty');
} }
if (!empty($cotisations)) { $prestataire->setGroupe($groupeObj);
if ($cotisations = $row['cotisations']) {
$cotisationArray = explode(',', $cotisations); $cotisationArray = explode(',', $cotisations);
if (count($cotisationArray) > 0) {
foreach ($cotisationArray as $cotisationDetails) { foreach ($cotisationArray as $cotisationDetails) {
$cotisation = new CotisationPrestataire(); $cotisation = new CotisationPrestataire();
$now = new DateTime(); $now = new DateTime();
...@@ -512,7 +505,7 @@ class ImportController extends CRUDController ...@@ -512,7 +505,7 @@ class ImportController extends CRUDController
$cotisation->setMoyen(MoyenEnum::MOYEN_AUTRE); $cotisation->setMoyen(MoyenEnum::MOYEN_AUTRE);
$cotisationDetailsArray = explode(':', $cotisationDetails); $cotisationDetailsArray = explode(':', $cotisationDetails);
if (count($cotisationDetailsArray) == 1) { if (count($cotisationDetailsArray) == 1) {
$cotisation->setMontant(intval($cotisationDetails)); $cotisation->setMontant(intval($cotisationDetails[0]));
$cotisation->getCotisationInfos()->setDebut($now); $cotisation->getCotisationInfos()->setDebut($now);
$cotisation->getCotisationInfos()->setFin(new DateTime('+ 1 year')); $cotisation->getCotisationInfos()->setFin(new DateTime('+ 1 year'));
} else { } else {
...@@ -524,11 +517,11 @@ class ImportController extends CRUDController ...@@ -524,11 +517,11 @@ class ImportController extends CRUDController
$this->em->persist($cotisation); $this->em->persist($cotisation);
$this->addSuccess($row, $line, 'cotisations', $this->translator->trans('Cotisation ajouté : ').$groupe); $this->addSuccess($row, $line, 'cotisations', $this->translator->trans('Cotisation ajouté : ').$groupe);
} }
}
} else { } else {
$this->addWarning($row, $line, 'cotisations', 'empty'); $this->addWarning($row, $line, 'cotisations', 'empty');
} }
if (!empty($rubriques)) {
if ($rubriques = $row['rubriques']) {
$rubriquesArray = explode(',', $rubriques); $rubriquesArray = explode(',', $rubriques);
foreach ($rubriquesArray as $rubrique) { foreach ($rubriquesArray as $rubrique) {
$rubriquesFound = $this->em->getRepository(Rubrique::class)->findOneBy(array('slug' => $this->slugify($rubrique))); $rubriquesFound = $this->em->getRepository(Rubrique::class)->findOneBy(array('slug' => $this->slugify($rubrique)));
...@@ -543,7 +536,8 @@ class ImportController extends CRUDController ...@@ -543,7 +536,8 @@ class ImportController extends CRUDController
} else { } else {
$this->addWarning($row, $line, 'rubriques', 'empty'); $this->addWarning($row, $line, 'rubriques', 'empty');
} }
if (!empty($tags)) {
if ($tags = $row['tags']) {
$tagsArray = explode(',', $tags); $tagsArray = explode(',', $tags);
foreach ($tagsArray as $tag) { foreach ($tagsArray as $tag) {
$tagsFound = $this->em->getRepository(EtatPrestataire::class)->findOneBy(array('slug' => $this->slugify($tag))); $tagsFound = $this->em->getRepository(EtatPrestataire::class)->findOneBy(array('slug' => $this->slugify($tag)));
...@@ -557,36 +551,49 @@ class ImportController extends CRUDController ...@@ -557,36 +551,49 @@ class ImportController extends CRUDController
} else { } else {
$this->addWarning($row, $line, 'tags', 'empty'); $this->addWarning($row, $line, 'tags', 'empty');
} }
if (!empty($adresse) || !empty($cpostal) || !empty($ville)) {
/**
* Add a Geoloc for this Prestataire.
* At this point, 'adresse', 'cpostal' and 'ville' fields exist and are not empty.
*/
$geoloc = new Geoloc();
$geoloc->setEnabled(true);
$geoloc->setAdresse($row['adresse']);
$geoloc->setCpostal($row['cpostal']);
$geoloc->setVille($row['ville']);
$geolocP = new GeolocPrestataire(); $geolocP = new GeolocPrestataire();
$geolocP->setName('Adresse'); $geolocP->setName('Adresse');
$geolocP->setPrestataire($prestataire); $geolocP->setPrestataire($prestataire);
$geolocFound = new Geoloc(); $geolocP->setGeoloc($geoloc);
$geolocFound->setEnabled(true);
$geolocFound->setAdresse($adresse);
$geolocFound->setCpostal(intval($cpostal));
$geolocFound->setVille($ville);
$geolocP->setGeoloc($geolocFound);
$prestataire->setGeolocs([$geolocP]);
$this->em->persist($geolocP); $this->em->persist($geolocP);
}
$prestataire->setGeolocs([$geolocP]);
} else { } else {
$this->addError($row, $line, 'name', $this->translator->trans("Le prestataire avec cette raison '".$raison."' existe déjà !")); $this->addError($row, $line, 'raison',
$this->translator->trans('prestataire.already_exists', [$row['raison']], 'import')
);
$this->nberrors++; $this->nberrors++;
$hasError = true; $hasError = true;
} }
if (!$hasError) { if (!$hasError) {
$this->addSuccess($row, $line, 'user', $this->translator->trans('Prestataire bien ajouté : ').$prestataire->__toString());
$this->nbsuccess++;
$this->em->persist($prestataire); $this->em->persist($prestataire);
$this->em->flush(); $this->em->flush();
$this->em->clear(); $this->em->clear();
// em is fully cleared: we need to refetch entities we get from em during process // em is fully cleared: we need to refetch entities we get from em during process
$operateur = $this->em->getRepository(User::class)->findOneBy(array('id' => $operateur_id)); $operateur = $this->em->getRepository(User::class)->findOneById($operateur_id);
} $this->siege = $this->em->getRepository(Siege::class)->findOneById(1);
$line++; $this->addSuccess($row, $line, 'user',
$this->translator->trans('prestataire.added', [(string) $prestataire], 'import')
);
$this->nbsuccess++;
} }
}
ksort($this->errors); ksort($this->errors);
ksort($this->warnings); ksort($this->warnings);
} }
......
...@@ -11,7 +11,7 @@ trait ContactEmailTelTrait ...@@ -11,7 +11,7 @@ trait ContactEmailTelTrait
/** /**
* @var null|string * @var null|string
* *
* @ORM\Column(name="tel", type="string", length=20, nullable=true) * @ORM\Column(name="tel", type="string", length=100, nullable=true)
* @Groups({"read", "write"}) * @Groups({"read", "write"})
*/ */
protected $tel; protected $tel;
......
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20200925152216 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contact_comptoir CHANGE tel tel VARCHAR(100) DEFAULT NULL');
$this->addSql('ALTER TABLE contact_prestataire CHANGE tel tel VARCHAR(100) DEFAULT NULL');
$this->addSql('ALTER TABLE groupeprestaire CHANGE tel tel VARCHAR(100) DEFAULT NULL');
$this->addSql('ALTER TABLE siege CHANGE ecompte ecompte NUMERIC(12, 2) DEFAULT \'0\' NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contact_comptoir CHANGE tel tel VARCHAR(20) CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci`');
$this->addSql('ALTER TABLE contact_prestataire CHANGE tel tel VARCHAR(20) CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci`');
$this->addSql('ALTER TABLE groupeprestaire CHANGE tel tel VARCHAR(20) CHARACTER SET utf8 DEFAULT NULL COLLATE `utf8_general_ci`');
$this->addSql('ALTER TABLE siege CHANGE ecompte ecompte NUMERIC(12, 2) NOT NULL');
}
}
prestataire:
already_exists: 'Le prestataire avec la raison "0" existe déjà !'
column_required: 'La colonne "0" ne doit pas être vide'
groupe_notfound_created: 'Création du groupe "0" car introuvable'
added: 'Prestaitaire bien ajouté : 0'
prestataire:
already_exists: 'Le prestataire avec la raison "0" existe déjà !'
column_required: 'La colonne "0" ne doit pas être vide'
groupe_notfound_created: 'Création du groupe "0" car introuvable'
added: 'Prestaitaire bien ajouté : 0'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment