Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ajout d'un outil de sélection spatiale et d'export pour publipostage pour les parcelles #97

Merged
merged 6 commits into from
Dec 18, 2023
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ tests/lizmap/qgis-server-plugins/
tests/lizmap/cache-python
tests/lizmap/local-python
tests/sql/majic/*.sql

# dev tools
*.code-workspace

# QGIS useless files
*_attachments.zip
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

## Unreleased


## 2.1.0 - 2023-12-18

### Added

* Panneau de recherche : ajout d'un onglet "Recherche spatiale" qui permet de sélectionner
les parcelles par croisement avec les objets sélectionnés d'une autre couche.
* Choix de la couche PostgreSQL de croisement (elle doit être dans la même base que la couche des Parcelles)
* Choix du tampon en mètres à utiliser pour rechercher les parcelles à partir des objets
* Choix optionnel du champ à ajouter à l'export CSV
* Ajout de 2 boutons qui permettent d'exporter la liste des propriétaires des parcelles sélectionnées

### Fixed

* Correction de l'affichage de la barre d'outil cadastre sur la popup des parcelles

## 2.0.5 - 2023-10-31

### Fixed
Expand All @@ -18,7 +34,7 @@
### Fixed

* Amélioration de la recherche des parcelles
* Utilisation du cache handler de projet
* Utilisation du cache handler de projet
* Amélioration des recherches par autocomplétion
* Amélioration de la recherche par section
* Amélioration du zoom lors de la recherche
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ php-cs-fixer-apply:
php-cs-fixer fix --config=.php-cs-fixer.dist.php

php-cs-fixer-apply-docker:
docker run --rm -it -w=/app -v ${PWD}:/app oskarstark/php-cs-fixer-ga:3.12.0 --allow-risky=yes --config=.php-cs-fixer.dist.php
docker run --rm -it -w=/app -v ${PWD}:/app oskarstark/php-cs-fixer-ga:latest --allow-risky=yes --config=.php-cs-fixer.dist.php
9 changes: 8 additions & 1 deletion cadastre/classes/cadastre.listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ public function ongetMapAdditions($event)
$jscode = array();
$css = array();

if ($hasCadastreConfig) {
// Add the cadastre config only if at least one right is granted
$hasEnoughRights = (
jAcl2::check('cadastre.use.search.tool')
|| jAcl2::check('cadastre.acces.donnees.proprio')
|| jAcl2::check('cadastre.acces.donnees.proprio.simple')
);

if ($hasCadastreConfig && $hasEnoughRights) {
$js = array(
jUrl::get('jelix~www:getfile', array('targetmodule' => 'cadastre', 'file' => 'cadastre.js')),
);
Expand Down
44 changes: 44 additions & 0 deletions cadastre/classes/cadastreDockable.listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,50 @@ public function onmapDockable($event)
$hasMajic = '1';
}
$searchForm->setData('has_majic', $hasMajic);

// Add the PostgreSQL layers of the same database in the 3rd search tab "Spatial"
if ($hasMajic == '1') {
// Get the project
$p = lizmap::getProject($event->repository . '~' . $event->project);
if ($p === null) {
throw new Exception("Spatial search: Unknown repository/project {$event->repository}.'~'.{$event->project}");
}

// Get the PostgreSQL database info of the Parcelle layer
/** @var \qgisVectorLayer $parcelleLayer The QGIS vector layer instance */
$parcelleLayer = $p->getLayer($parcelleId);
$parcelleProfile = $parcelleLayer->getDatasourceProfile(30, false);

// Get the list of PostgreSQL layers
$layers = array();
foreach ($p->getLayers() as $layer) {
/** @var \qgisVectorLayer $qgisLayer The QGIS vector layer instance */
$qgisLayer = $p->getLayer($layer->id);
// Only for existing layers
if (!$qgisLayer) {
continue;
}
// Not the parcelle layer itself
if ($qgisLayer->getId() == $parcelleId) {
continue;
}
// Only PostgreSQL layers
if ($qgisLayer->getProvider() != 'postgres') {
continue;
}
// Check if the database is the same as the Parcelle layer
if ($qgisLayer->getDatasourceProfile(30, false) != $parcelleProfile) {
continue;
}
$layers[$layer->id] = $layer->name;
}

// Add the list of spatial layers in the combobox
$datasource = new \jFormsStaticDatasource();
$datasource->data = $layers;
$searchForm->getControl('spatial_layer_id')->datasource = $datasource;
}

