Merge pull request #46 from expsa/migration-modules

exp_payroll_custom
This commit is contained in:
ahmed-nouri051 2025-10-09 18:16:15 +02:00 committed by GitHub
commit d42a805664
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
60 changed files with 15351 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizard
from . import report

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
{
'name': 'HR Advance Payroll',
'version': '18.0.1.0.0',
'category': 'Odex25-HR/Odex25-HR',
'sequence': 4,
'website': 'http://exp-sa.com',
'license': 'GPL-3',
'author': 'Expert Co. Ltd.',
'summary': 'Advance Payroll In HR',
'description': """
Helps you to manage All Payroll Requests of your company's staff.
""",
'depends': [
'exp_hr_payroll',
'hr_holidays_community',
'account',
'hr_contract',
'hr_base',
'report_xlsx',
'hr_contract_custom'
],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'security/ir_rule.xml',
'data/data.xml',
'views/salary_structure.xml',
# 'views/salary_advance.xml',
'views/payslip_view.xml',
'views/employee_promotions_view.xml',
'views/hr_salary_rules.xml',
'views/hr_salary_scale.xml',
'views/salary_scale_level_group.xml',
'views/hr_salary_scale_level.xml',
'views/hr_salary_scale_level_degree.xml',
'views/hr_recontract.xml',
'views/hr_employee.xml',
'views/hr_contract.xml',
'views/employee_reward_view.xml',
'views/payroll_report.xml',
'views/contract_advantage.xml',
'views/bank_pdf_report.xml',
'views/company_custom.xml',
'views/menu_security_cus.xml',
# menus
'views/payroll_menus.xml',
'views/hr_salary_menus.xml',
'wizard/payslip_monthly_report_view.xml',
'wizard/payroll_bank_report_view.xml',
'wizard/employee_selection_wizard.xml',
# reports templates
'templates/payroll_bank_text.xml',
'templates/hr_payslip_run_template.xml',
'templates/payslip_monthly_report.xml',
'templates/report_payslip_details.xml',
'templates/report_payslip.xml',
'templates/employee_cost_template.xml',
],
'installable': True,
'auto_install': False,
'application': True,
}

View File

@ -0,0 +1,36 @@
<odoo>
<data noupdate="1">
<!--Level sequence-->
<record id="level_sequence" model="ir.sequence">
<field name="name">level_sequence_name</field>
<field name="code">hr.salary.scale.level</field>
<field name="prefix">LO</field>
<field name="padding">5</field>
</record>
<!--Degree sequence-->
<record id="degree_sequence" model="ir.sequence">
<field name="name">degree_sequence_name</field>
<field name="code">hr.salary.scale.level.degree</field>
<field name="prefix">DO</field>
<field name="padding">5</field>
</record>
<!--Group sequence-->
<record id="group_sequence" model="ir.sequence">
<field name="name">group_sequence_name</field>
<field name="code">hr.salary.scale.level.group</field>
<field name="prefix">GO</field>
<field name="padding">5</field>
</record>
<!--Salary sequence-->
<record id="salary_scale_sequence" model="ir.sequence">
<field name="name">salary_sequence_name</field>
<field name="code">hr.payroll.structure</field>
<field name="prefix">SO</field>
<field name="padding">5</field>
</record>
</data>
</odoo>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from . import hr_salary_rules
from . import hr_salary_scale
from . import hr_salary_scale_level_group
from . import hr_salary_scale_level
from . import hr_salary_scale_level_degree
from . import hr_recontract
from . import hr_employee
from . import hr_contract
from . import salary_advance
from . import hr_advance_payslip
from . import employee_promotions
from . import employee_reward
from . import company_costum

View File

@ -0,0 +1,8 @@
from odoo import api, fields, models
class CompanyCustom(models.Model):
_inherit = 'res.company'
company_hr_no = fields.Char(string="Number Of Company For HR")
company_pay_no = fields.Char(string="Company Pay Number")

View File

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import models, fields, api, _, exceptions
class EmployeePromotions(models.Model):
_name = 'employee.promotions'
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'employee_id'
_description = 'Employee Promotions'
date = fields.Date(required=True)
comment = fields.Text()
state = fields.Selection(selection=[('draft', _('Draft')),
('confirm', _('HR Officer')),
('hr_manager', _('HR Manager')),
('approved', _('Approved')), ('refuse', 'Refused')],
default='draft', tracking=True)
# relational fields
employee_id = fields.Many2one('hr.employee', domain=[('state', '=', 'open')])
old_scale = fields.Many2one('hr.payroll.structure')
old_level = fields.Many2one('hr.payroll.structure')
old_group = fields.Many2one('hr.payroll.structure')
old_degree = fields.Many2one('hr.payroll.structure')
old_level_2 = fields.Many2one('hr.payroll.structure')
old_group_2 = fields.Many2one('hr.payroll.structure')
old_degree_2 = fields.Many2one('hr.payroll.structure')
new_level = fields.Many2one('hr.payroll.structure', domain=[('id', 'in', [])])
new_group = fields.Many2one('hr.payroll.structure', domain=[('id', 'in', [])])
new_degree = fields.Many2one('hr.payroll.structure', domain=[('id', 'in', [])])
company_id = fields.Many2one('res.company', string='Company',default=lambda self: self.env.company)
@api.onchange('employee_id')
def store_level_group_and_degree_values(self):
if self.employee_id:
self.old_scale = self.employee_id.salary_scale
self.old_level = self.employee_id.salary_level
self.old_group = self.employee_id.salary_group
self.old_degree = self.employee_id.salary_degree
self.old_level_2 = self.employee_id.salary_level
self.old_group_2 = self.employee_id.salary_group
self.old_degree_2 = self.employee_id.salary_degree
# dynamic domain to get new level and new group domain
@api.onchange('old_scale')
def _get_new_level_and_new_group_domain(self):
for item in self:
if item.old_scale:
level_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.old_scale.id), ('type', '=', 'level')])
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.old_scale.id), ('type', '=', 'group')])
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.old_scale.id), ('type', '=', 'degree')])
domain = {'new_level': [('id', 'in', level_ids.ids)],
'new_group': [('id', 'in', group_ids.ids)],
'new_degree': [('id', 'in', degree_ids.ids)]}
return {'domain': domain}
else:
domain = {'new_level': [('id', 'in', [])],
'new_group': [('id', 'in', [])],
'new_degree': [('id', 'in', [])]}
return {'domain': domain}
# filter depend on salary_level
@api.onchange('new_level')
def onchange_salary_level(self):
for item in self:
if item.new_level:
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_level_id', '=', item.new_level.id), ('type', '=', 'group')])
return {'domain': {'new_group': [('id', 'in', group_ids.ids)],
'new_degree': [('id', 'in', [])]}}
else:
return {'domain': {'new_group': [('id', 'in', [])],
'new_degree': [('id', 'in', [])]}}
# dynamic domain to get new degree domain
@api.onchange('new_group')
def _get_new_degree_domain(self):
for item in self:
if item.new_group:
# item.new_degree = False
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_group_id', '=', item.new_group.id), ('type', '=', 'degree')])
domain = {'new_degree': [('id', 'in', degree_ids.ids)]}
return {'domain': domain}
else:
domain = {'new_degree': [('id', 'in', [])]}
return {'domain': domain}
def confirm(self):
module_obj = self.env['ir.module.module'].sudo()
modules = module_obj.search([('state', '=', 'installed'), ('name', '=', 'hr_disciplinary_tracking')])
year_promotion = datetime.strptime(str(self.date), '%Y-%m-%d').strftime('%y')
if modules:
employee_penalty = self.env['hr.penalty.register'].search([('employee_id', '=', self.employee_id.id),
('state', 'not in', ['draft', 'refuse'])])
if employee_penalty:
for penalty in employee_penalty:
year_penalty = datetime.strptime(str(penalty.date), '%Y-%m-%d').strftime('%y')
if year_promotion == year_penalty:
for punish in penalty.punishment_id:
if punish.type == "deprivation":
raise exceptions.Warning(_('You can not promotions Employee has Penalty %s in this '
'Period.') % punish.name)
self.state = 'confirm'
def hr_manager(self):
self.confirm()
self.state = 'hr_manager'
def approved(self):
for rec in self:
rec.employee_id.contract_id.write({
'salary_level': rec.new_level.id,
'salary_group': rec.new_group.id,
'salary_degree': rec.new_degree.id,
'salary': rec.new_degree.base_salary,
'salary_insurnce': rec.new_degree.base_salary,
})
rec.state = 'approved'
def act_refuse(self):
self.state = 'refuse'
# change state to draft
def re_draft(self):
for rec in self:
rec.employee_id.contract_id.write({
'salary_level': rec.old_level_2.id,
'salary_group': rec.old_group_2.id,
'salary_degree': rec.old_degree_2.id,
'salary': rec.old_degree_2.base_salary,
'salary_insurnce': rec.old_degree_2.base_salary,
})
rec.state = 'draft'
@api.model
def create(self, values):
result = super(EmployeePromotions, self).create(values)
result.old_level_2 = result.old_level
result.old_group_2 = result.old_group
result.old_degree_2 = result.old_degree
return result
def unlink(self):
for item in self:
if item.state != 'draft':
raise exceptions.Warning(_(
'You can not delete employee promotions for "%s" in state not in draft.') % item.employee_id.name)
return super(EmployeePromotions, self).unlink()
class HrEmployee(models.Model):
_inherit = 'hr.employee'
promotions_count = fields.Integer(compute='get_employee_promotions')
def get_employee_promotions(self):
for item in self:
promotions = item.sudo().env['employee.promotions'].search([
('state', '=', 'approved'), ('employee_id', '=', item.id)])
item.sudo().promotions_count = len(promotions)
return promotions

View File

