Browse Source
[IMP][10.0] contract: Add templating (#42)
[IMP][10.0] contract: Add templating (#42)
Add template functionality for contractspull/121/head
Dave Lasley
8 years ago
committed by
Pedro M. Baeza
12 changed files with 392 additions and 164 deletions
-
1contract/README.rst
-
12contract/__manifest__.py
-
7contract/models/__init__.py
-
161contract/models/account_analytic_account.py
-
71contract/models/account_analytic_contract.py
-
87contract/models/account_analytic_invoice_line.py
-
0contract/models/account_invoice.py
-
3contract/security/ir.model.access.csv
-
19contract/tests/test_contract.py
-
65contract/views/account_analytic_account_view.xml
-
118contract/views/account_analytic_contract_view.xml
-
12contract/views/account_invoice_view.xml
@ -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 |
@ -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) |
@ -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 |
|||
|
@ -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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue