Files
tryton/work.py
T

637 lines
23 KiB
Python
Raw Normal View History

2014-12-02 12:55:43 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
2018-06-26 19:11:51 +02:00
2015-02-09 23:02:03 +01:00
2013-03-22 17:59:00 +01:00
from itertools import groupby
2015-09-17 11:21:05 +02:00
from collections import defaultdict
2013-03-22 17:59:00 +01:00
from decimal import Decimal
2015-02-09 23:02:03 +01:00
import datetime
from sql import Null
2013-09-06 22:34:32 +02:00
from sql.aggregate import Sum
2016-06-24 09:30:32 +02:00
from sql.operators import Concat
2013-03-22 17:59:00 +01:00
2018-12-29 14:20:29 +01:00
from trytond.i18n import gettext
2015-09-24 15:59:43 +02:00
from trytond.model import ModelSQL, ModelView, fields
2013-03-22 17:59:00 +01:00
from trytond.pool import PoolMeta
from trytond.pyson import Eval, Bool, PYSONEncoder
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateAction
2014-07-17 18:59:24 +02:00
from trytond.tools import reduce_ids, grouped_slice
2013-03-22 17:59:00 +01:00
2018-12-29 14:20:29 +01:00
from .exceptions import InvoicingError
2013-03-22 17:59:00 +01:00
2015-09-24 15:59:43 +02:00
__all__ = ['Work', 'WorkInvoicedProgress', 'OpenInvoice']
2013-03-22 17:59:00 +01:00
INVOICE_METHODS = [
('manual', 'Manual'),
('effort', 'On Effort'),
2015-09-24 15:59:43 +02:00
('progress', 'On Progress'),
2013-03-22 17:59:00 +01:00
('timesheet', 'On Timesheet'),
]
2018-06-26 19:11:51 +02:00
class Work(metaclass=PoolMeta):
2013-03-22 17:59:00 +01:00
__name__ = 'project.work'
project_invoice_method = fields.Selection(INVOICE_METHODS,
'Invoice Method',
states={
2015-02-09 23:02:03 +01:00
'readonly': Bool(Eval('invoiced_duration')),
2013-03-22 17:59:00 +01:00
'required': Eval('type') == 'project',
'invisible': Eval('type') != 'project',
},
2015-02-09 23:02:03 +01:00
depends=['invoiced_duration', 'type'])
2013-03-22 17:59:00 +01:00
invoice_method = fields.Function(fields.Selection(INVOICE_METHODS,
'Invoice Method'), 'on_change_with_invoice_method')
2015-02-09 23:02:03 +01:00
invoiced_duration = fields.Function(fields.TimeDelta('Invoiced Duration',
'company_work_time',
2013-03-22 17:59:00 +01:00
states={
'invisible': Eval('invoice_method') == 'manual',
},
2015-09-17 11:21:05 +02:00
depends=['invoice_method']), 'get_total')
2015-02-09 23:02:03 +01:00
duration_to_invoice = fields.Function(fields.TimeDelta(
'Duration to Invoice', 'company_work_time',
2013-03-22 17:59:00 +01:00
states={
'invisible': Eval('invoice_method') == 'manual',
},
2015-09-17 11:21:05 +02:00
depends=['invoice_method']), 'get_total')
2013-03-22 17:59:00 +01:00
invoiced_amount = fields.Function(fields.Numeric('Invoiced Amount',
digits=(16, Eval('currency_digits', 2)),
states={
'invisible': Eval('invoice_method') == 'manual',
},
depends=['currency_digits', 'invoice_method']),
2015-09-17 11:21:05 +02:00
'get_total')
2013-03-22 17:59:00 +01:00
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line',
readonly=True)
2015-09-24 15:59:43 +02:00
invoiced_progress = fields.One2Many('project.work.invoiced_progress',
'work', 'Invoiced Progress', readonly=True)
2013-03-22 17:59:00 +01:00
@classmethod
def __setup__(cls):
super(Work, cls).__setup__()
cls._buttons.update({
'invoice': {
'invisible': ((Eval('type') != 'project')
| (Eval('project_invoice_method', 'manual')
== 'manual')),
2015-02-09 23:02:03 +01:00
'readonly': ~Eval('duration_to_invoice'),
2018-02-19 11:39:25 +01:00
'depends': ['type', 'project_invoice_method',
'duration_to_invoice']
2013-03-22 17:59:00 +01:00
},
})
@staticmethod
def default_project_invoice_method():
return 'manual'
@classmethod
def copy(cls, records, default=None):
if default is None:
default = {}
2018-09-01 01:02:03 +02:00
else:
default = default.copy()
2013-03-22 17:59:00 +01:00
default.setdefault('invoice_line', None)
return super(Work, cls).copy(records, default=default)
@fields.depends('type', 'project_invoice_method',
'parent', '_parent_parent.invoice_method')
def on_change_with_invoice_method(self, name=None):
2013-03-22 17:59:00 +01:00
if self.type == 'project':
return self.project_invoice_method
elif self.parent:
2013-03-22 17:59:00 +01:00
return self.parent.invoice_method
else:
return 'manual'
2013-03-22 17:59:00 +01:00
@staticmethod
2015-02-09 23:02:03 +01:00
def default_invoiced_duration():
return datetime.timedelta()
@staticmethod
def _get_invoiced_duration_manual(works):
2013-03-22 17:59:00 +01:00
return {}
@staticmethod
2015-02-09 23:02:03 +01:00
def _get_invoiced_duration_effort(works):
return dict((w.id, w.effort_duration) for w in works
2015-09-17 11:21:05 +02:00
if w.invoice_line and w.effort_duration)
2013-03-22 17:59:00 +01:00
2015-09-24 15:59:43 +02:00
@staticmethod
def _get_invoiced_duration_progress(works):
durations = {}
for work in works:
durations[work.id] = sum((p.effort_duration
for p in work.invoiced_progress if p.effort_duration),
datetime.timedelta())
return durations
2013-03-22 17:59:00 +01:00
@classmethod
2015-02-09 23:02:03 +01:00
def _get_invoiced_duration_timesheet(cls, works):
return cls._get_duration_timesheet(works, True)
2013-03-22 17:59:00 +01:00
@staticmethod
2015-02-09 23:02:03 +01:00
def default_duration_to_invoice():
return datetime.timedelta()
2013-03-22 17:59:00 +01:00
@staticmethod
2015-02-09 23:02:03 +01:00
def _get_duration_to_invoice_manual(works):
2013-03-22 17:59:00 +01:00
return {}
@staticmethod
2015-02-09 23:02:03 +01:00
def _get_duration_to_invoice_effort(works):
return dict((w.id, w.effort_duration) for w in works
if w.state == 'done' and not w.invoice_line and w.effort_duration)
2013-03-22 17:59:00 +01:00
2015-09-24 15:59:43 +02:00
@staticmethod
def _get_duration_to_invoice_progress(works):
durations = {}
for work in works:
if work.progress is None or work.effort_duration is None:
continue
effort_to_invoice = datetime.timedelta(
hours=work.effort_hours * work.progress)
effort_invoiced = sum(
(p.effort_duration
for p in work.invoiced_progress),
datetime.timedelta())
if effort_to_invoice > effort_invoiced:
durations[work.id] = effort_to_invoice - effort_invoiced
else:
durations[work.id] = datetime.timedelta()
return durations
2013-03-22 17:59:00 +01:00
@classmethod
2015-02-09 23:02:03 +01:00
def _get_duration_to_invoice_timesheet(cls, works):
return cls._get_duration_timesheet(works, False)
2013-03-22 17:59:00 +01:00
@staticmethod
def default_invoiced_amount():
return Decimal(0)
@staticmethod
def _get_invoiced_amount_manual(works):
return {}
@staticmethod
def _get_invoiced_amount_effort(works):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
2015-09-07 13:57:43 +02:00
Currency = pool.get('currency.currency')
2013-03-22 17:59:00 +01:00
2014-09-17 21:45:42 +02:00
invoice_lines = InvoiceLine.browse([
w.invoice_line.id for w in works
if w.invoice_line])
2013-03-22 17:59:00 +01:00
id2invoice_lines = dict((l.id, l) for l in invoice_lines)
amounts = {}
for work in works:
2015-09-07 13:57:43 +02:00
currency = work.company.currency
2015-09-04 13:23:23 +02:00
if work.invoice_line:
2013-03-22 17:59:00 +01:00
invoice_line = id2invoice_lines[work.invoice_line.id]
2015-09-07 13:57:43 +02:00
invoice_currency = (invoice_line.invoice.currency
if invoice_line.invoice else invoice_line.currency)
amounts[work.id] = Currency.compute(invoice_currency,
Decimal(str(work.effort_hours)) * invoice_line.unit_price,
currency)
2013-03-22 17:59:00 +01:00
else:
amounts[work.id] = Decimal(0)
return amounts
2015-09-24 15:59:43 +02:00
@classmethod
def _get_invoiced_amount_progress(cls, works):
pool = Pool()
Progress = pool.get('project.work.invoiced_progress')
InvoiceLine = pool.get('account.invoice.line')
Company = pool.get('company.company')
Currency = pool.get('currency.currency')
cursor = Transaction().connection.cursor()
2015-09-24 15:59:43 +02:00
table = cls.__table__()
progress = Progress.__table__()
invoice_line = InvoiceLine.__table__()
company = Company.__table__()
amounts = defaultdict(Decimal)
work2currency = {}
work_ids = [w.id for w in works]
for sub_ids in grouped_slice(work_ids):
where = reduce_ids(table.id, sub_ids)
cursor.execute(*table.join(progress,
condition=progress.work == table.id
).join(invoice_line,
condition=progress.invoice_line == invoice_line.id
).select(table.id,
Sum(progress.effort_duration * invoice_line.unit_price),
where=where,
group_by=table.id))
for work_id, amount in cursor.fetchall():
if isinstance(amount, datetime.timedelta):
amount = amount.total_seconds()
# Amount computed in second instead of hours
if amount is not None:
amount /= 60 * 60
else:
amount = 0
amounts[work_id] = amount
cursor.execute(*table.join(company,
condition=table.company == company.id
).select(table.id, company.currency,
where=where))
work2currency.update(cursor.fetchall())
2018-06-26 19:11:51 +02:00
currencies = Currency.browse(set(work2currency.values()))
2015-09-24 15:59:43 +02:00
id2currency = {c.id: c for c in currencies}
for work in works:
currency = id2currency[work2currency[work.id]]
amounts[work.id] = currency.round(Decimal(amounts[work.id]))
return amounts
@classmethod
def _get_invoiced_amount_timesheet(cls, works):
2013-03-22 17:59:00 +01:00
pool = Pool()
TimesheetWork = pool.get('timesheet.work')
TimesheetLine = pool.get('timesheet.line')
2013-03-22 17:59:00 +01:00
InvoiceLine = pool.get('account.invoice.line')
Company = pool.get('company.company')
2015-09-07 13:57:43 +02:00
Currency = pool.get('currency.currency')
2013-03-22 17:59:00 +01:00
cursor = Transaction().connection.cursor()
table = cls.__table__()
timesheet_work = TimesheetWork.__table__()
timesheet_line = TimesheetLine.__table__()
invoice_line = InvoiceLine.__table__()
company = Company.__table__()
2013-03-22 17:59:00 +01:00
amounts = {}
work2currency = {}
work_ids = [w.id for w in works]
for sub_ids in grouped_slice(work_ids):
where = reduce_ids(table.id, sub_ids)
cursor.execute(*table.join(timesheet_work,
2016-06-24 09:30:32 +02:00
condition=(
Concat(cls.__name__ + ',', table.id)
== timesheet_work.origin)
).join(timesheet_line,
condition=timesheet_line.work == timesheet_work.id
).join(invoice_line,
condition=timesheet_line.invoice_line == invoice_line.id
).select(table.id,
Sum(timesheet_line.duration * invoice_line.unit_price),
where=where,
group_by=table.id))
amounts.update(cursor.fetchall())
cursor.execute(*table.join(company,
condition=table.company == company.id
).select(table.id, company.currency,
where=where))
work2currency.update(cursor.fetchall())
2018-06-26 19:11:51 +02:00
currencies = Currency.browse(set(work2currency.values()))
id2currency = {c.id: c for c in currencies}
2013-03-22 17:59:00 +01:00
for work in works:
currency = id2currency[work2currency[work.id]]
amount = amounts.get(work.id, 0)
if isinstance(amount, datetime.timedelta):
amount = amount.total_seconds()
amount = amount / 60 / 60
amounts[work.id] = currency.round(Decimal(str(amount)))
2013-03-22 17:59:00 +01:00
return amounts
@staticmethod
2015-02-09 23:02:03 +01:00
def _get_duration_timesheet(works, invoiced):
2013-03-22 17:59:00 +01:00
pool = Pool()
TimesheetLine = pool.get('timesheet.line')
cursor = Transaction().connection.cursor()
2013-09-06 22:34:32 +02:00
line = TimesheetLine.__table__()
2013-03-22 17:59:00 +01:00
2016-06-24 09:30:32 +02:00
durations = defaultdict(datetime.timedelta)
twork2work = {tw.id: w.id for w in works for tw in w.timesheet_works}
2018-06-26 19:11:51 +02:00
for sub_ids in grouped_slice(twork2work.keys()):
2013-09-06 22:34:32 +02:00
red_sql = reduce_ids(line.work, sub_ids)
if invoiced:
where = line.invoice_line != Null
2013-09-06 22:34:32 +02:00
else:
where = line.invoice_line == Null
2015-02-09 23:02:03 +01:00
cursor.execute(*line.select(line.work, Sum(line.duration),
2013-09-06 22:34:32 +02:00
where=red_sql & where,
group_by=line.work))
2015-02-09 23:02:03 +01:00
for twork_id, duration in cursor.fetchall():
2015-09-17 11:21:05 +02:00
if duration:
# SQLite uses float for SUM
if not isinstance(duration, datetime.timedelta):
duration = datetime.timedelta(seconds=duration)
2016-06-24 09:30:32 +02:00
durations[twork2work[twork_id]] += duration
2015-02-09 23:02:03 +01:00
return durations
2013-03-22 17:59:00 +01:00
@classmethod
2015-09-17 11:21:05 +02:00
def _get_invoice_values(cls, works, name):
default = getattr(cls, 'default_%s' % name)
durations = dict.fromkeys((w.id for w in works), default())
method2works = defaultdict(list)
2013-03-22 17:59:00 +01:00
for work in works:
2015-09-17 11:21:05 +02:00
method2works[work.invoice_method].append(work)
2018-06-26 19:11:51 +02:00
for method, m_works in method2works.items():
2013-03-22 17:59:00 +01:00
method = getattr(cls, '_get_%s_%s' % (name, method))
2015-09-17 11:21:05 +02:00
# Re-browse for cache alignment
durations.update(method(cls.browse(m_works)))
return durations
2013-03-22 17:59:00 +01:00
2015-09-17 11:21:05 +02:00
@classmethod
def _get_invoiced_duration(cls, works):
return cls._get_invoice_values(works, 'invoiced_duration')
@classmethod
def _get_duration_to_invoice(cls, works):
return cls._get_invoice_values(works, 'duration_to_invoice')
@classmethod
def _get_invoiced_amount(cls, works):
return cls._get_invoice_values(works, 'invoiced_amount')
2013-03-22 17:59:00 +01:00
@classmethod
@ModelView.button
def invoice(cls, works):
pool = Pool()
Invoice = pool.get('account.invoice')
invoices = []
uninvoiced = works[:]
while uninvoiced:
work = uninvoiced.pop(0)
invoice_lines, uninvoiced_children = work._get_lines_to_invoice()
uninvoiced.extend(uninvoiced_children)
2013-03-22 17:59:00 +01:00
if not invoice_lines:
continue
invoice = work._get_invoice()
invoice.save()
invoices.append(invoice)
for key, lines in groupby(invoice_lines,
key=work._group_lines_to_invoice_key):
lines = list(lines)
key = dict(key)
invoice_line = work._get_invoice_line(key, invoice, lines)
invoice_line.invoice = invoice.id
invoice_line.save()
origins = {}
for line in lines:
origin = line['origin']
origins.setdefault(origin.__class__, []).append(origin)
2018-06-26 19:11:51 +02:00
for klass, records in origins.items():
2015-09-24 15:59:43 +02:00
klass.save(records) # Store first new origins
2013-03-22 17:59:00 +01:00
klass.write(records, {
'invoice_line': invoice_line.id,
})
2014-09-17 21:45:42 +02:00
Invoice.update_taxes(invoices)
2013-03-22 17:59:00 +01:00
def _get_invoice(self):
"Return invoice for the work"
pool = Pool()
Invoice = pool.get('account.invoice')
Journal = pool.get('account.journal')
journals = Journal.search([
('type', '=', 'revenue'),
], limit=1)
if journals:
journal, = journals
else:
journal = None
if not self.party:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_party',
work=self.rec_name))
2013-03-22 17:59:00 +01:00
2014-09-17 21:45:42 +02:00
return Invoice(
company=self.company,
2016-03-20 22:59:18 +01:00
type='out',
2014-09-17 21:45:42 +02:00
journal=journal,
party=self.party,
invoice_address=self.party.address_get(type='invoice'),
currency=self.company.currency,
2017-09-28 10:18:41 +02:00
account=self.party.account_receivable_used,
2014-09-17 21:45:42 +02:00
payment_term=self.party.customer_payment_term,
description=self.name,
2014-09-17 21:45:42 +02:00
)
2013-03-22 17:59:00 +01:00
def _group_lines_to_invoice_key(self, line):
"The key to group lines"
return (('product', line['product']),
('unit', line['unit']),
2013-03-22 17:59:00 +01:00
('unit_price', line['unit_price']),
('description', line['description']))
def _get_invoice_line(self, key, invoice, lines):
"Return a invoice line for the lines"
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
Uom = pool.get('product.uom')
quantity = sum(l['quantity'] for l in lines)
product = key['product']
2014-09-17 21:45:42 +02:00
invoice_line = InvoiceLine()
2013-03-22 17:59:00 +01:00
invoice_line.type = 'line'
invoice_line.description = key['description']
invoice_line.account = product.account_revenue_used
if (key['unit']
and key['unit'].category == product.default_uom.category):
invoice_line.product = product
invoice_line.unit_price = Uom.compute_price(
key['unit'], key['unit_price'], product.default_uom)
invoice_line.quantity = Uom.compute_qty(
key['unit'], quantity, product.default_uom)
invoice_line.unit = product.default_uom
else:
invoice_line.unit_price = key['unit_price']
invoice_line.quantity = quantity
invoice_line.unit = key['unit']
2013-03-22 17:59:00 +01:00
taxes = []
pattern = invoice_line._get_tax_rule_pattern()
party = invoice.party
for tax in product.customer_taxes_used:
2013-04-29 21:31:01 +02:00
if party.customer_tax_rule:
2013-03-22 17:59:00 +01:00
tax_ids = party.customer_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if party.customer_tax_rule:
tax_ids = party.customer_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
invoice_line.taxes = taxes
return invoice_line
def _get_lines_to_invoice_manual(self):
return []
def _get_lines_to_invoice_effort(self):
pool = Pool()
ModelData = pool.get('ir.model.data')
Uom = pool.get('product.uom')
hour = Uom(ModelData.get_id('product', 'uom_hour'))
2015-02-09 23:02:03 +01:00
if (not self.invoice_line
and self.effort_hours
and self.state == 'done'):
2013-03-22 17:59:00 +01:00
if not self.product:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_product',
work=self.rec_name))
2013-03-22 17:59:00 +01:00
elif self.list_price is None:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_list_price',
work=self.rec_name))
2013-03-22 17:59:00 +01:00
return [{
'product': self.product,
2015-02-09 23:02:03 +01:00
'quantity': self.effort_hours,
'unit': hour,
2013-03-22 17:59:00 +01:00
'unit_price': self.list_price,
'origin': self,
'description': self.name,
2013-03-22 17:59:00 +01:00
}]
return []
2015-09-24 15:59:43 +02:00
def _get_lines_to_invoice_progress(self):
pool = Pool()
InvoicedProgress = pool.get('project.work.invoiced_progress')
ModelData = pool.get('ir.model.data')
Uom = pool.get('product.uom')
hour = Uom(ModelData.get_id('product', 'uom_hour'))
if self.progress is None or self.effort_duration is None:
return []
invoiced_progress = sum(x.effort_hours for x in self.invoiced_progress)
quantity = self.effort_hours * self.progress - invoiced_progress
if self.product:
quantity = Uom.compute_qty(
hour, quantity, self.product.default_uom)
2015-09-24 15:59:43 +02:00
if quantity > 0:
if not self.product:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_product',
work=self.rec_name))
2015-09-24 15:59:43 +02:00
elif self.list_price is None:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_list_price',
work=self.rec_name))
2015-09-24 15:59:43 +02:00
invoiced_progress = InvoicedProgress(work=self,
effort_duration=datetime.timedelta(hours=quantity))
return [{
'product': self.product,
'quantity': quantity,
'unit': hour,
2015-09-24 15:59:43 +02:00
'unit_price': self.list_price,
'origin': invoiced_progress,
'description': self.name,
}]
return []
2013-03-22 17:59:00 +01:00
def _get_lines_to_invoice_timesheet(self):
pool = Pool()
ModelData = pool.get('ir.model.data')
Uom = pool.get('product.uom')
hour = Uom(ModelData.get_id('product', 'uom_hour'))
2016-06-24 09:30:32 +02:00
if (self.timesheet_works
and any(tw.timesheet_lines for tw in self.timesheet_works)):
2013-03-22 17:59:00 +01:00
if not self.product:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_product',
work=self.rec_name))
2013-03-22 17:59:00 +01:00
elif self.list_price is None:
2018-12-29 14:20:29 +01:00
raise InvoicingError(
gettext('project_invoice.msg_missing_list_price',
work=self.rec_name))
2013-03-22 17:59:00 +01:00
return [{
'product': self.product,
'quantity': l.hours,
'unit': hour,
2013-03-22 17:59:00 +01:00
'unit_price': self.list_price,
'origin': l,
'description': self.name,
2016-06-24 09:30:32 +02:00
}
for tw in self.timesheet_works
for l in tw.timesheet_lines
2013-03-22 17:59:00 +01:00
if not l.invoice_line]
return []
def _test_group_invoice(self):
return (self.company, self.party)
def _get_lines_to_invoice(self, test=None):
"Return lines for work and children"
lines = []
if test is None:
test = self._test_group_invoice()
uninvoiced_children = []
2013-03-22 17:59:00 +01:00
lines += getattr(self, '_get_lines_to_invoice_%s' %
self.invoice_method)()
for children in self.children:
if children.type == 'project':
if test != children._test_group_invoice():
uninvoiced_children.append(children)
2013-03-22 17:59:00 +01:00
continue
child_lines, uninvoiced = children._get_lines_to_invoice(test=test)
lines.extend(child_lines)
uninvoiced_children.extend(uninvoiced)
return lines, uninvoiced_children
2013-03-22 17:59:00 +01:00
2015-09-24 15:59:43 +02:00
class WorkInvoicedProgress(ModelView, ModelSQL):
'Work Invoiced Progress'
__name__ = 'project.work.invoiced_progress'
work = fields.Many2One('project.work', 'Work', ondelete='RESTRICT',
select=True)
effort_duration = fields.TimeDelta('Effort', 'company_work_time')
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line',
ondelete='CASCADE')
@property
def effort_hours(self):
if not self.effort_duration:
return 0
return self.effort_duration.total_seconds() / 60 / 60
2013-03-22 17:59:00 +01:00
class OpenInvoice(Wizard):
'Open Invoice'
__name__ = 'project.open_invoice'
start_state = 'open_'
open_ = StateAction('account_invoice.act_invoice_form')
def do_open_(self, action):
pool = Pool()
Work = pool.get('project.work')
works = Work.search([
('parent', 'child_of', Transaction().context['active_ids']),
])
invoice_ids = set()
for work in works:
if work.invoice_line and work.invoice_line.invoice:
invoice_ids.add(work.invoice_line.invoice.id)
2016-06-24 09:30:32 +02:00
for twork in work.timesheet_works:
for timesheet_line in twork.timesheet_lines:
if (timesheet_line.invoice_line
and timesheet_line.invoice_line.invoice):
invoice_ids.add(timesheet_line.invoice_line.invoice.id)
2015-09-24 15:59:43 +02:00
if work.invoiced_progress:
for progress in work.invoiced_progress:
invoice_ids.add(progress.invoice_line.invoice.id)
2013-03-22 17:59:00 +01:00
encoder = PYSONEncoder()
action['pyson_domain'] = encoder.encode(
[('id', 'in', list(invoice_ids))])
action['pyson_search_value'] = encoder.encode([])
return action, {}