From c8be128c5c26ecc756cbdac8bb6cfa1514eed709 Mon Sep 17 00:00:00 2001 From: lorentz Date: Tue, 17 Mar 2026 23:56:40 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20companies=20sync=20=E2=80=94=20add=20UD?= =?UTF-8?q?Fs=20and=20fix=20all=20field=20mappings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migration 056: - ADD user_defined_fields JSONB (GIN indexed) - ADD parent_company_id, web_address, create_date, company_category_id - ADD is_client_portal_active, is_task_fire_active, is_comanaged - ADD country_id, bill_to_country_id, bill_to_address_to_use - ADD invoice_email_message_id, purchase_order_template_id - ADD additional_address_information, sic_code, stock_market, etc. entity-mapper.ts mapCompany(): - Fix broken snake_case field refs (was data.invoice_method, data.last_activity_date etc.) - All corrected to actual Autotask camelCase API names (invoiceMethod, lastActivityDate, etc.) - was data.webSiteURL → data.webAddress - was data.taxExempt → data.isTaxExempt - was data.lastTrackedModifiedDateTime (various) → data.lastTrackedModifiedDateTime - Add UDF conversion: userDefinedFields[] array → JSONB {name: value} object - 38 UDFs now stored: PassportalID, MimecastID, MSP Service Model, Short Name, Workstation Lifecycle Plan, Seats (End Users), CSProfileUID, UniFiID, etc. --- lib/utils/entity-mapper.ts | 60 ++++++++++++++----- .../056_companies_udf_and_missing_fields.sql | 31 ++++++++++ 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 migrations/056_companies_udf_and_missing_fields.sql diff --git a/lib/utils/entity-mapper.ts b/lib/utils/entity-mapper.ts index 0a91dd9..c51a500 100644 --- a/lib/utils/entity-mapper.ts +++ b/lib/utils/entity-mapper.ts @@ -96,44 +96,72 @@ export function mapAutotaskToDatabase( * Map Company entity */ function mapCompany(data: any): Record { + // Convert userDefinedFields array → JSONB object { name: value } + const udfs: Record = {}; + if (Array.isArray(data.userDefinedFields)) { + for (const udf of data.userDefinedFields) { + udfs[udf.name] = udf.value ?? null; + } + } + return { id: data.id, company_name: data.companyName || data.name, company_number: data.companyNumber, phone: data.phone, fax: data.fax, - website: data.webSiteURL, + web_address: data.webAddress, address1: data.address1, address2: data.address2, city: data.city, state: data.state, postal_code: data.postalCode, - country: data.country, + country_id: data.countryID, is_active: data.isActive !== undefined ? data.isActive : true, company_type: data.companyType, + company_category_id: data.companyCategoryID, owner_resource_id: data.ownerResourceID, territory_id: data.territoryID, market_segment_id: data.marketSegmentID, competitor_id: data.competitorID, + parent_company_id: data.parentCompanyID, billing_address1: data.billingAddress1, billing_address2: data.billingAddress2, - billing_city: data.billingCity, - billing_state: data.billingState, - billing_postal_code: data.billingPostalCode, - billing_country: data.billingCountry, + billing_city: data.billToCity, + billing_state: data.billToState, + billing_postal_code: data.billToZipCode, + bill_to_country_id: data.billToCountryID, + bill_to_address_to_use: data.billToAddressToUse, + bill_to_attention: data.billToAttention, + additional_address_information: data.additionalAddressInformation, + bill_to_additional_address_info: data.billToAdditionalAddressInformation, tax_id: data.taxID, - tax_exempt: data.taxExempt || false, + tax_exempt: data.isTaxExempt || false, tax_region_id: data.taxRegionID, currency_id: data.currencyID, - invoice_method: data.invoice_method, - invoice_template_id: data.invoice_template_id, - quote_template_id: data.quote_template_id, - key_account_icon: data.key_account_icon, - last_activity_date: data.last_activity_date, - last_tracked_modification_date_time: data.last_tracked_modification_date_time || data.last_modified_date, - api_vendor_id: data.api_vendor_id, - synced_at: data.synced_at, - is_deleted: data.is_deleted || false, + invoice_method: data.invoiceMethod, + invoice_template_id: data.invoiceTemplateID, + invoice_email_message_id: data.invoiceEmailMessageID, + quote_template_id: data.quoteTemplateID, + purchase_order_template_id: data.purchaseOrderTemplateID, + key_account_icon: data.keyAccountIcon, + is_client_portal_active: data.isClientPortalActive || false, + is_task_fire_active: data.isTaskFireActive || false, + is_comanaged: data.isEnabledForComanaged || false, + sic_code: data.sicCode, + stock_market: data.stockMarket, + stock_symbol: data.stockSymbol, + alternate_phone1: data.alternatePhone1, + alternate_phone2: data.alternatePhone2, + survey_company_rating: data.surveyCompanyRating, + asset_value: data.assetValue, + last_activity_date: data.lastActivityDate, + last_tracked_modification_date_time: data.lastTrackedModifiedDateTime, + api_vendor_id: data.apiVendorID, + create_date: data.createDate, + created_by_resource_id: data.createdByResourceID, + user_defined_fields: Object.keys(udfs).length > 0 ? JSON.stringify(udfs) : null, + is_deleted: data.isDeleted || false, }; } diff --git a/migrations/056_companies_udf_and_missing_fields.sql b/migrations/056_companies_udf_and_missing_fields.sql new file mode 100644 index 0000000..d392cd1 --- /dev/null +++ b/migrations/056_companies_udf_and_missing_fields.sql @@ -0,0 +1,31 @@ +-- Migration 056: Add UDF storage + missing fields to companies table + +ALTER TABLE companies + ADD COLUMN IF NOT EXISTS user_defined_fields JSONB, + ADD COLUMN IF NOT EXISTS parent_company_id BIGINT, + ADD COLUMN IF NOT EXISTS web_address VARCHAR(255), + ADD COLUMN IF NOT EXISTS create_date TIMESTAMP WITHOUT TIME ZONE, + ADD COLUMN IF NOT EXISTS company_category_id INTEGER, + ADD COLUMN IF NOT EXISTS is_client_portal_active BOOLEAN DEFAULT false, + ADD COLUMN IF NOT EXISTS is_task_fire_active BOOLEAN DEFAULT false, + ADD COLUMN IF NOT EXISTS is_comanaged BOOLEAN DEFAULT false, + ADD COLUMN IF NOT EXISTS country_id INTEGER, + ADD COLUMN IF NOT EXISTS bill_to_country_id INTEGER, + ADD COLUMN IF NOT EXISTS bill_to_address_to_use INTEGER, + ADD COLUMN IF NOT EXISTS invoice_email_message_id BIGINT, + ADD COLUMN IF NOT EXISTS purchase_order_template_id BIGINT, + ADD COLUMN IF NOT EXISTS additional_address_information TEXT, + ADD COLUMN IF NOT EXISTS bill_to_additional_address_info TEXT, + ADD COLUMN IF NOT EXISTS bill_to_attention VARCHAR(255), + ADD COLUMN IF NOT EXISTS sic_code VARCHAR(50), + ADD COLUMN IF NOT EXISTS stock_market VARCHAR(100), + ADD COLUMN IF NOT EXISTS stock_symbol VARCHAR(50), + ADD COLUMN IF NOT EXISTS alternate_phone1 VARCHAR(50), + ADD COLUMN IF NOT EXISTS alternate_phone2 VARCHAR(50), + ADD COLUMN IF NOT EXISTS survey_company_rating INTEGER, + ADD COLUMN IF NOT EXISTS asset_value NUMERIC(18,4), + ADD COLUMN IF NOT EXISTS created_by_resource_id BIGINT; + +-- Index for UDF queries (e.g. find by PassportalID, MimecastID) +CREATE INDEX IF NOT EXISTS idx_companies_udfs ON companies USING gin(user_defined_fields); +CREATE INDEX IF NOT EXISTS idx_companies_parent ON companies(parent_company_id) WHERE parent_company_id IS NOT NULL;