mirror of
https://github.com/OCA/bank-statement-import.git
synced 2025-01-20 12:37:43 +02:00
[IMP] account_bank_statement_import_online_transferwise: black, isort, prettier
This commit is contained in:
@@ -3,25 +3,16 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Online Bank Statements: Wise.com (TransferWise.com)',
|
||||
'version': '12.0.1.0.3',
|
||||
'author':
|
||||
'CorporateHub, '
|
||||
'Odoo Community Association (OCA)',
|
||||
'maintainers': ['alexey-pelykh'],
|
||||
'website': 'https://github.com/OCA/bank-statement-import/',
|
||||
'license': 'AGPL-3',
|
||||
'category': 'Accounting',
|
||||
'summary': 'Online bank statements for Wise.com (TransferWise.com)',
|
||||
'depends': [
|
||||
'account_bank_statement_import_online',
|
||||
'web_widget_dropdown_dynamic',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python': ['cryptography'],
|
||||
},
|
||||
'data': [
|
||||
'views/online_bank_statement_provider.xml',
|
||||
],
|
||||
'installable': True,
|
||||
"name": "Online Bank Statements: Wise.com (TransferWise.com)",
|
||||
"version": "12.0.1.0.3",
|
||||
"author": "CorporateHub, " "Odoo Community Association (OCA)",
|
||||
"maintainers": ["alexey-pelykh"],
|
||||
"website": "https://github.com/OCA/bank-statement-import/",
|
||||
"license": "AGPL-3",
|
||||
"category": "Accounting",
|
||||
"summary": "Online bank statements for Wise.com (TransferWise.com)",
|
||||
"depends": ["account_bank_statement_import_online", "web_widget_dropdown_dynamic"],
|
||||
"external_dependencies": {"python": ["cryptography"]},
|
||||
"data": ["views/online_bank_statement_provider.xml"],
|
||||
"installable": True,
|
||||
}
|
||||
|
||||
@@ -2,79 +2,76 @@
|
||||
# Copyright 2020-2021 CorporateHub (https://corporatehub.eu)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from base64 import b64encode
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import dateutil.parser
|
||||
from decimal import Decimal
|
||||
import itertools
|
||||
import json
|
||||
import pytz
|
||||
import logging
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from base64 import b64encode
|
||||
from decimal import Decimal
|
||||
from urllib.error import HTTPError
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
import dateutil.parser
|
||||
import pytz
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TRANSFERWISE_API_BASE = 'https://api.transferwise.com'
|
||||
TRANSFERWISE_API_BASE = "https://api.transferwise.com"
|
||||
|
||||
|
||||
class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
_inherit = 'online.bank.statement.provider'
|
||||
_inherit = "online.bank.statement.provider"
|
||||
|
||||
# NOTE: This is needed to workaround possible multiple 'origin' fields
|
||||
# present in the same view, resulting in wrong field view configuraion
|
||||
# if more than one is widget="dynamic_dropdown"
|
||||
transferwise_profile = fields.Char(
|
||||
related='origin',
|
||||
readonly=False,
|
||||
)
|
||||
transferwise_profile = fields.Char(related="origin", readonly=False,)
|
||||
|
||||
@api.model
|
||||
def values_transferwise_profile(self):
|
||||
api_base = self.env.context.get('api_base') or TRANSFERWISE_API_BASE
|
||||
api_key = self.env.context.get('api_key')
|
||||
api_base = self.env.context.get("api_base") or TRANSFERWISE_API_BASE
|
||||
api_key = self.env.context.get("api_key")
|
||||
if not api_key:
|
||||
return []
|
||||
try:
|
||||
url = api_base + '/v1/profiles'
|
||||
url = api_base + "/v1/profiles"
|
||||
data = self._transferwise_retrieve(url, api_key)
|
||||
except:
|
||||
_logger.warning('Unable to get profiles', exc_info=True)
|
||||
except BaseException:
|
||||
_logger.warning("Unable to get profiles", exc_info=True)
|
||||
return []
|
||||
return list(map(
|
||||
lambda entry: (
|
||||
str(entry['id']),
|
||||
'%s %s (personal)' % (
|
||||
entry['details']['firstName'],
|
||||
entry['details']['lastName'],
|
||||
)
|
||||
if entry['type'] == 'personal'
|
||||
else entry['details']['name']
|
||||
),
|
||||
data
|
||||
))
|
||||
return list(
|
||||
map(
|
||||
lambda entry: (
|
||||
str(entry["id"]),
|
||||
"%s %s (personal)"
|
||||
% (entry["details"]["firstName"], entry["details"]["lastName"],)
|
||||
if entry["type"] == "personal"
|
||||
else entry["details"]["name"],
|
||||
),
|
||||
data,
|
||||
)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _get_available_services(self):
|
||||
return super()._get_available_services() + [
|
||||
('transferwise', 'Wise.com (TransferWise.com)'),
|
||||
("transferwise", "Wise.com (TransferWise.com)"),
|
||||
]
|
||||
|
||||
@api.multi
|
||||
def _obtain_statement_data(self, date_since, date_until):
|
||||
self.ensure_one()
|
||||
if self.service != 'transferwise':
|
||||
if self.service != "transferwise":
|
||||
return super()._obtain_statement_data(
|
||||
date_since,
|
||||
date_until,
|
||||
date_since, date_until,
|
||||
) # pragma: no cover
|
||||
|
||||
api_base = self.api_base or TRANSFERWISE_API_BASE
|
||||
@@ -82,13 +79,9 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
private_key = self.certificate_private_key
|
||||
if private_key:
|
||||
private_key = serialization.load_pem_private_key(
|
||||
private_key.encode(),
|
||||
password=None,
|
||||
backend=default_backend(),
|
||||
private_key.encode(), password=None, backend=default_backend(),
|
||||
)
|
||||
currency = (
|
||||
self.currency_id or self.company_id.currency_id
|
||||
).name
|
||||
currency = (self.currency_id or self.company_id.currency_id).name
|
||||
|
||||
if date_since.tzinfo:
|
||||
date_since = date_since.astimezone(pytz.utc).replace(tzinfo=None)
|
||||
@@ -96,17 +89,14 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
date_until = date_until.astimezone(pytz.utc).replace(tzinfo=None)
|
||||
|
||||
# Get corresponding balance by currency
|
||||
url = api_base + '/v1/borderless-accounts?profileId=%s' % (
|
||||
self.origin,
|
||||
)
|
||||
url = api_base + "/v1/borderless-accounts?profileId={}".format(self.origin)
|
||||
data = self._transferwise_retrieve(url, api_key, private_key)
|
||||
if not data:
|
||||
return None
|
||||
borderless_account = data[0]['id']
|
||||
balance = list(filter(
|
||||
lambda balance: balance['currency'] == currency,
|
||||
data[0]['balances']
|
||||
))
|
||||
borderless_account = data[0]["id"]
|
||||
balance = list(
|
||||
filter(lambda balance: balance["currency"] == currency, data[0]["balances"])
|
||||
)
|
||||
if not balance:
|
||||
return None
|
||||
|
||||
@@ -114,10 +104,10 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
# - intervalStart <= date < intervalEnd
|
||||
|
||||
# Get starting balance
|
||||
starting_balance_timestamp = date_since.isoformat() + 'Z'
|
||||
starting_balance_timestamp = date_since.isoformat() + "Z"
|
||||
url = api_base + (
|
||||
'/v3/profiles/%s/borderless-accounts/%s/statement.json' +
|
||||
'?currency=%s&intervalStart=%s&intervalEnd=%s&type=COMPACT'
|
||||
"/v3/profiles/%s/borderless-accounts/%s/statement.json"
|
||||
+ "?currency=%s&intervalStart=%s&intervalEnd=%s&type=COMPACT"
|
||||
) % (
|
||||
self.origin,
|
||||
borderless_account,
|
||||
@@ -126,7 +116,7 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
starting_balance_timestamp,
|
||||
)
|
||||
data = self._transferwise_retrieve(url, api_key, private_key)
|
||||
balance_start = data['endOfStatementBalance']['value']
|
||||
balance_start = data["endOfStatementBalance"]["value"]
|
||||
|
||||
# Get statements, using 469 days (around 1 year 3 month) as step.
|
||||
interval_step = relativedelta(days=469)
|
||||
@@ -136,158 +126,139 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
balance_end = None
|
||||
while interval_start < interval_end:
|
||||
url = api_base + (
|
||||
'/v3/profiles/%s/borderless-accounts/%s/statement.json' +
|
||||
'?currency=%s&intervalStart=%s&intervalEnd=%s&type=COMPACT'
|
||||
"/v3/profiles/%s/borderless-accounts/%s/statement.json"
|
||||
+ "?currency=%s&intervalStart=%s&intervalEnd=%s&type=COMPACT"
|
||||
) % (
|
||||
self.origin,
|
||||
borderless_account,
|
||||
currency,
|
||||
interval_start.isoformat() + 'Z',
|
||||
min(
|
||||
interval_start + interval_step, interval_end
|
||||
).isoformat() + 'Z',
|
||||
interval_start.isoformat() + "Z",
|
||||
min(interval_start + interval_step, interval_end).isoformat() + "Z",
|
||||
)
|
||||
data = self._transferwise_retrieve(url, api_key, private_key)
|
||||
transactions += data['transactions']
|
||||
balance_end = data['endOfStatementBalance']['value']
|
||||
transactions += data["transactions"]
|
||||
balance_end = data["endOfStatementBalance"]["value"]
|
||||
interval_start += interval_step
|
||||
if balance_end is None:
|
||||
raise UserError(_('Ending balance unavailable'))
|
||||
raise UserError(_("Ending balance unavailable"))
|
||||
|
||||
# Normalize transactions' date, sort by it, and get lines
|
||||
transactions = map(
|
||||
lambda transaction: self._transferwise_preparse_transaction(
|
||||
transaction
|
||||
),
|
||||
transactions
|
||||
lambda transaction: self._transferwise_preparse_transaction(transaction),
|
||||
transactions,
|
||||
)
|
||||
lines = list(itertools.chain.from_iterable(map(
|
||||
lambda x: self._transferwise_transaction_to_lines(x),
|
||||
sorted(
|
||||
transactions,
|
||||
key=lambda transaction: transaction['date']
|
||||
lines = list(
|
||||
itertools.chain.from_iterable(
|
||||
map(
|
||||
lambda x: self._transferwise_transaction_to_lines(x),
|
||||
sorted(transactions, key=lambda transaction: transaction["date"]),
|
||||
)
|
||||
)
|
||||
)))
|
||||
)
|
||||
|
||||
return lines, {
|
||||
'balance_start': balance_start,
|
||||
'balance_end_real': balance_end,
|
||||
}
|
||||
return lines, {"balance_start": balance_start, "balance_end_real": balance_end}
|
||||
|
||||
@api.model
|
||||
def _transferwise_preparse_transaction(self, transaction):
|
||||
transaction['date'] = dateutil.parser.parse(
|
||||
transaction['date']
|
||||
).replace(tzinfo=None)
|
||||
transaction["date"] = dateutil.parser.parse(transaction["date"]).replace(
|
||||
tzinfo=None
|
||||
)
|
||||
return transaction
|
||||
|
||||
@api.model
|
||||
def _transferwise_transaction_to_lines(self, transaction):
|
||||
transaction_type = transaction['type']
|
||||
reference_number = transaction['referenceNumber']
|
||||
details = transaction.get('details', {})
|
||||
exchange_details = transaction.get('exchangeDetails')
|
||||
recipient = details.get('recipient')
|
||||
total_fees = transaction.get('totalFees')
|
||||
date = transaction['date']
|
||||
payment_reference = details.get('paymentReference')
|
||||
description = details.get('description')
|
||||
transaction_type = transaction["type"]
|
||||
reference_number = transaction["referenceNumber"]
|
||||
details = transaction.get("details", {})
|
||||
exchange_details = transaction.get("exchangeDetails")
|
||||
recipient = details.get("recipient")
|
||||
total_fees = transaction.get("totalFees")
|
||||
date = transaction["date"]
|
||||
payment_reference = details.get("paymentReference")
|
||||
description = details.get("description")
|
||||
note = reference_number
|
||||
if description:
|
||||
note = '%s: %s' % (
|
||||
note,
|
||||
description
|
||||
)
|
||||
amount = transaction['amount']
|
||||
amount_value = amount.get('value', 0)
|
||||
fees_value = total_fees.get('value', Decimal())
|
||||
if transaction_type == 'CREDIT' \
|
||||
and details.get('type') == 'MONEY_ADDED':
|
||||
note = "{}: {}".format(note, description)
|
||||
amount = transaction["amount"]
|
||||
amount_value = amount.get("value", 0)
|
||||
fees_value = total_fees.get("value", Decimal())
|
||||
if transaction_type == "CREDIT" and details.get("type") == "MONEY_ADDED":
|
||||
fees_value = fees_value.copy_negate()
|
||||
else:
|
||||
fees_value = fees_value.copy_sign(amount_value)
|
||||
amount_value -= fees_value
|
||||
unique_import_id = '%s-%s-%s' % (
|
||||
transaction_type,
|
||||
reference_number,
|
||||
int(date.timestamp()),
|
||||
unique_import_id = "{}-{}-{}".format(
|
||||
transaction_type, reference_number, int(date.timestamp()),
|
||||
)
|
||||
line = {
|
||||
'name': payment_reference or description or '',
|
||||
'amount': str(amount_value),
|
||||
'date': date,
|
||||
'note': note,
|
||||
'unique_import_id': unique_import_id,
|
||||
"name": payment_reference or description or "",
|
||||
"amount": str(amount_value),
|
||||
"date": date,
|
||||
"note": note,
|
||||
"unique_import_id": unique_import_id,
|
||||
}
|
||||
if recipient:
|
||||
if 'name' in recipient:
|
||||
line.update({
|
||||
'partner_name': recipient['name'],
|
||||
})
|
||||
if 'bankAccount' in recipient:
|
||||
line.update({
|
||||
'account_number': recipient['bankAccount'],
|
||||
})
|
||||
elif 'merchant' in details:
|
||||
merchant = details['merchant']
|
||||
if 'name' in merchant:
|
||||
line.update({
|
||||
'partner_name': merchant['name'],
|
||||
})
|
||||
if "name" in recipient:
|
||||
line.update({"partner_name": recipient["name"]})
|
||||
if "bankAccount" in recipient:
|
||||
line.update({"account_number": recipient["bankAccount"]})
|
||||
elif "merchant" in details:
|
||||
merchant = details["merchant"]
|
||||
if "name" in merchant:
|
||||
line.update({"partner_name": merchant["name"]})
|
||||
else:
|
||||
if 'senderName' in details:
|
||||
line.update({
|
||||
'partner_name': details['senderName'],
|
||||
})
|
||||
if 'senderAccount' in details:
|
||||
line.update({
|
||||
'account_number': details['senderAccount'],
|
||||
})
|
||||
if "senderName" in details:
|
||||
line.update({"partner_name": details["senderName"]})
|
||||
if "senderAccount" in details:
|
||||
line.update({"account_number": details["senderAccount"]})
|
||||
if exchange_details:
|
||||
to_amount = exchange_details['toAmount']
|
||||
from_amount = exchange_details['fromAmount']
|
||||
to_amount = exchange_details["toAmount"]
|
||||
from_amount = exchange_details["fromAmount"]
|
||||
other_amount_value = (
|
||||
to_amount['value']
|
||||
if to_amount['currency'] != amount['currency']
|
||||
else from_amount['value']
|
||||
to_amount["value"]
|
||||
if to_amount["currency"] != amount["currency"]
|
||||
else from_amount["value"]
|
||||
)
|
||||
other_currency_name = (
|
||||
to_amount['currency']
|
||||
if to_amount['currency'] != amount['currency']
|
||||
else from_amount['currency']
|
||||
to_amount["currency"]
|
||||
if to_amount["currency"] != amount["currency"]
|
||||
else from_amount["currency"]
|
||||
)
|
||||
other_amount_value = other_amount_value.copy_abs()
|
||||
if amount_value.is_signed():
|
||||
other_amount_value = other_amount_value.copy_negate()
|
||||
other_currency = self.env['res.currency'].search(
|
||||
[('name', '=', other_currency_name)],
|
||||
limit=1
|
||||
other_currency = self.env["res.currency"].search(
|
||||
[("name", "=", other_currency_name)], limit=1
|
||||
)
|
||||
if other_amount_value and other_currency:
|
||||
line.update({
|
||||
'amount_currency': str(other_amount_value),
|
||||
'currency_id': other_currency.id,
|
||||
})
|
||||
line.update(
|
||||
{
|
||||
"amount_currency": str(other_amount_value),
|
||||
"currency_id": other_currency.id,
|
||||
}
|
||||
)
|
||||
lines = [line]
|
||||
if fees_value:
|
||||
lines += [{
|
||||
'name': _('Fee for %s') % reference_number,
|
||||
'amount': str(fees_value),
|
||||
'date': date,
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': '%s-FEE' % unique_import_id,
|
||||
'note': _('Transaction fee for %s') % reference_number,
|
||||
}]
|
||||
lines += [
|
||||
{
|
||||
"name": _("Fee for %s") % reference_number,
|
||||
"amount": str(fees_value),
|
||||
"date": date,
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "%s-FEE" % unique_import_id,
|
||||
"note": _("Transaction fee for %s") % reference_number,
|
||||
}
|
||||
]
|
||||
return lines
|
||||
|
||||
@api.model
|
||||
def _transferwise_validate(self, content):
|
||||
content = json.loads(content, parse_float=Decimal)
|
||||
if 'error' in content and content['error']:
|
||||
if "error" in content and content["error"]:
|
||||
raise UserError(
|
||||
content['error_description']
|
||||
if 'error_description' in content
|
||||
else 'Unknown error'
|
||||
content["error_description"]
|
||||
if "error_description" in content
|
||||
else "Unknown error"
|
||||
)
|
||||
return content
|
||||
|
||||
@@ -296,31 +267,23 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
try:
|
||||
with self._transferwise_urlopen(url, api_key) as response:
|
||||
content = response.read().decode(
|
||||
response.headers.get_content_charset() or 'utf-8'
|
||||
response.headers.get_content_charset() or "utf-8"
|
||||
)
|
||||
except HTTPError as e:
|
||||
if e.code != 403 or \
|
||||
e.headers.get('X-2FA-Approval-Result') != 'REJECTED':
|
||||
if e.code != 403 or e.headers.get("X-2FA-Approval-Result") != "REJECTED":
|
||||
raise e
|
||||
if not private_key:
|
||||
raise UserError(_(
|
||||
'Strong Customer Authentication is not configured'
|
||||
))
|
||||
one_time_token = e.headers['X-2FA-Approval']
|
||||
raise UserError(_("Strong Customer Authentication is not configured"))
|
||||
one_time_token = e.headers["X-2FA-Approval"]
|
||||
signature = private_key.sign(
|
||||
one_time_token.encode(),
|
||||
padding.PKCS1v15(),
|
||||
hashes.SHA256(),
|
||||
one_time_token.encode(), padding.PKCS1v15(), hashes.SHA256(),
|
||||
)
|
||||
|
||||
with self._transferwise_urlopen(
|
||||
url,
|
||||
api_key,
|
||||
one_time_token,
|
||||
b64encode(signature).decode(),
|
||||
url, api_key, one_time_token, b64encode(signature).decode(),
|
||||
) as response:
|
||||
content = response.read().decode(
|
||||
response.headers.get_content_charset() or 'utf-8'
|
||||
response.headers.get_content_charset() or "utf-8"
|
||||
)
|
||||
|
||||
return self._transferwise_validate(content)
|
||||
@@ -328,17 +291,17 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
@api.model
|
||||
def _transferwise_urlopen(self, url, api_key, ott=None, signature=None):
|
||||
if not api_key:
|
||||
raise UserError(_('No API key specified!'))
|
||||
raise UserError(_("No API key specified!"))
|
||||
request = urllib.request.Request(url)
|
||||
request.add_header('Authorization', 'Bearer %s' % api_key)
|
||||
request.add_header("Authorization", "Bearer %s" % api_key)
|
||||
if ott and signature:
|
||||
request.add_header('X-2FA-Approval', ott)
|
||||
request.add_header('X-Signature', signature)
|
||||
request.add_header("X-2FA-Approval", ott)
|
||||
request.add_header("X-Signature", signature)
|
||||
return urllib.request.urlopen(request)
|
||||
|
||||
@api.onchange('certificate_private_key', 'service')
|
||||
@api.onchange("certificate_private_key", "service")
|
||||
def _onchange_transferwise_certificate_private_key(self):
|
||||
if self.service != 'transferwise':
|
||||
if self.service != "transferwise":
|
||||
return
|
||||
|
||||
self.certificate_public_key = False
|
||||
@@ -351,22 +314,23 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
password=None,
|
||||
backend=default_backend(),
|
||||
)
|
||||
self.certificate_public_key = private_key.public_key().public_bytes(
|
||||
serialization.Encoding.PEM,
|
||||
serialization.PublicFormat.PKCS1,
|
||||
).decode()
|
||||
except:
|
||||
_logger.warning('Unable to parse key', exc_info=True)
|
||||
raise UserError(_('Unable to parse key'))
|
||||
self.certificate_public_key = (
|
||||
private_key.public_key()
|
||||
.public_bytes(
|
||||
serialization.Encoding.PEM, serialization.PublicFormat.PKCS1,
|
||||
)
|
||||
.decode()
|
||||
)
|
||||
except BaseException:
|
||||
_logger.warning("Unable to parse key", exc_info=True)
|
||||
raise UserError(_("Unable to parse key"))
|
||||
|
||||
@api.multi
|
||||
def _transferwise_generate_key(self):
|
||||
self.ensure_one()
|
||||
|
||||
private_key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=2048,
|
||||
backend=default_backend(),
|
||||
public_exponent=65537, key_size=2048, backend=default_backend(),
|
||||
)
|
||||
self.certificate_private_key = private_key.private_bytes(
|
||||
serialization.Encoding.PEM,
|
||||
@@ -374,10 +338,11 @@ class OnlineBankStatementProviderTransferwise(models.Model):
|
||||
serialization.NoEncryption(),
|
||||
).decode()
|
||||
|
||||
self.certificate_public_key = private_key.public_key().public_bytes(
|
||||
serialization.Encoding.PEM,
|
||||
serialization.PublicFormat.PKCS1,
|
||||
).decode()
|
||||
self.certificate_public_key = (
|
||||
private_key.public_key()
|
||||
.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.PKCS1,)
|
||||
.decode()
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def button_transferwise_generate_key(self):
|
||||
|
||||
@@ -2,26 +2,26 @@
|
||||
# Copyright 2020-2021 CorporateHub (https://corporatehub.eu)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from decimal import Decimal
|
||||
import json
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from unittest import mock
|
||||
from urllib.error import HTTPError
|
||||
|
||||
from odoo.tests import common
|
||||
from odoo import fields
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
_module_ns = 'odoo.addons.account_bank_statement_import_online_transferwise'
|
||||
from odoo import fields
|
||||
from odoo.tests import common
|
||||
|
||||
_module_ns = "odoo.addons.account_bank_statement_import_online_transferwise"
|
||||
_provider_class = (
|
||||
_module_ns
|
||||
+ '.models.online_bank_statement_provider_transferwise'
|
||||
+ '.OnlineBankStatementProviderTransferwise'
|
||||
+ ".models.online_bank_statement_provider_transferwise"
|
||||
+ ".OnlineBankStatementProviderTransferwise"
|
||||
)
|
||||
|
||||
|
||||
class MockedResponse:
|
||||
|
||||
class Headers(dict):
|
||||
def get_content_charset(self):
|
||||
return None
|
||||
@@ -37,41 +37,35 @@ class MockedResponse:
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
# pylint: disable=method-required-super
|
||||
def read(self):
|
||||
if self.exception is not None:
|
||||
raise self.exception()
|
||||
return self.data
|
||||
|
||||
|
||||
class TestAccountBankAccountStatementImportOnlineTransferwise(
|
||||
common.TransactionCase
|
||||
):
|
||||
|
||||
class TestAccountBankAccountStatementImportOnlineTransferwise(common.TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.now = fields.Datetime.now()
|
||||
self.currency_eur = self.env.ref('base.EUR')
|
||||
self.currency_usd = self.env.ref('base.USD')
|
||||
self.AccountJournal = self.env['account.journal']
|
||||
self.OnlineBankStatementProvider = self.env[
|
||||
'online.bank.statement.provider'
|
||||
]
|
||||
self.AccountBankStatement = self.env['account.bank.statement']
|
||||
self.AccountBankStatementLine = self.env['account.bank.statement.line']
|
||||
self.currency_eur = self.env.ref("base.EUR")
|
||||
self.currency_usd = self.env.ref("base.USD")
|
||||
self.AccountJournal = self.env["account.journal"]
|
||||
self.OnlineBankStatementProvider = self.env["online.bank.statement.provider"]
|
||||
self.AccountBankStatement = self.env["account.bank.statement"]
|
||||
self.AccountBankStatementLine = self.env["account.bank.statement.line"]
|
||||
|
||||
Provider = self.OnlineBankStatementProvider
|
||||
self.transferwise_parse_transaction = lambda payload: (
|
||||
Provider._transferwise_transaction_to_lines(
|
||||
Provider._transferwise_preparse_transaction(
|
||||
json.loads(
|
||||
payload,
|
||||
parse_float=Decimal,
|
||||
)
|
||||
json.loads(payload, parse_float=Decimal,)
|
||||
)
|
||||
)
|
||||
)
|
||||
self.response_balance = MockedResponse(data="""[
|
||||
self.response_balance = MockedResponse(
|
||||
data=b"""[
|
||||
{
|
||||
"id": 42,
|
||||
"balances": [
|
||||
@@ -80,24 +74,26 @@ class TestAccountBankAccountStatementImportOnlineTransferwise(
|
||||
}
|
||||
]
|
||||
}
|
||||
]""".encode())
|
||||
self.response_ott = MockedResponse(exception=lambda: HTTPError(
|
||||
'https://wise.com/',
|
||||
403,
|
||||
'403',
|
||||
{
|
||||
'X-2FA-Approval-Result': 'REJECTED',
|
||||
'X-2FA-Approval': '0123456789',
|
||||
},
|
||||
None,
|
||||
))
|
||||
self.response_transactions = MockedResponse(data="""{
|
||||
]"""
|
||||
)
|
||||
self.response_ott = MockedResponse(
|
||||
exception=lambda: HTTPError(
|
||||
"https://wise.com/",
|
||||
403,
|
||||
"403",
|
||||
{"X-2FA-Approval-Result": "REJECTED", "X-2FA-Approval": "0123456789"},
|
||||
None,
|
||||
)
|
||||
)
|
||||
self.response_transactions = MockedResponse(
|
||||
data=b"""{
|
||||
"transactions": [],
|
||||
"endOfStatementBalance": {
|
||||
"value": 42.00,
|
||||
"currency": "EUR"
|
||||
}
|
||||
}""".encode())
|
||||
}"""
|
||||
)
|
||||
|
||||
def test_values_transferwise_profile(self):
|
||||
mocked_response = json.loads(
|
||||
@@ -117,63 +113,58 @@ class TestAccountBankAccountStatementImportOnlineTransferwise(
|
||||
"name": "Brainbean Apps OÜ"
|
||||
}
|
||||
}
|
||||
]""", parse_float=Decimal)
|
||||
]""",
|
||||
parse_float=Decimal,
|
||||
)
|
||||
values_transferwise_profile = []
|
||||
with mock.patch(
|
||||
_provider_class + '._transferwise_retrieve',
|
||||
return_value=mocked_response,
|
||||
_provider_class + "._transferwise_retrieve", return_value=mocked_response,
|
||||
):
|
||||
values_transferwise_profile = (
|
||||
self.OnlineBankStatementProvider.with_context({
|
||||
'api_base': 'https://example.com',
|
||||
'api_key': 'dummy',
|
||||
}).values_transferwise_profile()
|
||||
)
|
||||
values_transferwise_profile = self.OnlineBankStatementProvider.with_context(
|
||||
{"api_base": "https://example.com", "api_key": "dummy"}
|
||||
).values_transferwise_profile()
|
||||
self.assertEqual(
|
||||
values_transferwise_profile,
|
||||
[
|
||||
('1234567890', 'Alexey Pelykh (personal)'),
|
||||
('1234567891', 'Brainbean Apps OÜ'),
|
||||
]
|
||||
("1234567890", "Alexey Pelykh (personal)"),
|
||||
("1234567891", "Brainbean Apps OÜ"),
|
||||
],
|
||||
)
|
||||
|
||||
def test_values_transferwise_profile_no_key(self):
|
||||
values_transferwise_profile = (
|
||||
self.OnlineBankStatementProvider.with_context({
|
||||
'api_base': 'https://example.com',
|
||||
}).values_transferwise_profile()
|
||||
)
|
||||
values_transferwise_profile = self.OnlineBankStatementProvider.with_context(
|
||||
{"api_base": "https://example.com"}
|
||||
).values_transferwise_profile()
|
||||
self.assertEqual(values_transferwise_profile, [])
|
||||
|
||||
def test_values_transferwise_profile_error(self):
|
||||
values_transferwise_profile = []
|
||||
with mock.patch(
|
||||
_provider_class + '._transferwise_retrieve',
|
||||
_provider_class + "._transferwise_retrieve",
|
||||
side_effect=lambda: Exception(),
|
||||
):
|
||||
values_transferwise_profile = (
|
||||
self.OnlineBankStatementProvider.with_context({
|
||||
'api_base': 'https://example.com',
|
||||
'api_key': 'dummy',
|
||||
}).values_transferwise_profile()
|
||||
)
|
||||
values_transferwise_profile = self.OnlineBankStatementProvider.with_context(
|
||||
{"api_base": "https://example.com", "api_key": "dummy"}
|
||||
).values_transferwise_profile()
|
||||
self.assertEqual(values_transferwise_profile, [])
|
||||
|
||||
def test_pull(self):
|
||||
journal = self.AccountJournal.create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'code': 'BANK',
|
||||
'currency_id': self.currency_eur.id,
|
||||
'bank_statements_source': 'online',
|
||||
'online_bank_statement_provider': 'transferwise',
|
||||
})
|
||||
journal = self.AccountJournal.create(
|
||||
{
|
||||
"name": "Bank",
|
||||
"type": "bank",
|
||||
"code": "BANK",
|
||||
"currency_id": self.currency_eur.id,
|
||||
"bank_statements_source": "online",
|
||||
"online_bank_statement_provider": "transferwise",
|
||||
}
|
||||
)
|
||||
|
||||
provider = journal.online_bank_statement_provider_id
|
||||
provider.origin = '1234567891'
|
||||
provider.origin = "1234567891"
|
||||
|
||||
def mock_response(url, api_key, private_key=None):
|
||||
if '/borderless-accounts?profileId=1234567891' in url:
|
||||
if "/borderless-accounts?profileId=1234567891" in url:
|
||||
payload = """[
|
||||
{
|
||||
"id": 42,
|
||||
@@ -184,7 +175,7 @@ class TestAccountBankAccountStatementImportOnlineTransferwise(
|
||||
]
|
||||
}
|
||||
]"""
|
||||
elif '/borderless-accounts/42/statement.json' in url:
|
||||
elif "/borderless-accounts/42/statement.json" in url:
|
||||
payload = """{
|
||||
"transactions": [],
|
||||
"endOfStatementBalance": {
|
||||
@@ -193,57 +184,58 @@ class TestAccountBankAccountStatementImportOnlineTransferwise(
|
||||
}
|
||||
}"""
|
||||
return json.loads(payload, parse_float=Decimal)
|
||||
|
||||
with mock.patch(
|
||||
_provider_class + '._transferwise_retrieve',
|
||||
side_effect=mock_response,
|
||||
_provider_class + "._transferwise_retrieve", side_effect=mock_response,
|
||||
):
|
||||
data = provider._obtain_statement_data(
|
||||
self.now - relativedelta(hours=1),
|
||||
self.now,
|
||||
self.now - relativedelta(hours=1), self.now,
|
||||
)
|
||||
|
||||
self.assertEqual(len(data[0]), 0)
|
||||
self.assertEqual(data[1]['balance_start'], 42.0)
|
||||
self.assertEqual(data[1]['balance_end_real'], 42.0)
|
||||
self.assertEqual(data[1]["balance_start"], 42.0)
|
||||
self.assertEqual(data[1]["balance_end_real"], 42.0)
|
||||
|
||||
def test_pull_no_data(self):
|
||||
journal = self.AccountJournal.create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'code': 'BANK',
|
||||
'currency_id': self.currency_eur.id,
|
||||
'bank_statements_source': 'online',
|
||||
'online_bank_statement_provider': 'transferwise',
|
||||
})
|
||||
journal = self.AccountJournal.create(
|
||||
{
|
||||
"name": "Bank",
|
||||
"type": "bank",
|
||||
"code": "BANK",
|
||||
"currency_id": self.currency_eur.id,
|
||||
"bank_statements_source": "online",
|
||||
"online_bank_statement_provider": "transferwise",
|
||||
}
|
||||
)
|
||||
|
||||
provider = journal.online_bank_statement_provider_id
|
||||
provider.origin = '1234567891'
|
||||
provider.password = 'API_KEY'
|
||||
provider.origin = "1234567891"
|
||||
provider.password = "API_KEY"
|
||||
|
||||
with mock.patch(
|
||||
_provider_class + '._transferwise_retrieve',
|
||||
return_value=[],
|
||||
_provider_class + "._transferwise_retrieve", return_value=[],
|
||||
):
|
||||
data = provider._obtain_statement_data(
|
||||
self.now - relativedelta(hours=1),
|
||||
self.now,
|
||||
self.now - relativedelta(hours=1), self.now,
|
||||
)
|
||||
|
||||
self.assertFalse(data)
|
||||
|
||||
def test_update_public_key(self):
|
||||
journal = self.AccountJournal.create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'code': 'BANK',
|
||||
'currency_id': self.currency_eur.id,
|
||||
'bank_statements_source': 'online',
|
||||
'online_bank_statement_provider': 'transferwise',
|
||||
})
|
||||
journal = self.AccountJournal.create(
|
||||
{
|
||||
"name": "Bank",
|
||||
"type": "bank",
|
||||
"code": "BANK",
|
||||
"currency_id": self.currency_eur.id,
|
||||
"bank_statements_source": "online",
|
||||
"online_bank_statement_provider": "transferwise",
|
||||
}
|
||||
)
|
||||
|
||||
provider = journal.online_bank_statement_provider_id
|
||||
provider.origin = '1234567891'
|
||||
provider.password = 'API_KEY'
|
||||
provider.origin = "1234567891"
|
||||
provider.password = "API_KEY"
|
||||
|
||||
with common.Form(provider) as provider_form:
|
||||
provider_form.certificate_private_key = """
|
||||
@@ -279,22 +271,24 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
self.assertTrue(provider.certificate_public_key)
|
||||
|
||||
def test_sca(self):
|
||||
journal = self.AccountJournal.create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'code': 'BANK',
|
||||
'currency_id': self.currency_eur.id,
|
||||
'bank_statements_source': 'online',
|
||||
'online_bank_statement_provider': 'transferwise',
|
||||
})
|
||||
journal = self.AccountJournal.create(
|
||||
{
|
||||
"name": "Bank",
|
||||
"type": "bank",
|
||||
"code": "BANK",
|
||||
"currency_id": self.currency_eur.id,
|
||||
"bank_statements_source": "online",
|
||||
"online_bank_statement_provider": "transferwise",
|
||||
}
|
||||
)
|
||||
|
||||
provider = journal.online_bank_statement_provider_id
|
||||
provider.origin = '1234567891'
|
||||
provider.password = 'API_KEY'
|
||||
provider.origin = "1234567891"
|
||||
provider.password = "API_KEY"
|
||||
provider.button_transferwise_generate_key()
|
||||
|
||||
with mock.patch(
|
||||
'urllib.request.urlopen',
|
||||
"urllib.request.urlopen",
|
||||
side_effect=[
|
||||
self.response_balance,
|
||||
self.response_ott,
|
||||
@@ -304,16 +298,16 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
],
|
||||
):
|
||||
data = provider._obtain_statement_data(
|
||||
self.now - relativedelta(hours=1),
|
||||
self.now,
|
||||
self.now - relativedelta(hours=1), self.now,
|
||||
)
|
||||
|
||||
self.assertEqual(len(data[0]), 0)
|
||||
self.assertEqual(data[1]['balance_start'], 42.0)
|
||||
self.assertEqual(data[1]['balance_end_real'], 42.0)
|
||||
self.assertEqual(data[1]["balance_start"], 42.0)
|
||||
self.assertEqual(data[1]["balance_end_real"], 42.0)
|
||||
|
||||
def test_transaction_parse_1(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "CREDIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -337,23 +331,28 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '0.42',
|
||||
'name': 'REF-XYZ',
|
||||
'note': (
|
||||
'TRANSFER-123456789: Received money from SENDER with reference'
|
||||
' REF-XYZ'
|
||||
),
|
||||
'partner_name': 'SENDER',
|
||||
'account_number': 'XX00 0000 0000 0000',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "0.42",
|
||||
"name": "REF-XYZ",
|
||||
"note": (
|
||||
"TRANSFER-123456789: Received money from SENDER with reference"
|
||||
" REF-XYZ"
|
||||
),
|
||||
"partner_name": "SENDER",
|
||||
"account_number": "XX00 0000 0000 0000",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_2(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "DEBIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -379,28 +378,36 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '-200.00',
|
||||
'name': 'INVOICE 42-01',
|
||||
'note': 'TRANSFER-123456789: Sent money to John Doe',
|
||||
'partner_name': 'John Doe',
|
||||
'account_number': 'XX00 0000 0000 0000',
|
||||
'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '-0.60',
|
||||
'name': 'Fee for TRANSFER-123456789',
|
||||
'note': 'Transaction fee for TRANSFER-123456789',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "-200.00",
|
||||
"name": "INVOICE 42-01",
|
||||
"note": "TRANSFER-123456789: Sent money to John Doe",
|
||||
"partner_name": "John Doe",
|
||||
"account_number": "XX00 0000 0000 0000",
|
||||
"unique_import_id": "DEBIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "-0.60",
|
||||
"name": "Fee for TRANSFER-123456789",
|
||||
"note": "Transaction fee for TRANSFER-123456789",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "DEBIT-TRANSFER-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_3(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "DEBIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -436,24 +443,27 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "USD"
|
||||
},
|
||||
"referenceNumber": "CARD-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '-123.45',
|
||||
'name': (
|
||||
'Card transaction of 1234.56 USD issued by Paypal *XX CITY'
|
||||
),
|
||||
'note': (
|
||||
'CARD-123456789: Card transaction of 1234.56 USD issued by '
|
||||
'Paypal *XX CITY'
|
||||
),
|
||||
'partner_name': 'Paypal *XX',
|
||||
'unique_import_id': 'DEBIT-CARD-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "-123.45",
|
||||
"name": ("Card transaction of 1234.56 USD issued by Paypal *XX CITY"),
|
||||
"note": (
|
||||
"CARD-123456789: Card transaction of 1234.56 USD issued by "
|
||||
"Paypal *XX CITY"
|
||||
),
|
||||
"partner_name": "Paypal *XX",
|
||||
"unique_import_id": "DEBIT-CARD-123456789-946684800",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_4(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "DEBIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -499,34 +509,40 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "CARD-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '-455.55',
|
||||
'name': (
|
||||
'Card transaction of 1234.56 USD issued by Paypal *XX CITY'
|
||||
),
|
||||
'note': (
|
||||
'CARD-123456789: Card transaction of 1234.56 USD issued by'
|
||||
' Paypal *XX CITY'
|
||||
),
|
||||
'partner_name': 'Paypal *XX',
|
||||
'unique_import_id': 'DEBIT-CARD-123456789-946684800',
|
||||
'amount_currency': '-567.89',
|
||||
'currency_id': self.currency_usd.id,
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'amount': '-1.23',
|
||||
'name': 'Fee for CARD-123456789',
|
||||
'note': 'Transaction fee for CARD-123456789',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': 'DEBIT-CARD-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "-455.55",
|
||||
"name": ("Card transaction of 1234.56 USD issued by Paypal *XX CITY"),
|
||||
"note": (
|
||||
"CARD-123456789: Card transaction of 1234.56 USD issued by"
|
||||
" Paypal *XX CITY"
|
||||
),
|
||||
"partner_name": "Paypal *XX",
|
||||
"unique_import_id": "DEBIT-CARD-123456789-946684800",
|
||||
"amount_currency": "-567.89",
|
||||
"currency_id": self.currency_usd.id,
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"amount": "-1.23",
|
||||
"name": "Fee for CARD-123456789",
|
||||
"note": "Transaction fee for CARD-123456789",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "DEBIT-CARD-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_5(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "DEBIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -562,30 +578,38 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Invoice A from DD MMM YYYY',
|
||||
'note': 'TRANSFER-123456789: Sent money to Jane Doe',
|
||||
'partner_name': 'Jane Doe',
|
||||
'account_number': '(ADBCDEF) 0000000000000000',
|
||||
'amount': '-265.34',
|
||||
'amount_currency': '-297.00',
|
||||
'currency_id': self.currency_usd.id,
|
||||
'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Fee for TRANSFER-123456789',
|
||||
'note': 'Transaction fee for TRANSFER-123456789',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'amount': '-5.21',
|
||||
'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Invoice A from DD MMM YYYY",
|
||||
"note": "TRANSFER-123456789: Sent money to Jane Doe",
|
||||
"partner_name": "Jane Doe",
|
||||
"account_number": "(ADBCDEF) 0000000000000000",
|
||||
"amount": "-265.34",
|
||||
"amount_currency": "-297.00",
|
||||
"currency_id": self.currency_usd.id,
|
||||
"unique_import_id": "DEBIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Fee for TRANSFER-123456789",
|
||||
"note": "Transaction fee for TRANSFER-123456789",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"amount": "-5.21",
|
||||
"unique_import_id": "DEBIT-TRANSFER-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_6(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "CREDIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -606,18 +630,23 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Topped up balance',
|
||||
'note': 'TRANSFER-123456789: Topped up balance',
|
||||
'amount': '5000.00',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Topped up balance",
|
||||
"note": "TRANSFER-123456789: Topped up balance",
|
||||
"amount": "5000.00",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_7(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "CREDIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -657,20 +686,25 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "EUR"
|
||||
},
|
||||
"referenceNumber": "BALANCE-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Converted 7.93 USD to 6.93 EUR',
|
||||
'note': 'BALANCE-123456789: Converted 7.93 USD to 6.93 EUR',
|
||||
'amount': '6.93',
|
||||
'amount_currency': '7.93',
|
||||
'currency_id': self.currency_usd.id,
|
||||
'unique_import_id': 'CREDIT-BALANCE-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Converted 7.93 USD to 6.93 EUR",
|
||||
"note": "BALANCE-123456789: Converted 7.93 USD to 6.93 EUR",
|
||||
"amount": "6.93",
|
||||
"amount_currency": "7.93",
|
||||
"currency_id": self.currency_usd.id,
|
||||
"unique_import_id": "CREDIT-BALANCE-123456789-946684800",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_8(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "DEBIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -710,28 +744,36 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "USD"
|
||||
},
|
||||
"referenceNumber": "BALANCE-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Converted 7.93 USD to 6.93 EUR',
|
||||
'note': 'BALANCE-123456789: Converted 7.93 USD to 6.93 EUR',
|
||||
'amount': '-7.88',
|
||||
'amount_currency': '-6.93',
|
||||
'currency_id': self.currency_eur.id,
|
||||
'unique_import_id': 'DEBIT-BALANCE-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Fee for BALANCE-123456789',
|
||||
'note': 'Transaction fee for BALANCE-123456789',
|
||||
'amount': '-0.05',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': 'DEBIT-BALANCE-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Converted 7.93 USD to 6.93 EUR",
|
||||
"note": "BALANCE-123456789: Converted 7.93 USD to 6.93 EUR",
|
||||
"amount": "-7.88",
|
||||
"amount_currency": "-6.93",
|
||||
"currency_id": self.currency_eur.id,
|
||||
"unique_import_id": "DEBIT-BALANCE-123456789-946684800",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Fee for BALANCE-123456789",
|
||||
"note": "Transaction fee for BALANCE-123456789",
|
||||
"amount": "-0.05",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "DEBIT-BALANCE-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_9(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "CREDIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -752,26 +794,34 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "USD"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Topped up balance',
|
||||
'note': 'TRANSFER-123456789: Topped up balance',
|
||||
'amount': '25.68',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Fee for TRANSFER-123456789',
|
||||
'note': 'Transaction fee for TRANSFER-123456789',
|
||||
'amount': '-0.68',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Topped up balance",
|
||||
"note": "TRANSFER-123456789: Topped up balance",
|
||||
"amount": "25.68",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Fee for TRANSFER-123456789",
|
||||
"note": "Transaction fee for TRANSFER-123456789",
|
||||
"amount": "-0.68",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
def test_transaction_parse_10(self):
|
||||
lines = self.transferwise_parse_transaction("""{
|
||||
lines = self.transferwise_parse_transaction(
|
||||
"""{
|
||||
"type": "CREDIT",
|
||||
"date": "2000-01-01T00:00:00.000Z",
|
||||
"amount": {
|
||||
@@ -795,21 +845,28 @@ edF6byMgXSzgOWYuRPXwmHpBQV0GiexQUAxVyUzaVWfil69LaFfXaw==
|
||||
"currency": "USD"
|
||||
},
|
||||
"referenceNumber": "TRANSFER-123456789"
|
||||
}""")
|
||||
}"""
|
||||
)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Sent money to Acme Inc.',
|
||||
'note': 'TRANSFER-123456789: Sent money to Acme Inc.',
|
||||
'partner_name': 'Acme Inc.',
|
||||
'amount': '1800.00',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
|
||||
})
|
||||
self.assertEqual(lines[1], {
|
||||
'date': datetime(2000, 1, 1),
|
||||
'name': 'Fee for TRANSFER-123456789',
|
||||
'note': 'Transaction fee for TRANSFER-123456789',
|
||||
'amount': '4.33',
|
||||
'partner_name': 'Wise (former TransferWise)',
|
||||
'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800-FEE',
|
||||
})
|
||||
self.assertEqual(
|
||||
lines[0],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Sent money to Acme Inc.",
|
||||
"note": "TRANSFER-123456789: Sent money to Acme Inc.",
|
||||
"partner_name": "Acme Inc.",
|
||||
"amount": "1800.00",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800",
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
lines[1],
|
||||
{
|
||||
"date": datetime(2000, 1, 1),
|
||||
"name": "Fee for TRANSFER-123456789",
|
||||
"note": "Transaction fee for TRANSFER-123456789",
|
||||
"amount": "4.33",
|
||||
"partner_name": "Wise (former TransferWise)",
|
||||
"unique_import_id": "CREDIT-TRANSFER-123456789-946684800-FEE",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
|
||||
Copyright 2021 CorporateHub (https://corporatehub.eu)
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="online_bank_statement_provider_form">
|
||||
<field name="name">online.bank.statement.provider.form</field>
|
||||
<field name="model">online.bank.statement.provider</field>
|
||||
<field name="inherit_id" ref="account_bank_statement_import_online.online_bank_statement_provider_form"/>
|
||||
<field
|
||||
name="inherit_id"
|
||||
ref="account_bank_statement_import_online.online_bank_statement_provider_form"
|
||||
/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='configuration']" position="inside">
|
||||
<group attrs="{'invisible': [('service', '!=', 'transferwise')]}">
|
||||
@@ -42,10 +44,7 @@
|
||||
string="Private key"
|
||||
password="True"
|
||||
/>
|
||||
<field
|
||||
name="certificate_public_key"
|
||||
string="Public key"
|
||||
/>
|
||||
<field name="certificate_public_key" string="Public key" />
|
||||
<div col="2" colspan="2">
|
||||
<button
|
||||
name="button_transferwise_generate_key"
|
||||
@@ -59,5 +58,4 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../../../account_bank_statement_import_online_transferwise
|
||||
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user