Compare commits

...

3 Commits

Author SHA1 Message Date
gitea-actions
3ec1e1f10d chore: bump version to v0.1.55
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
Build Release Artefact / build (push) Successful in 1m22s
2026-03-18 14:40:57 +00:00
24b7512c8a Merge remote-tracking branch 'origin/develop' into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-03-18 15:40:44 +01:00
f047e3ed4b feat : ajout d'une colonne montant dans les Frais employé 2026-03-18 15:40:31 +01:00
10 changed files with 105 additions and 13 deletions

6
.idea/sqldialects.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/sirh.sql" dialect="GenericSQL" />
</component>
</project>

View File

@@ -1,2 +1,2 @@
parameters: parameters:
app.version: '0.1.54' app.version: '0.1.55'

View File

@@ -344,7 +344,24 @@ Tous les filtres checkbox sont cochés par défaut à l'ouverture du drawer.
| CHAUFFEUR - samedi | WorkHour (samedi) | Samedis travaillés (chauffeurs uniquement) | | CHAUFFEUR - samedi | WorkHour (samedi) | Samedis travaillés (chauffeurs uniquement) |
| Observations | — | Colonne vide pour saisie manuelle | | Observations | — | Colonne vide pour saisie manuelle |
## 12) Notifications ## 12) Frais
- Onglet "Frais" sur la fiche employé (icône `mdi:account-cash-outline`)
- Entité `MileageAllowance` (table `mileage_allowances`)
- Champs:
- `month` (mois, obligatoire)
- `kilometers` (nombre de km, optionnel)
- `amount` (montant en €, optionnel)
- `comment` (commentaire, optionnel)
- `receiptPath` / `receiptName` (justificatif PDF)
- Règle de validation:
- le mois est obligatoire
- au moins un des deux champs `kilometers` ou `amount` doit être > 0
- les deux peuvent être remplis simultanément
- Tableau: colonnes Mois, Nombre de Km, Montant €, Commentaire, Justificatif
- Justificatif: upload PDF uniquement, téléchargement via endpoint dédié
## 13) Notifications
- Icône cloche en topbar: - Icône cloche en topbar:
- badge = nombre de notifications non lues - badge = nombre de notifications non lues

View File

