mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[UPG] Contract for 10.0
This commit is contained in:
@@ -6,8 +6,9 @@
|
||||
Contracts for recurrent invoicing
|
||||
=================================
|
||||
|
||||
This module forward-port to v9 the contracts management with recurring
|
||||
invoicing functions.
|
||||
This module forward-port to v10 the contracts management with recurring
|
||||
invoicing functions. In upstream Odoo, this functionality was moved into the
|
||||
Enterprise edition.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
@@ -19,7 +20,7 @@ Usage
|
||||
|
||||
To use this module, you need to:
|
||||
|
||||
#. Go to Sales -> Contracts and select or create a new contract.
|
||||
#. Go to Accounting -> Contracts and select or create a new contract.
|
||||
#. Check *Generate recurring invoices automatically*.
|
||||
#. Fill fields for selecting the recurrency and invoice parameters:
|
||||
* Journal
|
||||
@@ -41,7 +42,7 @@ To use this module, you need to:
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/110/9.0
|
||||
:target: https://runbot.odoo-community.org/runbot/110/10.0
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
{
|
||||
'name': 'Contracts Management recurring',
|
||||
'version': '9.0.1.1.0',
|
||||
'version': '10.0.1.0.0',
|
||||
'category': 'Contract Management',
|
||||
'license': 'AGPL-3',
|
||||
'author': "OpenERP SA,"
|
||||
"Tecnativa,"
|
||||
"Odoo Community Association (OCA)",
|
||||
'website': 'http://openerp.com',
|
||||
'website': 'https://github.com/oca/contract',
|
||||
'depends': ['base', 'account', 'analytic'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
@@ -19,5 +19,5 @@
|
||||
'views/contract.xml',
|
||||
'views/account_invoice_view.xml',
|
||||
],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<?xml version="1.0" encoding='UTF-8'?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.cron" id="account_analytic_cron_for_invoice">
|
||||
<field name="name">Generate Recurring Invoices from Contracts</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="model" eval="'account.analytic.account'"/>
|
||||
<field name="function" eval="'cron_recurring_create_invoice'"/>
|
||||
<field name="args" eval="'()'"/>
|
||||
</record>
|
||||
<record model="ir.cron" id="account_analytic_cron_for_invoice">
|
||||
<field name="name">Generate Recurring Invoices from Contracts</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="model" eval="'account.analytic.account'"/>
|
||||
<field name="function" eval="'cron_recurring_create_invoice'"/>
|
||||
<field name="args" eval="'()'"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import logging
|
||||
|
||||
from openerp import api, fields, models
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
from openerp.exceptions import ValidationError
|
||||
from openerp.tools.translate import _
|
||||
from odoo import api, fields, models
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,7 +30,7 @@ class AccountAnalyticInvoiceLine(models.Model):
|
||||
price_unit = fields.Float('Unit Price', required=True)
|
||||
price_subtotal = fields.Float(
|
||||
compute='_compute_price_subtotal',
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
digits=dp.get_precision('Account'),
|
||||
string='Sub Total')
|
||||
discount = fields.Float(
|
||||
string='Discount (%)',
|
||||
@@ -155,7 +155,7 @@ class AccountAnalyticAccount(models.Model):
|
||||
self.recurring_next_date = self.date_start
|
||||
|
||||
@api.model
|
||||
def get_relalive_delta(self, recurring_rule_type, interval):
|
||||
def get_relative_delta(self, recurring_rule_type, interval):
|
||||
if recurring_rule_type == 'daily':
|
||||
return relativedelta(days=interval)
|
||||
elif recurring_rule_type == 'weekly':
|
||||
@@ -175,7 +175,7 @@ class AccountAnalyticAccount(models.Model):
|
||||
date_to = next_date - relativedelta(days=1)
|
||||
else:
|
||||
date_from = (date_start -
|
||||
self.get_relalive_delta(contract.recurring_rule_type,
|
||||
self.get_relative_delta(contract.recurring_rule_type,
|
||||
contract.recurring_interval) +
|
||||
relativedelta(days=1))
|
||||
date_to = date_start
|
||||
@@ -267,7 +267,7 @@ class AccountAnalyticAccount(models.Model):
|
||||
for contract in self:
|
||||
old_date = fields.Date.from_string(
|
||||
contract.recurring_next_date or fields.Date.today())
|
||||
new_date = old_date + self.get_relalive_delta(
|
||||
new_date = old_date + self.get_relative_delta(
|
||||
contract.recurring_rule_type, contract.recurring_interval)
|
||||
ctx = self.env.context.copy()
|
||||
ctx.update({
|
||||
@@ -287,6 +287,5 @@ class AccountAnalyticAccount(models.Model):
|
||||
def cron_recurring_create_invoice(self):
|
||||
contracts = self.search(
|
||||
[('recurring_next_date', '<=', fields.date.today()),
|
||||
('account_type', '=', 'normal'),
|
||||
('recurring_invoices', '=', True)])
|
||||
return contracts.recurring_create_invoice()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp import fields, models
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"account_analytic_invoice_line_manager","Recurring manager","model_account_analytic_invoice_line","base.group_sale_manager",1,1,1,1
|
||||
"account_analytic_invoice_line_user","Recurring user","model_account_analytic_invoice_line","base.group_sale_salesman",1,0,0,0
|
||||
"account_analytic_invoice_line_manager","Recurring manager","model_account_analytic_invoice_line","account.group_account_manager",1,1,1,1
|
||||
"account_analytic_invoice_line_user","Recurring user","model_account_analytic_invoice_line","account.group_account_user",1,0,0,0
|
||||
|
||||
|
||||
|
@@ -2,8 +2,8 @@
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp.exceptions import ValidationError
|
||||
from openerp.tests.common import TransactionCase
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestContract(TransactionCase):
|
||||
@@ -12,6 +12,8 @@ class TestContract(TransactionCase):
|
||||
super(TestContract, self).setUp()
|
||||
self.partner = self.env.ref('base.res_partner_2')
|
||||
self.product = self.env.ref('product.product_product_2')
|
||||
self.product.taxes_id += self.env['account.tax'].search(
|
||||
[('type_tax_use', '=', 'sale')], limit=1)
|
||||
self.product.description_sale = 'Test description sale'
|
||||
self.contract = self.env['account.analytic.account'].create({
|
||||
'name': 'Test Contract',
|
||||
@@ -53,6 +55,7 @@ class TestContract(TransactionCase):
|
||||
self.assertEqual(self.contract.recurring_next_date, '2016-03-29')
|
||||
|
||||
self.inv_line = self.invoice_monthly.invoice_line_ids[0]
|
||||
self.assertTrue(self.inv_line.invoice_line_tax_ids)
|
||||
self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
|
||||
self.assertEqual(self.contract.partner_id.user_id,
|
||||
self.invoice_monthly.user_id)
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<!-- Invoice search view with contract -->
|
||||
<record id="view_account_invoice_filter_contract" model="ir.ui.view">
|
||||
<field name="name">account.invoice.select.contract</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="after">
|
||||
<separator/>
|
||||
<field name="contract_id"/>
|
||||
</field>
|
||||
<!-- Invoice search view with contract -->
|
||||
<record id="view_account_invoice_filter_contract" model="ir.ui.view">
|
||||
<field name="name">account.invoice.select.contract</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="after">
|
||||
<separator/>
|
||||
<field name="contract_id"/>
|
||||
</field>
|
||||
</record>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,116 +1,114 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record id="act_recurring_invoices" model="ir.actions.act_window">
|
||||
<field name="context">{'search_default_contract_id':
|
||||
[active_id],
|
||||
'default_contract_id': active_id}
|
||||
</field>
|
||||
<field name="name">Invoices</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
<field name="view_id" ref="account.invoice_tree" />
|
||||
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
|
||||
</record>
|
||||
<record id="act_recurring_invoices" model="ir.actions.act_window">
|
||||
<field name="context">{'search_default_contract_id':
|
||||
[active_id],
|
||||
'default_contract_id': active_id}
|
||||
</field>
|
||||
<field name="name">Invoices</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
<field name="view_id" ref="account.invoice_tree" />
|
||||
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_account_recurring_form_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.invoice.recurring.form.inherit</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
|
||||
<field eval="40" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="before">
|
||||
<separator string="Recurring Invoices" attrs="{'invisible': [('recurring_invoices','!=',True)]}"/>
|
||||
<div>
|
||||
<field name="recurring_invoices" class="oe_inline"/>
|
||||
<label for="recurring_invoices" />
|
||||
<button name="recurring_create_invoice" type="object"
|
||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||
string="Create invoices" class="oe_link"
|
||||
groups="base.group_no_one"/>
|
||||
<button name="%(contract.act_recurring_invoices)d" type="action"
|
||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||
string="⇒ Show recurring invoices" class="oe_link"/>
|
||||
</div>
|
||||
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||
<field name="journal_id"/>
|
||||
<field name="pricelist_id"/>
|
||||
<label for="recurring_interval"/>
|
||||
<div>
|
||||
<field name="recurring_interval" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||
<field name="recurring_rule_type" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||
</div>
|
||||
<field name="recurring_invoicing_type"/>
|
||||
<field name="date_start"/>
|
||||
<field name="recurring_next_date"/>
|
||||
</group>
|
||||
<label for="recurring_invoice_line_ids" attrs="{'invisible': [('recurring_invoices','=',False)]}"/>
|
||||
<div attrs="{'invisible': [('recurring_invoices','=',False)]}">
|
||||
<field name="recurring_invoice_line_ids">
|
||||
<tree string="Account Analytic Lines" editable="bottom">
|
||||
<field name="product_id"/>
|
||||
<field name="name"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="discount" groups="sale.group_discount_per_so_line" />
|
||||
<field name="price_subtotal"/>
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
<group string="Legend (for the markers inside invoice lines description)"
|
||||
name="group_legend" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||
<p colspan="2"> <strong>#START#</strong>: Start date of the invoiced period</p>
|
||||
<p colspan="2"> <strong>#END#</strong>: End date of the invoiced period</p>
|
||||
</group>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inherited Analytic Account list for contracts -->
|
||||
<record id="view_account_analytic_account_journal_tree" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.journal.list</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_list" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="before">
|
||||
<field name="journal_id" groups="account.group_account_user"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Analytic Account search view for contract -->
|
||||
<record id="view_account_analytic_account_contract_search" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.contract.search</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<record id="account_analytic_account_recurring_form_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.invoice.recurring.form.inherit</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
|
||||
<field eval="40" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="main" position="after">
|
||||
<separator string="Recurring Invoices" attrs="{'invisible': [('recurring_invoices','!=',True)]}"/>
|
||||
<div>
|
||||
<field name="recurring_invoices" class="oe_inline"/>
|
||||
<label for="recurring_invoices" />
|
||||
<button name="recurring_create_invoice" type="object"
|
||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||
string="Create invoices" class="oe_link"
|
||||
groups="base.group_no_one"/>
|
||||
<button name="%(contract.act_recurring_invoices)d" type="action"
|
||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||
string="⇒ Show recurring invoices" class="oe_link"/>
|
||||
</div>
|
||||
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||
<field name="journal_id"/>
|
||||
<field name="pricelist_id"/>
|
||||
<filter name="recurring_invoices" string="Recurring Invoices" domain="[('recurring_invoices','=',True)]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Next Invoice" domain="[]" context="{'group_by':'recurring_next_date'}"/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<label for="recurring_interval"/>
|
||||
<div>
|
||||
<field name="recurring_interval" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||
<field name="recurring_rule_type" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||
</div>
|
||||
<field name="recurring_invoicing_type"/>
|
||||
<field name="date_start"/>
|
||||
<field name="recurring_next_date"/>
|
||||
</group>
|
||||
<label for="recurring_invoice_line_ids" attrs="{'invisible': [('recurring_invoices','=',False)]}"/>
|
||||
<div attrs="{'invisible': [('recurring_invoices','=',False)]}">
|
||||
<field name="recurring_invoice_line_ids">
|
||||
<tree string="Account Analytic Lines" editable="bottom">
|
||||
<field name="product_id"/>
|
||||
<field name="name"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="discount" groups="sale.group_discount_per_so_line" />
|
||||
<field name="price_subtotal"/>
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
<group string="Legend (for the markers inside invoice lines description)"
|
||||
name="group_legend" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||
<p colspan="2"> <strong>#START#</strong>: Start date of the invoiced period</p>
|
||||
<p colspan="2"> <strong>#END#</strong>: End date of the invoiced period</p>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Sales/Sales/Contracts -->
|
||||
<record id="action_account_analytic_overdue_all" model="ir.actions.act_window">
|
||||
<field name="name">Contracts</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_active':1, 'search_default_recurring_invoices':1}</field>
|
||||
<field name="search_view_id" ref="analytic.view_account_analytic_account_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new contract.
|
||||
</p>
|
||||
<!-- Inherited Analytic Account list for contracts -->
|
||||
<record id="view_account_analytic_account_journal_tree" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.journal.list</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_list" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="before">
|
||||
<field name="journal_id" groups="account.group_account_user"/>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="8" parent="base.menu_sales"/>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
<!-- Analytic Account search view for contract -->
|
||||
<record id="view_account_analytic_account_contract_search" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.contract.search</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<field name="journal_id"/>
|
||||
<field name="pricelist_id"/>
|
||||
<filter name="recurring_invoices" string="Recurring Invoices" domain="[('recurring_invoices','=',True)]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Next Invoice" domain="[]" context="{'group_by':'recurring_next_date'}"/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Sales/Sales/Contracts -->
|
||||
<record id="action_account_analytic_overdue_all" model="ir.actions.act_window">
|
||||
<field name="name">Contracts</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_active':1, 'search_default_recurring_invoices':1}</field>
|
||||
<field name="search_view_id" ref="analytic.view_account_analytic_account_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new contract.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="99" parent="account.menu_finance_receivables"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user