24-06-2025 .1

Merge branch 'develop'
This commit is contained in:
administrator 2025-06-24 18:19:14 +05:30
commit 41c9ebfb50
10 changed files with 526 additions and 0 deletions

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,21 @@
# __manifest__.py
{
'name': 'Employee JOD Form',
'version': '1.0',
'category': 'Human Resources',
'summary': 'Send JOD form to employee after joining',
'description': """
This module is used to send the JOD (Joining Onboarding Document) form
to employees after they have joined the organization.
""",
'author': 'FTPROTECH',
'website': 'https://ftprotech.in',
'depends': ['hr', 'mail','hr_employee_extended','hr_recruitment_extended'],
'data': [
'data/data.xml',
'data/actions.xml',
'data/template.xml',
'views/emp_jod.xml',
],
'license': 'LGPL-3',
}

View File

@ -0,0 +1 @@
from . import emp_jod_controller

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="action_send_jod_to_emp" model="ir.actions.server">
<field name="name">Send JOD to EMPLOYEE</field>
<field name="model_id" ref="hr.model_hr_employee"/>
<field name="groups_id" eval="[(4, ref('hr.group_hr_manager'))]"/>
<field name="binding_model_id" ref="hr.model_hr_employee"/>
<field name="binding_view_types">form</field>
<field name="state">code</field>
<field name="code">action = records.send_jod_form_to_employee()</field>
</record>
<record id="action_download_emp_joining_form" model="ir.actions.report">
<field name="name">Download Joining Form</field>
<field name="model">hr.employee</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">employee_jod.emp_joining_form_template</field>
<field name="report_file">employee_jod.emp_joining_form_template</field>
<field name="binding_model_id" ref="hr.model_hr_employee"/>
<field name="print_report_name">'JOD - %s' % (object.display_name)</field>
<field name="paperformat_id" ref="hr_recruitment_extended.custom_paper_format"/>
<field name="binding_type">report</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<!-- Original job record -->
<record model="hr.job" id="employee_jod_internal_job_id">
<field name="name">Internal Job</field>
<field name="active" eval="False"/>
</record>
<!-- Recruitment stage -->
<record model="hr.recruitment.stage" id="hired_stage8">
<field name="name">IJ</field>
<field name="is_default_field" eval="False"/>
<field name="hired_stage" eval="True"/>
<field name="post_onboarding_form" eval="True"/>
</record>
<!-- Changed ID for the recruitment record -->
<record model="hr.job.recruitment" id="employee_jod_internal_job_recruitment_id">
<field name="recruitment_sequence">IJ001</field>
<field name="job_id" ref="employee_jod_internal_job_id"/>
<field name="recruitment_stage_ids" eval="[(4, ref('hired_stage8'))]"/>
<field name="active" eval="False"/>
</record>
</data>
</odoo>

