Commit 5f4985db authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

- Possibilité d'importer plusieurs disciplines en utilisant le séparateur "#"

- DOC : Importation des activités mise à jour
parent aafbde95
Loading
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -86,7 +86,11 @@ Le fichier source est au [format JSON]([http://json.org/). Un échantillon de ce
        "John Doe",
        "Marcel Grossmann"
      ]
    }
    },
    "disciplines": [
      "Physique",
      "Chimie"
    ]
  }
]
```
@@ -119,6 +123,7 @@ organizations | Object | Oui | Non | Voir détails dans [Gestion d
persons         | Object    | Oui       | Non    | Voir détails dans [Gestion des personnes](#persons)
milestones      | Array     | Oui       | Non    | Voir détails dans [Gestion des jalons](#milestones)
payments        | Array     | Oui       | Non    | Voir détails dans [Gestion des versements](#payments)
disciplines        | Array     | Oui       | Non    | Voir détails dans [Gestion des disciplines](#disciplines)


```json
@@ -329,11 +334,16 @@ Ces objets contiennent une clef `date` qui contiendra une Date ISO correspondant
> Les versements sans valeur dans la clef `date` mais avec une clef `predicted` seront tagués comme prévisionnels.


## La clef TVA (float, ex: 19.6)
<a id="disciplines"></a>
### La clef disciplines (array de string)

La valeur doit correspondre à un taux présent dans la base de données (table `tva`)
La clef `disciplines` permet de spécifier une ou plusieurs disciplines a associer à l'activité. Le séparateur `#` dans la source CSV permet de gérer plusieurs disciplines : La valeur `Physique#Chimie` donnera `["Physique","Chimie"]. 

> Si la discipline est manquante, elle sera créée.

## La clef TVA (float, ex: 19.6)

La valeur doit correspondre à un taux présent dans la base de données (table `tva`)


