2022-08-09 13:08:41 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# This file is part of the cashbook-module from m-ds for Tryton.
|
|
|
|
# The COPYRIGHT file at the top level of this repository contains the
|
|
|
|
# full copyright notices and license terms.
|
|
|
|
|
2022-08-28 10:24:25 +00:00
|
|
|
from trytond.model import ModelView, ModelSQL, fields, Unique, Exclude, tree, sequence_ordered
|
2022-08-09 13:08:41 +00:00
|
|
|
from trytond.transaction import Transaction
|
2022-08-10 09:57:35 +00:00
|
|
|
from trytond.pool import Pool
|
2022-08-11 09:06:28 +00:00
|
|
|
from trytond.pyson import Eval, If, Bool
|
2022-08-10 15:06:20 +00:00
|
|
|
from trytond.exceptions import UserError
|
|
|
|
from trytond.i18n import gettext
|
2022-08-28 10:24:25 +00:00
|
|
|
from sql.operators import Equal
|
2022-08-29 21:34:36 +00:00
|
|
|
from sql import With
|
2022-08-10 15:06:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
sel_categorytype = [
|
|
|
|
('in', 'Revenue'),
|
|
|
|
('out', 'Expense'),
|
|
|
|
]
|
2022-08-09 13:08:41 +00:00
|
|
|
|
|
|
|
|
2022-08-10 09:57:35 +00:00
|
|
|
class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
|
2022-08-09 13:08:41 +00:00
|
|
|
'Category'
|
|
|
|
__name__ = 'cashbook.category'
|
|
|
|
|
|
|
|
name = fields.Char(string='Name', required=True, translate=True)
|
|
|
|
description = fields.Char(string='Description', translate=True)
|
2022-08-10 15:06:20 +00:00
|
|
|
cattype = fields.Selection(string='Type', required=True,
|
2022-08-11 09:06:28 +00:00
|
|
|
help='Type of Category', selection=sel_categorytype,
|
|
|
|
states={'readonly': Bool(Eval('parent_cattype'))},
|
|
|
|
domain=[If(Bool(Eval('parent_cattype')),
|
|
|
|
('cattype', '=', Eval('parent_cattype', '')),
|
|
|
|
())],
|
|
|
|
depends=['parent_cattype'])
|
|
|
|
parent_cattype = fields.Function(fields.Char(string='Parent Category Type',
|
|
|
|
readonly=True, states={'invisible': True}),
|
|
|
|
'on_change_with_parent_cattype')
|
2022-08-10 15:06:20 +00:00
|
|
|
|
2022-08-09 13:08:41 +00:00
|
|
|
company = fields.Many2One(string='Company', model_name='company.company',
|
|
|
|
required=True, ondelete="RESTRICT")
|
2022-08-10 09:57:35 +00:00
|
|
|
sequence = fields.Integer(string='Sequence', select=True)
|
2022-08-09 13:08:41 +00:00
|
|
|
parent = fields.Many2One(string="Parent",
|
|
|
|
model_name='cashbook.category', ondelete='RESTRICT',
|
|
|
|
left='left', right='right')
|
|
|
|
childs = fields.One2Many(string='Children', field='parent',
|
|
|
|
model_name='cashbook.category')
|
|
|
|
left = fields.Integer(string='Left', required=True, select=True)
|
|
|
|
right = fields.Integer(string='Right', required=True, select=True)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
|
|
|
super(Category, cls).__setup__()
|
|
|
|
cls._order.insert(0, ('name', 'ASC'))
|
|
|
|
t = cls.__table__()
|
|
|
|
cls._sql_constraints.extend([
|
2022-08-28 10:24:25 +00:00
|
|
|
('name_uniq',
|
|
|
|
Unique(t, t.name, t.company, t.parent),
|
|
|
|
'cashbook.msg_category_name_unique'),
|
|
|
|
('name2_uniq',
|
|
|
|
Exclude(t,
|
|
|
|
(t.name, Equal),
|
|
|
|
(t.cattype, Equal),
|
|
|
|
where=(t.parent == None)),
|
|
|
|
'cashbook.msg_category_name_unique'),
|
2022-08-09 13:08:41 +00:00
|
|
|
])
|
|
|
|
|
2022-08-10 15:06:20 +00:00
|
|
|
@classmethod
|
|
|
|
def default_cattype(cls):
|
|
|
|
return 'out'
|
|
|
|
|
2022-08-09 13:08:41 +00:00
|
|
|
@staticmethod
|
|
|
|
def default_company():
|
|
|
|
return Transaction().context.get('company') or None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_left():
|
|
|
|
return 0
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_right():
|
|
|
|
return 0
|
|
|
|
|
2022-08-29 21:34:36 +00:00
|
|
|
@staticmethod
|
|
|
|
def order_rec_name(tables):
|
|
|
|
""" order by pos
|
|
|
|
"""
|
|
|
|
Category2 = Pool().get('cashbook.category')
|
|
|
|
tab_cat = Category2.__table__()
|
|
|
|
table, _ = tables[None]
|
|
|
|
|
|
|
|
categories = With('id', 'name', 'name_path', recursive=True)
|
|
|
|
categories.query = select(tab_cat.id, tab_cat.name, array[])
|
|
|
|
|
|
|
|
# ~ with recursive categories (id, level, name, name_path) as (
|
|
|
|
# ~ select "a"."id", 0, "a"."name", array["a"."name"]
|
|
|
|
# ~ from cashbook_category as "a"
|
|
|
|
# ~ where "a"."parent" is null
|
|
|
|
|
|
|
|
# ~ union all
|
|
|
|
|
|
|
|
# ~ select "b"."id", "c"."level" + 1, "b"."name", array_append("c"."name_path", "b"."name")
|
|
|
|
# ~ from cashbook_category as "b"
|
|
|
|
# ~ inner join categories as "c" on "c"."id" = "b"."parent"
|
|
|
|
# ~ )
|
|
|
|
# ~ select "d"."id", array_to_string("d"."name_path", '/') as "rec_name"
|
|
|
|
# ~ from categories as "d"
|
|
|
|
# ~ order by "rec_name"
|
|
|
|
|
2022-08-11 09:06:28 +00:00
|
|
|
@fields.depends('parent', '_parent_parent.cattype')
|
|
|
|
def on_change_with_parent_cattype(self, name=None):
|
|
|
|
""" get type of parent category or None
|
|
|
|
"""
|
|
|
|
if self.parent:
|
|
|
|
return self.parent.cattype
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def check_category_hierarchy(cls, categories):
|
|
|
|
""" check if current category-type is equal to parent
|
|
|
|
"""
|
|
|
|
for category in categories:
|
|
|
|
if category.parent:
|
|
|
|
if category.parent.cattype != category.cattype:
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_category_type_not_like_parent',
|
|
|
|
parentname = category.parent.rec_name,
|
|
|
|
catname = category.rec_name,
|
|
|
|
))
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create(cls, vlist):
|
|
|
|
""" add debit/credit
|
|
|
|
"""
|
|
|
|
records = super(Category, cls).create(vlist)
|
|
|
|
cls.check_category_hierarchy(records)
|
|
|
|
return records
|
|
|
|
|
2022-08-10 15:06:20 +00:00
|
|
|
@classmethod
|
|
|
|
def write(cls, *args):
|
|
|
|
""" parent.cattape == cattype,
|
|
|
|
update sub-categories
|
|
|
|
"""
|
2022-08-15 10:35:31 +00:00
|
|
|
Category2 = Pool().get('cashbook.category')
|
|
|
|
|
2022-08-10 15:06:20 +00:00
|
|
|
actions = iter(args)
|
2022-08-11 09:06:28 +00:00
|
|
|
to_check = []
|
|
|
|
to_write = []
|
|
|
|
to_write2 = []
|
2022-08-10 15:06:20 +00:00
|
|
|
for categories, values in zip(actions, actions):
|
2022-08-11 09:06:28 +00:00
|
|
|
to_write2.extend([categories, values])
|
|
|
|
|
2022-08-10 15:06:20 +00:00
|
|
|
if 'cattype' in values.keys():
|
2022-08-11 09:06:28 +00:00
|
|
|
# update sub-categories
|
2022-08-15 10:35:31 +00:00
|
|
|
cats = Category2.search([
|
|
|
|
('parent', 'child_of', [x.id for x in categories]),
|
2022-08-11 09:06:28 +00:00
|
|
|
])
|
2022-08-10 15:06:20 +00:00
|
|
|
if len(cats) > 0:
|
|
|
|
to_write.extend([
|
|
|
|
cats,
|
|
|
|
{
|
|
|
|
'cattype': values['cattype'],
|
|
|
|
}])
|
2022-08-11 09:06:28 +00:00
|
|
|
to_check.extend(categories)
|
|
|
|
to_check.extend(cats)
|
2022-08-10 15:06:20 +00:00
|
|
|
|
2022-08-11 09:06:28 +00:00
|
|
|
# add category-updates after regulary writes
|
|
|
|
to_write2.extend(to_write)
|
|
|
|
super(Category, cls).write(*to_write2)
|
|
|
|
cls.check_category_hierarchy(to_check)
|
2022-08-10 15:06:20 +00:00
|
|
|
|
2022-08-09 13:08:41 +00:00
|
|
|
# end Category
|