Skip to content

Commit

Permalink
feat(integration-templates): [nan 1235] unanet integration (#2399)
Browse files Browse the repository at this point in the history
## Describe your changes
Adds several actions to unanet

## Issue ticket number and link
NAN-1235

## Checklist before requesting a review (skip if just adding/editing
APIs & templates)
- [ ] I added tests, otherwise the reason is: 
- [ ] I added observability, otherwise the reason is:
- [ ] I added analytics, otherwise the reason is:
  • Loading branch information
khaliqgant committed Jun 24, 2024
1 parent f55cc3c commit 5713e95
Show file tree
Hide file tree
Showing 18 changed files with 788 additions and 146 deletions.
16 changes: 16 additions & 0 deletions integration-templates/unanet/actions/create-company.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { NangoAction, Entity, Company } from '../../models';

import { getOrCreateCompany } from '../helpers/get-or-create-company.js';

export default async function runAction(nango: NangoAction, input: Entity): Promise<Company> {
if (!input?.name) {
throw new nango.ActionError({
message: 'Name is required to create a company',
code: 'missing_name'
});
}

const company = await getOrCreateCompany(nango, input.name);

return company;
}
31 changes: 31 additions & 0 deletions integration-templates/unanet/actions/create-lead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { NangoAction, Lead } from '../../models';
import type { UnanetLead } from '../types';
import { toLead } from '../mappers/to-lead.js';

export default async function runAction(nango: NangoAction, input: Lead): Promise<Lead> {
if (!input?.name) {
throw new nango.ActionError({
message: 'Name is required to create a lead',
code: 'missing_name'
});
}

const data: UnanetLead = {
Name: input.name
};

if (input.activities) {
const note = input.activities.map((activity) => {
return activity.message;
});

data.Notes = note.join(',');
}

const response = await nango.post({
endpoint: '/api/leads',
data: [data]
});

return toLead(response.data[0]);
}
56 changes: 56 additions & 0 deletions integration-templates/unanet/actions/create-opportunity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { NangoAction, Opportunity } from '../../models';
import type { CreateUnanetOpportunity } from '../types';

import { getOrCreateCompany } from '../helpers/get-or-create-company.js';
import { findStage } from '../helpers/find-stage.js';
import { toOpportunity } from '../mappers/to-opportunity.js';

export default async function runAction(nango: NangoAction, input: Opportunity): Promise<Opportunity> {
if (!input.companyName) {
throw new nango.ActionError({
message: 'Company Name is required to create an opportunity',
code: 'missing_company_name'
});
}

if (!input.name) {
throw new nango.ActionError({
message: 'Name is required to create an opportunity',
code: 'missing_name'
});
}

if (!input.stage) {
throw new nango.ActionError({
message: 'Stage is required to create an opportunity',
code: 'missing_stage'
});
}

const company = await getOrCreateCompany(nango, input.companyName);

const stage = await findStage(nango, input.stage);

if (!stage) {
throw new nango.ActionError({
message: 'Stage not found. Please use a valid stage',
code: 'stage_not_found'
});
}

const opportunity: CreateUnanetOpportunity = {
ClientId: Number(company.id),
ClientName: company.name,
OpportunityName: input.name,
Stage: input.stage,
StageId: stage.id,
ActiveInd: Number(input.active || true)
};

const response = await nango.post({
endpoint: '/api/opportunities',
data: [opportunity]
});

return toOpportunity(response.data[0]);
}
16 changes: 16 additions & 0 deletions integration-templates/unanet/actions/get-company.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { NangoAction, Entity, Company } from '../../models';

import { getCompany } from '../helpers/get-or-create-company.js';

export default async function runAction(nango: NangoAction, input: Entity): Promise<Company | null> {
if (!input?.name) {
throw new nango.ActionError({
message: 'Name is required to create a company',
code: 'missing_name'
});
}

const company = await getCompany(nango, input.name);

return company;
}
18 changes: 18 additions & 0 deletions integration-templates/unanet/actions/get-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { NangoAction, Entity, Schema } from '../../models';

export default async function runAction(nango: NangoAction, input: Entity): Promise<Schema[]> {
if (!input?.name) {
throw new nango.ActionError({
message: 'Name is required to look up an entity schema',
code: 'missing_name'
});
}

const response = await nango.get<Schema[]>({
endpoint: `/api/${input.name}/schema`
});

const { data } = response;

return data;
}
13 changes: 13 additions & 0 deletions integration-templates/unanet/actions/list-stages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { NangoAction, Stage } from '../../models';
import type { UnanetStage } from '../types';
import { toStage } from '../mappers/to-stage.js';

