from odoo import models, fields, api from odoo.exceptions import ValidationError from datetime import datetime, timedelta import calendar class PayrollPeriod(models.Model): _name = 'payroll.period' _description = 'Payroll Period' _rec_name = 'name' _sql_constraints = [ ('unique_name', 'unique(name)', 'The name must be unique.') ] from_date = fields.Date(string="From Date", required=True) to_date = fields.Date(string="To Date", required=True) name = fields.Char(string="Name", required=True) period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods") @api.onchange('from_date', 'to_date') def onchange_from_to_date(self): for rec in self: if rec.from_date and rec.to_date: rec.name = f"{rec.from_date.year}-{rec.to_date.year}" def action_generate_month_lines(self): self.ensure_one() if not (self.from_date and self.to_date): raise ValidationError("Please set both From Date and To Date.") lines = [] current = self.from_date.replace(day=1) while current <= self.to_date: end_of_month = current.replace(day=calendar.monthrange(current.year, current.month)[1]) if end_of_month > self.to_date: end_of_month = self.to_date lines.append((0, 0, { 'from_date': current, 'to_date': end_of_month, 'name': f"{current.strftime('%b')} - {str(current.year)[-2:]}" })) if current.month == 12: current = current.replace(year=current.year + 1, month=1) else: current = current.replace(month=current.month + 1) self.period_line_ids = lines class PayrollPeriodLine(models.Model): _name = 'payroll.period.line' _description = 'Payroll Period Line' _rec_name = 'name' period_id = fields.Many2one('payroll.period', string="Payroll Period", required=True, ondelete='cascade') from_date = fields.Date(string="From Date") to_date = fields.Date(string="To Date") name = fields.Char(string="Name")