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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
222 lines
6.7 KiB
TypeScript
222 lines
6.7 KiB
TypeScript
import { Knex } from 'knex';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { BillingCycleType } from 'server/src/interfaces/billing.interfaces';
|
|
import { TenantEntity } from 'server/src/interfaces/index';
|
|
import { IClient, IClientLocation } from 'server/src/interfaces/client.interfaces';
|
|
import type { ProductCode } from '@alga-psa/types';
|
|
|
|
/**
|
|
* Creates a new tenant in the database
|
|
* @param db Knex database instance
|
|
* @param name Optional tenant name (defaults to "Test Tenant")
|
|
* @returns The ID of the created tenant
|
|
*/
|
|
export async function createTenant(
|
|
db: Knex,
|
|
name: string = 'Test Tenant',
|
|
options: { productCode?: ProductCode } = {}
|
|
): Promise<string> {
|
|
const tenantId = uuidv4();
|
|
const now = new Date().toISOString();
|
|
|
|
await db('tenants').insert({
|
|
tenant: tenantId,
|
|
client_name: name,
|
|
phone_number: '555-0100',
|
|
email: `test-${tenantId.substring(0, 8)}@example.com`,
|
|
created_at: now,
|
|
updated_at: now,
|
|
payment_platform_id: `test-platform-${tenantId.substring(0, 8)}`,
|
|
payment_method_id: `test-method-${tenantId.substring(0, 8)}`,
|
|
auth_service_id: `test-auth-${tenantId.substring(0, 8)}`,
|
|
plan: 'pro',
|
|
product_code: options.productCode ?? 'psa',
|
|
});
|
|
|
|
return tenantId;
|
|
}
|
|
|
|
/**
|
|
* Creates a new client in the database
|
|
* @param db Knex database instance
|
|
* @param tenantId ID of the tenant this client belongs to
|
|
* @param name Optional client name (defaults to "Test Client")
|
|
* @param options Optional additional client properties
|
|
* @returns The ID of the created client
|
|
*/
|
|
export async function createClient(
|
|
db: Knex,
|
|
tenantId: string,
|
|
name: string = 'Test Client',
|
|
options: Partial<IClient> = {}
|
|
): Promise<string> {
|
|
const clientId = uuidv4();
|
|
const now = new Date().toISOString();
|
|
|
|
const client: IClient = {
|
|
client_id: clientId,
|
|
client_name: name,
|
|
tenant: tenantId,
|
|
billing_cycle: options.billing_cycle || 'monthly' as BillingCycleType,
|
|
is_tax_exempt: options.is_tax_exempt ?? false,
|
|
url: options.url || '',
|
|
created_at: now,
|
|
updated_at: now,
|
|
is_inactive: options.is_inactive ?? false,
|
|
credit_balance: options.credit_balance ?? 0,
|
|
client_type: options.client_type,
|
|
tax_id_number: options.tax_id_number,
|
|
notes: options.notes,
|
|
notes_document_id: options.notes_document_id,
|
|
properties: options.properties || {},
|
|
payment_terms: options.payment_terms,
|
|
credit_limit: options.credit_limit,
|
|
preferred_payment_method: options.preferred_payment_method,
|
|
auto_invoice: options.auto_invoice,
|
|
invoice_delivery_method: options.invoice_delivery_method,
|
|
region_code: options.region_code,
|
|
tax_exemption_certificate: options.tax_exemption_certificate,
|
|
timezone: options.timezone,
|
|
invoice_template_id: options.invoice_template_id,
|
|
billing_contact_id: options.billing_contact_id,
|
|
billing_email: options.billing_email
|
|
};
|
|
|
|
await db('clients').insert(client);
|
|
|
|
return clientId;
|
|
}
|
|
|
|
/**
|
|
* Creates a new client location in the database
|
|
* @param db Knex database instance
|
|
* @param clientId ID of the client this location belongs to
|
|
* @param tenantId ID of the tenant this location belongs to
|
|
* @param options Optional location properties
|
|
* @returns The ID of the created location
|
|
*/
|
|
export async function createClientLocation(
|
|
db: Knex,
|
|
clientId: string,
|
|
tenantId: string,
|
|
options: Partial<IClientLocation> = {}
|
|
): Promise<string> {
|
|
const locationId = uuidv4();
|
|
const now = new Date();
|
|
|
|
const location: IClientLocation = {
|
|
location_id: locationId,
|
|
client_id: clientId,
|
|
tenant: tenantId,
|
|
address_line1: options.address_line1 || '123 Test St',
|
|
address_line2: options.address_line2,
|
|
city: options.city || 'Test City',
|
|
state_province: options.state_province,
|
|
postal_code: options.postal_code,
|
|
country_code: options.country_code || 'US',
|
|
country_name: options.country_name || 'United States',
|
|
region_code: options.region_code || 'US-NY',
|
|
created_at: now.toISOString(),
|
|
updated_at: now.toISOString()
|
|
};
|
|
|
|
await db('client_locations').insert(location);
|
|
|
|
return locationId;
|
|
}
|
|
|
|
/**
|
|
* Creates a new user in the database
|
|
* @param db Knex database instance
|
|
* @param tenantId ID of the tenant this user belongs to
|
|
* @param options Optional user properties
|
|
* @returns The ID of the created user
|
|
*/
|
|
export async function createUser(
|
|
db: Knex,
|
|
tenantId: string,
|
|
options: {
|
|
email?: string;
|
|
username?: string;
|
|
first_name?: string;
|
|
last_name?: string;
|
|
hashed_password?: string;
|
|
user_type?: 'client' | 'internal';
|
|
two_factor_enabled?: boolean;
|
|
two_factor_secret?: string;
|
|
is_google_user?: boolean;
|
|
is_inactive?: boolean;
|
|
contact_id?: string;
|
|
phone?: string;
|
|
timezone?: string;
|
|
} = {}
|
|
): Promise<string> {
|
|
const userId = uuidv4();
|
|
const now = new Date();
|
|
|
|
const user = {
|
|
user_id: userId,
|
|
tenant: tenantId,
|
|
username: options.username || `test.user.${userId}`,
|
|
first_name: options.first_name || 'Test',
|
|
last_name: options.last_name || 'User',
|
|
email: options.email || `test.user.${userId}@example.com`,
|
|
hashed_password: options.hashed_password || 'hashed_password_here',
|
|
created_at: now,
|
|
two_factor_enabled: options.two_factor_enabled ?? false,
|
|
two_factor_secret: options.two_factor_secret,
|
|
is_google_user: options.is_google_user ?? false,
|
|
is_inactive: options.is_inactive ?? false,
|
|
user_type: options.user_type || 'internal',
|
|
contact_id: options.contact_id,
|
|
phone: options.phone,
|
|
timezone: options.timezone
|
|
};
|
|
|
|
await db('users').insert(user);
|
|
|
|
return userId;
|
|
}
|
|
|
|
/**
|
|
* Creates a complete test environment with tenant, client, location, and user
|
|
* @param db Knex database instance
|
|
* @param options Optional properties for the created entities
|
|
* @returns Object containing the created IDs
|
|
*/
|
|
export async function createTestEnvironment(
|
|
db: Knex,
|
|
options: {
|
|
clientName?: string;
|
|
userName?: string;
|
|
billingCycle?: BillingCycleType;
|
|
} = {}
|
|
): Promise<{
|
|
tenantId: string;
|
|
clientId: string;
|
|
locationId: string;
|
|
userId: string;
|
|
}> {
|
|
const tenantId = await createTenant(db);
|
|
const clientId = await createClient(db, tenantId, options.clientName, {
|
|
billing_cycle: options.billingCycle || 'monthly'
|
|
});
|
|
// For now, skip location creation due to region_code foreign key constraint
|
|
// const locationId = await createClientLocation(db, clientId, tenantId);
|
|
const locationId = ''; // Empty for now
|
|
const userId = await createUser(db, tenantId, {
|
|
username: options.userName
|
|
});
|
|
|
|
return { tenantId, clientId, locationId, userId };
|
|
}
|
|
|
|
/**
|
|
* Helper function to generate a timestamp for test data
|
|
* @param date Optional date to convert (defaults to current time)
|
|
* @returns ISO string timestamp
|
|
*/
|
|
export function getTestTimestamp(date: Date = new Date()): string {
|
|
return date.toISOString();
|
|
}
|