update front ts

This commit is contained in:
Arthur Barre 2024-12-16 14:53:24 +01:00
parent bc1c92a329
commit a6fc5bab7a
4 changed files with 260 additions and 16 deletions

View File

@ -0,0 +1,217 @@
const { PrismaClient } = require('@prisma/client');
const axios = require('axios');
const prisma = new PrismaClient();
async function incrementalSeed() {
try {
// Récupérer tous les clients
const clients = await prisma.client.findMany();
for (const client of clients) {
// Récupérer le dernier achat pour ce client
const lastPurchase = await prisma.purchase.findFirst({
where: { products: { some: { product: { clientId: client.id } } } },
orderBy: { id: 'desc' }
});
// Récupérer les données de l'API du client
const response = await axios.get(client.url);
const apiData = response.data;
// Filtrer pour n'avoir que les nouveaux achats
const newPurchases = apiData.filter(purchase =>
!lastPurchase || purchase.id > lastPurchase.id
);
for (const data of newPurchases) {
// 1. Create Categories
const allCategories = new Set([
...(data.customer?.categories || []),
...(data.products || []).map(p => p.product?.category).filter(Boolean)
]);
await Promise.all(
Array.from(allCategories).map(cat =>
prisma.category.upsert({
where: { id: cat?.id || 0 },
update: {},
create: {
id: cat?.id || 0,
name: cat?.name || 'Unknown',
imageName: cat?.image_name || null,
isForPurchase: cat?.is_for_purchase || false,
position: cat?.position || null
}
})
)
);
// 2. Create Customer
if (data.customer) {
await prisma.customer.upsert({
where: { id: data.customer?.id || 0 },
update: {},
create: {
id: data.customer?.id || 0,
name: data.customer?.name || 'Unknown',
email: data.customer?.email,
language: data.customer?.language || 'fr',
isNpai: data.customer?.is_npai || false,
country: data.customer?.country,
contactFirstName: data.customer?.contact_first_name,
contactLastName: data.customer?.contact_last_name,
discr: data.customer?.discr || 'professionalCustomer',
categories: {
connect: (data.customer?.categories || []).map(cat => ({ id: cat.id }))
}
}
});
}
// Skip if no products
if (!data.products || !data.products.length) {
console.log('No products found for this entry, skipping product creation');
continue;
}
// 3. Create States, Types, and AcquisitionModes
for (const product of data.products) {
if (product.product?.state) {
await prisma.state.upsert({
where: { id: product.product.state?.id || 1 },
update: {},
create: {
id: product.product.state?.id || 1,
name: product.product.state?.name || 'Unknown',
color: product.product.state?.color || '#000000'
}
});
}
if (product.product?.type) {
await prisma.type.upsert({
where: { id: product.product.type?.id || 1 },
update: {},
create: {
id: product.product.type?.id || 1,
name: product.product.type?.name || 'Unknown'
}
});
}
if (product.product?.acquisition_mode) {
await prisma.acquisitionMode.upsert({
where: { id: product.product.acquisition_mode?.id || 1 },
update: {},
create: {
id: product.product.acquisition_mode?.id || 1,
name: product.product.acquisition_mode?.name || 'Unknown',
type: product.product.acquisition_mode?.type || 'ACQUISITION'
}
});
}
}
// 4. Create Artists
for (const product of data.products) {
if (product.product?.artist) {
await prisma.artist.upsert({
where: { id: product.product.artist?.id || 0 },
update: {},
create: {
id: product.product.artist?.id || 0,
firstName: product.product.artist?.first_name,
lastName: product.product.artist?.last_name || 'Unknown',
dateBirth: product.product.artist?.date_birth,
dateDeath: product.product.artist?.date_death,
imageName: product.product.artist?.image_name,
isPhare: product.product.artist?.is_phare || false,
isCirca: product.product.artist?.is_circa || false
}
});
}
}
// 5. Create Products
await Promise.all(
data.products.map(item =>
prisma.product.upsert({
where: { code: item.product?.code || 'UNKNOWN' },
update: {},
create: {
code: item.product?.code || 'UNKNOWN',
title: item.product?.title || 'Unknown',
acquisitionPrice: item.product?.acquisition_price || 0,
dateFirstMeeting: item.product?.date_first_meeting,
dateAcquisition: item.product?.date_acquisition,
width: item.product?.width,
height: item.product?.height,
depth: item.product?.depth,
diametre: item.product?.diametre,
widthInch: item.product?.width_inch,
heightInch: item.product?.height_inch,
depthInch: item.product?.depth_inch,
diametreInch: item.product?.diametre_inch,
encadrement: item.product?.encadrement || false,
collectionPerso: item.product?.collection_perso || false,
venteDebout: item.product?.vente_debout || false,
onWall: item.product?.on_wall || false,
isMultiple: item.product?.is_multiple || false,
wantedPrice: item.product?.wanted_price,
wantedPriceMinimum: item.product?.wanted_price_minimum,
comments: item.product?.comments,
commentHistory: item.product?.comment_history,
imageName: item.product?.image_name,
year: item.product?.year,
isCirca: item.product?.is_circa || false,
artist: { connect: { id: item.product?.artist?.id || 0 } },
category: { connect: { id: item.product?.category?.id || 0 } },
type: { connect: { id: item.product?.type?.id || 1 } },
state: { connect: { id: 1 } },
acquisitionMode: { connect: { id: item.product?.acquisition_mode?.id || 1 } },
client: { connect: { id: client.id } }
}
})
)
);
// 6. Create Purchase
await prisma.purchase.create({
data: {
isGroupedPurchase: data.is_grouped_purchase || false,
location: data.location,
amountTotal: data.amount_total || 0,
amountDecremented: data.amount_decremented || 0,
fromDepotVente: data.from_depot_vente || false,
customer: { connect: { id: data.customer?.id || 0 } },
acquisitionMode: data.acquisition_mode?.id ?
{ connect: { id: data.acquisition_mode.id } } :
undefined,
products: {
create: data.products.map(item => ({
product: { connect: { code: item.product?.code || 'UNKNOWN' } },
acquisitionPrice: item.acquisition_price || 0,
quantity: item.quantity || 1
}))
}
}
});
console.log(`Import réussi pour l'achat ${data.id} du client ${client.name}!`);
}
console.log(`${newPurchases.length} nouveaux achats importés pour le client ${client.name}`);
}
} catch (error) {
console.error('Erreur lors de l\'import incrémental:', error);
} finally {
await prisma.$disconnect();
}
}
module.exports = { incrementalSeed };
if (require.main === module) {
incrementalSeed();
}

