Checkpoint: Transformation des cellules Service, Type d'achat et Ventilation en menus déroulants éditables directement dans la liste des factures. Les modifications sont sauvegardées automatiquement avec notification de succès.
This commit is contained in:
@@ -37,6 +37,8 @@ export default function Invoices() {
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [invoiceToDelete, setInvoiceToDelete] = useState<number | null>(null);
|
||||
const { data: invoices, isLoading } = trpc.invoices.list.useQuery();
|
||||
const { data: departments } = trpc.departments.getByUser.useQuery();
|
||||
const { data: allocations } = trpc.accountingAllocations.getByUser.useQuery();
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const exportExcelMutation = trpc.sftp.exportToExcel.useMutation({
|
||||
@@ -101,6 +103,16 @@ export default function Invoices() {
|
||||
},
|
||||
});
|
||||
|
||||
const updateFieldMutation = trpc.invoices.update.useMutation({
|
||||
onSuccess: () => {
|
||||
toast.success("Facture mise à jour");
|
||||
utils.invoices.list.invalidate();
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message || "Erreur lors de la mise à jour");
|
||||
},
|
||||
});
|
||||
|
||||
const filteredInvoices = invoices?.filter((inv) => {
|
||||
// Filter by search query
|
||||
if (searchQuery) {
|
||||
@@ -365,9 +377,56 @@ export default function Invoices() {
|
||||
? `${parseFloat(invoice.totalAmount as string).toFixed(2)} €`
|
||||
: "-"}
|
||||
</TableCell>
|
||||
<TableCell className="text-sm">{invoice.serviceConcerne || "-"}</TableCell>
|
||||
<TableCell className="text-sm">{invoice.typeAchat || "-"}</TableCell>
|
||||
<TableCell className="text-sm">{invoice.ventilationComptable || "-"}</TableCell>
|
||||
<TableCell className="text-sm">
|
||||
<select
|
||||
value={invoice.serviceConcerne || ""}
|
||||
onChange={(e) => {
|
||||
updateFieldMutation.mutate({
|
||||
id: invoice.id,
|
||||
data: { serviceConcerne: e.target.value || undefined },
|
||||
});
|
||||
}}
|
||||
className="w-full px-2 py-1 border rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">-</option>
|
||||
{departments?.map((dept) => (
|
||||
<option key={dept.id} value={dept.name}>{dept.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm">
|
||||
<select
|
||||
value={invoice.typeAchat || ""}
|
||||
onChange={(e) => {
|
||||
updateFieldMutation.mutate({
|
||||
id: invoice.id,
|
||||
data: { typeAchat: e.target.value as "CAPEX" | "OPEX" | undefined },
|
||||
});
|
||||
}}
|
||||
className="w-full px-2 py-1 border rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">-</option>
|
||||
<option value="CAPEX">CAPEX</option>
|
||||
<option value="OPEX">OPEX</option>
|
||||
</select>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm">
|
||||
<select
|
||||
value={invoice.ventilationComptable || ""}
|
||||
onChange={(e) => {
|
||||
updateFieldMutation.mutate({
|
||||
id: invoice.id,
|
||||
data: { ventilationComptable: e.target.value || undefined },
|
||||
});
|
||||
}}
|
||||
className="w-full px-2 py-1 border rounded text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">-</option>
|
||||
{allocations?.map((alloc) => (
|
||||
<option key={alloc.id} value={alloc.name}>{alloc.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</TableCell>
|
||||
<TableCell>{getQualityBadge(invoice.qualityScore)}</TableCell>
|
||||
<TableCell>{getExportStatusBadge(invoice.exportStatus || "not_exported")}</TableCell>
|
||||
<TableCell>
|
||||
|
||||
Reference in New Issue
Block a user