Stripe payment failing after trial period - javascript

I'm attempting to create a monthly subscription with free 7 day trial, but after the trial period the payment fails.
EDIT: It appears to fail because the customer has no default payment method, so despite the payment method being attached to customer, it is not set to default. I can not figure out how to set it to default payment method.
I am setting ConfirmCardSetup in frontend javascript, which I believe is tying the card to the customer. And I am creating the customer, and starting the subscription/trial in my backend django view.
I have found this in Stripe documentation:
"To use this PaymentMethod as the default for invoice or subscription
payments, set invoice_settings.default_payment_method, on the Customer
to the PaymentMethod’s ID."
but I am unsure how to get the Payment Method ID from front end, and use it to update the customer.
Here is my subscription create view:
class SubscriptionCreateView(View, SubscriptionCancellationMixin,
CustomerMixin, StripeReferenceMixin, FetchCouponMixin):
"""View to Create subscription and sync with stripe"""
def post(self, request, *args, **kwargs):
context = {}
subscription_payload = {}
price_id = request.POST.get('price_id')
coupon_id = request.POST.get('coupon_id')
customer = self.fetch_customer(request.user)
#Retrieve stripe coupon id or None
if coupon_id != '':
stripe_coupon_id, is_valid = self.is_coupon_valid(coupon_id)
#Set payload to create a subscription
subscription_payload['coupon'] = stripe_coupon_id
#Send invalid coupon response
if not is_valid:
context['invalid_coupon'] = True
response = JsonResponse(context)
response.status_code = 400
return response
if not customer:
customer = self.stripe.Customer.create(
email=request.user.email
)
try:
now = int(time.time())
# Cancel the previous subscription.
self.cancel_subscription(customer)
#Create a new subscription
subscription_payload.update({
'customer':customer.id,
'items': [{
'price': price_id,
},
],
'trial_end': now +30,
},
)
#create a setup intent
setup_intent = self.stripe.SetupIntent.create(
payment_method_types=["card"],
customer=customer.id,
)
subscription = self.stripe.Subscription.create(**subscription_payload)
# Sync the Stripe API return data to the database,
# this way we don't need to wait for a webhook-triggered sync
Subscription.sync_from_stripe_data(subscription)
request.session['created_subscription_id'] = subscription.get('id')
# Note we're sending the Subscription's
# latest invoice and client secret
# to the front end to confirm the payment
context['subscriptionId'] = subscription.id
context['clientSecret'] = setup_intent['client_secret']
except Exception as e:
response = JsonResponse({})
response.status_code = 400
return response
return JsonResponse(context)
And here's the relevant javascript!
var stripe = Stripe($('#public-key').val());
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
}
};
var card = elements.create("card", { style: style });
card.mount("#card-element");
//Capture modal payment button click
$(document).on('click', '#submit-payment-btn', function (e) {
e.preventDefault();
//Send an ajax call to backend to create a subscription
$(this).prop('disabled', true);
let spinnerHtml = '<div class="spinner-border text-light"></div>';
let origButtonHtml = $(this).html();
$(this).html(spinnerHtml);
$.ajax({
url: $(this).data('create-sub-url'),
type: 'POST',
data: {
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
'price_id': $(this).data('price-id'),
'coupon_id': $("#coupon_id").val()
},
success: function (result) {
if(!result.clientSecret)
{
console.log("result not okay")
window.location.href = '/'
}
else{
$('#client-secret').val(result.clientSecret);
// Confirm payment intent.
console.log('set up confirmed');
stripe.confirmCardSetup(result.clientSecret, {
payment_method: {
card: card,
billing_details: {
name: $('#cardholder-name').val(),
},
}
}).then((result) => {
if (result.error) {
alert('Payment failed:'. result.error.message);
} else {
window.location.href = '/'
}
});
}
},
error: function (result){
$('#submit-payment-btn').html(origButtonHtml);
if(result.responseJSON.invalid_coupon)
{
if($(".coupon-error").length == 0)
$('.coupon-div').append('<p class="coupon-error text-center" style="color:red">Invalid coupon code</p>')
}
else{
$('#payment-modal').modal('hide');
alert('Something Went Wrong!')
}
}
}
);
})
Thanks for any help or point in the right direction! I've been trying to solve this for hours!

