This commit is contained in:
Santi Sanchez 2015-11-17 15:32:58 +01:00
commit df798989ca
20 changed files with 412 additions and 120 deletions

View File

@ -1,3 +1,4 @@
* Add sequence on contract lines
* Make contracts start date and end date functional fields based on lines
* Improve rec_names of all fields
* Initial release

View File

@ -18,8 +18,10 @@ def register():
CreateInvoicesStart,
Configuration,
InvoiceLine,
CreditInvoiceStart,
module='contract', type_='model')
Pool.register(
CreateConsumptions,
CreateInvoices,
CreditInvoice,
module='contract', type_='wizard')

View File

@ -12,7 +12,7 @@ from decimal import Decimal
from trytond.config import config
from trytond.model import Workflow, ModelSQL, ModelView, Model, fields
from trytond.pool import Pool
from trytond.pyson import Eval, Bool
from trytond.pyson import Eval, Bool, If
from trytond.transaction import Transaction
from trytond.tools import reduce_ids, grouped_slice
from trytond.wizard import Wizard, StateView, StateAction, Button
@ -106,11 +106,10 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
start_period_date = fields.Date('Start Period Date', required=True,
states=_STATES, depends=_DEPENDS)
lines = fields.One2Many('contract.line', 'contract', 'Lines',
context={
'start_date': Eval('start_date'),
'end_date': Eval('end_date'),
states={
'readonly': Eval('state') == 'cancel',
},
depends=['start_date', 'end_date'])
depends=['state'])
state = fields.Selection([
('draft', 'Draft'),
('validated', 'Validated'),
@ -144,10 +143,6 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
'icon': 'tryton-cancel',
},
})
cls._error_messages.update({
'start_date_not_valid': ('Contract %(contract)s with '
'invalid date "%(date)s"'),
})
def _get_rec_name(self, name):
rec_name = []
@ -285,6 +280,14 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
date = r.after(last_invoice_date)
return date.date()
def get_start_period_date(self, start_date):
r = rrule(self.rrule._freq, interval=self.rrule._interval,
dtstart=self.start_period_date)
date = r.before(todatetime(start_date), inc=True)
if date:
return date.date()
return self.start_period_date
def get_consumptions(self, end_date=None):
pool = Pool()
Date = pool.get('ir.date')
@ -295,7 +298,7 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
consumptions = []
for line in self.lines:
start_period_date = line.start_date or self.start_period_date
start_period_date = self.get_start_period_date(line.start_date)
last_consumption_date = line.last_consumption_date
if last_consumption_date:
@ -309,7 +312,6 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
if end_contract:
self.rrule.until = end_contract
last_invoice_date = line.last_consumption_invoice_date
next_period = self.rrule.after(todatetime(start)) + \
@ -318,7 +320,6 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
if end_contract and next_period.date() < end_contract:
next_period = todatetime(end_contract)
for date in self.rrule.between(todatetime(start), next_period):
date -= relativedelta(days=+1)
date = date.date()
@ -339,8 +340,10 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
start_period = start_period_date
start = line.start_date or self.start
if (not end_contract or (invoice_date <= end_contract) or
(finish_date <= end_contract) or (invoice_date < end_date)):
if ((not end_contract or (invoice_date <= end_contract) or
(finish_date <= end_contract) or
(invoice_date < end_date))
and not start > date):
consumptions.append(line.get_consumption(start, date,
invoice_date, start_period, finish_date))
date += relativedelta(days=+1)
@ -363,23 +366,6 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
return ContractConsumption.create([c._save_values for c in to_create])
def check_start_date(self):
if not hasattr(self, 'rrule') or not self.start_date:
return
d = self.rrule.after(todatetime(self.start_period_date)).date()
if self.start_date >= self.start_period_date and self.start_date < d:
return True
self.raise_user_error('start_date_not_valid', {
'contract': self.rec_name,
'date': self.start_date,
})
@classmethod
def validate(cls, contracts):
super(Contract, cls).validate(contracts)
for contract in contracts:
contract.check_start_date()
class ContractLine(Workflow, ModelSQL, ModelView):
'Contract Line'
@ -388,8 +374,20 @@ class ContractLine(Workflow, ModelSQL, ModelView):
contract = fields.Many2One('contract', 'Contract', required=True,
ondelete='CASCADE')
service = fields.Many2One('contract.service', 'Service')
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date')
start_date = fields.Date('Start Date', required=True,
domain=[
If(Bool(Eval('end_date')),
('start_date', '<=', Eval('end_date', None)),
()),
],
depends=['end_date'])
end_date = fields.Date('End Date',
domain=[
If(Bool(Eval('end_date')),
('end_date', '>=', Eval('start_date', None)),
()),
],
depends=['start_date'])
description = fields.Text('Description', required=True)
unit_price = fields.Numeric('Unit Price', digits=(16, DIGITS),
required=True)
@ -399,7 +397,18 @@ class ContractLine(Workflow, ModelSQL, ModelView):
'Last Invoice Date'), 'get_last_consumption_invoice_date')
consumptions = fields.One2Many('contract.consumption', 'contract_line',
'Consumptions', readonly=True)
first_invoice_date = fields.Date('First Invoice Date')
first_invoice_date = fields.Date('First Invoice Date', required=True)
sequence = fields.Integer('Sequence')
@classmethod
def __setup__(cls):
super(ContractLine, cls).__setup__()
cls._order = [('contract', 'ASC'), ('sequence', 'ASC')]
@staticmethod
def order_sequence(tables):
table, _ = tables[None]
return [table.sequence == None, table.sequence]
def get_rec_name(self, name):
rec_name = self.contract.rec_name
@ -414,18 +423,6 @@ class ContractLine(Workflow, ModelSQL, ModelView):
('service.rec_name',) + tuple(clause[1:]),
]
@staticmethod
def default_start_date():
return Transaction().context.get('start_date')
@staticmethod
def default_end_date():
return Transaction().context.get('end_date')
@staticmethod
def default_first_invoice_date():
return Transaction().context.get('first_invoice_date')
@fields.depends('service', 'unit_price', 'description')
def on_change_service(self):
changes = {}
@ -437,6 +434,13 @@ class ContractLine(Workflow, ModelSQL, ModelView):
changes['description'] = self.service.product.rec_name
return changes
@fields.depends('start_date', 'first_invoice_date')
def on_change_start_date(self):
changes = {}
if self.start_date and not self.first_invoice_date:
changes['first_invoice_date'] = self.start_date
return changes
@classmethod
def get_last_consumption_date(cls, lines, name):
pool = Pool()
@ -490,13 +494,35 @@ class ContractConsumption(ModelSQL, ModelView):
contract_line = fields.Many2One('contract.line', 'Contract Line',
required=True)
init_period_date = fields.Date('Start Period Date', required=True)
end_period_date = fields.Date('Finish Period Date', required=True)
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
init_period_date = fields.Date('Start Period Date', required=True,
domain=[
('init_period_date', '<=', Eval('end_period_date', None)),
],
depends=['end_period_date'])
end_period_date = fields.Date('Finish Period Date', required=True,
domain=[
('end_period_date', '>=', Eval('init_period_date', None)),
],
depends=['init_period_date'])
start_date = fields.Date('Start Date', required=True,
domain=[
('start_date', '<=', Eval('end_date', None)),
],
depends=['end_date'])
end_date = fields.Date('End Date', required=True,
domain=[
('end_date', '>=', Eval('start_date', None)),
],
depends=['start_date'])
invoice_date = fields.Date('Invoice Date', required=True)
invoice_line = fields.One2Many('account.invoice.line', 'origin',
'Invoice Line', size=1)
invoice_lines = fields.One2Many('account.invoice.line', 'origin',
'Invoice Lines', readonly=True)
credit_lines = fields.Function(fields.One2Many('account.invoice.line',
None, 'Credit Lines',
states={
'invisible': ~Bool(Eval('credit_lines')),
}),
'get_credit_lines')
contract = fields.Function(fields.Many2One('contract',
'Contract'), 'get_contract', searcher='search_contract')
@ -510,14 +536,22 @@ class ContractConsumption(ModelSQL, ModelView):
'missing_account_revenue_property': ('Contract Line '
'"%(contract_line)s" misses an "account revenue" default '
'property.'),
'delete_invoiced_consumption': ('Consumption "%s" can not be'
' deleted because it is already invoiced.'),
})
cls._buttons.update({
'invoice': {
'invisible': Bool(Eval('invoice_line')),
'icon': 'tryton-go-next',
},
})
def get_credit_lines(self, name):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
return [x.id for x in InvoiceLine.search([
('origin.id', 'in', [l.id for l in self.invoice_lines],
'account.invoice.line')])]
def get_contract(self, name=None):
return self.contract_line.contract.id
@ -558,6 +592,7 @@ class ContractConsumption(ModelSQL, ModelView):
invoice_line.origin = self
invoice_line.company = self.contract_line.contract.company
invoice_line.currency = self.contract_line.contract.currency
invoice_line.sequence = self.contract_line.sequence
invoice_line.product = None
if self.contract_line.service:
invoice_line.product = self.contract_line.service.product
@ -603,9 +638,12 @@ class ContractConsumption(ModelSQL, ModelView):
})
invoice_line.taxes = taxes
invoice_line.invoice_type = 'out_invoice'
# Compute quantity based on dates
quantity = ((self.end_date - self.start_date).total_seconds() /
(self.end_period_date - self.init_period_date).total_seconds())
if self.end_period_date == self.init_period_date:
quantity = 0.0
else:
# Compute quantity based on dates
quantity = ((self.end_date - self.start_date).total_seconds() /
(self.end_period_date - self.init_period_date).total_seconds())
rounding = invoice_line.unit.rounding if invoice_line.unit else 1
invoice_line.quantity = Uom.round(quantity, rounding)
return invoice_line
@ -677,8 +715,6 @@ class ContractConsumption(ModelSQL, ModelView):
Invoice = pool.get('account.invoice')
lines = {}
for consumption in consumptions:
if consumption.invoice_line:
continue
line = consumption.get_invoice_line()
lines[consumption.id] = line
@ -698,6 +734,19 @@ class ContractConsumption(ModelSQL, ModelView):
Invoice.update_taxes(invoices)
return invoices
@classmethod
def delete(cls, consumptions):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
lines = InvoiceLine.search([
('origin', 'in', [str(c) for c in consumptions])
], limit=1)
if lines:
line, = lines
cls.raise_user_error('delete_invoiced_consumption',
line.origin.rec_name)
super(ContractConsumption, cls).delete(consumptions)
class CreateConsumptionsStart(ModelView):
'Create Consumptions Start'

View File

@ -113,7 +113,7 @@
id="act_contract_consumption_domain_to_invoiced">
<field name="name">To Invoice</field>
<field name="sequence" eval="10"/>
<field name="domain">[('invoice_line', '=', None)]</field>
<field name="domain">[('invoice_lines', '=', None)]</field>
<field name="act_window" ref="act_contract_consumption"/>
</record>
<record model="ir.action.act_window.domain"
@ -122,7 +122,6 @@
<field name="sequence" eval="9999"/>
<field name="act_window" ref="act_contract_consumption"/>
</record>
<!-- TODO: Add relate from consumption to invoices
<record model="ir.action.act_window" id="act_invoices">
<field name="name">Invoices</field>
<field name="res_model">account.invoice</field>
@ -133,7 +132,27 @@
<field name="model">contract.consumption,-1</field>
<field name="action" ref="act_invoices"/>
</record>
-->
<record model="ir.action.act_window" id="act_consumption_contracts">
<field name="name">Consumptions</field>
<field name="res_model">contract.consumption</field>
<field name="domain">[('contract', 'in', Eval('active_ids'))]</field>
</record>
<record model="ir.action.keyword" id="act_consumption_contracts_keyword1">
<field name="keyword">form_relate</field>
<field name="model">contract,-1</field>
<field name="action" ref="act_consumption_contracts"/>
</record>
<record model="ir.action.act_window" id="act_consumption_contract_line">
<field name="name">Consumptions</field>
<field name="res_model">contract.consumption</field>
<field name="domain">[('contract_line', 'in', Eval('active_ids'))]</field>
</record>
<record model="ir.action.keyword"
id="act_consumption_contract_line_keyword1">
<field name="keyword">form_relate</field>
<field name="model">contract.line,-1</field>
<field name="action" ref="act_consumption_contract_line"/>
</record>
<record model="ir.model.access" id="access_contract_consumption">
<field name="model" search="[('model', '=', 'contract.consumption')]"/>
<field name="perm_read" eval="True"/>

