mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-01 19:29:10 +00:00
Move Stripe to ERPNext
This commit is contained in:
85
erpnext/templates/includes/integrations/stripe_checkout.js
Normal file
85
erpnext/templates/includes/integrations/stripe_checkout.js
Normal file
@@ -0,0 +1,85 @@
|
||||
var stripe = Stripe("{{ publishable_key }}");
|
||||
|
||||
var elements = stripe.elements();
|
||||
|
||||
var style = {
|
||||
base: {
|
||||
color: '#32325d',
|
||||
lineHeight: '18px',
|
||||
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
|
||||
fontSmoothing: 'antialiased',
|
||||
fontSize: '16px',
|
||||
'::placeholder': {
|
||||
color: '#aab7c4'
|
||||
}
|
||||
},
|
||||
invalid: {
|
||||
color: '#fa755a',
|
||||
iconColor: '#fa755a'
|
||||
}
|
||||
};
|
||||
|
||||
var card = elements.create('card', {
|
||||
hidePostalCode: true,
|
||||
style: style
|
||||
});
|
||||
|
||||
card.mount('#card-element');
|
||||
|
||||
function setOutcome(result) {
|
||||
|
||||
if (result.token) {
|
||||
$('#submit').prop('disabled', true)
|
||||
$('#submit').html(__('Processing...'))
|
||||
frappe.call({
|
||||
method:"erpnext.templates.pages.integrations.stripe_checkout.make_payment",
|
||||
freeze:true,
|
||||
headers: {"X-Requested-With": "XMLHttpRequest"},
|
||||
args: {
|
||||
"stripe_token_id": result.token.id,
|
||||
"data": JSON.stringify({{ frappe.form_dict|json }}),
|
||||
"reference_doctype": "{{ reference_doctype }}",
|
||||
"reference_docname": "{{ reference_docname }}"
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message.status == "Completed") {
|
||||
$('#submit').hide()
|
||||
$('.success').show()
|
||||
setTimeout(function() {
|
||||
window.location.href = r.message.redirect_to
|
||||
}, 2000);
|
||||
} else {
|
||||
$('#submit').hide()
|
||||
$('.error').show()
|
||||
setTimeout(function() {
|
||||
window.location.href = r.message.redirect_to
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else if (result.error) {
|
||||
$('.error').html() = result.error.message;
|
||||
$('.error').show()
|
||||
}
|
||||
}
|
||||
|
||||
card.on('change', function(event) {
|
||||
var displayError = document.getElementById('card-errors');
|
||||
if (event.error) {
|
||||
displayError.textContent = event.error.message;
|
||||
} else {
|
||||
displayError.textContent = '';
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ready(function() {
|
||||
$('#submit').off("click").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
var extraDetails = {
|
||||
name: $('input[name=cardholder-name]').val(),
|
||||
email: $('input[name=cardholder-email]').val()
|
||||
}
|
||||
stripe.createToken(card, extraDetails).then(setOutcome);
|
||||
})
|
||||
});
|
||||
113
erpnext/templates/pages/integrations/stripe_checkout.css
Normal file
113
erpnext/templates/pages/integrations/stripe_checkout.css
Normal file
@@ -0,0 +1,113 @@
|
||||
.StripeElement {
|
||||
background-color: white;
|
||||
height: 40px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 #e6ebf1;
|
||||
-webkit-transition: box-shadow 150ms ease;
|
||||
transition: box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.StripeElement--focus {
|
||||
box-shadow: 0 1px 3px 0 #cfd7df;
|
||||
}
|
||||
|
||||
.StripeElement--invalid {
|
||||
border-color: #fa755a;
|
||||
}
|
||||
|
||||
.StripeElement--webkit-autofill {
|
||||
background-color: #fefde5 !important;
|
||||
}
|
||||
|
||||
.stripe #payment-form {
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.stripe button {
|
||||
float: right;
|
||||
display: block;
|
||||
background: #5e64ff;
|
||||
color: white;
|
||||
box-shadow: 0 7px 14px 0 rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08);
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
margin-top: 20px;
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
max-width: 40%;
|
||||
height: 40px;
|
||||
line-height: 38px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.stripe button:hover, .stripe button:focus {
|
||||
background: #2b33ff;
|
||||
border-color: #0711ff;
|
||||
}
|
||||
|
||||
.stripe button:active {
|
||||
background: #5e64ff;
|
||||
}
|
||||
|
||||
.stripe button:disabled {
|
||||
background: #515e80;
|
||||
}
|
||||
|
||||
.stripe .group {
|
||||
background: white;
|
||||
box-shadow: 2px 7px 14px 2px rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stripe label {
|
||||
position: relative;
|
||||
color: #8898AA;
|
||||
font-weight: 300;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
margin-left: 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stripe .group label:not(:last-child) {
|
||||
border-bottom: 1px solid #F0F5FA;
|
||||
}
|
||||
|
||||
.stripe label>span {
|
||||
width: 20%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.current-card {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.field {
|
||||
background: transparent;
|
||||
font-weight: 300;
|
||||
border: 0;
|
||||
color: #31325F;
|
||||
outline: none;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
cursor: text;
|
||||
width: 70%;
|
||||
height: 40px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.field::-webkit-input-placeholder {
|
||||
color: #CFD7E0;
|
||||
}
|
||||
|
||||
.field::-moz-placeholder {
|
||||
color: #CFD7E0;
|
||||
}
|
||||
|
||||
.field:-ms-input-placeholder {
|
||||
color: #CFD7E0;
|
||||
}
|
||||
56
erpnext/templates/pages/integrations/stripe_checkout.html
Normal file
56
erpnext/templates/pages/integrations/stripe_checkout.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{% extends "templates/web.html" %}
|
||||
|
||||
{% block title %} Payment {% endblock %}
|
||||
|
||||
{%- block header -%}
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
<script>{% include "templates/includes/integrations/stripe_checkout.js" %}</script>
|
||||
{% endblock %}
|
||||
|
||||
{%- block page_content -%}
|
||||
|
||||
<div class="row stripe" style="min-height: 400px; padding-bottom: 50px; margin-top:100px;">
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<img src={{image}}>
|
||||
<h2 class="text-center">{{description}}</h2>
|
||||
<form id="payment-form">
|
||||
<div class="form-row">
|
||||
<div class="group">
|
||||
<div>
|
||||
<label>
|
||||
<span>{{ _("Name") }}</span>
|
||||
<input id="cardholder-name" name="cardholder-name" class="field" placeholder="{{ _('John Doe') }}" value="{{payer_name}}"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div>
|
||||
<label>
|
||||
<span>{{ _("Email") }}</span>
|
||||
<input id="cardholder-email" name="cardholder-email" class="field" placeholder="{{ _('john@doe.com') }}" value="{{payer_email}}"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<label>
|
||||
<span>{{ _("Card Details") }}</span>
|
||||
<div id="card-element" name="card-element" class="field"></div>
|
||||
<div id="card-errors" role="alert"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<button type="submit" class="submit" id="submit">{{_('Pay')}} {{amount}}</button>
|
||||
<div class="outcome text-center">
|
||||
<div class="error" hidden>{{ _("An error occured during the payment process. Please contact us.") }}</div>
|
||||
<div class="success" hidden>{{ _("Your payment has been successfully registered.") }}</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
64
erpnext/templates/pages/integrations/stripe_checkout.py
Normal file
64
erpnext/templates/pages/integrations/stripe_checkout.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt, cint, fmt_money
|
||||
import json
|
||||
from erpnext.erpnext_integrations.doctype.stripe_settings.stripe_settings import get_gateway_controller
|
||||
|
||||
no_cache = 1
|
||||
no_sitemap = 1
|
||||
|
||||
expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'reference_docname',
|
||||
'payer_name', 'payer_email', 'order_id', 'currency')
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
|
||||
# all these keys exist in form_dict
|
||||
if not (set(expected_keys) - set(list(frappe.form_dict))):
|
||||
for key in expected_keys:
|
||||
context[key] = frappe.form_dict[key]
|
||||
|
||||
gateway_controller = get_gateway_controller(context.reference_docname)
|
||||
context.publishable_key = get_api_key(context.reference_docname, gateway_controller)
|
||||
context.image = get_header_image(context.reference_docname, gateway_controller)
|
||||
|
||||
context['amount'] = fmt_money(amount=context['amount'], currency=context['currency'])
|
||||
|
||||
if frappe.db.get_value(context.reference_doctype, context.reference_docname, "is_a_subscription"):
|
||||
payment_plan = frappe.db.get_value(context.reference_doctype, context.reference_docname, "payment_plan")
|
||||
recurrence = frappe.db.get_value("Payment Plan", payment_plan, "recurrence")
|
||||
|
||||
context['amount'] = context['amount'] + " " + _(recurrence)
|
||||
|
||||
else:
|
||||
frappe.redirect_to_message(_('Some information is missing'),
|
||||
_('Looks like someone sent you to an incomplete URL. Please ask them to look into it.'))
|
||||
frappe.local.flags.redirect_location = frappe.local.response.location
|
||||
raise frappe.Redirect
|
||||
|
||||
def get_api_key(doc, gateway_controller):
|
||||
publishable_key = frappe.db.get_value("Stripe Settings", gateway_controller, "publishable_key")
|
||||
if cint(frappe.form_dict.get("use_sandbox")):
|
||||
publishable_key = frappe.conf.sandbox_publishable_key
|
||||
|
||||
return publishable_key
|
||||
|
||||
def get_header_image(doc, gateway_controller):
|
||||
header_image = frappe.db.get_value("Stripe Settings", gateway_controller, "header_img")
|
||||
return header_image
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def make_payment(stripe_token_id, data, reference_doctype=None, reference_docname=None):
|
||||
data = json.loads(data)
|
||||
|
||||
data.update({
|
||||
"stripe_token_id": stripe_token_id
|
||||
})
|
||||
|
||||
gateway_controller = get_gateway_controller(reference_docname)
|
||||
data = frappe.get_doc("Stripe Settings", gateway_controller).create_request(data)
|
||||
frappe.db.commit()
|
||||
return data
|
||||
Reference in New Issue
Block a user