Browse Source

[REF] Contract Sale Invoicing: split from analytic account

[REF] Contract Sale Invoicing: update translations

[IMP] - Assert that the predecessor is available for new link at uncancel

[RMV] - remove usless changes

[RMV] - Remove usless field recurring_invoices

after the total isolation between contract model and account analytic one.
recurring_invoices which was used to mark analytic account as contract became usless

[IMP] - P3 syntax

[IMP] - use @openupgrade.migrate() and openupgrade.logged_query

[IMP] - drop transient table in migration script
13.0-mig-contract
Thomas Binsfeld 6 years ago
committed by Administrator
parent
commit
d12fc6f48e
  1. 7
      contract/__manifest__.py
  2. 4
      contract/migrations/12.0.2.0.0/post-migration.py
  3. 2
      contract/migrations/12.0.2.0.0/pre-migration.py
  4. 1
      contract/migrations/12.0.3.0.0/post-migration.py
  5. 25
      contract/migrations/12.0.4.0.0/post-migration.py
  6. 22
      contract/migrations/12.0.4.0.0/pre-migration.py
  7. 24
      contract/models/contract.py
  8. 13
      contract/models/contract_line.py
  9. 49
      contract/models/res_partner.py
  10. 60
      contract/report/report_contract.xml
  11. 11
      contract/tests/test_contract.py
  12. 16
      contract/views/contract.xml

7
contract/__manifest__.py

@ -13,10 +13,9 @@
'category': 'Contract Management',
'license': 'AGPL-3',
'author': "OpenERP SA, "
"Tecnativa, "
"LasLabs, "
"ACSONE SA/NV, "
"Odoo Community Association (OCA)",
"Tecnativa, "
"LasLabs, "
"Odoo Community Association (OCA)",
'website': 'https://github.com/oca/contract',
'depends': ['base', 'account', 'product'],
"external_dependencies": {"python": ["dateutil"]},

4
contract/migrations/12.0.2.0.0/post-migration.py