View File

@ -1,12 +1,13 @@
# This file is part of contract_invoice module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
from trytond.pool import PoolMeta
from trytond.model import ModelView, fields
from trytond.pool import Pool
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, StateAction, Button
__all__ = ['InvoiceLine', 'CreateInvoicesStart', 'CreateInvoices']
__all__ = ['InvoiceLine', 'CreateInvoicesStart', 'CreateInvoices',
'CreditInvoiceStart', 'CreditInvoice']
__metaclass__ = PoolMeta
@ -54,3 +55,50 @@ class CreateInvoices(Wizard):
if len(invoices) == 1:
action['views'].reverse()
return action, data
class CreditInvoiceStart:
__name__ = 'account.invoice.credit.start'
from_contract = fields.Boolean('From Contract', readonly=True)
reinvoice_contract = fields.Boolean('Reinvoice Contract',
states={
'invisible': ~Bool(Eval('from_contract')),
},
depends=['from_contract'],
help=('If true, the consumption that generated this line will be '
'reinvoiced.'))
class CreditInvoice:
__name__ = 'account.invoice.credit'
def default_start(self, fields):
pool = Pool()
Invoice = pool.get('account.invoice')
Consumption = pool.get('contract.consumption')
default = super(CreditInvoice, self).default_start(fields)
default.update({
'from_contract': False,
'reinvoice_contract': False,
})
for invoice in Invoice.browse(Transaction().context['active_ids']):
for line in invoice.lines:
if isinstance(line.origin, Consumption):
default['from_contract'] = True
break
return default
def do_credit(self, action):
pool = Pool()
Invoice = pool.get('account.invoice')
Consumption = pool.get('contract.consumption')
action, data = super(CreditInvoice, self).do_credit(action)
consumptions = set([])
for invoice in Invoice.browse(Transaction().context['active_ids']):
for line in invoice.lines:
if isinstance(line.origin, Consumption):
consumptions.add(line.origin)
Consumption.invoice(list(consumptions))
return action, data

