mirror of
https://github.com/bringout/oca-payroll.git
synced 2026-04-19 07:22:00 +02:00
Initial commit: OCA Payroll packages (5 packages)
This commit is contained in:
commit
d19274f581
407 changed files with 214057 additions and 0 deletions
|
|
@ -0,0 +1 @@
|
|||
from . import payroll_management_wizard
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
import base64
|
||||
from base64 import b64decode
|
||||
|
||||
from pypdf import PdfReader, PdfWriter
|
||||
|
||||
from odoo import _, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class PayrollManagamentWizard(models.TransientModel):
|
||||
_name = "payroll.management.wizard"
|
||||
_description = "Payroll Management"
|
||||
|
||||
subject = fields.Char(
|
||||
help="Enter the title of the payroll whether it is the month, week, day, etc."
|
||||
)
|
||||
payrolls = fields.Many2many(
|
||||
"ir.attachment",
|
||||
"payrol_rel",
|
||||
"doc_id",
|
||||
"attach_id3",
|
||||
copy=False,
|
||||
)
|
||||
|
||||
def send_payrolls(self):
|
||||
not_found = set()
|
||||
self.merge_pdfs()
|
||||
reader = PdfReader("/tmp/merged-pdf.pdf")
|
||||
employees = set()
|
||||
|
||||
# Validate if company have country
|
||||
if not self.env.company.country_id:
|
||||
raise UserError(_("You must to filled country field of company"))
|
||||
|
||||
# Find all IDs of the employees
|
||||
for page in reader.pages:
|
||||
for value in page.extract_text().split():
|
||||
if self.validate_id(value) and value != self.env.company.vat:
|
||||
employee = self.env["hr.employee"].search(
|
||||
[("identification_id", "=", value)]
|
||||
)
|
||||
if employee:
|
||||
employees.add(employee)
|
||||
else:
|
||||
not_found.add(value)
|
||||
break
|
||||
|
||||
for employee in list(employees):
|
||||
pdfWriter = PdfWriter()
|
||||
for page in reader.pages:
|
||||
if employee.identification_id in page.extract_text():
|
||||
# Save pdf with payrolls of employee
|
||||
pdfWriter.add_page(page)
|
||||
|
||||
path = "/tmp/" + _("Payroll ") + employee.name + ".pdf"
|
||||
|
||||
# Encrypt the payroll file with the identification identifier of the employee
|
||||
pdfWriter.encrypt(employee.identification_id, algorithm="AES-256")
|
||||
|
||||
f = open(path, "wb")
|
||||
pdfWriter.write(f)
|
||||
f.close()
|
||||
|
||||
# Send payroll to the employee
|
||||
self.send_mail(employee, path)
|
||||
|
||||
if not_found:
|
||||
return {
|
||||
"type": "ir.actions.client",
|
||||
"tag": "display_notification",
|
||||
"params": {
|
||||
"title": _("Employees not found"),
|
||||
"message": _("IDs whose employee has not been found: ")
|
||||
+ ", ".join(list(not_found)),
|
||||
"sticky": True,
|
||||
"type": "warning",
|
||||
"next": {
|
||||
"name": _("Payrolls sent"),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "hr.employee",
|
||||
"views": [
|
||||
(
|
||||
self.env.ref("hr.hr_employee_public_view_kanban").id,
|
||||
"list",
|
||||
)
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
"type": "ir.actions.client",
|
||||
"tag": "display_notification",
|
||||
"params": {
|
||||
"title": _("Payrolls sent"),
|
||||
"message": _("Payrolls sent to employees correctly"),
|
||||
"sticky": False,
|
||||
"type": "success",
|
||||
"next": {
|
||||
"name": _("Payrolls sent"),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "hr.employee",
|
||||
"views": [
|
||||
(self.env.ref("hr.hr_employee_public_view_kanban").id, "list")
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def merge_pdfs(self):
|
||||
# Merge the pdfs together
|
||||
pdfs = []
|
||||
for file in self.payrolls:
|
||||
b64 = file.datas
|
||||
btes = b64decode(b64, validate=True)
|
||||
if btes[0:4] != b"%PDF":
|
||||
raise ValidationError(_("Missing pdf file signature"))
|
||||
f = open("/tmp/" + file.name, "wb")
|
||||
f.write(btes)
|
||||
f.close()
|
||||
pdfs.append(f.name)
|
||||
|
||||
merger = PdfWriter()
|
||||
|
||||
for pdf in pdfs:
|
||||
merger.append(pdf)
|
||||
|
||||
merger.write("/tmp/merged-pdf.pdf")
|
||||
merger.close()
|
||||
|
||||
def send_mail(self, employee, path):
|
||||
# Open Payrolls of employee and encode content
|
||||
with open(path, "rb") as pdf_file:
|
||||
encoded_string = base64.b64encode(pdf_file.read())
|
||||
|
||||
# Attach file to email
|
||||
ir_values = {
|
||||
"name": _("Payroll") + "_" + self.subject + "_" + employee.name,
|
||||
"type": "binary",
|
||||
"datas": encoded_string,
|
||||
"store_fname": encoded_string,
|
||||
"res_model": "hr.employee",
|
||||
"res_id": employee.id,
|
||||
}
|
||||
|
||||
# Save payroll attachment to all employee payrolls attachments
|
||||
self.env["ir.attachment.payroll.custom"].create(
|
||||
{
|
||||
"attachment_id": self.env["ir.attachment"].create(ir_values).id,
|
||||
"employee": employee.name,
|
||||
"subject": self.subject,
|
||||
"identification_id": employee.identification_id,
|
||||
}
|
||||
)
|
||||
|
||||
# Send mail
|
||||
mail_template = self.env.ref(
|
||||
"hr_payroll_document.payroll_employee_email_template"
|
||||
)
|
||||
data_id = [(6, 0, [self.env["ir.attachment"].create(ir_values).id])]
|
||||
mail_template.attachment_ids = data_id
|
||||
mail_template.with_context(**{"subject": self.subject}).send_mail(
|
||||
employee.id, force_send=True
|
||||
)
|
||||
|
||||
def validate_id(self, number):
|
||||
return self.env["res.partner"].simple_vat_check(
|
||||
self.env.company.country_id.code, number
|
||||
)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="payrolls_management_wizard_form" model="ir.ui.view">
|
||||
<field name="name">payroll.management.wizard.form</field>
|
||||
<field name="model">payroll.management.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="subject" required="1" />
|
||||
</group>
|
||||
<field name="payrolls" widget="many2many_binary" />
|
||||
<footer>
|
||||
<button
|
||||
string="Send"
|
||||
name="send_payrolls"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button
|
||||
string="Close"
|
||||
class="btn btn-secondary"
|
||||
special="cancel"
|
||||
/>
|
||||
</footer>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="payrolls_management_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Payrolls Management</field>
|
||||
<field name="res_model">payroll.management.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="payrolls_management_wizard_menu_action"
|
||||
action="payrolls_management_wizard_action"
|
||||
parent="hr.menu_hr_root"
|
||||
/>
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue