Browse Source

Merge PR #207 into 12.0

Signed-off-by pedrobaeza
pull/366/merge
OCA-git-bot 5 years ago
parent
commit
ceb87ec3c6
  1. 1
      .gitignore
  2. 1
      contract/__init__.py
  3. 18
      contract/__manifest__.py
  4. 4
      contract/data/contract_cron.xml
  5. 16
      contract/data/contract_renew_cron.xml
  6. 2
      contract/data/mail_template.xml
  7. 94
      contract/migrations/12.0.2.0.0/pre-migration.py
  8. 47
      contract/migrations/12.0.4.0.0/post-migration.py
  9. 113
      contract/migrations/12.0.4.0.0/pre-migration.py
  10. 11
      contract/models/__init__.py
  11. 73
      contract/models/abstract_contract.py
  12. 206
      contract/models/abstract_contract_line.py
  13. 361
      contract/models/account_analytic_account.py
  14. 100
      contract/models/account_analytic_contract.py
  15. 221
      contract/models/account_analytic_contract_line.py
  16. 16
      contract/models/account_analytic_invoice_line.py
  17. 5
      contract/models/account_invoice.py
  18. 12
      contract/models/account_invoice_line.py
  19. 457
      contract/models/contract.py
  20. 1107
      contract/models/contract_line.py
  21. 428
      contract/models/contract_line_constraints.py
  22. 22
      contract/models/contract_template.py
  23. 24
      contract/models/contract_template_line.py
  24. 23
      contract/models/res_partner.py
  25. 3
      contract/readme/CONTRIBUTORS.rst
  26. 44
      contract/readme/USAGE.rst
  27. 2
      contract/report/contract_views.xml
  28. 5
      contract/report/report_contract.xml
  29. 2
      contract/security/contract_security.xml
  30. 14
      contract/security/ir.model.access.csv
  31. 1823
      contract/tests/test_contract.py
  32. 71
      contract/views/abstract_contract_line.xml
  33. 279
      contract/views/account_analytic_account_view.xml
  34. 44
      contract/views/account_invoice_view.xml
  35. 293
      contract/views/contract.xml
  36. 169
      contract/views/contract_line.xml
  37. 73
      contract/views/contract_template.xml
  38. 17
      contract/views/contract_template_line.xml
  39. 21
      contract/views/res_partner_view.xml
  40. 1
      contract/wizards/__init__.py
  41. 58
      contract/wizards/contract_line_wizard.py
  42. 100
      contract/wizards/contract_line_wizard.xml
  43. 10
      contract_sale/__manifest__.py
  44. 2
      contract_sale/i18n/contract_sale.pot
  45. 3
      contract_sale/i18n/gl.po
  46. 32
      contract_sale/migrations/12.0.2.0.0/pre-migration.py
  47. 8
      contract_sale/security/contract_security.xml
  48. 14
      contract_sale/security/ir.model.access.csv
  49. 16
      contract_sale/views/abstract_contract_line.xml
  50. 28
      contract_sale/views/account_analytic_account_view.xml
  51. 21
      contract_sale/views/account_analytic_contract_view.xml
  52. 12
      contract_sale/views/contract.xml
  53. 16
      contract_sale/views/contract_line.xml
  54. 17
      contract_sale/views/contract_template.xml
  55. 19
      contract_sale_invoicing/i18n/ca.po
  56. 14
      contract_sale_invoicing/i18n/contract_sale_invoicing.pot
  57. 31
      contract_sale_invoicing/i18n/de.po
  58. 19
      contract_sale_invoicing/i18n/el_GR.po
  59. 19
      contract_sale_invoicing/i18n/es.po
  60. 19
      contract_sale_invoicing/i18n/es_MX.po
  61. 19
      contract_sale_invoicing/i18n/fi.po
  62. 19
      contract_sale_invoicing/i18n/fr.po
  63. 19
      contract_sale_invoicing/i18n/gl.po
  64. 19
      contract_sale_invoicing/i18n/hi_IN.po
  65. 19
      contract_sale_invoicing/i18n/hr.po
  66. 19
      contract_sale_invoicing/i18n/hr_HR.po
  67. 19
      contract_sale_invoicing/i18n/hu.po
  68. 30
      contract_sale_invoicing/i18n/it.po
  69. 19
      contract_sale_invoicing/i18n/nl.po
  70. 15
      contract_sale_invoicing/i18n/pt.po
  71. 19
      contract_sale_invoicing/i18n/pt_PT.po
  72. 19
      contract_sale_invoicing/i18n/ro.po
  73. 19
      contract_sale_invoicing/i18n/sk_SK.po
  74. 19
      contract_sale_invoicing/i18n/sl.po
  75. 19
      contract_sale_invoicing/i18n/tr.po
  76. 19
      contract_sale_invoicing/i18n/tr_TR.po
  77. 19
      contract_sale_invoicing/i18n/zh.po
  78. 15
      contract_sale_invoicing/models/contract.py
  79. 4
      contract_sale_invoicing/tests/test_contract_sale_invoicing.py
  80. 16
      contract_sale_invoicing/views/contract_view.xml

1
.gitignore

@ -21,6 +21,7 @@ var/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
*.eggs
# Installer logs # Installer logs
pip-log.txt pip-log.txt

1
contract/__init__.py

@ -1 +1,2 @@
from . import models from . import models
from . import wizards

18
contract/__manifest__.py

@ -4,11 +4,12 @@
# Copyright 2016-2018 Tecnativa - Carlos Dauden # Copyright 2016-2018 Tecnativa - Carlos Dauden
# Copyright 2017 Tecnativa - Vicent Cubells # Copyright 2017 Tecnativa - Vicent Cubells
# Copyright 2016-2017 LasLabs Inc. # Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Contracts Management - Recurring',
'version': '12.0.1.0.0',
'name': 'Recurring - Contracts Management',
'version': '12.0.4.0.0',
'category': 'Contract Management', 'category': 'Contract Management',
'license': 'AGPL-3', 'license': 'AGPL-3',
'author': "OpenERP SA, " 'author': "OpenERP SA, "
@ -16,17 +17,22 @@
"LasLabs, " "LasLabs, "
"Odoo Community Association (OCA)", "Odoo Community Association (OCA)",
'website': 'https://github.com/oca/contract', 'website': 'https://github.com/oca/contract',
'depends': ['base', 'account', 'analytic'],
'depends': ['base', 'account', 'product'],
"external_dependencies": {"python": ["dateutil"]},
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'security/contract_security.xml', 'security/contract_security.xml',
'report/report_contract.xml', 'report/report_contract.xml',
'report/contract_views.xml', 'report/contract_views.xml',
'data/contract_cron.xml', 'data/contract_cron.xml',
'data/contract_renew_cron.xml',
'data/mail_template.xml', 'data/mail_template.xml',
'views/account_analytic_account_view.xml',
'views/account_analytic_contract_view.xml',
'views/account_invoice_view.xml',
'wizards/contract_line_wizard.xml',
'views/abstract_contract_line.xml',
'views/contract.xml',
'views/contract_line.xml',
'views/contract_template.xml',
'views/contract_template_line.xml',
'views/res_partner_view.xml', 'views/res_partner_view.xml',
], ],
'installable': True, 'installable': True,

4
contract/data/contract_cron.xml

@ -1,9 +1,9 @@
<?xml version="1.0" encoding='UTF-8'?> <?xml version="1.0" encoding='UTF-8'?>
<odoo noupdate="1"> <odoo noupdate="1">
<record model="ir.cron" id="account_analytic_cron_for_invoice">
<record model="ir.cron" id="contract_cron_for_invoice">
<field name="name">Generate Recurring Invoices from Contracts</field> <field name="name">Generate Recurring Invoices from Contracts</field>
<field name="model_id" ref="analytic.model_account_analytic_account"/>
<field name="model_id" ref="model_contract_contract"/>
<field name="state">code</field> <field name="state">code</field>
<field name="code">model.cron_recurring_create_invoice()</field> <field name="code">model.cron_recurring_create_invoice()</field>
<field name="user_id" ref="base.user_root" /> <field name="user_id" ref="base.user_root" />

16
contract/data/contract_renew_cron.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding='UTF-8'?>
<odoo noupdate="1">
<record model="ir.cron" id="contract_line_cron_for_renew">
<field name="name">Renew Contract lines</field>
<field name="model_id" ref="model_contract_line"/>
<field name="state">code</field>
<field name="code">model.cron_renew_contract_line()</field>
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
</odoo>

2
contract/data/mail_template.xml

@ -6,7 +6,7 @@
<field name="email_from">${(object.user_id.email and '%s &lt;%s&gt;' % (object.user_id.name, object.user_id.email) or '')|safe}</field> <field name="email_from">${(object.user_id.email and '%s &lt;%s&gt;' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
<field name="subject">${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</field> <field name="subject">${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</field>
<field name="partner_to">${object.partner_id.id}</field> <field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="contract.model_account_analytic_account"/>
<field name="model_id" ref="model_contract_contract"/>
<field name="auto_delete" eval="True"/> <field name="auto_delete" eval="True"/>
<field name="report_template" ref="contract.report_contract"/> <field name="report_template" ref="contract.report_contract"/>
<field name="report_name">Contract</field> <field name="report_name">Contract</field>

94
contract/migrations/12.0.2.0.0/pre-migration.py

@ -0,0 +1,94 @@
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openupgradelib import openupgrade
_logger = logging.getLogger(__name__)
def _set_finished_contract(cr):
_logger.info("set recurring_next_date to false for finished contract")
openupgrade.logged_query(
cr,
"""
UPDATE account_analytic_account
SET recurring_next_date=NULL
WHERE recurring_next_date > date_end
""",
)
def _move_contract_recurrence_info_to_contract_line(cr):
_logger.info("Move contract data to line level")
openupgrade.logged_query(
cr,
"""
ALTER TABLE account_analytic_invoice_line
ADD COLUMN IF NOT EXISTS recurring_rule_type VARCHAR(255),
ADD COLUMN IF NOT EXISTS recurring_invoicing_type VARCHAR(255),
ADD COLUMN IF NOT EXISTS recurring_interval INTEGER,
ADD COLUMN IF NOT EXISTS recurring_next_date DATE,
ADD COLUMN IF NOT EXISTS date_start DATE,
ADD COLUMN IF NOT EXISTS date_end DATE
""",
)
openupgrade.logged_query(
cr,
"""
UPDATE account_analytic_invoice_line AS contract_line
SET
recurring_rule_type=contract.recurring_rule_type,
recurring_invoicing_type=contract.recurring_invoicing_type,
recurring_interval=contract.recurring_interval,
recurring_next_date=contract.recurring_next_date,
date_start=contract.date_start,
date_end=contract.date_end
FROM
account_analytic_account AS contract
WHERE
contract.id=contract_line.analytic_account_id
""",
)
def _move_contract_template_recurrence_info_to_contract_template_line(cr):
_logger.info("Move contract template data to line level")
openupgrade.logged_query(
cr,
"""
ALTER TABLE account_analytic_contract_line
ADD COLUMN IF NOT EXISTS recurring_rule_type VARCHAR(255),
ADD COLUMN IF NOT EXISTS recurring_invoicing_type VARCHAR(255),
ADD COLUMN IF NOT EXISTS recurring_interval INTEGER
""",
)
openupgrade.logged_query(
cr,
"""
UPDATE account_analytic_contract_line AS contract_template_line
SET
recurring_rule_type=contract_template.recurring_rule_type,
recurring_invoicing_type=contract_template.recurring_invoicing_type,
recurring_interval=contract_template.recurring_interval
FROM
account_analytic_contract AS contract_template
WHERE
contract_template.id=contract_template_line.analytic_account_id
""",
)
@openupgrade.migrate()
def migrate(env, version):
"""
set recurring_next_date to false for finished contract
"""
_logger.info(">> Pre-Migration 12.0.2.0.0")
cr = env.cr
_set_finished_contract(cr)
_move_contract_recurrence_info_to_contract_line(cr)
_move_contract_template_recurrence_info_to_contract_template_line(cr)

47
contract/migrations/12.0.4.0.0/post-migration.py

@ -0,0 +1,47 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openupgradelib import openupgrade
from odoo.tools import parse_version
_logger = logging.getLogger(__name__)
def _update_no_update_ir_cron(env):
# Update ir.cron
env.ref('contract.contract_cron_for_invoice').model_id = env.ref(
'contract.model_contract_contract'
)
env.ref('contract.contract_line_cron_for_renew').model_id = env.ref(
'contract.model_contract_line'
)
env.ref('contract.email_contract_template').model_id = env.ref(
'contract.model_contract_contract'
)
def _init_last_date_invoiced_on_contract_lines(env):
_logger.info("init last_date_invoiced field for contract lines")
contract_lines = env["contract.line"].search(
[("recurring_next_date", "!=", False)]
)
contract_lines._init_last_date_invoiced()
def _init_invoicing_partner_id_on_contracts(env):
_logger.info("Populate invoicing partner field on contracts")
contracts = env["contract.contract"].search([])
contracts._inverse_partner_id()
@openupgrade.migrate()
def migrate(env, version):
_update_no_update_ir_cron(env)
if parse_version(version) < parse_version('12.0.2.0.0'):
# We check the version here as this post-migration script was in
# 12.0.2.0.0 and already done for those who used the module when
# it was a PR
_init_last_date_invoiced_on_contract_lines(env)
_init_invoicing_partner_id_on_contracts(env)

113
contract/migrations/12.0.4.0.0/pre-migration.py

@ -0,0 +1,113 @@
# Copyright 2019 ACSONE SA/NV
# Copyright 2019 Tecnativa 2019 - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openupgradelib import openupgrade
from psycopg2 import sql
_logger = logging.getLogger(__name__)
models_to_rename = [
# Contract Line Wizard
('account.analytic.invoice.line.wizard', 'contract.line.wizard'),
# Abstract Contract
('account.abstract.analytic.contract', 'contract.abstract.contract'),
# Abstract Contract Line
(
'account.abstract.analytic.contract.line',
'contract.abstract.contract.line',
),
# Contract Line
('account.analytic.invoice.line', 'contract.line'),
# Contract Template
('account.analytic.contract', 'contract.template'),
# Contract Template Line
('account.analytic.contract.line', 'contract.template.line'),
]
tables_to_rename = [
# Contract Line
('account_analytic_invoice_line', 'contract_line'),
# Contract Template
('account_analytic_contract', 'contract_template'),
# Contract Template Line
('account_analytic_contract_line', 'contract_template_line'),
]
columns_to_copy = {
'contract_line': [
('analytic_account_id', 'contract_id', None),
],
}
xmlids_to_rename = [
(
'contract.account_analytic_cron_for_invoice',
'contract.contract_cron_for_invoice',
),
(
'contract.account_analytic_contract_manager',
'contract.contract_template_manager',
),
(
'contract.account_analytic_contract_user',
'contract.contract_template_user',
),
(
'contract.account_analytic_invoice_line_manager',
'contract.contract_line_manager',
),
(
'contract.account_analytic_invoice_line_user',
'contract.contract_line_user',
),
(
'contract.account_analytic_contract_line_manager',
'contract.contract_template_line_manager',
),
(
'contract.account_analytic_contract_line_user',
'contract.contract_template_line_user',
),
]
def _get_contract_field_name(cr):
"""
Contract field changed the name from analytic_account_id to contract_id
in 12.0.2.0.0. This method used to get the contract field name in
account_analytic_invoice_line"""
return (
'contract_id'
if openupgrade.column_exists(
cr, 'account_analytic_invoice_line', 'contract_id'
)
else 'analytic_account_id'
)
def create_contract_records(cr):
contract_field_name = _get_contract_field_name(cr)
openupgrade.logged_query(
cr, """
CREATE TABLE contract_contract
(LIKE account_analytic_account INCLUDING ALL)""",
)
openupgrade.logged_query(
cr, sql.SQL("""
INSERT INTO contract_contract
SELECT * FROM account_analytic_account
WHERE id IN (SELECT DISTINCT {} FROM contract_line)
""").format(
sql.Identifier(contract_field_name),
),
)
@openupgrade.migrate()
def migrate(env, version):
cr = env.cr
openupgrade.rename_models(cr, models_to_rename)
openupgrade.rename_tables(cr, tables_to_rename)
openupgrade.rename_xmlids(cr, xmlids_to_rename)
openupgrade.copy_columns(cr, columns_to_copy)
create_contract_records(cr)

11
contract/models/__init__.py

@ -1,8 +1,11 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import account_analytic_contract
from . import account_analytic_account
from . import account_analytic_contract_line
from . import account_analytic_invoice_line
from . import abstract_contract
from . import abstract_contract_line
from . import contract_template
from . import contract
from . import contract_template_line
from . import contract_line
from . import account_invoice from . import account_invoice
from . import account_invoice_line
from . import res_partner from . import res_partner

73
contract/models/abstract_contract.py

@ -0,0 +1,73 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, fields
class ContractAbstractContract(models.AbstractModel):
_name = 'contract.abstract.contract'
_description = 'Abstract Recurring Contract'
# These fields will not be synced to the contract
NO_SYNC = ['name', 'partner_id']
name = fields.Char(required=True)
# Needed for avoiding errors on several inherited behaviors
partner_id = fields.Many2one(
comodel_name="res.partner", string="Partner (always False)", index=True
)
pricelist_id = fields.Many2one(
comodel_name='product.pricelist', string='Pricelist'
)
contract_type = fields.Selection(
selection=[('sale', 'Customer'), ('purchase', 'Supplier')],
default='sale',
index=True,
)
journal_id = fields.Many2one(
'account.journal',
string='Journal',
default=lambda s: s._default_journal(),
domain="[('type', '=', contract_type),"
"('company_id', '=', company_id)]",
index=True,
)
company_id = fields.Many2one(
'res.company',
string='Company',
required=True,
default=lambda self: self.env['res.company']._company_default_get(
self._name
),
)
@api.onchange('contract_type')
def _onchange_contract_type(self):
if self.contract_type == 'purchase':
self.contract_line_ids.filtered('automatic_price').update(
{'automatic_price': False}
)
self.journal_id = self.env['account.journal'].search(
[
('type', '=', self.contract_type),
('company_id', '=', self.company_id.id),
],
limit=1,
)
@api.model
def _default_journal(self):
company_id = self.env.context.get(
'company_id', self.env.user.company_id.id
)
domain = [
('type', '=', self.contract_type),
('company_id', '=', company_id),
]
return self.env['account.journal'].search(domain, limit=1)

206
contract/models/abstract_contract_line.py

@ -0,0 +1,206 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, fields
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError
from odoo.tools.translate import _
class ContractAbstractContractLine(models.AbstractModel):
_name = 'contract.abstract.contract.line'
_description = 'Abstract Recurring Contract Line'
product_id = fields.Many2one(
'product.product', string='Product', required=True
)
name = fields.Text(string='Description', required=True)
quantity = fields.Float(default=1.0, required=True)
uom_id = fields.Many2one(
'uom.uom', string='Unit of Measure', required=True
)
automatic_price = fields.Boolean(
string="Auto-price?",
help="If this is marked, the price will be obtained automatically "
"applying the pricelist to the product. If not, you will be "
"able to introduce a manual price",
)
specific_price = fields.Float(string='Specific Price')
price_unit = fields.Float(
string='Unit Price',
compute="_compute_price_unit",
inverse="_inverse_price_unit",
)
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',
)
sequence = fields.Integer(
string="Sequence",
default=10,
help="Sequence of the contract line when displaying contracts",
)
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.",
required=True,
)
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",
required=True,
)
recurring_interval = fields.Integer(
default=1,
string='Invoice Every',
help="Invoice every (Days/Week/Month/Year)",
required=True,
)
date_start = fields.Date(string='Date Start')
recurring_next_date = fields.Date(string='Date of Next Invoice')
last_date_invoiced = fields.Date(string='Last Date Invoiced')
is_canceled = fields.Boolean(string="Canceled", default=False)
is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
auto_renew_interval = fields.Integer(
default=1,
string='Renew Every',
help="Renew every (Days/Week/Month/Year)",
)
auto_renew_rule_type = fields.Selection(
[
('daily', 'Day(s)'),
('weekly', 'Week(s)'),
('monthly', 'Month(s)'),
('yearly', 'Year(s)'),
],
default='yearly',
string='Renewal type',
help="Specify Interval for automatic renewal.",
)
termination_notice_interval = fields.Integer(
default=1, string='Termination Notice Before'
)
termination_notice_rule_type = fields.Selection(
[('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)')],
default='monthly',
string='Termination Notice type',
)
contract_id = fields.Many2one(
string='Contract',
comodel_name='contract.abstract.contract',
required=True,
ondelete='cascade',
)
@api.depends(
'automatic_price',
'specific_price',
'product_id',
'quantity',
'contract_id.pricelist_id',
'contract_id.partner_id',
)
def _compute_price_unit(self):
"""Get the specific price if no auto-price, and the price obtained
from the pricelist otherwise.
"""
for line in self:
if line.automatic_price:
product = line.product_id.with_context(
quantity=line.env.context.get(
'contract_line_qty',
line.quantity,
),
pricelist=line.contract_id.pricelist_id.id,
partner=line.contract_id.partner_id.id,
date=line.env.context.get(
'old_date', fields.Date.context_today(line)
),
)
line.price_unit = product.price
else:
line.price_unit = line.specific_price
# Tip in https://github.com/odoo/odoo/issues/23891#issuecomment-376910788
@api.onchange('price_unit')
def _inverse_price_unit(self):
"""Store the specific price in the no auto-price records."""
for line in self.filtered(lambda x: not x.automatic_price):
line.specific_price = line.price_unit
@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.contract_id.pricelist_id:
cur = line.contract_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
date = self.recurring_next_date or fields.Date.context_today(self)
partner = self.contract_id.partner_id or self.env.user.partner_id
product = self.product_id.with_context(
lang=partner.lang,
partner=partner.id,
quantity=self.quantity,
date=date,
pricelist=self.contract_id.pricelist_id.id,
uom=self.uom_id.id,
)
vals['name'] = self.product_id.get_product_multiline_description_sale()
vals['price_unit'] = product.price
self.update(vals)
return {'domain': domain}

361
contract/models/account_analytic_account.py

@ -1,361 +0,0 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 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
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.translate import _
class AccountAnalyticAccount(models.Model):
_name = 'account.analytic.account'
_inherit = ['account.analytic.account',
'account.analytic.contract',
]
contract_template_id = fields.Many2one(
string='Contract Template',
comodel_name='account.analytic.contract',
)
recurring_invoice_line_ids = fields.One2many(
string='Invoice Lines',
comodel_name='account.analytic.invoice.line',
inverse_name='analytic_account_id',
copy=True,
)
date_start = fields.Date(
string='Date Start',
default=fields.Date.context_today,
)
date_end = fields.Date(
string='Date End',
index=True,
)
recurring_invoices = fields.Boolean(
string='Generate recurring invoices automatically',
)
recurring_next_date = fields.Date(
default=fields.Date.context_today,
copy=False,
string='Date of Next Invoice',
)
user_id = fields.Many2one(
comodel_name='res.users',
string='Responsible',
index=True,
default=lambda self: self.env.user,
)
create_invoice_visibility = fields.Boolean(
compute='_compute_create_invoice_visibility',
)
@api.depends('recurring_next_date', 'date_end')
def _compute_create_invoice_visibility(self):
for contract in self:
contract.create_invoice_visibility = (
not contract.date_end or
contract.recurring_next_date <= contract.date_end
)
@api.onchange('contract_template_id')
def _onchange_contract_template_id(self):
"""Update the contract fields with that of the template.
Take special consideration with the `recurring_invoice_line_ids`,
which must be created using the data from the contract lines. Cascade
deletion ensures that any errant lines that are created are also
deleted.
"""
contract = self.contract_template_id
if not contract:
return
for field_name, field in contract._fields.items():
if field.name == 'recurring_invoice_line_ids':
lines = self._convert_contract_lines(contract)
self.recurring_invoice_line_ids = lines
elif not any((
field.compute, field.related, field.automatic,
field.readonly, field.company_dependent,
field.name in self.NO_SYNC,
)):
self[field_name] = self.contract_template_id[field_name]
@api.onchange('date_start')
def _onchange_date_start(self):
if self.date_start:
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.constrains('partner_id', 'recurring_invoices')
def _check_partner_id_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.partner_id:
raise ValidationError(
_("You must supply a customer for the contract '%s'") %
contract.name
)
@api.constrains('recurring_next_date', 'date_start')
def _check_recurring_next_date_start_date(self):
for contract in self.filtered('recurring_next_date'):
if contract.date_start > contract.recurring_next_date:
raise ValidationError(
_("You can't have a next invoicing date before the start "
"of the contract '%s'") % contract.name
)
@api.constrains('recurring_next_date', 'recurring_invoices')
def _check_recurring_next_date_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.recurring_next_date:
raise ValidationError(
_("You must supply a next invoicing date for contract "
"'%s'") % contract.name
)
@api.constrains('date_start', 'recurring_invoices')
def _check_date_start_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.date_start:
raise ValidationError(
_("You must supply a start date for contract '%s'") %
contract.name
)
@api.constrains('date_start', 'date_end')
def _check_start_end_dates(self):
for contract in self.filtered('date_end'):
if contract.date_start > contract.date_end:
raise ValidationError(
_("Contract '%s' start date can't be later than end date")
% contract.name
)
@api.multi
def _convert_contract_lines(self, contract):
self.ensure_one()
new_lines = []
for contract_line in contract.recurring_invoice_line_ids:
vals = contract_line._convert_to_write(contract_line.read()[0])
# Remove template link field named as analytic account field
vals.pop('analytic_account_id', False)
new_lines.append((0, 0, vals))
return new_lines
@api.model
def get_relative_delta(self, recurring_rule_type, interval):
if recurring_rule_type == 'daily':
return relativedelta(days=interval)
elif recurring_rule_type == 'weekly':
return relativedelta(weeks=interval)
elif recurring_rule_type == 'monthly':
return relativedelta(months=interval)
elif recurring_rule_type == 'monthlylastday':
return relativedelta(months=interval, day=31)
else:
return relativedelta(years=interval)
@api.model
def _insert_markers(self, line, date_format):
date_from = fields.Date.from_string(line.date_from)
date_to = fields.Date.from_string(line.date_to)
name = line.name
name = name.replace('#START#', date_from.strftime(date_format))
name = name.replace('#END#', date_to.strftime(date_format))
return name
@api.model
def _prepare_invoice_line(self, line, invoice_id):
invoice_line = self.env['account.invoice.line'].new({
'invoice_id': invoice_id,
'product_id': line.product_id.id,
'quantity': line.quantity,
'uom_id': line.uom_id.id,
'discount': line.discount,
})
# Get other invoice line values from product onchange
invoice_line._onchange_product_id()
invoice_line_vals = invoice_line._convert_to_write(invoice_line._cache)
# Insert markers
contract = line.analytic_account_id
lang_obj = self.env['res.lang']
lang = lang_obj.search(
[('code', '=', contract.partner_id.lang)])
date_format = lang.date_format or '%m/%d/%Y'
name = self._insert_markers(line, date_format)
invoice_line_vals.update({
'name': name,
'account_analytic_id': contract.id,
'price_unit': line.price_unit,
})
return invoice_line_vals
@api.multi
def _prepare_invoice(self, journal=None):
self.ensure_one()
if not self.partner_id:
if self.contract_type == 'purchase':
raise ValidationError(
_("You must first select a Supplier for Contract %s!") %
self.name)
else:
raise ValidationError(
_("You must first select a Customer for Contract %s!") %
self.name)
if not journal:
journal = self.journal_id or self.env['account.journal'].search([
('type', '=', self.contract_type),
('company_id', '=', self.company_id.id)
], limit=1)
if not journal:
raise ValidationError(
_("Please define a %s journal for the company '%s'.") %
(self.contract_type, self.company_id.name or '')
)
currency = (
self.pricelist_id.currency_id or
self.partner_id.property_product_pricelist.currency_id or
self.company_id.currency_id
)
invoice_type = 'out_invoice'
if self.contract_type == 'purchase':
invoice_type = 'in_invoice'
invoice = self.env['account.invoice'].new({
'reference': self.code,
'type': invoice_type,
'partner_id': self.partner_id.address_get(
['invoice'])['invoice'],
'currency_id': currency.id,
'journal_id': journal.id,
'date_invoice': self.recurring_next_date,
'origin': self.name,
'company_id': self.company_id.id,
'contract_id': self.id,
'user_id': self.partner_id.user_id.id,
})
# Get other invoice values from partner onchange
invoice._onchange_partner_id()
return invoice._convert_to_write(invoice._cache)
@api.multi
def _prepare_invoice_update(self, invoice):
vals = self._prepare_invoice()
update_vals = {
'contract_id': self.id,
'date_invoice': vals.get('date_invoice', False),
'reference': ' '.join(filter(None, [
invoice.reference, vals.get('reference')])),
'origin': ' '.join(filter(None, [
invoice.origin, vals.get('origin')])),
}
return update_vals
@api.multi
def _create_invoice(self, invoice=False):
"""
:param invoice: If not False add lines to this invoice
:return: invoice created or updated
"""
self.ensure_one()
if invoice and invoice.state == 'draft':
invoice.update(self._prepare_invoice_update(invoice))
else:
invoice = self.env['account.invoice'].create(
self._prepare_invoice())
for line in self.recurring_invoice_line_ids:
invoice_line_vals = self._prepare_invoice_line(line, invoice.id)
if invoice_line_vals:
self.env['account.invoice.line'].create(invoice_line_vals)
invoice.compute_taxes()
return invoice
@api.multi
def recurring_create_invoice(self):
"""Create invoices from contracts
:return: invoices created
"""
invoices = self.env['account.invoice']
for contract in self:
ref_date = contract.recurring_next_date or fields.Date.today()
if (contract.date_start > ref_date or
contract.date_end and contract.date_end < ref_date):
if self.env.context.get('cron'):
continue # Don't fail on cron jobs
raise ValidationError(
_("You must review start and end dates!\n%s") %
contract.name
)
old_date = fields.Date.from_string(ref_date)
new_date = old_date + self.get_relative_delta(
contract.recurring_rule_type, contract.recurring_interval)
ctx = self.env.context.copy()
ctx.update({
'old_date': old_date,
'next_date': new_date,
# Force company for correct evaluation of domain access rules
'force_company': contract.company_id.id,
})
# Re-read contract with correct company
invoices |= contract.with_context(ctx)._create_invoice()
contract.write({
'recurring_next_date': fields.Date.to_string(new_date)
})
return invoices
@api.model
def cron_recurring_create_invoice(self):
today = fields.Date.today()
contracts = self.with_context(cron=True).search([
('recurring_invoices', '=', True),
('recurring_next_date', '<=', today),
'|',
('date_end', '=', False),
('date_end', '>=', today),
])
return contracts.recurring_create_invoice()
@api.multi
def action_contract_send(self):
self.ensure_one()
template = self.env.ref(
'contract.email_contract_template',
False,
)
compose_form = self.env.ref('mail.email_compose_message_wizard_form')
ctx = dict(
default_model='account.analytic.account',
default_res_id=self.id,
default_use_template=bool(template),
default_template_id=template and template.id or False,
default_composition_mode='comment',
)
return {
'name': _('Compose Email'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form.id, 'form')],
'view_id': compose_form.id,
'target': 'new',
'context': ctx,
}
@api.multi
def button_show_recurring_invoices(self):
self.ensure_one()
action = self.env.ref(
'contract.act_purchase_recurring_invoices')
if self.contract_type == 'sale':
action = self.env.ref(
'contract.act_recurring_invoices')
return action.read()[0]

100
contract/models/account_analytic_contract.py

@ -1,100 +0,0 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2015-2017 Tecnativa - Pedro M. Baeza
# 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'
_description = "Account Analytic Contract"
# These fields will not be synced to the contract
NO_SYNC = [
'name',
'partner_id',
]
name = fields.Char(
required=True,
)
# Needed for avoiding errors on several inherited behaviors
partner_id = fields.Many2one(
comodel_name="res.partner",
string="Partner (always False)",
)
contract_type = fields.Selection(
selection=[
('sale', 'Customer'),
('purchase', 'Supplier'),
], default='sale',
)
pricelist_id = fields.Many2one(
comodel_name='product.pricelist',
string='Pricelist',
)
recurring_invoice_line_ids = fields.One2many(
comodel_name='account.analytic.contract.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', '=', contract_type),"
"('company_id', '=', company_id)]",
)
company_id = fields.Many2one(
'res.company',
string='Company',
required=True,
default=lambda self: self.env.user.company_id,
)
@api.onchange('contract_type')
def _onchange_contract_type(self):
if self.contract_type == 'purchase':
self.recurring_invoice_line_ids.filtered('automatic_price').update(
{'automatic_price': False})
self.journal_id = self.env['account.journal'].search([
('type', '=', self.contract_type),
('company_id', '=', self.company_id.id)
], limit=1)
@api.model
def _default_journal(self):
company_id = self.env.context.get(
'company_id', self.env.user.company_id.id)
domain = [
('type', '=', self.contract_type),
('company_id', '=', company_id)]
return self.env['account.journal'].search(domain, limit=1)

221
contract/models/account_analytic_contract_line.py

@ -1,221 +0,0 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2015-2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from dateutil.relativedelta import relativedelta
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 AccountAnalyticContractLine(models.Model):
_name = 'account.analytic.contract.line'
_description = 'Contract Lines'
_order = "sequence,id"
product_id = fields.Many2one(
'product.product',
string='Product',
required=True,
)
analytic_account_id = fields.Many2one(
string='Contract',
comodel_name='account.analytic.contract',
required=True,
ondelete='cascade',
)
name = fields.Text(
string='Description',
required=True,
)
quantity = fields.Float(
default=1.0,
required=True,
)
uom_id = fields.Many2one(
'uom.uom',
string='Unit of Measure',
required=True,
)
automatic_price = fields.Boolean(
string="Auto-price?",
help="If this is marked, the price will be obtained automatically "
"applying the pricelist to the product. If not, you will be "
"able to introduce a manual price",
)
specific_price = fields.Float(
string='Specific Price',
)
price_unit = fields.Float(
string='Unit Price',
compute="_compute_price_unit",
inverse="_inverse_price_unit",
)
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',
)
sequence = fields.Integer(
string="Sequence",
default=10,
help="Sequence of the contract line when displaying contracts",
)
date_from = fields.Date(
string='Date From',
compute='_compute_date_from',
help='Date from invoiced period',
)
date_to = fields.Date(
string='Date To',
compute='_compute_date_to',
help='Date to invoiced period',
)
@api.depends(
'automatic_price',
'specific_price',
'product_id',
'quantity',
'analytic_account_id.pricelist_id',
'analytic_account_id.partner_id',
)
def _compute_price_unit(self):
"""Get the specific price if no auto-price, and the price obtained
from the pricelist otherwise.
"""
for line in self:
if line.automatic_price:
product = line.product_id.with_context(
quantity=line.env.context.get(
'contract_line_qty', line.quantity,
),
pricelist=line.analytic_account_id.pricelist_id.id,
partner=line.analytic_account_id.partner_id.id,
date=line.env.context.get('old_date', fields.Date.today()),
)
line.price_unit = product.price
else:
line.price_unit = line.specific_price
# Tip in https://github.com/odoo/odoo/issues/23891#issuecomment-376910788
@api.onchange('price_unit')
def _inverse_price_unit(self):
"""Store the specific price in the no auto-price records."""
for line in self.filtered(lambda x: not x.automatic_price):
line.specific_price = line.price_unit
@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
def _compute_date_from(self):
# When call from template line.analytic_account_id comodel is
# 'account.analytic.contract',
if self._name != 'account.analytic.invoice.line':
return
for line in self:
contract = line.analytic_account_id
date_start = (
self.env.context.get('old_date') or fields.Date.from_string(
contract.recurring_next_date or fields.Date.today())
)
if contract.recurring_invoicing_type == 'pre-paid':
date_from = date_start
else:
date_from = (date_start - contract.get_relative_delta(
contract.recurring_rule_type,
contract.recurring_interval) + relativedelta(days=1))
line.date_from = fields.Date.to_string(date_from)
def _compute_date_to(self):
# When call from template line.analytic_account_id comodel is
# 'account.analytic.contract',
if self._name != 'account.analytic.invoice.line':
return
for line in self:
contract = line.analytic_account_id
date_start = (
self.env.context.get('old_date') or fields.Date.from_string(
contract.recurring_next_date or fields.Date.today())
)
next_date = (
self.env.context.get('next_date') or
date_start + contract.get_relative_delta(
contract.recurring_rule_type, contract.recurring_interval)
)
if contract.recurring_invoicing_type == 'pre-paid':
date_to = next_date - relativedelta(days=1)
else:
date_to = date_start
line.date_to = fields.Date.to_string(date_to)
@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
if self.analytic_account_id._name == 'account.analytic.account':
date = (
self.analytic_account_id.recurring_next_date or
fields.Date.today()
)
partner = self.analytic_account_id.partner_id
else:
date = fields.Date.today()
partner = self.env.user.partner_id
product = self.product_id.with_context(
lang=partner.lang,
partner=partner.id,
quantity=self.quantity,
date=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}

16
contract/models/account_analytic_invoice_line.py

@ -1,16 +0,0 @@
# Copyright 2017 LasLabs Inc.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class AccountAnalyticInvoiceLine(models.Model):
_name = 'account.analytic.invoice.line'
_inherit = 'account.analytic.contract.line'
analytic_account_id = fields.Many2one(
comodel_name='account.analytic.account',
string='Analytic Account',
required=True,
ondelete='cascade',
)

5
contract/models/account_invoice.py

@ -7,6 +7,5 @@ from odoo import fields, models
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = 'account.invoice'
contract_id = fields.Many2one(
'account.analytic.account',
string='Contract')
# We keep this field for migration purpose
old_contract_id = fields.Many2one('contract.contract')

12
contract/models/account_invoice_line.py

@ -0,0 +1,12 @@
# Copyright 2018 ACSONE SA/NV.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
contract_line_id = fields.Many2one(
'contract.line', string='Contract Line', index=True
)

457
contract/models/contract.py