@ -0,0 +1,477 @@
# -*- coding: utf-8 -*-
import calendar
from datetime import date, datetime
from odoo import models, fields, api, _, exceptions
class EmployeeReward(models.Model):
_name = 'hr.employee.reward'
_rec_name = 'allowance_name'
_inherit = ['mail.thread', 'mail.activity.mixin']
line_ids_reward = fields.One2many(comodel_name='lines.ids.reward', inverse_name='employee_reward_id',
string="Reward Line")
date = fields.Date(default=lambda self: fields.Date.today(), string="Date Request",
required=True, tracking=True)
date_from = fields.Date(string="Date From", tracking=True)
date_to = fields.Date(string="Date To", tracking=True)
allowance_reason = fields.Text(string="Reward Reason", required=True)
allowance_name = fields.Many2one('hr.salary.rule', string="Allowance Name")
percentage = fields.Float(string="Percentage%", default=100)
amount = fields.Float(string="Amount")
account_id = fields.Many2one('account.account')
journal_id = fields.Many2one('account.journal', string='Payment Method')
next_approve = fields.Text(string="Next Required Approval", compute="_get_nxt_approve")
reward_type = fields.Selection(
[('allowance', 'Allowance'), ('amount', 'Amount')], default='allowance')
transfer_type = fields.Selection(
[('accounting', 'Accounting'), ('payroll', 'Payroll')], default='accounting')
state = fields.Selection(
[('draft', 'Draft'), ('submitted', 'Submit'), ('hrm', 'HRM Approval'),
('done', 'GM Approval'), ('refused', 'Refused')], default='draft', tracking=True)
benefits_discounts = fields.Many2one(comodel_name='hr.salary.rule', string='Rewards/Benefits')
check_appraisal = fields.Boolean(string='Appraisal Percentage', default=False)
reward_once = fields.Boolean(string='Reward Once Yearly', default=False)
company_id = fields.Many2one('res.company', string='Company',
default=lambda self: self.env.company)
def action_add_employees(self):
self.ensure_one()
ctx = dict(self.env.context)
if not self.id:
ctx.update({
'default_reward_vals': {
'name': self.name,
}
})
else:
ctx['default_employee_reward_id'] = self.id
if self.percentage:
ctx['default_percentage'] = self.percentage
ctx['default_employee_id'] = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
return {
'name': _('Add Employees to Reward'),
'view_mode': 'form',
'res_model': 'employee.selection.wizard',
'type': 'ir.actions.act_window',
'target': 'new',
'context': ctx,
}
@api.onchange('amount')
def chick_amount_positive(self):
for item in self:
if item.amount < 0:
raise exceptions.Warning(_('The Amount Must Be Greater Than Zero'))
@api.depends('state')
def _get_nxt_approve(self):
for record in self:
if record.state == "draft":
record.next_approve = "Submit"
for line in record.line_ids_reward:
line.reward_state = "draft"
elif record.state == "submitted":
record.next_approve = "HRM Approval"
for line in record.line_ids_reward:
line.reward_state = "submitted"
elif record.state == "hrm":
record.next_approve = "GM Approval"
for line in record.line_ids_reward:
line.reward_state = "hrm"
elif record.state == "done":
for line in record.line_ids_reward:
line.reward_state = "done"
elif record.state == "refused":
for line in record.line_ids_reward:
line.reward_state = "refused"
def action_submit(self):
if not self.line_ids_reward:
raise exceptions.Warning(_('Sorry, Can Not Request without The Employees'))
self.state = "submitted"
for line in self.line_ids_reward:
line.check_reward_once()
line.reward_state = "submitted"
def recalculate(self):
for line in self.line_ids_reward:
# line.amount = line.amount
# line.percentage = line.percentage
line._compute_calculate_amount()
def action_hrm(self):
self.state = "hrm"
for line in self.line_ids_reward:
line.check_reward_once()
line.reward_state = "hrm"
def action_done(self):
if self.transfer_type == 'accounting':
for item in self:
for record in item.line_ids_reward:
debit_line_vals = {
'name': record.employee_id.name,
'debit': record.amount,
'account_id': item.account_id.id,
'partner_id': record.employee_id.user_id.partner_id.id,
'analytic_account_id': record.employee_id.department_id.analytic_account_id.id
}
credit_line_vals = {
'name': record.employee_id.name,
'credit': record.amount,
'account_id': item.journal_id.default_account_id.id
#'partner_id': record.employee_id.user_id.partner_id.id
}
if not record.move_id:
move = record.env['account.move'].create({
'state': 'draft',
'journal_id': item.journal_id.id,
'date': item.date,
'ref': record.employee_id.name,
'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)],
'res_model': 'hr.employee.reward',
'res_id': self.id
})
record.move_id = move.id
self.state = "done"
for line in self.line_ids_reward:
line.reward_state = "done"
if self.transfer_type == 'payroll':
last_day_of_current_month = date.today().replace(
day=calendar.monthrange(date.today().year, date.today().month)[1])
first_day_of_current_month = date.today().replace(day=1)
for item in self:
for record in item.line_ids_reward:
if record.employee_id.contract_id:
advantage_arc = record.env['contract.advantage'].create({
'benefits_discounts': item.benefits_discounts.id,
'type': 'customize',
'date_from': item.date_from,
'date_to': item.date_to,
'amount': record.amount,
'reward_id': True,
'employee_id': record.employee_id.id,
'contract_advantage_id': record.employee_id.contract_id.id,
'out_rule': True,
'state': 'confirm',
'comments': item.allowance_reason})
record.advantage_id = advantage_arc.id
else:
raise exceptions.Warning(_(
'Employee "%s" has no contract Please create contract to add line to advantages')
% record.employee_id.name)
self.state = "done"
for line in self.line_ids_reward:
line.reward_state = "done"
def action_refuse(self):
self.state = "refused"
for line in self.line_ids_reward:
line.reward_state = "refused"
def re_draft(self):
# when redraft cancel the created account move
if self.transfer_type == 'payroll':
for record in self.line_ids_reward:
record.advantage_id.draft()
record.advantage_id.unlink()
record.reward_state = "draft"
self.state = "draft"
if self.transfer_type == 'accounting':
if self.transfer_type == 'accounting':
if self.line_ids_reward and self.line_ids_reward[0].move_id:
move_id_not_draft = False
for line in self.line_ids_reward:
if line.move_id.state == 'posted':
move_id_not_draft_name = line.move_id.name
move_id_not_draft = True
if move_id_not_draft:
raise exceptions.Warning(_(
'You can not cancel account move "%s" in state not draft') % move_id_not_draft_name)
else:
for record in self.line_ids_reward:
# record.move_id.write({'state': 'canceled'})
record.move_id.unlink()
record.write({'move_id': False, })
#record.account_id = False
#record.journal_id = False
record.reward_state = "draft"
self.write({'state': 'draft'})
#self.account_id = False
#self.journal_id = False
else:
self.write({
'state': 'draft',
#'account_id': False,
#'journal_id': False
})
for record in self.line_ids_reward:
record.write({
'move_id': False,
#'account_id': False,
#'journal_id': False,
'reward_state': 'draft'
})
def unlink(self):
for i in self:
if i.state != 'draft':
raise exceptions.Warning(_('You can not delete record in state not in draft'))
i.line_ids_reward.unlink()
return super(EmployeeReward, self).unlink()
@api.onchange('transfer_type', 'account_id', 'journal_id', 'line_ids_reward')
def onchange_transfer_type(self):
if self.transfer_type == 'payroll':
self.account_id = False
self.journal_id = False
for line in self.line_ids_reward:
line.account_id = False
line.journal_id = False
if self.transfer_type == 'accounting':
for line in self.line_ids_reward:
if self.state == 'hrm':
if not line.account_id:
line.account_id = self.account_id
if not line.journal_id:
line.journal_id = self.journal_id
else:
line.account_id = False
line.journal_id = False
@api.onchange('account_id')
def onchange_account_id(self):
for line in self.line_ids_reward:
self.recalculate()
line.account_id = self.account_id
@api.onchange('journal_id')
def onchange_journal_id(self):
for line in self.line_ids_reward:
self.recalculate()
line.journal_id = self.journal_id
class HrEmployee(models.Model):
_name = 'lines.ids.reward'
def _domain_get_employee(self):
return [('id', '!=', self.employee_id.id), ('state', '=', 'open')]
employee_reward_id = fields.Many2one('hr.employee.reward', string='Employee', required=True)
employee_id = fields.Many2one('hr.employee', string='Employee', required=True,
domain=lambda self: self._domain_get_employee())
amount = fields.Float(string="Amount", compute='_compute_calculate_amount', store=True)
account_id = fields.Many2one('account.account', string='Account')
journal_id = fields.Many2one('account.journal', string='Payment Method')
percentage = fields.Float(string="Percentage%")
move_id = fields.Many2one('account.move')
contract_advantage_id = fields.Many2one('hr.contract')
reward_state = fields.Selection(
[('draft', 'Draft'), ('submitted', 'Submit'), ('hrm', 'HRM Approval'),
('done', 'GM Approval'), ('refused', 'Refused')], default='draft')
amount_base = fields.Float(string="Amount Base", store=True)
check_appraisal = fields.Boolean('Appraisal Percentage', related='employee_reward_id.check_appraisal', store=True)
transfer_type = fields.Selection(related='employee_reward_id.transfer_type', string='Transfer type')
reward_once = fields.Boolean(related='employee_reward_id.reward_once', store=True)
date = fields.Date(related='employee_reward_id.date', string='Reward Once Yearly', tracking=True, store=True)
advantage_id = fields.Many2one(comodel_name='contract.advantage', string='Allowance Employee')
reward_type = fields.Selection(related='employee_reward_id.reward_type', string='Reward Type', store=True)
@api.onchange('amount_base')
def chick_amount_base_positive(self):
for item in self:
if item.amount_base < 0:
raise exceptions.Warning(_('The Employee %s Amount Must Be Greater Than Zero')% item.employee_id.name)
# Select employee once in reward Line
@api.onchange('employee_id')
def select_employee_once(self):
employee_ids = self.env['hr.employee'].search([('state', '=', 'open')]).ids
for line in self.employee_reward_id.line_ids_reward:
if line.employee_id:
if line.employee_id.id in employee_ids:
employee_ids.remove(line.employee_id.id)
return {'domain': {'employee_id': [('id', 'in', employee_ids)]}}
def get_salary_rules_account(self, record_id, amount, items):
record = self.env['hr.salary.rule.line'].create({
'salary_rule_id': record_id.id,
'amount': amount,
})
items.append(record.id)
def compute_salary_rule(self, record_id, item, items):
for record in self:
if not record.employee_id.id: continue
contract = self.env['hr.contract'].search([('employee_id', '=', record.employee_id.id)])
localdict = dict(employee=record.employee_id.id, contract=contract)
amount, total = 0.0, 0.0
if item.amount_select == 'fix':
if contract.advantages:
for con in contract.advantages:
if item.id == con.benefits_discounts.id:
if con.type == 'exception':
if con.amount > item._compute_rule(localdict)[0] or con.amount == \
item._compute_rule(localdict)[0]:
pass
elif con.amount < item._compute_rule(localdict)[0]:
total = item._compute_rule(localdict)[0] - con.amount
elif con.type == 'customize':
total = con.amount
amount = 0
amount += total
else:
amount = 0
amount += item._compute_rule(localdict)[0]
else:
amount += item._compute_rule(localdict)[0]
elif item.amount_select == 'percentage':
if contract and contract.advantages:
for con in contract.advantages:
if item.id == con.benefits_discounts.id:
if con.type == 'exception':
if con.amount > item._compute_rule(localdict)[0] or con.amount == \
item._compute_rule(localdict)[0]:
pass
elif con.amount < item._compute_rule(localdict)[0]:
total = item._compute_rule(localdict)[0] - con.amount
elif con.type == 'customize':
total = con.amount
amount = 0
amount += total
break
else:
if amount:
pass
else:
amount += item._compute_rule(localdict)[0]
else:
amount += item._compute_rule(localdict)[0]
else:
if contract.advantages:
for con in contract.advantages:
if item.id == con.benefits_discounts.id:
if con.type == 'exception':
if con.amount > item._compute_rule(localdict)[0] or con.amount == \
item._compute_rule(localdict)[0]:
pass
elif con.amount < item._compute_rule(localdict)[0]:
total = item._compute_rule(localdict)[0] - con.amount
elif con.type == 'customize':
total = con.amount
amount = 0
amount += total
else:
if amount:
pass
else:
amount = 0
amount += item._compute_rule(localdict)[0]
else:
amount += item._compute_rule(localdict)[0]
return amount
@api.depends('percentage', 'employee_reward_id', 'employee_id', 'account_id', 'journal_id','amount_base')
def _compute_calculate_amount(self):
for line in self:
if line.check_appraisal == True:
self.get_percentage_appraisal()
percentage = line.percentage
if line.employee_reward_id.reward_type == 'allowance':
if line.employee_reward_id.allowance_name:
items = []
for item in line.employee_reward_id.allowance_name:
total = 0.0
record_id = self.env['hr.salary.rule'].search([('id', '=', item.id)])
total = self.compute_salary_rule(record_id, item, items) or 0
amount = (total * percentage) / 100
line.amount = amount
amount_base = total
line.amount_base = amount_base
elif line.employee_reward_id.reward_type == 'amount':
amount_up = line.employee_reward_id.amount
if amount_up > 0:
amount = (amount_up * percentage) / 100
line.amount = amount
amount_base = amount_up
line.amount_base = amount_base
else:
line.amount = (line.amount_base * percentage) / 100
else:
line.amount = 0
@api.model
def default_get(self, fields):
res = super(HrEmployee, self).default_get(fields)
if self._context.get('percentage'):
res['percentage'] = self._context.get('percentage')
if self._context.get('account_id') and self._context.get('journal_id'):
res['account_id'] = self._context.get('account_id')
res['journal_id'] = self._context.get('journal_id')
return res
# get percentage from performance appraisal
def get_percentage_appraisal(self):
Module = self.env['ir.module.module'].sudo()
modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_hr_appraisal')])
for line in self:
if modules:
emp_appraisal = self.env['hr.employee.appraisal'].search([('employee_id', '=', line.employee_id.id),
('state', '!=', 'draft'),
('appraisal_type', '=', 'performance')],
order='appraisal_date desc', limit=1)
level_achieved = emp_appraisal.level_achieved
if line.check_appraisal:
if emp_appraisal:
line.percentage = level_achieved
else:
line.percentage = 0
# To Cannot Take More Than Once Reward In The Same Year
@api.constrains('employee_id', 'date', 'reward_once')
def check_reward_once(self):
for rec in self:
if rec.date:
current_year = datetime.strptime(str(rec.date), "%Y-%m-%d").date().year
last_reward = rec.search([('id', '!=', rec.id), ('employee_id', '=', rec.employee_id.id),
('reward_state', 'not in', ('draft', 'refused')),
('reward_once', '=', True)], order='date desc', limit=1).date
if last_reward:
last_year = datetime.strptime(str(last_reward), "%Y-%m-%d").date().year
if current_year == last_year and rec.reward_once:
raise exceptions.Warning(_('Sorry, The Employee %s Cannot be Taking More Than Once Reward '
'In The Same Year %s') % (rec.employee_id.name, current_year))
def unlink(self):
for i in self:
if i.reward_state != 'draft':
raise exceptions.Warning(_('You can not delete record in state not in draft'))
return super(HrEmployee, self).unlink()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,349 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class HrContractSalaryScale(models.Model):
_inherit = 'hr.contract'
salary_level = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
salary_scale = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])], index=True)
salary_group = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
salary_degree = fields.Many2one(comodel_name='hr.payroll.structure', domain=[('id', 'in', [])])
hide = fields.Boolean(string='Hide', compute="compute_type")
required_condition = fields.Boolean(string='Required Condition', compute='compute_move_type')
total_allowance = fields.Float(string='Total Allowance', compute='compute_function',store=True)
total_deduction = fields.Float(string='Total Deduction', compute='compute_function',store=True)
total_net = fields.Float(string='Total Net', compute='compute_function',store=True)
advantages = fields.One2many('contract.advantage', 'contract_advantage_id', string='Advantages')
house_allowance_temp = fields.Float(string='House Allowance', compute='compute_function',store=True)
transport_allowance = fields.Float(string='Transport Allowance', compute='compute_function',store=True)
@api.constrains('advantages', 'salary', 'salary_group')
def amount_constrains(self):
for rec in self:
localdict = dict(employee=rec.employee_id.id, contract=rec.env['hr.contract'].search([
('employee_id', '=', rec.employee_id.id)]))
if rec.salary_group.gread_max > 0 and rec.salary_group.gread_min > 0:
if rec.salary > rec.salary_group.gread_max or rec.salary < rec.salary_group.gread_min:
raise UserError(_('The Basic Salary Is Greater Than Group Gread Max Or less than Gread Min'))
for item in self.advantages:
item.to_get_contract_id()
if item.benefits_discounts._compute_rule(localdict)[0] < item.amount and item.type == 'exception':
raise UserError(_(
'The amount you put is greater than fact value of this Salary rule %s (%s).') % (
item.benefits_discounts.name, item.benefits_discounts.code))
@api.depends('salary_scale.transfer_type')
def compute_move_type(self):
self.compute_function()
if self.salary_scale.transfer_type == 'one_by_one':
self.required_condition = True
else:
self.required_condition = False
@api.depends('salary_scale', 'salary_level', 'salary_group', 'salary_degree','salary','advantages','house_allowance_temp','transport_allowance','total_deduction','salary_insurnce','total_allowance','state')
def compute_function(self):
for item in self:
item.house_allowance_temp = 0
item.transport_allowance = 0
item.total_net = 0
contract = self.env['hr.contract'].search([('employee_id', '=', item.employee_id.id)])
localdict = dict(employee=item.employee_id.id, contract=contract)
current_date = datetime.now().date()
# customize type in advantages
allowance_customize_items = item.advantages.filtered(
lambda key: key.type == 'customize' and key.out_rule is False and
key.benefits_discounts.category_id.rule_type == 'allowance' and
(datetime.strptime(str(key.date_to), "%Y-%m-%d").date() if key.date_to else current_date)
>= current_date >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date())
allow_sum_custom = sum(x.amount for x in allowance_customize_items)
for x in allowance_customize_items:
if x.benefits_discounts.rules_type == 'house':
item.house_allowance_temp += x.amount
if x.benefits_discounts.rules_type == 'transport':
item.transport_allowance += x.amount
# allow_custom_ids = [record.benefits_discounts.id for record in allowance_customize_items]
deduction_customize_items = item.advantages.filtered(
lambda key: key.type == 'customize' and key.out_rule is False and
key.benefits_discounts.category_id.rule_type == 'deduction' and
(datetime.strptime(str(key.date_to), "%Y-%m-%d").date() if key.date_to else current_date)
>= current_date >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date())
ded_sum_custom = sum(x.amount for x in deduction_customize_items)
ded_custom_ids = [record.benefits_discounts.id for record in deduction_customize_items]
# exception type in advantages
exception_items = item.advantages.filtered(lambda key: key.type == 'exception')
total_rule_result, sum_except, sum_customize_expect = 0.0, 0.0, 0.0
for x in exception_items:
rule_result = x.benefits_discounts._compute_rule(localdict)[0]
if x.date_from >= str(current_date):
total_rule_result = rule_result
elif str(current_date) > x.date_from:
if x.date_to and str(current_date) <= x.date_to:
total_rule_result = rule_result - x.amount
elif x.date_to and str(current_date) >= x.date_to:
total_rule_result = 0 # rule_result
elif not x.date_to:
total_rule_result = rule_result - x.amount
else:
if rule_result > x.amount:
total_rule_result = rule_result - x.amount
if total_rule_result:
if x.benefits_discounts.category_id.rule_type == 'allowance':
sum_customize_expect += total_rule_result
if x.benefits_discounts.rules_type == 'house':
item.house_allowance_temp += total_rule_result - x.amount
else:
sum_except += total_rule_result
if exception_items:
exception_items = item.advantages.filtered(
lambda key: (datetime.strptime(str(key.date_to),
"%Y-%m-%d").date().month if key.date_to else current_date.month)
>= current_date.month >= datetime.strptime(str(key.date_from), "%Y-%m-%d").date().month)
except_ids = [record.benefits_discounts.id for record in exception_items]
rule_ids = item.salary_scale.rule_ids.filtered(
lambda key: key.id not in ded_custom_ids and key.id not in except_ids)
level_rule_ids = item.salary_level.benefits_discounts_ids.filtered(lambda key: key.id not in except_ids)
# key.id not in allow_custom_ids and key.id not in ded_custom_ids and
group_rule_ids = item.salary_group.benefits_discounts_ids.filtered(lambda key: key.id not in except_ids)
# key.id not in allow_custom_ids and key.id not in ded_custom_ids and
total_allowance = 0
total_ded = 0
for line in rule_ids:
if line.category_id.rule_type == 'allowance':
try:
total_allowance += line._compute_rule(localdict)[0]
except:
total_allowance += 0
if line.category_id.rule_type == 'deduction':
try:
total_ded += line._compute_rule(localdict)[0]
except:
total_ded += 0
if line.rules_type == 'house':
item.house_allowance_temp += line._compute_rule(localdict)[0]
if line.rules_type == 'transport':
item.transport_allowance += line._compute_rule(localdict)[0]
item.total_allowance = total_allowance
item.total_deduction = -total_ded
if item.salary_level:
total_allowance = 0
total_deduction = 0
for line in level_rule_ids:
if line.category_id.rule_type == 'allowance':
try:
total_allowance += line._compute_rule(localdict)[0]
except:
total_allowance += 0
elif line.category_id.rule_type == 'deduction':
try:
total_deduction += line._compute_rule(localdict)[0]
except:
total_deduction += 0
item.total_allowance += total_allowance
item.total_deduction += -total_deduction
if item.salary_group:
total_allowance = 0
total_deduction = 0
for line in group_rule_ids:
if line.category_id.rule_type == 'allowance':
total_allowance += line._compute_rule(localdict)[0]
elif line.category_id.rule_type == 'deduction':
total_deduction += line._compute_rule(localdict)[0]
item.total_allowance += total_allowance
item.total_deduction += -total_deduction
item.total_allowance += allow_sum_custom
item.total_allowance += sum_customize_expect
item.total_deduction += -ded_sum_custom
item.total_deduction += -sum_except
item.total_net = item.total_allowance + item.total_deduction
# filter salary_level,salary_group,salary_degree
@api.onchange('salary_scale')
def onchange_salary_scale(self):
for item in self:
if item.salary_scale:
level_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'level')])
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'group')])
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'degree')])
return {'domain': {'salary_level': [('id', 'in', level_ids.ids)],
'salary_group': [('id', 'in', group_ids.ids)],
'salary_degree': [('id', 'in', degree_ids.ids)]}}
else:
item.total_allowance = 0.0
item.total_deduction = 0.0
item.total_net = 0.0
return {'domain': {'salary_level': [('id', 'in', [])],
'salary_group': [('id', 'in', [])],
'salary_degree': [('id', 'in', [])]}}
# filter depend on salary_level
@api.onchange('salary_level')
def onchange_salary_level(self):
for item in self:
if item.salary_level:
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_level_id', '=', item.salary_level.id), ('type', '=', 'group')])
return {'domain': {'salary_group': [('id', 'in', group_ids.ids)],
'salary_degree': [('id', 'in', [])]}}
else:
return {'domain': {'salary_group': [('id', 'in', [])],
'salary_degree': [('id', 'in', [])]}}
# filter depend on salary_group
@api.onchange('salary_group')
def onchange_salary_group(self):
for item in self:
if item.salary_group:
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_group_id', '=', item.salary_group.id), ('type', '=', 'degree')])
return {'domain': {'salary_degree': [('id', 'in', degree_ids.ids)]}}
else:
return {'domain': {'salary_degree': [('id', 'in', [])]}}
@api.depends('salary_degree')
def _get_amount(self):
for record in self:
record.transport_allowance_temp = record.transport_allowance * record.wage / 100 \
if record.transport_allowance_type == 'perc' else record.transport_allowance
record.house_allowance_temp = record.house_allowance * record.wage / 100 \
if record.house_allowance_type == 'perc' else record.house_allowance
record.communication_allowance_temp = record.communication_allowance * record.wage / 100 \
if record.communication_allowance_type == 'perc' else record.communication_allowance
record.field_allowance_temp = record.field_allowance * record.wage / 100 \
if record.field_allowance_type == 'perc' else record.field_allowance
record.special_allowance_temp = record.special_allowance * record.wage / 100 \
if record.special_allowance_type == 'perc' else record.special_allowance
record.other_allowance_temp = record.other_allowance * record.wage / 100 \
if record.other_allowance_type == 'perc' else record.other_allowance
@api.depends('contractor_type.salary_type')
def compute_type(self):
if self.contractor_type.salary_type == 'scale':
self.hide = True
else:
self.hide = False
class Advantages(models.Model):
_name = 'contract.advantage'
_rec_name = 'benefits_discounts'
_inherit = ['mail.thread', 'mail.activity.mixin']
date_from = fields.Date(string='Date From')
date_to = fields.Date(string='Date To')
amount = fields.Float(string='Amount', tracking=True)
type = fields.Selection(selection=[('customize', _('Customize')),
('exception', _('Exception'))], string='Type', default="customize")
# to link employee move line from official mission to advantages line in contract
official_mission_id = fields.Boolean(string="Official Mission", default=False)
# To link employee move line from over time to advantages line in contract
over_time_id = fields.Boolean(string="OverTime", default=False)
# To link employee move line from employee reward to advantages line in contract
reward_id = fields.Boolean(string="Reward", default=False)
penalty_id = fields.Boolean(string='Penalty Name', default=False)
# Relational fields
benefits_discounts = fields.Many2one(comodel_name='hr.salary.rule', string='Benefits/Discounts')
contract_advantage_id = fields.Many2one('hr.contract')
done = fields.Boolean(string="Done in Payroll")
out_rule = fields.Boolean(string="Out of Payroll", default=True)
employee_id = fields.Many2one('hr.employee', 'Employee Name', domain=[('state', '=', 'open')], tracking=True)
state = fields.Selection(selection=[('draft', _('Draft')), ('confirm', _('Confirmed')),
('refused', _('Refused'))],
default='draft', tracking=True)
comments = fields.Text(string='Comments')
payroll_month = fields.Text(string='Payroll Month', tracking=True)
company_id = fields.Many2one('res.company', string='Company', related='employee_id.company_id', store=True)
@api.constrains('date_from', 'date_to', 'amount')
def _chick_date(self):
for rec in self:
if rec.date_to:
if rec.date_to <= rec.date_from:
raise UserError(_('The Date Form Must be Less than Date To'))
if rec.amount <= 0:
raise UserError(_('The Amount Must be Greater Than Zero The Employee %s')% rec.employee_id.name)
def confirm(self):
self.state = 'confirm'
def refused(self):
self.state = 'refused'
def draft(self):
for rec in self:
rec.state = 'draft'
@api.onchange('employee_id')
def to_get_contract_id(self):
contract_id = self.employee_id.contract_id
self.employee_id = self.contract_advantage_id.employee_id.id
if contract_id:
self.contract_advantage_id = contract_id.id
self.employee_id = self.contract_advantage_id.employee_id.id
else:
return False
def unlink(self):
for item in self:
if item.state != 'draft':
raise UserError(_('You cannot delete The Salary rule %s For the Employee %s is Not Draft') % (
item.benefits_discounts.name, item.employee_id.name))
# if item.done == True:
# raise UserError(_('Sorry, The Salary rule %s For the Employee %s is Already Computed in Payroll') % (
# item.benefits_discounts.name, item.employee_id.name))
return super(Advantages, self).unlink()
@api.constrains('employee_id', 'date_from', 'date_to', 'benefits_discounts')
def check_rule_dates(self):
""" Function Can Not add Same Advantage at The Same Month
same employee.
"""
for rec in self:
domain = [
('date_from', '<=', rec.date_to),
('date_to', '>=', rec.date_from),
('employee_id', '=', rec.employee_id.id),
('id', '!=', rec.id),
('benefits_discounts', '=', rec.benefits_discounts.id), ]
advantages_id = self.search_count(domain)
if advantages_id:
# for adv in advantages_id:
raise UserError(
_('You Can Not add Same Allowance/Deduction at The Same Employee %s For The Same Month!')
% rec.employee_id.name)

View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class HrEmployeeSalaryScale(models.Model):
_inherit = 'hr.employee'
salary_scale = fields.Many2one(related='contract_id.salary_scale', string='Salary scale', store=True)
salary_level = fields.Many2one(related='contract_id.salary_level', string='Salary Level', store=True)
salary_group = fields.Many2one(related='contract_id.salary_group', string='Salary Group', store=True)
salary_degree = fields.Many2one(related='contract_id.salary_degree', string='Salary Degree', store=True)

View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class HrReContract(models.Model):
_inherit = 'hr.re.contract'
salary_scale = fields.Many2one('hr.payroll.structure', string='Salary Scale', compute='_get_employee_data')
salary_group = fields.Many2one('hr.payroll.structure', string='Salary Group', compute='_get_employee_data')
salary_level = fields.Many2one('hr.payroll.structure', string='Salary Level', compute='_get_employee_data')
salary_degree = fields.Many2one('hr.payroll.structure', string='Salary Degree', compute='_get_employee_data')
new_salary_scale = fields.Many2one(comodel_name='hr.payroll.structure')
new_salary_level = fields.Many2one(comodel_name='hr.payroll.structure')
new_salary_group = fields.Many2one(comodel_name='hr.payroll.structure')
new_salary_degree = fields.Many2one(comodel_name='hr.payroll.structure')
@api.onchange('new_salary_scale')
def onchange_new_salary_scale(self):
for item in self:
if item.new_salary_scale:
level_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.new_salary_scale.id), ('type', '=', 'level')])
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.new_salary_scale.id), ('type', '=', 'group')])
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.new_salary_scale.id), ('type', '=', 'degree')])
return {'domain': {'new_salary_level': [('id', 'in', level_ids.ids)],
'new_salary_group': [('id', 'in', group_ids.ids)],
'new_salary_degree': [('id', 'in', degree_ids.ids)]}}
else:
item.new_salary = 0.0
return {'domain': {'new_salary_level': [('id', 'in', [])],
'new_salary_group': [('id', 'in', [])],
'new_salary_degree': [('id', 'in', [])]}}
# filter depend on new_salary_level
@api.onchange('new_salary_level')
def onchange_new_salary_level(self):
for item in self:
if item.new_salary_level:
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_level_id', '=', item.new_salary_level.id), ('type', '=', 'group')])
return {'domain': {'new_salary_group': [('id', 'in', group_ids.ids)],
'new_salary_degree': [('id', 'in', [])]}}
else:
return {'domain': {'new_salary_group': [('id', 'in', [])],
'new_salary_degree': [('id', 'in', [])]}}
# filter depend on salary_group
@api.onchange('new_salary_group')
def onchange_salary_group(self):
for item in self:
if item.new_salary_group:
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_group_id', '=', item.new_salary_group.id), ('type', '=', 'degree')])
return {'domain': {'new_salary_degree': [('id', 'in', degree_ids.ids)]}}
else:
return {'domain': {'new_salary_degree': [('id', 'in', [])]}}
@api.onchange('new_salary_degree')
def onchange_degree(self):
if self.new_salary_degree:
self.new_salary = self.new_salary_degree.base_salary
@api.depends('employee_id')
def _get_employee_data(self):
for rec in self:
rec.hire_date = False
rec.contract_id = False
rec.start_date = False
rec.eoc_date = False
rec.job_id = False
rec.department_id = False
rec.salary_scale = False
rec.salary_level = False
rec.salary_group = False
rec.salary_degree = False
if rec.employee_id:
rec.hire_date = rec.employee_id.first_hiring_date
rec.contract_id = rec.employee_id.contract_id.id
rec.start_date = rec.employee_id.contract_id.date_start
rec.eoc_date = rec.employee_id.contract_id.date_end
rec.job_id = rec.employee_id.job_id.id
rec.department_id = rec.employee_id.department_id.id
rec.salary_scale = rec.employee_id.contract_id.salary_scale.id
rec.salary_level = rec.employee_id.contract_id.salary_level.id
rec.salary_group = rec.employee_id.contract_id.salary_group.id
rec.salary_degree = rec.employee_id.contract_id.salary_degree.id
def _get_default_category(self):
return self.env['hr.salary.rule.category'].search([('code', '=', 'NET')], limit=1)

View File

