fetch and save copper (#1472)

Fetch and save Copper CRM
This commit is contained in:
Xianny 2019-01-08 13:50:51 -08:00 committed by GitHub
parent 4689f20b86
commit 27fc640a9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 3517 additions and 7 deletions

View File

@ -0,0 +1,103 @@
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
const leads = new Table({
name: 'raw.copper_leads',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true },
{ name: 'name', type: 'varchar', isNullable: true },
{ name: 'first_name', type: 'varchar', isNullable: true },
{ name: 'last_name', type: 'varchar', isNullable: true },
{ name: 'middle_name', type: 'varchar', isNullable: true },
{ name: 'assignee_id', type: 'bigint', isNullable: true },
{ name: 'company_name', type: 'varchar', isNullable: true },
{ name: 'customer_source_id', type: 'bigint', isNullable: true },
{ name: 'monetary_value', type: 'integer', isNullable: true },
{ name: 'status', type: 'varchar' },
{ name: 'status_id', type: 'bigint' },
{ name: 'title', type: 'varchar', isNullable: true },
{ name: 'date_created', type: 'bigint' },
{ name: 'date_modified', type: 'bigint', isPrimary: true },
],
});
const activities = new Table({
name: 'raw.copper_activities',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true },
{ name: 'parent_id', type: 'bigint' },
{ name: 'parent_type', type: 'varchar' },
{ name: 'type_id', type: 'bigint' },
{ name: 'type_category', type: 'varchar' },
{ name: 'type_name', type: 'varchar', isNullable: true },
{ name: 'user_id', type: 'bigint' },
{ name: 'old_value_id', type: 'bigint', isNullable: true },
{ name: 'old_value_name', type: 'varchar', isNullable: true },
{ name: 'new_value_id', type: 'bigint', isNullable: true },
{ name: 'new_value_name', type: 'varchar', isNullable: true },
{ name: 'date_created', type: 'bigint' },
{ name: 'date_modified', type: 'bigint', isPrimary: true },
],
});
const opportunities = new Table({
name: 'raw.copper_opportunities',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true },
{ name: 'name', type: 'varchar' },
{ name: 'assignee_id', isNullable: true, type: 'bigint' },
{ name: 'close_date', isNullable: true, type: 'varchar' },
{ name: 'company_id', isNullable: true, type: 'bigint' },
{ name: 'company_name', isNullable: true, type: 'varchar' },
{ name: 'customer_source_id', isNullable: true, type: 'bigint' },
{ name: 'loss_reason_id', isNullable: true, type: 'bigint' },
{ name: 'pipeline_id', type: 'bigint' },
{ name: 'pipeline_stage_id', type: 'bigint' },
{ name: 'primary_contact_id', isNullable: true, type: 'bigint' },
{ name: 'priority', isNullable: true, type: 'varchar' },
{ name: 'status', type: 'varchar' },
{ name: 'interaction_count', type: 'bigint' },
{ name: 'monetary_value', isNullable: true, type: 'integer' },
{ name: 'win_probability', isNullable: true, type: 'integer' },
{ name: 'date_created', type: 'bigint' },
{ name: 'date_modified', type: 'bigint', isPrimary: true },
{ name: 'custom_fields', type: 'jsonb' },
],
});
const activityTypes = new Table({
name: 'raw.copper_activity_types',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true },
{ name: 'category', type: 'varchar' },
{ name: 'name', type: 'varchar' },
{ name: 'is_disabled', type: 'boolean', isNullable: true },
{ name: 'count_as_interaction', type: 'boolean', isNullable: true },
],
});
const customFields = new Table({
name: 'raw.copper_custom_fields',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true },
{ name: 'name', type: 'varchar' },
{ name: 'data_type', type: 'varchar' },
{ name: 'field_type', type: 'varchar', isNullable: true },
],
});
export class CreateCopperTables1544055699284 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.createTable(leads);
await queryRunner.createTable(activities);
await queryRunner.createTable(opportunities);
await queryRunner.createTable(activityTypes);
await queryRunner.createTable(customFields);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable(leads.name);
await queryRunner.dropTable(activities.name);
await queryRunner.dropTable(opportunities.name);
await queryRunner.dropTable(activityTypes.name);
await queryRunner.dropTable(customFields.name);
}
}

View File

@ -16,7 +16,7 @@
"test:coverage": "nyc npm run test:all --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"clean": "shx rm -rf lib",
"lint": "tslint --project . --format stylish --exclude ./migrations/**/*",
"lint": "tslint --project . --format stylish --exclude ./migrations/**/* --exclude ./test/fixtures/**/**/*.json",
"migrate:run": "yarn typeorm migration:run --config ./lib/src/ormconfig",
"migrate:revert": "yarn typeorm migration:revert --config ./lib/src/ormconfig",
"migrate:create": "yarn typeorm migration:create --config ./lib/src/ormconfig --dir migrations"

View File

@ -0,0 +1,126 @@
import { fetchAsync } from '@0x/utils';
import Bottleneck from 'bottleneck';
import {
CopperActivityTypeCategory,
CopperActivityTypeResponse,
CopperCustomFieldResponse,
CopperSearchResponse,
} from '../../parsers/copper';
const HTTP_OK_STATUS = 200;
const COPPER_URI = 'https://api.prosperworks.com/developer_api/v1';
const DEFAULT_PAGINATION_PARAMS = {
page_size: 200,
sort_by: 'date_modified',
sort_direction: 'desc',
};
export type CopperSearchParams = CopperLeadSearchParams | CopperActivitySearchParams | CopperOpportunitySearchParams;
export interface CopperLeadSearchParams {
page_number?: number;
}
export interface CopperActivitySearchParams {
minimum_activity_date: number;
page_number?: number;
}
export interface CopperOpportunitySearchParams {
sort_by: string; // must override the default 'date_modified' for this endpoint
page_number?: number;
}
export enum CopperEndpoint {
Leads = '/leads/search',
Opportunities = '/opportunities/search',
Activities = '/activities/search',
}
const ONE_SECOND = 1000;
function httpErrorCheck(response: Response): void {
if (response.status !== HTTP_OK_STATUS) {
throw new Error(`HTTP error while scraping Copper: [${JSON.stringify(response)}]`);
}
}
export class CopperSource {
private readonly _accessToken: string;
private readonly _userEmail: string;
private readonly _defaultHeaders: any;
private readonly _limiter: Bottleneck;
constructor(maxConcurrentRequests: number, accessToken: string, userEmail: string) {
this._accessToken = accessToken;
this._userEmail = userEmail;
this._defaultHeaders = {
'Content-Type': 'application/json',
'X-PW-AccessToken': this._accessToken,
'X-PW-Application': 'developer_api',
'X-PW-UserEmail': this._userEmail,
};
this._limiter = new Bottleneck({
minTime: ONE_SECOND / maxConcurrentRequests,
reservoir: 30,
reservoirRefreshAmount: 30,
reservoirRefreshInterval: maxConcurrentRequests,
});
}
public async fetchNumberOfPagesAsync(endpoint: CopperEndpoint, searchParams?: CopperSearchParams): Promise<number> {
const resp = await this._limiter.schedule(() =>
fetchAsync(COPPER_URI + endpoint, {
method: 'POST',
body: JSON.stringify({ ...DEFAULT_PAGINATION_PARAMS, ...searchParams }),
headers: this._defaultHeaders,
}),
);
httpErrorCheck(resp);
// total number of records that match the request parameters
if (resp.headers.has('X-Pw-Total')) {
const totalRecords: number = parseInt(resp.headers.get('X-Pw-Total') as string, 10); // tslint:disable-line:custom-no-magic-numbers
return Math.ceil(totalRecords / DEFAULT_PAGINATION_PARAMS.page_size);
} else {
return 1;
}
}
public async fetchSearchResultsAsync<T extends CopperSearchResponse>(
endpoint: CopperEndpoint,
searchParams?: CopperSearchParams,
): Promise<T[]> {
const request = { ...DEFAULT_PAGINATION_PARAMS, ...searchParams };
const response = await this._limiter.schedule(() =>
fetchAsync(COPPER_URI + endpoint, {
method: 'POST',
body: JSON.stringify(request),
headers: this._defaultHeaders,
}),
);
httpErrorCheck(response);
const json: T[] = await response.json();
return json;
}
public async fetchActivityTypesAsync(): Promise<Map<CopperActivityTypeCategory, CopperActivityTypeResponse[]>> {
const response = await this._limiter.schedule(() =>
fetchAsync(`${COPPER_URI}/activity_types`, {
method: 'GET',
headers: this._defaultHeaders,
}),
);
httpErrorCheck(response);
return response.json();
}
public async fetchCustomFieldsAsync(): Promise<CopperCustomFieldResponse[]> {
const response = await this._limiter.schedule(() =>
fetchAsync(`${COPPER_URI}/custom_field_definitions`, {
method: 'GET',
headers: this._defaultHeaders,
}),
);
httpErrorCheck(response);
return response.json();
}
}

