Getting customer information in Django RazorPay payment gateway - node.js

I just integrated Razorpay payment gateway in my django project and i am new to this payment gateway. When i am initiate the payment razorpay show me an payment interface(like this image) and there is options for writing customer contact and email. Here is my question how can i get this two fields back contact and email when customer click on proceed button.
Here is my code:
Template file
<h2>Product Checkout</h2>
<p>Product: {{ order_obj.product.name }}</p>
<p>Total: {{ order_obj.total }}</p>
<form method="POST"> {% csrf_token %}
<script src="https://checkout.razorpay.com/v1/checkout.js"
data-key="rxxxxxxxxxxxxitP7h"
data-amount= {{order_amount }}
data-currency={{order_currency}}
data-buttontext="Pay with Razorpay"
data-name="xxxxxInc"
data-description="We are listning"
data-image="https://www.bihhs.in/wp-content/uploads/2020/05/jj-logo.png"
data-prefill.name="company name"
data-prefill.email="abc#gmail.com"
data-theme.color="#F37254">
</script><input type="hidden" custom="Hidden Element" name="hidden">
</form>
Views.py file
client = razorpay.Client(auth=("rzxxxxxxxaitP7h", "dZH5xxxxxxxxFmzG"))
payment = client.order.create(dict(amount=order_amount, currency=order_currency))
if payment:
order_obj.mark_paid()
print(payment)
print(payment.get('email'))

