[IMP] account_bank_statement_import_paypal: black, isort, prettier

This commit is contained in:
Carlos Roca
2020-07-03 09:42:34 +02:00
committed by Pedro M. Baeza
parent 706ac62df9
commit 6612a81680
12 changed files with 507 additions and 578 deletions

View File

@@ -4,32 +4,25 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
'name': 'PayPal CSV Format Bank Statements Import',
'summary': 'Import PayPal CSV files as Bank Statements in Odoo',
'version': '12.0.2.2.1',
'category': 'Accounting',
'website': 'https://github.com/OCA/bank-statement-import',
'author':
'Akretion, '
'Brainbean Apps, '
'Odoo Community Association (OCA)',
'license': 'AGPL-3',
'installable': True,
'depends': [
'account_bank_statement_import',
'multi_step_wizard',
'web_widget_dropdown_dynamic',
"name": "PayPal CSV Format Bank Statements Import",
"summary": "Import PayPal CSV files as Bank Statements in Odoo",
"version": "12.0.2.2.1",
"category": "Accounting",
"website": "https://github.com/OCA/bank-statement-import",
"author": "Akretion, " "Brainbean Apps, " "Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"depends": [
"account_bank_statement_import",
"multi_step_wizard",
"web_widget_dropdown_dynamic",
],
'external_dependencies': {
'python': [
'csv',
]
},
'data': [
'security/ir.model.access.csv',
'data/maps.xml',
'views/account_bank_statement_import_paypal_mapping.xml',
'views/account_bank_statement_import.xml',
'wizards/account_bank_statement_import_paypal_mapping_wizard.xml',
"external_dependencies": {"python": ["csv"]},
"data": [
"security/ir.model.access.csv",
"data/maps.xml",
"views/account_bank_statement_import_paypal_mapping.xml",
"views/account_bank_statement_import.xml",
"wizards/account_bank_statement_import_paypal_mapping_wizard.xml",
],
}

View File

@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2019 Tecnativa - Vicent Cubells
Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo noupdate="1">
<record id="paypal_statement_map_en" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_statement_map_en"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Statement (EN)</field>
<field name="float_thousands_sep">comma</field>
<field name="float_decimal_sep">dot</field>
@@ -27,8 +29,10 @@
<field name="bank_name_column">Bank Name</field>
<field name="bank_account_column">Bank Account</field>
</record>
<record id="paypal_activity_map_en" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_activity_map_en"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Activity (EN)</field>
<field name="float_thousands_sep">comma</field>
<field name="float_decimal_sep">dot</field>
@@ -50,8 +54,10 @@
<field name="subject_column">Subject</field>
<field name="note_column">Note</field>
</record>
<record id="paypal_statement_map_es" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_statement_map_es"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Statement (ES)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
@@ -72,8 +78,10 @@
<field name="bank_name_column">Nombre del banco</field>
<field name="bank_account_column">Cuenta bancaria</field>
</record>
<record id="paypal_activity_map_es" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_activity_map_es"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Activity (ES)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
@@ -90,13 +98,17 @@
<field name="transaction_id_column">Id. de transacción</field>
<field name="type_column">Tipo</field>
<field name="from_email_address_column">Correo electrónico del remitente</field>
<field name="to_email_address_column">Correo electrónico del destinatario</field>
<field
name="to_email_address_column"
>Correo electrónico del destinatario</field>
<field name="invoice_id_column">Número de factura</field>
<field name="subject_column">Asunto</field>
<field name="note_column">Nota</field>
</record>
<record id="paypal_statement_map_de" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_statement_map_de"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Statement (DE)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
@@ -117,8 +129,10 @@
<field name="bank_name_column">Name der Bank</field>
<field name="bank_account_column">Bankkonto</field>
</record>
<record id="paypal_activity_map_de" model="account.bank.statement.import.paypal.mapping">
<record
id="paypal_activity_map_de"
model="account.bank.statement.import.paypal.mapping"
>
<field name="name">PayPal Activity (DE)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
@@ -140,5 +154,4 @@
<field name="subject_column">Betreff</field>
<field name="note_column">Hinweis</field>
</record>
</odoo>

View File

@@ -99,5 +99,5 @@ LEFT JOIN _mappings AS _bank_name
ON m.id = _bank_name.id AND _bank_name.field_to_assign = 'bank_name'
LEFT JOIN _mappings AS _bank_acc
ON m.id = _bank_acc.id AND _bank_acc.field_to_assign = 'bank_account';
"""
""",
)

View File

