summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/payment/models/payment_acquirer.py19
-rw-r--r--addons/payment/static/src/js/payment_form.js261
-rw-r--r--addons/payment/static/src/less/payment_form.less32
-rw-r--r--addons/payment/views/payment_assets.xml2
-rw-r--r--addons/payment/views/payment_templates.xml102
-rw-r--r--addons/payment_authorize/controllers/main.py26
-rw-r--r--addons/payment_authorize/models/authorize_request.py27
-rw-r--r--addons/payment_authorize/models/payment.py39
-rw-r--r--addons/payment_authorize/views/payment_authorize_templates.xml54
-rw-r--r--addons/payment_ogone/controllers/main.py34
-rw-r--r--addons/payment_ogone/models/payment.py10
-rw-r--r--addons/payment_ogone/views/payment_ogone_templates.xml53
-rw-r--r--addons/payment_stripe/controllers/main.py26
-rw-r--r--addons/payment_stripe/models/payment.py47
-rw-r--r--addons/payment_stripe/views/payment_stripe_templates.xml53
-rw-r--r--addons/website_payment/controllers/main.py31
-rw-r--r--addons/website_payment/static/src/css/website_payment.css2
-rw-r--r--addons/website_payment/static/src/css/website_payment.sass2
-rw-r--r--addons/website_payment/static/src/js/payment_acquirer.js55
-rw-r--r--addons/website_payment/views/website_payment_templates.xml43
20 files changed, 639 insertions, 279 deletions
diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py
index 80c84094c30..623676c7a9c 100644
--- a/addons/payment/models/payment_acquirer.py
+++ b/addons/payment/models/payment_acquirer.py
@@ -786,7 +786,7 @@ class PaymentToken(models.Model):
return False
reference = "VALIDATION-%s-%s" % (self.id, datetime.datetime.now().strftime('%y%m%d_%H%M%S'))
- tx = self.env['payment.transaction'].create({
+ tx = self.env['payment.transaction'].sudo().create({
'amount': amount,
'acquirer_id': self.acquirer_id.id,
'type': 'validation',
@@ -816,6 +816,17 @@ class PaymentToken(models.Model):
token.short_name = token.name.replace('XXXXXXXXXXXX', '***')
@api.multi
- def _get_linked_records(self):
- """ Returns the list of records currently using the records in self as payment token. """
- return {} \ No newline at end of file
+ def get_linked_records(self):
+ """ This method returns a dict containing all the records linked to the payment.token (e.g Subscriptions),
+ the key is the id of the payment.token and the value is an array that must follow the scheme below.
+
+ {
+ token_id: [
+ 'description': The model description (e.g 'Sale Subscription'),
+ 'id': The id of the record,
+ 'name': The name of the record,
+ 'url': The url to access to this record.
+ ]
+ }
+ """
+ return {r.id:[] for r in self}
diff --git a/addons/payment/static/src/js/payment_form.js b/addons/payment/static/src/js/payment_form.js
new file mode 100644
index 00000000000..ae2d44c1cb7
--- /dev/null
+++ b/addons/payment/static/src/js/payment_form.js
@@ -0,0 +1,261 @@
+odoo.define('payment.payment_form', function (require){
+ "use strict";
+
+ var ajax = require('web.ajax');
+ var core = require('web.core');
+ var Dialog = require("web.Dialog");
+ var Widget = require("web.Widget");
+ var rpc = require("web.rpc");
+ var _t = core._t;
+
+ var PaymentForm = Widget.extend({
+
+ events: {
+ 'click #o_payment_form_pay': 'payEvent',
+ 'click #o_payment_form_add_pm': 'addPmEvent',
+ 'click button[name="delete_pm"]': 'deletePmEvent',
+ 'click input[type="radio"]': 'radioClickEvent'
+ },
+
+ payEvent: function(ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var form = this.el;
+ var checked_radio = this.$('input[type="radio"]:checked');
+ var self = this;
+ var button = ev.target;
+
+ // first we check that the user has selected a payment method
+ if(checked_radio.length == 1) {
+ checked_radio = checked_radio[0];
+ // if the user is adding a new payment
+ if(this.isNewPaymentRadio(checked_radio)) {
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
+ var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
+ // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
+ var form_data = this.getFormData($('input', acquirer_form));
+ var ds = $('input[name="data_set"]', acquirer_form)[0];
+ $(button).attr('disabled', true);
+ $(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');
+
+ var verify_validity = this.$el.find('input[name="verify_validity"]');
+
+ if(verify_validity.length>0)
+ form_data.verify_validity = verify_validity[0].value === "1";
+
+ // do the call to the route stored in the 'data_set' input of the acquirer form, the data must be called 'create-route'
+ ajax.jsonRpc(ds.dataset.createRoute, 'call', form_data).then(function(data) {
+ // if the server has returned true
+ if(data.result) {
+ // and it need a 3DS authentication
+ if(data['3d_secure'] !== false) {
+ // then we display the 3DS page to the user
+ $("body").html(data['3d_secure']);
+ }
+ else {
+ checked_radio.value = data.id; // set the radio value to the new card id
+ form.submit();
+ }
+ }
+ // if the server has returned false, we display an error
+ else {
+ self.error(_t('Error'),
+ _t("<p>We are not able to add your payment method at the moment.</p>"));
+ }
+ // here we remove the 'processing' icon from the 'add a new payment' button
+ $(button).attr('disabled', false);
+ $(button).find('span.o_loader').remove();
+ }).fail(function(message, data) {
+ // if the rpc fails, pretty obvious
+ $(button).attr('disabled', false);
+ $(button).find('span.o_loader').remove();
+
+ self.error(_t('Error'),
+ _t("<p>We are not able to add your payment method at the moment.</p>") + (core.debug ? data.data.message : ''));
+ });
+ }
+ // if the user is using an old payment
+ else {
+ // then we just submit the form
+ form.submit();
+ }
+ }
+ else {
+ this.error(_t('Error'),
+ _t('<p>Please select a payment method</p>'));
+ }
+ },
+ // event handler when clicking on the button to add a new payment method
+ addPmEvent: function(ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var form = this.el;
+ var checked_radio = this.$('input[type="radio"]:checked');
+ var self = this;
+ var button = ev.target;
+
+ // we check if the user has selected a 'add a new payment' option
+ if(checked_radio.length == 1 && this.isNewPaymentRadio(checked_radio[0])) {
+ // then we add a 'processing' icon into the 'add a new payment' button
+ $(button).attr('disabled', true);
+ $(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');
+ // we retrieve which acquirer is used
+ checked_radio = checked_radio[0];
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
+ var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
+ // we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
+ var form_data = this.getFormData($('input', acquirer_form));
+ var ds = $('input[name="data_set"]', acquirer_form)[0];
+
+ // we force the check when adding a card trough here
+ form_data.verify_validity = true;
+
+ // do the call to the route stored in the 'data_set' input of the acquirer form, the data must be called 'create-route'
+ ajax.jsonRpc(ds.dataset.createRoute, 'call', form_data).then(function(data) {
+ // if the server has returned true
+ if(data.result) {
+ // and it need a 3DS authentication
+ if(data['3d_secure'] !== false) {
+ // then we display the 3DS page to the user
+ $("body").html(data['3d_secure']);
+ }
+ // if it doesn't require 3DS
+ else {
+ // we just go to the return_url or reload the page
+ if(form_data.return_url) {
+ window.location = form_data.return_url;
+ }
+ else {
+ window.location.reload();
+ }
+ }
+ }
+ // if the server has returned false, we display an error
+ else {
+ self.error(_t('Error'),
+ _t("<p>We are not able to add your payment method at the moment.</p>"));
+ }
+ // here we remove the 'processing' icon from the 'add a new payment' button
+ $(button).attr('disabled', false);
+ $(button).find('span.o_loader').remove();
+ }).fail(function(message, data) {
+ // if the rpc fails, pretty obvious
+ $(button).attr('disabled', false);
+ $(button).find('span.o_loader').remove();
+
+ self.error(_t('Error'),
+ _t("<p>We are not able to add your payment method at the moment.</p>") + (core.debug ? data.data.message : ''));
+ });
+ }
+ else {
+ this.error(_t('Error'),
+ _t('<p>Please select the option to add a new payment method</p>'));
+ }
+ },
+ // event handler when clicking on a button to delete a payment method
+ deletePmEvent: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var self = this;
+ var pm_id = parseInt(ev.target.value);
+
+ var Delete = function() {
+ rpc.query({
+ model: 'payment.token',
+ method: 'unlink',
+ args: [pm_id],
+ })
+ .then(function(result){
+ if(result === true) {
+ ev.target.closest('div').remove();
+ }
+ },function(type,err){
+ self.error(_t('Error'),
+ _t("<p>We are not able to delete your payment method at the moment.</p>"));
+ });
+ };
+
+ rpc.query({
+ model: 'payment.token',
+ method: 'get_linked_records',
+ args: [pm_id],
+ }).then(function(result){
+ if(result[pm_id].length > 0) {
+ // if there's records linked to this payment method
+ var content = '';
+ result[pm_id].forEach(function(sub) {
+ content += '<p><a href="' + sub.url + '" title="' + _.str.escapeHTML(sub.description) + '">' + _.str.escapeHTML(sub.name) + '</a><p/>';
+ });
+
+ content = $('<div>').html(_t('<p>This card is currently linked to the following records:<p/>') + content);
+ // Then we display the list of the records and ask the user if he really want to remove the ppayment method.
+ new Dialog(self, {
+ title: _t('Warning!'),
+ size: 'medium',
+ $content: content,
+ buttons: [
+ {text: _t('Confirm Deletion'), classes: 'btn-primary', close: true, click: Delete},
+ {text: _t('Cancel'), close: true}]}).open();
+ }
+ else {
+ // if there's no records linked to this payment method, then we delete it
+ Delete();
+ }
+ }, function(type, err){
+ self.error(_t('Error'),
+ _t("<p>We are not able to delete your payment method at the moment.</p>") + (core.debug ? err.data.message : ''));
+ });
+ },
+ // event handler when clicking on a radio button
+ radioClickEvent: function(ev) {
+ this.updateNewPaymentDisplayStatus();
+ },
+ updateNewPaymentDisplayStatus: function()
+ {
+ var checked_radio = this.$('input[type="radio"]:checked');
+ // we hide all the acquirers form
+ this.$('[id*="o_payment_add_token_acq_"]').addClass('hidden');
+ // if we clicked on an add new payment radio
+ if(checked_radio.length == 1 && this.isNewPaymentRadio(checked_radio[0]))
+ {
+ // then we retrieve the acquirer name
+ var acquirer_id = this.getAcquirerIdFromRadio(checked_radio[0]);
+ // and display its form
+ this.$('#o_payment_add_token_acq_' + acquirer_id).removeClass('hidden');
+ }
+ },
+ isNewPaymentRadio: function(element) {
+ return $(element).data('acquirer-id') !== undefined;
+ },
+ getAcquirerIdFromRadio: function(element) {
+ return $(element).data('acquirer-id');
+ },
+ error: function(title, message, url) {
+ return new Dialog(null, {
+ title: title || "",
+ $content: $(core.qweb.render('website.error_dialog', {
+ message: message || "",
+ })),
+ }).open();
+ },
+ getFormData: function($form){
+ var unindexed_array = $form.serializeArray();
+ var indexed_array = {};
+
+ $.map(unindexed_array, function(n, i){
+ indexed_array[n.name] = n.value;
+ });
+ return indexed_array;
+ },
+ start: function() {
+ this.updateNewPaymentDisplayStatus();
+ },
+ });
+
+
+
+ $(document).ready(function (){
+ var form = new PaymentForm();
+ form.attachTo($('.o_payment_form'));
+ });
+});
diff --git a/addons/payment/static/src/less/payment_form.less b/addons/payment/static/src/less/payment_form.less
new file mode 100644
index 00000000000..ce6b2aeab6e
--- /dev/null
+++ b/addons/payment/static/src/less/payment_form.less
@@ -0,0 +1,32 @@
+.o_payment_form {
+ label > input[type="radio"]{
+ vertical-align: bottom;
+ margin-right: 5px;
+ }
+
+ label {
+ font-size: 14px;
+ font-weight: normal !important;
+ font-family: Helvetica Neue, sans-serif;
+ line-height: 1.3em;
+ color: #4d4d4d;
+ }
+
+ .panel-body:first-child {
+ border-top: 0px;
+ }
+
+ .panel {
+ border-radius: 10px;
+ }
+
+ .panel-footer:last-child {
+ border-bottom-right-radius: 10px !important;
+ border-bottom-left-radius: 10px !important;
+ }
+
+ .panel-body {
+ border-top: 1px solid #ddd;
+ padding: 1.14em !important;
+ }
+} \ No newline at end of file
diff --git a/addons/payment/views/payment_assets.xml b/addons/payment/views/payment_assets.xml
index 47d4717ef97..76f32ae1ed1 100644
--- a/addons/payment/views/payment_assets.xml
+++ b/addons/payment/views/payment_assets.xml
@@ -3,6 +3,8 @@
<template id="assets_frontend" inherit_id="web.assets_frontend" name="Payment Tx Assets">
<xpath expr="." position="inside">
<script type="text/javascript" src="/payment/static/src/js/payment_transaction.js"></script>
+ <script type="text/javascript" src="/payment/static/src/js/payment_form.js"></script>
+ <link rel="stylesheet" href="/payment/static/src/less/payment_form.less"/>
</xpath>
</template>
</odoo> \ No newline at end of file
diff --git a/addons/payment/views/payment_templates.xml b/addons/payment/views/payment_templates.xml
index abf18e0cf25..ae9a1501632 100644
--- a/addons/payment/views/payment_templates.xml
+++ b/addons/payment/views/payment_templates.xml
@@ -9,59 +9,71 @@
<template id="payment_tokens_list" name="Payment Tokens list">
<!--
Variables description:
- - 'payment' set this variable when you're doing a payment, this will allow to display the radio buttons for each tokens and show the submit button
- - 'show_delete' when you want to display the delete button for each token
- - 'show_radio' when you want to display the radio button for each token
- - 'show_submit' when you want to display the submit button at the bottom of the form
- 'submit_txt' the text displayed inside the submit button
- 'submit_class' the css classes to style the submit button
+ - 'icon_class' font awesome class (e.g. 'fa-trash', 'fa-lock')
- 'form_action' the URI to the page that will handle the form values
- 'pms' the tokens
- 'checked_pm_id' the payment token that should be checked (for radio buttons)
+ - 'mode' can take two values, either 'payment' or 'manage'. 'manage' displays the add a new card and delete buttons. 'payment'
+ display a form that is used to pay and send the information to the form action url.
+ - 'acquirers' the list of the acquirers
+ - 'verify_validity' if we need to verify if the payment method is valid when adding a new one
-->
- <form id="payment_tokens_list" method="post" t-att-action="form_action if form_action else '#'">
+ <form method="post" t-att-action="form_action if form_action else '#'" class="o_payment_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <table class="table table-hover table-striped table-condensed">
- <thead>
- <tr>
- <th>Payment Methods</th>
- <th t-if="show_verification_status">Status</th>
- <th t-if="show_delete"></th>
- </tr>
- </thead>
- <tbody>
- <t t-foreach="pms" t-as="pm">
- <tr>
- <td>
- <t t-if="show_radio or payment">
- <div class="radio">
- <label><input type="radio" name="pm_id" t-att-value="pm.id" t-att-checked="checked_pm_id == pm.id"/><t t-esc="pm.short_name"/></label>
- </div>
- </t>
- <t t-else="1">
- <p><t t-esc="pm.short_name"/></p>
- </t>
- </td>
- <td t-if="show_verification_status"><t t-esc="'Verified' if pm.verified else 'Not Verified'"/></td>
- <td t-if="show_delete"><button type="submit" name="delete_pm_id" t-att-value="pm.id" class="btn btn-xs btn-primary pull-right"><i class="fa fa-trash"> Delete</i></button></td>
- </tr>
+ <input type="hidden" t-if="verify_validity==True" name="verify_validity" value="1"/>
+ <div class="panel panel-default">
+ <t t-foreach="acquirers" t-as="acq">
+ <div class="panel-body">
+ <label>
+ <t t-if="mode == 'manage'">
+ <input type="radio" t-att-data-acquirer-id="acq.id" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(acquirers)==1) else ''" t-att-checked="len(acquirers) == 1"/>
+ </t>
+ <t t-else="">
+ <input type="radio" t-att-data-acquirer-id="acq.id" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(acquirers)==1 and len(pms)==0) else ''" t-att-checked="len(acquirers)==1 and len(pms)==0"/>
+ </t>
+ <t t-esc="acq.name"/>
+ </label>
+ </div>
+ <div t-attf-id="o_payment_add_token_acq_{{acq.id}}" t-attf-class="panel-footer {{'hidden' if (len(acquirers)&gt;1 and len(pms)==0 and acquirers[0]!=acq) else 'hidden' if len(pms)&gt;0 else ''}}">
+ <div class="clearfix">
+ <t t-raw="acq.form" t-att-data-acquirer-id="acquirer.id"/>
+ </div>
+ </div>
+ </t>
+ <t t-foreach="pms" t-as="pm">
+ <div class="panel-body">
+ <label>
+ <input t-if="mode == 'payment'" type="radio" name="pm_id" t-att-value="pm.id" t-att-checked="checked_pm_id == pm.id"/>
+ <t t-esc="pm.name"/>
+ <t t-if="pm.verified">
+ <i class="fa fa-check text-success" title="This payment method is verified by our system."></i>
+ </t>
+ <t t-else="">
+ <i class="fa fa-close text-danger" title="This payment method has not been verified by our system."></i>
+ </t>
+ </label>
+ <button t-if="mode == 'manage'" name="delete_pm" t-att-value="pm.id" class="btn btn-primary btn-xs pull-right">
+ <i class="fa fa-trash"></i> Delete
+ </button>
+ </div>
+ </t>
+ </div>
+ <div class="pull-right">
+ <button t-if="mode == 'payment'" id="o_payment_form_pay" type="submit" t-att-class="submit_class if submit_class else 'btn btn-primary btn-lg mb8 mt8'">
+ <t t-if="submit_txt">
+ <i t-if="icon_class" t-attf-class="fa {{icon_class}}"/>
+ <t t-esc="submit_txt"/>
</t>
- <tr t-if="(payment or show_submit) and not delete">
- <th t-if="show_verification_status"></th>
- <th t-if="show_delete"></th>
- <th>
- <button type="submit" t-att-class="submit_class if submit_class else 'btn btn-primary btn-sm mb8 mt8 pull-right'">
- <t t-if="submit_txt">
- <t t-raw="submit_txt"/>
- </t>
- <t t-else="1">
- <span class="fa fa-lock"></span> Pay
- </t>
- </button>
- </th>
- </tr>
- </tbody>
- </table>
+ <t t-else="">
+ <i class="fa fa-lock"> Pay</i>
+ </t>
+ </button>
+ <button t-if="mode == 'manage'" id="o_payment_form_add_pm" class="btn btn-primary btn-lg mb8 mt8">
+ <i class="fa fa-plus-circle"> Add new card</i>
+ </button>
+ </div>
</form>
</template>
</odoo>
diff --git a/addons/payment_authorize/controllers/main.py b/addons/payment_authorize/controllers/main.py
index b42efe817bb..6b0aae9bf6a 100644
--- a/addons/payment_authorize/controllers/main.py
+++ b/addons/payment_authorize/controllers/main.py
@@ -35,7 +35,31 @@ class AuthorizeController(http.Controller):
def authorize_s2s_create_json(self, **kwargs):
acquirer_id = int(kwargs.get('acquirer_id'))
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
- return acquirer.s2s_process(kwargs)
+ return acquirer.s2s_process(kwargs).id
+
+ @http.route(['/payment/authorize/s2s/create_json_3ds'], type='json', auth='public', csrf=False)
+ def authorize_s2s_create_json_3ds(self, verify_validity=False, **kwargs):
+ token = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
+
+ if not token:
+ res = {
+ 'result': False,
+ }
+ return res
+
+ res = {
+ 'result': True,
+ 'id': token.id,
+ 'short_name': token.short_name,
+ '3d_secure': False,
+ 'verified': False,
+ }
+
+ if verify_validity != False:
+ token.validate()
+ res['verified'] = token.verified
+
+ return res
@http.route(['/payment/authorize/s2s/create'], type='http', auth='public')
def authorize_s2s_create(self, **post):
diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py
index d8191dfc34c..fcfab1e3ac2 100644
--- a/addons/payment_authorize/models/authorize_request.py
+++ b/addons/payment_authorize/models/authorize_request.py
@@ -163,6 +163,33 @@ class AuthorizeAPI():
res['name'] = response_profile.find('paymentProfile/payment/creditCard/cardNumber').text
return res
+ def credit(self, token, amount, transaction_id):
+ """ Refund a payment for the given amount.
+
+ :param record token: the payment.token record that must be refunded.
+ :param str amount: transaction amount
+ :param str transaction_id: the reference of the transacation that is going to be refunded.
+
+ :return: a dict containing the response code, transaction id and transaction type
+ :rtype: dict
+ """
+ root = self._base_tree('createTransactionRequest')
+ tx = etree.SubElement(root, "transactionRequest")
+ etree.SubElement(tx, "transactionType").text = "refundTransaction"
+ etree.SubElement(tx, "amount").text = str(amount)
+ payment = etree.SubElement(tx, "payment")
+ credit_card = etree.SubElement(payment, "creditCard")
+ idx = token.name.find(' - ')
+ etree.SubElement(credit_card, "cardNumber").text = token.name[idx-4:idx] # shitty hack, but that's the only way to get the 4 last digits
+ etree.SubElement(credit_card, "expirationDate").text = "XXXX"
+ etree.SubElement(tx, "refTransId").text = transaction_id
+ response = self._authorize_request(root)
+ res = dict()
+ res['x_response_code'] = response.find('transactionResponse/responseCode').text
+ res['x_trans_id'] = transaction_id
+ res['x_type'] = 'refund'
+ return res
+
# Transaction management
def auth_and_capture(self, token, amount, reference):
"""Authorize and capture a payment for the given amount.
diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py
index 184f07cdc58..bfc5bfd569a 100644
--- a/addons/payment_authorize/models/payment.py
+++ b/addons/payment_authorize/models/payment.py
@@ -116,7 +116,7 @@ class PaymentAcquirerAuthorize(models.Model):
'partner_id': int(data.get('partner_id'))
}
PaymentMethod = self.env['payment.token'].sudo().create(values)
- return PaymentMethod.id
+ return PaymentMethod
@api.multi
def authorize_s2s_form_validate(self, data):
@@ -191,7 +191,7 @@ class TxAuthorize(models.Model):
@api.multi
def _authorize_form_validate(self, data):
- if self.state == 'done':
+ if self.state in ['done', 'refunded']:
_logger.warning('Authorize: trying to validate an already validated tx (ref %s)' % self.reference)
return True
status_code = int(data.get('x_response_code', '0'))
@@ -219,6 +219,9 @@ class TxAuthorize(models.Model):
'partner_id': self.partner_id.id,
})
self.payment_token_id = token_id
+
+ if self.payment_token_id:
+ self.payment_token_id.verified = True
return True
elif status_code == self._authorize_pending_tx_status:
self.write({
@@ -253,6 +256,17 @@ class TxAuthorize(models.Model):
return self._authorize_s2s_validate_tree(res)
@api.multi
+ def authorize_s2s_do_refund(self):
+ self.ensure_one()
+ transaction = AuthorizeAPI(self.acquirer_id)
+ self.state = 'refunding'
+ if self.type == 'validation':
+ res = transaction.void(self.acquirer_reference)
+ else:
+ res = transaction.credit(self.payment_token_id, self.amount, self.acquirer_reference)
+ return self._authorize_s2s_validate_tree(res)
+
+ @api.multi
def authorize_s2s_capture_transaction(self):
self.ensure_one()
transaction = AuthorizeAPI(self.acquirer_id)
@@ -272,8 +286,7 @@ class TxAuthorize(models.Model):
@api.multi
def _authorize_s2s_validate(self, tree):
- self.ensure_one()
- if self.state == 'done':
+ if self.state in ['done', 'refunded']:
_logger.warning('Authorize: trying to validate an already validated tx (ref %s)' % self.reference)
return True
status_code = int(tree.get('x_response_code', '0'))
@@ -287,6 +300,10 @@ class TxAuthorize(models.Model):
})
if init_state != 'authorized':
self.execute_callback()
+
+ if self.payment_token_id:
+ self.payment_token_id.verified = True
+
if tree.get('x_type').lower() == 'auth_only':
self.write({
'state': 'authorized',
@@ -294,13 +311,19 @@ class TxAuthorize(models.Model):
})
self.execute_callback()
if tree.get('x_type').lower() == 'void':
- self.write({
- 'state': 'cancel',
- })
+ if self.type == 'validation' and self.state == 'refunding':
+ self.write({
+ 'state': 'refunded',
+ })
+ else:
+ self.write({
+ 'state': 'cancel',
+ })
return True
elif status_code == self._authorize_pending_tx_status:
+ new_state = 'refunding' if self.state == 'refunding' else 'pending'
self.write({
- 'state': 'pending',
+ 'state': new_state,
'acquirer_reference': tree.get('x_trans_id'),
})
return True
diff --git a/addons/payment_authorize/views/payment_authorize_templates.xml b/addons/payment_authorize/views/payment_authorize_templates.xml
index abbbc80b93a..c4b91605a00 100644
--- a/addons/payment_authorize/views/payment_authorize_templates.xml
+++ b/addons/payment_authorize/views/payment_authorize_templates.xml
@@ -54,38 +54,28 @@
</template>
<template id="authorize_s2s_form">
- <form method="post" t-att-action="'/payment/authorize/s2s/create' if not json else '/payment/authorize/s2s/create_json'">
- <div t-att-class="'row' if bootstrap_formatting else ''">
- <div t-att-class="'form-group col-md-8' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_number">Card number</label>
- <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;"/>
- <div class="card_placeholder"></div>
- <div class="visa"></div>
- <input type="hidden" name="cc_brand" value=""/>
- </div>
- <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_cvc">CVC</label>
- <input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
- </div>
- <div t-att-class="'form-group col-md-7' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_holder_name">Name</label>
- <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control"/>
- </div>
- <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_expires_mm">Expires</label>
- <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
- </div>
- <input type="hidden" name="acquirer_id" t-att-value="id"/>
- <input class="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
- <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
- <div class="clearfix"/>
+ <input type="hidden" name="data_set" data-create-route="/payment/authorize/s2s/create_json_3ds"/>
+ <div class="mt8">
+ <div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
+ <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
+ <div class="card_placeholder"></div>
+ <div class="visa"></div>
+ <input type="hidden" name="cc_brand" value=""/>
</div>
- <button t-att-class="submit_class" class="btn btn-primary" type="submit">
- <span t-if="not submit_txt">Confirm <span class="fa fa-long-arrow-right"></span></span>
- <span t-if="submit_txt"><t t-esc="submit_txt"/></span>
- </button>
- </form>
- </template>
+ <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
+ </div>
+ <div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
+ </div>
+ <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
+ </div>
+ </div>
+ <input type="hidden" name="acquirer_id" t-att-value="id"/>
+ <input class="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
+ <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
+ <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
+ </template>
</data>
</odoo>
diff --git a/addons/payment_ogone/controllers/main.py b/addons/payment_ogone/controllers/main.py
index 503f1de1419..9c81761a70e 100644
--- a/addons/payment_ogone/controllers/main.py
+++ b/addons/payment_ogone/controllers/main.py
@@ -33,6 +33,40 @@ class OgoneController(http.Controller):
new_id = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
return new_id.id
+ @http.route(['/payment/ogone/s2s/create_json_3ds'], type='json', auth='public', csrf=False)
+ def ogone_s2s_create_json_3ds(self, verify_validity=False, **kwargs):
+ token = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
+
+ if not token:
+ res = {
+ 'result': False,
+ }
+ return res
+
+ res = {
+ 'result': True,
+ 'id': token.id,
+ 'short_name': token.short_name,
+ '3d_secure': False,
+ 'verified': False,
+ }
+
+ if verify_validity != False:
+ baseurl = request.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ params = {
+ 'accept_url': baseurl + '/payment/ogone/validate/accept',
+ 'decline_url': baseurl + '/payment/ogone/validate/decline',
+ 'exception_url': baseurl + '/payment/ogone/validate/exception',
+ 'return_url': kwargs.get('return_url', baseurl)
+ }
+ tx = token.validate(**params)
+ res['verified'] = token.verified
+
+ if tx and tx.html_3ds:
+ res['3d_secure'] = tx.html_3ds
+
+ return res
+
@http.route(['/payment/ogone/s2s/create'], type='http', auth='public', methods=["POST"], csrf=False)
def ogone_s2s_create(self, **post):
error = ''
diff --git a/addons/payment_ogone/models/payment.py b/addons/payment_ogone/models/payment.py
index 0702d38c8bb..9ac90f9478f 100644
--- a/addons/payment_ogone/models/payment.py
+++ b/addons/payment_ogone/models/payment.py
@@ -302,10 +302,11 @@ class PaymentTxOgone(models.Model):
})
vals.update(payment_token_id=pm.id)
self.write(vals)
- self.payment_token_id.verified = True
+ if self.payment_token_id:
+ self.payment_token_id.verified = True
self.execute_callback()
# if this transaction is a validation one, then we refund the money we just withdrawn
- if self.type == 'verification':
+ if self.type == 'validation':
self.s2s_do_refund()
return True
@@ -454,7 +455,8 @@ class PaymentTxOgone(models.Model):
'name': tree.get('CARDNO'),
})
self.write({'payment_token_id': pm.id})
- self.payment_token_id.verified = True
+ if self.payment_token_id:
+ self.payment_token_id.verified = True
self.execute_callback()
return True
elif status in self._ogone_cancel_tx_status:
@@ -463,7 +465,7 @@ class PaymentTxOgone(models.Model):
'acquirer_reference': tree.get('PAYID'),
})
elif status in self._ogone_pending_tx_status:
- new_state = 'refunding' if self.type == 'validation' else 'pending'
+ new_state = 'refunding' if self.state == 'refunding' else 'pending'
self.write({
'state': new_state,
'acquirer_reference': tree.get('PAYID'),
diff --git a/addons/payment_ogone/views/payment_ogone_templates.xml b/addons/payment_ogone/views/payment_ogone_templates.xml
index 63b4af07142..c70d461d0a7 100644
--- a/addons/payment_ogone/views/payment_ogone_templates.xml
+++ b/addons/payment_ogone/views/payment_ogone_templates.xml
@@ -54,40 +54,27 @@
</template>
<template id="ogone_s2s_form">
- <form method="post" t-att-action="'/payment/ogone/s2s/create' if not json else '/payment/ogone/s2s/create_json'">
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <input t-if="verify_validity==True" type="hidden" name="verify_validity" value="1"/>
- <div t-att-class="'row' if bootstrap_formatting else None">
- <div t-att-class="'form-group col-md-8' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_number">Card number</label>
- <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;"/>
- <div class="card_placeholder"></div>
- <div class="visa"></div>
- <input type="hidden" name="cc_brand" value=""/>
- </div>
- <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_cvc">CVC</label>
- <input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
- </div>
- <div t-att-class="'form-group col-md-7' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_holder_name">Name</label>
- <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control"/>
- </div>
- <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_expires_mm">Expires</label>
- <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
- </div>
- <input type="hidden" name="acquirer_id" t-att-value="id"/>
- <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
- <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
- <div class="clearfix"/>
+ <input type="hidden" name="data_set" data-create-route="/payment/ogone/s2s/create_json_3ds"/>
+ <input type="hidden" name="acquirer_id" t-att-value="id"/>
+ <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
+ <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
+ <div class="mt8">
+ <div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
+ <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
+ <div class="card_placeholder"></div>
+ <div class="visa"></div>
+ <input type="hidden" name="cc_brand" value=""/>
</div>
- <button t-att-class="submit_class" class="btn btn-primary" type="submit">
- <span t-if="not submit_txt">Confirm <span class="fa fa-long-arrow-right"></span></span>
- <span t-if="submit_txt"><t t-esc="submit_txt"/></span>
- </button>
- </form>
+ <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
+ </div>
+ <div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
+ </div>
+ <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
+ </div>
+ </div>
</template>
-
</data>
</odoo>
diff --git a/addons/payment_stripe/controllers/main.py b/addons/payment_stripe/controllers/main.py
index b4627157a9e..55cad84fd9d 100644
--- a/addons/payment_stripe/controllers/main.py
+++ b/addons/payment_stripe/controllers/main.py
@@ -15,7 +15,7 @@ class StripeController(http.Controller):
def stripe_s2s_create_json(self, **kwargs):
acquirer_id = int(kwargs.get('acquirer_id'))
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
- return acquirer.s2s_process(kwargs)
+ return acquirer.s2s_process(kwargs).id
@http.route(['/payment/stripe/s2s/create'], type='http', auth='public')
def stripe_s2s_create(self, **post):
@@ -24,6 +24,30 @@ class StripeController(http.Controller):
acquirer.s2s_process(post)
return werkzeug.utils.redirect(post.get('return_url', '/'))
+ @http.route(['/payment/stripe/s2s/create_json_3ds'], type='json', auth='public', csrf=False)
+ def stripe_s2s_create_json_3ds(self, verify_validity=False, **kwargs):
+ token = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
+
+ if not token:
+ res = {
+ 'result': False,
+ }
+ return res
+
+ res = {
+ 'result': True,
+ 'id': token.id,
+ 'short_name': token.short_name,
+ '3d_secure': False,
+ 'verified': False,
+ }
+
+ if verify_validity != False:
+ token.validate()
+ res['verified'] = token.verified
+
+ return res
+
@http.route(['/payment/stripe/create_charge'], type='json', auth='public')
def stripe_create_charge(self, **post):
""" Create a payment transaction
diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py
index e43e0cbd71f..1bb4ea9aad8 100644
--- a/addons/payment_stripe/models/payment.py
+++ b/addons/payment_stripe/models/payment.py
@@ -71,7 +71,7 @@ class PaymentAcquirerStripe(models.Model):
'acquirer_id': int(data['acquirer_id']),
'partner_id': int(data['partner_id'])
})
- return payment_token.id
+ return payment_token
@api.multi
def stripe_s2s_form_validate(self, data):
@@ -83,6 +83,21 @@ class PaymentAcquirerStripe(models.Model):
return False
return True
+ def _get_feature_support(self):
+ """Get advanced feature support by provider.
+
+ Each provider should add its technical in the corresponding
+ key for the following features:
+ * fees: support payment fees computations
+ * authorize: support authorizing payment (separates
+ authorization and capture)
+ * tokenize: support saving payment data in a payment.tokenize
+ object
+ """
+ res = super(PaymentAcquirerStripe, self)._get_feature_support()
+ res['tokenize'].append('stripe')
+ return res
+
class PaymentTransactionStripe(models.Model):
_inherit = 'payment.transaction'
@@ -112,6 +127,29 @@ class PaymentTransactionStripe(models.Model):
result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref)
return self._stripe_s2s_validate_tree(result)
+
+ def _create_stripe_refund(self):
+ api_url_refund = 'https://%s/refunds' % (self.acquirer_id._get_stripe_api_url())
+
+ refund_params = {
+ 'charge': self.acquirer_reference,
+ 'amount': int(self.amount*100), # by default, stripe refund the full amount (we don't really need to specify the value)
+ 'metadata[reference]': self.reference,
+ }
+
+ r = requests.post(api_url_refund,
+ auth=(self.acquirer_id.stripe_secret_key, ''),
+ params=refund_params,
+ headers=STRIPE_HEADERS)
+ return r.json()
+
+ @api.multi
+ def stripe_s2s_do_refund(self, **kwargs):
+ self.ensure_one()
+ self.state = 'refunding'
+ result = self._create_stripe_refund()
+ return self._stripe_s2s_validate_tree(result)
+
@api.model
def _stripe_form_get_tx_from_data(self, data):
""" Given a data dict coming from stripe, verify it and find the related
@@ -135,18 +173,21 @@ class PaymentTransactionStripe(models.Model):
@api.multi
def _stripe_s2s_validate_tree(self, tree):
self.ensure_one()
- if self.state not in ('draft', 'pending'):
+ if self.state not in ('draft', 'pending', 'refunding'):
_logger.info('Stripe: trying to validate an already validated tx (ref %s)', self.reference)
return True
status = tree.get('status')
if status == 'succeeded':
+ new_state = 'refunded' if self.state == 'refunding' else 'done'
self.write({
- 'state': 'done',
+ 'state': new_state,
'date_validate': fields.datetime.now(),
'acquirer_reference': tree.get('id'),
})
self.execute_callback()
+ if self.payment_token_id:
+ self.payment_token_id.verified = True
return True
else:
error = tree['error']['message']
diff --git a/addons/payment_stripe/views/payment_stripe_templates.xml b/addons/payment_stripe/views/payment_stripe_templates.xml
index 9e8e28c4d07..8f7f8edd0eb 100644
--- a/addons/payment_stripe/views/payment_stripe_templates.xml
+++ b/addons/payment_stripe/views/payment_stripe_templates.xml
@@ -32,38 +32,29 @@
</template>
<template id="stripe_s2s_form">
- <form method="post" t-att-action="'/payment/stripe/s2s/create' if not json else '/payment/stripe/s2s/create_json'">
- <div t-att-class="'row' if bootstrap_formatting else None">
- <div t-att-class="'form-group col-md-8' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_number">Card Number</label>
- <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;&#8226;&#8226;&#8226;&#8226;&#32;"/>
- <div class="card_placeholder"></div>
- <div class="visa"></div>
- <input type="hidden" name="cc_brand" value=""/>
- </div>
- <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cvc">CVC</label>
- <input type="text" name="cvc" id="cvc" class="form-control" maxlength="4" placeholder="CVC"/>
- </div>
- <div t-att-class="'form-group col-md-7' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_holder_name">Card Holder Name</label>
- <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control"/>
- </div>
- <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
- <label class="control-label" for="cc_expires_mm">Expiration Date</label>
- <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
- </div>
- <input type="hidden" name="acquirer_id" t-att-value="id"/>
- <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
- <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <div class="clearfix"/>
+ <input type="hidden" name="data_set" data-create-route="/payment/stripe/s2s/create_json_3ds"/>
+ <div class="mt8">
+ <div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
+ <input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
+ <div class="card_placeholder"></div>
+ <div class="visa"></div>
+ <input type="hidden" name="cc_brand" value=""/>
</div>
- <button t-att-class="submit_class" class="btn btn-primary" type="submit">
- <span t-if="not submit_txt">Confirm <span class="fa fa-long-arrow-right"></span></span>
- <span t-if="submit_txt"><t t-esc="submit_txt"/></span>
- </button>
- </form>
+ <div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
+ </div>
+ <div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
+ </div>
+ <div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
+ <input type="text" name="cvc" id="cvc" class="form-control" maxlength="4" placeholder="CVC"/>
+ </div>
+ <input type="hidden" name="acquirer_id" t-att-value="id"/>
+ <input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
+ <input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
+ <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
+ <div class="clearfix"/>
+ </div>
</template>
<template id="payment_stripe_redirect" name="Payment Stripe">
diff --git a/addons/website_payment/controllers/main.py b/addons/website_payment/controllers/main.py
index f3548e9090f..2dad4025b47 100644
--- a/addons/website_payment/controllers/main.py
+++ b/addons/website_payment/controllers/main.py
@@ -18,16 +18,9 @@ class WebsitePayment(http.Controller):
}
return_url = request.params.get('redirect', '/my/payment_method')
for acquirer in acquirers:
- acquirer.form = acquirer.sudo()._registration_render(request.env.user.partner_id.id, {'error': {}, 'error_message': [], 'return_url': return_url, 'json': False, 'bootstrap_formatting': True, 'verify_validity': True})
+ acquirer.form = acquirer.sudo()._registration_render(request.env.user.partner_id.id, {'error': {}, 'error_message': [], 'return_url': return_url, 'json': False, 'bootstrap_formatting': True})
return request.render("website_payment.pay_methods", values)
- @http.route(['/website_payment/delete/'], methods=['POST'], type='http', auth="user", website=True)
- def delete(self, delete_pm_id=None):
- if delete_pm_id:
- pay_meth = request.env['payment.token'].browse(int(delete_pm_id))
- pay_meth.unlink()
- return request.redirect('/my/payment_method')
-
@http.route(['/website_payment/pay'], type='http', auth='public', website=True)
def pay(self, reference='', amount=False, currency_id=None, acquirer_id=None, **kw):
env = request.env
@@ -90,25 +83,3 @@ class WebsitePayment(http.Controller):
return request.render('website_payment.confirm', {'tx': tx, 'status': status, 'message': message})
else:
return request.redirect('/my/home')
-
- @http.route(['/website_payment/get_linked_records'], type='json', auth='user', website=True)
- def get_linked_records(self, payment_token_id):
- payment_token_id = int(payment_token_id)
-
- res = []
- token = request.env['payment.token'].search([('id','=',payment_token_id)])
- # if the payment token is valid
- if token:
- # then we retrieve the description for the model sale.subscription
- subscription_description = request.env['sale.subscription']._description
- # we retrieve all the linked records for the token
- records = token._get_linked_records()
- # transform the list of tuple into a dict so we can search easily
- records = dict(records[payment_token_id])
- # if there's subscriptions linked to that token
- if records.get(subscription_description):
- subscriptions = records[subscription_description]
- # we create our json with all the info needed
- for r in subscriptions:
- res.append({'id': r.id, 'name': r.name})
- return res \ No newline at end of file
diff --git a/addons/website_payment/static/src/css/website_payment.css b/addons/website_payment/static/src/css/website_payment.css
index 1892700fdd0..e9db1fd8d28 100644
--- a/addons/website_payment/static/src/css/website_payment.css
+++ b/addons/website_payment/static/src/css/website_payment.css
@@ -8,7 +8,7 @@ div.card_placeholder {
width: 32px;
height: 20px;
position: absolute;
- top: 34px;
+ top: 8px;
right: 20px;
-webkit-transition: 0.4s cubic-bezier(0.455, 0.03, 0.515, 0.955);
transition: 0.4s cubic-bezier(0.455, 0.03, 0.515, 0.955);
diff --git a/addons/website_payment/static/src/css/website_payment.sass b/addons/website_payment/static/src/css/website_payment.sass
index a396bae99c1..e7de8c55cd5 100644
--- a/addons/website_payment/static/src/css/website_payment.sass
+++ b/addons/website_payment/static/src/css/website_payment.sass
@@ -10,7 +10,7 @@ div.card_placeholder
width: 32px
height: 20px
position: absolute
- top: 34px
+ top: 8px
right: 20px
-webkit-transition: .4s cubic-bezier(0.455,0.03,0.515,0.955)
transition: .4s cubic-bezier(0.455,0.03,0.515,0.955)
diff --git a/addons/website_payment/static/src/js/payment_acquirer.js b/addons/website_payment/static/src/js/payment_acquirer.js
index e047694ac03..d7397f1b04d 100644
--- a/addons/website_payment/static/src/js/payment_acquirer.js
+++ b/addons/website_payment/static/src/js/payment_acquirer.js
@@ -60,58 +60,3 @@ $(document).ready(function () {
});
});
-
-
-odoo.define('website_payment.payment_acquirer', function (require) {
-"use strict";
-
-var website = require('website.website');
-var ajax = require('web.ajax');
-var Dialog = require('web.Dialog');
-
- var payment_methods = $('#payment_tokens_list');
-
- payment_methods.find('button[name="delete_pm_id"]').on('click', function(ev){
- ev.stopPropagation();
- ev.preventDefault();
- var self = this;
-
- // we retrieve the selected payment method id
- var payment_method_id = ev.target.value;
-
- var Delete = function()
- {
- payment_methods.find('button[name="delete_pm_id"]').off("click");
- ev.target.click();
- };
-
- ajax.jsonRpc('/website_payment/get_linked_records', 'call', {
- 'payment_token_id': payment_method_id,
- }).done(function (response) {
- // if there's records linked to the payment method we're trying to delete
- if(response.length > 0)
- {
- var content = '';
-
- response.forEach(function(sub) {
- content += '<p><a href="/my/subscription/' + sub.id + '">' + sub.name + '</a><p/>';
- });
-
- content = $('<div>').html('<p>This card is currently linked to the following records:<p/>' + content);
- // Then we display the list of the records and ask the user if he really want to remove the ppayment method.
- new Dialog(self, {
- title: 'Warning!',
- size: 'medium',
- $content: content,
- buttons: [
- {text: 'Confirm Deletion', classes: 'btn-primary', close: true, click: Delete},
- {text: 'Cancel', close: true}]}).open();
- }
- // otherwise if the user has no records linked to this payment method, then we just delete it.
- else
- {
- Delete();
- }
- });
- });
-});
diff --git a/addons/website_payment/views/website_payment_templates.xml b/addons/website_payment/views/website_payment_templates.xml
index bdaff74d0c4..27a4cada196 100644
--- a/addons/website_payment/views/website_payment_templates.xml
+++ b/addons/website_payment/views/website_payment_templates.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
- <template id="header_footer_custom_payment" inherit_id="website.footer_default" customize_show="True" active="False" name="Payment Acquirers">
+ <template id="header_footer_custom_payment" inherit_id="website.footer_default" customize_show="True" active="False" name="Payment Methods">
<xpath expr="//div[@id='info']" position="inside">
<h4 class="payment_method_title">Payment Acquirer</h4>
<ul class="payment_method_list list-inline">
@@ -24,45 +24,28 @@
</xpath>
</template>
- <template id="pay_methods" name="Payment Acquirers">
+ <template id="pay_methods" name="Payment Methods">
<t t-call="website.layout">
- <t t-set="additional_title">Payment Acquirers</t>
+ <t t-set="additional_title">Payment Methods</t>
<div class="wrap">
<div class="container">
<div class="row">
<div class="col-sm-6">
<ol class="breadcrumb mt8">
<li><a href="/my/home"><i class="fa fa-home"/></a></li>
- <li>Payment Acquirers</li>
+ <li>Payment Methods</li>
</ol>
</div>
</div>
- <h1>Payment Acquirers</h1>
- <h4 t-if="acquirers">Add a new payment acquirer:</h4>
- <div t-if="acquirers" class="row">
- <div class="col-sm-8">
- <div t-if="error_message" class="alert alert-danger">
- <t t-foreach="error_message" t-as="err"><t t-esc="err"/><br /></t>
+ <div class="clearfix">
+ <div class="row">
+ <div class="col-sm-8">
+ <h3>Manage your Payment Methods</h3>
+ <t t-call="payment.payment_tokens_list">
+ <t t-set="mode" t-value="'manage'"/>
+ <t t-set="verify_validity" t-value="True"/>
+ </t>
</div>
- <div t-if='len(acquirers)&gt;1'>
- <label class="control-label" for="pm_acquirer_id">Acquirer</label>
- <select name="pm_acquirer_id" class="form-control">
- <t t-foreach="acquirers" t-as="acquirer">
- <option t-att-value="acquirer.id" t-esc="acquirer.name"/>
- </t>
- </select>
- </div>
- <t t-foreach="acquirers" t-as="acquirer">
- <div t-raw="acquirer.form" t-att-data-acquirer-id="acquirer.id" t-attf-class="acquirer #{'hidden' if acquirer!=acquirers[0] else ''}"/>
- </t>
- </div>
- </div>
- <div t-if="pms" class="clearfix">
- <h4>Your payment Methods</h4>
- <t t-set="show_delete" t-value="True"/>
- <t t-set="form_action" t-value="'/website_payment/delete/'"/>
- <div class="col-sm-8">
- <t t-call="payment.payment_tokens_list"/>
</div>
</div>
</div>
@@ -73,7 +56,7 @@
<template id="pay_meth_link" inherit_id="website_portal.portal_layout" customize_show="True">
<xpath expr="//div[@class='o_my_details']" position="inside">
<t t-if="request.env['payment.acquirer'].search([('website_published', '=', True), ('registration_view_template_id', '!=', False)])">
- <div class='manage_payment_method mt16'><a href="/my/payment_method">Manage your payment acquirers</a></div>
+ <div class='manage_payment_method mt16'><a href="/my/payment_method">Manage your Payment Methods</a></div>
</t>
</xpath>
</template>