update front ts
This commit is contained in:
parent
bc1c92a329
commit
a6fc5bab7a
217
backend/src/utils/get-new-data.js
Normal file
217
backend/src/utils/get-new-data.js
Normal 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();
|
||||
}
|
||||
@ -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]">
|
||||
|
||||
@ -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 })
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user