From 98d8680fb501000c81ac2eca4e4a06c9e2042c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Sat, 10 Mar 2018 12:46:08 +0100 Subject: [PATCH] Allow to invoice sub-project with a different party issue7096 review43071002 --- CHANGELOG | 2 + setup.py | 1 + ...cenario_project_invoice_multiple_party.rst | 120 ++++++++++++++++++ tests/test_project_invoice.py | 5 + work.py | 15 ++- 5 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 tests/scenario_project_invoice_multiple_party.rst diff --git a/CHANGELOG b/CHANGELOG index b3bdf0adf5..ac23ee1cb7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Allow to invoice at once sub-projects with a different party + Version 4.6.0 - 2017-10-30 * Bug fixes (see mercurial logs for details) diff --git a/setup.py b/setup.py index e90dc2a945..353aa2beda 100644 --- a/setup.py +++ b/setup.py @@ -125,5 +125,6 @@ setup(name=name, 'tests/scenario_project_invoice_timesheet.rst', 'tests/scenario_project_invoice_progress.rst', 'tests/scenario_project_invoice_effort.rst', + 'tests/scenario_project_invoice_multiple_party.rst', ], ) diff --git a/tests/scenario_project_invoice_multiple_party.rst b/tests/scenario_project_invoice_multiple_party.rst new file mode 100644 index 0000000000..007a8534af --- /dev/null +++ b/tests/scenario_project_invoice_multiple_party.rst @@ -0,0 +1,120 @@ +=============================== +Project Invoice Effort Scenario +=============================== + +Imports:: + + >>> import datetime + >>> from dateutil.relativedelta import relativedelta + >>> from decimal import Decimal + >>> from proteus import Model, Wizard + >>> from trytond.tests.tools import activate_modules + >>> from trytond.modules.company.tests.tools import create_company, \ + ... get_company + >>> from trytond.modules.account.tests.tools import create_chart, \ + ... get_accounts + >>> today = datetime.date.today() + +Install project_invoice:: + + >>> config = activate_modules('project_invoice') + +Create company:: + + >>> _ = create_company() + >>> company = get_company() + +Create chart of accounts:: + + >>> _ = create_chart(company) + >>> accounts = get_accounts(company) + >>> revenue = accounts['revenue'] + +Create two customers:: + + >>> Party = Model.get('party.party') + >>> customer1 = Party(name='Customer 1') + >>> customer1.save() + >>> customer2 = Party(name='Customer 2') + >>> customer2.save() + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> hour, = ProductUom.find([('name', '=', 'Hour')]) + >>> ProductTemplate = Model.get('product.template') + + >>> template = ProductTemplate() + >>> template.name = 'Service' + >>> template.default_uom = hour + >>> template.type = 'service' + >>> template.list_price = Decimal('20') + >>> template.account_revenue = revenue + >>> template.save() + >>> product, = template.products + +Create a Project with multiple customers:: + + >>> ProjectWork = Model.get('project.work') + >>> project = ProjectWork() + >>> project.name = 'Test multiple party' + >>> project.type = 'project' + >>> project.party = customer1 + >>> project.project_invoice_method = 'effort' + >>> project.product = product + >>> project.effort_duration = datetime.timedelta(hours=1) + + >>> subproject = project.children.new() + >>> subproject.name = 'Subproject' + >>> subproject.type = 'project' + >>> subproject.party = customer2 + >>> subproject.project_invoice_method = 'effort' + >>> subproject.product = product + >>> subproject.effort_duration = datetime.timedelta(hours=5) + + >>> project.save() + >>> subproject, = project.children + +Check project duration:: + + >>> project.reload() + >>> project.invoiced_duration + datetime.timedelta(0) + >>> project.duration_to_invoice + datetime.timedelta(0) + >>> project.invoiced_amount + Decimal('0') + +Do project and subproject:: + + >>> subproject.state = 'done' + >>> subproject.save() + >>> project.state = 'done' + >>> project.save() + +Check project duration:: + + >>> project.reload() + >>> project.invoiced_duration + datetime.timedelta(0) + >>> project.duration_to_invoice + datetime.timedelta(0, 21600) + >>> project.invoiced_amount + Decimal('0') + +Invoice project:: + + >>> project.click('invoice') + >>> project.invoiced_duration + datetime.timedelta(0, 21600) + >>> project.duration_to_invoice + datetime.timedelta(0) + >>> project.invoiced_amount + Decimal('120.00') + + >>> Invoice = Model.get('account.invoice') + >>> invoices = Invoice.find([]) + >>> len(invoices) + 2 + >>> sorted([i.party.name for i in invoices]) + [u'Customer 1', u'Customer 2'] diff --git a/tests/test_project_invoice.py b/tests/test_project_invoice.py index bb3b3497ce..c8895954d0 100644 --- a/tests/test_project_invoice.py +++ b/tests/test_project_invoice.py @@ -32,4 +32,9 @@ def suite(): tearDown=doctest_teardown, encoding='utf-8', checker=doctest_checker, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) + suite.addTests(doctest.DocFileSuite( + 'scenario_project_invoice_multiple_party.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) return suite diff --git a/work.py b/work.py index 7481da2822..64f88ca924 100644 --- a/work.py +++ b/work.py @@ -365,8 +365,11 @@ class Work: Invoice = pool.get('account.invoice') invoices = [] - for work in works: - invoice_lines = work._get_lines_to_invoice() + uninvoiced = works[:] + while uninvoiced: + work = uninvoiced.pop(0) + invoice_lines, uninvoiced_children = work._get_lines_to_invoice() + uninvoiced.extend(uninvoiced_children) if not invoice_lines: continue invoice = work._get_invoice() @@ -563,14 +566,18 @@ class Work: lines = [] if test is None: test = self._test_group_invoice() + uninvoiced_children = [] lines += getattr(self, '_get_lines_to_invoice_%s' % self.invoice_method)() for children in self.children: if children.type == 'project': if test != children._test_group_invoice(): + uninvoiced_children.append(children) continue - lines += children._get_lines_to_invoice(test=test) - return lines + child_lines, uninvoiced = children._get_lines_to_invoice(test=test) + lines.extend(child_lines) + uninvoiced_children.extend(uninvoiced) + return lines, uninvoiced_children class WorkInvoicedProgress(ModelView, ModelSQL):