albilad
This commit is contained in:
parent
5e8f8b7f2b
commit
8f981a34ed
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
from . import wizard
|
||||
from . import report
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'HR Payroll Al-Bilad Bank',
|
||||
'version': '1.0',
|
||||
'category': 'Odex30-HR/Odex30-HR',
|
||||
'sequence': 5,
|
||||
'website': 'http://exp-sa.com',
|
||||
'license': 'GPL-3',
|
||||
'author': 'Expert Co. Ltd.',
|
||||
'summary': 'Al-Bilad Bank Payroll Report Extension',
|
||||
'description': """
|
||||
Extends payroll module to add Al-Bilad Bank report format.
|
||||
""",
|
||||
'depends': [
|
||||
'exp_payroll_custom',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/payroll_bank_report_view.xml',
|
||||
'report/payroll_bank_report_views.xml',
|
||||
'report/payroll_bank_albilad_pdf_template.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': False,
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import payroll_bank_albilad_report
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="albilad_bank_pdf">
|
||||
<t t-call="exp_payroll_albilad.external_layout_albilad">
|
||||
<main>
|
||||
<div class="page" dir="rtl">
|
||||
<style>
|
||||
.albilad-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.albilad-table th, .albilad-table td {
|
||||
border: 1px solid #000;
|
||||
padding: 6px 4px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.albilad-header {
|
||||
background-color: #3e5d7f;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.albilad-bank-header {
|
||||
background-color: #FFA500;
|
||||
font-weight: bold;
|
||||
font-size: 13pt;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.albilad-title {
|
||||
background-color: #3e5d7f;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
font-size: 12pt;
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.albilad-data-row {
|
||||
font-size: 9pt;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="albilad-title">
|
||||
<t t-esc="report_title"/> <t t-esc="date_from"/> - <t t-esc="date_to"/>
|
||||
</div>
|
||||
|
||||
<t t-if="no_details">
|
||||
<t t-foreach="payslip_data" t-as="bank_data">
|
||||
<div class="albilad-bank-header">
|
||||
<t t-esc="bank_data.get('bank_name', '')"/>
|
||||
</div>
|
||||
|
||||
<table class="albilad-table">
|
||||
<thead>
|
||||
<tr class="albilad-header">
|
||||
<th>المبلغ الاجمالي</th>
|
||||
<th>رقم الايبان</th>
|
||||
<th>اسم المستفيد</th>
|
||||
<th>بنك المستفيد</th>
|
||||
<th>تفاصيل التحويل</th>
|
||||
<th>الراتب الاساسي</th>
|
||||
<th>بدل السكن</th>
|
||||
<th>البدلات الاخرى</th>
|
||||
<th>الخصم</th>
|
||||
<th>رقم الهوية</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="bank_data.get('payslips', [])" t-as="payslip">
|
||||
<tr class="albilad-data-row">
|
||||
<td><t t-esc="payslip.get('total_amount', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('iban', '')"/></td>
|
||||
<td><t t-esc="payslip.get('name', '')"/></td>
|
||||
<td><t t-esc="payslip.get('bank_code', '')"/></td>
|
||||
<td><t t-esc="payslip.get('description', '')"/></td>
|
||||
<td><t t-esc="payslip.get('basic_salary', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('housing', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('other', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('deductions', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('national_id', '')"/></td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-if="not no_details">
|
||||
<table class="albilad-table">
|
||||
<thead>
|
||||
<!-- Arabic headers -->
|
||||
<tr class="albilad-header">
|
||||
<th>المبلغ الاجمالي</th>
|
||||
<th>رقم الايبان</th>
|
||||
<th>اسم المستفيد</th>
|
||||
<th>بنك المستفيد</th>
|
||||
<th>تفاصيل التحويل</th>
|
||||
<th>الراتب الاساسي</th>
|
||||
<th>بدل السكن</th>
|
||||
<th>البدلات الاخرى</th>
|
||||
<th>الخصم</th>
|
||||
<th>رقم الهوية</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="payslip_data" t-as="payslip">
|
||||
<tr class="albilad-data-row">
|
||||
<td><t t-esc="payslip.get('total_amount', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('iban', '')"/></td>
|
||||
<td><t t-esc="payslip.get('name', '')"/></td>
|
||||
<td><t t-esc="payslip.get('bank_code', '')"/></td>
|
||||
<td><t t-esc="payslip.get('description', '')"/></td>
|
||||
<td><t t-esc="payslip.get('basic_salary', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('housing', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('other', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('deductions', 0.0)"/></td>
|
||||
<td><t t-esc="payslip.get('national_id', '')"/></td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
</div>
|
||||
</main>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="external_layout_albilad" inherit_id="web.external_layout_standard">
|
||||
|
||||
<xpath expr="//img[@t-if='company.header']" position="replace">
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//img[@t-if='company.footer']" position="replace">
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
<record id="report_payroll_bank_albilad_pdf" model="ir.actions.report">
|
||||
<field name="name">Al-Bilad Bank Payroll Report (PDF)</field>
|
||||
<field name="model">payroll.bank.wiz</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">exp_payroll_albilad.albilad_bank_pdf</field>
|
||||
<field name="report_file">exp_payroll_albilad.albilad_bank_pdf</field>
|
||||
<field name="print_report_name">'Al-Bilad Bank Report - %s' % (object.date_from)</field>
|
||||
<field name="binding_model_id" ref="exp_payroll_custom.model_payroll_bank_wiz"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,631 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, api
|
||||
|
||||
|
||||
class PayrollBankAlbiladReportXlsx(models.AbstractModel):
|
||||
_name = "report.exp_payroll_albilad.payroll_bank_albilad_xlsx"
|
||||
_inherit = 'report.report_xlsx.abstract'
|
||||
_description = 'Al-Bilad Bank Payroll Report XLSX'
|
||||
|
||||
@api.model
|
||||
def generate_xlsx_report(self, workbook, data, payslips):
|
||||
emp_ids = data['employees']
|
||||
bank_ids = data['banks']
|
||||
salary_ids = data['salary']
|
||||
date_from = data['date_from']
|
||||
date_to = data['date_to']
|
||||
no_details = data['no_details']
|
||||
report_type = data['report_type']
|
||||
entry_type = data['entry_type']
|
||||
bank_type = data['bank_type']
|
||||
company_id = self.sudo().env['res.company'].browse(data['company_id'])
|
||||
|
||||
employees = self.sudo().env['hr.employee'].search([('id', 'in', emp_ids)])
|
||||
banks = self.sudo().env['res.bank'].search([('id', 'in', bank_ids)])
|
||||
salary = self.sudo().env['hr.payroll.structure'].search([('id', 'in', salary_ids)])
|
||||
|
||||
# Get branch setting
|
||||
branch_id = self.env['ir.config_parameter'].sudo().get_param('exp_payroll_custom.branch')
|
||||
branch = True if branch_id == 'True' else False
|
||||
|
||||
sheet = workbook.add_worksheet('Al-Bilad Bank Report')
|
||||
|
||||
# Define formats
|
||||
format1 = workbook.add_format({
|
||||
'bottom': True, 'right': True, 'left': True, 'top': True,
|
||||
'align': 'center', 'valign': 'vcenter'
|
||||
})
|
||||
format2 = workbook.add_format({
|
||||
'font_size': 11, 'bottom': True, 'right': True, 'left': True, 'top': True,
|
||||
'align': 'center', 'bold': True, 'valign': 'vcenter'
|
||||
})
|
||||
format3 = workbook.add_format({
|
||||
'font_size': 14, 'bottom': True, 'right': True, 'left': True, 'top': True,
|
||||
'align': 'center', 'bold': True, 'valign': 'vcenter',
|
||||
'bg_color': '#FFA500'
|
||||
})
|
||||
format4 = workbook.add_format({
|
||||
'font_size': 11, 'bottom': True, 'right': True, 'left': True, 'top': True,
|
||||
'align': 'center', 'bold': True, 'valign': 'vcenter'
|
||||
})
|
||||
|
||||
# Set column widths
|
||||
sheet.set_column('A:J', 20)
|
||||
|
||||
row = 0
|
||||
|
||||
if no_details:
|
||||
# With details section
|
||||
for bank in banks:
|
||||
row += 2
|
||||
sheet.write(row, 0, bank.name, format3)
|
||||
row += 1
|
||||
|
||||
sheet.write(row, 0, 'Total Amount', format2)
|
||||
sheet.write(row, 1, 'Beneficiary Account IBAN', format2)
|
||||
sheet.write(row, 2, 'Beneficiary Name', format2)
|
||||
sheet.write(row, 3, 'Beneficiary Bank CODE', format2)
|
||||
sheet.write(row, 4, 'Payment Description', format2)
|
||||
sheet.write(row, 5, 'Basic Salary', format2)
|
||||
sheet.write(row, 6, 'Housing Allowance', format2)
|
||||
sheet.write(row, 7, 'Other Earnings', format2)
|
||||
sheet.write(row, 8, 'Deductions', format2)
|
||||
sheet.write(row, 9, 'Beneficiary National/IqamaID', format2)
|
||||
row += 1
|
||||
|
||||
sheet.write(row, 0, 'المبلغ الاجمالي', format2)
|
||||
sheet.write(row, 1, 'رقم الايبان', format2)
|
||||
sheet.write(row, 2, 'اسم المستفيد', format2)
|
||||
sheet.write(row, 3, 'بنك المستفيد', format2)
|
||||
sheet.write(row, 4, 'تفاصيل التحويل', format2)
|
||||
sheet.write(row, 5, 'الراتب الاساسي', format2)
|
||||
sheet.write(row, 6, 'بدل السكن', format2)
|
||||
sheet.write(row, 7, 'البدلات الاخرى', format2)
|
||||
sheet.write(row, 8, 'الخصم', format2)
|
||||
sheet.write(row, 9, 'رقم الهوية', format2)
|
||||
|
||||
if report_type == 'salary':
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
# Get salary rules
|
||||
salary_rules = self.sudo().env['hr.salary.rule'].search([]).sorted(
|
||||
key=lambda v: v.sequence).ids
|
||||
payslip_line_obj = self.sudo().env['hr.payslip.line']
|
||||
|
||||
for payslip in payslip_ids:
|
||||
basic = 0.0
|
||||
housing = 0.0
|
||||
payslip_lines_ids = payslip_line_obj.sudo().search([('slip_id', '=', payslip.id)])
|
||||
|
||||
if not payslip_lines_ids:
|
||||
continue
|
||||
|
||||
for payslip_line_rec in payslip_lines_ids:
|
||||
if payslip_line_rec.salary_rule_id.id in salary_rules:
|
||||
if payslip_line_rec.salary_rule_id.rules_type == 'salary':
|
||||
basic += payslip_line_rec.total
|
||||
elif payslip_line_rec.salary_rule_id.rules_type == 'house':
|
||||
housing += payslip_line_rec.total
|
||||
|
||||
other = round((payslip.total_allowances - basic - housing), 2)
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality == True else payslip.employee_id.iqama_number.iqama_id,
|
||||
basic, housing, other, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
payslip.employee_id.branch_id.name if branch else payslip.employee_id.working_location.name,
|
||||
company_id.currency_id.name, 'Active'
|
||||
]
|
||||
|
||||
row += 1
|
||||
# Write AlBilad format data
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
elif report_type == 'allowance':
|
||||
row = self._write_allowance_data(sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1)
|
||||
|
||||
elif report_type == 'overtime':
|
||||
row = self._write_overtime_data(sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1)
|
||||
|
||||
elif report_type == 'mission':
|
||||
row = self._write_mission_data(sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1)
|
||||
|
||||
elif report_type == 'training':
|
||||
row = self._write_training_data(sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1)
|
||||
else:
|
||||
# No details section
|
||||
row = 1
|
||||
# English headers row
|
||||
sheet.write(0, 0, 'Total Amount', format2)
|
||||
sheet.write(0, 1, 'Beneficiary Account IBAN', format2)
|
||||
sheet.write(0, 2, 'Beneficiary Name', format2)
|
||||
sheet.write(0, 3, 'Beneficiary Bank CODE', format2)
|
||||
sheet.write(0, 4, 'Payment Description', format2)
|
||||
sheet.write(0, 5, 'Basic Salary', format2)
|
||||
sheet.write(0, 6, 'Housing Allowance', format2)
|
||||
sheet.write(0, 7, 'Other Earnings', format2)
|
||||
sheet.write(0, 8, 'Deductions', format2)
|
||||
sheet.write(0, 9, 'Beneficiary National/IqamaID', format2)
|
||||
|
||||
# Arabic headers row
|
||||
sheet.write(1, 0, 'المبلغ الاجمالي', format2)
|
||||
sheet.write(1, 1, 'رقم الايبان', format2)
|
||||
sheet.write(1, 2, 'اسم المستفيد', format2)
|
||||
sheet.write(1, 3, 'بنك المستفيد', format2)
|
||||
sheet.write(1, 4, 'تفاصيل التحويل', format2)
|
||||
sheet.write(1, 5, 'الراتب الاساسي', format2)
|
||||
sheet.write(1, 6, 'بدل السكن', format2)
|
||||
sheet.write(1, 7, 'البدلات الاخرى', format2)
|
||||
sheet.write(1, 8, 'الخصم', format2)
|
||||
sheet.write(1, 9, 'رقم الهوية', format2)
|
||||
|
||||
if report_type == 'salary':
|
||||
for bank in banks:
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
salary_rules = self.sudo().env['hr.salary.rule'].search([]).sorted(
|
||||
key=lambda v: v.sequence).ids
|
||||
payslip_line_obj = self.sudo().env['hr.payslip.line']
|
||||
|
||||
for payslip in payslip_ids:
|
||||
basic = 0.0
|
||||
housing = 0.0
|
||||
payslip_lines_ids = payslip_line_obj.sudo().search([('slip_id', '=', payslip.id)])
|
||||
|
||||
if not payslip_lines_ids:
|
||||
continue
|
||||
|
||||
for payslip_line_rec in payslip_lines_ids:
|
||||
if payslip_line_rec.salary_rule_id.id in salary_rules:
|
||||
if payslip_line_rec.salary_rule_id.rules_type == 'salary':
|
||||
basic += payslip_line_rec.total
|
||||
elif payslip_line_rec.salary_rule_id.rules_type == 'house':
|
||||
housing += payslip_line_rec.total
|
||||
|
||||
other = round((payslip.total_allowances - basic - housing), 2)
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality == True else payslip.employee_id.iqama_number.iqama_id,
|
||||
basic, housing, other, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
payslip.employee_id.branch_id.name if branch else payslip.employee_id.working_location.name,
|
||||
company_id.currency_id.name, 'Active'
|
||||
]
|
||||
|
||||
row += 1
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
def _get_payslips(self, date_from, date_to, entry_type, employees, salary, salary_ids, bank):
|
||||
domain_base = [
|
||||
('date_from', '>=', date_from),
|
||||
('date_to', '<=', date_to),
|
||||
('payslip_run_id.state', 'in', ['confirmed', 'transfered']),
|
||||
('employee_id.bank_account_id.bank_id', '=', bank.id)
|
||||
]
|
||||
|
||||
if entry_type == 'all':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.append(('employee_id', 'in', employees.ids))
|
||||
elif salary:
|
||||
domain.append(('struct_id', 'in', salary_ids))
|
||||
elif entry_type == 'posted':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.extend([
|
||||
('employee_id', 'in', employees.ids),
|
||||
'|',
|
||||
('move_id.state', '=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '=', 'posted')
|
||||
])
|
||||
elif salary:
|
||||
domain.extend([
|
||||
('struct_id', 'in', salary_ids),
|
||||
'|',
|
||||
('move_id.state', '=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '=', 'posted')
|
||||
])
|
||||
elif entry_type == 'unposted':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.extend([
|
||||
('employee_id', 'in', employees.ids),
|
||||
('move_id.state', '!=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '!=', 'posted')
|
||||
])
|
||||
elif salary:
|
||||
domain.extend([
|
||||
('struct_id', 'in', salary_ids),
|
||||
('move_id.state', '!=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '!=', 'posted')
|
||||
])
|
||||
else:
|
||||
domain = domain_base
|
||||
|
||||
return self.sudo().env['hr.payslip'].search(domain)
|
||||
|
||||
def _write_allowance_data(self, sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1):
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality else payslip.employee_id.iqama_number.iqama_id,
|
||||
payslip.total_allowances, 0.0, 0.0, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
]
|
||||
|
||||
row += 1
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
return row
|
||||
|
||||
def _write_overtime_data(self, sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1):
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality else payslip.employee_id.iqama_number.iqama_id,
|
||||
0.0, 0.0, payslip.total_allowances, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
]
|
||||
|
||||
row += 1
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
return row
|
||||
|
||||
def _write_mission_data(self, sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1):
|
||||
"""Write mission data"""
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
# For missions, show in "Other Earnings" column
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality else payslip.employee_id.iqama_number.iqama_id,
|
||||
0.0, 0.0, payslip.total_allowances, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
]
|
||||
|
||||
row += 1
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
return row
|
||||
|
||||
def _write_training_data(self, sheet, row, date_from, date_to, entry_type, employees, salary, salary_ids, bank, branch, company_id, format1):
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
data_list = [
|
||||
payslip.employee_id.emp_no,
|
||||
payslip.employee_id.name or ' ',
|
||||
payslip.employee_id.bank_account_id.acc_number or ' ',
|
||||
payslip.employee_id.bank_account_id.bank_id.bic,
|
||||
payslip.total_sum,
|
||||
payslip.employee_id.saudi_number.saudi_id if payslip.employee_id.check_nationality else payslip.employee_id.iqama_number.iqama_id,
|
||||
0.0, 0.0, payslip.total_allowances, round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
]
|
||||
|
||||
row += 1
|
||||
sheet.write(row, 0, data_list[4], format1)
|
||||
sheet.write(row, 1, data_list[2], format1)
|
||||
sheet.write(row, 2, data_list[1], format1)
|
||||
sheet.write(row, 3, data_list[3], format1)
|
||||
sheet.write(row, 4, '', format1)
|
||||
sheet.write(row, 5, data_list[6], format1)
|
||||
sheet.write(row, 6, data_list[7], format1)
|
||||
sheet.write(row, 7, data_list[8], format1)
|
||||
sheet.write(row, 8, data_list[9], format1)
|
||||
sheet.write(row, 9, data_list[5], format1)
|
||||
|
||||
return row
|
||||
|
||||
|
||||
class HrPayslipExtended(models.Model):
|
||||
_inherit = 'hr.payslip'
|
||||
|
||||
@api.model
|
||||
def search(self, args, offset=0, limit=None, order=None):
|
||||
|
||||
if self.env.context.get('use_payslip_run_confirmed_state'):
|
||||
modified_args = []
|
||||
for item in args:
|
||||
if isinstance(item, (tuple, list)) and len(item) == 3:
|
||||
field, operator, value = item
|
||||
if field == 'state' and operator == '=' and value == 'transfered':
|
||||
modified_args.append(('payslip_run_id.state', '=', 'confirmed'))
|
||||
else:
|
||||
modified_args.append(item)
|
||||
else:
|
||||
modified_args.append(item)
|
||||
args = modified_args
|
||||
|
||||
return super(HrPayslipExtended, self).search(args, offset, limit, order)
|
||||
|
||||
class PayrollXlsxExtended(models.AbstractModel):
|
||||
_inherit = 'report.exp_payroll_custom.report_payroll_bank_xlsx'
|
||||
|
||||
@api.model
|
||||
def generate_xlsx_report(self, workbook, data, payslips):
|
||||
return super(PayrollXlsxExtended, self.with_context(use_payslip_run_confirmed_state=True)).generate_xlsx_report(workbook, data, payslips)
|
||||
|
||||
|
||||
class PayrollBankAlbiladReportPdf(models.AbstractModel):
|
||||
_name = "report.exp_payroll_albilad.albilad_bank_pdf"
|
||||
_description = 'Al-Bilad Bank Payroll Report PDF'
|
||||
|
||||
@api.model
|
||||
def _get_report_values(self, docids, data=None):
|
||||
if not data:
|
||||
return {}
|
||||
|
||||
emp_ids = data.get('employees', [])
|
||||
bank_ids = data.get('banks', [])
|
||||
salary_ids = data.get('salary', [])
|
||||
date_from = data.get('date_from')
|
||||
date_to = data.get('date_to')
|
||||
no_details = data.get('no_details', False)
|
||||
report_type = data.get('report_type', 'salary')
|
||||
entry_type = data.get('entry_type', 'all')
|
||||
company_id = self.env['res.company'].browse(data.get('company_id'))
|
||||
|
||||
employees = self.env['hr.employee'].search([('id', 'in', emp_ids)])
|
||||
banks = self.env['res.bank'].search([('id', 'in', bank_ids)])
|
||||
salary = self.env['hr.payroll.structure'].search([('id', 'in', salary_ids)])
|
||||
|
||||
# Get branch setting
|
||||
branch_id = self.env['ir.config_parameter'].sudo().get_param('exp_payroll_custom.branch')
|
||||
branch = True if branch_id == 'True' else False
|
||||
|
||||
# Get report title based on type (Arabic)
|
||||
report_titles = {
|
||||
'salary': 'مسير البنك للرواتب',
|
||||
'allowance': 'مسير البنك للحوافز',
|
||||
'overtime': 'مسير البنك للعمل الإضافي',
|
||||
'training': 'مسير البنك للتدريب',
|
||||
'mission': 'مسير البنك لمهام العمل',
|
||||
}
|
||||
report_title = report_titles.get(report_type, 'مسير البنك للرواتب')
|
||||
|
||||
payslip_data = []
|
||||
|
||||
if no_details:
|
||||
# Group by bank
|
||||
for bank in banks:
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
bank_payslips = []
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
payslip_dict = self._prepare_payslip_data(payslip, report_type)
|
||||
bank_payslips.append(payslip_dict)
|
||||
|
||||
payslip_data.append({
|
||||
'bank_name': bank.name,
|
||||
'payslips': bank_payslips
|
||||
})
|
||||
else:
|
||||
# No grouping - all payslips in one list
|
||||
all_payslips = []
|
||||
for bank in banks:
|
||||
payslip_ids = self._get_payslips(date_from, date_to, entry_type, employees, salary, salary_ids, bank)
|
||||
|
||||
if payslip_ids:
|
||||
for payslip in payslip_ids:
|
||||
payslip_dict = self._prepare_payslip_data(payslip, report_type)
|
||||
all_payslips.append(payslip_dict)
|
||||
|
||||
payslip_data = all_payslips
|
||||
|
||||
date_from_str = str(date_from) if date_from else ''
|
||||
date_to_str = str(date_to) if date_to else ''
|
||||
|
||||
return {
|
||||
'doc_ids': docids,
|
||||
'doc_model': 'payroll.bank.wiz',
|
||||
'docs': self.env['payroll.bank.wiz'].browse(docids),
|
||||
'date_from': date_from_str,
|
||||
'date_to': date_to_str,
|
||||
'no_details': no_details,
|
||||
'report_type': report_type,
|
||||
'report_title': report_title,
|
||||
'payslip_data': payslip_data,
|
||||
'company': company_id,
|
||||
}
|
||||
|
||||
def _prepare_payslip_data(self, payslip, report_type):
|
||||
"""Prepare payslip data dictionary based on report type"""
|
||||
# Get national ID safely
|
||||
national_id = ''
|
||||
try:
|
||||
if hasattr(payslip.employee_id, 'check_nationality') and payslip.employee_id.check_nationality:
|
||||
if hasattr(payslip.employee_id, 'saudi_number') and payslip.employee_id.saudi_number:
|
||||
national_id = payslip.employee_id.saudi_number.saudi_id or ''
|
||||
else:
|
||||
if hasattr(payslip.employee_id, 'iqama_number') and payslip.employee_id.iqama_number:
|
||||
national_id = payslip.employee_id.iqama_number.iqama_id or ''
|
||||
except:
|
||||
national_id = ''
|
||||
|
||||
iban = ' '
|
||||
bank_code = ' '
|
||||
if payslip.employee_id.bank_account_id:
|
||||
iban = payslip.employee_id.bank_account_id.acc_number or ' '
|
||||
if payslip.employee_id.bank_account_id.bank_id:
|
||||
bank_code = payslip.employee_id.bank_account_id.bank_id.bic or ' '
|
||||
|
||||
if report_type == 'salary':
|
||||
salary_rules = self.env['hr.salary.rule'].search([]).sorted(key=lambda v: v.sequence).ids
|
||||
payslip_line_obj = self.env['hr.payslip.line']
|
||||
|
||||
basic = 0.0
|
||||
housing = 0.0
|
||||
payslip_lines_ids = payslip_line_obj.search([('slip_id', '=', payslip.id)])
|
||||
|
||||
for payslip_line_rec in payslip_lines_ids:
|
||||
if payslip_line_rec.salary_rule_id.id in salary_rules:
|
||||
if payslip_line_rec.salary_rule_id.rules_type == 'salary':
|
||||
basic += payslip_line_rec.total
|
||||
elif payslip_line_rec.salary_rule_id.rules_type == 'house':
|
||||
housing += payslip_line_rec.total
|
||||
|
||||
other = round((payslip.total_allowances - basic - housing), 2)
|
||||
|
||||
return {
|
||||
'total_amount': payslip.total_sum or 0.0,
|
||||
'iban': iban,
|
||||
'name': payslip.employee_id.name or ' ',
|
||||
'bank_code': bank_code,
|
||||
'description': '',
|
||||
'basic_salary': basic,
|
||||
'housing': housing,
|
||||
'other': other,
|
||||
'deductions': round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
'national_id': national_id,
|
||||
}
|
||||
elif report_type == 'allowance':
|
||||
# For allowances, show total allowances as basic
|
||||
return {
|
||||
'total_amount': payslip.total_sum or 0.0,
|
||||
'iban': iban,
|
||||
'name': payslip.employee_id.name or ' ',
|
||||
'bank_code': bank_code,
|
||||
'description': '',
|
||||
'basic_salary': payslip.total_allowances or 0.0,
|
||||
'housing': 0.0,
|
||||
'other': 0.0,
|
||||
'deductions': round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
'national_id': national_id,
|
||||
}
|
||||
elif report_type in ['overtime', 'mission', 'training']:
|
||||
# For overtime, mission, training - show as other earnings
|
||||
return {
|
||||
'total_amount': payslip.total_sum or 0.0,
|
||||
'iban': iban,
|
||||
'name': payslip.employee_id.name or ' ',
|
||||
'bank_code': bank_code,
|
||||
'description': '',
|
||||
'basic_salary': 0.0,
|
||||
'housing': 0.0,
|
||||
'other': payslip.total_allowances or 0.0,
|
||||
'deductions': round((payslip.total_deductions + payslip.total_loans), 2),
|
||||
'national_id': national_id,
|
||||
}
|
||||
|
||||
def _get_payslips(self, date_from, date_to, entry_type, employees, salary, salary_ids, bank):
|
||||
"""Helper method to get payslips based on criteria"""
|
||||
domain_base = [
|
||||
('date_from', '>=', date_from),
|
||||
('date_to', '<=', date_to),
|
||||
('payslip_run_id.state', 'in', ['confirmed', 'transfered']),
|
||||
('employee_id.bank_account_id.bank_id', '=', bank.id)
|
||||
]
|
||||
|
||||
if entry_type == 'all':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.append(('employee_id', 'in', employees.ids))
|
||||
elif salary:
|
||||
domain.append(('struct_id', 'in', salary_ids))
|
||||
elif entry_type == 'posted':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.extend([
|
||||
('employee_id', 'in', employees.ids),
|
||||
'|',
|
||||
('move_id.state', '=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '=', 'posted')
|
||||
])
|
||||
elif salary:
|
||||
domain.extend([
|
||||
('struct_id', 'in', salary_ids),
|
||||
'|',
|
||||
('move_id.state', '=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '=', 'posted')
|
||||
])
|
||||
elif entry_type == 'unposted':
|
||||
domain = domain_base.copy()
|
||||
if employees:
|
||||
domain.extend([
|
||||
('employee_id', 'in', employees.ids),
|
||||
('move_id.state', '!=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '!=', 'posted')
|
||||
])
|
||||
elif salary:
|
||||
domain.extend([
|
||||
('struct_id', 'in', salary_ids),
|
||||
('move_id.state', '!=', 'posted'),
|
||||
('payslip_run_id.move_id.state', '!=', 'posted')
|
||||
])
|
||||
else:
|
||||
domain = domain_base
|
||||
|
||||
return self.env['hr.payslip'].search(domain)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="report_payroll_bank_albilad_xlsx" model="ir.actions.report">
|
||||
<field name="name">Al-Bilad Bank Payroll Report</field>
|
||||
<field name="model">payroll.bank.wiz</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_name">exp_payroll_albilad.payroll_bank_albilad_xlsx</field>
|
||||
<field name="report_file">exp_payroll_albilad.payroll_bank_albilad_xlsx</field>
|
||||
<field name="binding_model_id" ref="exp_payroll_custom.model_payroll_bank_wiz"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import payroll_bank_report
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class BankPayslipReportAlbilad(models.TransientModel):
|
||||
_inherit = 'payroll.bank.wiz'
|
||||
|
||||
bank_type = fields.Selection(
|
||||
selection_add=[('albilad', 'Al-Bilad Bank')],
|
||||
ondelete={'albilad': 'set default'}
|
||||
)
|
||||
|
||||
def print_report(self):
|
||||
if self.bank_type == 'albilad':
|
||||
# Validate that banks are selected
|
||||
if not self.bank_ids:
|
||||
raise UserError(_('Please select at least one bank to generate the report.'))
|
||||
|
||||
[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_albilad.report_payroll_bank_albilad_xlsx').report_action(self, data=datas)
|
||||
else:
|
||||
return super(BankPayslipReportAlbilad, self).print_report()
|
||||
|
||||
def print_pdf_report(self):
|
||||
if self.bank_type == 'albilad':
|
||||
if not self.bank_ids:
|
||||
raise UserError(_('Please select at least one bank to generate the report.'))
|
||||
|
||||
[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_albilad.report_payroll_bank_albilad_pdf').report_action(self, data=datas)
|
||||
else:
|
||||
# Call parent method for other bank types if it exists
|
||||
if hasattr(super(BankPayslipReportAlbilad, self), 'print_pdf_report'):
|
||||
return super(BankPayslipReportAlbilad, self).print_pdf_report()
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'message': _('PDF report is only available for Al-Bilad bank type.'),
|
||||
'type': 'warning',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="bank_payroll_report_form_albilad" model="ir.ui.view">
|
||||
<field name="name">payroll.bank.wiz.form.albilad</field>
|
||||
<field name="model">payroll.bank.wiz</field>
|
||||
<field name="inherit_id" ref="exp_payroll_custom.bank_payroll_report_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bank_ids" position="attributes">
|
||||
<attribute name="required">[('bank_type', '=', 'albilad')]</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue