mirror of
https://github.com/hanzo-io/cloud.git
synced 2026-10-30 18:57:42 +00:00
368 lines
10 KiB
Vue
368 lines
10 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-4">
|
|
<div class="text-lg font-semibold text-gray-900">Payment details</div>
|
|
<div class="flex flex-col">
|
|
<div
|
|
v-if="team.doc.payment_mode == 'Card'"
|
|
class="flex items-center justify-between text-base text-gray-900"
|
|
>
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="font-medium">Active Card</div>
|
|
<div class="overflow-hidden text-ellipsis text-gray-700">
|
|
<div
|
|
v-if="team.doc.payment_method"
|
|
class="inline-flex items-center gap-2"
|
|
>
|
|
<component :is="cardBrandIcon(team.doc.payment_method.brand)" />
|
|
<div class="text-gray-700">
|
|
<span>{{ team.doc.payment_method.name_on_card }}</span>
|
|
<span> · Card ending in •••• </span>
|
|
<span>{{ team.doc.payment_method.last_4 }}</span>
|
|
</div>
|
|
</div>
|
|
<span v-else class="text-gray-700">No card added</span>
|
|
</div>
|
|
</div>
|
|
<div class="shrink-0">
|
|
<Button
|
|
:label="team.doc.payment_method ? 'Change card' : 'Add card'"
|
|
@click="changeMethod"
|
|
>
|
|
<template v-if="!team.doc.payment_method" #prefix>
|
|
<FeatherIcon class="h-4" name="plus" />
|
|
</template>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="team.doc.payment_mode == 'Card'"
|
|
class="my-3 h-px bg-gray-100"
|
|
/>
|
|
<div class="flex items-center justify-between text-base text-gray-900">
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="font-medium">Mode of payment</div>
|
|
<div
|
|
v-if="team.doc.payment_mode"
|
|
class="inline-flex items-center gap-2 text-gray-700"
|
|
>
|
|
<FeatherIcon class="h-4" name="info" />
|
|
{{ paymentMode.description }}
|
|
</div>
|
|
<span v-else class="text-gray-700">Not set</span>
|
|
</div>
|
|
<div class="shrink-0">
|
|
<Dropdown :options="paymentModeOptions">
|
|
<template #default="{ open }">
|
|
<Button
|
|
:label="team.doc.payment_mode ? paymentMode.label : 'Set mode'"
|
|
>
|
|
<template #suffix>
|
|
<FeatherIcon
|
|
:name="open ? 'chevron-up' : 'chevron-down'"
|
|
class="h-4"
|
|
/>
|
|
</template>
|
|
</Button>
|
|
</template>
|
|
</Dropdown>
|
|
</div>
|
|
</div>
|
|
<div class="my-3 h-px bg-gray-100" />
|
|
<div class="flex items-center justify-between text-base text-gray-900">
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="font-medium">Credit balance</div>
|
|
<div class="text-gray-700">
|
|
{{ availableCredits || currency + ' 0.00' }}
|
|
</div>
|
|
</div>
|
|
<div class="shrink-0">
|
|
<Button
|
|
:label="'Add credit'"
|
|
@click="
|
|
() => {
|
|
showMessage = false;
|
|
if (!billingDetailsSummary) {
|
|
showMessage = true;
|
|
showBillingDetailsDialog = true;
|
|
return;
|
|
}
|
|
showAddPrepaidCreditsDialog = true;
|
|
}
|
|
"
|
|
>
|
|
<template #prefix>
|
|
<FeatherIcon class="h-4" name="plus" />
|
|
</template>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div class="my-3 h-px bg-gray-100" />
|
|
<div class="flex items-center justify-between text-base text-gray-900">
|
|
<div class="flex flex-col gap-1.5">
|
|
<div class="font-medium">Billing address</div>
|
|
<div v-if="billingDetailsSummary" class="leading-5 text-gray-700">
|
|
{{ billingDetailsSummary }}
|
|
</div>
|
|
<div v-else class="text-gray-700">No address</div>
|
|
</div>
|
|
<div class="shrink-0">
|
|
<Button
|
|
:label="billingDetailsSummary ? 'Edit ' : 'Add billing address'"
|
|
@click="
|
|
() => {
|
|
showMessage = false;
|
|
showBillingDetailsDialog = true;
|
|
}
|
|
"
|
|
>
|
|
<template v-if="!billingDetailsSummary" #prefix>
|
|
<FeatherIcon class="h-4" name="plus" />
|
|
</template>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<BillingDetailsDialog
|
|
v-if="showBillingDetailsDialog"
|
|
v-model="showBillingDetailsDialog"
|
|
:showMessage="showMessage"
|
|
@success="billingDetails.reload()"
|
|
/>
|
|
<AddPrepaidCreditsDialog
|
|
v-if="showAddPrepaidCreditsDialog"
|
|
v-model="showAddPrepaidCreditsDialog"
|
|
:showMessage="showMessage"
|
|
@success="upcomingInvoice.reload()"
|
|
/>
|
|
<AddCardDialog
|
|
v-if="showAddCardDialog"
|
|
v-model="showAddCardDialog"
|
|
:showMessage="showMessage"
|
|
@success="
|
|
() => {
|
|
showMessage = false;
|
|
showAddCardDialog = false;
|
|
team.reload();
|
|
}
|
|
"
|
|
/>
|
|
<ChangeCardDialog
|
|
v-if="showChangeCardDialog"
|
|
v-model="showChangeCardDialog"
|
|
@addCard="
|
|
() => {
|
|
showChangeCardDialog = false;
|
|
showAddCardDialog = true;
|
|
}
|
|
"
|
|
@success="() => team.reload()"
|
|
/>
|
|
</template>
|
|
<script setup>
|
|
import DropdownItem from './DropdownItem.vue';
|
|
import BillingDetailsDialog from './BillingDetailsDialog.vue';
|
|
import AddPrepaidCreditsDialog from './AddPrepaidCreditsDialog.vue';
|
|
import AddCardDialog from './AddCardDialog.vue';
|
|
import ChangeCardDialog from './ChangeCardDialog.vue';
|
|
import { Dropdown, Button, FeatherIcon, createResource } from 'frappe-ui';
|
|
import {
|
|
cardBrandIcon,
|
|
confirmDialog,
|
|
renderDialog,
|
|
} from '../../utils/components';
|
|
import { computed, ref, inject, h, defineAsyncComponent } from 'vue';
|
|
import router from '../../router';
|
|
|
|
const team = inject('team');
|
|
const {
|
|
availableCredits,
|
|
upcomingInvoice,
|
|
currentBillingAmount,
|
|
unpaidInvoices,
|
|
} = inject('billing');
|
|
|
|
const showBillingDetailsDialog = ref(false);
|
|
const showAddPrepaidCreditsDialog = ref(false);
|
|
const showAddCardDialog = ref(false);
|
|
const showChangeCardDialog = ref(false);
|
|
|
|
const currency = computed(() => (team.doc.currency == 'INR' ? '₹' : '$'));
|
|
|
|
const billingDetails = createResource({
|
|
url: 'press.api.account.get_billing_information',
|
|
cache: 'billingDetails',
|
|
auto: true,
|
|
});
|
|
|
|
const changePaymentMode = createResource({
|
|
url: 'press.api.billing.change_payment_mode',
|
|
onSuccess: () => setTimeout(() => team.reload(), 1000),
|
|
});
|
|
|
|
const billingDetailsSummary = computed(() => {
|
|
let _billingDetails = billingDetails.data;
|
|
if (!_billingDetails) return '';
|
|
|
|
const { billing_name, address_line1, city, state, country, pincode, gstin } =
|
|
_billingDetails || {};
|
|
return [
|
|
billing_name,
|
|
address_line1,
|
|
city,
|
|
state,
|
|
country,
|
|
pincode,
|
|
gstin == 'Not Applicable' ? '' : gstin,
|
|
]
|
|
.filter(Boolean)
|
|
.join(', ');
|
|
});
|
|
|
|
const paymentModeOptions = [
|
|
{
|
|
label: 'Card',
|
|
value: 'Card',
|
|
description: 'Your card will be charged for monthly subscription',
|
|
component: () =>
|
|
h(DropdownItem, {
|
|
label: 'Card',
|
|
active: team.doc.payment_mode === 'Card',
|
|
onClick: () => updatePaymentMode('Card'),
|
|
}),
|
|
},
|
|
{
|
|
label: 'Prepaid credits',
|
|
value: 'Prepaid Credits',
|
|
description:
|
|
'You will be charged from your credit balance for monthly subscription',
|
|
component: () =>
|
|
h(DropdownItem, {
|
|
label: 'Prepaid credits',
|
|
active: team.doc.payment_mode === 'Prepaid Credits',
|
|
onClick: () => updatePaymentMode('Prepaid Credits'),
|
|
}),
|
|
},
|
|
{
|
|
label: 'Paid by Partner',
|
|
value: 'Paid By Partner',
|
|
condition: () => team.doc.partner_email,
|
|
description: 'Your partner will be charged for monthly subscription',
|
|
component: () =>
|
|
h(DropdownItem, {
|
|
label: 'Paid by Partner',
|
|
active: team.doc.payment_mode === 'Paid by Partner',
|
|
onClick: () =>
|
|
confirmDialog({
|
|
title: 'Confirm Payment Mode',
|
|
message: `By changing the payment mode to <strong>Paid by Partner</strong>, following details will be shared with your partner: <br><br><li>Site/Server name</li> <li>Plan name</li><li>Number of days site/server is active</li><br>Are you sure you want to proceed?`,
|
|
primaryAction: {
|
|
label: 'Change Payment Mode',
|
|
variant: 'solid',
|
|
onClick: ({ hide }) => {
|
|
updatePaymentMode('Paid By Partner');
|
|
hide();
|
|
},
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
{
|
|
component: () =>
|
|
h('div', [
|
|
h('div', { class: 'border-t border-gray-200 my-1' }),
|
|
h(DropdownItem, null, {
|
|
default: () =>
|
|
h('div', { class: 'flex gap-2' }, [
|
|
h(
|
|
'a',
|
|
{
|
|
href: 'https://frappecloud.com/payment-options',
|
|
target: '_blank',
|
|
},
|
|
'Alternate Payment Methods',
|
|
),
|
|
h(FeatherIcon, { name: 'external-link', class: 'h-4' }),
|
|
]),
|
|
}),
|
|
]),
|
|
},
|
|
];
|
|
|
|
const paymentMode = computed(() => {
|
|
return paymentModeOptions.find((o) => o.value === team.doc.payment_mode);
|
|
});
|
|
|
|
function payUnpaidInvoices() {
|
|
let _unpaidInvoices = unpaidInvoices.data;
|
|
if (_unpaidInvoices.length > 1) {
|
|
if (team.doc.payment_mode === 'Prepaid Credits') {
|
|
showAddPrepaidCreditsDialog.value = true;
|
|
} else {
|
|
confirmDialog({
|
|
title: 'Multiple unpaid invoices',
|
|
message:
|
|
'You have multiple unpaid invoices. Please pay them from the invoices page',
|
|
primaryAction: {
|
|
label: 'Go to invoices',
|
|
variant: 'solid',
|
|
onClick: ({ hide }) => {
|
|
router.push({ name: 'BillingInvoices' });
|
|
hide();
|
|
},
|
|
},
|
|
});
|
|
}
|
|
} else {
|
|
let invoice = _unpaidInvoices[0];
|
|
if (invoice.stripe_invoice_url && team.doc.payment_mode === 'Card') {
|
|
window.open(
|
|
`/api/method/press.api.client.run_doc_method?dt=Invoice&dn=${invoice.name}&method=stripe_payment_url`,
|
|
);
|
|
} else {
|
|
showAddPrepaidCreditsDialog.value = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
const showMessage = ref(false);
|
|
function updatePaymentMode(mode) {
|
|
showMessage.value = false;
|
|
if (!billingDetailsSummary.value) {
|
|
showMessage.value = true;
|
|
showBillingDetailsDialog.value = true;
|
|
return;
|
|
}
|
|
if (mode === 'Prepaid Credits' && team.doc.balance === 0) {
|
|
showMessage.value = true;
|
|
showAddPrepaidCreditsDialog.value = true;
|
|
return;
|
|
} else if (mode === 'Card' && !team.doc.payment_method) {
|
|
showMessage.value = true;
|
|
showAddCardDialog.value = true;
|
|
} else if (mode === 'Paid By Partner' && Boolean(unpaidInvoices.data.length > 0)) {
|
|
if (unpaidInvoices.data) {
|
|
payUnpaidInvoices();
|
|
return;
|
|
}
|
|
if (currentBillingAmount.value) {
|
|
const finalizeInvoicesDialog = defineAsyncComponent(
|
|
() => import('./FinalizeInvoicesDialog.vue'),
|
|
);
|
|
renderDialog(h(finalizeInvoicesDialog));
|
|
return;
|
|
}
|
|
}
|
|
if (!changePaymentMode.loading) changePaymentMode.submit({ mode });
|
|
}
|
|
|
|
function changeMethod() {
|
|
if (team.doc.payment_method) {
|
|
showChangeCardDialog.value = true;
|
|
} else {
|
|
showMessage.value = false;
|
|
showAddCardDialog.value = true;
|
|
}
|
|
}
|
|
</script>
|