From 78d5dc53ea1c6d6d3331d6852a990fe86a48a9ef Mon Sep 17 00:00:00 2001 From: vidhubk Date: Thu, 5 Mar 2026 17:08:54 +0530 Subject: [PATCH] Theme Files Added --- addons/accounting_community/__init__.py | 1 + addons/accounting_community/__manifest__.py | 27 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 151 bytes .../views/account_menus.xml | 36 +++ .../views/account_move_views.xml | 20 ++ .../views/account_views.xml | 4 + addons/c2c_payroll/__init__.py | 3 + addons/c2c_payroll/__manifest__.py | 38 +++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 194 bytes addons/c2c_payroll/models/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 253 bytes .../contract_extension.cpython-310.pyc | Bin 0 -> 924 bytes .../__pycache__/payslip.cpython-310.pyc | Bin 0 -> 7296 bytes .../salary_structure.cpython-310.pyc | Bin 0 -> 1960 bytes .../c2c_payroll/models/contract_extension.py | 23 ++ addons/c2c_payroll/models/payslip.py | 299 ++++++++++++++++++ addons/c2c_payroll/models/salary_structure.py | 49 +++ addons/c2c_payroll/reports/payslip_report.xml | 15 + .../reports/payslip_report_template.xml | 184 +++++++++++ .../c2c_payroll/security/ir.model.access.csv | 7 + addons/c2c_payroll/security/security.xml | 43 +++ addons/c2c_payroll/views/contract_views.xml | 27 ++ addons/c2c_payroll/views/menu.xml | 35 ++ addons/c2c_payroll/views/payslip_views.xml | 191 +++++++++++ .../views/salary_structure_views.xml | 76 +++++ addons/c2c_payroll/wizard/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 189 bytes .../payslip_generate_wizard.cpython-310.pyc | Bin 0 -> 2081 bytes .../wizard/payslip_generate_wizard.py | 72 +++++ addons/employee_documents/__init__.py | 1 + addons/employee_documents/__manifest__.py | 22 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 172 bytes addons/employee_documents/models/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 224 bytes .../employee_document.cpython-310.pyc | Bin 0 -> 976 bytes .../__pycache__/hr_employee.cpython-310.pyc | Bin 0 -> 500 bytes .../models/employee_document.py | 19 ++ .../employee_documents/models/hr_employee.py | 7 + .../security/ir.model.access.csv | 3 + .../employee_documents/security/security.xml | 10 + .../views/employee_document_views.xml | 78 +++++ .../views/hr_employee_views.xml | 23 ++ docker-compose.yml | 33 ++ 43 files changed, 1354 insertions(+) create mode 100644 addons/accounting_community/__init__.py create mode 100644 addons/accounting_community/__manifest__.py create mode 100644 addons/accounting_community/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/accounting_community/views/account_menus.xml create mode 100644 addons/accounting_community/views/account_move_views.xml create mode 100644 addons/accounting_community/views/account_views.xml create mode 100644 addons/c2c_payroll/__init__.py create mode 100644 addons/c2c_payroll/__manifest__.py create mode 100644 addons/c2c_payroll/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/c2c_payroll/models/__init__.py create mode 100644 addons/c2c_payroll/models/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc create mode 100644 addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc create mode 100644 addons/c2c_payroll/models/__pycache__/salary_structure.cpython-310.pyc create mode 100644 addons/c2c_payroll/models/contract_extension.py create mode 100644 addons/c2c_payroll/models/payslip.py create mode 100644 addons/c2c_payroll/models/salary_structure.py create mode 100644 addons/c2c_payroll/reports/payslip_report.xml create mode 100644 addons/c2c_payroll/reports/payslip_report_template.xml create mode 100644 addons/c2c_payroll/security/ir.model.access.csv create mode 100644 addons/c2c_payroll/security/security.xml create mode 100644 addons/c2c_payroll/views/contract_views.xml create mode 100644 addons/c2c_payroll/views/menu.xml create mode 100644 addons/c2c_payroll/views/payslip_views.xml create mode 100644 addons/c2c_payroll/views/salary_structure_views.xml create mode 100644 addons/c2c_payroll/wizard/__init__.py create mode 100644 addons/c2c_payroll/wizard/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/c2c_payroll/wizard/__pycache__/payslip_generate_wizard.cpython-310.pyc create mode 100644 addons/c2c_payroll/wizard/payslip_generate_wizard.py create mode 100644 addons/employee_documents/__init__.py create mode 100644 addons/employee_documents/__manifest__.py create mode 100644 addons/employee_documents/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/employee_documents/models/__init__.py create mode 100644 addons/employee_documents/models/__pycache__/__init__.cpython-310.pyc create mode 100644 addons/employee_documents/models/__pycache__/employee_document.cpython-310.pyc create mode 100644 addons/employee_documents/models/__pycache__/hr_employee.cpython-310.pyc create mode 100644 addons/employee_documents/models/employee_document.py create mode 100644 addons/employee_documents/models/hr_employee.py create mode 100644 addons/employee_documents/security/ir.model.access.csv create mode 100644 addons/employee_documents/security/security.xml create mode 100644 addons/employee_documents/views/employee_document_views.xml create mode 100644 addons/employee_documents/views/hr_employee_views.xml create mode 100644 docker-compose.yml diff --git a/addons/accounting_community/__init__.py b/addons/accounting_community/__init__.py new file mode 100644 index 0000000..737b477 --- /dev/null +++ b/addons/accounting_community/__init__.py @@ -0,0 +1 @@ +# from . import models diff --git a/addons/accounting_community/__manifest__.py b/addons/accounting_community/__manifest__.py new file mode 100644 index 0000000..327d927 --- /dev/null +++ b/addons/accounting_community/__manifest__.py @@ -0,0 +1,27 @@ +{ + 'name': 'Accounting Community', + 'version': '17.0.1.0.0', + 'summary': 'Full Accounting Features for Community Edition', + 'description': """ + Accounting Community + ==================== + This module unlocks the Full Accounting features in Odoo Community Edition. + + Features: + - Full Accounting Menu + - Journal Entries + - Journal Items + - General Ledger (Basic View) + - Partner Ledger (Basic View) + """, + 'category': 'Accounting/Accounting', + 'author': 'Antigravity', + 'depends': ['account'], + 'data': [ + 'views/account_menus.xml', + 'views/account_move_views.xml', + ], + 'installable': True, + 'application': False, + 'license': 'LGPL-3', +} diff --git a/addons/accounting_community/__pycache__/__init__.cpython-310.pyc b/addons/accounting_community/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45e16bf450426a5aa8ccf58523268a5b48fe9a6f GIT binary patch literal 151 zcmd1j<>g`kf~gNWGbMoZV-N=!FakLaKwQiMBvKfH88jLFRx%WUgb~CqEB)NO68+SQ zlA=W2#FUi$ykh;tc_`t0_pg8y@JYH95%W6DWy57 Nb|5p0nScZf0|3-KBufAQ literal 0 HcmV?d00001 diff --git a/addons/accounting_community/views/account_menus.xml b/addons/accounting_community/views/account_menus.xml new file mode 100644 index 0000000..3e79dfa --- /dev/null +++ b/addons/accounting_community/views/account_menus.xml @@ -0,0 +1,36 @@ + + + + + Accounting + + + + + + + + + + + + + + + + + diff --git a/addons/accounting_community/views/account_move_views.xml b/addons/accounting_community/views/account_move_views.xml new file mode 100644 index 0000000..6b35cf6 --- /dev/null +++ b/addons/accounting_community/views/account_move_views.xml @@ -0,0 +1,20 @@ + + + + + Journal Entries + account.move + tree,kanban,form + + + {'default_move_type': 'entry', 'search_default_misc_filter':1, 'view_no_maturity': True} + +