View File

@ -0,0 +1,41 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { numberToBigIntTransformer } from '../utils';
@Entity({ name: 'copper_activities', schema: 'raw' })
export class CopperActivity {
@PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
public id!: number;
@Index()
@Column({ name: 'parent_id', type: 'bigint', transformer: numberToBigIntTransformer })
public parentId!: number;
@Column({ name: 'parent_type', type: 'varchar' })
public parentType!: string;
// join with CopperActivityType
@Index()
@Column({ name: 'type_id', type: 'bigint', transformer: numberToBigIntTransformer })
public typeId!: number;
@Column({ name: 'type_category', type: 'varchar' })
public typeCategory!: string;
@Column({ name: 'type_name', type: 'varchar', nullable: true })
public typeName?: string;
@Column({ name: 'user_id', type: 'bigint', transformer: numberToBigIntTransformer })
public userId!: number;
@Column({ name: 'old_value_id', type: 'bigint', nullable: true, transformer: numberToBigIntTransformer })
public oldValueId?: number;
@Column({ name: 'old_value_name', type: 'varchar', nullable: true })
public oldValueName?: string;
@Column({ name: 'new_value_id', type: 'bigint', nullable: true, transformer: numberToBigIntTransformer })
public newValueId?: number;
@Column({ name: 'new_value_name', type: 'varchar', nullable: true })
public newValueName?: string;
@Index()
@Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
public dateCreated!: number;
@PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
public dateModified!: number;
}

View File

@ -0,0 +1,17 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { numberToBigIntTransformer } from '../utils';
@Entity({ name: 'copper_activity_types', schema: 'raw' })
export class CopperActivityType {
@PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
public id!: number;
@Column({ name: 'category', type: 'varchar' })
public category!: string;
@Column({ name: 'name', type: 'varchar' })
public name!: string;
@Column({ name: 'is_disabled', type: 'boolean', nullable: true })
public isDisabled?: boolean;
@Column({ name: 'count_as_interaction', type: 'boolean', nullable: true })
public countAsInteraction?: boolean;
}

View File

@ -0,0 +1,15 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { numberToBigIntTransformer } from '../utils';
@Entity({ name: 'copper_custom_fields', schema: 'raw' })
export class CopperCustomField {
@PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
public id!: number;
@Column({ name: 'data_type', type: 'varchar' })
public dataType!: string;
@Column({ name: 'field_type', type: 'varchar', nullable: true })
public fieldType?: string;
@Column({ name: 'name', type: 'varchar' })
public name!: string;
}

View File

@ -0,0 +1,38 @@
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
import { numberToBigIntTransformer } from '../utils';
@Entity({ name: 'copper_leads', schema: 'raw' })
export class CopperLead {
@PrimaryColumn({ type: 'bigint', transformer: numberToBigIntTransformer })
public id!: number;
@Column({ name: 'name', type: 'varchar', nullable: true })
public name?: string;
@Column({ name: 'first_name', type: 'varchar', nullable: true })
public firstName?: string;
@Column({ name: 'last_name', type: 'varchar', nullable: true })
public lastName?: string;
@Column({ name: 'middle_name', type: 'varchar', nullable: true })
public middleName?: string;
@Column({ name: 'assignee_id', type: 'bigint', transformer: numberToBigIntTransformer, nullable: true })
public assigneeId?: number;
@Column({ name: 'company_name', type: 'varchar', nullable: true })
public companyName?: string;
@Column({ name: 'customer_source_id', type: 'bigint', transformer: numberToBigIntTransformer, nullable: true })
public customerSourceId?: number;
@Column({ name: 'monetary_value', type: 'integer', nullable: true })
public monetaryValue?: number;
@Column({ name: 'status', type: 'varchar' })
public status!: string;
@Column({ name: 'status_id', type: 'bigint', transformer: numberToBigIntTransformer })
public statusId!: number;
@Column({ name: 'title', type: 'varchar', nullable: true })
public title?: string;
@Index()
@Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
public dateCreated!: number;
@PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
public dateModified!: number;
}

View File