@@ -2,9 +2,10 @@
<section class="mt-8"> <section class="mt-8">
<div class="overflow-hidden bg-white"> <div class="overflow-hidden bg-white">
<div <div
class="grid grid-cols-4 border border-black bg-tertiary-500 px-6 py-3 text-[20px] font-semibold text-black rounded-t-md"> class="grid grid-cols-5 border border-black bg-tertiary-500 px-6 py-3 text-[20px] font-semibold text-black rounded-t-md">
<p>Mois</p> <p>Mois</p>
<p>Nombre de Km</p> <p>Nombre de Km</p>
<p>Montant </p>
<p>Commentaire</p> <p>Commentaire</p>
<p>Justificatif</p> <p>Justificatif</p>
</div> </div>
@@ -15,11 +16,12 @@
<div <div
v-for="item in allowances" v-for="item in allowances"
:key="item.id" :key="item.id"
class="grid grid-cols-4 border-b border-primary-500 px-6 py-3 text-md font-bold text-primary-500 last:border-b-0 cursor-pointer hover:bg-tertiary-500" class="grid grid-cols-5 border-b border-primary-500 px-6 py-3 text-md font-bold text-primary-500 last:border-b-0 cursor-pointer hover:bg-tertiary-500"
@click="onOpenEditDrawer(item)" @click="onOpenEditDrawer(item)"
> >
<p>{{ formatMonth(item.month) }}</p> <p>{{ formatMonth(item.month) }}</p>
<p>{{ item.kilometers }}</p> <p>{{ item.kilometers }}</p>
<p>{{ item.amount ? item.amount + ' €' : '-' }}</p>
<p>{{ item.comment ?? '-' }}</p> <p>{{ item.comment ?? '-' }}</p>
<p> <p>
<a <a
@@ -48,7 +50,7 @@
</div> </div>
<AppDrawer v-model="isDrawerOpen" title="Frais Kms"> <AppDrawer v-model="isDrawerOpen" title="Frais">
<form class="space-y-4" @submit.prevent="onSubmit"> <form class="space-y-4" @submit.prevent="onSubmit">
<div> <div>
<label class="text-md font-semibold text-neutral-700" for="mileage-month"> <label class="text-md font-semibold text-neutral-700" for="mileage-month">
@@ -64,7 +66,7 @@
<div> <div>
<label class="text-md font-semibold text-neutral-700" for="mileage-kilometers"> <label class="text-md font-semibold text-neutral-700" for="mileage-kilometers">
Nombre de Km <span class="text-red-600">*</span> Nombre de Km
</label> </label>
<input <input
id="mileage-kilometers" id="mileage-kilometers"
@@ -76,6 +78,21 @@
/> />
</div> </div>
<div>
<label class="text-md font-semibold text-neutral-700" for="mileage-amount">
Montant ()
</label>
<input
id="mileage-amount"
v-model.number="form.amount"
type="number"
step="0.01"
min="0"
class="mt-2 w-full rounded-md border border-neutral-300 px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
/>
<p class="mt-1 text-sm text-neutral-500">Au moins un des deux champs doit être rempli</p>
</div>
<div> <div>
<label class="text-md font-semibold text-neutral-700" for="mileage-receipt"> <label class="text-md font-semibold text-neutral-700" for="mileage-receipt">
Justificatif Justificatif
@@ -148,8 +165,8 @@ const props = defineProps<{
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
(event: 'create', data: { month: string; kilometers: number; comment?: string }, file?: File): void (event: 'create', data: { month: string; kilometers: number; amount: number; comment?: string }, file?: File): void
(event: 'update', id: number, data: { month: string; kilometers: number; comment?: string }, file?: File): void (event: 'update', id: number, data: { month: string; kilometers: number; amount: number; comment?: string }, file?: File): void
(event: 'delete', id: number): void (event: 'delete', id: number): void
}>() }>()
@@ -168,11 +185,12 @@ const currentYearMonth = () => {
const form = reactive({ const form = reactive({
month: currentYearMonth(), month: currentYearMonth(),
kilometers: 0, kilometers: 0,
amount: 0,
comment: '' comment: ''
}) })
const isFormValid = computed(() => { const isFormValid = computed(() => {
return form.month && form.kilometers > 0 && !fileError.value return form.month && (form.kilometers > 0 || form.amount > 0) && !fileError.value
}) })
const monthLabels: Record<number, string> = { const monthLabels: Record<number, string> = {
@@ -201,6 +219,7 @@ const formatMonth = (dateStr: string): string => {
const resetForm = () => { const resetForm = () => {
form.month = currentYearMonth() form.month = currentYearMonth()
form.kilometers = 0 form.kilometers = 0
form.amount = 0
form.comment = '' form.comment = ''
selectedFile.value = undefined selectedFile.value = undefined
fileError.value = '' fileError.value = ''
@@ -222,6 +241,7 @@ const onOpenEditDrawer = (item: MileageAllowance) => {
// Extract YYYY-MM from YYYY-MM-DD // Extract YYYY-MM from YYYY-MM-DD
form.month = item.month.substring(0, 7) form.month = item.month.substring(0, 7)
form.kilometers = item.kilometers form.kilometers = item.kilometers
form.amount = item.amount
form.comment = item.comment ?? '' form.comment = item.comment ?? ''
selectedFile.value = undefined selectedFile.value = undefined
if (fileInput.value) { if (fileInput.value) {
@@ -247,6 +267,7 @@ const onSubmit = () => {
const data = { const data = {
month: `${form.month}-01`, month: `${form.month}-01`,
kilometers: form.kilometers, kilometers: form.kilometers,
amount: form.amount,
comment: form.comment || undefined comment: form.comment || undefined
} }

View File

@@ -32,12 +32,13 @@ export const useEmployeeMileage = (employee: Ref<Employee | null>, reloadEmploye
mileageDataLoaded.value = false mileageDataLoaded.value = false
} }
const submitCreateMileage = async (data: { month: string; kilometers: number; comment?: string }, file?: File) => { const submitCreateMileage = async (data: { month: string; kilometers: number; amount: number; comment?: string }, file?: File) => {
if (!employee.value) return if (!employee.value) return
const result = await createMileageAllowance({ const result = await createMileageAllowance({
employeeId: employee.value.id, employeeId: employee.value.id,
month: data.month, month: data.month,
kilometers: data.kilometers, kilometers: data.kilometers,
amount: data.amount,
comment: data.comment comment: data.comment
}) })
if (file && result?.id) { if (file && result?.id) {
@@ -46,7 +47,7 @@ export const useEmployeeMileage = (employee: Ref<Employee | null>, reloadEmploye
await reloadEmployee() await reloadEmployee()
} }
const submitUpdateMileage = async (id: number, data: { month: string; kilometers: number; comment?: string }, file?: File) => { const submitUpdateMileage = async (id: number, data: { month: string; kilometers: number; amount: number; comment?: string }, file?: File) => {
await updateMileageAllowance(id, data) await updateMileageAllowance(id, data)
if (file) { if (file) {
await uploadReceipt(apiBase, id, file) await uploadReceipt(apiBase, id, file)

View File

@@ -62,8 +62,8 @@
: 'border-transparent text-primary-500/50 hover:text-primary-500'" : 'border-transparent text-primary-500/50 hover:text-primary-500'"
@click="activeTab = 'mileage'" @click="activeTab = 'mileage'"
> >
<Icon name="mdi:car-outline" size="24" class="align-self"/> <Icon name="mdi:account-cash-outline" size="24" class="align-self"/>
Frais Kms Frais
</button> </button>
<button <button
class="pb-2 border-b-2 flex items-center gap-3" class="pb-2 border-b-2 flex items-center gap-3"

View File

@@ -2,6 +2,7 @@ export type MileageAllowance = {
id: number id: number
month: string month: string
kilometers: number kilometers: number
amount: number
comment: string | null comment: string | null
receiptPath: string | null receiptPath: string | null
receiptName: string | null receiptName: string | null

View File

@@ -16,6 +16,7 @@ export const createMileageAllowance = async (data: {
employeeId: number employeeId: number
month: string month: string
kilometers: number kilometers: number
amount: number
comment?: string comment?: string
}) => { }) => {
const api = useApi() const api = useApi()
@@ -23,6 +24,7 @@ export const createMileageAllowance = async (data: {
employee: `/api/employees/${data.employeeId}`, employee: `/api/employees/${data.employeeId}`,
month: data.month, month: data.month,
kilometers: data.kilometers, kilometers: data.kilometers,
amount: data.amount,
comment: data.comment comment: data.comment
}, { }, {
toastSuccessKey: 'success.mileage.create', toastSuccessKey: 'success.mileage.create',
@@ -33,12 +35,14 @@ export const createMileageAllowance = async (data: {
export const updateMileageAllowance = async (id: number, data: { export const updateMileageAllowance = async (id: number, data: {
month: string month: string
kilometers: number kilometers: number
amount: number
comment?: string comment?: string
}) => { }) => {
const api = useApi() const api = useApi()
return api.patch<MileageAllowance>(`/mileage_allowances/${id}`, { return api.patch<MileageAllowance>(`/mileage_allowances/${id}`, {
month: data.month, month: data.month,
kilometers: data.kilometers, kilometers: data.kilometers,
amount: data.amount,
comment: data.comment comment: data.comment
}, { }, {
toastSuccessKey: 'success.mileage.update', toastSuccessKey: 'success.mileage.update',

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260318143503 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add amount column to mileage_allowances';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE mileage_allowances ADD COLUMN amount DOUBLE PRECISION DEFAULT 0 NOT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE mileage_allowances DROP COLUMN amount');
}
}

View File

@@ -87,6 +87,10 @@ class MileageAllowance
#[Groups(['mileage_allowance:read', 'mileage_allowance:write'])] #[Groups(['mileage_allowance:read', 'mileage_allowance:write'])]
private float $kilometers = 0; private float $kilometers = 0;
#[ORM\Column(type: 'float', options: ['default' => 0])]
#[Groups(['mileage_allowance:read', 'mileage_allowance:write'])]
private float $amount = 0;
#[ORM\Column(type: 'text', nullable: true)] #[ORM\Column(type: 'text', nullable: true)]
#[Groups(['mileage_allowance:read', 'mileage_allowance:write'])] #[Groups(['mileage_allowance:read', 'mileage_allowance:write'])]
private ?string $comment = null; private ?string $comment = null;
@@ -149,6 +153,18 @@ class MileageAllowance
return $this; return $this;
} }
public function getAmount(): float
{
return $this->amount;
}
public function setAmount(float $amount): self
{
$this->amount = $amount;
return $this;
}
public function getComment(): ?string public function getComment(): ?string
{ {
return $this->comment; return $this->comment;