diff --git a/contract/README.rst b/contract/README.rst index af3ce01d..57ffab1b 100644 --- a/contract/README.rst +++ b/contract/README.rst @@ -25,10 +25,10 @@ Contracts Management - Recurring |badge1| |badge2| |badge3| |badge4| |badge5| -This module brings back the contracts management with recurring invoicing -features. Also you can print and send by email contract report. +This module enables contracts management with recurring +invoicing functions. Also you can print and send by email contract report. -In upstream Odoo, this functionality was moved into the Enterprise edition. +It works for customer contract and supplier contracts. **Table of contents** @@ -106,6 +106,7 @@ Contributors * Angel Moya * Dave Lasley * Vicent Cubells +* Miquel Raïch Maintainers ~~~~~~~~~~~ diff --git a/contract/__manifest__.py b/contract/__manifest__.py index 37155810..f065ff52 100644 --- a/contract/__manifest__.py +++ b/contract/__manifest__.py @@ -8,7 +8,7 @@ { 'name': 'Contracts Management - Recurring', - 'version': '11.0.3.0.0', + 'version': '11.0.4.0.0', 'category': 'Contract Management', 'license': 'AGPL-3', 'author': "OpenERP SA, " diff --git a/contract/models/account_analytic_account.py b/contract/models/account_analytic_account.py index 01f39037..bc268f79 100644 --- a/contract/models/account_analytic_account.py +++ b/contract/models/account_analytic_account.py @@ -202,14 +202,19 @@ class AccountAnalyticAccount(models.Model): def _prepare_invoice(self, journal=None): self.ensure_one() if not self.partner_id: - raise ValidationError( - _("You must first select a Customer for Contract %s!") % - self.name) + if self.contract_type == 'purchase': + raise ValidationError( + _("You must first select a Supplier for Contract %s!") % + self.name) + else: + raise ValidationError( + _("You must first select a Customer for Contract %s!") % + self.name) if not journal: journal = self.journal_id or self.env['account.journal'].search([ - ('type', '=', self.contract_type), - ('company_id', '=', self.company_id.id) - ], limit=1) + ('type', '=', self.contract_type), + ('company_id', '=', self.company_id.id) + ], limit=1) if not journal: raise ValidationError( _("Please define a %s journal for the company '%s'.") % diff --git a/contract/models/account_analytic_contract.py b/contract/models/account_analytic_contract.py index 1d67fb3b..162206cb 100644 --- a/contract/models/account_analytic_contract.py +++ b/contract/models/account_analytic_contract.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2004-2010 OpenERP SA # Copyright 2014 Angel Moya # Copyright 2016 Carlos Dauden @@ -6,7 +5,7 @@ # Copyright 2015-2017 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import api, fields, models class AccountAnalyticContract(models.Model): @@ -28,9 +27,9 @@ class AccountAnalyticContract(models.Model): ) contract_type = fields.Selection( selection=[ - ('sale', _('Sale')), - ('purchase', _('Purchase')), - ], default='sale' + ('sale', 'Customer'), + ('purchase', 'Supplier'), + ], default='sale', ) pricelist_id = fields.Many2one( comodel_name='product.pricelist', @@ -70,7 +69,8 @@ class AccountAnalyticContract(models.Model): 'account.journal', string='Journal', default=lambda s: s._default_journal(), - domain="[('company_id', '=', company_id)]", + domain="[('type', '=', contract_type)," + "('company_id', '=', company_id)]", ) company_id = fields.Many2one( 'res.company', @@ -81,6 +81,9 @@ class AccountAnalyticContract(models.Model): @api.onchange('contract_type') def _onchange_contract_type(self): + if self.contract_type == 'purchase': + self.recurring_invoice_line_ids.filtered('automatic_price').update( + {'automatic_price': False}) self.journal_id = self.env['account.journal'].search([ ('type', '=', self.contract_type), ('company_id', '=', self.company_id.id) @@ -91,6 +94,6 @@ class AccountAnalyticContract(models.Model): company_id = self.env.context.get( 'company_id', self.env.user.company_id.id) domain = [ - ('type', '=', 'sale'), + ('type', '=', self.contract_type), ('company_id', '=', company_id)] return self.env['account.journal'].search(domain, limit=1) diff --git a/contract/models/account_analytic_contract_line.py b/contract/models/account_analytic_contract_line.py index 5eff76aa..9dbb0f05 100644 --- a/contract/models/account_analytic_contract_line.py +++ b/contract/models/account_analytic_contract_line.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2004-2010 OpenERP SA # Copyright 2014 Angel Moya # Copyright 2016 Carlos Dauden diff --git a/contract/models/account_analytic_invoice_line.py b/contract/models/account_analytic_invoice_line.py index 9328178c..a82c8ee6 100644 --- a/contract/models/account_analytic_invoice_line.py +++ b/contract/models/account_analytic_invoice_line.py @@ -9,7 +9,7 @@ class AccountAnalyticInvoiceLine(models.Model): _inherit = 'account.analytic.contract.line' analytic_account_id = fields.Many2one( - 'account.analytic.account', + comodel_name='account.analytic.account', string='Analytic Account', required=True, ondelete='cascade', diff --git a/contract/models/res_partner.py b/contract/models/res_partner.py index f175912a..ead5e4c7 100644 --- a/contract/models/res_partner.py +++ b/contract/models/res_partner.py @@ -7,30 +7,45 @@ from odoo import fields, models class ResPartner(models.Model): _inherit = 'res.partner' - contract_count = fields.Integer( - string='Contracts', + sale_contract_count = fields.Integer( + string='Sale Contracts', + compute='_compute_contract_count', + ) + purchase_contract_count = fields.Integer( + string='Purchase Contracts', compute='_compute_contract_count', ) def _compute_contract_count(self): - Contract = self.env['account.analytic.account'] + contract_model = self.env['account.analytic.account'] today = fields.Date.today() + fetch_data = contract_model.read_group([ + ('recurring_invoices', '=', True), + ('partner_id', 'child_of', self.ids), + '|', + ('date_end', '=', False), + ('date_end', '>=', today)], + ['partner_id', 'contract_type'], ['partner_id', 'contract_type'], + lazy=False) + result = [[data['partner_id'][0], data['contract_type'], + data['__count']] for data in fetch_data] for partner in self: - partner.contract_count = Contract.search_count([ - ('recurring_invoices', '=', True), - ('partner_id', 'child_of', partner.ids), - '|', - ('date_end', '=', False), - ('date_end', '>=', today), - ]) + partner_child_ids = partner.child_ids.ids + partner.ids + partner.sale_contract_count = sum([ + r[2] for r in result + if r[0] in partner_child_ids and r[1] == 'sale']) + partner.purchase_contract_count = sum([ + r[2] for r in result + if r[0] in partner_child_ids and r[1] == 'purchase']) def act_show_contract(self): """ This opens contract view @return: the contract view """ self.ensure_one() - res = self.env['ir.actions.act_window'].for_xml_id( - 'contract', 'action_account_analytic_overdue_all') + contract_type = self._context.get('contract_type') + + res = self._get_act_window_contract_xml(contract_type) res.update( context=dict( self.env.context, @@ -43,3 +58,11 @@ class ResPartner(models.Model): ), ) return res + + def _get_act_window_contract_xml(self, contract_type): + if contract_type == 'purchase': + return self.env['ir.actions.act_window'].for_xml_id( + 'contract', 'action_account_analytic_purchase_overdue_all') + else: + return self.env['ir.actions.act_window'].for_xml_id( + 'contract', 'action_account_analytic_sale_overdue_all') diff --git a/contract/readme/CONTRIBUTORS.rst b/contract/readme/CONTRIBUTORS.rst index c749c1ef..ed395a7d 100644 --- a/contract/readme/CONTRIBUTORS.rst +++ b/contract/readme/CONTRIBUTORS.rst @@ -3,3 +3,4 @@ * Angel Moya * Dave Lasley * Vicent Cubells +* Miquel Raïch diff --git a/contract/readme/DESCRIPTION.rst b/contract/readme/DESCRIPTION.rst index ab6e258d..7498c830 100644 --- a/contract/readme/DESCRIPTION.rst +++ b/contract/readme/DESCRIPTION.rst @@ -1,4 +1,4 @@ -This module brings back the contracts management with recurring invoicing -features. Also you can print and send by email contract report. +This module enables contracts management with recurring +invoicing functions. Also you can print and send by email contract report. -In upstream Odoo, this functionality was moved into the Enterprise edition. +It works for customer contract and supplier contracts. diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py index df9c0525..cc676bbb 100644 --- a/contract/tests/test_contract.py +++ b/contract/tests/test_contract.py @@ -32,6 +32,15 @@ class TestContractBase(common.SavepointCase): 'date_start': '2016-02-15', 'recurring_next_date': '2016-02-29', }) + cls.contract2 = cls.env['account.analytic.account'].create({ + 'name': 'Test Contract 2', + 'partner_id': cls.partner.id, + 'pricelist_id': cls.partner.property_product_pricelist.id, + 'recurring_invoices': True, + 'date_start': '2016-02-15', + 'recurring_next_date': '2016-02-29', + 'contract_type': 'purchase', + }) cls.line_vals = { 'analytic_account_id': cls.contract.id, 'product_id': cls.product.id, @@ -275,24 +284,27 @@ class TestContract(TestContractBase): ])) def test_contract_count(self): - """It should return contract count.""" - count = self.partner.contract_count + 2 + """It should return sale contract count.""" + count = self.partner.sale_contract_count + 2 self.contract.copy() self.contract.copy() - self.assertEqual(self.partner.contract_count, count) + self.assertEqual(self.partner.sale_contract_count, count) + count = self.partner.purchase_contract_count + 1 + self.contract2.copy() + self.assertEqual(self.partner.purchase_contract_count, count) def test_same_date_start_and_date_end(self): """It should create one invoice with same start and end date.""" - AccountInvoice = self.env['account.invoice'] + account_invoice_model = self.env['account.invoice'] self.contract.write({ 'date_start': fields.Date.today(), 'date_end': fields.Date.today(), 'recurring_next_date': fields.Date.today(), }) - init_count = AccountInvoice.search_count( + init_count = account_invoice_model.search_count( [('contract_id', '=', self.contract.id)]) self.contract.cron_recurring_create_invoice() - last_count = AccountInvoice.search_count( + last_count = account_invoice_model.search_count( [('contract_id', '=', self.contract.id)]) self.assertEqual(last_count, init_count + 1) with self.assertRaises(ValidationError): @@ -311,14 +323,29 @@ class TestContract(TestContractBase): self.assertFalse(self.contract.create_invoice_visibility) def test_extend_invoice(self): - AccountInvoice = self.env['account.invoice'] + account_invoice_model = self.env['account.invoice'] self.contract.recurring_create_invoice() - invoice = AccountInvoice.search( + invoice = account_invoice_model.search( [('contract_id', '=', self.contract.id)]) invoice.origin = 'Orig Invoice' self.contract._create_invoice(invoice) self.assertEqual(invoice.origin, 'Orig Invoice Test Contract') - invoice_count = AccountInvoice.search_count( + invoice_count = account_invoice_model.search_count( [('contract_id', '=', self.contract.id)]) self.assertEqual(invoice_count, 1) self.assertEqual(len(invoice.invoice_line_ids), 2) + + def test_act_show_contract(self): + show_contract = self.partner.\ + with_context(contract_type='sale').act_show_contract() + self.assertDictContainsSubset( + { + 'name': 'Customer Contracts', + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'res_model': 'account.analytic.account', + 'xml_id': 'contract.action_account_analytic_sale_overdue_all', + }, + show_contract, + 'There was an error and the view couldn\'t be opened.' + ) diff --git a/contract/views/account_analytic_account_view.xml b/contract/views/account_analytic_account_view.xml index bf9ef8d5..1db6df28 100644 --- a/contract/views/account_analytic_account_view.xml +++ b/contract/views/account_analytic_account_view.xml @@ -16,6 +16,9 @@ +