@ -0,0 +1,457 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.translate import _
class ContractContract(models.Model):
_name = 'contract.contract'
_description = "Contract"
_order = 'code, name asc'
_inherit = [
'mail.thread',
'mail.activity.mixin',
'contract.abstract.contract',
]
active = fields.Boolean(
default=True,
)
code = fields.Char(
string="Reference",
)
group_id = fields.Many2one(
string="Group",
comodel_name='account.analytic.account',
ondelete='restrict',
)
currency_id = fields.Many2one(
related="company_id.currency_id",
string="Currency",
readonly=True,
)
contract_template_id = fields.Many2one(
string='Contract Template', comodel_name='contract.template'
)
contract_line_ids = fields.One2many(
string='Contract lines',
comodel_name='contract.line',
inverse_name='contract_id',
copy=True,
)
user_id = fields.Many2one(
comodel_name='res.users',
string='Responsible',
index=True,
default=lambda self: self.env.user,
)
create_invoice_visibility = fields.Boolean(
compute='_compute_create_invoice_visibility'
)
recurring_next_date = fields.Date(
compute='_compute_recurring_next_date',
string='Date of Next Invoice',
store=True,
)
date_end = fields.Date(
compute='_compute_date_end', string='Date End', store=True
)
payment_term_id = fields.Many2one(
comodel_name='account.payment.term', string='Payment Terms', index=True
)
invoice_count = fields.Integer(compute="_compute_invoice_count")
fiscal_position_id = fields.Many2one(
comodel_name='account.fiscal.position',
string='Fiscal Position',
ondelete='restrict',
)
invoice_partner_id = fields.Many2one(
string="Invoicing contact",
comodel_name='res.partner',
ondelete='restrict',
)
partner_id = fields.Many2one(
comodel_name='res.partner',
inverse='_inverse_partner_id',
required=True
)
@api.multi
def _inverse_partner_id(self):
for rec in self:
if not rec.invoice_partner_id:
rec.invoice_partner_id = rec.partner_id.address_get(
['invoice']
)['invoice']
@api.multi
def _get_related_invoices(self):
self.ensure_one()
invoices = (
self.env['account.invoice.line']
.search(
[
(
'contract_line_id',
'in',
self.contract_line_ids.ids,
)
]
)
.mapped('invoice_id')
)
invoices |= self.env['account.invoice'].search(
[('old_contract_id', '=', self.id)]
)
return invoices
@api.multi
def _compute_invoice_count(self):
for rec in self:
rec.invoice_count = len(rec._get_related_invoices())
@api.multi
def action_show_invoices(self):
self.ensure_one()
tree_view_ref = (
'account.invoice_supplier_tree'
if self.contract_type == 'purchase'
else 'account.invoice_tree_with_onboarding'
)
form_view_ref = (
'account.invoice_supplier_form'
if self.contract_type == 'purchase'
else 'account.invoice_form'
)
tree_view = self.env.ref(tree_view_ref, raise_if_not_found=False)
form_view = self.env.ref(form_view_ref, raise_if_not_found=False)
action = {
'type': 'ir.actions.act_window',
'name': 'Invoices',
'res_model': 'account.invoice',
'view_type': 'form',
'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity',
'domain': [('id', 'in', self._get_related_invoices().ids)],
}
if tree_view and form_view:
action['views'] = [(tree_view.id, 'tree'), (form_view.id, 'form')]
return action
@api.depends('contract_line_ids.date_end')
def _compute_date_end(self):
for contract in self:
contract.date_end = False
date_end = contract.contract_line_ids.mapped('date_end')
if date_end and all(date_end):
contract.date_end = max(date_end)
@api.depends(
'contract_line_ids.recurring_next_date',
'contract_line_ids.is_canceled',
)
def _compute_recurring_next_date(self):
for contract in self:
recurring_next_date = contract.contract_line_ids.filtered(
lambda l: l.recurring_next_date and not l.is_canceled
).mapped('recurring_next_date')
if recurring_next_date:
contract.recurring_next_date = min(recurring_next_date)
@api.depends('contract_line_ids.create_invoice_visibility')
def _compute_create_invoice_visibility(self):
for contract in self:
contract.create_invoice_visibility = any(
contract.contract_line_ids.mapped(
'create_invoice_visibility'
)
)
@api.onchange('contract_template_id')
def _onchange_contract_template_id(self):
"""Update the contract fields with that of the template.
Take special consideration with the `contract_line_ids`,
which must be created using the data from the contract lines. Cascade
deletion ensures that any errant lines that are created are also
deleted.
"""
contract_template_id = self.contract_template_id
if not contract_template_id:
return
for field_name, field in contract_template_id._fields.items():
if field.name == 'contract_line_ids':
lines = self._convert_contract_lines(contract_template_id)
self.contract_line_ids += lines
elif not any(
(
field.compute,
field.related,
field.automatic,
field.readonly,
field.company_dependent,
field.name in self.NO_SYNC,
)
):
self[field_name] = self.contract_template_id[field_name]
@api.onchange('partner_id')
def _onchange_partner_id(self):
self.pricelist_id = self.partner_id.property_product_pricelist.id
self.fiscal_position_id = self.partner_id.property_account_position_id
if self.contract_type == 'purchase':
self.payment_term_id = \
self.partner_id.property_supplier_payment_term_id
else:
self.payment_term_id = \
self.partner_id.property_payment_term_id
self.invoice_partner_id = self.partner_id.address_get(['invoice'])[
'invoice'
]
return {
'domain': {
'invoice_partner_id': [
'|',
('id', 'parent_of', self.partner_id.id),
('id', 'child_of', self.partner_id.id),
]
}
}
@api.multi
def _convert_contract_lines(self, contract):
self.ensure_one()
new_lines = self.env['contract.line']
contract_line_model = self.env['contract.line']
for contract_line in contract.contract_line_ids:
vals = contract_line._convert_to_write(contract_line.read()[0])
# Remove template link field
vals.pop('contract_template_id', False)
vals['date_start'] = fields.Date.context_today(contract_line)
vals['recurring_next_date'] = fields.Date.context_today(
contract_line
)
new_lines += contract_line_model.new(vals)
new_lines._onchange_date_start()
new_lines._onchange_is_auto_renew()
return new_lines
@api.multi
def _prepare_invoice(self, date_invoice, journal=None):
self.ensure_one()
if not journal:
journal = (
self.journal_id
if self.journal_id.type == self.contract_type
else self.env['account.journal'].search(
[
('type', '=', self.contract_type),
('company_id', '=', self.company_id.id),
],
limit=1,
)
)
if not journal:
raise ValidationError(
_("Please define a %s journal for the company '%s'.")
% (self.contract_type, self.company_id.name or '')
)
currency = (
self.pricelist_id.currency_id
or self.partner_id.property_product_pricelist.currency_id
or self.company_id.currency_id
)
invoice_type = 'out_invoice'
if self.contract_type == 'purchase':
invoice_type = 'in_invoice'
return {
'name': self.code,
'type': invoice_type,
'partner_id': self.invoice_partner_id.id,
'currency_id': currency.id,
'date_invoice': date_invoice,
'journal_id': journal.id,
'origin': self.name,
'company_id': self.company_id.id,
'user_id': self.user_id.id,
'payment_term_id': self.payment_term_id.id,
'fiscal_position_id': self.fiscal_position_id.id,
}
@api.multi
def action_contract_send(self):
self.ensure_one()
template = self.env.ref('contract.email_contract_template', False)
compose_form = self.env.ref('mail.email_compose_message_wizard_form')
ctx = dict(
default_model='contract.contract',
default_res_id=self.id,
default_use_template=bool(template),
default_template_id=template and template.id or False,
default_composition_mode='comment',
)
return {
'name': _('Compose Email'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form.id, 'form')],
'view_id': compose_form.id,
'target': 'new',
'context': ctx,
}
@api.model
def _finalize_invoice_values(self, invoice_values):
"""
This method adds the missing values in the invoice lines dictionaries.
If no account on the product, the invoice lines account is
taken from the invoice's journal in _onchange_product_id
This code is not in finalize_creation_from_contract because it's
not possible to create an invoice line with no account
:param invoice_values: dictionary (invoice values)
:return: updated dictionary (invoice values)
"""
# If no account on the product, the invoice lines account is
# taken from the invoice's journal in _onchange_product_id
# This code is not in finalize_creation_from_contract because it's
# not possible to create an invoice line with no account
new_invoice = self.env['account.invoice'].new(invoice_values)
for invoice_line in new_invoice.invoice_line_ids:
name = invoice_line.name
account_analytic_id = invoice_line.account_analytic_id
price_unit = invoice_line.price_unit
invoice_line.invoice_id = new_invoice
invoice_line._onchange_product_id()
invoice_line.update(
{
'name': name,
'account_analytic_id': account_analytic_id,
'price_unit': price_unit,
}
)
return new_invoice._convert_to_write(new_invoice._cache)
@api.model
def _finalize_invoice_creation(self, invoices):
for invoice in invoices:
payment_term = invoice.payment_term_id
fiscal_position = invoice.fiscal_position_id
invoice._onchange_partner_id()
invoice.payment_term_id = payment_term
invoice.fiscal_position_id = fiscal_position
invoices.compute_taxes()
@api.model
def _finalize_and_create_invoices(self, invoices_values):
"""
This method:
- finalizes the invoices values (onchange's...)
- creates the invoices
- finalizes the created invoices (onchange's, tax computation...)
:param invoices_values: list of dictionaries (invoices values)
:return: created invoices (account.invoice)
"""
if isinstance(invoices_values, dict):
invoices_values = [invoices_values]
final_invoices_values = []
for invoice_values in invoices_values:
final_invoices_values.append(
self._finalize_invoice_values(invoice_values)
)
invoices = self.env['account.invoice'].create(final_invoices_values)
self._finalize_invoice_creation(invoices)
return invoices
@api.model
def _get_contracts_to_invoice_domain(self, date_ref=None):
"""
This method builds the domain to use to find all
contracts (contract.contract) to invoice.
:param date_ref: optional reference date to use instead of today
:return: list (domain) usable on contract.contract
"""
domain = []
if not date_ref:
date_ref = fields.Date.context_today(self)
domain.extend([('recurring_next_date', '<=', date_ref)])
return domain
@api.multi
def _get_lines_to_invoice(self, date_ref):
"""
This method fetches and returns the lines to invoice on the contract
(self), based on the given date.
:param date_ref: date used as reference date to find lines to invoice
:return: contract lines (contract.line recordset)
"""
self.ensure_one()
return self.contract_line_ids.filtered(
lambda l: not l.is_canceled
and l.recurring_next_date
and l.recurring_next_date <= date_ref
)
@api.multi
def _prepare_recurring_invoices_values(self, date_ref=False):
"""
This method builds the list of invoices values to create, based on
the lines to invoice of the contracts in self.
!!! The date of next invoice (recurring_next_date) is updated here !!!
:return: list of dictionaries (invoices values)
"""
invoices_values = []
for contract in self:
if not date_ref:
date_ref = contract.recurring_next_date
if not date_ref:
# this use case is possible when recurring_create_invoice is
# called for a finished contract
continue
contract_lines = contract._get_lines_to_invoice(date_ref)
if not contract_lines:
continue
invoice_values = contract._prepare_invoice(date_ref)
for line in contract_lines:
invoice_values.setdefault('invoice_line_ids', [])
invoice_line_values = line._prepare_invoice_line(
invoice_id=False
)
if invoice_line_values:
invoice_values['invoice_line_ids'].append(
(0, 0, invoice_line_values)
)
invoices_values.append(invoice_values)
contract_lines._update_recurring_next_date()
return invoices_values
@api.multi
def recurring_create_invoice(self):
"""
This method triggers the creation of the next invoices of the contracts
even if their next invoicing date is in the future.
"""
return self._recurring_create_invoice()
@api.multi
def _recurring_create_invoice(self, date_ref=False):
invoices_values = self._prepare_recurring_invoices_values(date_ref)
return self._finalize_and_create_invoices(invoices_values)
@api.model
def cron_recurring_create_invoice(self):
domain = self._get_contracts_to_invoice_domain()
contracts_to_invoice = self.search(domain)
date_ref = fields.Date.context_today(contracts_to_invoice)
contracts_to_invoice._recurring_create_invoice(date_ref)

1107
contract/models/contract_line.py
File diff suppressed because it is too large
View File

428
contract/models/contract_line_constraints.py

@ -0,0 +1,428 @@
# Copyright 2018 ACSONE SA/NV.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import itertools
from collections import namedtuple
from odoo.fields import Date
Criteria = namedtuple(
'Criteria',
[
'when', # Contract line relatively to today (BEFORE, IN, AFTER)
'has_date_end', # Is date_end set on contract line (bool)
'has_last_date_invoiced', # Is last_date_invoiced set on contract line
'is_auto_renew', # Is is_auto_renew set on contract line (bool)
'has_successor', # Is contract line has_successor (bool)
'predecessor_has_successor',
# Is contract line predecessor has successor (bool)
# In almost of the cases
# contract_line.predecessor.successor == contract_line
# But at cancel action,
# contract_line.predecessor.successor == False
# This is to permit plan_successor on predecessor
# If contract_line.predecessor.successor != False
# and contract_line is canceled, we don't allow uncancel
# else we re-link contract_line and its predecessor
'canceled', # Is contract line canceled (bool)
],
)
Allowed = namedtuple(
'Allowed',
['plan_successor', 'stop_plan_successor', 'stop', 'cancel', 'uncancel'],
)
def _expand_none(criteria):
variations = []
for attribute, value in criteria._asdict().items():
if value is None:
if attribute == 'when':
variations.append(['BEFORE', 'IN', 'AFTER'])
else:
variations.append([True, False])
else:
variations.append([value])
return itertools.product(*variations)
def _add(matrix, criteria, allowed):
""" Expand None values to True/False combination """
for c in _expand_none(criteria):
matrix[c] = allowed
CRITERIA_ALLOWED_DICT = {
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=True,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=True,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=True,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=False,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=True,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=True,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=True,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=False,
has_last_date_invoiced=False,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=True,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=True,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=True,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=True,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='BEFORE',
has_date_end=False,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=True,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=True,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=True,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='IN',
has_date_end=False,
has_last_date_invoiced=True,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=True,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='AFTER',
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=True,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when='AFTER',
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=False,
has_successor=True,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=False,
cancel=False,
uncancel=False,
),
Criteria(
when='AFTER',
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=False,
has_successor=False,
predecessor_has_successor=None,
canceled=False,
): Allowed(
plan_successor=True,
stop_plan_successor=False,
stop=True,
cancel=False,
uncancel=False,
),
Criteria(
when=None,
has_date_end=None,
has_last_date_invoiced=None,
is_auto_renew=None,
has_successor=None,
predecessor_has_successor=False,
canceled=True,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=False,
cancel=False,
uncancel=True,
),
Criteria(
when=None,
has_date_end=None,
has_last_date_invoiced=None,
is_auto_renew=None,
has_successor=None,
predecessor_has_successor=True,
canceled=True,
): Allowed(
plan_successor=False,
stop_plan_successor=False,
stop=False,
cancel=False,
uncancel=False,
),
}
criteria_allowed_dict = {}
for c in CRITERIA_ALLOWED_DICT:
_add(criteria_allowed_dict, c, CRITERIA_ALLOWED_DICT[c])
def compute_when(date_start, date_end):
today = Date.today()
if today < date_start:
return 'BEFORE'
if date_end and today > date_end:
return 'AFTER'
return 'IN'
def compute_criteria(
date_start,
date_end,
has_last_date_invoiced,
is_auto_renew,
successor_contract_line_id,
predecessor_contract_line_id,
is_canceled,
):
return Criteria(
when=compute_when(date_start, date_end),
has_date_end=bool(date_end),
has_last_date_invoiced=bool(has_last_date_invoiced),
is_auto_renew=is_auto_renew,
has_successor=bool(successor_contract_line_id),
predecessor_has_successor=bool(
predecessor_contract_line_id.successor_contract_line_id
),
canceled=is_canceled,
)
def get_allowed(
date_start,
date_end,
has_last_date_invoiced,
is_auto_renew,
successor_contract_line_id,
predecessor_contract_line_id,
is_canceled,
):
criteria = compute_criteria(
date_start,
date_end,
has_last_date_invoiced,
is_auto_renew,
successor_contract_line_id,
predecessor_contract_line_id,
is_canceled,
)
if criteria in criteria_allowed_dict:
return criteria_allowed_dict[criteria]
return False

22
contract/models/contract_template.py

@ -0,0 +1,22 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ContractTemplate(models.Model):
_name = 'contract.template'
_inherit = 'contract.abstract.contract'
_description = "Contract Template"
contract_line_ids = fields.One2many(
comodel_name='contract.template.line',
inverse_name='contract_id',
copy=True,
string='Contract template lines',
)

24
contract/models/contract_template_line.py

@ -0,0 +1,24 @@
# Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ContractTemplateLine(models.Model):
_name = 'contract.template.line'
_inherit = 'contract.abstract.contract.line'
_description = "Contract Template Line"
_order = "sequence,id"
contract_id = fields.Many2one(
string='Contract',
comodel_name='contract.template',
required=True,
ondelete='cascade',
oldname='analytic_account_id',
)

23
contract/models/res_partner.py

@ -15,16 +15,16 @@ class ResPartner(models.Model):
string='Purchase Contracts', string='Purchase Contracts',
compute='_compute_contract_count', compute='_compute_contract_count',
) )
contract_ids = fields.One2many(
comodel_name='contract.contract',
inverse='partner_id',
string="Contracts",
)
def _compute_contract_count(self): def _compute_contract_count(self):
contract_model = self.env['account.analytic.account']
today = fields.Date.today()
contract_model = self.env['contract.contract']
fetch_data = contract_model.read_group([ fetch_data = contract_model.read_group([
('recurring_invoices', '=', True),
('partner_id', 'child_of', self.ids),
'|',
('date_end', '=', False),
('date_end', '>=', today)],
('partner_id', 'child_of', self.ids)],
['partner_id', 'contract_type'], ['partner_id', 'contract_type'], ['partner_id', 'contract_type'], ['partner_id', 'contract_type'],
lazy=False) lazy=False)
result = [[data['partner_id'][0], data['contract_type'], result = [[data['partner_id'][0], data['contract_type'],
@ -49,11 +49,8 @@ class ResPartner(models.Model):
res.update( res.update(
context=dict( context=dict(
self.env.context, self.env.context,
search_default_recurring_invoices=True,
search_default_not_finished=True,
search_default_partner_id=self.id, search_default_partner_id=self.id,
default_partner_id=self.id, default_partner_id=self.id,
default_recurring_invoices=True,
default_pricelist_id=self.property_product_pricelist.id, default_pricelist_id=self.property_product_pricelist.id,
), ),
) )
@ -62,7 +59,9 @@ class ResPartner(models.Model):
def _get_act_window_contract_xml(self, contract_type): def _get_act_window_contract_xml(self, contract_type):
if contract_type == 'purchase': if contract_type == 'purchase':
return self.env['ir.actions.act_window'].for_xml_id( return self.env['ir.actions.act_window'].for_xml_id(
'contract', 'action_account_analytic_purchase_overdue_all')
'contract', 'action_supplier_contract'
)
else: else:
return self.env['ir.actions.act_window'].for_xml_id( return self.env['ir.actions.act_window'].for_xml_id(
'contract', 'action_account_analytic_sale_overdue_all')
'contract', 'action_customer_contract'
)

3
contract/readme/CONTRIBUTORS.rst

@ -5,3 +5,6 @@
* Vicent Cubells <vicent.cubells@tecnativa.com> * Vicent Cubells <vicent.cubells@tecnativa.com>
* Miquel Raïch <miquel.raich@eficent.com> * Miquel Raïch <miquel.raich@eficent.com>
* Souheil Bejaoui <souheil.bejaoui@acsone.eu> * Souheil Bejaoui <souheil.bejaoui@acsone.eu>
* Thomas Binsfeld <thomas.binsfeld@acsone.eu>
* Rafael Blasco <rafael.blasco@tecnativa.com>
* Guillaume Vandamme <guillaume.vandamme@acsone.eu>

44
contract/readme/USAGE.rst

@ -1,27 +1,25 @@
To use this module, you need to:
#. Contracts are in Invoicing -> Customers -> Customer and Invoicing -> Vendors -> Supplier Contracts
#. When creating a contract, fill fields for selecting the invoicing parameters:
#. 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:
* a journal
* a price list (optional)
* Journal
* Pricelist
* Period. It can be any interval of days, weeks, months, months last day or
years.
* Start date and next invoice date.
* Invoicing type: pre-paid or post-paid.
#. And add the lines to be invoiced with:
#. Add the lines to be invoiced with the product, description, quantity and
price.
#. You can mark Auto-price? for having a price automatically obtained applying
the pricelist to the product price.
#. You have the possibility to use the markers #START# or #END# in the
description field to show the start and end date of the invoiced period.
#. Choosing between pre-paid and post-paid, you modify the dates that are shown
with the markers.
#. A cron is created with daily interval, but if you are in debug mode, you can
click on *Create invoices* to force this action.
#. Click *Show recurring invoices* link to show all invoices created by the
* the product with a description, a quantity and a price
* the recurrence parameters: interval (days, weeks, months, months last day or years),
start date, date of next invoice (automatically computed, can be modified) and end date (optional)
* auto-price, for having a price automatically obtained from the price list
* #START# or #END# in the description field to display the start/end date of
the invoiced period in the invoice line description
* pre-paid (invoice at period start) or post-paid (invoice at start of next period)
#. The "Generate Recurring Invoices from Contracts" cron runs daily to generate the invoices.
If you are in debug mode, you can click on the invoice creation button.
#. The *Show recurring invoices* shortcut on contracts shows all invoices created from the
contract. contract.
#. Click on *Print > Contract* menu to print contract report.
#. Click on *Send by Email* button to send contract by email.
#. The contract report can be printed from the Print menu
#. The contract can be sent by email with the *Send by Email* button
#. Contract templates can be created from the Configuration -> Contracts -> Contract Templates menu.
They allow to define default journal, price list and lines when creating a contract.
To use it, just select the template on the contract and fields will be filled automatically.

2
contract/report/contract_views.xml

@ -3,7 +3,7 @@
<report <report
id="report_contract" id="report_contract"
model="account.analytic.account"
model="contract.contract"
string="Contract" string="Contract"
report_type="qweb-pdf" report_type="qweb-pdf"
name="contract.report_contract_document" name="contract.report_contract_document"

5
contract/report/report_contract.xml

@ -16,7 +16,6 @@
</div> </div>
<div class="row" id="header_info"> <div class="row" id="header_info">
<div class="col-xs-3"> <div class="col-xs-3">
<strong>Date Start: </strong><p t-field="o.date_start"/>
<strong>Responsible: </strong><p t-field="o.user_id"/> <strong>Responsible: </strong><p t-field="o.user_id"/>
<strong>Contract: </strong><p t-field="o.code"/> <strong>Contract: </strong><p t-field="o.code"/>
</div> </div>
@ -33,6 +32,7 @@
<th class="text-right"><strong>Quantity</strong></th> <th class="text-right"><strong>Quantity</strong></th>
<th class="text-right"><strong>Unit Price</strong></th> <th class="text-right"><strong>Unit Price</strong></th>
<th class="text-right"><strong>Price</strong></th> <th class="text-right"><strong>Price</strong></th>
<th class="text-right"><strong>Date Start</strong></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -49,6 +49,9 @@
<td class="text-right"> <td class="text-right">
<span t-field="l.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/> <span t-field="l.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td> </td>
<td>
<span t-field="l.date_start"/>
</td>
<t t-set="total" t-value="total + l.price_subtotal"/> <t t-set="total" t-value="total + l.price_subtotal"/>
</tr> </tr>
</tbody> </tbody>

2
contract/security/contract_security.xml

@ -2,7 +2,7 @@
<record id="rule_contract_template_multi_company" model="ir.rule"> <record id="rule_contract_template_multi_company" model="ir.rule">
<field name="name">Contract template multi-company</field> <field name="name">Contract template multi-company</field>
<field name="model_id" ref="model_account_analytic_contract"/>
<field name="model_id" ref="model_contract_template"/>
<field name="global" eval="True"/> <field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>

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

@ -1,7 +1,9 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "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_invoice",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_invoice",1,0,0,0
"account_analytic_contract_line_manager","Recurring manager","model_account_analytic_contract_line","account.group_account_manager",1,1,1,1
"account_analytic_contract_line_user","Recurring user","model_account_analytic_contract_line","account.group_account_invoice",1,0,0,0
"contract_template_manager","Recurring manager","model_contract_template","account.group_account_manager",1,1,1,1
"contract_template_user","Recurring user","model_contract_template","account.group_account_invoice",1,0,0,0
"contract_manager","Recurring manager","model_contract_contract","account.group_account_manager",1,1,1,1
"contract_user","Recurring user","model_contract_contract","account.group_account_invoice",1,0,0,0
"contract_line_manager","Recurring manager","model_contract_line","account.group_account_manager",1,1,1,1
"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_user","Recurring user","model_contract_template_line","account.group_account_invoice",1,0,0,0

1823
contract/tests/test_contract.py
File diff suppressed because it is too large
View File

71
contract/views/abstract_contract_line.xml

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--FORM view-->
<record id="contract_abstract_contract_line_form_view" model="ir.ui.view">
<field name="name">contract.abstract.contract.line form view (in contract)</field>
<field name="model">contract.abstract.contract.line</field>
<field name="arch" type="xml">
<form>
<header/>
<sheet>
<group col="4">
<field colspan="4" name="product_id"/>
<field colspan="4" name="name"/>
<field colspan="2" name="quantity"/>
<field colspan="2" name="uom_id"/>
<field colspan="2" name="automatic_price"/>
<field name="specific_price" invisible="1"/>
<field colspan="2" name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field colspan="2" name="discount" groups="base.group_no_one"/>
</group>
<group col="4">
<field colspan="2" name="is_auto_renew"/>
<field colspan="2" name="is_canceled" invisible="1"/>
</group>
<group attrs="{'invisible':[('is_auto_renew', '=', False)]}">
<group>
<label for="auto_renew_interval"/>
<div>
<field name="auto_renew_interval"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field name="auto_renew_rule_type"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
</div>
</group>
<group>
<label for="termination_notice_interval"/>
<div>
<field name="termination_notice_interval"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field name="termination_notice_rule_type"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
</div>
</group>
</group>
<group name="recurrence_info">
<group>
<label for="recurring_interval"/>
<div>
<field name="recurring_interval"
class="oe_inline" nolabel="1"/>
<field name="recurring_rule_type"
class="oe_inline" nolabel="1"/>
</div>
</group>
<group>
<field name="recurring_invoicing_type"
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
</odoo>

279
contract/views/account_analytic_account_view.xml

@ -1,279 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_analytic_account_recurring_form_form" model="ir.ui.view">
<field name="name">Contract form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="mode">primary</field>
<field name="priority" eval="9999"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="attrs">{'required': [('recurring_invoices', '=', True)]}</attribute>
</field>
<xpath expr="//div[@name='button_box']/.." position="before">
<header>
<button name="action_contract_send" type="object" string="Send by Email" groups="base.group_user"/>
</header>
</xpath>
<xpath expr='//field[@name="code"]' position='before'>
<field name="contract_type" invisible="1" required="1"/>
</xpath>
<group name="main" position="after">
<separator string="Recurring Invoices"
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
/>
<div>
<field name="recurring_invoices" class="oe_inline"/>
<field name="create_invoice_visibility" invisible="1"/>
<label for="recurring_invoices" />
<button name="recurring_create_invoice"
type="object"
attrs="{'invisible': ['|', ('recurring_invoices', '!=', True), ('create_invoice_visibility', '=', False)]}"
string="Create invoices"
class="oe_link"
groups="base.group_no_one"
/>
<button name="button_show_recurring_invoices"
type="object"
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
string="⇒ Show recurring invoices"
class="oe_link"
/>
</div>
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
<field name="contract_template_id" colspan="4" domain="['|', ('contract_type', '=', contract_type), ('contract_type', '=', False)]" context="{'default_contract_type': contract_type}"/>
<field name="journal_id"
domain="[('type', '=', contract_type),('company_id', '=', company_id)]"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="pricelist_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<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"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="date_start"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="date_end"/>
<field name="recurring_next_date"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
</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="sequence" widget="handle" />
<field name="product_id"/>
<field name="name"/>
<field name="quantity"/>
<field name="uom_id"/>
<field name="automatic_price"/>
<field name="price_unit" attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field name="specific_price" invisible="1"/>
<field name="discount" groups="base.group_no_one" />
<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>
<record id="account_analytic_account_sale_form" model="ir.ui.view">
<field name="name">account.analytic.account.sale.form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account_analytic_account_recurring_form_form"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="string">Customer</attribute>
<attribute name="domain">[('customer', '=', True)]</attribute>
<attribute name="context">{'default_customer': True, 'default_supplier': False}</attribute>
</field>
<field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'sale'),('company_id', '=', company_id)]</attribute>
</field>
<field name="product_id" position="attributes">
<attribute name="domain">[('sale_ok', '=', True)]</attribute>
</field>
</field>
</record>
<record id="account_analytic_account_purchase_form" model="ir.ui.view">
<field name="name">account.analytic.account.purchase.form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account_analytic_account_recurring_form_form"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="string">Supplier</attribute>
<attribute name="domain">[('supplier', '=', True)]</attribute>
<attribute name="context">{'default_customer': False, 'default_supplier': True}</attribute>
</field>
<field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'purchase'),('company_id', '=', company_id)]</attribute>
</field>
<field name="product_id" position="attributes">
<attribute name="domain">[('purchase_ok', '=', True)]</attribute>
</field>
<xpath expr="//field[@name='recurring_invoice_line_ids']/tree/field[@name='automatic_price']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
</field>
</record>
<!-- Inherited Analytic Account list for contracts -->
<record id="view_account_analytic_account_journal_tree" model="ir.ui.view">
<field name="name">Contract list</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_list" />
<field name="mode">primary</field>
<field name="priority" eval="9999"/>
<field name="arch" type="xml">
<field name="partner_id" position="before">
<field name="journal_id" groups="account.group_account_user"/>
</field>
<field name="partner_id" position="after">
<field name="recurring_next_date" invisible="not context.get('is_contract', False)"/>
</field>
</field>
</record>
<!-- Analytic Account search view for contract -->
<record id="view_account_analytic_account_contract_search" model="ir.ui.view">
<field name="name">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="partner_id" position="after">
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"
string="Partner and dependents"/>
</field>
<field name="name" position="after">
<field name="journal_id"/>
<field name="pricelist_id"/>
<separator/>
<filter name="recurring_invoices"
string="Recurring Invoices"
domain="[('recurring_invoices','=',True)]"
/>
<separator/>
<filter name="not_finished"
string="Valid"
domain="['|', ('date_end', '=', False), ('date_end', '&gt;=', time.strftime('%Y-%m-%d'))]"
/>
<filter name="finished"
string="Finished"
domain="[('date_end', '&lt;', time.strftime('%Y-%m-%d'))]"
/>
<group expand="0" string="Group By...">
<filter name="next_invoice"
string="Next Invoice"
domain="[]"
context="{'group_by':'recurring_next_date'}"
/>
<filter name="date_end"
string="Date End"
domain="[]"
context="{'group_by':'date_end'}"
/>
</group>
</field>
</field>
</record>
<!-- Action Sales/Sales/Contracts -->
<record id="action_account_analytic_sale_overdue_all" model="ir.actions.act_window">
<field name="name">Customer 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="domain">[('contract_type', '=', 'sale')]</field>
<field name="context">{'is_contract':1, 'search_default_not_finished':1, 'search_default_recurring_invoices':1, 'default_recurring_invoices': 1, 'default_contract_type': 'sale'}</field>
<field name="search_view_id" ref="view_account_analytic_account_contract_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p>
</field>
</record>
<record id="action_account_analytic_sale_overdue_all_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="view_account_analytic_account_journal_tree"/>
<field name="act_window_id" ref="action_account_analytic_sale_overdue_all"/>
</record>
<record id="action_account_analytic_sale_overdue_all_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="account_analytic_account_sale_form"/>
<field name="act_window_id" ref="action_account_analytic_sale_overdue_all"/>
</record>
<menuitem id="menu_action_account_analytic_sale_overdue_all"
parent="account.menu_finance_receivables"
action="action_account_analytic_sale_overdue_all"
sequence="99"
/>
<!-- Action Purchases/Purchases/Contracts -->
<record id="action_account_analytic_purchase_overdue_all" model="ir.actions.act_window">
<field name="name">Supplier 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="domain">[('contract_type', '=', 'purchase')]</field>
<field name="context">{'is_contract':1, 'search_default_not_finished':1, 'search_default_recurring_invoices':1, 'default_recurring_invoices': 1, 'default_contract_type': 'purchase'}</field>
<field name="search_view_id" ref="view_account_analytic_account_contract_search"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p>
</field>
</record>
<record id="action_account_analytic_purchase_overdue_all_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="view_account_analytic_account_journal_tree"/>
<field name="act_window_id" ref="action_account_analytic_purchase_overdue_all"/>
</record>
<record id="action_account_analytic_purchase_overdue_all_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="account_analytic_account_purchase_form"/>
<field name="act_window_id" ref="action_account_analytic_purchase_overdue_all"/>
</record>
<menuitem id="menu_action_account_analytic_purchase_overdue_all"
parent="account.menu_finance_payables"
action="action_account_analytic_purchase_overdue_all"
sequence="99"
/>
</odoo>

