Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/Command/ImportSignalementCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$io->warning($msg);
}
if (\count($metadata['desordres_not_found'])) {
$msg = [];
foreach ($metadata['desordres_not_found'] as $desordreNotFound => $nbSignalement) {
$msg[] = \sprintf('Desordre "%s" not found on %s signalement(s)', $desordreNotFound, $nbSignalement);
}
$io->warning($msg);
}
if ($this->signalementImportLoader->hasErrors()) {
$io->error('Des erreurs ont été détectées, l\'import est annulé. Veuillez corriger les erreurs et relancer l\'import.');

return Command::FAILURE;
}
$io->success(\sprintf('%s signalement(s) have been imported', $metadata['count_signalement']));

return Command::SUCCESS;
Expand Down
203 changes: 123 additions & 80 deletions src/Service/Import/Signalement/SignalementImportLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
namespace App\Service\Import\Signalement;

use App\Entity\Affectation;
use App\Entity\Critere;
use App\Entity\Criticite;
use App\Entity\Enum\AffectationStatus;
use App\Entity\Enum\MotifCloture;
use App\Entity\Enum\OccupantLink;
use App\Entity\Enum\ProfileDeclarant;
use App\Entity\Enum\SuiviCategory;
use App\Entity\File;
use App\Entity\Partner;
use App\Entity\Signalement;
use App\Entity\Suivi;
use App\Entity\Territory;
Expand All @@ -24,6 +22,7 @@
use App\Manager\UserSignalementSubscriptionManager;
use App\Repository\CritereRepository;
use App\Repository\CriticiteRepository;
use App\Repository\PartnerRepository;
use App\Service\Signalement\CriticiteCalculator;
use App\Service\Signalement\Qualification\SignalementQualificationUpdater;
use Doctrine\Common\Collections\ArrayCollection;
Expand Down Expand Up @@ -57,16 +56,21 @@ class SignalementImportLoader
* partners_not_found: array<string, int>,
* motif_cloture_not_found: array<string, int>,
* files_not_found: array<string, string>,
* desordres_not_found: array<string, int>,
* }
*/
private array $metadata = [
'count_signalement' => 0,
'partners_not_found' => [],
'motif_cloture_not_found' => [],
'files_not_found' => [],
'desordres_not_found' => [],
];

private ?User $userSystem = null;
private array $indexedCriteres = [];
private array $indexedCriticites = [];
private array $indexedPartners = [];

