Skip to content

Commit

Permalink
perf(documents): refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Wlkr123 committed Apr 4, 2023
1 parent 0f1f1a1 commit f198c62
Show file tree
Hide file tree
Showing 21 changed files with 655 additions and 66 deletions.
2 changes: 1 addition & 1 deletion packages/api-plugin-template.erxes/src/index.ts
Expand Up @@ -562,7 +562,7 @@ async function startServer() {
`${configs.name}:documents.editorAttributes`,
async args => ({
status: 'success',
data: await documents.editorAttributes()
data: await documents.editorAttributes(args)
})
);

Expand Down
115 changes: 92 additions & 23 deletions packages/plugin-cards-api/src/documents.ts
Expand Up @@ -2,35 +2,75 @@ import { generateModels } from './connectionResolver';
import {
sendContactsMessage,
sendCoreMessage,
sendProductsMessage
sendProductsMessage,
sendFormsMessage
} from './messageBroker';

import * as _ from 'lodash';
const toMoney = value => {
return new Intl.NumberFormat().format(value);
};

export default {
editorAttributes: async () => {
return [
{ value: 'name', name: 'Name' },
{ value: 'createdAt', name: 'Created at' },
{ value: 'closeDate', name: 'Close date' },
{ value: 'description', name: 'Description' },
{ value: 'productsInfo', name: 'Products information' },
{ value: 'servicesInfo', name: 'Services information' },
{ value: 'assignedUsers', name: 'Assigned users' },
{ value: 'customers', name: 'Customers' },
{ value: 'companies', name: 'Companies' },
{ value: 'now', name: 'Now' },
{ value: 'productTotalAmount', name: 'Products total amount' },
{ value: 'servicesTotalAmount', name: 'Services total amount' },
{ value: 'totalAmount', name: 'Total amount' },
{ value: 'totalAmountVat', name: 'Total amount vat' },
{ value: 'totalAmountWithoutVat', name: 'Total amount without vat' },
{ value: 'discount', name: 'Discount' },
{ value: 'paymentCash', name: 'Payment cash' },
{ value: 'paymentNonCash', name: 'Payment non cash' }
const getCustomFields = async ({ subdomain }) => {
let fields: any[] = [];

for (const cardType of ['task', 'ticket', 'deal']) {
let items = await sendFormsMessage({
subdomain,
action: 'fields.fieldsCombinedByContentType',
isRPC: true,
data: {
contentType: `cards:${cardType}`
},
defaultValue: []
});

fields = [
...fields,
...items.map(f => ({
value: f.name,
name: `${cardType}:${f.label}`
}))
];
}
return fields;
};

const commonFields = [
{ value: 'name', name: 'Name' },
{ value: 'createdAt', name: 'Created at' },
{ value: 'closeDate', name: 'Close date' },
{ value: 'description', name: 'Description' },
{ value: 'productsInfo', name: 'Products information' },
{ value: 'servicesInfo', name: 'Services information' },
{ value: 'assignedUsers', name: 'Assigned users' },
{ value: 'customers', name: 'Customers' },
{ value: 'companies', name: 'Companies' },
{ value: 'now', name: 'Now' },
{ value: 'productTotalAmount', name: 'Products total amount' },
{ value: 'servicesTotalAmount', name: 'Services total amount' },
{ value: 'totalAmount', name: 'Total amount' },
{ value: 'totalAmountVat', name: 'Total amount vat' },
{ value: 'totalAmountWithoutVat', name: 'Total amount without vat' },
{ value: 'discount', name: 'Discount' },
{ value: 'paymentCash', name: 'Payment cash' },
{ value: 'paymentNonCash', name: 'Payment non cash' }
];

export default {
types: [
{
label: 'Cards',
type: 'cards'
}
],

editorAttributes: async ({ subdomain }) => {
const customFields = await getCustomFields({ subdomain });
const uniqueFields = customFields.filter(
customField =>
!commonFields.some(field => field.value === customField.value)
);
return [...commonFields, ...uniqueFields];
},

replaceContent: async ({ subdomain, data: { stageId, itemId, content } }) => {
Expand Down Expand Up @@ -331,6 +371,35 @@ export default {
toMoney(replaceProductsResult.discount + replaceServicesResult.discount)
);

for (const customFieldData of item.customFieldsData || []) {
replacedContent = replacedContent.replace(
new RegExp(`{{ customFieldsData.${customFieldData.field} }}`, 'g'),
customFieldData.stringValue
);
}

const fileds = (await getCustomFields({ subdomain })).filter(
customField =>
customField.name.includes(stage.type) &&
!customField.value.includes('customFieldsData')
);

for (const field of fileds) {
const propertyNames = field.value.includes('.')
? field.value.split('.')
: [field.value];
let propertyValue = item;

for (const propertyName of propertyNames) {
propertyValue = item[propertyName];
}

replacedContent = replacedContent.replace(
new RegExp(`{{ ${field.value} }}`, 'g'),
propertyValue || ''
);
}

return [replacedContent];
}
};
2 changes: 2 additions & 0 deletions packages/plugin-contacts-api/src/configs.ts
Expand Up @@ -22,6 +22,7 @@ import {
updateContactValidationStatus
} from './verifierUtils';
import exporter from './exporter';
import documents from './documents';

export let mainDb;
export let graphqlPubsub;
Expand Down Expand Up @@ -56,6 +57,7 @@ export default {
webhooks,
dashboards,
exporter,
documents,
// for fixing permissions
permissions
},
Expand Down
170 changes: 170 additions & 0 deletions packages/plugin-contacts-api/src/documents.ts
@@ -0,0 +1,170 @@
import { generateModels } from './connectionResolver';
import { sendCoreMessage, sendFormsMessage } from './messageBroker';

const getContactDetail = async (subdomain, contentType, contentTypeId) => {
const models = await generateModels(subdomain);

let contact;

if (contentType === 'contacts:customer') {
contact = await models.Customers.findOne({ _id: contentTypeId });
}
if (contentType === 'contacts:company') {
contact = await models.Companies.findOne({ _id: contentTypeId });
}

return contact;
};

const getFields = async ({ subdomain, contentType }) => {
const fields = await sendFormsMessage({
subdomain,
action: 'fields.fieldsCombinedByContentType',
isRPC: true,
data: {
contentType
},
defaultValue: []
});
return fields.map(f => ({ value: f.name, name: f.label }));
};

export default {
types: [
{
label: 'Customer',
type: 'contacts:customer'
},
{
label: 'Company',
type: 'contacts:company'
}
],

editorAttributes: async ({ subdomain, data: { contentType } }) => {
return await getFields({ subdomain, contentType });
},
replaceContent: async ({
subdomain,
data: { contentTypeId, content, contentType }
}) => {
const contact = await getContactDetail(
subdomain,
contentType,
contentTypeId
);

if (!contact) {
return '';
}

let replacedContent: any = content || {};

['names', 'emails', 'phones'].forEach(field => {
replacedContent = replacedContent.replace(
new RegExp(`{{ ${field} }}`, 'g'),
(contact[field] || []).join(', ')
);
});

[
'status',
'primaryName',
'primaryPhone',
'primaryEmail',
'firstName',
'lastName',
'middleName',
'sex',
'score',
'position',
'department',
'code',
'country',
'city',
'region',
'industry'
].forEach(field => {
replacedContent = replacedContent.replace(
new RegExp(`{{ ${field} }}`, 'g'),
contact[field] || ''
);
});

['createdAt', 'modifiedAt', 'birthDate'].forEach(field => {
replacedContent = replacedContent.replace(
new RegExp(` {{ ${field} }} `, 'g'),
contact[field] ? contact[field].toLocaleDateString() : ''
);
});

if (replacedContent.includes(`{{ parentCompanyId }}`)) {
const parent = await getContactDetail(
subdomain,
contentType,
contact.parentCompanyId
);

if (parent) {
replacedContent = replacedContent.replace(
/{{ parentCompanyId }}/g,
(parent?.names || []).join(',')
);
}
}
if (replacedContent.includes(`{{ ownerId }}`)) {
const owner = await sendCoreMessage({
subdomain,
action: 'users.findOne',
data: {
_id: contact.ownerId
},
isRPC: true,
defaultValue: {}
});

if (owner) {
if (owner.firstName && owner.lastName) {
replacedContent = replacedContent.replace(
/{{ ownerId }}/g,
`${owner?.firstName} ${owner?.lastName}`
);
} else {
replacedContent = replacedContent.replace(
/{{ ownerId }}/g,
owner?.email || ''
);
}
}
}

for (const customFieldData of contact.customFieldsData) {
replacedContent = replacedContent.replace(
new RegExp(`{{ customFieldsData.${customFieldData.field} }}`, 'g'),
customFieldData.stringValue
);
}

const fields = (await getFields({ subdomain, contentType })).filter(
customField => !customField.value.includes('customFieldsData')
);

for (const field of fields) {
const propertyNames = field.value.includes('.')
? field.value.split('.')
: [field.value];
let propertyValue = contact;

for (const propertyName in propertyNames) {
propertyValue = propertyValue[propertyName] || propertyValue;
}

replacedContent = replacedContent.replace(
new RegExp(` {{ ${field.value} }} `, 'g'),
propertyValue || ''
);
}

return [replacedContent];
}
};
Expand Up @@ -12,6 +12,7 @@ import { UserHeader } from '@erxes/ui-contacts/src/customers/styles';
import Wrapper from '@erxes/ui/src/layout/components/Wrapper';
import { __ } from 'coreui/utils';
import { isEnabled } from '@erxes/ui/src/utils/core';
import PrintAction from '@erxes/ui-contacts/src/customers/components/common/PrintAction';

type Props = {
company: ICompany;
Expand Down Expand Up @@ -56,6 +57,9 @@ class CompanyDetails extends React.Component<Props> {
mainHead={
<UserHeader>
<InfoSection company={company}>
{isEnabled('documents') && (
<PrintAction coc={company} contentType="contacts:company" />
)}
<BasicInfo company={company} />
</InfoSection>
</UserHeader>
Expand Down
Expand Up @@ -19,6 +19,7 @@ import { TabTitle } from '@erxes/ui/src/components/tabs';
import Widget from '@erxes/ui-engage/src/containers/Widget';
import Wrapper from '@erxes/ui/src/layout/components/Wrapper';
import { isEnabled } from '@erxes/ui/src/utils/core';
import PrintAction from '@erxes/ui-contacts/src/customers/components/common/PrintAction';

type Props = {
customer: ICustomer;
Expand Down Expand Up @@ -143,6 +144,9 @@ class CustomerDetails extends React.Component<Props> {
mainHead={
<UserHeader>
<InfoSection avatarSize={40} customer={customer}>
{isEnabled('documents') && (
<PrintAction coc={customer} contentType="contacts:customer" />
)}
<ActionSection customer={customer} />
</InfoSection>
<LeadState customer={customer} />
Expand Down
9 changes: 8 additions & 1 deletion packages/plugin-documents-api/src/configs.ts
Expand Up @@ -105,9 +105,16 @@ export default {
replacedContents.push(content);
} else {
try {
const serviceName = document.contentType.includes(':')
? document.contentType.substring(
0,
document.contentType.indexOf(':')
)
: document.contentType;

replacedContents = await sendCommonMessage({
subdomain,
serviceName: document.contentType,
serviceName,
action: 'documents.replaceContent',
isRPC: true,
data: {
Expand Down

0 comments on commit f198c62

Please sign in to comment.