[ADD] create sql-view for lines violating rules

This commit is contained in:
Iryna Vushnevska
2019-07-09 01:02:13 +03:00
committed by Iryna Vyshnevska
parent f71235ef40
commit 447abc40cf
17 changed files with 263 additions and 18 deletions

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import models

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import account_move_line

View File

@@ -1,2 +0,0 @@
Prohibits items reconcilation for different partners, and items with partner and
without it.

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import models
from . import report

View File

@@ -3,8 +3,9 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
'name': 'Account Partner Reconciliation',
'summary': 'Allows run reconciliation only for same partner',
'name': 'Reconcile restrict partner mismatch',
'summary': 'Restrict reconciliation on receivable '
'and payable accounts to the same partner',
'version': '10.0.1.0.0',
'depends': ['account'],
'author': 'Camptocamp, Odoo Community Association (OCA)',
@@ -12,7 +13,8 @@
'category': 'Finance',
'license': 'AGPL-3',
'data': [
'report/account_move_lines_report.xml'
'report/account_move_lines_report.xml',
'security/ir.model.access.csv',
],
'installable': True,
}

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import account_move_line

View File

@@ -12,7 +12,8 @@ class AccountMoveLine(models.Model):
@api.multi
def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False):
if config['test_enable']:
if (config['test_enable']
and not self.env.context.get('test_partner_mismatch')):
return super(AccountMoveLine, self).reconcile(
writeoff_acc_id, writeoff_journal_id)
@@ -21,13 +22,10 @@ class AccountMoveLine(models.Model):
return True
partners = set()
for line in self:
if (line.account_id.internal_type in ('receivable', 'payable')):
if line.account_id.internal_type in ('receivable', 'payable'):
partners.add(line.partner_id.id)
if len(partners) > 1:
raise UserError(_('The partner has to be the same on all'
' lines for receivable and payable accounts!'))
if len(partners) and not all([l.partner_id for l in self]):
raise UserError(_('You cannot match entries with and '
'without partner!'))
return super(AccountMoveLine, self).reconcile(
writeoff_acc_id, writeoff_journal_id)

View File

@@ -0,0 +1,10 @@
This module restricts reconciliation between journal items when:
- both items have different partners
- one item is with partner and the other without it
This rule applies only for journal items using receivable and payable account type.
As at the moment of installation some journal items could have been reconciled
using different partners, you can detect them in menu Accounting > Adviser >
Reconciled items with partner mismatch.

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import report_reconciled_lines

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_account_move_reconciled_report_tree" model="ir.ui.view">
<field name="name">Reconciled items with partner mismatch</field>
<field name="model">account.reconcile.partner.mismatch.report</field>
<field name="arch" type="xml">
<tree string="Reconciled items with partner mismatch" create="false" delete="false" edit="false">
<!-- links are not clickable in tree view
only after open form view -->
<field name="partial_reconcile_id" />
<field name="full_reconcile_id" />
<field name="debit_move_id" />
<field name="debit_amount" />
<field name="debit_partner_id" />
<field name="credit_move_id" />
<field name="credit_amount" />
<field name="credit_partner_id" />
<field name="account_type_id" />
<field name="account_id" />
</tree>
</field>
</record>
<record id="account_reconcile_partner_mismatch_report_view_form" model="ir.ui.view">
<field name="name">account.reconcile.partner.mismatch.report.form</field>
<field name="model">account.reconcile.partner.mismatch.report</field>
<field name="arch" type="xml">
<form string="Reconciled items with partner mismatch" create="false" delete="false" edit="false">
<sheet>
<group>
<group>
<field name="partial_reconcile_id" />
<field name="full_reconcile_id" />
<field name="debit_amount" />
<field name="credit_amount" />
<field name="debit_partner_id" />
<field name="credit_partner_id" />
</group>
<group>
<field name="account_id" />
<field name="account_type_id" />
<field name="debit_move_id" />
<field name="credit_move_id" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_account_reconcile_partner_mismatch_report" model="ir.actions.act_window">
<field name="name">Reconciled items with partner mismatch</field>
<field name="res_model">account.reconcile.partner.mismatch.report</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_account_reconcile_partner_mismatch_report"
parent="account.menu_finance_entries" sequence="80"
action="action_account_reconcile_partner_mismatch_report"
name="Reconciled items with partner mismatch"/>
</odoo>