@ -0,0 +1,45 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { numberToBigIntTransformer } from '../utils';
@Entity({ name: 'copper_opportunities', schema: 'raw' })
export class CopperOpportunity {
@PrimaryColumn({ name: 'id', type: 'bigint', transformer: numberToBigIntTransformer })
public id!: number;
@Column({ name: 'name', type: 'varchar' })
public name!: string;
@Column({ name: 'assignee_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
public assigneeId?: number;
@Column({ name: 'close_date', nullable: true, type: 'varchar' })
public closeDate?: string;
@Column({ name: 'company_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
public companyId?: number;
@Column({ name: 'company_name', nullable: true, type: 'varchar' })
public companyName?: string;
@Column({ name: 'customer_source_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
public customerSourceId?: number;
@Column({ name: 'loss_reason_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
public lossReasonId?: number;
@Column({ name: 'pipeline_id', type: 'bigint', transformer: numberToBigIntTransformer })
public pipelineId!: number;
@Column({ name: 'pipeline_stage_id', type: 'bigint', transformer: numberToBigIntTransformer })
public pipelineStageId!: number;
@Column({ name: 'primary_contact_id', nullable: true, type: 'bigint', transformer: numberToBigIntTransformer })
public primaryContactId?: number;
@Column({ name: 'priority', nullable: true, type: 'varchar' })
public priority?: string;
@Column({ name: 'status', type: 'varchar' })
public status!: string;
@Column({ name: 'interaction_count', type: 'bigint', transformer: numberToBigIntTransformer })
public interactionCount!: number;
@Column({ name: 'monetary_value', nullable: true, type: 'integer' })
public monetaryValue?: number;
@Column({ name: 'win_probability', nullable: true, type: 'integer' })
public winProbability?: number;
@Column({ name: 'date_created', type: 'bigint', transformer: numberToBigIntTransformer })
public dateCreated!: number;
@PrimaryColumn({ name: 'date_modified', type: 'bigint', transformer: numberToBigIntTransformer })
public dateModified!: number;
@Column({ name: 'custom_fields', type: 'jsonb' })
public customFields!: { [key: number]: number };
}

View File

@ -16,4 +16,10 @@ export { TokenOrderbookSnapshot } from './token_order';
export { Transaction } from './transaction';
export { ERC20ApprovalEvent } from './erc20_approval_event';
export { CopperLead } from './copper_lead';
export { CopperActivity } from './copper_activity';
export { CopperOpportunity } from './copper_opportunity';
export { CopperActivityType } from './copper_activity_type';
export { CopperCustomField } from './copper_custom_field';
export type ExchangeEvent = ExchangeFillEvent | ExchangeCancelEvent | ExchangeCancelUpToEvent;

View File

@ -2,6 +2,11 @@ import { ConnectionOptions } from 'typeorm';
import {
Block,
CopperActivity,
CopperActivityType,
CopperCustomField,
CopperLead,
CopperOpportunity,
DexTrade,
ERC20ApprovalEvent,
ExchangeCancelEvent,
@ -18,6 +23,11 @@ import {
const entities = [
Block,
CopperOpportunity,
CopperActivity,
CopperActivityType,
CopperCustomField,
CopperLead,
DexTrade,
ExchangeCancelEvent,
ExchangeCancelUpToEvent,

View File

@ -0,0 +1,259 @@
import * as R from 'ramda';
import { CopperActivity, CopperActivityType, CopperCustomField, CopperLead, CopperOpportunity } from '../../entities';
const ONE_SECOND = 1000;
export type CopperSearchResponse = CopperLeadResponse | CopperActivityResponse | CopperOpportunityResponse;
export interface CopperLeadResponse {
id: number;
name?: string;
first_name?: string;
last_name?: string;
middle_name?: string;
assignee_id?: number;
company_name?: string;
customer_source_id?: number;
monetary_value?: number;
status: string;
status_id: number;
title?: string;
date_created: number; // in seconds
date_modified: number; // in seconds
}
export interface CopperActivityResponse {
id: number;
parent: CopperActivityParentResponse;
type: CopperActivityTypeResponse;
user_id: number;
activity_date: number;
old_value: CopperActivityValueResponse;
new_value: CopperActivityValueResponse;
date_created: number; // in seconds
date_modified: number; // in seconds
}
export interface CopperActivityValueResponse {
id: number;
name: string;
}
export interface CopperActivityParentResponse {
id: number;
type: string;
}
// custom activity types
export enum CopperActivityTypeCategory {
user = 'user',
system = 'system',
}
export interface CopperActivityTypeResponse {
id: number;
category: CopperActivityTypeCategory;
name: string;
is_disabled?: boolean;
count_as_interaction?: boolean;
}
export interface CopperOpportunityResponse {
id: number;
name: string;
assignee_id?: number;
close_date?: string;
company_id?: number;
company_name?: string;
customer_source_id?: number;
loss_reason_id?: number;
pipeline_id: number;
pipeline_stage_id: number;
primary_contact_id?: number;
priority?: string;
status: string;
tags: string[];
interaction_count: number;
monetary_value?: number;
win_probability?: number;
date_created: number; // in seconds
date_modified: number; // in seconds
custom_fields: CopperNestedCustomFieldResponse[];
}
interface CopperNestedCustomFieldResponse {
custom_field_definition_id: number;
value: number | number[] | null;
}
// custom fields
export enum CopperCustomFieldType {
String = 'String',
Text = 'Text',
Dropdown = 'Dropdown',
MultiSelect = 'MultiSelect', // not in API documentation but shows up in results
Date = 'Date',
Checkbox = 'Checkbox',
Float = 'Float',
URL = 'URL',
Percentage = 'Percentage',
Currency = 'Currency',
Connect = 'Connect',
}
export interface CopperCustomFieldOptionResponse {
id: number;
name: string;
}
export interface CopperCustomFieldResponse {
id: number;
name: string;
data_type: CopperCustomFieldType;
options?: CopperCustomFieldOptionResponse[];
}
/**
* Parse response from Copper API /search/leads/
*
* @param leads - The array of leads returned from the API
* @returns Returns an array of Copper Lead entities
*/
export function parseLeads(leads: CopperLeadResponse[]): CopperLead[] {
return leads.map(lead => {
const entity = new CopperLead();
entity.id = lead.id;
entity.name = lead.name || undefined;
entity.firstName = lead.first_name || undefined;
entity.lastName = lead.last_name || undefined;
entity.middleName = lead.middle_name || undefined;
entity.assigneeId = lead.assignee_id || undefined;
entity.companyName = lead.company_name || undefined;
entity.customerSourceId = lead.customer_source_id || undefined;
entity.monetaryValue = lead.monetary_value || undefined;
entity.status = lead.status;
entity.statusId = lead.status_id;
entity.title = lead.title || undefined;
entity.dateCreated = lead.date_created * ONE_SECOND;
entity.dateModified = lead.date_modified * ONE_SECOND;
return entity;
});
}
/**
* Parse response from Copper API /search/activities/
*
* @param activities - The array of activities returned from the API
* @returns Returns an array of Copper Activity entities
*/
export function parseActivities(activities: CopperActivityResponse[]): CopperActivity[] {
return activities.map(activity => {
const entity = new CopperActivity();
entity.id = activity.id;
entity.parentId = activity.parent.id;
entity.parentType = activity.parent.type;
entity.typeId = activity.type.id;
entity.typeCategory = activity.type.category.toString();
entity.typeName = activity.type.name;
entity.userId = activity.user_id;
entity.dateCreated = activity.date_created * ONE_SECOND;
entity.dateModified = activity.date_modified * ONE_SECOND;
// nested nullable fields
entity.oldValueId = R.path(['old_value', 'id'], activity);
entity.oldValueName = R.path(['old_value', 'name'], activity);
entity.newValueId = R.path(['new_value', 'id'], activity);
entity.newValueName = R.path(['new_value', 'name'], activity);
return entity;
});
}
/**
* Parse response from Copper API /search/opportunities/
*
* @param opportunities - The array of opportunities returned from the API
* @returns Returns an array of Copper Opportunity entities
*/
export function parseOpportunities(opportunities: CopperOpportunityResponse[]): CopperOpportunity[] {
return opportunities.map(opp => {
const customFields: { [key: number]: number } = opp.custom_fields
.filter(f => f.value !== null)
.map(f => ({
...f,
value: ([] as number[]).concat(f.value || []), // normalise all values to number[]
}))
.map(f => f.value.map(val => [f.custom_field_definition_id, val] as [number, number])) // pair each value with the custom_field_definition_id
.reduce((acc, pair) => acc.concat(pair)) // flatten
.reduce<{ [key: number]: number }>((obj, [key, value]) => {
// transform into object literal
obj[key] = value;
return obj;
}, {});
const entity = new CopperOpportunity();
entity.id = opp.id;
entity.name = opp.name;
entity.assigneeId = opp.assignee_id || undefined;
entity.closeDate = opp.close_date || undefined;
entity.companyId = opp.company_id || undefined;
entity.companyName = opp.company_name || undefined;
entity.customerSourceId = opp.customer_source_id || undefined;
entity.lossReasonId = opp.loss_reason_id || undefined;
entity.pipelineId = opp.pipeline_id;
entity.pipelineStageId = opp.pipeline_stage_id;
entity.primaryContactId = opp.primary_contact_id || undefined;
entity.priority = opp.priority || undefined;
entity.status = opp.status;
entity.interactionCount = opp.interaction_count;
entity.monetaryValue = opp.monetary_value || undefined;
entity.winProbability = opp.win_probability === null ? undefined : opp.win_probability;
entity.dateCreated = opp.date_created * ONE_SECOND;
entity.dateModified = opp.date_modified * ONE_SECOND;
entity.customFields = customFields;
return entity;
});
}
/**
* Parse response from Copper API /activity_types/
*
* @param activityTypeResponse - Activity Types response from the API, keyed by "user" or "system"
* @returns Returns an array of Copper Activity Type entities
*/
export function parseActivityTypes(
activityTypeResponse: Map<CopperActivityTypeCategory, CopperActivityTypeResponse[]>,
): CopperActivityType[] {
const values: CopperActivityTypeResponse[] = R.flatten(Object.values(activityTypeResponse));
return values.map(activityType => ({
id: activityType.id,
name: activityType.name,
category: activityType.category.toString(),
isDisabled: activityType.is_disabled,
countAsInteraction: activityType.count_as_interaction,
}));
}
/**
* Parse response from Copper API /custom_field_definitions/
*
* @param customFieldResponse - array of custom field definitions returned from the API, consisting of top-level fields and nested fields
* @returns Returns an array of Copper Custom Field entities
*/
export function parseCustomFields(customFieldResponse: CopperCustomFieldResponse[]): CopperCustomField[] {
function parseTopLevelField(field: CopperCustomFieldResponse): CopperCustomField[] {
const topLevelField: CopperCustomField = {
id: field.id,
name: field.name,
dataType: field.data_type.toString(),
};
if (field.options !== undefined) {
const nestedFields: CopperCustomField[] = field.options.map(option => ({
id: option.id,
name: option.name,
dataType: field.name,
fieldType: 'option',
}));
return nestedFields.concat(topLevelField);
} else {
return [topLevelField];
}
}
return R.chain(parseTopLevelField, customFieldResponse);
}

View File

@ -0,0 +1,129 @@
// tslint:disable:no-console
import * as R from 'ramda';
import { Connection, ConnectionOptions, createConnection, Repository } from 'typeorm';
import { CopperEndpoint, CopperSearchParams, CopperSource } from '../data_sources/copper';
import { CopperActivity, CopperActivityType, CopperCustomField, CopperLead, CopperOpportunity } from '../entities';
import * as ormConfig from '../ormconfig';
import {
CopperSearchResponse,
parseActivities,
parseActivityTypes,
parseCustomFields,
parseLeads,
parseOpportunities,
} from '../parsers/copper';
import { handleError } from '../utils';
const ONE_SECOND = 1000;
const COPPER_RATE_LIMIT = 10;
let connection: Connection;
(async () => {
connection = await createConnection(ormConfig as ConnectionOptions);
const accessToken = process.env.COPPER_ACCESS_TOKEN;
const userEmail = process.env.COPPER_USER_EMAIL;
if (accessToken === undefined || userEmail === undefined) {
throw new Error('Missing required env var: COPPER_ACCESS_TOKEN and/or COPPER_USER_EMAIL');
}
const source = new CopperSource(COPPER_RATE_LIMIT, accessToken, userEmail);
const fetchPromises = [
fetchAndSaveLeadsAsync(source),
fetchAndSaveOpportunitiesAsync(source),
fetchAndSaveActivitiesAsync(source),
fetchAndSaveCustomFieldsAsync(source),
fetchAndSaveActivityTypesAsync(source),
];
fetchPromises.forEach(async fn => {
await fn;
});
})().catch(handleError);
async function fetchAndSaveLeadsAsync(source: CopperSource): Promise<void> {
const repository = connection.getRepository(CopperLead);
const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_leads');
console.log(`Fetching Copper leads starting from ${startTime}...`);
await fetchAndSaveAsync(CopperEndpoint.Leads, source, startTime, {}, parseLeads, repository);
}
async function fetchAndSaveOpportunitiesAsync(source: CopperSource): Promise<void> {
const repository = connection.getRepository(CopperOpportunity);
const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_opportunities');
console.log(`Fetching Copper opportunities starting from ${startTime}...`);
await fetchAndSaveAsync(
CopperEndpoint.Opportunities,
source,
startTime,
{ sort_by: 'name' },
parseOpportunities,
repository,
);
}
async function fetchAndSaveActivitiesAsync(source: CopperSource): Promise<void> {
const repository = connection.getRepository(CopperActivity);
const startTime = await getMaxAsync(connection, 'date_modified', 'raw.copper_activities');
const searchParams = {
minimum_activity_date: Math.floor(startTime / ONE_SECOND),
};
console.log(`Fetching Copper activities starting from ${startTime}...`);
await fetchAndSaveAsync(CopperEndpoint.Activities, source, startTime, searchParams, parseActivities, repository);
}
async function getMaxAsync(conn: Connection, sortColumn: string, tableName: string): Promise<number> {
const queryResult = await conn.query(`SELECT MAX(${sortColumn}) as _max from ${tableName};`);
if (R.isEmpty(queryResult)) {
return 0;
} else {
return queryResult[0]._max;
}
}
// (Xianny): Copper API doesn't allow queries to filter by date. To ensure that we are filling in ascending chronological
// order and not missing any records, we are scraping all available pages. If Copper data gets larger,
// it would make sense to search for and start filling from the first page that contains a new record.
// This search would increase our network calls and is not efficient to implement with our current small volume
// of Copper records.
async function fetchAndSaveAsync<T extends CopperSearchResponse, E>(
endpoint: CopperEndpoint,
source: CopperSource,
startTime: number,
searchParams: CopperSearchParams,
parseFn: (recs: T[]) => E[],
repository: Repository<E>,
): Promise<void> {
let saved = 0;
const numPages = await source.fetchNumberOfPagesAsync(endpoint);
try {
for (let i = numPages; i > 0; i--) {
console.log(`Fetching page ${i}/${numPages} of ${endpoint}...`);
const raw = await source.fetchSearchResultsAsync<T>(endpoint, {
...searchParams,
page_number: i,
});
const newRecords = raw.filter(rec => rec.date_modified * ONE_SECOND > startTime);
const parsed = parseFn(newRecords);
await repository.save<any>(parsed);
saved += newRecords.length;
}
} catch (err) {
console.log(`Error fetching ${endpoint}, stopping: ${err.stack}`);
} finally {
console.log(`Saved ${saved} items from ${endpoint}, done.`);
}
}
async function fetchAndSaveActivityTypesAsync(source: CopperSource): Promise<void> {
console.log(`Fetching Copper activity types...`);
const activityTypes = await source.fetchActivityTypesAsync();
const repository = connection.getRepository(CopperActivityType);
await repository.save(parseActivityTypes(activityTypes));
}
async function fetchAndSaveCustomFieldsAsync(source: CopperSource): Promise<void> {
console.log(`Fetching Copper custom fields...`);
const customFields = await source.fetchCustomFieldsAsync();
const repository = connection.getRepository(CopperCustomField);
await repository.save(parseCustomFields(customFields));
}

View File

@ -9,8 +9,12 @@ const decimalRadix = 10;
// https://github.com/typeorm/typeorm/issues/2400 for more information.
export class NumberToBigIntTransformer implements ValueTransformer {
// tslint:disable-next-line:prefer-function-over-method
public to(value: number): string {
return value.toString();
public to(value: number): string | null {
if (value === null || value === undefined) {
return null;
} else {
return value.toString();
}
}
// tslint:disable-next-line:prefer-function-over-method

View File

@ -0,0 +1,54 @@
import 'mocha';
import 'reflect-metadata';
import {
CopperActivity,
CopperActivityType,
CopperCustomField,
CopperLead,
CopperOpportunity,
} from '../../src/entities';
import { createDbConnectionOnceAsync } from '../db_setup';
import {
ParsedActivities,
ParsedActivityTypes,
ParsedCustomFields,
ParsedLeads,
ParsedOpportunities,
} from '../fixtures/copper/parsed_entities';
import { chaiSetup } from '../utils/chai_setup';
import { testSaveAndFindEntityAsync } from './util';
chaiSetup.configure();
describe('Copper entities', () => {
describe('save and find', async () => {
it('Copper lead', async () => {
const connection = await createDbConnectionOnceAsync();
const repository = connection.getRepository(CopperLead);
ParsedLeads.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
});
it('Copper activity', async () => {
const connection = await createDbConnectionOnceAsync();
const repository = connection.getRepository(CopperActivity);
ParsedActivities.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
});
// searching on jsonb fields is broken in typeorm
it.skip('Copper opportunity', async () => {
const connection = await createDbConnectionOnceAsync();
const repository = connection.getRepository(CopperOpportunity);
ParsedOpportunities.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
});
it('Copper activity type', async () => {
const connection = await createDbConnectionOnceAsync();
const repository = connection.getRepository(CopperActivityType);
ParsedActivityTypes.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
});
it('Copper custom field', async () => {
const connection = await createDbConnectionOnceAsync();
const repository = connection.getRepository(CopperCustomField);
ParsedCustomFields.forEach(async entity => testSaveAndFindEntityAsync(repository, entity));
});
});
});

View File

@ -15,9 +15,9 @@ const expect = chai.expect;
* @param entity An instance of a TypeORM entity which will be saved/retrieved from the database.
*/
export async function testSaveAndFindEntityAsync<T>(repository: Repository<T>, entity: T): Promise<void> {
// Note(albrow): We are forced to use an 'as any' hack here because
// Note(albrow): We are forced to use an 'any' hack here because
// TypeScript complains about stack depth when checking the types.
await repository.save(entity as any);
await repository.save<any>(entity);
const gotEntity = await repository.findOneOrFail({
where: entity,
});

View File

@ -0,0 +1,24 @@
{
"user": [
{ "id": 0, "category": "user", "name": "Note", "is_disabled": false, "count_as_interaction": false },
{ "id": 660496, "category": "user", "name": "To Do", "is_disabled": false, "count_as_interaction": false },
{ "id": 660495, "category": "user", "name": "Meeting", "is_disabled": false, "count_as_interaction": true },
{ "id": 660494, "category": "user", "name": "Phone Call", "is_disabled": false, "count_as_interaction": true }
],
"system": [
{
"id": 1,
"category": "system",
"name": "Property Changed",
"is_disabled": false,
"count_as_interaction": false
},
{
"id": 3,
"category": "system",
"name": "Pipeline Stage Changed",
"is_disabled": false,
"count_as_interaction": false
}
]
}

View File

@ -0,0 +1,16 @@
import { CopperActivityType } from '../../../src/entities';
const ParsedActivityTypes: CopperActivityType[] = [
{ id: 0, name: 'Note', category: 'user', isDisabled: false, countAsInteraction: false },
{ id: 660496, name: 'To Do', category: 'user', isDisabled: false, countAsInteraction: false },
{ id: 660495, name: 'Meeting', category: 'user', isDisabled: false, countAsInteraction: true },
{ id: 660494, name: 'Phone Call', category: 'user', isDisabled: false, countAsInteraction: true },
{ id: 1, name: 'Property Changed', category: 'system', isDisabled: false, countAsInteraction: false },
{
id: 3,
name: 'Pipeline Stage Changed',
category: 'system',
isDisabled: false,
countAsInteraction: false,
},
];
export { ParsedActivityTypes };

View File

@ -0,0 +1,38 @@
[
{
"id": 261066,
"name": "Integration Type",
"canonical_name": null,
"data_type": "MultiSelect",
"available_on": ["opportunity", "company", "person"],
"options": [
{ "id": 394020, "name": "Strategic Relationship", "rank": 7 },
{ "id": 394013, "name": "ERC-20 Exchange", "rank": 0 },
{ "id": 394014, "name": "ERC-721 Marketplace", "rank": 1 },
{ "id": 394015, "name": "Trade Widget", "rank": 2 },
{ "id": 394016, "name": "Prediction Market Exchange", "rank": 3 },
{ "id": 394017, "name": "Security Token Exchange", "rank": 4 },
{ "id": 394018, "name": "Complementary Company", "rank": 5 },
{ "id": 394019, "name": "Service Provider", "rank": 6 }
]
},
{
"id": 261067,
"name": "Company Type",
"canonical_name": null,
"data_type": "Dropdown",
"available_on": ["company", "opportunity", "person"],
"options": [
{ "id": 394129, "name": "Market Maker", "rank": 6 },
{ "id": 394130, "name": "Events", "rank": 2 },
{ "id": 394023, "name": "Exchange", "rank": 3 },
{ "id": 394024, "name": "Investor", "rank": 5 },
{ "id": 394026, "name": "Service Provider", "rank": 8 },
{ "id": 394027, "name": "Wallet", "rank": 9 },
{ "id": 394134, "name": "Game", "rank": 4 },
{ "id": 394025, "name": "OTC", "rank": 7 },
{ "id": 394021, "name": "Blockchain/Protocol", "rank": 0 },
{ "id": 394022, "name": "dApp", "rank": 1 }
]
}
]

View File

@ -0,0 +1,39 @@
import { CopperCustomField } from '../../../src/entities';
const ParsedCustomFields: CopperCustomField[] = [
{
id: 394020,
name: 'Strategic Relationship',
dataType: 'Integration Type',
fieldType: 'option',
},
{ id: 394013, name: 'ERC-20 Exchange', dataType: 'Integration Type', fieldType: 'option' },
{ id: 394014, name: 'ERC-721 Marketplace', dataType: 'Integration Type', fieldType: 'option' },
{ id: 394015, name: 'Trade Widget', dataType: 'Integration Type', fieldType: 'option' },
{
id: 394016,
name: 'Prediction Market Exchange',
dataType: 'Integration Type',
fieldType: 'option',
},
{
id: 394017,
name: 'Security Token Exchange',
dataType: 'Integration Type',
fieldType: 'option',
},
{ id: 394018, name: 'Complementary Company', dataType: 'Integration Type', fieldType: 'option' },
{ id: 394019, name: 'Service Provider', dataType: 'Integration Type', fieldType: 'option' },
{ id: 261066, name: 'Integration Type', dataType: 'MultiSelect' },
{ id: 394129, name: 'Market Maker', dataType: 'Company Type', fieldType: 'option' },
{ id: 394130, name: 'Events', dataType: 'Company Type', fieldType: 'option' },
{ id: 394023, name: 'Exchange', dataType: 'Company Type', fieldType: 'option' },
{ id: 394024, name: 'Investor', dataType: 'Company Type', fieldType: 'option' },
{ id: 394026, name: 'Service Provider', dataType: 'Company Type', fieldType: 'option' },
{ id: 394027, name: 'Wallet', dataType: 'Company Type', fieldType: 'option' },
{ id: 394134, name: 'Game', dataType: 'Company Type', fieldType: 'option' },
{ id: 394025, name: 'OTC', dataType: 'Company Type', fieldType: 'option' },
{ id: 394021, name: 'Blockchain/Protocol', dataType: 'Company Type', fieldType: 'option' },
{ id: 394022, name: 'dApp', dataType: 'Company Type', fieldType: 'option' },
{ id: 261067, name: 'Company Type', dataType: 'Dropdown' },
];
export { ParsedCustomFields };

View File

@ -0,0 +1,242 @@
[
{
"id": 5015299552,
"parent": { "id": 14667512, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1545329595,
"old_value": { "id": 2392929, "name": "Evaluation" },
"new_value": { "id": 2392931, "name": "Integration Started" },
"date_created": 1545329595,
"date_modified": 1545329595
},
{
"id": 5010214065,
"parent": { "id": 14978865, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1545245706,
"old_value": { "id": 2392928, "name": "Intro" },
"new_value": { "id": 2392929, "name": "Evaluation" },
"date_created": 1545245706,
"date_modified": 1545245706
},
{
"id": 5006149111,
"parent": { "id": 70430977, "type": "person" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1545166908,
"old_value": null,
"new_value": null,
"date_created": 1545168280,
"date_modified": 1545166908
},
{
"id": 5005314622,
"parent": { "id": 27778968, "type": "company" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1545080504,
"old_value": null,
"new_value": null,
"date_created": 1545160479,
"date_modified": 1545080504
},
{
"id": 5000006802,
"parent": { "id": 14956518, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1545071374,
"old_value": null,
"new_value": null,
"date_created": 1545071500,
"date_modified": 1545071374
},
{
"id": 4985504199,
"parent": { "id": 14912790, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544644058,
"old_value": null,
"new_value": null,
"date_created": 1544644661,
"date_modified": 1544644058
},
{
"id": 4985456147,
"parent": { "id": 14912790, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544644048,
"old_value": null,
"new_value": null,
"date_created": 1544644053,
"date_modified": 1544644048
},
{
"id": 4980975996,
"parent": { "id": 14902828, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544563171,
"old_value": null,
"new_value": null,
"date_created": 1544563224,
"date_modified": 1544563171
},
{
"id": 4980910331,
"parent": { "id": 14902828, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544562495,
"old_value": { "id": 2392928, "name": "Intro" },
"new_value": { "id": 2392931, "name": "Integration Started" },
"date_created": 1544562495,
"date_modified": 1544562495
},
{
"id": 4980872220,
"parent": { "id": 14888910, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544559279,
"old_value": null,
"new_value": null,
"date_created": 1544562118,
"date_modified": 1544559279
},
{
"id": 4980508097,
"parent": { "id": 14050167, "type": "opportunity" },
"type": { "id": 1, "category": "system", "name": "Status Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544558077,
"old_value": "Open",
"new_value": "Won",
"date_created": 1544558077,
"date_modified": 1544558077
},
{
"id": 4980508095,
"parent": { "id": 66538237, "type": "person" },
"type": { "id": 1, "category": "system" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544558077,
"old_value": null,
"new_value": null,
"date_created": 1544558077,
"date_modified": 1544558077
},
{
"id": 4980508092,
"parent": { "id": 27779020, "type": "company" },
"type": { "id": 1, "category": "system" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544558077,
"old_value": null,
"new_value": null,
"date_created": 1544558077,
"date_modified": 1544558077
},
{
"id": 4980507507,
"parent": { "id": 14050167, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544558071,
"old_value": { "id": 2392931, "name": "Integration Started" },
"new_value": { "id": 2405442, "name": "Integration Complete" },
"date_created": 1544558071,
"date_modified": 1544558071
},
{
"id": 4980479684,
"parent": { "id": 14901232, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544557777,
"old_value": { "id": 2392928, "name": "Intro" },
"new_value": { "id": 2392929, "name": "Evaluation" },
"date_created": 1544557777,
"date_modified": 1544557777
},
{
"id": 4980327164,
"parent": { "id": 14901232, "type": "opportunity" },
"type": { "id": 660495, "category": "user" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544554864,
"old_value": null,
"new_value": null,
"date_created": 1544556132,
"date_modified": 1544554864
},
{
"id": 4975270470,
"parent": { "id": 14888744, "type": "opportunity" },
"type": { "id": 3, "category": "system", "name": "Stage Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544469501,
"old_value": { "id": 2392928, "name": "Intro" },
"new_value": { "id": 2392931, "name": "Integration Started" },
"date_created": 1544469501,
"date_modified": 1544469501
},
{
"id": 4975255523,
"parent": { "id": 64713448, "type": "person" },
"type": { "id": 1, "category": "system" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544469389,
"old_value": null,
"new_value": null,
"date_created": 1544469389,
"date_modified": 1544469389
},
{
"id": 4975255519,
"parent": { "id": 13735617, "type": "opportunity" },
"type": { "id": 1, "category": "system", "name": "Status Change" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544469388,
"old_value": "Open",
"new_value": "Won",
"date_created": 1544469388,
"date_modified": 1544469388
},
{
"id": 4975255514,
"parent": { "id": 27778968, "type": "company" },
"type": { "id": 1, "category": "system" },
"user_id": 680302,
"details": "blah blah",
"activity_date": 1544469388,
"old_value": null,
"new_value": null,
"date_created": 1544469388,
"date_modified": 1544469388
}
]

View File

@ -0,0 +1,305 @@
import { CopperActivity } from '../../../src/entities';
const ParsedActivities: CopperActivity[] = [
{
id: 5015299552,
parentId: 14667512,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1545329595000,
dateModified: 1545329595000,
oldValueId: 2392929,
oldValueName: 'Evaluation',
newValueId: 2392931,
newValueName: 'Integration Started',
},
{
id: 5010214065,
parentId: 14978865,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1545245706000,
dateModified: 1545245706000,
oldValueId: 2392928,
oldValueName: 'Intro',
newValueId: 2392929,
newValueName: 'Evaluation',
},
{
id: 5006149111,
parentId: 70430977,
parentType: 'person',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1545168280000,
dateModified: 1545166908000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 5005314622,
parentId: 27778968,
parentType: 'company',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1545160479000,
dateModified: 1545080504000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 5000006802,
parentId: 14956518,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1545071500000,
dateModified: 1545071374000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4985504199,
parentId: 14912790,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1544644661000,
dateModified: 1544644058000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4985456147,
parentId: 14912790,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1544644053000,
dateModified: 1544644048000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980975996,
parentId: 14902828,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1544563224000,
dateModified: 1544563171000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980910331,
parentId: 14902828,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1544562495000,
dateModified: 1544562495000,
oldValueId: 2392928,
oldValueName: 'Intro',
newValueId: 2392931,
newValueName: 'Integration Started',
},
{
id: 4980872220,
parentId: 14888910,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1544562118000,
dateModified: 1544559279000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980508097,
parentId: 14050167,
parentType: 'opportunity',
typeId: 1,
typeCategory: 'system',
typeName: 'Status Change',
userId: 680302,
dateCreated: 1544558077000,
dateModified: 1544558077000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980508095,
parentId: 66538237,
parentType: 'person',
typeId: 1,
typeCategory: 'system',
typeName: undefined,
userId: 680302,
dateCreated: 1544558077000,
dateModified: 1544558077000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980508092,
parentId: 27779020,
parentType: 'company',
typeId: 1,
typeCategory: 'system',
typeName: undefined,
userId: 680302,
dateCreated: 1544558077000,
dateModified: 1544558077000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4980507507,
parentId: 14050167,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1544558071000,
dateModified: 1544558071000,
oldValueId: 2392931,
oldValueName: 'Integration Started',
newValueId: 2405442,
newValueName: 'Integration Complete',
},
{
id: 4980479684,
parentId: 14901232,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1544557777000,
dateModified: 1544557777000,
oldValueId: 2392928,
oldValueName: 'Intro',
newValueId: 2392929,
newValueName: 'Evaluation',
},
{
id: 4980327164,
parentId: 14901232,
parentType: 'opportunity',
typeId: 660495,
typeCategory: 'user',
typeName: undefined,
userId: 680302,
dateCreated: 1544556132000,
dateModified: 1544554864000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4975270470,
parentId: 14888744,
parentType: 'opportunity',
typeId: 3,
typeCategory: 'system',
typeName: 'Stage Change',
userId: 680302,
dateCreated: 1544469501000,
dateModified: 1544469501000,
oldValueId: 2392928,
oldValueName: 'Intro',
newValueId: 2392931,
newValueName: 'Integration Started',
},
{
id: 4975255523,
parentId: 64713448,
parentType: 'person',
typeId: 1,
typeCategory: 'system',
typeName: undefined,
userId: 680302,
dateCreated: 1544469389000,
dateModified: 1544469389000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4975255519,
parentId: 13735617,
parentType: 'opportunity',
typeId: 1,
typeCategory: 'system',
typeName: 'Status Change',
userId: 680302,
dateCreated: 1544469388000,
dateModified: 1544469388000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
{
id: 4975255514,
parentId: 27778968,
parentType: 'company',
typeId: 1,
typeCategory: 'system',
typeName: undefined,
userId: 680302,
dateCreated: 1544469388000,
dateModified: 1544469388000,
oldValueId: undefined,
oldValueName: undefined,
newValueId: undefined,
newValueName: undefined,
},
];
export { ParsedActivities };

View File

@ -0,0 +1,583 @@
[
{
"id": 9150547,
"name": "My Contact",
"prefix": null,
"first_name": "My",
"last_name": "Contact",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mycontact@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1490045162,
"date_modified": 1490045162
},
{
"id": 9150552,
"name": "My Contact",
"prefix": null,
"first_name": "My",
"last_name": "Contact",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": null,
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [
{
"number": "415-123-45678",
"category": "mobile"
}
],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1490045237,
"date_modified": 1490045237
},
{
"id": 9150578,
"name": "My Contact",
"prefix": null,
"first_name": "My",
"last_name": "Contact",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": null,
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [
{
"number": "415-123-45678",
"category": "mobile"
}
],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1490045279,
"date_modified": 1490045279
},
{
"id": 8982554,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1489528899,
"date_modified": 1489528899
},
{
"id": 8982702,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@gmail.test",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1489531171,
"date_modified": 1489531171
},
{
"id": 9094361,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1489791225,
"date_modified": 1489791225
},
{
"id": 9094364,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": "123456789012345678901234567890"
},
{
"custom_field_definition_id": 103481,
"value": "123456789012345678901234567890"
}
],
"date_created": 1489791283,
"date_modified": 1489791283
},
{
"id": 9094371,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
},
{
"custom_field_definition_id": 103481,
"value": "123456789012345678901234567890"
}
],
"date_created": 1489791417,
"date_modified": 1489791417
},
{
"id": 9094372,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
},
{
"custom_field_definition_id": 103481,
"value": "123456789012345678901234567890"
}
],
"date_created": 1489791453,
"date_modified": 1489791453
},
{
"id": 9094373,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
},
{
"custom_field_definition_id": 103481,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
}
],
"date_created": 1489791470,
"date_modified": 1489791470
},
{
"id": 9094383,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5-----"
},
{
"custom_field_definition_id": 103481,
"value":
"|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------|--------1---------2---------3---------4---------5---------6---------7---------8---------9---------"
}
],
"date_created": 1489791672,
"date_modified": 1489791672
},
{
"id": 9174441,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": "Text fields are 255 chars or less!"
},
{
"custom_field_definition_id": 103481,
"value": "text \n text"
}
],
"date_created": 1490112942,
"date_modified": 1490112942
},
{
"id": 9174443,
"name": "My Lead",
"prefix": null,
"first_name": "My",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": null,
"assignee_id": null,
"company_name": null,
"customer_source_id": null,
"details": null,
"email": {
"email": "mylead@noemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": null,
"socials": [],
"status": "New",
"status_id": 208231,
"tags": [],
"title": null,
"websites": [],
"phone_numbers": [],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": "Text fields are 255 chars or less!"
},
{
"custom_field_definition_id": 103481,
"value": "text /n text"
}
],
"date_created": 1490112953,
"date_modified": 1490112953
},
{
"id": 8894157,
"name": "Test Lead",
"prefix": null,
"first_name": "Test",
"last_name": "Lead",
"middle_name": null,
"suffix": null,
"address": {
"street": "301 Howard St Ste 600",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105",
"country": "US"
},
"assignee_id": 137658,
"company_name": "Lead's Company",
"customer_source_id": 331241,
"details": "This is an update",
"email": {
"email": "address@workemail.com",
"category": "work"
},
"interaction_count": 0,
"monetary_value": 100,
"socials": [
{
"url": "facebook.com/test_lead",
"category": "facebook"
}
],
"status": "New",
"status_id": 208231,
"tags": ["tag 1", "tag 2"],
"title": "Title",
"websites": [
{
"url": "www.workwebsite.com",
"category": "work"
}
],
"phone_numbers": [
{
"number": "415-999-4321",
"category": "mobile"
},
{
"number": "415-555-1234",
"category": "work"
}
],
"custom_fields": [
{
"custom_field_definition_id": 100764,
"value": null
},
{
"custom_field_definition_id": 103481,
"value": null
}
],
"date_created": 1489018784,
"date_modified": 1496692911
}
]

View File

@ -0,0 +1,229 @@
import { CopperLead } from '../../../src/entities';
const ParsedLeads: CopperLead[] = [
{
id: 9150547,
name: 'My Contact',
firstName: 'My',
lastName: 'Contact',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1490045162000,
dateModified: 1490045162000,
},
{
id: 9150552,
name: 'My Contact',
firstName: 'My',
lastName: 'Contact',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1490045237000,
dateModified: 1490045237000,
},
{
id: 9150578,
name: 'My Contact',
firstName: 'My',
lastName: 'Contact',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1490045279000,
dateModified: 1490045279000,
},
{
id: 8982554,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489528899000,
dateModified: 1489528899000,
},
{
id: 8982702,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489531171000,
dateModified: 1489531171000,
},
{
id: 9094361,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791225000,
dateModified: 1489791225000,
},
{
id: 9094364,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791283000,
dateModified: 1489791283000,
},
{
id: 9094371,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791417000,
dateModified: 1489791417000,
},
{
id: 9094372,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791453000,
dateModified: 1489791453000,
},
{
id: 9094373,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791470000,
dateModified: 1489791470000,
},
{
id: 9094383,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1489791672000,
dateModified: 1489791672000,
},
{
id: 9174441,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1490112942000,
dateModified: 1490112942000,
},
{
id: 9174443,
name: 'My Lead',
firstName: 'My',
lastName: 'Lead',
middleName: undefined,
assigneeId: undefined,
companyName: undefined,
customerSourceId: undefined,
monetaryValue: undefined,
status: 'New',
statusId: 208231,
title: undefined,
dateCreated: 1490112953000,
dateModified: 1490112953000,
},
{
id: 8894157,
name: 'Test Lead',
firstName: 'Test',
lastName: 'Lead',
middleName: undefined,
assigneeId: 137658,
companyName: "Lead's Company",
customerSourceId: 331241,
monetaryValue: 100,
status: 'New',
statusId: 208231,
title: 'Title',
dateCreated: 1489018784000,
dateModified: 1496692911000,
},
];
export { ParsedLeads };

View File

@ -0,0 +1,662 @@
[
{
"id": 14050269,
"name": "8Base RaaS",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 27778962,
"company_name": "8base",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 66088850,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 81,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542653860,
"date_last_contacted": 1544757550,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1538414159,
"date_modified": 1544769562,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013, 394018] },
{ "custom_field_definition_id": 261067, "value": 394026 }
]
},
{
"id": 14631430,
"name": "Alice.si TW + ERC 20 Marketplace",
"assignee_id": 680302,
"close_date": "12/15/2018",
"company_id": 30238847,
"company_name": "Alice SI",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 69354024,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 4,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542304481,
"date_last_contacted": 1542304800,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542304481,
"date_modified": 1542304943,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013, 394015] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14632057,
"name": "Altcoin.io Relayer",
"assignee_id": 680302,
"close_date": "12/15/2018",
"company_id": 29936486,
"company_name": "Altcoin.io",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 68724646,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 22,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542310909,
"date_last_contacted": 1543864597,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542306827,
"date_modified": 1543864667,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013, 394017] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14667523,
"name": "Altcoin.io Relayer",
"assignee_id": 680302,
"close_date": "12/19/2018",
"company_id": 29936486,
"company_name": "Altcoin.io",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 68724646,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 21,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542657437,
"date_last_contacted": 1543864597,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542657437,
"date_modified": 1543864667,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013, 394017] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14666706,
"name": "Amadeus Relayer",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 29243209,
"company_name": "Amadeus",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 66912020,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 11,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542654284,
"date_last_contacted": 1543264254,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542654284,
"date_modified": 1543277520,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14666718,
"name": "Ambo Relayer",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 29249190,
"company_name": "Ambo",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 66927869,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 126,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542654352,
"date_last_contacted": 1545252349,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542654352,
"date_modified": 1545253761,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14164318,
"name": "Augur TW",
"assignee_id": 680302,
"close_date": "12/10/2018",
"company_id": 27778967,
"company_name": "Augur",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 67248692,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 22,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1544469362,
"date_last_contacted": 1544491567,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1539204858,
"date_modified": 1544653867,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394021 }
]
},
{
"id": 14666626,
"name": "Autonio",
"assignee_id": 680302,
"close_date": "12/19/2018",
"company_id": 27920701,
"company_name": "Auton",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392931,
"primary_contact_id": 64742640,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 54,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542653834,
"date_last_contacted": 1542658568,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542653834,
"date_modified": 1542658808,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013, 394019] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14050921,
"name": "Axie Infinity 721 Marketplace",
"assignee_id": 680302,
"close_date": "11/1/2018",
"company_id": 27779033,
"company_name": "Axie Infinity",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392931,
"primary_contact_id": 66499254,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 4,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1543861025,
"date_last_contacted": 1539024738,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1538416687,
"date_modified": 1543861025,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394014] },
{ "custom_field_definition_id": 261067, "value": 394134 }
]
},
{
"id": 13735617,
"name": "Balance TW",
"assignee_id": 680302,
"close_date": "12/10/2018",
"company_id": 27778968,
"company_name": "Balance",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 64713448,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 34,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1544469382,
"date_last_contacted": 1545082200,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1535668009,
"date_modified": 1545082454,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394027 }
]
},
{
"id": 14667112,
"name": "Bamboo Relayer",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 29243795,
"company_name": "Bamboo Relay",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 66914687,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 46,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542655143,
"date_last_contacted": 1545252349,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542655143,
"date_modified": 1545253761,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 13627309,
"name": "Ben TW",
"assignee_id": 680302,
"close_date": "1/1/2019",
"company_id": 27702348,
"company_name": "Ben",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 64262622,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 64,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1541527279,
"date_last_contacted": 1541639882,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1534887789,
"date_modified": 1541651395,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394027 }
]
},
{
"id": 14808512,
"name": "Bit2Me Relayer",
"assignee_id": 680302,
"close_date": "12/3/2018",
"company_id": 30793050,
"company_name": "Bit2Me",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405442,
"primary_contact_id": 70267217,
"priority": "None",
"status": "Won",
"tags": [],
"interaction_count": 0,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1543861167,
"date_last_contacted": null,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1543861167,
"date_modified": 1543861189,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394013] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14050312,
"name": "Bitcoin.tax Reporting Integration",
"assignee_id": 680302,
"close_date": "11/1/2018",
"company_id": 27957614,
"company_name": "Bitcoin",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392928,
"primary_contact_id": 66539479,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 5,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1538414308,
"date_last_contacted": 1536766098,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1538414308,
"date_modified": 1538414314,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394019] },
{ "custom_field_definition_id": 261067, "value": 394026 }
]
},
{
"id": 14331463,
"name": "Bitpie TW",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 27779026,
"company_name": "Bitpie",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 67700943,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 9,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1539984566,
"date_last_contacted": 1541529947,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1539984566,
"date_modified": 1541530233,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394027 }
]
},
{
"id": 14331481,
"name": "Bitski Wallet SDK TW",
"assignee_id": 680302,
"close_date": "11/19/2018",
"company_id": 29489300,
"company_name": "Bitski",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 67697528,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 23,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1539984735,
"date_last_contacted": 1544811399,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1539984735,
"date_modified": 1544818605,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394026 }
]
},
{
"id": 14531554,
"name": "BitUniverse TW",
"assignee_id": 680302,
"close_date": "12/6/2018",
"company_id": 29901805,
"company_name": "BitUniverse Co., Ltd (Cryptocurrency Portfolio)",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 68692107,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 15,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1543861104,
"date_last_contacted": 1544803276,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1541527110,
"date_modified": 1544812979,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394026 }
]
},
{
"id": 14050895,
"name": "BlitzPredict PMR",
"assignee_id": 680302,
"close_date": "11/1/2018",
"company_id": 28758258,
"company_name": "BlitzPredict",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 66378659,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 32,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1539985501,
"date_last_contacted": 1544830560,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1538416597,
"date_modified": 1544830709,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394016] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
},
{
"id": 14209841,
"name": "Blockfolio TW",
"assignee_id": 680302,
"close_date": "11/15/2018",
"company_id": 29332516,
"company_name": "Blockfolio",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2405443,
"primary_contact_id": 67247027,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 20,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1539984098,
"date_last_contacted": 1539977661,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1539624801,
"date_modified": 1539984098,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394015] },
{ "custom_field_definition_id": 261067, "value": 394026 }
]
},
{
"id": 14633220,
"name": "BlockSwap 721 / 1155 Conversational Marketplace",
"assignee_id": 680302,
"close_date": "12/15/2018",
"company_id": 30210921,
"company_name": "BlockSwap",
"customer_source_id": null,
"details": "blah blah",
"loss_reason_id": null,
"pipeline_id": 512676,
"pipeline_stage_id": 2392929,
"primary_contact_id": 69296220,
"priority": "None",
"status": "Open",
"tags": [],
"interaction_count": 82,
"monetary_unit": null,
"monetary_value": null,
"converted_unit": null,
"converted_value": null,
"win_probability": 0,
"date_stage_changed": 1542311056,
"date_last_contacted": 1543536442,
"leads_converted_from": [],
"date_lead_created": null,
"date_created": 1542311056,
"date_modified": 1543557877,
"custom_fields": [
{ "custom_field_definition_id": 261066, "value": [394014] },
{ "custom_field_definition_id": 261067, "value": 394023 }
]
}
]