@ -0,0 +1,390 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import api, fields, models, _
from odoo.exceptions import UserError,ValidationError
from odoo.tools.safe_eval import safe_eval
class HrSalaryRuleAccount(models.Model):
_name = 'hr.salary.rule.account'
_description = 'Salary Rule Account Mapping'
rule_id = fields.Many2one('hr.salary.rule', string="Salary Rule", required=True, ondelete="cascade")
emp_type_id = fields.Many2one('hr.contract.type', string="Employee Type", required=True)
credit_account_id = fields.Many2one('account.account', string="Credit Account", required=True)
debit_account_id = fields.Many2one('account.account', string="Debit Account", required=True)
class HrSalaryRules(models.Model):
_inherit = 'hr.salary.rule'
start_date = fields.Date(string='Start Date', default=fields.date.today())
end_date = fields.Date(string='End Date')
salary_type = fields.Selection([('fixed', _('Fixed for all')),
('related_levels', _('Related with Levels')),
('related_groups', _('Related with Groups')),
('related_degrees', _('Related with Degrees'))], default="fixed",
string='Type Scale')
related_qualifications = fields.Boolean(string='Related with qualifications')
special = fields.Boolean(string='Special')
reduce_with_leaves = fields.Boolean(string='Reduce With Leaves',default=True)
min_leave_days_to_deduct = fields.Integer(string='Min Leave Days To Deduct')
company_id = fields.Many2one(comodel_name='res.company', string='Company', required=True,
default=lambda self: self.env.user.company_id)
discount_absence = fields.Selection([('by_day', _('By Day')),
('by_hour', _('By Hour')),
('no_discount', _('No discount'))],
default="no_discount", string='Discount Absence')
fixed_amount = fields.Integer(string='Fixed Amount')
# relational fields
related_benefits_discounts = fields.Many2many(comodel_name='hr.salary.rule',
relation='salary_rule_benefit_discount_rel',
column1='rule_id', column2='sub_rule_id',
string='Related Benefits and Discount')
salary_amount_ids = fields.One2many('related.salary.amount', 'salary_rule_id')
rule_credit_account_id = fields.Many2one('account.account')
rule_debit_account_id = fields.Many2one('account.account')
rules_type = fields.Selection([('salary', _('Salary Allowance')),
('house', _('House Allowance')),
('overtime', _('Overtime Allowance')),
('mandate', _('Mandate Allowance')),
('transport', _('Transport Allowance')),
('termination', _('End Of Services')),
('insurnce', _('Insurnce Deduction')),
('other', _('Other'))
], string='Rules Type')
account_ids = fields.One2many('hr.salary.rule.account', 'rule_id')
transfer_by_emp_type = fields.Boolean('Transfer By Employee Type')
def get_debit_account_id(self, emp_type):
if not self.transfer_by_emp_type: return self.rule_debit_account_id.id
account_mapping = self.sudo().account_ids.filtered(lambda a: a.emp_type_id.id == emp_type)
return account_mapping[0].debit_account_id.id if account_mapping else False
def get_credit_account_id(self, emp_type):
if not self.transfer_by_emp_type: return self.rule_credit_account_id.id
account_mapping = self.sudo().account_ids.filtered(lambda a: a.emp_type_id.id == emp_type)
return account_mapping[0].credit_account_id.id if account_mapping else False
@api.constrains('rules_type', 'category_id')
def _check_dates(self):
for rec in self:
if rec.category_id.rule_type != 'deduction' and rec.rules_type == 'insurnce':
raise UserError(_("The Salary Rule is Not Deduction"))
# Override function compute rule in hr salary rule
def _compute_rule(self, localdict):
payslip = localdict.get('payslip')
contract = localdict.get('contract')
if self.amount_select == 'percentage':
total_percent, total = 0, 0
if self.related_benefits_discounts:
for line in self.related_benefits_discounts:
calc_line = line._compute_rule(localdict)[0]
if line.amount_select == 'fix':
if contract.advantages:
for con in contract.advantages:
if line.id == con.benefits_discounts.id:
if payslip:
if con.date_from > payslip.date_from:
total_percent = calc_line
elif con.date_to is not None and str(
con.date_to) >= payslip.date_to or con.date_to is None:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent += total
else:
if str(con.date_from) < str(datetime.now().date()):
if con.date_to:
if datetime.strptime(str(con.date_to), "%Y-%m-%d").date().month \
>= datetime.now().date().month or not con.date_to:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent += total
else:
total_percent = calc_line
else:
total_percent += calc_line
elif line.amount_select == 'percentage':
if contract.advantages:
for con in contract.advantages:
if line.id == con.benefits_discounts.id:
if payslip:
if con.date_from > payslip.date_from:
total_percent = calc_line
elif con.date_to is not None and str(
con.date_to) >= payslip.date_to or con.date_to is None:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent -= calc_line
total_percent += total
else:
if str(con.date_from) < str(datetime.now().date()):
if con.date_to:
if datetime.strptime(str(con.date_to), "%Y-%m-%d").date().month \
>= datetime.now().date().month or not con.date_to:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent -= calc_line
total_percent += total
else:
if con.type != 'exception':
total_percent += calc_line
break
else:
total_percent += calc_line
else:
if contract.advantages:
for con in contract.advantages:
if line.id == con.benefits_discounts.id:
if payslip:
if con.date_from > payslip.date_from:
total_percent = calc_line
elif con.date_to is not None and con.date_to >= payslip.date_to or con.date_to is None:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent = 0
total_percent += total
else:
if con.date_from < (datetime.now().date()):
if con.date_to:
if datetime.strptime(str(con.date_to), "%Y-%m-%d").date().month \
>= datetime.now().date().month or not con.date_to:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount
total_percent = 0
total_percent += total
else:
if datetime.strptime(str(con.date_from),
"%Y-%m-%d").date().month >= datetime.now().date().month:
if con.type == 'exception':
if con.amount > calc_line or con.amount == calc_line:
pass
elif con.amount < calc_line:
total = calc_line - con.amount
elif con.type == 'customize':
total = con.amount + calc_line
total_percent = 0
total_percent += total
else:
if not total_percent:
total_percent = calc_line
else:
total_percent += calc_line
if total_percent:
if self.salary_type == 'fixed':
try:
return float(total_percent * self.amount_percentage / 100), \
float(safe_eval(self.quantity, localdict)), self.amount_percentage
except:
raise UserError(
_('Wrong percentage base or quantity defined for salary rule %s (%s).') % (
self.name, self.code))
elif self.salary_type == 'related_levels':
levels_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_level.id == contract.salary_level.id)
if levels_ids:
for l in levels_ids:
try:
return float(l.salary * total_percent / 100), float(
safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (
self.name, self.code))
else:
return 0, 0, 0
elif self.salary_type == 'related_groups':
groups_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_group.id == contract.salary_group.id)
if groups_ids:
for g in groups_ids:
try:
return float(g.salary * total_percent / 100), float(
safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (
self.name, self.code))
else:
return 0, 0, 0
elif self.salary_type == 'related_degrees':
degrees_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_degree.id == contract.salary_degree.id)
if degrees_ids:
for d in degrees_ids:
try:
return float(d.salary * total_percent / 100), float(
safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (
self.name, self.code))
else:
return 0, 0, 0
else:
try:
return 0, 0, 0
except:
raise UserError(_('There is no total for rule : %s') % self.name)
elif self.amount_select == 'fix':
if self.salary_type == 'fixed':
try:
return self.fixed_amount, float(safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(_('Wrong quantity defined for salary rule %s (%s).') % (self.name, self.code))
elif self.salary_type == 'related_levels':
levels_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_level.id == contract.salary_level.id)
if levels_ids:
for l in levels_ids:
try:
return l.salary, float(safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (self.name, self.code))
else:
return 0, 0, 0
elif self.salary_type == 'related_groups':
groups_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_group.id == contract.salary_group.id)
if groups_ids:
for g in groups_ids:
try:
return g.salary, float(safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (self.name, self.code))
else:
return 0, 0, 0
elif self.salary_type == 'related_degrees':
degrees_ids = self.salary_amount_ids.filtered(
lambda item: item.salary_scale_degree.id == contract.salary_degree.id)
if degrees_ids:
for d in degrees_ids:
try:
return d.salary, float(safe_eval(self.quantity, localdict)), 100.0
except:
raise UserError(
_('Wrong quantity defined for salary rule %s (%s).') % (self.name, self.code))
else:
return 0, 0, 0
else:
raise UserError(_('Error, Select Salary type to calculate rule'))
else:
try:
safe_eval(self.amount_python_compute, localdict, mode='exec', nocopy=True)
return float(localdict['result']), 'result_qty' in localdict and localdict[
'result_qty'] or 1.0, 'result_rate' in localdict and localdict['result_rate'] or 100.0
except:
raise UserError(_('Wrong python code defined for salary rule %s (%s).') % (self.name, self.code))
class SalaryConfig(models.Model):
_name = 'related.salary.amount'
salary_scale = fields.Many2one('hr.payroll.structure')
salary_scale_level = fields.Many2one('hr.payroll.structure')
salary_scale_group = fields.Many2one('hr.payroll.structure')
salary_scale_degree = fields.Many2one('hr.payroll.structure')
salary = fields.Float(string='Salary / Percentage')
# relations fields
salary_rule_id = fields.Many2one(comodel_name='hr.salary.rule')
# filter salary_level,salary_group,salary_degree
@api.onchange('salary_scale')
def onchange_salary_scale(self):
for item in self:
if item.salary_scale:
level_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'level')])
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'group')])
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale.id), ('type', '=', 'degree')])
return {'domain': {'salary_scale_level': [('id', 'in', level_ids.ids)],
'salary_scale_group': [('id', 'in', group_ids.ids)],
'salary_scale_degree': [('id', 'in', degree_ids.ids)]}}
else:
return {'domain': {'salary_scale_level': [('id', 'in', [])],
'salary_scale_group': [('id', 'in', [])],
'salary_scale_degree': [('id', 'in', [])]}}
# filter depend on salary_level
@api.onchange('salary_scale_level')
def onchange_salary_level(self):
for item in self:
if item.salary_scale_level:
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_level_id', '=', item.salary_scale_level.id), ('type', '=', 'group')])
return {'domain': {'salary_scale_group': [('id', 'in', group_ids.ids)],
'salary_scale_degree': [('id', 'in', [])]}}
else:
return {'domain': {'salary_scale_group': [('id', 'in', [])],
'salary_scale_degree': [('id', 'in', [])]}}
# filter depend on salary_group
@api.onchange('salary_scale_group')
def onchange_salary_group(self):
for item in self:
if item.salary_scale_group:
degree_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_group_id', '=', item.salary_scale_group.id), ('type', '=', 'degree')])
return {'domain': {'salary_scale_degree': [('id', 'in', degree_ids.ids)]}}
else:
return {'domain': {'salary_scale_degree': [('id', 'in', [])]}}
class SalaryRuleCategory(models.Model):
_inherit = 'hr.salary.rule.category'
rule_type = fields.Selection(selection=[('allowance', _('Allowance')), ('deduction', _('Deduction')),
('base', _('Base')), ('gross', _('Gross')),
('net', _('Net')), ('end_of_service', _('End of Service'))], string='Type')

View File

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class HrSalaryScale(models.Model):
_inherit = 'hr.payroll.structure'
active = fields.Boolean(string='Active', default=True)
start_date = fields.Date(string='Start Date')
end_date = fields.Date(string='End Date')
level_num = fields.Integer(string='Number Of Levels')
retirement_age = fields.Integer('Retirement Age', default=60)
type = fields.Selection(selection=[('scale', _('Scale')), ('level', _('Level')),
('group', _('Group')), ('degree', _('Degree'))], default='scale', string='Type')
transfer_type = fields.Selection(selection=[('all', _('All Employee')),
('per_analytic_account', _('Per Analytic Account')),
('one_by_one', _('Per Employee')),
('per_bank', _('Per Bank'))], string='Transfer type')
# relation fields
salary_scale_levels_ids = fields.One2many('hr.payroll.structure', 'salary_scale_id',
domain=[('type', '=', 'level')], store=True)
salary_scale_level_degrees_ids = fields.One2many('hr.payroll.structure', 'salary_scale_id',
domain=[('type', '=', 'degree')], store=True)
salary_scale_level_groups_ids = fields.One2many('hr.payroll.structure', 'salary_scale_id',
domain=[('type', '=', 'group')], store=True)
salary_scale_id = fields.Many2one('hr.payroll.structure', string='Salary Scale', index=True) # salary scale
#Percentage_increase = fields.Float('Percentage Increase %',default=0.05)
analytic_account_id = fields.Many2one(comodel_name='account.analytic.account')
# Override Function
def get_all_rules(self):
"""
@return: returns a list of tuple (id, sequence) of rules that are maybe to apply
"""
all_rules = []
for struct in self:
if struct.benefits_discounts_ids:
all_rules += struct.benefits_discounts_ids._recursive_search_of_rules()
else:
all_rules += struct.rule_ids._recursive_search_of_rules()
return all_rules
# filter salary_level,salary_group
@api.onchange('salary_scale_id')
def onchange_salary_scale_id(self):
for item in self:
if item.salary_scale_id:
level_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_id', '=', item.salary_scale_id.id), ('type', '=', 'level')])
item.salary_scale_level_id = []
item.salary_scale_group_id = []
return {'domain': {'salary_scale_level_id': [('id', 'in', level_ids.ids)]}}
# filter depend on salary_level
@api.onchange('salary_scale_level_id')
def onchange_salary_scale_level_id(self):
for item in self:
if item.salary_scale_level_id:
group_ids = self.env['hr.payroll.structure'].search(
[('salary_scale_level_id', '=', item.salary_scale_level_id.id), ('type', '=', 'group')])
item.salary_scale_group_id = []
return {'domain': {'salary_scale_group_id': [('id', 'in', group_ids.ids)]}}

View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class HrSalaryScaleLevel(models.Model):
_inherit = 'hr.payroll.structure'
groups_number = fields.Integer(string='Number Of Groups')
salary_scale_id = fields.Many2one('hr.payroll.structure', string='Salary Scale', index=True)
benefits_discounts_ids = fields.Many2many('hr.salary.rule', string='Benefits and discounts')

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class HrSalaryScaleDegree(models.Model):
_inherit = 'hr.payroll.structure'
base_salary = fields.Float(string='Base Salary')
interval_time = fields.Integer(string='Interval Time')
salary_scale_group_id = fields.Many2one(comodel_name='hr.payroll.structure', index=True)
@api.constrains('base_salary', 'salary_scale_group_id')
def base_salary_constrains(self):
if self.salary_scale_group_id.gread_max > 0 and self.salary_scale_group_id.gread_min > 0:
if self.base_salary > self.salary_scale_group_id.gread_max or \
self.base_salary < self.salary_scale_group_id.gread_min:
raise UserError(_('The Basic Salary Is Greater Than Group Gread Max Or less than Gread Min'))

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class HrSalaryScaleLevel(models.Model):
_inherit = 'hr.payroll.structure'
degree_number = fields.Integer(string='Number of Degrees')
salary_scale_level_id = fields.Many2one(comodel_name='hr.payroll.structure', string='Salary Scale Level',
index=True)
gread_min = fields.Float(string='Gread Min')
gread_max = fields.Float(string='Gread Max')
@api.constrains('gread_min', 'gread_max')
def zero_constrains(self):
if self.gread_max < 0 or self.gread_min < 0:
raise UserError(_('The Gread Max Or Gread Min is not Negative'))
if self.gread_max < self.gread_min:
raise UserError(_('The Gread Max Is Greater Than Gread Min'))

View File

@ -0,0 +1,180 @@
# -*- coding: utf-8 -*-
import time
from datetime import datetime
from odoo import exceptions
from odoo import fields, models, api, _
from odoo.exceptions import UserError
class SalaryAdvancePayment(models.Model):
_name = "salary.advance"
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string='Name', readonly=True, default=lambda self: 'Adv/')
employee_id = fields.Many2one(comodel_name='hr.employee', string='Employee', required=True, index=True)
date = fields.Date(string='Date', required=True, default=lambda self: fields.Date.today())
reason = fields.Text(string='Reason')
currency_id = fields.Many2one(comodel_name='res.currency', string='Currency', required=True,
default=lambda self: self.env.user.company_id.currency_id)
company_id = fields.Many2one(comodel_name='res.company', string='Company', required=True,
default=lambda self: self.env.user.company_id)
advance = fields.Float(string='Advance', required=True)
payment_method = fields.Many2one(comodel_name='account.journal', string='Payment Method')
exceed_condition = fields.Boolean(string='Exceed than maximum',
help="The Advance is greater than the maximum percentage in salary structure")
department = fields.Many2one(comodel_name='hr.department', string='Department')
state = fields.Selection(selection=[('draft', 'Draft'),
('submit', 'Submitted'),
('waiting_approval', 'Waiting Approval'),
('approve', 'Approved'),
('cancel', 'Cancelled'),
('reject', 'Rejected')], string='Status', default='draft', tracking=True)
debit = fields.Many2one(comodel_name='account.account', string='Debit Account')
credit = fields.Many2one(comodel_name='account.account', string='Credit Account')
journal = fields.Many2one(comodel_name='account.journal', string='Journal')
employee_contract_id = fields.Many2one(comodel_name='hr.contract', string='Contract')
@api.onchange('employee_id')
def onchange_employee_id(self):
department_id = self.employee_id.department_id.id
domain = [('employee_id', '=', self.employee_id.id)]
return {'value': {'department': department_id}, 'domain': {
'employee_contract_id': domain,
}}
@api.onchange('company_id')
def onchange_company_id(self):
company = self.company_id
domain = [('company_id.id', '=', company.id)]
result = {
'domain': {
'journal': domain,
},
}
return result
def submit_to_manager(self):
self.state = 'submit'
def cancel(self):
self.state = 'cancel'
def reject(self):
self.state = 'reject'
@api.model
def create(self, vals):
vals['name'] = self.env['ir.sequence'].get('salary.advance.seq') or ' '
res_id = super(SalaryAdvancePayment, self).create(vals)
return res_id
def approve_request(self):
"""This Approve the employee salary advance request.
"""
emp_obj = self.env['hr.employee']
address = emp_obj.browse([self.employee_id.id]).address_home_id
if not address.id:
raise UserError('Error!', 'Define home address for employee')
salary_advance_search = self.search([('employee_id', '=', self.employee_id.id), ('id', '!=', self.id),
('state', '=', 'approve')])
current_month = datetime.strptime(str(self.date), '%Y-%m-%d').date().month
for each_advance in salary_advance_search:
existing_month = datetime.strptime(str(each_advance.date), '%Y-%m-%d').date().month
if current_month == existing_month:
raise UserError('Error!', 'Advance can be requested once in a month')
if not self.employee_contract_id:
raise UserError('Error!', 'Define a contract for the employee')
struct_id = self.employee_contract_id.struct_id
if not struct_id.max_percent or not struct_id.advance_date:
raise UserError('Error!', 'Max percentage or advance days are not provided in Contract')
adv = self.advance
amt = (self.employee_contract_id.struct_id.max_percent * self.employee_contract_id.wage) / 100
if adv > amt and not self.exceed_condition:
raise UserError('Error!', 'Advance amount is greater than allotted')
if not self.advance:
raise UserError('Warning', 'You must Enter the Salary Advance amount')
payslip_obj = self.env['hr.payslip'].search([('employee_id', '=', self.employee_id.id),
('state', '=', 'done'), ('date_from', '<=', self.date),
('date_to', '>=', self.date)])
if payslip_obj:
raise UserError('Warning', "This month salary already calculated")
for slip in self.env['hr.payslip'].search([('employee_id', '=', self.employee_id.id)]):
slip_moth = datetime.strptime(str(slip.date_from), '%Y-%m-%d').date().month
if current_month == slip_moth + 1:
slip_day = datetime.strptime(str(slip.date_from), '%Y-%m-%d').date().day
current_day = datetime.strptime(str(self.date), '%Y-%m-%d').date().day
if current_day - slip_day < struct_id.advance_date:
raise exceptions.Warning(
_('Request can be done after "%s" Days From previous month salary') % struct_id.advance_date)
self.state = 'waiting_approval'
def approve_request_acc_dept(self):
"""This Approve the employee salary advance request from accounting department.
"""
salary_advance_search = self.search([('employee_id', '=', self.employee_id.id), ('id', '!=', self.id),
('state', '=', 'approve')])
current_month = datetime.strptime(str(self.date), '%Y-%m-%d').date().month
for each_advance in salary_advance_search:
existing_month = datetime.strptime(str(each_advance.date), '%Y-%m-%d').date().month
if current_month == existing_month:
raise UserError('Error!', 'Advance can be requested once in a month')
if not self.debit or not self.credit or not self.journal:
raise UserError('Warning', "You must enter Debit & Credit account and journal to approve ")
if not self.advance:
raise UserError('Warning', 'You must Enter the Salary Advance amount')
move_obj = self.env['account.move']
timenow = time.strftime('%Y-%m-%d')
line_ids = []
debit_sum = 0.0
credit_sum = 0.0
for request in self:
amount = request.advance
request_name = request.employee_id.name
reference = request.name
journal_id = request.journal.id
move = {
'narration': 'Salary Advance Of ' + request_name,
'ref': reference,
'journal_id': journal_id,
'date': timenow,
'state': 'posted',
}
debit_account_id = request.debit.id
credit_account_id = request.credit.id
if debit_account_id:
debit_line = (0, 0, {
'name': request_name,
'account_id': debit_account_id,
'journal_id': journal_id,
'date': timenow,
'debit': amount > 0.0 and amount or 0.0,
'credit': amount < 0.0 and -amount or 0.0,
'currency_id': self.currency_id.id,
})
line_ids.append(debit_line)
debit_sum += debit_line[2]['debit'] - debit_line[2]['credit']
if credit_account_id:
credit_line = (0, 0, {
'name': request_name,
'account_id': credit_account_id,
'journal_id': journal_id,
'date': timenow,
'debit': amount < 0.0 and -amount or 0.0,
'credit': amount > 0.0 and amount or 0.0,
'currency_id': self.currency_id.id,
})
line_ids.append(credit_line)
credit_sum += credit_line[2]['credit'] - credit_line[2]['debit']
move.update({'line_ids': line_ids})
move_obj.create(move)
self.state = 'approve'
return True

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import payslip_monthly_report
from . import bank_pdf_report

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
from odoo import models, api, _
from odoo.exceptions import ValidationError
class PayslipMonthlyReport(models.AbstractModel):
_name = 'report.exp_payroll_custom.payslip_monthly_report'
_description = 'Payslip Monthly Report'
def get_rule_values(self, data=None, context={}):
docs = []
payslip_line = self.env['hr.payslip.line']
count = 0
exception = False
if data['delist'] == 'ff':
ftotal = 0
title = _('Allowances and deduction Totals')
docs.append({'count': '#', 'rule': _('Name'), 'type': _('Type'), 'amount': _('Amount'), })
rules = self.env[data['model']].browse(data['ids']).sorted('sequence')
for rule in rules:
count += 1
total = sum(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda r: r.salary_rule_id.id == rule.id).mapped('total'))
ftotal += total
docs.append({
'count': count,
'rule': rule.name,
'type': _(dict(rule.category_id._fields['rule_type'].selection, context={}).get(
rule.category_id.rule_type)),
'amount': "{:.2f}".format(total),
})
docs.append({'count': '', 'rule': _('Total'), 'type': '', 'amount': "{:.2f}".format(ftotal), })
elif data['delist'] == 'tt':
# TODO review bellow raise
if not data['payslip_line_ids'] or not data['rule_ids']: raise ValidationError(
_('Sorry No Data To Be Printed'))
title = _('Employees Paysheet')
rule_dict = {}
sorted_rules = self.env['hr.salary.rule'].browse(data['rule_ids']).sorted('sequence')
for line in sorted_rules:
rule_dict.setdefault(line.category_id.rule_type, [])
rule_dict[line.category_id.rule_type] += line
tdict = {'count': '#', 'emp_no':_('EMP #'),'emp': _('Name'), }
ndict = {'count': '', 'emp_no': _('Nets'),'emp':'' }
for key, value in rule_dict.items():
for x in value:
tdict[x.id], ndict[x.id] = x.name, 0
rule_type_name = dict(
x.category_id._fields['rule_type']._description_selection(self.env)
).get(key)
tdict[key], ndict[key] = _('%s %s') % (_('Total'), rule_type_name), 0
tdict['net'], ndict['net'], = _('Net'), 0
if self.env.context.get('track_emp', False): tdict['track_id'] = 'track_id'
docs.append(tdict)
fnet = 0
for emp in self.env[data['model']].browse(data['ids']):
emp_dict = {}
count += 1
net = 0
for key, value in tdict.items():
if value == _('#'):
emp_dict[key] = count
continue
elif value == _('EMP #'):
emp_dict[key] = emp.emp_no
continue
elif value == _('Name'):
emp_dict[key] = emp.name
continue
elif value == 'track_id':
emp_dict['track_id'] = emp.id
continue
elif isinstance(key, int):
total = sum(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda r: r.employee_id.id == emp.id and r.salary_rule_id.id == key).mapped('total'))
emp_dict[key] = "{:.2f}".format(total)
net += total
fnet += total
ndict[key] += total
elif isinstance(key, str):
total = sum(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda
r: r.employee_id.id == emp.id and r.salary_rule_id.category_id.rule_type == key).mapped(
'total'))
emp_dict[key] = "{:.2f}".format(total)
ndict[key] += total
elif isinstance(key, bool):
total = sum(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda
r: r.employee_id.id == emp.id and r.salary_rule_id.category_id.rule_type == False).mapped(
'total'))
emp_dict[key] = "{:.2f}".format(total)
ndict[key] += total
if value == _('Net'):
emp_dict[key] = "{:.2f}".format(net)
continue
docs.append(emp_dict)
for key in ndict:
if isinstance(ndict[key], (int, float)) and key not in ['count', 'emp_no', 'emp']:
ndict[key] = "{:.2f}".format(ndict[key])
ndict['net'] = "{:.2f}".format(fnet)
docs.append(ndict)
else:
title = _('Specific Allowance and deduction Report')
exception = True
rules = self.env[data['model']].browse(data['ids']).sorted('sequence')
for rule in rules:
count = 0
ftotal = 0
inner_doc = {'rule': rule.name, 'lines': [], }
inner_doc['lines'].append({'count': '#', 'emp_no': _('EMP #'), 'emp': _('Employee'), 'amount': _('Amount'), })
for emp in set(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda r: r.salary_rule_id.id == rule.id).mapped('employee_id')):
count += 1
total = sum(payslip_line.browse(data['payslip_line_ids']).filtered(
lambda r: r.employee_id.id == emp.id and r.salary_rule_id.id == rule.id).mapped('total'))
ftotal += total
inner_doc['lines'].append({'count': count, 'emp_no': emp.emp_no, 'emp': emp.name, 'amount': "{:.2f}".format(total), })
inner_doc['lines'].append({'count': '', 'emp_no': _('Total'),'emp':'', 'amount': "{:.2f}".format(ftotal), })
docs.append(inner_doc)
return title, exception, docs
@api.model
def _get_report_values(self, docids, data=None):
title, exception, docs = self.get_rule_values(data)
return {
'exception': exception,
'title': title,
'date_from': data['form']['date_from'],
'date_to': data['form']['date_to'],
'docs': docs,
}
class PayslipMonthlyReportXlsx(models.AbstractModel):
_name = "report.exp_payroll_custom.payslip_monthly_report_xlsx"
_inherit = 'report.report_xlsx.abstract'
@api.model
def generate_xlsx_report(self, workbook, data, objs):
title, exception, docs = self.env['report.exp_payroll_custom.payslip_monthly_report'].get_rule_values(data)
sheet = workbook.add_worksheet('Proll Monthly report')
format1 = workbook.add_format({'bottom': True, 'right': True, 'left': True, 'top': True, 'align': 'center', })
format2 = workbook.add_format({'font_size': 14, 'bottom': True, 'right': True, 'left': True, 'top': True,
'align': 'center', 'bold': True})
format2.set_align('center')
format2.set_align('vcenter')
format3 = workbook.add_format({'bottom': True, 'align': 'center', 'bold': True, })
format_amount = workbook.add_format({
'bottom': True, 'right': True, 'left': True, 'top': True, 'align': 'center',
'num_format': '#,##0.00',
})
if data['delist'] != 'tf':
sheet.merge_range('C5:F5', title, format2)
sheet.merge_range('C6:F6', data['form']['date_from'] + ' - ' + data['form']['date_to'], format2)
else:
sheet.merge_range('C5:E5', title, format2)
sheet.merge_range('C6:E6', data['form']['date_from'] + ' - ' + data['form']['date_to'], format2)
sheet.set_column('C:C', 10)
sheet.set_column('D:D', 40)
# sheet.set_column('E:Z', 20)
row = 6
for line in docs:
if data['delist'] != 'tf':
row += 1
clm = 1
for k, v in line.items():
clm += 1
if isinstance(v, (int, float)):
sheet.write(row, clm, v, format_amount)
else:
sheet.write(row, clm, v, format1)
#sheet.write(row, clm, line[k], format1)
else:
row += 1
clm = 2
sheet.write(row, clm, line['rule'], format3)
for ln in line['lines']:
row += 1
clm = 1
for k, v in ln.items():
clm += 1
if isinstance(v, (int, float)):
sheet.write(row, clm, v, format_amount)
else:
sheet.write(row, clm, v, format1)
#sheet.write(row, clm, ln[k], format1)
row += 1

