fix funcionality in general
This commit is contained in:
parent
a7c97b1007
commit
39c5612efb
|
@ -1,5 +1,5 @@
|
||||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
#this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
from trytond.model import ModelView, ModelSQL, ModelSingleton, fields
|
from trytond.model import ModelView, ModelSQL, ModelSingleton, fields
|
||||||
from trytond.pyson import Eval
|
from trytond.pyson import Eval
|
||||||
|
|
||||||
|
|
432
contract.py
432
contract.py
|
@ -1,8 +1,8 @@
|
||||||
# The COPYRIGHT file at the top level of this repository contains
|
# The COPYRIGHT file at the top level of this repository contains
|
||||||
# the full copyright notices and license terms.
|
# the full copyright notices and license terms.
|
||||||
from datetime import datetime
|
import datetime
|
||||||
from dateutil.rrule import rrule, SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, \
|
from dateutil.relativedelta import relativedelta
|
||||||
MONTHLY, YEARLY
|
from dateutil.rrule import rrule, DAILY, WEEKLY, MONTHLY, YEARLY
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from sql.aggregate import Max
|
from sql.aggregate import Max
|
||||||
|
|
||||||
|
@ -15,190 +15,24 @@ from trytond.tools import reduce_ids
|
||||||
from trytond.wizard import Wizard, StateView, StateAction, Button
|
from trytond.wizard import Wizard, StateView, StateAction, Button
|
||||||
DIGITS = config.getint('digits', 'unit_price_digits', 4)
|
DIGITS = config.getint('digits', 'unit_price_digits', 4)
|
||||||
|
|
||||||
__all__ = ['ContractService', 'Contract', 'ContractLine',
|
__all__ = ['ContractService', 'Contract', 'ContractLine', 'RRuleMixin',
|
||||||
'ContractConsumption', 'CreateConsumptionsStart', 'CreateConsumptions']
|
'ContractConsumption', 'CreateConsumptionsStart', 'CreateConsumptions']
|
||||||
|
|
||||||
|
|
||||||
class RRuleMixin(Model):
|
class RRuleMixin(Model):
|
||||||
_rec_name = 'freq'
|
_rec_name = 'freq'
|
||||||
freq = fields.Selection([
|
freq = fields.Selection([
|
||||||
('secondly', 'Secondly'),
|
(None, 'None'),
|
||||||
('minutely', 'Minutely'),
|
|
||||||
('hourly', 'Hourly'),
|
|
||||||
('daily', 'Daily'),
|
('daily', 'Daily'),
|
||||||
('weekly', 'Weekly'),
|
('weekly', 'Weekly'),
|
||||||
('monthly', 'Monthly'),
|
('monthly', 'Monthly'),
|
||||||
('yearly', 'Yearly'),
|
('yearly', 'Yearly'),
|
||||||
], 'Frequency', required=True)
|
], 'Frequency')
|
||||||
until_date = fields.Boolean('Is Date',
|
|
||||||
help='Ignore time of field "Until Date", but handle as date only.')
|
|
||||||
until = fields.DateTime('Until Date')
|
|
||||||
count = fields.Integer('Count')
|
|
||||||
interval = fields.Integer('Interval')
|
interval = fields.Integer('Interval')
|
||||||
bysecond = fields.Char('By Second')
|
|
||||||
byminute = fields.Char('By Minute')
|
|
||||||
byhour = fields.Char('By Hour')
|
|
||||||
byday = fields.Char('By Day')
|
|
||||||
bymonthday = fields.Char('By Month Day')
|
|
||||||
byyearday = fields.Char('By Year Day')
|
|
||||||
byweekno = fields.Char('By Week Number')
|
|
||||||
bymonth = fields.Char('By Month')
|
|
||||||
bysetpos = fields.Char('By Position')
|
|
||||||
wkst = fields.Selection([
|
|
||||||
(None, ''),
|
|
||||||
('su', 'Sunday'),
|
|
||||||
('mo', 'Monday'),
|
|
||||||
('tu', 'Tuesday'),
|
|
||||||
('we', 'Wednesday'),
|
|
||||||
('th', 'Thursday'),
|
|
||||||
('fr', 'Friday'),
|
|
||||||
('sa', 'Saturday'),
|
|
||||||
], 'Week Day', sort=False)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def __setup__(cls):
|
|
||||||
super(RRuleMixin, cls).__setup__()
|
|
||||||
cls._sql_constraints += [
|
|
||||||
('until_count_only_one',
|
|
||||||
'CHECK(until IS NULL OR count IS NULL OR count = 0)',
|
|
||||||
'Only one of "until" and "count" can be set.'),
|
|
||||||
]
|
|
||||||
cls._error_messages.update({
|
|
||||||
'invalid_bysecond': ('Invalid "By Second" in recurrence rule '
|
|
||||||
'"%s"'),
|
|
||||||
'invalid_byminute': ('Invalid "By Minute" in recurrence rule '
|
|
||||||
'"%s"'),
|
|
||||||
'invalid_byhour': 'Invalid "By Hour" in recurrence rule "%s"',
|
|
||||||
'invalid_byday': 'Invalid "By Day" in recurrence rule "%s"',
|
|
||||||
'invalid_bymonthday': ('Invalid "By Month Day" in recurrence '
|
|
||||||
'rule "%s"'),
|
|
||||||
'invalid_byyearday': ('Invalid "By Year Day" in recurrence '
|
|
||||||
'rule "%s"'),
|
|
||||||
'invalid_byweekno': ('Invalid "By Week Number" in recurrence '
|
|
||||||
'rule "%s"'),
|
|
||||||
'invalid_bymonth': (
|
|
||||||
'Invalid "By Month" in recurrence rule "%s"'),
|
|
||||||
'invalid_bysetpos': (
|
|
||||||
'Invalid "By Position" in recurrence rule "%s"'),
|
|
||||||
})
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def validate(cls, rules):
|
|
||||||
super(RRuleMixin, cls).validate(rules)
|
|
||||||
for rule in rules:
|
|
||||||
rule.check_bysecond()
|
|
||||||
rule.check_byminute()
|
|
||||||
rule.check_byhour()
|
|
||||||
rule.check_byday()
|
|
||||||
rule.check_bymonthday()
|
|
||||||
rule.check_byyearday()
|
|
||||||
rule.check_byweekno()
|
|
||||||
rule.check_bymonth()
|
|
||||||
rule.check_bysetpos()
|
|
||||||
|
|
||||||
def check_bysecond(self):
|
|
||||||
if self.bysecond:
|
|
||||||
for second in self.bysecond.split(','):
|
|
||||||
try:
|
|
||||||
second = int(second)
|
|
||||||
except Exception:
|
|
||||||
second = -1
|
|
||||||
if not (second >= 0 and second <= 59):
|
|
||||||
self.raise_user_error('invalid_bysecond', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_byminute(self):
|
|
||||||
if self.byminute:
|
|
||||||
for minute in self.byminute.split(','):
|
|
||||||
try:
|
|
||||||
minute = int(minute)
|
|
||||||
except Exception:
|
|
||||||
minute = -1
|
|
||||||
if not (minute >= 0 and minute <= 59):
|
|
||||||
self.raise_user_error('invalid_byminute', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_byhour(self):
|
|
||||||
if self.byhour:
|
|
||||||
for hour in self.byhour.split(','):
|
|
||||||
try:
|
|
||||||
hour = int(hour)
|
|
||||||
except Exception:
|
|
||||||
hour = -1
|
|
||||||
if not (hour >= 0 and hour <= 23):
|
|
||||||
self.raise_user_error('invalid_byhour', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_byday(self):
|
|
||||||
if self.byday:
|
|
||||||
for weekdaynum in self.byday.split(','):
|
|
||||||
weekday = weekdaynum[-2:]
|
|
||||||
if weekday not in ('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'):
|
|
||||||
self.raise_user_error('invalid_byday', (self.rec_name,))
|
|
||||||
ordwk = weekday[:-2]
|
|
||||||
if not ordwk:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
ordwk = int(ordwk)
|
|
||||||
except Exception:
|
|
||||||
ordwk = -1
|
|
||||||
if not (abs(ordwk) >= 1 and abs(ordwk) <= 53):
|
|
||||||
self.raise_user_error('invalid_byday', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_bymonthday(self):
|
|
||||||
if self.bymonthday:
|
|
||||||
for monthdaynum in self.bymonthday.split(','):
|
|
||||||
try:
|
|
||||||
monthdaynum = int(monthdaynum)
|
|
||||||
except Exception:
|
|
||||||
monthdaynum = -100
|
|
||||||
if not (abs(monthdaynum) >= 1 and abs(monthdaynum) <= 31):
|
|
||||||
self.raise_user_error('invalid_bymonthday', (
|
|
||||||
self.rec_name,))
|
|
||||||
|
|
||||||
def check_byyearday(self):
|
|
||||||
if self.byyearday:
|
|
||||||
for yeardaynum in self.byyearday.split(','):
|
|
||||||
try:
|
|
||||||
yeardaynum = int(yeardaynum)
|
|
||||||
except Exception:
|
|
||||||
yeardaynum = -1000
|
|
||||||
if not (abs(yeardaynum) >= 1 and abs(yeardaynum) <= 366):
|
|
||||||
self.raise_user_error('invalid_byyearday',
|
|
||||||
(self.rec_name,))
|
|
||||||
|
|
||||||
def check_byweekno(self):
|
|
||||||
if self.byweekno:
|
|
||||||
for weeknum in self.byweekno.split(','):
|
|
||||||
try:
|
|
||||||
weeknum = int(weeknum)
|
|
||||||
except Exception:
|
|
||||||
weeknum = -100
|
|
||||||
if not (abs(weeknum) >= 1 and abs(weeknum) <= 53):
|
|
||||||
self.raise_user_error('invalid_byweekno', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_bymonth(self):
|
|
||||||
if self.bymonth:
|
|
||||||
for monthnum in self.bymonth.split(','):
|
|
||||||
try:
|
|
||||||
monthnum = int(monthnum)
|
|
||||||
except Exception:
|
|
||||||
monthnum = -1
|
|
||||||
if not (monthnum >= 1 and monthnum <= 12):
|
|
||||||
self.raise_user_error('invalid_bymonth', (self.rec_name,))
|
|
||||||
|
|
||||||
def check_bysetpos(self):
|
|
||||||
if self.bysetpos:
|
|
||||||
for setposday in self.bysetpos.split(','):
|
|
||||||
try:
|
|
||||||
setposday = int(setposday)
|
|
||||||
except Exception:
|
|
||||||
setposday = -1000
|
|
||||||
if not (abs(setposday) >= 1 and abs(setposday) <= 366):
|
|
||||||
self.raise_user_error('invalid_bysetpos', (self.rec_name,))
|
|
||||||
|
|
||||||
def _rule2update(self):
|
def _rule2update(self):
|
||||||
res = {}
|
res = {}
|
||||||
for field in ('freq', 'until_date', 'until', 'count', 'interval',
|
for field in ('freq', 'interval'):
|
||||||
'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
|
|
||||||
'byyearday', 'byweekno', 'bymonth', 'bysetpos', 'wkst'):
|
|
||||||
res[field] = getattr(self, field)
|
res[field] = getattr(self, field)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -206,19 +40,13 @@ class RRuleMixin(Model):
|
||||||
values = {}
|
values = {}
|
||||||
mappings = {
|
mappings = {
|
||||||
'freq': {
|
'freq': {
|
||||||
'secondly': SECONDLY,
|
|
||||||
'minutely': MINUTELY,
|
|
||||||
'hourly': HOURLY,
|
|
||||||
'daily': DAILY,
|
'daily': DAILY,
|
||||||
'weekly': WEEKLY,
|
'weekly': WEEKLY,
|
||||||
'monthly': MONTHLY,
|
'monthly': MONTHLY,
|
||||||
'yearly': YEARLY,
|
'yearly': YEARLY,
|
||||||
},
|
},
|
||||||
'byday': 'bymonthday',
|
|
||||||
}
|
}
|
||||||
for field in ('freq', 'until_date', 'until', 'count', 'interval',
|
for field in ('freq', 'interval'):
|
||||||
'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
|
|
||||||
'byyearday', 'byweekno', 'bymonth', 'bysetpos', 'wkst'):
|
|
||||||
value = getattr(self, field)
|
value = getattr(self, field)
|
||||||
if not value:
|
if not value:
|
||||||
continue
|
continue
|
||||||
|
@ -228,10 +56,6 @@ class RRuleMixin(Model):
|
||||||
else:
|
else:
|
||||||
value = mappings[field][value]
|
value = mappings[field][value]
|
||||||
values[field] = value
|
values[field] = value
|
||||||
# Convert string to list of tuples
|
|
||||||
for field in ('bymonthday', 'byyearday', 'byweekno', 'bymonth'):
|
|
||||||
if field in values:
|
|
||||||
values[field] = tuple(map(int, values[field].split(',')))
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -241,7 +65,7 @@ class RRuleMixin(Model):
|
||||||
return rrule(**values)
|
return rrule(**values)
|
||||||
|
|
||||||
|
|
||||||
class ContractService(RRuleMixin, ModelSQL, ModelView):
|
class ContractService(ModelSQL, ModelView):
|
||||||
'Contract Service'
|
'Contract Service'
|
||||||
__name__ = 'contract.service'
|
__name__ = 'contract.service'
|
||||||
|
|
||||||
|
@ -260,6 +84,10 @@ _STATES = {
|
||||||
_DEPENDS = ['state']
|
_DEPENDS = ['state']
|
||||||
|
|
||||||
|
|
||||||
|
def todatetime(date):
|
||||||
|
return datetime.datetime.combine(date, datetime.datetime.min.time())
|
||||||
|
|
||||||
|
|
||||||
class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
'Contract'
|
'Contract'
|
||||||
__name__ = 'contract'
|
__name__ = 'contract'
|
||||||
|
@ -274,6 +102,8 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
start_date = fields.Date('Start Date', required=True,
|
start_date = fields.Date('Start Date', required=True,
|
||||||
states=_STATES, depends=_DEPENDS)
|
states=_STATES, depends=_DEPENDS)
|
||||||
end_date = fields.Date('End Date')
|
end_date = fields.Date('End Date')
|
||||||
|
start_period_date = fields.Date('Start Period Date', required=True,
|
||||||
|
states=_STATES, depends=_DEPENDS)
|
||||||
first_invoice_date = fields.Date('First Invoice Date', states=_STATES,
|
first_invoice_date = fields.Date('First Invoice Date', states=_STATES,
|
||||||
depends=_DEPENDS)
|
depends=_DEPENDS)
|
||||||
lines = fields.One2Many('contract.line', 'contract', 'Lines',
|
lines = fields.One2Many('contract.line', 'contract', 'Lines',
|
||||||
|
@ -291,9 +121,7 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
@classmethod
|
@classmethod
|
||||||
def __setup__(cls):
|
def __setup__(cls):
|
||||||
super(Contract, cls).__setup__()
|
super(Contract, cls).__setup__()
|
||||||
for field_name in ('freq', 'until_date', 'until', 'count', 'interval',
|
for field_name in ('freq', 'interval'):
|
||||||
'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
|
|
||||||
'byyearday', 'byweekno', 'bymonth', 'bysetpos', 'wkst'):
|
|
||||||
field = getattr(cls, field_name)
|
field = getattr(cls, field_name)
|
||||||
field.states = _STATES
|
field.states = _STATES
|
||||||
field.depends = _DEPENDS
|
field.depends = _DEPENDS
|
||||||
|
@ -317,6 +145,10 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
'icon': 'tryton-cancel',
|
'icon': 'tryton-cancel',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
cls._error_messages.update({
|
||||||
|
'start_date_not_valid': ('Contract %(contract)s with '
|
||||||
|
'invalid date "%(date)s"'),
|
||||||
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_company():
|
def default_company():
|
||||||
|
@ -364,18 +196,13 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
@ModelView.button
|
@ModelView.button
|
||||||
@Workflow.transition('draft')
|
@Workflow.transition('draft')
|
||||||
def draft(cls, contracts):
|
def draft(cls, contracts):
|
||||||
pool = Pool()
|
pass
|
||||||
ContractLine = pool.get('contract.line')
|
|
||||||
ContractLine.hold([l for c in contracts for l in c.lines])
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ModelView.button
|
@ModelView.button
|
||||||
@Workflow.transition('validated')
|
@Workflow.transition('validated')
|
||||||
def validate_contract(cls, contracts):
|
def validate_contract(cls, contracts):
|
||||||
pool = Pool()
|
|
||||||
ContractLine = pool.get('contract.line')
|
|
||||||
cls.set_reference(contracts)
|
cls.set_reference(contracts)
|
||||||
ContractLine.active([l for c in contracts for l in c.lines])
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ModelView.button
|
@ModelView.button
|
||||||
|
@ -385,10 +212,15 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
|
|
||||||
def rrule_values(self):
|
def rrule_values(self):
|
||||||
values = super(Contract, self).rrule_values()
|
values = super(Contract, self).rrule_values()
|
||||||
values['dtstart'] = datetime.combine(self.start_date,
|
values['dtstart'] = todatetime(self.start_period_date)
|
||||||
datetime.min.time())
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
def get_invoice_date(self, last_invoice_date):
|
||||||
|
last_invoice_date = todatetime(last_invoice_date)
|
||||||
|
r = rrule(self.rrule._freq, dtstart=last_invoice_date)
|
||||||
|
date = r.after(last_invoice_date)
|
||||||
|
return date.date()
|
||||||
|
|
||||||
def get_consumptions(self, end_date=None):
|
def get_consumptions(self, end_date=None):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
Date = pool.get('ir.date')
|
Date = pool.get('ir.date')
|
||||||
|
@ -396,20 +228,53 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
if end_date is None:
|
if end_date is None:
|
||||||
end_date = Date.today()
|
end_date = Date.today()
|
||||||
|
|
||||||
end_date = datetime.combine(end_date, datetime.min.time())
|
end_date = todatetime(end_date)
|
||||||
consumptions = []
|
consumptions = []
|
||||||
|
|
||||||
for line in self.lines:
|
for line in self.lines:
|
||||||
if line.state != 'active':
|
|
||||||
continue
|
start_period_date = self.start_period_date
|
||||||
start_date = datetime.combine(line.last_consumption_date
|
|
||||||
or line.start_date or line.contract.start_date,
|
last_consumption_date = line.last_consumption_date
|
||||||
datetime.min.time())
|
if last_consumption_date:
|
||||||
print self.rrule_values()
|
last_consumption_date = todatetime(line.last_consumption_date)
|
||||||
print start_date, end_date
|
last_consumption_date += relativedelta(days=+1)
|
||||||
print self.rrule.between(start_date, end_date)
|
|
||||||
for date in self.rrule.between(start_date, end_date):
|
start = start_period_date
|
||||||
consumptions.append(line.get_consumption(start_date, date))
|
if last_consumption_date:
|
||||||
start_date = date
|
start = (last_consumption_date + relativedelta(days=+1)).date()
|
||||||
|
|
||||||
|
end_contract = None
|
||||||
|
if end_contract:
|
||||||
|
end_contract = todatetime(self.end)
|
||||||
|
self.rrule.until = end_contract
|
||||||
|
|
||||||
|
last_invoice_date = line.last_consumption_invoice_date
|
||||||
|
|
||||||
|
for date in self.rrule.between(todatetime(start), end_date):
|
||||||
|
date -= relativedelta(days=+1)
|
||||||
|
date = date.date()
|
||||||
|
invoice_date = last_invoice_date or self.first_invoice_date \
|
||||||
|
or date
|
||||||
|
if last_invoice_date:
|
||||||
|
invoice_date = self.get_invoice_date(last_invoice_date)
|
||||||
|
|
||||||
|
finish_date = date
|
||||||
|
if end_contract and end_contract <= date:
|
||||||
|
date = end_contract
|
||||||
|
|
||||||
|
start_period = start
|
||||||
|
if last_consumption_date is None:
|
||||||
|
start_period = start_period_date
|
||||||
|
start = self.start_date
|
||||||
|
|
||||||
|
consumptions.append(line.get_consumption(start, date,
|
||||||
|
invoice_date, start_period, finish_date))
|
||||||
|
date += relativedelta(days=+1)
|
||||||
|
start_period = date
|
||||||
|
start = date
|
||||||
|
last_invoice_date = invoice_date
|
||||||
|
last_consumption_date = date
|
||||||
return consumptions
|
return consumptions
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -418,11 +283,31 @@ class Contract(RRuleMixin, Workflow, ModelSQL, ModelView):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
ContractConsumption = pool.get('contract.consumption')
|
ContractConsumption = pool.get('contract.consumption')
|
||||||
|
|
||||||
|
date += relativedelta(days=+1) # to support included.
|
||||||
to_create = []
|
to_create = []
|
||||||
for contract in contracts:
|
for contract in contracts:
|
||||||
to_create += contract.get_consumptions(date)
|
to_create += contract.get_consumptions(date)
|
||||||
|
|
||||||
return ContractConsumption.create([c._save_values for c in to_create])
|
return ContractConsumption.create([c._save_values for c in to_create])
|
||||||
|
|
||||||
|
def check_start_date(self):
|
||||||
|
if not hasattr(self, 'rrule'):
|
||||||
|
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()
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ContractLine(Workflow, ModelSQL, ModelView):
|
class ContractLine(Workflow, ModelSQL, ModelView):
|
||||||
'Contract Line'
|
'Contract Line'
|
||||||
|
@ -435,59 +320,15 @@ class ContractLine(Workflow, ModelSQL, ModelView):
|
||||||
description = fields.Text('Description', required=True)
|
description = fields.Text('Description', required=True)
|
||||||
unit_price = fields.Numeric('Unit Price', digits=(16, DIGITS),
|
unit_price = fields.Numeric('Unit Price', digits=(16, DIGITS),
|
||||||
required=True)
|
required=True)
|
||||||
start_date = fields.Date('Start Date', required=True)
|
|
||||||
end_date = fields.Date('End Date')
|
|
||||||
state = fields.Selection([
|
|
||||||
('draft', 'Draft'),
|
|
||||||
('active', 'Active'),
|
|
||||||
('hold', 'Hold'),
|
|
||||||
], 'State', required=True, readonly=True)
|
|
||||||
last_consumption_date = fields.Function(fields.Date(
|
last_consumption_date = fields.Function(fields.Date(
|
||||||
'Last Consumption Date'), 'get_last_consumption_date')
|
'Last Consumption Date'), 'get_last_consumption_date')
|
||||||
|
last_consumption_invoice_date = fields.Function(fields.Date(
|
||||||
@classmethod
|
'Last Consumption Date'), 'get_last_consumption_date')
|
||||||
def __setup__(cls):
|
|
||||||
super(ContractLine, cls).__setup__()
|
|
||||||
for attr in dir(RRuleMixin):
|
|
||||||
if not hasattr(cls, attr):
|
|
||||||
continue
|
|
||||||
if isinstance(getattr(cls, attr), fields.Field):
|
|
||||||
field = getattr(cls, attr)
|
|
||||||
field.states = _STATES
|
|
||||||
field.depends = _DEPENDS
|
|
||||||
|
|
||||||
cls._transitions |= set((
|
|
||||||
('draft', 'active'),
|
|
||||||
('active', 'hold'),
|
|
||||||
('hold', 'active'),
|
|
||||||
))
|
|
||||||
cls._buttons.update({
|
|
||||||
'active': {
|
|
||||||
'invisible': Eval('state') == 'active',
|
|
||||||
'icon': 'tryton-go-next',
|
|
||||||
},
|
|
||||||
'hold': {
|
|
||||||
'invisible': Eval('state') != 'hold',
|
|
||||||
'icon': 'tryton-go-previous',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
cls._error_messages.update({
|
|
||||||
'line_outside_contract': ('Line "%(line)s" is outside its '
|
|
||||||
'contract "%(contract)s" period')
|
|
||||||
})
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_state():
|
def default_state():
|
||||||
return 'draft'
|
return 'draft'
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def default_start_date():
|
|
||||||
return Transaction().context.get('start_date')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def default_end_date():
|
|
||||||
return Transaction().context.get('end_date')
|
|
||||||
|
|
||||||
@fields.depends('service', 'unit_price', 'description')
|
@fields.depends('service', 'unit_price', 'description')
|
||||||
def on_change_service(self):
|
def on_change_service(self):
|
||||||
changes = {
|
changes = {
|
||||||
|
@ -501,14 +342,6 @@ class ContractLine(Workflow, ModelSQL, ModelView):
|
||||||
changes['description'] = self.service.product.rec_name
|
changes['description'] = self.service.product.rec_name
|
||||||
return changes
|
return changes
|
||||||
|
|
||||||
@property
|
|
||||||
def rrule(self):
|
|
||||||
if not self.service:
|
|
||||||
return
|
|
||||||
values = self.service.rrule_values()
|
|
||||||
values['dtstart'] = self.start_date
|
|
||||||
return rrule(**values)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_last_consumption_date(cls, lines, name):
|
def get_last_consumption_date(cls, lines, name):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
|
@ -518,50 +351,31 @@ class ContractLine(Workflow, ModelSQL, ModelView):
|
||||||
|
|
||||||
line_ids = [l.id for l in lines]
|
line_ids = [l.id for l in lines]
|
||||||
values = dict.fromkeys(line_ids, None)
|
values = dict.fromkeys(line_ids, None)
|
||||||
cursor.execute(*table.select(table.contract_line, Max(table.end_date),
|
cursor.execute(*table.select(table.contract_line,
|
||||||
|
Max(table.end_period_date),
|
||||||
where=reduce_ids(table.contract_line, line_ids),
|
where=reduce_ids(table.contract_line, line_ids),
|
||||||
group_by=table.contract_line))
|
group_by=table.contract_line))
|
||||||
values.update(dict(cursor.fetchall()))
|
values.update(dict(cursor.fetchall()))
|
||||||
return values
|
return values
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, lines):
|
def get_last_consumption_invoice_date(cls, lines, name):
|
||||||
super(ContractLine, cls).validate(lines)
|
pool = Pool()
|
||||||
for line in lines:
|
Consumption = pool.get('contract.consumption')
|
||||||
line.check_contract_period()
|
table = Consumption.__table__()
|
||||||
|
cursor = Transaction().cursor
|
||||||
|
|
||||||
def check_contract_period(self):
|
line_ids = [l.id for l in lines]
|
||||||
if self.start_date < self.contract.start_date:
|
values = dict.fromkeys(line_ids, None)
|
||||||
self.raise_user_error('line_outside_contract', {
|
cursor.execute(*table.select(table.contract_line,
|
||||||
'line': self.rec_name,
|
Max(table.invoice_date),
|
||||||
'contract': self.contract.rec_name,
|
where=reduce_ids(table.contract_line, line_ids),
|
||||||
})
|
group_by=table.contract_line))
|
||||||
if (self.contract.end_date and
|
values.update(dict(cursor.fetchall()))
|
||||||
self.end_date > self.contract.end_date):
|
return values
|
||||||
self.raise_user_error('line_outside_contract', {
|
|
||||||
'line': self.rec_name,
|
|
||||||
'contract': self.contract.rec_name,
|
|
||||||
})
|
|
||||||
|
|
||||||
@classmethod
|
def get_consumption(self, start_date, end_date, invoice_date, start_period,
|
||||||
@ModelView.button
|
finish_period):
|
||||||
@Workflow.transition('draft')
|
|
||||||
def draft(cls, lines):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@ModelView.button
|
|
||||||
@Workflow.transition('active')
|
|
||||||
def active(cls, lines):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@ModelView.button
|
|
||||||
@Workflow.transition('hold')
|
|
||||||
def hold(cls, lines):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_consumption(self, start_date, end_date):
|
|
||||||
'Returns the consumption for date date'
|
'Returns the consumption for date date'
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
Consumption = pool.get('contract.consumption')
|
Consumption = pool.get('contract.consumption')
|
||||||
|
@ -569,10 +383,8 @@ class ContractLine(Workflow, ModelSQL, ModelView):
|
||||||
consumption.contract_line = self
|
consumption.contract_line = self
|
||||||
consumption.start_date = start_date
|
consumption.start_date = start_date
|
||||||
consumption.end_date = end_date
|
consumption.end_date = end_date
|
||||||
invoice_date = end_date
|
consumption.init_period_date = start_period
|
||||||
if self.contract.first_invoice_date:
|
consumption.end_period_date = finish_period
|
||||||
invoice_date += (self.contract.first_invoice_date -
|
|
||||||
self.contract.start_date)
|
|
||||||
consumption.invoice_date = invoice_date
|
consumption.invoice_date = invoice_date
|
||||||
return consumption
|
return consumption
|
||||||
|
|
||||||
|
@ -584,8 +396,10 @@ class ContractConsumption(ModelSQL, ModelView):
|
||||||
contract_line = fields.Many2One('contract.line', 'Contract Line',
|
contract_line = fields.Many2One('contract.line', 'Contract Line',
|
||||||
required=True)
|
required=True)
|
||||||
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line')
|
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line')
|
||||||
start_date = fields.DateTime('Start Date')
|
init_period_date = fields.Date('Start Period Date')
|
||||||
end_date = fields.DateTime('End Date')
|
end_period_date = fields.Date('Finish Period Date')
|
||||||
|
start_date = fields.Date('Start Date')
|
||||||
|
end_date = fields.Date('End Date')
|
||||||
invoice_date = fields.Date('Invoice Date')
|
invoice_date = fields.Date('Invoice Date')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -667,10 +481,8 @@ class ContractConsumption(ModelSQL, ModelView):
|
||||||
invoice_line.taxes = taxes
|
invoice_line.taxes = taxes
|
||||||
invoice_line.invoice_type = 'out_invoice'
|
invoice_line.invoice_type = 'out_invoice'
|
||||||
# Compute quantity based on dates
|
# Compute quantity based on dates
|
||||||
contract_start = self.contract_line.contract.start_date
|
quantity = ((self.end_date - self.start_date).total_seconds() /
|
||||||
invoice_date = self.contract_line.contract.rrule.after(contract_start)
|
(self.end_period_date - self.init_period_date).total_seconds())
|
||||||
quantity = ((self.end_date - self.start_date).total_seconds()
|
|
||||||
/ (invoice_date - contract_start).total_seconds())
|
|
||||||
rounding = invoice_line.unit.rounding if invoice_line.unit else 1
|
rounding = invoice_line.unit.rounding if invoice_line.unit else 1
|
||||||
invoice_line.quantity = Uom.round(quantity, rounding)
|
invoice_line.quantity = Uom.round(quantity, rounding)
|
||||||
return invoice_line
|
return invoice_line
|
||||||
|
@ -735,8 +547,8 @@ class ContractConsumption(ModelSQL, ModelView):
|
||||||
invoices = []
|
invoices = []
|
||||||
for key, grouped_lines in groupby(lines, key=cls._group_invoice_key):
|
for key, grouped_lines in groupby(lines, key=cls._group_invoice_key):
|
||||||
invoice = cls._get_invoice(key)
|
invoice = cls._get_invoice(key)
|
||||||
invoice.lines = (list(getattr(invoice, 'lines', []))
|
invoice.lines = (list(getattr(invoice, 'lines', [])) +
|
||||||
+ list(x[1] for x in grouped_lines))
|
list(x[1] for x in grouped_lines))
|
||||||
invoices.append(invoice)
|
invoices.append(invoice)
|
||||||
|
|
||||||
invoices = Invoice.create([x._save_values for x in invoices])
|
invoices = Invoice.create([x._save_values for x in invoices])
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#This file is part of contract_invoice module for Tryton.
|
# This file is part of contract_invoice module for Tryton.
|
||||||
#The COPYRIGHT file at the top level of this repository contains
|
# The COPYRIGHT file at the top level of this repository contains
|
||||||
#the full copyright notices and license terms.
|
# the full copyright notices and license terms.
|
||||||
from trytond.pool import PoolMeta
|
from trytond.pool import PoolMeta
|
||||||
|
|
||||||
__all__ = ['InvoiceLine']
|
__all__ = ['InvoiceLine']
|
||||||
|
|
330
locale/ca_ES.po
330
locale/ca_ES.po
|
@ -18,142 +18,10 @@ msgstr ""
|
||||||
"Falta el compte d'ingressos al producte \"%(product)s\" de la línia de "
|
"Falta el compte d'ingressos al producte \"%(product)s\" de la línia de "
|
||||||
"contracte \"%(contract_line)s\"."
|
"contracte \"%(contract_line)s\"."
|
||||||
|
|
||||||
msgctxt "error:contract.line:"
|
|
||||||
msgid "Line \"%(line)s\" is outside its contract \"%(contract)s\" period"
|
|
||||||
msgstr "La línia \"%(line)s\" es fora del període del seu contracte \"%(contract)s\""
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per dia\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Hour\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per hora\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Minute\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per minut\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Month Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per dia del mes\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Month\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per mes\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Position\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per ubicació\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Second\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per segon\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Week Number\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El camp \"per número de la setmana\" de la regla de recurrència \"%s\" no és"
|
|
||||||
" correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Year Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El camp \"per dia de l'any\" de la regla de recurrència \"%s\" no és "
|
|
||||||
"correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Only one of \"until\" and \"count\" can be set."
|
|
||||||
msgstr "Defineix un \"fins\" i un \"comptador\"."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per dia\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Hour\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per hora\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Minute\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per minut\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Month Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per dia del mes\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Month\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per mes\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Position\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per ubicació\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Second\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El camp \"per segon\" de la regla de recurrència \"%s\" no és correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Week Number\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El camp \"per número de la setmana\" de la regla de recurrència \"%s\" no és"
|
|
||||||
" correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Year Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El camp \"per dia de l'any\" de la regla de recurrència \"%s\" no és "
|
|
||||||
"correcte."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Only one of \"until\" and \"count\" can be set."
|
|
||||||
msgstr "Defineix un \"fins\" i un \"comptador\"."
|
|
||||||
|
|
||||||
msgctxt "field:contract,byday:"
|
|
||||||
msgid "By Day"
|
|
||||||
msgstr "Per dia"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byhour:"
|
|
||||||
msgid "By Hour"
|
|
||||||
msgstr "Per hora"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byminute:"
|
|
||||||
msgid "By Minute"
|
|
||||||
msgstr "Per minut"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bymonth:"
|
|
||||||
msgid "By Month"
|
|
||||||
msgstr "Per mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bymonthday:"
|
|
||||||
msgid "By Month Day"
|
|
||||||
msgstr "Per dia del mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bysecond:"
|
|
||||||
msgid "By Second"
|
|
||||||
msgstr "Per segon"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bysetpos:"
|
|
||||||
msgid "By Position"
|
|
||||||
msgstr "Per ubicació"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byweekno:"
|
|
||||||
msgid "By Week Number"
|
|
||||||
msgstr "Per número de la setmana"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byyearday:"
|
|
||||||
msgid "By Year Day"
|
|
||||||
msgstr "Per dia de l'any"
|
|
||||||
|
|
||||||
msgctxt "field:contract,company:"
|
msgctxt "field:contract,company:"
|
||||||
msgid "Company"
|
msgid "Company"
|
||||||
msgstr "Empresa"
|
msgstr "Empresa"
|
||||||
|
|
||||||
msgctxt "field:contract,count:"
|
|
||||||
msgid "Count"
|
|
||||||
msgstr "Comptador"
|
|
||||||
|
|
||||||
msgctxt "field:contract,create_date:"
|
msgctxt "field:contract,create_date:"
|
||||||
msgid "Create Date"
|
msgid "Create Date"
|
||||||
msgstr "Data creació"
|
msgstr "Data creació"
|
||||||
|
@ -210,18 +78,6 @@ msgctxt "field:contract,state:"
|
||||||
msgid "State"
|
msgid "State"
|
||||||
msgstr "Estat"
|
msgstr "Estat"
|
||||||
|
|
||||||
msgctxt "field:contract,until:"
|
|
||||||
msgid "Until Date"
|
|
||||||
msgstr "Fins a la data"
|
|
||||||
|
|
||||||
msgctxt "field:contract,until_date:"
|
|
||||||
msgid "Is Date"
|
|
||||||
msgstr "Es una data"
|
|
||||||
|
|
||||||
msgctxt "field:contract,wkst:"
|
|
||||||
msgid "Week Day"
|
|
||||||
msgstr "Dia de la setmana"
|
|
||||||
|
|
||||||
msgctxt "field:contract,write_date:"
|
msgctxt "field:contract,write_date:"
|
||||||
msgid "Write Date"
|
msgid "Write Date"
|
||||||
msgstr "Data modificació"
|
msgstr "Data modificació"
|
||||||
|
@ -326,10 +182,6 @@ msgctxt "field:contract.line,description:"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
msgctxt "field:contract.line,end_date:"
|
|
||||||
msgid "End Date"
|
|
||||||
msgstr "Data final"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,id:"
|
msgctxt "field:contract.line,id:"
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
@ -350,14 +202,6 @@ msgctxt "field:contract.line,service:"
|
||||||
msgid "Service"
|
msgid "Service"
|
||||||
msgstr "Serveis"
|
msgstr "Serveis"
|
||||||
|
|
||||||
msgctxt "field:contract.line,start_date:"
|
|
||||||
msgid "Start Date"
|
|
||||||
msgstr "Data inici"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,state:"
|
|
||||||
msgid "State"
|
|
||||||
msgstr "Estat"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,unit_price:"
|
msgctxt "field:contract.line,unit_price:"
|
||||||
msgid "Unit Price"
|
msgid "Unit Price"
|
||||||
msgstr "Preu unitat"
|
msgstr "Preu unitat"
|
||||||
|
@ -370,46 +214,6 @@ msgctxt "field:contract.line,write_uid:"
|
||||||
msgid "Write User"
|
msgid "Write User"
|
||||||
msgstr "Usuari modificació"
|
msgstr "Usuari modificació"
|
||||||
|
|
||||||
msgctxt "field:contract.service,byday:"
|
|
||||||
msgid "By Day"
|
|
||||||
msgstr "Per dia"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byhour:"
|
|
||||||
msgid "By Hour"
|
|
||||||
msgstr "Per hora"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byminute:"
|
|
||||||
msgid "By Minute"
|
|
||||||
msgstr "Per minut"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bymonth:"
|
|
||||||
msgid "By Month"
|
|
||||||
msgstr "Per mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bymonthday:"
|
|
||||||
msgid "By Month Day"
|
|
||||||
msgstr "Per dia del mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bysecond:"
|
|
||||||
msgid "By Second"
|
|
||||||
msgstr "Per segon"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bysetpos:"
|
|
||||||
msgid "By Position"
|
|
||||||
msgstr "Per ubicació"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byweekno:"
|
|
||||||
msgid "By Week Number"
|
|
||||||
msgstr "Per número de la setmana"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byyearday:"
|
|
||||||
msgid "By Year Day"
|
|
||||||
msgstr "Per dia de l'any"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,count:"
|
|
||||||
msgid "Count"
|
|
||||||
msgstr "Comptador"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,create_date:"
|
msgctxt "field:contract.service,create_date:"
|
||||||
msgid "Create Date"
|
msgid "Create Date"
|
||||||
msgstr "Data creació"
|
msgstr "Data creació"
|
||||||
|
@ -438,18 +242,6 @@ msgctxt "field:contract.service,rec_name:"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
msgctxt "field:contract.service,until:"
|
|
||||||
msgid "Until Date"
|
|
||||||
msgstr "Fins a la data"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,until_date:"
|
|
||||||
msgid "Is Date"
|
|
||||||
msgstr "Es una data"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,wkst:"
|
|
||||||
msgid "Week Day"
|
|
||||||
msgstr "Dia de la setmana"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,write_date:"
|
msgctxt "field:contract.service,write_date:"
|
||||||
msgid "Write Date"
|
msgid "Write Date"
|
||||||
msgstr "Data modificació"
|
msgstr "Data modificació"
|
||||||
|
@ -458,16 +250,6 @@ msgctxt "field:contract.service,write_uid:"
|
||||||
msgid "Write User"
|
msgid "Write User"
|
||||||
msgstr "Usuari modificació"
|
msgstr "Usuari modificació"
|
||||||
|
|
||||||
msgctxt "help:contract,until_date:"
|
|
||||||
msgid "Ignore time of field \"Until Date\", but handle as date only."
|
|
||||||
msgstr ""
|
|
||||||
"Ignora la hora del camp \"Fins a la data\", però utilitza com a única data."
|
|
||||||
|
|
||||||
msgctxt "help:contract.service,until_date:"
|
|
||||||
msgid "Ignore time of field \"Until Date\", but handle as date only."
|
|
||||||
msgstr ""
|
|
||||||
"Ignora la hora del camp \"Fins a la data\", però utilitza com a única data."
|
|
||||||
|
|
||||||
msgctxt "model:contract,name:"
|
msgctxt "model:contract,name:"
|
||||||
msgid "Contract"
|
msgid "Contract"
|
||||||
msgstr "Contracte"
|
msgstr "Contracte"
|
||||||
|
@ -497,7 +279,7 @@ msgid "Contract"
|
||||||
msgstr "Contractes"
|
msgstr "Contractes"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_configuration_form"
|
msgctxt "model:ir.action,name:act_contract_configuration_form"
|
||||||
msgid "Contract Configuration"
|
msgid "Contracts Configuration"
|
||||||
msgstr "Configuració de contractes"
|
msgstr "Configuració de contractes"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_consumption"
|
msgctxt "model:ir.action,name:act_contract_consumption"
|
||||||
|
@ -509,7 +291,7 @@ msgid "Contract Line"
|
||||||
msgstr "Línia de contracte"
|
msgstr "Línia de contracte"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_service"
|
msgctxt "model:ir.action,name:act_contract_service"
|
||||||
msgid "Services"
|
msgid "Contract Service"
|
||||||
msgstr "Servei de contracte"
|
msgstr "Servei de contracte"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:wizard_create_consumptions"
|
msgctxt "model:ir.action,name:wizard_create_consumptions"
|
||||||
|
@ -555,7 +337,7 @@ msgid "Contract"
|
||||||
msgstr "Contracte"
|
msgstr "Contracte"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_configuration"
|
msgctxt "model:ir.ui.menu,name:menu_contract_configuration"
|
||||||
msgid "Contract Configuration"
|
msgid "Contracts Configuration"
|
||||||
msgstr "Configuració de contractes"
|
msgstr "Configuració de contractes"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_consumption"
|
msgctxt "model:ir.ui.menu,name:menu_contract_consumption"
|
||||||
|
@ -567,7 +349,7 @@ msgid "Contract"
|
||||||
msgstr "Contracte"
|
msgstr "Contracte"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_service"
|
msgctxt "model:ir.ui.menu,name:menu_contract_service"
|
||||||
msgid "Services"
|
msgid "Contract Service"
|
||||||
msgstr "Servei de contracte"
|
msgstr "Servei de contracte"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_create_consumptions"
|
msgctxt "model:ir.ui.menu,name:menu_create_consumptions"
|
||||||
|
@ -575,33 +357,21 @@ msgid "Create Consumptions"
|
||||||
msgstr "Crea consums"
|
msgstr "Crea consums"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_contract"
|
msgctxt "model:res.group,name:group_contract"
|
||||||
msgid "Contract User"
|
msgid "Contract"
|
||||||
msgstr "Contractes"
|
msgstr "Contractes"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_contract_admin"
|
msgctxt "model:res.group,name:group_contract_admin"
|
||||||
msgid "Contract Administrator"
|
msgid "Contract Administration"
|
||||||
msgstr "Administració de contractes"
|
msgstr "Administració de contractes"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Diàriament"
|
msgstr "Diàriament"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
|
||||||
msgid "Hourly"
|
|
||||||
msgstr "Cada hora"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
|
||||||
msgid "Minutely"
|
|
||||||
msgstr "Cada minut"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensualment"
|
msgstr "Mensualment"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
|
||||||
msgid "Secondly"
|
|
||||||
msgstr "Cada segon"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Weekly"
|
msgid "Weekly"
|
||||||
msgstr "Setmanalment"
|
msgstr "Setmanalment"
|
||||||
|
@ -622,70 +392,14 @@ msgctxt "selection:contract,state:"
|
||||||
msgid "Validated"
|
msgid "Validated"
|
||||||
msgstr "Validat"
|
msgstr "Validat"
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid ""
|
|
||||||
msgstr " "
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Friday"
|
|
||||||
msgstr "Divendres"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Monday"
|
|
||||||
msgstr "Dilluns"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Saturday"
|
|
||||||
msgstr "Dissabte"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Sunday"
|
|
||||||
msgstr "Diumenge"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Thursday"
|
|
||||||
msgstr "Dijous"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Tuesday"
|
|
||||||
msgstr "Dimarts"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Wednesday"
|
|
||||||
msgstr "Dimecres"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Active"
|
|
||||||
msgstr "Actiu"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Draft"
|
|
||||||
msgstr "Esborrany"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Hold"
|
|
||||||
msgstr "En espera"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Diàriament"
|
msgstr "Diàriament"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
|
||||||
msgid "Hourly"
|
|
||||||
msgstr "Cada hora"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
|
||||||
msgid "Minutely"
|
|
||||||
msgstr "Cada minut"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensualment"
|
msgstr "Mensualment"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
|
||||||
msgid "Secondly"
|
|
||||||
msgstr "Cada segon"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Weekly"
|
msgid "Weekly"
|
||||||
msgstr "Setmanalment"
|
msgstr "Setmanalment"
|
||||||
|
@ -694,38 +408,6 @@ msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Yearly"
|
msgid "Yearly"
|
||||||
msgstr "Anualment"
|
msgstr "Anualment"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid ""
|
|
||||||
msgstr " "
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Friday"
|
|
||||||
msgstr "Divendres"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Monday"
|
|
||||||
msgstr "Dilluns"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Saturday"
|
|
||||||
msgstr "Dissabte"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Sunday"
|
|
||||||
msgstr "Diumenge"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Thursday"
|
|
||||||
msgstr "Dijous"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Tuesday"
|
|
||||||
msgstr "Dimarts"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Wednesday"
|
|
||||||
msgstr "Dimecres"
|
|
||||||
|
|
||||||
msgctxt "view:contract.configuration:"
|
msgctxt "view:contract.configuration:"
|
||||||
msgid "Contract Configuration"
|
msgid "Contract Configuration"
|
||||||
msgstr "Configuració de contractes"
|
msgstr "Configuració de contractes"
|
||||||
|
|
348
locale/es_ES.po
348
locale/es_ES.po
|
@ -18,146 +18,14 @@ msgstr ""
|
||||||
"Falta la cuenta de ingresos par el producto \"%(product)s\" de la linea de "
|
"Falta la cuenta de ingresos par el producto \"%(product)s\" de la linea de "
|
||||||
"contracto \"%(contract_line)s\"."
|
"contracto \"%(contract_line)s\"."
|
||||||
|
|
||||||
msgctxt "error:contract.line:"
|
|
||||||
msgid "Line \"%(line)s\" is outside its contract \"%(contract)s\" period"
|
|
||||||
msgstr "La línea \"%(line)s\" esta fuera del período de su contrato \"%(contract)s\"."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por dia\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Hour\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por hora\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Minute\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por minuto\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Month Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por día del mes\" de la regla de recurrencia \"%s\" no es "
|
|
||||||
"correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Month\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por mes\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Position\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por ubicación\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Second\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por segundo\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Week Number\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por número de la semana\" de la regla de recurrencia \"%s\" no es"
|
|
||||||
" correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Invalid \"By Year Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por día del año\" de la regla de recurrencia \"%s\" no es "
|
|
||||||
"correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract.service:"
|
|
||||||
msgid "Only one of \"until\" and \"count\" can be set."
|
|
||||||
msgstr "Define un \"hasta\" y un \"contador\"."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
msgctxt "error:contract:"
|
||||||
msgid "Invalid \"By Day\" in recurrence rule \"%s\""
|
msgid "Contract %(contract)s with invalid date \"%(date)s\""
|
||||||
msgstr "El campo \"por dia\" de la regla de recurrencia \"%s\" no es correcto."
|
msgstr "El contracto %(contract)s tiene fecha de comienzo inválida \"%(date)s\""
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Hour\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por hora\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Minute\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por minuto\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Month Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por día del mes\" de la regla de recurrencia \"%s\" no es "
|
|
||||||
"correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Month\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por mes\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Position\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por ubicación\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Second\" in recurrence rule \"%s\""
|
|
||||||
msgstr "El campo \"por segundo\" de la regla de recurrencia \"%s\" no es correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Week Number\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por número de la semana\" de la regla de recurrencia \"%s\" no es"
|
|
||||||
" correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Invalid \"By Year Day\" in recurrence rule \"%s\""
|
|
||||||
msgstr ""
|
|
||||||
"El campo \"por día del año\" de la regla de recurrencia \"%s\" no es "
|
|
||||||
"correcto."
|
|
||||||
|
|
||||||
msgctxt "error:contract:"
|
|
||||||
msgid "Only one of \"until\" and \"count\" can be set."
|
|
||||||
msgstr "Define un \"hasta\" y un \"contador\"."
|
|
||||||
|
|
||||||
msgctxt "field:contract,byday:"
|
|
||||||
msgid "By Day"
|
|
||||||
msgstr "Por día"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byhour:"
|
|
||||||
msgid "By Hour"
|
|
||||||
msgstr "Por hora"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byminute:"
|
|
||||||
msgid "By Minute"
|
|
||||||
msgstr "Por minuto"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bymonth:"
|
|
||||||
msgid "By Month"
|
|
||||||
msgstr "Por mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bymonthday:"
|
|
||||||
msgid "By Month Day"
|
|
||||||
msgstr "Por día del mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bysecond:"
|
|
||||||
msgid "By Second"
|
|
||||||
msgstr "Por segundo"
|
|
||||||
|
|
||||||
msgctxt "field:contract,bysetpos:"
|
|
||||||
msgid "By Position"
|
|
||||||
msgstr "Por ubicación"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byweekno:"
|
|
||||||
msgid "By Week Number"
|
|
||||||
msgstr "Por número de la semana"
|
|
||||||
|
|
||||||
msgctxt "field:contract,byyearday:"
|
|
||||||
msgid "By Year Day"
|
|
||||||
msgstr "Por día del año"
|
|
||||||
|
|
||||||
msgctxt "field:contract,company:"
|
msgctxt "field:contract,company:"
|
||||||
msgid "Company"
|
msgid "Company"
|
||||||
msgstr "Empresa"
|
msgstr "Empresa"
|
||||||
|
|
||||||
msgctxt "field:contract,count:"
|
|
||||||
msgid "Count"
|
|
||||||
msgstr "Contador"
|
|
||||||
|
|
||||||
msgctxt "field:contract,create_date:"
|
msgctxt "field:contract,create_date:"
|
||||||
msgid "Create Date"
|
msgid "Create Date"
|
||||||
msgstr "Fecha creación"
|
msgstr "Fecha creación"
|
||||||
|
@ -210,22 +78,14 @@ msgctxt "field:contract,start_date:"
|
||||||
msgid "Start Date"
|
msgid "Start Date"
|
||||||
msgstr "Fecha inicial"
|
msgstr "Fecha inicial"
|
||||||
|
|
||||||
|
msgctxt "field:contract,start_period_date:"
|
||||||
|
msgid "Start Period Date"
|
||||||
|
msgstr "Fecha inicio de período"
|
||||||
|
|
||||||
msgctxt "field:contract,state:"
|
msgctxt "field:contract,state:"
|
||||||
msgid "State"
|
msgid "State"
|
||||||
msgstr "Estado"
|
msgstr "Estado"
|
||||||
|
|
||||||
msgctxt "field:contract,until:"
|
|
||||||
msgid "Until Date"
|
|
||||||
msgstr "Hasta la fecha"
|
|
||||||
|
|
||||||
msgctxt "field:contract,until_date:"
|
|
||||||
msgid "Is Date"
|
|
||||||
msgstr "Es una fecha"
|
|
||||||
|
|
||||||
msgctxt "field:contract,wkst:"
|
|
||||||
msgid "Week Day"
|
|
||||||
msgstr "Día de la semana"
|
|
||||||
|
|
||||||
msgctxt "field:contract,write_date:"
|
msgctxt "field:contract,write_date:"
|
||||||
msgid "Write Date"
|
msgid "Write Date"
|
||||||
msgstr "Fecha modificación"
|
msgstr "Fecha modificación"
|
||||||
|
@ -278,10 +138,18 @@ msgctxt "field:contract.consumption,end_date:"
|
||||||
msgid "End Date"
|
msgid "End Date"
|
||||||
msgstr "Fecha finalización"
|
msgstr "Fecha finalización"
|
||||||
|
|
||||||
|
msgctxt "field:contract.consumption,end_period_date:"
|
||||||
|
msgid "Finish Period Date"
|
||||||
|
msgstr "Fecha final de período"
|
||||||
|
|
||||||
msgctxt "field:contract.consumption,id:"
|
msgctxt "field:contract.consumption,id:"
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
|
msgctxt "field:contract.consumption,init_period_date:"
|
||||||
|
msgid "Start Period Date"
|
||||||
|
msgstr "Fecha inicio de período"
|
||||||
|
|
||||||
msgctxt "field:contract.consumption,invoice_date:"
|
msgctxt "field:contract.consumption,invoice_date:"
|
||||||
msgid "Invoice Date"
|
msgid "Invoice Date"
|
||||||
msgstr "Fecha factura"
|
msgstr "Fecha factura"
|
||||||
|
@ -330,10 +198,6 @@ msgctxt "field:contract.line,description:"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripción"
|
msgstr "Descripción"
|
||||||
|
|
||||||
msgctxt "field:contract.line,end_date:"
|
|
||||||
msgid "End Date"
|
|
||||||
msgstr "Fecha final"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,id:"
|
msgctxt "field:contract.line,id:"
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
@ -342,6 +206,10 @@ msgctxt "field:contract.line,last_consumption_date:"
|
||||||
msgid "Last Consumption Date"
|
msgid "Last Consumption Date"
|
||||||
msgstr "Fecha último consumo"
|
msgstr "Fecha último consumo"
|
||||||
|
|
||||||
|
msgctxt "field:contract.line,last_consumption_invoice_date:"
|
||||||
|
msgid "Last Consumption Date"
|
||||||
|
msgstr "Fecha último consumo"
|
||||||
|
|
||||||
msgctxt "field:contract.line,name:"
|
msgctxt "field:contract.line,name:"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
@ -354,14 +222,6 @@ msgctxt "field:contract.line,service:"
|
||||||
msgid "Service"
|
msgid "Service"
|
||||||
msgstr "Servicios"
|
msgstr "Servicios"
|
||||||
|
|
||||||
msgctxt "field:contract.line,start_date:"
|
|
||||||
msgid "Start Date"
|
|
||||||
msgstr "Fecha inicial"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,state:"
|
|
||||||
msgid "State"
|
|
||||||
msgstr "Estado"
|
|
||||||
|
|
||||||
msgctxt "field:contract.line,unit_price:"
|
msgctxt "field:contract.line,unit_price:"
|
||||||
msgid "Unit Price"
|
msgid "Unit Price"
|
||||||
msgstr "Precio unidad"
|
msgstr "Precio unidad"
|
||||||
|
@ -374,46 +234,6 @@ msgctxt "field:contract.line,write_uid:"
|
||||||
msgid "Write User"
|
msgid "Write User"
|
||||||
msgstr "Usuario modificación"
|
msgstr "Usuario modificación"
|
||||||
|
|
||||||
msgctxt "field:contract.service,byday:"
|
|
||||||
msgid "By Day"
|
|
||||||
msgstr "Por día"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byhour:"
|
|
||||||
msgid "By Hour"
|
|
||||||
msgstr "Por hora"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byminute:"
|
|
||||||
msgid "By Minute"
|
|
||||||
msgstr "Por minuto"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bymonth:"
|
|
||||||
msgid "By Month"
|
|
||||||
msgstr "Por mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bymonthday:"
|
|
||||||
msgid "By Month Day"
|
|
||||||
msgstr "Por día del mes"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bysecond:"
|
|
||||||
msgid "By Second"
|
|
||||||
msgstr "Por segundo"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,bysetpos:"
|
|
||||||
msgid "By Position"
|
|
||||||
msgstr "Por ubicación"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byweekno:"
|
|
||||||
msgid "By Week Number"
|
|
||||||
msgstr "Por número de la semana"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,byyearday:"
|
|
||||||
msgid "By Year Day"
|
|
||||||
msgstr "Por día del año"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,count:"
|
|
||||||
msgid "Count"
|
|
||||||
msgstr "Contador"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,create_date:"
|
msgctxt "field:contract.service,create_date:"
|
||||||
msgid "Create Date"
|
msgid "Create Date"
|
||||||
msgstr "Fecha creación"
|
msgstr "Fecha creación"
|
||||||
|
@ -442,18 +262,6 @@ msgctxt "field:contract.service,rec_name:"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
msgctxt "field:contract.service,until:"
|
|
||||||
msgid "Until Date"
|
|
||||||
msgstr "Hasta la fecha"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,until_date:"
|
|
||||||
msgid "Is Date"
|
|
||||||
msgstr "Es una fecha"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,wkst:"
|
|
||||||
msgid "Week Day"
|
|
||||||
msgstr "Día de la semana"
|
|
||||||
|
|
||||||
msgctxt "field:contract.service,write_date:"
|
msgctxt "field:contract.service,write_date:"
|
||||||
msgid "Write Date"
|
msgid "Write Date"
|
||||||
msgstr "Fecha modificación"
|
msgstr "Fecha modificación"
|
||||||
|
@ -462,14 +270,6 @@ msgctxt "field:contract.service,write_uid:"
|
||||||
msgid "Write User"
|
msgid "Write User"
|
||||||
msgstr "Usuario modificación"
|
msgstr "Usuario modificación"
|
||||||
|
|
||||||
msgctxt "help:contract,until_date:"
|
|
||||||
msgid "Ignore time of field \"Until Date\", but handle as date only."
|
|
||||||
msgstr "Ignora la hora del campo \"Hasta la fecha\", pero usar como única fecha."
|
|
||||||
|
|
||||||
msgctxt "help:contract.service,until_date:"
|
|
||||||
msgid "Ignore time of field \"Until Date\", but handle as date only."
|
|
||||||
msgstr "Ignora la hora del campo \"Hasta la fecha\", pero usar como única fecha."
|
|
||||||
|
|
||||||
msgctxt "model:contract,name:"
|
msgctxt "model:contract,name:"
|
||||||
msgid "Contract"
|
msgid "Contract"
|
||||||
msgstr "Contrato"
|
msgstr "Contrato"
|
||||||
|
@ -499,7 +299,7 @@ msgid "Contract"
|
||||||
msgstr "Contratos"
|
msgstr "Contratos"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_configuration_form"
|
msgctxt "model:ir.action,name:act_contract_configuration_form"
|
||||||
msgid "Contract Configuration"
|
msgid "Contracts Configuration"
|
||||||
msgstr "Configuración de contratos"
|
msgstr "Configuración de contratos"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_consumption"
|
msgctxt "model:ir.action,name:act_contract_consumption"
|
||||||
|
@ -511,7 +311,7 @@ msgid "Contract Line"
|
||||||
msgstr "Línea de contrato"
|
msgstr "Línea de contrato"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:act_contract_service"
|
msgctxt "model:ir.action,name:act_contract_service"
|
||||||
msgid "Services"
|
msgid "Contract Service"
|
||||||
msgstr "Servicio de contrato"
|
msgstr "Servicio de contrato"
|
||||||
|
|
||||||
msgctxt "model:ir.action,name:wizard_create_consumptions"
|
msgctxt "model:ir.action,name:wizard_create_consumptions"
|
||||||
|
@ -557,7 +357,7 @@ msgid "Contract"
|
||||||
msgstr "Contrato"
|
msgstr "Contrato"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_configuration"
|
msgctxt "model:ir.ui.menu,name:menu_contract_configuration"
|
||||||
msgid "Contract Configuration"
|
msgid "Contracts Configuration"
|
||||||
msgstr "Configuración de contratos"
|
msgstr "Configuración de contratos"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_consumption"
|
msgctxt "model:ir.ui.menu,name:menu_contract_consumption"
|
||||||
|
@ -569,7 +369,7 @@ msgid "Contract"
|
||||||
msgstr "Contratos"
|
msgstr "Contratos"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_contract_service"
|
msgctxt "model:ir.ui.menu,name:menu_contract_service"
|
||||||
msgid "Services"
|
msgid "Contract Service"
|
||||||
msgstr "Servicio de contrato"
|
msgstr "Servicio de contrato"
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_create_consumptions"
|
msgctxt "model:ir.ui.menu,name:menu_create_consumptions"
|
||||||
|
@ -577,32 +377,24 @@ msgid "Create Consumptions"
|
||||||
msgstr "Crear consumos"
|
msgstr "Crear consumos"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_contract"
|
msgctxt "model:res.group,name:group_contract"
|
||||||
msgid "Contract User"
|
msgid "Contract"
|
||||||
msgstr "Contratos"
|
msgstr "Contratos"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_contract_admin"
|
msgctxt "model:res.group,name:group_contract_admin"
|
||||||
msgid "Contract Administrator"
|
msgid "Contract Administration"
|
||||||
msgstr "Administración de contratos"
|
msgstr "Administración de contratos"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Diariamente"
|
msgstr "Diariamente"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
|
||||||
msgid "Hourly"
|
|
||||||
msgstr "Cada hora"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
|
||||||
msgid "Minutely"
|
|
||||||
msgstr "Cada minuto"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensualmente"
|
msgstr "Mensualmente"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Secondly"
|
msgid "None"
|
||||||
msgstr "Cada segundo"
|
msgstr "Ninguno"
|
||||||
|
|
||||||
msgctxt "selection:contract,freq:"
|
msgctxt "selection:contract,freq:"
|
||||||
msgid "Weekly"
|
msgid "Weekly"
|
||||||
|
@ -624,69 +416,17 @@ msgctxt "selection:contract,state:"
|
||||||
msgid "Validated"
|
msgid "Validated"
|
||||||
msgstr "Valido"
|
msgstr "Valido"
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Friday"
|
|
||||||
msgstr "Viernes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Monday"
|
|
||||||
msgstr "Lunes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Saturday"
|
|
||||||
msgstr "Sábado"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Sunday"
|
|
||||||
msgstr "Domingo"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Thursday"
|
|
||||||
msgstr "Jueves"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Tuesday"
|
|
||||||
msgstr "Martes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract,wkst:"
|
|
||||||
msgid "Wednesday"
|
|
||||||
msgstr "Miércoles"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Active"
|
|
||||||
msgstr "Activo"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Draft"
|
|
||||||
msgstr "Borrador"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.line,state:"
|
|
||||||
msgid "Hold"
|
|
||||||
msgstr "En espera"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Diariamente"
|
msgstr "Diariamente"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
|
||||||
msgid "Hourly"
|
|
||||||
msgstr "Cada hora"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
|
||||||
msgid "Minutely"
|
|
||||||
msgstr "Cada minuto"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensualmente"
|
msgstr "Mensualmente"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Secondly"
|
msgid "None"
|
||||||
msgstr "Cada segundo"
|
msgstr "Ninguno"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,freq:"
|
msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Weekly"
|
msgid "Weekly"
|
||||||
|
@ -696,38 +436,6 @@ msgctxt "selection:contract.service,freq:"
|
||||||
msgid "Yearly"
|
msgid "Yearly"
|
||||||
msgstr "Anualmente"
|
msgstr "Anualmente"
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Friday"
|
|
||||||
msgstr "Viernes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Monday"
|
|
||||||
msgstr "Lunes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Saturday"
|
|
||||||
msgstr "Sábado"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Sunday"
|
|
||||||
msgstr "Domingo"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Thursday"
|
|
||||||
msgstr "Jueves"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Tuesday"
|
|
||||||
msgstr "Martes"
|
|
||||||
|
|
||||||
msgctxt "selection:contract.service,wkst:"
|
|
||||||
msgid "Wednesday"
|
|
||||||
msgstr "Miércoles"
|
|
||||||
|
|
||||||
msgctxt "view:contract.configuration:"
|
msgctxt "view:contract.configuration:"
|
||||||
msgid "Contract Configuration"
|
msgid "Contract Configuration"
|
||||||
msgstr "Configuración de contratos"
|
msgstr "Configuración de contratos"
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -61,8 +61,8 @@ setup(name='%s_%s' % (PREFIX, MODULE),
|
||||||
'trytond.modules.%s.tests' % MODULE,
|
'trytond.modules.%s.tests' % MODULE,
|
||||||
],
|
],
|
||||||
package_data={
|
package_data={
|
||||||
'trytond.modules.%s' % MODULE: (info.get('xml', [])
|
'trytond.modules.%s' % MODULE: (info.get('xml', []) +
|
||||||
+ ['tryton.cfg', 'locale/*.po', 'tests/*.rst']),
|
['tryton.cfg', 'locale/*.po', 'tests/*.rst']),
|
||||||
},
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
================
|
=====================================
|
||||||
Contract Scenario
|
Monthly Contract, Full Month Scenario
|
||||||
================
|
=====================================
|
||||||
|
|
||||||
|
.. Define contract with monthly periodicity
|
||||||
|
.. Start date = Start Period Date = Invoce Date.
|
||||||
|
.. Create Consumptions.
|
||||||
|
.. Check consumptions dates.
|
||||||
|
.. Create Invoice.
|
||||||
|
.. Check Invoice Lines Amounts
|
||||||
|
.. Check Invoice Date.
|
||||||
|
|
||||||
Imports::
|
Imports::
|
||||||
>>> import datetime
|
>>> import datetime
|
||||||
|
@ -183,51 +191,50 @@ Create monthly service::
|
||||||
>>> Service = Model.get('contract.service')
|
>>> Service = Model.get('contract.service')
|
||||||
>>> service = Service()
|
>>> service = Service()
|
||||||
>>> service.product = product
|
>>> service.product = product
|
||||||
>>> service.freq = 'monthly'
|
>>> service.freq = None
|
||||||
>>> service.save()
|
>>> service.save()
|
||||||
|
|
||||||
|
|
||||||
Create a contract::
|
Create a contract::
|
||||||
|
|
||||||
>>> Contract = Model.get('contract')
|
>>> Contract = Model.get('contract')
|
||||||
>>> contract = Contract()
|
>>> contract = Contract()
|
||||||
>>> contract.party = party
|
>>> contract.party = party
|
||||||
>>> contract.start_date = today + relativedelta(day=1)
|
>>> contract.start_period_date = datetime.date(2015,01,01)
|
||||||
|
>>> contract.start_date = datetime.date(2015,01,01)
|
||||||
>>> contract.freq = 'monthly'
|
>>> contract.freq = 'monthly'
|
||||||
>>> line = contract.lines.new()
|
>>> line = contract.lines.new()
|
||||||
>>> line.start_date == today + relativedelta(day=1)
|
|
||||||
True
|
|
||||||
>>> line.service = service
|
>>> line.service = service
|
||||||
>>> line.unit_price
|
>>> line.unit_price
|
||||||
Decimal('40')
|
Decimal('40')
|
||||||
>>> contract.click('validate_contract')
|
>>> contract.click('validate_contract')
|
||||||
>>> contract.state
|
>>> contract.state
|
||||||
u'validated'
|
u'validated'
|
||||||
>>> contract_line, = contract.lines
|
>>> contract.save()
|
||||||
>>> contract_line.state
|
>>> contract.reload()
|
||||||
u'active'
|
|
||||||
|
|
||||||
Generate consumed lines::
|
Generate consumed lines::
|
||||||
|
|
||||||
>>> create_consumptions = Wizard('contract.create_consumptions')
|
>>> create_consumptions = Wizard('contract.create_consumptions')
|
||||||
>>> create_consumptions.form.date += relativedelta(months=1)
|
>>> create_consumptions.form.date = datetime.date(2015,02,01)
|
||||||
>>> create_consumptions.execute('create_consumptions')
|
>>> create_consumptions.execute('create_consumptions')
|
||||||
>>> Consumption = Model.get('contract.consumption')
|
>>> Consumption = Model.get('contract.consumption')
|
||||||
>>> consumption, = Consumption.find([])
|
>>> consumption, = Consumption.find([])
|
||||||
>>> consumption.contract_line == contract_line
|
>>> consumption.start_date == datetime.date(2015,01,01)
|
||||||
|
True
|
||||||
|
>>> consumption.end_date == datetime.date(2015,01,31)
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == datetime.date(2015,01,31)
|
||||||
True
|
True
|
||||||
>>> consumption.invoice_line
|
|
||||||
|
|
||||||
Generate invoice for consumed lines::
|
Generate invoice for consumed lines::
|
||||||
|
|
||||||
>>> consumption.invoice_date = datetime.date.today()
|
|
||||||
>>> consumption.click('invoice')
|
>>> consumption.click('invoice')
|
||||||
>>> invoice = consumption.invoice_line.invoice
|
>>> invoice = consumption.invoice_line.invoice
|
||||||
>>> invoice.type
|
>>> invoice.type
|
||||||
u'out_invoice'
|
u'out_invoice'
|
||||||
>>> invoice.party == party
|
>>> invoice.party == party
|
||||||
True
|
True
|
||||||
>>> invoice.invoice_date == datetime.date.today()
|
|
||||||
True
|
|
||||||
>>> invoice.untaxed_amount
|
>>> invoice.untaxed_amount
|
||||||
Decimal('40.00')
|
Decimal('40.00')
|
||||||
>>> invoice.tax_amount
|
>>> invoice.tax_amount
|
||||||
|
@ -236,5 +243,6 @@ Generate invoice for consumed lines::
|
||||||
Decimal('44.00')
|
Decimal('44.00')
|
||||||
>>> consumption.invoice_line.product == product
|
>>> consumption.invoice_line.product == product
|
||||||
True
|
True
|
||||||
|
>>> consumption.invoice_date == invoice.invoice_date
|
||||||
|
True
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
=====================================
|
||||||
|
Monthly Contract, Full Month Scenario
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
.. Define contract with monthly periodicity
|
||||||
|
.. Start date = Start Period Date = Invoce Date.
|
||||||
|
.. Create Consumptions.
|
||||||
|
.. Check consumptions dates.
|
||||||
|
.. Create Invoice.
|
||||||
|
.. Check Invoice Lines Amounts
|
||||||
|
.. Check Invoice Date.
|
||||||
|
|
||||||
|
Imports::
|
||||||
|
>>> import datetime
|
||||||
|
>>> from dateutil.relativedelta import relativedelta
|
||||||
|
>>> from decimal import Decimal
|
||||||
|
>>> from operator import attrgetter
|
||||||
|
>>> from proteus import config, Model, Wizard
|
||||||
|
>>> today = datetime.datetime.combine(datetime.date.today(),
|
||||||
|
... datetime.datetime.min.time())
|
||||||
|
>>> tomorrow = datetime.date.today() + relativedelta(days=1)
|
||||||
|
|
||||||
|
Create database::
|
||||||
|
|
||||||
|
>>> config = config.set_trytond()
|
||||||
|
>>> config.pool.test = True
|
||||||
|
|
||||||
|
Install account_invoice::
|
||||||
|
|
||||||
|
>>> Module = Model.get('ir.module.module')
|
||||||
|
>>> contract_module, = Module.find([('name', '=', 'contract')])
|
||||||
|
>>> Module.install([contract_module.id], config.context)
|
||||||
|
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||||
|
|
||||||
|
Create company::
|
||||||
|
|
||||||
|
>>> Currency = Model.get('currency.currency')
|
||||||
|
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||||
|
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||||
|
>>> if not currencies:
|
||||||
|
... currency = Currency(name='US Dollar', symbol=u'$', code='USD',
|
||||||
|
... rounding=Decimal('0.01'), mon_grouping='[]',
|
||||||
|
... mon_decimal_point='.')
|
||||||
|
... currency.save()
|
||||||
|
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||||
|
... rate=Decimal('1.0'), currency=currency).save()
|
||||||
|
... else:
|
||||||
|
... currency, = currencies
|
||||||
|
>>> Company = Model.get('company.company')
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> company_config = Wizard('company.company.config')
|
||||||
|
>>> company_config.execute('company')
|
||||||
|
>>> company = company_config.form
|
||||||
|
>>> party = Party(name='Dunder Mifflin')
|
||||||
|
>>> party.save()
|
||||||
|
>>> company.party = party
|
||||||
|
>>> company.currency = currency
|
||||||
|
>>> company_config.execute('add')
|
||||||
|
>>> company, = Company.find([])
|
||||||
|
|
||||||
|
Reload the context::
|
||||||
|
|
||||||
|
>>> User = Model.get('res.user')
|
||||||
|
>>> config._context = User.get_preferences(True, config.context)
|
||||||
|
|
||||||
|
Create fiscal year::
|
||||||
|
|
||||||
|
>>> FiscalYear = Model.get('account.fiscalyear')
|
||||||
|
>>> Sequence = Model.get('ir.sequence')
|
||||||
|
>>> SequenceStrict = Model.get('ir.sequence.strict')
|
||||||
|
>>> fiscalyear = FiscalYear(name=str(today.year))
|
||||||
|
>>> fiscalyear.start_date = today + relativedelta(month=1, day=1)
|
||||||
|
>>> fiscalyear.end_date = today + relativedelta(month=12, day=31)
|
||||||
|
>>> fiscalyear.company = company
|
||||||
|
>>> post_move_seq = Sequence(name=str(today.year), code='account.move',
|
||||||
|
... company=company)
|
||||||
|
>>> post_move_seq.save()
|
||||||
|
>>> fiscalyear.post_move_sequence = post_move_seq
|
||||||
|
>>> invoice_seq = SequenceStrict(name=str(today.year),
|
||||||
|
... code='account.invoice', company=company)
|
||||||
|
>>> invoice_seq.save()
|
||||||
|
>>> fiscalyear.out_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.out_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.save()
|
||||||
|
>>> FiscalYear.create_period([fiscalyear.id], config.context)
|
||||||
|
|
||||||
|
Create chart of accounts::
|
||||||
|
|
||||||
|
>>> AccountTemplate = Model.get('account.account.template')
|
||||||
|
>>> Account = Model.get('account.account')
|
||||||
|
>>> account_template, = AccountTemplate.find([('parent', '=', None)])
|
||||||
|
>>> create_chart = Wizard('account.create_chart')
|
||||||
|
>>> create_chart.execute('account')
|
||||||
|
>>> create_chart.form.account_template = account_template
|
||||||
|
>>> create_chart.form.company = company
|
||||||
|
>>> create_chart.execute('create_account')
|
||||||
|
>>> receivable, = Account.find([
|
||||||
|
... ('kind', '=', 'receivable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> payable, = Account.find([
|
||||||
|
... ('kind', '=', 'payable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> revenue, = Account.find([
|
||||||
|
... ('kind', '=', 'revenue'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> expense, = Account.find([
|
||||||
|
... ('kind', '=', 'expense'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> account_tax, = Account.find([
|
||||||
|
... ('kind', '=', 'other'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ('name', '=', 'Main Tax'),
|
||||||
|
... ])
|
||||||
|
>>> create_chart.form.account_receivable = receivable
|
||||||
|
>>> create_chart.form.account_payable = payable
|
||||||
|
>>> create_chart.execute('create_properties')
|
||||||
|
|
||||||
|
Create tax::
|
||||||
|
|
||||||
|
>>> TaxCode = Model.get('account.tax.code')
|
||||||
|
>>> Tax = Model.get('account.tax')
|
||||||
|
>>> tax = Tax()
|
||||||
|
>>> tax.name = 'Tax'
|
||||||
|
>>> tax.description = 'Tax'
|
||||||
|
>>> tax.type = 'percentage'
|
||||||
|
>>> tax.rate = Decimal('.10')
|
||||||
|
>>> tax.invoice_account = account_tax
|
||||||
|
>>> tax.credit_note_account = account_tax
|
||||||
|
>>> invoice_base_code = TaxCode(name='invoice base')
|
||||||
|
>>> invoice_base_code.save()
|
||||||
|
>>> tax.invoice_base_code = invoice_base_code
|
||||||
|
>>> invoice_tax_code = TaxCode(name='invoice tax')
|
||||||
|
>>> invoice_tax_code.save()
|
||||||
|
>>> tax.invoice_tax_code = invoice_tax_code
|
||||||
|
>>> credit_note_base_code = TaxCode(name='credit note base')
|
||||||
|
>>> credit_note_base_code.save()
|
||||||
|
>>> tax.credit_note_base_code = credit_note_base_code
|
||||||
|
>>> credit_note_tax_code = TaxCode(name='credit note tax')
|
||||||
|
>>> credit_note_tax_code.save()
|
||||||
|
>>> tax.credit_note_tax_code = credit_note_tax_code
|
||||||
|
>>> tax.save()
|
||||||
|
|
||||||
|
Create party::
|
||||||
|
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> party = Party(name='Party')
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create product::
|
||||||
|
|
||||||
|
>>> ProductUom = Model.get('product.uom')
|
||||||
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||||
|
>>> ProductTemplate = Model.get('product.template')
|
||||||
|
>>> Product = Model.get('product.product')
|
||||||
|
>>> product = Product()
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'product'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.type = 'service'
|
||||||
|
>>> template.list_price = Decimal('40')
|
||||||
|
>>> template.cost_price = Decimal('25')
|
||||||
|
>>> template.account_expense = expense
|
||||||
|
>>> template.account_revenue = revenue
|
||||||
|
>>> template.customer_taxes.append(tax)
|
||||||
|
>>> template.save()
|
||||||
|
>>> product.template = template
|
||||||
|
>>> product.save()
|
||||||
|
|
||||||
|
Create payment term::
|
||||||
|
|
||||||
|
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||||
|
>>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
|
||||||
|
>>> payment_term = PaymentTerm(name='Term')
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='percent', days=20,
|
||||||
|
... percentage=Decimal(50))
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='remainder', days=40)
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term.save()
|
||||||
|
>>> party.customer_payment_term = payment_term
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create monthly service::
|
||||||
|
|
||||||
|
>>> Service = Model.get('contract.service')
|
||||||
|
>>> service = Service()
|
||||||
|
>>> service.product = product
|
||||||
|
>>> service.freq = None
|
||||||
|
>>> service.save()
|
||||||
|
|
||||||
|
|
||||||
|
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.first_invoice_date = datetime.date(2015,02,05)
|
||||||
|
>>> contract.freq = 'monthly'
|
||||||
|
>>> line = contract.lines.new()
|
||||||
|
>>> line.service = service
|
||||||
|
>>> line.unit_price
|
||||||
|
Decimal('40')
|
||||||
|
>>> contract.click('validate_contract')
|
||||||
|
>>> contract.state
|
||||||
|
u'validated'
|
||||||
|
>>> contract.save()
|
||||||
|
>>> contract.reload()
|
||||||
|
|
||||||
|
Generate consumed lines::
|
||||||
|
|
||||||
|
>>> create_consumptions = Wizard('contract.create_consumptions')
|
||||||
|
>>> create_consumptions.form.date = datetime.date(2015,03,01)
|
||||||
|
>>> create_consumptions.execute('create_consumptions')
|
||||||
|
>>> Consumption = Model.get('contract.consumption')
|
||||||
|
>>> consumptions = Consumption.find([])
|
||||||
|
>>> consumption = consumptions[0]
|
||||||
|
>>> consumption.start_date == datetime.date(2015,01,01)
|
||||||
|
True
|
||||||
|
>>> consumption.end_date == datetime.date(2015,01,31)
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == datetime.date(2015,02,05)
|
||||||
|
True
|
||||||
|
>>> consumption1 = consumptions[1]
|
||||||
|
>>> consumption1.start_date == datetime.date(2015,02,01)
|
||||||
|
True
|
||||||
|
>>> consumption1.end_date == datetime.date(2015,02,28)
|
||||||
|
True
|
||||||
|
>>> consumption1.invoice_date == datetime.date(2015,03,05)
|
||||||
|
True
|
||||||
|
|
||||||
|
Generate invoice for consumed lines::
|
||||||
|
|
||||||
|
>>> consumption.click('invoice')
|
||||||
|
>>> invoice = consumption.invoice_line.invoice
|
||||||
|
>>> invoice.type
|
||||||
|
u'out_invoice'
|
||||||
|
>>> invoice.party == party
|
||||||
|
True
|
||||||
|
>>> invoice.untaxed_amount
|
||||||
|
Decimal('40.00')
|
||||||
|
>>> invoice.tax_amount
|
||||||
|
Decimal('4.00')
|
||||||
|
>>> invoice.total_amount
|
||||||
|
Decimal('44.00')
|
||||||
|
>>> consumption.invoice_line.product == product
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == invoice.invoice_date
|
||||||
|
True
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
=====================================
|
||||||
|
Monthly Contract, Full Month Scenario
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
.. Define contract with monthly periodicity
|
||||||
|
.. Start date = Start Period Date = Invoce Date.
|
||||||
|
.. Create Consumptions.
|
||||||
|
.. Check consumptions dates.
|
||||||
|
.. Create Invoice.
|
||||||
|
.. Check Invoice Lines Amounts
|
||||||
|
.. Check Invoice Date.
|
||||||
|
|
||||||
|
Imports::
|
||||||
|
>>> import datetime
|
||||||
|
>>> from dateutil.relativedelta import relativedelta
|
||||||
|
>>> from decimal import Decimal
|
||||||
|
>>> from operator import attrgetter
|
||||||
|
>>> from proteus import config, Model, Wizard
|
||||||
|
>>> today = datetime.datetime.combine(datetime.date.today(),
|
||||||
|
... datetime.datetime.min.time())
|
||||||
|
>>> tomorrow = datetime.date.today() + relativedelta(days=1)
|
||||||
|
|
||||||
|
Create database::
|
||||||
|
|
||||||
|
>>> config = config.set_trytond()
|
||||||
|
>>> config.pool.test = True
|
||||||
|
|
||||||
|
Install account_invoice::
|
||||||
|
|
||||||
|
>>> Module = Model.get('ir.module.module')
|
||||||
|
>>> contract_module, = Module.find([('name', '=', 'contract')])
|
||||||
|
>>> Module.install([contract_module.id], config.context)
|
||||||
|
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||||
|
|
||||||
|
Create company::
|
||||||
|
|
||||||
|
>>> Currency = Model.get('currency.currency')
|
||||||
|
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||||
|
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||||
|
>>> if not currencies:
|
||||||
|
... currency = Currency(name='US Dollar', symbol=u'$', code='USD',
|
||||||
|
... rounding=Decimal('0.01'), mon_grouping='[]',
|
||||||
|
... mon_decimal_point='.')
|
||||||
|
... currency.save()
|
||||||
|
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||||
|
... rate=Decimal('1.0'), currency=currency).save()
|
||||||
|
... else:
|
||||||
|
... currency, = currencies
|
||||||
|
>>> Company = Model.get('company.company')
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> company_config = Wizard('company.company.config')
|
||||||
|
>>> company_config.execute('company')
|
||||||
|
>>> company = company_config.form
|
||||||
|
>>> party = Party(name='Dunder Mifflin')
|
||||||
|
>>> party.save()
|
||||||
|
>>> company.party = party
|
||||||
|
>>> company.currency = currency
|
||||||
|
>>> company_config.execute('add')
|
||||||
|
>>> company, = Company.find([])
|
||||||
|
|
||||||
|
Reload the context::
|
||||||
|
|
||||||
|
>>> User = Model.get('res.user')
|
||||||
|
>>> config._context = User.get_preferences(True, config.context)
|
||||||
|
|
||||||
|
Create fiscal year::
|
||||||
|
|
||||||
|
>>> FiscalYear = Model.get('account.fiscalyear')
|
||||||
|
>>> Sequence = Model.get('ir.sequence')
|
||||||
|
>>> SequenceStrict = Model.get('ir.sequence.strict')
|
||||||
|
>>> fiscalyear = FiscalYear(name=str(today.year))
|
||||||
|
>>> fiscalyear.start_date = today + relativedelta(month=1, day=1)
|
||||||
|
>>> fiscalyear.end_date = today + relativedelta(month=12, day=31)
|
||||||
|
>>> fiscalyear.company = company
|
||||||
|
>>> post_move_seq = Sequence(name=str(today.year), code='account.move',
|
||||||
|
... company=company)
|
||||||
|
>>> post_move_seq.save()
|
||||||
|
>>> fiscalyear.post_move_sequence = post_move_seq
|
||||||
|
>>> invoice_seq = SequenceStrict(name=str(today.year),
|
||||||
|
... code='account.invoice', company=company)
|
||||||
|
>>> invoice_seq.save()
|
||||||
|
>>> fiscalyear.out_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.out_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.save()
|
||||||
|
>>> FiscalYear.create_period([fiscalyear.id], config.context)
|
||||||
|
|
||||||
|
Create chart of accounts::
|
||||||
|
|
||||||
|
>>> AccountTemplate = Model.get('account.account.template')
|
||||||
|
>>> Account = Model.get('account.account')
|
||||||
|
>>> account_template, = AccountTemplate.find([('parent', '=', None)])
|
||||||
|
>>> create_chart = Wizard('account.create_chart')
|
||||||
|
>>> create_chart.execute('account')
|
||||||
|
>>> create_chart.form.account_template = account_template
|
||||||
|
>>> create_chart.form.company = company
|
||||||
|
>>> create_chart.execute('create_account')
|
||||||
|
>>> receivable, = Account.find([
|
||||||
|
... ('kind', '=', 'receivable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> payable, = Account.find([
|
||||||
|
... ('kind', '=', 'payable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> revenue, = Account.find([
|
||||||
|
... ('kind', '=', 'revenue'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> expense, = Account.find([
|
||||||
|
... ('kind', '=', 'expense'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> account_tax, = Account.find([
|
||||||
|
... ('kind', '=', 'other'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ('name', '=', 'Main Tax'),
|
||||||
|
... ])
|
||||||
|
>>> create_chart.form.account_receivable = receivable
|
||||||
|
>>> create_chart.form.account_payable = payable
|
||||||
|
>>> create_chart.execute('create_properties')
|
||||||
|
|
||||||
|
Create tax::
|
||||||
|
|
||||||
|
>>> TaxCode = Model.get('account.tax.code')
|
||||||
|
>>> Tax = Model.get('account.tax')
|
||||||
|
>>> tax = Tax()
|
||||||
|
>>> tax.name = 'Tax'
|
||||||
|
>>> tax.description = 'Tax'
|
||||||
|
>>> tax.type = 'percentage'
|
||||||
|
>>> tax.rate = Decimal('.10')
|
||||||
|
>>> tax.invoice_account = account_tax
|
||||||
|
>>> tax.credit_note_account = account_tax
|
||||||
|
>>> invoice_base_code = TaxCode(name='invoice base')
|
||||||
|
>>> invoice_base_code.save()
|
||||||
|
>>> tax.invoice_base_code = invoice_base_code
|
||||||
|
>>> invoice_tax_code = TaxCode(name='invoice tax')
|
||||||
|
>>> invoice_tax_code.save()
|
||||||
|
>>> tax.invoice_tax_code = invoice_tax_code
|
||||||
|
>>> credit_note_base_code = TaxCode(name='credit note base')
|
||||||
|
>>> credit_note_base_code.save()
|
||||||
|
>>> tax.credit_note_base_code = credit_note_base_code
|
||||||
|
>>> credit_note_tax_code = TaxCode(name='credit note tax')
|
||||||
|
>>> credit_note_tax_code.save()
|
||||||
|
>>> tax.credit_note_tax_code = credit_note_tax_code
|
||||||
|
>>> tax.save()
|
||||||
|
|
||||||
|
Create party::
|
||||||
|
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> party = Party(name='Party')
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create product::
|
||||||
|
|
||||||
|
>>> ProductUom = Model.get('product.uom')
|
||||||
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||||
|
>>> ProductTemplate = Model.get('product.template')
|
||||||
|
>>> Product = Model.get('product.product')
|
||||||
|
>>> product = Product()
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'product'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.type = 'service'
|
||||||
|
>>> template.list_price = Decimal('40')
|
||||||
|
>>> template.cost_price = Decimal('25')
|
||||||
|
>>> template.account_expense = expense
|
||||||
|
>>> template.account_revenue = revenue
|
||||||
|
>>> template.customer_taxes.append(tax)
|
||||||
|
>>> template.save()
|
||||||
|
>>> product.template = template
|
||||||
|
>>> product.save()
|
||||||
|
|
||||||
|
Create payment term::
|
||||||
|
|
||||||
|
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||||
|
>>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
|
||||||
|
>>> payment_term = PaymentTerm(name='Term')
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='percent', days=20,
|
||||||
|
... percentage=Decimal(50))
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='remainder', days=40)
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term.save()
|
||||||
|
>>> party.customer_payment_term = payment_term
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create monthly service::
|
||||||
|
|
||||||
|
>>> Service = Model.get('contract.service')
|
||||||
|
>>> service = Service()
|
||||||
|
>>> service.product = product
|
||||||
|
>>> service.freq = None
|
||||||
|
>>> service.save()
|
||||||
|
|
||||||
|
|
||||||
|
Create a contract::
|
||||||
|
|
||||||
|
>>> Contract = Model.get('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.unit_price
|
||||||
|
Decimal('40')
|
||||||
|
>>> contract.click('validate_contract')
|
||||||
|
>>> contract.state
|
||||||
|
u'validated'
|
||||||
|
>>> contract.save()
|
||||||
|
>>> contract.reload()
|
||||||
|
|
||||||
|
Generate consumed lines::
|
||||||
|
|
||||||
|
>>> create_consumptions = Wizard('contract.create_consumptions')
|
||||||
|
>>> create_consumptions.form.date = datetime.date(2015,02,06)
|
||||||
|
>>> create_consumptions.execute('create_consumptions')
|
||||||
|
>>> Consumption = Model.get('contract.consumption')
|
||||||
|
>>> consumption, = Consumption.find([])
|
||||||
|
>>> consumption.start_date == datetime.date(2015,01,05)
|
||||||
|
True
|
||||||
|
>>> consumption.end_date == datetime.date(2015,02,04)
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == datetime.date(2015,02,04)
|
||||||
|
True
|
||||||
|
>>> consumption.init_period_date == datetime.date(2015,01,05)
|
||||||
|
True
|
||||||
|
>>> consumption.end_period_date == datetime.date(2015,02,04)
|
||||||
|
True
|
||||||
|
|
||||||
|
Generate invoice for consumed lines::
|
||||||
|
|
||||||
|
>>> consumption.click('invoice')
|
||||||
|
>>> invoice = consumption.invoice_line.invoice
|
||||||
|
>>> invoice.type
|
||||||
|
u'out_invoice'
|
||||||
|
>>> invoice.party == party
|
||||||
|
True
|
||||||
|
>>> invoice.untaxed_amount
|
||||||
|
Decimal('40.00')
|
||||||
|
>>> invoice.tax_amount
|
||||||
|
Decimal('4.00')
|
||||||
|
>>> invoice.total_amount
|
||||||
|
Decimal('44.00')
|
||||||
|
>>> consumption.invoice_line.product == product
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == invoice.invoice_date
|
||||||
|
True
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
=====================================
|
||||||
|
Monthly Contract, Full Month Scenario
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
.. Define contract with monthly periodicity
|
||||||
|
.. Start date = Start Period Date = Invoce Date.
|
||||||
|
.. Create Consumptions.
|
||||||
|
.. Check consumptions dates.
|
||||||
|
.. Create Invoice.
|
||||||
|
.. Check Invoice Lines Amounts
|
||||||
|
.. Check Invoice Date.
|
||||||
|
|
||||||
|
Imports::
|
||||||
|
>>> import datetime
|
||||||
|
>>> from dateutil.relativedelta import relativedelta
|
||||||
|
>>> from decimal import Decimal
|
||||||
|
>>> from operator import attrgetter
|
||||||
|
>>> from proteus import config, Model, Wizard
|
||||||
|
>>> today = datetime.datetime.combine(datetime.date.today(),
|
||||||
|
... datetime.datetime.min.time())
|
||||||
|
>>> tomorrow = datetime.date.today() + relativedelta(days=1)
|
||||||
|
|
||||||
|
Create database::
|
||||||
|
|
||||||
|
>>> config = config.set_trytond()
|
||||||
|
>>> config.pool.test = True
|
||||||
|
|
||||||
|
Install account_invoice::
|
||||||
|
|
||||||
|
>>> Module = Model.get('ir.module.module')
|
||||||
|
>>> contract_module, = Module.find([('name', '=', 'contract')])
|
||||||
|
>>> Module.install([contract_module.id], config.context)
|
||||||
|
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||||
|
|
||||||
|
Create company::
|
||||||
|
|
||||||
|
>>> Currency = Model.get('currency.currency')
|
||||||
|
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||||
|
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||||
|
>>> if not currencies:
|
||||||
|
... currency = Currency(name='US Dollar', symbol=u'$', code='USD',
|
||||||
|
... rounding=Decimal('0.01'), mon_grouping='[]',
|
||||||
|
... mon_decimal_point='.')
|
||||||
|
... currency.save()
|
||||||
|
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||||
|
... rate=Decimal('1.0'), currency=currency).save()
|
||||||
|
... else:
|
||||||
|
... currency, = currencies
|
||||||
|
>>> Company = Model.get('company.company')
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> company_config = Wizard('company.company.config')
|
||||||
|
>>> company_config.execute('company')
|
||||||
|
>>> company = company_config.form
|
||||||
|
>>> party = Party(name='Dunder Mifflin')
|
||||||
|
>>> party.save()
|
||||||
|
>>> company.party = party
|
||||||
|
>>> company.currency = currency
|
||||||
|
>>> company_config.execute('add')
|
||||||
|
>>> company, = Company.find([])
|
||||||
|
|
||||||
|
Reload the context::
|
||||||
|
|
||||||
|
>>> User = Model.get('res.user')
|
||||||
|
>>> config._context = User.get_preferences(True, config.context)
|
||||||
|
|
||||||
|
Create fiscal year::
|
||||||
|
|
||||||
|
>>> FiscalYear = Model.get('account.fiscalyear')
|
||||||
|
>>> Sequence = Model.get('ir.sequence')
|
||||||
|
>>> SequenceStrict = Model.get('ir.sequence.strict')
|
||||||
|
>>> fiscalyear = FiscalYear(name=str(today.year))
|
||||||
|
>>> fiscalyear.start_date = today + relativedelta(month=1, day=1)
|
||||||
|
>>> fiscalyear.end_date = today + relativedelta(month=12, day=31)
|
||||||
|
>>> fiscalyear.company = company
|
||||||
|
>>> post_move_seq = Sequence(name=str(today.year), code='account.move',
|
||||||
|
... company=company)
|
||||||
|
>>> post_move_seq.save()
|
||||||
|
>>> fiscalyear.post_move_sequence = post_move_seq
|
||||||
|
>>> invoice_seq = SequenceStrict(name=str(today.year),
|
||||||
|
... code='account.invoice', company=company)
|
||||||
|
>>> invoice_seq.save()
|
||||||
|
>>> fiscalyear.out_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_invoice_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.out_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.in_credit_note_sequence = invoice_seq
|
||||||
|
>>> fiscalyear.save()
|
||||||
|
>>> FiscalYear.create_period([fiscalyear.id], config.context)
|
||||||
|
|
||||||
|
Create chart of accounts::
|
||||||
|
|
||||||
|
>>> AccountTemplate = Model.get('account.account.template')
|
||||||
|
>>> Account = Model.get('account.account')
|
||||||
|
>>> account_template, = AccountTemplate.find([('parent', '=', None)])
|
||||||
|
>>> create_chart = Wizard('account.create_chart')
|
||||||
|
>>> create_chart.execute('account')
|
||||||
|
>>> create_chart.form.account_template = account_template
|
||||||
|
>>> create_chart.form.company = company
|
||||||
|
>>> create_chart.execute('create_account')
|
||||||
|
>>> receivable, = Account.find([
|
||||||
|
... ('kind', '=', 'receivable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> payable, = Account.find([
|
||||||
|
... ('kind', '=', 'payable'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> revenue, = Account.find([
|
||||||
|
... ('kind', '=', 'revenue'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> expense, = Account.find([
|
||||||
|
... ('kind', '=', 'expense'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ])
|
||||||
|
>>> account_tax, = Account.find([
|
||||||
|
... ('kind', '=', 'other'),
|
||||||
|
... ('company', '=', company.id),
|
||||||
|
... ('name', '=', 'Main Tax'),
|
||||||
|
... ])
|
||||||
|
>>> create_chart.form.account_receivable = receivable
|
||||||
|
>>> create_chart.form.account_payable = payable
|
||||||
|
>>> create_chart.execute('create_properties')
|
||||||
|
|
||||||
|
Create tax::
|
||||||
|
|
||||||
|
>>> TaxCode = Model.get('account.tax.code')
|
||||||
|
>>> Tax = Model.get('account.tax')
|
||||||
|
>>> tax = Tax()
|
||||||
|
>>> tax.name = 'Tax'
|
||||||
|
>>> tax.description = 'Tax'
|
||||||
|
>>> tax.type = 'percentage'
|
||||||
|
>>> tax.rate = Decimal('.10')
|
||||||
|
>>> tax.invoice_account = account_tax
|
||||||
|
>>> tax.credit_note_account = account_tax
|
||||||
|
>>> invoice_base_code = TaxCode(name='invoice base')
|
||||||
|
>>> invoice_base_code.save()
|
||||||
|
>>> tax.invoice_base_code = invoice_base_code
|
||||||
|
>>> invoice_tax_code = TaxCode(name='invoice tax')
|
||||||
|
>>> invoice_tax_code.save()
|
||||||
|
>>> tax.invoice_tax_code = invoice_tax_code
|
||||||
|
>>> credit_note_base_code = TaxCode(name='credit note base')
|
||||||
|
>>> credit_note_base_code.save()
|
||||||
|
>>> tax.credit_note_base_code = credit_note_base_code
|
||||||
|
>>> credit_note_tax_code = TaxCode(name='credit note tax')
|
||||||
|
>>> credit_note_tax_code.save()
|
||||||
|
>>> tax.credit_note_tax_code = credit_note_tax_code
|
||||||
|
>>> tax.save()
|
||||||
|
|
||||||
|
Create party::
|
||||||
|
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> party = Party(name='Party')
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create product::
|
||||||
|
|
||||||
|
>>> ProductUom = Model.get('product.uom')
|
||||||
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||||
|
>>> ProductTemplate = Model.get('product.template')
|
||||||
|
>>> Product = Model.get('product.product')
|
||||||
|
>>> product = Product()
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'product'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.type = 'service'
|
||||||
|
>>> template.list_price = Decimal('40')
|
||||||
|
>>> template.cost_price = Decimal('25')
|
||||||
|
>>> template.account_expense = expense
|
||||||
|
>>> template.account_revenue = revenue
|
||||||
|
>>> template.customer_taxes.append(tax)
|
||||||
|
>>> template.save()
|
||||||
|
>>> product.template = template
|
||||||
|
>>> product.save()
|
||||||
|
|
||||||
|
Create payment term::
|
||||||
|
|
||||||
|
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||||
|
>>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
|
||||||
|
>>> payment_term = PaymentTerm(name='Term')
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='percent', days=20,
|
||||||
|
... percentage=Decimal(50))
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='remainder', days=40)
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term.save()
|
||||||
|
>>> party.customer_payment_term = payment_term
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create monthly service::
|
||||||
|
|
||||||
|
>>> Service = Model.get('contract.service')
|
||||||
|
>>> service = Service()
|
||||||
|
>>> service.product = product
|
||||||
|
>>> service.freq = None
|
||||||
|
>>> service.save()
|
||||||
|
|
||||||
|
|
||||||
|
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.freq = 'monthly'
|
||||||
|
>>> line = contract.lines.new()
|
||||||
|
>>> line.service = service
|
||||||
|
>>> line.unit_price
|
||||||
|
Decimal('40')
|
||||||
|
>>> contract.click('validate_contract')
|
||||||
|
>>> contract.state
|
||||||
|
u'validated'
|
||||||
|
>>> contract.save()
|
||||||
|
>>> contract.reload()
|
||||||
|
|
||||||
|
Generate consumed lines::
|
||||||
|
|
||||||
|
>>> create_consumptions = Wizard('contract.create_consumptions')
|
||||||
|
>>> create_consumptions.form.date = datetime.date(2015,02,01)
|
||||||
|
>>> create_consumptions.execute('create_consumptions')
|
||||||
|
>>> Consumption = Model.get('contract.consumption')
|
||||||
|
>>> consumption, = Consumption.find([])
|
||||||
|
>>> consumption.start_date == datetime.date(2015,01,10)
|
||||||
|
True
|
||||||
|
>>> consumption.end_date == datetime.date(2015,01,31)
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == datetime.date(2015,01,31)
|
||||||
|
True
|
||||||
|
>>> consumption.init_period_date == datetime.date(2015,01,1)
|
||||||
|
True
|
||||||
|
>>> consumption.end_period_date == datetime.date(2015,01,31)
|
||||||
|
True
|
||||||
|
|
||||||
|
Generate invoice for consumed lines::
|
||||||
|
|
||||||
|
>>> consumption.click('invoice')
|
||||||
|
>>> invoice = consumption.invoice_line.invoice
|
||||||
|
>>> invoice.type
|
||||||
|
u'out_invoice'
|
||||||
|
>>> invoice.party == party
|
||||||
|
True
|
||||||
|
>>> invoice.untaxed_amount
|
||||||
|
Decimal('40.00')
|
||||||
|
>>> invoice.tax_amount
|
||||||
|
Decimal('4.00')
|
||||||
|
>>> invoice.total_amount
|
||||||
|
Decimal('44.00')
|
||||||
|
>>> consumption.invoice_line.product == product
|
||||||
|
True
|
||||||
|
>>> consumption.invoice_date == invoice.invoice_date
|
||||||
|
True
|
||||||
|
|
|
@ -26,7 +26,21 @@ def suite():
|
||||||
suite = trytond.tests.test_tryton.suite()
|
suite = trytond.tests.test_tryton.suite()
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
|
||||||
TestContractCase))
|
TestContractCase))
|
||||||
suite.addTests(doctest.DocFileSuite('scenario_contract.rst',
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_monthly_full_month_contract.rst',
|
||||||
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_monthly_start_in_month_contract.rst',
|
||||||
|
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||||
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_monthly_natural_days_contract.rst',
|
||||||
|
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||||
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_monthly_full_month_with_invoice_date_contract.rst',
|
||||||
|
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||||
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
|
||||||
return suite
|
return suite
|
||||||
|
|
|
@ -7,5 +7,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<field name="end_date"/>
|
<field name="end_date"/>
|
||||||
<field name="invoice_date"/>
|
<field name="invoice_date"/>
|
||||||
<field name="invoice_line"/>
|
<field name="invoice_line"/>
|
||||||
|
<field name="init_period_date"/>
|
||||||
|
<field name="end_period_date"/>
|
||||||
<button name="invoice" string="Invoice" tree_invisible="1"/>
|
<button name="invoice" string="Invoice" tree_invisible="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -10,50 +10,21 @@
|
||||||
<field name="party"/>
|
<field name="party"/>
|
||||||
<label name="currency"/>
|
<label name="currency"/>
|
||||||
<field name="currency"/>
|
<field name="currency"/>
|
||||||
|
<label name="start_period_date"/>
|
||||||
|
<field name="start_period_date"/>
|
||||||
|
<label name="first_invoice_date"/>
|
||||||
|
<field name="first_invoice_date"/>
|
||||||
<label name="start_date"/>
|
<label name="start_date"/>
|
||||||
<field name="start_date"/>
|
<field name="start_date"/>
|
||||||
<label name="end_date"/>
|
<label name="end_date"/>
|
||||||
<field name="end_date"/>
|
<field name="end_date"/>
|
||||||
<label name="first_invoice_date"/>
|
<separator id="recurrence" string="Invoice recurrence" colspan="4"/>
|
||||||
<field name="first_invoice_date"/>
|
<label name="freq"/>
|
||||||
<notebook>
|
<field name="freq"/>
|
||||||
<page id="recurrence" string="Invoice recurrence">
|
<label name="interval"/>
|
||||||
<label name="freq"/>
|
<field name="interval"/>
|
||||||
<field name="freq"/>
|
<newline/>
|
||||||
<label name="interval"/>
|
<field name="lines" colspan="4"/>
|
||||||
<field name="interval"/>
|
|
||||||
<label name="count"/>
|
|
||||||
<field name="count"/>
|
|
||||||
<newline/>
|
|
||||||
<label name="until"/>
|
|
||||||
<field name="until"/>
|
|
||||||
<label name="until_date"/>
|
|
||||||
<field name="until_date"/>
|
|
||||||
<label name="byday"/>
|
|
||||||
<field name="byday"/>
|
|
||||||
<label name="byhour"/>
|
|
||||||
<field name="byhour"/>
|
|
||||||
<label name="byminute"/>
|
|
||||||
<field name="byminute"/>
|
|
||||||
<label name="bymonth"/>
|
|
||||||
<field name="bymonth"/>
|
|
||||||
<label name="bymonthday"/>
|
|
||||||
<field name="bymonthday"/>
|
|
||||||
<label name="bysecond"/>
|
|
||||||
<field name="bysecond"/>
|
|
||||||
<label name="bysetpos"/>
|
|
||||||
<field name="bysetpos"/>
|
|
||||||
<label name="byweekno"/>
|
|
||||||
<field name="byweekno"/>
|
|
||||||
<label name="byyearday"/>
|
|
||||||
<field name="byyearday"/>
|
|
||||||
<label name="wkst"/>
|
|
||||||
<field name="wkst"/>
|
|
||||||
</page>
|
|
||||||
<page name="lines">
|
|
||||||
<field name="lines" colspan="4"/>
|
|
||||||
</page>
|
|
||||||
</notebook>
|
|
||||||
<label name="state"/>
|
<label name="state"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<group id="buttons" colspan="2">
|
<group id="buttons" colspan="2">
|
||||||
|
|
|
@ -10,16 +10,6 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<label name="unit_price"/>
|
<label name="unit_price"/>
|
||||||
<field name="unit_price"/>
|
<field name="unit_price"/>
|
||||||
<label name="start_date"/>
|
|
||||||
<field name="start_date"/>
|
|
||||||
<label name="end_date"/>
|
|
||||||
<field name="end_date"/>
|
|
||||||
<separator name="description" colspan="4"/>
|
<separator name="description" colspan="4"/>
|
||||||
<field name="description" colspan="4"/>
|
<field name="description" colspan="4"/>
|
||||||
<label name="state"/>
|
|
||||||
<field name="state"/>
|
|
||||||
<group id="buttons" colspan="2">
|
|
||||||
<button name="active" string="Active"/>
|
|
||||||
<button name="hold" string="Hold"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -4,8 +4,5 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<tree string="Contract Line">
|
<tree string="Contract Line">
|
||||||
<field name="contract"/>
|
<field name="contract"/>
|
||||||
<field name="service"/>
|
<field name="service"/>
|
||||||
<field name="start_date"/>
|
|
||||||
<field name="end_date"/>
|
|
||||||
<field name="unit_price"/>
|
<field name="unit_price"/>
|
||||||
<field name="state"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -9,31 +9,5 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<field name="freq"/>
|
<field name="freq"/>
|
||||||
<label name="interval"/>
|
<label name="interval"/>
|
||||||
<field name="interval"/>
|
<field name="interval"/>
|
||||||
<label name="count"/>
|
|
||||||
<field name="count"/>
|
|
||||||
<newline/>
|
<newline/>
|
||||||
<label name="until"/>
|
|
||||||
<field name="until"/>
|
|
||||||
<label name="until_date"/>
|
|
||||||
<field name="until_date"/>
|
|
||||||
<label name="byday"/>
|
|
||||||
<field name="byday"/>
|
|
||||||
<label name="byhour"/>
|
|
||||||
<field name="byhour"/>
|
|
||||||
<label name="byminute"/>
|
|
||||||
<field name="byminute"/>
|
|
||||||
<label name="bymonth"/>
|
|
||||||
<field name="bymonth"/>
|
|
||||||
<label name="bymonthday"/>
|
|
||||||
<field name="bymonthday"/>
|
|
||||||
<label name="bysecond"/>
|
|
||||||
<field name="bysecond"/>
|
|
||||||
<label name="bysetpos"/>
|
|
||||||
<field name="bysetpos"/>
|
|
||||||
<label name="byweekno"/>
|
|
||||||
<field name="byweekno"/>
|
|
||||||
<label name="byyearday"/>
|
|
||||||
<field name="byyearday"/>
|
|
||||||
<label name="wkst"/>
|
|
||||||
<field name="wkst"/>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -4,6 +4,4 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<tree string="Contract Line Service">
|
<tree string="Contract Line Service">
|
||||||
<field name="product"/>
|
<field name="product"/>
|
||||||
<field name="interval"/>
|
<field name="interval"/>
|
||||||
<field name="until"/>
|
|
||||||
<field name="count"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -10,4 +10,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<field name="interval"/>
|
<field name="interval"/>
|
||||||
<field name="freq"/>
|
<field name="freq"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
|
<button name="draft" string="Draft" tree_invisible="1"/>
|
||||||
|
<button name="validate_contract" string="Validate" tree_invisible="1"/>
|
||||||
|
<button name="cancel" string="Cancel" tree_invisible="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -4,36 +4,4 @@
|
||||||
<form string="Contract Service">
|
<form string="Contract Service">
|
||||||
<label name="product"/>
|
<label name="product"/>
|
||||||
<field name="product"/>
|
<field name="product"/>
|
||||||
<newline/>
|
|
||||||
<label name="freq"/>
|
|
||||||
<field name="freq"/>
|
|
||||||
<label name="interval"/>
|
|
||||||
<field name="interval"/>
|
|
||||||
<label name="count"/>
|
|
||||||
<field name="count"/>
|
|
||||||
<newline/>
|
|
||||||
<label name="until"/>
|
|
||||||
<field name="until"/>
|
|
||||||
<label name="until_date"/>
|
|
||||||
<field name="until_date"/>
|
|
||||||
<label name="byday"/>
|
|
||||||
<field name="byday"/>
|
|
||||||
<label name="byhour"/>
|
|
||||||
<field name="byhour"/>
|
|
||||||
<label name="byminute"/>
|
|
||||||
<field name="byminute"/>
|
|
||||||
<label name="bymonth"/>
|
|
||||||
<field name="bymonth"/>
|
|
||||||
<label name="bymonthday"/>
|
|
||||||
<field name="bymonthday"/>
|
|
||||||
<label name="bysecond"/>
|
|
||||||
<field name="bysecond"/>
|
|
||||||
<label name="bysetpos"/>
|
|
||||||
<field name="bysetpos"/>
|
|
||||||
<label name="byweekno"/>
|
|
||||||
<field name="byweekno"/>
|
|
||||||
<label name="byyearday"/>
|
|
||||||
<field name="byyearday"/>
|
|
||||||
<label name="wkst"/>
|
|
||||||
<field name="wkst"/>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -3,7 +3,4 @@
|
||||||
copyright notices and license terms. -->
|
copyright notices and license terms. -->
|
||||||
<tree string="Contract Service">
|
<tree string="Contract Service">
|
||||||
<field name="product"/>
|
<field name="product"/>
|
||||||
<field name="freq"/>
|
|
||||||
<field name="interval"/>
|
|
||||||
<field name="count"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
|
|
Loading…
Reference in New Issue