Add recurring bills schema and cycle math helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -944,6 +944,61 @@ export const companyAccountTransactions = pgTable(
|
||||
]
|
||||
);
|
||||
|
||||
// ── Recurring Bills ────────────────────────────────────
|
||||
|
||||
export const recurringBillCycleEnum = pgEnum('recurring_bill_cycle', [
|
||||
'weekly',
|
||||
'monthly',
|
||||
'quarterly',
|
||||
'yearly'
|
||||
]);
|
||||
|
||||
export const recurringBillStatusEnum = pgEnum('recurring_bill_status', [
|
||||
'active',
|
||||
'paused',
|
||||
'ended'
|
||||
]);
|
||||
|
||||
export const recurringBills = pgTable(
|
||||
'recurring_bills',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
companyId: uuid('company_id')
|
||||
.notNull()
|
||||
.references(() => companies.id, { onDelete: 'cascade' }),
|
||||
projectId: uuid('project_id')
|
||||
.notNull()
|
||||
.references(() => projects.id, { onDelete: 'restrict' }),
|
||||
accountId: uuid('account_id')
|
||||
.notNull()
|
||||
.references(() => companyAccounts.id, { onDelete: 'restrict' }),
|
||||
categoryId: uuid('category_id').references(() => categories.id, { onDelete: 'set null' }),
|
||||
partyId: uuid('party_id').references(() => parties.id, { onDelete: 'set null' }),
|
||||
name: text('name').notNull(),
|
||||
description: text('description'),
|
||||
cycle: recurringBillCycleEnum('cycle').notNull(),
|
||||
defaultAmount: numeric('default_amount', { precision: 15, scale: 2 }).notNull(),
|
||||
nextCycleAmount: numeric('next_cycle_amount', { precision: 15, scale: 2 }),
|
||||
currency: text('currency').notNull().default('THB'),
|
||||
dayOfCycle: integer('day_of_cycle'),
|
||||
startDate: date('start_date').notNull(),
|
||||
endDate: date('end_date'),
|
||||
nextDueDate: date('next_due_date').notNull(),
|
||||
lastPostedDate: date('last_posted_date'),
|
||||
status: recurringBillStatusEnum('status').notNull().default('active'),
|
||||
pausedAt: timestamp('paused_at', { withTimezone: true }),
|
||||
skipNext: boolean('skip_next').notNull().default(false),
|
||||
createdBy: text('created_by').references(() => users.id, { onDelete: 'set null' }),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow()
|
||||
},
|
||||
(table) => [
|
||||
index('recurring_bills_company_next_due_idx').on(table.companyId, table.nextDueDate),
|
||||
index('recurring_bills_company_status_idx').on(table.companyId, table.status)
|
||||
]
|
||||
);
|
||||
|
||||
export const companyAddresses = pgTable(
|
||||
'company_addresses',
|
||||
{
|
||||
@@ -1037,7 +1092,14 @@ export const companyLogEventEnum = pgEnum('company_log_event', [
|
||||
'account_deleted',
|
||||
'account_transaction_added',
|
||||
'account_transfer_posted',
|
||||
'account_reconciled'
|
||||
'account_reconciled',
|
||||
'recurring_bill_created',
|
||||
'recurring_bill_updated',
|
||||
'recurring_bill_deleted',
|
||||
'recurring_bill_paused',
|
||||
'recurring_bill_resumed',
|
||||
'recurring_bill_skipped',
|
||||
'recurring_bill_posted'
|
||||
]);
|
||||
|
||||
export const companyLog = pgTable(
|
||||
|
||||
Reference in New Issue
Block a user