From ef904b820c2e47bc0570f72bc2bafec093f82252 Mon Sep 17 00:00:00 2001 From: Matthieu Dietrich Date: Tue, 24 May 2016 11:51:51 +0200 Subject: [PATCH] Remane import modules --- account_move_transactionid_import/README.rst | 54 +++++++++++++ account_move_transactionid_import/__init__.py | 5 ++ .../__openerp__.py | 28 +++++++ .../data/completion_rule_data.xml | 16 ++++ .../data/statement.csv | 4 + .../data/statement.xls | Bin 0 -> 7680 bytes ...account_statement_transactionid_import.pot | 27 +++++++ account_move_transactionid_import/i18n/es.po | 29 +++++++ .../models/__init__.py | 5 ++ .../models/account_journal.py | 15 ++++ .../models/account_move.py | 76 ++++++++++++++++++ .../parser/__init__.py | 4 + .../parser/transactionid_file_parser.py | 71 ++++++++++++++++ .../completion_invoice_transactionid_test.yml | 44 ++++++++++ .../test/completion_transactionid_test.yml | 48 +++++++++++ .../test/invoice.yml | 25 ++++++ .../test/sale.yml | 21 +++++ 17 files changed, 472 insertions(+) create mode 100644 account_move_transactionid_import/README.rst create mode 100644 account_move_transactionid_import/__init__.py create mode 100644 account_move_transactionid_import/__openerp__.py create mode 100644 account_move_transactionid_import/data/completion_rule_data.xml create mode 100644 account_move_transactionid_import/data/statement.csv create mode 100644 account_move_transactionid_import/data/statement.xls create mode 100644 account_move_transactionid_import/i18n/account_statement_transactionid_import.pot create mode 100644 account_move_transactionid_import/i18n/es.po create mode 100644 account_move_transactionid_import/models/__init__.py create mode 100644 account_move_transactionid_import/models/account_journal.py create mode 100644 account_move_transactionid_import/models/account_move.py create mode 100644 account_move_transactionid_import/parser/__init__.py create mode 100644 account_move_transactionid_import/parser/transactionid_file_parser.py create mode 100644 account_move_transactionid_import/test/completion_invoice_transactionid_test.yml create mode 100644 account_move_transactionid_import/test/completion_transactionid_test.yml create mode 100644 account_move_transactionid_import/test/invoice.yml create mode 100644 account_move_transactionid_import/test/sale.yml diff --git a/account_move_transactionid_import/README.rst b/account_move_transactionid_import/README.rst new file mode 100644 index 00000000..2da1e2c1 --- /dev/null +++ b/account_move_transactionid_import/README.rst @@ -0,0 +1,54 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +==================================== +Bank statement transaction ID import +==================================== + +This module extends the functionality of +account_statement_base_import, in order to add both importation +and auto-completion for the "transaction_ref" field added in +base_transaction_id. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/98/9.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Joël Grand-Guillaume +* Matthieu Dietrich + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +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. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_move_transactionid_import/__init__.py b/account_move_transactionid_import/__init__.py new file mode 100644 index 00000000..728557cc --- /dev/null +++ b/account_move_transactionid_import/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +from . import parser +from . import models diff --git a/account_move_transactionid_import/__openerp__.py b/account_move_transactionid_import/__openerp__.py new file mode 100644 index 00000000..869581e8 --- /dev/null +++ b/account_move_transactionid_import/__openerp__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +{ + 'name': "Bank statement transactionID import", + 'version': '9.0.1.0.0', + 'author': "Camptocamp,Odoo Community Association (OCA)", + 'maintainer': 'Camptocamp', + 'category': 'Finance', + 'complexity': 'normal', + 'depends': [ + 'account_move_base_import', + 'base_transaction_id' + ], + 'data': [ + 'data/completion_rule_data.xml' + ], + 'test': [ + 'test/sale.yml', + 'test/completion_transactionid_test.yml', + 'test/invoice.yml', + 'test/completion_invoice_transactionid_test.yml', + ], + 'website': 'http://www.camptocamp.com', + 'installable': True, + 'auto_install': False, + 'license': 'AGPL-3', +} diff --git a/account_move_transactionid_import/data/completion_rule_data.xml b/account_move_transactionid_import/data/completion_rule_data.xml new file mode 100644 index 00000000..1f993602 --- /dev/null +++ b/account_move_transactionid_import/data/completion_rule_data.xml @@ -0,0 +1,16 @@ + + + + + Match from Sales Order using transaction ref + 30 + get_from_transaction_ref_and_so + + + + Match from Invoice using transaction ref + 40 + get_from_transaction_ref_and_invoice + + + diff --git a/account_move_transactionid_import/data/statement.csv b/account_move_transactionid_import/data/statement.csv new file mode 100644 index 00000000..ecda301b --- /dev/null +++ b/account_move_transactionid_import/data/statement.csv @@ -0,0 +1,4 @@ +"transaction_ref";"date";"amount";"commission_amount";"label" +50969286;2011-03-07 13:45:14;118.4;-11.84;"label a" +51065326;2011-03-05 13:45:14;189;-15.12;"label b" +51179306;2011-03-02 17:45:14;189;-15.12;"label c" diff --git a/account_move_transactionid_import/data/statement.xls b/account_move_transactionid_import/data/statement.xls new file mode 100644 index 0000000000000000000000000000000000000000..2d1ac86589ad767dddc46a85b8f849fa806d7c7f GIT binary patch literal 7680 zcmeHMYiyHM7=FKAM#l#0#+YNk_!uxYw!tnkHZHDX8;r!kGErkff?erGp!YVP#Xed)MVt5Vd>`2}&VnUkSXebnl&`3^(J7@-O zhWpAjv|tgf0M~p9U;{FNsX!LMGSkA(J7|cLUA@H&bcqi?zv$8?{df+@6IkKYLjg1< zR(vWoW9>yM<;N>C*?x2e#+xg?kDY(oZ`yG)Fy8*B?dSfV4&(qh0wfp617-mEz)YY3 zxCbZ%W&uUOY+w#B7bphi0Xi@rC;=7#3xP#IDXTqCRJ=xMAPPD}=bF)YXr+A@TW8R{`#Jw$+?;y`6 zXV^(#iq@jq^hmdAzu1y3$9W2`Z`;_`)qH=kr9fWcZfk8_*3q%-5ri#zd;7|cj$+F^ zIe~qtExwk|ca)Lf#5B(rAJk3JPo%8}_l$pD3T3gm)(3 zby(qo+*mmRwN&F>m>b8RxHVtt98=!t59F6c(; zQP2E6FMk`?6f_yO9m$sP?|u#IRA#11LG z$^#S!stv+yI52I0;7q+C2b8nTj-gfmfU|$l>GFGg{aXjzJ!o^A)9=RUoPEBbem@L? z%h%WE860E*gM$n2b#}YGaNn0#H`X`SHq^t8C`xydtf{VFURN6>yA@fpqOqLOPgoHWq<=QPPtBJuUjwe+@~7Yui{d4rcQ+`O^ajFWk~O2Qa|$4JlBdG==4WQnZxWSft<{Cmya^>An-R^Mp+wi_Me`OY z+{g2yc`S_fLY9#i6MZs6C5=0r%|zv5x}ExnvN=MI8LO-w!%=DDIVx~0cT?R04gXHW z$Z7EOD9Ff}kfS6cXGV@PjGP7jAeWap)+mH*Y!dXEvoK3GmY#g5_Uj)VXK|AAlrIwV zd-NOk{Spe9!?i5%A-St5gYC>wcT~!tiWxGV|H_cTxh#_3QLIQ@mm@Mv=)-KRpdo|3 zo1^ZxlwnpfUVd`))RC|Zb3z$rC4)-;vvg9ugY8H|wS$zarWFIt5p%E_`5dt*bD>FQ z&{z+UF~KBLRXt7)XXHLpp1h+>mqV56Qt?Z8T@EjIF6Ao5Xb8z(*p1%kCgN1ke`TS& zeq(Yus7xtr%)f0UW0o1mF0&rH%$W7Gml<{bT4vRRL&Zikxx8uF-HBh`>e%JQp_lgZ zqRvDvZ;WmvO=`Hsnz7Zn>+Lq$ML2jWmUX;ycX(U_zCmA)UvJy(a(ng06;+$*9C+Qz zn6CBo^cYtrqfXi}ES}M5+BJ;|qp(%nr1624^x}b|*RF5cZa?*$O)3_j{)QH{5HI)* zg70?$thpPYUEB}wlsN=&9fkoK(^mm_K=L*~TR8&I7vv3$R`N1HcZ)Y5`Z^TOHnQ=g z{3|z&Zx(Emf!{A~CryX2!|C^L_qd1jR*&01;Bjpa%Vm2Urvr!tMVEnyk@!bZzRoUl+F*@%38n6t_Q zGKBH>;p-E>{cpg(06l6=$oTOk%m*fUC=0hwdz\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_statement_transactionid_import +#: code:addons/account_statement_transactionid_import/account_move.py:65 +#, python-format +msgid "Line named \"%s\" was matched by more than one partner." +msgstr "" + +#. module: account_statement_transactionid_import +#: model:ir.model,name:account_statement_transactionid_import.model_account_move_completion_rule +msgid "account.move.completion.rule" +msgstr "" diff --git a/account_move_transactionid_import/i18n/es.po b/account_move_transactionid_import/i18n/es.po new file mode 100644 index 00000000..bdf10323 --- /dev/null +++ b/account_move_transactionid_import/i18n/es.po @@ -0,0 +1,29 @@ +# Spanish translation for banking-addons +# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 +# This file is distributed under the same license as the banking-addons package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: banking-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2014-01-21 12:02+0000\n" +"PO-Revision-Date: 2014-06-05 22:41+0000\n" +"Last-Translator: Pedro Manuel Baeza \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2014-06-06 06:36+0000\n" +"X-Generator: Launchpad (build 17031)\n" + +#. module: account_statement_transactionid +#: code:addons/account_statement_transactionid/account_move.py:65 +#, python-format +msgid "Line named \"%s\" (Ref:%s) was matched by more than one partner." +msgstr "La línea llamada \"%s\" (Ref: %s) se casó con más de una empresa." + +#. module: account_statement_transactionid +#: model:ir.model,name:account_statement_transactionid.model_account_move_completion_rule +msgid "account.move.completion.rule" +msgstr "account.move.completion.rule" diff --git a/account_move_transactionid_import/models/__init__.py b/account_move_transactionid_import/models/__init__.py new file mode 100644 index 00000000..079b873d --- /dev/null +++ b/account_move_transactionid_import/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +from . import account_journal +from . import account_move diff --git a/account_move_transactionid_import/models/account_journal.py b/account_move_transactionid_import/models/account_journal.py new file mode 100644 index 00000000..f8dda41b --- /dev/null +++ b/account_move_transactionid_import/models/account_journal.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +from openerp import models + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + def _get_import_type_selection(self): + """Has to be inherited to add parser""" + res = super(AccountJournal, self)._get_import_type_selection() + res.append(('generic_csvxls_transaction', + 'Generic .csv/.xls based on SO transaction ID')) + return res diff --git a/account_move_transactionid_import/models/account_move.py b/account_move_transactionid_import/models/account_move.py new file mode 100644 index 00000000..e2a31bb9 --- /dev/null +++ b/account_move_transactionid_import/models/account_move.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +from openerp import _, models +from openerp.addons.account_move_base_import.models.account_move import \ + ErrorTooManyPartner + + +class AccountMoveCompletionRule(models.Model): + """Add a rule based on transaction ID""" + + _inherit = "account.move.completion.rule" + + def _get_functions(self): + res = super(AccountMoveCompletionRule, self)._get_functions() + res += [ + ('get_from_transaction_ref_and_so', + 'Match Sales Order using transaction ref'), + ('get_from_transaction_ref_and_invoice', + 'Match Invoice using transaction ref'), + ] + return res + + def get_from_transaction_ref_and_so(self, line): + """ + Match the partner based on the transaction ID field of the SO. + Then, call the generic st_line method to complete other values. + In that case, we always fullfill the reference of the line with the SO + name. + :param dict st_line: read of the concerned account.bank.statement.line + :return: + A dict of value that can be passed directly to the write method of + the statement line or {} + {'partner_id': value, + 'account_id' : value, + ...} + """ + res = {} + so_obj = self.env['sale.order'] + sales = so_obj.search([('transaction_id', '=', line.transaction_ref)]) + if len(sales) > 1: + raise ErrorTooManyPartner( + _('Line named "%s" was matched by more than ' + 'one partner.') % line.name) + if len(sales) == 1: + sale = sales[0] + res['partner_id'] = sale.partner_id.id + return res + + def get_from_transaction_ref_and_invoice(self, line): + """Match the partner based on the transaction ID field of the invoice. + Then, call the generic st_line method to complete other values. + + In that case, we always fullfill the reference of the line with the + invoice name. + + :param dict st_line: read of the concerned account.bank.statement.line + :return: + A dict of value that can be passed directly to the write method of + the statement line or {} + {'partner_id': value, + 'account_id' : value, + ...} + """ + res = {} + invoice_obj = self.env['account.invoice'] + invoices = invoice_obj.search( + [('transaction_id', '=', line.transaction_ref)]) + if len(invoices) > 1: + raise ErrorTooManyPartner( + _('Line named "%s" was matched by more than ' + 'one partner.') % line.name) + elif len(invoices) == 1: + invoice = invoices[0] + res['partner_id'] = invoice.commercial_partner_id.id + return res diff --git a/account_move_transactionid_import/parser/__init__.py b/account_move_transactionid_import/parser/__init__.py new file mode 100644 index 00000000..9102553c --- /dev/null +++ b/account_move_transactionid_import/parser/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +from . import transactionid_file_parser diff --git a/account_move_transactionid_import/parser/transactionid_file_parser.py b/account_move_transactionid_import/parser/transactionid_file_parser.py new file mode 100644 index 00000000..a11501c3 --- /dev/null +++ b/account_move_transactionid_import/parser/transactionid_file_parser.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# © 2011-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +import datetime +from openerp.tools import ustr +from openerp.addons.account_move_base_import.parser.file_parser import ( + FileParser, float_or_zero +) + + +class TransactionIDFileParser(FileParser): + """TransactionID parser that use a define format in csv or xls to import + bank statement. + """ + + def __init__(self, profile, ftype='csv', extra_fields=None, header=None, + **kwargs): + """Add transaction_id in header keys + :param char: profile: Reference to the profile + :param char: ftype: extension of the file (could be csv or xls) + :param dict: extra_fields: extra fields to add to the conversion + dict. In the format {fieldname: fieldtype} + :param list: header : specify header fields if the csv file has no + header + """ + conversion_dict = { + 'transaction_ref': ustr, + 'label': ustr, + 'date': datetime.datetime, + 'amount': float_or_zero, + 'commission_amount': float_or_zero, + } + super(TransactionIDFileParser, self).__init__( + profile, extra_fields=conversion_dict, ftype=ftype, header=header, + **kwargs) + + @classmethod + def parser_for(cls, parser_name): + """Used by the new_bank_statement_parser class factory. Return true if + the providen name is generic_csvxls_transaction + """ + return parser_name == 'generic_csvxls_transaction' + + def get_move_line_vals(self, line, *args, **kwargs): + """This method must return a dict of vals that can be passed to create + method of statement line in order to record it. It is the + responsibility of every parser to give this dict of vals, so each one + can implement his own way of recording the lines. + :param: line: a dict of vals that represent a line of + result_row_list + :return: dict of values to give to the create method of statement + line, it MUST contain at least: + { + 'name':value, + 'date':value, + 'amount':value, + 'ref':value, + 'label':value, + 'commission_amount':value, + } + In this generic parser, the commission is given for every line, so we + store it for each one. + """ + amount = line.get('amount', 0.0) + return { + 'name': line.get('label', '/'), + 'date_maturity': line.get('date', datetime.datetime.now().date()), + 'credit': amount > 0.0 and amount or 0.0, + 'debit': amount < 0.0 and amount or 0.0, + 'transaction_ref': line.get('transaction_ref', '/'), + } diff --git a/account_move_transactionid_import/test/completion_invoice_transactionid_test.yml b/account_move_transactionid_import/test/completion_invoice_transactionid_test.yml new file mode 100644 index 00000000..ebfc3206 --- /dev/null +++ b/account_move_transactionid_import/test/completion_invoice_transactionid_test.yml @@ -0,0 +1,44 @@ +- + In order to test the banking framework, I first need to create a journal +- + !record {model: account.journal, id: account.bank_journal}: + used_for_completion: True + rule_ids: + - bank_statement_completion_rule_trans_id_invoice +- + Now I create a move. I create statment lines separately because I need + to find each one by XML id +- + !record {model: account.move, id: move_invoice_transactionid_test1}: + name: Move with transaction ID + journal_id: account.bank_journal + company_id: base.main_company +- + I create a move line for a SO with transaction ID +- + !record {model: account.move.line, id: move_line_invoice_transactionid}: + name: Test autocompletion based on invoice with transaction ID + account_id: account.a_sale + move_id: move_invoice_transactionid_test1 + transaction_ref: XXX77Z + date_maturity: !eval time.strftime('%Y-%m-%d') + credit: 0.0 +- + and add the correct amount +- + !python {model: account.move.line}: | + context['check_move_validity'] = False + model.write(cr, uid, [ref('move_line_invoice_transactionid')], + {'credit': 450.0}, + context) +- + I run the auto complete +- + !python {model: account.move}: | + result = self.button_auto_completion(cr, uid, [ref("move_invoice_transactionid_test1")]) +- + Now I can check that all is nice and shiny, line 1. I expect the invoice has been + recognised from the transaction ID. +- + !assert {model: account.move.line, id: move_line_invoice_transactionid, string: Check completion by Invoice transaction ID}: + - partner_id.name == u'Agrolait' diff --git a/account_move_transactionid_import/test/completion_transactionid_test.yml b/account_move_transactionid_import/test/completion_transactionid_test.yml new file mode 100644 index 00000000..889be36c --- /dev/null +++ b/account_move_transactionid_import/test/completion_transactionid_test.yml @@ -0,0 +1,48 @@ +- + In order to test the banking framework, I first need to create a journal +- + !record {model: account.journal, id: account.bank_journal}: + used_for_completion: True + rule_ids: + - bank_statement_completion_rule_4 + - account_statement_base_import.bank_statement_completion_rule_4 + - account_statement_base_import.bank_statement_completion_rule_5 + - account_statement_base_import.bank_statement_completion_rule_2 + - account_statement_base_import.bank_statement_completion_rule_3 +- + Now I create a move. I create statment lines separately because I need + to find each one by XML id +- + !record {model: account.move, id: move_transactionid_test1}: + name: Move with transaction ID + journal_id: account.bank_journal + company_id: base.main_company +- + I create a move line for a SO with transaction ID +- + !record {model: account.move.line, id: move_line_transactionid}: + name: Test autocompletion based on SO with transaction ID + account_id: account.a_sale + move_id: move_transactionid_test1 + transaction_ref: XXX66Z + date_maturity: !eval "'%s-01-06' %(datetime.now().year)" + credit: 0.0 +- + and add the correct amount +- + !python {model: account.move.line}: | + context['check_move_validity'] = False + model.write(cr, uid, [ref('move_line_transactionid')], + {'credit': 118.4}, + context) +- + I run the auto complete +- + !python {model: account.move}: | + result = self.button_auto_completion(cr, uid, [ref("move_transactionid_test1")]) +- + Now I can check that all is nice and shiny, line 1. I expect the SO has been + recognised from the transaction ID. +- + !assert {model: account.move.line, id: move_line_transactionid, string: Check completion by SO transaction ID}: + - partner_id.name == u'Agrolait' diff --git a/account_move_transactionid_import/test/invoice.yml b/account_move_transactionid_import/test/invoice.yml new file mode 100644 index 00000000..61c10aa2 --- /dev/null +++ b/account_move_transactionid_import/test/invoice.yml @@ -0,0 +1,25 @@ +- + I create a new invoice with transaction ID +- + !record {model: account.invoice, id: invoice_with_transaction_id}: + company_id: base.main_company + currency_id: base.EUR + partner_id: base.res_partner_2 + transaction_id: XXX77Z + invoice_line_ids: + - name: '[PCSC234] PC Assemble SC234' + price_unit: 450.0 + quantity: 1.0 + product_id: product.product_product_3 + uom_id: product.product_uom_unit + journal_id: account.bank_journal + reference_type: none +- + I confirm the Invoice +- + !workflow {model: account.invoice, action: invoice_open, ref: invoice_with_transaction_id} +- + I check that the invoice state is "Open" +- + !assert {model: account.invoice, id: invoice_with_transaction_id}: + - state == 'open' diff --git a/account_move_transactionid_import/test/sale.yml b/account_move_transactionid_import/test/sale.yml new file mode 100644 index 00000000..d712f8ad --- /dev/null +++ b/account_move_transactionid_import/test/sale.yml @@ -0,0 +1,21 @@ +- + I import account minimal data +- + !python {model: account.invoice}: | + openerp.tools.convert_file(cr, + 'account', + openerp.modules.get_module_resource( + 'account', + 'test', + 'account_minimal_test.xml'), + {}, 'init', False, 'test') +- + I create a new Sale Order with transaction ID +- + !record {model: sale.order, id: so_with_transaction_id}: + partner_id: base.res_partner_2 + note: Invoice after delivery + transaction_id: XXX66Z + order_line: + - product_id: product.product_product_7 + product_uom_qty: 8