export default async function runAction(nango: NangoAction, _input?: void): Promise<Stage[]> {
const response = await nango.get<UnanetStage[]>({
endpoint: '/api/opportunities/stage'
});

const { data } = response;

return data.map(toStage);
}
35 changes: 35 additions & 0 deletions integration-templates/unanet/actions/update-lead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { NangoAction, Lead } from '../../models';
import type { UnanetLead } from '../types';
import { toLead } from '../mappers/to-lead.js';

export default async function runAction(nango: NangoAction, input: Lead): Promise<Lead> {
if (!input.id) {
throw new nango.ActionError({
message: 'ID is required to update a lead',
code: 'missing_id'
});
}

const data: UnanetLead = {
Name: input.name
};

if (input.description) {
data.Description = input.description;
}

if (input.activities) {
const note = input.activities.map((activity) => {
return activity.message;
});

data.Notes = note.join(',');
}

const response = await nango.put({
endpoint: `/api/leads/${input.id}`,
data
});

return toLead(response.data);
}
16 changes: 16 additions & 0 deletions integration-templates/unanet/helpers/find-stage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Stage, NangoAction } from '../../models';
import { toStage } from '../mappers/to-stage.js';

export async function findStage(nango: NangoAction, name: string): Promise<Stage | null> {
const response = await nango.get({
endpoint: `/api/opportunities/stage/search?q=StageName:"${name}"`
});

const { data } = response;

if (data && data.length > 0) {
return toStage(data[0]);
}

return null;
}
35 changes: 35 additions & 0 deletions integration-templates/unanet/helpers/get-or-create-company.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Company, NangoAction } from '../../models';
import { toCompany } from '../mappers/to-company.js';

export async function getCompany(nango: NangoAction, name: string): Promise<Company | null> {
const response = await nango.get({
endpoint: `/api/companies/search?q=Name:"${name}"`
});

const { data } = response;

if (data.length > 0) {
return toCompany(data[0]);
}

return null;
}

export async function getOrCreateCompany(nango: NangoAction, name: string): Promise<Company> {
const foundCompany = await getCompany(nango, name);

if (foundCompany) {
return foundCompany;
}

const company = await nango.post({
endpoint: '/api/companies',
data: [
{
Name: name
}
]
});

return toCompany(company.data);
}
12 changes: 12 additions & 0 deletions integration-templates/unanet/mappers/to-company.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { UnanetCompany } from '../types';
import type { Company } from '../../models';

export function toCompany(company: UnanetCompany): Company {
return {
id: company.CompanyId.toString(),
name: company.Name,
externalId: company.ExternalId,
shortName: company.Acronym,
description: company.Notes
};
}
26 changes: 26 additions & 0 deletions integration-templates/unanet/mappers/to-lead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Lead } from '../../models';
import type { UnanetLead } from '../types';

export function toLead(unanetLead: UnanetLead): Lead {
if (!unanetLead.LeadId) {
throw new Error('LeadId is required');
}

const lead: Lead = {
id: unanetLead.LeadId?.toString(),
name: unanetLead.Name,
description: unanetLead.Description || '',
createdAt: unanetLead.CreateDate ? new Date(unanetLead.CreateDate).toISOString() : '',
updatedAt: unanetLead.ModifyDate ? new Date(unanetLead.ModifyDate).toISOString() : ''
};

if (unanetLead.StageId) {
lead.stage = {
id: unanetLead.StageId,
name: unanetLead.StageName || '',
status: unanetLead.StageTypeName || ''
};
}

return lead;
}
14 changes: 14 additions & 0 deletions integration-templates/unanet/mappers/to-opportunity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Opportunity } from '../../models';
import type { UnanetOpportunity } from '../types';

export function toOpportunity(opportunity: UnanetOpportunity): Opportunity {
return {
name: opportunity.OpportunityName,
description: '',
id: opportunity.OpportunityId.toString(),
externalId: opportunity.ExternalId,
companyName: opportunity.ClientName,
stage: opportunity.Stage,
active: opportunity.ActiveInd === 1
};
}
10 changes: 10 additions & 0 deletions integration-templates/unanet/mappers/to-stage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Stage } from '../../models';
import type { UnanetStage } from '../types';

export function toStage(stage: UnanetStage): Stage {
return {
id: stage.StageID,
name: stage.StageName,
status: stage.StageType.StageTypeName
};
}
Loading

0 comments on commit 5713e95

Please sign in to comment.