132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError
|
|
from datetime import date
|
|
|
|
|
|
class PayrollTaxPaymentSchedule(models.Model):
|
|
"""
|
|
Tax Payment Schedule
|
|
Date-effective payment schedules for provincial taxes.
|
|
"""
|
|
_name = 'payroll.tax.payment.schedule'
|
|
_description = 'Tax Payment Schedule'
|
|
_order = 'province, effective_date desc'
|
|
|
|
config_id = fields.Many2one(
|
|
'payroll.config.settings',
|
|
string='Payroll Settings',
|
|
required=True,
|
|
ondelete='cascade',
|
|
)
|
|
company_id = fields.Many2one(
|
|
related='config_id.company_id',
|
|
string='Company',
|
|
store=True,
|
|
)
|
|
province = fields.Selection([
|
|
('AB', 'Alberta'),
|
|
('BC', 'British Columbia'),
|
|
('MB', 'Manitoba'),
|
|
('NB', 'New Brunswick'),
|
|
('NL', 'Newfoundland and Labrador'),
|
|
('NS', 'Nova Scotia'),
|
|
('NT', 'Northwest Territories'),
|
|
('NU', 'Nunavut'),
|
|
('ON', 'Ontario'),
|
|
('PE', 'Prince Edward Island'),
|
|
('QC', 'Quebec'),
|
|
('SK', 'Saskatchewan'),
|
|
('YT', 'Yukon'),
|
|
], string='Province', required=True)
|
|
payment_frequency = fields.Selection([
|
|
('monthly', 'Monthly'),
|
|
('quarterly', 'Quarterly'),
|
|
('annually', 'Annually'),
|
|
], string='Payment Frequency', required=True, default='quarterly')
|
|
effective_date = fields.Date(
|
|
string='Effective Date',
|
|
required=True,
|
|
help='Date when this payment schedule becomes effective',
|
|
)
|
|
form_type = fields.Char(
|
|
string='Form Type',
|
|
help='Tax form type (e.g., Form PD7A)',
|
|
)
|
|
is_current = fields.Boolean(
|
|
string='Current Schedule',
|
|
compute='_compute_is_current',
|
|
store=True,
|
|
help='True if this is the currently active schedule',
|
|
)
|
|
display_name = fields.Char(
|
|
string='Display Name',
|
|
compute='_compute_display_name',
|
|
)
|
|
|
|
@api.depends('payment_frequency', 'effective_date', 'is_current')
|
|
def _compute_display_name(self):
|
|
"""Compute display name for the schedule."""
|
|
for schedule in self:
|
|
freq_map = {
|
|
'monthly': 'Monthly',
|
|
'quarterly': 'Quarterly',
|
|
'annually': 'Annually',
|
|
}
|
|
freq = freq_map.get(schedule.payment_frequency, schedule.payment_frequency)
|
|
date_str = schedule.effective_date.strftime('%m/%d/%Y') if schedule.effective_date else ''
|
|
current = ' (current schedule)' if schedule.is_current else ''
|
|
schedule.display_name = f"{freq} since {date_str}{current}"
|
|
|
|
@api.depends('effective_date', 'province', 'config_id.provincial_tax_schedule_ids')
|
|
def _compute_is_current(self):
|
|
"""Determine if this is the current active schedule."""
|
|
today = date.today()
|
|
for schedule in self:
|
|
# Get all schedules for this province, ordered by effective_date desc
|
|
all_schedules = self.search([
|
|
('config_id', '=', schedule.config_id.id),
|
|
('province', '=', schedule.province),
|
|
], order='effective_date desc')
|
|
|
|
# The current schedule is the one with the most recent effective_date <= today
|
|
current_schedule = None
|
|
for sched in all_schedules:
|
|
if sched.effective_date <= today:
|
|
current_schedule = sched
|
|
break
|
|
|
|
schedule.is_current = (current_schedule and current_schedule.id == schedule.id)
|
|
|
|
@api.model
|
|
def get_current_schedule(self, config_id, province, check_date=None):
|
|
"""Get the current active schedule for a province."""
|
|
if not check_date:
|
|
check_date = date.today()
|
|
|
|
schedule = self.search([
|
|
('config_id', '=', config_id),
|
|
('province', '=', province),
|
|
('effective_date', '<=', check_date),
|
|
], order='effective_date desc', limit=1)
|
|
|
|
return schedule
|
|
|
|
@api.constrains('effective_date', 'province', 'config_id')
|
|
def _check_overlapping_schedules(self):
|
|
"""Warn if schedules overlap (but allow for historical changes)."""
|
|
for schedule in self:
|
|
# Allow multiple schedules, but warn if dates are very close
|
|
overlapping = self.search([
|
|
('config_id', '=', schedule.config_id.id),
|
|
('province', '=', schedule.province),
|
|
('id', '!=', schedule.id),
|
|
('effective_date', '=', schedule.effective_date),
|
|
])
|
|
if overlapping:
|
|
raise UserError(_(
|
|
'A payment schedule for %s already exists with effective date %s. '
|
|
'Please use a different date.'
|
|
) % (schedule.province, schedule.effective_date.strftime('%m/%d/%Y')))
|