From a9a9f08ff988d10dea845011c5f12073b6c25fa4 Mon Sep 17 00:00:00 2001 From: pranaysaidurga Date: Fri, 19 Jun 2026 14:05:09 +0530 Subject: [PATCH] recritment bug fixes --- .../cwf_timesheet/models/timesheet.py | 1 - .../models/it_tax_statement_wiz.py | 8 +- .../views/it_tax_menu_and_wizard_view.xml | 2 +- .../wizards/letout_house_property.py | 13 +- .../models/hr_attendance_report.py | 1 - .../models/hr_applicant.py | 3 +- .../models/hr_candidate.py | 3 +- .../models/hr_job_recruitment.py | 1 + .../views/hr_applicant_views.xml | 10 +- .../wizard/hr_recruitment_auto_doc_wizard.py | 40 +++- .../models/hr_applicant.py | 198 ++++++++------- .../hr_employee_education_employer_family.py | 24 +- .../models/hr_recruitment.py | 2 + .../static/src/js/recruitment_match_panel.js | 109 +++++++-- .../src/scss/recruitment_match_panel.scss | 39 +++ .../views/hr_applicant_views.xml | 25 +- .../hr_employee_education_employer_family.xml | 2 +- .../views/hr_recruitment.xml | 28 ++- .../post_onboarding_attachment_wizard.py | 1 - .../controllers/hrms_emp_dashboard.py | 7 - .../offer_letters/__manifest__.py | 1 + .../offer_letters/models/__init__.py | 1 + .../offer_letters/models/hr_applicant.py | 2 + .../offer_letters/models/offer_letter.py | 12 +- .../offer_letters/models/stages.py | 6 + .../views/hr_applicant_offer_views.xml | 2 +- .../offer_letters/views/stages.xml | 14 ++ .../wizards/offer_release_request_wizard.py | 6 +- .../project_dashboard_controller.py | 4 - .../static/src/search_tabs/search_tabs.scss | 4 + .../models/application_candidate_changes.py | 11 +- .../static/src/css/candidate_card.css | 21 ++ .../views/hr_applicant_form.xml | 3 +- .../views/hr_candidate_form.xml | 226 ++++++++++++++++++ .../controllers/main.py | 1 - .../models/website.py | 2 - 36 files changed, 651 insertions(+), 182 deletions(-) create mode 100644 addons_extensions/offer_letters/models/stages.py create mode 100644 addons_extensions/offer_letters/views/stages.xml diff --git a/addons_extensions/cwf_timesheet/models/timesheet.py b/addons_extensions/cwf_timesheet/models/timesheet.py index 4d257ab38..8245e95d0 100644 --- a/addons_extensions/cwf_timesheet/models/timesheet.py +++ b/addons_extensions/cwf_timesheet/models/timesheet.py @@ -115,7 +115,6 @@ class CwfTimesheet(models.Model): external_group_id = self.env.ref("hr_employee_extended.group_external_user") users = self.env["res.users"].search([("groups_id", "=", external_group_id.id)]) employees = self.env['hr.employee'].search([('user_id', 'in', users.ids),'|',('doj','=',False),('doj','>=', self.week_start_date)]) - print(employees) # Loop through each day of the week and create timesheet lines for each employee while current_date <= end_date: for employee in employees: diff --git a/addons_extensions/employee_it_declaration/models/it_tax_statement_wiz.py b/addons_extensions/employee_it_declaration/models/it_tax_statement_wiz.py index 6ebe1fd82..3f19c27df 100644 --- a/addons_extensions/employee_it_declaration/models/it_tax_statement_wiz.py +++ b/addons_extensions/employee_it_declaration/models/it_tax_statement_wiz.py @@ -756,9 +756,9 @@ class ITTaxStatementWizard(models.TransientModel): if not self.employee_id or not self.contract_id or not self.period_id or not self.period_line: raise ValidationError(_("Select employee, period, and period line before checking comparison.")) - values = self._get_tax_base_values(include_comparison=True) + values = self.sudo()._get_tax_base_values(include_comparison=True) if not values['comparison_available']: - self._reset_regime_comparison() + self.sudo()._reset_regime_comparison() raise ValidationError(_("Tax comparison is available only when both old and new regime slabs are configured.")) self.write({ @@ -938,7 +938,7 @@ class ITTaxStatementWizard(models.TransientModel): return {'data': data} def action_generate_report(self): - report_data = self._prepare_income_tax_data(include_comparison=False) + report_data = self.sudo()._prepare_income_tax_data(include_comparison=False) return self.env.ref('employee_it_declaration.income_tax_statement_action_report').report_action( self, @@ -946,7 +946,7 @@ class ITTaxStatementWizard(models.TransientModel): ) def action_generate_comparison_report(self): - report_data = self._prepare_income_tax_data(include_comparison=True) + report_data = self.sudo()._prepare_income_tax_data(include_comparison=True) if not report_data['data']['comparison']['available']: raise ValidationError(_("Tax comparison is available only when both old and new regime slabs are configured.")) diff --git a/addons_extensions/employee_it_declaration/views/it_tax_menu_and_wizard_view.xml b/addons_extensions/employee_it_declaration/views/it_tax_menu_and_wizard_view.xml index 59bfaa342..203375040 100644 --- a/addons_extensions/employee_it_declaration/views/it_tax_menu_and_wizard_view.xml +++ b/addons_extensions/employee_it_declaration/views/it_tax_menu_and_wizard_view.xml @@ -43,7 +43,7 @@ - + diff --git a/addons_extensions/employee_it_declaration/wizards/letout_house_property.py b/addons_extensions/employee_it_declaration/wizards/letout_house_property.py index 72510de3e..45d116d9f 100644 --- a/addons_extensions/employee_it_declaration/wizards/letout_house_property.py +++ b/addons_extensions/employee_it_declaration/wizards/letout_house_property.py @@ -1,10 +1,10 @@ from odoo import models, fields, api import math -class LetoutHouseProperty(models.Model): - _name = 'letout.house.property' - _inherit = ['it.declaration.submitted.lock.mixin'] - _description = 'Letout House Property Details' +class LetoutHouseProperty(models.Model): + _name = 'letout.house.property' + _inherit = ['it.declaration.submitted.lock.mixin'] + _description = 'Letout House Property Details' it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration") other_il_id = fields.Many2one('other.il.costing.type', string="Other Income/Loss Costing Type") @@ -36,9 +36,6 @@ class LetoutHouseProperty(models.Model): deduction = net_annual_value * 0.30 income_loss = net_annual_value - deduction - record.interest_paid_to - print(net_annual_value) - print(deduction) - print(income_loss) record.net_annual_value = net_annual_value record.deduction_for_repairs = round(deduction) - record.income_loss = round(income_loss) + record.income_loss = round(income_loss) diff --git a/addons_extensions/hr_attendance_extended/models/hr_attendance_report.py b/addons_extensions/hr_attendance_extended/models/hr_attendance_report.py index d745b1592..7a1e4687b 100644 --- a/addons_extensions/hr_attendance_extended/models/hr_attendance_report.py +++ b/addons_extensions/hr_attendance_extended/models/hr_attendance_report.py @@ -209,7 +209,6 @@ ORDER BY except Exception as e: error_msg = f"Error executing attendance report query: {str(e)}" - print(error_msg) raise UserError( _("An error occurred while generating the attendance report. Please check the logs for details.")) diff --git a/addons_extensions/hr_recruitment_auto_doc/models/hr_applicant.py b/addons_extensions/hr_recruitment_auto_doc/models/hr_applicant.py index 61d7e106b..2c09d56b2 100644 --- a/addons_extensions/hr_recruitment_auto_doc/models/hr_applicant.py +++ b/addons_extensions/hr_recruitment_auto_doc/models/hr_applicant.py @@ -8,7 +8,8 @@ class HrApplicant(models.Model): action = self.env.ref("hr_recruitment_auto_doc.action_hr_recruitment_auto_doc_wizard_applicant").read()[0] context = dict(self.env.context) context['single_parser'] = True - action["context"]['current_id'] = self.id + context['applicant_id'] = self.id + context['target_model'] = 'applicant' if len(self) == 1 and self.hr_job_recruitment: context["default_job_recruitment_id"] = self.hr_job_recruitment.id action["context"] = context diff --git a/addons_extensions/hr_recruitment_auto_doc/models/hr_candidate.py b/addons_extensions/hr_recruitment_auto_doc/models/hr_candidate.py index 677e3e177..3526071c2 100644 --- a/addons_extensions/hr_recruitment_auto_doc/models/hr_candidate.py +++ b/addons_extensions/hr_recruitment_auto_doc/models/hr_candidate.py @@ -8,6 +8,7 @@ class HrCandidate(models.Model): action = self.env.ref("hr_recruitment_auto_doc.action_hr_recruitment_auto_doc_wizard_candidate").read()[0] action["context"] = dict(self.env.context) action["context"]['single_parser'] = True - action["context"]['current_id'] = self.id + action["context"]['target_model'] = 'candidate' + action["context"]['candidate_id'] = self.id action["name"] = _("Parse Resumes") return action diff --git a/addons_extensions/hr_recruitment_auto_doc/models/hr_job_recruitment.py b/addons_extensions/hr_recruitment_auto_doc/models/hr_job_recruitment.py index 9eae68c54..96a0aa4da 100644 --- a/addons_extensions/hr_recruitment_auto_doc/models/hr_job_recruitment.py +++ b/addons_extensions/hr_recruitment_auto_doc/models/hr_job_recruitment.py @@ -7,6 +7,7 @@ class HrJobRecruitment(models.Model): def action_open_auto_doc_wizard(self): action = self.env.ref("hr_recruitment_auto_doc.action_hr_recruitment_auto_doc_wizard_job_recruitment").read()[0] context = dict(self.env.context) + context['target_model'] = 'job_recruitment' if len(self) == 1: context["default_job_recruitment_id"] = self.id action["context"] = context diff --git a/addons_extensions/hr_recruitment_auto_doc/views/hr_applicant_views.xml b/addons_extensions/hr_recruitment_auto_doc/views/hr_applicant_views.xml index 76674e62a..0e4b76753 100644 --- a/addons_extensions/hr_recruitment_auto_doc/views/hr_applicant_views.xml +++ b/addons_extensions/hr_recruitment_auto_doc/views/hr_applicant_views.xml @@ -39,11 +39,11 @@ - @@ -322,28 +329,88 @@ patch(RecruitmentFormController.prototype, {
-
- -
- ${this._renderSkillTags(payload.primary_skill_names || [], "o_hr_match_chip_primary")} -
-
-
- -
- ${this._renderSkillTags(payload.secondary_skill_names || [], "o_hr_match_chip_secondary")} -
-
-
+ + ${ + payload.primary_skill_names?.length + ? ` +
+ + ${this._primarySkillsExpanded ? "▼" : "▶"} + ${escapeHtml(_t("Primary Skills"))} + + + + (${payload.primary_skill_names.length}) + +
+ + ${ + this._primarySkillsExpanded + ? ` +
+ ${this._renderSkillTags(payload.primary_skill_names, "o_hr_match_chip_primary")} +
+ ` + : "" + } + ` + : "" + } + + ${ + payload.secondary_skill_names?.length + ? ` +
+ + ${this._secondarySkillsExpanded ? "▼" : "▶"} + ${escapeHtml(_t("Secondary Skills"))} + + + + (${payload.secondary_skill_names.length}) + +
+ + ${ + this._secondarySkillsExpanded + ? ` +
+ ${this._renderSkillTags(payload.secondary_skill_names, "o_hr_match_chip_secondary")} +
+ ` + : "" + } + ` + : "" + } + +
${this._matchPanelLoading ? `
${escapeHtml(_t("Refreshing matches..."))}
` : activeCards}
`; panel.classList.add("o_hr_match_panel_open"); + panel.querySelector('[data-toggle="primary"]')?.addEventListener("click", () => { + this._primarySkillsExpanded = !this._primarySkillsExpanded; + this._renderRecruitmentMatchPanel(); + }); + panel.querySelector('[data-toggle="secondary"]')?.addEventListener("click", () => { + this._secondarySkillsExpanded = !this._secondarySkillsExpanded; + this._renderRecruitmentMatchPanel(); + }); panel.querySelector(".o_hr_match_close")?.addEventListener("click", () => this._closeRecruitmentMatchPanel()); - panel.querySelector(".o_hr_match_refresh")?.addEventListener("click", () => this._loadRecruitmentMatchPanelData()); + panel.querySelector(".o_hr_match_refresh")?.addEventListener("click", () => { + this._matchPanelScrollPosition = { + candidates: 0, + applicants: 0, + }; + this._loadRecruitmentMatchPanelData() + } + ); panel.querySelectorAll(".o_hr_match_tab").forEach((tabButton) => { tabButton.addEventListener("click", () => { this._matchPanelActiveTab = tabButton.dataset.tab || "candidates"; @@ -401,7 +468,17 @@ patch(RecruitmentFormController.prototype, { } }); } + const body = panel.querySelector(".o_hr_match_panel_body"); + if (body) { + // Restore previous scroll for this tab + body.scrollTop = previousScroll; + + // Continuously save scroll position + body.addEventListener("scroll", () => { + this._matchPanelScrollPosition[this._matchPanelActiveTab] = body.scrollTop; + }); + } const button = this._getRecruitmentMatchPanelButton(); if (button) { button.classList.add("o_hr_match_fab_hidden"); diff --git a/addons_extensions/hr_recruitment_extended/static/src/scss/recruitment_match_panel.scss b/addons_extensions/hr_recruitment_extended/static/src/scss/recruitment_match_panel.scss index 208544dec..e9732c4ca 100644 --- a/addons_extensions/hr_recruitment_extended/static/src/scss/recruitment_match_panel.scss +++ b/addons_extensions/hr_recruitment_extended/static/src/scss/recruitment_match_panel.scss @@ -100,6 +100,7 @@ margin-top: 6px; font-size: 22px; font-weight: 700; + color: white; } .o_hr_match_panel_header span { @@ -416,6 +417,44 @@ display: grid; gap: 14px; } +.o_hr_match_collapsible { + margin-bottom: 12px; +} + +.o_hr_match_collapsible_header { + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + padding: 8px 12px; + border-radius: 8px; + background: #f5f5f5; + font-weight: 600; +} + +.o_hr_match_collapsible_header:hover { + background: #ececec; +} +.o_hr_match_skill_header { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .08em; + margin-bottom: 10px; + color: #334155; +} + +.o_hr_match_skill_header:hover { + color: var(--o-brand-primary); +} + +.o_hr_match_skill_count { + color: #64748b; + font-weight: 600; +} @media (min-width: 768px) { .o_hr_match_skill_split { diff --git a/addons_extensions/hr_recruitment_extended/views/hr_applicant_views.xml b/addons_extensions/hr_recruitment_extended/views/hr_applicant_views.xml index 4412341cd..3528775de 100644 --- a/addons_extensions/hr_recruitment_extended/views/hr_applicant_views.xml +++ b/addons_extensions/hr_recruitment_extended/views/hr_applicant_views.xml @@ -7,6 +7,7 @@ hold_state == 'hold' + id desc @@ -16,7 +17,7 @@ - + @@ -289,6 +290,26 @@ is_on_hold + + + + +
+
+ + + + +
+ + + + +
+
@@ -297,7 +318,7 @@ + quick_create_view="hr_recruitment.quick_create_applicant_form" sample="1" default_order="id desc"> diff --git a/addons_extensions/hr_recruitment_extended/views/hr_employee_education_employer_family.xml b/addons_extensions/hr_recruitment_extended/views/hr_employee_education_employer_family.xml index ebda49b45..4cfe126ae 100644 --- a/addons_extensions/hr_recruitment_extended/views/hr_employee_education_employer_family.xml +++ b/addons_extensions/hr_recruitment_extended/views/hr_employee_education_employer_family.xml @@ -29,7 +29,7 @@ name="action_validate_personal_details" type="object" class="btn btn-danger" - invisible="not employee_id"> + invisible="employee_id">
Click here to save, Validate and Update into Employee Data + + hr.candidate.view.tree.inherit + hr.candidate + + + + id desc + + + hr.candidate.view.kanban.inherit hr.candidate @@ -284,14 +294,30 @@ + {'active_test': False, 'kanban': True} + id desc - +
+
+ + +
+ + + + +
diff --git a/addons_extensions/hr_recruitment_extended/wizards/post_onboarding_attachment_wizard.py b/addons_extensions/hr_recruitment_extended/wizards/post_onboarding_attachment_wizard.py index b7aefcee0..145505d9e 100644 --- a/addons_extensions/hr_recruitment_extended/wizards/post_onboarding_attachment_wizard.py +++ b/addons_extensions/hr_recruitment_extended/wizards/post_onboarding_attachment_wizard.py @@ -98,7 +98,6 @@ class PostOnboardingAttachmentWizard(models.TransientModel): lambda a: a.attachment_type == 'previous_employer').mapped('name') other_docs = rec.req_attachment_ids.filtered(lambda a: a.attachment_type == 'others').mapped('name') - print(request_upload_url) email_context = { 'applicant_request_form_id': rec.request_form_id.id, 'applicant_request_form_token': request_token, diff --git a/addons_extensions/hrms_emp_dashboard/controllers/hrms_emp_dashboard.py b/addons_extensions/hrms_emp_dashboard/controllers/hrms_emp_dashboard.py index 6c6ee5e0f..150aa9f59 100644 --- a/addons_extensions/hrms_emp_dashboard/controllers/hrms_emp_dashboard.py +++ b/addons_extensions/hrms_emp_dashboard/controllers/hrms_emp_dashboard.py @@ -37,7 +37,6 @@ class HrmsEmployeeDashboard(http.Controller): calendar_attendances = self._get_attendances(employee, calendar_start, calendar_end) calendar_leaves = self._get_leaves(employee, calendar_start, calendar_end) calendar_public_holidays = self._get_public_holidays(employee, calendar_start, calendar_end) - print(self._expense_data(employee, range_start, range_end)) return { "success": True, "employee": self._employee_card(employee), @@ -325,12 +324,6 @@ class HrmsEmployeeDashboard(http.Controller): ("date", "<=", date_to), ]) for expense in emp_expenses: - print( - "Expense: %s | Date: %s | Amount: %s", - expense.name, - expense.date, - expense.total_amount - ) totals[expense.date.strftime("%Y-%m")] += expense.total_amount or 0.0 state_totals[expense.state or "draft"] += expense.total_amount or 0.0 diff --git a/addons_extensions/offer_letters/__manifest__.py b/addons_extensions/offer_letters/__manifest__.py index b7a27c728..3104f490b 100644 --- a/addons_extensions/offer_letters/__manifest__.py +++ b/addons_extensions/offer_letters/__manifest__.py @@ -12,6 +12,7 @@ 'data': [ 'security/ir.model.access.csv', 'data/mail_template.xml', + 'views/stages.xml', 'views/offer_letter_views.xml', 'views/hr_applicant_offer_views.xml', 'views/offer_response_templates.xml', diff --git a/addons_extensions/offer_letters/models/__init__.py b/addons_extensions/offer_letters/models/__init__.py index 3afed8da1..2e82655fc 100644 --- a/addons_extensions/offer_letters/models/__init__.py +++ b/addons_extensions/offer_letters/models/__init__.py @@ -1,3 +1,4 @@ +from . import stages from . import offer_letter from . import hr_applicant from . import hr_candidate \ No newline at end of file diff --git a/addons_extensions/offer_letters/models/hr_applicant.py b/addons_extensions/offer_letters/models/hr_applicant.py index b47e5e51c..5f768a093 100644 --- a/addons_extensions/offer_letters/models/hr_applicant.py +++ b/addons_extensions/offer_letters/models/hr_applicant.py @@ -26,6 +26,8 @@ class HRApplicant(models.Model): store=False, ) + request_offer_release = fields.Boolean(related='recruitment_stage_id.request_offer_release') + @api.depends('offer_letter_ids', 'offer_letter_ids.create_date', 'offer_letter_ids.state') def _compute_current_offer_letter(self): for applicant in self: diff --git a/addons_extensions/offer_letters/models/offer_letter.py b/addons_extensions/offer_letters/models/offer_letter.py index d8b18eea7..25287fccb 100644 --- a/addons_extensions/offer_letters/models/offer_letter.py +++ b/addons_extensions/offer_letters/models/offer_letter.py @@ -174,12 +174,12 @@ class OfferLetter(models.Model): first_day = today.replace(day=1) last_day = today.replace(day=calendar.monthrange(today.year, today.month)[1]) - payslip = self.env['hr.payslip'].new({ + payslip = self.env['hr.payslip'].sudo().new({ 'date_from': first_day, 'date_to': last_day, }) - contract = self.env['hr.contract'].new({ + contract = self.env['hr.contract'].sudo().new({ 'date_start': first_day, 'date_end': last_day, 'l10n_in_medical_insurance':self.mi, @@ -205,7 +205,7 @@ class OfferLetter(models.Model): '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): + for rule in sorted(self.sudo().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 @@ -223,15 +223,15 @@ class OfferLetter(models.Model): 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) + total = payslip.sudo()._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) + tot_rule = payslip.sudo()._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.category_id.sudo()._sum_salary_rule_category(localdict, tot_rule - previous_amount) localdict[rule_code] = total rules_dict[rule_code] = rule diff --git a/addons_extensions/offer_letters/models/stages.py b/addons_extensions/offer_letters/models/stages.py new file mode 100644 index 000000000..8699343c0 --- /dev/null +++ b/addons_extensions/offer_letters/models/stages.py @@ -0,0 +1,6 @@ +from odoo import models, fields, api, _ + +class RecruitmentStage(models.Model): + _inherit = 'hr.recruitment.stage' + + request_offer_release = fields.Boolean(string="Request Offer Release") \ No newline at end of file diff --git a/addons_extensions/offer_letters/views/hr_applicant_offer_views.xml b/addons_extensions/offer_letters/views/hr_applicant_offer_views.xml index 34cb2153c..ff04f7765 100644 --- a/addons_extensions/offer_letters/views/hr_applicant_offer_views.xml +++ b/addons_extensions/offer_letters/views/hr_applicant_offer_views.xml @@ -26,7 +26,7 @@