mirror of
https://github.com/NaN-tic/trytond-account_invoice_tree.git
synced 2023-12-14 04:03:00 +01:00
156 lines
5.4 KiB
Python
156 lines
5.4 KiB
Python
# The COPYRIGHT file at the top level of this repository contains the full
|
|
# copyright notices and license terms.
|
|
from decimal import Decimal
|
|
|
|
from trytond.model import fields
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval
|
|
from trytond.transaction import Transaction
|
|
|
|
__all__ = ['Invoice', 'InvoiceLine']
|
|
|
|
|
|
class ChapterMixin(object):
|
|
chapter_number = fields.Function(fields.Char('Chapter Number'),
|
|
'get_chapter_number')
|
|
|
|
@classmethod
|
|
def get_1st_level_chapters(cls, records):
|
|
"""Return iterator over list of first records' ancestors children"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def get_chapter_number(cls, records, name):
|
|
result = dict.fromkeys((r.id for r in records), None)
|
|
# Calculate full sale to get the order correctly
|
|
for children in cls.get_1st_level_chapters(records):
|
|
values = cls._compute_chapter_number(children)
|
|
for child_id, value in values.iteritems():
|
|
if child_id not in result:
|
|
continue
|
|
result[child_id] = value
|
|
return result
|
|
|
|
@classmethod
|
|
def _compute_chapter_number(cls, children, prefix=None):
|
|
if prefix is None:
|
|
prefix = ''
|
|
result = {}
|
|
for i, child in enumerate(children, 1):
|
|
result[child.id] = '%s%s' % (prefix, i)
|
|
if child.childs:
|
|
result.update(cls._compute_chapter_number(
|
|
child.childs, prefix=result[child.id] + '.'))
|
|
return result
|
|
|
|
|
|
class Invoice:
|
|
__metaclass__ = PoolMeta
|
|
__name__ = 'account.invoice'
|
|
lines_tree = fields.Function(fields.One2Many('account.invoice.line',
|
|
None, 'Lines',
|
|
domain=[
|
|
('parent', '=', None),
|
|
]),
|
|
'get_lines_tree', setter='set_lines_tree')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Invoice, cls).__setup__()
|
|
if cls.lines.domain:
|
|
cls.lines_tree._field.domain.extend(cls.lines.domain)
|
|
if cls.lines.add_remove:
|
|
cls.lines_tree._field.add_remove = cls.lines.add_remove[:]
|
|
cls.lines_tree._field.states = cls.lines.states
|
|
cls.lines_tree._field.context = cls.lines.context
|
|
cls.lines_tree._field.depends = cls.lines.depends
|
|
|
|
def get_lines_tree(self, name):
|
|
return [x.id for x in self.lines if not x.parent]
|
|
|
|
@classmethod
|
|
def set_lines_tree(cls, lines, name, value):
|
|
with Transaction().set_context(skip_update_taxes=True):
|
|
cls.write(lines, {
|
|
'lines': value,
|
|
})
|
|
|
|
@fields.depends('lines', 'lines_tree', methods=['lines'])
|
|
def on_change_lines_tree(self, name=None):
|
|
lines = self.lines
|
|
self.lines = self.lines_tree
|
|
self.on_change_lines()
|
|
self.lines_tree = self.lines
|
|
self.lines = lines
|
|
|
|
@classmethod
|
|
def copy(cls, invoices, default=None):
|
|
pool = Pool()
|
|
InvoiceLine = pool.get('invoice.line')
|
|
if default is None:
|
|
default = {}
|
|
default['lines'] = []
|
|
new_invoices = super(Invoice, cls).copy(invoices, default=default)
|
|
for invoice, new_invoice in zip(invoices, new_invoices):
|
|
new_default = default.copy()
|
|
new_default['invoice'] = new_invoice.id
|
|
InvoiceLine.copy(invoice.lines_tree, default=new_default)
|
|
return new_invoices
|
|
|
|
|
|
class InvoiceLine(ChapterMixin):
|
|
__metaclass__ = PoolMeta
|
|
__name__ = 'account.invoice.line'
|
|
|
|
parent = fields.Many2One('account.invoice.line', 'Parent', select=True,
|
|
ondelete='CASCADE',
|
|
domain=[
|
|
('invoice', '=', Eval('invoice')),
|
|
('type', '=', 'title'),
|
|
],
|
|
depends=['invoice'])
|
|
childs = fields.One2Many('account.invoice.line', 'parent', 'Childs',
|
|
domain=[
|
|
('invoice', '=', Eval('invoice')),
|
|
],
|
|
depends=['invoice'])
|
|
|
|
def get_amount(self, name):
|
|
if self.parent and (self.type == 'subtotal'
|
|
and self.parent.type == 'title'):
|
|
def get_amount_rec(parent):
|
|
subtotal = Decimal(0)
|
|
for line2 in parent.childs:
|
|
if line2.childs:
|
|
subtotal += get_amount_rec(line2)
|
|
if line2.type == 'line':
|
|
subtotal += line2.sale.currency.round(
|
|
Decimal(str(line2.quantity)) * line2.unit_price)
|
|
elif line2.type == self.type:
|
|
if self == line2:
|
|
return subtotal
|
|
subtotal = Decimal(0)
|
|
return subtotal
|
|
|
|
return get_amount_rec(self.parent)
|
|
return super(InvoiceLine, self).get_amount(name)
|
|
|
|
@classmethod
|
|
def get_1st_level_chapters(cls, records):
|
|
for invoice in {l.invoice for l in records}:
|
|
if invoice: # compatibility with account_invoice_line_standalone
|
|
yield invoice.lines_tree
|
|
|
|
@classmethod
|
|
def copy(cls, lines, default=None):
|
|
if default is None:
|
|
default = {}
|
|
default['childs'] = []
|
|
new_lines = []
|
|
for line in lines:
|
|
new_line, = super(InvoiceLine, cls).copy([line], default)
|
|
new_lines.append(new_line)
|
|
new_default = default.copy()
|
|
new_default['parent'] = new_line.id
|
|
cls.copy(line.childs, default=new_default)
|
|
return new_lines
|