trytonpsk-staff_payroll/wage_type.py

191 lines
7.3 KiB
Python

# This file is part of Tryton. 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 ModelView, ModelSQL, fields
from trytond.pyson import Not, Bool, Eval, If
from trytond.transaction import Transaction
from trytond.i18n import gettext
from .exceptions import WageTypeValidationError
from trytond.tools import lstrip_wildcard
from trytond.pool import Pool
STATES = {'readonly': Not(Bool(Eval('active')))}
class WageType(ModelSQL, ModelView):
"Wage Type"
__name__ = "staff.wage_type"
name = fields.Char('Name', select=True, required=True)
sequence = fields.Integer('Sequence', select=True)
code = fields.Char('Code', select=True)
active = fields.Boolean('Active')
company = fields.Many2One('company.company', 'Company', required=True,
domain=[
('id', If(Eval('context', {}).contains('company'), '=', '!='),
Eval('context', {}).get('company', 0)),
])
definition = fields.Selection([
('payment', 'Payment'),
('discount', 'Discount'),
('deduction', 'Deduction'),
], 'Definition', required=True)
unit_price_formula = fields.Char('Unit Price Formula',
help="""Python expression for eval(expr) \b
-salary: the salary employee \b
-minimum_salary: the salary minimum fixed """)
expense_formula = fields.Char('Expense Formula',
help="""Python expression for eval(expr) \b
-salary: the salary employee \b
-minimum_salary: the salary minimum fixed """)
uom = fields.Many2One('product.uom', 'UOM', required=True)
default_quantity = fields.Numeric('Default Quantity', digits=(16, 2))
type_concept = fields.Selection([
('salary', 'Salary'),
('extras', 'Extras'),
('unpaid_leave', 'Unpaid Leave'),
('other', 'Other'),
('special', 'Special'),
('', ''),
], 'Type Concept')
salary_constitute = fields.Boolean('Salary Constitute',
select=True,
states={
'invisible': Eval('definition') != 'payment',
})
debit_account = fields.Many2One('account.account',
'Debit Account', domain=[
('company', '=', Eval('context', {}).get('company', 0)),
('type', '!=', None),
],
states={
'invisible': ~Eval('context', {}).get('company'),
})
credit_account = fields.Many2One('account.account',
'Credit Account', domain=[
('type', '!=', None),
('company', '=', Eval('context', {}).get('company', 0))],
states={
'invisible': ~Eval('context', {}).get('company'),
})
deduction_account = fields.Many2One('account.account',
'Deduction Account', domain=[
('type', '!=', None),
('company', '=', Eval('context', {}).get('company', 0))],
states={
'invisible': Eval('definition') == 'payment',
'required': Eval('definition') != 'payment',
}, depends=['definition'])
receipt = fields.Boolean('Receipt', select=True)
parent = fields.Many2One('staff.wage_type', 'Parent', select=True)
concepts_salary = fields.Many2Many('staff.wage_type-staff.wage_type',
'parent', 'child', 'Concepts Salary')
contract_finish = fields.Boolean('Contract Finish', select=True)
party_required = fields.Boolean('Party Required', select=True)
limit_days = fields.Numeric('Limit Days', digits=(4, 0), states={
'invisible': Eval('type_concept') != 'special',
'required': Eval('type_concept') == 'special',
})
rate_employee = fields.Numeric('Rate Employee', digits=(16,5))
rate_company = fields.Numeric('Rate Company', digits=(16,5))
@classmethod
def __setup__(cls):
super(WageType, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
@staticmethod
def default_company():
return Transaction().context.get('company')
@classmethod
def validate(cls, wage_types):
super(WageType, cls).validate(wage_types)
for wage in wage_types:
test_salary = {'salary': 1000}
if wage.unit_price_formula:
cls.compute_formula(wage.unit_price_formula, test_salary)
if wage.expense_formula:
cls.compute_formula(wage.expense_formula, test_salary)
@classmethod
def search_rec_name(cls, name, clause):
if clause[1].startswith('!') or clause[1].startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
code_value = clause[2]
if clause[1].endswith('like'):
code_value = lstrip_wildcard(clause[2])
return [bool_op,
('name',) + tuple(clause[1:]),
('code', clause[1], code_value) + tuple(clause[3:]),
]
@staticmethod
def default_unit_price_formula():
return 'salary'
@staticmethod
def default_active():
return True
@classmethod
def compute_unit_price(cls, formula, args):
return cls.compute_formula(formula, args)
@classmethod
def compute_expense(cls, formula, args):
return cls.compute_formula(formula, args)
def compute_formula2(self, formula, args=None):
'''
Compute a formula field with a salary value as float
:return: A decimal
'''
Configuration = Pool().get('staff.configuration')
configuration = Configuration(1)
minimum_salary = float(configuration.minimum_salary or 0)
formula = getattr(self, formula)
if not formula:
return Decimal('0.0')
if args.get('salary') != None:
salary = float(args['salary'])
try:
value = Decimal(str(round(eval(formula), 2)))
return value
except Exception:
raise WageTypeValidationError(
gettext('staff_payroll.msg_invalid_formula', formula=formula))
@classmethod
def compute_formula(cls, formula, args=None):
'''
Compute a formula field with a salary value as float
:return: A decimal
'''
Configuration = Pool().get('staff.configuration')
configuration = Configuration(1)
minimum_salary = float(configuration.minimum_salary or 0)
# formula = getattr(self, formula)
if not formula:
return Decimal('0.0')
if args.get('salary') != None:
salary = float(args['salary'])
print('formula ....', formula)
if 1: #try:
value = Decimal(str(round(eval(formula), 2)))
return value
# except Exception:
# raise WageTypeValidationError(
# gettext('staff_payroll.msg_invalid_formula', formula=formula))
class WageTypeSalary(ModelSQL):
"Wage Type Salary"
__name__ = "staff.wage_type-staff.wage_type"
_table = 'staff_wage_type_salary_rel'
parent = fields.Many2One('staff.wage_type', 'Parent', ondelete='CASCADE',
select=True, required=True)
child = fields.Many2One('staff.wage_type', 'Child', ondelete='RESTRICT',
select=True, required=True)