PSA/server/migrations/20260611100200_create_accounting_sync_task_definitions.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

118 lines
3.8 KiB
JavaScript

/**
* Migration: system task definitions + shared form for accounting sync
* exceptions (drift, unmapped payments, export errors, unlinked customers,
* expired connections). Supersedes the never-wired qbo_mapping_error type,
* which is left in place for any existing tasks.
*/
const FORM_NAME = 'accounting-sync-exception-form';
const TASK_TYPES = [
{
task_type: 'accounting_sync_drift',
name: 'Resolve accounting sync drift',
description: 'An exported document was changed, voided, or deleted in the accounting system.'
},
{
task_type: 'accounting_sync_unmapped_payment',
name: 'Resolve unmapped accounting payment',
description: 'A payment in the accounting system references an invoice Alga does not know.'
},
{
task_type: 'accounting_sync_export_error',
name: 'Resolve accounting export error',
description: 'A scheduled accounting export failed validation or delivery.'
},
{
task_type: 'accounting_sync_customer_unlinked',
name: 'Re-link accounting customer',
description: 'A linked accounting customer was deleted, merged, or made inactive.'
},
{
task_type: 'accounting_connection_expired',
name: 'Reconnect accounting integration',
description: 'The accounting connection failed authentication and needs to be reconnected.'
}
];
const FORM = {
json_schema: {
type: 'object',
properties: {
message: { type: 'string', title: 'What happened', readOnly: true },
details: { type: 'string', title: 'Details', readOnly: true },
settingsLink: {
type: 'string',
title: 'Accounting Integration Settings',
format: 'uri',
description: 'Open the accounting integration settings'
}
},
required: ['message']
},
ui_schema: {
message: { 'ui:widget': 'AlertWidget', 'ui:options': { alertType: 'warning' } },
details: { 'ui:widget': 'textarea', 'ui:options': { rows: 6 } },
settingsLink: {
'ui:widget': 'ButtonLinkWidget',
'ui:options': { buttonText: 'Open Integration Settings', target: '_blank' }
},
'ui:order': ['message', 'details', 'settingsLink']
},
default_values: {
message: '${contextData.message}',
details: '${contextData.details}',
settingsLink: '/msp/settings?tab=integrations&category=accounting'
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.transaction(async (trx) => {
const existingForm = await trx('system_workflow_form_definitions').where({ name: FORM_NAME }).first();
if (!existingForm) {
await trx('system_workflow_form_definitions').insert({
name: FORM_NAME,
description: 'Shared form for accounting sync exceptions.',
version: '1.0',
status: 'ACTIVE',
json_schema: JSON.stringify(FORM.json_schema),
ui_schema: JSON.stringify(FORM.ui_schema),
default_values: JSON.stringify(FORM.default_values),
created_by: null,
created_at: new Date(),
updated_at: new Date()
});
}
for (const task of TASK_TYPES) {
const existing = await trx('system_workflow_task_definitions').where({ task_type: task.task_type }).first();
if (!existing) {
await trx('system_workflow_task_definitions').insert({
...task,
form_id: FORM_NAME,
form_type: 'system',
default_priority: 'medium',
created_by: null,
created_at: new Date(),
updated_at: new Date()
});
}
}
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.transaction(async (trx) => {
await trx('system_workflow_task_definitions')
.whereIn('task_type', TASK_TYPES.map((task) => task.task_type))
.del();
await trx('system_workflow_form_definitions').where({ name: FORM_NAME }).del();
});
};