View File

@ -0,0 +1,55 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_salary_advance_user,salary.advance,model_salary_advance,base.group_user,1,1,1,0
access_salary_advance_officer,salary.advance,model_salary_advance,hr.group_hr_user,1,1,1,1
access_salary_advance_manager,salary.advance,model_salary_advance,hr.group_hr_manager,1,1,1,1
access_account_manager,salary.advance,model_salary_advance,account.group_account_manager,1,1,1,1
access_hr_salary_rule_emp,hr.salary.rule.emp,model_hr_salary_rule,base.group_user,1,0,0,0
access_hr_salary_rule_category_emp,hr.salary.rule.category.emp,model_hr_salary_rule_category,base.group_user,1,0,0,0
access_hr_payroll_structure_emp,hr.payroll.structure.emp,model_hr_payroll_structure,base.group_user,1,0,0,0
access_hr_reward_line_officer,hr.reward.line.officer,model_lines_ids_reward,hr.group_hr_user,1,0,0,0
access_hr_reward_line_hr_manager,hr.reward.line.hr.manager,model_lines_ids_reward,hr.group_hr_manager,1,1,1,0
access_hr_reward_line_division,hr.reward.line.division,model_lines_ids_reward,hr_base.group_division_manager,1,1,1,1
access_hr_reward_line_general_manager,hr.reward.line.gm,model_lines_ids_reward,hr_base.group_general_manager,1,1,0,0
access_hr_reward_line_department,hr.reward.department,model_lines_ids_reward,hr_base.group_department_manager,1,0,0,0
access_hr_reward_hr_user,hr.reward.hr.user,model_hr_employee_reward,hr.group_hr_user,1,1,0,0
access_hr_reward_hr_manager,hr.reward.hr.manager,model_hr_employee_reward,hr.group_hr_manager,1,1,1,0
access_hr_reward_division,hr.reward.division,model_hr_employee_reward,hr_base.group_division_manager,1,1,1,1
access_hr_reward_general_manager,hr.reward.gm,model_hr_employee_reward,hr_base.group_general_manager,1,1,0,0
access_hr_reward_department,hr.reward.department,model_hr_employee_reward,hr_base.group_department_manager,1,0,0,0
access_hr_employee_reward,access_hr_employee_reward,model_hr_employee_reward,base.group_user,1,0,0,0
access_hr_contract_advantage_officer,hr_contract_advantage_officer,model_contract_advantage,hr.group_hr_user,1,1,1,0
access_hr_contract_advantage_manager,hr_contract_advantage_manager,model_contract_advantage,hr.group_hr_manager,1,1,1,1
access_hr_contract_advantage_executive,hr_contract_advantage_executive,model_contract_advantage,hr_base.group_executive_manager,1,1,0,0
access_hr_contract_advantage_general_manager,hr_contract_advantage_gm,model_contract_advantage,hr_base.group_general_manager,1,0,0,0
access_hr_contract_advantage_employee,hr_contract_advantage_employee,model_contract_advantage,base.group_user,1,0,0,0
access_payslip_loans_user,payslip.loans.payroll.user,model_payslip_loans,exp_hr_payroll.group_hr_payroll_user,1,1,1,1
access_hr_payslip_payroll_contributor,hr.payslip.line.payroll.contributor,model_hr_payslip,exp_payroll_custom.group_hr_payroll_contributor,1,1,0,0
access_hr_payslip_line_payroll_contributor,hr.payslip.line.payroll.contributor,model_hr_payslip_line,exp_payroll_custom.group_hr_payroll_contributor,1,1,0,0
exp_hr_payroll.access_hr_payslip_run,hr.payslip.run,model_hr_payslip_run,exp_hr_payroll.group_hr_payroll_user,1,1,1,1
access_employee_promotions_contributor,employee.promotions.contributor,model_employee_promotions,exp_payroll_custom.group_hr_payroll_contributor,1,1,0,0
access_employee_promotions_payroll_user,employee.promotions.payroll.user,model_employee_promotions,exp_hr_payroll.group_hr_payroll_user,1,1,1,1
access_hr_payslip_emp,hr.payslip.emp,model_hr_payslip,base.group_user,1,0,0,0
access_hr_payslip_line_emp,hr.payslip.line.emp,model_hr_payslip_line,base.group_user,1,0,0,0
access_payslip_loans_emp,payslip.loans.emp,model_payslip_loans,base.group_user,1,0,0,0
access_related_salary_amount_officer,related_salary_amount_officer,model_related_salary_amount,hr.group_hr_user,1,1,1,1
access_related_salary_amount_emp,related_salary_amount_emp,model_related_salary_amount,base.group_user,1,0,0,0
access_payroll_bank_wiz_user,access_payroll_bank_wiz_user,model_payroll_bank_wiz,hr.group_hr_user,1,1,1,0
access_payslip_monthly_report_user,access_payslip_monthly_report_user,model_payslip_monthly_report,hr.group_hr_user,1,1,1,0
access_employee_selection_wizard_hr_manager,employee.selection.wizard.hr.manager,model_employee_selection_wizard,,1,1,1,1
access_hr_salary_rule_account_emp,hr_salary_rule_account_emp,model_hr_salary_rule_account,base.group_user,1,0,0,0
access_hr_salary_rule_account_hr_user,hr_salary_rule_account_hr_user,model_hr_salary_rule_account,hr.group_hr_user,1,1,1,1
access_hr_payslip_finance_review,access_hr_payslip_finance_review,model_hr_payslip,exp_payroll_custom.group_payroll_finance_review,1,1,0,0
access_hr_payslip_expense_manger,access_hr_payslip_expense_manger,model_hr_payslip,exp_payroll_custom.group_payroll_expense_manger,1,1,0,0
access_hr_payslip_account_manager,access_hr_payslip_account_manager,model_hr_payslip,hr_base.group_account_manager,1,1,0,0
access_hr_payslip_hr_manager,access_hr_payslip_hr_manager,model_hr_payslip,hr.group_hr_manager,1,1,0,0
access_hr_payslip_general_manager,access_hr_payslip_general_manager,model_hr_payslip,hr_base.group_general_manager,1,1,0,0
access_hr_payslip_run_finance_review,access_hr_payslip_finance_review,model_hr_payslip_run,exp_payroll_custom.group_payroll_finance_review,1,1,0,0
access_hr_payslip_run_expense_manger,access_hr_payslip_expense_manger,model_hr_payslip_run,exp_payroll_custom.group_payroll_expense_manger,1,1,0,0
access_hr_payslip_run_account_manager,access_hr_payslip_account_manager,model_hr_payslip_run,hr_base.group_account_manager,1,1,0,0
access_hr_payslip_run_hr_manager,access_hr_payslip_hr_manager,model_hr_payslip_run,hr.group_hr_manager,1,1,0,0
access_hr_payslip_run_general_manager,access_hr_payslip_general_manager,model_hr_payslip_run,hr_base.group_general_manager,1,1,0,0
access_hr_payslip_line_finance_review,access_hr_payslip_finance_review,model_hr_payslip_line,exp_payroll_custom.group_payroll_finance_review,1,1,0,0
access_hr_payslip_line_expense_manger,access_hr_payslip_expense_manger,model_hr_payslip_line,exp_payroll_custom.group_payroll_expense_manger,1,1,0,0
access_hr_payslip_line_account_manager,access_hr_payslip_account_manager,model_hr_payslip_line,hr_base.group_account_manager,1,1,0,0
access_hr_payslip_line_hr_manager,access_hr_payslip_hr_manager,model_hr_payslip_line,hr.group_hr_manager,1,1,0,0
access_hr_payslip_line_general_manager,access_hr_payslip_general_manager,model_hr_payslip_line,hr_base.group_general_manager,1,1,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_salary_advance_user salary.advance model_salary_advance base.group_user 1 1 1 0
3 access_salary_advance_officer salary.advance model_salary_advance hr.group_hr_user 1 1 1 1
4 access_salary_advance_manager salary.advance model_salary_advance hr.group_hr_manager 1 1 1 1
5 access_account_manager salary.advance model_salary_advance account.group_account_manager 1 1 1 1
6 access_hr_salary_rule_emp hr.salary.rule.emp model_hr_salary_rule base.group_user 1 0 0 0
7 access_hr_salary_rule_category_emp hr.salary.rule.category.emp model_hr_salary_rule_category base.group_user 1 0 0 0
8 access_hr_payroll_structure_emp hr.payroll.structure.emp model_hr_payroll_structure base.group_user 1 0 0 0
9 access_hr_reward_line_officer hr.reward.line.officer model_lines_ids_reward hr.group_hr_user 1 0 0 0
10 access_hr_reward_line_hr_manager hr.reward.line.hr.manager model_lines_ids_reward hr.group_hr_manager 1 1 1 0
11 access_hr_reward_line_division hr.reward.line.division model_lines_ids_reward hr_base.group_division_manager 1 1 1 1
12 access_hr_reward_line_general_manager hr.reward.line.gm model_lines_ids_reward hr_base.group_general_manager 1 1 0 0
13 access_hr_reward_line_department hr.reward.department model_lines_ids_reward hr_base.group_department_manager 1 0 0 0
14 access_hr_reward_hr_user hr.reward.hr.user model_hr_employee_reward hr.group_hr_user 1 1 0 0
15 access_hr_reward_hr_manager hr.reward.hr.manager model_hr_employee_reward hr.group_hr_manager 1 1 1 0
16 access_hr_reward_division hr.reward.division model_hr_employee_reward hr_base.group_division_manager 1 1 1 1
17 access_hr_reward_general_manager hr.reward.gm model_hr_employee_reward hr_base.group_general_manager 1 1 0 0
18 access_hr_reward_department hr.reward.department model_hr_employee_reward hr_base.group_department_manager 1 0 0 0
19 access_hr_employee_reward access_hr_employee_reward model_hr_employee_reward base.group_user 1 0 0 0
20 access_hr_contract_advantage_officer hr_contract_advantage_officer model_contract_advantage hr.group_hr_user 1 1 1 0
21 access_hr_contract_advantage_manager hr_contract_advantage_manager model_contract_advantage hr.group_hr_manager 1 1 1 1
22 access_hr_contract_advantage_executive hr_contract_advantage_executive model_contract_advantage hr_base.group_executive_manager 1 1 0 0
23 access_hr_contract_advantage_general_manager hr_contract_advantage_gm model_contract_advantage hr_base.group_general_manager 1 0 0 0
24 access_hr_contract_advantage_employee hr_contract_advantage_employee model_contract_advantage base.group_user 1 0 0 0
25 access_payslip_loans_user payslip.loans.payroll.user model_payslip_loans exp_hr_payroll.group_hr_payroll_user 1 1 1 1
26 access_hr_payslip_payroll_contributor hr.payslip.line.payroll.contributor model_hr_payslip exp_payroll_custom.group_hr_payroll_contributor 1 1 0 0
27 access_hr_payslip_line_payroll_contributor hr.payslip.line.payroll.contributor model_hr_payslip_line exp_payroll_custom.group_hr_payroll_contributor 1 1 0 0
28 exp_hr_payroll.access_hr_payslip_run hr.payslip.run model_hr_payslip_run exp_hr_payroll.group_hr_payroll_user 1 1 1 1
29 access_employee_promotions_contributor employee.promotions.contributor model_employee_promotions exp_payroll_custom.group_hr_payroll_contributor 1 1 0 0
30 access_employee_promotions_payroll_user employee.promotions.payroll.user model_employee_promotions exp_hr_payroll.group_hr_payroll_user 1 1 1 1
31 access_hr_payslip_emp hr.payslip.emp model_hr_payslip base.group_user 1 0 0 0
32 access_hr_payslip_line_emp hr.payslip.line.emp model_hr_payslip_line base.group_user 1 0 0 0
33 access_payslip_loans_emp payslip.loans.emp model_payslip_loans base.group_user 1 0 0 0
34 access_related_salary_amount_officer related_salary_amount_officer model_related_salary_amount hr.group_hr_user 1 1 1 1
35 access_related_salary_amount_emp related_salary_amount_emp model_related_salary_amount base.group_user 1 0 0 0
36 access_payroll_bank_wiz_user access_payroll_bank_wiz_user model_payroll_bank_wiz hr.group_hr_user 1 1 1 0
37 access_payslip_monthly_report_user access_payslip_monthly_report_user model_payslip_monthly_report hr.group_hr_user 1 1 1 0
38 access_employee_selection_wizard_hr_manager employee.selection.wizard.hr.manager model_employee_selection_wizard 1 1 1 1
39 access_hr_salary_rule_account_emp hr_salary_rule_account_emp model_hr_salary_rule_account base.group_user 1 0 0 0
40 access_hr_salary_rule_account_hr_user hr_salary_rule_account_hr_user model_hr_salary_rule_account hr.group_hr_user 1 1 1 1
41 access_hr_payslip_finance_review access_hr_payslip_finance_review model_hr_payslip exp_payroll_custom.group_payroll_finance_review 1 1 0 0
42 access_hr_payslip_expense_manger access_hr_payslip_expense_manger model_hr_payslip exp_payroll_custom.group_payroll_expense_manger 1 1 0 0
43 access_hr_payslip_account_manager access_hr_payslip_account_manager model_hr_payslip hr_base.group_account_manager 1 1 0 0
44 access_hr_payslip_hr_manager access_hr_payslip_hr_manager model_hr_payslip hr.group_hr_manager 1 1 0 0
45 access_hr_payslip_general_manager access_hr_payslip_general_manager model_hr_payslip hr_base.group_general_manager 1 1 0 0
46 access_hr_payslip_run_finance_review access_hr_payslip_finance_review model_hr_payslip_run exp_payroll_custom.group_payroll_finance_review 1 1 0 0
47 access_hr_payslip_run_expense_manger access_hr_payslip_expense_manger model_hr_payslip_run exp_payroll_custom.group_payroll_expense_manger 1 1 0 0
48 access_hr_payslip_run_account_manager access_hr_payslip_account_manager model_hr_payslip_run hr_base.group_account_manager 1 1 0 0
49 access_hr_payslip_run_hr_manager access_hr_payslip_hr_manager model_hr_payslip_run hr.group_hr_manager 1 1 0 0
50 access_hr_payslip_run_general_manager access_hr_payslip_general_manager model_hr_payslip_run hr_base.group_general_manager 1 1 0 0
51 access_hr_payslip_line_finance_review access_hr_payslip_finance_review model_hr_payslip_line exp_payroll_custom.group_payroll_finance_review 1 1 0 0
52 access_hr_payslip_line_expense_manger access_hr_payslip_expense_manger model_hr_payslip_line exp_payroll_custom.group_payroll_expense_manger 1 1 0 0
53 access_hr_payslip_line_account_manager access_hr_payslip_account_manager model_hr_payslip_line hr_base.group_account_manager 1 1 0 0
54 access_hr_payslip_line_hr_manager access_hr_payslip_hr_manager model_hr_payslip_line hr.group_hr_manager 1 1 0 0
55 access_hr_payslip_line_general_manager access_hr_payslip_general_manager model_hr_payslip_line hr_base.group_general_manager 1 1 0 0

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="employee_promotion_rule_comp_rule" model="ir.rule">
<field name="name">Employee promotions multi company rule</field>
<field name="model_id" ref="model_employee_promotions" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="employee_reward_rule_comp_rule" model="ir.rule">
<field name="name">Employee reward multi company rule</field>
<field name="model_id" ref="model_hr_employee_reward" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="hr_payslip_run_rule_comp_rule" model="ir.rule">
<field name="name">Employee hr payslip run multi company rule</field>
<field name="model_id" ref="model_hr_payslip_run" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="salary_rule_comp_rule" model="ir.rule">
<field name="name">Employee hr_salary_rule multi company rule</field>
<field name="model_id" ref="model_hr_salary_rule" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="hr_payroll_structure_comp_rule" model="ir.rule">
<field name="name">Employee hr_salary_rule multi company rule</field>
<field name="model_id" ref="model_hr_payroll_structure" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="rule_advance_salary_multi_company" model="ir.rule">
<field name="name">Advance Request Multi Company</field>
<field name="model_id" ref="model_salary_advance" />
<field eval="True" name="global" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',company_ids)]
</field>
</record>
<record id="hr_payslip_rule_comp_rule" model="ir.rule">
<field name="name">Employee hr payslip multi company rule</field>
<field name="model_id" ref="model_hr_payslip" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="contract_advantage_rule_comp_rule" model="ir.rule">
<field name="name">Employee contract advantage multi company rule</field>
<field name="model_id" ref="model_contract_advantage" />
<field name="domain_force">['|', ('company_id','=',False), ('company_id', 'in',
company_ids)]</field>
</record>
<record id="hr_salary_advance_manager_rule" model="ir.rule">
<field name="name">Salary Advance</field>
<field name="model_id" ref="model_salary_advance" />
<field name="groups"
eval="[(4, ref('hr.group_hr_user')),(4, ref('account.group_account_user'))]" />
<field name="perm_write" eval="True" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_unlink" eval="True" />
</record>
<record id="hr_salary_advance_employee_rule" model="ir.rule">
<field name="name">Salary Advance Rule For Employee</field>
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
<field name="global" eval="True" />
<field name="model_id" ref="model_salary_advance" />
<field name="groups" eval="[(4,ref('base.group_user'))]" />
<field name="perm_write" eval="True" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_unlink" eval="True" />
</record>
<record id="hr_payroll_rule_employee" model="ir.rule">
<field name="name">Employee Payslip</field>
<field name="model_id" ref="model_hr_payslip" />
<field name="domain_force">[('employee_id.user_id.id', '=', user.id),('state', '=',
'transfered')]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]" />
</record>
<record id="hr_payslip_contributor_rule" model="ir.rule">
<field name="name">All Payslip</field>
<field name="model_id" ref="model_hr_payslip" />
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups"
eval="[(4, ref('exp_payroll_custom.group_hr_payroll_contributor')),
(4, ref('hr_base.group_general_manager')),
(4, ref('exp_hr_payroll.group_hr_payroll_user')),
(4, ref('hr_base.group_executive_manager')),
(4, ref('hr.group_hr_manager')),
(4, ref('hr_base.group_account_manager')),
(4, ref('exp_payroll_custom.group_payroll_expense_manger')),
(4, ref('exp_payroll_custom.group_payroll_finance_review'))]" />
</record>
<record id="employee_promotion_employee_rule" model="ir.rule">
<field name="name">Employee: views its promotions only</field>
<field name="model_id" ref="model_employee_promotions" />
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]" />
</record>
<record id="employee_promotion_division_manager_rule" model="ir.rule">
<field name="name">Division/Dep Manager: views promotions of its subordinates</field>
<field name="model_id" ref="model_employee_promotions" />
<field name="domain_force">['|','|',('employee_id.department_id.manager_id','=',False),
('employee_id.department_id.manager_id.user_id','=', user.id),
('employee_id.department_id.parent_id.manager_id.user_id','=', user.id)]
</field>
<field name="groups"
eval="[(4, ref('hr_base.group_department_manager')),(4, ref('hr_base.group_division_manager'))]" />
</record>
<record id="employee_promotion_all_rule" model="ir.rule">
<field name="name">Manager: views promotions of all employee</field>
<field name="model_id" ref="model_employee_promotions" />
<field name="domain_force">[(1 ,'=', 1)]</field>
<field name="groups"
eval="[(3, ref('hr_base.group_account_manager')),
(4, ref('hr_base.group_executive_manager')),
(4, ref('hr_base.group_general_manager')),
(4, ref('hr.group_hr_manager'))]" />
</record>
</odoo>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="group_hr_payroll_contributor" model="res.groups">
<field name="name">Contributor</field>
<field name="comment">This user is a participant in payroll related processes.</field>
</record>
<record id="group_payroll_finance_review" model="res.groups">
<field name="name">Finance Review</field>
<field name="category_id" ref="base.module_category_payroll_localization"/>
</record>
<record id="group_payroll_expense_manger" model="res.groups">
<field name="name">Expense Manager</field>
<field name="category_id" ref="base.module_category_payroll_localization"/>
</record>
</data>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,22 @@
@media (min-width: 768px){
.rtl .navbar-right{
float: left !important;
}
.rtl .navbar-right .dropdown .dropdown-menu{
right: auto !important;
left: 0 !important;
}
.rtl .navbar-left{
float: right !important;
}
.rtl .navbar-left .dropdown .dropdown-menu{
left: auto !important;
right: 0 !important;
}
.navbar-nav.navbar-right:last-child{
margin-left: auto;
}
.rtl .pull-left{
float: right !important;
}
}

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<template id="report_payroll_bank_pdf">
<t t-call="web.html_container">
<t t-call="web.external_layout" t-att-data-oe-lang="data['form'].get('create_uid.lang')">
<div class="page">
<h5 class="text-center">Salary Bank Payslip Report</h5>
<h5 class="text-center">
<span t-esc="date_from"/>
---
<span t-esc="date_to"/>
</h5>
<t t-foreach="data" t-as="v">
<h5 class="text-left">
<span t-esc="v['bank']"/>
</h5>
<table class="table table-condensed table-bordered"
style="background-color:#0f80d6;width:100%;">
<thead style="background: #3e5d7f;text-align: center;color: #ffffff;font-family:verdana;valign: middle;"
class="text-center">
<th style="text-align:center;">Employee Number</th>
<th style="text-align:center;">Employee Name</th>
<th style="text-align:center;">Account #</th>
<th style="text-align:center;">Bank</th>
<th style="text-align:center;">Amount</th>
<th style="text-align:center;">Legal #</th>
<th style="text-align:center;">Basic Salary</th>
<th style="text-align:center;">Housing Allowance</th>
<th style="text-align:center;">Other Earnings</th>
<th style="text-align:center;">Deduction</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td>
<span t-esc="o['ID']"/>
</td>
<td>
<span t-esc="o['Name']"/>
</td>
<td>
<span t-esc="o['Account #']"/>
</td>
<td>
<span t-esc="o['Bank']"/>
</td>
<td>
<span t-esc="o['Salary']"/>
</td>
<td>
<span t-esc="o['National']"/>
</td>
<td>
<span t-esc="o['Basic']"/>
</td>
<td>
<span t-esc="o['Housing']"/>
</td>
<td>
<span t-esc="o['Other']"/>
</td>
<td>
<span t-esc="o['Deduction']"/>
</td>
</tr>
</tbody>
<br/>
<br/>
<br/>
</table>
</t>
</div>
</t>
</t>
</template>
</data>
</odoo>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<template id="employee_cost_report">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<!-- <h1 class="text-center"> Employee Cost </h1>-->
<!-- <h3 class="text-center"><span t-esc="date_from"/> - <span t-esc="date_to"/></h3>-->
<table class="table table-condensed table-bordered">
<thead class="text-center">
<tr style="background-color:#0f80d6;width:100%;">
<th colspan="12" class="text-center" style="color:#f7f7f7;font-size:20px"> Employee Cost Report <span t-esc="date_from"/> - <span t-esc="date_to"/></th>
</tr>
<tr style="background-color: #b8bcbf;width:100%;">
<th >#</th>
<th >Department</th>
<th >Employee ID</th>
<th >Employee Name</th>
<th >Employee Basic Wage</th>
<th >House Allowance</th>
<th >Other Benefits</th>
<th >Employee GOSI</th>
<th >Employer GOSI</th>
<th >Daily Wage</th>
<th >Total</th>
<th>Annual Cost</th>
</tr>
</thead>
<tbody class="text-center">
<t t-set="sequence" t-value="0"/>
<t t-foreach="docs" t-as="o">
<t t-set="salary_value" t-value="o.get_employee_data_report(o.contract_id,date_from,date_to)"/>
<tr>
<td>
<t t-set="sequence" t-value="sequence +1"/>
<t t-esc="sequence"/>
</td>
<td>
<t t-esc="o.department_id.name"/>
</td>
<td>
<span t-esc="o.emp_no"/>
</td>
<td>
<span t-esc="o.name"/>
</td>
<td>
<span t-esc="o.contract_id.salary"/>
</td>
<td>
<span t-esc="o.contract_id.house_allowance_temp"/>
</td>
<td>
<t t-esc="salary_value[1]"/>
</td>
<td>
<span t-esc="o.contract_id.gosi_deduction"/>
</td>
<td>
<span t-esc="o.contract_id.gosi_employer_deduction"/>
</td>
<td>
<span t-esc="salary_value[0]"/>
</td>
<td>
<span t-esc="o.contract_id.total_net"/>
</td>
<td>
<span t-esc="salary_value[2]"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
<record id ="employee_cost_report_act" model="ir.actions.report">
<field name="model">hr.contract</field>
<field name="name">Employee Cost Report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_payroll_custom.employee_cost_report</field>
<field name="report_file">exp_payroll_custom.employee_cost_report</field>
</record>
<record id ="employee_cost_report_act_xlsx" model="ir.actions.report">
<field name="model">hr.contract</field>
<field name="name">Employee Cost Report</field>
<field name="report_type">xlsx</field>
<field name="report_name">exp_payroll_custom.employee_cost_report_xlsx</field>
<field name="report_file">exp_payroll_custom.employee_cost_report_xlsx</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="report.paperformat" id="paperformat_payslips_batches_recap_report">
<field name="name">paperformat.payslips.batches.recap.report</field>
<field name="default" eval="True"/>
<field name="format">A3</field>
<field name="page_width">0</field>
<field name="page_width">0</field>
<field name="orientation">Portrait</field>
<field name="margin_top">30</field>
<field name="margin_right">5</field>
<field name="margin_bottom">10</field>
<field name="margin_left">5</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">20</field>
<field name="dpi">90</field>
</record>
<template id="hr_payslip_run_report_pdf_template">
<t t-call="web.html_container">
<t t-call="web.internal_layout">
<t t-call="web.external_layout">
<table class="table table-condensed table-bordered" style="width: 100%">
<thead>
<thead>
<th class="text-center" style="width: 2%;background:#e9ebee;color:#003c79">
#
</th>
<th class="text-center" style="width: 4%;background:#e9ebee;color:#003c79">
Employee No
</th>
<th class="text-center" style="width: 4%;background:#e9ebee;color:#003c79">
Employee
</th>
<th class="text-center" style="width: 4%;background:#e9ebee;color:#003c79">
Total Allowance
</th>
<th class="text-center" style="width: 4%;background:#e9ebee;color:#003c79">
Total Deduction
</th>
<th class="text-center" style="width: 4%;background:#e9ebee;color:#003c79">
Total Net
</th>
</thead>
</thead>
<tbody>
<t t-set="sequence" t-value="0"/>
<t t-foreach="docs" t-as="doc">
<t t-foreach="doc['slip_ids']" t-as='o'>
<tr>
<td>
<t t-set="sequence" t-value="sequence +1"/>
<t t-esc="sequence"/>
</td>
<td>
<span t-esc="o.employee_id.emp_no"/>
</td>
<td>
<span t-esc="o.employee_id.name"/>
</td>
<td>
<span t-esc="o.total_allowances"/>
</td>
<td>
<span t-esc="o.total_deductions"/>
</td>
<td>
<span t-esc="o.total_sum"/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
</t>
</t>
</t>
</template>
<!-- QWeb Reports -->
<!-- NAME & FILE_NAME should be the same -->
<record id="hr_payslip_run_report_pdf" model="ir.actions.report">
<field name="model">hr.payslip.run</field>
<field name="name">Payslips Batches Report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_payroll_custom.hr_payslip_run_report_pdf_template</field>
<field name="report_file">exp_payroll_custom.hr_payslip_run_report_pdf_template</field>
<field name="paperformat_id" ref="paperformat_payslips_batches_recap_report"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<template id="report_payroll_bank_pdf_docx"><t t-foreach="data" t-as="v"><t>IFH,IFILE,CSV,ABCD5953001,SASABBGSA003888815,<t><t t-esc="random_char"/></t><t t-set="date_value" t-value="pay_date"/><t t-esc="date_value.replace('-', '').replace('/', '').replace(':', '')"/>00,</t><t t-esc="datestamp" widget="datetime"></t>,<t><t t-esc="timestamp" widget="datetime"></t></t><t>,P,1.0,</t><t><t t-esc="number_of_records"/></t>
<t>BATHDR,ACH-CR,<t><t t-esc="counter"/></t>,,,,<t><t t-esc="salary_type"/></t>,Salary,,@1ST@,<t t-set="date_value" t-value="pay_date"/><t t-esc="date_value.replace('-', '').replace('/', '')"/>,00<t t-esc="company_pay_no"></t>,<t t-esc="currency"></t>,<t t-esc="round(total_amount_salary,2)"></t>,,,,,,,<t t-esc="company_id"></t>,<t><t t-esc="company_hr_no"/></t>,<t><t t-esc="company_registry"/></t>,,,,<t><t t-esc="random_char2"/></t><t t-set="date_value" t-value="timestamp" widget="datetime"/><t t-esc="date_value.replace('-', '').replace('/', '').replace(':', '')"/>00</t><t t-if="bank_type=='rajhi'"><t t-foreach="v['docs']" t-as="o"><t></t>
<t>SECPTY,</t><t><t t-esc="o['Account #']"/></t>,<t><t t-esc="o['Name']"/></t>,<t><t t-esc="o['ID']"/></t>,<t><t t-esc="o['Bank']"/></t>,,,<t><t t-esc="'%.2f'% o['Salary']"/></t>,,,,,,,N,N,,,,,,@SACH@,<t><t t-esc="o['National']"/></t>,<t><t t-esc="'%.2f'% o['Basic']"/></t>,<t><t t-esc="'%.2f'% o['Housing']"/></t><t>,<t t-esc="'%.2f'% o['Other']"/></t>,<t><t t-esc="'%.2f'% o['Deduction']"/></t>,<t>salary of <t t-esc="pay_slip"/></t></t></t>
<t t-elif="bank_type=='alahli'"><t t-foreach="v['docs']" t-as="o"><t></t>
<t>SECPTY,</t><t><t t-esc="o['Account #']"/></t>,<t><t t-esc="o['Name']"/></t>,<t><t t-esc="o['ID']"/></t>,<t><t t-esc="o['Bank']"/></t>,,,<t><t t-esc="'%.2f'% o['Salary']"/></t>,,,,,,,N,N,,,,,,@SACH@,<t><t t-esc="o['National']"/></t>,<t><t t-esc="'%.2f'% o['Basic']"/></t>,<t><t t-esc="'%.2f'% o['Housing']"/></t><t>,<t t-esc="'%.2f'% o['Other']"/></t>,<t><t t-esc="'%.2f'% o['Deduction']"/></t>,<t>salary of <t t-esc="pay_slip"/></t></t></t>
<t t-elif="bank_type=='riyadh'"><t t-foreach="v['docs']" t-as="o"><t></t>
<t>SECPTY,</t><t><t t-esc="o+['Account #']"/></t>,<t><t t-esc="o['Name']"/></t>,<t><t t-esc="o['ID']"/></t>,<t><t t-esc="o['Bank']"/></t>,,,<t><t t-esc="'%.2f'% o['Salary']"/></t>,,,,,,,N,N,,,,,,@SACH@,<t><t t-esc="o['National']"/></t>,<t><t t-esc="'%.2f'% o['Basic']"/></t>,<t><t t-esc="'%.2f'% o['Housing']"/></t><t>,<t t-esc="'%.2f'% o['Other']"/></t>,<t><t t-esc="'%.2f'% o['Deduction']"/></t>,<t>salary of <t t-esc="pay_slip"/></t></t></t></t>
</template>
</data>
</odoo>