$assign = array(
'form' => $searchForm,
'has_majic' => $hasMajic,
Expand Down
182 changes: 182 additions & 0 deletions cadastre/classes/cadastreExtraInfos.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,160 @@ protected function getLocauxAndProprioSql($parcelle_ids, $withGeom = false, $for
return $sql;
}

/**
* Get SQL request to get parcelles and proprios data for parcelle ids.
*
* @param array $parcelle_ids The ids of parcelles
* @param bool $withGeom With geometry data (optional)
* @param bool $forThirdParty Without infos for third party (optional)
* @param null|array $intersectionData If the query must compute list of item codes from the intersected layer
*
* @return string The SQL
*/
protected function getParcellesAndProprioSql($parcelle_ids, $withGeom = false, $forThirdParty = false, $intersectionData = null)
{
$hasIntersectionData = ($intersectionData !== null && is_array($intersectionData));

$sql = "
--SET SEARCH_PATH TO cadastre_caen, public;

SELECT
-- commune
c.libcom AS commune,
-- proprio
pr.dnuper AS code_proprietaire,
trim(pr.dqualp) AS qualite,
trim(pr.dnomus) AS nom,
trim(pr.dprnus) AS prenom,
-- on ne garde que le nom d'usage
--trim(pr.dnomlp) AS nom,
--trim(pr.dprnlp) AS prenom,
trim(pr.ddenom) AS denomination,

-- adresse du propriétaire
ltrim(trim(coalesce(pr.dlign4, '')), '0') AS adresse,
trim(coalesce(pr.dlign5, '')) AS complement_adresse,
trim(coalesce(pr.ccopos, '')) AS code_postal,
replace(
trim(coalesce(pr.dlign6, '')),
trim(coalesce(pr.ccopos, '')),
''
) AS ville,
replace(
ltrim(trim(coalesce(pr.dlign4, ' ')), '0') || ' ' || trim(coalesce(pr.dlign5, ' ')) || ' ' || trim(coalesce(pr.dlign6, ' ')),
' ',
' '
) AS adresse_complete,
";

// Ajout des informations de naissance
if (!$forThirdParty) {
$sql .= "
coalesce( trim(cast(pr.jdatnss AS text) ), '-') AS date_naissance,
coalesce(trim(pr.dldnss), '-') AS lieu_naissance,
";
}
$sql .= "
-- parcelles
string_agg(DISTINCT p.parcelle, ', ' ORDER BY p.parcelle) AS parcelles
";

// Ajout de la géométrie
if ($withGeom) {
$sql .= ',
-- geometrie
ST_Centroid(geom)::geometry(point,2154) AS geom
';
}

// Ajout des objets intersectés
// Ceux qui ont été sélectionnés dans l'onglet "Recherche spatiale"
// du panneau de recherche
if ($hasIntersectionData) {
$sql .= '
-- Code objet
,
string_agg(DISTINCT z."' . $intersectionData['field'] . '"::text, \', \' ORDER BY z."' . $intersectionData['field'] . '"::text)
FILTER (WHERE z."' . $intersectionData['field'] . '" IS NOT NULL) AS code_objet
';
}

$sql .= '
FROM parcelle p
INNER JOIN parcelle_info gp ON gp.geo_parcelle = p.parcelle
LEFT JOIN proprietaire AS pr ON pr.comptecommunal = p.comptecommunal
LEFT JOIN commune AS c ON c.commune = concat(pr.ccodep, pr.ccodir, pr.ccocom)
';

// Ajout des objets intersectés
// Ceux qui ont été sélectionnés dans l'onglet "Recherche spatiale"
// du panneau de recherche
if ($hasIntersectionData) {
$sql .= '
-- Code objet
LEFT JOIN "' . $intersectionData['schema'] . '"."' . $intersectionData['table'] . '" AS z
ON z."' . $intersectionData['pk'] . '" IN (' . $intersectionData['selectedIds'] . ')
AND ST_DWithin(z."' . $intersectionData['geometryColumn'] . '", gp.geom, ' . $intersectionData['buffer'] . ')
';
}

$pids = array();
foreach ($parcelle_ids as $pid) {
$pids[] = "'" . $pid . "'";
}

$sql .= '
WHERE
p.parcelle IN ( ' . implode(', ', $pids) . ' )
';

// Questions
// Seulement le principal ou les usufruitiers ?
// Seulement les peronnes physiques ou tout le monde ?

$filterConfig = cadastreConfig::getFilterByLogin($this->repository, $this->project, $this->config->parcelle->id);
$layerSql = cadastreConfig::getLayerSql($this->repository, $this->project, $this->config->parcelle->id);
$polygonFilter = cadastreConfig::getPolygonFilter($this->repository, $this->project, $this->config->parcelle->id);

if ($filterConfig !== null) {
$sql .= ' AND ';
$sql .= $this->getFilterSql($filterConfig);
}
if ($layerSql) {
$sql .= ' AND (' . $layerSql . ')';
}
if ($polygonFilter) {
$sql .= ' AND (' . $polygonFilter . ')';
}

// Regroupement par propriétaire
$sql .= '
GROUP BY
c.libcom,
pr.dnuper, pr.dqualp,
pr.dnomus, pr.dprnus,
-- pr.dnomlp, pr.dprnlp,
pr.ddenom,
pr.dlign4, pr.dlign5, pr.dlign6, pr.ccopos
';
if (!$forThirdParty) {
$sql .= '
, pr.jdatnss, pr.dldnss
';
}
if ($withGeom) {
$sql .= ',
, geom
';
}

$sql .= '
ORDER BY c.libcom, pr.ddenom
';

return $sql;
}

/**
* Get data from database and return an array.
*
Expand Down Expand Up @@ -234,4 +388,32 @@ public function getLocauxAndProprioInfos($repository, $project, $parcelleLayer,

return $this->buildCsv($rows);
}

/**
* Build the parcelles and proprios CSV file and return its path.
*
* @param string $repository
* @param string $project
* @param mixed $parcelleLayer
* @param array $parcelle_ids The ids of parcelles
* @param bool $withGeom With geometry data (optional)
* @param bool $forThirdParty Without infos for third party (optional)
* @param null|array $intersectionData Array containing needed parameters used to get intersected layer data
*
* @return string The CSV file path
*/
public function getParcellesAndProprioInfos($repository, $project, $parcelleLayer, $parcelle_ids, $withGeom = false, $forThirdParty = false, $intersectionData = null)
{
$this->repository = $repository;
$this->project = $project;
$this->config = cadastreConfig::get($repository, $project);
$sql = $this->getParcellesAndProprioSql($parcelle_ids, $withGeom, $forThirdParty, $intersectionData);

$profile = cadastreProfile::get($repository, $project, $parcelleLayer);

$parameters = array();
$rows = $this->query($sql, $parameters, $profile);

return $this->buildCsv($rows);
}
}
Loading