[MIG] account_bank_statement_import_adyen Migrate to 13.0

This commit is contained in:
Ronald Portier
2021-02-17 16:55:26 +01:00
committed by Ronald Portier (Therp BV)
parent 9e2a82cca0
commit 302e0d8955
19 changed files with 747 additions and 175 deletions

View File

@@ -0,0 +1 @@
from . import test_clearing_account

View File

@@ -0,0 +1,120 @@
# Copyright 2017 Opener BV <https://opener.amsterdam>
# Copyright 2020 Vanmoof BV <https://www.vanmoof.com>
# Copyright 2015-2021 Therp BV <https://therp.nl>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests.common import SavepointCase
class TestClearingAccount(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.journal = cls.env["account.journal"].create(
{
"company_id": cls.env.user.company_id.id,
"name": "Clearing account test",
"code": "CAT",
"type": "bank",
"currency_id": cls.env.ref("base.USD").id,
}
)
cls.partner_customer = cls.env["res.partner"].create({"name": "cutomer"})
cls.partner_provider = cls.env["res.partner"].create({"name": "provider"})
# Enable reconcilation on the default journal account to trigger
# the functionality from account_bank_statement_clearing_account
cls.journal.default_debit_account_id.reconcile = True
def test_reconcile_unreconcile(self):
"""Test that a bank statement that satiesfies the conditions, cab be
automatically reconciled and unreconciled on confirmation or reset of the
statement.
"""
account = self.journal.default_debit_account_id
statement = self.env["account.bank.statement"].create(
{
"name": "Test autoreconcile 2021-03-08",
"reference": "AUTO-2021-08-03",
"date": "2021-03-08",
"state": "open",
"journal_id": self.journal.id,
"line_ids": [
(
0,
0,
{
"name": "web sale",
"partner_id": self.partner_customer.id,
"amount": 100.00,
"account_id": account.id,
},
),
(
0,
0,
{
"name": "transaction_fees",
"partner_id": False,
"amount": -1.25,
"account_id": account.id,
},
),
(
0,
0,
{
"name": "due_from_provider",
"partner_id": self.partner_provider.id,
"amount": -98.75,
"account_id": account.id,
},
),
],
}
)
self.assertEqual(statement.journal_id, self.journal)
self.assertEqual(len(statement.line_ids), 3)
self.assertTrue(
self.env.user.company_id.currency_id.is_zero(
sum(line.amount for line in statement.line_ids)
)
)
account = self.env["account.account"].search(
[("internal_type", "=", "receivable")], limit=1
)
for line in statement.line_ids:
line.process_reconciliation(
new_aml_dicts=[
{
"debit": -line.amount if line.amount < 0 else 0,
"credit": line.amount if line.amount > 0 else 0,
"account_id": account.id,
}
]
)
statement.button_confirm_bank()
self.assertEqual(statement.state, "confirm")
lines = self.env["account.move.line"].search(
[
("account_id", "=", self.journal.default_debit_account_id.id),
("statement_id", "=", statement.id),
]
)
reconcile = lines.mapped("full_reconcile_id")
self.assertEqual(len(reconcile), 1)
self.assertEqual(lines, reconcile.reconciled_line_ids)
# Reset the bank statement to see the counterpart lines being
# unreconciled
statement.button_reopen()
self.assertEqual(statement.state, "open")
self.assertFalse(lines.mapped("matched_debit_ids"))
self.assertFalse(lines.mapped("matched_credit_ids"))
self.assertFalse(lines.mapped("full_reconcile_id"))
# Confirm the statement without the correct clearing account settings
self.journal.default_debit_account_id.reconcile = False
statement.button_confirm_bank()
self.assertEqual(statement.state, "confirm")
self.assertFalse(lines.mapped("matched_debit_ids"))
self.assertFalse(lines.mapped("matched_credit_ids"))
self.assertFalse(lines.mapped("full_reconcile_id"))

View File

@@ -1,35 +1,97 @@
**This file is going to be generated by oca-gen-addon-readme.**
======================
Adyen statement import
======================
*Manual changes will be overwritten.*
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Please provide content in the ``readme`` directory:
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github
:target: https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_adyen
:alt: OCA/bank-statement-import
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/bank-statement-import-13-0/bank-statement-import-13-0-account_bank_statement_import_adyen
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/174/13.0
:alt: Try me on Runbot
* **DESCRIPTION.rst** (required)
* INSTALL.rst (optional)
* CONFIGURE.rst (optional)
* **USAGE.rst** (optional, highly recommended)
* DEVELOP.rst (optional)
* ROADMAP.rst (optional)
* HISTORY.rst (optional, recommended)
* **CONTRIBUTORS.rst** (optional, highly recommended)
* CREDITS.rst (optional)
|badge1| |badge2| |badge3| |badge4| |badge5|
Content of this README will also be drawn from the addon manifest,
from keys such as name, authors, maintainers, development_status,
and license.
This module processes Adyen transaction statements, the settlement details report,
in excel or csv format.
A good, one sentence summary in the manifest is also highly recommended.
You can import the statements in a dedicated journal. Reconcile your sale invoices
with the credit transations. Reconcile the aggregated counterpart
transaction with the transaction in your real bank journal and register the
aggregated fee line containing commision and markup on the applicable
cost account.
**Table of contents**
Automatic changelog generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. contents::
:local:
`HISTORY.rst` can be auto generated using `towncrier <https://pypi.org/project/towncrier>`_.
Configuration
=============
Just put towncrier compatible changelog fragments into `readme/newsfragments`
and the changelog file will be automatically generated and updated when a new fragment is added.
Configure a pseudo bank journal by creating a new journal linked to your Adyen
merchant account. Set your merchant account string in the Advanced settings
on the journal form.
Please refer to `towncrier` documentation to know more.
Usage
=====
NOTE: the changelog will be automatically generated when using `/ocabot merge $option`.
If you need to run it manually, refer to `OCA/maintainer-tools README <https://github.com/OCA/maintainer-tools>`_.
After installing this module, you can import your Adyen transaction statements
through Menu Finance -> Bank -> Import. Don't enter a journal in the import
wizard.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-statement-import/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_adyen%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Opener BV
* Vanmoof BV
Contributors
~~~~~~~~~~~~
* Stefan Rijnhart <stefan@opener.amsterdam> (https://opener.amsterdam)
* Martin Pishpecki <pishpecki@gmail.com> (https://www.vanmoof.com)
* Ronald Portier <ronald@therp.nl> (https://therp.nl)
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/bank-statement-import <https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_adyen>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -1,18 +1,19 @@
# © 2017 Opener BV (<https://opener.amsterdam>)
# © 2020 Vanmoof BV (<https://www.vanmoof.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2017 Opener BV <https://opener.amsterdam>
# Copyright 2020 Vanmoof BV <https://www.vanmoof.com>
# Copyright 2021 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Adyen statement import",
"version": "12.0.1.0.0",
"version": "13.0.1.0.0",
"author": "Opener BV, Vanmoof BV, Odoo Community Association (OCA)",
"category": "Banking addons",
"website": "https://github.com/oca/bank-statement-import",
"license": "AGPL-3",
"depends": [
"base_import",
"account_bank_statement_import",
"account_bank_statement_clearing_account",
],
"external_dependencies": {"python": ["openpyxl",],},
"data": ["views/account_journal.xml",],
"data": ["views/account_journal.xml"],
"installable": True,
}

View File

@@ -1,13 +1,12 @@
# © 2017 Opener BV (<https://opener.amsterdam>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from io import BytesIO
from zipfile import BadZipfile
# Copyright 2017 Opener BV (<https://opener.amsterdam>)
# Copyright 2021 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import logging
from openpyxl import load_workbook
from odoo import api, fields, models
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools.translate import _
_logger = logging.getLogger(__name__)
class AccountBankStatementImport(models.TransientModel):
@@ -15,15 +14,14 @@ class AccountBankStatementImport(models.TransientModel):
@api.model
def _parse_file(self, data_file):
"""Parse an Adyen xlsx file and map merchant account strings
to journals. """
"""Parse an Adyen xlsx file and map merchant account strings to journals."""
try:
return self.import_adyen_xlsx(data_file)
except ValueError:
return super(AccountBankStatementImport, self)._parse_file(data_file)
return super()._parse_file(data_file)
def _find_additional_data(self, currency_code, account_number):
""" Try to find journal by Adyen merchant account """
"""Try to find journal by Adyen merchant account."""
if account_number:
journal = self.env["account.journal"].search(
[("adyen_merchant_account", "=", account_number)], limit=1
@@ -39,14 +37,12 @@ class AccountBankStatementImport(models.TransientModel):
% account_number
)
self = self.with_context(journal_id=journal.id)
return super(AccountBankStatementImport, self)._find_additional_data(
currency_code, account_number
)
return super()._find_additional_data(currency_code, account_number)
@api.model
def balance(self, row):
return -(row[15] or 0) + sum(
row[i] if row[i] else 0.0 for i in (16, 17, 18, 19, 20)
return -(float(row[15]) if row[15] else 0.0) + sum(
float(row[i]) if row[i] else 0.0 for i in (16, 17, 18, 19, 20)
)
@api.model
@@ -62,7 +58,7 @@ class AccountBankStatementImport(models.TransientModel):
statement["transactions"].append(transaction)
@api.model
def import_adyen_xlsx(self, data_file):
def parse_adyen_file(self, data_file):
statements = []
statement = None
headers = False
@@ -71,52 +67,49 @@ class AccountBankStatementImport(models.TransientModel):
payout = 0.0
statement_id = None
with BytesIO() as buf:
buf.write(data_file)
try:
sheet = load_workbook(buf)._sheets[0]
except BadZipfile as e:
raise ValueError(e)
for row in sheet.rows:
row = [cell.value for cell in row]
if len(row) != 31:
raise ValueError(
"Not an Adyen statement. Unexpected row length %s "
"instead of 31" % len(row)
)
if not row[1]:
continue
if not headers:
if row[1] != "Company Account":
raise ValueError(
'Not an Adyen statement. Unexpected header "%s" '
'instead of "Company Account"',
row[1],
)
headers = True
continue
if not statement:
statement = {"transactions": []}
statements.append(statement)
statement_id = "{} {}/{}".format(
row[2],
row[6].strftime("%Y"),
int(row[23]),
)
currency_code = row[14]
merchant_id = row[2]
statement["name"] = "{} {}/{}".format(row[2], row[6].year, row[23])
date = fields.Date.from_string(row[6])
if not statement.get("date") or statement.get("date") > date:
statement["date"] = date
import_model = self.env["base_import.import"]
importer = import_model.create(
{"file": data_file, "file_name": "Ayden settlemnt details"}
)
rows = importer._read_file({})
row[8] = row[8].strip()
if row[8] == "MerchantPayout":
payout -= self.balance(row)
else:
balance += self.balance(row)
self.import_adyen_transaction(statement, statement_id, row)
fees += sum(row[i] if row[i] else 0.0 for i in (17, 18, 19, 20))
for row in rows:
if len(row) != 31:
raise ValueError(
"Not an Adyen statement. Unexpected row length %s "
"instead of 31" % len(row)
)
if not row[1]:
continue
if not headers:
if row[1] != "Company Account":
raise ValueError(
'Not an Adyen statement. Unexpected header "%s" '
'instead of "Company Account"',
row[1],
)
headers = True
continue
if not statement:
statement = {"transactions": []}
statements.append(statement)
statement_id = "{merchant} {year}/{batch}".format(
merchant=row[2], year=row[6][:4], batch=row[23],
)
currency_code = row[14]
merchant_id = row[2]
statement["name"] = statement_id
date = fields.Date.from_string(row[6])
if not statement.get("date") or statement.get("date") > date:
statement["date"] = date
row[8] = row[8].strip()
if row[8] == "MerchantPayout":
payout -= self.balance(row)
else:
balance += self.balance(row)
self.import_adyen_transaction(statement, statement_id, row)
fees += sum(float(row[i]) if row[i] else 0.0 for i in (17, 18, 19, 20))
if not headers:
raise ValueError("Not an Adyen statement. Did not encounter header row.")

View File

@@ -1,10 +1,10 @@
# © 2017 Opener BV (<https://opener.amsterdam>)
# © 2020 Vanmoof BV (<https://www.vanmoof.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2017 Opener BV (<https://opener.amsterdam>)
# Copyright 2020 Vanmoof BV (<https://www.vanmoof.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class Journal(models.Model):
class AccountJournal(models.Model):
_inherit = "account.journal"
adyen_merchant_account = fields.Char(
@@ -15,6 +15,6 @@ class Journal(models.Model):
)
def _get_bank_statements_available_import_formats(self):
res = super(Journal, self)._get_bank_statements_available_import_formats()
res = super()._get_bank_statements_available_import_formats()
res.append("adyen")
return res

View File

@@ -1,3 +1,3 @@
Configure a pseudo bank journal by creating a new journal with a dedicated
Adyen clearing account as the default ledger account. Set your merchant
account string in the Advanced settings on the journal form.
Configure a pseudo bank journal by creating a new journal linked to your Adyen
merchant account. Set your merchant account string in the Advanced settings
on the journal form.

View File

@@ -1,2 +1,3 @@
* Stefan Rijnhart <stefan@opener.amsterdam> (https://opener.amsterdam)
* Martin Pishpecki <pishpecki@gmail.com> (https://www.vanmoof.com)
* Ronald Portier <ronald@therp.nl> (https://therp.nl)

View File

@@ -1,9 +1,7 @@
======================
Adyen statement import
======================
This module processes Adyen transaction statements, the settlement details report,
in excel or csv format.
This module processes Adyen transaction statements in xlsx format. You can
import the statements in a dedicated journal. Reconcile your sale invoices
You can import the statements in a dedicated journal. Reconcile your sale invoices
with the credit transations. Reconcile the aggregated counterpart
transaction with the transaction in your real bank journal and register the
aggregated fee line containing commision and markup on the applicable

View File

@@ -0,0 +1,442 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Adyen statement import</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="adyen-statement-import">
<h1 class="title">Adyen statement import</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_adyen"><img alt="OCA/bank-statement-import" src="https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/bank-statement-import-13-0/bank-statement-import-13-0-account_bank_statement_import_adyen"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/174/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module processes Adyen transaction statements, the settlement details report,
in excel or csv format.</p>
<p>You can import the statements in a dedicated journal. Reconcile your sale invoices
with the credit transations. Reconcile the aggregated counterpart
transaction with the transaction in your real bank journal and register the
aggregated fee line containing commision and markup on the applicable
cost account.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
<p>Configure a pseudo bank journal by creating a new journal linked to your Adyen
merchant account. Set your merchant account string in the Advanced settings
on the journal form.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<p>After installing this module, you can import your Adyen transaction statements
through Menu Finance -&gt; Bank -&gt; Import. Dont enter a journal in the import
wizard.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/bank-statement-import/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_adyen%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Opener BV</li>
<li>Vanmoof BV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul class="simple">
<li>Stefan Rijnhart &lt;<a class="reference external" href="mailto:stefan&#64;opener.amsterdam">stefan&#64;opener.amsterdam</a>&gt; (<a class="reference external" href="https://opener.amsterdam">https://opener.amsterdam</a>)</li>
<li>Martin Pishpecki &lt;<a class="reference external" href="mailto:pishpecki&#64;gmail.com">pishpecki&#64;gmail.com</a>&gt; (<a class="reference external" href="https://www.vanmoof.com">https://www.vanmoof.com</a>)</li>
<li>Ronald Portier &lt;<a class="reference external" href="mailto:ronald&#64;therp.nl">ronald&#64;therp.nl</a>&gt; (<a class="reference external" href="https://therp.nl">https://therp.nl</a>)</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_adyen">OCA/bank-statement-import</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,7 +1,7 @@
# © 2017 Opener BV (<https://opener.amsterdam>)
# © 2020 Vanmoof BV (<https://www.vanmoof.com>)
# © 2015 Therp BV (<http://therp.nl>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2017 Opener BV <https://opener.amsterdam>
# Copyright 2020 Vanmoof BV <https://www.vanmoof.com>
# Copyright 2015-2021 Therp BV <https://therp.nl>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import base64
from odoo.exceptions import UserError
@@ -12,7 +12,7 @@ from odoo.tests.common import SavepointCase
class TestImportAdyen(SavepointCase):
@classmethod
def setUpClass(cls):
super(TestImportAdyen, cls).setUpClass()
super().setUpClass()
cls.journal = cls.env["account.journal"].create(
{
"company_id": cls.env.user.company_id.id,
@@ -20,7 +20,6 @@ class TestImportAdyen(SavepointCase):
"code": "ADY",
"type": "bank",
"adyen_merchant_account": "YOURCOMPANY_ACCOUNT",
"update_posted": True,
"currency_id": cls.env.ref("base.USD").id,
}
)
@@ -33,9 +32,7 @@ class TestImportAdyen(SavepointCase):
lines on the default journal (clearing) account are fully reconciled
with each other """
self._test_statement_import(
"account_bank_statement_import_adyen",
"adyen_test.xlsx",
"YOURCOMPANY_ACCOUNT 2016/48",
"adyen_test.xlsx", "YOURCOMPANY_ACCOUNT 2016/48",
)
statement = self.env["account.bank.statement"].search(
[], order="create_date desc", limit=1
@@ -48,76 +45,33 @@ class TestImportAdyen(SavepointCase):
)
)
account = self.env["account.account"].search(
[("internal_type", "=", "receivable")], limit=1
)
for line in statement.line_ids:
line.process_reconciliation(
new_aml_dicts=[
{
"debit": -line.amount if line.amount < 0 else 0,
"credit": line.amount if line.amount > 0 else 0,
"account_id": account.id,
}
]
)
statement.button_confirm_bank()
self.assertEqual(statement.state, "confirm")
lines = self.env["account.move.line"].search(
[
("account_id", "=", self.journal.default_debit_account_id.id),
("statement_id", "=", statement.id),
]
)
reconcile = lines.mapped("full_reconcile_id")
self.assertEqual(len(reconcile), 1)
self.assertEqual(lines, reconcile.reconciled_line_ids)
# Reset the bank statement to see the counterpart lines being
# unreconciled
statement.button_draft()
self.assertEqual(statement.state, "open")
self.assertFalse(lines.mapped("matched_debit_ids"))
self.assertFalse(lines.mapped("matched_credit_ids"))
self.assertFalse(lines.mapped("full_reconcile_id"))
# Confirm the statement without the correct clearing account settings
self.journal.default_debit_account_id.reconcile = False
statement.button_confirm_bank()
self.assertEqual(statement.state, "confirm")
self.assertFalse(lines.mapped("matched_debit_ids"))
self.assertFalse(lines.mapped("matched_credit_ids"))
self.assertFalse(lines.mapped("full_reconcile_id"))
def test_02_import_adyen_credit_fees(self):
""" Import an Adyen statement with credit fees """
self._test_statement_import(
"account_bank_statement_import_adyen",
"adyen_test_credit_fees.xlsx",
"YOURCOMPANY_ACCOUNT 2016/8",
"adyen_test_credit_fees.xlsx", "YOURCOMPANY_ACCOUNT 2016/8",
)
def test_03_import_adyen_invalid(self):
""" Trying to hit that coverall target """
with self.assertRaisesRegex(UserError, "Could not make sense"):
self._test_statement_import(
"account_bank_statement_import_adyen",
"adyen_test_invalid.xls",
"invalid",
"adyen_test_invalid.xls", "invalid",
)
def _test_statement_import(self, module_name, file_name, statement_name):
def _test_statement_import(self, file_name, statement_name):
"""Test correct creation of single statement."""
statement_path = get_module_resource(module_name, "test_files", file_name)
statement_file = open(statement_path, "rb").read()
import_wizard = self.env["account.bank.statement.import"].create(
{"data_file": base64.b64encode(statement_file), "filename": file_name}
testfile = get_module_resource(
"account_bank_statement_import_adyen", "test_files", file_name
)
import_wizard.import_file()
# statement name is account number + '-' + date of last line:
statements = self.env["account.bank.statement"].search(
[("name", "=", statement_name)]
)
self.assertTrue(statements)
return statements
with open(testfile, "rb") as datafile:
data_file = base64.b64encode(datafile.read())
import_wizard = self.env["account.bank.statement.import"].create(
{"attachment_ids": [(0, 0, {"name": "test file", "datas": data_file})]}
)
import_wizard.import_file()
# statement name is account number + '-' + date of last line:
statements = self.env["account.bank.statement"].search(
[("name", "=", statement_name)]
)
self.assertTrue(statements)
return statements