@@ -3,33 +3,29 @@
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
from odoo import api, fields, models
import logging
_logger = logging.getLogger(__name__)
class AccountBankStatementImport(models.TransientModel):
_inherit = 'account.bank.statement.import'
_inherit = "account.bank.statement.import"
paypal_mapping_id = fields.Many2one(
string='PayPal mapping',
comodel_name='account.bank.statement.import.paypal.mapping',
string="PayPal mapping",
comodel_name="account.bank.statement.import.paypal.mapping",
)
@api.multi
def _parse_file(self, data_file):
self.ensure_one()
try:
Parser = self.env['account.bank.statement.import.paypal.parser']
return Parser.parse(
self.paypal_mapping_id,
data_file,
self.filename
)
except:
if self.env.context.get(
'account_bank_statement_import_paypal_test'):
Parser = self.env["account.bank.statement.import.paypal.parser"]
return Parser.parse(self.paypal_mapping_id, data_file, self.filename)
except Exception:
if self.env.context.get("account_bank_statement_import_paypal_test"):
raise
_logger.warning('PayPal parser error', exc_info=True)
_logger.warning("PayPal parser error", exc_info=True)
return super()._parse_file(data_file)

View File

@@ -6,125 +6,68 @@ from odoo import api, fields, models
class AccountBankStatementImportPayPalMapping(models.Model):
_name = 'account.bank.statement.import.paypal.mapping'
_description = 'Account Bank Statement Import PayPal Mapping'
_name = "account.bank.statement.import.paypal.mapping"
_description = "Account Bank Statement Import PayPal Mapping"
name = fields.Char(
required=True,
)
name = fields.Char(required=True,)
float_thousands_sep = fields.Selection(
string='Thousands Separator',
selection=[
('dot', 'dot (.)'),
('comma', 'comma (,)'),
('none', 'none'),
],
default='dot',
string="Thousands Separator",
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none")],
default="dot",
required=True,
)
float_decimal_sep = fields.Selection(
string='Decimals Separator',
selection=[
('dot', 'dot (.)'),
('comma', 'comma (,)'),
('none', 'none'),
],
default='comma',
required=True,
)
date_format = fields.Char(
string='Date Format',
required=True,
)
time_format = fields.Char(
string='Time Format',
required=True,
)
date_column = fields.Char(
string='"Date" column',
required=True,
)
time_column = fields.Char(
string='"Time" column',
required=True,
)
tz_column = fields.Char(
string='"Timezone" column',
required=True,
)
name_column = fields.Char(
string='"Name" column',
required=True,
)
currency_column = fields.Char(
string='"Currency" column',
required=True,
)
gross_column = fields.Char(
string='"Gross" column',
required=True,
)
fee_column = fields.Char(
string='"Fee" column',
required=True,
)
balance_column = fields.Char(
string='"Balance" column',
string="Decimals Separator",
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none")],
default="comma",
required=True,
)
date_format = fields.Char(string="Date Format", required=True,)
time_format = fields.Char(string="Time Format", required=True,)
date_column = fields.Char(string='"Date" column', required=True,)
time_column = fields.Char(string='"Time" column', required=True,)
tz_column = fields.Char(string='"Timezone" column', required=True,)
name_column = fields.Char(string='"Name" column', required=True,)
currency_column = fields.Char(string='"Currency" column', required=True,)
gross_column = fields.Char(string='"Gross" column', required=True,)
fee_column = fields.Char(string='"Fee" column', required=True,)
balance_column = fields.Char(string='"Balance" column', required=True,)
transaction_id_column = fields.Char(
string='"Transaction ID" column',
required=True,
)
description_column = fields.Char(
string='"Description" column',
)
type_column = fields.Char(
string='"Type" column',
)
from_email_address_column = fields.Char(
string='"From Email Address" column',
)
to_email_address_column = fields.Char(
string='"To Email Address" column',
)
invoice_id_column = fields.Char(
string='"Invoice ID" column',
)
subject_column = fields.Char(
string='"Subject" column',
)
note_column = fields.Char(
string='"Note" column',
)
bank_name_column = fields.Char(
string='"Bank Name" column',
)
bank_account_column = fields.Char(
string='"Bank Account" column',
string='"Transaction ID" column', required=True,
)
description_column = fields.Char(string='"Description" column',)
type_column = fields.Char(string='"Type" column',)
from_email_address_column = fields.Char(string='"From Email Address" column',)
to_email_address_column = fields.Char(string='"To Email Address" column',)
invoice_id_column = fields.Char(string='"Invoice ID" column',)
subject_column = fields.Char(string='"Subject" column',)
note_column = fields.Char(string='"Note" column',)
bank_name_column = fields.Char(string='"Bank Name" column',)
bank_account_column = fields.Char(string='"Bank Account" column',)
@api.onchange('float_thousands_sep')
@api.onchange("float_thousands_sep")
def onchange_thousands_separator(self):
if 'dot' == self.float_thousands_sep == self.float_decimal_sep:
self.float_decimal_sep = 'comma'
elif 'comma' == self.float_thousands_sep == self.float_decimal_sep:
self.float_decimal_sep = 'dot'
if "dot" == self.float_thousands_sep == self.float_decimal_sep:
self.float_decimal_sep = "comma"
elif "comma" == self.float_thousands_sep == self.float_decimal_sep:
self.float_decimal_sep = "dot"
@api.onchange('float_decimal_sep')
@api.onchange("float_decimal_sep")
def onchange_decimal_separator(self):
if 'dot' == self.float_thousands_sep == self.float_decimal_sep:
self.float_thousands_sep = 'comma'
elif 'comma' == self.float_thousands_sep == self.float_decimal_sep:
self.float_thousands_sep = 'dot'
if "dot" == self.float_thousands_sep == self.float_decimal_sep:
self.float_thousands_sep = "comma"
elif "comma" == self.float_thousands_sep == self.float_decimal_sep:
self.float_thousands_sep = "dot"
@api.multi
def _get_float_separators(self):
self.ensure_one()
separators = {
'dot': '.',
'comma': ',',
'none': '',
"dot": ".",
"comma": ",",
"none": "",
}
return (separators[self.float_thousands_sep],
separators[self.float_decimal_sep])
return (
separators[self.float_thousands_sep],
separators[self.float_decimal_sep],
)