View File

@ -16,10 +16,40 @@ import { useState } from "react"
import { Eye, ArrowUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
type Product = {
title: string
width?: number
height?: number
year?: string
dateAcquisition: string
artist: {
firstName?: string
lastName: string
}
imageName?: string
client?: {
url: string
}
}
type PurchaseProduct = {
product: Product
}
interface Purchase {
products: PurchaseProduct[]
customer: {
id: number
contactFirstName: string
contactLastName: string
}
amountTotal: number
}
const columns: ColumnDef<Purchase>[] = [
{
id: "artwork",
accessorFn: (row) => row.products[0]?.product.title,
accessorFn: (row) => row.products[0]?.product.title ?? '',
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting()} className="w-full justify-start">
Œuvre <ArrowUpDown className="ml-2 h-4 w-4" />
@ -39,7 +69,7 @@ const columns: ColumnDef<Purchase>[] = [
},
{
id: "artist",
accessorFn: (row) => `${row.products[0]?.product.artist.firstName || ''} ${row.products[0]?.product.artist.lastName}`,
accessorFn: (row) => `${row.products[0]?.product.artist.firstName || ''} ${row.products[0]?.product.artist.lastName || ''}`,
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting()} className="w-full justify-start">
Artiste <ArrowUpDown className="ml-2 h-4 w-4" />
@ -48,7 +78,7 @@ const columns: ColumnDef<Purchase>[] = [
},
{
id: "Date d'acquisition",
accessorFn: (row) => row.products[0]?.product.title,
accessorFn: (row) => row.products[0]?.product.dateAcquisition ?? '',
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting()} className="w-full justify-start">
Date d'acquisition <ArrowUpDown className="ml-2 h-4 w-4" />
@ -56,22 +86,20 @@ const columns: ColumnDef<Purchase>[] = [
),
cell: ({ row }) => {
const product = row.original.products[0]?.product
return (
return product?.dateAcquisition ? (
<div className="text-sm text-gray-500">
{new Date(product?.dateAcquisition).toLocaleDateString('fr-FR')}
{new Date(product.dateAcquisition).toLocaleDateString('fr-FR')}
</div>
)
) : null
}
},
{
id: "contact",
accessorFn: (row) => `${row.customer.contactFirstName} ${row.customer.contactLastName}`,
header: ({ column }) => (
accessorFn: (row) => `${row.customer.contactFirstName || ''} ${row.customer.contactLastName || ''}`,
header: () => (
<div className="text-left">Contact</div>
),
},
{
accessorKey: "amountTotal",
header: ({ column }) => (
@ -104,12 +132,12 @@ const columns: ColumnDef<Purchase>[] = [
]
export default function Purchases() {
const { data: purchases = [], isLoading: purchasesLoading } = useQuery({
const { data: purchases = [], isLoading: purchasesLoading } = useQuery<Purchase[]>({
queryKey: ['purchases'],
queryFn: purchaseService.getAll
})
const { data: clients = [], isLoading: clientsLoading } = useQuery({
const { data: clients = [], isLoading: clientsLoading } = useQuery<Client[]>({
queryKey: ['clients'],
queryFn: clientService.getAll
})
@ -123,7 +151,7 @@ export default function Purchases() {
if (purchasesLoading || clientsLoading) return <div>Chargement...</div>
return (
<div className="container mx-auto py-10">
<div className="container mx-auto p4 py-10 p4">
<div className="mb-4">
<Select value={selectedClient} onValueChange={setSelectedClient}>
<SelectTrigger className="w-[280px]">

View File

@ -42,7 +42,7 @@ export default function Login() {
<Input
id="email"
type="email"
placeholder="name@example.com"
placeholder="Entrez votre email"
disabled={isLoading}
onChange={(e) =>
setFormData({ ...formData, email: e.target.value })
@ -54,6 +54,7 @@ export default function Login() {
<Input
id="password"
type="password"
placeholder="********"
disabled={isLoading}
onChange={(e) =>
setFormData({ ...formData, password: e.target.value })

View File

@ -1,6 +1,5 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": [
@ -27,7 +26,6 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": [
"src"