View File

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="emp_joining_form_template">
<t t-call="web.external_layout">
<main class="page"
style="margin: 0px; padding: 0px; font-size: 16px; font-family: 'Arial', sans-serif;">
<t t-foreach="docs" t-as="doc">
<!-- Candidate Image -->
<t t-if="doc.image_1920">
<div style="text-align: center; margin-bottom: 30px;">
<img t-attf-src="data:image/png;base64,#{doc.image_1920}"
style="width: 280px; height: 400px; object-fit: cover; border: 2px solid #333; border-radius: 8px;"/>
</div>
</t>
<!-- Header -->
<div style="text-align:center; margin-bottom: 40px;">
<h1 style="margin: 0; font-size: 24px;">Welcome to FTPROTECH</h1>
<h2 style="margin: 10px 0 0;">Employee Joining Form</h2>
</div>
<!-- Reusable styles -->
<t t-set="row_style" t-value="'display: flex; margin-bottom: 12px; page-break-inside: avoid;'"/>
<t t-set="label_style" t-value="'width: 35%; font-weight: bold; color: #333;'"/>
<t t-set="value_style" t-value="'width: 65%; color: #000;'"/>
<!-- Personal Info -->
<div style="page-break-inside: avoid;">
<h3 style="margin-top: 30px; color: #005580;">Personal Details</h3>
<div t-att-style="row_style">
<div t-att-style="label_style">Employee Code:</div>
<div t-att-style="value_style">
<t t-esc="doc.employee_id or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Date of Joining:</div>
<div t-att-style="value_style">
<t t-esc="doc.doj or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Full Name:</div>
<div t-att-style="value_style">
<t t-esc="doc.name or doc.name or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Email:</div>
<div t-att-style="value_style">
<t t-esc="doc.work_email or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Mobile No:</div>
<div t-att-style="value_style">
<t t-esc="doc.work_phone or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Alternate Mobile:</div>
<div t-att-style="value_style">
<t t-esc="doc.mobile_phone or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Gender:</div>
<div t-att-style="value_style">
<t t-esc="doc.gender or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Date of Birth:</div>
<div t-att-style="value_style">
<t t-esc="doc.birthday or ''"/>
</div>
</div>
</div>
<!-- Address -->
<div style="page-break-inside: avoid;">
<h3 style="margin-top: 30px; color: #005580;">Address</h3>
<div t-att-style="row_style">
<div t-att-style="label_style">Present Address:</div>
<div t-att-style="value_style">
<t t-esc="doc.private_street or ''"/>
<t t-esc="doc.private_street2 or ''"/>,
<t t-esc="doc.private_city or ''"/>
<t t-esc="doc.private_zip or ''"/>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Permanent Address:</div>
<div t-att-style="value_style">
<t t-esc="doc.permanent_street or ''"/>
<t t-esc="doc.permanent_street2 or ''"/>,
<t t-esc="doc.permanent_city or ''"/>
<t t-esc="doc.permanent_zip or ''"/>
</div>
</div>
</div>
<div t-att-style="row_style">
<div t-att-style="label_style">Marital Status:</div>
<div t-att-style="value_style">
<t t-esc="doc.marital or ''"/>
</div>
</div>
<!-- Section: Family Details -->
<div style="page-break-inside: avoid;">
<t t-if="doc.family_details">
<h3 style="margin-top: 35px; color: #005580;">Family Details</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 15px;">
<thead style="background: #f1f1f1;">
<tr>
<th style="border: 1px solid #ccc; padding: 8px;">Name</th>
<th style="border: 1px solid #ccc; padding: 8px;">Contact</th>
<th style="border: 1px solid #ccc; padding: 8px;">Date of Birth</th>
<th style="border: 1px solid #ccc; padding: 8px;">Location</th>
</tr>
</thead>
<tbody>
<t t-foreach="doc.family_details" t-as="member">
<tr>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="member.name or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="member.contact_no or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="member.dob or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="member.location or ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
<!-- Section: Education -->
<div style="page-break-inside: avoid;">
<t t-if="doc.education_history">
<h3 style="margin-top: 35px; color: #005580;">Education Details</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 15px;">
<thead style="background: #f1f1f1;">
<tr>
<th style="border: 1px solid #ccc; padding: 8px;">Specialization</th>
<th style="border: 1px solid #ccc; padding: 8px;">University</th>
<th style="border: 1px solid #ccc; padding: 8px;">Start Year</th>
<th style="border: 1px solid #ccc; padding: 8px;">End Year</th>
<th style="border: 1px solid #ccc; padding: 8px;">Grade</th>
</tr>
</thead>
<tbody>
<t t-foreach="doc.education_history" t-as="edu">
<tr>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="edu.name or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="edu.university or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="edu.start_year or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="edu.end_year or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="edu.marks_or_grade or ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
<!-- Section: Previous Employer -->
<div style="page-break-inside: avoid;">
<t t-if="doc.employer_history">
<h3 style="margin-top: 35px; color: #005580;">Previous Employment</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 15px;">
<thead style="background: #f1f1f1;">
<tr>
<th style="border: 1px solid #ccc; padding: 8px;">Company</th>
<th style="border: 1px solid #ccc; padding: 8px;">Designation</th>
<th style="border: 1px solid #ccc; padding: 8px;">Joining</th>
<th style="border: 1px solid #ccc; padding: 8px;">Last Working Day</th>
<th style="border: 1px solid #ccc; padding: 8px;">CTC</th>
</tr>
</thead>
<tbody>
<t t-foreach="doc.employer_history" t-as="job">
<tr>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="job.company_name or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="job.designation or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="job.date_of_joining or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="job.last_working_day or ''"/>
</td>
<td style="border: 1px solid #ccc; padding: 8px;">
<t t-esc="job.ctc or ''"/>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
<!-- Section: Bank Details -->
<div style="page-break-inside: avoid;">
<h3 style="margin-top: 35px; color: #005580;">Bank Account Details</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 15px;">
<tbody>
<tr>
<th style="width: 35%; text-align: left;">Name as per Bank</th>
<td>
<t t-if="doc.bank_account_id" t-esc="doc.bank_account_id.full_name or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">Bank Name</th>
<td>
<t t-if="doc.bank_account_id and doc.bank_account_id.bank_id" t-esc="doc.bank_account_id.bank_id.name or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">Branch</th>
<td>
<t t-if="doc.bank_account_id and doc.bank_account_id.bank_id" t-esc="doc.bank_account_id.bank_id.branch or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">Account No</th>
<td>
<t t-if="doc.bank_account_id" t-esc="doc.bank_account_id.acc_number or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">IFSC Code</th>
<td>
<t t-if="doc.bank_account_id and doc.bank_account_id.bank_id" t-esc="doc.bank_account_id.bank_id.bic or ''"/>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Section: Identification -->
<div style="page-break-inside: avoid;">
<h3 style="margin-top: 35px; color: #005580;">Identification</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 15px;">
<tbody>
<tr>
<th style="width: 35%; text-align: left;">PAN No</th>
<td>
<t t-esc="doc.pan_no or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">Aadhar No</th>
<td>
<t t-esc="doc.identification_id or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">PF No</th>
<td>
<t t-esc="doc.previous_company_pf_no or ''"/>
</td>
</tr>
<tr>
<th style="text-align: left;">UAN No</th>
<td>
<t t-esc="doc.previous_company_uan_no or ''"/>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Declaration -->
<div style="margin-top: 40px; font-style: italic; text-align: justify;">
I hereby declare that all the above information is true to the best of my knowledge.
</div>
</t>
</main>
</t>
</template>
</odoo>