14
invoice.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="credit_start_view_form">
<field name="model">account.invoice.credit.start</field>
<field name="name">credit_start_form</field>
<field name="inherit" ref="account_invoice.credit_start_view_form"/>
</record>
</data>
</tryton>

View File

@ -2,6 +2,10 @@
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "error:contract.consumption:"
msgid "Consumption \"%s\" can not be deleted because it is already invoiced."
msgstr "No es pot eliminar el consum \"%s\" perquè ja esta facturat."
msgctxt "error:contract.consumption:"
msgid ""
"Contract Line \"%(contract_line)s\" misses an \"account revenue\" default "
@ -18,9 +22,13 @@ msgstr ""
"Falta el compte d'ingressos al producte \"%(product)s\" de la línia de "
"contracte \"%(contract_line)s\"."
msgctxt "error:contract:"
msgid "Contract %(contract)s with invalid date \"%(date)s\""
msgstr "El contracte \"%(contract)s\" té dates invàlides \"%(date)s\""
msgctxt "field:account.invoice.credit.start,from_contract:"
msgid "From Contract"
msgstr "Provinent de contracte"
msgctxt "field:account.invoice.credit.start,reinvoice_contract:"
msgid "Reinvoice Contract"
msgstr "Refacturar el contracte"
msgctxt "field:contract,company:"
msgid "Company"
@ -134,6 +142,10 @@ msgctxt "field:contract.consumption,create_uid:"
msgid "Create User"
msgstr "Usuari creació"
msgctxt "field:contract.consumption,credit_lines:"
msgid "Credit Lines"
msgstr "Línies d'abonament"
msgctxt "field:contract.consumption,end_date:"
msgid "End Date"
msgstr "Data finalització"
@ -154,9 +166,9 @@ msgctxt "field:contract.consumption,invoice_date:"
msgid "Invoice Date"
msgstr "Data factura"
msgctxt "field:contract.consumption,invoice_line:"
msgid "Invoice Line"
msgstr "Línia de factura"
msgctxt "field:contract.consumption,invoice_lines:"
msgid "Invoice Lines"
msgstr "Línies de factura"
msgctxt "field:contract.consumption,rec_name:"
msgid "Name"
@ -234,6 +246,10 @@ msgctxt "field:contract.line,rec_name:"
msgid "Name"
msgstr "Nom"
msgctxt "field:contract.line,sequence:"
msgid "Sequence"
msgstr "Seqüència"
msgctxt "field:contract.line,service:"
msgid "Service"
msgstr "Serveis"
@ -298,6 +314,12 @@ msgctxt "field:party.party,contract_grouping_method:"
msgid "Contract Grouping Method"
msgstr "Mètode d'agrupació de contractes"
msgctxt "help:account.invoice.credit.start,reinvoice_contract:"
msgid "If true, the consumption that generated this line will be reinvoiced."
msgstr ""
"Si es marca, es tornaran a facturar els consums que han generat aquestes "
"línies de factura."
msgctxt "model:contract,name:"
msgid "Contract"
msgstr "Contracte"
@ -326,6 +348,14 @@ msgctxt "model:contract.service,name:"
msgid "Contract Service"
msgstr "Servei de contracte"
msgctxt "model:ir.action,name:act_consumption_contract_line"
msgid "Consumptions"
msgstr "Consums"
msgctxt "model:ir.action,name:act_consumption_contracts"
msgid "Consumptions"
msgstr "Consums"
msgctxt "model:ir.action,name:act_contract"
msgid "Contract"
msgstr "Contractes"
@ -346,6 +376,14 @@ msgctxt "model:ir.action,name:act_contract_service"
msgid "Contract Service"
msgstr "Servei de contracte"
msgctxt "model:ir.action,name:act_invoices"
msgid "Invoices"
msgstr "Factures"
msgctxt "model:ir.action,name:act_open_contract"
msgid "Contracts"
msgstr "Contractes"
msgctxt "model:ir.action,name:wizard_create_consumptions"
msgid "Create Consumptions"
msgstr "Crea consums"
@ -484,6 +522,14 @@ msgctxt "selection:party.party,contract_grouping_method:"
msgid "None"
msgstr "Cap"
msgctxt "view:account.invoice.credit.start:"
msgid ""
"Those/this invoice(s) have been generated from contracts, are you sure you "
"want to credit them?"
msgstr ""
"Aquesta(es) factures s'han generat a través de contracte. Esteu segur que "
"les voleu abonar? "
msgctxt "view:contract.configuration:"
msgid "Contract Configuration"
msgstr "Configuració de contractes"