Related

Call Restlet from User Event Script Error INVALID_LOGIN_ATTEMPT

I am trying to access Restlet from User Event script but i am receiving error: body":"error code: INVALID_LOGIN_ATTEMPT\nerror message: Invalid login attempt. Do i need to pass credentials too? what should i pass client id, client secret? is there another way?
I also tried url.resolveScript but no luck.
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope Public
*/
define(["N/https", "N/log", "N/record", "N/url" ],
function(https, log, record, url) {
function beforeLoad(context) {
// log.debug('beforeLoad Triggered');
// context.newRecord;
// context.type;
// context.form;
return;
}
function afterSubmit(context) {
log.debug('Before code');
var record = context.newRecord;
var requestBody = {
"recordId": record.id,
"recordType": record.type,
};
var output = url.resolveScript({
scriptId: '1157',
deploymentId: '1',
});
var output1 = 'https://12345-sb5.restlets.api.netsuite.com';
log.debug('After code', output );
var response = https.post({
url: output1 + output,
body: requestBody,
});
if (response.code === 200) {
// success!
} else {
// handle error
}
log.debug('After code', response );
return;
}
function beforeSubmit(context) {
// log.debug('beforeSubmit Triggered');
// context.newRecord;
// context.oldRecord;
// context.type;
return;
}
return {
beforeLoad : beforeLoad,
afterSubmit : afterSubmit,
beforeSubmit : beforeSubmit
}
})
Why do you need your UE Script to submit and trigger your RESTlet every record submit?
Below could work for ClientScript, just not sure if saveRecord (only when the Submit/Save is clicked) entry point will trigger this.
var requestBody = JSON.stringify({
recordId: record.id,
recordType: record.type
});
var output = url.resolveScript({
scriptId: '1157',
deploymentId: '1'
});
var response = https.post({
url: output,
body: requestBody
});
Previously you could manipulate the cookies and pass it. However, it's no longer the case and Server Scripts cannot call Server Scripts unless you pass Authentication which is a pain if you have no library. Oauth1 + SHA256 is complicated to figure out without libraries.
You could probably approach this on another angle depending on your use case. At this moment, it isn't clear why you want AfterSubmit to call RESTlet. If you do this, if you have routine Scheduled Scripts that touches that record and saves the record, it will keep triggering your AfterSubmit unless you place an if statement.
try https.requestRestlet
var response = https.requestRestlet({
body: JSON.stringify({
"recordId": record.id,
"recordType": record.type,
}),
deploymentId: '1',
method: 'POST',
scriptId: 1157,
});

Not able to figure out the way to call a function at the correct place in django website

