diff --git a/hr_payroll_commission/__init__.py b/hr_payroll_commission/__init__.py
new file mode 100644
index 00000000..09434554
--- /dev/null
+++ b/hr_payroll_commission/__init__.py
@@ -0,0 +1,3 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from . import models
diff --git a/hr_payroll_commission/__manifest__.py b/hr_payroll_commission/__manifest__.py
new file mode 100644
index 00000000..7ac30f0c
--- /dev/null
+++ b/hr_payroll_commission/__manifest__.py
@@ -0,0 +1,29 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+{
+ 'name': 'Commissions in Payslips',
+ 'author': 'Hibou Corp.',
+ 'version': '13.0.1.0.0',
+ 'license': 'OPL-1',
+ 'category': 'Accounting/Commissions',
+ 'sequence': 95,
+ 'summary': 'Reimburse Commissions in Payslips',
+ 'description': """
+Reimburse Commissions in Payslips
+ """,
+ 'depends': [
+ 'hr_commission',
+ 'hr_payroll',
+ ],
+ 'data': [
+ 'views/hr_commission_views.xml',
+ 'views/hr_payslip_views.xml',
+ 'data/hr_payroll_commission_data.xml',
+ ],
+ 'demo': [
+ 'data/hr_payroll_commission_demo.xml',
+ ],
+ 'installable': True,
+ 'application': False,
+ 'auto_install': True,
+}
diff --git a/hr_payroll_commission/data/hr_payroll_commission_data.xml b/hr_payroll_commission/data/hr_payroll_commission_data.xml
new file mode 100644
index 00000000..a666f821
--- /dev/null
+++ b/hr_payroll_commission/data/hr_payroll_commission_data.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ Commissions
+ COMMISSION
+
+
+
diff --git a/hr_payroll_commission/data/hr_payroll_commission_demo.xml b/hr_payroll_commission/data/hr_payroll_commission_demo.xml
new file mode 100644
index 00000000..77e8ccfa
--- /dev/null
+++ b/hr_payroll_commission/data/hr_payroll_commission_demo.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ python
+
+result = inputs.COMMISSION.amount > 0.0 if inputs.COMMISSION else False
+
+ code
+
+result = inputs.COMMISSION.amount if inputs.COMMISSION else 0
+
+ COMMISSION
+
+ Commissions
+
+
+
+
+
diff --git a/hr_payroll_commission/models/__init__.py b/hr_payroll_commission/models/__init__.py
new file mode 100644
index 00000000..ba3bcc23
--- /dev/null
+++ b/hr_payroll_commission/models/__init__.py
@@ -0,0 +1,4 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from . import hr_commission
+from . import hr_payslip
diff --git a/hr_payroll_commission/models/hr_commission.py b/hr_payroll_commission/models/hr_commission.py
new file mode 100644
index 00000000..3cd127ff
--- /dev/null
+++ b/hr_payroll_commission/models/hr_commission.py
@@ -0,0 +1,13 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from odoo import fields, models, _
+
+
+class CommissionPayment(models.Model):
+ _inherit = 'hr.commission.payment'
+
+ pay_in_payslip = fields.Boolean(string="Reimburse In Next Payslip")
+ payslip_id = fields.Many2one('hr.payslip', string="Payslip", readonly=True)
+
+ def action_report_in_next_payslip(self):
+ self.filtered(lambda p: not p.payslip_id).write({'pay_in_payslip': True})
diff --git a/hr_payroll_commission/models/hr_payslip.py b/hr_payroll_commission/models/hr_payslip.py
new file mode 100644
index 00000000..510afdd7
--- /dev/null
+++ b/hr_payroll_commission/models/hr_payslip.py
@@ -0,0 +1,63 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+
+
+class HrPayslip(models.Model):
+ _inherit = 'hr.payslip'
+
+ commission_payment_ids = fields.One2many(
+ 'hr.commission.payment', 'payslip_id', string='Commissions',
+ help="Commissions to reimburse to employee.",
+ states={'draft': [('readonly', False)], 'verify': [('readonly', False)]})
+ commission_count = fields.Integer(compute='_compute_commission_count')
+
+ @api.depends('commission_payment_ids.commission_ids', 'commission_payment_ids.payslip_id')
+ def _compute_commission_count(self):
+ for payslip in self:
+ payslip.commission_count = len(payslip.mapped('commission_payment_ids.commission_ids'))
+
+ @api.onchange('input_line_ids')
+ def _onchange_input_line_ids(self):
+ commission_type = self.env.ref('hr_payroll_commission.commission_other_input', raise_if_not_found=False)
+ if not self.input_line_ids.filtered(lambda line: line.input_type_id == commission_type):
+ self.commission_payment_ids.write({'payslip_id': False})
+
+ @api.onchange('employee_id', 'struct_id', 'contract_id', 'date_from', 'date_to')
+ def _onchange_employee(self):
+ res = super()._onchange_employee()
+ if self.state == 'draft':
+ self.commission_payment_ids = self.env['hr.commission.payment'].search([
+ ('employee_id', '=', self.employee_id.id),
+ ('pay_in_payslip', '=', True),
+ ('payslip_id', '=', False)])
+ self._onchange_commission_payment_ids()
+ return res
+
+ @api.onchange('commission_payment_ids')
+ def _onchange_commission_payment_ids(self):
+ commission_type = self.env.ref('hr_payroll_commission.commission_other_input', raise_if_not_found=False)
+ if not commission_type:
+ return
+
+ total = sum(self.commission_payment_ids.mapped('commission_amount'))
+ if not total:
+ return
+
+ lines_to_keep = self.input_line_ids.filtered(lambda x: x.input_type_id != commission_type)
+ input_lines_vals = [(5, 0, 0)] + [(4, line.id, False) for line in lines_to_keep]
+ input_lines_vals.append((0, 0, {
+ 'amount': total,
+ 'input_type_id': commission_type.id,
+ }))
+ self.update({'input_line_ids': input_lines_vals})
+
+ def open_commissions(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Reimbursed Commissions'),
+ 'res_model': 'hr.commission',
+ 'view_mode': 'tree,form',
+ 'domain': [('id', 'in', self.mapped('commission_payment_ids.commission_ids').ids)],
+ }
diff --git a/hr_payroll_commission/static/description/icon.png b/hr_payroll_commission/static/description/icon.png
new file mode 100644
index 00000000..9ccbaed5
Binary files /dev/null and b/hr_payroll_commission/static/description/icon.png differ
diff --git a/hr_payroll_commission/tests/__init__.py b/hr_payroll_commission/tests/__init__.py
new file mode 100755
index 00000000..0ce84cbf
--- /dev/null
+++ b/hr_payroll_commission/tests/__init__.py
@@ -0,0 +1,3 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from . import test_payslip_commission
diff --git a/hr_payroll_commission/tests/test_payslip_commission.py b/hr_payroll_commission/tests/test_payslip_commission.py
new file mode 100644
index 00000000..0e1dcc17
--- /dev/null
+++ b/hr_payroll_commission/tests/test_payslip_commission.py
@@ -0,0 +1,37 @@
+# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+
+from datetime import date, timedelta
+
+from odoo.addons.hr_commission.tests import test_commission
+
+
+class TestCommissionPayslip(test_commission.TestCommission):
+
+ def test_commission(self):
+ super().test_commission()
+ commission_type = self.env.ref('hr_payroll_commission.commission_other_input')
+ payslip = self.env['hr.payslip'].create({
+ 'name': 'test slip',
+ 'employee_id': self.employee.id,
+ 'date_from': date.today() - timedelta(days=1),
+ 'date_to': date.today() + timedelta(days=14),
+ })
+ payslip._onchange_employee()
+ self.assertFalse(payslip.commission_payment_ids)
+
+ # find unpaid commission payments from super().test_commission()
+ commission_payments = self.env['hr.commission.payment'].search([
+ ('employee_id', '=', self.employee.id),
+ ])
+ self.assertTrue(commission_payments)
+
+ # press the button to pay it via payroll
+ commission_payments.action_report_in_next_payslip()
+
+ payslip._onchange_employee()
+ # has attached commission payments
+ self.assertTrue(payslip.commission_payment_ids)
+ commission_input_lines = payslip.input_line_ids.filtered(lambda l: l.input_type_id == commission_type)
+ self.assertTrue(commission_input_lines)
+ self.assertEqual(sum(commission_input_lines.mapped('amount')),
+ sum(commission_payments.mapped('commission_amount')))
diff --git a/hr_payroll_commission/views/hr_commission_views.xml b/hr_payroll_commission/views/hr_commission_views.xml
new file mode 100644
index 00000000..cbc1cb27
--- /dev/null
+++ b/hr_payroll_commission/views/hr_commission_views.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ hr.expense.sheet.view.form.payroll
+ hr.commission.payment
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hr_payroll_commission/views/hr_payslip_views.xml b/hr_payroll_commission/views/hr_payslip_views.xml
new file mode 100644
index 00000000..aa3717fb
--- /dev/null
+++ b/hr_payroll_commission/views/hr_payslip_views.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ hr.payslip.view.form.inherit
+ hr.payslip
+
+
+
+
+
+
+
+
+
+
+
+