Skip to content

Commit

Permalink
feat: add contact object
Browse files Browse the repository at this point in the history
  • Loading branch information
Iamsidar07 committed Aug 19, 2024
1 parent 83eb00a commit 941ced2
Show file tree
Hide file tree
Showing 3 changed files with 424 additions and 0 deletions.
140 changes: 140 additions & 0 deletions packages/api/src/crm/contact/services/leadsquared/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { Injectable } from '@nestjs/common';
import { IContactService } from '@crm/contact/types';
import { CrmObject } from '@crm/@lib/@types';
import axios from 'axios';
import { LoggerService } from '@@core/@core-services/logger/logger.service';
import { PrismaService } from '@@core/@core-services/prisma/prisma.service';
import { ActionType, handle3rdPartyServiceError } from '@@core/utils/errors';
import { EncryptionService } from '@@core/@core-services/encryption/encryption.service';
import { ApiResponse } from '@@core/utils/types';
import { ServiceRegistry } from '../registry.service';
import {
LeadSquaredContactInput,
LeadSquaredContactOutput,
LeadSquaredContactResponse,
} from './types';
import { SyncParam } from '@@core/utils/types/interface';

@Injectable()
export class LeadSquaredService implements IContactService {
constructor(
private prisma: PrismaService,
private logger: LoggerService,
private cryptoService: EncryptionService,
private registry: ServiceRegistry,
) {
this.logger.setContext(
CrmObject.contact.toUpperCase() + ':' + LeadSquaredService.name,
);
this.registry.registerService('zoho', this);
}

formatDate(date: Date): string {
const year = date.getUTCFullYear();
const month = date.getUTCMonth();
const currentDate = date.getUTCDate();
const hours = date.getUTCHours();
const minutes = date.getUTCMinutes();
const seconds = date.getUTCSeconds();
return `${year}-${month}-${currentDate} ${hours}:${minutes}:${seconds}`;
}

async addContact(
contactData: LeadSquaredContactInput,
linkedUserId: string,
): Promise<ApiResponse<LeadSquaredContactOutput>> {
try {
const connection = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
provider_slug: 'leadsquared',
vertical: 'crm',
},
});
const headers = {
'Content-Type': 'application/json',
'x-LSQ-AccessKey': this.cryptoService.decrypt(connection.access_token),
'x-LSQ-SecretKey': this.cryptoService.decrypt(connection.secret_token),
};

const resp = await axios.post(
`${connection.account_url}/v2/LeadManagement.svc/Lead.Create`,
contactData,
{
headers,
},
);
const userId = resp.data['Message']['Id'];
const final_res = await axios.get(
`${connection.account_url}/v2/LeadManagement.svc/Leads.GetById?id=${userId}`,
{
headers,
},
);

return {
data: final_res.data.data[0],
message: 'Leadsquared contact created',
statusCode: 201,
};
} catch (error) {
throw error;
}
}

async sync(
data: SyncParam,
): Promise<ApiResponse<LeadSquaredContactOutput[]>> {
try {
const { linkedUserId } = data;
const connection = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
provider_slug: 'leadsquared',
vertical: 'crm',
},
});
const headers = {
'Content-Type': 'application/json',
'x-LSQ-AccessKey': this.cryptoService.decrypt(connection.access_token),
'x-LSQ-SecretKey': this.cryptoService.decrypt(connection.secret_token),
};

const fromDate = this.formatDate(new Date(0));
const toDate = this.formatDate(new Date());

const resp = await axios.get(
`${connection.account_url}/v2/LeadManagement.svc/Leads.RecentlyModified`,
{
Parameter: {
FromDate: fromDate,
ToDate: toDate,
},
},
{
headers,
},
);
const leads = resp?.data['Leads'].map(
(lead: LeadSquaredContactResponse) => {
const leadSquaredContact: LeadSquaredContactOutput = {};
lead.LeadPropertyList.map(
({ Attribute, Value }: { Attribute: string; Value: string }) => {
leadSquaredContact[Attribute] = Value;
},
);
return leadSquaredContact;
},
);
//this.logger.log('CONTACTS LEADSQUARED ' + JSON.stringify(resp.data.data));
this.logger.log(`Synced leadsquared contacts !`);
return {
data: leads || [],
message: 'Leadsquared contacts retrieved',
statusCode: 200,
};
} catch (error) {
throw error;
}
}
}
176 changes: 176 additions & 0 deletions packages/api/src/crm/contact/services/leadsquared/mappers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { Address } from '@crm/@lib/@types';
import {
UnifiedCrmContactInput,
UnifiedCrmContactOutput,
} from '@crm/contact/types/model.unified';
import { IContactMapper } from '@crm/contact/types';
import { LeadSquaredContactInput, LeadSquaredContactOutput } from './types';
import { Utils } from '@crm/@lib/@utils';
import { MappersRegistry } from '@@core/@core-services/registries/mappers.registry';
import { Injectable } from '@nestjs/common';