@ -11,7 +11,7 @@ _logger = logging.getLogger(__name__)
def migrate(cr, version):
"""Copy recurrence info from contract to contract lines and compute
last_date_invoiced"""
_logger.info(">> Post-Migration 12.0.2.0.0")
cr.execute(
"""UPDATE account_analytic_invoice_line AS contract_line
SET recurring_rule_type=contract.recurring_rule_type,
@ -23,8 +23,6 @@ def migrate(cr, version):
FROM account_analytic_account AS contract
WHERE contract.id=contract_line.contract_id"""
)
_logger.info("order all contract line")
env = api.Environment(cr, SUPERUSER_ID, {})
contract_lines = env["account.analytic.invoice.line"].search(
[("recurring_next_date", "!=", False)]

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

@ -12,7 +12,7 @@ def migrate(cr, version):
"""
set recurring_next_date to false for finished contract
"""
_logger.info("order all contract line")
_logger.info(">> Pre-Migration 12.0.2.0.0")
with api.Environment(cr, SUPERUSER_ID, {}) as env:
contracts = env["account.analytic.account"].search([])
finished_contract = contracts.filtered(

1
contract/migrations/12.0.3.0.0/post-migration.py

@ -9,6 +9,7 @@ _logger = logging.getLogger(__name__)
def migrate(cr, version):
_logger.info(">> Post-Migration 12.0.3.0.0")
_logger.info("Populate invoicing partner field on contracts")
env = api.Environment(cr, SUPERUSER_ID, {})
contracts = env["account.analytic.account"].search([])

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

@ -8,8 +8,11 @@ from openupgradelib import openupgrade
_logger = logging.getLogger(__name__)
def migrate(cr, version):
cr.execute(
@openupgrade.migrate()
def migrate(env, version):
cr = env.cr
openupgrade.logged_query(
cr,
"""
INSERT INTO contract_contract (
id,
@ -24,7 +27,6 @@ def migrate(cr, version):
code,
group_id,
contract_template_id,
recurring_invoices,
user_id,
recurring_next_date,
date_end,
@ -49,7 +51,6 @@ def migrate(cr, version):
code,
group_id,
contract_template_id,
recurring_invoices,
user_id,
recurring_next_date,
date_end,
@ -62,10 +63,13 @@ def migrate(cr, version):
write_uid,
write_date
FROM account_analytic_account
WHERE recurring_invoices = TRUE
WHERE id in (
SELECT DISTINCT contract_id FROM account_analytic_invoice_line
)
"""
)
cr.execute(
openupgrade.logged_query(
cr,
"""
INSERT INTO contract_line (
id,
@ -126,18 +130,21 @@ def migrate(cr, version):
)
openupgrade.rename_models(cr, [('account.analytic.invoice.line',
'contract.line')])
cr.execute(
openupgrade.logged_query(
cr,
"""
DROP TABLE account_analytic_invoice_line
"""
)
cr.execute(
openupgrade.logged_query(
cr,
"""
UPDATE account_invoice_line
SET contract_line_id = contract_line_id_tmp
"""
)
cr.execute(
openupgrade.logged_query(
cr,
"""
ALTER TABLE account_invoice_line
DROP COLUMN contract_line_id_tmp

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

@ -8,7 +8,16 @@ from openupgradelib import openupgrade
_logger = logging.getLogger(__name__)
def migrate(cr, version):
@openupgrade.migrate()
def migrate(env, version):
_logger.info(">> Pre-Migration 12.0.4.0.0")
cr = env.cr
openupgrade.logged_query(
cr,
"""
DROP TABLE IF EXISTS account_analytic_invoice_line_wizard
"""
)
models_to_rename = [
# Contract Line Wizard
('account.analytic.invoice.line.wizard', 'contract.line.wizard'),
@ -25,8 +34,6 @@ def migrate(cr, version):
('account.analytic.contract.line', 'contract.template.line'),
]
tables_to_rename = [
# Contract Line Wizard
('account_analytic_invoice_line_wizard', 'contract_line_wizard'),
# Contract Template
('account_analytic_contract', 'contract_template'),
# Contract Template Line
@ -53,19 +60,22 @@ def migrate(cr, version):
openupgrade.rename_xmlids(cr, xmlids_to_rename)
# A temporary column is needed to avoid breaking the foreign key constraint
# The temporary column is dropped in the post-migration script
cr.execute(
openupgrade.logged_query(
cr,
"""
ALTER TABLE account_invoice_line
ADD COLUMN contract_line_id_tmp INTEGER
"""
)
cr.execute(
openupgrade.logged_query(
cr,
"""
UPDATE account_invoice_line
SET contract_line_id_tmp = contract_line_id
"""
)
cr.execute(
openupgrade.logged_query(
cr,
"""
UPDATE account_invoice_line SET contract_line_id = NULL
"""

24
contract/models/contract.py

@ -45,9 +45,7 @@ class ContractContract(models.Model):
copy=True,
oldnae='contract_line_ids',
)
recurring_invoices = fields.Boolean(
string='Generate recurring invoices automatically'
)
user_id = fields.Many2one(
comodel_name='res.users',
string='Responsible',
@ -80,7 +78,9 @@ class ContractContract(models.Model):
ondelete='restrict',
)
partner_id = fields.Many2one(
comodel_name='res.partner', inverse='_inverse_partner_id'
comodel_name='res.partner',
inverse='_inverse_partner_id',
required=True
)
@api.multi
@ -225,15 +225,6 @@ class ContractContract(models.Model):
}
}
@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 partner for the contract '%s'")
% contract.name
)
@api.multi
def _convert_contract_lines(self, contract):
self.ensure_one()
@ -393,12 +384,7 @@ class ContractContract(models.Model):
domain = []
if not date_ref:
date_ref = fields.Date.context_today(self)
domain.extend(
[
('recurring_invoices', '=', True),
('recurring_next_date', '<=', date_ref),
]
)
domain.extend([('recurring_next_date', '<=', date_ref)])
return domain
@api.multi

13
contract/models/contract_line.py

@ -455,7 +455,7 @@ class ContractLine(models.Model):
@api.constrains('recurring_next_date')
def _check_recurring_next_date_recurring_invoices(self):
for rec in self.filtered('contract_id.recurring_invoices'):
for rec in self:
if not rec.recurring_next_date and (
not rec.date_end
or not rec.last_date_invoiced
@ -916,9 +916,9 @@ class ContractLine(models.Model):
contract.message_post(body=msg)
for rec in self:
if rec.predecessor_contract_line_id:
rec.predecessor_contract_line_id.successor_contract_line_id = (
rec
)
predecessor_contract_line = rec.predecessor_contract_line_id
assert not predecessor_contract_line.successor_contract_line_id
predecessor_contract_line.successor_contract_line_id = rec
rec.is_canceled = False
rec.recurring_next_date = recurring_next_date
return True
@ -1052,7 +1052,6 @@ class ContractLine(models.Model):
return [
('is_auto_renew', '=', True),
('is_canceled', '=', False),
('contract_id.recurring_invoices', '=', True),
('termination_notice_date', '<=', fields.Date.context_today(self)),
]
@ -1080,7 +1079,7 @@ class ContractLine(models.Model):
view_id = self.env.ref(
'contract.contract_line_customer_form_view'
).id
return super(ContractLine, self).fields_view_get(
return super().fields_view_get(
view_id, view_type, toolbar, submenu
)
@ -1091,7 +1090,7 @@ class ContractLine(models.Model):
raise ValidationError(
_("Contract line must be canceled before delete")
)
return super(ContractLine, self).unlink()
return super().unlink()
@api.multi
def _get_quantity_to_invoice(

49
contract/models/res_partner.py

@ -8,43 +8,30 @@ class ResPartner(models.Model):
_inherit = 'res.partner'
sale_contract_count = fields.Integer(
string='Sale Contracts', compute='_compute_contract_count'
string='Sale Contracts',
compute='_compute_contract_count',
)
purchase_contract_count = fields.Integer(
string='Purchase Contracts', compute='_compute_contract_count'
string='Purchase Contracts',
compute='_compute_contract_count',
)
def _compute_contract_count(self):
contract_model = self.env['contract.contract']
fetch_data = contract_model.read_group(
[
('recurring_invoices', '=', True),
('partner_id', 'child_of', self.ids),
],
['partner_id', 'contract_type'],
['partner_id', 'contract_type'],
lazy=False,
)
result = [
[data['partner_id'][0], data['contract_type'], data['__count']]
for data in fetch_data
]
fetch_data = contract_model.read_group([
('partner_id', 'child_of', self.ids)],
['partner_id', 'contract_type'], ['partner_id', 'contract_type'],
lazy=False)
result = [[data['partner_id'][0], data['contract_type'],
data['__count']] for data in fetch_data]
for partner in self:
partner_child_ids = partner.child_ids.ids + partner.ids
partner.sale_contract_count = sum(
[
r[2]
for r in result
if r[0] in partner_child_ids and r[1] == 'sale'
]
)
partner.purchase_contract_count = sum(
[
r[2]
for r in result
if r[0] in partner_child_ids and r[1] == 'purchase'
]
)
partner.sale_contract_count = sum([
r[2] for r in result
if r[0] in partner_child_ids and r[1] == 'sale'])
partner.purchase_contract_count = sum([
r[2] for r in result
if r[0] in partner_child_ids and r[1] == 'purchase'])
def act_show_contract(self):
""" This opens contract view
@ -57,12 +44,10 @@ class ResPartner(models.Model):
res.update(
context=dict(
self.env.context,
search_default_recurring_invoices=True,
search_default_partner_id=self.id,
default_partner_id=self.id,
default_recurring_invoices=True,
default_pricelist_id=self.property_product_pricelist.id,
)
),
)
return res

60
contract/report/report_contract.xml

@ -9,54 +9,34 @@
<div class="oe_structure"/>
<div class="row" id="partner_info">
<div class="col-xs-5 col-xs-offset-7">
<p id="partner_info">
<strong>Partner:</strong>
</p>
<div t-field="o.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
<p t-if="o.partner_id.vat">VAT:
<span t-field="o.partner_id.vat"/>
</p>
<p id="partner_info"><strong>Partner:</strong></p>
<div t-field="o.partner_id" t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
</div>
<div class="row" id="header_info">
<div class="col-xs-3">
<strong>Responsible:</strong>
<p t-field="o.user_id"/>
<strong>Contract:</strong>
<p t-field="o.code"/>
<strong>Responsible: </strong><p t-field="o.user_id"/>
<strong>Contract: </strong><p t-field="o.code"/>
</div>
</div>
<div class="row" id="invoice_info">
<t t-set="total" t-value="0"/>
<div class="col-xs-12">
<t t-set="total" t-value="0"/>
<p id="services_info">
<strong>Recurring Items</strong>
</p>
<p id="services_info"><strong>Recurring Items</strong></p>
<table class="table table-condensed">
<thead>
<tr>
<th>
<strong>Description</strong>
</th>
<th class="text-right">
<strong>Quantity</strong>
</th>
<th class="text-right">
<strong>Unit Price</strong>
</th>
<th class="text-right">
<strong>Price</strong>
</th>
<th class="text-right">
<strong>Date Start</strong>
</th>
<th><strong>Description</strong></th>
<th class="text-right"><strong>Quantity</strong></th>
<th class="text-right"><strong>Unit Price</strong></th>
<th class="text-right"><strong>Price</strong></th>
<th class="text-right"><strong>Date Start</strong></th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.contract_line_ids"
t-as="l">
<tr t-foreach="o.recurring_invoice_line_ids" t-as="l">
<td>
<span t-field="l.name"/>
</td>
@ -64,18 +44,15 @@
<span t-field="l.quantity"/>
</td>
<td class="text-right">
<span t-field="l.price_unit"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
<span t-field="l.price_unit" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
<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>
<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>
</tbody>
</table>
@ -83,12 +60,9 @@
<div class="col-xs-4 pull-right">
<table class="table table-condensed">
<tr class="border-black">
<td>
<strong>Total</strong>
</td>
<td><strong>Total</strong></td>
<td class="text-right">
<span t-esc="total"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
<span t-esc="total" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
</tr>
</table>

11
contract/tests/test_contract.py

@ -16,7 +16,7 @@ def to_date(date):
class TestContractBase(common.SavepointCase):
@classmethod
def setUpClass(cls):
super(TestContractBase, cls).setUpClass()
super().setUpClass()
cls.today = fields.Date.today()
cls.partner = cls.env.ref('base.res_partner_2')
cls.product_1 = cls.env.ref('product.product_product_1')
@ -56,7 +56,6 @@ class TestContractBase(common.SavepointCase):
'name': 'Test Contract',
'partner_id': cls.partner.id,
'pricelist_id': cls.partner.property_product_pricelist.id,
'recurring_invoices': True,
}
)
cls.contract2 = cls.env['contract.contract'].create(
@ -64,7 +63,6 @@ class TestContractBase(common.SavepointCase):
'name': 'Test Contract 2',
'partner_id': cls.partner.id,
'pricelist_id': cls.partner.property_product_pricelist.id,
'recurring_invoices': True,
'contract_type': 'purchase',
'contract_line_ids': [
(
@ -141,8 +139,6 @@ class TestContract(TestContractBase):
res = self.acct_line._onchange_product_id()
self.assertIn('uom_id', res['domain'])
self.acct_line.price_unit = 100.0
with self.assertRaises(ValidationError):
self.contract.partner_id = False
self.contract.partner_id = self.partner.id
self.contract.recurring_create_invoice()
self.invoice_monthly = self.contract._get_related_invoices()
@ -388,11 +384,6 @@ class TestContract(TestContractBase):
}
)
def test_check_recurring_next_date_recurring_invoices(self):
with self.assertRaises(ValidationError):
self.contract.write({'recurring_invoices': True})
self.acct_line.write({'recurring_next_date': False})
def test_onchange_contract_template_id(self):
"""It should change the contract values to match the template."""
self.contract.contract_template_id = False

16
contract/views/contract.xml

@ -74,11 +74,6 @@
context="{'default_contract_type': contract_type}"/>
</page>
<page name="info" string="Other Information">
<div invisible="1">
<field name="recurring_invoices"
class="oe_inline"/>
<label for="recurring_invoices"/>
</div>
<field name="create_invoice_visibility"
invisible="1"/>
<group>
@ -184,10 +179,6 @@
<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="In progress"
@ -230,8 +221,6 @@
<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="contract_contract_search_view"/>
@ -271,10 +260,7 @@
<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'}
'default_contract_type': 'purchase'}
</field>
<field name="search_view_id" ref="contract_contract_search_view"/>
<field name="help" type="html">

Loading…
Cancel
Save