trytonpsk-staff_payroll_co/liquidation.py

1371 lines
53 KiB
Python
Raw Normal View History

2020-11-04 02:24:58 +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.
2020-04-16 00:38:42 +02:00
from decimal import Decimal
from trytond.model import Workflow, ModelSQL, ModelView, fields
from trytond.pool import Pool
from trytond.report import Report
from trytond.pyson import Eval, If, Bool
2023-09-12 17:13:11 +02:00
from trytond.wizard import (Wizard, StateView, Button,
StateTransition, StateReport)
2020-04-16 00:38:42 +02:00
from trytond.transaction import Transaction
2021-06-09 18:07:42 +02:00
from trytond.i18n import gettext
2021-08-13 03:41:35 +02:00
from .exceptions import (
LiquidationEmployeeError, MissingSecuenceLiquidation,
LiquidationMoveError, WageTypeConceptError, LiquidationDeleteError,
RecordDuplicateError
2021-08-13 03:41:35 +02:00
)
2020-04-16 00:38:42 +02:00
2020-11-04 02:24:58 +01:00
STATES = {'readonly': (Eval('state') != 'draft')}
2020-04-16 00:38:42 +02:00
_ZERO = Decimal('0.0')
BONUS_SERVICE = ['bonus_service']
2020-11-04 02:24:58 +01:00
CONTRACT = [
'bonus_service', 'health', 'retirement', 'unemployment', 'interest',
2022-01-19 20:29:53 +01:00
'holidays', 'convencional_bonus'
2023-09-12 17:13:11 +02:00
]
2020-04-16 00:38:42 +02:00
concept_social_security = ['health', 'risk', 'box_family', 'retirement', 'fsp']
2020-04-16 00:38:42 +02:00
class Liquidation(Workflow, ModelSQL, ModelView):
'Staff Liquidation'
__name__ = 'staff.liquidation'
number = fields.Char('Number', readonly=True, help="Secuence",
select=True)
employee = fields.Many2One('company.employee', 'Employee',
states=STATES, required=True, depends=['state'])
start_period = fields.Many2One('staff.payroll.period', 'Start Period',
required=True, states=STATES)
end_period = fields.Many2One('staff.payroll.period', 'End Period',
required=True, states=STATES, depends=['start_period'])
kind = fields.Selection([
2023-09-12 17:13:11 +02:00
('contract', 'Contract'),
('bonus_service', 'Bonus Service'),
('interest', 'Interest'),
('unemployment', 'Unemployment'),
('holidays', 'Vacation'),
('convencional_bonus', 'Convencional Bonus'),
], 'Kind', required=True, states=STATES)
2020-04-16 00:38:42 +02:00
liquidation_date = fields.Date('Liquidation Date', states=STATES,
2023-09-12 17:13:11 +02:00
required=True)
2020-04-16 00:38:42 +02:00
lines = fields.One2Many('staff.liquidation.line', 'liquidation',
2023-09-12 17:13:11 +02:00
'Lines', states=STATES, depends=['employee', 'state'])
2020-04-16 00:38:42 +02:00
gross_payments = fields.Function(fields.Numeric(
2023-09-12 17:13:11 +02:00
'Gross Payments', states=STATES, digits=(16, 2)),
'get_sum_operation')
2020-04-16 00:38:42 +02:00
total_deductions = fields.Function(fields.Numeric(
2023-09-12 17:13:11 +02:00
'Total Deductions', states=STATES, digits=(16, 2)),
'get_sum_operation')
2020-04-16 00:38:42 +02:00
net_payment = fields.Function(fields.Numeric(
2023-09-12 17:13:11 +02:00
'Net Payment', states=STATES, digits=(16, 2)),
'get_net_payment')
2020-04-16 00:38:42 +02:00
time_contracting = fields.Integer('Time Contracting', states=STATES,
depends=['start_period', 'end_period', 'employee'])
state = fields.Selection([
2023-09-12 17:13:11 +02:00
('draft', 'Draft'),
('confirmed', 'Confirmed'),
('posted', 'Posted'),
('cancel', 'Cancel'),
], 'State', readonly=True)
2020-04-16 00:38:42 +02:00
company = fields.Many2One('company.company', 'Company', required=True,
states={
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
2023-09-12 17:13:11 +02:00
},
2020-04-16 00:38:42 +02:00
domain=[
('id', If(Eval('context', {}).contains('company'), '=', '!='),
Eval('context', {}).get('company', 0)),
2023-09-12 17:13:11 +02:00
],
2020-04-16 00:38:42 +02:00
depends=['state'], select=True)
description = fields.Char('Description', states=STATES, select=True)
cause = fields.Char('Cause', states=STATES)
permissons = fields.Char('Permissons', states=STATES)
journal = fields.Many2One('account.journal', 'Journal', required=True,
states=STATES)
currency = fields.Many2One('currency.currency', 'Currency',
required=True, states={
'readonly': ((Eval('state') != 'draft')
| (Eval('lines', [0]) & Eval('currency'))),
2023-09-12 17:13:11 +02:00
},
2020-04-16 00:38:42 +02:00
depends=['state'])
move = fields.Many2One('account.move', 'Move', readonly=True)
2021-08-03 18:16:51 +02:00
contract = fields.Many2One('staff.contract', 'Contract',
2021-02-04 16:45:22 +01:00
states=STATES, domain=[('employee', '=', Eval('employee'))])
2020-04-16 00:38:42 +02:00
account = fields.Many2One('account.account', 'Account',
required=True, domain=[
2021-06-09 18:07:42 +02:00
('type', '!=', None),
2020-04-16 00:38:42 +02:00
])
payrolls = fields.Function(fields.Many2Many('staff.payroll',
None, None, 'Payroll', depends=['start_period', 'end_period'],
2023-09-12 17:13:11 +02:00
domain=[
('employee', '=', Eval('employee')),
('kind', '=', 'normal'),
],), 'get_payrolls')
2020-04-16 00:38:42 +02:00
start = fields.Function(fields.Date('Start Date'), 'get_dates')
end = fields.Function(fields.Date('End Date'), 'get_dates')
2021-02-04 16:45:22 +01:00
party_to_pay = fields.Many2One('party.party', 'Party to Pay', states=STATES)
2021-07-21 00:21:59 +02:00
last_salary = fields.Numeric('Last Salary', states=STATES,
digits=(16, 2))
2020-04-16 00:38:42 +02:00
@classmethod
def __setup__(cls):
super(Liquidation, cls).__setup__()
cls._transitions |= set((
2021-02-04 16:45:22 +01:00
('draft', 'cancel'),
('cancel', 'draft'),
('confirmed', 'draft'),
('confirmed', 'posted'),
('draft', 'confirmed'),
('posted', 'draft'),
))
2020-04-16 00:38:42 +02:00
cls._buttons.update({
'draft': {
'invisible': Eval('state') == 'draft',
},
'confirm': {
'invisible': Eval('state') != 'draft',
},
'cancel': {
'invisible': Eval('state') != 'draft',
},
'post': {
'invisible': Eval('state') != 'confirmed',
},
'compute_liquidation': {
'invisible': Bool(Eval('lines')),
},
})
2020-04-16 00:38:42 +02:00
2022-01-19 20:50:37 +01:00
@classmethod
def __register__(cls, module_name):
super(Liquidation, cls).__register__(module_name)
cursor = Transaction().connection.cursor()
sql_table = cls.__table__()
cursor.execute(*sql_table.update(
2023-09-12 17:13:11 +02:00
[sql_table.kind], ['holidays'],
where=sql_table.kind == 'vacation'))
2022-01-19 20:50:37 +01:00
2020-04-16 00:38:42 +02:00
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_kind():
return 'contract'
@staticmethod
def default_state():
return 'draft'
@staticmethod
def default_currency():
Company = Pool().get('company.company')
company = Transaction().context.get('company')
if company:
company = Company(company)
return company.currency.id
@staticmethod
def default_journal():
Configuration = Pool().get('staff.configuration')
configuration = Configuration(1)
if configuration.default_journal:
return configuration.default_journal.id
@classmethod
def search_rec_name(cls, name, clause):
if clause[1].startswith('!') or clause[1].startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
2020-11-04 02:24:58 +01:00
return [
bool_op,
('employee',) + tuple(clause[1:]),
('number',) + tuple(clause[1:]),
2020-04-16 00:38:42 +02:00
]
@classmethod
@ModelView.button
@Workflow.transition('confirmed')
def confirm(cls, records):
for rec in records:
2021-08-03 18:16:51 +02:00
if not rec.contract:
2023-09-12 17:13:11 +02:00
raise LiquidationEmployeeError(
gettext('staff_payroll_co.msg_dont_contract'))
2020-04-16 00:38:42 +02:00
rec.set_number()
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, records):
pass
@classmethod
@ModelView.button
@Workflow.transition('cancel')
def cancel(cls, records):
pass
@classmethod
@ModelView.button
@Workflow.transition('posted')
def post(cls, records):
for rec in records:
rec.create_move()
@classmethod
2020-11-27 06:34:19 +01:00
def create_withholding(cls, liquidation):
rec = liquidation
pool = Pool()
UvtWithholding = pool.get('staff.payroll.uvt_withholding')
WageType = pool.get('staff.wage_type')
2023-05-11 00:07:51 +02:00
fields_names = [
'unit_price_formula', 'concepts_salary', 'salary_constitute',
'name', 'sequence', 'definition', 'unit_price_formula',
'expense_formula', 'uom', 'default_quantity', 'type_concept',
'salary_constitute', 'receipt', 'concepts_salary',
'contract_finish', 'limit_days', 'month_application',
'minimal_amount', 'adjust_days_worked', 'round_amounts',
2023-09-12 23:43:04 +02:00
'debit_account.name', 'credit_account.name',
2023-05-11 00:07:51 +02:00
'deduction_account.name', 'account_60_40.name'
]
2023-09-12 17:13:11 +02:00
wage_tax = WageType.search_read([('type_concept', '=', 'tax')],
fields_names=fields_names)
2020-11-27 06:34:19 +01:00
if not wage_tax:
return
2020-11-27 06:34:19 +01:00
wage_tax = wage_tax[0]
deductions_month = sum([
2023-09-12 17:13:11 +02:00
ln.amount for ln in rec.lines if ln.wage.definition != 'payment'
2020-11-27 06:34:19 +01:00
])
salary_full = rec.net_payment
payrolls = {p.end: p for p in rec.payrolls}
2020-12-03 22:18:04 +01:00
if not payrolls:
return
2020-11-27 06:34:19 +01:00
max_date = max(payrolls.keys())
if rec.liquidation_date.month == max_date.month:
payroll = payrolls[max_date]
line_tax = None
for line in payroll.lines:
if line.wage_type.type_concept == 'tax' and line.amount:
line_tax = line
if not line_tax:
deductions_month += payroll.get_deductions_month()
salary_args = payroll.get_salary_full(wage_tax)
salary_full += salary_args['salary']
base_salary_withholding = salary_full - deductions_month
amount_tax = UvtWithholding.compute_withholding(
2023-09-12 17:13:11 +02:00
base_salary_withholding)
2020-11-27 06:34:19 +01:00
amount_tax = rec.currency.round(Decimal(amount_tax))
if amount_tax:
create_tax = {
2023-05-11 00:07:51 +02:00
'sequence': wage_tax['sequence'],
'wage': wage_tax['id'],
'description': wage_tax['name'],
2020-11-27 06:34:19 +01:00
'amount': amount_tax * -1,
'days': rec.time_contracting,
2023-05-16 18:21:58 +02:00
'account': wage_tax['credit_account.']['id'],
2020-11-27 06:34:19 +01:00
}
cls.write([rec], {
'lines': [('create', [create_tax])]
2021-02-04 16:45:22 +01:00
})
2020-04-16 00:38:42 +02:00
@classmethod
@ModelView.button
def compute_liquidation(cls, records):
for rec in records:
rec.set_liquidation_lines()
2020-11-27 06:34:19 +01:00
cls.create_withholding(rec)
2020-04-16 00:38:42 +02:00
@classmethod
def copy(cls, records, default=None):
2023-09-12 17:13:11 +02:00
raise RecordDuplicateError(
gettext('staff_payroll_co.msg_cannot_duplicate_record'))
2020-04-16 00:38:42 +02:00
def get_dates(self, name):
2021-10-27 18:49:32 +02:00
res = None
if self.contract:
if name == 'start':
values = [self.start_period.start]
if self.contract.start_date:
values.append(self.contract.start_date)
res = max(values)
elif name == 'end':
values = [self.end_period.end]
if self.contract.end_date:
values.append(self.contract.end_date)
res = min(values)
2020-04-16 00:38:42 +02:00
return res
def get_payrolls(self, name):
if not self.employee or not self.contract:
return
Payroll = Pool().get('staff.payroll')
2020-12-08 12:45:42 +01:00
date_start, date_end = self._get_dates()
2020-04-16 00:38:42 +02:00
payrolls = Payroll.search([
('employee', '=', self.employee.id),
('start', '>=', date_start),
('end', '<=', date_end),
('contract', '=', self.contract.id),
])
payrolls_ids = [payroll.id for payroll in payrolls]
return payrolls_ids
2021-07-21 00:21:59 +02:00
def get_salary(self, name):
res = 0
if self.contract:
if name == 'last_salary':
res = self.contract.salary
elif name == 'salary_average':
Payroll = Pool().get('staff.payroll')
Wage = Pool().get('staff.wage_type')
wage, = Wage.search([('type_concept', '=', 'unemployment')])
2023-09-12 17:13:11 +02:00
res = Payroll.get_salary_average(
self.end,
self.employee,
self.contract, wage)
2021-07-21 00:21:59 +02:00
values = [self.end_period.end]
2021-08-04 22:46:00 +02:00
if self.contract.end_date:
values.append(self.contract.end_date)
2021-07-21 00:21:59 +02:00
res = min(values)
return res
2020-04-16 00:38:42 +02:00
def create_move(self):
pool = Pool()
Move = pool.get('account.move')
MoveLine = pool.get('account.move.line')
Period = pool.get('account.period')
if self.move:
return
move_lines, grouped = self.get_moves_lines()
if move_lines:
period_id = Period.find(self.company.id, date=self.liquidation_date)
move, = Move.create([{
'journal': self.journal.id,
2022-05-03 15:38:28 +02:00
'origin': str(self),
2020-04-16 00:38:42 +02:00
'period': period_id,
'date': self.liquidation_date,
'description': self.description,
'lines': [('create', move_lines)],
}])
self.write([self], {'move': move.id})
for ml in move.lines:
2023-09-12 17:13:11 +02:00
statement = ml.account.type.statement
account_id = ml.account.id
if account_id not in grouped.keys() or (statement not in ('balance')):
2020-04-16 00:38:42 +02:00
continue
to_reconcile = [ml]
2023-09-12 17:13:11 +02:00
to_reconcile.extend(grouped[account_id]['lines'])
2021-08-06 16:42:00 +02:00
if len(to_reconcile) > 1:
MoveLine.reconcile(set(to_reconcile))
2020-06-12 07:07:52 +02:00
Move.post([move])
2020-04-16 00:38:42 +02:00
def get_moves_lines(self):
2023-10-03 18:31:00 +02:00
Configuration = Pool().get('staff.configuration')
configuration = Configuration(1)
tax = getattr(configuration, 'tax_withholding')
2020-04-16 00:38:42 +02:00
lines_moves = []
to_reconcile = []
grouped = {}
amount = []
2023-10-03 18:31:00 +02:00
party_id = self.employee.party.id
2020-04-16 00:38:42 +02:00
for line in self.lines:
definition = line.wage.definition
concept = line.wage.type_concept
2020-04-16 00:38:42 +02:00
if line.move_lines:
for moveline in line.move_lines:
to_reconcile.append(moveline)
2022-12-22 15:36:06 +01:00
account_id = moveline.account.id
2022-12-23 15:34:32 +01:00
amount_line = moveline.debit - moveline.credit * -1
2022-12-22 15:36:06 +01:00
if account_id not in grouped.keys():
grouped[account_id] = {
2020-04-16 00:38:42 +02:00
'amount': [],
2023-09-14 22:09:55 +02:00
'description': line.description,
2020-04-16 00:38:42 +02:00
'lines': [],
}
2022-12-22 15:36:06 +01:00
grouped[account_id]['amount'].append(amount_line)
grouped[account_id]['lines'].append(moveline)
amount.append(amount_line)
elif concept in concept_social_security:
if definition == 'payment':
account_credit = line.account.id
if account_credit not in grouped.keys():
grouped[account_credit] = {
'amount': [],
'description': line.description,
'lines': [],
'party_to_pay': line.party_to_pay,
}
grouped[account_credit]['amount'].append(line.amount * -1)
account_debit = line.wage.debit_account.id
if account_debit not in grouped.keys():
grouped[account_debit] = {
'amount': [],
'description': line.description,
'lines': [],
'party_to_pay': line.party_to_pay,
}
grouped[account_debit]['amount'].append(line.amount)
else:
account_id = line.account.id
if account_id not in grouped.keys():
grouped[account_id] = {
'amount': [],
'description': line.description,
'lines': [],
'party_to_pay': line.party_to_pay,
}
grouped[account_id]['amount'].append(line.amount)
amount.append(line.amount)
if line.wage.expense_formula:
expense = line.get_expense_amount()
debit_account = line.wage.debit_account
grouped[account_id]['amount'].append(expense * -1)
if debit_account not in grouped.keys():
grouped[debit_account] = {
'amount': [],
'description': line.description,
'lines': [],
'party_to_pay': line.party_to_pay,
}
grouped[debit_account]['amount'].append(expense)
for adjust in line.adjustments:
2022-08-02 16:48:40 +02:00
key = adjust.account.id
if key not in grouped.keys():
2022-12-22 15:36:06 +01:00
grouped[key] = {
'amount': [],
'description': adjust.description,
2020-04-16 00:38:42 +02:00
'lines': [],
2023-09-12 23:43:04 +02:00
'party_to_pay': line.party_to_pay
2020-04-16 00:38:42 +02:00
}
2022-08-02 16:48:40 +02:00
if hasattr(adjust, 'analytic_account') and adjust.analytic_account:
2022-12-22 15:36:06 +01:00
grouped[key]['analytic'] = adjust.analytic_account
2023-10-03 18:31:00 +02:00
if tax and line.tax_base:
tax_line = {
'amount': line.tax_base,
'tax': tax.id,
'type': 'base',
}
grouped[key]['tax_lines'] = [('create', [tax_line])]
grouped[adjust.account.id]['amount'].append(adjust.amount)
amount.append(adjust.amount)
2022-08-02 16:48:40 +02:00
2020-04-16 00:38:42 +02:00
for account_id, values in grouped.items():
2020-12-03 19:58:38 +01:00
_amount = sum(values['amount'])
2023-10-03 18:31:00 +02:00
party = values.get('party_to_pay', party_id)
if not party:
party = party_id
line = {
'description': values['description'],
'debit': _amount,
'credit': _ZERO,
'account': account_id,
'party': party,
'tax_lines': values.get('tax_lines', None),
}
# debit = _amount
# credit = _ZERO
lines_moves.append(self._prepare_line(line, values.get('analytic')))
2020-04-16 00:38:42 +02:00
if lines_moves:
2023-10-03 18:31:00 +02:00
line = {
'description': self.description,
'debit': _ZERO,
'credit': sum(amount),
'account': self.account.id,
'party': self.party_to_pay if self.party_to_pay else party_id,
}
lines_moves.append(self._prepare_line(line))
2020-04-16 00:38:42 +02:00
return lines_moves, grouped
2023-10-03 18:31:00 +02:00
def _prepare_line(self, line, analytic=None):
if line['debit'] < _ZERO:
line['credit'] = abs(line['debit'])
line['debit'] = _ZERO
elif line['credit'] < _ZERO:
line['debit'] = abs(line['credit'])
line['credit'] = _ZERO
# credit = abs(credit)
# debit = abs(debit)
# party_id = self.employee.party.id
# if party_to_pay:
# party_id = party_to_pay.id
# res = {
# 'description': description,
# 'debit': debit,
# 'credit': credit,
# 'account': account_id,
# 'party': party_id,
# }
2022-08-02 16:48:40 +02:00
if analytic:
2023-10-03 18:31:00 +02:00
line['analytic_lines'] = [
2022-08-02 16:48:40 +02:00
('create', [{
2023-10-03 18:31:00 +02:00
'debit': line['debit'],
'credit': line['credit'],
2022-08-02 16:48:40 +02:00
'account': analytic.id,
'date': self.liquidation_date
}])]
2023-10-03 18:31:00 +02:00
return line
2020-04-16 00:38:42 +02:00
2020-12-08 12:45:42 +01:00
def _get_dates(self):
2020-04-16 00:38:42 +02:00
date_end_contract = None
2021-02-04 20:15:05 +01:00
date_start = self.start_period.start
2020-04-16 00:38:42 +02:00
if self.contract.start_date > self.start_period.start:
date_start = self.contract.start_date
if self.contract.futhermores:
date_end_contract = self.contract.finished_date
2021-02-04 20:15:05 +01:00
date_end = self.end_period.end
2020-04-16 00:38:42 +02:00
if date_end_contract and date_end_contract <= self.end_period.end:
date_end = date_end_contract
elif self.contract.end_date and self.contract.end_date < self.end_period.end:
date_end = self.contract.end_date
return date_start, date_end
2021-02-18 17:51:38 +01:00
def _get_dates_liquidation(self):
# date_end_contract = None
date_start = self.start_period.start
if self.contract.start_date > self.start_period.start:
date_start = self.contract.start_date
2023-09-14 22:09:55 +02:00
date_end = self.end_period.end
if self.kind == 'contract':
date_end = self.contract.finished_date
2021-02-18 17:51:38 +01:00
return date_start, date_end
@classmethod
2023-09-12 17:13:11 +02:00
def get_moves_lines_pending(cls, employee, wage_type, effective_date, moves=[]):
MoveLine = Pool().get('account.move.line')
lines = []
if not wage_type.credit_account:
return
account_id = wage_type.credit_account.id
2023-09-12 17:13:11 +02:00
domain = [
2021-02-09 22:57:29 +01:00
('move.date', '<=', effective_date),
('credit', '>', 0),
('account', '=', account_id),
('party', '=', employee.party.id),
('reconciliation', '=', None),
2023-10-02 16:48:13 +02:00
[
'OR',
('move.origin', 'not ilike', 'staff.payroll'),
('move.origin', '=', None),
]
2023-09-12 17:13:11 +02:00
]
lines1 = MoveLine.search(domain)
lines2 = []
2023-09-12 17:13:11 +02:00
if moves:
domain = [
('credit', '>', 0),
('account', '=', account_id),
('party', '=', employee.party.id),
('reconciliation', '=', None),
('move', 'in', moves),
]
lines2 = MoveLine.search(domain)
lines = set(lines1 + lines2)
return lines
@classmethod
def delete(cls, records):
# Cancel before delete
cls.cancel(records)
for liquidation in records:
if liquidation.state != 'cancel':
raise LiquidationDeleteError(
gettext('staff_payroll_co.msg_delete_cancel', liquidation=liquidation.rec_name))
if liquidation.move:
raise LiquidationDeleteError(
gettext('staff_payroll_co.msg_existing_move', liquidation=liquidation.rec_name))
2022-06-02 16:48:12 +02:00
super(Liquidation, cls).delete(records)
2020-04-16 00:38:42 +02:00
def set_liquidation_lines(self):
pool = Pool()
Payroll = pool.get('staff.payroll')
LiquidationMove = pool.get('staff.liquidation.line-move.line')
2021-02-18 17:51:38 +01:00
date_start, date_end = self._get_dates_liquidation()
2020-04-16 00:38:42 +02:00
payrolls = Payroll.search([
('employee', '=', self.employee.id),
('start', '>=', date_start),
('end', '<=', date_end),
('contract', '=', self.contract.id),
2021-08-06 16:42:00 +02:00
('state', '=', 'posted')
2020-04-16 00:38:42 +02:00
])
wages = {}
wages_target = {}
2023-09-12 17:13:11 +02:00
moves = [p.move.id for p in payrolls]
2020-04-16 00:38:42 +02:00
for payroll in payrolls:
for l in payroll.lines:
2023-09-16 00:43:35 +02:00
wage = l.wage_type
print(wage, wage.contract_finish, wage.provision_cancellation, self.kind, 'asasdasd')
if wage.contract_finish or wage.provision_cancellation:
if wage.provision_cancellation and not wage.contract_finish:
wage = wage.provision_cancellation
2023-09-16 00:43:35 +02:00
if self.kind == 'contract':
print(wage.type_concept, 'validate2323')
2023-09-16 00:43:35 +02:00
if wage.type_concept not in CONTRACT:
continue
elif self.kind != wage.type_concept:
2020-04-16 00:38:42 +02:00
continue
print('va a buscar')
2023-09-16 00:43:35 +02:00
if wage.id not in wages_target.keys():
mlines = self.get_moves_lines_pending(
payroll.employee, wage, date_end, moves
)
if not mlines:
continue
wages_target[wage.id] = [
wage.credit_account.id,
mlines,
wage,
]
for (account_id, lines, wage_type) in wages_target.values():
values = []
lines_to_reconcile = []
for line in lines:
values.append(abs(line.debit - line.credit))
lines_to_reconcile.append(line.id)
2022-01-25 20:08:32 +01:00
value = self.get_line_(wage_type, sum(values), self.time_contracting, account_id, party=self.party_to_pay)
lines = LiquidationMove.search([
('move_line', 'in', lines_to_reconcile)
])
if lines:
liquidation = lines[0].line.liquidation
raise RecordDuplicateError(
2023-01-23 14:52:49 +01:00
gettext('staff_payroll_co.msg_duplicate_liquidation',
liquidation=liquidation.id, state=liquidation.state))
2022-01-25 20:08:32 +01:00
value.update({
'move_lines': [('add', lines_to_reconcile)],
2022-01-25 20:08:32 +01:00
})
wages[wage_type.id] = value
2020-04-16 00:38:42 +02:00
2022-08-02 16:48:40 +02:00
self.write([self], {'lines': [('create', wages.values())]})
2022-01-25 20:08:32 +01:00
if self.kind == 'contract':
self.process_loans_to_pay()
2023-09-15 00:25:35 +02:00
# self.calculate_discounts()
2022-01-25 20:08:32 +01:00
def get_line_(self, wage, amount, days, account_id, party=None):
value = {
'sequence': wage.sequence,
'wage': wage.id,
'account': account_id,
'description': wage.name,
'amount': amount,
'days': days,
'party_to_pay': party,
}
return value
def calculate_social_security(self):
2023-09-14 22:09:55 +02:00
LiquidationLine = Pool().get('staff.liquidation.line')
wages = [mw for mw in self.employee.mandatory_wages \
if mw.wage_type.type_concept in concept_social_security]
2023-09-14 22:09:55 +02:00
lines_to_create = []
for mw in wages:
2023-09-14 22:09:55 +02:00
wage = mw.wage_type
concepts_salary = [c.id for c in wage.concepts_salary]
if concepts_salary:
salary_full = sum(
line.amount for line in self.lines if line.wage.id in concepts_salary)
amount = wage.compute_unit_price(
wage.unit_price_formula,
{'salary': salary_full})
if amount > 0:
if wage.definition != 'payment':
amount = amount * -1
2023-09-14 22:09:55 +02:00
value = self.get_line_(
wage, amount,
2023-09-14 22:09:55 +02:00
1,
wage.credit_account.id,
2023-09-14 22:09:55 +02:00
party=mw.party)
value['liquidation'] = self
lines_to_create.append(value)
LiquidationLine.create(lines_to_create)
2022-01-25 20:08:32 +01:00
def process_loans_to_pay(self):
pool = Pool()
MoveLine = pool.get('account.move.line')
LoanLine = pool.get('staff.loan.line')
LiquidationLine = pool.get('staff.liquidation.line')
dom = [
('loan.wage_type', '!=', None),
('loan.party', '=', self.employee.party.id),
('state', 'in', ['pending', 'partial']),
]
lines_loan = LoanLine.search(dom)
for m in lines_loan:
move_lines = MoveLine.search([
('origin', 'in', ['staff.loan.line,' + str(m)]),
])
party = m.loan.party_to_pay.id if m.loan.party_to_pay else None
2022-12-23 15:34:32 +01:00
res = self.get_line_(m.loan.wage_type, m.amount * -1, 1, m.loan.account_debit.id, party=party)
res['move_lines'] = [('add', move_lines)]
res['liquidation'] = self.id
line_, = LiquidationLine.create([res])
LoanLine.write([m], {'state': 'paid', 'origin': line_})
2020-04-16 00:38:42 +02:00
@fields.depends('start_period', 'end_period', 'contract')
def on_change_with_time_contracting(self):
delta = None
if self.start_period and self.end_period and self.contract:
2021-02-04 17:35:52 +01:00
try:
date_start, date_end = self._get_dates()
2021-12-16 15:03:03 +01:00
delta = self.contract.get_time_days(date_start, date_end)
2023-09-12 17:13:11 +02:00
except Exception:
2021-06-09 18:07:42 +02:00
raise LiquidationEmployeeError(
gettext('staff_payroll_co.msg_error_dates', s=self.employee.party.name))
2021-02-04 17:58:02 +01:00
delta = 0
2020-04-16 00:38:42 +02:00
return delta
2021-07-21 00:21:59 +02:00
def on_change_contract(self):
if self.contract:
self.last_salary = self.contract.salary
2020-04-16 00:38:42 +02:00
def set_number(self):
if self.number:
return
pool = Pool()
Configuration = pool.get('staff.configuration')
configuration = Configuration(1)
if not configuration.staff_liquidation_sequence:
2021-06-09 18:07:42 +02:00
raise MissingSecuenceLiquidation(
gettext('staff_payroll_co.msg_sequence_missing'))
seq = configuration.staff_liquidation_sequence.get()
self.write([self], {'number': seq})
2020-04-16 00:38:42 +02:00
def get_sum_operation(self, name):
res = []
for line in self.lines:
if not line.amount:
continue
2023-09-16 00:17:47 +02:00
if name == 'gross_payments' and line.wage.definition == 'payment' and line.wage.type_concept not in concept_social_security:
2020-04-16 00:38:42 +02:00
res.append(line.amount)
elif name == 'total_deductions' and line.wage.definition != 'payment':
res.append(line.amount)
return sum(res)
def get_net_payment(self, name):
2021-08-06 16:42:00 +02:00
res = (self.gross_payments or 0) - abs((self.total_deductions or 0))
2021-02-04 17:26:53 +01:00
if res:
return self.currency.round(res)
return 0
2020-04-16 00:38:42 +02:00
def get_currency(self, name):
return self.company.currency.id
class LiquidationLine(ModelSQL, ModelView):
'Staff Liquidation Line'
__name__ = 'staff.liquidation.line'
sequence = fields.Integer('Sequence', required=True)
liquidation = fields.Many2One('staff.liquidation', 'Liquidation',
2020-11-04 02:24:58 +01:00
required=True)
2020-04-16 00:38:42 +02:00
wage = fields.Many2One('staff.wage_type', 'Wage Type', required=True)
description = fields.Char('Description', required=True)
2020-12-08 12:45:42 +01:00
amount = fields.Numeric('Amount', digits=(16, 2), required=True,
depends=['adjustments', 'move_lines'])
2020-04-16 00:38:42 +02:00
days = fields.Integer('Days')
notes = fields.Char('Notes')
account = fields.Many2One('account.account', 'Account')
move_lines = fields.Many2Many('staff.liquidation.line-move.line',
'line', 'move_line', 'Liquidation Line - Move Line',
2020-11-04 02:24:58 +01:00
domain=[
2020-04-16 00:38:42 +02:00
('party', '=', Eval('party')),
('account', '=', Eval('account')),
], depends=['party', 'account'])
party = fields.Function(fields.Many2One('party.party', 'Party'),
'get_party')
2020-12-08 12:45:42 +01:00
adjustments = fields.One2Many('staff.liquidation.line_adjustment',
'staff_liquidation_line', 'Adjustments')
2021-02-04 16:45:22 +01:00
party_to_pay = fields.Many2One('party.party', 'Party to Pay')
2021-07-21 00:21:59 +02:00
salary_average = fields.Function(fields.Numeric('Salary Average',
digits=(16, 2)), 'get_average_payroll')
2023-10-03 18:31:00 +02:00
tax_base = fields.Numeric('Tax Base', digits=(16, 2))
is_wage_tax = fields.Function(fields.Boolean('Is wage tax'),
'on_change_with_is_wage_tax')
2020-04-18 20:23:40 +02:00
2020-04-16 00:38:42 +02:00
@classmethod
def __setup__(cls):
super(LiquidationLine, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
@classmethod
def __register__(cls, module_name):
2021-06-09 18:07:42 +02:00
table_h = cls.__table_handler__(module_name)
2020-04-16 00:38:42 +02:00
# Migration from 4.0: remove hoard_amount
2021-06-09 18:07:42 +02:00
if table_h.column_exist('hoard_amount'):
table_h.drop_column('hoard_amount')
2020-04-16 00:38:42 +02:00
super(LiquidationLine, cls).__register__(module_name)
2023-10-13 21:49:52 +02:00
@fields.depends('wage')
2023-10-03 18:31:00 +02:00
def on_change_with_is_wage_tax(self, name=None):
2023-10-13 21:49:52 +02:00
if self.wage:
return self.wage.type_concept == 'tax'
2023-10-03 18:31:00 +02:00
return False
2020-04-16 00:38:42 +02:00
def get_party(self, name=None):
if self.liquidation.employee:
return self.liquidation.employee.party.id
@fields.depends('wage', 'description', 'amount', 'liquidation',
2020-11-04 02:24:58 +01:00
'_parent_liquidation.employee', '_parent_liquidation.time_contracting',
'_parent_liquidation.start_period', '_parent_liquidation.end_period',
'_parent_liquidation.currency', 'sequence')
2020-04-16 00:38:42 +02:00
def on_change_wage(self):
if not self.wage:
return
self.sequence = self.wage.sequence
self.description = self.wage.name
self.days = self.liquidation.time_contracting
@fields.depends('amount', 'adjustments', 'move_lines')
def on_change_with_amount(self, name=None):
2023-01-11 15:37:50 +01:00
if not self.adjustments and not self.move_lines:
amount_ = self.amount
else:
amount_ = 0
if self.adjustments:
amount_ += sum([ad.amount or 0 for ad in self.adjustments])
if self.move_lines:
amount_ += sum([(ml.credit - ml.debit) for ml in self.move_lines])
return amount_
2020-04-16 00:38:42 +02:00
2021-07-21 00:21:59 +02:00
def get_average_payroll(self, name):
contract = self.liquidation.contract
employee = self.liquidation.employee
end = self.liquidation.end
Payroll = Pool().get('staff.payroll')
2021-09-13 22:13:04 +02:00
try:
res = Payroll.get_salary_average(end, employee, contract, self.wage) * 30
except:
res = 0
2021-07-21 00:21:59 +02:00
return res
def get_expense_amount(self):
expense = 0
if self.wage.expense_formula:
concepts_salary = [c.id for c in self.wage.concepts_salary]
salary = sum(
line.amount for line in self.liquidation.lines if line.wage.id in concepts_salary)
expense = self.wage.compute_expense(self.wage.expense_formula, {'salary': salary})
return expense
2022-01-25 22:59:26 +01:00
@classmethod
def delete(cls, lines):
LoanLine = Pool().get('staff.loan.line')
loan_lines = LoanLine.search([
('origin', 'in', ['staff.liquidation.line,' + str(l.id) for l in lines])
])
LoanLine.write([m for m in loan_lines], {'state': 'pending', 'origin': None})
super(LiquidationLine, cls).delete(lines)
2020-04-16 00:38:42 +02:00
class LiquidationLineAdjustment(ModelSQL, ModelView):
'Liquidation Adjustment'
__name__ = 'staff.liquidation.line_adjustment'
2020-04-18 20:23:40 +02:00
staff_liquidation_line = fields.Many2One('staff.liquidation.line', 'Line',
required=True, select=True)
account = fields.Many2One('account.account', 'Acount',
required=True, domain=[
('company', '=', Eval('context', {}).get('company', -1)),
2021-06-09 18:07:42 +02:00
('type', '!=', None),
2020-04-18 20:23:40 +02:00
])
description = fields.Char('Description', required=True)
amount = fields.Numeric('Amount', digits=(10,2), required=True)
2020-04-16 00:38:42 +02:00
class LiquidationReport(Report):
__name__ = 'staff.liquidation.report'
class LiquidationLineMoveLine(ModelSQL):
"Liquidation Line - MoveLine"
__name__ = "staff.liquidation.line-move.line"
_table = 'staff_liquidation_line_move_line_rel'
line = fields.Many2One('staff.liquidation.line', 'Line',
ondelete='CASCADE', select=True, required=True)
move_line = fields.Many2One('account.move.line', 'Move Line',
ondelete='RESTRICT', select=True, required=True)
2020-04-18 20:23:40 +02:00
class LiquidationAdjustmentStart(ModelView):
'Create Liquidation Adjustment Start'
__name__ = 'staff.liquidation_adjustment.start'
wage_type = fields.Many2One('staff.wage_type', 'Wage Type', required=True, domain=[
('contract_finish', '=', True)
])
amount = fields.Numeric('Amount', required=True)
account = fields.Many2One('account.account', 'Acount',
required=True, domain=[
('company', '=', Eval('context', {}).get('company', -1)),
2021-06-09 18:07:42 +02:00
('type', '!=', None),
2020-04-18 20:23:40 +02:00
])
description = fields.Char('Description', required=True)
@fields.depends('wage_type', 'account')
def on_change_wage_type(self):
if self.wage_type and self.wage_type.debit_account:
self.account = self.wage_type.debit_account.id
2020-04-18 20:23:40 +02:00
class LiquidationAdjustment(Wizard):
'Create Liquidation Adjustment'
__name__ = 'staff.liquidation_adjustment'
start = StateView('staff.liquidation_adjustment.start',
'staff_payroll_co.liquidation_adjustment_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Create', 'accept', 'tryton-ok', default=True),
])
accept = StateTransition()
@classmethod
def __setup__(cls):
super(LiquidationAdjustment, cls).__setup__()
def create_adjustment(self, line):
LineAdjustment = Pool().get('staff.liquidation.line_adjustment')
adjust, = LineAdjustment.create([{
'staff_liquidation_line': line.id,
'account': self.start.account.id,
'description': self.start.description,
'amount': self.start.amount,
}])
return adjust
2020-04-18 20:23:40 +02:00
def transition_accept(self):
pool = Pool()
Liquidation = pool.get('staff.liquidation')
LiquidationLine = pool.get('staff.liquidation.line')
id_ = Transaction().context['active_id']
liquidation, = Liquidation.search([('id', '=', id_)])
line_created = None
if liquidation:
if liquidation.move:
2021-06-09 18:07:42 +02:00
raise LiquidationMoveError(
gettext('staff_payroll_co.msg_liquidation_with_move', s=liquidation.number))
for line in liquidation.lines:
if line.wage.id == self.start.wage_type.id:
if line.amount:
line.amount += self.start.amount
line.save()
line_created = self.create_adjustment(line)
if not line_created:
line, = LiquidationLine.create([{
2020-06-13 01:50:41 +02:00
'sequence': len(liquidation.lines) + 1,
'liquidation': liquidation.id,
'wage': self.start.wage_type.id,
'description': self.start.wage_type.name,
'amount': self.start.amount,
}])
self.create_adjustment(line)
2020-04-18 20:23:40 +02:00
return 'end'
2020-06-10 22:59:25 +02:00
class LiquidationGroupStart(ModelView):
'Liquidation Group Start'
__name__ = 'staff.liquidation_group.start'
start_period = fields.Many2One('staff.payroll.period', 'Start Period',
2021-02-04 20:15:05 +01:00
required=True)
2020-06-10 22:59:25 +02:00
end_period = fields.Many2One('staff.payroll.period', 'End Period',
2021-02-04 20:15:05 +01:00
required=True, depends=['start_period'])
2020-06-10 22:59:25 +02:00
kind = fields.Selection([
2023-09-12 17:13:11 +02:00
('contract', 'Contract'),
('bonus_service', 'Bonus Service'),
('interest', 'Interest'),
('holidays', 'Vacation'),
('unemployment', 'Unemployment'),
], 'Kind', required=True)
2020-06-10 22:59:25 +02:00
liquidation_date = fields.Date('Liquidation Date', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
description = fields.Char('Description', required=True)
2020-12-03 22:04:55 +01:00
account = fields.Many2One('account.account', 'Account', required=True,
domain=[
2021-06-09 18:07:42 +02:00
('type.payable', '=', True),
2020-06-10 22:59:25 +02:00
('company', '=', Eval('company'))
])
2021-06-05 01:15:33 +02:00
employees = fields.Many2Many('company.employee', None, None, 'Employee')
2021-02-04 16:45:22 +01:00
party_to_pay = fields.Many2One('party.party', 'Party to Pay', states={
'invisible': Eval('kind') != 'unemployment'
})
2020-06-10 22:59:25 +02:00
@staticmethod
def default_company():
return Transaction().context.get('company')
class LiquidationGroup(Wizard):
'Liquidation Group'
__name__ = 'staff.liquidation_group'
start = StateView('staff.liquidation_group.start',
2020-11-04 02:24:58 +01:00
'staff_payroll_co.liquidation_group_start_view_form', [
2020-06-13 01:50:41 +02:00
Button('Cancel', 'end', 'tryton-cancel'),
Button('Accept', 'open_', 'tryton-ok', default=True),
2020-11-04 02:24:58 +01:00
])
2020-06-10 22:59:25 +02:00
open_ = StateTransition()
def transition_open_(self):
pool = Pool()
Liquidation = pool.get('staff.liquidation')
2020-06-12 03:55:45 +02:00
Contract = pool.get('staff.contract')
2021-02-04 16:45:22 +01:00
Employee = pool.get('company.employee')
2021-06-05 00:49:33 +02:00
Period = pool.get('staff.payroll.period')
2021-02-04 20:15:05 +01:00
to_liquidation = []
2020-06-10 22:59:25 +02:00
start_period = self.start.start_period.id
end_period = self.start.end_period.id
kind = self.start.kind
liquidation_date = self.start.liquidation_date
company_id = self.start.company.id
description = self.start.description
currency_id = self.start.company.currency.id
account_id = self.start.account.id
2021-06-05 00:49:33 +02:00
start_date = self.start.start_period.start
end_date = self.start.end_period.end
periods = Period.search([
('start', '>=', start_date),
('start', '<=', end_date)
])
2020-12-03 22:04:55 +01:00
dom_contracts = [('kind', '=', kind)]
if self.start.employees:
employees = self.start.employees
employee_ids = [e.id for e in employees]
dom_contracts.append(('employee', 'in', employee_ids))
2021-02-04 16:45:22 +01:00
else:
2021-06-05 01:07:58 +02:00
employees = Employee.search([('contract', '!=', None)])
2020-12-03 22:04:55 +01:00
2021-06-05 00:49:33 +02:00
if periods:
periods_ids = [p.id for p in periods]
dom_contracts.append(('start_period', 'in', periods_ids))
dom_contracts.append(('end_period', 'in', periods_ids))
2020-12-03 22:04:55 +01:00
contracts = Liquidation.search_read(
dom_contracts, fields_names=['contract']
)
2020-06-10 22:59:25 +02:00
contract_ids = [i['contract'] for i in contracts]
for employee in employees:
2020-06-12 04:00:17 +02:00
contracts = Contract.search([
('employee', '=', employee.id),
('id', 'not in', contract_ids),
2020-06-12 06:41:33 +02:00
])
2020-12-03 22:04:55 +01:00
if not contracts:
continue
contract = contracts[0]
if kind == 'unemployment':
wages = [
mw for mw in employee.mandatory_wages
if mw.wage_type.type_concept == 'unemployment'
]
if not wages:
continue
wage = wages[0]
lines = Liquidation.get_moves_lines_pending(
2021-02-09 22:57:29 +01:00
employee, wage.wage_type, self.start.end_period.end
)
if not lines:
continue
2020-12-03 22:04:55 +01:00
lqt_create = {
'start_period': start_period,
'end_period': end_period,
'employee': employee.id,
'contract': contract.id,
'kind': kind,
'liquidation_date': liquidation_date,
'time_contracting': None,
'state': 'draft',
'company': company_id,
'description': description,
'currency': currency_id,
2021-02-04 16:45:22 +01:00
'account': account_id,
'party_to_pay': self.start.party_to_pay.id if self.start.party_to_pay else None
2020-12-03 22:04:55 +01:00
}
2020-12-09 21:49:53 +01:00
liq, = Liquidation.create([lqt_create])
liq.time_contracting = liq.on_change_with_time_contracting()
liq.save()
2021-02-04 20:15:05 +01:00
to_liquidation.append(liq)
2020-06-10 22:59:25 +02:00
2021-02-04 20:15:05 +01:00
Liquidation.compute_liquidation(to_liquidation)
2020-06-10 22:59:25 +02:00
return 'end'
class MoveProvisionBonusServiceStart(ModelView):
'Move Privision Bonus Service Start'
__name__ = 'staff.move_provision_bonus_service.start'
period = fields.Many2One('staff.payroll.period', 'Period',
required=True, domain=[('state', '=', 'open')])
description = fields.Char('Description', required=True)
company = fields.Many2One('company.company', 'Company',
required=True)
wage_type = fields.Many2One('staff.wage_type', 'Wage Types', domain=[
('type_concept', '=', 'bonus_service')
], required=True)
category = fields.Many2One('staff.employee_category', 'Category')
@staticmethod
def default_company():
return Transaction().context.get('company')
class MoveProvisionBonusService(Wizard):
'Move Provision Bonus Service'
__name__ = 'staff.move_provision_bonus_service'
start = StateView('staff.move_provision_bonus_service.start',
'staff_payroll_co.move_provision_bonus_service_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Accept', 'open_', 'tryton-ok', default=True),
])
open_ = StateTransition()
def transition_open_(self):
pool = Pool()
Contract = pool.get('staff.contract')
Move = pool.get('account.move')
AccountPeriod = pool.get('account.period')
configuration = Pool().get('staff.configuration')(1)
journal_id = None
if configuration and configuration.default_journal:
journal_id = configuration.default_journal.id
_end_date = self.start.period.end
_company = self.start.company
provision_wage = self.start.wage_type
period_days = (self.start.period.end - self.start.period.start).days + 1
dom_contract = [
2020-11-04 02:24:58 +01:00
['AND', ['OR', [
('end_date', '>', self.start.period.start),
2020-11-04 02:24:58 +01:00
], [
('end_date', '=', None),
],
2020-11-04 02:24:58 +01:00
]],
]
if self.start.category:
dom_contract.append(
('employee.category', '=', self.start.category.id)
)
for contract in Contract.search(dom_contract):
2020-06-17 16:04:57 +02:00
period_in_month = 1 if period_days > 15 else 2
salary_amount = contract.get_salary_in_date(_end_date)
base_ = salary_amount
move_lines = []
employee = contract.employee
for concept in contract.employee.mandatory_wages:
if concept.wage_type and concept.wage_type.salary_constitute:
if concept.wage_type.type_concept == 'transport':
2020-06-17 16:04:57 +02:00
base_ += concept.wage_type.compute_unit_price({'salary': 0}) * concept.wage_type.default_quantity
if concept.fix_amount:
base_ += concept.fix_amount
period_id = AccountPeriod.find(_company.id, date=_end_date)
provision_amount = provision_wage.compute_unit_price(
2020-06-17 16:04:57 +02:00
{'salary': (round((base_ / period_in_month), 2))}
2020-11-04 02:24:58 +01:00
)
move_lines.extend([
{
'debit': provision_amount,
'credit': 0,
'party': employee.party.id,
'account': provision_wage.debit_account.id
},
{
'debit': 0,
'credit': provision_amount,
'party': employee.party.id,
2020-06-17 16:28:55 +02:00
'account': provision_wage.credit_account.id
}
])
move, = Move.create([{
'journal': journal_id,
# 'origin': str(contract),
'period': period_id,
'company': _company.id,
'date': _end_date,
'state': 'draft',
'description': self.start.description,
'lines': [('create', move_lines)],
}])
return 'end'
2021-02-23 22:47:31 +01:00
class LiquidationExportStart(ModelView):
'Liquidation Export Start'
__name__ = 'staff.liquidation_export.start'
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
department = fields.Many2One('company.department', 'Department')
kind = fields.Selection([
('contract', 'Contract'),
('bonus_service', 'Bonus Service'),
('interest', 'Interest'),
('unemployment', 'Unemployment'),
('vacation', 'Vacation'),
], 'Kind')
@staticmethod
def default_company():
return Transaction().context.get('company')
@fields.depends('start_date')
def on_change_with_end_date(self, name=None):
if self.start_date:
return self.start_date
class LiquidationExport(Wizard):
'Liquidation Export'
__name__ = 'staff.liquidation_export'
start = StateView('staff.liquidation_export.start',
'staff_payroll_co.liquidation_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('staff.liquidation_export.report')
def do_print_(self, action):
department_id = None
if self.start.department:
department_id = self.start.department.id
data = {
2021-06-09 18:07:42 +02:00
'ids': [],
2021-02-23 22:47:31 +01:00
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'department': department_id,
'kind': self.start.kind,
}
return action, data
def transition_print_(self):
return 'end'
class LiquidationExportReport(Report):
__name__ = 'staff.liquidation_export.report'
@classmethod
def get_domain_liquidation(cls, data):
dom_liquidation = []
return dom_liquidation
@classmethod
2021-06-09 18:07:42 +02:00
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
2021-02-23 22:47:31 +01:00
pool = Pool()
user = pool.get('res.user')(Transaction().user)
Liquidation = pool.get('staff.liquidation')
Department = pool.get('company.department')
dom_liq = cls.get_domain_liquidation(data)
dom_liq.append(('state', 'in', ['processed', 'posted', 'draft']),)
dom_liq.append(('liquidation_date', '>=', data['start_date']),)
dom_liq.append(('liquidation_date', '<=', data['end_date']),)
if data['department']:
2021-07-13 22:35:41 +02:00
dom_liq.append(('employee.department', '=', data['department']),)
2021-02-23 22:47:31 +01:00
department = Department(data['department']).name
else:
department = None
if data['kind']:
dom_liq.append(('kind', '=', data['kind']))
liquidations = Liquidation.search(dom_liq)
# default_vals = cls.default_values()
sum_gross_payments = []
sum_total_deductions = []
sum_net_payment = []
parties = {}
payments = ['interest', 'holidays', 'bonus_service', 'unemployment']
for liquidation in liquidations:
employee_id = liquidation.employee.id
if employee_id not in parties.keys():
position_employee = liquidation.employee.position.name if liquidation.employee.position else ''
position_contract = liquidation.contract.position.name if liquidation.contract and liquidation.contract.position else ''
parties[employee_id] = {}
parties[employee_id]['employee_code'] = liquidation.employee.code
parties[employee_id]['employee_contract'] = liquidation.contract.id
parties[employee_id]['employee'] = liquidation.employee.party.name
parties[employee_id]['employee_id_number'] = liquidation.employee.party.id_number
parties[employee_id]['employee_position'] = position_contract or position_employee or ''
for line in liquidation.lines:
2022-01-05 17:43:27 +01:00
concept = None
2021-02-23 22:47:31 +01:00
if line.wage.type_concept in (payments):
concept = line.wage.type_concept
else:
2022-01-05 17:51:14 +01:00
if line.wage.definition == 'payment':
2021-02-23 22:47:31 +01:00
concept = 'others_payments'
elif line.wage.definition == 'deduction' or \
line.wage.definition == 'discount' and \
line.wage.receipt:
concept = 'others_deductions'
if not concept:
2021-06-09 18:07:42 +02:00
raise WageTypeConceptError(
gettext('staff_payroll_co.msg_type_concept_not_exists', s=line.wage.name))
2021-02-23 22:47:31 +01:00
if concept not in parties[employee_id].keys():
parties[employee_id][concept] = 0
parties[employee_id][concept] += line.amount
parties[employee_id]['time_contracting'] = liquidation.time_contracting
parties[employee_id]['net_payment'] = liquidation.net_payment
parties[employee_id]['gross_payments'] = liquidation.gross_payments
parties[employee_id]['total_deductions'] = liquidation.total_deductions
sum_gross_payments.append(liquidation.gross_payments)
sum_total_deductions.append(liquidation.total_deductions)
sum_net_payment.append(liquidation.net_payment)
employee_dict = {e['employee']: e for e in parties.values()}
report_context['records'] = sorted(employee_dict.items(), key=lambda t: t[0])
report_context['department'] = department
report_context['start_date'] = data['start_date']
report_context['end_date'] = data['end_date']
report_context['company'] = user.company
report_context['user'] = user
report_context['sum_gross_payments'] = sum(sum_gross_payments)
report_context['sum_net_payment'] = sum(sum_net_payment)
report_context['sum_total_deductions'] = sum(sum_total_deductions)
return report_context
class LiquidationDeduction(Wizard):
'Liquidation Deduction'
__name__ = 'staff.liquidation_calculate_social_security'
start_state = 'calculate_social_security'
calculate_social_security = StateTransition()
def transition_calculate_social_security(self):
Liquidation = Pool().get('staff.liquidation')
liquidations_ids = Transaction().context['active_ids']
if liquidations_ids:
liquidations = Liquidation.browse(liquidations_ids)
for liq in liquidations:
liq.calculate_social_security()
return 'end'