+ Create a journal entry +

+ A journal entry consists of several journal items, each of + which is either a debit or a credit. +

+
+
+
diff --git a/addons/accounting_community/views/account_views.xml b/addons/accounting_community/views/account_views.xml new file mode 100644 index 0000000..49431e3 --- /dev/null +++ b/addons/accounting_community/views/account_views.xml @@ -0,0 +1,4 @@ + + + + diff --git a/addons/c2c_payroll/__init__.py b/addons/c2c_payroll/__init__.py new file mode 100644 index 0000000..408a600 --- /dev/null +++ b/addons/c2c_payroll/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from . import wizard diff --git a/addons/c2c_payroll/__manifest__.py b/addons/c2c_payroll/__manifest__.py new file mode 100644 index 0000000..36516ce --- /dev/null +++ b/addons/c2c_payroll/__manifest__.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'C2C Payroll', + 'version': '17.0.1.0.0', + 'category': 'Human Resources/Payroll', + 'summary': 'Enterprise-like Payroll for Odoo Community', + 'description': """ + Complete payroll solution for Odoo 17 Community Edition. + Features: + - Salary Structures (Basic, HRA, Allowances) + - Automatic PF, ESI, Professional Tax deductions + - Payslip generation with auto-computed net salary + - Accounting journal entry on payslip confirmation + - QWeb PDF payslip report + - Multi-company support + """, + 'author': 'C2C', + 'website': '', + 'license': 'LGPL-3', + 'depends': [ + 'hr', + 'hr_contract', + 'account', + ], + 'data': [ + 'security/security.xml', + 'security/ir.model.access.csv', + 'views/salary_structure_views.xml', + 'views/payslip_views.xml', + 'views/contract_views.xml', + 'views/menu.xml', + 'reports/payslip_report.xml', + 'reports/payslip_report_template.xml', + ], + 'installable': True, + 'application': True, + 'auto_install': False, +} diff --git a/addons/c2c_payroll/__pycache__/__init__.cpython-310.pyc b/addons/c2c_payroll/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38f60c0d21be2f1e07ae82f357edb4b40640235a GIT binary patch literal 194 zcmd1j<>g`k0`2GXGF^f6V-N=!FabFZKwK;XBvKes7;_kM8KW2(L2M=V7P5Jef-*jBWbtenDI*jTBf$R|kSZX1Mv0*Qsyz)IfBq|cSMbz%7msXV00 zNc?&8H6KXZ?JJ{__ivBXZ*}-zoQ5-3#L2Zh1*WzOKDU!P$^_+trzq)2&Sf52vr6KuYxT;*`_aui{ vBt=mlw6!T_Y2J;ZIHnNfkgN+?D&?auN*%{}*?f>W1@~D$mFp!fw6KFG$a+1H literal 0 HcmV?d00001 diff --git a/addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc b/addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2127d4c5f7e8445dc30ef76beef66ef465a8d927 GIT binary patch literal 924 zcmZ`&&2AGh5cdA$r)g4(T5KEL2#&MgKk^_VGz`cYfe@l^1R@dMMqi^ehImHCoj>SH#-Z!Zb0NXF?oxq}CiCj;(Lr#G(_Eks zBn^P1Ap~h8;@gf74KZ}SM`;&v54zAp6sCPdJJ5$67{D%C2Mr#=2=*Gh3s10!efRW4 z6;|`ip59qem|PY0?m{QoT3a7xZ?eR2$@MBRR#%y=w5a!IjfT!Pnq;ln_|VD-pmU{Z z$yY|^CC${btSq;fBk}h}*SxrK@j}S59-e7s3~i&-udbBklHN4BHamTJa&vKKir}b|Eyq)apwPqOf#Y74Ue5a_=n+wTjwBZm_bJ zgJc|OPq*uVnDa_n-9=RIoz6aPWti5JhYa4ZDdqoRFUCXHXRP2$!I&E`hEH8dzaKL8 zx#Dtd>9f4R!gH%bUq%0%7ppg_5bmJmfNj`iIk?VLDsJ7dVTrXKuJ=JHDR|*V<(xJ5 zY*=x7!sJ`{C(#F(q7i?OCd zo-*?sMW4h$9L7NybnoLhT(1w#M#KpMdVg*Vy7uEQui0hpD{%_2WwY9rLZ|}ct PS$h}wbUyEX@GSZVy)6%l literal 0 HcmV?d00001 diff --git a/addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc b/addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40aa21fc532e84c4c95d140cbf5896c26a3beb1e GIT binary patch literal 7296 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 Z>c7Ck=ij!3iB>YdqH|noiL}V9^#TXb7%Bh& literal 0 HcmV?d00001 diff --git a/addons/c2c_payroll/models/contract_extension.py b/addons/c2c_payroll/models/contract_extension.py new file mode 100644 index 0000000..77a4716 --- /dev/null +++ b/addons/c2c_payroll/models/contract_extension.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from odoo import fields, models + + +class ContractExtension(models.Model): + _inherit = 'hr.contract' + + salary_structure_id = fields.Many2one( + 'c2c.salary.structure', string='Salary Structure', + help='Salary structure used for payslip computation.', + ) + gross_salary = fields.Float( + string='Gross Salary', + help='Total gross salary (CTC) before deductions.', + ) + pf_applicable = fields.Boolean( + string='PF Applicable', default=True, + help='Whether Provident Fund deduction applies to this contract.', + ) + esi_applicable = fields.Boolean( + string='ESI Applicable', default=False, + help='Whether ESI deduction applies to this contract.', + ) diff --git a/addons/c2c_payroll/models/payslip.py b/addons/c2c_payroll/models/payslip.py new file mode 100644 index 0000000..47272d7 --- /dev/null +++ b/addons/c2c_payroll/models/payslip.py @@ -0,0 +1,299 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class Payslip(models.Model): + _name = 'c2c.payslip' + _description = 'Employee Payslip' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _order = 'date_from desc, id desc' + _rec_name = 'display_name' + + # ------------------------------------------------------------------ + # Core fields + # ------------------------------------------------------------------ + employee_id = fields.Many2one( + 'hr.employee', string='Employee', required=True, + tracking=True, + ) + contract_id = fields.Many2one( + 'hr.contract', string='Contract', required=True, + tracking=True, + domain="[('employee_id', '=', employee_id), ('state', '=', 'open')]", + ) + date_from = fields.Date( + string='Period From', required=True, + ) + date_to = fields.Date( + string='Period To', required=True, + ) + company_id = fields.Many2one( + 'res.company', string='Company', required=True, + default=lambda self: self.env.company, + ) + + # ------------------------------------------------------------------ + # Earnings (computed & stored) + # ------------------------------------------------------------------ + gross_salary = fields.Float( + string='Gross Salary', compute='_compute_salary', store=True, + ) + basic = fields.Float( + string='Basic', compute='_compute_salary', store=True, + ) + hra = fields.Float( + string='HRA', compute='_compute_salary', store=True, + ) + allowances = fields.Float( + string='Allowances', compute='_compute_salary', store=True, + ) + + # ------------------------------------------------------------------ + # Deductions (computed & stored) + # ------------------------------------------------------------------ + pf_deduction = fields.Float( + string='PF Deduction', compute='_compute_salary', store=True, + ) + esi_deduction = fields.Float( + string='ESI Deduction', compute='_compute_salary', store=True, + ) + professional_tax = fields.Float( + string='Professional Tax', compute='_compute_salary', store=True, + ) + total_deductions = fields.Float( + string='Total Deductions', compute='_compute_salary', store=True, + ) + + # ------------------------------------------------------------------ + # Net + # ------------------------------------------------------------------ + net_salary = fields.Float( + string='Net Salary', compute='_compute_salary', store=True, + ) + + # ------------------------------------------------------------------ + # State & Accounting + # ------------------------------------------------------------------ + state = fields.Selection([ + ('draft', 'Draft'), + ('confirmed', 'Confirmed'), + ('paid', 'Paid'), + ], string='Status', default='draft', tracking=True, copy=False) + + journal_entry_id = fields.Many2one( + 'account.move', string='Journal Entry', readonly=True, copy=False, + ) + journal_entry_count = fields.Integer( + compute='_compute_journal_entry_count', + ) + + # ------------------------------------------------------------------ + # Display name + # ------------------------------------------------------------------ + display_name = fields.Char(compute='_compute_display_name', store=True) + + @api.depends('employee_id', 'date_from', 'date_to') + def _compute_display_name(self): + for rec in self: + emp_name = rec.employee_id.name or 'New' + date_from = rec.date_from or '' + date_to = rec.date_to or '' + rec.display_name = '%s (%s - %s)' % (emp_name, date_from, date_to) + + # ------------------------------------------------------------------ + # Computed salary + # ------------------------------------------------------------------ + @api.depends( + 'contract_id', + 'contract_id.gross_salary', + 'contract_id.salary_structure_id', + 'contract_id.salary_structure_id.basic_percentage', + 'contract_id.salary_structure_id.hra_percentage', + 'contract_id.salary_structure_id.allowance_percentage', + 'contract_id.salary_structure_id.pf_percentage', + 'contract_id.salary_structure_id.esi_percentage', + 'contract_id.salary_structure_id.professional_tax_fixed', + 'contract_id.pf_applicable', + 'contract_id.esi_applicable', + ) + def _compute_salary(self): + for rec in self: + contract = rec.contract_id + structure = contract.salary_structure_id if contract else False + + if not contract or not structure: + rec.gross_salary = 0.0 + rec.basic = 0.0 + rec.hra = 0.0 + rec.allowances = 0.0 + rec.pf_deduction = 0.0 + rec.esi_deduction = 0.0 + rec.professional_tax = 0.0 + rec.total_deductions = 0.0 + rec.net_salary = 0.0 + continue + + gross = contract.gross_salary + rec.gross_salary = gross + + # Earnings + rec.basic = gross * structure.basic_percentage / 100.0 + rec.hra = gross * structure.hra_percentage / 100.0 + rec.allowances = gross * structure.allowance_percentage / 100.0 + + # Deductions + pf = (rec.basic * structure.pf_percentage / 100.0) if contract.pf_applicable else 0.0 + esi = (gross * structure.esi_percentage / 100.0) if contract.esi_applicable else 0.0 + pt = structure.professional_tax_fixed + + rec.pf_deduction = pf + rec.esi_deduction = esi + rec.professional_tax = pt + rec.total_deductions = pf + esi + pt + rec.net_salary = gross - rec.total_deductions + + # ------------------------------------------------------------------ + # Journal entry count + # ------------------------------------------------------------------ + @api.depends('journal_entry_id') + def _compute_journal_entry_count(self): + for rec in self: + rec.journal_entry_count = 1 if rec.journal_entry_id else 0 + + # ------------------------------------------------------------------ + # Onchange helpers + # ------------------------------------------------------------------ + @api.onchange('employee_id') + def _onchange_employee_id(self): + """Auto-fill contract when employee changes.""" + if self.employee_id: + contract = self.env['hr.contract'].search([ + ('employee_id', '=', self.employee_id.id), + ('state', '=', 'open'), + ('company_id', '=', self.env.company.id), + ], limit=1) + self.contract_id = contract + else: + self.contract_id = False + + # ------------------------------------------------------------------ + # Constraints + # ------------------------------------------------------------------ + @api.constrains('date_from', 'date_to') + def _check_dates(self): + for rec in self: + if rec.date_from and rec.date_to and rec.date_from > rec.date_to: + raise ValidationError('Period From cannot be after Period To.') + + # ------------------------------------------------------------------ + # Actions + # ------------------------------------------------------------------ + def action_confirm(self): + """Confirm the payslip and create an accounting journal entry.""" + for rec in self: + if rec.state != 'draft': + raise UserError('Only draft payslips can be confirmed.') + if not rec.contract_id or not rec.contract_id.salary_structure_id: + raise UserError( + 'Please set a salary structure on the contract before confirming.' + ) + if rec.net_salary <= 0: + raise UserError('Net salary must be greater than zero to confirm.') + + # Get accounts from system parameters (company-specific) + ICP = self.env['ir.config_parameter'].sudo() + expense_account_id = int( + ICP.get_param('c2c_payroll.salary_expense_account_id', default=0) + ) + payable_account_id = int( + ICP.get_param('c2c_payroll.salary_payable_account_id', default=0) + ) + + if not expense_account_id or not payable_account_id: + raise UserError( + 'Please configure Salary Expense and Payable accounts in ' + 'Settings → Technical → Parameters → System Parameters.\n\n' + 'Keys:\n' + ' • c2c_payroll.salary_expense_account_id\n' + ' • c2c_payroll.salary_payable_account_id' + ) + + # Validate accounts exist + expense_account = self.env['account.account'].browse(expense_account_id) + payable_account = self.env['account.account'].browse(payable_account_id) + if not expense_account.exists() or not payable_account.exists(): + raise UserError( + 'Configured salary accounts do not exist. ' + 'Please verify the system parameter values.' + ) + + journal = self.env['account.journal'].search([ + ('type', '=', 'general'), + ('company_id', '=', rec.company_id.id), + ], limit=1) + if not journal: + raise UserError( + 'No general journal found for company %s.' % rec.company_id.name + ) + + move_vals = { + 'journal_id': journal.id, + 'date': rec.date_to, + 'ref': 'Payslip: %s' % rec.display_name, + 'company_id': rec.company_id.id, + 'line_ids': [ + (0, 0, { + 'name': 'Salary Expense - %s' % rec.employee_id.name, + 'account_id': expense_account_id, + 'debit': rec.net_salary, + 'credit': 0.0, + }), + (0, 0, { + 'name': 'Employee Payable - %s' % rec.employee_id.name, + 'account_id': payable_account_id, + 'debit': 0.0, + 'credit': rec.net_salary, + }), + ], + } + move = self.env['account.move'].create(move_vals) + rec.write({ + 'state': 'confirmed', + 'journal_entry_id': move.id, + }) + + def action_mark_paid(self): + """Mark confirming payslip as paid.""" + for rec in self: + if rec.state != 'confirmed': + raise UserError('Only confirmed payslips can be marked as paid.') + rec.write({'state': 'paid'}) + + def action_reset_to_draft(self): + """Reset to draft (deletes journal entry if unposted).""" + for rec in self: + if rec.state == 'paid': + raise UserError('Paid payslips cannot be reset to draft.') + if rec.journal_entry_id: + if rec.journal_entry_id.state == 'posted': + raise UserError( + 'Cannot reset: the journal entry is already posted. ' + 'Please cancel it first.' + ) + rec.journal_entry_id.unlink() + rec.write({'state': 'draft', 'journal_entry_id': False}) + + def action_open_journal_entry(self): + """Smart button to open the linked journal entry.""" + self.ensure_one() + if not self.journal_entry_id: + raise UserError('No journal entry linked to this payslip.') + return { + 'type': 'ir.actions.act_window', + 'name': 'Journal Entry', + 'res_model': 'account.move', + 'res_id': self.journal_entry_id.id, + 'view_mode': 'form', + 'target': 'current', + } diff --git a/addons/c2c_payroll/models/salary_structure.py b/addons/c2c_payroll/models/salary_structure.py new file mode 100644 index 0000000..144c1cf --- /dev/null +++ b/addons/c2c_payroll/models/salary_structure.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models + + +class SalaryStructure(models.Model): + _name = 'c2c.salary.structure' + _description = 'Salary Structure' + _rec_name = 'name' + + name = fields.Char(string='Name', required=True) + basic_percentage = fields.Float( + string='Basic (%)', required=True, default=50.0, + help='Percentage of gross salary allocated as Basic.', + ) + hra_percentage = fields.Float( + string='HRA (%)', required=True, default=20.0, + help='Percentage of gross salary allocated as HRA.', + ) + allowance_percentage = fields.Float( + string='Allowances (%)', required=True, default=30.0, + help='Percentage of gross salary allocated as Allowances.', + ) + pf_percentage = fields.Float( + string='PF (%)', required=True, default=12.0, + help='Provident Fund deduction percentage on Basic salary.', + ) + esi_percentage = fields.Float( + string='ESI (%)', required=True, default=1.75, + help='ESI deduction percentage on Gross salary.', + ) + professional_tax_fixed = fields.Float( + string='Professional Tax (Fixed)', default=200.0, + help='Fixed professional tax amount deducted per month.', + ) + company_id = fields.Many2one( + 'res.company', string='Company', required=True, + default=lambda self: self.env.company, + ) + active = fields.Boolean(default=True) + + @api.constrains('basic_percentage', 'hra_percentage', 'allowance_percentage') + def _check_percentages(self): + for rec in self: + total = rec.basic_percentage + rec.hra_percentage + rec.allowance_percentage + if abs(total - 100.0) > 0.01: + raise models.ValidationError( + 'Basic + HRA + Allowances percentages must equal 100%%. ' + 'Current total: %.2f%%' % total + ) diff --git a/addons/c2c_payroll/reports/payslip_report.xml b/addons/c2c_payroll/reports/payslip_report.xml new file mode 100644 index 0000000..6e7e858 --- /dev/null +++ b/addons/c2c_payroll/reports/payslip_report.xml @@ -0,0 +1,15 @@ + + + + + + + Payslip + c2c.payslip + qweb-pdf + c2c_payroll.report_payslip_document + c2c_payroll.report_payslip_document + + report + + diff --git a/addons/c2c_payroll/reports/payslip_report_template.xml b/addons/c2c_payroll/reports/payslip_report_template.xml new file mode 100644 index 0000000..64a7b28 --- /dev/null +++ b/addons/c2c_payroll/reports/payslip_report_template.xml @@ -0,0 +1,184 @@ + + + + diff --git a/addons/c2c_payroll/security/ir.model.access.csv b/addons/c2c_payroll/security/ir.model.access.csv new file mode 100644 index 0000000..fe757a0 --- /dev/null +++ b/addons/c2c_payroll/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_salary_structure_user,c2c.salary.structure.user,model_c2c_salary_structure,c2c_payroll.group_payroll_user,1,0,0,0 +access_salary_structure_manager,c2c.salary.structure.manager,model_c2c_salary_structure,c2c_payroll.group_payroll_manager,1,1,1,1 +access_payslip_user,c2c.payslip.user,model_c2c_payslip,c2c_payroll.group_payroll_user,1,1,1,0 +access_payslip_manager,c2c.payslip.manager,model_c2c_payslip,c2c_payroll.group_payroll_manager,1,1,1,1 +access_payslip_wizard_user,c2c.payslip.generate.wizard.user,model_c2c_payslip_generate_wizard,c2c_payroll.group_payroll_user,1,1,1,1 +access_payslip_wizard_manager,c2c.payslip.generate.wizard.manager,model_c2c_payslip_generate_wizard,c2c_payroll.group_payroll_manager,1,1,1,1 diff --git a/addons/c2c_payroll/security/security.xml b/addons/c2c_payroll/security/security.xml new file mode 100644 index 0000000..f1ca0c6 --- /dev/null +++ b/addons/c2c_payroll/security/security.xml @@ -0,0 +1,43 @@ + + + + + + + C2C Payroll + Access rights for C2C Payroll module. + 30 + + + + + + + Payroll User + + + + + + Payroll Manager + + + + + + + + + Payslip: multi-company + + [('company_id', 'in', company_ids)] + + + + + Salary Structure: multi-company + + [('company_id', 'in', company_ids)] + + + diff --git a/addons/c2c_payroll/views/contract_views.xml b/addons/c2c_payroll/views/contract_views.xml new file mode 100644 index 0000000..513360f --- /dev/null +++ b/addons/c2c_payroll/views/contract_views.xml @@ -0,0 +1,27 @@ + + + + + + + hr.contract.form.inherit.c2c.payroll + hr.contract + + + + + + + + + + + + + + + + + + + diff --git a/addons/c2c_payroll/views/menu.xml b/addons/c2c_payroll/views/menu.xml new file mode 100644 index 0000000..51da1d1 --- /dev/null +++ b/addons/c2c_payroll/views/menu.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/addons/c2c_payroll/views/payslip_views.xml b/addons/c2c_payroll/views/payslip_views.xml new file mode 100644 index 0000000..9399df4 --- /dev/null +++ b/addons/c2c_payroll/views/payslip_views.xml @@ -0,0 +1,191 @@ + + + + + + + c2c.payslip.tree + c2c.payslip + + + + + + + + + + + + + + + + + + + c2c.payslip.form + c2c.payslip + +
+
+
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + + + + c2c.payslip.search + c2c.payslip + + + + + + + + + + + + + + + + + + + Payslips + c2c.payslip + tree,form + +

