Browse Source

[12.0][IMP] - Add an action for contracts manual invoicing

It happen that a company has to trigger the invoicing action to generate invoices before
the scheduled date (to print and prepare invoices documents, check invoices, etc.).
This requires technical access for end users with the risk that this represents.

This commit adds a new wizard to run the invoicing action for a given date with a helper
to see and check the contract that will be invoiced. When the manual action is called,
the system displays all created invoices.
pull/414/head
sbejaoui 5 years ago
parent
commit
20cdcdede2
  1. 1
      contract/__manifest__.py
  2. 9
      contract/models/contract.py
  3. 1
      contract/security/ir.model.access.csv
  4. 33
      contract/tests/test_contract.py
  5. 1
      contract/wizards/__init__.py
  6. 62
      contract/wizards/contract_manually_create_invoice.py
  7. 58
      contract/wizards/contract_manually_create_invoice.xml

1
contract/__manifest__.py

@ -29,6 +29,7 @@
'data/contract_renew_cron.xml', 'data/contract_renew_cron.xml',
'data/mail_template.xml', 'data/mail_template.xml',
'wizards/contract_line_wizard.xml', 'wizards/contract_line_wizard.xml',
'wizards/contract_manually_create_invoice.xml',
'views/abstract_contract_line.xml', 'views/abstract_contract_line.xml',
'views/contract.xml', 'views/contract.xml',
'views/contract_line.xml', 'views/contract_line.xml',

9
contract/models/contract.py

@ -460,8 +460,9 @@ class ContractContract(models.Model):
return self._finalize_and_create_invoices(invoices_values) return self._finalize_and_create_invoices(invoices_values)
@api.model @api.model
def cron_recurring_create_invoice(self):
domain = self._get_contracts_to_invoice_domain()
def cron_recurring_create_invoice(self, date_ref=None):
if not date_ref:
date_ref = fields.Date.context_today(self)
domain = self._get_contracts_to_invoice_domain(date_ref)
contracts_to_invoice = self.search(domain) contracts_to_invoice = self.search(domain)
date_ref = fields.Date.context_today(contracts_to_invoice)
contracts_to_invoice._recurring_create_invoice(date_ref)
return contracts_to_invoice._recurring_create_invoice(date_ref)

1
contract/security/ir.model.access.csv

@ -7,3 +7,4 @@
"contract_line_user","Recurring user","model_contract_line","account.group_account_invoice",1,0,0,0 "contract_line_user","Recurring user","model_contract_line","account.group_account_invoice",1,0,0,0
"contract_template_line_manager","Recurring manager","model_contract_template_line","account.group_account_manager",1,1,1,1 "contract_template_line_manager","Recurring manager","model_contract_template_line","account.group_account_manager",1,1,1,1
"contract_template_line_user","Recurring user","model_contract_template_line","account.group_account_invoice",1,0,0,0 "contract_template_line_user","Recurring user","model_contract_template_line","account.group_account_invoice",1,0,0,0
"contract_manually_create_invoice_manager","Recurring manager access to manually invoice contract action","model_contract_manually_create_invoice","account.group_account_manager",1,1,1,0

33
contract/tests/test_contract.py

@ -1711,6 +1711,39 @@ class TestContract(TestContractBase):
len(invoice_lines), len(invoice_lines),
) )
def test_contract_manually_create_invoice(self):
self.acct_line.date_start = '2018-01-01'
self.acct_line.recurring_invoicing_type = 'post-paid'
self.acct_line.date_end = '2018-03-15'
self.acct_line._onchange_date_start()
self.contract2.unlink()
contracts = self.contract
for i in range(10):
contracts |= self.contract.copy()
wizard = self.env['contract.manually.create.invoice'].create({
'invoice_date': self.today
})
wizard.action_show_contract_to_invoice()
contract_to_invoice_count = wizard.contract_to_invoice_count
self.assertEqual(
contracts,
self.env['contract.contract'].search(
wizard.action_show_contract_to_invoice()['domain']
),
)
action = wizard.create_invoice()
invoice_lines = self.env['account.invoice.line'].search(
[('contract_line_id', 'in',
contracts.mapped('contract_line_ids').ids)]
)
self.assertEqual(
len(contracts.mapped('contract_line_ids')),
len(invoice_lines),
)
invoices = self.env['account.invoice'].search(action['domain'])
self.assertEqual(invoice_lines.mapped('invoice_id'), invoices)
self.assertEqual(len(invoices), contract_to_invoice_count)
def test_get_period_to_invoice_monthlylastday_postpaid(self): def test_get_period_to_invoice_monthlylastday_postpaid(self):
self.acct_line.date_start = '2018-01-05' self.acct_line.date_start = '2018-01-05'
self.acct_line.recurring_invoicing_type = 'post-paid' self.acct_line.recurring_invoicing_type = 'post-paid'

