From 206d6bba680fa5e81ac70297a08e079dbb7ee9c9 Mon Sep 17 00:00:00 2001 From: metatroncubeswdev Date: Thu, 11 Jun 2026 01:38:47 -0400 Subject: [PATCH] removed unwanted addons --- CLAUDE.md | 72 +++++ addons/c2c_payroll/__init__.py | 3 - addons/c2c_payroll/__manifest__.py | 38 --- .../__pycache__/__init__.cpython-310.pyc | Bin 194 -> 0 bytes addons/c2c_payroll/models/__init__.py | 4 - .../__pycache__/__init__.cpython-310.pyc | Bin 253 -> 0 bytes .../contract_extension.cpython-310.pyc | Bin 924 -> 0 bytes .../__pycache__/payslip.cpython-310.pyc | Bin 7296 -> 0 bytes .../salary_structure.cpython-310.pyc | Bin 1960 -> 0 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 189 -> 0 bytes .../payslip_generate_wizard.cpython-310.pyc | Bin 2081 -> 0 bytes .../wizard/payslip_generate_wizard.py | 72 ----- 24 files changed, 72 insertions(+), 1068 deletions(-) create mode 100644 CLAUDE.md delete mode 100644 addons/c2c_payroll/__init__.py delete mode 100644 addons/c2c_payroll/__manifest__.py delete mode 100644 addons/c2c_payroll/__pycache__/__init__.cpython-310.pyc delete mode 100644 addons/c2c_payroll/models/__init__.py delete mode 100644 addons/c2c_payroll/models/__pycache__/__init__.cpython-310.pyc delete mode 100644 addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc delete mode 100644 addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc delete mode 100644 addons/c2c_payroll/models/__pycache__/salary_structure.cpython-310.pyc delete mode 100644 addons/c2c_payroll/models/contract_extension.py delete mode 100644 addons/c2c_payroll/models/payslip.py delete mode 100644 addons/c2c_payroll/models/salary_structure.py delete mode 100644 addons/c2c_payroll/reports/payslip_report.xml delete mode 100644 addons/c2c_payroll/reports/payslip_report_template.xml delete mode 100644 addons/c2c_payroll/security/ir.model.access.csv delete mode 100644 addons/c2c_payroll/security/security.xml delete mode 100644 addons/c2c_payroll/views/contract_views.xml delete mode 100644 addons/c2c_payroll/views/menu.xml delete mode 100644 addons/c2c_payroll/views/payslip_views.xml delete mode 100644 addons/c2c_payroll/views/salary_structure_views.xml delete mode 100644 addons/c2c_payroll/wizard/__init__.py delete mode 100644 addons/c2c_payroll/wizard/__pycache__/__init__.cpython-310.pyc delete mode 100644 addons/c2c_payroll/wizard/__pycache__/payslip_generate_wizard.cpython-310.pyc delete mode 100644 addons/c2c_payroll/wizard/payslip_generate_wizard.py diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7dd9bb1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,72 @@ +# Odoo Metatroncube — Project Context + +## Live Instance + +| Field | Value | +|----------|--------------------------------------------| +| URL | https://workplace.metatroncube.in/ | +| Database | `metatroncube_db` | +| User | `info@metatroncubesolutions.com` | +| Version | Odoo 17.0 (Community) | + +## MCP Connection + +The `.mcp.json` in this folder connects Claude to the live Odoo instance via `odoo-mcp`. +To connect at the start of a session run: + +``` +connect to metatroncube Odoo — url https://workplace.metatroncube.in/, db metatroncube_db, user info@metatroncubesolutions.com +``` + +Or use the `mcp__odoo-mcp__connect_database` tool with `instance_name: metatroncube`. + +## Local Docker Environment + +File: `docker-compose.yml` + +- Odoo 17.0 container → port `10001` (http://localhost:10001) +- PostgreSQL 15 +- Addons mounted at `./addons:/mnt/extra-addons` +- External volumes: + - `odoo-testing-addons_metatroncube_pgdata` + - `odoo-testing-addons_metatroncube_odoo_data` + +Start locally: +```bash +docker compose up -d +``` + +## Custom Addons + +All addons live in `./addons/`. Author: **Metatroncube Software Solutions**. + +| Module | Version | Purpose | Depends On | +|------------------------------|---------------|----------------------------------------------------------|-----------------------| +| `accounting_community` | 17.0.1.0.0 | Unlocks full accounting menus on Community Edition | `account` | +| `employee_documents` | — | Document management for employees | — | +| `mcs_appointment_booking` | 17.0.1.0.0 | Website appointment booking with calendar integration | `calendar`, `website` | +| `mcs_invoice_currency_display` | — | Currency display on invoices | — | +| `mcs_payroll_localization` | 17.0.1.0.0 | India & Canada payroll structures (OCA Payroll) | `payroll_account` | +| `payroll` | — | OCA Payroll base module | — | +| `payroll_account` | — | OCA Payroll + Accounting integration | `payroll` | + +## Key Custom Modules Detail + +### `mcs_appointment_booking` +- Full module: models, views, controllers, security +- Website-facing booking forms + backend calendar views +- License: AGPL-3 + +### `mcs_payroll_localization` +- India and Canada payroll structures +- Has a `post_init_hook` in `hooks.py` +- License: LGPL-3 + +### `accounting_community` +- By Antigravity (third-party, included in repo) +- Adds Journal Entries, Items, General Ledger, Partner Ledger to Community +- License: LGPL-3 + +## Snapshots + +Odoo MCP snapshots are stored in `./snapshots/` — used for rollback via `mcp__odoo-mcp__rollback_snapshot`. diff --git a/addons/c2c_payroll/__init__.py b/addons/c2c_payroll/__init__.py deleted file mode 100644 index 408a600..0000000 --- a/addons/c2c_payroll/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -from . import models -from . import wizard diff --git a/addons/c2c_payroll/__manifest__.py b/addons/c2c_payroll/__manifest__.py deleted file mode 100644 index 36516ce..0000000 --- a/addons/c2c_payroll/__manifest__.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- 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 deleted file mode 100644 index 38f60c0d21be2f1e07ae82f357edb4b40640235a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc b/addons/c2c_payroll/models/__pycache__/contract_extension.cpython-310.pyc deleted file mode 100644 index 2127d4c5f7e8445dc30ef76beef66ef465a8d927..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc b/addons/c2c_payroll/models/__pycache__/payslip.cpython-310.pyc deleted file mode 100644 index 40aa21fc532e84c4c95d140cbf5896c26a3beb1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7296 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 Z>c7Ck=ij!3iB>YdqH|noiL}V9^#TXb7%Bh& diff --git a/addons/c2c_payroll/models/contract_extension.py b/addons/c2c_payroll/models/contract_extension.py deleted file mode 100644 index 77a4716..0000000 --- a/addons/c2c_payroll/models/contract_extension.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- 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 deleted file mode 100644 index 47272d7..0000000 --- a/addons/c2c_payroll/models/payslip.py +++ /dev/null @@ -1,299 +0,0 @@ -# -*- 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 deleted file mode 100644 index 144c1cf..0000000 --- a/addons/c2c_payroll/models/salary_structure.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- 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 deleted file mode 100644 index 6e7e858..0000000 --- a/addons/c2c_payroll/reports/payslip_report.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - 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 deleted file mode 100644 index 64a7b28..0000000 --- a/addons/c2c_payroll/reports/payslip_report_template.xml +++ /dev/null @@ -1,184 +0,0 @@ - - - - diff --git a/addons/c2c_payroll/security/ir.model.access.csv b/addons/c2c_payroll/security/ir.model.access.csv deleted file mode 100644 index fe757a0..0000000 --- a/addons/c2c_payroll/security/ir.model.access.csv +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index f1ca0c6..0000000 --- a/addons/c2c_payroll/security/security.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - 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 deleted file mode 100644 index 513360f..0000000 --- a/addons/c2c_payroll/views/contract_views.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - hr.contract.form.inherit.c2c.payroll - hr.contract - - - - - - - - - - - - - - - - - - - diff --git a/addons/c2c_payroll/views/menu.xml b/addons/c2c_payroll/views/menu.xml deleted file mode 100644 index 51da1d1..0000000 --- a/addons/c2c_payroll/views/menu.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/addons/c2c_payroll/views/payslip_views.xml b/addons/c2c_payroll/views/payslip_views.xml deleted file mode 100644 index 9399df4..0000000 --- a/addons/c2c_payroll/views/payslip_views.xml +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - 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 deleted file mode 100644 index b1b9452..0000000 --- a/addons/c2c_payroll/views/salary_structure_views.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - 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 deleted file mode 100644 index 6aff706..0000000 --- a/addons/c2c_payroll/wizard/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- 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 deleted file mode 100644 index 7893fff6981aceec3b38bd59707126aebb3dfa34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/addons/c2c_payroll/wizard/payslip_generate_wizard.py b/addons/c2c_payroll/wizard/payslip_generate_wizard.py deleted file mode 100644 index c210b05..0000000 --- a/addons/c2c_payroll/wizard/payslip_generate_wizard.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- 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', - }