ajout view email proposé pour les commerçants

This commit is contained in:
Tykayn 2025-06-19 10:20:40 +02:00 committed by tykayn
parent e71177dee1
commit dbe2f62c45
12 changed files with 275 additions and 12 deletions

View file

@ -0,0 +1,35 @@
<?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 Version20250619074501 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(<<<'SQL'
ALTER TABLE place ADD osm_data_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL
SQL);
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL'
ALTER TABLE place DROP osm_data_date
SQL);
}
}

View file

@ -0,0 +1,53 @@
<?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 Version20250619074657 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(<<<'SQL'
ALTER TABLE place ADD osm_data_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats ADD osm_data_date_min TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats ADD osm_data_date_avg TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats ADD osm_data_date_max TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL
SQL);
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL'
ALTER TABLE place DROP osm_data_date
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats DROP osm_data_date_min
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats DROP osm_data_date_avg
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE stats DROP osm_data_date_max
SQL);
}
}

View file

@ -82,8 +82,11 @@ final class AdminController extends AbstractController
->setSiret($this->motocultrice->find_siret($placeData['tags']) ?? '')
->setAskedHumainsSupport(false)
->setLastContactAttemptDate(null)
->setNote('')
->setPlaceCount(0);
->setNote($this->motocultrice->find_tag($placeData['tags'], 'note') ? true : false)
->setNoteContent($this->motocultrice->find_tag($placeData['tags'], 'note') ?? '')
->setPlaceCount(0)
// ->setOsmData($placeData['modified'] ?? null)
;
// Mettre à jour les données depuis Overpass
$place->update_place_from_overpass_data($placeData);
@ -175,15 +178,6 @@ final class AdminController extends AbstractController
$urls = $stats->getAllCTCUrlsMap();
$statsHistory = $this->entityManager->getRepository(StatsHistory::class)
->createQueryBuilder('sh')
->where('sh.stats = :stats')
->setParameter('stats', $stats)
->orderBy('sh.id', 'DESC')
->setMaxResults(365)
->getQuery()
->getResult();
// Calculer les statistiques
$calculatedStats = $this->motocultrice->calculateStats($commerces);
@ -209,6 +203,15 @@ final class AdminController extends AbstractController
$this->entityManager->persist($stats);
$this->entityManager->flush();
// Récupérer l'historique des stats APRÈS que l'entité soit persistée
$statsHistory = $this->entityManager->getRepository(StatsHistory::class)
->createQueryBuilder('sh')
->where('sh.stats = :stats')
->setParameter('stats', $stats)
->orderBy('sh.id', 'DESC')
->setMaxResults(365)
->getQuery()
->getResult();
return $this->render('admin/stats.html.twig', [
'stats' => $stats,
@ -514,4 +517,23 @@ final class AdminController extends AbstractController
return $response;
}
#[Route('/admin/make_email_for_place/{id}', name: 'app_admin_make_email_for_place')]
public function make_email_for_place(Place $place): Response
{
return $this->render('admin/view_email_for_place.html.twig', ['place' => $place]);
}
#[Route('/admin/no_more_sollicitation_for_place/{id}', name: 'app_admin_no_more_sollicitation_for_place')]
public function no_more_sollicitation_for_place(Place $place): Response
{
$place->setOptedOut(true);
$this->entityManager->persist($place);
$this->entityManager->flush();
$this->addFlash('success', 'Votre lieu '.$place->getName().' ne sera plus sollicité pour mettre à jour ses informations.');
return $this->redirectToRoute('app_public_index');
}
}

View file

@ -103,6 +103,43 @@ class Place
#[ORM\Column(nullable: true)]
private ?int $habitants = null;
#[ORM\Column(nullable: true)]
private ?\DateTime $osm_data_date = null;
public function getPlaceTypeName(): ?string
{
if ($this->main_tag == 'amenity=restaurant') {
return 'restaurant';
}
if ($this->main_tag == 'amenity=bar') {
return 'bar';
}
if ($this->main_tag == 'amenity=cafe') {
return 'café';
}
if ($this->main_tag == 'amenity=hotel') {
return 'hôtel';
}
if ($this->main_tag == 'amenity=supermarket') {
return 'supermarché';
}
if ($this->main_tag == 'amenity=pharmacy') {
return 'pharmacie';
}
if ($this->main_tag == 'amenity=bank') {
return 'banque';
}
if ($this->main_tag == 'amenity=post_office') {
return 'poste';
}
if ($this->main_tag == 'amenity=school') {
return 'école';
}
return 'lieu';
}
public function getMainTag(): ?string
{
return $this->main_tag;
@ -594,4 +631,16 @@ class Place
return $this;
}
public function getOsmDataDate(): ?\DateTime
{
return $this->osm_data_date;
}
public function setOsmDataDate(?\DateTime $osm_data_date): static
{
$this->osm_data_date = $osm_data_date;
return $this;
}
}

View file