I am working on a django website and have come across an error which I am not able to solve and Its been a couple of days but I wasnt able to solve the error. I am trying to integrate a payment gateway to my site. I have a payment button which on click is supposed to post the data to the database as well as go to the payment site. But it is storing the data but not going to payment site.
Here is the javascript for my button:
document.getElementById('payment-info').addEventListener('click', function (e) {
submitFormData()
})
function submitFormData() {
console.log('Payment Button Clicked')
var userFormData = {
'name': null,
}
var shippingInfo = {
'address': null,
}
shippingInfo.address = form.address.value
userFormData.name=form.name.value
var url = "/process_order/"
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
body:JSON.stringify({'form': userFormData, 'shipping': shippingInfo }),
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
alert('Transaction Completed')
window.location.href = "{% url 'index' %}"
})
}
</script>
This is my views.py:
def processOrder(request):
transaction_id = datetime.datetime.now().timestamp()
data = json.loads(request.body)
if request.user.is_authenticated:
customer=request.user.customer
order, created=Order.objects.get_or_create(customer=customer, complete=False)
total=float(data['form']['total'])
order.transaction_id=transaction_id
if total == order.get_cart_total:
order.complete = True
order.save()
ShippingAddress.objects.create(
customer=customer,
order=order,
address=data['shipping']['address'],
name=data['form']['name'],
)
//Code for integration below
param_dict = {
'MID': 'DIY12386817555501617',
'ORDER_ID': str(order.id),
'TXN_AMOUNT': '4',
'CUST_ID': 'j',
'INDUSTRY_TYPE_ID': 'Retail',
'WEBSITE': 'WEBSTAGING',
'CHANNEL_ID': 'WEB',
'CALLBACK_URL':'http://127.0.0.1:8000/handlerequest/',
}
param_dict['CHECKSUMHASH'] = Checksum.generate_checksum(param_dict, MERCHANT_KEY)
return render(request, 'paytm.html', {'param_dict': param_dict})
return JsonResponse('Done',safe=False)
#csrf_exempt
def handlerequest(request):
# paytm will send you post request here
form = request.POST
response_dict = {}
for i in form.keys():
response_dict[i] = form[i]
if i == 'CHECKSUMHASH':
checksum = form[i]
verify = Checksum.verify_checksum(response_dict, MERCHANT_KEY, checksum)
if verify:
if response_dict['RESPCODE'] == '01':
print('order successful')
else:
print('order was not successful because' + response_dict['RESPMSG'])
return HttpResponse('doneee')
And this is my urls.py:
path("process_order/",views.processOrder,name="process_order"),
path("handlerequest/",views.handlerequest,name="handlerequest"),
This code is not working . After clicking the payment button I am getting this error:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
This error is referring to the submitformdata() in my javascript code.
I want to workout a way so that once a person clicks on the payment button and his transaction is completed then his data is submitted to the database otherwise not for which I have written the code in handlerequest.
Please help me out.

How to wait for promise to complete with returned value using angularjs

I’m having an issue with my project. In my angularjs controller a function is being executed and then my function to make a call to my database to update a record is executing without waiting for the first function to complete and therefore sending over an undefined result variable.
Below you can find my code snippets with my attempts so far.
Submit button function:
$scope.submitNewStarters = function () {
// result is returning as undefined <<<<< Issue
var result = $scope.sendNewStarterDetailsToApi();
$scope.updateArchivedImportFlag(result);
};
Controller function handling the logic:
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport).then(function (response) {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
});
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return newStartsToImport;
}
else
toastr.info("No new starter details were sent to API", "Information!");
});
};
Factory function for API call:
postNewStarterDetailsToApi: function (data) {
return $http({
url: "https://www.example.com/services/service.svc/Import",
method: "POST",
data: data,
headers: {
'Content-Type': 'application/json; charset=utf-8',
}
}).then(function successCallbwack(response) {
// this callback will be called asynchronously
// when the response is available
return response;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log('An error has occured during the function call postNewStarterDetailsToApi(): ', response);
});
}
So with the concept of promises how am I able to execute the sendNewStarterDetailsToApi function, wait for it to complete and then return the populated array? Once the populated array (result) is returned then execute the updateArchivedImportFlag function.
Below I've added an illustration of what I'd like to achieve:
The approach I am using is , save all the promises in an array .
Use any promise library or es6 Promise, and use .all function to wait for all promises to execute
The syntax i wrote is not totally correct. Since you are using angular js , you can use $q.all
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
var res = [];
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
res.push(apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport))
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return Promise.all(res);
}
else
toastr.info("No new starter details were sent to API", "Information!");
}).then(function (data) {
data.forEach((response) => {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
})
}).then((res) => {
//call Submit new starters
})
};

Get parameters and store and use them on variables to use on my method

