diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/pos_mercury/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/pos_mercury/models')
| -rw-r--r-- | addons/pos_mercury/models/__init__.py | 5 | ||||
| -rw-r--r-- | addons/pos_mercury/models/pos_mercury.py | 78 | ||||
| -rw-r--r-- | addons/pos_mercury/models/pos_mercury_transaction.py | 123 |
3 files changed, 206 insertions, 0 deletions
diff --git a/addons/pos_mercury/models/__init__.py b/addons/pos_mercury/models/__init__.py new file mode 100644 index 00000000..3494c05b --- /dev/null +++ b/addons/pos_mercury/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import pos_mercury +from . import pos_mercury_transaction diff --git a/addons/pos_mercury/models/pos_mercury.py b/addons/pos_mercury/models/pos_mercury.py new file mode 100644 index 00000000..900e696f --- /dev/null +++ b/addons/pos_mercury/models/pos_mercury.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging + +from odoo import models, fields, api, _ +from odoo.tools.float_utils import float_compare + +_logger = logging.getLogger(__name__) + + +class BarcodeRule(models.Model): + _inherit = 'barcode.rule' + + type = fields.Selection(selection_add=[ + ('credit', 'Credit Card') + ], ondelete={'credit': 'set default'}) + + +class PosMercuryConfiguration(models.Model): + _name = 'pos_mercury.configuration' + _description = 'Point of Sale Vantiv Configuration' + + name = fields.Char(required=True, help='Name of this Vantiv configuration') + merchant_id = fields.Char(string='Merchant ID', required=True, help='ID of the merchant to authenticate him on the payment provider server') + merchant_pwd = fields.Char(string='Merchant Password', required=True, help='Password of the merchant to authenticate him on the payment provider server') + + +class PoSPayment(models.Model): + _inherit = "pos.payment" + + mercury_card_number = fields.Char(string='Card Number', help='The last 4 numbers of the card used to pay') + mercury_prefixed_card_number = fields.Char(string='Card Number Prefix', compute='_compute_prefixed_card_number', help='The card number used for the payment.') + mercury_card_brand = fields.Char(string='Card Brand', help='The brand of the payment card (e.g. Visa, AMEX, ...)') + mercury_card_owner_name = fields.Char(string='Card Owner Name', help='The name of the card owner') + mercury_ref_no = fields.Char(string='Vantiv reference number', help='Payment reference number from Vantiv Pay') + mercury_record_no = fields.Char(string='Vantiv record number', help='Payment record number from Vantiv Pay') + mercury_invoice_no = fields.Char(string='Vantiv invoice number', help='Invoice number from Vantiv Pay') + + def _compute_prefixed_card_number(self): + for line in self: + if line.mercury_card_number: + line.mercury_prefixed_card_number = "********" + line.mercury_card_number + else: + line.mercury_prefixed_card_number = "" + + +class PoSPaymentMethod(models.Model): + _inherit = 'pos.payment.method' + + pos_mercury_config_id = fields.Many2one('pos_mercury.configuration', string='Vantiv Credentials', help='The configuration of Vantiv used for this journal') + + def _get_payment_terminal_selection(self): + return super(PoSPaymentMethod, self)._get_payment_terminal_selection() + [('mercury', 'Vantiv')] + + @api.onchange('use_payment_terminal') + def _onchange_use_payment_terminal(self): + super(PoSPaymentMethod, self)._onchange_use_payment_terminal() + if self.use_payment_terminal != 'mercury': + self.pos_mercury_config_id = False + +class PosOrder(models.Model): + _inherit = "pos.order" + + @api.model + def _payment_fields(self, order, ui_paymentline): + fields = super(PosOrder, self)._payment_fields(order, ui_paymentline) + + fields.update({ + 'mercury_card_number': ui_paymentline.get('mercury_card_number'), + 'mercury_card_brand': ui_paymentline.get('mercury_card_brand'), + 'mercury_card_owner_name': ui_paymentline.get('mercury_card_owner_name'), + 'mercury_ref_no': ui_paymentline.get('mercury_ref_no'), + 'mercury_record_no': ui_paymentline.get('mercury_record_no'), + 'mercury_invoice_no': ui_paymentline.get('mercury_invoice_no') + }) + + return fields diff --git a/addons/pos_mercury/models/pos_mercury_transaction.py b/addons/pos_mercury/models/pos_mercury_transaction.py new file mode 100644 index 00000000..c30d0c64 --- /dev/null +++ b/addons/pos_mercury/models/pos_mercury_transaction.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from datetime import date, timedelta + +import requests +import werkzeug + +from odoo import models, api, service +from odoo.tools.translate import _ +from odoo.exceptions import UserError +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, misc + + +class MercuryTransaction(models.Model): + _name = 'pos_mercury.mercury_transaction' + _description = 'Point of Sale Vantiv Transaction' + + def _get_pos_session(self): + pos_session = self.env['pos.session'].search([('state', '=', 'opened'), ('user_id', '=', self.env.uid)], limit=1) + if not pos_session: + raise UserError(_("No opened point of sale session for user %s found.", self.env.user.name)) + + pos_session.login() + + return pos_session + + def _get_pos_mercury_config_id(self, config, payment_method_id): + payment_method = config.current_session_id.payment_method_ids.filtered(lambda pm: pm.id == payment_method_id) + + if payment_method and payment_method.pos_mercury_config_id: + return payment_method.pos_mercury_config_id + else: + raise UserError(_("No Vantiv configuration associated with the payment method.")) + + def _setup_request(self, data): + # todo: in master make the client include the pos.session id and use that + pos_session = self._get_pos_session() + + config = pos_session.config_id + pos_mercury_config = self._get_pos_mercury_config_id(config, data['payment_method_id']) + + data['operator_id'] = pos_session.user_id.login + data['merchant_id'] = pos_mercury_config.sudo().merchant_id + data['merchant_pwd'] = pos_mercury_config.sudo().merchant_pwd + data['memo'] = "Odoo " + service.common.exp_version()['server_version'] + + def _do_request(self, template, data): + xml_transaction = self.env.ref(template)._render(data).decode() + + if not data['merchant_id'] or not data['merchant_pwd']: + return "not setup" + + soap_header = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mer="http://www.mercurypay.com"><soapenv:Header/><soapenv:Body><mer:CreditTransaction><mer:tran>' + soap_footer = '</mer:tran><mer:pw>' + data['merchant_pwd'] + '</mer:pw></mer:CreditTransaction></soapenv:Body></soapenv:Envelope>' + xml_transaction = soap_header + misc.html_escape(xml_transaction) + soap_footer + + response = '' + + headers = { + 'Content-Type': 'text/xml', + 'SOAPAction': 'http://www.mercurypay.com/CreditTransaction', + } + + url = 'https://w1.mercurypay.com/ws/ws.asmx' + if self.env['ir.config_parameter'].sudo().get_param('pos_mercury.enable_test_env'): + url = 'https://w1.mercurycert.net/ws/ws.asmx' + + try: + r = requests.post(url, data=xml_transaction, headers=headers, timeout=65) + r.raise_for_status() + response = werkzeug.utils.unescape(r.content.decode()) + except Exception: + response = "timeout" + + return response + + def _do_reversal_or_voidsale(self, data, is_voidsale): + try: + self._setup_request(data) + except UserError: + return "internal error" + + data['is_voidsale'] = is_voidsale + response = self._do_request('pos_mercury.mercury_voidsale', data) + return response + + @api.model + def do_payment(self, data): + try: + self._setup_request(data) + except UserError: + return "internal error" + + response = self._do_request('pos_mercury.mercury_transaction', data) + return response + + @api.model + def do_reversal(self, data): + return self._do_reversal_or_voidsale(data, False) + + @api.model + def do_voidsale(self, data): + return self._do_reversal_or_voidsale(data, True) + + def do_return(self, data): + try: + self._setup_request(data) + except UserError: + return "internal error" + + response = self._do_request('pos_mercury.mercury_return', data) + return response + + # One time (the ones we use) Vantiv tokens are required to be + # deleted after 6 months + @api.autovacuum + def _gc_old_tokens(self): + expired_creation_date = (date.today() - timedelta(days=6 * 30)).strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + for order in self.env['pos.order'].search([('create_date', '<', expired_creation_date)]): + order.ref_no = "" + order.record_no = "" |
