feat(04-03): Vendor, ExpenseCategory, Expense schema + category seeding + COA additions
- Add ExpenseStatus and ExpensePaymentMethod enums - Add Vendor model (@@unique([tenantId, name])) - Add ExpenseCategory model with accountCode linking to COA - Add Expense model with approval workflow and JE reference - Add User relations: createdExpenses, approvedExpenses - Add COA accounts 5080 Fuel/Transportation, 5085 Rent Expense (31 total) - Seed 9 default expense categories in createTenant transaction - Add Vendor subject to CASL types, Expense/Vendor permissions for OFFICE_STAFF Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -276,6 +276,20 @@ export const ISP_CHART_OF_ACCOUNTS: COAAccountDefinition[] = [
|
||||
normalBalance: "DEBIT",
|
||||
parentCode: "5000",
|
||||
},
|
||||
{
|
||||
code: "5080",
|
||||
name: "Fuel and Transportation",
|
||||
accountType: "EXPENSE",
|
||||
normalBalance: "DEBIT",
|
||||
parentCode: "5000",
|
||||
},
|
||||
{
|
||||
code: "5085",
|
||||
name: "Rent Expense",
|
||||
accountType: "EXPENSE",
|
||||
normalBalance: "DEBIT",
|
||||
parentCode: "5000",
|
||||
},
|
||||
{
|
||||
code: "5090",
|
||||
name: "Other Expense",
|
||||
|
||||
@@ -62,6 +62,10 @@ export function definePermissionsFor(
|
||||
can("update", "TechnicianProfile");
|
||||
// Inventory management
|
||||
can("manage", "Inventory");
|
||||
// Expense management (record, list, view)
|
||||
can("manage", "Expense");
|
||||
// Vendor management (CRUD)
|
||||
can("manage", "Vendor");
|
||||
// Job type rates (read-only for office staff — admin configures rates)
|
||||
can("read", "JobTypeRate");
|
||||
// View financial reports (read-only)
|
||||
|
||||
@@ -20,6 +20,7 @@ export type AppSubjects =
|
||||
| "JobTypeRate"
|
||||
| "Inventory"
|
||||
| "Expense"
|
||||
| "Vendor"
|
||||
| "Account"
|
||||
| "Report"
|
||||
| "all";
|
||||
|
||||
@@ -210,6 +210,22 @@ export async function createTenant(input: CreateTenantInput): Promise<CreateTena
|
||||
];
|
||||
await tx.ticketCategory.createMany({ data: defaultCategories });
|
||||
|
||||
// Seed default ISP expense categories for this tenant.
|
||||
// Each category maps to a COA expense account for automatic JE posting.
|
||||
// System categories (isSystemCategory=true) cannot be deleted by admins.
|
||||
const defaultExpenseCategories = [
|
||||
{ name: "Internet Bandwidth", accountCode: "5040", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Equipment & Supplies", accountCode: "5030", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Salary & Wages", accountCode: "5010", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Technician Compensation", accountCode: "5020", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Office Supplies", accountCode: "5050", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Utilities", accountCode: "5060", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Fuel & Transportation", accountCode: "5080", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Rent", accountCode: "5085", isSystemCategory: true, tenantId: tenant.id },
|
||||
{ name: "Other", accountCode: "5090", isSystemCategory: true, tenantId: tenant.id },
|
||||
];
|
||||
await tx.expenseCategory.createMany({ data: defaultExpenseCategories });
|
||||
|
||||
return { tenant, user };
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user