diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index 83eb56de0..026675fbf 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -1,4 +1,6 @@ { + "headernews": "New feature: Public profiles are now live! Easily create and share public templates", + "headernewsbtn": "Setup Now", "create-account": "Create Account", "login": "Login", "language": "Language", @@ -39,7 +41,7 @@ "upgrade-now": "Upgrade now", "upgrade-to": "Upgrade to", "plan": "Plan", - "subscribe-card-plan": "Sign 100 docs using API. Only $0.15/doc after that.", + "subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.", "user-name-limit-char": "To have a username less than 8 character please subscribe", "tour-content": "Don't show this again", "pro": "PRO", @@ -554,7 +556,7 @@ "home-layout-1": "You have logged in successfully! Let's take a look.", "home-layout-2": "To upload documents for self-signing or to request others’ signatures, simply select the respective buttons.", "home-layout-3": "You are ready to start using OpenSign! If you need support feel free to contact us.", - "generate-token": "Upgrade now to generate API token", + "generate-token": "Upgrade now to generate production API token.", "opensign-drive-1": "Click on the breadcrumb links to easily navigate through the folder hierarchy and view the documents within each folder.", "opensign-drive-2": "Click the add button to create a new folder or document.", "opensign-drive-3": "Sort your documents by Date or Name using this menu.", @@ -617,13 +619,19 @@ "remainingapis": "Remaining APIs Credits:", "additional-quicksend": "Please purchase add-on quick send", "quantityofquicksend": "Quantity of Quick send", + "quantityofcredits": "Quantity of premium credits", + "remainingcredits": "Premium credits available:", + "remainingcreditshelp":"Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", + "additional-credits": "Please purchase premium credits", "quotaerrquicksend": "Quota Reached, You don't have enough credits.", - "buycredits": "Buy credits", - "rotate-right": "Rotate right", - "rotate-left": "Rotate left", - "rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?", - "templateid": "Template-Id", - "bulksendsubcriptionalert": "Please upgrade to Professional or Team plan to use quicksend.", + "buycredits": "Buy Premium Credits", + "rotate-right":"Rotate right", + "rotate-left":"Rotate left", + "rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?", + "templateid":"Template-Id", + "bulksendsubcriptionalert":"Please upgrade to Professional or Team plan to use bulk send.", "generate-test-token":"Generate Test Token", - "regenerate-test-token":"Regenerate Test Token" + "regenerate-test-token":"Regenerate Test Token", + "help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.", + "help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans." } diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index 376a16011..1d2af552f 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -1,4 +1,6 @@ { + "headernews": "Nouvelle fonctionnalité : les profils publics sont désormais en ligne ! Créez et partagez facilement des modèles publics", + "headernewsbtn": "Configurer maintenant", "create-account": "Créer un compte", "login": "Se Connecter", "language": "Langue", @@ -40,7 +42,7 @@ "upgrade-to": "Mettre à niveau vers", "pro": "PRO", "plan": "Offre", - "subscribe-card-plan": "Signez 100 documents à l'aide de l'API. Seulement 0,15 $/doc par la suite.", + "subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.", "user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner", "tour-content": "Ne plus afficher", "team": "Équipe", @@ -553,7 +555,7 @@ "home-layout-1": "Vous vous êtes connecté avec succès ! Jetons un coup d'oeil.", "home-layout-2": "Pour télécharger des documents à auto-signature ou pour demander la signature d'autres personnes, sélectionnez simplement les boutons correspondants.", "home-layout-3": "Vous êtes prêt à commencer à utiliser OpenSign ! Si vous avez besoin d'aide, n'hésitez pas à nous contacter.", - "generate-token": "Mettez à niveau maintenant pour générer un jeton API", + "generate-token": "Effectuez la mise à niveau maintenant pour générer un jeton API de production.", "opensign-drive-1": "Cliquez sur les liens du fil d'Ariane pour naviguer facilement dans la hiérarchie des dossiers et afficher les documents dans chaque dossier.", "opensign-drive-2": "Cliquez sur le bouton Ajouter pour créer un nouveau dossier ou document.", "opensign-drive-3": "Triez vos documents par date ou par nom à l'aide de ce menu.", @@ -615,14 +617,20 @@ "additionalapis": "Veuillez acheter des API complémentaires", "remainingapis": "API restantes Crédits:", "additional-quicksend": "Veuillez acheter le module complémentaire quick send", + "quantityofcredits":"Quantité de crédits de prime", + "remainingcredits":"Crédits premium disponibles :", + "additional-credits":"Veuillez acheter des crédits premium", + "remainingcreditshelp":"Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", "quantityofquicksend": "Quantité de Quick send", "quotaerrquicksend": "Quota atteint, vous n'avez pas assez de crédits.", - "buycredits": "Acheter des crédits", - "rotate-right": "Faire pivoter à droite", - "rotate-left": "Faire pivoter à gauche", - "rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", - "templateid": "ID de modèle", - "bulksendsubcriptionalert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", - "generate-test-token": "Générer jeton de test", - "regenerate-test-token":"Régénérer le jeton de test" + "buycredits": "Acheter des crédits premium", + "rotate-right" :"Faire pivoter à droite", + "rotate-left" :"Faire pivoter à gauche", + "rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", + "templateid":"ID de modèle", + "bulksendsubcriptionalert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", + "generate-test-token": "Générer jeton de test", + "regenerate-test-token":"Régénérer le jeton de test", + "help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.", + "help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants." } diff --git a/apps/OpenSign/src/components/BulkSendUi.js b/apps/OpenSign/src/components/BulkSendUi.js index 5a6e218fb..b46584235 100644 --- a/apps/OpenSign/src/components/BulkSendUi.js +++ b/apps/OpenSign/src/components/BulkSendUi.js @@ -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) => { ))}
- + {isEnableSubscription && ( + + )} @@ -412,14 +419,14 @@ const BulkSendUi = (props) => { ) : (

- {t("additional-quicksend")} + {t("additional-credits")}

{ - const route = paidUrl(plan); - if (route === "/subscription") { - window.location.href = route; - } else { - openInNewTab(route, "_self"); - } + const handleNavigation = () => { + window.location.href = "/subscription"; }; async function checkIsSubscribed(extUserId, contactId) { const isGuestSign = isGuestSignFlow || false; diff --git a/apps/OpenSign/src/pages/PlaceHolderSign.js b/apps/OpenSign/src/pages/PlaceHolderSign.js index 8e6a4bebb..7b28d007a 100644 --- a/apps/OpenSign/src/pages/PlaceHolderSign.js +++ b/apps/OpenSign/src/pages/PlaceHolderSign.js @@ -35,7 +35,6 @@ import { fetchSubscription, convertPdfArrayBuffer, getContainerScale, - openInNewTab, convertBase64ToFile, onClickZoomIn, onClickZoomOut, @@ -60,7 +59,6 @@ import Loader from "../primitives/Loader"; import { useSelector } from "react-redux"; import PdfZoom from "../components/pdf/PdfZoom"; import LottieWithLoader from "../primitives/DotLottieReact"; -import { paidUrl } from "../json/plansArr"; import { useTranslation } from "react-i18next"; import RotateAlert from "../components/RotateAlert"; @@ -235,13 +233,8 @@ function PlaceHolderSign() { return () => clearTimeout(timer); // eslint-disable-next-line react-hooks/exhaustive-deps }, [divRef.current, isHeader]); - const handleNavigation = (plan) => { - const route = paidUrl(plan); - if (route === "/subscription") { - navigate(route); - } else { - openInNewTab(route, "_self"); - } + const handleNavigation = () => { + navigate("/subscription"); }; async function checkIsSubscribed() { const res = await fetchSubscription(); diff --git a/apps/OpenSign/src/pages/SSOVerify.js b/apps/OpenSign/src/pages/SSOVerify.js index 80a75f116..d695e07b1 100644 --- a/apps/OpenSign/src/pages/SSOVerify.js +++ b/apps/OpenSign/src/pages/SSOVerify.js @@ -3,12 +3,11 @@ import { useLocation, useNavigate } from "react-router-dom"; import Parse from "parse"; import { appInfo } from "../constant/appinfo"; import { isEnableSubscription } from "../constant/const"; -import { fetchSubscription, openInNewTab } from "../constant/Utils"; +import { fetchSubscription } from "../constant/Utils"; import { useDispatch } from "react-redux"; import { showTenant } from "../redux/reducers/ShowTenant"; import ModalUi from "../primitives/ModalUi"; import Loader from "../primitives/Loader"; -import { paidUrl } from "../json/plansArr"; import { useTranslation } from "react-i18next"; const SSOVerify = () => { @@ -51,13 +50,8 @@ const SSOVerify = () => { console.log("err", err.message); } }; - const handlePaidRoute = (plan) => { - const route = paidUrl(plan); - if (route === "/subscription") { - navigate(route); - } else { - openInNewTab(route, "_self"); - } + const handlePaidRoute = () => { + navigate("/subscription"); }; const checkExtUser = async (ssosign) => { const params = { email: ssosign?.email }; diff --git a/apps/OpenSign/src/pages/TemplatePlaceholder.js b/apps/OpenSign/src/pages/TemplatePlaceholder.js index cc37bf17c..92a438379 100644 --- a/apps/OpenSign/src/pages/TemplatePlaceholder.js +++ b/apps/OpenSign/src/pages/TemplatePlaceholder.js @@ -26,7 +26,6 @@ import { radioButtonWidget, fetchSubscription, getContainerScale, - openInNewTab, convertBase64ToFile, rotatePdfPage, onClickZoomOut, @@ -47,7 +46,6 @@ import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption"; import Parse from "parse"; import { useSelector } from "react-redux"; import PdfZoom from "../components/pdf/PdfZoom"; -import { paidUrl } from "../json/plansArr"; import { useTranslation } from "react-i18next"; import RotateAlert from "../components/RotateAlert"; const TemplatePlaceholder = () => { @@ -196,13 +194,8 @@ const TemplatePlaceholder = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [divRef.current, isHeader]); - const handleNavigation = (plan) => { - const route = paidUrl(plan); - if (route === "/subscription") { - navigate(route); - } else { - openInNewTab(route, "_self"); - } + const handleNavigation = () => { + navigate("/subscription"); }; async function checkIsSubscribed() { const res = await fetchSubscription(); diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index 1158137a9..541a45418 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -17,7 +17,7 @@ import { import Upgrade from "../primitives/Upgrade"; import ModalUi from "../primitives/ModalUi"; import Loader from "../primitives/Loader"; -import { paidUrl, validplan } from "../json/plansArr"; +import { validplan } from "../json/plansArr"; import { useTranslation } from "react-i18next"; import SelectLanguage from "../components/pdf/SelectLanguage"; import { RWebShare } from "react-web-share"; @@ -336,12 +336,7 @@ function UserProfile() { setIsDisableDocId(extendUser?.[0]?.HeaderDocId); }; const handlePaidRoute = () => { - const route = paidUrl(isPlan.plan); - if (route === "/subscription") { - navigate(route); - } else { - openInNewTab(route, "_self"); - } + navigate("/subscription"); }; const copytoclipboard = () => { diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index 674be0372..f0542233b 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -1456,7 +1456,13 @@ const ReportTable = (props) => { {act.btnLabel && ( - {t(`btnLabel.${act.btnLabel}`)} + {act.btnLabel.includes( + "Quick send" + ) && isEnableSubscription + ? "Bulk Send" + : `${t( + `btnLabel.${act.btnLabel}` + )}`} )} {isOption[item.objectId] && @@ -1783,7 +1789,11 @@ const ReportTable = (props) => { {isBulkSend[item.objectId] && ( setIsBulkSend({})} > {isLoader[item.objectId] ? ( diff --git a/apps/OpenSign/src/primitives/SubscribeCard.js b/apps/OpenSign/src/primitives/SubscribeCard.js index 3abf97fac..69977fefe 100644 --- a/apps/OpenSign/src/primitives/SubscribeCard.js +++ b/apps/OpenSign/src/primitives/SubscribeCard.js @@ -1,29 +1,22 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; -import { paidUrl } from "../json/plansArr"; -import { openInNewTab } from "../constant/Utils"; -const SubscribeCard = ({ plan, price, plan_code }) => { +const SubscribeCard = ({ plan, price }) => { const { t } = useTranslation(); const navigate = useNavigate(); const handlePaidRoute = () => { - const route = paidUrl(plan_code); - if (route === "/subscription") { - navigate(route); - } else { - openInNewTab(route, "_self"); - } + navigate("/subscription"); }; + const premiumPrice = price ? "$" + price : "$9.99"; + const addonPrice = "$0.15"; return (

- {t("upgrade-to")} {plan ? plan : "PRO"} {t("plan")} + {t("upgrade-to")} {plan ? plan : "Paid"} {t("plan")}

-

- ${price ? price : "29.99"}/month: {t("subscribe-card-plan")} -

+

{t("subscribe-card-plan", { premiumPrice, addonPrice })}

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™ here.

'; - - 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 = + "

Digital Signature Request

" + + template.ExtUserPtr.Name + + ' has requested you to review and sign ' + + template.Name + + ".

Sender " + + sender + + "
Organization " + + orgName + + "
Expires on " + + localExpireDate + + "

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™ here.

'; + + 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!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index ffa310bfd..a4cc211a3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -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 = - "

Digital Signature Request

" + - parseExtUser.Name + - ' has requested you to review and sign ' + - name + - ".

Sender " + - sender + - "
Organization " + - orgName + - "
Expires on " + - localExpireDate + - "

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™ here.

'; - 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 = + "

Digital Signature Request

" + + parseExtUser.Name + + ' has requested you to review and sign ' + + name + + ".

Sender " + + sender + + "
Organization " + + orgName + + "
Expires on " + + localExpireDate + + "

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™ here.

'; + 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!' }); diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index fc4f61817..b8cd1d7e4 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -6,7 +6,6 @@ import usersignup from './parsefunction/usersignup.js'; import FacebookSign from './parsefunction/FacebookSign.js'; import DocumentAftersave from './parsefunction/DocumentAftersave.js'; import ContactbookAftersave from './parsefunction/ContactBookAftersave.js'; -// import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js'; import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js'; import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js'; import getUserId from './parsefunction/getUserId.js'; @@ -62,12 +61,10 @@ import getOrgAdmins from './parsefunction/getOrgAdmins.js'; import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js'; import AllowedUsers from './parsefunction/AlllowedUsers.js'; import BuyAddonUsers from './parsefunction/BuyAddonUsers.js'; -import AllowedApis from './parsefunction/AllowedApis.js'; -import BuyApis from './parsefunction/BuyApis.js'; -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); @@ -143,7 +140,5 @@ Parse.Cloud.define('getorgadmins', getOrgAdmins); Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg); Parse.Cloud.define('allowedusers', AllowedUsers); Parse.Cloud.define('buyaddonusers', BuyAddonUsers); -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); diff --git a/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js b/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js index 740a0cc07..e24cdcd3c 100644 --- a/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js +++ b/apps/OpenSignServer/cloud/parsefunction/AddAdmin.js @@ -189,34 +189,3 @@ export default async function AddAdmin(request) { console.log('Err ', err); } } - -// async function saveSubscription(extUserId, UserId, tenantId, subscription) { -// const SubscriptionId = subscription?.data?.subscription?.subscription_id || ''; -// const Next_billing_date = subscription?.data?.subscription?.next_billing_at || ''; -// const planCode = subscription?.data?.subscription?.plan?.plan_code || ''; -// try { -// const createSubscription = new Parse.Object('contracts_Subscriptions'); -// createSubscription.set('SubscriptionId', SubscriptionId); -// createSubscription.set('SubscriptionDetails', subscription); -// createSubscription.set('ExtUserPtr', { -// __type: 'Pointer', -// className: 'contracts_Users', -// objectId: extUserId, -// }); -// createSubscription.set('CreatedBy', { -// __type: 'Pointer', -// className: '_User', -// objectId: UserId, -// }); -// createSubscription.set('TenantId', { -// __type: 'Pointer', -// className: 'partners_Tenant', -// objectId: tenantId, -// }); -// createSubscription.set('Next_billing_date', new Date(Next_billing_date)); -// createSubscription.set('PlanCode', planCode); -// await createSubscription.save(null, { useMasterKey: true }); -// } catch (err) { -// console.log('err in save subscription pgsignup', err); -// } -// } diff --git a/apps/OpenSignServer/cloud/parsefunction/AllowedApis.js b/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js similarity index 79% rename from apps/OpenSignServer/cloud/parsefunction/AllowedApis.js rename to apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js index debecc649..04b0eb79e 100644 --- a/apps/OpenSignServer/cloud/parsefunction/AllowedApis.js +++ b/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js @@ -1,4 +1,4 @@ -export default async function AllowedApis(request) { +export default async function AllowedCredits(request) { if (!request?.user) { throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); } @@ -22,14 +22,15 @@ export default async function AllowedApis(request) { const resSub = await subscription.first({ useMasterKey: true }); if (resSub) { const _resSub = JSON.parse(JSON.stringify(resSub)); - const allowedapis = _resSub?.AllowedApis || 0; - return allowedapis; + 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 allowedapis', 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); diff --git a/apps/OpenSignServer/cloud/parsefunction/AllowedQuicksend.js b/apps/OpenSignServer/cloud/parsefunction/AllowedQuicksend.js deleted file mode 100644 index ab69c55c2..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/AllowedQuicksend.js +++ /dev/null @@ -1,37 +0,0 @@ -export default async function AllowedQuicksend(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 allowedquicksend = _resSub?.AllowedQuicksend || 0; - return allowedquicksend; - } - } else { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.'); - } - } catch (err) { - console.log('err in allowedapis', err); - const code = err?.code || 400; - const msg = err?.message || 'Something went wrong.'; - throw new Parse.Error(code, msg); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/BuyApis.js b/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js similarity index 78% rename from apps/OpenSignServer/cloud/parsefunction/BuyApis.js rename to apps/OpenSignServer/cloud/parsefunction/BuyCredits.js index 8cc53d8d2..0e0e99827 100644 --- a/apps/OpenSignServer/cloud/parsefunction/BuyApis.js +++ b/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js @@ -1,10 +1,10 @@ import axios from 'axios'; -export default async function BuyApis(request) { - const apis = request.params.apis; +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 (apis) { + if (credits) { try { const extUser = new Parse.Query('contracts_Users'); extUser.equalTo('UserId', { @@ -37,36 +37,37 @@ export default async function BuyApis(request) { 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(apis); - const addoncode = 'api-signatures'; + const quantity = parseInt(credits); + const addoncode = 'addon-credits'; const data = JSON.stringify({ plan: { plan_code: plan_code }, addons: [ - { addon_code: addoncode, addon_description: 'API Signatures', quantity: quantity }, + { addon_code: addoncode, addon_description: 'addon credits', quantity: quantity }, ], }); - const apiUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`; - const resAPis = await axios.post(apiUrl, data, { + 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('resAPis ', resAPis.data); - if (resAPis.data) { - const existAllowedApis = _resSub?.AllowedApis ? _resSub.AllowedApis : 0; - const allowedapis = existAllowedApis + quantity; + // 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('AllowedApis', allowedapis); + updateSub.set('AddonCredits', addonCredits); const resupdateSub = await updateSub.save(null, { useMasterKey: true }); // console.log('resupdateSub ', resupdateSub); - return { status: 'success', addon: allowedapis }; + return { status: 'success', addon: addonCredits }; } } else { throw new Parse.Error('400', 'Invalid access token.'); diff --git a/apps/OpenSignServer/cloud/parsefunction/BuyQuicksend.js b/apps/OpenSignServer/cloud/parsefunction/BuyQuicksend.js deleted file mode 100644 index 7abcc4dde..000000000 --- a/apps/OpenSignServer/cloud/parsefunction/BuyQuicksend.js +++ /dev/null @@ -1,89 +0,0 @@ -import axios from 'axios'; -export default async function BuyQuickSend(request) { - const apis = request.params.quicksend; - if (!request?.user) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); - } - if (apis) { - 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(apis); - const addoncode = 'bulk-signatures'; - const data = JSON.stringify({ - plan: { plan_code: plan_code }, - addons: [ - { addon_code: addoncode, addon_description: 'Bulk Signatures', quantity: quantity }, - ], - }); - const apiUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`; - const resAPis = await axios.post(apiUrl, data, { - headers: { - Authorization: 'Zoho-oauthtoken ' + res.data.access_token, - 'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID, - }, - }); - if (resAPis.data) { - const existQuickSend = _resSub?.AllowedQuicksend ? _resSub.AllowedQuicksend : 0; - const allowedQuicksend = existQuickSend + quantity; - const updateSub = new Parse.Object('contracts_Subscriptions'); - updateSub.id = resSub.id; - updateSub.set('AllowedQuicksend', allowedQuicksend); - const resupdateSub = await updateSub.save(null, { useMasterKey: true }); - return { status: 'success', addon: allowedQuicksend }; - } - } 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 buyaddon', code, msg); - throw new Parse.Error(code, msg); - } - } else { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.'); - } -} diff --git a/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js b/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js index 11bab60f9..49bad4060 100644 --- a/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js +++ b/apps/OpenSignServer/cloud/parsefunction/SubscribeFree.js @@ -21,6 +21,8 @@ export default async function SubscribeFree(request) { const updateSubscription = new Parse.Object('contracts_Subscriptions'); updateSubscription.id = subcripitions.id; updateSubscription.set('PlanCode', 'freeplan'); + updateSubscription.set('AllowedCredits', 0); + updateSubscription.set('PlanCredits', 0); await updateSubscription.save(null, { useMasterKey: true }); return { status: 'success', result: 'subscribed!' }; } catch (err) { @@ -34,6 +36,8 @@ export default async function SubscribeFree(request) { const updateSubscription = new Parse.Object('contracts_Subscriptions'); updateSubscription.id = subcripitions.id; updateSubscription.set('PlanCode', 'freeplan'); + updateSubscription.set('AllowedCredits', 0); + updateSubscription.set('PlanCredits', 0); await updateSubscription.save(null, { useMasterKey: true }); return { status: 'success', result: 'subscribed!' }; } catch (err) { @@ -61,6 +65,8 @@ export default async function SubscribeFree(request) { objectId: extUser.get('TenantId').id, }); } + createSubscription.set('AllowedCredits', 0); + createSubscription.set('PlanCredits', 0); await createSubscription.save(null, { useMasterKey: true }); return { status: 'success', result: 'subscribed!' }; } catch (err) { diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js index 35e602cc3..f6ba12a4f 100644 --- a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js +++ b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js @@ -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,37 +203,72 @@ 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 (requests?.length <= 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 code = error?.response?.data?.code || error?.response?.status || error?.code || 400; const msg = - err?.response?.data?.error || - err?.response?.data || - err?.message || + error?.response?.data?.error || + error?.response?.data || + error?.message || 'Something went wrong.'; console.log('Error performing batch query:', code, msg); throw new Parse.Error(code, msg); } } } 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); diff --git a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js b/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js index 12fbbdcdd..2eef1d220 100644 --- a/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js +++ b/apps/OpenSignServer/cloud/parsefunction/saveSubscription.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; +import { cloudServerUrl, planCredits } from '../../Utils.js'; export default async function saveSubscription(request) { const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const appId = process.env.APP_ID; @@ -8,6 +8,7 @@ export default async function saveSubscription(request) { const body = subscription; const Next_billing_date = subscription.data.subscription.next_billing_at; const planCode = subscription.data.subscription.plan.plan_code; + const credits = planCredits?.[planCode] || 0; let existAddon = 0; try { const userRes = await axios.get(serverUrl + '/users/me', { @@ -69,6 +70,24 @@ export default async function saveSubscription(request) { if (existAddon > 0) { updateSubscription.set('AllowedUsers', parseInt(existAddon)); } + const isSameAsPrevPlan = subscription?.get('PlanCode') === planCode; + if (isSameAsPrevPlan) { + const planCredits = subscription?.get('PlanCredits'); + if (planCredits) { + updateSubscription.set('AllowedCredits', planCredits); + } else { + if (credits > 0) { + updateSubscription.set('AllowedCredits', credits); + updateSubscription.set('PlanCredits', credits); + } + } + } else { + if (credits > 0) { + updateSubscription.set('AllowedCredits', credits); + updateSubscription.set('PlanCredits', credits); + } + } + await updateSubscription.save(null, { useMasterKey: true }); return { status: 'update subscription!' }; } else { @@ -95,6 +114,10 @@ export default async function saveSubscription(request) { if (existAddon > 0) { createSubscription.set('AllowedUsers', parseInt(existAddon)); } + if (credits > 0) { + createSubscription.set('AllowedCredits', credits); + createSubscription.set('PlanCredits', credits); + } await createSubscription.save(null, { useMasterKey: true }); return { status: 'create subscription!' }; } diff --git a/apps/OpenSignServer/cloud/parsefunction/usersignup.js b/apps/OpenSignServer/cloud/parsefunction/usersignup.js index 35057ba83..44f9665b4 100644 --- a/apps/OpenSignServer/cloud/parsefunction/usersignup.js +++ b/apps/OpenSignServer/cloud/parsefunction/usersignup.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { cloudServerUrl } from '../../Utils.js'; +import { cloudServerUrl, planCredits } from '../../Utils.js'; const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const APPID = process.env.APP_ID; const masterKEY = process.env.MASTER_KEY; @@ -135,6 +135,8 @@ async function saveSubscription(extUserId, UserId, tenantId, subscription) { const SubscriptionId = subscription?.data?.subscription?.subscription_id || ''; const Next_billing_date = subscription?.data?.subscription?.next_billing_at || ''; const planCode = subscription?.data?.subscription?.plan?.plan_code || ''; + const credits = planCredits?.[planCode] || 0; + try { const createSubscription = new Parse.Object('contracts_Subscriptions'); createSubscription.set('SubscriptionId', SubscriptionId); @@ -156,6 +158,10 @@ async function saveSubscription(extUserId, UserId, tenantId, subscription) { }); createSubscription.set('Next_billing_date', new Date(Next_billing_date)); createSubscription.set('PlanCode', planCode); + if (credits > 0) { + createSubscription.set('AllowedCredits', credits); + createSubscription.set('PlanCredits', credits); + } await createSubscription.save(null, { useMasterKey: true }); } catch (err) { console.log('err in save subscription pgsignup', err);