Skip to content

Commit

Permalink
Merge pull request #2377 from shadrak98/fc_partnership_fee
Browse files Browse the repository at this point in the history
feat(partner): Partnership Fees via dashboard
  • Loading branch information
shadrak98 authored Jan 6, 2025
2 parents ddef086 + c9724ce commit 5e905e7
Show file tree
Hide file tree
Showing 29 changed files with 1,186 additions and 151 deletions.
2 changes: 1 addition & 1 deletion dashboard/src2/components/NavigationItems.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default {
disabled: enforce2FA
},
{
name: 'Partners',
name: 'Partner Portal',
icon: () => h(Globe),
route: '/partners',
isActive: routeName.startsWith('Partner'),
Expand Down
4 changes: 3 additions & 1 deletion dashboard/src2/components/billing/BuyCreditsRazorpay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ onBeforeUnmount(() => {
const createRazorpayOrder = createResource({
url: 'press.api.billing.create_razorpay_order',
params: { amount: props.amount },
params: {
amount: props.amount
},
onSuccess: data => processOrder(data),
validate: () => {
if (props.amount < props.minimumAmount) {
Expand Down
12 changes: 5 additions & 7 deletions dashboard/src2/components/billing/PaymentDetails.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
<template>
<div class="flex flex-col gap-4">
<div class="text-lg font-semibold text-gray-900">
{{ 'Payment details' }}
</div>
<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="font-medium">Active Card</div>
<div class="overflow-hidden text-ellipsis text-gray-700">
<div
v-if="team.doc.payment_method"
Expand Down Expand Up @@ -42,7 +40,7 @@
/>
<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 class="font-medium">Mode of payment</div>
<div
v-if="team.doc.payment_mode"
class="inline-flex items-center gap-2 text-gray-700"
Expand Down Expand Up @@ -72,7 +70,7 @@
<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="font-medium">Credit balance</div>
<div class="text-gray-700">
{{ availableCredits || currency + ' 0.00' }}
</div>
Expand Down Expand Up @@ -101,7 +99,7 @@
<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 class="font-medium">Billing address</div>
<div v-if="billingDetailsSummary" class="leading-5 text-gray-700">
{{ billingDetailsSummary }}
</div>
Expand Down
134 changes: 134 additions & 0 deletions dashboard/src2/components/partners/BuyPartnerCreditsRazorpay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<template>
<div>
<span
v-if="team.doc.currency === 'INR'"
class="mt-2.5 inline-flex gap-2 text-base text-gray-700"
>
<FeatherIcon name="info" class="my-1 h-4" />
<span class="leading-5">
If you select Razorpay, you can pay using Credit Card, Debit Card, Net
Banking, UPI, Wallets, etc. If you are using Net Banking, it may take
upto 5 days for balance to reflect.
</span>
</span>
<ErrorMessage class="mt-3" :message="createRazorpayOrder.error" />
<div class="mt-8">
<Button
v-if="!isPaymentComplete"
class="w-full"
size="md"
variant="solid"
label="Proceed to payment using Razorpay"
:loading="createRazorpayOrder.loading"
@click="createRazorpayOrder.submit()"
/>
<Button
v-else
class="w-full"
size="md"
label="Confirming payment"
variant="solid"
:loading="isVerifyingPayment"
/>
</div>
</div>
</template>
<script setup>
import { Button, ErrorMessage, FeatherIcon, createResource } from 'frappe-ui';
import { ref, onMounted, onBeforeUnmount, inject } from 'vue';
import { toast } from 'vue-sonner';
import { DashboardError } from '../../utils/error';
const props = defineProps({
amount: {
type: Number,
default: 0
},
maximumAmount: {
type: Number,
default: 0
},
type: {
type: String,
default: 'prepaid-credits'
}
});
const emit = defineEmits(['success']);
const team = inject('team');
const isPaymentComplete = ref(false);
const isVerifyingPayment = ref(false);
const razorpayCheckoutJS = ref(null);
onMounted(() => {
razorpayCheckoutJS.value = document.createElement('script');
razorpayCheckoutJS.value.setAttribute(
'src',
'https://checkout.razorpay.com/v1/checkout.js'
);
razorpayCheckoutJS.value.async = true;
document.head.appendChild(razorpayCheckoutJS.value);
});
onBeforeUnmount(() => {
razorpayCheckoutJS.value?.remove();
});
let order_type =
props.type === 'prepaid-credits' ? 'Prepaid Credits' : 'Partnership Fee';
const createRazorpayOrder = createResource({
url: 'press.api.billing.create_razorpay_order',
params: {
amount: props.amount,
type: order_type
},
onSuccess: data => processOrder(data),
validate: () => {
if (props.amount > props.maximumAmount) {
throw new DashboardError('Amount more than maximum amount required');
}
}
});
const handlePaymentFailed = createResource({
url: 'press.api.billing.handle_razorpay_payment_failed',
onSuccess: () => {
console.log('Payment Failed.');
}
});
function processOrder(data) {
const options = {
key: data.key_id,
order_id: data.order_id,
name: 'Frappe Cloud',
image: 'https://frappe.io/files/cloud.png',
prefill: { email: team.doc?.user },
handler: handlePaymentSuccess,
theme: { color: '#171717' }
};
const rzp = new Razorpay(options);
// Opens the payment checkout frame
rzp.open();
// Attach failure handler
rzp.on('payment.failed', handlePaymentFailure);
// rzp.on('payment.success', this.handlePaymentSuccess);
}
function handlePaymentFailure(response) {
handlePaymentFailed.submit({ response });
toast.error('Payment failed');
}
function handlePaymentSuccess() {
isPaymentComplete.value = true;
emit('success');
toast.success('Payment successful');
}
</script>
168 changes: 168 additions & 0 deletions dashboard/src2/components/partners/BuyPartnerCreditsStripe.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<template>
<div>
<label
class="block"
:class="{
'pointer-events-none h-0.5 opacity-0': step != 'Add Card Details',
'mt-4': step == 'Add Card Details'
}"
>
<span class="text-sm leading-4 text-gray-700">
Credit or Debit Card
</span>
<div class="form-input mt-2 block w-full pl-3" ref="cardElementRef"></div>
<ErrorMessage class="mt-1" :message="cardErrorMessage" />
</label>

<div v-if="step == 'Setting up Stripe'" class="mt-8 flex justify-center">
<Spinner class="h-4 w-4 text-gray-700" />
</div>
<ErrorMessage
class="mt-2"
:message="createPaymentIntent.error || errorMessage"
/>
<div class="mt-8">
<Button
v-if="step == 'Get Amount'"
class="w-full"
size="md"
variant="solid"
label="Proceed to payment using Stripe"
:loading="createPaymentIntent.loading"
@click="createPaymentIntent.submit()"
/>
<Button
v-else-if="step == 'Add Card Details'"
class="w-full"
size="md"
variant="solid"
label="Make payment via Stripe"
:loading="paymentInProgress"
@click="onBuyClick"
/>
</div>
</div>
</template>
<script setup>
import { Button, ErrorMessage, Spinner, createResource } from 'frappe-ui';
import { loadStripe } from '@stripe/stripe-js';
import { ref, nextTick, inject } from 'vue';
import { toast } from 'vue-sonner';
import { DashboardError } from '../../utils/error';
const props = defineProps({
amount: {
type: Number,
default: 0
},
maximumAmount: {
type: Number,
default: 0
}
});
const emit = defineEmits(['success']);
const team = inject('team');
const step = ref('Get Amount');
const clientSecret = ref(null);
const cardErrorMessage = ref(null);
const errorMessage = ref(null);
const paymentInProgress = ref(false);
const stripe = ref(null);
const card = ref(null);
const elements = ref(null);
const ready = ref(false);
const cardElementRef = ref(null);
const createPaymentIntent = createResource({
url: 'press.api.billing.create_payment_intent_for_partnership_fees',
params: { amount: props.amount },
validate() {
if (props.amount > props.maximumAmount) {
throw new DashboardError(
`Amount must be lesser than or equal to ${props.maximumAmount}`
);
}
},
async onSuccess(data) {
step.value = 'Setting up Stripe';
let { publishable_key, client_secret } = data;
clientSecret.value = client_secret;
stripe.value = await loadStripe(publishable_key);
elements.value = stripe.value.elements();
const style = {
base: {
color: '#171717',
fontFamily: [
'ui-sans-serif',
'system-ui',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'"Noto Sans"',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
'"Noto Color Emoji"'
].join(', '),
fontSmoothing: 'antialiased',
fontSize: '13px',
'::placeholder': {
color: '#C7C7C7'
}
},
invalid: {
color: '#7C7C7C',
iconColor: '#7C7C7C'
}
};
card.value = elements.value.create('card', {
hidePostalCode: true,
style: style,
classes: {
complete: '',
focus: 'bg-gray-100'
}
});
step.value = 'Add Card Details';
nextTick(() => {
card.value.mount(cardElementRef.value);
});
card.value.addEventListener('change', event => {
cardErrorMessage.value = event.error?.message || null;
});
card.value.addEventListener('ready', () => {
ready.value = true;
});
}
});
async function onBuyClick() {
paymentInProgress.value = true;
let payload = await stripe.value.confirmCardPayment(clientSecret.value, {
payment_method: { card: card.value }
});
if (payload.error) {
errorMessage.value = payload.error.message;
paymentInProgress.value = false;
} else {
toast.success(
'Payment processed successfully, we will update your account shortly on confirmation from Stripe'
);
paymentInProgress.value = false;
emit('success');
errorMessage.value = null;
}
}
</script>
2 changes: 1 addition & 1 deletion dashboard/src2/components/partners/PartnerContribution.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default {
resources: {
getPartnerContribution() {
return {
url: 'press.api.partner.get_partner_contribution',
url: 'press.api.partner.get_partner_contribution_list',
auto: true,
params: {
partner_email: this.partnerEmail
Expand Down
Loading

0 comments on commit 5e905e7

Please sign in to comment.