<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data noupdate="1">

        <!-- ============================================================ -->
        <!-- OVERTIME PAY - 1.5x Regular Rate                              -->
        <!-- ============================================================ -->
        <record id="hr_overtime_pay" model="hr.salary.rule">
            <field name="name">Overtime Pay</field>
            <field name="code">OT_PAY</field>
            <field name="sequence">101</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.ALW"/>
            <field name="condition_select">python</field>
            <field name="condition_python">result = 'OT_HOURS' in inputs</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Overtime Pay - 1.5x regular hourly rate
OT_MULTIPLIER = 1.5
ot_hours = inputs['OT_HOURS'].amount if 'OT_HOURS' in inputs else 0
# Calculate hourly rate from paid amount (assuming semi-monthly ~86.67 hours)
hourly_rate = payslip.paid_amount / 86.67 if payslip.paid_amount else 0
result = ot_hours * hourly_rate * OT_MULTIPLIER
</field>
        </record>

        <!-- ============================================================ -->
        <!-- STAT HOLIDAY PAY                                              -->
        <!-- ============================================================ -->
        <record id="hr_stat_holiday_pay" model="hr.salary.rule">
            <field name="name">Stat Holiday Pay</field>
            <field name="code">STAT_PAY</field>
            <field name="sequence">102</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.ALW"/>
            <field name="condition_select">python</field>
            <field name="condition_python">result = 'STAT_HOURS' in inputs</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Stat Holiday Pay
stat_hours = inputs['STAT_HOURS'].amount if 'STAT_HOURS' in inputs else 0
hourly_rate = payslip.paid_amount / 86.67 if payslip.paid_amount else 0
result = stat_hours * hourly_rate
</field>
        </record>

        <!-- ============================================================ -->
        <!-- BONUS PAY                                                     -->
        <!-- ============================================================ -->
        <record id="hr_bonus_pay" model="hr.salary.rule">
            <field name="name">Bonus</field>
            <field name="code">BONUS_PAY</field>
            <field name="sequence">103</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.ALW"/>
            <field name="condition_select">python</field>
            <field name="condition_python">result = 'BONUS' in inputs</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Bonus Pay - direct amount from input
result = inputs['BONUS'].amount if 'BONUS' in inputs else 0
</field>
        </record>

        <!-- ============================================================ -->
        <!-- CPP EMPLOYEE - Canada Pension Plan (Employee Portion)         -->
        <!-- Uses rule parameters for rates and limits                     -->
        <!-- ============================================================ -->
        <record id="hr_cpp_employee" model="hr.salary.rule">
            <field name="name">CPP Employee</field>
            <field name="code">CPP_EE</field>
            <field name="sequence">150</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.DED"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# CPP Employee Deduction - Using Rule Parameters
CPP_RATE = payslip._rule_parameter('ca_cpp_rate')
CPP_EXEMPTION = payslip._rule_parameter('ca_cpp_exemption')
CPP_MAX = payslip._rule_parameter('ca_cpp_max')
PAY_PERIODS = 24  # Semi-monthly

exemption_per_period = CPP_EXEMPTION / PAY_PERIODS
gross = categories['GROSS']
pensionable = max(0, gross - exemption_per_period)
cpp = pensionable * CPP_RATE

# YTD check - get year start
from datetime import date
year_start = date(payslip.date_from.year, 1, 1)
ytd = payslip._sum('CPP_EE', year_start, payslip.date_from) or 0
remaining = CPP_MAX + ytd  # ytd is negative

if remaining &lt;= 0:
    result = 0
elif cpp > remaining:
    result = -remaining
else:
    result = -cpp
</field>
        </record>

        <!-- ============================================================ -->
        <!-- CPP EMPLOYER - 1:1 Match                                      -->
        <!-- ============================================================ -->
        <record id="hr_cpp_employer" model="hr.salary.rule">
            <field name="name">CPP Employer</field>
            <field name="code">CPP_ER</field>
            <field name="sequence">151</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.COMP"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# CPP Employer - 1:1 match with employee