View File

@ -2,6 +2,10 @@
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "error:contract.consumption:"
msgid "Consumption \"%s\" can not be deleted because it is already invoiced."
msgstr "No se puede eliminar el consumo \"%s\" porqué ya esta facturado."
msgctxt "error:contract.consumption:"
msgid ""
"Contract Line \"%(contract_line)s\" misses an \"account revenue\" default "
@ -18,9 +22,13 @@ msgstr ""
"Falta la cuenta de ingresos par el producto \"%(product)s\" de la linea de "
"contracto \"%(contract_line)s\"."
msgctxt "error:contract:"
msgid "Contract %(contract)s with invalid date \"%(date)s\""
msgstr "El contracto %(contract)s tiene fecha de comienzo inválida \"%(date)s\""
msgctxt "field:account.invoice.credit.start,from_contract:"
msgid "From Contract"
msgstr "Proveniente de contrato"
msgctxt "field:account.invoice.credit.start,reinvoice_contract:"
msgid "Reinvoice Contract"
msgstr "Refacturar el contrato"
msgctxt "field:contract,company:"
msgid "Company"
@ -134,6 +142,10 @@ msgctxt "field:contract.consumption,create_uid:"
msgid "Create User"
msgstr "Usuario creación"
msgctxt "field:contract.consumption,credit_lines:"
msgid "Credit Lines"
msgstr "Lineas de abono"
msgctxt "field:contract.consumption,end_date:"
msgid "End Date"
msgstr "Fecha finalización"
@ -154,9 +166,9 @@ msgctxt "field:contract.consumption,invoice_date:"
msgid "Invoice Date"
msgstr "Fecha factura"
msgctxt "field:contract.consumption,invoice_line:"
msgid "Invoice Line"
msgstr "Línea de factura"
msgctxt "field:contract.consumption,invoice_lines:"
msgid "Invoice Lines"
msgstr "Líneas de factura"
msgctxt "field:contract.consumption,rec_name:"
msgid "Name"
@ -234,6 +246,10 @@ msgctxt "field:contract.line,rec_name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:contract.line,sequence:"
msgid "Sequence"
msgstr "Secuencia"
msgctxt "field:contract.line,service:"
msgid "Service"
msgstr "Servicios"
@ -298,6 +314,12 @@ msgctxt "field:party.party,contract_grouping_method:"
msgid "Contract Grouping Method"
msgstr "Método agrupación contratos"
msgctxt "help:account.invoice.credit.start,reinvoice_contract:"
msgid "If true, the consumption that generated this line will be reinvoiced."
msgstr ""
"Si se marca, el consumo que ha generado estas líneas de contracto será "
"refacturado."
msgctxt "model:contract,name:"
msgid "Contract"
msgstr "Contrato"
@ -326,6 +348,14 @@ msgctxt "model:contract.service,name:"
msgid "Contract Service"
msgstr "Servicio de contrato"
msgctxt "model:ir.action,name:act_consumption_contract_line"
msgid "Consumptions"
msgstr "Consumos"
msgctxt "model:ir.action,name:act_consumption_contracts"
msgid "Consumptions"
msgstr "Consumos"
msgctxt "model:ir.action,name:act_contract"
msgid "Contract"
msgstr "Contratos"
@ -346,6 +376,14 @@ msgctxt "model:ir.action,name:act_contract_service"
msgid "Contract Service"
msgstr "Servicio de contrato"
msgctxt "model:ir.action,name:act_invoices"
msgid "Invoices"
msgstr "Facturas"
msgctxt "model:ir.action,name:act_open_contract"
msgid "Contracts"
msgstr "Contratos"
msgctxt "model:ir.action,name:wizard_create_consumptions"
msgid "Create Consumptions"
msgstr "Crear consumos"
@ -488,6 +526,14 @@ msgctxt "selection:party.party,contract_grouping_method:"
msgid "None"
msgstr "Ninguno"
msgctxt "view:account.invoice.credit.start:"
msgid ""
"Those/this invoice(s) have been generated from contracts, are you sure you "
"want to credit them?"
msgstr ""
"Esta factura(s) se ha generado a partir de contratos, estas seguro que las "
"quieres abonar?"
msgctxt "view:contract.configuration:"
msgid "Contract Configuration"
msgstr "Configuración de contratos"