View File

@ -0,0 +1,134 @@
<odoo>
<data>
<template id="payslip_monthly_report">
<t t-call="web.html_container">
<t t-call="hr_base.hr_layout">
<style>
@font-face {font-family: "Sakkal Majalla"; src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot"); src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot?#iefix")
format("embedded-opentype"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff2") format("woff2"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff") format("woff"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.ttf") format("truetype");
}
table td {
font-size: 12pt;
}
</style>
<div class="page" style="font-family: 'Sakkal Majalla'!important;font-size:15pt;">
<t t-if="exception==False">
<h3 class="text-center">
<span t-esc="title"/>
</h3>
<h4 class="text-center">
<span t-esc="date_from"/>
-
<span t-esc="date_to"/>
</h4>
<br/>
<table class="table table-condensed table-bordered" style="width: 100%">
<t t-foreach="docs" t-as="doc">
<t t-if="doc['count']=='#'">
<thead style="background: #3e5d7f;text-align: center;
color: #ffffff;font-family:'Sakkal Majalla'!important: middle;">
<span t-foreach="doc" t-as="clm">
<th>
<span t-esc="doc[clm]"/>
</th>
</span>
</thead>
</t>
<t t-if="doc['count']!='#'">
<tbody style="text-align: justify; padding: 0.7em;font-family:'Sakkal Majalla'!important;">
<span t-foreach="doc" t-as="clm">
<t t-if="doc_last">
<td style="font-weight: bold; ">
<t t-if=" isinstance(doc[clm] , float) ">
<span t-esc="'%.2f'%doc[clm]"/>
</t>
<t t-else="">
<span t-esc="doc[clm]"/>
</t>
</td>
</t>
<t t-else="">
<td>
<t t-if=" isinstance(doc[clm] , float) ">
<span t-esc="'%.2f'%doc[clm]"/>
</t>
<t t-else="">
<span t-esc="doc[clm]"/>
</t>
</td>
</t>
</span>
</tbody>
</t>
</t>
</table>
</t>
<t t-if="exception==True">
<h3 class="text-center">
<span t-esc="title"/>
</h3>
<h4 class="text-center">
<span t-esc="date_from"/>
-
<span t-esc="date_to"/>
</h4>
<t t-foreach="docs" t-as="doc">
<h4 class="text-center">
<span t-esc="doc['rule']"/>
</h4>
<table class="table table-condensed table-bordered" style="width: 100%">
<t t-foreach="doc['lines']" t-as="line">
<t t-if="line['count']=='#'">
<thead style="text-align:center; background: #3e5d7f;color: #ffffff;
font-family:'Sakkal Majalla'!important;">
<span t-foreach="line" t-as="clm">
<th>
<span t-esc="line[clm]"/>
</th>
</span>
</thead>
</t>
<t t-if="line['count']!='#'">
<tbody style="text-align: justify; padding: 0.7em;font-family:'Sakkal Majalla'!important;">
<t t-if="line_last">
<span t-foreach="line" t-as="clm">
<td style="font-weight: bold;">
<t t-if=" isinstance(line[clm] , float) ">
<span t-esc="'%.2f'%line[clm]"/>
</t>
<t t-else="">
<span t-esc="line[clm]"/>
</t>
</td>
</span>
</t>
<t t-else="">
<span t-foreach="line" t-as="clm">
<td>
<t t-if=" isinstance(line[clm] , float) ">
<span t-esc="'%.2f'%line[clm]"/>
</t>
<t t-else="">
<span t-esc="line[clm]"/>
</t>
</td>
</span>
</t>
</tbody>
</t>
</t>
</table>
</t>
</t>
</div>
</t>
</t>
</template>
</data>
</odoo>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_payslip_inherit" inherit_id="exp_hr_payroll.report_payslip">
<xpath expr="//span[@t-field='o.employee_id.identification_id']" position="replace">
<span t-field="o.employee_id.identity_number"/>
</xpath>
<xpath expr="//div/table[2]/tbody" position="inside">
<tr>
<td colspan="2">
<strong>Total Allowances</strong>
</td>
<td>
<strong>
<span t-esc="sum([s.amount for s in o.allowance_ids])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
<td>
<strong>
<span t-esc="sum([s.total for s in o.allowance_ids])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
</tr>
<tr>
<td colspan="2">
<strong>Total Deductions</strong>
</td>
<td>
<strong>
<span t-esc="sum([s.amount for s in o.deduction_ids])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
<td>
<strong>
<span t-esc="sum([s.total for s in o.deduction_ids])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
</tr>
<tr>
<td colspan="2">
<strong>Total Loans</strong>
</td>
<td>
<strong>
<span t-esc="sum([s.amount for s in o.loan_ids])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
<td>
<!-- <strong>-->
<!-- <span t-esc="sum([s.amount for s in o.loan_ids])"-->
<!-- t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>-->
<!-- </strong>-->
</td>
</tr>
<tfoot>
<tr>
<td colspan="2">
<strong>NET</strong>
</td>
<td>
<strong>
<span t-esc="round( sum([s.amount for s in o.line_ids.filtered(lambda line: line.appears_on_payslip)]) + sum([s.amount for s in o.loan_ids]), 2)"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
<td>
<strong>
<span t-esc="round(sum([s.total for s in o.line_ids.filtered(lambda line: line.appears_on_payslip)]) + sum([s.amount for s in o.loan_ids]), 2)"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
</tr>
</tfoot>
</xpath>
</template>
</odoo>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_payslip_details_inherit"
inherit_id="exp_hr_payroll.report_payslip_details">
<xpath expr="//div/table[2]/tbody" position="after">
<tr>
<td colspan="2">
<strong>NET</strong>
</td>
<td class="text-right">
<strong>
<span t-esc="sum([h['total'] for h in get_details_by_rule_category.get(o.id, []) if not h['level']==0 ])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
</tr>
</xpath>
<xpath expr="//div/table[3]/tbody/tr" position="after">
<tr >
<td colspan="3"><strong>NET</strong></td>
<td class="text-right">
<strong><span t-esc="sum([p['total'] for p in get_lines_by_contribution_register.get(o.id, []) ])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
<td class="text-right">
<strong><span t-esc="sum([p['total'] for p in get_lines_by_contribution_register.get(o.id, []) ])"
t-esc-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</strong>
</td>
</tr>
</xpath>
</template>
</odoo>

View File

