import { Company } from "../../generated/prisma/client"; import { connectWiseApi } from "../constants"; import { fetchCwCompanyById } from "../modules/cw-utils/fetchCompany"; import { fetchCompanyConfigurations } from "../modules/cw-utils/configurations/fetchCompanyConfigurations"; import { updateCwInternalCompany } from "../modules/cw-utils/updateCompany"; import { fetchCompanySites, fetchCompanySite, serializeCwSite, } from "../modules/cw-utils/sites/companySites"; import { Company as CWCompany, Contact } from "../types/ConnectWiseTypes"; /** * Company Controller * * This class is for creating a controller that can manage company data, * synchronize with external systems, and provide methods for accessing * and updating company information within our internal system. */ export class CompanyController { public readonly id: string; public name: string; public readonly cw_Identifier: string; public readonly cw_CompanyId: number; public cw_Data?: { company: CWCompany; defaultContact: Contact | null; allContacts: Contact[]; }; constructor(companyData: Company, cwData?: typeof this.cw_Data) { this.id = companyData.id; this.name = companyData.name; this.cw_Identifier = companyData.cw_Identifier; this.cw_CompanyId = companyData.cw_CompanyId; this.cw_Data = cwData; } /** * Hydrate CW Data * * Fetches and populates the full ConnectWise company data * (company, default contact, all contacts) if not already loaded. * * @returns {ThisType} */ public async hydrateCwData() { if (this.cw_Data) return this; const cwCompany = await fetchCwCompanyById(this.cw_CompanyId); if (!cwCompany) return this; const allContactsData = await connectWiseApi.get( `${cwCompany._info.contacts_href}&pageSize=1000`, ); // Derive default contact from allContacts instead of a separate CW call const defaultContactId = cwCompany.defaultContact?.id; const defaultContactData = defaultContactId ? ((allContactsData.data as any[]).find( (c: any) => c.id === defaultContactId, ) ?? null) : null; this.cw_Data = { company: cwCompany, defaultContact: defaultContactData, allContacts: allContactsData.data, }; return this; } /** * Refresh Internal Company Data from ConnectWise * * This method fetches the latest company data from ConnectWise and updates * the internal company information accordingly. * * @returns {ThisType} - Updated Controller */ public async refreshFromCW() { const data = await updateCwInternalCompany(this.cw_CompanyId); this.name = data?.name || this.name; return this; } /** * Fetch ConnectWise Company Data * * This method retrieves the latest company data directly from ConnectWise * using the stored ConnectWise Company ID. * * @returns {Company} */ public async fetchCwData(): Promise { const data = await fetchCwCompanyById(this.cw_CompanyId); return data; } /** * Fetch Company Configurations * * This method retrieves the configurations associated with * the company from ConnectWise. * * @returns {ProcessedConfiguration} */ public async fetchConfigurations() { const data = await fetchCompanyConfigurations(this.cw_CompanyId); return data; } /** * Fetch Company Sites * * Retrieves all sites for this company from ConnectWise * and returns them as serialized site objects. */ public async fetchSites() { const sites = await fetchCompanySites(this.cw_CompanyId); return sites.map(serializeCwSite); } /** * Fetch Company Site by ID * * Retrieves a single site by its ConnectWise site ID * and returns a serialized site object. * * @param cwSiteId - The ConnectWise site ID */ public async fetchSite(cwSiteId: number) { const site = await fetchCompanySite(this.cw_CompanyId, cwSiteId); return serializeCwSite(site); } public toJson(opts?: { includeAddress: boolean; includePrimaryContact: boolean; includeAllContacts?: boolean; }) { return { id: this.id, name: this.name, cw_Identifier: this.cw_Identifier, cw_CompanyId: this.cw_CompanyId, cw_Data: { address: !opts?.includeAddress ? undefined : { line1: this.cw_Data?.company.addressLine1, line2: this.cw_Data?.company.addressLine2 ?? null, city: this.cw_Data?.company.city, state: this.cw_Data?.company.state, zip: this.cw_Data?.company.zip, country: this.cw_Data?.company.country ? this.cw_Data.company.country.name : "United States", }, primaryContact: !opts?.includePrimaryContact ? undefined : this.cw_Data?.defaultContact ? { firstName: this.cw_Data.defaultContact.firstName, lastName: this.cw_Data.defaultContact.lastName, cwId: this.cw_Data.defaultContact.id, inactive: this.cw_Data.defaultContact.inactiveFlag, title: this.cw_Data.defaultContact.title, phone: this.cw_Data.defaultContact.defaultPhoneNbr, email: (() => { if (!this.cw_Data?.defaultContact?.communicationItems) return null; return ( this.cw_Data.defaultContact.communicationItems.find( (v) => v.type.name === "Email", )?.value ?? null ); })(), } : null, allContacts: !opts?.includeAllContacts ? undefined : this.cw_Data?.allContacts.map((contact) => ({ firstName: contact.firstName, lastName: contact.lastName, cwId: contact.id, inactive: contact.inactiveFlag, title: contact.title, phone: contact.defaultPhoneNbr, email: (() => { if (!contact.communicationItems) return null; return ( contact.communicationItems.find( (v) => v.type.name === "Email", )?.value ?? null ); })(), })), }, }; } }