@ -86,6 +86,15 @@ class Stats
#[ORM\Column(nullable: true)]
private ?int $avec_name = null;
#[ORM\Column(nullable: true)]
private ?\DateTime $osm_data_date_min = null;
#[ORM\Column(nullable: true)]
private ?\DateTime $osm_data_date_avg = null;
#[ORM\Column(nullable: true)]
private ?\DateTime $osm_data_date_max = null;
public function getCTCurlBase(): ?string
{
$base = 'https://complete-tes-commerces.fr/';
@ -493,6 +502,42 @@ class Stats
return $this;
}
public function getOsmDataDateMin(): ?\DateTime
{
return $this->osm_data_date_min;
}
public function setOsmDataDateMin(?\DateTime $osm_data_date_min): static
{
$this->osm_data_date_min = $osm_data_date_min;
return $this;
}
public function getOsmDataDateAvg(): ?\DateTime
{
return $this->osm_data_date_avg;
}
public function setOsmDataDateAvg(?\DateTime $osm_data_date_avg): static
{
$this->osm_data_date_avg = $osm_data_date_avg;
return $this;
}
public function getOsmDataDateMax(): ?\DateTime
{
return $this->osm_data_date_max;
}
public function setOsmDataDateMax(?\DateTime $osm_data_date_max): static
{
$this->osm_data_date_max = $osm_data_date_max;
return $this;
}
}

View file

@ -216,6 +216,13 @@ out center tags;';
return null;
}
public function find_tag($tags, $tag) {
if(isset($tags[$tag]) && $tags[$tag] != '') {
return $tags[$tag];
}
return null;
}
public function get_city_osm_from_zip_code($zip_code) {
// Requête Overpass pour obtenir la zone administrative de niveau 8 avec un nom
$query = "[out:json][timeout:25];

View file

@ -0,0 +1,27 @@
<div class="content">
<i class="bi bi-shop-window"></i>
<p>Bonjour, votre {{place.getPlaceTypeName()}} "{{place.name }}" est présent dans la base de données mondiale OpenStreetMap avec 650 000 autres en France. Ces informations sont utilisées dans des milliers de sites web, par Île de France mobilités, TomTom, Geovelo, Cartes IGN, Facebook, Instagram, et Apple Plans.
<br>
Plus les informations seront à jour et plus vous aurez de chances d'avoir des clients satisfaits.</p>
<p> Vous pouvez le modifier en cliquant sur le bouton ci-dessous, c'est gratuit et sans engagement.</p>
<a href="{{ path('app_admin_commerce', {'id': place.id}) }}" class="btn btn-primary">
<i class="bi bi-pencil-square"></i>
Compléter les informations de mon commerce</a>
<br>
Les bénévoles de l'association OpenStreetMap France ont mis en place cet outil pour faciliter la mise à jour des informations de vos commerces et améliorer la souveraineté numérique. Si vous avez besoin d'aide, n'hésitez pas à nous contacter à l'adresse <a href="mailto:contact@openstreetmap.fr">contact@openstreetmap.fr</a>.
<br>
Pour des besoins de prestation de services concernant l'intégration de données, vous pouvez contacter la fédération des pros d'OpenStreetMap France sur <a href="https://fposm.fr">https://fposm.fr</a>.
<br>
En vous souhaitant une bonne journée.
<br>
- Les bénévoles de l'association OpenStreetMap France.
<br>
<hr>
<a href="{{ path('app_admin_commerce', {'id': place.id}) }}">Ne plus être sollicité pour mettre à jour mon commerce</a>
</div>

View file

@ -10,6 +10,12 @@
{% endif %}
</a>
</td>
<td>
<a href="{{ path('app_admin_make_email_for_place', {'id': commerce.id}) }}">
voir email
<i class="bi bi-envelope-fill"></i>
</a>
</td>
<td class="text-right completion-cell"
style="background : rgba(0,255,0,{{ commerce.getCompletionPercentage() / 100 }})"
data-bs-toggle="popover"

View file

@ -2,6 +2,10 @@
<tr>
<th>Nom ({{ stats.places|length }})</th>
<th>
<i class="bi bi-envelope-fill"></i>
Email
</th>
<th>
<i class="bi bi-circle-fill"></i>
Completion %
</th>

View file

@ -0,0 +1,12 @@
{% extends 'base.html.twig' %}
{% block title %}Email pour {{ place.name }}{% endblock %}
{% block body %}
<div class="container mt-4">
<h1>Email pour {{ place.name }}</h1>
<div class="content">
{% include 'admin/email_content.html.twig' with {'place': place} %}
</div>
</div>
{% endblock %}

View file

@ -97,6 +97,7 @@
>
<i class="bi bi-recycle"></i>
</a>
<a href="{{ path('app_admin_delete_by_zone', {'insee_code': stat.zone}) }}"
class="btn btn-sm btn-danger"
onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette zone ?')"

View file

@ -9,8 +9,9 @@
<thead>
<tr>
<th>Nom</th>
<th>Code postal</th>
<th>Code insee</th>
<th>Note</th>
<th>contenu de note</th>
<th>Actions</th>
</tr>
</thead>
@ -25,6 +26,7 @@
<td>
{{place.zipcode}}
</td>
<td>{{ place.note }}</td>
<td>{{ place.noteContent }}</td>
<td><a class="btn btn-primary" href="{{ path('app_admin_commerce', {'id': place.id}) }}">
<i class="bi bi-pencil"></i>