Files
odoo_source/addons/pos_adyen/models/pos_payment_method.py
T
Xavier Morel 9ebbfdac73 [FIX] *: incorrect translations markings
Fixes a large number of cases where strings are translated then
formatted, instead of letting `_()` do the formatting internally,
which allows it to recover from incorrect translations (missing,
broken, or extra placeholders).

Also

- removes translation markers entirely when there's nothing to
  translate e.g. `_("%s - %s")` is not useful
- fixes a few messes which lead to only partial translatability
  (DRY is generally a bad idea when translations are involved, even
  more so when you don't make the variable part translatable)
- fixes a few nearby issues noticed at the same time
- replaces a few `"%s"` by `%r`, which should automatically quote
  strings relatively appropriately
- fixes translated strings which use `\` to escape a newline (in order
  to fill-paragraph): `\` escapes only the newline, if the
  continuation string is indented this results in a bunch of spaces
  ending in the string to translate, which is pretty garbage for the
  translator, using implicit concatenation works much better

Note: some of the updates revert f-string parameters to %, because
babel (2.9) apparently has trouble with f-strings and blows up trying
to extract them.

Not in scope:

Helping translators fix translatable strings e.g. any translation
string with more than one placeholder probably should use keyword
placeholders

- Provides more context / data to the translator to make sense of the
  sentence.
- Allows reordering the translated terms, which can be necessary
  depending on the sentence and language.

closes odoo/odoo#139314

Related: odoo/enterprise#49311
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2023-10-23 16:45:09 +00:00

119 lines
5.1 KiB
Python

# coding: utf-8
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging
import pprint
import random
import requests
import string
from werkzeug.exceptions import Forbidden
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
class PosPaymentMethod(models.Model):
_inherit = 'pos.payment.method'
def _get_payment_terminal_selection(self):
return super(PosPaymentMethod, self)._get_payment_terminal_selection() + [('adyen', 'Adyen')]
# Adyen
adyen_api_key = fields.Char(string="Adyen API key", help='Used when connecting to Adyen: https://docs.adyen.com/user-management/how-to-get-the-api-key/#description', copy=False)
adyen_terminal_identifier = fields.Char(help='[Terminal model]-[Serial number], for example: P400Plus-123456789', copy=False)
adyen_test_mode = fields.Boolean(help='Run transactions in the test environment.')
adyen_latest_response = fields.Char(copy=False, groups='base.group_erp_manager') # used to buffer the latest asynchronous notification from Adyen.
adyen_latest_diagnosis = fields.Char(copy=False, groups='base.group_erp_manager') # used to determine if the terminal is still connected.
@api.constrains('adyen_terminal_identifier')
def _check_adyen_terminal_identifier(self):
for payment_method in self:
if not payment_method.adyen_terminal_identifier:
continue
# sudo() to search all companies
existing_payment_method = self.sudo().search([('id', '!=', payment_method.id),
('adyen_terminal_identifier', '=', payment_method.adyen_terminal_identifier)],
limit=1)
if existing_payment_method:
if existing_payment_method.company_id == payment_method.company_id:
raise ValidationError(_('Terminal %s is already used on payment method %s.',
payment_method.adyen_terminal_identifier, existing_payment_method.display_name))
else:
raise ValidationError(_('Terminal %s is already used in company %s on payment method %s.',
payment_method.adyen_terminal_identifier,
existing_payment_method.company_id.name,
existing_payment_method.display_name))
def _get_adyen_endpoints(self):
return {
'terminal_request': 'https://terminal-api-%s.adyen.com/async',
}
def _is_write_forbidden(self, fields):
whitelisted_fields = {'adyen_latest_response', 'adyen_latest_diagnosis'}
return super(PosPaymentMethod, self)._is_write_forbidden(fields - whitelisted_fields)
def _adyen_diagnosis_request_data(self, pos_config_name):
service_id = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
return {
"SaleToPOIRequest": {
"MessageHeader": {
"ProtocolVersion": "3.0",
"MessageClass": "Service",
"MessageCategory": "Diagnosis",
"MessageType": "Request",
"ServiceID": service_id,
"SaleID": pos_config_name,
"POIID": self.adyen_terminal_identifier,
},
"DiagnosisRequest": {
"HostDiagnosisFlag": False
}
}
}
def get_latest_adyen_status(self):
self.ensure_one()
latest_response = self.sudo().adyen_latest_response
latest_response = json.loads(latest_response) if latest_response else False
return latest_response
def proxy_adyen_request(self, data, operation=False):
''' Necessary because Adyen's endpoints don't have CORS enabled '''
if data['SaleToPOIRequest']['MessageHeader']['MessageCategory'] == 'Payment': # Clear only if it is a payment request
self.sudo().adyen_latest_response = '' # avoid handling old responses multiple times
if not operation:
operation = 'terminal_request'
return self._proxy_adyen_request_direct(data, operation)
def _proxy_adyen_request_direct(self, data, operation):
self.ensure_one()
TIMEOUT = 10
_logger.info('request to adyen\n%s', pprint.pformat(data))
environment = 'test' if self.adyen_test_mode else 'live'
endpoint = self._get_adyen_endpoints()[operation] % environment
headers = {
'x-api-key': self.adyen_api_key,
}
req = requests.post(endpoint, json=data, headers=headers, timeout=TIMEOUT)
# Authentication error doesn't return JSON
if req.status_code == 401:
return {
'error': {
'status_code': req.status_code,
'message': req.text
}
}
if req.text == 'ok':
return True
return req.json()