@ -0,0 +1,612 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<template id="report_payroll_bank_pdf_docx">
<t t-call="web.html_container">
<t t-call="hr_base.hr_layout" translation="off">
<style>
@font-face {font-family: "Sakkal Majalla"; src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot"); src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot?#iefix")
format("embedded-opentype"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff2") format("woff2"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff") format("woff"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.ttf") format("truetype");
}
</style>
<div class="page" style="font-family: 'Sakkal Majalla'!important;font-size:14pt;direction:rtl">
<t t-set="sequence" t-value="0"/>
<t t-foreach="data" t-as="v">
<h3 style="text-align: center;color: font-weight: bold;">
<strong t-if="v['report_type']=='salary'">مسير البنك للرواتب</strong>
<strong t-if="v['report_type']=='allowance'">مسير البنك للحوافز</strong>
<strong t-if="v['report_type']=='overtime'">مسير البنك للعمل الإضافي</strong>
<strong t-if="v['report_type']=='training'">مسير البنك للتدريب</strong>
<strong t-if="v['report_type']=='mission'">مسير البنك لمهام العمل</strong>
<br/>
<span t-esc="date_from"/>
---
<span t-esc="date_to"/>
</h3>
<p t-if="v['no_details']==False"
style="text-align:right;font-weight:bold;padding:0px; line-height: 1.1;">
<span>بنك :</span>
<span t-esc="v['bank']"/>
</p>
<t t-if="bank_type=='rajhi'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
إسم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الحساب
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
البنك
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
المبلغ
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الهوية
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الراتب الأساسي
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدل السكن
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدلات أخرى
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الخصم
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Account #']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
<t t-elif="bank_type=='alahli'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Bank
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Account Number
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Total Salary
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Transaction Reference
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Employee Name
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
National ID/Iqama ID
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Employee Address
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Basic Salary
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Housing Allowance
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Other Earnings
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Deductions
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Account #']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Address']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
<t t-elif="bank_type=='riyadh'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
SN
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
هوية المستفيد/ المرجع
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
المستفيد / اسم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الحساب
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رمز البنك
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
إجمالي المبلغ
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الراتب الأساسي
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدل السكن
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
دخل آخر
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الخصومات
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
العنوان
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
العملة
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الحالة
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
وصف الدفع
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
مرجع الدفع
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<t t-set="sequence" t-value="sequence +1"/>
<t t-esc="sequence"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Address']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['currency']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Pay Description']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
</t>
</div>
</t>
</t>
</template>
<template id="report_payroll_bank_pdf">
<t t-call="web.html_container">
<t t-call="hr_base.hr_layout" translation="off">
<style>
@font-face {font-family: "Sakkal Majalla"; src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot"); src:
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.eot?#iefix")
format("embedded-opentype"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff2") format("woff2"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.woff") format("woff"),
url("/employee_requests/static/fonts/ce7b5754581057e6f7444e2192850cc8.ttf") format("truetype");
}
</style>
<div class="page" style="font-family: 'Sakkal Majalla'!important;font-size:14pt;direction:rtl">
<t t-set="sequence" t-value="0"/>
<t t-foreach="data" t-as="v">
<h3 style="text-align: center;color: font-weight: bold;">
<strong t-if="v['report_type']=='salary'">مسير البنك للرواتب</strong>
<strong t-if="v['report_type']=='allowance'">مسير البنك للحوافز</strong>
<strong t-if="v['report_type']=='overtime'">مسير البنك للعمل الإضافي</strong>
<strong t-if="v['report_type']=='training'">مسير البنك للتدريب</strong>
<strong t-if="v['report_type']=='mission'">مسير البنك لمهام العمل</strong>
<br/>
<span t-esc="date_from"/>
---
<span t-esc="date_to"/>
</h3>
<p t-if="v['no_details']==False"
style="text-align:right;font-weight:bold;padding:0px; line-height: 1.1;">
<span>بنك :</span>
<span t-esc="v['bank']"/>
</p>
<t t-if="bank_type=='rajhi'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
إسم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الحساب
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
البنك
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
المبلغ
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الهوية
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الراتب الأساسي
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدل السكن
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدلات أخرى
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الخصم
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Account #']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
<t t-elif="bank_type=='alahli'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Bank
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Account Number
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Total Salary
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Transaction Reference
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Employee Name
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
National ID/Iqama ID
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Employee Address
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Basic Salary
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Housing Allowance
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Other Earnings
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
Deductions
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Account #']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Address']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
<t t-elif="bank_type=='riyadh'">
<table class="table table-condensed table-bordered">
<thead style="margin-top:0px;background: #3e5d7f;text-align: center;color: #ffffff;valign: middle;"
class="text-center">
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
SN
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
هوية المستفيد/ المرجع
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
المستفيد / اسم الموظف
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رقم الحساب
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
رمز البنك
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
إجمالي المبلغ
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الراتب الأساسي
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
بدل السكن
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
دخل آخر
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الخصومات
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
العنوان
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
العملة
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
الحالة
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
وصف الدفع
</th>
<th style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;text-align:center;">
مرجع الدفع
</th>
</thead>
<tbody>
<tr t-foreach="v['docs']" t-as="o">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<t t-set="sequence" t-value="sequence +1"/>
<t t-esc="sequence"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['National']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Name']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Bank']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="'%.2f'% o['Salary']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Basic']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Housing']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Other']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Deduction']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Address']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['currency']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['Pay Description']"/>
</td>
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap">
<span t-esc="o['ID']"/>
</td>
</tr>
</tbody>
</table>
<p style="page-break-after:always"></p>
</t>
</t>
</div>
</t>
</t>
</template>
</data>
</odoo>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_company_form_inherit" model="ir.ui.view">
<field name="name">res.company.form.inherit</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='phone']" position="after">
<field name="company_hr_no"/>
<field name="company_pay_no"/>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,128 @@
<odoo>
<data>
<!-- Action -->
<record model="ir.actions.act_window" id="employee_advantage_list_action">
<field name="name">Employee Allowances and Deductions</field>
<field name="res_model">contract.advantage</field>
<field name="view_mode">list,form</field>
</record>
<!-- Form View -->
<record id="employee_advantage_form_view" model="ir.ui.view">
<field name="name">Employee Allowances and Deductions</field>
<field name="model">contract.advantage</field>
<field name="arch" type="xml">
<form string="Employee Allowances and Deductions">
<header>
<button name="confirm" string="Confirm" type="object"
class="oe_highlight"
invisible="state != 'draft'"
groups="hr.group_hr_user,hr.group_hr_manager" />
<button name="refused" string="Refused" type="object"
class="oe_highlight"
invisible="state != 'confirm'"
groups="hr.group_hr_user,hr.group_hr_manager" />
<button name="draft" string="Re-Draft" type="object"
class="oe_highlight"
invisible="state != 'refused'"
groups="hr.group_hr_user,hr.group_hr_manager" />
<field name="state" widget="statusbar" />
</header>
<sheet>
<group>
<group>
<field name="employee_id" string="Employee Name"
required="True"
readonly="state != 'draft'" />
<field name="contract_advantage_id" readonly="True"
force_save="1" store="1" />
<field name="type" required="True"
readonly="state != 'draft'"
invisible="True" />
<field name="benefits_discounts" required="True"
readonly="state != 'draft'" />
</group>
<group>
<field name="date_from" required="True"
readonly="state != 'draft'" />
<field name="date_to"
readonly="state != 'draft'" />
<field name="amount" required="True"
readonly="state != 'draft'" />
<field name="out_rule"
readonly="state != 'draft'" />
</group>
<group string="Allowances Or Deductions Types">
<field name="over_time_id" readonly="True" />
<field name="official_mission_id" readonly="True" />
<field name="reward_id" readonly="True" />
<field name="penalty_id" readonly="True" />
</group>
<group string="Comments">
<field name="comments"
readonly="state != 'draft'" />
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<!-- Tree View -->
<record model="ir.ui.view" id="employee_advantage_tree_view">
<field name="name">Employee Allowances and Deductions</field>
<field name="model">contract.advantage</field>
<field name="arch" type="xml">
<list string="Employee Allowances and Deductions"
decoration-info="state == 'draft'"
decoration-danger="state == 'refused'">
<field name="employee_id" string="Employee Name" />
<field name="type" invisible="True" />
<field name="benefits_discounts" />
<field name="date_from" />
<field name="date_to" />
<field name="amount" />
<field name="state" string="State" />
</list>
</field>
</record>
<!-- Search View -->
<record id="view_employee_filter_advantage" model="ir.ui.view">
<field name="name">Employee Allowances and Deductions</field>
<field name="model">contract.advantage</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Employee Allowances and Deductions">
<field name="employee_id" />
<field name="benefits_discounts" />
<field name="date_from" />
</search>
</field>
</record>
<!-- Menu Item -->
<menuitem id="employee_advantage_menu"
name="Employee Allowances and Deductions"
parent="exp_hr_payroll.menu_hr_payroll_root"
action="employee_advantage_list_action"
sequence="10"
groups="hr_base.group_executive_manager,hr_base.group_general_manager,exp_hr_payroll.group_hr_payroll_user" />
</data>
</odoo>

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="employee_promotions_action" model="ir.actions.act_window">
<field name="name">Employee promotions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">employee.promotions</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Create Requests.
</p>
</field>
</record>
<record id="employee_promotions_form_view" model="ir.ui.view">
<field name="name">employee.promotions.form</field>
<field name="model">employee.promotions</field>
<field name="arch" type="xml">
<form string="Employee promotions">
<header>
<button name="confirm" string="HR Officer" type="object"
invisible="state != 'draft'"
class="oe_highlight"
groups="hr.group_hr_user,exp_hr_payroll.group_hr_payroll_user" />
<button name="hr_manager" string="HR Manager" type="object"
invisible="state != 'confirm'"
class="oe_highlight" groups="hr.group_hr_manager" />
<button string="Refused" name="act_refuse" type="object"
invisible="state != 'confirm'"
class="oe_highlight" groups="hr.group_hr_manager" />
<button name="approved" string="Approved" type="object"
invisible="state != 'hr_manager'"
class="oe_highlight"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<button string="Refused" name="act_refuse" type="object"
invisible="state != 'hr_manager'"
class="oe_highlight"
groups="hr_base.group_general_manager,hr_base.group_executive_manager" />
<button name="re_draft" string="Re-Draft" type="object"
invisible="state not in ['refuse', 'approved']"
class="oe_highlight" groups="hr.group_hr_manager"
confirm="Are you sure to Reset To Draft This Record?" />
<field name="state" widget="statusbar" />
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="employee_id"
placeholder="Employee Name"
string="Employee" required="1"
readonly="state != 'draft'" />
</h1>
</div>
<group>
<group>
<field name="new_level" string="Promotion Level"
domain="[('type','=','level')]"
readonly="state != 'draft'" required="1" widget="selection"
context="{'default_type': 'level'}" />
<field name="new_group" string="Promotion Group"
domain="[('type','=','group')]"
context="{'default_type': 'group'}"
readonly="state != 'draft'"
required="1" widget="selection" />
<field name="new_degree" string="Promotion Degree"
domain="[('type','=','degree')]"
context="{'default_type': 'degree'}"
readonly="state != 'draft'" required="1" widget="selection" />
</group>
<group>
<field name="date" string="Promotion Date"
readonly="state != 'draft'" />
<field name="company_id" groups="base.group_multi_company"
readonly="1" />
<field name="old_scale" string="Current Scale" readonly="1"
force_save="1" />
<field name="old_level" string="Current Level" invisible="1" />
<field name="old_group" string="Current Group" invisible="1" />
<field name="old_degree" string="Current Degree" invisible="1" />
<field name="old_level_2" string="Current Level" readonly="1"
force_save="1" />
<field name="old_group_2" string="Current Group" readonly="1"
force_save="1" />
<field name="old_degree_2" string="Current Degree" readonly="1"
force_save="1" />
</group>
</group>
<separator string="Comment" />
<field name="comment" string="" readonly="state != 'draft'" />
</sheet>
<!-- Discuss widgets for history and communication -->
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<record model="ir.ui.view" id="employee_promotions_tree_view">
<field name="name">employee.promotions.tree</field>
<field name="model">employee.promotions</field>
<field name="arch" type="xml">
<list decoration-success="state=='approved'" decoration-info="state == 'draft'"
decoration-danger="state == 'refuse'" string="Employee promotions">
<field name="employee_id" string="Employee" />
<field name="date" string="Date" />
<field name="new_level" string="New level" />
<field name="new_group" string="New group" />
<field name="new_degree" string="New degree" />
<field name="state" string="State" />
</list>
</field>
</record>
<menuitem id="employee_promotions_view" name="Employee Promotions"
parent="exp_hr_payroll.menu_hr_payroll_root"
action="employee_promotions_action"
sequence="11" />
<!--#########################
Smart button employee promotions #######-->
<record id="employee_promotions_action_hr_employee" model="ir.actions.act_window">
<field name="name">Promotions Action</field>
<field name="res_model">employee.promotions</field>
<field name="view_mode">list,form</field>
<field name="context">{'search_default_employee_id': active_id, 'default_employee_id':
active_id}</field>
<field name="domain">[('state','=','approved'), ('employee_id','=',active_id)]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a Promotions...
</p>
</field>
</record>
<record id="view_employee_promotions_inherit" model="ir.ui.view">
<field name="name">hr.employee</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form" />
<field name="priority">14</field>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="%(employee_promotions_action_hr_employee)d"
class="oe_stat_button"
type="action" icon="fa-book">
<field name="promotions_count" widget="statinfo" string="Promotions" />
</button>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,171 @@
<odoo>
<data>
<!-- Action -->
<record model="ir.actions.act_window" id="employee_reward_list_action">
<field name="name">Employee Reward and Allowances</field>
<field name="res_model">hr.employee.reward</field>
<field name="view_mode">list,form</field>
</record>
<!-- Form View -->
<record id="employee_reward_form_view" model="ir.ui.view">
<field name="name">Employee Reward and Allowances</field>
<field name="model">hr.employee.reward</field>
<field name="arch" type="xml">
<form string="Employee Reward and Allowances">
<header>
<button string="Direct Manager" type="object" name="action_submit"
invisible="state != 'draft'"
class="oe_highlight"
groups="hr_base.group_division_manager" />
<button string="HRM Approval" type="object" name="action_hrm"
invisible="state != 'submitted'"
class="oe_highlight"
groups="hr.group_hr_manager" />
<button string="GM Approval" type="object" name="action_done"
invisible="state != 'hrm'"
class="oe_highlight"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<button string="Recalculate" type="object" name="recalculate"
invisible="state not in ['draft', 'submitted']"
class="oe_highlight"
groups="hr.group_hr_user, hr.group_hr_manager" />
<button string="Add Employees" type="object" name="action_add_employees"
invisible="state != 'draft'"
class="oe_highlight"
groups="hr.group_hr_user, hr.group_hr_manager" />
<button string="Refuse" type="object" name="action_refuse"
invisible="state not in ['submitted', 'hrm']"
class="oe_highlight"
groups="hr.group_hr_manager, hr_base.group_general_manager" />
<button string="Re-Draft" type="object" name="re_draft"
invisible="state not in ['refused', 'done']"
class="oe_highlight"
confirm="Are you sure to Reset To Draft This Record?"
groups="hr.group_hr_manager" />
<field name="state" widget="statusbar" />
</header>
<sheet>
<group>
<group>
<field name="transfer_type"
readonly="state not in ['draft', 'submitted']"
required="True" />
<field name="reward_type"
readonly="state != 'draft'"
required="True" />
<field name="allowance_name"
invisible="reward_type != 'allowance'"
readonly="state not in ['draft', 'submitted']"
required="reward_type == 'allowance'" />
<field name="account_id" string="Account"
invisible="transfer_type != 'accounting'"
readonly="state != 'hrm'"
required="transfer_type == 'accounting' and state == 'hrm'" />
<field name="journal_id" string="Journal"
invisible="transfer_type != 'accounting'"
readonly="state != 'hrm'"
required="transfer_type == 'accounting' and state == 'hrm'" />
<field name="benefits_discounts"
invisible="transfer_type != 'payroll'"
readonly="state != 'submitted'"
required="transfer_type == 'payroll' and state == 'submitted'" />
<field name="date_from"
invisible="transfer_type != 'payroll'"
readonly="state != 'submitted'"
required="transfer_type == 'payroll' and state == 'submitted'" />
<field name="date_to"
invisible="transfer_type != 'payroll'"
readonly="state != 'submitted'"
required="transfer_type == 'payroll' and state == 'submitted'" />
</group>
<group>
<field name="date" widget="date"
readonly="state != 'draft'" />
<field name="allowance_reason"
readonly="state != 'draft'" />
<field name="amount"
invisible="reward_type != 'amount'"
readonly="state != 'draft'"
required="True" />
<field name="check_appraisal"
readonly="state not in ['draft', 'submitted']"
groups="hr.group_hr_user, hr.group_hr_manager" />
<field name="percentage"
readonly="state != 'draft'"
invisible="check_appraisal == True" />
<field name="reward_once"
readonly="state not in ['draft', 'submitted']"
groups="hr.group_hr_user, hr.group_hr_manager" />
<field name="company_id"
groups="base.group_multi_company"
readonly="True" />
</group>
</group>
<field name="line_ids_reward"
context="{'percentage': percentage, 'account_id': account_id, 'journal_id': journal_id}"
readonly="state in ['submitted', 'done', 'refused']"
required="state == 'hrm'">
<list string="Employee Reward and Allowances" editable="bottom">
<field name="amount"
groups="hr_base.group_executive_manager,hr.group_hr_user" />
<field name="percentage" />
<field name="reward_state" invisible="True" />
</list>
</field>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<!-- Tree View -->
<record model="ir.ui.view" id="employee_reward_tree_view">
<field name="name">Employee Reward and Allowances</field>
<field name="model">hr.employee.reward</field>
<field name="arch" type="xml">
<list decoration-success="state == 'done'" decoration-info="state == 'draft'"
string="Employee Reward and Allowances">
<field name="date" widget="date" />
<field name="allowance_reason" />
<field name="reward_type" />
<field name="state" />
</list>
</field>
</record>
<!-- Menu Item -->
<menuitem id="employee_reward_menu"
name="Employee Reward and Allowances"
parent="exp_hr_payroll.menu_hr_payroll_root"
action="employee_reward_list_action"
sequence="10"
groups="hr_base.group_executive_manager,hr_base.group_general_manager,exp_hr_payroll.group_hr_payroll_user" />
</data>
</odoo>

View File

@ -0,0 +1,109 @@
<odoo>
<data>
<!--inheriting hr_employee form view-->
<record id="hr_contract_salary_form_view" model="ir.ui.view">
<field name="name">hr.contract.salary.form.inherit</field>
<field name="model">hr.contract</field>
<field name="inherit_id" ref="hr_contract.hr_contract_view_form" />
<field name="arch" type="xml">
<xpath expr="//group[@name='salary']" position="before">
<group invisible="1">
<field name="hide" invisible="1" />
<field name="required_condition" invisible="1" />
</group>
</xpath>
<xpath expr="//group[@name='salary']" position="after">
<group>
<field name="total_allowance" readonly="1"
invisible="[('consultants', '==', True)]"
groups="hr.group_hr_user,hr.group_hr_manager" />
<field name="total_deduction" readonly="1"
invisible="[('consultants', '==', True)]"
groups="hr.group_hr_user,hr.group_hr_manager" />
<field name="total_net" readonly="1"
invisible="[('consultants', '==', True)]"
groups="hr.group_hr_user,hr.group_hr_manager" />
</group>
</xpath>
<xpath expr="//field[@name='salary_insurnce']" position="after">
<field name="house_allowance_temp" readonly="[('state', '!=', 'draft')]"
groups="hr.group_hr_user,hr.group_hr_manager" />
<field name="transport_allowance" readonly="[('state', '!=', 'draft')]"
groups="hr.group_hr_user,hr.group_hr_manager" />
</xpath>
<xpath expr="//group[@name='salary_info']" position="after">
<group name="advantage" groups="hr.group_hr_user,hr.group_hr_manager">
<separator colspan="2" string="Advantages" />
<field name="advantages" nolabel="1" readonly="[('state', '!=', 'draft')]">
<list>
<!-- <field name="benefits_discounts" required="1" />-->
<field name="type" invisible="1" />
<field name="date_from" required="1" />
<field name="date_to" />
<field name="amount" required="1" />
<field name="done" readonly="1" />
<field name="out_rule" invisible="[('type', '!=', 'customize')]" />
<!--To
link employee move line from official mission to advantages line in
contract-->
<field name="official_mission_id" invisible="1" />
<!--To
link employee move line from over time to advantages line in
contract-->
<field name="over_time_id" invisible="1" />
<!--To
link employee move line from employee reward to advantages line in
contract-->
<field name="reward_id" invisible="1" />
<field name="penalty_id" invisible="1" />
</list>
</field>
</group>
</xpath>
<xpath expr="//group[@name='duration_group']" position="after">
<group name="accounting_info" string="Accounting">
<field name="journal_id" required="[('required_condition', '=', True)]"
readonly="[('state', '!=', 'draft')]" widget="selection" />
<field name="analytic_account_id"
required="[('required_condition', '=', True)]"
readonly="[('state', '!=', 'draft')]" widget="selection" />
</group>
</xpath>
<xpath expr="//group[@name='salary_scale_group']" position="inside">
<field name="salary_scale" required="1" widget="selection"
domain="[('type', '=', 'scale')]"
context="{'default_type': 'scale'}" readonly="[('state', '!=', 'draft')]" />
<field name="salary_level" string="Salary Level" widget="selection"
context="{'default_type': 'level'}"
invisible="[('hide', '==', False)]"
readonly="[('state', '!=', 'draft')]"
required="[('hide', '==', True)]"
domain="[('type', '=', 'level')]" />
<field name="salary_group" string="Salary Group" widget="selection"
domain="[('type', '=', 'group')]"
invisible="[('hide', '==', False)]"
readonly="[('state', '!=', 'draft')]"
required="[('hide', '==', True)]"
context="{'default_type': 'group'}" />
<field name="salary_degree" string="Salary Degree" widget="selection"
domain="[('type', '=', 'degree')]"
invisible="[('hide', '==', False)]"
readonly="[('state', '!=', 'draft')]"
required="[('hide', '==', True)]"
context="{'default_type': 'degree'}" />
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,22 @@
<odoo>
<data>
inheriting hr_employee form view
<record model="ir.ui.view" id="hr_employee_salary_scale_inherited_form_view">
<field name="name">hr.employee.form.view</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='bank_info']" position="after">
<group col="2">
<group string="Salary Scale" name="salary_scale">
<field name="salary_scale" widget="selection" readonly="1"/>
<field name="salary_level" widget="selection" readonly="1"/>
<field name="salary_group" widget="selection" readonly="1"/>
<field name="salary_degree" widget="selection" readonly="1"/>
</group>
</group>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!--inheriting re-contract form view-->
<record model="ir.ui.view" id="re_contract_inherited_form_view">
<field name="name">hr.re.contract.inherited.form.view</field>
<field name="model">hr.re.contract</field>
<field name="inherit_id" ref="hr_contract_custom.view_re-contracting_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='contract_id']" position="after">
<field name="salary_scale" invisible="1" readonly="1"/>
<field name="salary_level" invisible="1" readonly="1"/>
<field name="salary_group" invisible="1" readonly="1"/>
<field name="salary_degree" invisible="1" readonly="1"/>
</xpath>
<!--xpath expr="//field[@name='increase_salary']" position="after">
<field name="new_salary_scale" widget="selection" domain="[('type','=','scale')]"
string="New Salary Scale" context="{'default_type': 'scale'}"
attrs="{'invisible':[('state','=','draft'),('increase_salary','in',['no',''])],
'required':[('state','!=','draft'),('increase_salary','=','yes')],'readonly':[('state','!=','submitted')]}"/>
<field name="new_salary_level" widget="selection"
domain="[('type','=','level'),('salary_scale_id', '=',new_salary_scale)]"
string="New Salary Level" context="{'default_type': 'level'}"
attrs="{'invisible':[('state','=','draft'),('increase_salary','in',['no',''])],
'required':[('state','!=','draft'),('increase_salary','=','yes')],'readonly':[('state','!=','submitted')]}"/>
<field name="new_salary_group" widget="selection"
domain="[('type','=','group'),('salary_scale_level_id', '=', new_salary_level)]"
string="New Salary Group" context="{'default_type': 'group'}"
attrs="{'invisible':[('state','=','draft'),('increase_salary','in',['no',''])],
'required':[('state','!=','draft'),('increase_salary','=','yes')],'readonly':[('state','!=','submitted')]}"/>
<field name="new_salary_degree" widget="selection"
domain="[('type','=','degree'),('salary_scale_group_id', '=', new_salary_group)]"
string="New Salary Degree" context="{'default_type': 'degree'}"
attrs="{'invisible':[('state','=','draft'),('increase_salary','in',['no',''])],
'required':[('state','!=','draft'),('increase_salary','=','yes')],'readonly':[('state','!=','submitted')]}"/>
</xpath-->
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,47 @@
<odoo>
<data>
<!--MENU ITEM SALARY SCALE main-->
<menuitem
id="salary_scale_main_menu"
name="Salary Scale"
parent="exp_hr_payroll.menu_hr_payroll_configuration"
sequence="1"
/>
<!--MENU ITEM SALARY SCALE child-->
<menuitem
id="salary_scale_menu"
name="Salary Scale"
parent="salary_scale_main_menu"
sequence="1"
action="salary_scale_record_action"
/>
<!--MENU ITEM SALARY SCALE level degree child-->
<menuitem
id="salary_scale_level_degree_menu"
name="Scale degree"
parent="salary_scale_main_menu"
sequence="4"
action="salary_scale_level_degree_record_action"
/>
<!--MENU ITEM SALARY SCALE level group -->
<menuitem
id="salary_scale_level_group_menu"
name="Scale Group"
parent="salary_scale_main_menu"
sequence="3"
action="salary_scale_level_group_record_action"
/>
<!--MENU ITEM SALARY SCALE level -->
<menuitem
id="salary_scale_level_menu"
name="Scale Levels"
parent="salary_scale_main_menu"
sequence="2"
action="salary_scale_level_action"
/>
</data>
</odoo>

View File

