initial release testing

This commit is contained in:
2026-03-23 16:16:45 -05:00
parent f079fdca62
commit 6659707890
37 changed files with 3374 additions and 37 deletions

319
lib/repository.ts Normal file
View File

@@ -0,0 +1,319 @@
import { getDb } from "@/lib/db";
import type {
AccountBalanceRow,
AccountRow,
ContactRow,
DashboardStats,
InvoiceRow,
JournalEntryRow,
KitRow,
LowStockRow,
PartRow,
PurchaseOrderListRow,
SalesOrderListRow,
VendorBillRow
} from "@/lib/types";
function db() {
return getDb();
}
export function getDashboardStats(): DashboardStats {
const row = db()
.prepare(
`
SELECT
(SELECT COUNT(*) FROM parts WHERE kind = 'part') AS total_parts,
(SELECT COUNT(*) FROM parts WHERE kind = 'assembly') AS total_assemblies,
(SELECT COUNT(*) FROM customers) AS active_customers,
(SELECT COUNT(*) FROM vendors) AS active_vendors,
(SELECT COUNT(*) FROM sales_orders WHERE status IN ('draft', 'open', 'partial')) AS open_sales_orders,
(SELECT COUNT(*) FROM purchase_orders WHERE status IN ('draft', 'ordered', 'partial')) AS open_purchase_orders,
(SELECT COUNT(*) FROM customer_invoices WHERE status IN ('open', 'partial')) AS open_invoices,
(SELECT COUNT(*) FROM vendor_bills WHERE status IN ('open', 'partial')) AS open_vendor_bills,
(
SELECT COUNT(*)
FROM parts p
LEFT JOIN inventory_balances ib ON ib.part_id = p.id
WHERE ib.quantity_on_hand <= p.reorder_point
) AS low_stock_count,
(
SELECT COALESCE(SUM(ib.quantity_on_hand * p.unit_cost), 0)
FROM parts p
LEFT JOIN inventory_balances ib ON ib.part_id = p.id
) AS inventory_value,
(
SELECT COALESCE(SUM(total_amount - paid_amount), 0)
FROM customer_invoices
WHERE status IN ('open', 'partial')
) AS accounts_receivable,
(
SELECT COALESCE(SUM(total_amount - paid_amount), 0)
FROM vendor_bills
WHERE status IN ('open', 'partial')
) AS accounts_payable
`
)
.get() as Record<string, number>;
return {
totalParts: row.total_parts ?? 0,
totalAssemblies: row.total_assemblies ?? 0,
activeCustomers: row.active_customers ?? 0,
activeVendors: row.active_vendors ?? 0,
openSalesOrders: row.open_sales_orders ?? 0,
openPurchaseOrders: row.open_purchase_orders ?? 0,
openInvoices: row.open_invoices ?? 0,
openVendorBills: row.open_vendor_bills ?? 0,
lowStockCount: row.low_stock_count ?? 0,
inventoryValue: row.inventory_value ?? 0,
accountsReceivable: row.accounts_receivable ?? 0,
accountsPayable: row.accounts_payable ?? 0
};
}
export function getParts(): PartRow[] {
return db()
.prepare(
`
SELECT
p.id,
p.sku,
p.name,
p.kind,
p.unit_cost AS unitCost,
p.sale_price AS salePrice,
p.reorder_point AS reorderPoint,
p.unit_of_measure AS unitOfMeasure,
COALESCE(ib.quantity_on_hand, 0) AS quantityOnHand
FROM parts p
LEFT JOIN inventory_balances ib ON ib.part_id = p.id
ORDER BY p.kind DESC, p.sku ASC
`
)
.all() as PartRow[];
}
export function getAssembliesWithComponents(): KitRow[] {
return db()
.prepare(
`
SELECT
a.sku AS assemblySku,
a.name AS assemblyName,
c.sku AS componentSku,
c.name AS componentName,
kc.quantity
FROM kit_components kc
INNER JOIN parts a ON a.id = kc.assembly_part_id
INNER JOIN parts c ON c.id = kc.component_part_id
ORDER BY a.sku, c.sku
`
)
.all() as KitRow[];
}
export function getCustomers(): ContactRow[] {
return db().prepare(`SELECT id, code, name, email, phone FROM customers ORDER BY code`).all() as ContactRow[];
}
export function getVendors(): ContactRow[] {
return db().prepare(`SELECT id, code, name, email, phone FROM vendors ORDER BY code`).all() as ContactRow[];
}
export function getSalesOrders(): SalesOrderListRow[] {
return db()
.prepare(
`
SELECT
so.id,
so.order_number AS orderNumber,
c.name AS customerName,
so.status,
so.created_at AS createdAt,
COALESCE(SUM(sol.quantity * sol.unit_price), 0) AS totalAmount,
COALESCE(SUM(sol.quantity), 0) AS orderedQuantity,
COALESCE(SUM(sol.shipped_quantity), 0) AS fulfilledQuantity
FROM sales_orders so
INNER JOIN customers c ON c.id = so.customer_id
LEFT JOIN sales_order_lines sol ON sol.sales_order_id = so.id
GROUP BY so.id, so.order_number, c.name, so.status, so.created_at
ORDER BY so.created_at DESC
`
)
.all() as SalesOrderListRow[];
}
export function getPurchaseOrders(): PurchaseOrderListRow[] {
return db()
.prepare(
`
SELECT
po.id,
po.order_number AS orderNumber,
v.name AS vendorName,
po.status,
po.created_at AS createdAt,
COALESCE(SUM(pol.quantity * pol.unit_cost), 0) AS totalAmount,
COALESCE(SUM(pol.quantity), 0) AS orderedQuantity,
COALESCE(SUM(pol.received_quantity), 0) AS fulfilledQuantity
FROM purchase_orders po
INNER JOIN vendors v ON v.id = po.vendor_id
LEFT JOIN purchase_order_lines pol ON pol.purchase_order_id = po.id
GROUP BY po.id, po.order_number, v.name, po.status, po.created_at
ORDER BY po.created_at DESC
`
)
.all() as PurchaseOrderListRow[];
}
export function getJournalEntries(): JournalEntryRow[] {
const entries = db()
.prepare(
`
SELECT
id,
entry_type AS entryType,
reference_type AS referenceType,
reference_id AS referenceId,
description,
created_at AS createdAt
FROM journal_entries
ORDER BY created_at DESC, id DESC
`
)
.all() as Array<Omit<JournalEntryRow, "lines">>;
const lineStatement = db().prepare(
`
SELECT
account_code AS accountCode,
account_name AS accountName,
debit,
credit
FROM journal_lines
WHERE journal_entry_id = ?
ORDER BY id
`
);
return entries.map((entry) => ({
...entry,
lines: lineStatement.all(entry.id) as JournalEntryRow["lines"]
}));
}
export function getInvoices(): InvoiceRow[] {
return db()
.prepare(
`
SELECT
ci.id,
ci.invoice_number AS invoiceNumber,
ci.sales_order_id AS salesOrderId,
c.name AS customerName,
ci.status,
ci.invoice_date AS invoiceDate,
ci.due_date AS dueDate,
ci.total_amount AS totalAmount,
ci.paid_amount AS paidAmount,
ci.total_amount - ci.paid_amount AS balanceDue
FROM customer_invoices ci
INNER JOIN customers c ON c.id = ci.customer_id
ORDER BY ci.invoice_date DESC, ci.id DESC
`
)
.all() as InvoiceRow[];
}
export function getVendorBills(): VendorBillRow[] {
return db()
.prepare(
`
SELECT
vb.id,
vb.bill_number AS billNumber,
vb.purchase_order_id AS purchaseOrderId,
v.name AS vendorName,
vb.status,
vb.bill_date AS billDate,
vb.due_date AS dueDate,
vb.total_amount AS totalAmount,
vb.paid_amount AS paidAmount,
vb.total_amount - vb.paid_amount AS balanceDue
FROM vendor_bills vb
INNER JOIN vendors v ON v.id = vb.vendor_id
ORDER BY vb.bill_date DESC, vb.id DESC
`
)
.all() as VendorBillRow[];
}
export function getAccounts(): AccountRow[] {
return db()
.prepare(
`
SELECT
code,
name,
category,
is_system AS isSystem
FROM accounts
ORDER BY code
`
)
.all() as AccountRow[];
}
export function getAccountBalances(): AccountBalanceRow[] {
return db()
.prepare(
`
SELECT
a.code,
a.name,
a.category,
COALESCE(SUM(jl.debit), 0) AS debitTotal,
COALESCE(SUM(jl.credit), 0) AS creditTotal,
CASE
WHEN a.category IN ('asset', 'expense') THEN COALESCE(SUM(jl.debit), 0) - COALESCE(SUM(jl.credit), 0)
ELSE COALESCE(SUM(jl.credit), 0) - COALESCE(SUM(jl.debit), 0)
END AS balance
FROM accounts a
LEFT JOIN journal_lines jl ON jl.account_code = a.code
GROUP BY a.code, a.name, a.category
ORDER BY a.code
`
)
.all() as AccountBalanceRow[];
}
export function getLowStockParts(): LowStockRow[] {
return db()
.prepare(
`
SELECT
p.id,
p.sku,
p.name,
p.unit_of_measure AS unitOfMeasure,
COALESCE(ib.quantity_on_hand, 0) AS quantityOnHand,
p.reorder_point AS reorderPoint,
MAX(p.reorder_point - COALESCE(ib.quantity_on_hand, 0), 0) AS suggestedReorderQuantity,
(
SELECT v.name
FROM purchase_order_lines pol
INNER JOIN purchase_orders po ON po.id = pol.purchase_order_id
INNER JOIN vendors v ON v.id = po.vendor_id
WHERE pol.part_id = p.id
ORDER BY po.created_at DESC
LIMIT 1
) AS preferredVendorName
FROM parts p
LEFT JOIN inventory_balances ib ON ib.part_id = p.id
WHERE p.kind = 'part' AND COALESCE(ib.quantity_on_hand, 0) <= p.reorder_point
ORDER BY suggestedReorderQuantity DESC, p.sku ASC
`
)
.all() as LowStockRow[];
}