View File

@ -8,5 +8,16 @@
<field name="inherit" ref="party.party_view_form"/>
<field name="name">party_form</field>
</record>
<record model="ir.action.act_window" id="act_open_contract">
<field name="name">Contracts</field>
<field name="res_model">contract</field>
<field name="domain">[('party', 'in', Eval('active_ids'))]</field>
</record>
<record model="ir.action.keyword"
id="act_open_contract_keyword1">
<field name="keyword">form_relate</field>
<field name="model">party.party,-1</field>
<field name="action" ref="act_open_contract"/>
</record>
</data>
</tryton>

View File

@ -197,9 +197,9 @@ Create two contract for grouped party::
>>> contract = Contract()
>>> contract.party = party
>>> contract.start_period_date = datetime.date(today.year, 01, 01)
>>> contract.start_date = datetime.date(today.year, 01, 01)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.start_date = datetime.date(today.year, 01, 01)
>>> line.first_invoice_date = datetime.date(today.year, 01, 31)
>>> line.service = service
>>> line.unit_price
@ -213,6 +213,7 @@ Create two contract for grouped party::
>>> contract.start_date = datetime.date(today.year, 01, 01)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.start_date = datetime.date(today.year, 01, 01)
>>> line.first_invoice_date = datetime.date(today.year, 01, 31)
>>> line.service = service
>>> line.unit_price
@ -227,9 +228,9 @@ Create two contract for non grouped party::
>>> contract = Contract()
>>> contract.party = non_grouping_party
>>> contract.start_period_date = datetime.date(today.year, 01, 01)
>>> contract.start_date = datetime.date(today.year, 01, 01)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.start_date = datetime.date(today.year, 01, 01)
>>> line.first_invoice_date = datetime.date(today.year, 01, 31)
>>> line.service = service
>>> line.unit_price
@ -243,6 +244,7 @@ Create two contract for non grouped party::
>>> contract.start_date = datetime.date(today.year, 01, 01)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.start_date = datetime.date(today.year, 01, 01)
>>> line.first_invoice_date = datetime.date(today.year, 01, 31)
>>> line.service = service
>>> line.unit_price
@ -289,4 +291,3 @@ Two invoices are generated for non grouping party::
Decimal('40.00')
>>> second_invoice.total_amount
Decimal('44.00')

View File

@ -201,11 +201,11 @@ Create a contract::
>>> Contract = Model.get('contract')
>>> contract = Contract()
>>> contract.party = party
>>> contract.start_period_date = datetime.date(2015,01,01)
>>> contract.start_date = datetime.date(2015,01,01)
>>> contract.start_period_date = datetime.date(2015, 01, 01)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.first_invoice_date = datetime.date(2015,01,31)
>>> line.start_date = datetime.date(2015, 01, 01)
>>> line.first_invoice_date = datetime.date(2015, 01, 31)
>>> line.service = service
>>> line.unit_price
Decimal('40')
@ -232,7 +232,7 @@ Generate consumed lines::
Generate invoice for consumed lines::
>>> invoices = consumption.click('invoice')
>>> invoice = consumption.invoice_line[0].invoice
>>> invoice = consumption.invoice_lines[0].invoice
>>> invoice.type
u'out_invoice'
>>> invoice.party == party
@ -243,7 +243,7 @@ Generate invoice for consumed lines::
Decimal('4.00')
>>> invoice.total_amount
Decimal('44.00')
>>> consumption.invoice_line[0].product == product
>>> consumption.invoice_lines[0].product == product
True
>>> consumption.invoice_date == invoice.invoice_date
True

View File

