mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: mandate flow
This commit is contained in:
@@ -264,6 +264,7 @@ export enum Submit {
|
||||
PaymentMethodUpdate = 'submit_payment_method_update',
|
||||
PaymentMethodDelete = 'submit_payment_method_delete',
|
||||
RetryPayment = 'submit_retry_payment',
|
||||
VerifyPayment = 'submit_verify_payment',
|
||||
BillingAddressCreate = 'submit_billing_address_create',
|
||||
BillingAddressUpdate = 'submit_billing_address_update',
|
||||
BillingAddressDelete = 'submit_billing_address_delete',
|
||||
|
||||
@@ -2,28 +2,25 @@
|
||||
import { page } from '$app/stores';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { HeaderAlert } from '$lib/layout';
|
||||
import { actionRequiredInvoices } from '$lib/stores/billing';
|
||||
import { paymentMissingMandate } from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { VARS } from '$lib/system';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { confirmSetup } from '$lib/stores/stripe';
|
||||
|
||||
const endpoint = VARS.APPWRITE_ENDPOINT ?? `${$page.url.origin}/v1`;
|
||||
async function verifyPaymentMethod() {
|
||||
const method = await sdk.forConsole.billing.setupPaymentMandate(
|
||||
$organization.$id,
|
||||
$paymentMissingMandate.$id
|
||||
);
|
||||
await confirmSetup(method.clientSecret, method.$id);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $actionRequiredInvoices && $actionRequiredInvoices?.invoices?.length && !$page.url.pathname.includes('/console/account')}
|
||||
<HeaderAlert title="Authorization required" type="error">
|
||||
Please authorize your upcoming payment for {$organization.name}. Your bank requires this
|
||||
security measure to proceed with payment.
|
||||
{#if $paymentMissingMandate && $paymentMissingMandate.country === 'in' && $paymentMissingMandate.mandateId === null && !$page.url.pathname.includes('/console/account')}
|
||||
<HeaderAlert title="Authorization required" type="info">
|
||||
The payment method for {$organization.name} needs to be verified.
|
||||
<svelte:fragment slot="buttons">
|
||||
<Button
|
||||
text
|
||||
href={`${endpoint}/organizations/${$organization.$id}/invoices/${$actionRequiredInvoices.invoices[0].$id}/view`}>
|
||||
View invoice
|
||||
</Button>
|
||||
<Button
|
||||
secondary
|
||||
href={`/console/organization-${$organization.$id}/billing?type=confirmation&invoice=${$actionRequiredInvoices.invoices[0].$id}`}>
|
||||
Authorize payment
|
||||
</Button>
|
||||
<Button secondary on:click={verifyPaymentMethod}>Verify payment method</Button>
|
||||
</svelte:fragment>
|
||||
</HeaderAlert>
|
||||
{/if}
|
||||
|
||||
@@ -2,7 +2,14 @@ import { page } from '$app/stores';
|
||||
import { derived, get, writable } from 'svelte/store';
|
||||
import { sdk } from './sdk';
|
||||
import { organization, type Organization } from './organization';
|
||||
import type { InvoiceList, AddressesList, Invoice, PaymentList, PlansMap } from '$lib/sdk/billing';
|
||||
import type {
|
||||
InvoiceList,
|
||||
AddressesList,
|
||||
Invoice,
|
||||
PaymentList,
|
||||
PlansMap,
|
||||
PaymentMethodData
|
||||
} from '$lib/sdk/billing';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { cachedStore } from '$lib/helpers/cache';
|
||||
import { Query } from '@appwrite.io/console';
|
||||
@@ -14,6 +21,7 @@ import { base } from '$app/paths';
|
||||
import { activeHeaderAlert } from '$routes/console/store';
|
||||
import MarkedForDeletion from '$lib/components/billing/alerts/markedForDeletion.svelte';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import PaymentMandate from '$lib/components/billing/alerts/paymentMandate.svelte';
|
||||
|
||||
export type Tier = 'tier-0' | 'tier-1' | 'tier-2';
|
||||
|
||||
@@ -266,10 +274,19 @@ export function checkForMarkedForDeletion(org: Organization) {
|
||||
}
|
||||
}
|
||||
|
||||
export const paymentMissingMandate = writable<PaymentMethodData>(null);
|
||||
|
||||
export async function checkForMandate(org: Organization) {
|
||||
const paymentId = org.paymentMethodId ?? org.backupPaymentMethodId;
|
||||
const paymentMethod = await sdk.forConsole.billing.getPaymentMethod(paymentId);
|
||||
if (paymentMethod.mandateId === null && paymentMethod.country === 'in') {
|
||||
const method = sdk.forConsole.billing.setupPaymentMandate(org.$id, paymentId);
|
||||
headerAlert.add({
|
||||
id: 'paymentMandate',
|
||||
component: PaymentMandate,
|
||||
show: true,
|
||||
importance: 8
|
||||
});
|
||||
activeHeaderAlert.set(headerAlert.get());
|
||||
paymentMissingMandate.set(paymentMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { get, writable } from 'svelte/store';
|
||||
import type { PaymentMethodData } from '$lib/sdk/billing';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { addNotification } from './notifications';
|
||||
import { organization } from './organization';
|
||||
|
||||
export const stripe = writable<Stripe>();
|
||||
let paymentMethod: PaymentMethodData;
|
||||
@@ -63,7 +64,8 @@ export async function submitStripeCard(name: string, urlRoute?: string) {
|
||||
clientSecret,
|
||||
confirmParams: {
|
||||
return_url: `${baseUrl}${
|
||||
urlRoute ?? `organization/billing?clientSecret=${clientSecret}`
|
||||
urlRoute ??
|
||||
`organization-${get(organization).$id}/billing?clientSecret=${clientSecret}`
|
||||
}`,
|
||||
payment_method_data: {
|
||||
billing_details: {
|
||||
@@ -133,6 +135,45 @@ export async function confirmPayment(
|
||||
}
|
||||
}
|
||||
|
||||
export async function confirmSetup(
|
||||
clientSecret: string,
|
||||
paymentMethodId: string,
|
||||
urlRoute?: string
|
||||
) {
|
||||
const baseUrl = 'https://cloud.appwrite.io/console/';
|
||||
|
||||
const { setupIntent, error } = await get(stripe).confirmCardSetup(clientSecret, {
|
||||
payment_method: paymentMethodId,
|
||||
return_url: `${baseUrl}${
|
||||
urlRoute ?? `organization-${get(organization).$id}/billing?clientSecret=${clientSecret}`
|
||||
}`
|
||||
});
|
||||
|
||||
if (error) {
|
||||
const e = new Error(error.message);
|
||||
trackError(e, Submit.VerifyPayment);
|
||||
addNotification({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
if (setupIntent && setupIntent.status === 'succeeded') {
|
||||
trackEvent(Submit.VerifyPayment);
|
||||
addNotification({
|
||||
message: 'Payment method verified successfully',
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
const e = new Error('Something went wrong. Please try again later.');
|
||||
trackError(e, Submit.VerifyPayment);
|
||||
addNotification({
|
||||
message: e.message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const apperanceLight = {
|
||||
variables: {
|
||||
colorPrimary: '#606a7b',
|
||||
|
||||
Reference in New Issue
Block a user