summaryrefslogtreecommitdiff
path: root/addons/pos_mercury/models
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/pos_mercury/models
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/pos_mercury/models')
-rw-r--r--addons/pos_mercury/models/__init__.py5
-rw-r--r--addons/pos_mercury/models/pos_mercury.py78
-rw-r--r--addons/pos_mercury/models/pos_mercury_transaction.py123
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 = ""