@ -0,0 +1,189 @@
<odoo>
<data>
<record id="hr_salary_rule_view_form_inherit" model="ir.ui.view">
<field name="name">hr.salary.rule.form.inherit</field>
<field name="model">hr.salary.rule</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_salary_rule_form" />
<field name="arch" type="xml">
<xpath expr="//label[@for='category_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//group[1]" position="replace">
<group>
<group>
<field name="category_id" />
<field name="code" />
<field name="sequence" />
<field name="company_id" options="{'no_create': True}"
groups="base.group_multi_company" />
</group>
<group>
<field name="start_date" />
<field name="end_date" />
</group>
</group>
</xpath>
<xpath expr="//page[1]" position="replace">
<field name="active" invisible="1" />
<page string="General">
<separator colspan="4" string="Computation" />
<group>
<group>
<field name="amount_select" />
<newline />
<field colspan="4" name="amount_python_compute"
invisible="amount_select != 'code'"
required="amount_select == 'code'" />
<newline />
<field name="salary_type" invisible="amount_select == 'code'" />
<field name="fixed_amount"
invisible="salary_type != 'fixed' or amount_select in ('percentage', 'code')"
required="salary_type == 'fixed'" />
<field name="related_benefits_discounts" widget="many2many_tags"
invisible="amount_select != 'percentage'"
required="amount_select == 'percentage'" />
<newline />
<field name="amount_percentage"
invisible="amount_select != 'percentage' or salary_type in ('related_levels', 'related_groups', 'related_degrees')"
required="amount_select == 'percentage'" />
</group>
<group>
<field name="special" />
<field name="rules_type" required="1" />
<field name="reduce_with_leaves" />
<field name="min_leave_days_to_deduct"
invisible="reduce_with_leaves == False" />
<!--field
name="related_qualifications"/-->
</group>
</group>
<!--group
col="2">
<group>
<separator colspan="2" string="Conditions"/>
<field name="condition_select"/>
<newline/>
<field name="condition_python"
invisible="condition_select != 'python'"
required="condition_select == 'python'"
colspan="4"/>
<newline/>
<field name="condition_range"
invisible="condition_select != 'range'"
required="condition_select == 'range'"/>
<newline/>
<field name="condition_range_min" colspan="2"
invisible="condition_select != 'range'"
required="condition_select == 'range'"/>
<newline/>
<field name="condition_range_max" colspan="2"
invisible="condition_select != 'range'"
required="condition_select == 'range'"/>
<newline/>
</group>
<group>
<separator colspan="2" string="Company Contribution"/>
<field name="register_id"/>
</group>
</group-->
</page>
</xpath>
<!--[add]
adding accounting info in salary rule -->
<xpath expr="//page[1]" position="after">
<page string="Accounting Info">
<group>
<field name="transfer_by_emp_type" string="Transfer By Employee Type" />
<field name="rule_debit_account_id" string="Debit Account"
invisible="transfer_by_emp_type == True" />
<field name="rule_credit_account_id" string="Credit Account"
invisible="transfer_by_emp_type == True" />
</group>
<field name="account_ids" invisible="transfer_by_emp_type == False">
<list editable="bottom">
<field name="emp_type_id" string="Employee Type" />
<field name="debit_account_id" string="Debit Account" />
<field name="credit_account_id" string="Credit Account" />
</list>
</field>
</page>
</xpath>
<xpath expr="//notebook/page[1]" position="after">
<page name="related_salary" string="Related Salary Configuration"
invisible="salary_type in (False, 'fixed')">
<field name="salary_amount_ids">
<list editable="bottom">
<field name="salary_scale" required="1"
domain="[('type','=','scale')]"
context="{'default_type': 'scale'}" />
<field name="salary_scale_level" required="1"
domain="[('type','=','level')]"
context="{'default_type': 'level'}" />
<field name="salary_scale_group" required="1"
domain="[('type','=','group')]"
context="{'default_type': 'group'}"
column_invisible="parent.salary_type not in ('related_groups', 'related_degrees')" />
<field name="salary_scale_degree" required="1"
domain="[('type','=','degree')]"
context="{'default_type': 'degree'}"
column_invisible="parent.salary_type != 'related_degrees'" />
<field name="salary" required="1" />
</list>
</field>
</page>
</xpath>
<!-- page invisible-->
<xpath expr="//page[@name='rules']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//page[5]" position="replace">
<page string="Inputs" invisible="1">
<field name="input_ids" mode="list">
<list string="Input Data" editable="bottom">
<field name="name" />
<field name="code" />
</list>
</field>
</page>
</xpath>
<!-- page-->
</field>
</record>
<!-- Salary Category-->
<record id="hr_salary_rule_category__inherited_form" model="ir.ui.view">
<field name="name">hr.salary.rule.category.inherited.form</field>
<field name="model">hr.salary.rule.category</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_salary_rule_category_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='code']" position="after">
<field name="rule_type" required="1" />
</xpath>
</field>
</record>
<!-- Salary rule tree-->
<record id="hr_salary_rule_list2" model="ir.ui.view">
<field name="name">hr.salary.rule.list</field>
<field name="model">hr.salary.rule</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_salary_rule_list" />
<field name="arch" type="xml">
<xpath expr="//field[@name='register_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='code']" position="after">
<field name="company_id" />
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,140 @@
<?xml version="1.0"?>
<odoo>
<data>
<!-- Search View -->
<record id="salary_scale_filter_view" model="ir.ui.view">
<field name="name">salary.scale.filter.view</field>
<field name="model">hr.payroll.structure</field>
<field name="arch" type="xml">
<search string="Search Salary Scale">
<field name="name" filter_domain="[('name','ilike',self)]" />
<separator />
<filter string="Scale" name="scale" domain="[('type','=', 'scale')]" />
<filter string="Level" name="level" domain="[('type','=', 'level')]" />
<filter string="Group" name="group" domain="[('type','=', 'group')]" />
<filter string="Degree" name="degree" domain="[('type','=', 'degree')]" />
</search>
</field>
</record>
<!-- Action -->
<record id="salary_scale_record_action" model="ir.actions.act_window">
<field name="name">Salary Scale</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">list,form</field>
<field name="domain">[('type','=','scale')]</field>
<field name="context">{'default_type':'scale', 'search_default_scale': 1}</field>
<field name="search_view_id" ref="salary_scale_filter_view" />
</record>
<!-- Form View -->
<record id="salary_scale_form_view" model="ir.ui.view">
<field name="name">Salary Scale</field>
<field name="model">hr.payroll.structure</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_employee_grade_form" />
<field name="arch" type="xml">
<xpath expr="//group[1]" position="replace">
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object" class="oe_stat_button"
icon="fa-archive">
<field name="active" widget="boolean_button"
options="{'terminology': 'archive'}" />
</button>
</div>
<div class="oe_title oe_left">
<div class="oe_edit_only">
<label for="name" />
</div>
<h1>
<field name="name" default_focus="1" />
</h1>
</div>
<group>
<field name="code" />
<field name="salary_scale_id"
invisible="type == 'scale'"
required="type != 'scale'"
domain="[('type', '=', 'scale')]"
context="{'default_type': 'scale'}" />
<field name="salary_scale_level_id"
invisible="type in ['level', 'scale']"
required="type not in ['level', 'scale']"
domain="[('type', '=', 'level')]"
context="{'default_type': 'level'}" />
<field name="salary_scale_group_id"
invisible="type != 'degree'"
required="type == 'degree'"
domain="[('type', '=', 'group')]"
context="{'default_type': 'group'}" />
<field name="company_id" groups="base.group_multi_company" readonly="1"
options="{'no_create': True}" />
</group>
<group name="salary_scale">
<group>
<field name="base_salary"
invisible="type != 'degree'"
required="type == 'degree'" />
<field name="level_num"
invisible="type != 'scale'"
required="type == 'scale'" />
<field name="retirement_age"
invisible="type != 'scale'"
required="type == 'scale'" />
</group>
<group>
<field name="start_date"
invisible="type != 'scale'" />
<field name="end_date"
invisible="type != 'scale'" />
<field name="transfer_type"
invisible="type != 'scale'"
required="type == 'scale'" />
<field name="analytic_account_id" string="Analytic Account"
invisible="type != 'scale'" />
<field name="groups_number"
invisible="type != 'level'"
required="type == 'level'" />
<field name="degree_number"
invisible="type != 'group'"
required="type == 'group'" />
<field name="gread_min"
invisible="type != 'group'" />
<field name="gread_max"
invisible="type != 'group'" />
<field name="interval_time"
invisible="type != 'degree'" />
<field name="type" invisible="1" />
</group>
</group>
</xpath>
<xpath expr="//notebook" position="replace">
<notebook invisible="type != 'scale'">
<page name="salary_scale_levels" string="Salary Scale Levels">
<field name="salary_scale_levels_ids"
readonly="1" required="1" />
</page>
<page name="salary_scale_level_groups" string="Salary Scale Level Groups">
<field name="salary_scale_level_groups_ids"
readonly="1" required="1" />
</page>
<page name="salary_scale_level_degrees" string="Salary Scale Level Degrees">
<field name="salary_scale_level_degrees_ids"
readonly="1" required="1" />
</page>
<page name="salary_rules" string="Benefits and discounts">
<field name="rule_ids">
<list>
<field name="name" />
<field name="code" />
<field name="company_id" />
</list>
</field>
</page>
</notebook>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="salary_scale_level_action" model="ir.actions.act_window">
<field name="name">Salary Scale Level</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">list,form</field>
<field name="domain">[('type','=','level')]</field>
<field name="context">{'default_type':'level', 'search_default_level': 1}</field>
<field name="search_view_id" ref="salary_scale_filter_view" />
</record>
<record id="salary_scale_level_form_view" model="ir.ui.view">
<field name="name">Salary Scale Level</field>
<field name="model">hr.payroll.structure</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_employee_grade_form" />
<field name="arch" type="xml">
<xpath expr="//notebook" position="before">
<group>
<field name="benefits_discounts_ids" widget="many2many_tags"
invisible="[('type', 'not in', ['level', 'group'])]"
domain="[('category_id.rule_type','=',('allowance','deduction'))]" />
</group>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="salary_scale_level_degree_record_action" model="ir.actions.act_window">
<field name="name">Salary Scale Level Degree</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('type','=','degree')]</field>
<field name="context">{'default_type':'degree', 'search_default_degree': 1}</field>
<field name="search_view_id" ref="salary_scale_filter_view"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Customize menus security -->
<odoo>
<record model="ir.ui.menu" id="exp_hr_payroll.menu_hr_payroll_root">
<field name="groups_id" eval="[(4,ref('exp_hr_payroll.group_hr_payroll_user')),
(4,ref('hr_base.group_general_manager'))]"/>
</record>
</odoo>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<odoo>
<data>
<menuitem id="exp_hr_payroll.menu_hr_payroll_root" name="Payroll"
groups="exp_payroll_custom.group_hr_payroll_contributor,exp_hr_payroll.group_hr_payroll_user,exp_payroll_custom.group_payroll_finance_review,exp_payroll_custom.group_payroll_expense_manger,hr_base.group_account_manager,hr.group_hr_manager,hr_base.group_general_manager"/>
<menuitem id="exp_hr_payroll.menu_hr_payslip_run" sequence="1"
parent="exp_hr_payroll.menu_hr_payroll_root"
groups="hr_base.group_executive_manager,exp_payroll_custom.group_hr_payroll_contributor,exp_hr_payroll.group_hr_payroll_user,exp_payroll_custom.group_payroll_finance_review,exp_payroll_custom.group_payroll_expense_manger,hr_base.group_account_manager,hr.group_hr_manager,hr_base.group_general_manager"
/>
<record model="ir.ui.menu" id="exp_hr_payroll.menu_department_tree">
<field name="groups_id"
eval="[(4,ref('exp_hr_payroll.group_hr_payroll_user')),
(4,ref('hr_base.group_general_manager'))]"/>
</record>
<record model="ir.ui.menu" id="exp_hr_payroll.menu_hr_payroll_configuration">
<field name="groups_id" eval="[(4, ref('exp_hr_payroll.group_hr_payroll_user'))]"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="act_payslip_monthly_report" model="ir.actions.report">
<field name="model">hr.payslip</field>
<field name="name">Payslip PDF Report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_payroll_custom.payslip_monthly_report</field>
<field name="report_file">exp_payroll_custom.payslip_monthly_report</field>
</record>
<record id="payslip_monthly_report_xlsx" model="ir.actions.report">
<field name="model">hr.payslip</field>
<field name="name">Payslip Xlsx Report</field>
<field name="report_type">xlsx</field>
<field name="report_name">exp_payroll_custom.payslip_monthly_report_xlsx</field>
<field name="report_file">exp_payroll_custom.payslip_monthly_report_xlsx</field>
</record>
<record id="act_payslip_monthly_report" model="ir.actions.report">
<field name="model">hr.payslip</field>
<field name="name">Payslip PDF Report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_payroll_custom.payslip_monthly_report</field>
<field name="report_file">exp_payroll_custom.payslip_monthly_report</field>
<field name="binding_model_id" eval="False"/>
</record>
<record id="payslip_monthly_report_xlsx" model="ir.actions.report">
<field name="model">hr.payslip</field>
<field name="name">Payslip Xlsx Report</field>
<field name="report_type">xlsx</field>
<field name="report_name">exp_payroll_custom.payslip_monthly_report_xlsx</field>
<field name="report_file">exp_payroll_custom.payslip_monthly_report_xlsx</field>
<field name="binding_model_id" eval="False"/>
</record>
<record id="report_payroll_bank_xlsx" model="ir.actions.report">
<field name="model">payroll.bank.wiz</field>
<field name="name">Payroll Bank Report</field>
<field name="report_type">xlsx</field>
<field name="report_name">exp_payroll_custom.report_payroll_bank_xlsx</field>
<field name="report_file">Payroll Bank Report</field>
<field name="attachment_use">False</field>
</record>
<record id="bank_payslip_report" model="ir.actions.report">
<field name="model">payroll.bank.wiz</field>
<field name="name">Payroll Bank Report</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">exp_payroll_custom.report_payroll_bank_pdf</field>
<field name="attachment_use">False</field>
</record>
<record id="payroll_bank_wiz_report_docx" model="ir.actions.report">
<field name="model">payroll.bank.wiz</field>
<field name="name">Print Text</field>
<field name="report_type">qweb-text</field>
<field name="report_name">exp_payroll_custom.report_payroll_bank_pdf_docx</field>
<field name="binding_type">report</field>
<field name="attachment_use">False</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,339 @@
<odoo>
<data>
<record model="ir.ui.view" id="model_payslip_form_view">
<field name="name">hr.payslip.form</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_payslip_form" />
<field name="arch" type="xml">
<xpath expr="//header" position="replace">
<header>
<button string="Confirm" name="confirm" type="object"
invisible="state != 'computed'" class="oe_highlight"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<button string="Withdraw" name="withdraw" type="object"
invisible="state != 'computed'" class="oe_highlight"
confirm="Are you sure to Delete Compute Salaries?"
groups="hr.group_hr_manager" />
<button string="Recompute" name="compute_sheet" type="object"
invisible="state != 'computed'" class="oe_highlight"
confirm="Are you sure to Recompute Salaries?"
groups="exp_hr_payroll.group_hr_payroll_user" />
<button string="Transfer" name="transfer" type="object"
invisible="state != 'confirmed'" class="oe_highlight"
confirm="Are you sure to Transfer Accounting?"
groups="hr.group_hr_manager" />
<button string="Return" name="return_button" type="object"
invisible="state not in ['confirmed', 'transfered']"
class="oe_highlight" confirm="Are you sure to Return Compute Salaries?"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<button string="Compute Sheet" name="compute_sheet" type="object"
invisible="state != 'draft'" class="oe_highlight"
groups="exp_hr_payroll.group_hr_payroll_user" />
<field name="state" widget="statusbar"
statusbar_visible="draft,computed,confirmed,transfered" />
</header>
</xpath>
<xpath expr="//form" position="attributes">
<attribute name="edit">0</attribute>
<attribute name="delete">0</attribute>
<attribute name="create">0</attribute>
</xpath>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//group[1]" position="replace">
<group col="4">
<label for="date_from" string="Period" />
<div>
<field name="date_from" class="oe_inline" /> - <field name="date_to"
class="oe_inline" />
</div>
<field name="contract_id" context="{'default_employee_id': employee_id}" />
<field name="struct_id" domain="[('type','=','scale')]"
string="Salary Scale" />
<field name="move_id" readonly="1" />
</group>
</xpath>
<xpath expr="//page[4]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//page[3]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//page[2]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//notebook/page[1]" position="before">
<page string="Allowances">
<field name="allowance_ids" readonly="1">
<list>
<field name="name" />
<field name="category_id" string="Allowance" />
<field name="sequence" invisible="1" />
<field name="quantity" invisible="1" />
<field name="rate" />
<field name="salary_rule_id" invisible="1" />
<field name="amount" />
<field name="total" />
</list>
</field>
</page>
<page string="Deductions">
<field name="deduction_ids" readonly="1">
<list>
<field name="name" />
<field name="category_id" string="Deduction" />
<field name="sequence" invisible="1" />
<field name="quantity" invisible="1" />
<field name="rate" invisible="1" />
<field name="salary_rule_id" invisible="1" />
<field name="amount" />
<field name="total" />
</list>
</field>
</page>
<page name="loans" string="Loans"
groups="hr_loans_salary_advance.group_loan_manager">
<field name="loan_ids" readonly="1"
groups="hr_loans_salary_advance.group_loan_manager">
<list name="loans">
<field name="name" />
<field name="date" />
<field name="account_id" />
<field name="amount" />
<field name="paid" invisible="1" />
</list>
</field>
</page>
</xpath>
<xpath expr="//form/sheet/notebook" position="after">
<group col="4" colspan="4">
<field name="total_allowances" />
<field name="total_deductions" />
<field name="total_loans"
groups="hr_loans_salary_advance.group_loan_manager" />
<field name="total_sum" />
</group>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="hr_payslip_run_inherited_form_view">
<field name="name">hr.payslip.run.inherit.form</field>
<field name="model">hr.payslip.run</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_payslip_run_form" />
<field name="arch" type="xml">
<xpath expr="//header" position="replace">
<header>
<button name="compute_sheet" type="object" invisible="state != 'draft'"
string="Generate Payslip" class="oe_highlight"
groups="exp_hr_payroll.group_hr_payroll_user" />
<button name="confirm" type="object" invisible="state != 'computed'"
string="Confirm" class="oe_highlight"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<button name="withdraw" type="object" invisible="state != 'computed'"
string="Withdraw" class="oe_highlight" groups="hr.group_hr_manager"
confirm="Are you sure to Delete Compute Salaries?" />
<button name="compute_sheet" type="object" invisible="state != 'computed'"
string="Recompute" class="oe_highlight"
confirm="Are you sure to Recompute Salaries?"
groups="exp_hr_payroll.group_hr_payroll_user" />
<button string="Transfer" name="transfer" type="object"
invisible="state != 'confirmed'" class="oe_highlight"
confirm="Are you sure to Transfer Accounting?"
groups="hr.group_hr_manager" />
<button string="Return" name="return_button" type="object"
invisible="state not in ['confirmed', 'transfered']"
class="oe_highlight" confirm="Are you sure to Return Compute Salaries?"
groups="hr_base.group_executive_manager,hr_base.group_general_manager" />
<field name="state" widget="statusbar"
statusbar_visible="draft,computed,confirmed,transfered" />
</header>
</xpath>
<xpath expr="//field[@name='credit_note']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='credit_note']" position="before">
<label for="holiday_start_date" string="Holiday Period" />
<div>
<field name="holiday_start_date" class="oe_inline" /> - <field
name="holiday_end_date" class="oe_inline" />
</div>
<field name="salary_scale" domain="[('type', '=', 'scale')]"
readonly="state != 'draft'" required="1" />
<field name="journal_id" readonly="state != 'draft'"
required="required_condition == True" />
<field name="move_id" readonly="1" invisible="required_condition == False" />
<field name="company_id" groups="base.group_multi_company" readonly="1"
options="{'no_create': True}" />
<field name="required_condition" invisible="1" />
<field name="employee_value_ids" invisible="1" />
</xpath>
<xpath expr="//field[@name='slip_ids']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//separator[1]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//form/sheet" position="inside">
<notebook>
<page name="payslip_ids" string="Payslips">
<field name="slip_ids" />
</page>
<page name="employee_ids" string="Employees">
<field name="employee_ids" nolabel="1" widget="many2many"
readonly="state != 'draft'" />
</page>
<page name="department_ids" string="Departments">
<field name="department_ids" nolabel="1" widget="many2many"
readonly="state != 'draft'" />
</page>
</notebook>
</xpath>
</field>
</record>
<record id="hr_payslip_run_tree_inherit" model="ir.ui.view">
<field name="name">hr.payslip.run.tree</field>
<field name="model">hr.payslip.run</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_payslip_run_tree" />
<field name="arch" type="xml">
<list position="replace">
<list decoration-success="state=='transfered'"
decoration-info="state == 'draft'">
<field name="name" />
<field name="date_start" />
<field name="date_end" />
<field name="credit_note" invisible="1" />
<field name="state" />
</list>
</list>
</field>
</record>
<record id="inherited_hr_payslip_line_form" model="ir.ui.view">
<field name="name">hr.payslip.line.form.inherited</field>
<field name="model">hr.payslip.line</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_payslip_line_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="after">
<field name="leave_request_case" />
</xpath>
</field>
</record>
<record id="inherited_view_hr_payslip_line_tree" model="ir.ui.view">
<field name="name">hr.payslip.line.tree.inherited</field>
<field name="model">hr.payslip.line</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_payslip_line_tree" />
<field name="arch" type="xml">
<xpath expr="//field[@name='category_id']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='employee_id']" position="attributes">
<attribute name="invisible">0</attribute>
</xpath>
<xpath expr="//field[@name='employee_id']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='sequence']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='code']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='quantity']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='rate']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='amount']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='total']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
</field>
</record>
<record id="view_hr_payslip_inherit_tree" model="ir.ui.view">
<field name="name">hr.payslip.tree</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_payslip_tree" />
<field name="arch" type="xml">
<list position="replace">
<list decoration-success="state=='transfered'"
decoration-info="state == 'draft'" create="false" edit="false"
delete="false">
<field name="employee_no" string="Employee Number" />
<field name="employee_id" />
<field name="company_id" groups="base.group_multi_company"
options="{'no_create': True}" />
<field name="date_from" optional="hide" />
<field name="date_to" optional="hide" />
<field name="payslip_run_id" invisible="1" />
<field name="basic_allowances" sum="Basic Salary" />
<field name="house_allowances" sum="House Allowance" />
<field name="trans_allowances" sum="Transport Allowance" />
<field name="other_allowances" sum="Others Allowance" />
<field name="total_allowances" sum="Total Allowance" decoration-bf="1" />
<field name="employee_insurnce" sum="Employee Insurnce" />
<field name="total_deductions" sum="Total Deduction" decoration-bf="1"
decoration-danger="1" />
<field name="total_loans" sum="Total Loans"
groups="hr_loans_salary_advance.group_loan_manager" />
<field name="total_sum" sum="Total Net" decoration-bf="1"
decoration-success="1" />
<field name="state" optional="hide" />
</list>
</list>
</field>
</record>
<record id="hr_payslip_view_kanban_inherit" model="ir.ui.view">
<field name="name">hr.payslip.kanban</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="exp_hr_payroll.hr_payslip_view_kanban" />
<field name="arch" type="xml">
<xpath expr="//kanban" position="attributes">
<attribute name="edit">0</attribute>
<attribute name="delete">0</attribute>
<attribute name="create">0</attribute>
</xpath>
<xpath expr="//field[@name='employee_id']" position="after">
<div class="col-12">
<span>
<field name="contract_id" />
</span>
</div>
</xpath>
<xpath expr="//field[@name='name']" position="after">
<div class="col-12">
<span>
<field name="total_sum" />
</span>
</div>
</xpath>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
<record id="view_hr_payslip_filter_inherit" model="ir.ui.view">
<field name="name">hr.payslip.select</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="exp_hr_payroll.view_hr_payslip_filter" />
<field name="arch" type="xml">
<xpath expr="//field[@name='employee_id']" position="after">
<field name="employee_no" string="Employee Number" />
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="view_salary_advance_form" model="ir.ui.view">
<field name="name">salary.advance.form</field>
<field name="model">salary.advance</field>
<field name="arch" type="xml">
<form string="Salary Advance">
<header>
<button name="submit_to_manager" string="Submit" type="object" states="draft"
class="oe_highlight"/>
<button name="approve_request" string="Approve" type="object" states="submit"
class="oe_highlight" groups="hr.group_hr_manager,hr.group_hr_user"/>
<button name="approve_request_acc_dept" string="Approve" type="object" states="waiting_approval"
class="oe_highlight" groups="account.group_account_manager,account.group_account_user"/>
<button name="cancel" string="Cancel" type="object" states="draft,submit"/>
<button name="reject" string="Reject" type="object" states="waiting_approval"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,submit,waiting_approval,approve,cancel,reject"/>
</header>
<sheet>
<div class="oe_title oe_left">
<h2>
<field name="name" class="oe_inline" readonly="1"/>
</h2>
</div>
<group>
<group>
<field name="employee_id"/>
<field name="department"/>
<field name="date"/>
<field name="reason"/>
<field name="exceed_condition" groups="hr.group_hr_manager,hr.group_hr_user"/>
</group>
<group>
<field name="advance"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="company_id" groups="base.group_multi_currency"/>
<field name="credit"
attrs="{'invisible':[('state', '=', 'draft'), ('state', '=', 'submit')]}"
groups="account.group_account_manager"/>
<field name="debit"
attrs="{'invisible':[('state', '=', 'draft'), ('state', '=', 'submit')]}"
groups="account.group_account_manager"/>
<field name="journal"
attrs="{'invisible': [('state', '=', 'draft'), ('state', '=', 'submit')]}"
groups="account.group_account_manager"/>
<field name="employee_contract_id"
attrs="{'invisible': ['|', ('state', '=', 'draft'), ('state', '=', 'approve')]}"
groups="hr.group_hr_manager,hr.group_hr_user"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_salary_advance_tree">
<field name="name">salary.advance.tree</field>
<field name="model">salary.advance</field>
<field name="arch" type="xml">
<tree string="Salary Advance">
<field name="employee_id"/>
<field name="date"/>
<field name="advance"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_salary_advance_filter" model="ir.ui.view">
<field name="name">salary.advance.select</field>
<field name="model">salary.advance</field>
<field name="arch" type="xml">
<search string="Search">
<field name="name" string="Salary Advance" filter_domain="['|',('name','ilike',self)]"/>
<field name="employee_id"/>
<field name="state"/>
<filter string="My Requests" domain="[('employee_id.user_id.id','=',uid)]"
name="my_requests_filter"/>
<filter domain="[('state', '=', 'draft')]" string="To Submit" name="to_report" help="New Requests"/>
<filter domain="[('state','in',('submit','waiting_approval'))]" string="To Approve" name="submitted"
help="Submitted Requests"/>
<filter domain="[('state', '=', 'approve')]" string="Approved" name="approved"
help="Approved Requests"/>
<separator/>
<filter string="Employee" name="employee_id" domain="[]" context="{'group_by':'employee_id'}"/>
<filter name="State" string="State" domain="[]" context="{'group_by':'state'}"/>
<filter string="Date" domain="[]" name="date" context="{'group_by':'date'}"/>
</search>
</field>
</record>
<record id="action_my_salary_advance" model="ir.actions.act_window">
<field name="name">Salary Advance</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">salary.advance</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_salary_advance_filter"/>
<field name="context">{'search_default_my_requests_filter':1}</field>
<field name="domain">[('employee_id.user_id', '=', uid)]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Create Requests.
</p>
</field>
</record>
<record id="action_my_salary_advance_request_approved" model="ir.actions.act_window">
<field name="name">Salary Advance</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">salary.advance</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_salary_advance_filter"/>
<field name="context">{'search_default_approved':1}</field>
<field name="domain">[('employee_id.user_id', '=', uid)]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Create Requests.
</p>
</field>
</record>
<record id="action_salary_advance_to_approve" model="ir.actions.act_window">
<field name="name">Salary Advance</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">salary.advance</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_salary_advance_filter"/>
<field name="context">{'search_default_submitted': 1}</field>
<field name="domain"></field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Create Requests.
</p>
</field>
</record>
<record id="ir_seq_hr_advance" model="ir.sequence">
<field name="name">Salary Advance Request</field>
<field name="code">salary.advance.seq</field>
<field name="prefix">SAR</field>
<field name="padding">4</field>
<field name="number_increment">1</field>
<field name="number_next_actual">1</field>
<field name="company_id" eval="False"/>
</record>
<menuitem id="parent_menu_salary_advance" name="Advance" parent="hr_loans.menu_hr_loans_and_advances"
sequence="7"/>
<menuitem id="menu_my_salary_advance" action="action_my_salary_advance" parent="parent_menu_salary_advance"
name="Request Salary Advance" sequence="1"/>
<menuitem id="menu_salary_advance" action="action_salary_advance_to_approve" parent="parent_menu_salary_advance"
name="Salary Advance To Approve" sequence="3"
groups="hr.group_hr_manager,hr.group_hr_user,account.group_account_manager"/>
<menuitem id="menu_my_salary_advance_approved" action="action_my_salary_advance_request_approved"
parent="parent_menu_salary_advance" name="My Approved Salary Advance" sequence="2"/>
</data>
</odoo>

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="salary_scale_level_group_record_action" model="ir.actions.act_window">
<field name="name">Salary Scale Group</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('type','=','group')]</field>
<field name="context">{'default_type':'group', 'search_default_group': 1}</field>
<field name="search_view_id" ref="salary_scale_filter_view"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<!-- Salary Structure >
<record id="structure_base" model="hr.payroll.structure">
<field name="code">Scale</field>
<field name="name">Salary Scale</field>
<field name="transfer_type">all</field>
<field name="rule_ids" eval="[(6, 0, [ref('hr_rule_basic'), ref('hr_rule_house'),ref('hr_rule_transport'),ref('hr_rule_gosi')])]"/>
<field name="company_id" ref="base.main_company"/>
</record-->
<!-- advance salary rule -->
<!--record id="hr_rule_basic" model="hr.salary.rule">
<field name="name">Basic Salary</field>
<field name="sequence" eval="1"/>
<field name="code">BASIC Salary</field>
<field name="category_id" ref="exp_hr_payroll.ALW"/>
<field name="rules_type">salary</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.salary</field>
</record>
<record id="hr_rule_house" model="hr.salary.rule">
<field name="name">House Allowance</field>
<field name="sequence" eval="2"/>
<field name="code">House</field>
<field name="category_id" ref="exp_hr_payroll.ALW"/>
<field name="salary_type">fixed</field>
<field name="related_benefits_discounts" eval="[(6, 0, [ref('hr_rule_basic')])]"/>
<field name="rules_type">house</field>
<field name="condition_select">none</field>
<field name="amount_select">percentage</field>
<field name="amount_percentage">25</field>
</record>
<record id="hr_rule_transport" model="hr.salary.rule">
<field name="name">Transport Allowance</field>
<field name="sequence" eval="3"/>
<field name="code">Transport</field>
<field name="category_id" ref="exp_hr_payroll.ALW"/>
<field name="salary_type">fixed</field>
<field name="related_benefits_discounts" eval="[(6, 0, [ref('hr_rule_basic')])]"/>
<field name="rules_type">transport</field>
<field name="condition_select">none</field>
<field name="amount_select">percentage</field>
<field name="amount_percentage">10</field>
</record>
<record id="hr_rule_gosi" model="hr.salary.rule">
<field name="name">GOSI Deduction</field>
<field name="sequence" eval="4"/>
<field name="code">GOSI</field>
<field name="category_id" ref="exp_hr_payroll.DED"/>
<field name="rules_type">insurnce</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result=0
if contract.employee_id.check_nationality==True and contract.is_gosi_deducted=='yes':
result =contract.salary*0.0975
if result > 4387.5:
result= 4387.5
else:
result=result</field>
</record-->
</data>
</odoo>