44
contract/views/account_invoice_view.xml

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<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>
</field>
</record>
<record id="act_recurring_invoices" model="ir.actions.act_window">
<field name="name">Invoices</field>
<field name="res_model">account.invoice</field>
<field name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('account.invoice_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('account.invoice_form')})]"/>
<field name="context">{
'search_default_contract_id': [active_id],
'default_contract_id': active_id}
</field>
<field name="domain">[('type','in', ['out_invoice', 'out_refund'])]</field>
</record>
<record id="act_purchase_recurring_invoices" model="ir.actions.act_window">
<field name="name">Vendor Bills</field>
<field name="res_model">account.invoice</field>
<field name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('account.invoice_supplier_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('account.invoice_supplier_form')})]"/>
<field name="context">{
'search_default_contract_id': [active_id],
'default_contract_id': active_id}
</field>
<field name="domain">[('type','in', ['in_invoice', 'in_refund'])]</field>
</record>
</odoo>

293
contract/views/contract.xml

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Main FORM view-->
<record id="contract_contract_form_view" model="ir.ui.view">
<field name="name">contract.contract form view (in contract)</field>
<field name="model">contract.contract</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_contract_send"
type="object"
string="Send by Email"
groups="base.group_user"/>
<button name="recurring_create_invoice"
type="object"
attrs="{'invisible': [('create_invoice_visibility', '=', False)]}"
string="Create invoices"
groups="base.group_no_one"/>
</header>
<sheet string="Contract">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object"
name="toggle_active" icon="fa-archive">
<field name="active" widget="boolean_button"
options="{&quot;terminology&quot;: &quot;archive&quot;}"/>
</button>
<button name="action_show_invoices"
type="object" icon="fa-list"
class="oe_stat_button">
<field string="Invoices"
name="invoice_count"
widget="statinfo"/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Contract Name"
class="oe_edit_only"/>
<h3>
<field name="name" class="oe_inline"
placeholder="e.g. Contract XYZ"/>
</h3>
</div>
<group name="main">
<group>
<field name="partner_id" required="1"/>
<field name="payment_term_id"/>
<field name="user_id"/>
</group>
<group>
<field name="contract_template_id"
domain="['|', ('contract_type', '=', contract_type), ('contract_type', '=', False)]"
context="{'default_contract_type': contract_type}"/>
<field name="contract_type" invisible="1"
required="1"/>
<field name="fiscal_position_id"/>
</group>
</group>
<group name="recurring_invoices">
<group>
<field name="journal_id" required="1"/>
<field name="recurring_next_date"/>
</group>
<group>
<field name="pricelist_id"/>
<field name="date_end"/>
</group>
</group>
<notebook>
<page name="recurring_invoice_line"
string="Recurring Invoices">
<field name="contract_line_ids"
context="{'default_contract_type': contract_type}"/>
</page>
<page name="info" string="Other Information">
<field name="create_invoice_visibility"
invisible="1"/>
<group>
<field name="code"/>
<field name="group_id"/>
<field name="company_id"
options="{'no_create': True}"
groups="base.group_multi_company"/>
<field name="currency_id"
options="{'no_create': True}"
groups="base.group_multi_currency"/>
<field name="invoice_partner_id"
required="1"/>
</group>
<group string="Legend (for the markers inside invoice lines description)"
name="group_legend">
<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>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<!--Customer FORM view-->
<record id="contract_contract_customer_form_view" model="ir.ui.view">
<field name="name">contract.contract customer form view (in contract)</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract_contract_form_view"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="string">Customer</attribute>
<attribute name="domain">[('customer', '=', True)]</attribute>
<attribute name="context">{'default_customer': True, 'default_supplier': False}</attribute>
</field>
<field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'sale'),('company_id', '=', company_id)]</attribute>
</field>
</field>
</record>
<!--Supplier FORM view-->
<record id="contract_contract_supplier_form_view" model="ir.ui.view">
<field name="name">contract.contract supplier form view (in contract)</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract_contract_form_view"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="string">Supplier</attribute>
<attribute name="domain">[('supplier', '=', True)]</attribute>
<attribute name="context">{'default_customer': False, 'default_supplier': True}</attribute>
</field>
<field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'purchase'),('company_id', '=', company_id)]</attribute>
</field>
</field>
</record>
<!--TREE view-->
<record id="contract_contract_tree_view" model="ir.ui.view">
<field name="name">contract.contract tree view (in contract)</field>
<field name="model">contract.contract</field>
<field name="arch" type="xml">
<tree>
<field name="name" string="Name"/>
<field name="code"/>
<field name="journal_id" groups="account.group_account_user"/>
<field name="partner_id"/>
<field name="active" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<!--SEARCH view-->
<record id="contract_contract_search_view" model="ir.ui.view">
<field name="name">contract.contract search view (in contract)</field>
<field name="model">contract.contract</field>
<field name="arch" type="xml">
<search>
<field name="name"
filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]"/>
<field name="journal_id"/>
<field name="pricelist_id"/>
<separator/>
<separator/>
<filter name="not_finished"
string="In progress"
domain="['|', ('date_end', '&gt;=', context_today().strftime('%Y-%m-%d')), ('date_end', '=', False)]"
/>
<filter name="finished"
string="Finished"
domain="[('date_end', '&lt;', context_today().strftime('%Y-%m-%d')), ('recurring_next_date', '=', False)]"
/>
<field name="partner_id"/>
<filter string="Archived"
domain="[('active', '=', False)]"
name="inactive"/>
<group expand="0" string="Group By...">
<filter string="Associated Partner"
name="group_by_partner"
domain="[]"
context="{'group_by':'partner_id'}"/>
<filter name="group_by_next_invoice"
string="Next Invoice"
domain="[('recurring_next_date', '!=', False)]"
context="{'group_by':'recurring_next_date'}"
/>
<filter name="group_by_date_end"
string="Date End"
domain="[]"
context="{'group_by':'date_end'}"
/>
</group>
</search>
</field>
</record>
<!--ACTION customer contracts-->
<record id="action_customer_contract" model="ir.actions.act_window">
<field name="name">Customer Contracts</field>
<field name="res_model">contract.contract</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('contract_type', '=', 'sale')]</field>
<field name="context">{'is_contract':1,
'search_default_not_finished':1,
'default_contract_type': 'sale'}
</field>
<field name="search_view_id" ref="contract_contract_search_view"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p>
</field>
</record>
<record id="action_customer_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view"/>
<field name="act_window_id" ref="action_customer_contract"/>
</record>
<record id="action_customer_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_customer_form_view"/>
<field name="act_window_id" ref="action_customer_contract"/>
</record>
<menuitem id="menu_contract_contract_customer"
parent="account.menu_finance_receivables"
action="action_customer_contract"
sequence="99"
/>
<!--ACTION supplier contracts-->
<record id="action_supplier_contract" model="ir.actions.act_window">
<field name="name">Supplier Contracts</field>
<field name="res_model">contract.contract</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('contract_type', '=', 'purchase')]</field>
<field name="context">{'is_contract':1,
'search_default_not_finished':1,
'default_contract_type': 'purchase'}
</field>
<field name="search_view_id" ref="contract_contract_search_view"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p>
</field>
</record>
<record id="action_supplier_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view"/>
<field name="act_window_id" ref="action_supplier_contract"/>
</record>
<record id="action_supplier_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_supplier_form_view"/>
<field name="act_window_id" ref="action_supplier_contract"/>
</record>
<menuitem id="menu_contract_contract_supplier"
parent="account.menu_finance_payables"
action="action_supplier_contract"
sequence="99"
/>
</odoo>

169
contract/views/contract_line.xml

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--FORM view-->
<record id="contract_line_form_view" model="ir.ui.view">
<field name="name">contract.line form view (in contract)</field>
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract_abstract_contract_line_form_view"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<header position="inside">
<field name="state" widget="statusbar"/>
</header>
<group name="recurrence_info" position="inside">
<group>
<field name="create_invoice_visibility" invisible="1"/>
<field name="date_start" required="1"/>
<field name="recurring_next_date"/>
</group>
<group>
<field name="date_end"
attrs="{'required': [('is_auto_renew', '=', True)]}"/>
</group>
<group groups="base.group_no_one">
<field name="last_date_invoiced" readonly="True"/>
<field name="termination_notice_date" readonly="True"/>
</group>
<group>
<field name="manual_renew_needed"/>
</group>
<group>
<field name="predecessor_contract_line_id"/>
</group>
<group>
<field name="successor_contract_line_id"/>
</group>
</group>
<group name="recurrence_info" position="after">
<group name="analytic" groups="analytic.group_analytic_accounting">
<field name="analytic_account_id"/>
</group>
</group>
</field>
</record>
<!--Customer FORM view-->
<record id="contract_line_customer_form_view" model="ir.ui.view">
<field name="name">contract.line customer form view (in contract)</field>
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract_line_form_view"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="product_id" position="attributes">
<attribute name="domain">[('sale_ok', '=', True)]</attribute>
</field>
</field>
</record>
<!--Supplier FORM view-->
<record id="contract_line_supplier_form_view" model="ir.ui.view">
<field name="name">contract.line supplier form view (in contract)</field>
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract_line_form_view"/>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<field name="product_id" position="attributes">
<attribute name="domain">[('purchase_ok', '=', True)]</attribute>
</field>
<field name="automatic_price" position="attributes">
<attribute name="invisible">True</attribute>
</field>
</field>
</record>
<!--TREE view-->
<record id="contract_line_tree_view" model="ir.ui.view">
<field name="name">contract.line tree view (in contract)</field>
<field name="model">contract.line</field>
<field name="arch" type="xml">
<tree decoration-muted="is_canceled"
decoration-info="create_invoice_visibility and not is_canceled">
<field name="sequence" widget="handle"/>
<field name="product_id"/>
<field name="name"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
<field name="quantity"/>
<field name="uom_id"/>
<field name="automatic_price"/>
<field name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field name="specific_price"
invisible="1"/>
<field name="discount"
groups="base.group_no_one"/>
<field name="price_subtotal"/>
<field name="recurring_interval"
invisible="1"/>
<field name="recurring_rule_type"
invisible="1"/>
<field name="recurring_invoicing_type"
invisible="1"/>
<field name="date_start" required="1"/>
<field name="date_end"/>
<field name="recurring_next_date"
required="1"/>
<field name="last_date_invoiced"
groups="base.group_no_one"/>
<field name="create_invoice_visibility"
invisible="1"/>
<field name="is_plan_successor_allowed"
invisible="1"/>
<field name="is_stop_plan_successor_allowed"
invisible="1"/>
<field name="is_stop_allowed"
invisible="1"/>
<field name="is_cancel_allowed"
invisible="1"/>
<field name="is_un_cancel_allowed"
invisible="1"/>
<field name="is_auto_renew" invisible="1"/>
<field name="is_canceled" invisible="1"/>
<button name="action_plan_successor"
string="Plan Start" type="object"
icon="fa-calendar text-success"
attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"/>
<button name="action_stop_plan_successor"
string="Stop Plan Successor"
type="object"
icon="fa-pause text-muted"
attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"/>
<button name="action_stop" string="Stop"
type="object"
icon="fa-stop text-danger"
attrs="{'invisible': [('is_stop_allowed', '=', False)]}"/>
<button name="cancel" string="Cancel"
type="object"
icon="fa-ban text-danger"
confirm="Are you sure you want to cancel this line"
attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"/>
<button name="action_uncancel"
string="Un-cancel" type="object"
icon="fa-ban text-success"
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"/>
<button name="renew" string="Renew"
type="object"
icon="fa-fast-forward text-success"
groups="base.group_no_one"
attrs="{'invisible': [('is_auto_renew', '=', False)]}"/>
</tree>
</field>
</record>
<!--Supplier TREE view-->
<record id="contract_line_supplier_tree_view" model="ir.ui.view">
<field name="name">contract.line supplier tree view (in contract)</field>
<field name="model">contract.line</field>
<field name="mode">primary</field>
<field name="priority" eval="20"/>
<field name="inherit_id" ref="contract_line_tree_view"/>
<field name="arch" type="xml">
<field name="automatic_price" position="attributes">
<attribute name="invisible">True</attribute>
</field>
</field>
</record>
</odoo>

73
contract/views/account_analytic_contract_view.xml → contract/views/contract_template.xml

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <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>
<!--FORM view-->
<record id="contract_template_form_view" model="ir.ui.view">
<field name="name">contract.template form view (in contract)</field>
<field name="model">contract.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Contract Template"> <form string="Contract Template">
<group name="name"> <group name="name">
@ -16,24 +17,10 @@
<field name="pricelist_id" /> <field name="pricelist_id" />
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/> <field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group> </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>
<group name="group_invoice_lines" string="Invoice Lines">
<field name="recurring_invoice_line_ids" nolabel="1">
<tree string="Account Analytic Lines" editable="bottom">
<group name="group_invoice_lines" string="Contract Template Lines">
<field name="contract_line_ids" nolabel="1">
<tree>
<field name="sequence" widget="handle" /> <field name="sequence" widget="handle" />
<field name="product_id" /> <field name="product_id" />
<field name="name" /> <field name="name" />
@ -44,6 +31,9 @@
<field name="specific_price" invisible="1"/> <field name="specific_price" invisible="1"/>
<field name="discount" groups="base.group_no_one" /> <field name="discount" groups="base.group_no_one" />
<field name="price_subtotal" /> <field name="price_subtotal" />
<field name="recurring_rule_type" invisible="1"/>
<field name="recurring_interval" invisible="1"/>
<field name="recurring_invoicing_type" invisible="1"/>
</tree> </tree>
</field> </field>
</group> </group>
@ -57,45 +47,33 @@
</field> </field>
</record> </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>
<!--TREE view-->
<record id="contract_template_tree_view" model="ir.ui.view">
<field name="name">contract.template tree view (in contract)</field>
<field name="model">contract.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Contract Templates">
<tree>
<field name="name" /> <field name="name" />
<field name="contract_type" /> <field name="contract_type" />
<field name="recurring_rule_type" />
<field name="recurring_interval" />
<field name="recurring_invoicing_type" />
<field name="pricelist_id" /> <field name="pricelist_id" />
</tree> </tree>
</field> </field>
</record> </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>
<!--SEARCH view-->
<record id="contract_template_search_view" model="ir.ui.view">
<field name="name">contract.template search view (in contract)</field>
<field name="model">contract.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Contract Templates">
<search>
<field name="name" /> <field name="name" />
<field name="contract_type" /> <field name="contract_type" />
<field name="recurring_rule_type" />
<field name="recurring_interval" />
<field name="recurring_invoicing_type" />
<field name="pricelist_id" /> <field name="pricelist_id" />
<field name="journal_id" /> <field name="journal_id" />
<filter name="contract_type" <filter name="contract_type"
string="Contract Type" string="Contract Type"
context="{'group_by': 'contract_type'}" context="{'group_by': 'contract_type'}"
/> />
<filter name="recurring_rule_type"
string="Recurrence"
context="{'group_by': 'recurring_rule_type'}"
/>
<filter name="recurring_invoicing_type"
string="Invoicing type"
context="{'group_by': 'recurring_invoicing_type'}"
/>
<filter name="pricelist_id" <filter name="pricelist_id"
string="Pricelist" string="Pricelist"
context="{'group_by': 'pricelist_id'}" context="{'group_by': 'pricelist_id'}"
@ -108,12 +86,13 @@
</field> </field>
</record> </record>
<record id="account_analytic_contract_action" model="ir.actions.act_window">
<!--ACTION-->
<record id="contract_template_action" model="ir.actions.act_window">
<field name="name">Contract Templates</field> <field name="name">Contract Templates</field>
<field name="res_model">account.analytic.contract</field>
<field name="res_model">contract.template</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="search_view_id" ref="account_analytic_contract_view_search"/>
<field name="search_view_id" ref="contract_template_search_view"/>
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
Click to create a new contract template. Click to create a new contract template.
@ -127,9 +106,9 @@
parent="account.menu_finance_configuration" parent="account.menu_finance_configuration"
/> />
<menuitem id="account_analytic_contract_menu"
<menuitem id="contract_template_menu"
parent="menu_config_contract" parent="menu_config_contract"
action="account_analytic_contract_action"
action="contract_template_action"
sequence="1" sequence="1"
/> />

