fix: website payment. (#1026)

This commit is contained in:
Prateek Shourya
2024-09-03 19:01:52 +05:30
committed by GitHub
parent 437535a9a6
commit 4d7d5dfd73
5 changed files with 70 additions and 89 deletions

View File

@@ -13,7 +13,6 @@ from plane.ee.models import WorkspaceLicense
def fetch_workspace_license(workspace_id, workspace_slug, free_seats=12):
# If the number of free seats is less than 12, set it to 12
workspace_free_seats = 12 if free_seats <= 12 else free_seats
owner_email = Workspace.objects.get(slug=workspace_slug).owner.email
@@ -78,6 +77,7 @@ def is_on_trial(workspace_license):
"Check if the workspace is on a trial"
if (
workspace_license.subscription
and not has_upgraded(workspace_license)
and workspace_license.trial_end_date
and workspace_license.trial_end_date >= timezone.now()
):
@@ -89,6 +89,7 @@ def trial_remaining_days(workspace_license):
"""Calculate the remaining days of the trial"""
if (
workspace_license.subscription
and not has_upgraded(workspace_license)
and workspace_license.trial_end_date
and workspace_license.trial_end_date >= timezone.now()
):
@@ -96,6 +97,21 @@ def trial_remaining_days(workspace_license):
return None
def is_billing_active(workspace_license):
"""Check if the billing is active"""
if workspace_license.plan == WorkspaceLicense.PlanChoice.FREE:
return False
if (
workspace_license.plan == WorkspaceLicense.PlanChoice.PRO
and is_on_trial(workspace_license)
):
return False
return True
def show_payment_button(workspace_license):
"""Check if the workspace is allowed to show the payment button"""
@@ -135,7 +151,6 @@ def resync_workspace_license(workspace_slug, force=False):
if (
workspace_license.last_synced_at - timezone.now()
).total_seconds() > 3600 or force:
# Fetch the workspace license
response = fetch_workspace_license(
workspace_id=str(workspace.id),

View File

@@ -21,6 +21,8 @@ from plane.ee.models import WorkspaceLicense
from plane.utils.exception_logger import log_exception
from plane.payment.utils.workspace_license_request import (
resync_workspace_license,
is_billing_active,
is_on_trial,
)
@@ -93,36 +95,55 @@ class WebsiteUserWorkspaceEndpoint(BaseAPIView):
def get(self, request):
try:
# Get all the workspaces where the user is admin
workspace_ids = WorkspaceMember.objects.filter(
member=request.user,
is_active=True,
role=20,
).values_list("workspace_id", flat=True)
# Fetch the workspaces from the workspace license
workspace_licenses = (
WorkspaceLicense.objects.filter(workspace_id__in=workspace_ids)
.annotate(slug=F("workspace__slug"))
.annotate(name=F("workspace__name"))
.annotate(logo=F("workspace__logo"))
.annotate(product=F("plan"))
workspaces = (
WorkspaceMember.objects.filter(
member=request.user,
is_active=True,
role=20,
)
.annotate(
slug=F("workspace__slug"),
logo=F("workspace__logo"),
name=F("workspace__name"),
)
.values(
"workspace_id",
"slug",
"name",
"logo",
"product",
"trial_end_date",
"has_activated_free_trial",
"has_added_payment_method",
"current_period_end_date",
"is_offline_payment",
"subscription",
)
)
workspace_ids = [workspace["workspace_id"] for workspace in workspaces]
# Fetch the workspaces from the workspace license
workspace_licenses = WorkspaceLicense.objects.filter(
workspace_id__in=workspace_ids
)
for workspace in workspaces:
licenses = [
license
for license in workspace_licenses
if str(license.workspace_id) == str(workspace["workspace_id"])
]
if licenses:
workspace["product"] = licenses[0].plan
workspace["is_on_trial"] = is_on_trial(
licenses[0]
)
workspace["is_billing_active"] = is_billing_active(
licenses[0]
)
else:
workspace["product"] = "FREE"
workspace["is_on_trial"] = False
workspace["is_billing_active"] = False
# Get the workspace details
return Response(workspace_licenses, status=status.HTTP_200_OK)
return Response(workspaces, status=status.HTTP_200_OK)
except requests.exceptions.RequestException as e:
if e.response.status_code == 400:
@@ -165,7 +186,6 @@ class WorkspaceProductEndpoint(BaseAPIView):
class WorkspaceLicenseRefreshEndpoint(BaseAPIView):
def post(self, request, slug):
# Resync the workspace license
_ = resync_workspace_license(workspace_slug=slug, force=True)

View File

@@ -57,13 +57,6 @@ const CloudUpgradePlanPage = observer(() => {
}
);
// fetch workspace current plan
const { data: workspaceSubscription, isLoading: workspaceSubscriptionLoading } = useSWR(
workspaceSlug ? `CLOUD_PRO_WORKSPACE_SUBSCRIPTION_PLAN_${workspaceSlug}` : null,
workspaceSlug ? () => paymentService.getWorkspaceCurrentPlan(workspaceSlug.toString()) : null,
{ revalidateIfStale: false, revalidateOnFocus: false }
);
// derived values
const totalWorkspaceMembers = (workspaceMembers || [])?.filter((member) => member.role >= 15)?.length;
const proProduct = (products || [])?.find((product: IPaymentProduct) => product?.type === "PRO");
@@ -75,9 +68,6 @@ const CloudUpgradePlanPage = observer(() => {
const yearlyPlanUnitPrice = (yearlyPlan?.unit_amount || 0) / 1200;
const yearlyDiscountedPrice = calculateYearlyDiscount(monthlyPlanUnitPrice, yearlyPlanUnitPrice);
const workspaceOnTrial =
workspaceSubscription?.has_activated_free_trial && workspaceSubscription?.trial_end_date ? true : false;
const handleStripeCheckout = (priceId: string) => {
if (!workspaceSlug) {
setToast({
@@ -93,38 +83,8 @@ const CloudUpgradePlanPage = observer(() => {
product_id: proProduct?.id,
})
.then((response) => {
if (response.payment_link) {
window.open(response.payment_link, "_self");
}
})
.catch((error) => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: error?.detail ?? "Failed to generate payment link. Please try again.",
});
})
.finally(() => {
setLoading(false);
});
};
const handleTrialStripeCheckout = (priceId: string) => {
if (!workspaceSlug) {
setToast({
type: TOAST_TYPE.INFO,
title: "Please select a workspace to continue",
});
return;
}
setLoading(true);
paymentService
.modifyTrailSubscription(workspaceSlug.toString(), {
price_id: priceId,
})
.then((response) => {
if (response.session_url) {
window.open(response.session_url, "_self");
if (response.url) {
window.open(response.url, "_self");
}
})
.catch((error) => {
@@ -143,12 +103,12 @@ const CloudUpgradePlanPage = observer(() => {
<div className="w-full h-full flex flex-col items-center justify-center gap-2">
<div className="flex flex-col items-center gap-2 pb-4">
<div className="text-3xl font-semibold">Choose your billing frequency</div>
{yearlyDiscountedPrice && (
{!!yearlyDiscountedPrice && (
<div className="text-center text-base text-custom-text-300">{`Upgrade to our yearly plan and get ${Math.round(yearlyDiscountedPrice)}% off.`}</div>
)}
</div>
{isFetching || isLoadingProduct || workspaceSubscriptionLoading ? (
{isFetching || isLoadingProduct ? (
<div className="flex flex-col rounded gap-1 w-full">
<Loader.Item height="90px" />
<Loader.Item height="90px" />
@@ -209,12 +169,7 @@ const CloudUpgradePlanPage = observer(() => {
{selectedPlan?.recurring && selectedPlan.unit_amount ? (
<>
<Button
className="w-full px-2 my-4"
onClick={() =>
workspaceOnTrial ? handleTrialStripeCheckout(selectedPlan.id) : handleStripeCheckout(selectedPlan.id)
}
>
<Button className="w-full px-2 my-4" onClick={() => handleStripeCheckout(selectedPlan.id)}>
{isLoading
? "Redirecting to Stripe..."
: `Pay $${renderPlanPricing(selectedPlan.unit_amount, totalWorkspaceMembers, selectedPlan.recurring)} every ${selectedPlan?.recurring}`}

View File

@@ -72,16 +72,11 @@ const CloudUpgradePage = observer(() => {
};
const workspaceSubscription = (workspace: TWorkspaceWithProductDetails): "FREE" | "PRO" | "TRIAL" => {
if (!workspace.subscription) return "FREE";
switch (workspace.product) {
case "PRO":
if (workspace.is_offline_payment) {
return "PRO";
} else if (workspace.trial_end_date && workspace.has_added_payment_method) {
return "PRO";
} else if (workspace.trial_end_date && !workspace.has_added_payment_method) {
if (workspace.is_on_trial) {
return "TRIAL";
}
} else return "PRO";
case "FREE":
return "FREE";
default:
@@ -95,7 +90,7 @@ const CloudUpgradePage = observer(() => {
name="workspace-upgrade-radio-input"
label={
<div className="flex flex-col items-center gap-2 pb-4">
<div className="text-3xl font-semibold">
<div className="text-center text-3xl font-semibold">
{isAnyWorkspaceAvailable
? "Choose your workspace"
: "We didn't find an eligible workspace for this upgrade. Try another email address."}
@@ -164,7 +159,7 @@ const CloudUpgradePage = observer(() => {
</div>
),
value: workspace.slug,
disabled: ["PRO"].includes(workspaceSubscription(workspace)),
disabled: workspace.is_billing_active,
}))
: []
}

View File

@@ -7,10 +7,6 @@ export type TWorkspaceWithProductDetails = {
name: string;
logo: string;
product: TProductSubscriptionType;
current_period_end_date: string;
has_activated_free_trial: boolean;
has_added_payment_method: boolean;
trial_end_date: string;
is_offline_payment: boolean;
subscription: string;
is_on_trial: boolean;
is_billing_active: boolean;
};