Skip to content
This repository was archived by the owner on Nov 21, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 85 additions & 11 deletions src/__tests__/ticketQueries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,41 @@ import {
companyFactory,
conformityFactory,
customerFactory,
fieldFactory,
pipelineFactory,
pipelineLabelFactory,
productFactory,
stageFactory,
ticketFactory,
userFactory,
} from '../db/factories';
import { Tickets } from '../db/models';
import { Boards, Pipelines, Stages, Tickets } from '../db/models';

import { BOARD_TYPES } from '../db/models/definitions/constants';
import './setup.ts';

describe('ticketQueries', () => {
const commonTicketTypes = `
const commonTicketFields = `
_id
userId
createdAt
order
name
stageId
assignedUserIds
closeDate
reminderMinute
isComplete
description
assignedUserIds
watchedUserIds
labelIds
stageId
initialStageId
modifiedAt
modifiedBy
priority
productsData
source

companies { _id }
customers { _id }
assignedUsers { _id }
Expand All @@ -31,6 +48,8 @@ describe('ticketQueries', () => {
isWatched
hasNotified
labels { _id }
products
amount
`;

const qryTicketFilter = `
Expand All @@ -52,21 +71,24 @@ describe('ticketQueries', () => {
source: $source
closeDateType: $closeDateType
) {
${commonTicketTypes}
${commonTicketFields}
}
}
`;

const qryDetail = `
query ticketDetail($_id: String!) {
ticketDetail(_id: $_id) {
${commonTicketTypes}
${commonTicketFields}
}
}
`;

afterEach(async () => {
// Clearing test data
await Boards.deleteMany({});
await Pipelines.deleteMany({});
await Stages.deleteMany({});
await Tickets.deleteMany({});
});

Expand Down Expand Up @@ -134,7 +156,6 @@ describe('ticketQueries', () => {
const board = await boardFactory({ type: BOARD_TYPES.TICKET });
const pipeline = await pipelineFactory({ boardId: board._id, type: BOARD_TYPES.TICKET });
const stage = await stageFactory({ pipelineId: pipeline._id, type: BOARD_TYPES.TICKET });

const args = { stageId: stage._id };

await ticketFactory(args);
Expand All @@ -144,7 +165,7 @@ describe('ticketQueries', () => {
const qryList = `
query tickets($stageId: String!) {
tickets(stageId: $stageId) {
${commonTicketTypes}
${commonTicketFields}
}
}
`;
Expand All @@ -155,13 +176,66 @@ describe('ticketQueries', () => {
});

test('Ticket detail', async () => {
const ticket = await ticketFactory();
const field = await fieldFactory({ contentType: 'product', text: 'text' });
const customFieldsData = { [field._id]: 'field1' };
const product1 = await productFactory({ customFieldsData });
const product2 = await productFactory({ customFieldsData });
const user1 = await userFactory();
const user2 = await userFactory();
const label1 = await pipelineLabelFactory();
const label2 = await pipelineLabelFactory();
const board = await boardFactory({ type: BOARD_TYPES.TICKET });
const pipeline = await pipelineFactory({ boardId: board._id, type: BOARD_TYPES.TICKET });
const stage = await stageFactory({ pipelineId: pipeline._id, type: BOARD_TYPES.TICKET });

const args = { _id: ticket._id };
const productsData = [
{
productId: product1._id,
currency: 'USD',
amount: 200,
},
{
productId: product2._id,
currency: 'MNT',
amount: 300,
},
];

const ticket = await ticketFactory({
productsData,
assignedUserIds: [user1._id],
watchedUserIds: [user2._id],
labelIds: [label1._id, label2._id],
stageId: stage._id,
});

const response = await graphqlRequest(qryDetail, 'ticketDetail', args);
const response = await graphqlRequest(qryDetail, 'ticketDetail', { _id: ticket._id }, { user: user2 });

expect(response._id).toBe(ticket._id);
expect(response.userId).toBe(ticket.userId);
expect(response.order).toBe(ticket.order);
expect(response.name).toBe(ticket.name);
expect(response.reminderMinute).toBe(ticket.reminderMinute);
expect(response.isComplete).toBe(ticket.isComplete);
expect(response.description).toBe(ticket.description);
expect(response.assignedUserIds.length).toBe((ticket.assignedUserIds || []).length);
expect(response.watchedUserIds.length).toBe((ticket.watchedUserIds || []).length);
expect(response.labelIds.length).toBe((ticket.labelIds || []).length);
expect(response.stageId).toBe(ticket.stageId);
expect(response.initialStageId).toBe(ticket.initialStageId);
expect(response.modifiedBy).toBe(ticket.modifiedBy);
expect(response.priority).toBe(ticket.priority);
expect(response.source).toBe(ticket.source);
expect(response.productsData.length).toBe(2);
// resolvers
expect(response.labels.length).toBe(2);
expect(response.amount).toMatchObject({ USD: 200, MNT: 300 });
expect(response.stage._id).toBe(stage._id);
expect(response.boardId).toBe(board._id);
expect(response.assignedUsers.length).toBe(1);
expect(response.pipeline._id).toBe(pipeline._id);
expect(response.isWatched).toBe(true);
expect(response.products.length).toBe(2);
});

test('Ticket detail with watchedUserIds', async () => {
Expand Down
59 changes: 59 additions & 0 deletions src/data/resolvers/tickets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {
Companies,
Conformities,
Customers,
Fields,
Notifications,
PipelineLabels,
Pipelines,
Products,
Stages,
Users,
} from '../../db/models';
Expand Down Expand Up @@ -68,4 +70,61 @@ export default {
labels(ticket: ITicketDocument) {
return PipelineLabels.find({ _id: { $in: ticket.labelIds || [] } });
},

async products(ticket: ITicketDocument) {
const products: any = [];

for (const data of ticket.productsData || []) {
const product = await Products.getProduct({ _id: data.productId });

const { customFieldsData } = product;

if (customFieldsData) {
const customFields = {};
const fieldIds: string[] = [];

Object.keys(customFieldsData).forEach(_id => {
fieldIds.push(_id);
});

const fields = await Fields.find({ _id: { $in: fieldIds }, contentType: 'product' });

for (const field of fields) {
customFields[field._id] = {
text: field.text,
data: customFieldsData[field._id],
};
}

product.customFieldsData = customFields;
}

// Add product object to resulting list
products.push({
...data.toJSON(),
product: product.toJSON(),
});
}

return products;
},

amount(ticket: ITicketDocument) {
const data = ticket.productsData;
const amountsMap = {};

(data || []).forEach(product => {
const type = product.currency;

if (type) {
if (!amountsMap[type]) {
amountsMap[type] = 0;
}

amountsMap[type] += product.amount || 0;
}
});

return amountsMap;
},
};
10 changes: 7 additions & 3 deletions src/data/schema/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ export const conformityQueryFields = `
`;

export const commonTypes = `
userId: String
name: String!
order: Int
createdAt: Date
hasNotified: Boolean
assignedUserIds: [String]
assignedUsers: [User]
watchedUserIds: [String]
labelIds: [String]
labels: [PipelineLabel]
closeDate: Date
description: String
modifiedAt: Date
Expand All @@ -40,9 +40,13 @@ export const commonTypes = `
isComplete: Boolean,
isWatched: Boolean,
stageId: String
priority: String
initialStageId: String

labels: [PipelineLabel]
assignedUsers: [User]
stage: Stage
pipeline: Pipeline
boardId: String
priority: String
attachments: [Attachment]
`;
9 changes: 7 additions & 2 deletions src/data/schema/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ export const types = `
type Ticket {
_id: String!
source: String
${commonTypes}
productsData: JSON

products: JSON
amount: JSON
companies: [Company]
customers: [Customer]
${commonTypes}
}
`;

Expand Down Expand Up @@ -40,7 +44,8 @@ const commonParams = `
priority: String,
source: String,
reminderMinute: Int,
isComplete: Boolean
isComplete: Boolean,
productsData: JSON
`;

export const mutations = `
Expand Down
20 changes: 17 additions & 3 deletions src/db/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ export const dealFactory = async (params: IDealFactoryInput = {}) => {
amount: faker.random.objectElement(),
...(!params.noCloseDate ? { closeDate: params.closeDate || new Date() } : {}),
description: faker.random.word(),
productsDate: params.productsData,
productsData: params.productsData,
assignedUserIds: params.assignedUserIds || [faker.random.word()],
userId: params.userId || faker.random.word(),
watchedUserIds: params.watchedUserIds,
Expand Down Expand Up @@ -954,6 +954,13 @@ interface ITicketFactoryInput {
source?: string;
watchedUserIds?: string[];
labelIds?: string[];
productsData?: any;
initialStageId?: string;
userId?: string;
order?: number;
reminderMinute?: number;
isComplete?: boolean;
modifiedBy?: string;
}

export const ticketFactory = async (params: ITicketFactoryInput = {}) => {
Expand All @@ -968,10 +975,17 @@ export const ticketFactory = async (params: ITicketFactoryInput = {}) => {
...(!params.noCloseDate ? { closeDate: params.closeDate || new Date() } : {}),
description: faker.random.word(),
assignedUserIds: params.assignedUserIds,
priority: params.priority,
source: params.source,
priority: params.priority || faker.random.word(),
source: params.source || faker.random.word(),
watchedUserIds: params.watchedUserIds,
labelIds: params.labelIds || [],
productsData: params.productsData || [],
initialStageId: params.initialStageId || stage._id,
userId: params.userId || faker.random.uuid(),
order: params.order || faker.random.number(),
reminderMinute: params.reminderMinute || faker.random.number(),
isComplete: params.isComplete || faker.random.boolean(),
modifiedBy: params.modifiedBy || faker.random.uuid(),
});

return ticket.save();
Expand Down
32 changes: 32 additions & 0 deletions src/db/models/definitions/boards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ export interface IItemCommonFields {
order?: number;
searchText?: string;
priority?: string;
reminderMinute?: number;
isComplete?: boolean;
}

export interface IProductData extends Document {
productId: string;
uom: string;
currency: string;
quantity: number;
unitPrice: number;
taxPercent?: number;
tax?: number;
discountPercent?: number;
discount?: number;
amount?: number;
}

export interface IItemCommonFieldsDocument extends IItemCommonFields, Document {
Expand Down Expand Up @@ -84,6 +99,23 @@ export interface IOrderInput {
order: number;
}

export const productDataSchema = new Schema(
{
_id: field({ type: String }),
productId: field({ type: String, label: 'Product' }),
uom: field({ type: String, label: 'Unit of measurement' }),
currency: field({ type: String, label: 'Currency' }),
quantity: field({ type: Number, label: 'Quantity' }),
unitPrice: field({ type: Number, label: 'Unit price' }),
taxPercent: field({ type: Number, label: 'Tax percent' }),
tax: field({ type: Number, label: 'Tax' }),
discountPercent: field({ type: Number, label: 'Discount percent' }),
discount: field({ type: Number, label: 'Discount' }),
amount: field({ type: Number, label: 'Amount' }),
},
{ _id: false },
);

const attachmentSchema = new Schema(
{
name: field({ type: String, label: 'Name' }),
Expand Down
Loading