+ No payslips yet +

+

+ Create payslips individually or use the "Generate Payslips" wizard + to create them in bulk for all employees with active contracts. +

+
+
+ + + + + + c2c.payslip.generate.wizard.form + c2c.payslip.generate.wizard + +
+ + + + + +
+
+
+
+
+ + + Generate Payslips + c2c.payslip.generate.wizard + form + new + +
diff --git a/addons/c2c_payroll/views/salary_structure_views.xml b/addons/c2c_payroll/views/salary_structure_views.xml new file mode 100644 index 0000000..b1b9452 --- /dev/null +++ b/addons/c2c_payroll/views/salary_structure_views.xml @@ -0,0 +1,76 @@ + + + + + + + c2c.salary.structure.tree + c2c.salary.structure + + + + + + + + + + + + + + + + + + + c2c.salary.structure.form + c2c.salary.structure + +
+ +
+
+ + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + Salary Structures + c2c.salary.structure + tree,form + +

+ Create your first Salary Structure +

+

+ Define how gross salary is split into Basic, HRA, and Allowances, + and configure PF, ESI, and Professional Tax deduction rules. +

+
+
+
diff --git a/addons/c2c_payroll/wizard/__init__.py b/addons/c2c_payroll/wizard/__init__.py new file mode 100644 index 0000000..6aff706 --- /dev/null +++ b/addons/c2c_payroll/wizard/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import payslip_generate_wizard diff --git a/addons/c2c_payroll/wizard/__pycache__/__init__.cpython-310.pyc b/addons/c2c_payroll/wizard/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7893fff6981aceec3b38bd59707126aebb3dfa34 GIT binary patch literal 189 zcmd1j<>g`k0>kI?G97^QV-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+G6ID) z8E=UfBvuyZWERAyr{<*=C6=VdmuFTb7Nz)UGTmY*0vWQBp@;=Yfr(!R`nh=}`l%Hq zMTxqJDJl7R#rnxc$?-r#it=-E^dWlnq{LMRDAxt_8_uo2QoU^%XySr0yDyFJ;A zHTy#HhVl<0lsxj6`jrQizp#lCs(frFLfGnZcUN_FeRVnC*ytMg{PEA9@uxWZn-=Sj zg^TMr)YnMB0G1dj8?%&;d1{VLMteN5QhRJO4&@Xi66aCE2Q75R-6`6z@SIb_YiV=?zX+#&hEZqC{v62mj5IgTe&% znEg&`3-~4Dxn0K?*UrqHnBagrwO+7ewqk0C(q6^!E*ht&I+u)NzT(H`irqAR`R3SK z@tF->uvgZsQ|aj89PdPJ{c6T>hI!Q9F|}X=22c61y|U&0;qHn*@78CLx^xl;uccx0 znT^&sD|6-iU>ut$ZK^}G>kQcgXW<-X;Ca}B3oCQho0wAu7vY0v4hC|&{I>O_-vmSX zlU({?lK3K>C;3tcSI`hwkj~yPuNv$<#UngZj(bn4DuYt1VzrPFbU-{zyw}I#X<_?mHgwYw~^PM z%3P_SmN;S8B;{!N<6izB3lYg8gT{KlKH#6K^h4xTx>^|G1%el~27N$aXusZ}*f7G3au{f&c+JQU`@sLx5aw>{pUw1{O zC_Fj#uXpfl!boi$TaXB4bWj17mudSGB9(8P2yqrdn=z=NEBhqhY5k?N+Z4M#Q_BH$ z4{DZ5d##lA#G_ah)a2ZTTlJrsQ0vg!wQt__m{!YKnhc)ZU&*5#b_8OPUoZMoH# z@we97u5B@oTfEP@_@cyXZac3mhck;i%&K08d9S*zg&J`8Ew|}gYjaM@QG=t6N7J<1O%N)Q@thJsnuOT8iC%pd4ei~<7Qago zqO_A=5uql%M#xi=esweyiFpP=8}I>Ahu$}RyOP)&dRVuR=aQOob)%$zwBDr6k$4n| s$`&Ol3-n-LhM9^n!|u}Gwo(^b literal 0 HcmV?d00001 diff --git a/addons/c2c_payroll/wizard/payslip_generate_wizard.py b/addons/c2c_payroll/wizard/payslip_generate_wizard.py new file mode 100644 index 0000000..c210b05 --- /dev/null +++ b/addons/c2c_payroll/wizard/payslip_generate_wizard.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models +from odoo.exceptions import UserError + + +class PayslipGenerateWizard(models.TransientModel): + _name = 'c2c.payslip.generate.wizard' + _description = 'Generate Payslips Wizard' + + date_from = fields.Date(string='Period From', required=True) + date_to = fields.Date(string='Period To', required=True) + company_id = fields.Many2one( + 'res.company', string='Company', required=True, + default=lambda self: self.env.company, + ) + + def action_generate_payslips(self): + """Generate payslips for all employees with active contracts.""" + self.ensure_one() + + if self.date_from > self.date_to: + raise UserError('Period From cannot be after Period To.') + + contracts = self.env['hr.contract'].search([ + ('state', '=', 'open'), + ('company_id', '=', self.company_id.id), + ('salary_structure_id', '!=', False), + ('gross_salary', '>', 0), + ]) + + if not contracts: + raise UserError( + 'No active contracts found with a salary structure and gross salary ' + 'for company %s.' % self.company_id.name + ) + + Payslip = self.env['c2c.payslip'] + created_payslips = Payslip + + for contract in contracts: + # Skip if payslip already exists for this employee and period + existing = Payslip.search([ + ('employee_id', '=', contract.employee_id.id), + ('date_from', '=', self.date_from), + ('date_to', '=', self.date_to), + ('company_id', '=', self.company_id.id), + ], limit=1) + if existing: + continue + + payslip = Payslip.create({ + 'employee_id': contract.employee_id.id, + 'contract_id': contract.id, + 'date_from': self.date_from, + 'date_to': self.date_to, + 'company_id': self.company_id.id, + }) + created_payslips |= payslip + + if not created_payslips: + raise UserError( + 'All eligible employees already have payslips for the selected period.' + ) + + return { + 'type': 'ir.actions.act_window', + 'name': 'Generated Payslips', + 'res_model': 'c2c.payslip', + 'view_mode': 'tree,form', + 'domain': [('id', 'in', created_payslips.ids)], + 'target': 'current', + } diff --git a/addons/employee_documents/__init__.py b/addons/employee_documents/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/addons/employee_documents/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/addons/employee_documents/__manifest__.py b/addons/employee_documents/__manifest__.py new file mode 100644 index 0000000..7832049 --- /dev/null +++ b/addons/employee_documents/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Employee Documents', + 'version': '1.0', + 'category': 'Human Resources', + 'summary': 'Manage Employee Documents', + 'description': """ + This module allows you to manage employee documents such as Offer Letters, Contracts, ID Proofs, etc. + It adds a documents tab in the Employee form view. + """, + 'author': 'Antigravity', + 'depends': ['hr'], + 'data': [ + 'security/security.xml', + 'security/ir.model.access.csv', + 'views/employee_document_views.xml', + 'views/hr_employee_views.xml', + ], + 'installable': True, + 'application': True, + 'license': 'LGPL-3', +} diff --git a/addons/employee_documents/__pycache__/__init__.cpython-310.pyc b/addons/employee_documents/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab04e4dba9c55cfe34cb43e0aad8946a13bda06c GIT binary patch literal 172 zcmd1j<>g`kf{ROAGsS@PV-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+G6ID) z8E>)W=BK3Q6#Hp1-C`&L=~>B8!~&$i#4iK=+`JO~)QXa#MBT)cl>EG6{nXrooczkv s)cBPAN3>07h0065etpET3 literal 0 HcmV?d00001 diff --git a/addons/employee_documents/models/__init__.py b/addons/employee_documents/models/__init__.py new file mode 100644 index 0000000..a996134 --- /dev/null +++ b/addons/employee_documents/models/__init__.py @@ -0,0 +1,2 @@ +from . import employee_document +from . import hr_employee diff --git a/addons/employee_documents/models/__pycache__/__init__.cpython-310.pyc b/addons/employee_documents/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2320b846cba5d2f690922b56595f98f0d9ebfb2c GIT binary patch literal 224 zcmd1j<>g`kg3C)=Gi`wMV-N=!FabFZKwK;XBvKes7;_kM8KW2(L2M=k(`3HIPy{l$h#5$%WGG?< zu|dQybN$@B68+SQlA=W2#FUi$ykdQrHn?%c`nmZjsX4{^@$s2?nI-Y@dIgoYIBbA| Sr8%i~AXgN#00|xj0Y(7Xv^R4A literal 0 HcmV?d00001 diff --git a/addons/employee_documents/models/__pycache__/employee_document.cpython-310.pyc b/addons/employee_documents/models/__pycache__/employee_document.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65f5883cb3a5b39a3be6504306fd663cb263c41e GIT binary patch literal 976 zcmZWo&2H2%5VjL1>;3JvLcOvQTymf*aX=gps%QZr(H7Bi$t8+*X4_Orymh>S%@sKI zCAjfQzH&mm0bCeoH%lcfc{1Plo1cuwYB=mMT2Fs{&F=e*{czy!5(ExuS5HU)1D>;j z$Gq@jukd4^JDZn_Ld1fz*9?3RUl<7F*TH8$4k0*aQTUU5S>)TWP=I-5!+C}|RMt-y zS;Vb`)S$@i(5JXd_zL28slc2Wn2P zNsh*#t_NohP2M($PUTFMMyE4l<)UU^Ua(!epw{G=G%w=qlA#IG&X!X}Nl=O0@m9 zK}iO-dyYBIoQoZ{H;@?m5gWe9%2cncm{Y;F>*P9-bcMPRvwo>Q+WxXBKXHTio#_XZ zxDme(r$uR|_=(#3CekvrcP^i;8~dCSs$9-{oI-nl0n0}f Ai~s-t literal 0 HcmV?d00001 diff --git a/addons/employee_documents/models/__pycache__/hr_employee.cpython-310.pyc b/addons/employee_documents/models/__pycache__/hr_employee.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a0c21fbfbc0a6293042d8c2f034024251494d47 GIT binary patch literal 500 zcmYjNJ5R$f5VoBMp${GsVrD|hKqE0CggSs=p$u$Utf*&bs@N`eDp6Ko>>9buP@AoK<=u#6x#t2BIyt+iU=OJeNY%uG>Pq1h;;=f^AA&Y->}h+Yu5b zoU1|#&RvId9Clv$yvO<7yr@>4gqLa}Oj(-%r*z4c5{I%-3)gG4P{F>^} z)tR`jO>s~FXl1kCY1&6NTP`P?7~VDqvxV^s_ikeh2?^;AYp_uoxln`FhIyT4mgv&& aw`u>WFSAX& + + + + HR Documents + + + + + diff --git a/addons/employee_documents/views/employee_document_views.xml b/addons/employee_documents/views/employee_document_views.xml new file mode 100644 index 0000000..c02e408 --- /dev/null +++ b/addons/employee_documents/views/employee_document_views.xml @@ -0,0 +1,78 @@ + + + + + + employee.document.tree + employee.document + + + + + + + + + + + + + employee.document.form + employee.document + +
+ + + + + + + + + + + + + + +
+
+
+ + + + employee.document.search + employee.document + + + + + + + + + + + + + + + + Documents + employee.document + tree,form + +

+ Create your first employee document +

+
+
+ + + + +
diff --git a/addons/employee_documents/views/hr_employee_views.xml b/addons/employee_documents/views/hr_employee_views.xml new file mode 100644 index 0000000..f6c7444 --- /dev/null +++ b/addons/employee_documents/views/hr_employee_views.xml @@ -0,0 +1,23 @@ + + + + hr.employee.form.inherit.document + hr.employee + + + + + + + + + + + + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8c0709f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3.8" + +services: + db: + image: postgres:15 + container_name: odoo_metatroncube_db + environment: + POSTGRES_DB: postgres + POSTGRES_USER: odoo + POSTGRES_PASSWORD: odoo + volumes: + - client1_pgdata:/var/lib/postgresql/data + restart: always + + odoo: + image: odoo:17.0 + container_name: odoo_metatroncube + depends_on: + - db + ports: + - "10101:8069" + environment: + HOST: db + USER: odoo + PASSWORD: odoo + volumes: + - client1_odoo_data:/var/lib/odoo + - ./addons:/mnt/extra-addons + restart: always + +volumes: + client1_pgdata: + client1_odoo_data: \ No newline at end of file