import axios from 'axios'; // `replaceMailVaribles` is used to replace variables from mail with there actual values function replaceMailVaribles(subject, body, variables) { let replacedSubject = subject; let replacedBody = body; for (const variable in variables) { const regex = new RegExp(`{{${variable}}}`, 'g'); if (subject) { replacedSubject = replacedSubject.replace(regex, variables[variable]); } if (body) { replacedBody = replacedBody.replace(regex, variables[variable]); } } const result = { subject: replacedSubject, body: replacedBody, }; return result; } // `sendmail` is used to signing reminder mail to signer async function sendMail(doc, signer) { const subject = `{{sender_name}} has requested you to sign "{{document_title}}"`; const body = `

Hi {{receiver_name}},


We hope this email finds you well. {{sender_name}} has requested you to review and sign "{{document_title}}".

Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.


{{signing_url}}


If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.


Thanks

Team OpenSign™


`; const url = `${process.env.SERVER_URL}/functions/sendmailv3`; const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': process.env.APP_ID, }; const baseUrl = new URL(process.env.PUBLIC_URL); const encodeBase64 = btoa(`${doc.objectId}/${signer.Email}/${signer.objectId}`); const expireDate = doc?.ExpiryDate?.iso; const newDate = new Date(expireDate); const localExpireDate = newDate.toLocaleDateString('en-US', { day: 'numeric', month: 'long', year: 'numeric', }); const signPdf = `${baseUrl.origin}/login/${encodeBase64}`; const variables = { document_title: doc.Name, sender_name: doc.ExtUserPtr.Name, sender_mail: doc.ExtUserPtr.Email, sender_phone: doc.ExtUserPtr?.Phone || '', receiver_name: signer.Name, receiver_email: signer.Email, receiver_phone: signer?.Phone || '', expiry_date: localExpireDate, company_name: doc?.ExtUserPtr?.Company || '', signing_url: `Sign here`, }; const mail = replaceMailVaribles(subject, body, variables); let params = { mailProvider: doc?.ExtUserPtr?.active_mail_adapter, extUserId: doc?.ExtUserPtr?.objectId, recipient: signer.Email, subject: mail.subject, from: doc?.ExtUserPtr?.Email, html: mail.body, }; try { // The axios request is used to send a signing reminder email. const res = await axios.post(url, params, { headers: headers }); // console.log('res ', res.data.result); if (res.data.result.status === 'success') { return { status: 'success' }; } } catch (err) { console.log('err in mail of sendreminder api', err); return { status: 'error' }; } } export default async function autoReminder(request, response) { // The query below is used to find documents where the reminder date is less than or equal to the current date, and which have existing signers and a signed URL. try { const docQuery = new Parse.Query('contracts_Document'); docQuery.limit(2000); docQuery.lessThanOrEqualTo('NextReminderDate', new Date()); docQuery.equalTo('AutomaticReminders', true); docQuery.exists('NextReminderDate'); docQuery.exists('Signers'); docQuery.exists('SignedUrl'); docQuery.descending('createdAt'); docQuery.include('Signers,AuditTrail.UserPtr,ExtUserPtr'); docQuery.notEqualTo('IsCompleted', true); docQuery.notEqualTo('IsDeclined', true); docQuery.notEqualTo('IsArchive', true); docQuery.greaterThanOrEqualTo('ExpiryDate', new Date()); const docsArr = await docQuery.find({ useMasterKey: true }); if (docsArr && docsArr.length > 0) { const _docsArr = JSON.parse(JSON.stringify(docsArr)); let mailCount = 0; let docCount = 0; for (const doc of _docsArr) { // The reminderDate variable is used to calculate the next reminder date. const RemindOnceInEvery = doc?.RemindOnceInEvery || 5; const ReminderDate = new Date(); ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery); // The sendInOrder variable is used to determine whether to send emails in order or not. const SendInOrder = doc?.SendinOrder || false; if (SendInOrder) { // The auditTrail variable is used to get the count of how many users have already signed the document. const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed'); const count = auditTrail?.length || 0; const signer = doc?.Signers?.[count]; if (signer) { docCount += 1; const mailRes = await sendMail(doc, signer); if (mailRes && mailRes.status === 'success') { mailCount += 1; } try { // The code below is used to update the next reminder date of the document based on the "remind once every X days" setting. const updateDoc = new Parse.Object('contracts_Document'); updateDoc.id = doc.objectId; updateDoc.set('NextReminderDate', ReminderDate); const updateRes = await updateDoc.save(null, { useMasterKey: true }); // console.log('updateRes ', updateRes); } catch (err) { console.log('err in update document', err); } } } else { // The AuditTrail variable is used to check if there is any user who has already signed the document. const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed'); if (auditTrail?.length > 0) { // The signers variable is used to get the signers who haven't signed the document. const signers = doc?.Signers.filter(signer => { const signedUser = auditTrail?.find(y => y.UserPtr.objectId === signer.objectId); if (!signedUser) { return signer; } }); if (signers?.length > 0) { docCount += 1; // The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet. for (const signer of signers) { const mailRes = await sendMail(doc, signer); if (mailRes && mailRes.status === 'success') { mailCount += 1; } } } } else { // The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet. const signers = doc?.Signers; if (signers?.length > 0) { docCount += 1; for (const signer of signers) { const mailRes = await sendMail(doc, signer); if (mailRes && mailRes.status === 'success') { mailCount += 1; } } } } // The code below is used to update the next reminder date of the document based on the "remind once every X days" setting. try { const updateDoc = new Parse.Object('contracts_Document'); updateDoc.id = doc.objectId; updateDoc.set('NextReminderDate', ReminderDate); const updateRes = await updateDoc.save(null, { useMasterKey: true }); // console.log('updateRes ', updateRes); } catch (err) { console.log('err in sendmail', err); } } } if (docCount > 0) { response.json({ status: 'success', document_count: docCount, mail_count: mailCount }); } else { response.json({ status: 'no record found' }); } } else { response.json({ status: 'no record found' }); } } catch (err) { console.log('err ', err); const code = err?.code || 400; const message = err?.message || 'Somehting went wrong!'; response.status(code).json({ error: message }); } }