View File

@@ -2,16 +2,17 @@
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, models, _
import itertools
import logging
from datetime import datetime
from decimal import Decimal
from io import StringIO
from os import path
import itertools
from pytz import timezone, utc
import logging
from odoo import _, api, models
_logger = logging.getLogger(__name__)
try:
@@ -21,62 +22,56 @@ except (ImportError, IOError) as err:
class AccountBankStatementImportPayPalParser(models.TransientModel):
_name = 'account.bank.statement.import.paypal.parser'
_description = 'Account Bank Statement Import PayPal Parser'
_name = "account.bank.statement.import.paypal.parser"
_description = "Account Bank Statement Import PayPal Parser"
@api.model
def parse_header(self, data_file):
data = StringIO(data_file.decode('utf-8-sig'))
data = StringIO(data_file.decode("utf-8-sig"))
csv_data = reader(data)
return list(next(csv_data))
@api.model
def parse(self, mapping, data_file, filename):
journal = self.env['account.journal'].browse(
self.env.context.get('journal_id')
)
currency_code = (
journal.currency_id or journal.company_id.currency_id
).name
journal = self.env["account.journal"].browse(self.env.context.get("journal_id"))
currency_code = (journal.currency_id or journal.company_id.currency_id).name
account_number = journal.bank_account_id.acc_number
name = _('%s: %s') % (
journal.code,
path.basename(filename),
)
name = _("%s: %s") % (journal.code, path.basename(filename),)
lines = self._parse_lines(mapping, data_file, currency_code)
if not lines:
return currency_code, account_number, [{
'name': name,
'transactions': [],
}]
return currency_code, account_number, [{"name": name, "transactions": []}]
lines = list(sorted(
lines,
key=lambda line: line['timestamp']
))
lines = list(sorted(lines, key=lambda line: line["timestamp"]))
first_line = lines[0]
balance_start = first_line['balance_amount']
balance_start -= first_line['gross_amount']
balance_start -= first_line['fee_amount']
balance_start = first_line["balance_amount"]
balance_start -= first_line["gross_amount"]
balance_start -= first_line["fee_amount"]
last_line = lines[-1]
balance_end = last_line['balance_amount']
balance_end = last_line["balance_amount"]
transactions = list(itertools.chain.from_iterable(map(
lambda line: self._convert_line_to_transactions(line),
lines
)))
transactions = list(
itertools.chain.from_iterable(
map(lambda line: self._convert_line_to_transactions(line), lines)
)
)
return currency_code, account_number, [{
'name': name,
'date': first_line['timestamp'].date(),
'balance_start': float(balance_start),
'balance_end_real': float(balance_end),
'transactions': transactions,
}]
return (
currency_code,
account_number,
[
{
"name": name,
"date": first_line["timestamp"].date(),
"balance_start": float(balance_start),
"balance_end_real": float(balance_end),
"transactions": transactions,
}
],
)
def _parse_lines(self, mapping, data_file, currency_code):
data = StringIO(data_file.decode('utf-8-sig'))
data = StringIO(data_file.decode("utf-8-sig"))
csv_data = reader(data)
header = list(next(csv_data))
@@ -98,15 +93,11 @@ class AccountBankStatementImportPayPalParser(models.TransientModel):
except ValueError:
type_column = None
try:
from_email_address_column = header.index(
mapping.from_email_address_column
)
from_email_address_column = header.index(mapping.from_email_address_column)
except ValueError:
from_email_address_column = None
try:
to_email_address_column = header.index(
mapping.to_email_address_column
)
to_email_address_column = header.index(mapping.to_email_address_column)
except ValueError:
to_email_address_column = None
try:
@@ -142,24 +133,31 @@ class AccountBankStatementImportPayPalParser(models.TransientModel):
fee_value = row[fee_column]
balance_value = row[balance_column]
transaction_id_value = row[transaction_id_column]
description_value = row[description_column] \
if description_column is not None else None
type_value = row[type_column] \
if type_column is not None else None
from_email_address_value = row[from_email_address_column] \
if from_email_address_column is not None else None
to_email_address_value = row[to_email_address_column] \
if to_email_address_column is not None else None
invoice_id_value = row[invoice_id_column] \
if invoice_id_column is not None else None
subject_value = row[subject_column] \
if subject_column is not None else None
note_value = row[note_column] \
if note_column is not None else None
bank_name_value = row[bank_name_column] \
if bank_name_column is not None else None
bank_account_value = row[bank_account_column] \
if bank_account_column is not None else None
description_value = (
row[description_column] if description_column is not None else None
)
type_value = row[type_column] if type_column is not None else None
from_email_address_value = (
row[from_email_address_column]
if from_email_address_column is not None
else None
)
to_email_address_value = (
row[to_email_address_column]
if to_email_address_column is not None
else None
)
invoice_id_value = (
row[invoice_id_column] if invoice_id_column is not None else None
)
subject_value = row[subject_column] if subject_column is not None else None
note_value = row[note_column] if note_column is not None else None
bank_name_value = (
row[bank_name_column] if bank_name_column is not None else None
)
bank_account_value = (
row[bank_account_column] if bank_account_column is not None else None
)
if currency_value != currency_code:
continue
@@ -174,102 +172,100 @@ class AccountBankStatementImportPayPalParser(models.TransientModel):
gross_amount = self._parse_decimal(gross_value, mapping)
fee_amount = self._parse_decimal(fee_value, mapping)
balance_amount = self._parse_decimal(balance_value, mapping)
bank = '%s - %s' % (
bank_name_value,
bank_account_value,
) if bank_name_value and bank_account_value else None
bank = (
"{} - {}".format(bank_name_value, bank_account_value)
if bank_name_value and bank_account_value
else None
)
if to_email_address_column is None:
payer_email = from_email_address_value
else:
payer_email = to_email_address_value \
if gross_amount < 0.0 else from_email_address_value
payer_email = (
to_email_address_value
if gross_amount < 0.0
else from_email_address_value
)
lines.append({
'transaction_id': transaction_id_value,
'invoice': invoice_id_value,
'description': description_value or type_value,
'details': subject_value or note_value or bank,
'timestamp': timestamp,
'gross_amount': gross_amount,
'fee_amount': fee_amount,
'balance_amount': balance_amount,
'payer_name': name_value,
'payer_email': payer_email,
'partner_bank_name': bank_name_value,
'partner_bank_account': bank_account_value,
})
lines.append(
{
"transaction_id": transaction_id_value,
"invoice": invoice_id_value,
"description": description_value or type_value,
"details": subject_value or note_value or bank,
"timestamp": timestamp,
"gross_amount": gross_amount,
"fee_amount": fee_amount,
"balance_amount": balance_amount,
"payer_name": name_value,
"payer_email": payer_email,
"partner_bank_name": bank_name_value,
"partner_bank_account": bank_account_value,
}
)
return lines
@api.model
def _convert_line_to_transactions(self, line):
transactions = []
transaction_id = line['transaction_id']
invoice = line['invoice']
description = line['description']
details = line['details']
timestamp = line['timestamp']
gross_amount = line['gross_amount']
fee_amount = line['fee_amount']
payer_name = line['payer_name']
payer_email = line['payer_email']
partner_bank_account = line['partner_bank_account']
transaction_id = line["transaction_id"]
invoice = line["invoice"]
description = line["description"]
details = line["details"]
timestamp = line["timestamp"]
gross_amount = line["gross_amount"]
fee_amount = line["fee_amount"]
payer_name = line["payer_name"]
payer_email = line["payer_email"]
partner_bank_account = line["partner_bank_account"]
if invoice:
invoice = _('Invoice %s') % invoice
note = '%s %s' % (
description,
transaction_id,
)
invoice = _("Invoice %s") % invoice
note = "{} {}".format(description, transaction_id)
if details:
note += ': %s' % details
note += ": %s" % details
if payer_email:
note += ' (%s)' % payer_email
note += " (%s)" % payer_email
unique_import_id = '%s-%s' % (
transaction_id,
int(timestamp.timestamp()),
)
name = invoice or details or description or '',
unique_import_id = "{}-{}".format(transaction_id, int(timestamp.timestamp()))
name = (invoice or details or description or "",)
transaction = {
'name': invoice or details or description or '',
'amount': str(gross_amount),
'date': timestamp,
'note': note,
'unique_import_id': unique_import_id,
"name": invoice or details or description or "",
"amount": str(gross_amount),
"date": timestamp,
"note": note,
"unique_import_id": unique_import_id,
}
if payer_name:
line.update({
'partner_name': payer_name,
})
line.update({"partner_name": payer_name})
if partner_bank_account:
line.update({
'account_number': partner_bank_account,
})
line.update({"account_number": partner_bank_account})
transactions.append(transaction)
if fee_amount:
transactions.append({
'name': _('Fee for %s') % (name or transaction_id),
'amount': str(fee_amount),
'date': timestamp,
'partner_name': 'PayPal',
'unique_import_id': '%s-FEE' % unique_import_id,
'note': _('Transaction fee for %s') % note,
})
transactions.append(
{
"name": _("Fee for %s") % (name or transaction_id),
"amount": str(fee_amount),
"date": timestamp,
"partner_name": "PayPal",
"unique_import_id": "%s-FEE" % unique_import_id,
"note": _("Transaction fee for %s") % note,
}
)
return transactions
@api.model
def _parse_decimal(self, value, mapping):
thousands, decimal = mapping._get_float_separators()
value = value.replace(thousands, '')
value = value.replace(decimal, '.')
value = value.replace(thousands, "")
value = value.replace(decimal, ".")
return Decimal(value)
@api.model
def _normalize_tz(self, value):
if value in ['PDT', 'PST']:
return 'America/Los_Angeles'
elif value in ['CET', 'CEST']:
return 'Europe/Paris'
if value in ["PDT", "PST"]:
return "America/Los_Angeles"
elif value in ["CET", "CEST"]:
return "Europe/Paris"
return value