I want to get some parameters and use them to reset password function from firebase.
This is how my link looks like:
http://localhost:8080/passwordreset?mode=resetPassword&oobCode=y6FIOAtRUKYf88Rt5OlEwxUuTyEmb3M4gquZSIseX2UAAAFevpj-gw&apiKey=AIzaSyBaCCvq-ZEfQmdrL7fmElXDjZF_J-tku2I
I want to get mode, oobCode and apiKey.
Here is what I have for now:
export default {
data: function() {
return {
passwordNew: '',
passwordConfirm: '',
mode:'',
actionCode: '',
continueUrl: '',
}
},
methods: {
handleResetPassword: function() {
var accountEmail;
firebase.auth().verifyPasswordResetCode(actionCode).then(function(email) {
var accountEmail = email;
firebase.auth().confirmPasswordReset(this.actionCode, this.passwordNew).then(function(resp) {
alert("Password reset success");
this.$router.push('hello')
}).catch(function(error) {
// Error occurred during confirmation. The code might have expired or the
// password is too weak.
console.log("error 1")
});
}).catch(function(error) {
// Invalid or expired action code. Ask user to try to reset the password
// again.
console.log("error 2")
});
},
}
}
From Firebase documentation:
Some user management actions, such as updating a user's email address
and resetting a user's password, result in emails being sent to the
user. These emails contain links that recipients can open to complete
or cancel the user management action. By default, user management
emails link to the default action handler, which is a web page hosted
at a URL in your project's Firebase Hosting domain.
link: https://firebase.google.com/docs/auth/custom-email-handler
You need to get those parameters and store them on variables, from firebase documentation i got those snippets and just wrote the getParameterByName function:
function getParameterByName( name ){
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
// Get the action to complete.
var mode = getParameterByName('mode');
// Get the one-time code from the query parameter.
var actionCode = getParameterByName('oobCode');
// (Optional) Get the continue URL from the query parameter if available.
var continueUrl = getParameterByName('continueUrl');
You need to get those parameters first and verify the actioncode on the verifyPasswordResetCode method, then you can change the password and store it along with the action code to the method.
In your export default :
data: function() {
return {
passwordNew: '',
passwordConfirm: '',
mode: mode,
actionCode: actionCode,
continueUrl: continueUrl,
}
},
methods: {
handleResetPassword: function() {
var passwordNew = this.passwordNew
var actionCode = this.actionCode
firebase.auth().verifyPasswordResetCode(actionCode).then(function(email) {
console.log("ActionCode: "+ actionCode);
firebase.auth().confirmPasswordReset(actionCode, passwordNew).then(function(resp) {
alert("Password reset success");
this.$router.push('hello')
}).catch(function(error) {
console.log("error 1"+ error)
});
}).catch(function(error) {
console.log("Action code is invalid"+ error)
});
},
}

flask-security ajax logout causes session errors

When I post to a flask endpoint:
#app.route('/api/v1/logout', methods=['POST','GET'])
def logout():
logout_user()
return jsonify(status=200, message='User has been successfully logged out.')
I get an error when I try to log in the next time
InvalidRequestError: Object '<User at 0x7f09b4831c90>' is already attached to session '1' (this is '4')
I was wondering how to logout and in safely using ajax.
Edit- angularjs login controller:
LoginController: function ($scope, $http, authService, $location) {
$scope.submit = function() {
console.log('in logincontroller')
$http.defaults.headers.post['X-CSRFToken'] = csrf_token;
$http.defaults.headers.common['Content-Type'] = 'application/json'
//debugger;
$http.post(
'/login',
JSON.stringify({ email: $scope.email, password: $scope.password })
).success(
function(data) {
if (data.meta){
var status_code = data.meta.code;
}
else{
var status_code = data.status;
}
if (status_code == 200){
$.cookie('email', $scope.email, { expires: 7 });
$.cookie('auth_token', data.authentication_token, { expires: 7 });
$http.defaults.headers.common['Authentication-Token'] = data.authentication_token;
authService.loginConfirmed();
$location.path("/dashboard");
}
else{
//form stuff
}
}
).error(
function(data) {
alert('LoginController submit error');
$scope.errorMsg = data.reason;
//debugger;
}
);
};
}
I guess You have to redirect at the end to get out of the existing session
#app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
You are doing it very wrong.
Since you didn't provide your login method, I guess from the error log that you were storing a User model in the session. This is totally wrong.
My suggestion is that you store your user's id in the session. e.g.
def login_user(user):
session['user_id'] = user.id
If you need to know the current user:
def get_current_user():
return User.get(session['user_id'])
Ask the right question, so that people can help you.

Categories

Resources