Files
alrahma_sunday_school/app/Database/Migrations/2026-07-19-000100_CreateInvoiceLines.php
T
root 2be16553df
Tests / PHPUnit (push) Successful in 1m21s
fix test run issue
2026-07-18 23:18:49 -04:00

204 lines
7.0 KiB
PHP

<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateInvoiceLines extends Migration
{
public function up()
{
if (!$this->db->tableExists('invoice_lines')) {
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'auto_increment' => true,
],
'invoice_id' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => false,
],
'school_year' => [
'type' => 'VARCHAR',
'constraint' => 9,
'null' => false,
],
'line_type' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => false,
],
'source_type' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => true,
],
'source_id' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'null' => true,
],
'active_source_key' => [
'type' => 'VARCHAR',
'constraint' => 120,
'null' => true,
],
'description' => [
'type' => 'VARCHAR',
'constraint' => 255,
'null' => false,
],
'quantity' => [
'type' => 'DECIMAL',
'constraint' => '10,2',
'null' => false,
'default' => '1.00',
],
'unit_amount_cents' => [
'type' => 'INT',
'constraint' => 11,
'null' => false,
'default' => 0,
],
'line_amount_cents' => [
'type' => 'INT',
'constraint' => 11,
'null' => false,
'default' => 0,
],
'discount_eligible' => [
'type' => 'TINYINT',
'constraint' => 1,
'null' => false,
'default' => 1,
],
'calculation_version' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => true,
],
'metadata_json' => [
'type' => 'TEXT',
'null' => true,
],
'created_at' => [
'type' => 'DATETIME',
'null' => false,
],
'updated_at' => [
'type' => 'DATETIME',
'null' => false,
],
'voided_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
$this->forge->addKey('id', true);
$this->forge->addKey('invoice_id');
$this->forge->addKey(['source_type', 'source_id']);
$this->forge->addUniqueKey('active_source_key', 'uniq_invoice_lines_active_source_key');
$this->forge->createTable('invoice_lines', true);
}
$this->ensureSchoolYearColumn();
$this->backfillLegacyInvoiceLines();
}
public function down()
{
if ($this->db->tableExists('invoice_lines')) {
$this->forge->dropTable('invoice_lines', true);
}
}
private function backfillLegacyInvoiceLines(): void
{
if (!$this->db->tableExists('invoices') || !$this->db->tableExists('invoice_lines')) {
return;
}
$existingRows = $this->db->table('invoice_lines')
->select('invoice_id')
->groupBy('invoice_id')
->get()
->getResultArray();
$existing = array_fill_keys(array_map(static fn ($row) => (int) ($row['invoice_id'] ?? 0), $existingRows), true);
$invoices = $this->db->table('invoices')
->select('id, total_amount, invoice_number, school_year, created_at, updated_at')
->orderBy('id', 'ASC')
->get()
->getResultArray();
$now = date('Y-m-d H:i:s');
foreach ($invoices as $invoice) {
$invoiceId = (int) ($invoice['id'] ?? 0);
if ($invoiceId <= 0 || isset($existing[$invoiceId])) {
continue;
}
$amountCents = (int) round(((float) ($invoice['total_amount'] ?? 0)) * 100);
$createdAt = $invoice['created_at'] ?? $now;
$updatedAt = $invoice['updated_at'] ?? $createdAt;
$this->db->table('invoice_lines')->insert([
'invoice_id' => $invoiceId,
'school_year' => (string)($invoice['school_year'] ?? ''),
'line_type' => 'legacy_invoice_total',
'source_type' => 'legacy_invoice',
'source_id' => $invoiceId,
'active_source_key' => null,
'description' => 'Legacy invoice total preserved from invoice ' . (string) ($invoice['invoice_number'] ?? $invoiceId),
'quantity' => '1.00',
'unit_amount_cents' => $amountCents,
'line_amount_cents' => $amountCents,
'discount_eligible' => 0,
'calculation_version' => 'legacy_import',
'metadata_json' => json_encode([
'source' => 'invoices.total_amount',
'legacy_discount_eligible_base_cents' => 0,
'reconciliation_required' => true,
], JSON_UNESCAPED_SLASHES),
'created_at' => $createdAt ?: $now,
'updated_at' => $updatedAt ?: $now,
'voided_at' => null,
]);
}
}
private function ensureSchoolYearColumn(): void
{
if (!$this->db->tableExists('invoice_lines')) {
return;
}
if (!$this->db->fieldExists('school_year', 'invoice_lines')) {
$this->forge->addColumn('invoice_lines', [
'school_year' => [
'type' => 'VARCHAR',
'constraint' => 9,
'null' => true,
'after' => 'invoice_id',
],
]);
}
if ($this->db->tableExists('invoices')) {
$this->db->query(
"UPDATE invoice_lines il
INNER JOIN invoices i ON i.id = il.invoice_id
SET il.school_year = i.school_year
WHERE il.school_year IS NULL OR TRIM(il.school_year) = ''"
);
}
$this->db->query("ALTER TABLE invoice_lines MODIFY school_year VARCHAR(9) NOT NULL");
}
}