feat: validtion of quicksend

This commit is contained in:
prafull-opensignlabs
2024-08-20 15:56:00 +05:30
parent 9a03bfb9e7
commit 5d89f724f4
16 changed files with 561 additions and 288 deletions
@@ -608,5 +608,9 @@
"buyapiaddon":"Buy APIs",
"quantityofapis" :"Quantity of APIs",
"additionalapis":"Please purchase add-on APIs",
"remainingapis":"Remaining APIs:"
"remainingapis": "Remaining APIs Credits:",
"additional-quicksend": "Please purchase add-on quick send",
"quantityofquicksend": "Quantity of Quick send",
"quotaerrquicksend": "Quota Reached, You don't have enough credits.",
"buycredits": "Buy credits"
}
@@ -608,5 +608,10 @@
"buyapiaddon":"Acheter des API",
"quantityofapis":"Quantité d'API",
"additionalapis":"Veuillez acheter des API complémentaires",
"remainingapis":"API restantes :"
"remainingapis":"API restantes Crédits:",
"additional-quicksend":"Veuillez acheter le module complémentaire quick send",
"quantityofquicksend": "Quantité de Quick send",
"quotaerrquicksend": "Quota atteint, vous n'avez pas assez de crédits.",
"buycredits": "Acheter des crédits"
}
+4 -13
View File
@@ -52,9 +52,6 @@ const AddUser = (props) => {
const getTeamList = async () => {
if (isEnableSubscription) {
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
try {
setIsLoader(true);
const resSub = await fetchSubscriptionInfo();
@@ -70,9 +67,7 @@ const AddUser = (props) => {
price: resSub.price,
totalPrice: resSub.price + resSub.totalPrice
}));
const res = await Parse.Cloud.run("allowedusers", {
tenantId: extUser?.TenantId?.objectId
});
const res = await Parse.Cloud.run("allowedusers");
if (props.setFormHeader) {
if (res > 0) {
props.setFormHeader(t("add-user"));
@@ -304,13 +299,9 @@ const AddUser = (props) => {
e.preventDefault();
e.stopPropagation();
setIsFormLoader(true);
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
try {
const resAddon = await Parse.Cloud.run("buyaddon", {
users: amount.quantity,
tenantId: extUser?.TenantId?.objectId
const resAddon = await Parse.Cloud.run("buyaddonusers", {
users: amount.quantity
});
if (resAddon) {
const _resAddon = JSON.parse(JSON.stringify(resAddon));
@@ -352,7 +343,7 @@ const AddUser = (props) => {
allowedUser < 2 ? "op-text-accent" : "op-text-primary"
} font-medium ml-1`}
>
{allowedUser} of {planInfo.totalAllowedUser}
{allowedUser} {t("of")} {planInfo.totalAllowedUser}
</span>
</p>
<div className="mb-3">
+229 -101
View File
@@ -3,7 +3,8 @@ import axios from "axios";
import SuggestionInput from "./shared/fields/SuggestionInput";
import Loader from "../primitives/Loader";
import { useTranslation } from "react-i18next";
import Parse from "parse";
import ModalUi from "../primitives/ModalUi";
const BulkSendUi = (props) => {
const { t } = useTranslation();
const [forms, setForms] = useState([]);
@@ -13,6 +14,16 @@ const BulkSendUi = (props) => {
const [isSubmit, setIsSubmit] = useState(false);
const [allowedForm, setAllowedForm] = useState(0);
const [isSignatureExist, setIsSignatureExist] = useState();
const [isBulkAvailable, setIsBulkAvailable] = useState(false);
const quantityList = [500, 1000, 5000, 50000];
const [amount, setAmount] = useState({
price: (75.0).toFixed(2),
quantity: 500,
totalPrice: 0,
priceperbulksend: 0.15,
totalQuickSend: 0
});
const [isQuotaReached, setIsQuotaReached] = useState(false);
const allowedSigners = 50;
useEffect(() => {
signatureExist();
@@ -20,14 +31,26 @@ const BulkSendUi = (props) => {
}, []);
//function to check atleast one signature field exist
const signatureExist = () => {
const getPlaceholder = props.item?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
holder?.pos?.some((posItem) => posItem?.type === "signature")
)
);
setIsSignatureExist(checkIsSignatureExistt);
const signatureExist = async () => {
setIsSubmit(true);
try {
const allowedquicksend = await Parse.Cloud.run("allowedquicksend");
if (allowedquicksend > 0) {
setIsBulkAvailable(true);
const getPlaceholder = props.item?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
holder?.pos?.some((posItem) => posItem?.type === "signature")
)
);
setIsSignatureExist(checkIsSignatureExistt);
}
setAmount((obj) => ({ ...obj, totalQuickSend: allowedquicksend }));
setIsSubmit(false);
} catch (err) {
setIsSubmit(false);
console.log("Err", err);
}
};
useEffect(() => {
if (scrollOnNextUpdate && formRef.current) {
@@ -76,29 +99,33 @@ const BulkSendUi = (props) => {
const handleAddForm = (e) => {
e.preventDefault();
// Check if the quick send limit has been reached
if (forms?.length < allowedForm) {
if (props?.Placeholders.length > 0) {
let newForm = [];
props?.Placeholders?.forEach((element) => {
if (!element.signerObjId) {
newForm = [
...newForm,
{
fieldId: element.Id,
email: "",
label: element.Role,
signer: {}
}
];
}
});
setForms([...forms, { Id: formId, fields: newForm }]);
if (forms.length <= amount.totalQuickSend) {
if (forms?.length < allowedForm) {
if (props?.Placeholders.length > 0) {
let newForm = [];
props?.Placeholders?.forEach((element) => {
if (!element.signerObjId) {
newForm = [
...newForm,
{
fieldId: element.Id,
email: "",
label: element.Role,
signer: {}
}
];
}
});
setForms([...forms, { Id: formId, fields: newForm }]);
}
setFormId(formId + 1);
setScrollOnNextUpdate(true);
} else {
// If the limit has been reached, throw an error with the appropriate message
alert(t("quick-send-alert-4"));
}
setFormId(formId + 1);
setScrollOnNextUpdate(true);
} else {
// If the limit has been reached, throw an error with the appropriate message
alert(t("quick-send-alert-4"));
setIsQuotaReached(true);
}
};
@@ -162,13 +189,9 @@ const BulkSendUi = (props) => {
: [...existSigner]
});
} else {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders
});
Documents.push({ ...props.item, Placeholders: updatedPlaceholders });
}
});
//console.log("Documents ", Documents);
await batchQuery(Documents);
};
@@ -180,9 +203,7 @@ const BulkSendUi = (props) => {
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
};
const params = {
Documents: JSON.stringify(Documents)
};
const params = { Documents: JSON.stringify(Documents) };
try {
const res = await axios.post(functionsUrl, params, { headers: headers });
// console.log("res ", res);
@@ -196,7 +217,48 @@ const BulkSendUi = (props) => {
setIsSubmit(false);
}
};
const handleAddOnQuickSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsSubmit(true);
try {
const resAddon = await Parse.Cloud.run("buyquicksend", {
quicksend: amount.quantity
});
if (resAddon) {
const _resAddon = JSON.parse(JSON.stringify(resAddon));
if (_resAddon.status === "success") {
setIsBulkAvailable(true);
handleCloseQuotaReached();
setAmount((obj) => ({
...obj,
quantity: 500,
priceperapi: 0.15,
price: (75.0).toFixed(2),
totalapis: _resAddon.addon
}));
}
}
} catch (err) {
console.log("Err in buy addon", err);
alert(t("something-went-wrong-mssg"));
} finally {
setIsSubmit(false);
}
};
const handlePricePerQuick = async (e) => {
const quantity = e.target?.value;
const price =
quantity > 0
? (Math.round(quantity * amount.priceperbulksend * 100) / 100).toFixed(
2
)
: 500 * amount.priceperbulksend;
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
};
const handleCloseQuotaReached = () => {
setIsQuotaReached(false);
};
return (
<>
{isSubmit && (
@@ -204,75 +266,141 @@ const BulkSendUi = (props) => {
<Loader />
</div>
)}
{props.Placeholders?.length > 0 ? (
isSignatureExist ? (
<>
{props.Placeholders?.some((x) => !x.signerObjId) ? (
<form onSubmit={handleSubmit}>
<div className="min-h-max max-h-[250px] overflow-y-auto">
{forms?.map((form, index) => (
<div
key={form.Id}
className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content grid grid-cols-1 md:grid-cols-2 gap-2 relative"
>
{form?.fields?.map((field, fieldIndex) => (
<div className="flex flex-col" key={field.fieldId}>
<label>{field.label}</label>
<SuggestionInput
required
type="email"
value={field.value}
index={fieldIndex}
onChange={(signer) =>
handleInputChange(index, signer, fieldIndex)
}
/>
</div>
))}
{forms?.length > 1 && (
{isBulkAvailable ? (
<>
{props.Placeholders?.length > 0 ? (
isSignatureExist ? (
<>
{props.Placeholders?.some((x) => !x.signerObjId) ? (
<div>
<form onSubmit={handleSubmit}>
<div className="min-h-max max-h-[250px] overflow-y-auto">
{forms?.map((form, index) => (
<div
key={form.Id}
className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content grid grid-cols-1 md:grid-cols-2 gap-2 relative"
>
{form?.fields?.map((field, fieldIndex) => (
<div
className="flex flex-col"
key={field.fieldId}
>
<label>{field.label}</label>
<SuggestionInput
required
type="email"
value={field.value}
index={fieldIndex}
onChange={(signer) =>
handleInputChange(index, signer, fieldIndex)
}
/>
</div>
))}
{forms?.length > 1 && (
<button
onClick={() => handleRemoveForm(index)}
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
>
<i className="fa-light fa-trash"></i>
</button>
)}
<div ref={formRef}></div>
</div>
))}
</div>
<div className="flex flex-col mx-4 mb-4 gap-3">
<button
onClick={() => handleRemoveForm(index)}
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
onClick={handleAddForm}
className="op-btn op-btn-primary focus:outline-none"
>
<i className="fa-light fa-trash"></i>
<i className="fa-light fa-plus"></i>{" "}
<span>{t("add-new")}</span>
</button>
)}
<div ref={formRef}></div>
</div>
))}
</div>
<div className="flex flex-col mx-4 mb-4 gap-3">
<button
onClick={handleAddForm}
className="op-btn op-btn-primary focus:outline-none"
>
<i className="fa-light fa-plus"></i>{" "}
<span>{t("add-new")}</span>
</button>
<button
type="submit"
className="op-btn op-btn-secondary focus:outline-none"
>
<i className="fa-light fa-paper-plane"></i>{" "}
<span>{t("send")}</span>
</button>
</div>
</form>
<button
type="submit"
className="op-btn op-btn-secondary focus:outline-none"
>
<i className="fa-light fa-paper-plane"></i>{" "}
<span>{t("send")}</span>
</button>
</div>
</form>
<ModalUi
isOpen={isQuotaReached}
handleClose={() => handleCloseQuotaReached()}
>
<div className="p-4 flex justify-center items-center flex-col gap-y-3">
<p className="text-center text-base-content">
{t("quotaerrquicksend")}
</p>
<button
onClick={() => setIsBulkAvailable(false)}
className=" op-btn op-btn-primary w-28"
>
{t("buycredits")}
</button>
</div>
</ModalUi>
</div>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
{t("quick-send-alert-1")}
</div>
)}
</>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
{t("quick-send-alert-1")}
{t("quick-send-alert-2")}
</div>
)}
</>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
{t("quick-send-alert-2")}
</div>
)
)
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
{t("quick-send-alert-3")}
</div>
)}
</>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
{t("quick-send-alert-3")}
</div>
<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")}
</p>
<div className="mb-3 flex justify-between">
<label
htmlFor="quantity"
className="block text-xs text-gray-700 font-semibold"
>
{t("quantityofquicksend")}
<span className="text-[red] text-[13px]">*</span>
</label>
<select
value={amount.quantity}
onChange={(e) => handlePricePerQuick(e)}
name="quantity"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs"
required
>
{quantityList.length > 0 &&
quantityList.map((x) => (
<option key={x} value={x}>
{x}
</option>
))}
</select>
</div>
<div className="mb-3 flex justify-between">
<label className="block text-xs text-gray-700 font-semibold">
{t("Price")} (1 * {amount.priceperbulksend})
</label>
<div className="w-1/4 flex justify-center items-center text-sm">
USD {amount.price}
</div>
</div>
<hr className="text-base-content mb-3" />
<button className="op-btn op-btn-primary w-full mt-2">
{t("Proceed")}
</button>
</form>
)}
</>
);
+17 -15
View File
@@ -27,12 +27,13 @@ function GenerateToken() {
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isTour, setIsTour] = useState(false);
const [amount, setAmount] = useState({
quantity: 1,
quantity: 500,
priceperapi: 0.15,
totalapis: 0,
price: 0.15
price: (75.0).toFixed(2)
});
const [isFormLoader, setIsFormLoader] = useState(false);
const quantityList = [500, 1000, 5000, 50000];
useEffect(() => {
fetchToken();
// eslint-disable-next-line
@@ -49,14 +50,9 @@ function GenerateToken() {
const subscribe = await checkIsSubscribed();
setIsSubscribe(subscribe);
}
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
const res = await Parse.Cloud.run("getapitoken");
if (res) {
const allowedapis = await Parse.Cloud.run("allowedapis", {
tenantId: extUser?.TenantId?.objectId
});
const allowedapis = await Parse.Cloud.run("allowedapis");
setAmount((obj) => ({ ...obj, totalapis: allowedapis }));
SetApiToken(res?.result);
}
@@ -119,7 +115,7 @@ function GenerateToken() {
const price =
quantity > 0
? (Math.round(quantity * amount.priceperapi * 100) / 100).toFixed(2)
: 1 * amount.priceperapi;
: 500 * amount.priceperapi;
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
};
const handleAddOnApiSubmit = async (e) => {
@@ -137,7 +133,7 @@ function GenerateToken() {
...obj,
quantity: 1,
priceperapi: 0.15,
price: 0.15,
price: (75.0).toFixed(2),
totalapis: _resAddon.addon
}));
}
@@ -276,14 +272,20 @@ function GenerateToken() {
{t("quantityofapis")}
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="number"
name="quantity"
<select
value={amount.quantity}
onChange={(e) => handlePricePerAPIs(e)}
className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
name="quantity"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs"
required
/>
>
{quantityList.length > 0 &&
quantityList.map((x) => (
<option key={x} value={x}>
{x}
</option>
))}
</select>
</div>
<div className="mb-3 flex justify-between">
<label className="block text-xs text-gray-700 font-semibold">
@@ -74,15 +74,7 @@ const ReportTable = (props) => {
const extClass = Extand_Class && JSON.parse(Extand_Class);
const startIndex = (currentPage - 1) * props.docPerPage;
const { isMoreDocs, setIsNextRecord } = props;
// For loop is used to calculate page numbers visible below table
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation
// const pageNumbers = useMemo(() => {
// const calculatedPageNumbers = [];
// for (let i = 1; i <= Math.ceil(props.List.length / props.docPerPage); i++) {
// calculatedPageNumbers.push(i);
// }
// return calculatedPageNumbers;
// }, [props.List, props.docPerPage]);
const getPaginationRange = () => {
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
const pages = [];
@@ -449,7 +441,6 @@ const ReportTable = (props) => {
}
setReason("");
};
const handleShare = (item) => {
setActLoader({ [item.objectId]: true });
const host = window.location.origin;
@@ -839,10 +830,7 @@ const ReportTable = (props) => {
console.log("err in fetch template in bulk modal", err);
setIsBulkSend({});
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
setTimeout(() => setIsAlert(false), 1500);
}
};
@@ -393,7 +393,7 @@ export default async function createDocumentWithTemplate(request, response) {
} else {
return response
.status(429)
.json({ error: 'Quota reached. Please buy API credits and try again later.' });
.json({ error: 'Quota reached, Please buy API credits and try again later.' });
}
} else {
return response.status(405).json({ error: 'Invalid API Token!' });
@@ -413,7 +413,7 @@ export default async function createDocumentwithCoordinate(request, response) {
} else {
return response
.status(429)
.json({ error: 'Quota reached. Please buy API credits and try again later.' });
.json({ error: 'Quota reached, Please buy API credits and try again later.' });
}
} else {
return response.status(405).json({ error: 'Invalid API Token!' });
+6 -3
View File
@@ -61,14 +61,15 @@ import updateTeam from './parsefunction/updateTeam.js';
import getOrgAdmins from './parsefunction/getOrgAdmins.js';
import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js';
import AllowedUsers from './parsefunction/AlllowedUsers.js';
import Buyaddon from './parsefunction/BuyAddon.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';
// 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);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
// Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave);
Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave);
@@ -134,6 +135,8 @@ Parse.Cloud.define('updateteam', updateTeam);
Parse.Cloud.define('getorgadmins', getOrgAdmins);
Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg);
Parse.Cloud.define('allowedusers', AllowedUsers);
Parse.Cloud.define('buyaddon', Buyaddon);
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);
@@ -1,39 +1,50 @@
export default async function AllowedUsers(request) {
const tenantId = request.params.tenantId;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
try {
const subscription = new Parse.Query('contracts_Subscriptions');
subscription.equalTo('TenantId', {
const extUser = new Parse.Query('contracts_Users');
extUser.equalTo('UserId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: tenantId,
className: '_User',
objectId: request.user.id,
});
subscription.include('ExtUserPtr');
const resSub = await subscription.first({ useMasterKey: true });
if (resSub) {
const _resSub = JSON.parse(JSON.stringify(resSub));
const userCls = new Parse.Query('contracts_Users');
userCls.equalTo('OrganizationId', {
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: 'contracts_Organizations',
objectId: _resSub.ExtUserPtr.OrganizationId.objectId,
className: 'partners_Tenant',
objectId: _resExtUser.TenantId.objectId,
});
userCls.notEqualTo('IsDisabled', true);
const count = await userCls.count({ useMasterKey: true });
if (count > 0) {
const allowedUser = resSub.get('AllowedUsers') || 0;
const remainUsers = allowedUser - count;
if (remainUsers > 0) {
return remainUsers;
subscription.include('ExtUserPtr');
const resSub = await subscription.first({ useMasterKey: true });
if (resSub) {
const _resSub = JSON.parse(JSON.stringify(resSub));
const userCls = new Parse.Query('contracts_Users');
userCls.equalTo('OrganizationId', {
__type: 'Pointer',
className: 'contracts_Organizations',
objectId: _resSub.ExtUserPtr.OrganizationId.objectId,
});
userCls.notEqualTo('IsDisabled', true);
const count = await userCls.count({ useMasterKey: true });
if (count > 0) {
const allowedUser = resSub.get('AllowedUsers') || 0;
const remainUsers = allowedUser - count;
if (remainUsers > 0) {
return remainUsers;
} else {
return 0;
}
} else {
return 0;
const alloweduser = resSub.get('AllowedUsers') || 0;
return alloweduser;
}
} else {
const alloweduser = resSub.get('AllowedUsers') || 0;
return alloweduser;
}
} else {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
}
} catch (err) {
console.log('err in allowedusers', err);
@@ -25,6 +25,8 @@ export default async function AllowedApis(request) {
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);
@@ -0,0 +1,37 @@
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,113 +0,0 @@
import axios from 'axios';
export default async function Buyaddon(request) {
const tenantId = request.params.tenantId;
const users = request.params.users;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
if (users && tenantId) {
try {
const subscription = new Parse.Query('contracts_Subscriptions');
subscription.equalTo('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: tenantId,
});
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 price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price;
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || [];
let addon = 0;
if (addonsArr?.length > 0) {
let allowedUsersMonthly = 0;
let allowedUsersYearly = 0;
addonsArr?.forEach(item => {
if (item.addon_code === 'extra-teams-users-monthly') {
allowedUsersMonthly += item.quantity;
} else if (item.addon_code === 'extra-teams-users-yearly') {
allowedUsersYearly += item.quantity;
} else if (item.addon_code === 'extra-users') {
allowedUsersMonthly += item.quantity;
}
});
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
addon = allowedUsersMonthly + allowedUsersYearly;
}
}
const quantity = parseInt(users) + parseInt(addon);
const addoncode = plan_code.includes('yearly')
? 'extra-teams-users-yearly'
: 'extra-teams-users-monthly';
const data = JSON.stringify({
plan: { plan_code: plan_code },
addons: [
{
addon_code: addoncode,
addon_description: 'Extra users',
price: price,
quantity: quantity,
},
],
});
await axios.put(
'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId,
data,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const hostedpage_id = _resSub.SubscriptionDetails.hostedpage_id;
const userData = await axios.get(
'https://www.zohoapis.in/billing/v1/hostedpages/' + hostedpage_id,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const allowedUsers = quantity + 1;
const updateSub = new Parse.Object('contracts_Subscriptions');
updateSub.id = resSub.id;
updateSub.set('SubscriptionDetails', userData.data);
updateSub.set('AllowedUsers', allowedUsers);
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
return { status: 'success', addon: allowedUsers };
} else {
throw new Parse.Error('400', 'Invalid access token.');
}
}
} 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);
}
}
}
@@ -0,0 +1,124 @@
import axios from 'axios';
export default async function BuyAddonUsers(request) {
const users = request.params.users;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
if (users) {
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 price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price;
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || [];
let addon = 0;
if (addonsArr?.length > 0) {
let allowedUsersMonthly = 0;
let allowedUsersYearly = 0;
addonsArr?.forEach(item => {
if (item.addon_code === 'extra-teams-users-monthly') {
allowedUsersMonthly += item.quantity;
} else if (item.addon_code === 'extra-teams-users-yearly') {
allowedUsersYearly += item.quantity;
} else if (item.addon_code === 'extra-users') {
allowedUsersMonthly += item.quantity;
}
});
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
addon = allowedUsersMonthly + allowedUsersYearly;
}
}
const quantity = parseInt(users) + parseInt(addon);
const addoncode = plan_code.includes('yearly')
? 'extra-teams-users-yearly'
: 'extra-teams-users-monthly';
const data = JSON.stringify({
plan: { plan_code: plan_code },
addons: [
{
addon_code: addoncode,
addon_description: 'Extra users',
price: price,
quantity: quantity,
},
],
});
await axios.put(
'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId,
data,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const hostedpage_id = _resSub.SubscriptionDetails.hostedpage_id;
const userData = await axios.get(
'https://www.zohoapis.in/billing/v1/hostedpages/' + hostedpage_id,
{
headers: {
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
},
}
);
const allowedUsers = quantity + 1;
const updateSub = new Parse.Object('contracts_Subscriptions');
updateSub.id = resSub.id;
updateSub.set('SubscriptionDetails', userData.data);
updateSub.set('AllowedUsers', allowedUsers);
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
return { status: 'success', addon: allowedUsers };
} 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);
}
}
}
@@ -72,6 +72,8 @@ export default async function BuyApis(request) {
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;
@@ -80,7 +82,7 @@ export default async function BuyApis(request) {
err?.response?.data ||
err?.message ||
'Something went wrong.';
console.log('err in buyaddon', code, msg);
console.log('err in Buyaddonusers', code, msg);
throw new Parse.Error(code, msg);
}
} else {
@@ -0,0 +1,89 @@
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.');
}
}