All materials
seed.ts
tsseed.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const cooperatives = [
{ nom: 'Cooperative Agricole de Korhogo', village: 'Korhogo', contact_name: 'Sekou Coulibaly', contact_phone: '+225 07 01 23 45' },
{ nom: 'Groupement des Producteurs de Ferkessedougou', village: 'Ferkessedougou', contact_name: 'Mariam Traore', contact_phone: '+225 07 02 34 56' },
{ nom: 'Union des Femmes de Boundiali', village: 'Boundiali', contact_name: 'Awa Kone', contact_phone: '+225 07 03 45 67' },
{ nom: 'Cooperative de Tengrela', village: 'Tengrela', contact_name: 'Ibrahim Ouattara', contact_phone: '+225 07 04 56 78' },
{ nom: 'Groupement Paysan de Sinematiali', village: 'Sinematiali', contact_name: 'Fatoumata Diallo', contact_phone: '+225 07 05 67 89' },
{ nom: 'Cooperative des Planteurs de Dikodougou', village: 'Dikodougou', contact_name: 'Moussa Sangare', contact_phone: null },
{ nom: 'Association des Producteurs de Niakara', village: 'Niakara', contact_name: 'Aminata Bamba', contact_phone: '+225 07 07 89 01' },
{ nom: 'Groupement de Kong', village: 'Kong', contact_name: 'Drissa Konate', contact_phone: '+225 07 08 90 12' },
]
const varieties = ['W320', 'W240', 'W180']
const stages = ['reception', 'shelling', 'grading', 'roasting', 'packaging']
const checkTypes = ['moisture', 'defect_rate', 'size_grade', 'color_check']
const inspectors = ['Konan Y.', 'Bamba S.', 'Toure M.', 'Diarra K.', 'Ouattara F.']
const destinations = ['Marseille', 'Hamburg', 'Milan', 'Rotterdam', 'Barcelona']
const shipmentStatuses = ['pending', 'pending', 'pending', 'pending', 'pending', 'in_transit', 'in_transit', 'in_transit', 'in_transit', 'in_transit', 'delivered', 'delivered', 'delivered', 'delivered', 'delivered']
const certificateTypes = ['certificate_of_origin', 'phytosanitary']
function randomDate(start: Date, end: Date): Date {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()))
}
function randomChoice<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)]
}
async function main() {
console.log('Seeding database...')
// Clear existing data
await prisma.exportCertificate.deleteMany()
await prisma.shipmentItem.deleteMany()
await prisma.shipment.deleteMany()
await prisma.qualityCheck.deleteMany()
await prisma.batch.deleteMany()
await prisma.cooperative.deleteMany()
// Create cooperatives
const createdCoops = await Promise.all(
cooperatives.map(coop => prisma.cooperative.create({ data: coop }))
)
console.log(`Created ${createdCoops.length} cooperatives`)
// Create 50 batches across stages
const seasonStart = new Date('2025-10-01')
const seasonEnd = new Date('2026-03-15')
const batches = []
for (let i = 0; i < 50; i++) {
const variety = randomChoice(varieties)
const poidsBrut = 800 + Math.random() * 1200 // 800-2000 kg
const stageIndex = Math.floor(i / 10) // 10 per stage
const stage = stages[stageIndex]
const batch = await prisma.batch.create({
data: {
cooperative_id: randomChoice(createdCoops).id,
date_reception: randomDate(seasonStart, seasonEnd),
poids_brut: Math.round(poidsBrut * 10) / 10,
net_weight: stage !== 'reception' ? Math.round(poidsBrut * 0.23 * 10) / 10 : null,
variete: variety,
stage: stage,
grade_qualite: ['grading', 'roasting', 'packaging'].includes(stage)
? (Math.random() > 0.15 ? 'export' : (Math.random() > 0.5 ? 'domestic' : 'reject'))
: null,
notes: i % 7 === 0 ? 'Lot necessite attention supplementaire' : null,
}
})
batches.push(batch)
}
console.log(`Created ${batches.length} batches`)
// Create 200 quality checks (4 per batch)
let checksCreated = 0
for (const batch of batches) {
const variety = batch.variete
const passRate = variety === 'W320' ? 0.85 : variety === 'W240' ? 0.90 : 0.92
for (let j = 0; j < 4; j++) {
const passed = Math.random() < passRate
await prisma.qualityCheck.create({
data: {
batch_id: batch.id,
check_type: checkTypes[j],
result: passed ? 'pass' : 'fail',
moisture_pct: checkTypes[j] === 'moisture' ? 5 + Math.random() * 5 : null,
defect_pct: checkTypes[j] === 'defect_rate' ? (passed ? Math.random() * 3 : 3 + Math.random() * 7) : null,
inspector: randomChoice(inspectors),
notes: !passed ? 'Verification supplementaire requise' : null,
}
})
checksCreated++
}
}
console.log(`Created ${checksCreated} quality checks`)
// Create 15 shipments
const shipments = []
for (let i = 0; i < 15; i++) {
const status = shipmentStatuses[i]
const shipment = await prisma.shipment.create({
data: {
destination: destinations[i % destinations.length],
vessel_name: status !== 'pending' ? `MV ${['Atlantic Star', 'Mediterranean Express', 'West Africa Pearl', 'Europa', 'Sahel Trader'][i % 5]}` : null,
departure_date: status !== 'pending' ? randomDate(new Date('2025-11-01'), new Date('2026-03-01')) : null,
status: status,
container_id: status !== 'pending' ? `MSKU${String(1234567 + i).padStart(7, '0')}` : null,
}
})
shipments.push(shipment)
// Add 2-4 batch items per shipment
const itemCount = 2 + Math.floor(Math.random() * 3)
const packagingBatches = batches.filter(b => b.stage === 'packaging')
for (let j = 0; j < Math.min(itemCount, packagingBatches.length); j++) {
await prisma.shipmentItem.create({
data: {
shipment_id: shipment.id,
batch_id: packagingBatches[j % packagingBatches.length].id,
quantity_kg: 200 + Math.random() * 300,
}
})
}
}
console.log(`Created ${shipments.length} shipments`)
// Create 10 export certificates for delivered shipments
const deliveredShipments = shipments.filter(s => s.status === 'delivered')
let certsCreated = 0
for (const shipment of deliveredShipments) {
for (const certType of certificateTypes) {
await prisma.exportCertificate.create({
data: {
shipment_id: shipment.id,
type_certificat: certType,
numero: `CI-${certType === 'certificate_of_origin' ? 'CO' : 'PHY'}-${String(2025000 + certsCreated).padStart(7, '0')}`,
date_expiration: new Date('2026-12-31'),
}
})
certsCreated++
}
}
console.log(`Created ${certsCreated} export certificates`)
console.log('Seeding complete.')
}
main()
.catch((e) => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})