View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# LCT, Life Connection Technology
# Copyright (C) 2019-2020 LCT
#
##############################################################################
from . import payslip_monthly_report
from . import payroll_bank_report
from . import employee_selection_wizard

View File

@ -0,0 +1,82 @@
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class EmployeeSelectionWizard(models.TransientModel):
_name = 'employee.selection.wizard'
_description = 'Employee Selection Wizard'
employee_ids = fields.Many2many(
'hr.employee',
string='Employees',
required=True,
)
employee_reward_id = fields.Many2one(comodel_name='hr.employee.reward',string='Employee_reward_id')
@api.onchange('employee_ids')
def _onchange_employee_ids(self):
return {
'domain': {
'employee_ids': [
('id', 'not in', self.employee_ids.ids),
('state','=','open'),
('active', '=', True)
]
}
}
def _get_active_employee_reward(self):
reward_id = self.env.context.get('default_employee_reward_id')
if not reward_id and self.env.context.get('active_model') == 'hr.employee.reward':
reward_id = self.env.context.get('active_id')
return reward_id
def action_confirm(self):
"""
Action to add employees to current employee reward record
"""
self.ensure_one()
# Get the current reward record or create a new one
reward = self.env['hr.employee.reward'].browse(self._get_active_employee_reward())
if not reward.exists():
# Get values from context
reward_vals = self.env.context.get('default_reward_vals', {})
reward = self.env['hr.employee.reward'].create(reward_vals)
print('percentage >>>>>>', self.env.context.get('default_reward_vals', {}))
# Prepare values for reward lines
vals_list = [
{
'employee_id': employee.id,
'employee_reward_id': reward.id,
}
for employee in self.employee_ids
]
existing_employees = reward.line_ids_reward.mapped('employee_id').ids
duplicate_employees = set(self.employee_ids.ids) & set(existing_employees)
if duplicate_employees:
duplicate_names = self.env['hr.employee'].browse(list(duplicate_employees)).mapped('name')
raise ValidationError(_(
"The following employees are already in reward lines: %s" % ', '.join(duplicate_names)
))
# Create all records in a single operation
reward.write({
'line_ids_reward': [(0, 0, vals) for vals in vals_list]
})
for line in reward.line_ids_reward:
fields = ['percentage', 'account_id', 'journal_id']
default_values = line.sudo().default_get(fields)
# Apply the default values to the line
line.write(default_values)
line.sudo().get_percentage_appraisal()
line.sudo()._compute_calculate_amount()
return {'type': 'ir.actions.act_window_close'}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_employee_selection_wizard_form" model="ir.ui.view">
<field name="name">employee.selection.wizard.form</field>
<field name="model">employee.selection.wizard</field>
<field name="arch" type="xml">
<form string="Select Employees">
<sheet>
<group>
<field name="employee_ids"
options="{'no_create': True, 'no_create_edit': True}"/>
<field name="employee_reward_id" invisible="1"/>
</group>
</sheet>
<footer>
<button name="action_confirm"
string="Add"
type="object"
class="btn-primary"/>
<button string="Cancel"
class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action to open the wizard -->
<record id="action_employee_selection_wizard" model="ir.actions.act_window">
<field name="name">Select Employees</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">employee.selection.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@ -0,0 +1,195 @@
# -*- coding:utf-8 -*-
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _
from zoneinfo import ZoneInfo
import datetime
import random
class BankPayslipReport(models.TransientModel):
_name = 'payroll.bank.wiz'
_description = "Bank Payslips Report"
date_from = fields.Date(string='Date From',required=True,
default=lambda self: date(date.today().year, date.today().month, 1))
date_to = fields.Date(string='Date To', required=True,
default=lambda self: date(date.today().year, date.today().month, 1)+relativedelta(months=1,days=-1))
pay_date = fields.Date(
string='Pay Date',
required=False)
salary_type= fields.Char(
string='',
required=False)
bank_ids = fields.Many2many('res.bank', string='Banks',required=True)
salary_ids = fields.Many2many('hr.payroll.structure', 'hrpayroll_rel', 'salary_id', 'colum2_id',string='Salary Structures')
level_ids = fields.Many2many('hr.payroll.structure','hrpayroll_rel_str', 'col1', 'col2', string='Salary Levels')
group_ids = fields.Many2many('hr.payroll.structure','hrpayroll_rel3', 'col11', 'colid2', string='Salary Degrees')
degree_ids = fields.Many2many('hr.payroll.structure','hrpayroll_rel4', 'colid1', 'col22' ,string='Salary Basice')
company_id = fields.Many2one('res.company', string="Company", default=lambda self:self.env.company.id)
employee_ids = fields.Many2many('hr.employee', string='Employees')
no_details = fields.Boolean('No Details' ,default=False)
report_type = fields.Selection(
[('salary', 'Salary'),
('overtime', 'Overtime'),
('mission', 'Mission'),
('training', 'Training'),
('allowance', 'Allowance'),
],default='salary', string='Report Type')
entry_type = fields.Selection(
[('all', 'ALL'),
('posted', 'Post'),
('unposted', 'Un Post'),
], default='all', string='Entry Type')
bank_type = fields.Selection(
[('rajhi', 'Al-Rajhi Bank'),
('alahli', 'Al-Ahli Bank'),
('riyadh', 'Al-Riyadh Bank'),
], default='rajhi', string='Select Bank')
@api.onchange('date_from')
def onchange_date_from(self):
if self.date_from :
self.date_to = fields.Date.from_string(self.date_from)+relativedelta(months=+1, day=1, days=-1)
def print_pdf_report(self):
self.ensure_one()
[data] = self.read()
date_from = self.date_from
date_to = self.date_to
employees = self.env['hr.employee'].search([('id', 'in', self.employee_ids.ids)])
banks = self.env['res.bank'].search([('id', 'in', self.bank_ids.ids)])
salary = self.env['hr.payroll.structure'].search([('id', 'in', self.salary_ids.ids)])
no_details =self.no_details
report_type = self.report_type
entry_type = self.entry_type
bank_type = self.bank_type
company_id = self.env['res.company'].search([('id', '=', self.company_id.id)])
datas = {
'employees': employees.ids,
'banks': banks.ids,
'salary': salary.ids,
'form': data,
'date_from': date_from,
'date_to': date_to,
'no_details': no_details,
'report_type': report_type,
'entry_type': entry_type,
'bank_type': bank_type,
'company_id': company_id,
}
return self.env.ref('exp_payroll_custom.bank_payslip_report').report_action(self, data=datas)
def print_report(self):
[data] = self.read()
date_from = self.date_from
date_to = self.date_to
no_details=self.no_details
report_type=self.report_type
entry_type=self.entry_type
bank_type=self.bank_type
employees = self.env['hr.employee'].search([('id', 'in', self.employee_ids.ids)])
banks = self.env['res.bank'].search([('id', 'in', self.bank_ids.ids)])
salary = self.env['hr.payroll.structure'].search([('id', 'in', self.salary_ids.ids)])
company_id = self.env['res.company'].search([('id', '=', self.company_id.id)])
datas = {
'employees': employees.ids,
'banks': banks.ids,
'salary': salary.ids,
'form': data,
'date_from': date_from,
'date_to': date_to,
'no_details': no_details,
'report_type': report_type,
'entry_type': entry_type,
'bank_type': bank_type,
'company_id': company_id.id,
}
return self.env.ref('exp_payroll_custom.report_payroll_bank_xlsx').report_action(self,data=datas)
def print_report_text(self):
self.ensure_one()
[data] = self.read()
date_from = self.date_from.strftime("%B")
date_from = self.date_from
date_to = self.date_to
pay_slip = self.date_from.strftime("%B %Y")
employees = self.env['hr.employee'].search([('id', 'in', self.employee_ids.ids)])
banks = self.env['res.bank'].search([('id', 'in', self.bank_ids.ids)])
salary = self.env['hr.payroll.structure'].search([('id', 'in', self.salary_ids.ids)])
no_details = self.no_details
report_type = self.report_type
entry_type = self.entry_type
bank_type = self.bank_type
company_id = self.env['res.company'].search([('id', '=', self.company_id.id)])
company_hr_no = self.env['res.company'].search([('id', '=', self.company_id.id)]).company_hr_no
phone = self.env['res.company'].search([('id', '=', self.company_id.id)]).phone
company_pay_no = self.env['res.company'].search([('id', '=', self.company_id.id)]).company_pay_no
company_registry = self.env['res.company'].search([('id', '=', self.company_id.id)]).company_registry
datestamp = datetime.datetime.now().strftime("%Y/%m/%d")
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
currency = self.env['res.company'].search([('id', '=', self.company_id.id)]).currency_id.name
if self.pay_date:
pay_date = self.pay_date
else:
pay_date = self.date_to
if report_type == 'salary':
self.salary_type = 'S'
elif report_type=='overtime':
self.salary_type = 'O'
else:
self.salary_type='B'
salary_type = self.salary_type
## Ranom vlaues in report
length_of_string = 5
length_of_string2 = 4
sample = "ABCDEFGHIJKLMNOPQURSTYWXZ0123456789"
generated_string1 = ''.join(random.choice(sample) for _ in range(length_of_string))
generated_string2 = ''.join(random.choice(sample) for _ in range(length_of_string2))
random_char = str(generated_string1)
random_char2 = str(generated_string2)
datas = {
'employees': employees.ids,
'banks': banks.ids,
'salary': salary.ids,
'form': data,
'date_from':date_from,
'date_to': date_to,
'no_details': no_details,
'report_type': report_type,
'entry_type': entry_type,
'bank_type': bank_type,
'company_id': company_id.english_name,
'timestamp': timestamp,
'datestamp': datestamp,
'currency': currency,
'pay_date': pay_date,
'salary_type': salary_type,
'company_hr_no': company_hr_no,
'phone': phone,
'company_pay_no': company_pay_no,
'company_registry': company_registry,
'pay_slip': pay_slip,
'random_char': random_char,
'random_char2': random_char2,
}
return self.env.ref('exp_payroll_custom.payroll_bank_wiz_report_docx').report_action(self, data=datas)

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Wizard view -->
<record id="bank_payroll_report_form" model="ir.ui.view">
<field name="name">payroll.bank.wiz.form</field>
<field name="model">payroll.bank.wiz</field>
<field name="arch" type="xml">
<form string="Bank Payroll Report">
<sheet>
<group>
<group>
<field name="date_from" />
<field name="no_details" />
<field name="bank_type" />
<field name="pay_date" />
<field name="company_id" groups="base.group_multi_company"
readonly="1" />
</group>
<group>
<field name="date_to" />
<!-- Odoo 18 declarative syntax -->
<field name="bank_ids"
widget="many2many_tags"
required="not no_details"
invisible="no_details" />
<field name="report_type" />
<field name="entry_type" required="1" />
</group>
</group>
<group col="4" colspan="4">
<notebook>
<page string="Salary Structures">
<group col="4" colspan="4">
<field name="salary_ids" domain="[('type','=','scale')]"
widget="many2many_tags" colspan="4" />
<field name="level_ids"
domain="[('type','=','level'),('salary_scale_id','in',salary_ids)]"
widget="many2many_tags" colspan="4" />
<field name="group_ids"
domain="[('type','=','group'),('salary_scale_level_id','in',level_ids)]"
widget="many2many_tags" colspan="4" />
<field name="degree_ids"
domain="[('type','=','degree'),('salary_scale_group_id','in',group_ids)]"
widget="many2many_tags" colspan="4" />
</group>
</page>
<page string="Employees">
<field name="employee_ids" />
</page>
</notebook>
</group>
</sheet>
<footer>
<button name="print_pdf_report" string="Print PDF" type="object"
class="btn-primary" />
<button name="print_report" string="Print Excel" type="object"
default_focus="1" class="btn-primary" />
<button name="print_report_text" string="Print Text" type="object"
default_focus="1" class="btn-primary" />
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
<!-- Wizard action -->
<record id="action_bank_payroll_report" model="ir.actions.act_window">
<field name="name">Bank Payslip Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">payroll.bank.wiz</field>
<field name="view_mode">form</field>
<field name="view_id" ref="bank_payroll_report_form" />
<field name="target">new</field>
</record>
<!-- Action placement -->
<menuitem action="action_bank_payroll_report"
id="menu_bank_payroll_report"
name="Bank Payslip Report"
parent="exp_payroll_custom.menu_hr_payroll_report" />
</data>
</odoo>

View File

@ -0,0 +1,118 @@
## -*- coding: utf-8 -*-
##############################################################################
#
# LCT, Life Connection Technology
# Copyright (C) 2019-2020 LCT
#
##############################################################################
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError, UserError
class PayslipMonthlyReport(models.TransientModel):
_name = 'payslip.monthly.report'
_description = "Payslips Monthly Report"
date_from = fields.Date(string='Date From', required=True,
default=lambda self: date(date.today().year, date.today().month, 1))
date_to = fields.Date(string='Date To', required=True,
default=lambda self: date(date.today().year, date.today().month, 1) + relativedelta(months=1,
days=-1))
detailed = fields.Boolean('Detail By Employees', default=False)
listed = fields.Boolean('List By Rules', default=False)
salary_ids = fields.Many2many('hr.payroll.structure', 'wiz_sal_rel', 'w_id', 'sal_id', string='Salary Structures')
level_ids = fields.Many2many('hr.payroll.structure', 'wiz_lvl_rel', 'w_id', 'lvl_id', string='Salary Levels')
group_ids = fields.Many2many('hr.payroll.structure', 'wiz_grp_rel', 'w_id', 'grp_id', string='Salary Groups')
degree_ids = fields.Many2many('hr.payroll.structure', 'wiz_dgr_rel', 'w_id', 'dgr_id', string='Salary Degrees')
rule_ids = fields.Many2many('hr.salary.rule', string='Rules')
allow = fields.Boolean('Allowances')
deduct = fields.Boolean('Deductions')
employee_ids = fields.Many2many('hr.employee', string='Employees')
no_rule = fields.Boolean('No Rules', default=False)
@api.onchange('date_from')
def onchange_date_from(self):
if self.date_from:
self.date_to = fields.Date.from_string(self.date_from) + relativedelta(months=+1, day=1, days=-1)
@api.onchange('allow', 'deduct')
def get_rule(self):
domain = (self.allow and self.deduct) and [('category_id.rule_type', 'in', ('allowance', 'deduction')), ] or \
self.allow and [('category_id.rule_type', '=', 'allowance'), ] or \
self.deduct and [('category_id.rule_type', '=', 'deduction'), ] or []
domain += [('appears_on_payslip', '=', True), ('active', '=', True)]
return {'domain': {'rule_ids': [('id', 'in', self.env['hr.salary.rule'].search(domain).ids)]}}
def get_payslip_line(self):
domain = [('slip_id.date_from', '>=', self.date_from), ('slip_id.date_to', '<=', self.date_to),
('slip_id.state', '!=', 'cancel'), ('appears_on_payslip', '=', True), ]
if self.rule_ids:
domain += [('salary_rule_id', 'in', self.rule_ids.ids)]
if self.allow and self.deduct:
domain += [('category_id.rule_type', 'in', ('allowance', 'deduction'))]
elif self.deduct:
domain += [('salary_rule_id.category_id.rule_type', '=', 'deduction')]
elif self.allow:
domain += [('salary_rule_id.category_id.rule_type', '=', 'allowance')]
if self.employee_ids:
domain += [('employee_id', 'in', self.employee_ids.ids)]
if self.salary_ids:
domain += [('slip_id.struct_id', 'in', self.salary_ids.ids)]
if self.level_ids:
domain += [('slip_id.level_id', 'in', self.level_ids.ids)]
if self.group_ids:
domain += [('slip_id.group_id', 'in', self.group_ids.ids)]
if self.degree_ids:
domain += [('slip_id.degree_id', 'in', self.degree_ids.ids)]
return self.env['hr.payslip.line'].search(domain)
def check_data(self):
landscape = False
if self.date_from > self.date_to:
raise UserError(_('Date From must be less than or equal Date To'))
payslip_lines = self.get_payslip_line()
if not payslip_lines:
raise ValidationError(_('Sorry No Data To Be Printed'))
rule_ids = self.no_rule and [0, ] or self.rule_ids and self.rule_ids.ids or \
self.env['hr.salary.rule'].search([('appears_on_payslip', '=', True), ('active', '=', True)]).ids
rule_ids = list(set(rule_ids) and set([r.id for r in payslip_lines.mapped('salary_rule_id')]))
datas = {
'ids': rule_ids,
'model': 'hr.salary.rule',
'payslip_line_ids': [pl.id for pl in payslip_lines],
'form': (self.read()[0]),
'rule_ids': rule_ids,
}
ctx = self.env.context.copy()
ctx.update({'active_model': 'hr.salary.rule', 'active_ids': rule_ids, })
if self.detailed and self.listed:
delist = 'tt'
emp_ids = self.employee_ids and self.employee_ids.ids or \
list(set(r['employee_id'][0] for r in self.env['hr.payslip'].search_read([
('date_from', '>=', self.date_from), ('date_to', '<=', self.date_to),
('state', '!=', 'cancel')], ['employee_id', ])))
emp_ids = list(set(emp_ids) and set([emp.id for emp in payslip_lines.mapped('employee_id')]))
datas['ids'] = emp_ids
datas['model'] = 'hr.employee'
ctx.update({'active_model': 'hr.employee', 'active_ids': emp_ids, })
landscape = True
elif self.detailed and not self.listed:
delist = 'tf'
else:
delist = 'ff'
datas['delist'] = delist
return datas, ctx, landscape
def print_report(self):
datas, ctx, lndkp = self.check_data()
return self.env.ref('exp_payroll_custom.act_payslip_monthly_report').with_context(
ctx, landscape=lndkp).report_action(self, data=datas)
def print_report_xlsx(self):
datas, ctx, lndkp = self.check_data()
return self.env.ref('exp_payroll_custom.payslip_monthly_report_xlsx').with_context(
ctx).report_action(self, data=datas)

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="payslip_xslx_report_form">
<field name="name">payslip.monthly.report.form</field>
<field name="model">payslip.monthly.report</field>
<field name="arch" type="xml">
<form>
<sheet>
<group col="4" colspan="2">
<field name="date_from" />
<field name="detailed" />
<field name="date_to" />
<!-- Odoo 18 declarative syntax -->
<field name="listed" invisible="not detailed" />
</group>
<group col="4" colspan="4">
<notebook>
<page string="Salary Structures">
<group col="4" colspan="4">
<field name="salary_ids" domain="[('type','=','scale')]"
widget="many2many_tags" colspan="4" />
<field name="level_ids"
domain="[('type','=','level'),('salary_scale_id','in',salary_ids)]"
widget="many2many_tags" colspan="4" />
<field name="group_ids"
domain="[('type','=','group'),('salary_scale_level_id','in',level_ids)]"
widget="many2many_tags" colspan="4" />
<field name="degree_ids"
domain="[('type','=','degree'),('salary_scale_group_id','in',group_ids)]"
widget="many2many_tags" colspan="4" />
</group>
</page>
<page string="Payroll Items">
<group col="6" colspan="2">
<field name="allow" />
<field name="deduct" />
</group>
<group>
<field name="rule_ids" colspan="4" nolabel="1" />
</group>
</page>
<page string="Employees">
<field name="employee_ids" />
</page>
</notebook>
</group>
</sheet>
<footer>
<button name="print_report" string="Print PDF" type="object"
class="btn-primary" />
<button name="print_report_xlsx" string="Print Excel" type="object"
class="btn-primary" />
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="payslip_xslx_report_action" model="ir.actions.act_window">
<field name="name">Payslips Report</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">payslip.monthly.report</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem
id="menu_hr_payroll_report"
name="Reporting"
parent="exp_hr_payroll.menu_hr_payroll_root"
sequence="90"
/>
<menuitem
id="payslip_xslx_report_menu"
name="Payslips Report"
parent="exp_payroll_custom.menu_hr_payroll_report"
action="payslip_xslx_report_action"
/>
</data>
</odoo>