Compare commits

...

7 Commits

Author SHA1 Message Date
gitea-actions
9505201499 chore: bump version to v0.0.56
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m23s
2026-02-26 07:42:10 +00:00
624591c096 feat : finalisation du tableau d'estimation des poids bovin
All checks were successful
Auto Tag Develop / tag (push) Successful in 7s
2026-02-26 08:41:56 +01:00
gitea-actions
e31bdce713 chore: bump version to v0.0.55
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m14s
2026-02-25 14:48:38 +00:00
5d72beaf8d Merge remote-tracking branch 'origin/develop' into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-02-25 15:48:19 +01:00
43f34015c6 fix : app seed 2026-02-25 15:39:05 +01:00
gitea-actions
ac5ce07e61 chore: bump version to v0.0.54
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m15s
2026-02-25 14:31:35 +00:00
e9fb36cc24 fix : suppression des repositories qui ne servent à rien
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
2026-02-25 15:31:26 +01:00
14 changed files with 67 additions and 289 deletions

View File

@@ -8,6 +8,7 @@ Project overview
Backend conventions Backend conventions
- Use English for code identifiers/messages; keep “pont-bascule” as domain term. - Use English for code identifiers/messages; keep “pont-bascule” as domain term.
- API Platform operations are defined on Doctrine entities. - API Platform operations are defined on Doctrine entities.
- No custom repository classes are used (`src/Repository` removed); use default Doctrine repositories via `EntityManagerInterface`.
- Reception entity is in `src/Entity/Reception.php`, with custom weigh endpoint `/receptions/weigh`. - Reception entity is in `src/Entity/Reception.php`, with custom weigh endpoint `/receptions/weigh`.
- Reception fields: `date_reception`, `license_plate`, `current_step` (default 0), `is_valid` (default false). - Reception fields: `date_reception`, `license_plate`, `current_step` (default 0), `is_valid` (default false).
- Reception also has `identification_number` (auto `N-BR-####`), `merchandise_type`, `merchandise_detail`, `buildings` (M2M), and `pellet_buildings` (via `reception_pellet_building`). - Reception also has `identification_number` (auto `N-BR-####`), `merchandise_type`, `merchandise_detail`, `buildings` (M2M), and `pellet_buildings` (via `reception_pellet_building`).
@@ -17,6 +18,13 @@ Backend conventions
- Custom exception: `App\Exception\PontBasculeException` with French messages, mapped to 500 in provider. - Custom exception: `App\Exception\PontBasculeException` with French messages, mapped to 500 in provider.
- Parsing of pont-bascule payload is in `src/Service/PontBasculePayloadDecoder.php`. - Parsing of pont-bascule payload is in `src/Service/PontBasculePayloadDecoder.php`.
- `config/reference.php` is auto-generated; keep it. - `config/reference.php` is auto-generated; keep it.
- Bovine storage:
- `src/Entity/Bovine.php` with fields `nationalNumber` (unique), `receivedWeight`, `arrivalDate`, and `buildingCase` (ManyToOne).
- `src/Entity/BuildingCase.php` has `bovines` (OneToMany).
- Case PDF report:
- Endpoint: `GET /building_cases/{id}/weights-report` (provider: `App\State\BuildingCaseWeightsReportProvider`).
- Template: `templates/case_weights_report.html.twig`.
- Projection logic is done in backend from `arrivalDate`; daily gain is currently fixed at `1.3 kg/day` for all races.
Frontend conventions Frontend conventions
- Nuxt SSR disabled; Tailwind used. - Nuxt SSR disabled; Tailwind used.
@@ -36,6 +44,7 @@ Frontend conventions
- Service layer lives in `frontend/services/` with typed DTOs in `frontend/services/dto/`. - Service layer lives in `frontend/services/` with typed DTOs in `frontend/services/dto/`.
- Reception service uses `receptions`, `receptions/{id}`, `receptions/weigh` and supports success/error toast keys. - Reception service uses `receptions`, `receptions/{id}`, `receptions/weigh` and supports success/error toast keys.
- Reception receipt endpoint is `receptions/{id}/receipt` (PDF) via `frontend/composables/usePdfPrinter.ts`. - Reception receipt endpoint is `receptions/{id}/receipt` (PDF) via `frontend/composables/usePdfPrinter.ts`.
- Infrastructure case page prints the case weight report PDF from `frontend/pages/infrastructure/case.vue` using `usePdfPrinter('/building_cases/{id}/weights-report')`.
Environment & routing Environment & routing
- Frontend dev server: `npm run dev` in `frontend/`. - Frontend dev server: `npm run dev` in `frontend/`.
@@ -47,6 +56,11 @@ Environment & routing
Notes Notes
- Do not add a GET that creates resources; use POST + PATCH. - Do not add a GET that creates resources; use POST + PATCH.
- Keep endpoints in plural (API Platform convention). - Keep endpoints in plural (API Platform convention).
- Seed and fixtures conventions:
- `app:seed` now seeds infrastructure (`statut`, `building_layout`, `building_case`, `building_case_position`) and bovines.
- `app:seed` uses intermediate flushes (after buildings and after infrastructure) so find queries can resolve just-created records.
- Bovine seed rows use a legacy case token mapping to building-case code (`B{building}-C{case}`) before fallback to direct id lookup.
- Fixtures include `BuildingInfrastructureFixtures` + `BovineFixtures` (via `AppFixtures` dependencies).
- New reference data added: - New reference data added:
- Reception types (`reception_type`, fields: `label`, `code`), selectable on reception form. - Reception types (`reception_type`, fields: `label`, `code`), selectable on reception form.
- Merchandise types (`merchandise_type`, fields: `label`, `code`) and pellet types (`pellet_type`, fields: `label`, `code`). - Merchandise types (`merchandise_type`, fields: `label`, `code`) and pellet types (`pellet_type`, fields: `label`, `code`).

