mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
@@ -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',
|
||||||
|
|||||||
@@ -457,7 +457,17 @@ class ContractContract(models.Model):
|
|||||||
This method triggers the creation of the next invoices of the contracts
|
This method triggers the creation of the next invoices of the contracts
|
||||||
even if their next invoicing date is in the future.
|
even if their next invoicing date is in the future.
|
||||||
"""
|
"""
|
||||||
return self._recurring_create_invoice()
|
invoice = self._recurring_create_invoice()
|
||||||
|
if invoice:
|
||||||
|
self.message_post(
|
||||||
|
body=_(
|
||||||
|
'Contract manually invoiced: '
|
||||||
|
'<a href="#" data-oe-model="%s" data-oe-id="%s">Invoice'
|
||||||
|
'</a>'
|
||||||
|
)
|
||||||
|
% (invoice._name, invoice.id)
|
||||||
|
)
|
||||||
|
return invoice
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def _recurring_create_invoice(self, date_ref=False):
|
def _recurring_create_invoice(self, date_ref=False):
|
||||||
@@ -465,8 +475,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):
|
def cron_recurring_create_invoice(self, date_ref=None):
|
||||||
domain = self._get_contracts_to_invoice_domain()
|
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)
|
return contracts_to_invoice._recurring_create_invoice(date_ref)
|
||||||
contracts_to_invoice._recurring_create_invoice(date_ref)
|
|
||||||
|
|||||||
@@ -1737,6 +1737,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 +1,2 @@
|
|||||||
from . import contract_line_wizard
|
from . import contract_line_wizard
|
||||||
|
from . import contract_manually_create_invoice
|
||||||
|
|||||||
66
contract/wizards/contract_manually_create_invoice.py
Normal file
66
contract/wizards/contract_manually_create_invoice.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# 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.TransientModel):
|
||||||
|
|
||||||
|
_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_ids"
|
||||||
|
)
|
||||||
|
contract_to_invoice_ids = fields.Many2many(
|
||||||
|
comodel_name="contract.contract",
|
||||||
|
compute="_compute_contract_to_invoice_ids",
|
||||||
|
)
|
||||||
|
contract_type = fields.Selection(
|
||||||
|
selection=[('sale', 'Customer'), ('purchase', 'Supplier')],
|
||||||
|
default='sale',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends('invoice_date')
|
||||||
|
def _compute_contract_to_invoice_ids(self):
|
||||||
|
if not self.invoice_date:
|
||||||
|
# trick to show no invoice when no date has been entered yet
|
||||||
|
contract_to_invoice_domain = [('id', '=', False)]
|
||||||
|
else:
|
||||||
|
contract_to_invoice_domain = self.env[
|
||||||
|
'contract.contract'
|
||||||
|
]._get_contracts_to_invoice_domain(self.invoice_date)
|
||||||
|
self.contract_to_invoice_ids = self.env['contract.contract'].search(
|
||||||
|
contract_to_invoice_domain
|
||||||
|
+ [('contract_type', '=', self.contract_type)]
|
||||||
|
)
|
||||||
|
self.contract_to_invoice_count = len(self.contract_to_invoice_ids)
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def action_show_contract_to_invoice(self):
|
||||||
|
self.ensure_one()
|
||||||
|
return {
|
||||||
|
"type": "ir.actions.act_window",
|
||||||
|
"name": _("Contracts to invoice"),
|
||||||
|
"res_model": "contract.contract",
|
||||||
|
"domain": [('id', 'in', self.contract_to_invoice_ids.ids)],
|
||||||
|
"view_mode": "tree,form",
|
||||||
|
"context": self.env.context,
|
||||||
|
}
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def create_invoice(self):
|
||||||
|
self.ensure_one()
|
||||||
|
invoices = self.env['account.invoice']
|
||||||
|
for contract in self.contract_to_invoice_ids:
|
||||||
|
invoices |= contract.recurring_create_invoice()
|
||||||
|
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,
|
||||||
|
}
|
||||||
79
contract/wizards/contract_manually_create_invoice.xml
Normal file
79
contract/wizards/contract_manually_create_invoice.xml
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?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"/>
|
||||||
|
<field name="contract_type" invisible="1"/>
|
||||||
|
</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', '>', 1)]}">
|
||||||
|
contract to invoice
|
||||||
|
</span>
|
||||||
|
<span attrs="{'invisible': [('contract_to_invoice_count', '<', 1)]}">
|
||||||
|
contracts to invoice
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button name="create_invoice"
|
||||||
|
attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}"
|
||||||
|
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="sale_contract_manually_create_invoice_act_window">
|
||||||
|
<field name="name">Manually Invoice Sale Contracts</field>
|
||||||
|
<field name="res_model">contract.manually.create.invoice</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="context">{'default_contract_type': 'sale'}</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.menu" id="sale_contract_manually_create_invoice_menu">
|
||||||
|
<field name="name">Manually Invoice Sale Contracts</field>
|
||||||
|
<field name="parent_id" ref="account.menu_finance_receivables"/>
|
||||||
|
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_manager')])]"/>
|
||||||
|
<field name="action"
|
||||||
|
ref="sale_contract_manually_create_invoice_act_window"/>
|
||||||
|
<field name="sequence" eval="999"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.actions.act_window"
|
||||||
|
id="purchase_contract_manually_create_invoice_act_window">
|
||||||
|
<field name="name">Manually Invoice Purchase Contracts</field>
|
||||||
|
<field name="res_model">contract.manually.create.invoice</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="context">{'default_contract_type': 'purchase'}</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.menu" id="purchase_contract_manually_create_invoice_menu">
|
||||||
|
<field name="name">Manually Invoice Purchase Contracts</field>
|
||||||
|
<field name="parent_id" ref="account.menu_finance_payables"/>
|
||||||
|
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_manager')])]"/>
|
||||||
|
<field name="action"
|
||||||
|
ref="purchase_contract_manually_create_invoice_act_window"/>
|
||||||
|
<field name="sequence" eval="999"/>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user