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,306 @@
# -*- coding: utf-8 -*-
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api
from odoo.exceptions import UserError
class HrTaxRemittance(models.Model):
_name = 'hr.tax.remittance'
_description = 'Payroll Tax Remittance'
_order = 'period_start desc'
_inherit = ['mail.thread', 'mail.activity.mixin']
STATE_SELECTION = [
('draft', 'Draft'),
('pending', 'Pending'),
('due', 'Due Soon'),
('past_due', 'Past Due'),
('paid', 'Paid'),
]
PERIOD_TYPE = [
('monthly', 'Monthly'),
('quarterly', 'Quarterly'),
]
name = fields.Char(
string='Reference',
required=True,
copy=False,
default=lambda self: self.env['ir.sequence'].next_by_code('hr.tax.remittance') or 'New',
)
company_id = fields.Many2one(
'res.company',
string='Company',
required=True,
default=lambda self: self.env.company,
)
currency_id = fields.Many2one(
related='company_id.currency_id',
string='Currency',
)
state = fields.Selection(
selection=STATE_SELECTION,
string='Status',
default='draft',
tracking=True,
compute='_compute_state',
store=True,
)
# === Period Information ===
period_type = fields.Selection(
selection=PERIOD_TYPE,
string='Period Type',
default='monthly',
)
period_start = fields.Date(
string='Period Start',
required=True,
)
period_end = fields.Date(
string='Period End',
required=True,
)
due_date = fields.Date(
string='Due Date',
required=True,
help='CRA remittance due date (15th of following month for regular remitters)',
)
# === CPP Amounts ===
cpp_employee = fields.Monetary(
string='CPP Employee',
currency_field='currency_id',
help='Total employee CPP contributions for period',
)
cpp_employer = fields.Monetary(
string='CPP Employer',
currency_field='currency_id',
help='Total employer CPP contributions for period',
)
cpp2_employee = fields.Monetary(
string='CPP2 Employee',
currency_field='currency_id',
help='Total employee CPP2 (second CPP) contributions for period',
)
cpp2_employer = fields.Monetary(
string='CPP2 Employer',
currency_field='currency_id',
help='Total employer CPP2 contributions for period',
)
# === EI Amounts ===
ei_employee = fields.Monetary(
string='EI Employee',
currency_field='currency_id',
help='Total employee EI premiums for period',
)
ei_employer = fields.Monetary(
string='EI Employer',
currency_field='currency_id',
help='Total employer EI premiums (1.4x employee) for period',
)
# === Tax Amounts ===
income_tax = fields.Monetary(
string='Income Tax',
currency_field='currency_id',
help='Total federal + provincial income tax withheld for period',
)
# === Totals ===
total = fields.Monetary(
string='Total Remittance',
currency_field='currency_id',
compute='_compute_total',
store=True,
)
# === Payment Information ===
payment_date = fields.Date(
string='Payment Date',
tracking=True,
)
payment_reference = fields.Char(
string='Payment Reference',
help='Bank reference or confirmation number',
)
payment_method = fields.Selection([
('cra_my_business', 'CRA My Business Account'),
('bank_payment', 'Bank Payment'),
('cheque', 'Cheque'),
], string='Payment Method')
# === Linked Payslips ===
payslip_ids = fields.Many2many(
'hr.payslip',
string='Related Payslips',
help='Payslips included in this remittance period',
)
payslip_count = fields.Integer(
string='Payslip Count',
compute='_compute_payslip_count',
)
@api.depends('cpp_employee', 'cpp_employer', 'cpp2_employee', 'cpp2_employer',
'ei_employee', 'ei_employer', 'income_tax')
def _compute_total(self):
for rec in self:
rec.total = (
rec.cpp_employee + rec.cpp_employer +
rec.cpp2_employee + rec.cpp2_employer +
rec.ei_employee + rec.ei_employer +
rec.income_tax
)
@api.depends('due_date', 'payment_date')
def _compute_state(self):
today = date.today()
for rec in self:
if rec.payment_date:
rec.state = 'paid'
elif not rec.due_date:
rec.state = 'draft'
elif rec.due_date < today:
rec.state = 'past_due'
elif rec.due_date <= today + timedelta(days=7):
rec.state = 'due'
else:
rec.state = 'pending'
def _compute_payslip_count(self):
for rec in self:
rec.payslip_count = len(rec.payslip_ids)
def action_calculate_amounts(self):
"""Calculate remittance amounts from payslips in the period"""
self.ensure_one()
# Find all confirmed payslips in the period
payslips = self.env['hr.payslip'].search([
('company_id', '=', self.company_id.id),
('state', 'in', ['validated', 'paid']),
('date_from', '>=', self.period_start),
('date_to', '<=', self.period_end),
])
if not payslips:
raise UserError('No confirmed payslips found for this period.')
# Sum up amounts by rule code
cpp_ee = cpp_er = cpp2_ee = cpp2_er = 0
ei_ee = ei_er = 0
income_tax = 0
for payslip in payslips:
for line in payslip.line_ids:
code = line.code
amount = abs(line.total)
if code == 'CPP_EE':
cpp_ee += amount
elif code == 'CPP_ER':
cpp_er += amount
elif code == 'CPP2_EE':
cpp2_ee += amount
elif code == 'CPP2_ER':
cpp2_er += amount
elif code == 'EI_EE':
ei_ee += amount
elif code == 'EI_ER':
ei_er += amount
elif code in ('FED_TAX', 'PROV_TAX'):
income_tax += amount
self.write({
'cpp_employee': cpp_ee,
'cpp_employer': cpp_er,
'cpp2_employee': cpp2_ee,
'cpp2_employer': cpp2_er,
'ei_employee': ei_ee,
'ei_employer': ei_er,
'income_tax': income_tax,
'payslip_ids': [(6, 0, payslips.ids)],
})
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': 'Amounts Calculated',
'message': f'Calculated from {len(payslips)} payslips. Total: ${self.total:,.2f}',
'type': 'success',
}
}
def action_mark_paid(self):
"""Mark remittance as paid"""
self.ensure_one()
if not self.payment_date:
self.payment_date = date.today()
self.state = 'paid'
def action_view_payslips(self):
"""View related payslips"""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Payslips',
'res_model': 'hr.payslip',
'view_mode': 'list,form',
'domain': [('id', 'in', self.payslip_ids.ids)],
}
@api.model
def _get_payment_frequency_from_settings(self, company_id=None):
"""Get payment frequency from payroll settings."""
if not company_id:
company_id = self.env.company.id
settings = self.env['payroll.config.settings'].get_settings(company_id)
return settings.federal_tax_payment_frequency or 'monthly'
def create_monthly_remittance(self, year, month, company_id=None):
"""Create a monthly remittance record"""
if not company_id:
company_id = self.env.company.id
# Get settings for payment frequency and CRA info
settings = self.env['payroll.config.settings'].get_settings(company_id)
payment_freq = settings.federal_tax_payment_frequency or 'monthly'
# Calculate period dates
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
due_date = date(year + 1, 1, 15)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
due_date = date(year, month + 1, 15)
# Create the remittance
remittance = self.create({
'company_id': company_id,
'period_type': payment_freq if payment_freq in ['monthly', 'quarterly'] else 'monthly',
'period_start': period_start,
'period_end': period_end,
'due_date': due_date,
})
# Calculate amounts
remittance.action_calculate_amounts()
return remittance
class HrTaxRemittanceSequence(models.Model):
"""Create sequence for tax remittance"""
_name = 'hr.tax.remittance.sequence'
_description = 'Tax Remittance Sequence Setup'
_auto = False
def init(self):
# This will be handled by ir.sequence data instead
pass