@ -234,7 +234,7 @@ Generate consumed lines::
Generate invoice for consumed lines::
>>> invoices = consumption.click('invoice')
>>> invoice = consumption.invoice_line[0].invoice
>>> invoice = consumption.invoice_lines[0].invoice
>>> invoice.type
u'out_invoice'
>>> invoice.party == party
@ -245,7 +245,7 @@ Generate invoice for consumed lines::
Decimal('4.00')
>>> invoice.total_amount
Decimal('44.00')
>>> consumption.invoice_line[0].product == product
>>> consumption.invoice_lines[0].product == product
True
>>> consumption.invoice_date == invoice.invoice_date
True

View File

@ -202,10 +202,11 @@ Create a contract::
>>> contract = Contract()
>>> contract.party = party
>>> contract.start_period_date = datetime.date(2015,01,05)
>>> contract.start_date = datetime.date(2015,01,05)
>>> contract.freq = 'monthly'
>>> line = contract.lines.new()
>>> line.service = service
>>> line.start_date = datetime.date(2015,01,05)
>>> line.first_invoice_date = datetime.date(2015,02,04)
>>> line.unit_price
Decimal('40')
>>> contract.click('validate_contract')
@ -235,7 +236,7 @@ Generate consumed lines::
Generate invoice for consumed lines::
>>> invoices = consumption.click('invoice')
>>> invoice = consumption.invoice_line[0].invoice
>>> invoice = consumption.invoice_lines[0].invoice
>>> invoice.type
u'out_invoice'
>>> invoice.party == party
@ -246,7 +247,7 @@ Generate invoice for consumed lines::
Decimal('4.00')
>>> invoice.total_amount
Decimal('44.00')
>>> consumption.invoice_line[0].product == product
>>> consumption.invoice_lines[0].product == product
True
>>> consumption.invoice_date == invoice.invoice_date
True

View File

@ -152,10 +152,17 @@ Create party::
>>> party = Party(name='Party')
>>> party.save()
Create product::
Configure unit to accept decimals::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> unit.rounding = 0.01
>>> unit.digits = 2
>>> unit.save()
Create product::
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> product = Product()
@ -201,24 +208,23 @@ Create a contract::
>>> Contract = Model.get('contract')
>>> contract = Contract()
>>> contract.party = party
>>> contract.start_period_date = datetime.date(2015,01,01)
>>> contract.start_date = datetime.date(2015,01,10)
>>> contract.start_period_date = datetime.date(2015, 01, 01)
>>> contract.freq = 'monthly'
>>> contract.interval = 1
>>> contract.first_invoice_date = datetime.date(2015,02,10)
>>> line = contract.lines.new()
>>> line.start_date = datetime.date(2015, 01, 10)
>>> line.first_invoice_date = datetime.date(2015, 02, 10)
>>> line.service = service
>>> line.unit_price
Decimal('40')
>>> line.end_date = datetime.date(2015,01,31)
>>> line.first_invoice_date = contract.first_invoice_date
>>> line.end_date = datetime.date(2015, 01, 31)
>>> line2 = contract.lines.new()
>>> line2.service = service
>>> line2.unit_price = Decimal('100')
>>> line2.unit_price
Decimal('100')
>>> line2.start_date = datetime.date(2015,02,01)
>>> line2.first_invoice_date = datetime.date(2015,03,01)
>>> line2.start_date = datetime.date(2015, 02, 01)
>>> line2.first_invoice_date = datetime.date(2015, 03, 01)
>>> contract.click('validate_contract')
>>> contract.state
u'validated'
@ -228,49 +234,74 @@ Create a contract::
Generate consumed lines::
>>> create_consumptions = Wizard('contract.create_consumptions')
>>> create_consumptions.form.date = datetime.date(2015,03,01)
>>> create_consumptions.form.date = datetime.date(2015, 03, 01)
>>> create_consumptions.execute('create_consumptions')
>>> Consumption = Model.get('contract.consumption')
>>> consumption, consumption2 = Consumption.find([])
>>> consumption.start_date == datetime.date(2015,01,10)
>>> consumption.start_date == datetime.date(2015, 01, 10)
True
>>> consumption.end_date == datetime.date(2015,01,31)
>>> consumption.end_date == datetime.date(2015, 01, 31)
True
>>> consumption.invoice_date == datetime.date(2015,02,10)
>>> consumption.invoice_date == datetime.date(2015, 02, 10)
True
>>> consumption.init_period_date == datetime.date(2015,01,10)
>>> consumption.init_period_date == datetime.date(2015, 01, 01)
True
>>> consumption.end_period_date == datetime.date(2015,01,31)
>>> consumption.end_period_date == datetime.date(2015, 01, 31)
True
>>> consumption2.start_date == datetime.date(2015,02,01)
>>> consumption2.start_date == datetime.date(2015, 02, 01)
True
>>> consumption2.end_date == datetime.date(2015,02,28)
>>> consumption2.end_date == datetime.date(2015, 02, 28)
True
>>> consumption2.invoice_date == datetime.date(2015,03,01)
>>> consumption2.invoice_date == datetime.date(2015, 03, 01)
True
>>> consumption2.init_period_date == datetime.date(2015,02,1)
>>> consumption2.init_period_date == datetime.date(2015, 02, 1)
True
>>> consumption2.end_period_date == datetime.date(2015,02,28)
>>> consumption2.end_period_date == datetime.date(2015, 02, 28)
True
Generate invoice for consumed lines::
Invoice first consumed line::
>>> invoices = consumption.click('invoice')
>>> invoice = consumption.invoice_line[0].invoice
>>> invoice = consumption.invoice_lines[0].invoice
>>> invoice.type
u'out_invoice'
>>> invoice.party == party
True
>>> invoice.untaxed_amount
Decimal('40.00')
Decimal('28.00')
>>> invoice.tax_amount
Decimal('4.00')
Decimal('2.80')
>>> invoice.total_amount
Decimal('44.00')
>>> consumption.invoice_line[0].product == product
Decimal('30.80')
>>> consumption.invoice_lines[0].product == product
True
>>> consumption.invoice_date == invoice.invoice_date
True
>>> invoice_line, = invoice.lines
>>> invoice_line.quantity
0.7
Invoice second consumed line::
>>> invoices = consumption2.click('invoice')
>>> invoice = consumption2.invoice_lines[0].invoice
>>> invoice.type
u'out_invoice'
>>> invoice.party == party
True
>>> invoice.untaxed_amount
Decimal('100.00')
>>> invoice.tax_amount
Decimal('10.00')
>>> invoice.total_amount
Decimal('110.00')
>>> consumption2.invoice_lines[0].product == product
True
>>> consumption2.invoice_date == invoice.invoice_date
True
>>> invoice_line, = invoice.lines
>>> invoice_line.quantity
1.0

