mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
refactor: change help text
This commit is contained in:
@@ -24,7 +24,7 @@ const BulkSendUi = (props) => {
|
||||
price: (75.0).toFixed(2),
|
||||
quantity: 500,
|
||||
priceperbulksend: 0.15,
|
||||
totalQuickSend: 0
|
||||
totalcredits: 0
|
||||
});
|
||||
const [isQuotaReached, setIsQuotaReached] = useState(false);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
@@ -44,11 +44,16 @@ const BulkSendUi = (props) => {
|
||||
if (subscription?.plan === "freeplan") {
|
||||
setIsFreePlan(true);
|
||||
}
|
||||
const allowedquicksend = await Parse.Cloud.run("allowedquicksend");
|
||||
if (allowedquicksend > 0) {
|
||||
setIsBulkAvailable(true);
|
||||
const resCredits = await Parse.Cloud.run("allowedcredits");
|
||||
if (resCredits) {
|
||||
const allowedcredits = resCredits?.allowedcredits || 0;
|
||||
const addoncredits = resCredits?.addoncredits || 0;
|
||||
const totalcredits = allowedcredits + addoncredits;
|
||||
if (totalcredits > 0) {
|
||||
setIsBulkAvailable(true);
|
||||
}
|
||||
setAmount((obj) => ({ ...obj, totalcredits: totalcredits }));
|
||||
}
|
||||
setAmount((obj) => ({ ...obj, totalQuickSend: allowedquicksend }));
|
||||
const getPlaceholder = props.item?.Placeholders;
|
||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||
placeholderObj?.placeHolder?.some((holder) =>
|
||||
@@ -121,7 +126,7 @@ const BulkSendUi = (props) => {
|
||||
const handleAddForm = (e) => {
|
||||
e.preventDefault();
|
||||
// Check if the quick send limit has been reached
|
||||
if (isEnableSubscription && forms.length >= amount.totalQuickSend) {
|
||||
if (isEnableSubscription && forms.length >= amount.totalcredits) {
|
||||
setIsQuotaReached(true);
|
||||
} else {
|
||||
if (forms?.length < allowedForm) {
|
||||
@@ -244,8 +249,8 @@ const BulkSendUi = (props) => {
|
||||
e.stopPropagation();
|
||||
setIsSubmit(true);
|
||||
try {
|
||||
const resAddon = await Parse.Cloud.run("buyquicksend", {
|
||||
quicksend: amount.quantity
|
||||
const resAddon = await Parse.Cloud.run("buycredits", {
|
||||
credits: amount.quantity
|
||||
});
|
||||
if (resAddon) {
|
||||
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||
@@ -257,7 +262,7 @@ const BulkSendUi = (props) => {
|
||||
quantity: 500,
|
||||
priceperbulksend: 0.15,
|
||||
price: (75.0).toFixed(2),
|
||||
totalQuickSend: _resAddon.addon
|
||||
totalcredits: _resAddon.addon
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -345,13 +350,15 @@ const BulkSendUi = (props) => {
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col mx-4 mb-4 gap-3">
|
||||
<button
|
||||
onClick={handleAddForm}
|
||||
className="op-btn op-btn-primary focus:outline-none"
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>{" "}
|
||||
<span>{t("add-new")}</span>
|
||||
</button>
|
||||
{isEnableSubscription && (
|
||||
<button
|
||||
onClick={handleAddForm}
|
||||
className="op-btn op-btn-primary focus:outline-none"
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>{" "}
|
||||
<span>{t("add-new")}</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-accent focus:outline-none"
|
||||
|
||||
@@ -29,7 +29,8 @@ function GenerateToken() {
|
||||
const [amount, setAmount] = useState({
|
||||
quantity: 500,
|
||||
priceperapi: 0.15,
|
||||
totalapis: 0,
|
||||
allowedcredits: 0,
|
||||
addoncredits: 0,
|
||||
price: (75.0).toFixed(2)
|
||||
});
|
||||
const [isFormLoader, setIsFormLoader] = useState(false);
|
||||
@@ -59,8 +60,12 @@ function GenerateToken() {
|
||||
};
|
||||
const res = await axios.post(url, {}, { headers: headers });
|
||||
if (res) {
|
||||
const allowedapis = await Parse.Cloud.run("allowedapis");
|
||||
setAmount((obj) => ({ ...obj, totalapis: allowedapis }));
|
||||
const resCredits = await Parse.Cloud.run("allowedcredits");
|
||||
setAmount((obj) => ({
|
||||
...obj,
|
||||
allowedcredits: resCredits.allowedcredits,
|
||||
addoncredits: resCredits.addoncredits
|
||||
}));
|
||||
SetApiToken(res?.data?.result?.result);
|
||||
}
|
||||
const body = { email: Parse?.User?.current()?.getEmail() || "" };
|
||||
@@ -142,8 +147,8 @@ function GenerateToken() {
|
||||
e.stopPropagation();
|
||||
setIsFormLoader(true);
|
||||
try {
|
||||
const resAddon = await Parse.Cloud.run("buyapis", {
|
||||
apis: amount.quantity
|
||||
const resAddon = await Parse.Cloud.run("buycredits", {
|
||||
credits: amount.quantity
|
||||
});
|
||||
if (resAddon) {
|
||||
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||
@@ -153,7 +158,7 @@ function GenerateToken() {
|
||||
quantity: 500,
|
||||
priceperapi: 0.15,
|
||||
price: (75.0).toFixed(2),
|
||||
totalapis: _resAddon.addon
|
||||
addoncredits: _resAddon.addon
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -293,7 +298,11 @@ function GenerateToken() {
|
||||
</li>
|
||||
<div className="text-xs md:text-[15px] my-4">
|
||||
<span className="font-medium">{t("remainingapis")}</span>{" "}
|
||||
{amount.totalapis}
|
||||
{amount.allowedcredits}
|
||||
</div>
|
||||
<div className="text-xs md:text-[15px] my-4">
|
||||
<span className="font-medium">Addon credits: </span>{" "}
|
||||
{amount.addoncredits}
|
||||
</div>
|
||||
<hr />
|
||||
</ul>
|
||||
|
||||
@@ -1456,7 +1456,13 @@ const ReportTable = (props) => {
|
||||
<i className={act.btnIcon}></i>
|
||||
{act.btnLabel && (
|
||||
<span className="uppercase font-medium">
|
||||
{t(`btnLabel.${act.btnLabel}`)}
|
||||
{act.btnLabel.includes(
|
||||
"Quick send"
|
||||
) && isEnableSubscription
|
||||
? "Bulk Send"
|
||||
: `${t(
|
||||
`btnLabel.${act.btnLabel}`
|
||||
)}`}
|
||||
</span>
|
||||
)}
|
||||
{isOption[item.objectId] &&
|
||||
@@ -1783,7 +1789,11 @@ const ReportTable = (props) => {
|
||||
{isBulkSend[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={t("quick-send")}
|
||||
title={
|
||||
isEnableSubscription
|
||||
? "Bulk send"
|
||||
: t("quick-send")
|
||||
}
|
||||
handleClose={() => setIsBulkSend({})}
|
||||
>
|
||||
{isLoader[item.objectId] ? (
|
||||
|
||||
@@ -83,283 +83,302 @@ export default async function createDocumentWithTemplate(request, response) {
|
||||
subscription.include('ExtUserPtr');
|
||||
subscription.greaterThan('AllowedApis', 0);
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
|
||||
if (resSub) {
|
||||
const templateQuery = new Parse.Query('contracts_Template');
|
||||
templateQuery.include('ExtUserPtr');
|
||||
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
|
||||
if (templateRes) {
|
||||
const template = JSON.parse(JSON.stringify(templateRes));
|
||||
if (template?.Placeholders?.length > 0) {
|
||||
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
|
||||
const isValid =
|
||||
signers.length >= emptyplaceholder.length &&
|
||||
signers.length <= template?.Placeholders?.length;
|
||||
const placeholder =
|
||||
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
|
||||
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
|
||||
// console.log('isValid ', isValid);
|
||||
if (isValid && updateSigners) {
|
||||
//Check if every item's placeholders contain at least one placeholder with type 'signature'.
|
||||
let isSignature = template?.Placeholders?.every(item =>
|
||||
item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature'))
|
||||
);
|
||||
if (!isSignature) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
const folderPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
};
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', template.Name);
|
||||
if (template?.Note) {
|
||||
object.set('Note', template.Note);
|
||||
}
|
||||
if (template?.Description) {
|
||||
object.set('Description', template.Description);
|
||||
}
|
||||
object.set('IsSendMail', send_email);
|
||||
if (sendInOrder) {
|
||||
object.set('SendinOrder', sendInOrder);
|
||||
} else if (template?.SendinOrder && template?.SendinOrder) {
|
||||
object.set('SendinOrder', template?.SendinOrder);
|
||||
}
|
||||
let templateSigner = template?.Signers ? template?.Signers : [];
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners = [...signers];
|
||||
let createContactUrl = protocol + '/v1/createcontact';
|
||||
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const addonCredits = _resSub?.AddonCredits || 0;
|
||||
const totalcredits = allowedCredits + addonCredits;
|
||||
if (totalcredits > 0) {
|
||||
const templateQuery = new Parse.Query('contracts_Template');
|
||||
templateQuery.include('ExtUserPtr');
|
||||
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
|
||||
if (templateRes) {
|
||||
const template = JSON.parse(JSON.stringify(templateRes));
|
||||
if (template?.Placeholders?.length > 0) {
|
||||
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
|
||||
const isValid =
|
||||
signers.length >= emptyplaceholder.length &&
|
||||
signers.length <= template?.Placeholders?.length;
|
||||
const placeholder =
|
||||
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
|
||||
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
|
||||
// console.log('isValid ', isValid);
|
||||
if (isValid && updateSigners) {
|
||||
//Check if every item's placeholders contain at least one placeholder with type 'signature'.
|
||||
let isSignature = template?.Placeholders?.every(item =>
|
||||
item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature'))
|
||||
);
|
||||
if (!isSignature) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
const folderPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
};
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', template.Name);
|
||||
if (template?.Note) {
|
||||
object.set('Note', template.Note);
|
||||
}
|
||||
if (template?.Description) {
|
||||
object.set('Description', template.Description);
|
||||
}
|
||||
object.set('IsSendMail', send_email);
|
||||
if (sendInOrder) {
|
||||
object.set('SendinOrder', sendInOrder);
|
||||
} else if (template?.SendinOrder && template?.SendinOrder) {
|
||||
object.set('SendinOrder', template?.SendinOrder);
|
||||
}
|
||||
let templateSigner = template?.Signers ? template?.Signers : [];
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners = [...signers];
|
||||
let createContactUrl = protocol + '/v1/createcontact';
|
||||
|
||||
for (const obj of parseSigners) {
|
||||
const body = {
|
||||
name: obj?.name || '',
|
||||
email: obj?.email || '',
|
||||
phone: obj?.phone || '',
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(createContactUrl, body, {
|
||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||
});
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: res.data?.objectId,
|
||||
for (const obj of parseSigners) {
|
||||
const body = {
|
||||
name: obj?.name || '',
|
||||
email: obj?.email || '',
|
||||
phone: obj?.phone || '',
|
||||
};
|
||||
const newObj = { ...obj, contactPtr: contactPtr };
|
||||
contact.push(newObj);
|
||||
} catch (err) {
|
||||
// console.log('err ', err);
|
||||
if (err?.response?.data?.objectId) {
|
||||
try {
|
||||
const res = await axios.post(createContactUrl, body, {
|
||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||
});
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: err.response.data?.objectId,
|
||||
objectId: res.data?.objectId,
|
||||
};
|
||||
const newObj = { ...obj, contactPtr: contactPtr };
|
||||
contact.push(newObj);
|
||||
} else {
|
||||
console.log('err ', err);
|
||||
} catch (err) {
|
||||
// console.log('err ', err);
|
||||
if (err?.response?.data?.objectId) {
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: err.response.data?.objectId,
|
||||
};
|
||||
const newObj = { ...obj, contactPtr: contactPtr };
|
||||
contact.push(newObj);
|
||||
} else {
|
||||
console.log('err ', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const contactPtrs = contact.map(x => x.contactPtr);
|
||||
object.set('Signers', [...templateSigner, ...contactPtrs]);
|
||||
const contactPtrs = contact.map(x => x.contactPtr);
|
||||
object.set('Signers', [...templateSigner, ...contactPtrs]);
|
||||
|
||||
let updatedPlaceholder = template?.Placeholders?.map(x => {
|
||||
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
|
||||
let updatedPlaceholder = template?.Placeholders?.map(x => {
|
||||
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
|
||||
|
||||
if (matchingSigner) {
|
||||
return {
|
||||
...x,
|
||||
signerObjId: matchingSigner?.contactPtr?.objectId,
|
||||
signerPtr: matchingSigner?.contactPtr,
|
||||
};
|
||||
} else {
|
||||
return { ...x };
|
||||
}
|
||||
});
|
||||
object.set('Placeholders', updatedPlaceholder);
|
||||
} else {
|
||||
object.set('Signers', templateSigner);
|
||||
}
|
||||
object.set('URL', template.URL);
|
||||
object.set('SignedUrl', template.URL);
|
||||
object.set('SentToOthers', true);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('CreatedBy', template.CreatedBy);
|
||||
object.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: template.ExtUserPtr.objectId,
|
||||
});
|
||||
if (folderId) {
|
||||
object.set('Folder', folderPtr);
|
||||
}
|
||||
const newACL = new Parse.ACL();
|
||||
newACL.setPublicReadAccess(false);
|
||||
newACL.setPublicWriteAccess(false);
|
||||
newACL.setReadAccess(userPtr.objectId, true);
|
||||
newACL.setWriteAccess(userPtr.objectId, true);
|
||||
object.setACL(newACL);
|
||||
const res = await object.save(null, { useMasterKey: true });
|
||||
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = template.ExtUserPtr.Email;
|
||||
let sendMail;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
||||
imgPng +
|
||||
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
template.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
template.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||
sender +
|
||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: template.Name,
|
||||
sender_name: template.ExtUserPtr.Name,
|
||||
sender_mail: template.ExtUserPtr.Email,
|
||||
sender_phone: template.ExtUserPtr?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
body: email_html,
|
||||
if (matchingSigner) {
|
||||
return {
|
||||
...x,
|
||||
signerObjId: matchingSigner?.contactPtr?.objectId,
|
||||
signerPtr: matchingSigner?.contactPtr,
|
||||
};
|
||||
} else {
|
||||
return { ...x };
|
||||
}
|
||||
});
|
||||
object.set('Placeholders', updatedPlaceholder);
|
||||
} else {
|
||||
object.set('Signers', templateSigner);
|
||||
}
|
||||
object.set('URL', template.URL);
|
||||
object.set('SignedUrl', template.URL);
|
||||
object.set('SentToOthers', true);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('CreatedBy', template.CreatedBy);
|
||||
object.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: template.ExtUserPtr.objectId,
|
||||
});
|
||||
if (folderId) {
|
||||
object.set('Folder', folderPtr);
|
||||
}
|
||||
const newACL = new Parse.ACL();
|
||||
newACL.setPublicReadAccess(false);
|
||||
newACL.setPublicWriteAccess(false);
|
||||
newACL.setReadAccess(userPtr.objectId, true);
|
||||
newACL.setWriteAccess(userPtr.objectId, true);
|
||||
object.setACL(newACL);
|
||||
const res = await object.save(null, { useMasterKey: true });
|
||||
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: template.ExtUserPtr.objectId,
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = template.ExtUserPtr.Email;
|
||||
let sendMail;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = template.ExtUserPtr.Company
|
||||
? template.ExtUserPtr.Company
|
||||
: '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
||||
imgPng +
|
||||
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
template.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
template.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||
sender +
|
||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: template.Name,
|
||||
sender_name: template.ExtUserPtr.Name,
|
||||
sender_mail: template.ExtUserPtr.Email,
|
||||
sender_phone: template.ExtUserPtr?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
body: email_html,
|
||||
};
|
||||
}
|
||||
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: template.ExtUserPtr.objectId,
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
try {
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: template?.URL,
|
||||
name: template?.Name,
|
||||
note: template?.Note || '',
|
||||
description: template?.Description || '',
|
||||
signers: contact?.map(x => ({
|
||||
name: x.name,
|
||||
email: x.email,
|
||||
phone: x?.phone || '',
|
||||
})),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
|
||||
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
try {
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: template?.URL,
|
||||
name: template?.Name,
|
||||
note: template?.Note || '',
|
||||
description: template?.Description || '',
|
||||
signers: contact?.map(x => ({
|
||||
name: x.name,
|
||||
email: x.email,
|
||||
phone: x?.phone || '',
|
||||
})),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
|
||||
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err', err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err', err);
|
||||
}
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 200 },
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
if (allowedCredits > 0) {
|
||||
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log("resSubcription ", resSubcription)
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers properly!' });
|
||||
}
|
||||
const updateApiCount =
|
||||
resSub?.get('AllowedApis') && resSub.get('AllowedApis') > 0
|
||||
? resSub.get('AllowedApis') - 1
|
||||
: 0;
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
subscriptionCls.set('AllowedApis', updateApiCount);
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log("resSubcription ", resSubcription)
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
@@ -368,32 +387,25 @@ export default async function createDocumentWithTemplate(request, response) {
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers properly!' });
|
||||
return response.status(400).json({ error: 'Please setup template properly!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 400 },
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please setup template properly!' });
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||
}
|
||||
} else {
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy API credits and try again later.' });
|
||||
return response.status(400).json({ error: 'Please buy subscriptions.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||
|
||||
@@ -95,325 +95,335 @@ export default async function createDocumentwithCoordinate(request, response) {
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
subscription.greaterThan('AllowedApis', 0);
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
if (signers && signers.length > 0) {
|
||||
// Check if at least one signature exists among all items in the signers array
|
||||
let isSignExist = signers.every(item =>
|
||||
item.widgets.some(data => data?.type === 'signature')
|
||||
);
|
||||
if (!isSignExist) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
let fileUrl;
|
||||
if (request.files?.[0]) {
|
||||
const base64 = fileData?.toString('base64');
|
||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||
base64: base64,
|
||||
});
|
||||
await file.save({ useMasterKey: true });
|
||||
fileUrl = file.url();
|
||||
const buffer = Buffer.from(base64, 'base64');
|
||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||
} else {
|
||||
const filename = sanitizeFileName(`${name}.pdf`);
|
||||
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
fileUrl = file.url();
|
||||
const buffer = Buffer.from(base64File, 'base64');
|
||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||
}
|
||||
const contractsUser = new Parse.Query('contracts_Users');
|
||||
contractsUser.equalTo('UserId', userPtr);
|
||||
const extUser = await contractsUser.first({ useMasterKey: true });
|
||||
const parseExtUser = JSON.parse(JSON.stringify(extUser));
|
||||
|
||||
const extUserPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
};
|
||||
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', name);
|
||||
|
||||
if (note) {
|
||||
object.set('Note', note);
|
||||
}
|
||||
if (description) {
|
||||
object.set('Description', description);
|
||||
}
|
||||
if (sendInOrder) {
|
||||
object.set('SendinOrder', sendInOrder);
|
||||
}
|
||||
object.set('URL', fileUrl);
|
||||
object.set('SignedUrl', fileUrl);
|
||||
object.set('SentToOthers', true);
|
||||
object.set('CreatedBy', userPtr);
|
||||
object.set('ExtUserPtr', extUserPtr);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('IsSendMail', send_email);
|
||||
let contact = [];
|
||||
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const addonCredits = _resSub?.AddonCredits || 0;
|
||||
const totalcredits = allowedCredits + addonCredits;
|
||||
if (totalcredits > 0) {
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners;
|
||||
if (base64File) {
|
||||
parseSigners = signers;
|
||||
} else {
|
||||
parseSigners = JSON.parse(signers);
|
||||
// Check if at least one signature exists among all items in the signers array
|
||||
let isSignExist = signers.every(item =>
|
||||
item.widgets.some(data => data?.type === 'signature')
|
||||
);
|
||||
if (!isSignExist) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
let createContactUrl = protocol + '/v1/createcontact';
|
||||
let fileUrl;
|
||||
if (request.files?.[0]) {
|
||||
const base64 = fileData?.toString('base64');
|
||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||
base64: base64,
|
||||
});
|
||||
await file.save({ useMasterKey: true });
|
||||
fileUrl = file.url();
|
||||
const buffer = Buffer.from(base64, 'base64');
|
||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||
} else {
|
||||
const filename = sanitizeFileName(`${name}.pdf`);
|
||||
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
fileUrl = file.url();
|
||||
const buffer = Buffer.from(base64File, 'base64');
|
||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||
}
|
||||
const contractsUser = new Parse.Query('contracts_Users');
|
||||
contractsUser.equalTo('UserId', userPtr);
|
||||
const extUser = await contractsUser.first({ useMasterKey: true });
|
||||
const parseExtUser = JSON.parse(JSON.stringify(extUser));
|
||||
|
||||
for (const [index, element] of parseSigners.entries()) {
|
||||
const body = {
|
||||
name: element?.name || '',
|
||||
email: element?.email || '',
|
||||
phone: element?.phone || '',
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(createContactUrl, body, {
|
||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||
});
|
||||
// console.log('res ', res.data);
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: res.data?.objectId,
|
||||
const extUserPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
};
|
||||
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', name);
|
||||
|
||||
if (note) {
|
||||
object.set('Note', note);
|
||||
}
|
||||
if (description) {
|
||||
object.set('Description', description);
|
||||
}
|
||||
if (sendInOrder) {
|
||||
object.set('SendinOrder', sendInOrder);
|
||||
}
|
||||
object.set('URL', fileUrl);
|
||||
object.set('SignedUrl', fileUrl);
|
||||
object.set('SentToOthers', true);
|
||||
object.set('CreatedBy', userPtr);
|
||||
object.set('ExtUserPtr', extUserPtr);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('IsSendMail', send_email);
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners;
|
||||
if (base64File) {
|
||||
parseSigners = signers;
|
||||
} else {
|
||||
parseSigners = JSON.parse(signers);
|
||||
}
|
||||
let createContactUrl = protocol + '/v1/createcontact';
|
||||
|
||||
for (const [index, element] of parseSigners.entries()) {
|
||||
const body = {
|
||||
name: element?.name || '',
|
||||
email: element?.email || '',
|
||||
phone: element?.phone || '',
|
||||
};
|
||||
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
||||
contact.push(newObj);
|
||||
} catch (err) {
|
||||
// console.log('err ', err.response);
|
||||
if (err?.response?.data?.objectId) {
|
||||
try {
|
||||
const res = await axios.post(createContactUrl, body, {
|
||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||
});
|
||||
// console.log('res ', res.data);
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: err.response.data?.objectId,
|
||||
objectId: res.data?.objectId,
|
||||
};
|
||||
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
||||
contact.push(newObj);
|
||||
} catch (err) {
|
||||
// console.log('err ', err.response);
|
||||
if (err?.response?.data?.objectId) {
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: err.response.data?.objectId,
|
||||
};
|
||||
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
||||
contact.push(newObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
object.set(
|
||||
'Signers',
|
||||
contact?.map(x => x.contactPtr)
|
||||
);
|
||||
let updatePlaceholders = contact.map(signer => {
|
||||
const placeHolder = [];
|
||||
object.set(
|
||||
'Signers',
|
||||
contact?.map(x => x.contactPtr)
|
||||
);
|
||||
let updatePlaceholders = contact.map(signer => {
|
||||
const placeHolder = [];
|
||||
|
||||
for (const widget of signer.widgets) {
|
||||
const pageNumber = widget.page;
|
||||
const options = formatWidgetOptions(widget.type, widget.options);
|
||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||
const widgetData = {
|
||||
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
||||
key: randomId(),
|
||||
isDrag: false,
|
||||
scale: 1,
|
||||
isMobile: false,
|
||||
zIndex: 1,
|
||||
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
||||
options: options,
|
||||
Width: widget.w,
|
||||
Height: widget.h,
|
||||
xPosition: widget.x,
|
||||
yPosition: widget.y,
|
||||
};
|
||||
|
||||
if (page) {
|
||||
page.pos.push(widgetData);
|
||||
} else {
|
||||
placeHolder.push({ pageNumber, pos: [widgetData] });
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
signerObjId: signer?.contactPtr?.objectId,
|
||||
signerPtr: signer?.contactPtr,
|
||||
Role: signer.role,
|
||||
Id: randomId(),
|
||||
blockColor: color[signer?.index],
|
||||
placeHolder,
|
||||
};
|
||||
});
|
||||
object.set('Placeholders', updatePlaceholders);
|
||||
}
|
||||
if (folderId) {
|
||||
object.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
});
|
||||
}
|
||||
const newACL = new Parse.ACL();
|
||||
newACL.setPublicReadAccess(false);
|
||||
newACL.setPublicWriteAccess(false);
|
||||
newACL.setReadAccess(userPtr.objectId, true);
|
||||
newACL.setWriteAccess(userPtr.objectId, true);
|
||||
object.setACL(newACL);
|
||||
const res = await object.save(null, { useMasterKey: true });
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: fileUrl,
|
||||
name: name,
|
||||
note: note || '',
|
||||
description: description || '',
|
||||
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (parseExtUser && parseExtUser.Webhook) {
|
||||
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
|
||||
}
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = parseExtUser.Email;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
parseExtUser.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||
sender +
|
||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: name,
|
||||
sender_name: parseExtUser.Name,
|
||||
sender_mail: parseExtUser.Email,
|
||||
sender_phone: parseExtUser?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
body: email_html,
|
||||
for (const widget of signer.widgets) {
|
||||
const pageNumber = widget.page;
|
||||
const options = formatWidgetOptions(widget.type, widget.options);
|
||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||
const widgetData = {
|
||||
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
||||
key: randomId(),
|
||||
isDrag: false,
|
||||
scale: 1,
|
||||
isMobile: false,
|
||||
zIndex: 1,
|
||||
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
||||
options: options,
|
||||
Width: widget.w,
|
||||
Height: widget.h,
|
||||
xPosition: widget.x,
|
||||
yPosition: widget.y,
|
||||
};
|
||||
|
||||
if (page) {
|
||||
page.pos.push(widgetData);
|
||||
} else {
|
||||
placeHolder.push({ pageNumber, pos: [widgetData] });
|
||||
}
|
||||
}
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: extUser.id,
|
||||
return {
|
||||
signerObjId: signer?.contactPtr?.objectId,
|
||||
signerPtr: signer?.contactPtr,
|
||||
Role: signer.role,
|
||||
Id: randomId(),
|
||||
blockColor: color[signer?.index],
|
||||
placeHolder,
|
||||
};
|
||||
});
|
||||
object.set('Placeholders', updatePlaceholders);
|
||||
}
|
||||
if (folderId) {
|
||||
object.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
});
|
||||
}
|
||||
const newACL = new Parse.ACL();
|
||||
newACL.setPublicReadAccess(false);
|
||||
newACL.setPublicWriteAccess(false);
|
||||
newACL.setReadAccess(userPtr.objectId, true);
|
||||
newACL.setWriteAccess(userPtr.objectId, true);
|
||||
object.setACL(newACL);
|
||||
const res = await object.save(null, { useMasterKey: true });
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: fileUrl,
|
||||
name: name,
|
||||
note: note || '',
|
||||
description: description || '',
|
||||
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (parseExtUser && parseExtUser.Webhook) {
|
||||
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
|
||||
}
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = parseExtUser.Email;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
parseExtUser.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||
sender +
|
||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: name,
|
||||
sender_name: parseExtUser.Name,
|
||||
sender_mail: parseExtUser.Email,
|
||||
sender_phone: parseExtUser?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
body: email_html,
|
||||
};
|
||||
}
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: extUser.id,
|
||||
};
|
||||
|
||||
await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 200 },
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
if (allowedCredits > 0) {
|
||||
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log('resSubcription ', resSubcription);
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
// }
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers!' });
|
||||
}
|
||||
const updateApiCount =
|
||||
resSub?.get('AllowedApis') && resSub.get('AllowedApis') > 0
|
||||
? resSub.get('AllowedApis') - 1
|
||||
: 0;
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
subscriptionCls.set('AllowedApis', updateApiCount);
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log('resSubcription ', resSubcription);
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
// }
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers!' });
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||
}
|
||||
} else {
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy API credits and try again later.' });
|
||||
return response.status(400).json({ error: 'Please buy subscriptions.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||
|
||||
@@ -68,6 +68,8 @@ import AllowedQuicksend from './parsefunction/AllowedQuicksend.js';
|
||||
import BuyQuickSend from './parsefunction/BuyQuicksend.js';
|
||||
import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
|
||||
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
|
||||
import AllowedCredits from './parsefunction/AllowedCredits.js';
|
||||
import BuyCredits from './parsefunction/BuyCredits.js';
|
||||
|
||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||
@@ -147,3 +149,5 @@ Parse.Cloud.define('allowedapis', AllowedApis);
|
||||
Parse.Cloud.define('allowedquicksend', AllowedQuicksend);
|
||||
Parse.Cloud.define('buyapis', BuyApis);
|
||||
Parse.Cloud.define('buyquicksend', BuyQuickSend);
|
||||
Parse.Cloud.define('allowedcredits', AllowedCredits);
|
||||
Parse.Cloud.define('buycredits', BuyCredits);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
export default async function AllowedCredits(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||
if (resExtUser) {
|
||||
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: _resExtUser.TenantId.objectId,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||
const AllowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const AddonCredits = _resSub?.AddonCredits || 0;
|
||||
return { allowedcredits: AllowedCredits, addoncredits: AddonCredits };
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in allowedCredits', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import axios from 'axios';
|
||||
export default async function BuyCredits(request) {
|
||||
const credits = request.params.credits;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
if (credits) {
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||
if (resExtUser) {
|
||||
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: _resExtUser.TenantId.objectId,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||
// Define the URL
|
||||
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||
|
||||
// Convert the data to x-www-form-urlencoded format
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||
formData.append('grant_type', 'refresh_token');
|
||||
|
||||
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||
|
||||
// Make the POST request using Axios
|
||||
const res = await axios.post(url, formData, { headers });
|
||||
if (res.data.access_token) {
|
||||
const subscriptionId = _resSub.SubscriptionId;
|
||||
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
|
||||
const quantity = parseInt(credits);
|
||||
const addoncode = 'addon-credits';
|
||||
const data = JSON.stringify({
|
||||
plan: { plan_code: plan_code },
|
||||
addons: [
|
||||
{ addon_code: addoncode, addon_description: 'addon credits', quantity: quantity },
|
||||
],
|
||||
});
|
||||
const creditsUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`;
|
||||
const resCredits = await axios.post(creditsUrl, data, {
|
||||
headers: {
|
||||
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||
},
|
||||
});
|
||||
// console.log('resCredits ', resCredits.data);
|
||||
if (resCredits.data) {
|
||||
const existAddonCredits = _resSub?.AddonCredits ? _resSub.AddonCredits : 0;
|
||||
const addonCredits = existAddonCredits + quantity;
|
||||
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||
updateSub.id = resSub.id;
|
||||
updateSub.set('AddonCredits', addonCredits);
|
||||
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
|
||||
// console.log('resupdateSub ', resupdateSub);
|
||||
return { status: 'success', addon: addonCredits };
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error('400', 'Invalid access token.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const msg =
|
||||
err?.response?.data?.error ||
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Something went wrong.';
|
||||
console.log('err in Buyaddonusers', code, msg);
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
|
||||
}
|
||||
}
|
||||
@@ -3,35 +3,28 @@ import { cloudServerUrl } from '../../Utils.js';
|
||||
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
async function deductcount(tenantId, docs, extUserId) {
|
||||
const licenseKey = process.env.LICENSE_KEY;
|
||||
async function deductcount(docsCount, extUserId, subscription) {
|
||||
try {
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
subscription.greaterThan('AllowedQuicksend', 0);
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const updateApiCount =
|
||||
resSub?.get('AllowedQuicksend') && resSub.get('AllowedQuicksend') > 0
|
||||
? resSub.get('AllowedQuicksend') - docs
|
||||
: 0;
|
||||
if (licenseKey) {
|
||||
const allowedCredits = subscription?.AllowedCredits || 0;
|
||||
const addonCredits = subscription?.AddonCredits || 0;
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
if (updateApiCount > 0) {
|
||||
subscriptionCls.set('AllowedQuicksend', updateApiCount);
|
||||
subscriptionCls.id = subscription.objectId;
|
||||
if (docsCount <= allowedCredits) {
|
||||
const updateAllowedcredits = allowedCredits - docsCount;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
subscriptionCls.set('AllowedQuicksend', 0);
|
||||
const remaingCount = docsCount - allowedCredits;
|
||||
const updateAddonCredits = addonCredits - remaingCount;
|
||||
subscriptionCls.set('AllowedCredits', 0);
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
await subscriptionCls.save(null, { useMasterKey: true });
|
||||
}
|
||||
|
||||
const extCls = new Parse.Object('contracts_Users');
|
||||
extCls.id = extUserId;
|
||||
extCls.increment('DocumentCount', docs);
|
||||
extCls.increment('DocumentCount', docsCount);
|
||||
const resExt = await extCls.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('Err in deduct in quick send', err);
|
||||
@@ -210,24 +203,59 @@ export default async function createBatchDocs(request) {
|
||||
};
|
||||
});
|
||||
// console.log('requests ', requests);
|
||||
|
||||
const response = await axios.post('batch', { requests: requests }, parseConfig);
|
||||
// // Handle the batch query response
|
||||
// console.log('Batch query response:', response.data);
|
||||
if (response.data && response.data.length > 0) {
|
||||
const updateDocuments = Documents.map((x, i) => ({
|
||||
...x,
|
||||
objectId: response.data[i]?.success?.objectId,
|
||||
createdAt: response.data[i]?.success?.createdAt,
|
||||
}));
|
||||
deductcount(_resExt.TenantId.objectId, response.data.length, resExt.id);
|
||||
for (let i = 0; i < updateDocuments.length; i++) {
|
||||
sendMail(updateDocuments[i], sessionToken);
|
||||
if (licenseKey) {
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: _resExt.TenantId.objectId,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const addonCredits = _resSub?.AddonCredits || 0;
|
||||
const totalcredits = allowedCredits + addonCredits;
|
||||
if (docsCount <= totalcredits) {
|
||||
const response = await axios.post('batch', { requests: requests }, parseConfig);
|
||||
// // Handle the batch query response
|
||||
// console.log('Batch query response:', response.data);
|
||||
if (response.data && response.data.length > 0) {
|
||||
const updateDocuments = Documents.map((x, i) => ({
|
||||
...x,
|
||||
objectId: response.data[i]?.success?.objectId,
|
||||
createdAt: response.data[i]?.success?.createdAt,
|
||||
}));
|
||||
deductcount(response.data.length, resExt.id, _resSub);
|
||||
for (let i = 0; i < updateDocuments.length; i++) {
|
||||
sendMail(updateDocuments[i], sessionToken);
|
||||
}
|
||||
return 'success';
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
429,
|
||||
'Quota reached, Please buy credits and try again later.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please buy subscriptions.');
|
||||
}
|
||||
} else {
|
||||
const response = await axios.post('batch', { requests: requests[0] }, parseConfig);
|
||||
// // Handle the batch query response
|
||||
// console.log('Batch query response:', response.data);
|
||||
if (response.data && response.data.length > 0) {
|
||||
const updateDocuments = {
|
||||
objectId: response.data[0]?.success?.objectId,
|
||||
createdAt: response.data[0]?.success?.createdAt,
|
||||
};
|
||||
deductcount(response.data.length, resExt.id, _resSub);
|
||||
sendMail(updateDocuments, sessionToken);
|
||||
return 'success';
|
||||
}
|
||||
return 'success';
|
||||
}
|
||||
|
||||
// Handle individual responses within response.data.results
|
||||
} catch (error) {
|
||||
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const msg =
|
||||
@@ -240,7 +268,7 @@ export default async function createBatchDocs(request) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in createbatchdoc', err);
|
||||
|
||||
Reference in New Issue
Block a user