## Currency (string, ex: €)
@@ -402,7 +412,8 @@ return [
    27  => "financialImpact",
    28  => "currency",
    29  => "assietteSubventionnable",
    30  => "status"
    30  => "status",
    31 => "disciplines"
];
```

@@ -528,7 +539,7 @@ On obtiendra en JSON :

### payments.POSITIONS

La clef `payments` indique l'emplacement du montant du versement et prends comme premier paramètre la date prévue du versement, et en deuxième paramêtre la date effective souf la forme `payments.PREVU.EFFECTIF`.
La clef `payments` indique l'emplacement du montant du versement et prends comme premier paramètre la date prévue du versement, et en deuxième paramêtre la date effective sous la forme `payments.PREVU.EFFECTIF`.

#### Exemple 1

+11 −4
Original line number Diff line number Diff line
@@ -62,12 +62,12 @@ class OscarActivityCsvToJsonCommand extends OscarCommandAbstract


        if (!is_file($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas un fichier... faites un effort.",
            throw new OscarException(sprintf("Le chemin '%s' n'est pas un fichier...",
                $realpath));
        }

        if (!is_readable($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas lisible....",
            throw new OscarException(sprintf("Le chemin '%s' n'est pas lisible...",
                $realpath));
        }

@@ -84,8 +84,6 @@ class OscarActivityCsvToJsonCommand extends OscarCommandAbstract

        $io = new SymfonyStyle($input, $output);

        $io->title("Conversion CSV > JSON des activités");

        ///////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////// SERVICES
        /** @var OscarConfigurationService $oscarConfig */
@@ -100,6 +98,15 @@ class OscarActivityCsvToJsonCommand extends OscarCommandAbstract

        // Fichiers
        try {

            $optFichier = $input->getOption('fichier');
            $optConfig = $input->getOption('config');

            if( !$optConfig || !$optFichier ){
                $io->error("Les options --fichier <SOURCE CSV> et --config <FICHIER PHP> sont requises");
                return 0;
            }

            $sourceFilePath = $this->getReadablePath($input->getOption('fichier'));
            $configurationFilePath = $this->getReadablePath($input->getOption('config'));
            $skip = $input->getOption('skip');
+87 −35
Original line number Diff line number Diff line
@@ -43,26 +43,55 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
    {
        $this
            ->setDescription("Synchronisation d'activité de recherche à partir d'un fichier JSON")
            ->addOption('fichier', 'f', InputOption::VALUE_REQUIRED, 'Fichier JSON')
        ;

        $this->addOption('create-missing-project', 'p', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les projets manquants",false);
            ->addOption('fichier', 'f', InputOption::VALUE_REQUIRED, 'Fichier JSON');

        $this->addOption(
            'create-missing-project',
            'p',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les projets manquants",
            false
        );
//
        $this->addOption('create-missing-person', 'e', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les personnes manquantes",false);

        $this->addOption('create-missing-person-role', 'r', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des personnes manquants",false);

        $this->addOption('create-missing-organization', 'o', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les organisations manquantes",false);

        $this->addOption('create-missing-organization-role', 'l', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des organisations manquants",false);

        $this->addOption('create-missing-activity-type', 'y', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les types d'activités manquantes",false);
        $this->addOption(
            'create-missing-person',
            'e',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les personnes manquantes",
            false
        );

        $this->addOption(
            'create-missing-person-role',
            'r',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des personnes manquants",
            false
        );

        $this->addOption(
            'create-missing-organization',
            'o',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les organisations manquantes",
            false
        );

        $this->addOption(
            'create-missing-organization-role',
            'l',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des organisations manquants",
            false
        );

        $this->addOption(
            'create-missing-activity-type',
            'y',
            InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les types d'activités manquantes",
            false
        );
    }

    private function getReadablePath($path)
@@ -70,19 +99,31 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
        $realpath = realpath($path);

        if (!$realpath) {
            throw new OscarException(sprintf("Le chemin '%s' n'a aucun sens...",
                $path));
            throw new OscarException(
                sprintf(
                    "Le chemin '%s' n'a aucun sens...",
                    $path
                )
            );
        }


        if (!is_file($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas un fichier... faites un effort.",
                $realpath));
            throw new OscarException(
                sprintf(
                    "Le chemin '%s' n'est pas un fichier...",
                    $realpath
                )
            );
        }

        if (!is_readable($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas lisible....",
                $realpath));
            throw new OscarException(
                sprintf(
                    "Le chemin '%s' n'est pas lisible...",
                    $realpath
                )
            );
        }

        return $realpath;
@@ -125,7 +166,10 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
            'create-missing-person' => $input->getOption('create-missing-person', false) !== false,
            'create-missing-person-role' => $input->getOption('create-missing-person-role', false) !== false,
            'create-missing-organization' => $input->getOption('create-missing-organization', false) !== false,
            'create-missing-organization-role' => $input->getOption('create-missing-organization-role', false) !== false,
            'create-missing-organization-role' => $input->getOption(
                    'create-missing-organization-role',
                    false
                ) !== false,
            'create-missing-activity-type' => $input->getOption('create-missing-activity-type', false) !== false,
        ];

@@ -143,8 +187,10 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
            $correspondanceRolesActivites = [];
            /** @var Role $role */
            foreach ($rolesPersons as $role) {
                $correspondanceRolesActivites[$role] = array_search($role,
                    $headers);
                $correspondanceRolesActivites[$role] = array_search(
                    $role,
                    $headers
                );
            }

            // Construction de la correspondance role > colonne
@@ -152,12 +198,16 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
            $correspondanceRolesOrga = [];
            /** @var OrganizationRole $role */
            foreach ($rolesOrganizations as $role) {
                $correspondanceRolesOrga[$role->getLabel()] = array_search($role->getLabel(),
                    $headers);
                $correspondanceRolesOrga[$role->getLabel()] = array_search(
                    $role->getLabel(),
                    $headers
                );
            }

            $converteur = new ActivityCSVToObject($correspondanceRolesActivites,
                $correspondanceRolesOrga);
            $converteur = new ActivityCSVToObject(
                $correspondanceRolesActivites,
                $correspondanceRolesOrga
            );
            $json = $converteur->convert($file);
        } elseif ($fileExtension == "json") {
            $json = json_decode(file_get_contents($file));
@@ -165,8 +215,10 @@ class OscarActivityImportJsonCommand extends OscarCommandAbstract
            die("ERROR : Format non pris en charge.");
        }

        $importer = new ConnectorActivityJSON($json, $entityManager,
            $options);
        $importer = new ConnectorActivityJSON(
            $json, $entityManager,
            $options
        );
        $repport = $importer->syncAll();

        $output = new ConnectorRepportToPlainText();
+78 −51
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
            case "project":
                return new FieldImportProjectStrategy($this->entityManager);
            case "persons":
                return NEW FieldImportPersonStrategy($this->entityManager, $split[1]);
                return new FieldImportPersonStrategy($this->entityManager, $split[1]);
            case "organizations":
                return new FieldImportOrganizationStrategy($this->entityManager, $split[1]);
            case "payments":
@@ -131,12 +131,14 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
    protected function getHandler($index)
    {
        // Si la clef n'existe pas dans la conf on ne fait rien
        if (!array_key_exists($index, $this->config))
        if (!array_key_exists($index, $this->config)) {
            return;
        }

        // Si la clef existe mais que la valeur de conf est vide on passe
        if (!$this->config[$index])
        if (!$this->config[$index]) {
            return;
        }

        // Si la clef est une chaîne, on détermine si c'est un appel de setter
        // simple ou un mécanisme plus "avancé"
@@ -146,7 +148,6 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface

        // Chaîne
        if (is_string($key)) {

            // Chaîne : setter avancé
            if (stripos($key, '.') > 0) {
                return $this->getHandlerByKey($key);
@@ -182,7 +183,9 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
            $values = explode($separator, $value);
            foreach ($values as $v) {
                $extracted = trim($v);
                if ($extracted != "") $out[] = trim($v);
                if ($extracted != "") {
                    $out[] = trim($v);
                }
            }
        }
        return $out;
@@ -198,7 +201,6 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface

        $i = 1;
        while ($datas = fgetcsv($this->csvDatas)) {

            $json = [
                "uid" => 'LN-' . ($i++),
                "organizations" => [],
@@ -210,7 +212,14 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
                "currency" => null,
                "assietteSubventionnable" => null,
                "financialImpact" => null,
                "disciplines" => []
                "disciplines" => [],
                "datepfi" => null,
                "datestart" => null,
                "dateend" => null,
                "amount" => null,
                "datePFI" => null,
                "datesigned" => null,
                "pfi" => null,
            ];

            foreach ($datas as $index => $value) {
@@ -240,6 +249,7 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
                    $separator = $this->config[$index]['separator'];
                }

                // ORGANIZATIONS
                if (preg_match("/organizations\.(.*)/", $key, $matches)) {
                    $role = $matches[1];

@@ -248,9 +258,13 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
                        $json['organizations'][$role] = [];
                    }
                    if (!in_array($value, $json['organizations'][$role])) {
                        $json['organizations'][$role] = array_merge($json['organizations'][$role], $this->extractArrayString($value, $separator));
                        $json['organizations'][$role] = array_merge(
                            $json['organizations'][$role],
                            $this->extractArrayString($value, $separator)
                        );
                    }
                } else if (preg_match("/persons\.(.*)/", $key, $matches)) {
                } // PERSONS
                elseif (preg_match("/persons\.(.*)/", $key, $matches)) {
                    $role = $matches[1];

                    // Création de la clef si besoin
@@ -258,15 +272,19 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
                        $json['persons'][$role] = [];
                    }
                    if (!in_array($value, $json['persons'][$role])) {
                        $json['persons'][$role] = array_merge($json['persons'][$role], $this->extractArrayString($value, $separator));
                        $json['persons'][$role] = array_merge(
                            $json['persons'][$role],
                            $this->extractArrayString($value, $separator)
                        );
                    }
                } else if (preg_match("/milestones\.(.*)/", $key, $matches)) {
                } // JALONS
                elseif (preg_match("/milestones\.(.*)/", $key, $matches)) {
                    $json['milestones'][] = [
                        "type" => $matches[1],
                        "date" => $value
                    ];
                } else if (preg_match("/payments\.([\-.\d]*)/", $key, $matches)) {

                } // VERSEMENTS
                elseif (preg_match("/payments\.([\-.\d]*)/", $key, $matches)) {
                    $datesPos = explode('.', $matches[1]);

                    // Calcule des positions pour les données
@@ -287,59 +305,64 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
                        "date" => $paymentDatePayment,
                        "predicted" => $paymentDatePredicted,
                    ];
                }

                // PFI
                } // PFI
                elseif ($key == "currency") {
                    $json['currency'] = $value;
                }

                } // TVA
                elseif ($key == "tva") {
                    $json['tva'] = floatval(str_replace(',', '.', $value));
                }

                } // assietteSubventionnable
                elseif ($key == "assietteSubventionnable") {
                    $json['assietteSubventionnable'] = (float)$value;
                }

                } // financialImpact
                elseif ($key == "financialImpact") {
                    $json['financialImpact'] = $value;
                }

                // PFI
                } // PFI
                elseif ($key == "PFI") {
                    $json['pfi'] = $value;
                }

                } // Status
                elseif ($key == "status") {
                    $json['status'] = $value;
                }
                } // Disciplines
                elseif ($key == "disciplines") {
                    if( !in_array($value, $json['disciplines']) ){
                        $json['disciplines'][] = $value;
                    $findDisciplines = explode('#', $value);
                    foreach ($findDisciplines as $discipline) {
                        if (!in_array($discipline, $json['disciplines'])) {
                            $json['disciplines'][] = $discipline;
                        }
                    }
                } // datePFI
                elseif ($key == "datePFI") {
                    $json['datepfi'] = $value;
                } else if ($key == "type") {
                } // Type
                elseif ($key == "type") {
                    $json['type'] = $value;
                } else if ($key == "amount") {
                } // Type
                elseif ($key == "amount") {
                    $json['amount'] = doubleval($value);
                } else if ($key == "dateStart") {
                } // dateStart
                elseif ($key == "dateStart") {
                    $json['datestart'] = $value;
                } else if ($key == "dateEnd") {
                } // dateEnd
                elseif ($key == "dateEnd") {
                    $json['dateend'] = $value;
                } else if ($key == "dateSigned") {
                } // dateSigned
                elseif ($key == "dateSigned") {
                    $json['datesigned'] = $value;
                } else if ($key == "label") {
                } // label
                elseif ($key == "label") {
                    $json['label'] = $value;
                } else if ($key == "description") {
                } // description
                elseif ($key == "description") {
                    $json['description'] = $value;
                } else if ($key == "uid") {
                } // uid
                elseif ($key == "uid") {
                    $json['uid'] = $value;
                } else if ($key == "project.acronym") {
                } // project
                elseif ($key == "project.acronym") {
                    $json['acronym'] = $value;
                } else if ($key == "project.label") {
                } // project
                elseif ($key == "project.label") {
                    $json['projectlabel'] = $value;
                } else {
                    throw new OscarException("La clef '$key' n'est pas géré dans la configuration");
@@ -363,9 +386,13 @@ class ConnectorActivityCSVWithConf implements ConnectorInterface
     */
    protected function getCheckedDateString($string)
    {
        if ($string == "") return "";
        if ($string == "") {
            return "";
        }
        if (!preg_match('/(\d{4})-(\d{2})-(\d{2})/', $string)) {
            throw new OscarException("Format de date '$string' inattendu, assurez vous que la forme ISO YYYY-MM-JJ est respectée.");
            throw new OscarException(
                "Format de date '$string' inattendu, assurez vous que la forme ISO YYYY-MM-JJ est respectée."
            );
        }
        $date = new \DateTime($string);
        return $date->format('Y-m-d');
+3 −4
Original line number Diff line number Diff line
@@ -443,8 +443,8 @@ class ConnectorActivityJSON implements ConnectorInterface
            // Projet de l'activité
            $projectAcronym = $data->acronym;

            if ($data->project || $data->projectlabel) {
                $projectLabel = $data->project ?: $data->projectlabel;
            if ($data->projectlabel) {
                $projectLabel = $data->projectlabel;
            }


@@ -491,7 +491,6 @@ class ConnectorActivityJSON implements ConnectorInterface
                $status = Activity::STATUS_ERROR_STATUS;
            }


            $activity
                ->setLabel($this->getPropertyObject($data, 'label'))
                ->setDescription($this->getPropertyObject($data, 'description', false))
@@ -506,7 +505,7 @@ class ConnectorActivityJSON implements ConnectorInterface
                ->setStatus($status)
                ->setAmount(((double)$data->amount));

            if ($data->datestart) {
            if (property_exists($data, 'datestart') ){
                try {
                    $dateStart = new \DateTime($data->datestart);
                } catch (\Exception $e) {