View File

@ -0,0 +1 @@
from . import emp_jod

View File

@ -0,0 +1,119 @@
from odoo import fields, api, models, _
from odoo.exceptions import UserError
class HREmployee(models.Model):
_inherit = 'hr.employee'
applicant_id = fields.Many2one("hr.applicant")
def send_jod_form_to_employee(self):
for rec in self:
if not rec.applicant_id:
application = self.env['hr.applicant'].sudo().search([('employee_id','=',rec.id)],limit=1)
if not application:
candidate = self.env['hr.candidate'].sudo().create({
'partner_name': rec.name,
'email_from': rec.work_email,
'partner_phone': rec.work_phone,
'employee_id': rec.id,
})
application = self.env['hr.applicant'].sudo().create({
'candidate_id': candidate.id,
'hr_job_recruitment': self.env.ref('employee_jod.employee_jod_internal_job_recruitment_id').id,
'recruitment_stage_id': self.env.ref('employee_jod.hired_stage8').id,
})
rec.applicant_id = application.id
rec.sudo().applicant_id.send_post_onboarding_form = True
return rec.sudo().applicant_id.send_post_onboarding_form_to_candidate()
class PostOnboardingAttachmentWizard(models.TransientModel):
_inherit = 'post.onboarding.attachment.wizard'
@api.onchange('template_id')
def _onchange_template_id(self):
""" Update the email body and recipients based on the selected template. """
if self.template_id:
record_id = self.env.context.get('active_id')
model = self.env.context.get('active_model')
if model == 'hr.applicant':
applicant = self.env['hr.applicant'].browse(record_id)
else:
if model == 'hr.employee':
applicant = self.env['hr.employee'].browse(record_id).applicant_id
if applicant:
record = self.env[self.template_id.model].sudo().browse(applicant.id)
if not record.exists():
raise UserError("The record does not exist or is not accessible.")
# Fetch email template
email_template = self.env['mail.template'].sudo().browse(self.template_id.id)
if not email_template:
raise UserError("Email template not found.")
self.email_from = self.env.company.email
self.email_to = applicant.email_from
self.email_body = email_template.body_html # Assign the rendered email bodyc
self.email_subject = email_template.subject
def action_confirm(self):
for rec in self:
self.ensure_one()
context = self.env.context
active_id = context.get('active_id')
model = context.get('active_model')
if model == 'hr.applicant':
applicant = self.env['hr.applicant'].browse(active_id)
else:
if model == 'hr.employee':
applicant = self.env['hr.employee'].browse(active_id).applicant_id
applicant.recruitment_attachments = [(4, attachment.id) for attachment in rec.req_attachment_ids]
template = rec.template_id
personal_docs = rec.req_attachment_ids.filtered(lambda a: a.attachment_type == 'personal').mapped('name')
education_docs = rec.req_attachment_ids.filtered(lambda a: a.attachment_type == 'education').mapped('name')
previous_employer_docs = rec.req_attachment_ids.filtered(
lambda a: a.attachment_type == 'previous_employer').mapped('name')
other_docs = rec.req_attachment_ids.filtered(lambda a: a.attachment_type == 'others').mapped('name')
# Prepare context for the template
email_context = {
'personal_docs': personal_docs,
'education_docs': education_docs,
'previous_employer_docs': previous_employer_docs,
'other_docs': other_docs,
}
email_values = {
'email_from': rec.email_from,
'email_to': rec.email_to,
'email_cc': rec.email_cc,
'subject': rec.email_subject,
'attachment_ids': [(6, 0, rec.attachment_ids.ids)],
}
# Use 'with_context' to override the email template fields dynamically
template.sudo().with_context(default_body_html=rec.email_body,
**email_context).send_mail(applicant.id, email_values=email_values,
force_send=True)
if rec.is_pre_onboarding_attachment_request:
applicant.doc_requests_form_status = 'email_sent_to_candidate'
else:
applicant.post_onboarding_form_status = 'email_sent_to_candidate'
return {'type': 'ir.actions.act_window_close'}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="hr_employee_view_form_applicant_id" model="ir.ui.view">
<field name="name">hr.employee.view.form.applicant.id</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
<xpath expr="//label[@for='user_id']" position="before">
<field name="applicant_id" string="Application ID" />
</xpath>
</field>
</record>
</odoo>