2026-05-11 13:30:24 +03:00

153 lines
6.3 KiB
PHP

<?php
namespace Database\Seeders;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\InvoiceLine;
use App\Models\Quote;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class InvoiceSeeder extends Seeder
{
public function run(): void
{
$clientIds = Client::pluck('id')->toArray();
$products = DB::table('products')->select('id', 'prix_unitaire')->get()->keyBy('id');
$productIds = $products->keys()->toArray();
if (empty($clientIds) || empty($productIds)) {
$this->command->warn('InvoiceSeeder: aucun client ou produit trouvé — skip.');
return;
}
// ── 1. Invoices liées à des devis acceptés ────────────────────────────
$acceptedQuotes = Quote::where('status', 'accepte')
->orderBy('id')
->limit(35)
->get();
foreach ($acceptedQuotes as $quote) {
$invoiceDate = $quote->quote_date->copy()->addDays(rand(2, 10))->format('Y-m-d');
$dueDate = date('Y-m-d', strtotime($invoiceDate . ' +30 days'));
// Statuses for quote-linked invoices (mostly paid)
$s = ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee'];
Invoice::create([
'client_id' => $quote->client_id,
'source_quote_id' => $quote->id,
'status' => $s[array_rand($s)],
'invoice_date' => $invoiceDate,
'due_date' => $dueDate,
'currency' => 'EUR',
'total_ht' => $quote->total_ht,
'total_tva' => $quote->total_tva,
'total_ttc' => $quote->total_ttc,
]);
// Lines are not duplicated — source quote already has them
}
// ── 2. Invoices autonomes ─────────────────────────────────────────────
// 2024 historical — statuses varied, many paid
$this->createBatch($clientIds, $productIds, $products, [
'yearRange' => [[2024, 1, 12]],
'countPerMonth' => [3, 5],
'statusPool' => ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee', 'echue'],
]);
// 2025 main year — rich dataset
$this->createBatch($clientIds, $productIds, $products, [
'yearRange' => [[2025, 1, 12]],
'countPerMonth' => [4, 7],
'statusPool' => ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee', 'echue', 'echue'],
]);
// 2026 Jan-Apr — no echue (due dates not yet past)
$this->createBatch($clientIds, $productIds, $products, [
'yearRange' => [[2026, 1, 4]],
'countPerMonth' => [4, 6],
'statusPool' => ['payee', 'payee', 'emise', 'envoyee', 'partiellement_payee'],
]);
// 2026 May 1-8 — recent, mostly emise
$this->createBatch($clientIds, $productIds, $products, [
'yearRange' => [[2026, 5, 5]],
'countPerMonth' => [4, 6],
'maxDay' => 8,
'statusPool' => ['payee', 'emise', 'emise', 'envoyee'],
]);
$total = Invoice::count();
$this->command->info("InvoiceSeeder: {$total} factures au total.");
}
// ─────────────────────────────────────────────────────────────────────────
private function createBatch(
array $clientIds,
array $productIds,
\Illuminate\Support\Collection $products,
array $opts
): void {
foreach ($opts['yearRange'] as [$year, $startM, $endM]) {
for ($m = $startM; $m <= $endM; $m++) {
$maxDay = $opts['maxDay'] ?? 28;
$count = rand(...$opts['countPerMonth']);
for ($i = 0; $i < $count; $i++) {
$invoiceDate = sprintf('%04d-%02d-%02d', $year, $m, rand(1, $maxDay));
$status = $opts['statusPool'][array_rand($opts['statusPool'])];
// due_date
if ($status === 'echue') {
$dueDate = date('Y-m-d', strtotime($invoiceDate . ' +10 days'));
} else {
$dueDate = date('Y-m-d', strtotime($invoiceDate . ' +30 days'));
}
$clientId = $clientIds[array_rand($clientIds)];
// Build lines
$lineData = [];
$totalHt = 0.0;
for ($l = 0, $nl = rand(1, 3); $l < $nl; $l++) {
$pid = $productIds[array_rand($productIds)];
$unitPrice = (float) ($products->get($pid)->prix_unitaire ?? 150.00);
$qty = rand(1, 3);
$lineHt = round($unitPrice * $qty, 2);
$totalHt += $lineHt;
$lineData[] = [
'product_id' => $pid,
'description' => 'Prestation funéraire',
'qty_base' => $qty,
'unit_price' => $unitPrice,
'discount_pct' => 0,
'total_ht' => $lineHt,
];
}
$totalTva = round($totalHt * 0.20, 2);
$totalTtc = round($totalHt + $totalTva, 2);
$invoice = Invoice::create([
'client_id' => $clientId,
'status' => $status,
'invoice_date' => $invoiceDate,
'due_date' => $dueDate,
'currency' => 'EUR',
'total_ht' => $totalHt,
'total_tva' => $totalTva,
'total_ttc' => $totalTtc,
]);
foreach ($lineData as $line) {
InvoiceLine::create(array_merge($line, ['invoice_id' => $invoice->id]));
}
}
}
}
}
}