View File

@ -6,3 +6,4 @@ xml:
contract.xml
configuration.xml
party.xml
invoice.xml

View File

@ -6,12 +6,17 @@ this repository contains the full copyright notices and license terms. -->
<field name="contract" colspan="3"/>
<label name="contract_line"/>
<field name="contract_line"/>
<label name="invoice_date"/>
<field name="invoice_date"/>
<label name="start_date"/>
<field name="start_date"/>
<label name="end_date"/>
<field name="end_date"/>
<label name="invoice_date"/>
<field name="invoice_date"/>
<field name="invoice_line" colspan="4"/>
<label name="init_period_date"/>
<field name="init_period_date"/>
<label name="end_period_date"/>
<field name="end_period_date"/>
<field name="invoice_lines" colspan="4"/>
<field name="credit_lines" colspan="4"/>
<button name="invoice" string="Invoice" icon="tryton-go-next" colspan="4"/>
</form>

View File

@ -9,6 +9,5 @@ this repository contains the full copyright notices and license terms. -->
<field name="invoice_date"/>
<field name="init_period_date"/>
<field name="end_period_date"/>
<field name="invoice_line" tree_invisible="1"/>
<button name="invoice" string="Invoice" tree_invisible="1"/>
</tree>

View File

@ -14,6 +14,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="unit_price"/>
<label name="first_invoice_date"/>
<field name="first_invoice_date"/>
<label name="sequence"/>
<field name="sequence"/>
<separator name="description" colspan="4"/>
<field name="description" colspan="4"/>
</form>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree string="Contract Line">
<tree string="Contract Line" sequence="sequence">
<field name="contract"/>
<field name="service"/>
<field name="unit_price"/>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<data>
<xpath expr="/form" position="inside">
<group col="2" name="from_contract" string="" colspan="2">
<image name="tryton-dialog-warning" xexpand="0"
xfill="0" states="{'invisible': ~Bool(Eval('from_contract'))}"/>
<label string="Those/this invoice(s) have been generated from contracts, are you sure you want to credit them?"
id="credit_contract" colspan="2" yalign="0.0" xalign="0.0"
xexpand="1" states="{'invisible': ~Bool(Eval('from_contract'))}"/>
<label name="reinvoice_contract"/>
<field name="reinvoice_contract"/>
</group>
</xpath>
</data>