mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP][10.0] contract: Add templating (#42)
Add template functionality for contracts
This commit is contained in:
committed by
Pedro M. Baeza
parent
c5d3267ee7
commit
3e876611f5
@@ -67,6 +67,7 @@ Contributors
|
||||
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
* Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
* Angel Moya <angel.moya@domatix.com>
|
||||
* Dave Lasley <dave@laslabs.com>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
@@ -4,19 +4,21 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Contracts Management recurring',
|
||||
'version': '10.0.1.0.0',
|
||||
'name': 'Contracts Management - Recurring',
|
||||
'version': '10.0.1.0.1',
|
||||
'category': 'Contract Management',
|
||||
'license': 'AGPL-3',
|
||||
'author': "OpenERP SA, "
|
||||
"Tecnativa, "
|
||||
"LasLabs, "
|
||||
"Odoo Community Association (OCA)",
|
||||
'website': 'https://github.com/oca/contract',
|
||||
'depends': ['base', 'account', 'analytic'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/contract_cron.xml',
|
||||
'views/contract.xml',
|
||||
'views/account_analytic_account_view.xml',
|
||||
'views/account_analytic_contract_view.xml',
|
||||
'views/account_invoice_view.xml',
|
||||
],
|
||||
'installable': True,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import contract
|
||||
from . import invoice
|
||||
from . import account_analytic_contract
|
||||
from . import account_analytic_account
|
||||
from . import account_analytic_invoice_line
|
||||
from . import account_invoice
|
||||
|
||||
@@ -3,157 +3,58 @@
|
||||
# © 2014 Angel Moya <angel.moya@domatix.com>
|
||||
# © 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# Copyright 2016-2017 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import logging
|
||||
|
||||
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__)
|
||||
|
||||
|
||||
class AccountAnalyticInvoiceLine(models.Model):
|
||||
_name = 'account.analytic.invoice.line'
|
||||
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', required=True)
|
||||
analytic_account_id = fields.Many2one(
|
||||
'account.analytic.account', string='Analytic Account')
|
||||
name = fields.Text(string='Description', required=True)
|
||||
quantity = fields.Float(default=1.0, required=True)
|
||||
uom_id = fields.Many2one(
|
||||
'product.uom', string='Unit of Measure', required=True)
|
||||
price_unit = fields.Float('Unit Price', required=True)
|
||||
price_subtotal = fields.Float(
|
||||
compute='_compute_price_subtotal',
|
||||
digits=dp.get_precision('Account'),
|
||||
string='Sub Total')
|
||||
discount = fields.Float(
|
||||
string='Discount (%)',
|
||||
digits=dp.get_precision('Discount'),
|
||||
help='Discount that is applied in generated invoices.'
|
||||
' It should be less or equal to 100')
|
||||
|
||||
@api.multi
|
||||
@api.depends('quantity', 'price_unit', 'discount')
|
||||
def _compute_price_subtotal(self):
|
||||
for line in self:
|
||||
subtotal = line.quantity * line.price_unit
|
||||
discount = line.discount / 100
|
||||
subtotal *= 1 - discount
|
||||
if line.analytic_account_id.pricelist_id:
|
||||
cur = line.analytic_account_id.pricelist_id.currency_id
|
||||
line.price_subtotal = cur.round(subtotal)
|
||||
else:
|
||||
line.price_subtotal = subtotal
|
||||
|
||||
@api.multi
|
||||
@api.constrains('discount')
|
||||
def _check_discount(self):
|
||||
for line in self:
|
||||
if line.discount > 100:
|
||||
raise ValidationError(
|
||||
_("Discount should be less or equal to 100"))
|
||||
|
||||
@api.multi
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id(self):
|
||||
if not self.product_id:
|
||||
return {'domain': {'uom_id': []}}
|
||||
|
||||
vals = {}
|
||||
domain = {'uom_id': [
|
||||
('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
||||
if not self.uom_id or (self.product_id.uom_id.category_id.id !=
|
||||
self.uom_id.category_id.id):
|
||||
vals['uom_id'] = self.product_id.uom_id
|
||||
|
||||
product = self.product_id.with_context(
|
||||
lang=self.analytic_account_id.partner_id.lang,
|
||||
partner=self.analytic_account_id.partner_id.id,
|
||||
quantity=self.quantity,
|
||||
date=self.analytic_account_id.recurring_next_date,
|
||||
pricelist=self.analytic_account_id.pricelist_id.id,
|
||||
uom=self.uom_id.id
|
||||
)
|
||||
|
||||
name = product.name_get()[0][1]
|
||||
if product.description_sale:
|
||||
name += '\n' + product.description_sale
|
||||
vals['name'] = name
|
||||
|
||||
vals['price_unit'] = product.price
|
||||
self.update(vals)
|
||||
return {'domain': domain}
|
||||
|
||||
|
||||
class AccountAnalyticAccount(models.Model):
|
||||
_inherit = 'account.analytic.account'
|
||||
_name = 'account.analytic.account'
|
||||
_inherit = ['account.analytic.account',
|
||||
'account.analytic.contract',
|
||||
]
|
||||
|
||||
@api.model
|
||||
def _default_journal(self):
|
||||
company_id = self.env.context.get(
|
||||
'company_id', self.env.user.company_id.id)
|
||||
domain = [
|
||||
('type', '=', 'sale'),
|
||||
('company_id', '=', company_id)]
|
||||
return self.env['account.journal'].search(domain, limit=1)
|
||||
|
||||
pricelist_id = fields.Many2one(
|
||||
comodel_name='product.pricelist',
|
||||
string='Pricelist')
|
||||
contract_template_id = fields.Many2one(
|
||||
string='Contract Template',
|
||||
comodel_name='account.analytic.contract',
|
||||
)
|
||||
date_start = fields.Date(default=fields.Date.context_today)
|
||||
recurring_invoice_line_ids = fields.One2many(
|
||||
comodel_name='account.analytic.invoice.line',
|
||||
inverse_name='analytic_account_id',
|
||||
copy=True,
|
||||
string='Invoice Lines')
|
||||
recurring_invoices = fields.Boolean(
|
||||
string='Generate recurring invoices automatically')
|
||||
recurring_rule_type = fields.Selection(
|
||||
[('daily', 'Day(s)'),
|
||||
('weekly', 'Week(s)'),
|
||||
('monthly', 'Month(s)'),
|
||||
('monthlylastday', 'Month(s) last day'),
|
||||
('yearly', 'Year(s)'),
|
||||
],
|
||||
default='monthly',
|
||||
string='Recurrency',
|
||||
help="Specify Interval for automatic invoice generation.")
|
||||
recurring_invoicing_type = fields.Selection(
|
||||
[('pre-paid', 'Pre-paid'),
|
||||
('post-paid', 'Post-paid'),
|
||||
],
|
||||
default='pre-paid',
|
||||
string='Invoicing type',
|
||||
help="Specify if process date is 'from' or 'to' invoicing date")
|
||||
recurring_interval = fields.Integer(
|
||||
default=1,
|
||||
string='Repeat Every',
|
||||
help="Repeat every (Days/Week/Month/Year)")
|
||||
string='Generate recurring invoices automatically',
|
||||
)
|
||||
recurring_next_date = fields.Date(
|
||||
default=fields.Date.context_today,
|
||||
copy=False,
|
||||
string='Date of Next Invoice')
|
||||
journal_id = fields.Many2one(
|
||||
'account.journal',
|
||||
string='Journal',
|
||||
default=_default_journal,
|
||||
domain="[('type', '=', 'sale'),('company_id', '=', company_id)]")
|
||||
string='Date of Next Invoice',
|
||||
)
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def _onchange_partner_id(self):
|
||||
self.pricelist_id = self.partner_id.property_product_pricelist.id
|
||||
@api.onchange('contract_template_id')
|
||||
def _onchange_contract_template_id(self):
|
||||
""" It updates contract fields with that of the template """
|
||||
contract = self.contract_template_id
|
||||
for field_name, field in contract._fields.iteritems():
|
||||
if any((
|
||||
field.compute, field.related, field.automatic,
|
||||
field.readonly, field.company_dependent,
|
||||
field.name in self.NO_SYNC,
|
||||
)):
|
||||
continue
|
||||
self[field_name] = self.contract_template_id[field_name]
|
||||
|
||||
@api.onchange('recurring_invoices')
|
||||
def _onchange_recurring_invoices(self):
|
||||
if self.date_start and self.recurring_invoices:
|
||||
self.recurring_next_date = self.date_start
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def _onchange_partner_id(self):
|
||||
self.pricelist_id = self.partner_id.property_product_pricelist.id
|
||||
|
||||
@api.model
|
||||
def get_relative_delta(self, recurring_rule_type, interval):
|
||||
if recurring_rule_type == 'daily':
|
||||
71
contract/models/account_analytic_contract.py
Normal file
71
contract/models/account_analytic_contract.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2004-2010 OpenERP SA
|
||||
# © 2014 Angel Moya <angel.moya@domatix.com>
|
||||
# © 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# Copyright 2016-2017 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AccountAnalyticContract(models.Model):
|
||||
_name = 'account.analytic.contract'
|
||||
|
||||
# These fields will not be synced to the contract
|
||||
NO_SYNC = [
|
||||
'name',
|
||||
]
|
||||
|
||||
name = fields.Char(
|
||||
required=True,
|
||||
)
|
||||
pricelist_id = fields.Many2one(
|
||||
comodel_name='product.pricelist',
|
||||
string='Pricelist',
|
||||
)
|
||||
recurring_invoice_line_ids = fields.One2many(
|
||||
comodel_name='account.analytic.invoice.line',
|
||||
inverse_name='analytic_account_id',
|
||||
copy=True,
|
||||
string='Invoice Lines',
|
||||
)
|
||||
recurring_rule_type = fields.Selection(
|
||||
[('daily', 'Day(s)'),
|
||||
('weekly', 'Week(s)'),
|
||||
('monthly', 'Month(s)'),
|
||||
('monthlylastday', 'Month(s) last day'),
|
||||
('yearly', 'Year(s)'),
|
||||
],
|
||||
default='monthly',
|
||||
string='Recurrence',
|
||||
help="Specify Interval for automatic invoice generation.",
|
||||
)
|
||||
recurring_invoicing_type = fields.Selection(
|
||||
[('pre-paid', 'Pre-paid'),
|
||||
('post-paid', 'Post-paid'),
|
||||
],
|
||||
default='pre-paid',
|
||||
string='Invoicing type',
|
||||
help="Specify if process date is 'from' or 'to' invoicing date",
|
||||
)
|
||||
recurring_interval = fields.Integer(
|
||||
default=1,
|
||||
string='Repeat Every',
|
||||
help="Repeat every (Days/Week/Month/Year)",
|
||||
)
|
||||
journal_id = fields.Many2one(
|
||||
'account.journal',
|
||||
string='Journal',
|
||||
default=lambda s: s._default_journal(),
|
||||
domain="[('type', '=', 'sale'),('company_id', '=', company_id)]",
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _default_journal(self):
|
||||
company_id = self.env.context.get(
|
||||
'company_id', self.env.user.company_id.id)
|
||||
domain = [
|
||||
('type', '=', 'sale'),
|
||||
('company_id', '=', company_id)]
|
||||
return self.env['account.journal'].search(domain, limit=1)
|
||||
87
contract/models/account_analytic_invoice_line.py
Normal file
87
contract/models/account_analytic_invoice_line.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2004-2010 OpenERP SA
|
||||
# © 2014 Angel Moya <angel.moya@domatix.com>
|
||||
# © 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
class AccountAnalyticInvoiceLine(models.Model):
|
||||
_name = 'account.analytic.invoice.line'
|
||||
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', required=True)
|
||||
analytic_account_id = fields.Many2one(
|
||||
'account.analytic.account', string='Analytic Account')
|
||||
name = fields.Text(string='Description', required=True)
|
||||
quantity = fields.Float(default=1.0, required=True)
|
||||
uom_id = fields.Many2one(
|
||||
'product.uom', string='Unit of Measure', required=True)
|
||||
price_unit = fields.Float('Unit Price', required=True)
|
||||
price_subtotal = fields.Float(
|
||||
compute='_compute_price_subtotal',
|
||||
digits=dp.get_precision('Account'),
|
||||
string='Sub Total')
|
||||
discount = fields.Float(
|
||||
string='Discount (%)',
|
||||
digits=dp.get_precision('Discount'),
|
||||
help='Discount that is applied in generated invoices.'
|
||||
' It should be less or equal to 100')
|
||||
|
||||
@api.multi
|
||||
@api.depends('quantity', 'price_unit', 'discount')
|
||||
def _compute_price_subtotal(self):
|
||||
for line in self:
|
||||
subtotal = line.quantity * line.price_unit
|
||||
discount = line.discount / 100
|
||||
subtotal *= 1 - discount
|
||||
if line.analytic_account_id.pricelist_id:
|
||||
cur = line.analytic_account_id.pricelist_id.currency_id
|
||||
line.price_subtotal = cur.round(subtotal)
|
||||
else:
|
||||
line.price_subtotal = subtotal
|
||||
|
||||
@api.multi
|
||||
@api.constrains('discount')
|
||||
def _check_discount(self):
|
||||
for line in self:
|
||||
if line.discount > 100:
|
||||
raise ValidationError(
|
||||
_("Discount should be less or equal to 100"))
|
||||
|
||||
@api.multi
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id(self):
|
||||
if not self.product_id:
|
||||
return {'domain': {'uom_id': []}}
|
||||
|
||||
vals = {}
|
||||
domain = {'uom_id': [
|
||||
('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
||||
if not self.uom_id or (self.product_id.uom_id.category_id.id !=
|
||||
self.uom_id.category_id.id):
|
||||
vals['uom_id'] = self.product_id.uom_id
|
||||
|
||||
product = self.product_id.with_context(
|
||||
lang=self.analytic_account_id.partner_id.lang,
|
||||
partner=self.analytic_account_id.partner_id.id,
|
||||
quantity=self.quantity,
|
||||
date=self.analytic_account_id.recurring_next_date,
|
||||
pricelist=self.analytic_account_id.pricelist_id.id,
|
||||
uom=self.uom_id.id
|
||||
)
|
||||
|
||||
name = product.name_get()[0][1]
|
||||
if product.description_sale:
|
||||
name += '\n' + product.description_sale
|
||||
vals['name'] = name
|
||||
|
||||
vals['price_unit'] = product.price
|
||||
self.update(vals)
|
||||
return {'domain': domain}
|
||||
@@ -1,4 +1,5 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"account_analytic_contract_manager","Recurring manager","model_account_analytic_contract","account.group_account_manager",1,1,1,1
|
||||
"account_analytic_contract_user","Recurring user","model_account_analytic_contract","account.group_account_user",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
|
||||
|
||||
|
||||
|
@@ -15,6 +15,14 @@ class TestContract(TransactionCase):
|
||||
self.product.taxes_id += self.env['account.tax'].search(
|
||||
[('type_tax_use', '=', 'sale')], limit=1)
|
||||
self.product.description_sale = 'Test description sale'
|
||||
self.template_vals = {
|
||||
'recurring_rule_type': 'yearly',
|
||||
'recurring_interval': 12345,
|
||||
'name': 'Test Contract Template',
|
||||
}
|
||||
self.template = self.env['account.analytic.contract'].create(
|
||||
self.template_vals,
|
||||
)
|
||||
self.contract = self.env['account.analytic.account'].create({
|
||||
'name': 'Test Contract',
|
||||
'partner_id': self.partner.id,
|
||||
@@ -136,3 +144,14 @@ class TestContract(TransactionCase):
|
||||
journal.write({'type': 'general'})
|
||||
with self.assertRaises(ValidationError):
|
||||
contract_no_journal.recurring_create_invoice()
|
||||
|
||||
def test_onchange_contract_template_id(self):
|
||||
""" It should change the contract values to match the template. """
|
||||
self.contract.contract_template_id = self.template
|
||||
self.contract._onchange_contract_template_id()
|
||||
res = {
|
||||
'recurring_rule_type': self.contract.recurring_rule_type,
|
||||
'recurring_interval': self.contract.recurring_interval,
|
||||
}
|
||||
del self.template_vals['name']
|
||||
self.assertDictEqual(res, self.template_vals)
|
||||
|
||||
@@ -1,49 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="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="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<group name="main" position="after">
|
||||
<separator string="Recurring Invoices" attrs="{'invisible': [('recurring_invoices','!=',True)]}"/>
|
||||
<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"
|
||||
<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"
|
||||
string="Create invoices"
|
||||
class="oe_link"
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
<button name="contract.act_recurring_invoices"
|
||||
type="action"
|
||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||
string="⇒ Show recurring invoices" class="oe_link"/>
|
||||
string="⇒ Show recurring invoices"
|
||||
class="oe_link"
|
||||
/>
|
||||
</div>
|
||||
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||
<field name="contract_template_id" />
|
||||
<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)]}"/>
|
||||
<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)]}"/>
|
||||
<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">
|
||||
@@ -87,9 +93,15 @@
|
||||
<field name="name" position="after">
|
||||
<field name="journal_id"/>
|
||||
<field name="pricelist_id"/>
|
||||
<filter name="recurring_invoices" string="Recurring Invoices" domain="[('recurring_invoices','=',True)]"/>
|
||||
<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'}"/>
|
||||
<filter string="Next Invoice"
|
||||
domain="[]"
|
||||
context="{'group_by':'recurring_next_date'}"
|
||||
/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
@@ -109,6 +121,11 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="99" parent="account.menu_finance_receivables"/>
|
||||
|
||||
<menuitem id="menu_action_account_analytic_overdue_all"
|
||||
parent="account.menu_finance_receivables"
|
||||
action="action_account_analytic_overdue_all"
|
||||
sequence="99"
|
||||
/>
|
||||
|
||||
</odoo>
|
||||
118
contract/views/account_analytic_contract_view.xml
Normal file
118
contract/views/account_analytic_contract_view.xml
Normal file
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="account_analytic_contract_view_form" model="ir.ui.view">
|
||||
<field name="name">Account Analytic Contract Form View</field>
|
||||
<field name="model">account.analytic.contract</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Contract Template">
|
||||
<group name="group_main">
|
||||
<field name="name" />
|
||||
<group name="group_main_left">
|
||||
<field name="journal_id" />
|
||||
<field name="pricelist_id" />
|
||||
</group>
|
||||
<group name="group_main_right">
|
||||
<field name="recurring_invoicing_type" />
|
||||
<label for="recurring_interval" />
|
||||
<div>
|
||||
<field name="recurring_interval"
|
||||
class="oe_inline"
|
||||
required="True"
|
||||
/>
|
||||
<field name="recurring_rule_type"
|
||||
class="oe_inline"
|
||||
required="True"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group name="group_invoice_lines" string="Invoice Lines">
|
||||
<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>
|
||||
</group>
|
||||
<group name="group_legend"
|
||||
string="Legend (for the markers inside invoice lines description)"
|
||||
>
|
||||
<p> <strong>#START#</strong>: Start date of the invoiced period</p>
|
||||
<p> <strong>#END#</strong>: End date of the invoiced period</p>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_contract_view_tree" model="ir.ui.view">
|
||||
<field name="name">Account Analytic Contract Tree View</field>
|
||||
<field name="model">account.analytic.contract</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Contract Templates">
|
||||
<field name="name" />
|
||||
<field name="recurring_rule_type" />
|
||||
<field name="recurring_interval" />
|
||||
<field name="recurring_invoicing_type" />
|
||||
<field name="pricelist_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_contract_view_search" model="ir.ui.view">
|
||||
<field name="name">Account Analytic Contract Search View</field>
|
||||
<field name="model">account.analytic.contract</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Contract Templates">
|
||||
<field name="name" />
|
||||
<field name="recurring_rule_type" />
|
||||
<field name="recurring_interval" />
|
||||
<field name="recurring_invoicing_type" />
|
||||
<field name="pricelist_id" />
|
||||
<field name="journal_id" />
|
||||
<filter string="Recurrence"
|
||||
context="{'group_by': 'recurring_rule_type'}"
|
||||
/>
|
||||
<filter string="Invoicing Type"
|
||||
context="{'group_by': 'recurring_invoicing_type'}"
|
||||
/>
|
||||
<filter string="Pricelist"
|
||||
context="{'group_by': 'pricelist_id'}"
|
||||
/>
|
||||
<filter string="Journal"
|
||||
context="{'group_by': 'journal_id'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_contract_action" model="ir.actions.act_window">
|
||||
<field name="name">Contract Templates</field>
|
||||
<field name="res_model">account.analytic.contract</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new contract template.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_config_contract"
|
||||
name="Contracts"
|
||||
sequence="1"
|
||||
parent="account.menu_finance_configuration"
|
||||
/>
|
||||
|
||||
<menuitem id="account_analytic_contract_menu"
|
||||
parent="menu_config_contract"
|
||||
action="account_analytic_contract_action"
|
||||
sequence="1"
|
||||
/>
|
||||
|
||||
</odoo>
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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>
|
||||
@@ -14,4 +13,15 @@
|
||||
</field>
|
||||
</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>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -77,11 +77,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="contract.menu_config_contract"
|
||||
name="Contracts"
|
||||
sequence="5"
|
||||
parent="account.menu_finance_configuration"
|
||||
/>
|
||||
<menuitem id="menu_contract_quantity_formula"
|
||||
action="action_contract_quantity_formula"
|
||||
parent="contract.menu_config_contract"
|
||||
|
||||
Reference in New Issue
Block a user