chore: import codes
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* Invoice Module - Database
|
||||
* Database initialization and tables for invoice module
|
||||
*/
|
||||
|
||||
import { query } from '@hykocx/zen/database';
|
||||
|
||||
/**
|
||||
* Check if a table exists in the database
|
||||
* @param {string} tableName - Name of the table to check
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function tableExists(tableName) {
|
||||
const result = await query(
|
||||
`SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = $1
|
||||
)`,
|
||||
[tableName]
|
||||
);
|
||||
return result.rows[0].exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create all invoice-related tables (includes clients, items, and transactions)
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function createTables() {
|
||||
const created = [];
|
||||
const skipped = [];
|
||||
|
||||
// Import clients, items, categories, transactions and recurrences table creation
|
||||
const { createClientsTable } = await import('../clients/db.js');
|
||||
const { createItemsTable } = await import('./items/db.js');
|
||||
const { createCategoriesTable } = await import('./categories/db.js');
|
||||
const { createTransactionsTable } = await import('./transactions/db.js');
|
||||
const { createRecurrencesTable } = await import('./recurrences/db.js');
|
||||
|
||||
// Create clients table first (dependency for invoices)
|
||||
console.log('\n--- Clients (Invoice Module) ---');
|
||||
const clientsResult = await createClientsTable();
|
||||
if (clientsResult.created) created.push(clientsResult.tableName);
|
||||
else skipped.push(clientsResult.tableName);
|
||||
|
||||
// Create categories table first (dependency for items)
|
||||
console.log('\n--- Categories (Invoice Module) ---');
|
||||
const categoriesResult = await createCategoriesTable();
|
||||
if (categoriesResult.created) created.push(categoriesResult.tableName);
|
||||
else skipped.push(categoriesResult.tableName);
|
||||
|
||||
// Create items table (depends on categories)
|
||||
console.log('\n--- Items (Invoice Module) ---');
|
||||
const itemsResult = await createItemsTable();
|
||||
if (itemsResult.created) created.push(itemsResult.tableName);
|
||||
else skipped.push(itemsResult.tableName);
|
||||
|
||||
// 1. Main invoices table
|
||||
const invoicesTableExists = await tableExists('zen_invoices');
|
||||
if (!invoicesTableExists) {
|
||||
await query(`
|
||||
CREATE TABLE zen_invoices (
|
||||
id SERIAL PRIMARY KEY,
|
||||
invoice_number VARCHAR(50) UNIQUE NOT NULL,
|
||||
token VARCHAR(64) UNIQUE NOT NULL,
|
||||
client_id INTEGER NOT NULL REFERENCES zen_clients(id) ON DELETE RESTRICT,
|
||||
issue_date DATE NOT NULL,
|
||||
due_date DATE NOT NULL,
|
||||
subtotal DECIMAL(10, 2) NOT NULL DEFAULT 0,
|
||||
tax_rate DECIMAL(5, 2) DEFAULT 0,
|
||||
tax_amount DECIMAL(10, 2) DEFAULT 0,
|
||||
total_amount DECIMAL(10, 2) NOT NULL,
|
||||
paid_amount DECIMAL(10, 2) DEFAULT 0,
|
||||
interest_amount DECIMAL(10, 2) DEFAULT 0,
|
||||
interest_last_calculated DATE,
|
||||
notes TEXT,
|
||||
status VARCHAR(50) DEFAULT 'draft',
|
||||
paid_at TIMESTAMPTZ,
|
||||
first_reminder_days INTEGER DEFAULT 30,
|
||||
is_recurring BOOLEAN DEFAULT false,
|
||||
recurring_frequency VARCHAR(50),
|
||||
recurring_end_date DATE,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
await query(`CREATE INDEX idx_zen_invoices_invoice_number ON zen_invoices(invoice_number)`);
|
||||
await query(`CREATE INDEX idx_zen_invoices_token ON zen_invoices(token)`);
|
||||
await query(`CREATE INDEX idx_zen_invoices_client_id ON zen_invoices(client_id)`);
|
||||
await query(`CREATE INDEX idx_zen_invoices_status ON zen_invoices(status)`);
|
||||
await query(`CREATE INDEX idx_zen_invoices_due_date ON zen_invoices(due_date)`);
|
||||
await query(`CREATE INDEX idx_zen_invoices_interest_calc ON zen_invoices(status, due_date, interest_last_calculated) WHERE status IN ('sent', 'partial', 'overdue')`);
|
||||
|
||||
created.push('zen_invoices');
|
||||
console.log('✓ Created table: zen_invoices');
|
||||
} else {
|
||||
skipped.push('zen_invoices');
|
||||
console.log('- Table already exists: zen_invoices');
|
||||
}
|
||||
|
||||
// 2. Invoice items table
|
||||
const itemsTableExists = await tableExists('zen_invoice_items');
|
||||
if (!itemsTableExists) {
|
||||
await query(`
|
||||
CREATE TABLE zen_invoice_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
invoice_id INTEGER NOT NULL REFERENCES zen_invoices(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
quantity DECIMAL(10, 2) NOT NULL,
|
||||
unit_price DECIMAL(10, 2) NOT NULL,
|
||||
total DECIMAL(10, 2) NOT NULL,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
await query(`CREATE INDEX idx_zen_invoice_items_invoice_id ON zen_invoice_items(invoice_id)`);
|
||||
|
||||
created.push('zen_invoice_items');
|
||||
console.log('✓ Created table: zen_invoice_items');
|
||||
} else {
|
||||
skipped.push('zen_invoice_items');
|
||||
console.log('- Table already exists: zen_invoice_items');
|
||||
}
|
||||
|
||||
// 3. Invoice reminders table
|
||||
const remindersTableExists = await tableExists('zen_invoice_reminders');
|
||||
if (!remindersTableExists) {
|
||||
await query(`
|
||||
CREATE TABLE zen_invoice_reminders (
|
||||
id SERIAL PRIMARY KEY,
|
||||
invoice_id INTEGER NOT NULL REFERENCES zen_invoices(id) ON DELETE CASCADE,
|
||||
reminder_type VARCHAR(50) NOT NULL,
|
||||
days_before INTEGER NOT NULL,
|
||||
sent_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
await query(`CREATE INDEX idx_zen_invoice_reminders_invoice_id ON zen_invoice_reminders(invoice_id)`);
|
||||
await query(`CREATE INDEX idx_zen_invoice_reminders_sent_at ON zen_invoice_reminders(sent_at)`);
|
||||
|
||||
created.push('zen_invoice_reminders');
|
||||
console.log('✓ Created table: zen_invoice_reminders');
|
||||
} else {
|
||||
skipped.push('zen_invoice_reminders');
|
||||
console.log('- Table already exists: zen_invoice_reminders');
|
||||
}
|
||||
|
||||
// 4. Interac credentials table
|
||||
const interacTableExists = await tableExists('zen_invoice_interac');
|
||||
if (!interacTableExists) {
|
||||
await query(`
|
||||
CREATE TABLE zen_invoice_interac (
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_id INTEGER NOT NULL UNIQUE REFERENCES zen_clients(id) ON DELETE CASCADE,
|
||||
security_question VARCHAR(255) NOT NULL,
|
||||
security_answer VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
await query(`CREATE INDEX idx_zen_invoice_interac_client_id ON zen_invoice_interac(client_id)`);
|
||||
|
||||
created.push('zen_invoice_interac');
|
||||
console.log('✓ Created table: zen_invoice_interac');
|
||||
} else {
|
||||
skipped.push('zen_invoice_interac');
|
||||
console.log('- Table already exists: zen_invoice_interac');
|
||||
}
|
||||
|
||||
// 5. Transactions table (depends on invoices)
|
||||
console.log('\n--- Transactions (Invoice Module) ---');
|
||||
const transactionsResult = await createTransactionsTable();
|
||||
if (transactionsResult.created) created.push(transactionsResult.tableName);
|
||||
else skipped.push(transactionsResult.tableName);
|
||||
|
||||
// 6. Recurrences table (depends on clients and invoices)
|
||||
console.log('\n--- Recurrences (Invoice Module) ---');
|
||||
const recurrencesResult = await createRecurrencesTable();
|
||||
if (recurrencesResult.created) created.push(recurrencesResult.tableName);
|
||||
else skipped.push(recurrencesResult.tableName);
|
||||
|
||||
return { created, skipped };
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all invoice-related tables (includes clients, items, and transactions)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function dropTables() {
|
||||
// Import drop functions
|
||||
const { dropClientsTable } = await import('../clients/db.js');
|
||||
const { dropItemsTable } = await import('./items/db.js');
|
||||
const { dropCategoriesTable } = await import('./categories/db.js');
|
||||
const { dropTransactionsTable } = await import('./transactions/db.js');
|
||||
const { dropRecurrencesTable } = await import('./recurrences/db.js');
|
||||
|
||||
// Drop recurrences first (depends on invoices)
|
||||
await dropRecurrencesTable();
|
||||
|
||||
// Drop transactions (depends on invoices)
|
||||
await dropTransactionsTable();
|
||||
|
||||
// Drop invoice tables
|
||||
const tables = [
|
||||
'zen_invoice_reminders',
|
||||
'zen_invoice_interac',
|
||||
'zen_invoice_items',
|
||||
'zen_invoices'
|
||||
];
|
||||
|
||||
for (const tableName of tables) {
|
||||
const exists = await tableExists(tableName);
|
||||
if (exists) {
|
||||
await query(`DROP TABLE IF EXISTS ${tableName} CASCADE`);
|
||||
console.log(`✓ Dropped table: ${tableName}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop items (depends on categories)
|
||||
await dropItemsTable();
|
||||
|
||||
// Drop categories
|
||||
await dropCategoriesTable();
|
||||
|
||||
// Drop clients last
|
||||
await dropClientsTable();
|
||||
}
|
||||
|
||||
// Backward compatibility aliases
|
||||
export const createInvoiceTables = createTables;
|
||||
export const dropInvoiceTables = dropTables;
|
||||
Reference in New Issue
Block a user