View File

@@ -6,9 +6,9 @@ from odoo import models
class AccountJournal(models.Model):
_inherit = 'account.journal'
_inherit = "account.journal"
def _get_bank_statements_available_import_formats(self):
res = super()._get_bank_statements_available_import_formats()
res.append('PayPal Reports')
res.append("PayPal Reports")
return res

View File

@@ -2,200 +2,210 @@
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from base64 import b64encode
from os import path
from odoo import fields
from odoo.exceptions import UserError
from odoo.tests import common
from base64 import b64encode
from os import path
class TestAccountBankStatementImportPayPal(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.currency_eur = self.env.ref("base.EUR")
self.currency_usd = self.env.ref("base.USD")
self.paypal_statement_map_en = self.env.ref(
'account_bank_statement_import_paypal.paypal_statement_map_en'
"account_bank_statement_import_paypal.paypal_statement_map_en"
)
self.paypal_statement_map_es = self.env.ref(
'account_bank_statement_import_paypal.paypal_statement_map_es'
"account_bank_statement_import_paypal.paypal_statement_map_es"
)
self.paypal_activity_map_en = self.env.ref(
'account_bank_statement_import_paypal.paypal_activity_map_en'
"account_bank_statement_import_paypal.paypal_activity_map_en"
)
self.AccountJournal = self.env['account.journal']
self.AccountBankStatement = self.env['account.bank.statement']
self.AccountBankStatementImport = self.env[
'account.bank.statement.import'
]
self.AccountJournal = self.env["account.journal"]
self.AccountBankStatement = self.env["account.bank.statement"]
self.AccountBankStatementImport = self.env["account.bank.statement.import"]
self.AccountBankStatementImportPayPalMapping = self.env[
'account.bank.statement.import.paypal.mapping'
"account.bank.statement.import.paypal.mapping"
]
self.AccountBankStatementImportPayPalMappingWizard = self.env[
'account.bank.statement.import.paypal.mapping.wizard'
"account.bank.statement.import.paypal.mapping.wizard"
]
def _data_file(self, filename):
with open(path.join(path.dirname(__file__), filename)) as file:
return b64encode(file.read().encode('utf-8'))
return b64encode(file.read().encode("utf-8"))
def test_import_statement_en_usd(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_usd.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/statement_en.csv',
'data_file': self._data_file('fixtures/statement_en.csv'),
'paypal_mapping_id': self.paypal_statement_map_en.id,
})
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
journal = self.AccountJournal.create(
{
"name": "PayPal",
"type": "bank",
"code": "PP",
"currency_id": self.currency_usd.id,
}
)
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id}
).create(
{
"filename": "fixtures/statement_en.csv",
"data_file": self._data_file("fixtures/statement_en.csv"),
"paypal_mapping_id": self.paypal_statement_map_en.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_paypal_test": True,
}
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 18)
def test_import_statement_en_eur(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_eur.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/statement_en.csv',
'data_file': self._data_file('fixtures/statement_en.csv'),
'paypal_mapping_id': self.paypal_statement_map_en.id,
})
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
journal = self.AccountJournal.create(
{
"name": "PayPal",
"type": "bank",
"code": "PP",
"currency_id": self.currency_eur.id,
}
)
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id}
).create(
{
"filename": "fixtures/statement_en.csv",
"data_file": self._data_file("fixtures/statement_en.csv"),
"paypal_mapping_id": self.paypal_statement_map_en.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_paypal_test": True,
}
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 8)
def test_import_statement_es(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_eur.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/statement_es.csv',
'data_file': self._data_file('fixtures/statement_es.csv'),
'paypal_mapping_id': self.paypal_statement_map_es.id,
})
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
journal = self.AccountJournal.create(
{
"name": "PayPal",
"type": "bank",
"code": "PP",
"currency_id": self.currency_eur.id,
}
)
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id}
).create(
{
"filename": "fixtures/statement_es.csv",
"data_file": self._data_file("fixtures/statement_es.csv"),
"paypal_mapping_id": self.paypal_statement_map_es.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_paypal_test": True,
}
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 8)
def test_import_activity_en(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_usd.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/activity_en.csv',
'data_file': self._data_file('fixtures/activity_en.csv'),
'paypal_mapping_id': self.paypal_activity_map_en.id,
})
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
journal = self.AccountJournal.create(
{
"name": "PayPal",
"type": "bank",
"code": "PP",
"currency_id": self.currency_usd.id,
}
)
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id}
).create(
{
"filename": "fixtures/activity_en.csv",
"data_file": self._data_file("fixtures/activity_en.csv"),
"paypal_mapping_id": self.paypal_activity_map_en.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_paypal_test": True,
}
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 71)
def test_import_empty_activity(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_usd.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/empty_activity.csv',
'data_file': self._data_file('fixtures/empty_activity.csv'),
'paypal_mapping_id': self.paypal_activity_map_en.id,
})
journal = self.AccountJournal.create(
{
"name": "PayPal",
"type": "bank",
"code": "PP",
"currency_id": self.currency_usd.id,
}
)
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id}
).create(
{
"filename": "fixtures/empty_activity.csv",
"data_file": self._data_file("fixtures/empty_activity.csv"),
"paypal_mapping_id": self.paypal_activity_map_en.id,
}
)
with self.assertRaises(UserError):
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_paypal_test": True,
}
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 0)
def test_import_activity_mapping_en(self):
with common.Form(
self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = 'fixtures/activity_en.csv'
form.data_file = self._data_file(
'fixtures/activity_en.csv'
)
with common.Form(self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = "fixtures/activity_en.csv"
form.data_file = self._data_file("fixtures/activity_en.csv")
self.assertEqual(
len(
self.AccountBankStatementImportPayPalMappingWizard
.with_context(
header=form.header,
).statement_columns()
self.AccountBankStatementImportPayPalMappingWizard.with_context(
header=form.header,
).statement_columns()
),
22
22,
)
wizard = form.save()
wizard.import_mapping()
def test_import_statement_mapping_en(self):
with common.Form(
self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = 'fixtures/statement_en.csv'
form.data_file = self._data_file(
'fixtures/statement_en.csv'
)
with common.Form(self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = "fixtures/statement_en.csv"
form.data_file = self._data_file("fixtures/statement_en.csv")
self.assertEqual(
len(
self.AccountBankStatementImportPayPalMappingWizard
.with_context(
header=form.header,
).statement_columns()
self.AccountBankStatementImportPayPalMappingWizard.with_context(
header=form.header,
).statement_columns()
),
18
18,
)
wizard = form.save()
wizard.import_mapping()

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2014-2017 Akretion (http://www.akretion.com).
Copyright 2019 Tecnativa - Vicent Cubells
@@ -6,18 +6,22 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_bank_statement_import_view" model="ir.ui.view">
<field name="name">account.bank.statement.import</field>
<field name="model">account.bank.statement.import</field>
<field name="inherit_id" ref="account_bank_statement_import.account_bank_statement_import_view"/>
<field
name="inherit_id"
ref="account_bank_statement_import.account_bank_statement_import_view"
/>
<field name="arch" type="xml">
<xpath expr="//ul[@id='statement_format']" position="inside">
<li>
PayPal Report mapping: <field name="paypal_mapping_id" nolabel="1"/>
PayPal Report mapping: <field
name="paypal_mapping_id"
nolabel="1"
/>
</li>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,21 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2019 Tecnativa - Vicent Cubells
Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_bank_statement_import_paypal_mapping_form" model="ir.ui.view">
<field name="name">account.bank.statement.import.paypal.mapping.form</field>
<field name="model">account.bank.statement.import.paypal.mapping</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="name" />
</tree>
</field>
</record>
<record id="account_bank_statement_import_paypal_mapping_tree" model="ir.ui.view">
<field name="name">account.bank.statement.import.paypal.mapping.tree</field>
<field name="model">account.bank.statement.import.paypal.mapping</field>
@@ -23,56 +21,58 @@
<form>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<label for="name" class="oe_edit_only" />
<h1>
<field name="name" />
</h1>
</div>
<group>
<group>
<field name="float_thousands_sep"/>
<field name="float_decimal_sep"/>
<field name="float_thousands_sep" />
<field name="float_decimal_sep" />
</group>
<group>
<field name="date_format"/>
<field name="time_format"/>
<field name="date_format" />
<field name="time_format" />
</group>
</group>
<group string="Columns">
<field name="date_column"/>
<field name="time_column"/>
<field name="tz_column"/>
<field name="name_column"/>
<field name="currency_column"/>
<field name="gross_column"/>
<field name="fee_column"/>
<field name="balance_column"/>
<field name="transaction_id_column"/>
<field name="description_column"/>
<field name="type_column"/>
<field name="from_email_address_column"/>
<field name="to_email_address_column"/>
<field name="invoice_id_column"/>
<field name="subject_column"/>
<field name="note_column"/>
<field name="bank_name_column"/>
<field name="bank_account_column"/>
<field name="date_column" />
<field name="time_column" />
<field name="tz_column" />
<field name="name_column" />
<field name="currency_column" />
<field name="gross_column" />
<field name="fee_column" />
<field name="balance_column" />
<field name="transaction_id_column" />
<field name="description_column" />
<field name="type_column" />
<field name="from_email_address_column" />
<field name="to_email_address_column" />
<field name="invoice_id_column" />
<field name="subject_column" />
<field name="note_column" />
<field name="bank_name_column" />
<field name="bank_account_column" />
</group>
</sheet>
</form>
</field>
</record>
<record id="action_statement_import_paypal_report_mappings" model="ir.actions.act_window">
<record
id="action_statement_import_paypal_report_mappings"
model="ir.actions.act_window"
>
<field name="name">PayPal Report Mappings</field>
<field name="res_model">account.bank.statement.import.paypal.mapping</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_statement_import_paypal_mapping"
parent="account.account_account_menu"
action="action_statement_import_paypal_report_mappings"
name="PayPal Report Mappings"
/>
</odoo>

View File

@@ -2,82 +2,43 @@
# Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from base64 import b64decode
import json
from base64 import b64decode
from os import path
from odoo import _, api, fields, models
class AccountBankStatementImportPayPalMappingWizard(models.TransientModel):
_name = 'account.bank.statement.import.paypal.mapping.wizard'
_description = 'Account Bank Statement Import PayPal Mapping Wizard'
_inherit = ['multi.step.wizard.mixin']
_name = "account.bank.statement.import.paypal.mapping.wizard"
_description = "Account Bank Statement Import PayPal Mapping Wizard"
_inherit = ["multi.step.wizard.mixin"]
data_file = fields.Binary(
string='PayPal Report File',
required=True,
)
data_file = fields.Binary(string="PayPal Report File", required=True,)
filename = fields.Char()
header = fields.Char()
date_column = fields.Char(
string='"Date" column',
)
time_column = fields.Char(
string='"Time" column',
)
tz_column = fields.Char(
string='"Timezone" column',
)
name_column = fields.Char(
string='"Name" column',
)
currency_column = fields.Char(
string='"Currency" column',
)
gross_column = fields.Char(
string='"Gross" column',
)
fee_column = fields.Char(
string='"Fee" column',
)
balance_column = fields.Char(
string='"Balance" column',
)
transaction_id_column = fields.Char(
string='"Transaction ID" column',
)
description_column = fields.Char(
string='"Description" column',
)
type_column = fields.Char(
string='"Type" column',
)
from_email_address_column = fields.Char(
string='"From Email Address" column',
)
to_email_address_column = fields.Char(
string='"To Email Address" column',
)
invoice_id_column = fields.Char(
string='"Invoice ID" column',
)
subject_column = fields.Char(
string='"Subject" column',
)
note_column = fields.Char(
string='"Note" column',
)
bank_name_column = fields.Char(
string='"Bank Name" column',
)
bank_account_column = fields.Char(
string='"Bank Account" column',
)
date_column = fields.Char(string='"Date" column',)
time_column = fields.Char(string='"Time" column',)
tz_column = fields.Char(string='"Timezone" column',)
name_column = fields.Char(string='"Name" column',)
currency_column = fields.Char(string='"Currency" column',)
gross_column = fields.Char(string='"Gross" column',)
fee_column = fields.Char(string='"Fee" column',)
balance_column = fields.Char(string='"Balance" column',)
transaction_id_column = fields.Char(string='"Transaction ID" column',)
description_column = fields.Char(string='"Description" column',)
type_column = fields.Char(string='"Type" column',)
from_email_address_column = fields.Char(string='"From Email Address" column',)
to_email_address_column = fields.Char(string='"To Email Address" column',)
invoice_id_column = fields.Char(string='"Invoice ID" column',)
subject_column = fields.Char(string='"Subject" column',)
note_column = fields.Char(string='"Note" column',)
bank_name_column = fields.Char(string='"Bank Name" column',)
bank_account_column = fields.Char(string='"Bank Account" column',)
@api.onchange('data_file')
@api.onchange("data_file")
def _onchange_data_file(self):
Parser = self.env['account.bank.statement.import.paypal.parser']
Parser = self.env["account.bank.statement.import.paypal.parser"]
if not self.data_file:
return
header = Parser.parse_header(b64decode(self.data_file))
@@ -117,7 +78,7 @@ class AccountBankStatementImportPayPalMappingWizard(models.TransientModel):
@api.model
def statement_columns(self):
header = self.env.context.get('header')
header = self.env.context.get("header")
if not header:
return []
return [(x, x) for x in json.loads(header)]
@@ -127,42 +88,43 @@ class AccountBankStatementImportPayPalMappingWizard(models.TransientModel):
"""Hook for extension"""
self.ensure_one()
return {
'name': _('Mapping from %s') % path.basename(self.filename),
'float_thousands_sep': 'comma',
'float_decimal_sep': 'dot',
'date_format': '%d/%m/%Y',
'time_format': '%H:%M:%S',
'date_column': self.date_column,
'time_column': self.time_column,
'tz_column': self.tz_column,
'name_column': self.name_column,
'currency_column': self.currency_column,
'gross_column': self.gross_column,
'fee_column': self.fee_column,
'balance_column': self.balance_column,
'transaction_id_column': self.transaction_id_column,
'description_column': self.description_column,
'type_column': self.type_column,
'from_email_address_column': self.from_email_address_column,
'to_email_address_column': self.to_email_address_column,
'invoice_id_column': self.invoice_id_column,
'subject_column': self.subject_column,
'note_column': self.note_column,
'bank_name_column': self.bank_name_column,
'bank_account_column': self.bank_account_column,
"name": _("Mapping from %s") % path.basename(self.filename),
"float_thousands_sep": "comma",
"float_decimal_sep": "dot",
"date_format": "%d/%m/%Y",
"time_format": "%H:%M:%S",
"date_column": self.date_column,
"time_column": self.time_column,
"tz_column": self.tz_column,
"name_column": self.name_column,
"currency_column": self.currency_column,
"gross_column": self.gross_column,
"fee_column": self.fee_column,
"balance_column": self.balance_column,
"transaction_id_column": self.transaction_id_column,
"description_column": self.description_column,
"type_column": self.type_column,
"from_email_address_column": self.from_email_address_column,
"to_email_address_column": self.to_email_address_column,
"invoice_id_column": self.invoice_id_column,
"subject_column": self.subject_column,
"note_column": self.note_column,
"bank_name_column": self.bank_name_column,
"bank_account_column": self.bank_account_column,
}
@api.multi
def import_mapping(self):
self.ensure_one()
mapping = self.env['account.bank.statement.import.paypal.mapping']\
.create(self._get_mapping_values())
mapping = self.env["account.bank.statement.import.paypal.mapping"].create(
self._get_mapping_values()
)
return {
'type': 'ir.actions.act_window',
'name': _('Imported Mapping'),
'res_model': 'account.bank.statement.import.paypal.mapping',
'res_id': mapping.id,
'view_mode': 'form',
'view_id': False,
'target': 'current',
"type": "ir.actions.act_window",
"name": _("Imported Mapping"),
"res_model": "account.bank.statement.import.paypal.mapping",
"res_id": mapping.id,
"view_mode": "form",
"view_id": False,
"target": "current",
}

View File

@@ -1,28 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2019 Tecnativa - Vicent Cubells
Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_bank_statement_import_paypal_mapping_wizard_form" model="ir.ui.view">
<field name="name">account.bank.statement.import.paypal.mapping.wizard.form</field>
<record
id="account_bank_statement_import_paypal_mapping_wizard_form"
model="ir.ui.view"
>
<field
name="name"
>account.bank.statement.import.paypal.mapping.wizard.form</field>
<field name="model">account.bank.statement.import.paypal.mapping.wizard</field>
<field name="mode">primary</field>
<field name="inherit_id" ref="multi_step_wizard.multi_step_wizard_form"/>
<field name="inherit_id" ref="multi_step_wizard.multi_step_wizard_form" />
<field name="arch" type="xml">
<xpath expr="//footer" position="before">
<h2>Select a PayPal report file to import mapping.</h2>
<group name="start" attrs="{'invisible': [('state', '!=', 'start')]}">
<group colspan="2">
<field name="data_file" filename="filename" placeholder="Choose a file to import..."/>
<field name="filename" invisible="1"/>
<field
name="data_file"
filename="filename"
placeholder="Choose a file to import..."
/>
<field name="filename" invisible="1" />
</group>
</group>
<group name="final" attrs="{'invisible': [('state', '!=', 'final')]}">
<group colspan="2">
<field name="header" invisible="1"/>
<field name="header" invisible="1" />
<field
name="date_column"
widget="dynamic_dropdown"
@@ -144,11 +152,16 @@
</group>
</xpath>
<xpath expr="//div[@name='states_buttons']/button" position="before">
<button name="import_mapping" string="Import" type="object" class="btn-primary" attrs="{'invisible': [('state', '!=', 'final')]}"/>
<button
name="import_mapping"
string="Import"
type="object"
class="btn-primary"
attrs="{'invisible': [('state', '!=', 'final')]}"
/>
</xpath>
</field>
</record>
<act_window
id="action_account_bank_statement_import_paypal_mapping_wizard"
name="Import Mapping"
@@ -158,5 +171,4 @@
target="new"
key2="client_action_multi"
/>
</odoo>