1
contract/wizards/__init__.py

@ -1 +1,2 @@
from . import contract_line_wizard from . import contract_line_wizard
from . import contract_manually_create_invoice

62
contract/wizards/contract_manually_create_invoice.py

@ -0,0 +1,62 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
class ContractManuallyCreateInvoice(models.Model):
_name = 'contract.manually.create.invoice'
_description = 'Contract Manually Create Invoice Wizard'
invoice_date = fields.Date(string="Invoice Date", required=True)
contract_to_invoice_count = fields.Integer(
compute="_compute_contract_to_invoice_count"
)
@api.multi
def action_show_contract_to_invoice(self):
self.ensure_one()
if not self.invoice_date:
contract_to_invoice_domain = [('id', '=', False)]
else:
contract_to_invoice_domain = self.env[
'contract.contract'
]._get_contracts_to_invoice_domain(self.invoice_date)
return {
"type": "ir.actions.act_window",
"name": _("Contracts to invoice"),
"res_model": "contract.contract",
"domain": contract_to_invoice_domain,
"view_mode": "tree,form",
"context": self.env.context,
}
@api.depends('invoice_date')
def _compute_contract_to_invoice_count(self):
self.ensure_one()
if not self.invoice_date:
self.contract_to_invoice_count = 0
else:
contract_model = self.env['contract.contract']
self.contract_to_invoice_count = contract_model.search_count(
contract_model._get_contracts_to_invoice_domain(
self.invoice_date
)
)
@api.multi
def create_invoice(self):
self.ensure_one()
invoices = self.env['contract.contract'].cron_recurring_create_invoice(
self.invoice_date
)
return {
"type": "ir.actions.act_window",
"name": _("Invoices"),
"res_model": "account.invoice",
"domain": [('id', 'in', invoices.ids)],
"view_mode": "tree,form",
"context": self.env.context,
}

58
contract/wizards/contract_manually_create_invoice.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="contract_manually_create_invoice_form_view">
<field name="model">contract.manually.create.invoice</field>
<field name="arch" type="xml">
<form string="Contract Manually Create Invoice">
<group>
<group>
<field name="invoice_date"/>
</group>
<group>
<button name="action_show_contract_to_invoice" type="object"
class="btn-link"
attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}">
<field name="contract_to_invoice_count"/>
<span attrs="{'invisible': [('contract_to_invoice_count', '&gt;', 1)]}">
contract to invoice
</span>
<span attrs="{'invisible': [('contract_to_invoice_count', '&lt;', 1)]}">
contracts to invoice
</span>
</button>
</group>
</group>
<footer>
<button name="create_invoice"
string="Create Invoices"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window"
id="contract_manually_create_invoice_act_window">
<field name="name">Manually Invoice Contracts</field>
<field name="res_model">contract.manually.create.invoice</field>
<field name="view_mode">form</field>
<field name="context">{}</field>
<field name="target">new</field>
</record>
<record model="ir.ui.menu" id="contract_manually_create_invoice_menu">
<field name="name">Manually Invoice Contracts</field>
<field name="parent_id" ref="account.menu_finance"/>
<field name="action"
ref="contract_manually_create_invoice_act_window"/>
<field name="sequence" eval="16"/>
</record>
</odoo>
Loading…
Cancel
Save