View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models, tools
class AccountReconcilePartnerMismatchReport(models.Model):
_name = 'account.reconcile.partner.mismatch.report'
_auto = False
partial_reconcile_id = fields.Many2one(
'account.partial.reconcile',
string="Partial Reconcile"
)
full_reconcile_id = fields.Many2one('account.full.reconcile')
account_id = fields.Many2one(
'account.account',
string="Account"
)
account_type_id = fields.Many2one(
'account.account.type',
string="Account type",
)
debit_move_id = fields.Many2one('account.move.line', string="Debit move")
debit_amount = fields.Float("Debit amount")
debit_partner_id = fields.Many2one('res.partner', string="Debit partner")
credit_move_id = fields.Many2one('account.move.line', string="Credit move")
credit_amount = fields.Float("Credit amount")
credit_partner_id = fields.Many2one('res.partner', string="Credit partner")
@api.model_cr
def init(self):
"""Select lines which violate defined rules"""
tools.drop_view_if_exists(self.env.cr, self._table)
self._cr.execute(
"""CREATE OR REPLACE VIEW %s AS (
SELECT pr.id id
, pr.id partial_reconcile_id
, pr.full_reconcile_id
, pr.debit_move_id
, daml.debit debit_amount
, aat.id account_type_id
, daml.partner_id debit_partner_id
, daml.account_id account_id
, pr.credit_move_id
, caml.credit credit_amount
, caml.partner_id credit_partner_id
FROM account_partial_reconcile pr
LEFT JOIN account_move_line daml
ON daml.id = pr.debit_move_id
LEFT JOIN account_move_line caml
ON caml.id = pr.credit_move_id
LEFT JOIN account_account_type aat
ON daml.user_type_id = aat.id
WHERE aat.type in ('receivable', 'payable')
AND (daml.partner_id <> caml.partner_id
OR (daml.partner_id IS NULL
AND caml.partner_id IS NOT NULL)
OR (caml.partner_id IS NULL
AND daml.partner_id IS NOT NULL))
)
"""
% self._table
)

View File

@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_reconcile_partner_mismatch_report,access_account_reconcile_partner_mismatch_report,model_account_reconcile_partner_mismatch_report,account.group_account_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_reconcile_partner_mismatch_report access_account_reconcile_partner_mismatch_report model_account_reconcile_partner_mismatch_report account.group_account_user 1 0 0 0

View File

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

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

View File

@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
from odoo.exceptions import UserError
class TestReconciliation(AccountingTestCase):
def setUp(self):
super(TestReconciliation, self).setUp()
self.env = self.env(context=dict(
self.env.context, tracking_disable=True,
test_partner_mismatch=True)
)
self.partner = self.env.ref("base.res_partner_2")
self.partner_id = self.partner.id
rec_type = self.env['account.account'].search([
('user_type_id', '=',
self.env.ref('account.data_account_type_receivable').id)
], limit=1)
pay_type = self.env['account.account'].search([
('user_type_id', '=',
self.env.ref('account.data_account_type_payable').id)
], limit=1)
self.account_rcv = (self.partner.property_account_receivable_id
or rec_type)
self.account_rsa = self.partner.property_account_payable_id or pay_type
self.bank_journal = self.env['account.journal']. \
create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'})
self.aml = self.init_moves()
self.wizard = self.env['account.move.line.reconcile.writeoff']. \
with_context(active_ids=[x.id for x in self.aml]).create({
'journal_id': self.bank_journal.id,
'writeoff_acc_id': self.account_rsa.id
})
def create_move(self, name, amount):
debit_line_vals = {
'name': name,
'debit': amount > 0 and amount or 0.0,
'credit': amount < 0 and -amount or 0.0,
'account_id': self.account_rcv.id,
}
credit_line_vals = debit_line_vals.copy()
credit_line_vals['debit'] = debit_line_vals['credit']
credit_line_vals['credit'] = debit_line_vals['debit']
credit_line_vals['account_id'] = self.account_rsa.id
vals = {
'journal_id': self.bank_journal.id,
'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)]
}
return self.env['account.move'].create(vals).id
def init_moves(self):
move_list_vals = [
('1', -1.83),
('2', 728.35),
('3', -4.46),
('4', 0.32),
('5', 14.72),
('6', -737.10),
]
move_ids = []
for name, amount in move_list_vals:
move_ids.append(self.create_move(name, amount))
aml_recs = self.env['account.move.line'].search([
('move_id', 'in', move_ids),
('account_id', '=', self.account_rcv.id)
])
return aml_recs
def test_reconcile_no_partner(self):
self.wizard.trans_rec_reconcile()
self.assertTrue(all(self.aml.mapped('reconciled')))
def test_reconcile_partner_mismatch(self):
self.aml[0].partner_id = self.partner.id
with self.assertRaises(UserError):
self.wizard.trans_rec_reconcile()
# all lines with same partner allowed
self.aml.write({'partner_id': self.partner.id})
self.wizard.trans_rec_reconcile()
self.assertTrue(all(self.aml.mapped('reconciled')))
def test_reconcile_accounts_excluded(self):
self.aml[0].partner_id = self.partner.id
with self.assertRaises(UserError):
self.wizard.trans_rec_reconcile()
# reconciliation forbiden only for certain types of accounts
account = self.env['account.account'].search([
('user_type_id.type', '=', 'other')
], limit=1)
account.reconcile = True
self.aml[0].account_id = account.id
with self.assertRaises(UserError):
self.wizard.trans_rec_reconcile()
# reconciliation for different partners allowed
# for not forbidden types
self.aml.write({'account_id': account.id})
self.wizard.trans_rec_reconcile()
self.assertTrue(all(self.aml.mapped('reconciled')))