Merge pull request #1141 from OpenSignLabs/validation

This commit is contained in:
Amol
2024-09-01 18:45:59 +05:30
committed by GitHub
27 changed files with 42694 additions and 2086 deletions
@@ -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",
@@ -38,7 +40,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",
@@ -607,19 +609,17 @@
"user-name-exist": "user name already exist",
"format": "format",
"select-date-format": "Select a date format",
"buyapiaddon":"Buy APIs Credits",
"quantityofapis" :"Quantity of APIs",
"additionalapis":"Please purchase add-on APIs",
"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",
"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 quicksend.",
"bulksendsubcriptionalert":"Please upgrade to Professional or Team plan to use bulk send.",
"generate-test-token":"Generate 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 youve completed your testing, you can upgrade to one of our paid plans to generate a production token.",
@@ -1,5 +1,7 @@
{
"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",
@@ -607,14 +609,13 @@
"Add-seats": "Ajouter des sièges",
"format": "format",
"select-date-format": "Sélectionnez un format de date",
"buyapiaddon":"Acheter des API Crédits",
"quantityofapis":"Quantité d'API",
"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",
"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 ?",
@@ -624,5 +625,4 @@
"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 à lun 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."
}
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -378,7 +378,7 @@ const BulkSendUi = (props) => {
</p>
<button
onClick={() => setIsBulkAvailable(false)}
className=" op-btn op-btn-primary w-28"
className=" op-btn op-btn-primary w-[200px]"
>
{t("buycredits")}
</button>
@@ -419,14 +419,14 @@ const BulkSendUi = (props) => {
) : (
<form onSubmit={handleAddOnQuickSubmit} className="p-3">
<p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium">
{t("additional-quicksend")}
{t("additional-credits")}
</p>
<div className="mb-3 flex justify-between">
<label
htmlFor="quantity"
className="block text-xs text-gray-700 font-semibold"
>
{t("quantityofquicksend")}
{t("quantityofcredits")}
<span className="text-[red] text-[13px]">*</span>
</label>
<select
+4 -11
View File
@@ -11,7 +11,7 @@ import {
saveLanguageInLocal
} from "../constant/Utils";
import { isEnableSubscription, isStaging } from "../constant/const";
import { paidUrl, validplan } from "../json/plansArr";
import { validplan } from "../json/plansArr";
import { useTranslation } from "react-i18next";
const Header = ({ showSidebar }) => {
@@ -101,25 +101,18 @@ const Header = ({ showSidebar }) => {
}
};
const handleNavigation = () => {
const route = paidUrl(isTeam.plan);
if (route === "/subscription") {
navigate(route);
} else {
openInNewTab(route, "_self");
}
navigate("/subscription");
};
return (
<div>
{isEnableSubscription && (
<div className="shadow py-1 text-center bg-[#CAE4FA] text-[14px] p-1">
New Feature: Public Profiles are now live! Create and share public
templates with ease
{t("headernews")}
<span
className="cursor-pointer font-medium underline text-blue-800"
onClick={() => navigate("/profile")}
>
{" "}
Setup Now.
{" " + t("headernewsbtn") + "."}
</span>
</div>
)}
+8 -10
View File
@@ -27,7 +27,6 @@ const plans = [
"Decline document support",
"Email notifications",
"Recipient authentication using OTP",
"Bulk send (upto 5 docs)",
"Public profiles",
"And much more"
],
@@ -46,7 +45,6 @@ const plans = [
"Decline document support",
"Email notifications",
"Recipient authentication using OTP",
"Bulk send (upto 5 docs)",
"Public profiles",
"And much more"
]
@@ -77,10 +75,10 @@ const plans = [
"Webhooks",
"Zapier integration",
"API Access",
"100 API signatures included",
"upto 100 API signatures",
"Custom email templates",
"Auto reminders",
"Bulk send (upto 20 docs)",
"Bulk send (upto 100 docs)",
"Premium Public profile usernames",
"Embedding (coming soon)"
],
@@ -92,10 +90,10 @@ const plans = [
"Webhooks",
"Zapier integration",
"API Access",
"240 API signatures included",
"upto 240 API signatures",
"Custom email templates",
"Auto reminders",
"Bulk send (upto 20 docs)",
"Bulk send (upto 240 docs)",
"Premium Public profile usernames",
"Embedding (coming soon)"
]
@@ -118,23 +116,23 @@ const plans = [
target: "_self",
benefits: [
"Everything in OpenSign™ professional",
"100 API signatures included",
"upto 100 API signatures",
"Teams and Organizations",
"Share Templates with teams",
"Share Templates with individuals",
"DocumentId removal from signed docs",
"Bulk send (upto 50 docs)",
"Bulk send (upto 100 docs)",
"Request Payments (coming soon)",
"Mobile app (coming soon)"
],
yearlyBenefits: [
"Everything in OpenSign™ professional",
"500 API signatures included",
"upto 500 API signatures",
"Teams and Organizations",
"Share Templates with teams",
"Share Templates with individuals",
"DocumentId removal from signed docs",
"Bulk send (upto 50 docs)",
"Bulk send (upto 500 docs)",
"Request Payments (coming soon)",
"Mobile app (coming soon)"
]
+3 -9
View File
@@ -11,10 +11,9 @@ import ModalUi from "../primitives/ModalUi";
import { useNavigate, useLocation, Outlet } from "react-router-dom";
import { isEnableSubscription } from "../constant/const";
import { useCookies } from "react-cookie";
import { fetchSubscription, openInNewTab } from "../constant/Utils";
import { fetchSubscription } from "../constant/Utils";
import Loader from "../primitives/Loader";
import { showHeader } from "../redux/reducers/showHeader";
import { paidUrl } from "../json/plansArr";
import { useTranslation } from "react-i18next";
const HomeLayout = () => {
@@ -96,13 +95,8 @@ const HomeLayout = () => {
domain: updateDomain
});
};
const handleNavigation = (plan) => {
const route = paidUrl(plan);
if (route === "/subscription") {
navigate(route);
} else {
openInNewTab(route, "_self");
}
const handleNavigation = () => {
navigate("/subscription");
};
async function checkIsSubscribed() {
if (isEnableSubscription) {
+32 -18
View File
@@ -31,6 +31,7 @@ function GenerateToken() {
priceperapi: 0.15,
allowedcredits: 0,
addoncredits: 0,
totalcredits: 0,
price: (75.0).toFixed(2)
});
const [isFormLoader, setIsFormLoader] = useState(false);
@@ -61,10 +62,14 @@ function GenerateToken() {
const res = await axios.post(url, {}, { headers: headers });
if (res) {
const resCredits = await Parse.Cloud.run("allowedcredits");
const allowedcredits = resCredits?.allowedcredits || 0;
const addoncredits = resCredits?.addoncredits || 0;
const totalcredits = allowedcredits + addoncredits;
setAmount((obj) => ({
...obj,
allowedcredits: resCredits.allowedcredits,
addoncredits: resCredits.addoncredits
allowedcredits: allowedcredits,
addoncredits: addoncredits,
totalcredits: totalcredits
}));
SetApiToken(res?.data?.result?.result);
}
@@ -162,7 +167,8 @@ function GenerateToken() {
quantity: 500,
priceperapi: 0.15,
price: (75.0).toFixed(2),
addoncredits: _resAddon.addon
totalcredits: obj?.totalcredits + _resAddon.addon,
addoncredits: obj?.addoncredits + _resAddon.addon
}));
}
}
@@ -229,7 +235,7 @@ function GenerateToken() {
/>
</h1>
<ul className="w-full flex flex-col p-2 text-sm">
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
<li className="flex flex-col md:flex-row justify-between items-center border-t-[1px] border-gray-300 break-all py-2">
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5">
<span className="ml-1">
<span className="font-medium">API Test Token : </span>
@@ -254,7 +260,7 @@ function GenerateToken() {
</div>
<button
onClick={handleGenerateTestToken}
className="op-btn op-btn-primary w-[180px] md:w-auto"
className="op-btn op-btn-primary w-[200px] md:w-auto"
>
{apitestToken
? t("regenerate-test-token")
@@ -295,18 +301,26 @@ function GenerateToken() {
</div>
<button
onClick={apiToken ? handleModal : handleSubmit}
className="op-btn op-btn-primary w-[180px] md:w-auto"
className="op-btn op-btn-primary w-[200px] md:w-auto"
>
{apiToken ? t("regenerate-token") : t("generate-token")}
</button>
</li>
<div className="text-xs md:text-[15px] my-4">
<span className="font-medium">{t("remainingapis")}</span>{" "}
{amount.allowedcredits}
</div>
<div className="text-xs md:text-[15px] my-4">
<span className="font-medium">Addon credits: </span>{" "}
{amount.addoncredits}
<div className="text-xs md:text-[15px] my-3 w-full md:w-[70%] flex-col md:flex-row flex items-center gap-x-5">
<span className="font-medium">
{t("remainingcredits")}{" "}
<span className="text-xs">
<Tooltip
message={t("remainingcreditshelp", {
allowedcredits: amount?.allowedcredits || 0,
addoncredits: amount?.addoncredits || 0
})}
/>
</span>
</span>
<span className="md:text-end py-2 md:py-0">
{amount.totalcredits}
</span>
</div>
<hr />
</ul>
@@ -318,16 +332,16 @@ function GenerateToken() {
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="op-btn op-btn-secondary mt-2 md:mb-3 px-8 w-[180px] md:w-auto"
className="op-btn op-btn-secondary mt-2 md:mb-3 px-8 w-[200px] md:w-auto"
>
{t("view-docs")}
</button>
<button
type="button"
onClick={() => handleBuyAPIsModal()}
className="op-btn op-btn-secondary mt-2 mb-3 px-8 w-[180px] md:w-auto"
className="op-btn op-btn-secondary mt-2 mb-3 px-8 w-[200px] md:w-auto"
>
{t("buyapiaddon")}
{t("buycredits")}
</button>
</div>
<ModalUi
@@ -359,7 +373,7 @@ function GenerateToken() {
{/* buy APIs */}
<ModalUi
isOpen={isModal.buyapis}
title={"Buy Addon APIs"}
title={"Buy Credits"}
handleClose={handleBuyAPIsModal}
>
{isFormLoader && (
@@ -373,7 +387,7 @@ function GenerateToken() {
htmlFor="quantity"
className="block text-xs text-gray-700 font-semibold"
>
{t("quantityofapis")}
{t("quantityofcredits")}
<span className="text-[red] text-[13px]"> *</span>
</label>
<select
+2 -9
View File
@@ -31,7 +31,6 @@ import {
handleDownloadPdf,
handleToPrint,
handleDownloadCertificate,
openInNewTab,
getDefaultSignature,
onClickZoomIn,
onClickZoomOut,
@@ -51,7 +50,6 @@ import { useSelector } from "react-redux";
import SignerListComponent from "../components/pdf/SignerListComponent";
import VerifyEmail from "../components/pdf/VerifyEmail";
import PdfZoom from "../components/pdf/PdfZoom";
import { paidUrl } from "../json/plansArr";
import { useTranslation } from "react-i18next";
function PdfRequestFiles(props) {
@@ -239,13 +237,8 @@ function PdfRequestFiles(props) {
await handleSendOTP(currentUser?.email);
};
const handleNavigation = (plan) => {
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;
+2 -9
View File
@@ -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();
+3 -9
View File
@@ -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 };
@@ -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();
+2 -7
View File
@@ -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";
@@ -315,12 +315,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 = () => {
+6 -13
View File
@@ -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 (
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
<div className="op-card-body">
<h2 className="op-card-title">
{t("upgrade-to")} {plan ? plan : "PRO"} {t("plan")}
{t("upgrade-to")} {plan ? plan : "Paid"} {t("plan")}
</h2>
<p>
${price ? price : "29.99"}/month: {t("subscribe-card-plan")}
</p>
<p>{t("subscribe-card-plan", { premiumPrice, addonPrice })}</p>
<div className="op-card-actions justify-end">
<button
onClick={() => handlePaidRoute()}
@@ -38,7 +38,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",
@@ -39,7 +39,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",
+11
View File
@@ -210,3 +210,14 @@ export const useLocal = process.env.USE_LOCAL ? process.env.USE_LOCAL.toLowerCas
export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '465' ? false : true;
export const smtpenable =
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
export const planCredits = {
'pro-weekly': 100,
'pro-yearly': 240,
'professional-monthly': 100,
'professional-yearly': 240,
'team-weekly': 100,
'team-yearly': 500,
'teams-monthly': 100,
'teams-yearly': 500,
};
@@ -1,3 +1,5 @@
import { planCredits } from '../../Utils.js';
export default async function saveSubscription(request, response) {
const SubscriptionId = request.body?.data?.subscription?.subscription_id;
const body = request.body;
@@ -5,6 +7,7 @@ export default async function saveSubscription(request, response) {
const Next_billing_date = request.body?.data?.subscription?.next_billing_at;
const planCode = request.body?.data?.subscription?.plan?.plan_code;
const addons = request.body?.data?.subscription?.addons || [];
const credits = planCredits?.[planCode] || 0;
let existAddon = 0;
if (addons?.length > 0) {
let allowedUsersMonthly = 0;
@@ -52,6 +55,24 @@ export default async function saveSubscription(request, response) {
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 response.status(200).json({ status: 'update subscription!' });
} else {
@@ -82,6 +103,9 @@ export default async function saveSubscription(request, response) {
if (existAddon > 0) {
createSubscription.set('AllowedUsers', parseInt(existAddon));
}
if (credits > 0) {
createSubscription.set('AllowedCredits', credits);
}
await createSubscription.save(null, { useMasterKey: true });
return response.status(200).json({ status: 'create subscription!' });
}
-9
View File
@@ -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,10 +61,6 @@ 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';
@@ -145,9 +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);
@@ -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);
// }
// }
@@ -1,37 +0,0 @@
export default async function AllowedApis(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 allowedapis = _resSub?.AllowedApis || 0;
return allowedapis;
}
} 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);
}
}
@@ -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);
}
}
@@ -1,91 +0,0 @@
import axios from 'axios';
export default async function BuyApis(request) {
const apis = request.params.apis;
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 = 'api-signatures';
const data = JSON.stringify({
plan: { plan_code: plan_code },
addons: [
{ addon_code: addoncode, addon_description: 'API 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,
},
});
// console.log('resAPis ', resAPis.data);
if (resAPis.data) {
const existAllowedApis = _resSub?.AllowedApis ? _resSub.AllowedApis : 0;
const allowedapis = existAllowedApis + quantity;
const updateSub = new Parse.Object('contracts_Subscriptions');
updateSub.id = resSub.id;
updateSub.set('AllowedApis', allowedapis);
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
// console.log('resupdateSub ', resupdateSub);
return { status: 'success', addon: allowedapis };
}
} 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.');
}
}
@@ -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.');
}
}
@@ -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) {
@@ -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!' };
}
@@ -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);