public function __construct(
private SignalementImportMapper $signalementImportMapper,
Expand All @@ -84,6 +88,9 @@ public function __construct(
#[Autowire(service: 'html_sanitizer.sanitizer.app.message_sanitizer')]
private HtmlSanitizerInterface $htmlSanitizer,
private UserSignalementSubscriptionManager $userSignalementSubscriptionManager,
private readonly CritereRepository $critereRepository,
private readonly CriticiteRepository $criticiteRepository,
private readonly PartnerRepository $partnerRepository,
) {
}

Expand All @@ -97,67 +104,86 @@ public function __construct(
public function load(Territory $territory, array $data, array $headers, ?OutputInterface $output = null): void
{
$countSignalement = 0;
$this->userSystem = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $this->parameterBag->get('user_system_email')]);
if ($output) {
$progressBar = new ProgressBar($output);
$progressBar->start(\count($data));
$output->writeln('Vérification des données à importer.');
}

$this->userSystem = $this->entityManager->getRepository(User::class)->findOneBy(
[
'email' => $this->parameterBag->get('user_system_email'), ]
);

$dataMappedOk = [];
foreach ($data as $item) {
$dataMapped = $this->signalementImportMapper->map($headers, $item);
if (!empty($dataMapped)) {
++$countSignalement;
if ($output) {
$progressBar->advance();
}
$signalement = $this->signalementManager->createOrUpdateFromArrayForImport($territory, $dataMapped);
if (!$signalement->getProfileDeclarant()) {
if (!$signalement->getIsNotOccupant()) {
$signalement->setProfileDeclarant(ProfileDeclarant::LOCATAIRE);
} elseif (OccupantLink::PRO->name == mb_strtoupper($signalement->getLienDeclarantOccupant())) {
$signalement->setProfileDeclarant(ProfileDeclarant::TIERS_PRO);
} else {
$signalement->setProfileDeclarant(ProfileDeclarant::TIERS_PARTICULIER);
}
$dataMappedToCheck = $this->signalementImportMapper->map($headers, $item);
if (empty($dataMappedToCheck)) {
continue;
}
foreach (self::SITUATIONS as $situation) {
$this->loadSignalementSituation($dataMappedToCheck, $situation);
}
$this->loadAffectation($territory, $dataMappedToCheck);
$this->loadFiles($dataMappedToCheck['photos']);
$this->loadFiles($dataMappedToCheck['documents']);
if ($dataMappedToCheck['motifCloture'] && !MotifCloture::tryFrom($dataMappedToCheck['motifCloture'])) {
if (!isset($this->metadata['motif_cloture_not_found'][$dataMappedToCheck['motifCloture']])) {
$this->metadata['motif_cloture_not_found'][$dataMappedToCheck['motifCloture']] = 0;
}
$this->signalementManager->save($signalement);
++$this->metadata['motif_cloture_not_found'][$dataMappedToCheck['motifCloture']];
}
$dataMappedOk[] = $dataMappedToCheck;
}

$signalement = $this->loadTags($signalement, $territory, $dataMapped);
foreach (self::SITUATIONS as $situation) {
$signalement = $this->loadSignalementSituation($signalement, $dataMapped, $situation);
}
if ($this->hasErrors()) {
$this->logger->info('Des erreurs ont été détectées, l\'import est annulé.');

$signalement->setScore($this->criticiteCalculator->calculate($signalement));
$this->signalementQualificationUpdater->updateQualificationFromScore($signalement);
return;
}

$affectationCollection = $this->loadAffectation($signalement, $territory, $dataMapped);
foreach ($affectationCollection as $affectation) {
$signalement->addAffectation($affectation);
}
if ($output) {
$output->writeln('Aucune erreur détectée, lancement de l\'import.');
$progressBar = new ProgressBar($output);
$progressBar->start(\count($dataMappedOk));
}

$suiviCollection = $this->loadSuivi($signalement, $dataMapped);
foreach ($suiviCollection as $suivi) {
$signalement->addSuivi($suivi);
foreach ($dataMappedOk as $dataMapped) {
++$countSignalement;
$signalement = $this->signalementManager->createOrUpdateFromArrayForImport($territory, $dataMapped);
if (!$signalement->getProfileDeclarant()) {
if (!$signalement->getIsNotOccupant()) {
$signalement->setProfileDeclarant(ProfileDeclarant::LOCATAIRE);
} elseif (OccupantLink::PRO->name == mb_strtoupper($signalement->getLienDeclarantOccupant())) {
$signalement->setProfileDeclarant(ProfileDeclarant::TIERS_PRO);
} else {
$signalement->setProfileDeclarant(ProfileDeclarant::TIERS_PARTICULIER);
}
}
$this->signalementManager->save($signalement);

$this->loadFiles($signalement, $dataMapped['photos']);
$this->loadFiles($signalement, $dataMapped['documents']);
$this->loadTags($signalement, $territory, $dataMapped);
foreach (self::SITUATIONS as $situation) {
$this->loadSignalementSituation($dataMapped, $situation, $signalement);
}

$this->metadata['count_signalement'] = $countSignalement;
if (0 === $countSignalement % self::FLUSH_COUNT) {
$this->logger->info(\sprintf('in progress - %s signalements saved', $countSignalement));
$this->signalementManager->flush();
}
if ($dataMapped['motifCloture'] && !MotifCloture::tryFrom($dataMapped['motifCloture'])) {
if (!isset($this->metadata['motif_cloture_not_found'][$dataMapped['motifCloture']])) {
$this->metadata['motif_cloture_not_found'][$dataMapped['motifCloture']] = 1;
}
++$this->metadata['motif_cloture_not_found'][$dataMapped['motifCloture']];
}
$signalement->setScore($this->criticiteCalculator->calculate($signalement));
$this->signalementQualificationUpdater->updateQualificationFromScore($signalement);

$affectationCollection = $this->loadAffectation($territory, $dataMapped, $signalement);
foreach ($affectationCollection as $affectation) {
$signalement->addAffectation($affectation);
}

$suiviCollection = $this->loadSuivi($signalement, $dataMapped);
foreach ($suiviCollection as $suivi) {
$signalement->addSuivi($suivi);
}

$this->loadFiles($dataMapped['photos'], signalement: $signalement);
$this->loadFiles($dataMapped['documents'], signalement: $signalement);

$this->metadata['count_signalement'] = $countSignalement;
if (0 === $countSignalement % self::FLUSH_COUNT) {
$this->logger->info(\sprintf('in progress - %s signalements saved', $countSignalement));
$this->signalementManager->flush();
}
if ($output) {
$progressBar->advance();
}
}

Expand All @@ -173,32 +199,39 @@ public function load(Territory $territory, array $data, array $headers, ?OutputI
* partners_not_found: array<string, int>,
* motif_cloture_not_found: array<string, int>,
* files_not_found: array<string, string>,
* desordres_not_found: array<string, int>,
* }
*/
public function getMetadata(): array
{
return $this->metadata;
}

public function hasErrors(): bool
{
return \count($this->metadata['partners_not_found']) > 0
|| \count($this->metadata['motif_cloture_not_found']) > 0
|| \count($this->metadata['files_not_found']) > 0
|| \count($this->metadata['desordres_not_found']) > 0;
}

/**
* @param array<string, mixed> $dataMapped
*/
private function loadTags(Signalement $signalement, Territory $territory, array $dataMapped): Signalement
private function loadTags(Signalement $signalement, Territory $territory, array $dataMapped): void
{
if (isset($dataMapped['tags']) && !empty($dataMapped['tags'])) {
$tag = $this->tagManager->createOrGet($territory, $dataMapped['tags']);
$signalement->addTag($tag);
}

return $signalement;
}

/**
* @param array<string, mixed> $dataMapped
*
* @return ArrayCollection<int, Affectation>
*/
private function loadAffectation(Signalement $signalement, Territory $territory, array $dataMapped): ArrayCollection
private function loadAffectation(Territory $territory, array $dataMapped, ?Signalement $signalement = null): ArrayCollection
{
$affectationCollection = new ArrayCollection();
if (isset($dataMapped['partners']) && !empty($dataMapped['partners'])) {
Expand All @@ -211,17 +244,20 @@ private function loadAffectation(Signalement $signalement, Territory $territory,
}
foreach ($partnersName as $partnerName) {
$partnerNameCleaned = mb_trim(preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $partnerName)); // remove non printable chars
$partner = $this->entityManager->getRepository(Partner::class)->findOneBy([
'nom' => $partnerNameCleaned,
'territory' => $territory,
]);
if (!array_key_exists($partnerNameCleaned, $this->indexedPartners)) {
$this->indexedPartners[$partnerNameCleaned] = $this->partnerRepository->findOneBy(['nom' => $partnerNameCleaned, 'territory' => $territory]);
}
$partner = $this->indexedPartners[$partnerNameCleaned];
if (!$partner) {
if (!isset($this->metadata['partners_not_found'][$partnerNameCleaned])) {
$this->metadata['partners_not_found'][$partnerNameCleaned] = 1;
$this->metadata['partners_not_found'][$partnerNameCleaned] = 0;
}
++$this->metadata['partners_not_found'][$partnerNameCleaned];
continue;
}
if (!$signalement) {
continue;
}

$affectation = $this->affectationManager->createAffectationFrom(
signalement: $signalement,
Expand Down Expand Up @@ -256,42 +292,46 @@ private function loadAffectation(Signalement $signalement, Territory $territory,
* @param array<string, mixed> $dataMapped
*/
private function loadSignalementSituation(
Signalement $signalement,
array $dataMapped,
string $situation,
): Signalement {
?Signalement $signalement = null,
): void {
if (isset($dataMapped[$situation]) && !empty($dataMapped[$situation])) {
foreach ($dataMapped[$situation] as $critereLabel => $etat) {
/** @var CritereRepository $critereRepository */
$critereRepository = $this->entityManager->getRepository(Critere::class);

/** @var Critere $critere */
$critere = $critereRepository->findByLabel(trim($critereLabel));
$critereLabel = trim($critereLabel);
if (!array_key_exists($critereLabel, $this->indexedCriteres)) {
/* @var Critere $critere */
$this->indexedCriteres[$critereLabel] = $this->critereRepository->findByLabel($critereLabel);
}
try {
if (null !== $critere) {
if (null !== $this->indexedCriteres[$critereLabel]) {
/** @var Criticite $criticite */
$criticite = $critere->getCriticites()->filter(function (Criticite $criticite) use ($etat) {
return $criticite->getScore() === Criticite::ETAT_LABEL[trim($etat)];
$criticite = $this->indexedCriteres[$critereLabel]->getCriticites()->filter(function (Criticite $c) use ($etat) {
return $c->getScore() === Criticite::ETAT_LABEL[trim($etat)];
})->first();
} else {
/** @var CriticiteRepository $criticiteRepository */
$criticiteRepository = $this->entityManager->getRepository(Criticite::class);
$criticites = $criticiteRepository->findByLabel(trim($critereLabel));
$criticite = !empty($criticites) ? $criticites[0] : null;
$critere = $criticite?->getCritere();
if (!array_key_exists($critereLabel, $this->indexedCriticites)) {
$this->indexedCriticites[$critereLabel] = $this->criticiteRepository->findByLabel($critereLabel);
}
$criticite = !empty($this->indexedCriticites[$critereLabel]) ? $this->indexedCriticites[$critereLabel][0] : null;
}

if (null !== $criticite) {
$signalement
->addCriticite($criticite);
if ($signalement) {
$signalement->addCriticite($criticite);
}
} else {
if (!isset($this->metadata['desordres_not_found'][$critereLabel])) {
$this->metadata['desordres_not_found'][$critereLabel] = 0;
}
++$this->metadata['desordres_not_found'][$critereLabel];
continue;
}
} catch (\Throwable $exception) {
$this->logger->error($critereLabel.' - '.$exception->getMessage());
}
}
}

return $signalement;
}

/**
Expand Down Expand Up @@ -335,7 +375,7 @@ private function loadSuivi(Signalement $signalement, array $dataMapped): ArrayCo
return $suiviCollection;
}

private function loadFiles(Signalement $signalement, string $data): void
private function loadFiles(string $data, ?Signalement $signalement = null): void
{
if (empty($data)) {
return;
Expand All @@ -351,6 +391,9 @@ private function loadFiles(Signalement $signalement, string $data): void
$this->metadata['files_not_found'][$filename] = $filename;
continue;
}
if (!$signalement) {
continue;
}

$file = $this->fileManager->createOrUpdate(
filename: $filename,
Expand Down
Loading
Loading