You should be getting an id in the response json. As per the docs here RazorpayAPI Reference and you can then get the details of the order with that ID. Then you create a payment with that order ID and then once payment is made you get a payment ID. There are methods to Fetch Payments with a Payment ID which should have these details if the user has filled it.
For your Reference, these are python method guidelines for Razorpay:
Payment Reference Python Razorpay
Here's a pseudo-code for the changes:
client = razorpay.Client(auth=("rzxxxxxxxaitP7h", "dZH5xxxxxxxxFmzG"))
order_details = client.order.create(dict(amount=order_amount, currency=order_currency))
if payment:
order_obj.mark_paid()
payment_id= client.order.payments(str(order_details["id"]))
payment_details= client.payment.fetch(str(payment_id)
payment_email= payment_details["email"]
print (payment)
print(payment_details)

Related

Adding Items to Shopping Cart Python Flask

I'm trying to create an AddtoCart and Checkout functionality using python flask and flask-sqlalchemy. I consider myself to be a beginner at web development in general. How do I take a product item and add it to a cart as a cart item using a button? I would also like to calculate the total price of cart items.
So far I created two models (ProductItem,CartItem). I created successfuly 2 ProductItems (dummy data) and was able to display them in a view using a for loop with jinja2 template. I've tried to create a function to select the product and add it to the cart but I couldn't figure out the way on how to make the add to cart button functionality work.
Thanks in advance!!
class ProductItem(db.Model):
__tablename__='products'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True)
descr = db.Column(db.Text,unique=True,nullable=True)
price = db.Column(db.Float,nullable=False)
img = db.Column(db.String(64),unique=True)
cartitems = db.relationship('CartItem', backref='Product')
def __repr__(self):
return '<ProductName %r>' % self.name
class CartItem(db.Model):
__tablename__='cartitems'
id = db.Column(db.Integer,primary_key=True)
# adding the foreign key
product_id = db.Column(db.Integer, db.ForeignKey('products.id'))
#app.route('/')
def index():
products = Product.query.all()
return render_template('home.html',products=products)
def getproductitem():
itemid = product.id
productname = product.name
productname = CartItem(product_id=itemid)
db.session.add(product)
db.session.commit()
----------------html jinja----------
{% for product in products %}
<div class="product-item">
<h3>{{ product.name }}</h3>
<img src="static/img/products/{{ product.img }}" alt="" width="200px" height="200px">
<p> {{ product.price }}</p>
<button onclick="getproductitem()" type="button" class="btn btn-primary">Add to Cart</button>
</div>
{% endfor %}
Edit
Realised I didn't answer the question about the button. Seems like you're trying to call you python function from the html (unless you have a javascript function also in your front end template).
Your python lives on the server and your html/javascript will be on the client browser - you need to make them communicate by sending a HTTP request from your page to the server, you can't call functions directly.
Server:
#app.route('/cart/<int:product_id>', methods=['POST'])
def add_to_cart(product_id):
product = Product.query.filter(Product.id == product_id)
cart_item = CartItem(product=product)
db.session.add(cart_item)
db.session.commit()
return render_tempate('home.html', product=products)
add to your html:
<script>
function addToCart(productId) {
fetch('[your.local.host.]/cart/productId',
{method: 'POST'}
)
}
</script>
change the button:
<button onclick="addToCart({{product.id}})" type="button" class="btn btn-primary">Add to Cart</button>
Or something similar. Your page needs to talk to your server via HTTP requests.
Original answer about carts
It's probably not necessary to persist your cart in the database unless you really want your users to be able to access the same cart when logging in across devices, or you anticipate they will need to keep items there more long term.
Persisting will add unnecessary time to user requests (while you add/retrieve them) and that CartItem table will continue to get larger and larger and most rows will become redundant (unlikely people want to view their old shopping cart once they've bought products). One solution would be to also link the carts to a User table so you only have one cart per user (provided your users are logged in when shopping), or make sure you delete carts once they're bought or after a certain time period.
However, if you have no need to persist longer term, consider storing the product ids either in either
The flask session. Essentially a lightweight, in memory store on the server that is linked to a user and can be accessed during the request handling. See a tutorial on sessions here.
Inside a cookie. A cookie is stored in the browser (not the server) and usually signed with a key. This does not make them secure - it just means you can be sure no one has modified its content when you retrieve it on the server. See a tutorial here.
This article discusses a few drawbacks/merits to both approaches.

I didn't get any confirmation from stripe after creating a charge. I know it's very common.But lot solution are didn't matching for my one

This is my checkout.php page. I cant see after this form submitting charge will happen on stripe.
<div class="row">
<div class='col-sm-offset-9 col-sm-3'>
<form action="process.php" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_Ccg6bLuZ261haQizFhV8Ma9k"
data-amount="<?php echo $amount?>"
data-name="Skarten.com"
data-description="Widget"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-shipping-address="true"
data-email="<?php echo $user->get_email()?>"
data-locale="auto">
</script>
</form>
</div>
</div>
This is my process.php. But my problem is how to get any confirmation from stripe. If the charge is success or not.
session_start();
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
require_once('stripe-php/init.php');// add the php library for stripe
\Stripe\Stripe::setApiKey("sk_test_8UDgizhVo91Z8MJqk7G9n9BN");
// Token is created using Checkout or Elements!
// Get the payment token ID submitted by the form:
$token = $_POST['stripeToken'];
$amount=$_SESSION['amount'];
// Charge the user's card:
$charge = \Stripe\Charge::create(array(
"amount" => $amount,
"currency" => "usd",
"description" => "Example charge",
"metadata" => array("order_id" => 6735),
"source" => $token,
));
If the charge is successful, the Charge object will be populated with something that has a Charge ID. If it's not successful, that API Method \Stripe\Charge::create() will raise an exception (probably a Card Error exception). You can learn more about those here:
https://stripe.com/docs/api#error_handling
Hope that helps get you started!
The best way to get the 100% confirmation result is to use the Stripe Webhooks
Stripe will send a payload to your endpoint about any event what you registered
Stripe will send you an Event object which will contain specific event's response with details.
In your case you need to catch the charge.succeeded event which will hold the charge object where you can get detail info about it!

Set Stripe checkout custom amount from GET parameter

I can't figure out, just want to pass to checkout page a value as GET parameter
so that https://xxxxxx/?setAmount=200000 did go to a page with this script
<form action="custom action" method="POST">
<script
let params = new URLSearchParams(document.location.search.substring(1));
let amount=params.get(setAmount);
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_UUbDY16wDCECOujIs0vQ2vTi"
data-amount=amount;
data-name="Company"
data-description="Widget"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-locale="auto"
data-zip-code="true"
data-currency="eur">
</script>
</form>
The checkout button show out but didn't get the amount parameter, so that no amount is defined.
I didn't have access to server side on the server hosting the website with the button so I need to go forth and back to another site using Podio Globiflow.
Stripe Checkout supports two modes -- Simple and Custom. Custom lets you control what pops up using javascript instead of data properties set on the server. To get the behavior you seek, you could do something like this:
$('#customButton').on('click', function(e) {
const params = new URLSearchParams(document.location.search)
const amountInCents = params.get("amount")
const displayAmount = parseFloat(amountInCents / 100).toFixed(2);
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: 'Custom amount ($' + displayAmount + ')',
amount: amountInCents,
});
e.preventDefault();
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
It is worth noting, that this amount has no impact on how much you actually Charge your Customer and is only for display purposes. Checkout tokenizes the Card details; the amount Charged is entirely controlled by server side logic as outlined in the official Stripe docs.

Angularjs + Laravel Stripe integration - Response goes to server and other details missing

i have an Angular Storefront app set up. I have a shopping cart functionality in place and a stripe "pay with card" button etc. pretty much looks like this:
<form action="/#/order" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripeApiKey }}"
data-billingAddress=true
data-shippingAddres=true
data-amount="{{ amount }}"
data-name="StoreFront Name"
data-description="Custom-Made Jewellery"
data-image="../images/www/logo.png"
data-locale="auto">
</script>
</form>
Evrything up to this point is working fine. I submit the form and stripe returns the token but the form goes to the server following the route localhost/order (without the # symbol) instead of angular's localhost/#/order.
Why is stripe forcing this redirect? In other words why isn't angular capturing this return call?
Anyways. Then I create a route with Laravel to capture this and dump to inspect the returned data like so:
Route::post('/order', function($request){
dd($request);
});
Yep, data captured by stripe-generated form is returned except amount is missing... I mean everything including stripeToken, buyer's details such as: Name, Email, Billing and Shipping address are returned BUT detail regarding the amount is missing.
Is this normal or I'm I missing something?
Lastly currency is still showing the default: Where can I change currency from say USD to GBP?
Thanks in advance
1/ I don't think Checkout is forcing the redirect, but I don't know enough about Angular to explain what's going on, sorry.
2/ Yes, this is normal. The amount passed to Checkout in the data-amount configuration option is used for display purposes only. The actual amount that is charged is the one you pass in the amount parameter in the charge creation request in your server-side code.
If you need the amount to be user-specified (for instance, if you're taking donations), you'll need to add the amount to the form. Here is a simple JSFiddle to illustrate this case: https://jsfiddle.net/ywain/g2ufa8xr/
3/ You can use the data-currency parameter to change the currency displayed in the Checkout form. Just like data-amount, this is for display purposes only and the actual currency used for the charge is specified by the currency parameter in the charge creation.
This is what i managed to do.
I went with the custom form approach. I had a form template to capture both customer and card inputs in billing.template.html like so:
<form method="POST" id="payment-form">
<span class="payment-errors"></span>
<div>
<label>Name</label>
<input type="text" name="name" data-stripe="name">
</div>
<div>
<label>Email</label>
<input type="text" name="email" data-stripe="address_email">
</div>
<div>
<label>Address Line 1</label>
<input type="text" name="street" data-stripe="address_line1">
</div>
<div>
<label>Postcode</label>
<input type="text" name="postcode" data-stripe="address_zip">
</div>
<div>
<label for="country">Country</label>
<select ng-include="'../templates/_partials/_countrylist.html'"
id="countries" name="country" class="form-control"
name="country" ng-model="country" id="country" size="2"
data-stripe="address_country" required></select>
</div>
<div class="form-row">
<label>
<span>Card Number</span>
<input type="text" name="cardNumber" size="20" data-stripe="number"/>
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<input type="text" name="cvc" size="4" data-stripe="cvc"/>
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text" name="expMonth" size="2" data-stripe="exp-month"/>
</label>
<span> / </span>
<input type="text" name="expYear" size="4" data-stripe="exp-year"/>
</div>
<button id="customButton">Pay with Card</button>
</form>
I know we are not supposed to use name attribute in those form inputs but i left them so i could use angular validation, but i remove them using jquery before submitting to server.
Now i created a controller to handle the form: BillingController.js. In there i had an "on click" handler which kick started things by getting a hold of the form and doing some preparatory work: disabling button to prevent further clicks and removing those 'dreaded' name attributes, comme ca:
$('#customButton').on('click',function(event) {
var $form = $('#payment-form');
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
//NOW REMOVE THOSE NAME ATTRIBUTES
$form.find('input').removeAttr('name');
// call Stripe object and send form data to get back the token.
// NOTE first argument is $form
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
Now let me quote the documentation here as this is very important to understand: https://stripe.com/docs/tutorials/forms
The important code to notice is the call to Stripe.card.createToken.
The first argument is the form element containing credit card data
entered by the user. The relevant values are fetched from their
associated inputs using the data-stripe attribute specified in the
form.
Next we create stripeResponseHandler(). Remember it was the second argument in Stripe.card.createToken($form, stripeResponseHandler); above which gets called when Stripe returns the token.
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
This is copy and paste stuff from stripe's own documentation: https://stripe.com/docs/tutorials/forms. Now, I want to say that, this is where a lot of us were tripping over the fact that form was performing a redirect etc. - notice final line $form.get(0).submit(); . Thats what caused the auto submit, redirecting to what ever action was on form, if u had any (in my case action attribute wasn't necessary as i was doing redirects in my controller).
So i decided to remove $form.get(0).submit() and implemented my own redirect after i was done sending data to the server.
NOTE: Stripe's response will have included data from the $form - try console.log(response); to have an idea of what's being posted back.
FINALLY:
We check if there were any errors returned and if so display them. Otherwise its all good, send data to the server.
The final code looks like:
function stripeResponseHandler(status, response) {
var $form = $('payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// prepare data
var data = {
stripeToken: token,
fullName: response.card.name,
street: response.card.address_line1,
postcode: response.card.address_zip,
town: response.card.address_city,
country: response.card.address_country,
last4: response.card.last4
};
// send to server
$http.post('/checkout', data).then(function(result){
// here you can redirect yourself.
window.location.href = "/#/order-complete";
});
}
};
Angular really playing well with stripe here. Check out this link also: https://gist.github.com/boucher/1750368 - learn a lot from it.
I hope it helps someone today. Happy coding!
Stripe doesn't get involved with your form aside from preventing the default action on form submit event and stopping event propagation. Once the checkout process completes, it appends the relevant data to your form and then triggers a form submit event that is handled by HTML / Javascript natively.
I recommend using something like https://github.com/tobyn/angular-stripe-checkout to get your Stripe response handled correctly by Angular.
Otherwise you could add ng-submit="handleStripeCheckout($event)" to your form instead of action="/#/form". When Stripe's checkout process completes, your $scope.handleStripeCheckout method will be run and you can analyze the new form data inside that method.
Edit: Stripe checkout.js actually triggers form.submit(). That's a pretty bad bug on their part considering that almost no browsers handle that correctly. (Form submitted using submit() from a link cannot be caught by onsubmit handler)

Problems with Braintree Javascript integration - braintree.Environment.Sandbox undefined error?

I'm trying to integrate a Braintree payment solution using Javascript & Node JS.
As per the Braintree documentation, I have the following in my html:
<div id="panel-payment">
<div id="payment-form"></div>
<input id="btn-checkout" type="submit" value="Process Order">
</div>
<script>
$(document).ready(function(){
console.log(braintree); <---- defined AOK
console.log(braintree.Environment); <---- undefined
console.log(braintree.Environment.Sandbox); <---- undefined
var clientToken = "...";
braintree.setup(clientToken, "dropin", {
container: $("#payment-form")
});
});
</script>
I can't get the environment variable, yet the braintree object seems to instantiate fine? Anyone have any ideas?
The braintree object returns:
Object {api: Object, cse: Object, paypal: Object, dropin: Object, Form: Object…}
I also get the dreaded "Unable to find valid container" when I call the braintree.setup() function, even though the container value $("#payment-form") is valid value and I am calling the setup function when the HTML has loaded..
The Environment variable is only available in the NodeJS package.
See here.
For the client side in javascript your need a valid token generated by your server.
So you need a dedicated route delivering a token with the Braintree node package as described here.
And for your container problem try to pass only the id of the div to braintree, not a jQuery element.
braintree.setup(clientToken, "dropin", {
container: "payment-form"
});
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
#chambo_e's answer is correct regarding the difference between the attributes accessible on the node package versus Braintree.js. The environment attribute is only available on the Braintree node module.
I am guessing that the error you are actually seeing is "Uncaught Unable to find a valid FORM" and that is because your payment forms are not enclosed by a form element. By default, Braintree.js looks for the nearest parent form.
<form id="checkout" method="post" action="/checkout">
<div id="panel-payment">
<div id="payment-form"></div>
<input id="btn-checkout" type="submit" value="Process Order">
</div>
</form>
<script src="https://js.braintreegateway.com/v2/braintree.js"></script>
<script>
$(document).ready(function(){
var clientToken = "client token generated form server";
braintree.setup(clientToken, "dropin", {
container: $("#payment-form")
});
});
</script>
If you'd like it to use a different form, you can specify that in the setup call. See these docs for more details
<div id="dropin-container"></div>
<form id="checkout-form">
<input type='submit' value='Pay'/>
</form>
<script>
braintree.setup("CLIENT-TOKEN-FROM-SERVER", "dropin", {
container: "dropin-container",
form: "checkout-form"
});
</script>

Resources