View File

@@ -1,2 +1,2 @@
parameters: parameters:
app.version: '0.0.53' app.version: '0.0.56'

View File

@@ -5,7 +5,7 @@
:disabled="!hasCaseId" :disabled="!hasCaseId"
@click="printCaseReport" @click="printCaseReport"
> >
Imprimer case {{ caseId || '-' }} Imprimer
</UiButton> </UiButton>
</div> </div>
</template> </template>

View File

@@ -58,7 +58,11 @@ class SeedCommand extends Command
$this->seedMerchandiseTypes(); $this->seedMerchandiseTypes();
$this->seedPelletTypes(); $this->seedPelletTypes();
$this->seedBuildings(); $this->seedBuildings();
$this->entityManager->flush();
$this->seedBuildingInfrastructure(); $this->seedBuildingInfrastructure();
$this->entityManager->flush();
$this->seedBovines($io); $this->seedBovines($io);
$this->seedReceptionTypes(); $this->seedReceptionTypes();
$this->seedBovineTypes(); $this->seedBovineTypes();

View File

@@ -7,7 +7,6 @@ namespace App\Entity;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation; use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
use App\Repository\BuildingCaseRepository;
use App\State\BuildingCaseWeightsReportProvider; use App\State\BuildingCaseWeightsReportProvider;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
@@ -15,7 +14,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Attribute\SerializedName;
#[ORM\Entity(repositoryClass: BuildingCaseRepository::class)] #[ORM\Entity]
#[ApiResource( #[ApiResource(
operations: [ operations: [
new Get( new Get(

View File

@@ -4,12 +4,11 @@ declare(strict_types=1);
namespace App\Entity; namespace App\Entity;
use App\Repository\BuildingCasePositionRepository;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Attribute\SerializedName;
#[ORM\Entity(repositoryClass: BuildingCasePositionRepository::class)] #[ORM\Entity]
class BuildingCasePosition class BuildingCasePosition
{ {
#[ORM\Id] #[ORM\Id]

View File

@@ -4,14 +4,13 @@ declare(strict_types=1);
namespace App\Entity; namespace App\Entity;
use App\Repository\BuildingLayoutRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Attribute\SerializedName;
#[ORM\Entity(repositoryClass: BuildingLayoutRepository::class)] #[ORM\Entity]
class BuildingLayout class BuildingLayout
{ {
#[ORM\Id] #[ORM\Id]

View File

@@ -7,14 +7,13 @@ namespace App\Entity;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use App\Repository\StatutRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Attribute\SerializedName;
#[ORM\Entity(repositoryClass: StatutRepository::class)] #[ORM\Entity]
#[ApiResource( #[ApiResource(
operations: [ operations: [
new Get( new Get(

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\BuildingCasePosition;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<BuildingCasePosition>
*/
class BuildingCasePositionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BuildingCasePosition::class);
}
// /**
// * @return BuildingCasePosition[] Returns an array of BuildingCasePosition objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('b.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?BuildingCasePosition
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\BuildingCase;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<BuildingCase>
*/
class BuildingCaseRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BuildingCase::class);
}
// /**
// * @return BuildingCase[] Returns an array of BuildingCase objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('b.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?BuildingCase
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\BuildingLayout;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<BuildingLayout>
*/
class BuildingLayoutRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BuildingLayout::class);
}
// /**
// * @return BuildingLayout[] Returns an array of BuildingLayout objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('b.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?BuildingLayout
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\Statut;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Statut>
*/
class StatutRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Statut::class);
}
// /**
// * @return Statut[] Returns an array of Statut objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('s.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Statut
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -150,11 +150,7 @@ final readonly class BuildingCaseWeightsReportProvider implements ProviderInterf
private function resolveDailyGainKg(?string $breedCode): float private function resolveDailyGainKg(?string $breedCode): float
{ {
return match ($breedCode) { return 1.3;
'34' => 1.3, // Limousin
'38' => 1.5, // Charolais
default => 1.4, // Other breeds
};
} }
/** /**

View File

@@ -178,39 +178,9 @@
/* ========================= /* =========================
FOOTER VACCINS / NOTES FOOTER VACCINS / NOTES
========================= */ ========================= */
.footer { .footer {
margin-top: 6px; font-size: 12px;
} }
.footer th {
background: #ffffff;
font-size: 9px;
font-weight: 700;
padding: 2px;
}
.footer td {
font-size: 8px;
padding: 2px;
height: 18px;
}
.footer .small {
font-size: 8px;
}
/* Ligne méta */
.meta {
margin-top: 3px;
text-align: right;
font-size: 8px;
color: #444;
line-height: 1.2;
}
/* Petits ajustements dompdf */
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
/* Header droit sans bordures par défaut */ /* Header droit sans bordures par défaut */
.header-right-free, .header-right-free,
@@ -363,68 +333,46 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<!-- ========================= <!-- =========================
FOOTER (traitements / vaccins) FOOTER (traitements / vaccins)
========================= --> ========================= -->
{# <table class="footer">#} <table class="footer" style="border-collapse:collapse; margin-top: 32px">
{# <colgroup>#} <tr>
{# #}{# 14 colonnes pour gérer proprement les colspan #} <td style="height: 20px; border: 0" colspan="4"></td>
{# <col style="width:12.5%">#} <td style="font-weight: 700" colspan="2">Grippe</td>
{# <col style="width:8%">#} <td style="font-weight: 700" colspan="2">Protivity</td>
{# <col style="width:12.5%">#} </tr>
{# <col style="width:8%">#} <tr>
{# <col style="width:12.5%">#} <td style="height: 20px">Date</td>
{# <col style="width:8%">#} <td>Antibiotique</td>
{# <col style="width:12.5%">#} <td>Date</td>
{# <col style="width:8%">#} <td>Antero</td>
{# <col style="width:8%">#} <td>Date</td>
{# <col style="width:6%">#} <td>Intranasale</td>
{# <col style="width:8%">#} <td>Date</td>
{# <col style="width:8%">#} <td>Rappel 30 jours</td>
{# <col style="width:6%">#} </tr>
{# <col style="width:8%">#} <tr>
{# </colgroup>#} <td style="height: 20px"></td>
<td></td>
{# <tr>#} <td></td>
{# <th colspan="2">Date</th>#} <td></td>
{# <th colspan="2">Antibiotique</th>#} <td></td>
{# <th colspan="2">Date</th>#} <td></td>
{# <th colspan="2">Antero</th>#} <td></td>
{# <th colspan="3">Grippe</th>#} <td></td>
{# <th colspan="3">Protivity</th>#} </tr>
{# </tr>#} <tr>
<td style="height: 20px"></td>
{# <tr>#} <td></td>
{# <td colspan="2"></td>#} <td></td>
{# <td colspan="2"></td>#} <td></td>
{# <td colspan="2"></td>#} <td></td>
{# <td colspan="2"></td>#} <td></td>
<td></td>
{# <td class="small">Date</td>#} <td></td>
{# <td colspan="2" class="small">Intranasale</td>#} </tr>
</table>
{# <td class="small">Date</td>#}
{# <td colspan="2" class="small">Rappel 30 jours</td>#}
{# </tr>#}
{# <tr>#}
{# <td colspan="2"></td>#}
{# <td colspan="2"></td>#}
{# <td colspan="2"></td>#}
{# <td colspan="2" class="small">Rappel 30 jours</td>#}
{# <td></td>#}
{# <td colspan="2" class="small">Rappel 90 jours</td>#}
{# <td></td>#}
{# <td colspan="2" class="small">3 semaines</td>#}
{# </tr>#}
{# </table>#}
{# <div class="meta">#}
{# Édité le {{ printedAt|date('d/m/Y H:i') }} - Case {{ buildingCase.code ?? '' }}#}
{# </div>#}
</div> </div>
</body> </body>
</html> </html>