result = abs(CPP_EE) if CPP_EE else 0
</field>
        </record>

        <!-- ============================================================ -->
        <!-- CPP2 EMPLOYEE - Second Canada Pension Plan                    -->
        <!-- Uses rule parameters for rates and limits                     -->
        <!-- ============================================================ -->
        <record id="hr_cpp2_employee" model="hr.salary.rule">
            <field name="name">CPP2 Employee</field>
            <field name="code">CPP2_EE</field>
            <field name="sequence">152</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.DED"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# CPP2 (Second CPP) - Using Rule Parameters
CPP2_RATE = payslip._rule_parameter('ca_cpp2_rate')
YMPE = payslip._rule_parameter('ca_ympe')
YAMPE = payslip._rule_parameter('ca_yampe')
CPP2_MAX = payslip._rule_parameter('ca_cpp2_max')
PAY_PERIODS = 24

gross = categories['GROSS']
annual_equiv = gross * PAY_PERIODS

result = 0
# CPP2 only on earnings between YMPE and YAMPE
if annual_equiv > YMPE:
    cpp2_base = min(annual_equiv, YAMPE) - YMPE
    cpp2_per_period = (cpp2_base * CPP2_RATE) / PAY_PERIODS
    
    # YTD check
    from datetime import date
    year_start = date(payslip.date_from.year, 1, 1)
    ytd = abs(payslip._sum('CPP2_EE', year_start, payslip.date_from) or 0)
    remaining = CPP2_MAX - ytd
    
    if remaining > 0:
        result = -min(cpp2_per_period, remaining)
</field>
        </record>

        <!-- ============================================================ -->
        <!-- CPP2 EMPLOYER - 1:1 Match                                     -->
        <!-- ============================================================ -->
        <record id="hr_cpp2_employer" model="hr.salary.rule">
            <field name="name">CPP2 Employer</field>
            <field name="code">CPP2_ER</field>
            <field name="sequence">153</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.COMP"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# CPP2 Employer - 1:1 match
result = abs(CPP2_EE) if CPP2_EE else 0
</field>
        </record>

        <!-- ============================================================ -->
        <!-- EI EMPLOYEE - Employment Insurance                            -->
        <!-- Uses rule parameters for rates and limits                     -->
        <!-- ============================================================ -->
        <record id="hr_ei_employee" model="hr.salary.rule">
            <field name="name">EI Employee</field>
            <field name="code">EI_EE</field>
            <field name="sequence">154</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.DED"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# EI Employee - Using Rule Parameters
EI_RATE = payslip._rule_parameter('ca_ei_rate')
EI_MAX = payslip._rule_parameter('ca_ei_max')

gross = categories['GROSS']
ei = gross * EI_RATE

# YTD check
from datetime import date
year_start = date(payslip.date_from.year, 1, 1)
ytd = abs(payslip._sum('EI_EE', year_start, payslip.date_from) or 0)
remaining = EI_MAX - ytd

if remaining &lt;= 0:
    result = 0
elif ei > remaining:
    result = -remaining
else:
    result = -ei
</field>
        </record>

        <!-- ============================================================ -->
        <!-- EI EMPLOYER - 1.4x Employee Premium                           -->
        <!-- ============================================================ -->
        <record id="hr_ei_employer" model="hr.salary.rule">
            <field name="name">EI Employer</field>
            <field name="code">EI_ER</field>
            <field name="sequence">155</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.COMP"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# EI Employer - Using Rule Parameter for multiplier
EI_ER_MULT = payslip._rule_parameter('ca_ei_employer_mult')
result = abs(EI_EE) * EI_ER_MULT if EI_EE else 0
</field>
        </record>

        <!-- ============================================================ -->
        <!-- FEDERAL INCOME TAX                                            -->
        <!-- Uses rule parameters for brackets and credits                 -->
        <!-- ============================================================ -->
        <record id="hr_fed_tax" model="hr.salary.rule">
            <field name="name">Federal Income Tax</field>
            <field name="code">FED_TAX</field>
            <field name="sequence">160</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.DED"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Federal Income Tax - Using Rule Parameters
PAY_PERIODS = 24
brackets = payslip._rule_parameter('ca_fed_brackets')
BPA = payslip._rule_parameter('ca_fed_bpa')
CEA = payslip._rule_parameter('ca_fed_cea')
CPP_MAX = payslip._rule_parameter('ca_cpp_max')
EI_MAX = payslip._rule_parameter('ca_ei_max')

gross = categories['GROSS']
annual = gross * PAY_PERIODS

# Calculate tax using brackets
tax = 0
prev_threshold = 0
for threshold, rate in brackets:
    if annual &lt;= threshold:
        tax += (annual - prev_threshold) * rate
        break
    else:
        tax += (threshold - prev_threshold) * rate
        prev_threshold = threshold

# Basic personal amount credit
tax_credit = BPA * brackets[0][1]  # Lowest rate

# CPP/EI credits
cpp_credit = min(abs(CPP_EE) * PAY_PERIODS if CPP_EE else 0, CPP_MAX) * brackets[0][1]
ei_credit = min(abs(EI_EE) * PAY_PERIODS if EI_EE else 0, EI_MAX) * brackets[0][1]

# Canada Employment Amount credit
cea_credit = CEA * brackets[0][1]

annual_tax = max(0, tax - tax_credit - cpp_credit - ei_credit - cea_credit)
result = -(annual_tax / PAY_PERIODS)
</field>
        </record>

        <!-- ============================================================ -->
        <!-- PROVINCIAL INCOME TAX (ONTARIO)                               -->
        <!-- Uses rule parameters for brackets and credits                 -->
        <!-- ============================================================ -->
        <record id="hr_prov_tax" model="hr.salary.rule">
            <field name="name">Provincial Income Tax</field>
            <field name="code">PROV_TAX</field>
            <field name="sequence">161</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.DED"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Ontario Provincial Tax - Using Rule Parameters
PAY_PERIODS = 24
brackets = payslip._rule_parameter('ca_on_brackets')
BPA_ON = payslip._rule_parameter('ca_on_bpa')
CPP_MAX = payslip._rule_parameter('ca_cpp_max')
EI_MAX = payslip._rule_parameter('ca_ei_max')

gross = categories['GROSS']
annual = gross * PAY_PERIODS

# Calculate tax using brackets
tax = 0
prev_threshold = 0
for threshold, rate in brackets:
    if annual &lt;= threshold:
        tax += (annual - prev_threshold) * rate
        break
    else:
        tax += (threshold - prev_threshold) * rate
        prev_threshold = threshold

# Ontario Basic Personal Amount credit
tax_credit = BPA_ON * brackets[0][1]  # Lowest rate

# CPP/EI credits at lowest rate
cpp_credit = min(abs(CPP_EE) * PAY_PERIODS if CPP_EE else 0, CPP_MAX) * brackets[0][1]
ei_credit = min(abs(EI_EE) * PAY_PERIODS if EI_EE else 0, EI_MAX) * brackets[0][1]

annual_tax = max(0, tax - tax_credit - cpp_credit - ei_credit)
result = -(annual_tax / PAY_PERIODS)
</field>
        </record>

        <!-- ============================================================ -->
        <!-- VACATION PAY - 4% of Earnings                                 -->
        <!-- ============================================================ -->
        <record id="hr_vacation_pay" model="hr.salary.rule">
            <field name="name">Vacation Pay</field>
            <field name="code">VAC_PAY</field>
            <field name="sequence">170</field>
            <field name="struct_id" ref="hr_payroll_structure_canada"/>
            <field name="category_id" ref="hr_payroll.ALW"/>
            <field name="condition_select">none</field>
            <field name="amount_select">code</field>
            <field name="appears_on_payslip">True</field>
            <field name="amount_python_compute">
# Vacation Pay - Using Rule Parameter
VAC_RATE = payslip._rule_parameter('ca_vacation_rate')
result = categories['BASIC'] * VAC_RATE
</field>
        </record>

    </data>
</odoo>