17
contract/views/contract_template_line.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--FORM view-->
<record id="contract_template_line_form_view" model="ir.ui.view">
<field name="name">contract.template.line form view (in contract)</field>
<field name="model">contract.template.line</field>
<field name="inherit_id" ref="contract_abstract_contract_line_form_view"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<form position="attributes">
<attribute name="string">Contract Template Line</attribute>
</form>
</field>
</record>
</odoo>

21
contract/views/res_partner_view.xml

@ -3,7 +3,7 @@
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="view_partner_form" model="ir.ui.view">
<record id="view_partner_form" model="ir.ui.view">
<field name="inherit_id" ref="base.view_partner_form" /> <field name="inherit_id" ref="base.view_partner_form" />
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field type="xml" name="arch"> <field type="xml" name="arch">
@ -21,7 +21,22 @@
<field name="purchase_contract_count" widget="statinfo" string="Purchase Contracts"/> <field name="purchase_contract_count" widget="statinfo" string="Purchase Contracts"/>
</button> </button>
</xpath> </xpath>
</field>
</record>
</field>
</record>
<record id="view_res_partner_filter" model="ir.ui.view">
<field name="inherit_id" ref="base.view_res_partner_filter" />
<field name="model">res.partner</field>
<field type="xml" name="arch">
<filter name="inactive" position="after">
<separator/>
<filter
name="filter_running_contract"
string="With running contracts"
domain="['|', ('contract_ids.date_end', '&gt;=', context_today().strftime('%Y-%m-%d')), ('contract_ids.date_end', '=', False)]"
/>
</filter>
</field>
</record>
</odoo> </odoo>

1
contract/wizards/__init__.py

@ -0,0 +1 @@
from . import contract_line_wizard

58
contract/wizards/contract_line_wizard.py

@ -0,0 +1,58 @@
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class ContractLineWizard(models.TransientModel):
_name = 'contract.line.wizard'
_description = 'Contract Line Wizard'
date_start = fields.Date(string='Date Start')
date_end = fields.Date(string='Date End')
recurring_next_date = fields.Date(string='Next Invoice Date')
is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
manual_renew_needed = fields.Boolean(
string="Manual renew needed",
default=False,
help="This flag is used to make a difference between a definitive stop"
"and temporary one for which a user is not able to plan a"
"successor in advance",
)
contract_line_id = fields.Many2one(
comodel_name="contract.line",
string="Contract Line",
required=True,
index=True,
)
@api.multi
def stop(self):
for wizard in self:
wizard.contract_line_id.stop(
wizard.date_end, manual_renew_needed=wizard.manual_renew_needed
)
return True
@api.multi
def plan_successor(self):
for wizard in self:
wizard.contract_line_id.plan_successor(
wizard.date_start, wizard.date_end, wizard.is_auto_renew
)
return True
@api.multi
def stop_plan_successor(self):
for wizard in self:
wizard.contract_line_id.stop_plan_successor(
wizard.date_start, wizard.date_end, wizard.is_auto_renew
)
return True
@api.multi
def uncancel(self):
for wizard in self:
wizard.contract_line_id.uncancel(wizard.recurring_next_date)
return True

100
contract/wizards/contract_line_wizard.xml

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="contract_line_wizard_stop_form_view">
<field name="name">contract.line.stop.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True"/>
<field string="Stop Date" name="date_end" required="True"/>
<field string="Is suspension without end date" name="manual_renew_needed"/>
</group>
<footer>
<button name="stop"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.ui.view" id="contract_line_wizard_plan_successor_form_view">
<field name="name">contract.line.plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True"/>
<field name="date_start" required="True"/>
<field name="date_end" attrs="{'required': [('is_auto_renew', '=', True)]}"/>
<field name="is_auto_renew"/>
</group>
<footer>
<button name="plan_successor"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.ui.view" id="contract_line_wizard_stop_plan_successor_form_view">
<field name="name">contract.line.stop_plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True"/>
<field string="Suspension Start Date" name="date_start" required="True"/>
<field string="Suspension End Date" name="date_end" required="True"/>
<field name="is_auto_renew" invisible="1"/>
</group>
<footer>
<button name="stop_plan_successor"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.ui.view" id="contract_line_wizard_uncancel_form_view">
<field name="name">contract.line.stop_plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True"/>
<field name="recurring_next_date" required="True"/>
</group>
<footer>
<button name="uncancel"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>

10
contract_sale/__manifest__.py

@ -3,7 +3,7 @@
{ {
'name': 'Contract from Sale', 'name': 'Contract from Sale',
'version': '12.0.1.0.0',
'version': '12.0.2.0.0',
'category': 'Sales', 'category': 'Sales',
'author': 'Tecnativa, ' 'author': 'Tecnativa, '
'Odoo Community Association (OCA)', 'Odoo Community Association (OCA)',
@ -14,9 +14,11 @@
], ],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'security/account_analytic_account_security.xml',
'views/account_analytic_account_view.xml',
'views/account_analytic_contract_view.xml',
'security/contract_security.xml',
'views/abstract_contract_line.xml',
'views/contract.xml',
'views/contract_line.xml',
'views/contract_template.xml',
], ],
'license': 'AGPL-3', 'license': 'AGPL-3',
'installable': True, 'installable': True,

2
contract_sale/i18n/contract_sale.pot

@ -6,6 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 12.0\n" "Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-29 10:00+0000\n"
"PO-Revision-Date: 2019-05-29 10:00+0000\n"
"Last-Translator: <>\n" "Last-Translator: <>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"

3
contract_sale/i18n/gl.po

@ -1,11 +1,12 @@
# Translation of Odoo Server. # Translation of Odoo Server.
# This file contains the translation of the following modules: # This file contains the translation of the following modules:
# * contract_sale
# * contract_sale
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 12.0\n" "Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-29 10:00+0000\n"
"PO-Revision-Date: 2019-02-04 18:50+0000\n" "PO-Revision-Date: 2019-02-04 18:50+0000\n"
"Last-Translator: Marta Vázquez Rodríguez <vazrodmar@gmail.com>\n" "Last-Translator: Marta Vázquez Rodríguez <vazrodmar@gmail.com>\n"
"Language-Team: none\n" "Language-Team: none\n"

32
contract_sale/migrations/12.0.2.0.0/pre-migration.py

@ -0,0 +1,32 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openupgradelib import openupgrade
_logger = logging.getLogger(__name__)
def migrate(cr, version):
xmlids_to_rename = [
('contract_sale.account_analytic_account_own_salesman',
'contract_sale.contract_contract_own_salesman'),
('contract_sale.account_analytic_account_see_all',
'contract_sale.contract_contract_see_all'),
('contract_sale.account_analytic_contract_salesman',
'contract_sale.contract_template_salesman'),
('contract_sale.account_analytic_contract_sale_manager',
'contract_sale.contract_template_sale_manager'),
('contract_sale.account_analytic_invoice_line_saleman',
'contract_sale.contract_line_saleman'),
('contract_sale.account_analytic_invoice_line_manager',
'contract_sale.contract_line_manager'),
('contract_sale.account_analytic_contract_line_salesman',
'contract_sale.contract_template_line_salesman'),
('contract_sale.account_analytic_contract_line_manager',
'contract_sale.contract_template_line_manager'),
('contract_sale.account_analytic_account_contract_salesman',
'contract_sale.contract_contract_salesman'),
]
openupgrade.rename_xmlids(cr, xmlids_to_rename)

8
contract_sale/security/account_analytic_account_security.xml → contract_sale/security/contract_security.xml

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1"> <odoo noupdate="1">
<record id="account_analytic_account_own_salesman" model="ir.rule">
<record id="contract_contract_own_salesman" model="ir.rule">
<field name="name">See Own Contracts</field> <field name="name">See Own Contracts</field>
<field name="model_id" ref="analytic.model_account_analytic_account"/>
<field name="model_id" ref="contract.model_contract_contract"/>
<field name="domain_force">['|', ('user_id','=',user.id), ('user_id','=',False)]</field> <field name="domain_force">['|', ('user_id','=',user.id), ('user_id','=',False)]</field>
<field name="groups" eval="[(4,ref('sales_team.group_sale_salesman'))]"/> <field name="groups" eval="[(4,ref('sales_team.group_sale_salesman'))]"/>
</record> </record>
<record id="account_analytic_account_see_all" model="ir.rule">
<record id="contract_contract_see_all" model="ir.rule">
<field name="name">See All Contracts</field> <field name="name">See All Contracts</field>
<field name="model_id" ref="analytic.model_account_analytic_account"/>
<field name="model_id" ref="contract.model_contract_contract"/>
<field name="domain_force">[(1,'=',1)]</field> <field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[ <field name="groups" eval="[
(4,ref('sales_team.group_sale_salesman_all_leads')), (4,ref('sales_team.group_sale_salesman_all_leads')),

14
contract_sale/security/ir.model.access.csv

@ -1,12 +1,12 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"account_analytic_contract_salesman","Recurring Salesman","contract.model_account_analytic_contract","sales_team.group_sale_salesman",1,1,1,0
"account_analytic_contract_sale_manager","Recurring Sale Manager","contract.model_account_analytic_contract","sales_team.group_sale_manager",1,1,1,1
"account_analytic_invoice_line_saleman","Recurring Invoice Line Saleman","contract.model_account_analytic_invoice_line","sales_team.group_sale_salesman",1,1,1,0
"account_analytic_invoice_line_manager","Recurring Invoice Line Manager","contract.model_account_analytic_invoice_line","sales_team.group_sale_manager",1,1,1,1
"account_analytic_contract_line_salesman","Recurring Contract Line Salesman","contract.model_account_analytic_contract_line","sales_team.group_sale_salesman",1,1,1,0
"account_analytic_contract_line_manager","Recurring Contract Line Manager","contract.model_account_analytic_contract_line","sales_team.group_sale_manager",1,1,1,1
"contract_template_salesman","Recurring Salesman","contract.model_contract_template","sales_team.group_sale_salesman",1,1,1,0
"contract_template_sale_manager","Recurring Sale Manager","contract.model_contract_template","sales_team.group_sale_manager",1,1,1,1
"contract_line_saleman","Recurring Invoice Line Saleman","contract.model_contract_line","sales_team.group_sale_salesman",1,1,1,0
"contract_line_manager","Recurring Invoice Line Manager","contract.model_contract_line","sales_team.group_sale_manager",1,1,1,1
"contract_template_line_salesman","Recurring Contract Line Salesman","contract.model_contract_template_line","sales_team.group_sale_salesman",1,1,1,0
"contract_template_line_manager","Recurring Contract Line Manager","contract.model_contract_template_line","sales_team.group_sale_manager",1,1,1,1
"account_analytic_line_contract_salesman","Recurring Analytic Line Salesman","analytic.model_account_analytic_line","sales_team.group_sale_salesman",1,1,1,0 "account_analytic_line_contract_salesman","Recurring Analytic Line Salesman","analytic.model_account_analytic_line","sales_team.group_sale_salesman",1,1,1,0
"account_analytic_account_contract_salesman","Recurring Analytic Account Salesman","analytic.model_account_analytic_account","sales_team.group_sale_salesman",1,1,1,0
"contract_contract_salesman","Recurring Analytic Account Salesman","contract.model_contract_contract","sales_team.group_sale_salesman",1,1,1,0
"account_analytic_tag_contract_salesman","Recurring Account Analytic Tag Salesman","analytic.model_account_analytic_tag","sales_team.group_sale_salesman",1,1,1,0 "account_analytic_tag_contract_salesman","Recurring Account Analytic Tag Salesman","analytic.model_account_analytic_tag","sales_team.group_sale_salesman",1,1,1,0
"account_invoice_contract_salesman","Recurring Account Inoice Salesman","account.model_account_invoice","sales_team.group_sale_salesman",1,0,0,0 "account_invoice_contract_salesman","Recurring Account Inoice Salesman","account.model_account_invoice","sales_team.group_sale_salesman",1,0,0,0
"account_journal_contract_salesman","Recurring Account Journal Salesman","account.model_account_journal","sales_team.group_sale_salesman",1,0,0,0 "account_journal_contract_salesman","Recurring Account Journal Salesman","account.model_account_journal","sales_team.group_sale_salesman",1,0,0,0

16
contract_sale/views/abstract_contract_line.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--FORM view-->
<record id="contract_abstract_contract_line_form_view" model="ir.ui.view">
<field name="name">contract.abstract.contract.line form view (in contract_sale)</field>
<field name="model">contract.abstract.contract.line</field>
<field name="inherit_id" ref="contract.contract_abstract_contract_line_form_view"/>
<field name="arch" type="xml">
<field name="discount" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line</attribute>
</field>
</field>
</record>
</odoo>

28
contract_sale/views/account_analytic_account_view.xml

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_analytic_account_recurring_form_form"
model="ir.ui.view">
<field name="name">Contract form (in contract_sale)</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id"
ref="contract.account_analytic_account_recurring_form_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='discount']" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line
</attribute>
</xpath>
</field>
</record>
<menuitem
id="menu_contract_sale" name="Contracts"
parent="sale.sale_order_menu"
action="contract.action_account_analytic_sale_overdue_all"
sequence="2"
groups="sales_team.group_sale_salesman"
/>
</odoo>

21
contract_sale/views/account_analytic_contract_view.xml

@ -1,21 +0,0 @@
<?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 (in
sale_contract)
</field>
<field name="model">account.analytic.contract</field>
<field name="inherit_id"
ref="contract.account_analytic_contract_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='discount']" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line
</attribute>
</xpath>
</field>
</record>
</odoo>

12
contract_sale/views/contract.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem
id="menu_contract_sale" name="Contracts"
parent="sale.sale_order_menu"
action="contract.action_supplier_contract"
sequence="2"
groups="sales_team.group_sale_salesman"
/>
</odoo>

16
contract_sale/views/contract_line.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--TREE view-->
<record id="contract_line_tree_view" model="ir.ui.view">
<field name="name">contract.template.line tree view (in contract_sale)</field>
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract.contract_line_tree_view"/>
<field name="arch" type="xml">
<field name="discount" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line</attribute>
</field>
</field>
</record>
</odoo>

17
contract_sale/views/contract_template.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--FORM view-->
<record id="contract_template_form_view" model="ir.ui.view">
<field name="name">contract.template form view (in contract_sale)</field>
<field name="model">contract.template</field>
<field name="inherit_id" ref="contract.contract_template_form_view"/>
<field name="arch" type="xml">
<field name="discount" position="attributes">
<attribute name="groups">sale.group_discount_per_so_line</attribute>
</field>
</field>
</record>
</odoo>

19
contract_sale_invoicing/i18n/ca.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n" "Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Compte analític"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Compte analític"

14
contract_sale_invoicing/i18n/contract_sale_invoicing.pot

@ -6,6 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 12.0\n" "Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2019-05-29 14:59+0000\n"
"Last-Translator: <>\n" "Last-Translator: <>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -14,17 +16,17 @@ msgstr ""
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "If checked include sales with same analytic account to invoice in contract invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
msgid "If checked include sales with same analytic account to invoice in contract invoice creation."
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
msgid "Invoice Pending Sales Orders"
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr "" msgstr ""

31
contract_sale_invoicing/i18n/de.po

@ -8,33 +8,32 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"PO-Revision-Date: 2019-06-28 13:42+0000\n"
"Last-Translator: Maria Sparenberg <maria.sparenberg@gmx.net>\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" "Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n"
"Language: de\n" "Language: de\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.6.1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Kostenstelle"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
"Wenn der Haken gesetzt ist, dann werden alle noch abzurechnenden "
"Verkaufsaufträge mit derselben Kostenstelle bei der Rechnungserstellung für "
"den Vertrag einbezogen."
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "Ausstehende Verkaufsaufträge abrechnen"
msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Kostenstelle"

19
contract_sale_invoicing/i18n/el_GR.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Greek (Greece) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Greek (Greece) (https://www.transifex.com/oca/teams/23907/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Αναλυτικός Λογαριασμός"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Αναλυτικός Λογαριασμός"

19
contract_sale_invoicing/i18n/es.po

@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-06 17:36+0200\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-06 17:38+0200\n" "PO-Revision-Date: 2018-04-06 17:38+0200\n"
"Last-Translator: Carlos Dauden <carlos.dauden@tecnativa.com>\n" "Last-Translator: Carlos Dauden <carlos.dauden@tecnativa.com>\n"
"Language-Team: \n" "Language-Team: \n"
@ -18,12 +18,7 @@ msgstr ""
"X-Generator: Poedit 1.8.7.1\n" "X-Generator: Poedit 1.8.7.1\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Cuenta analítica"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
@ -32,6 +27,14 @@ msgstr ""
"cuenta analítica en la creación de la factura del contrato" "cuenta analítica en la creación de la factura del contrato"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "Facturar pedidos pendientes" msgstr "Facturar pedidos pendientes"
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Cuenta analítica"

19
contract_sale_invoicing/i18n/es_MX.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Spanish (Mexico) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Spanish (Mexico) (https://www.transifex.com/oca/teams/23907/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Cuenta analítica"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Cuenta analítica"

19
contract_sale_invoicing/i18n/fi.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Finnish (https://www.transifex.com/oca/teams/23907/fi/)\n" "Language-Team: Finnish (https://www.transifex.com/oca/teams/23907/fi/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analyyttinen tili"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analyyttinen tili"

19
contract_sale_invoicing/i18n/fr.po

@ -9,7 +9,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-05 02:28+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-05-05 02:28+0000\n" "PO-Revision-Date: 2018-05-05 02:28+0000\n"
"Last-Translator: Quentin THEURET <odoo@kerpeo.com>, 2018\n" "Last-Translator: Quentin THEURET <odoo@kerpeo.com>, 2018\n"
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" "Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n"
@ -20,12 +20,7 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Compte analytique"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
@ -34,6 +29,14 @@ msgstr ""
"de la création de facture du contrat." "de la création de facture du contrat."
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "Commandes avec une facture en attente" msgstr "Commandes avec une facture en attente"
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Compte analytique"

19
contract_sale_invoicing/i18n/gl.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Galician (https://www.transifex.com/oca/teams/23907/gl/)\n" "Language-Team: Galician (https://www.transifex.com/oca/teams/23907/gl/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Conta analítica"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Conta analítica"

19
contract_sale_invoicing/i18n/hi_IN.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Hindi (India) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Hindi (India) (https://www.transifex.com/oca/teams/23907/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "विश्लेषणात्मक खाता"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "विश्लेषणात्मक खाता"

19
contract_sale_invoicing/i18n/hr.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" "Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n"
@ -20,18 +20,21 @@ msgstr ""
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analitički konto"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analitički konto"

19
contract_sale_invoicing/i18n/hr_HR.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Croatian (Croatia) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Croatian (Croatia) (https://www.transifex.com/oca/teams/23907/"
@ -21,18 +21,21 @@ msgstr ""
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Konto analitike"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Konto analitike"

19
contract_sale_invoicing/i18n/hu.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Hungarian (https://www.transifex.com/oca/teams/23907/hu/)\n" "Language-Team: Hungarian (https://www.transifex.com/oca/teams/23907/hu/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analitikus gyűjtőkód könyvelés"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analitikus gyűjtőkód könyvelés"

30
contract_sale_invoicing/i18n/it.po

@ -8,32 +8,32 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"PO-Revision-Date: 2019-06-26 15:42+0000\n"
"Last-Translator: Sergio Zanchetta <primes2h@gmail.com>\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" "Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n"
"Language: it\n" "Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.6.1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Conto analitico"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
"Se selezionato, in fase di creazione del contratto aggiunge alla fattura le "
"vendite con lo stesso conto analitico."
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "Ordini di vendita in sospeso della fattura"
msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Conto Analitico"

19
contract_sale_invoicing/i18n/nl.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Dutch (https://www.transifex.com/oca/teams/23907/nl/)\n" "Language-Team: Dutch (https://www.transifex.com/oca/teams/23907/nl/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Kostenplaats"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Kostenplaats"

15
contract_sale_invoicing/i18n/pt.po

@ -8,9 +8,9 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"PO-Revision-Date: 2019-08-14 13:44+0000\n"
"Last-Translator: Pedro Castro Silva <pedrocs@exo.pt>\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Portuguese (https://www.transifex.com/oca/teams/23907/pt/)\n" "Language-Team: Portuguese (https://www.transifex.com/oca/teams/23907/pt/)\n"
"Language: pt\n" "Language: pt\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -20,12 +20,7 @@ msgstr ""
"X-Generator: Weblate 3.7.1\n" "X-Generator: Weblate 3.7.1\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Conta Analítica"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
@ -34,6 +29,6 @@ msgstr ""
"faturas do contrato." "faturas do contrato."
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "Faturar Encomendas de Venda Pendentes" msgstr "Faturar Encomendas de Venda Pendentes"

19
contract_sale_invoicing/i18n/pt_PT.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Portuguese (Portugal) (https://www.transifex.com/oca/" "Language-Team: Portuguese (Portugal) (https://www.transifex.com/oca/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Conta Analítica"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Conta Analítica"

19
contract_sale_invoicing/i18n/ro.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Romanian (https://www.transifex.com/oca/teams/23907/ro/)\n" "Language-Team: Romanian (https://www.transifex.com/oca/teams/23907/ro/)\n"
@ -20,18 +20,21 @@ msgstr ""
"2:1));\n" "2:1));\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Cont analitic"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Cont analitic"

19
contract_sale_invoicing/i18n/sk_SK.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Slovak (Slovakia) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Slovak (Slovakia) (https://www.transifex.com/oca/teams/23907/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analytický účet"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analytický účet"

19
contract_sale_invoicing/i18n/sl.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n" "Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n"
@ -20,18 +20,21 @@ msgstr ""
"%100==4 ? 2 : 3);\n" "%100==4 ? 2 : 3);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analitični konto"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analitični konto"

19
contract_sale_invoicing/i18n/tr.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/tr/)\n" "Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/tr/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analitik Hesap"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analitik Hesap"

19
contract_sale_invoicing/i18n/tr_TR.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-17 02:41+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-17 02:41+0000\n" "PO-Revision-Date: 2018-04-17 02:41+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n" "Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2018\n"
"Language-Team: Turkish (Turkey) (https://www.transifex.com/oca/teams/23907/" "Language-Team: Turkish (Turkey) (https://www.transifex.com/oca/teams/23907/"
@ -20,18 +20,21 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "Analitik Hesap"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "" msgstr ""
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "" msgstr ""
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "Analitik Hesap"

19
contract_sale_invoicing/i18n/zh.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-27 01:12+0000\n"
"POT-Creation-Date: 2019-05-29 14:59+0000\n"
"PO-Revision-Date: 2018-04-27 01:12+0000\n" "PO-Revision-Date: 2018-04-27 01:12+0000\n"
"Last-Translator: DIT INTL <ditintlgroup@gmail.com>, 2018\n" "Last-Translator: DIT INTL <ditintlgroup@gmail.com>, 2018\n"
"Language-Team: Chinese (https://www.transifex.com/oca/teams/23907/zh/)\n" "Language-Team: Chinese (https://www.transifex.com/oca/teams/23907/zh/)\n"
@ -19,18 +19,21 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n" "Plural-Forms: nplurals=1; plural=0;\n"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_account_analytic_account
msgid "Analytic Account"
msgstr "分析会计"
#. module: contract_sale_invoicing
#: model:ir.model.fields,help:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,help:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "" msgid ""
"If checked include sales with same analytic account to invoice in contract " "If checked include sales with same analytic account to invoice in contract "
"invoice creation." "invoice creation."
msgstr "如果选中,则在销售发票中包含分析帐户。" msgstr "如果选中,则在销售发票中包含分析帐户。"
#. module: contract_sale_invoicing #. module: contract_sale_invoicing
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_account_analytic_account__invoicing_sales
#: model:ir.model.fields,field_description:contract_sale_invoicing.field_contract_contract__invoicing_sales
msgid "Invoice Pending Sales Orders" msgid "Invoice Pending Sales Orders"
msgstr "发票挂起的销售订单" msgstr "发票挂起的销售订单"
#. module: contract_sale_invoicing
#: model:ir.model,name:contract_sale_invoicing.model_contract_contract
msgid "contract.contract"
msgstr ""
#~ msgid "Analytic Account"
#~ msgstr "分析会计"

15
contract_sale_invoicing/models/contract.py

@ -4,8 +4,8 @@
from odoo import api, fields, models from odoo import api, fields, models
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
class ContractContract(models.Model):
_inherit = 'contract.contract'
invoicing_sales = fields.Boolean( invoicing_sales = fields.Boolean(
string='Invoice Pending Sales Orders', string='Invoice Pending Sales Orders',
@ -14,11 +14,12 @@ class AccountAnalyticAccount(models.Model):
) )
@api.multi @api.multi
def _create_invoice(self, invoice=False):
def _recurring_create_invoice(self, date_ref=False):
invoices = super()._recurring_create_invoice(date_ref)
if not self.invoicing_sales: if not self.invoicing_sales:
return super(AccountAnalyticAccount, self)._create_invoice()
return invoices
sales = self.env['sale.order'].search([ sales = self.env['sale.order'].search([
('analytic_account_id', '=', self.id),
('analytic_account_id', '=', self.analytic_account_id.id),
('partner_invoice_id', 'child_of', ('partner_invoice_id', 'child_of',
self.partner_id.commercial_partner_id.ids), self.partner_id.commercial_partner_id.ids),
('invoice_status', '=', 'to invoice'), ('invoice_status', '=', 'to invoice'),
@ -27,6 +28,4 @@ class AccountAnalyticAccount(models.Model):
]) ])
if sales: if sales:
invoice_ids = sales.action_invoice_create() invoice_ids = sales.action_invoice_create()
invoice = self.env['account.invoice'].browse(invoice_ids)[:1]
return super(AccountAnalyticAccount, self)._create_invoice(
invoice=invoice)
invoices |= self.env['account.invoice'].browse(invoice_ids)[:1]

4
contract_sale_invoicing/tests/test_contract_sale_invoicing.py

@ -8,6 +8,8 @@ class TestContractSaleInvoicing(TestContractBase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestContractSaleInvoicing, cls).setUpClass() super(TestContractSaleInvoicing, cls).setUpClass()
cls.contract.analytic_account_id = \
cls.env['account.analytic.account'].search([], limit=1)
cls.product_so = cls.env.ref( cls.product_so = cls.env.ref(
'product.product_product_1') 'product.product_product_1')
cls.product_so.invoice_policy = 'order' cls.product_so.invoice_policy = 'order'
@ -21,7 +23,7 @@ class TestContractSaleInvoicing(TestContractBase):
'product_uom': cls.product_so.uom_id.id, 'product_uom': cls.product_so.uom_id.id,
'price_unit': cls.product_so.list_price})], 'price_unit': cls.product_so.list_price})],
'pricelist_id': cls.partner.property_product_pricelist.id, 'pricelist_id': cls.partner.property_product_pricelist.id,
'analytic_account_id': cls.contract.id,
'analytic_account_id': cls.contract.analytic_account_id.id,
'date_order': '2016-02-15', 'date_order': '2016-02-15',
}) })

16
contract_sale_invoicing/views/contract_view.xml

@ -4,14 +4,14 @@
<odoo> <odoo>
<record id="account_analytic_account_recurring_form_form" model="ir.ui.view">
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="contract.account_analytic_account_recurring_form_form"/>
<field name="arch" type="xml">
<field name="recurring_next_date" position="after">
<field name="invoicing_sales"/>
<record id="contract_contract_form_view" model="ir.ui.view">
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_form_view"/>
<field name="arch" type="xml">
<field name="recurring_next_date" position="after">
<field name="invoicing_sales"/>
</field>
</field> </field>
</field>
</record>
</record>
</odoo> </odoo>
Loading…
Cancel
Save