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:
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) |
| 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:
- badge = nombre de notifications non lues

View File

@@ -2,9 +2,10 @@
<section class="mt-8">
<div class="overflow-hidden bg-white">
<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>Nombre de Km</p>
<p>Montant </p>
<p>Commentaire</p>
<p>Justificatif</p>
</div>
@@ -15,11 +16,12 @@
<div
v-for="item in allowances"
: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)"
>
<p>{{ formatMonth(item.month) }}</p>
<p>{{ item.kilometers }}</p>
<p>{{ item.amount ? item.amount + ' €' : '-' }}</p>
<p>{{ item.comment ?? '-' }}</p>
<p>
<a
@@ -48,7 +50,7 @@
</div>
<AppDrawer v-model="isDrawerOpen" title="Frais Kms">
<AppDrawer v-model="isDrawerOpen" title="Frais">
<form class="space-y-4" @submit.prevent="onSubmit">
<div>
<label class="text-md font-semibold text-neutral-700" for="mileage-month">
@@ -64,7 +66,7 @@
<div>
<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>
<input
id="mileage-kilometers"
@@ -76,6 +78,21 @@
/>
</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>
<label class="text-md font-semibold text-neutral-700" for="mileage-receipt">
Justificatif
@@ -148,8 +165,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
(event: 'create', data: { month: string; kilometers: number; comment?: string }, file?: File): void
(event: 'update', id: number, 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; amount: number; comment?: string }, file?: File): void
(event: 'delete', id: number): void
}>()
@@ -168,11 +185,12 @@ const currentYearMonth = () => {
const form = reactive({
month: currentYearMonth(),
kilometers: 0,
amount: 0,
comment: ''
})
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> = {
@@ -201,6 +219,7 @@ const formatMonth = (dateStr: string): string => {
const resetForm = () => {
form.month = currentYearMonth()
form.kilometers = 0
form.amount = 0
form.comment = ''
selectedFile.value = undefined
fileError.value = ''
@@ -222,6 +241,7 @@ const onOpenEditDrawer = (item: MileageAllowance) => {
// Extract YYYY-MM from YYYY-MM-DD
form.month = item.month.substring(0, 7)
form.kilometers = item.kilometers
form.amount = item.amount
form.comment = item.comment ?? ''
selectedFile.value = undefined
if (fileInput.value) {
@@ -247,6 +267,7 @@ const onSubmit = () => {
const data = {
month: `${form.month}-01`,
kilometers: form.kilometers,
amount: form.amount,
comment: form.comment || undefined
}

View File

@@ -32,12 +32,13 @@ export const useEmployeeMileage = (employee: Ref<Employee | null>, reloadEmploye
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
const result = await createMileageAllowance({
employeeId: employee.value.id,
month: data.month,
kilometers: data.kilometers,
amount: data.amount,
comment: data.comment
})
if (file && result?.id) {
@@ -46,7 +47,7 @@ export const useEmployeeMileage = (employee: Ref<Employee | null>, reloadEmploye
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)
if (file) {
await uploadReceipt(apiBase, id, file)

View File

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

View File

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

View File

@@ -16,6 +16,7 @@ export const createMileageAllowance = async (data: {
employeeId: number
month: string
kilometers: number
amount: number
comment?: string
}) => {
const api = useApi()
@@ -23,6 +24,7 @@ export const createMileageAllowance = async (data: {
employee: `/api/employees/${data.employeeId}`,
month: data.month,
kilometers: data.kilometers,
amount: data.amount,
comment: data.comment
}, {
toastSuccessKey: 'success.mileage.create',
@@ -33,12 +35,14 @@ export const createMileageAllowance = async (data: {
export const updateMileageAllowance = async (id: number, data: {
month: string
kilometers: number
amount: number
comment?: string
}) => {
const api = useApi()
return api.patch<MileageAllowance>(`/mileage_allowances/${id}`, {
month: data.month,
kilometers: data.kilometers,
amount: data.amount,
comment: data.comment
}, {
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'])]
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)]
#[Groups(['mileage_allowance:read', 'mileage_allowance:write'])]
private ?string $comment = null;
@@ -149,6 +153,18 @@ class MileageAllowance
return $this;
}
public function getAmount(): float
{
return $this->amount;
}
public function setAmount(float $amount): self
{
$this->amount = $amount;
return $this;
}
public function getComment(): ?string
{
return $this->comment;