View File

@ -0,0 +1,425 @@
// tslint:disable:custom-no-magic-numbers
import { CopperOpportunity } from '../../../src/entities';
const ParsedOpportunities: CopperOpportunity[] = [
{
id: 14050269,
name: '8Base RaaS',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 27778962,
companyName: '8base',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 66088850,
priority: 'None',
status: 'Won',
interactionCount: 81,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1538414159000,
dateModified: 1544769562000,
customFields: { '261066': 394018, '261067': 394026 },
},
{
id: 14631430,
name: 'Alice.si TW + ERC 20 Marketplace',
assigneeId: 680302,
closeDate: '12/15/2018',
companyId: 30238847,
companyName: 'Alice SI',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 69354024,
priority: 'None',
status: 'Open',
interactionCount: 4,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542304481000,
dateModified: 1542304943000,
customFields: { '261066': 394015, '261067': 394023 },
},
{
id: 14632057,
name: 'Altcoin.io Relayer',
assigneeId: 680302,
closeDate: '12/15/2018',
companyId: 29936486,
companyName: 'Altcoin.io',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 68724646,
priority: 'None',
status: 'Open',
interactionCount: 22,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542306827000,
dateModified: 1543864667000,
customFields: { '261066': 394017, '261067': 394023 },
},
{
id: 14667523,
name: 'Altcoin.io Relayer',
assigneeId: 680302,
closeDate: '12/19/2018',
companyId: 29936486,
companyName: 'Altcoin.io',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 68724646,
priority: 'None',
status: 'Open',
interactionCount: 21,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542657437000,
dateModified: 1543864667000,
customFields: { '261066': 394017, '261067': 394023 },
},
{
id: 14666706,
name: 'Amadeus Relayer',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 29243209,
companyName: 'Amadeus',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 66912020,
priority: 'None',
status: 'Won',
interactionCount: 11,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542654284000,
dateModified: 1543277520000,
customFields: { '261066': 394013, '261067': 394023 },
},
{
id: 14666718,
name: 'Ambo Relayer',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 29249190,
companyName: 'Ambo',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 66927869,
priority: 'None',
status: 'Won',
interactionCount: 126,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542654352000,
dateModified: 1545253761000,
customFields: { '261066': 394013, '261067': 394023 },
},
{
id: 14164318,
name: 'Augur TW',
assigneeId: 680302,
closeDate: '12/10/2018',
companyId: 27778967,
companyName: 'Augur',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 67248692,
priority: 'None',
status: 'Won',
interactionCount: 22,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1539204858000,
dateModified: 1544653867000,
customFields: { '261066': 394015, '261067': 394021 },
},
{
id: 14666626,
name: 'Autonio',
assigneeId: 680302,
closeDate: '12/19/2018',
companyId: 27920701,
companyName: 'Auton',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392931,
primaryContactId: 64742640,
priority: 'None',
status: 'Open',
interactionCount: 54,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542653834000,
dateModified: 1542658808000,
customFields: { '261066': 394019, '261067': 394023 },
},
{
id: 14050921,
name: 'Axie Infinity 721 Marketplace',
assigneeId: 680302,
closeDate: '11/1/2018',
companyId: 27779033,
companyName: 'Axie Infinity',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392931,
primaryContactId: 66499254,
priority: 'None',
status: 'Open',
interactionCount: 4,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1538416687000,
dateModified: 1543861025000,
customFields: { '261066': 394014, '261067': 394134 },
},
{
id: 13735617,
name: 'Balance TW',
assigneeId: 680302,
closeDate: '12/10/2018',
companyId: 27778968,
companyName: 'Balance',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 64713448,
priority: 'None',
status: 'Won',
interactionCount: 34,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1535668009000,
dateModified: 1545082454000,
customFields: { '261066': 394015, '261067': 394027 },
},
{
id: 14667112,
name: 'Bamboo Relayer',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 29243795,
companyName: 'Bamboo Relay',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 66914687,
priority: 'None',
status: 'Won',
interactionCount: 46,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542655143000,
dateModified: 1545253761000,
customFields: { '261066': 394013, '261067': 394023 },
},
{
id: 13627309,
name: 'Ben TW',
assigneeId: 680302,
closeDate: '1/1/2019',
companyId: 27702348,
companyName: 'Ben',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 64262622,
priority: 'None',
status: 'Open',
interactionCount: 64,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1534887789000,
dateModified: 1541651395000,
customFields: { '261066': 394015, '261067': 394027 },
},
{
id: 14808512,
name: 'Bit2Me Relayer',
assigneeId: 680302,
closeDate: '12/3/2018',
companyId: 30793050,
companyName: 'Bit2Me',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405442,
primaryContactId: 70267217,
priority: 'None',
status: 'Won',
interactionCount: 0,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1543861167000,
dateModified: 1543861189000,
customFields: { '261066': 394013, '261067': 394023 },
},
{
id: 14050312,
name: 'Bitcoin.tax Reporting Integration',
assigneeId: 680302,
closeDate: '11/1/2018',
companyId: 27957614,
companyName: 'Bitcoin',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392928,
primaryContactId: 66539479,
priority: 'None',
status: 'Open',
interactionCount: 5,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1538414308000,
dateModified: 1538414314000,
customFields: { '261066': 394019, '261067': 394026 },
},
{
id: 14331463,
name: 'Bitpie TW',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 27779026,
companyName: 'Bitpie',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 67700943,
priority: 'None',
status: 'Open',
interactionCount: 9,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1539984566000,
dateModified: 1541530233000,
customFields: { '261066': 394015, '261067': 394027 },
},
{
id: 14331481,
name: 'Bitski Wallet SDK TW',
assigneeId: 680302,
closeDate: '11/19/2018',
companyId: 29489300,
companyName: 'Bitski',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 67697528,
priority: 'None',
status: 'Open',
interactionCount: 23,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1539984735000,
dateModified: 1544818605000,
customFields: { '261066': 394015, '261067': 394026 },
},
{
id: 14531554,
name: 'BitUniverse TW',
assigneeId: 680302,
closeDate: '12/6/2018',
companyId: 29901805,
companyName: 'BitUniverse Co., Ltd (Cryptocurrency Portfolio)',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 68692107,
priority: 'None',
status: 'Open',
interactionCount: 15,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1541527110000,
dateModified: 1544812979000,
customFields: { '261066': 394015, '261067': 394026 },
},
{
id: 14050895,
name: 'BlitzPredict PMR',
assigneeId: 680302,
closeDate: '11/1/2018',
companyId: 28758258,
companyName: 'BlitzPredict',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 66378659,
priority: 'None',
status: 'Open',
interactionCount: 32,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1538416597000,
dateModified: 1544830709000,
customFields: { '261066': 394016, '261067': 394023 },
},
{
id: 14209841,
name: 'Blockfolio TW',
assigneeId: 680302,
closeDate: '11/15/2018',
companyId: 29332516,
companyName: 'Blockfolio',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2405443,
primaryContactId: 67247027,
priority: 'None',
status: 'Open',
interactionCount: 20,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1539624801000,
dateModified: 1539984098000,
customFields: { '261066': 394015, '261067': 394026 },
},
{
id: 14633220,
name: 'BlockSwap 721 / 1155 Conversational Marketplace',
assigneeId: 680302,
closeDate: '12/15/2018',
companyId: 30210921,
companyName: 'BlockSwap',
customerSourceId: undefined,
lossReasonId: undefined,
pipelineId: 512676,
pipelineStageId: 2392929,
primaryContactId: 69296220,
priority: 'None',
status: 'Open',
interactionCount: 82,
monetaryValue: undefined,
winProbability: 0,
dateCreated: 1542311056000,
dateModified: 1543557877000,
customFields: { '261066': 394014, '261067': 394023 },
},
];
export { ParsedOpportunities };

View File

@ -0,0 +1,5 @@
export { ParsedActivityTypes } from './api_v1_activity_types';
export { ParsedCustomFields } from './api_v1_custom_field_definitions';
export { ParsedActivities } from './api_v1_list_activities';
export { ParsedLeads } from './api_v1_list_leads';
export { ParsedOpportunities } from './api_v1_list_opportunities';

View File

@ -0,0 +1,87 @@
import * as chai from 'chai';
import 'mocha';
import {
CopperActivity,
CopperActivityType,
CopperCustomField,
CopperLead,
CopperOpportunity,
} from '../../../src/entities';
import {
CopperActivityResponse,
CopperActivityTypeCategory,
CopperActivityTypeResponse,
CopperCustomFieldResponse,
CopperSearchResponse,
parseActivities,
parseActivityTypes,
parseCustomFields,
parseLeads,
parseOpportunities,
} from '../../../src/parsers/copper';
import { chaiSetup } from '../../utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
type CopperResponse = CopperSearchResponse | CopperCustomFieldResponse;
type CopperEntity = CopperLead | CopperActivity | CopperOpportunity | CopperActivityType | CopperCustomField;
import * as activityTypesApiResponse from '../../fixtures/copper/api_v1_activity_types.json';
import * as customFieldsApiResponse from '../../fixtures/copper/api_v1_custom_field_definitions.json';
import * as listActivitiesApiResponse from '../../fixtures/copper/api_v1_list_activities.json';
import * as listLeadsApiResponse from '../../fixtures/copper/api_v1_list_leads.json';
import * as listOpportunitiesApiResponse from '../../fixtures/copper/api_v1_list_opportunities.json';
import {
ParsedActivities,
ParsedActivityTypes,
ParsedCustomFields,
ParsedLeads,
ParsedOpportunities,
} from '../../fixtures/copper/parsed_entities';
interface TestCase {
input: CopperResponse[];
expected: CopperEntity[];
parseFn(input: CopperResponse[]): CopperEntity[];
}
const testCases: TestCase[] = [
{
input: listLeadsApiResponse,
expected: ParsedLeads,
parseFn: parseLeads,
},
{
input: (listActivitiesApiResponse as unknown) as CopperActivityResponse[],
expected: ParsedActivities,
parseFn: parseActivities,
},
{
input: listOpportunitiesApiResponse,
expected: ParsedOpportunities,
parseFn: parseOpportunities,
},
{
input: customFieldsApiResponse,
expected: ParsedCustomFields,
parseFn: parseCustomFields,
},
];
describe('Copper parser', () => {
it('parses API responses', () => {
testCases.forEach(testCase => {
const actual: CopperEntity[] = testCase.parseFn(testCase.input);
expect(actual).deep.equal(testCase.expected);
});
});
// special case because the API response is not an array
it('parses activity types API response', () => {
const actual: CopperActivityType[] = parseActivityTypes((activityTypesApiResponse as unknown) as Map<
CopperActivityTypeCategory,
CopperActivityTypeResponse[]
>);
expect(actual).deep.equal(ParsedActivityTypes);
});
});

View File

@ -4,7 +4,15 @@
"outDir": "lib",
"rootDir": ".",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
"experimentalDecorators": true,
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./migrations/**/*"]
"include": ["./src/**/*", "./test/**/*", "./migrations/**/*"],
"files": [
"./test/fixtures/copper/api_v1_activity_types.json",
"./test/fixtures/copper/api_v1_custom_field_definitions.json",
"./test/fixtures/copper/api_v1_list_activities.json",
"./test/fixtures/copper/api_v1_list_leads.json",
"./test/fixtures/copper/api_v1_list_opportunities.json"
]
}