PSA/server/migrations/20251012000000_create_contract_pricing_schedules.cjs
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

102 lines
3.4 KiB
JavaScript

const tableExists = async (knex, tableName) => {
const result = await knex.schema.hasTable(tableName);
return result;
};
exports.up = async function up(knex) {
const exists = await tableExists(knex, 'contract_pricing_schedules');
if (!exists) {
await knex.schema.createTable('contract_pricing_schedules', (table) => {
// Primary key
table.uuid('schedule_id').defaultTo(knex.raw('gen_random_uuid()')).notNullable();
// Tenant for multi-tenancy
table.uuid('tenant').notNullable();
// Composite primary key for Citus compatibility
table.primary(['tenant', 'schedule_id']);
// Foreign key to contracts
table.uuid('contract_id').notNullable();
// Date range for the pricing schedule
table.date('effective_date').notNullable();
table.date('end_date');
// Duration-based end date (alternative to explicit end_date)
table.integer('duration_value'); // e.g., 6 for "6 months"
table.enum('duration_unit', ['days', 'weeks', 'months', 'years']); // Unit for duration
// Custom rate in cents (nullable means use default rate from plan)
table.integer('custom_rate');
// Notes for the pricing change
table.text('notes');
// Audit columns
table.timestamp('created_at').defaultTo(knex.fn.now());
table.timestamp('updated_at').defaultTo(knex.fn.now());
table.uuid('created_by');
table.uuid('updated_by');
// Indexes
table.index(['tenant', 'contract_id'], 'idx_contract_pricing_schedules_contract');
table.index(['tenant', 'effective_date'], 'idx_contract_pricing_schedules_effective_date');
});
// Add foreign key constraint to contracts
await knex.raw(`
ALTER TABLE contract_pricing_schedules
ADD CONSTRAINT fk_contract_pricing_schedules_contract
FOREIGN KEY (tenant, contract_id)
REFERENCES contracts (tenant, contract_id)
ON DELETE CASCADE;
`);
// Add foreign key constraints to users for audit columns
await knex.raw(`
ALTER TABLE contract_pricing_schedules
ADD CONSTRAINT fk_contract_pricing_schedules_created_by
FOREIGN KEY (tenant, created_by)
REFERENCES users (tenant, user_id);
`);
await knex.raw(`
ALTER TABLE contract_pricing_schedules
ADD CONSTRAINT fk_contract_pricing_schedules_updated_by
FOREIGN KEY (tenant, updated_by)
REFERENCES users (tenant, user_id);
`);
// Check constraint to ensure end_date is after effective_date
await knex.raw(`
ALTER TABLE contract_pricing_schedules
ADD CONSTRAINT chk_contract_pricing_schedules_date_range
CHECK (end_date IS NULL OR end_date > effective_date);
`);
// Check constraint to ensure custom_rate is positive when provided
await knex.raw(`
ALTER TABLE contract_pricing_schedules
ADD CONSTRAINT chk_contract_pricing_schedules_positive_rate
CHECK (custom_rate IS NULL OR custom_rate >= 0);
`);
console.log('Created contract_pricing_schedules table');
} else {
console.log('contract_pricing_schedules table already exists, skipping');
}
};
exports.down = async function down(knex) {
const exists = await tableExists(knex, 'contract_pricing_schedules');
if (exists) {
await knex.schema.dropTableIfExists('contract_pricing_schedules');
console.log('Dropped contract_pricing_schedules table');
}
};
exports.config = { transaction: false };