@Injectable()
export class LeadSquaredContactMapper implements IContactMapper {
constructor(
private mappersRegistry: MappersRegistry,
private utils: Utils,
) {
this.mappersRegistry.registerService('crm', 'contact', 'zoho', this);
}
desunify(
source: UnifiedCrmContactInput,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): LeadSquaredContactInput {
// Assuming 'email_addresses' array contains at least one email and 'phone_numbers' array contains at least one phone number
const primaryEmail = source.email_addresses?.[0]?.email_address;
const primaryPhone = source.phone_numbers?.[0]?.phone_number;

const result: LeadSquaredContactInput = {
First_Name: source.first_name,
Last_Name: source.last_name,
};
if (primaryEmail) {
result.EmailAddress = primaryEmail;
}
if (primaryPhone && source.phone_numbers?.[0]?.phone_type == 'WORK') {
result.Account_Phone = primaryPhone;
}
if (primaryPhone && source.phone_numbers?.[0]?.phone_type == 'MOBILE') {
result.Mobile = primaryPhone;
}
if (source.addresses && source.addresses[0]) {
result.Account_Street1 = source.addresses[0].street_1;
result.Account_City = source.addresses[0].city;
result.Account_State = source.addresses[0].state;
result.Account_Zip = source.addresses[0].postal_code;
result.Account_Country = source.addresses[0].country;
}
if (source.user_id) {
result.OwnerId = source.user_id;
}
if (customFieldMappings && source.field_mappings) {
for (const [k, v] of Object.entries(source.field_mappings)) {
const mapping = customFieldMappings.find(
(mapping) => mapping.slug === k,
);
if (mapping) {
result[mapping.remote_id] = v;
}
}
}

return result;
}

async unify(
source: LeadSquaredContactOutput | LeadSquaredContactOutput[],
connectionId: string,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): Promise<UnifiedCrmContactOutput | UnifiedCrmContactOutput[]> {
if (!Array.isArray(source)) {
return this.mapSingleContactToUnified(
source,
connectionId,
customFieldMappings,
);
}

// Handling array of HubspotContactOutput
return Promise.all(
source.map((contact) =>
this.mapSingleContactToUnified(
contact,
connectionId,
customFieldMappings,
),
),
);
}

private async mapSingleContactToUnified(
contact: LeadSquaredContactOutput,
connectionId: string,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): Promise<UnifiedCrmContactOutput> {
const field_mappings: { [key: string]: any } = {};
if (customFieldMappings) {
for (const mapping of customFieldMappings) {
field_mappings[mapping.slug] = contact[mapping.remote_id];
}
}
// Constructing email and phone details
const email_addresses =
contact && contact.EmailAddress
? [
{
email_address: contact.EmailAddress,
email_address_type: 'PERSONAL',
},
]
: [];

const phone_numbers = [];

if (contact && contact.Account_Phone) {
phone_numbers.push({
phone_number: contact.Account_Phone,
phone_type: 'WORK',
});
}
if (contact && contact.Mobile) {
phone_numbers.push({
phone_number: contact.Mobile,
phone_type: 'MOBILE',
});
}
if (contact && contact.Account_Fax) {
phone_numbers.push({
phone_number: contact.Account_Fax,
phone_type: 'fax',
});
}
if (contact && contact.Phone) {
phone_numbers.push({
phone_number: contact.Phone,
phone_type: 'home',
});
}

const address: Address = {
street_1: contact.Account_Street1,
city: contact.Account_City,
state: contact.Account_State,
postal_code: contact.Account_Zip,
country: contact.Account_Country,
};

const opts: any = {};
if (contact.OwnerId) {
opts.user_id = await this.utils.getUserUuidFromRemoteId(
contact.OwnerId,
connectionId,
);
}

return {
remote_id: String(contact.pros),
remote_data: contact,
first_name: contact.First_Name ?? null,
last_name: contact.Last_Name ?? null,
email_addresses,
phone_numbers,
field_mappings,
...opts,
addresses: [address],
};
}
}
Loading

0 comments on commit 941ced2

Please sign in to comment.