Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,350 @@
# -*- coding: utf-8 -*-
"""
Tax Reports
===========
- Payroll Tax Liability
- Payroll Tax Payments
- Payroll Tax and Wage Summary
"""
from odoo import api, fields, models, _
class PayrollReportTaxLiability(models.AbstractModel):
"""
Payroll Tax Liability Report
Shows tax amounts owed vs paid.
"""
_name = 'payroll.report.tax.liability'
_inherit = 'payroll.report'
_description = 'Payroll Tax Liability Report'
report_name = 'Payroll Tax Liability'
report_code = 'tax_liability'
filter_employee = False
def _get_columns(self):
return [
{'name': _('Tax Type'), 'field': 'tax_type', 'type': 'char', 'sortable': True},
{'name': _('Tax Amount'), 'field': 'tax_amount', 'type': 'monetary', 'sortable': True},
{'name': _('Tax Paid'), 'field': 'tax_paid', 'type': 'monetary', 'sortable': True},
{'name': _('Tax Owed'), 'field': 'tax_owed', 'type': 'monetary', 'sortable': True},
]
def _get_lines(self, options):
date_from = options.get('date', {}).get('date_from')
date_to = options.get('date', {}).get('date_to')
# Build domain for payslips
domain = [
('state', 'in', ['done', 'paid']),
('company_id', '=', self.env.company.id),
]
if date_from:
domain.append(('date_from', '>=', date_from))
if date_to:
domain.append(('date_to', '<=', date_to))
payslips = self.env['hr.payslip'].search(domain)
# Calculate totals by tax type
tax_totals = {
'income_tax': {'name': _('Income Tax'), 'amount': 0, 'codes': ['FED_TAX', 'PROV_TAX']},
'ei_employee': {'name': _('Employment Insurance'), 'amount': 0, 'codes': ['EI']},
'ei_employer': {'name': _('Employment Insurance Employer'), 'amount': 0, 'codes': ['EI_ER']},
'cpp_employee': {'name': _('Canada Pension Plan'), 'amount': 0, 'codes': ['CPP']},
'cpp_employer': {'name': _('Canada Pension Plan Employer'), 'amount': 0, 'codes': ['CPP_ER']},
'cpp2_employee': {'name': _('Second Canada Pension Plan'), 'amount': 0, 'codes': ['CPP2']},
'cpp2_employer': {'name': _('Second Canada Pension Plan Employer'), 'amount': 0, 'codes': ['CPP2_ER']},
}
for slip in payslips:
if not hasattr(slip, 'line_ids') or not slip.line_ids:
continue
for line in slip.line_ids:
if not hasattr(line, 'code') or not line.code:
continue
for key, data in tax_totals.items():
if line.code in data['codes']:
tax_totals[key]['amount'] += abs(line.total or 0)
# Get paid amounts from remittances
remittance_domain = [
('state', '=', 'paid'),
('company_id', '=', self.env.company.id),
]
if date_from:
remittance_domain.append(('period_start', '>=', date_from))
if date_to:
remittance_domain.append(('period_end', '<=', date_to))
remittances = self.env['hr.tax.remittance'].search(remittance_domain)
# Safely get remittance fields
def safe_sum(records, field_name):
if not records:
return 0
try:
return sum(records.mapped(field_name)) or 0
except:
return 0
paid_totals = {
'income_tax': safe_sum(remittances, 'income_tax'),
'ei_employee': safe_sum(remittances, 'ei_employee'),
'ei_employer': safe_sum(remittances, 'ei_employer'),
'cpp_employee': safe_sum(remittances, 'cpp_employee'),
'cpp2_employee': safe_sum(remittances, 'cpp2_employee'),
'cpp_employer': safe_sum(remittances, 'cpp_employer'),
'cpp2_employer': safe_sum(remittances, 'cpp2_employer'),
}
lines = []
grand_total = {'amount': 0, 'paid': 0, 'owed': 0}
# Federal Taxes header
lines.append({
'id': 'federal_header',
'name': _('Federal Taxes'),
'values': {
'tax_type': _('Federal Taxes'),
'tax_amount': '',
'tax_paid': '',
'tax_owed': '',
},
'level': -1,
'class': 'fw-bold',
})
for key, data in tax_totals.items():
paid = paid_totals.get(key, 0)
owed = data['amount'] - paid
grand_total['amount'] += data['amount']
grand_total['paid'] += paid
grand_total['owed'] += owed
lines.append({
'id': f'tax_{key}',
'name': data['name'],
'values': {
'tax_type': f" {data['name']}",
'tax_amount': data['amount'],
'tax_paid': paid,
'tax_owed': owed,
},
'level': 0,
})
# Grand total
lines.append({
'id': 'grand_total',
'name': _('Total'),
'values': {
'tax_type': _('Total'),
'tax_amount': grand_total['amount'],
'tax_paid': grand_total['paid'],
'tax_owed': grand_total['owed'],
},
'level': -1,
'class': 'o_payroll_report_total fw-bold',
})
return lines
class PayrollReportTaxPayments(models.AbstractModel):
"""
Payroll Tax Payments Report
Shows history of tax remittance payments.
"""
_name = 'payroll.report.tax.payments'
_inherit = 'payroll.report'
_description = 'Payroll Tax Payments Report'
report_name = 'Payroll Tax Payments'
report_code = 'tax_payments'
filter_employee = False
def _get_columns(self):
return [
{'name': _('Payment Date'), 'field': 'payment_date', 'type': 'date', 'sortable': True},
{'name': _('Tax Type'), 'field': 'tax_type', 'type': 'char', 'sortable': True},
{'name': _('Amount'), 'field': 'amount', 'type': 'monetary', 'sortable': True},
{'name': _('Payment Method'), 'field': 'payment_method', 'type': 'char', 'sortable': False},
{'name': _('Notes'), 'field': 'notes', 'type': 'char', 'sortable': False},
]
def _get_lines(self, options):
date_from = options.get('date', {}).get('date_from')
date_to = options.get('date', {}).get('date_to')
domain = [
('state', '=', 'paid'),
('company_id', '=', self.env.company.id),
]
if date_from:
domain.append(('payment_date', '>=', date_from))
if date_to:
domain.append(('payment_date', '<=', date_to))
remittances = self.env['hr.tax.remittance'].search(domain, order='payment_date desc')
lines = []
for rem in remittances:
period_start = getattr(rem, 'period_start', '') or ''
period_end = getattr(rem, 'period_end', '') or ''
period_str = f"{period_start} - {period_end}" if period_start and period_end else ''
lines.append({
'id': f'remit_{rem.id}',
'name': rem.name or 'Unknown',
'values': {
'payment_date': getattr(rem, 'payment_date', '') or '',
'tax_type': f"Federal Taxes\n{period_str}" if period_str else 'Federal Taxes',
'amount': getattr(rem, 'total', 0) or 0,
'payment_method': getattr(rem, 'payment_method', None) or 'Manual',
'notes': getattr(rem, 'payment_reference', None) or '',
},
'level': 0,
'model': 'hr.tax.remittance',
'res_id': rem.id,
})
return lines
class PayrollReportTaxWageSummary(models.AbstractModel):
"""
Payroll Tax and Wage Summary Report
Shows total wages, excess wages, taxable wages, and tax amounts.
"""
_name = 'payroll.report.tax.wage.summary'
_inherit = 'payroll.report'
_description = 'Payroll Tax and Wage Summary Report'
report_name = 'Payroll Tax and Wage Summary'
report_code = 'tax_wage_summary'
filter_employee = False
def _get_columns(self):
return [
{'name': _('Tax Type'), 'field': 'tax_type', 'type': 'char', 'sortable': True},
{'name': _('Total Wages'), 'field': 'total_wages', 'type': 'monetary', 'sortable': True},
{'name': _('Excess Wages'), 'field': 'excess_wages', 'type': 'monetary', 'sortable': True},
{'name': _('Taxable Wages'), 'field': 'taxable_wages', 'type': 'monetary', 'sortable': True},
{'name': _('Tax Amount'), 'field': 'tax_amount', 'type': 'monetary', 'sortable': True},
]
def _get_lines(self, options):
date_from = options.get('date', {}).get('date_from')
date_to = options.get('date', {}).get('date_to')
domain = [
('state', 'in', ['done', 'paid']),
('company_id', '=', self.env.company.id),
]
if date_from:
domain.append(('date_from', '>=', date_from))
if date_to:
domain.append(('date_to', '<=', date_to))
payslips = self.env['hr.payslip'].search(domain)
# Calculate totals - safely handle missing gross_wage field
total_wages = 0
for slip in payslips:
total_wages += getattr(slip, 'gross_wage', 0) or 0
# Tax calculations
tax_data = [
{
'name': _('Income Tax'),
'codes': ['FED_TAX', 'PROV_TAX'],
'total_wages': total_wages,
'excess_wages': 0, # No excess for income tax
},
{
'name': _('Employment Insurance'),
'codes': ['EI'],
'total_wages': total_wages,
'excess_wages': 0, # Would need to calculate based on max
},
{
'name': _('Employment Insurance Employer'),
'codes': ['EI_ER'],
'total_wages': total_wages,
'excess_wages': 0,
},
{
'name': _('Canada Pension Plan'),
'codes': ['CPP'],
'total_wages': total_wages,
'excess_wages': 0,
},
{
'name': _('Canada Pension Plan Employer'),
'codes': ['CPP_ER'],
'total_wages': total_wages,
'excess_wages': 0,
},
{
'name': _('Second Canada Pension Plan'),
'codes': ['CPP2'],
'total_wages': total_wages,
'excess_wages': 0,
},
{
'name': _('Second Canada Pension Plan Employer'),
'codes': ['CPP2_ER'],
'total_wages': total_wages,
'excess_wages': 0,
},
]
lines = []
# Federal header
lines.append({
'id': 'federal_header',
'name': _('Federal Taxes'),
'values': {
'tax_type': _('Federal Taxes'),
'total_wages': '',
'excess_wages': '',
'taxable_wages': '',
'tax_amount': '',
},
'level': -1,
'class': 'fw-bold',
})
grand_tax = 0
for data in tax_data:
tax_amount = 0
for slip in payslips:
if not hasattr(slip, 'line_ids') or not slip.line_ids:
continue
for line in slip.line_ids:
if not hasattr(line, 'code') or not line.code:
continue
if line.code in data['codes']:
tax_amount += abs(line.total or 0)
taxable = data['total_wages'] - data['excess_wages']
grand_tax += tax_amount
lines.append({
'id': f"tax_{data['name']}",
'name': data['name'],
'values': {
'tax_type': f" {data['name']}",
'total_wages': data['total_wages'],
'excess_wages': data['excess_wages'],
'taxable_wages': taxable,
'tax_amount': tax_amount,
},
'level': 0,
})
return lines