225 lines
7.8 KiB
Python
225 lines
7.8 KiB
Python
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError
|
|
from collections import defaultdict
|
|
from datetime import timedelta, datetime
|
|
|
|
from odoo.tools.safe_eval import safe_eval
|
|
import json
|
|
import calendar
|
|
|
|
class DefaultDictroll(defaultdict):
|
|
def get(self, key, default=None):
|
|
if key not in self and default is not None:
|
|
self[key] = default
|
|
return self[key]
|
|
|
|
class OfferLetter(models.Model):
|
|
_name = 'offer.letter'
|
|
_description = 'Employee Offer Letter'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_order = 'create_date desc'
|
|
|
|
name = fields.Char(
|
|
string='Reference',
|
|
required=True,
|
|
default=lambda self: _('New'),
|
|
copy=False
|
|
)
|
|
candidate_id = fields.Many2one( 'hr.applicant', string='Candidate', required=True,
|
|
)
|
|
|
|
employee_id = fields.Char(
|
|
string='Employee ID',
|
|
readonly=True
|
|
)
|
|
position = fields.Char(
|
|
string='Position',
|
|
required=True
|
|
)
|
|
|
|
salary = fields.Float(
|
|
string='Salary',
|
|
required=True
|
|
)
|
|
mi = fields.Float(
|
|
string='Medical Insurance',
|
|
)
|
|
currency_id = fields.Many2one(
|
|
'res.currency',
|
|
string='Currency',
|
|
default=lambda self: self.env.company.currency_id
|
|
)
|
|
joining_date = fields.Date(
|
|
string='Joining Date',
|
|
default=lambda self: (datetime.now() + timedelta(days=14)).strftime('%Y-%m-%d'))
|
|
contract_type = fields.Selection([
|
|
('permanent', 'Permanent'),
|
|
('contract', 'Fixed Term Contract'),
|
|
('intern', 'Internship')],
|
|
string='Contract Type',
|
|
default='permanent'
|
|
)
|
|
probation_period = fields.Integer(
|
|
string='Probation Period (months)',
|
|
default=3
|
|
)
|
|
terms_conditions = fields.Text(
|
|
string='Terms and Conditions',
|
|
default=lambda self: self._default_terms()
|
|
)
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('sent', 'Sent'),
|
|
('accepted', 'Accepted'),
|
|
('rejected', 'Rejected'),
|
|
('expired', 'Expired')],
|
|
string='Status',
|
|
default='draft',
|
|
tracking=True
|
|
)
|
|
sent_date = fields.Datetime(string='Sent Date')
|
|
response_date = fields.Datetime(string='Response Date')
|
|
pay_struct_id = fields.Many2one('hr.payroll.structure', string="Salary Structure", required=True)
|
|
manager_id = fields.Many2one('hr.employee', string='Manager')
|
|
|
|
|
|
@api.model
|
|
def _default_terms(self):
|
|
return """
|
|
<p>1. This offer is contingent upon satisfactory reference checks.</p>
|
|
<p>2. You will be required to sign a confidentiality agreement.</p>
|
|
<p>3. The company reserves the right to modify job responsibilities.</p>
|
|
"""
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
if vals.get('name', _('New')) == _('New'):
|
|
vals['name'] = self.env['ir.sequence'].next_by_code('offer.letter') or _('New')
|
|
return super(OfferLetter, self).create(vals)
|
|
|
|
def action_send_offer(self):
|
|
self.ensure_one()
|
|
# template = self.env.ref('offer_letters.email_template_offer_letter')
|
|
self.write({'state': 'sent', 'sent_date': fields.Datetime.now()})
|
|
# template.send_mail(self.id, force_send=True)
|
|
return True
|
|
|
|
def action_accept_offer(self):
|
|
self.ensure_one()
|
|
# employee = self.env['hr.employee'].create({
|
|
# 'name': self.candidate_id.partner_name,
|
|
# 'job_title': self.position,
|
|
# 'department_id': self.department_id.id,
|
|
# 'currency_id': self.currency_id.id,
|
|
# })
|
|
self.write({
|
|
'state': 'accepted',
|
|
# 'employee_id': employee,
|
|
'response_date': fields.Datetime.now()
|
|
})
|
|
return True
|
|
|
|
def action_reject_offer(self):
|
|
self.ensure_one()
|
|
self.write({
|
|
'state': 'rejected',
|
|
'response_date': fields.Datetime.now()
|
|
})
|
|
return True
|
|
|
|
@api.onchange('candidate_id')
|
|
def _onchange_candidate_id(self):
|
|
self.position = self.candidate_id.job_id.name
|
|
|
|
def get_paydetailed_lines(self):
|
|
today = fields.Date.today()
|
|
first_day = today.replace(day=1)
|
|
last_day = today.replace(day=calendar.monthrange(today.year, today.month)[1])
|
|
|
|
payslip = self.env['hr.payslip'].new({
|
|
'date_from': first_day,
|
|
'date_to': last_day,
|
|
})
|
|
|
|
contract = self.env['hr.contract'].new({
|
|
'date_start': first_day,
|
|
'date_end': last_day,
|
|
'l10n_in_medical_insurance':self.mi,
|
|
'l10n_in_provident_fund': True,
|
|
'name': 'test',
|
|
'wage': self.salary / 12,
|
|
})
|
|
|
|
categories_dict = {}
|
|
rules_dict = {}
|
|
result = {}
|
|
|
|
localdict = {
|
|
'payslip': payslip,
|
|
'contract': contract,
|
|
'worked_days': {},
|
|
'categories': defaultdict(lambda: 0), # Fixed: Changed DefaultDictroll to defaultdict
|
|
'rules': defaultdict(lambda: dict(total=0, amount=0, quantity=0)),
|
|
'result': None,
|
|
'result_qty': 1.0,
|
|
'result_rate': 100,
|
|
'result_name': False,
|
|
'inputs': {},
|
|
}
|
|
blacklisted_ids = set(self.env.context.get('prevent_payslip_computation_line_ids', []))
|
|
for rule in sorted(self.pay_struct_id.rule_ids, key=lambda r: r.sequence):
|
|
if rule.id in blacklisted_ids or not rule._satisfy_condition(localdict):
|
|
continue
|
|
qty = 1.0
|
|
rate = 100.0
|
|
amount = 0.0
|
|
try:
|
|
if rule.amount_select == 'fix':
|
|
amount = rule.amount_fix
|
|
elif rule.amount_select == 'percentage':
|
|
base = float(safe_eval(rule.amount_percentage_base or '0.0', localdict, mode='exec', nocopy=True))
|
|
amount = base * rule.amount_percentage / 100
|
|
elif rule.amount_select == 'code':
|
|
safe_eval(rule.amount_python_compute or '0.0', localdict, mode='exec', nocopy=True)
|
|
amount = float(localdict.get('result', 0.0))
|
|
except Exception as e:
|
|
raise UserError(_("Error in rule %s: %s") % (rule.name, str(e)))
|
|
|
|
total = payslip._get_payslip_line_total(amount, qty, rate, rule)
|
|
rule_code = rule.code
|
|
previous_amount = localdict.get(rule.code, 0.0)
|
|
category_code = rule.category_id.code
|
|
tot_rule = payslip._get_payslip_line_total(amount, qty, rate, rule)
|
|
|
|
# Make sure _sum_salary_rule_category method exists
|
|
if hasattr(rule.category_id, '_sum_salary_rule_category'):
|
|
localdict = rule.category_id._sum_salary_rule_category(localdict, tot_rule - previous_amount)
|
|
|
|
localdict[rule_code] = total
|
|
rules_dict[rule_code] = rule
|
|
categories_dict[category_code] = categories_dict.get(category_code, 0.0) + amount
|
|
|
|
result[rule_code] = {
|
|
'sequence': rule.sequence,
|
|
'code': rule_code,
|
|
'name': rule.name, # Simplified name retrieval
|
|
'salary_rule_id': rule.id,
|
|
'amount': round(amount,2),
|
|
'y_amount': round((amount * 12),2),
|
|
'quantity': qty,
|
|
'rate': rate,
|
|
'total': round(total,2),
|
|
}
|
|
|
|
self.terms_conditions = json.dumps(list(result.values()))
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': self._name,
|
|
'res_id': self.id,
|
|
'view_mode': 'form',
|
|
'view_type': 'form',
|
|
'target': 'current',
|
|
}
|
|
|
|
def generate_pdf_report(self):
|
|
return self.env.ref('offer_letters.hr_offer_letters_employee_print').report_action(self) |