hr_payroll_holidays
hr_payroll_input_name_report
hr_payroll_input_report
hr_payroll_payment
hr_payroll_timesheet
hr_payslip_line_date
l10n_us_fl_hr_payroll
l10n_us_hr_payroll
l10n_us_mo_hr_payroll
l10n_us_oh_hr_payroll
l10n_us_va_hr_payroll
This commit is contained in:
Jared Kipe
2018-04-30 08:15:31 -07:00
parent f3ffb075da
commit fe9bb91497
4 changed files with 229 additions and 0 deletions

3
hr_payroll_payment/__init__.py Executable file
View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import hr_payroll_register_payment

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
{
'name': 'Payroll Payments',
'author': 'Hibou Corp. <hello@hibou.io>',
'version': '11.0.0.0.0',
'category': 'Human Resources',
'sequence': 95,
'summary': 'Register payments for Payroll Payslips',
'description': """
Adds the ability to register a payment on a payslip.
""",
'website': 'https://hibou.io/',
'depends': ['hr_payroll_account'],
'data': [
'hr_payroll_register_payment.xml',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class HrPayslip(models.Model):
_inherit = 'hr.payslip'
@api.multi
@api.depends('move_id', 'move_id.line_ids.full_reconcile_id')
def _is_paid(self):
for payslip in self:
payslip.is_paid = (
payslip.move_id and len(payslip.move_id.line_ids.filtered(lambda l: (
l.partner_id.id == payslip.employee_id.address_home_id.id and
l.account_id.internal_type == 'payable' and
not l.reconciled
))) == 0
)
is_paid = fields.Boolean(string="Has been Paid", compute='_is_paid', store=True)
class HrPayrollRegisterPaymentWizard(models.TransientModel):
_name = "hr.payroll.register.payment.wizard"
_description = "Hr Payroll Register Payment wizard"
@api.model
def _default_partner_id(self):
context = dict(self._context or {})
active_ids = context.get('active_ids', [])
payslip = self.env['hr.payslip'].browse(active_ids)
return payslip.employee_id.address_home_id.id
@api.model
def _default_amount(self):
context = dict(self._context or {})
active_ids = context.get('active_ids', [])
payslip = self.env['hr.payslip'].browse(active_ids)
amount = 0.0
for line in payslip.move_id.line_ids:
if line.account_id.internal_type == 'payable' and line.partner_id.id == payslip.employee_id.address_home_id.id:
amount += abs(line.balance)
return amount
@api.model
def _default_communication(self):
context = dict(self._context or {})
active_ids = context.get('active_ids', [])
payslip = self.env['hr.payslip'].browse(active_ids)
return payslip.number
partner_id = fields.Many2one('res.partner', string='Partner', required=True, default=_default_partner_id)
journal_id = fields.Many2one('account.journal', string='Payment Method', required=True, domain=[('type', 'in', ('bank', 'cash'))])
company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', readonly=True, required=True)
payment_method_id = fields.Many2one('account.payment.method', string='Payment Type', required=True)
amount = fields.Monetary(string='Payment Amount', required=True, default=_default_amount)
currency_id = fields.Many2one('res.currency', string='Currency', required=True, default=lambda self: self.env.user.company_id.currency_id)
payment_date = fields.Date(string='Payment Date', default=fields.Date.context_today, required=True)
communication = fields.Char(string='Memo', default=_default_communication)
hide_payment_method = fields.Boolean(compute='_compute_hide_payment_method',
help="Technical field used to hide the payment method if the selected journal has only one available which is 'manual'")
@api.one
@api.constrains('amount')
def _check_amount(self):
if not self.amount > 0.0:
raise ValidationError('The payment amount must be strictly positive.')
@api.one
@api.depends('journal_id')
def _compute_hide_payment_method(self):
if not self.journal_id:
self.hide_payment_method = True
return
journal_payment_methods = self.journal_id.outbound_payment_method_ids
self.hide_payment_method = len(journal_payment_methods) == 1 and journal_payment_methods[0].code == 'manual'
@api.onchange('journal_id')
def _onchange_journal(self):
if self.journal_id:
# Set default payment method (we consider the first to be the default one)
payment_methods = self.journal_id.outbound_payment_method_ids
self.payment_method_id = payment_methods and payment_methods[0] or False
# Set payment method domain (restrict to methods enabled for the journal and to selected payment type)
return {'domain': {'payment_method_id': [('payment_type', '=', 'outbound'), ('id', 'in', payment_methods.ids)]}}
return {}
@api.multi
def payroll_post_payment(self):
self.ensure_one()
context = dict(self._context or {})
active_ids = context.get('active_ids', [])
payslip = self.env['hr.payslip'].browse(active_ids)
# Create payment and post it
payment = self.env['account.payment'].create({
'partner_type': 'supplier',
'payment_type': 'outbound',
'partner_id': self.partner_id.id,
'journal_id': self.journal_id.id,
'company_id': self.company_id.id,
'payment_method_id': self.payment_method_id.id,
'amount': self.amount,
'currency_id': self.currency_id.id,
'payment_date': self.payment_date,
'communication': self.communication
})
payment.post()
# Reconcile the payment and the payroll, i.e. lookup on the payable account move lines
account_move_lines_to_reconcile = self.env['account.move.line']
for line in payment.move_line_ids:
if line.account_id.internal_type == 'payable':
account_move_lines_to_reconcile |= line
for line in payslip.move_id.line_ids:
if line.account_id.internal_type == 'payable' and line.partner_id.id == self.partner_id.id:
account_move_lines_to_reconcile |= line
account_move_lines_to_reconcile.reconcile()
return {'type': 'ir.actions.act_window_close'}

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Add Filter for "Needs Payment" -->
<record id="payslip_filter_needs_payment" model="ir.ui.view">
<field name="name">hr.payslip.select</field>
<field name="model">hr.payslip</field>
<field name="priority">20</field>
<field name="inherit_id" ref="hr_payroll.view_hr_payslip_filter"/>
<field name="arch" type="xml">
<data>
<xpath expr="//filter[last()]" position="after">
<filter string="Needs Payment" domain="[('is_paid', '=', False)]" help="Needs Payment Slip"/>
</xpath>
</data>
</field>
</record>
<!-- Wizard view to register payment -->
<record id="hr_payroll_register_payment_view_form" model="ir.ui.view">
<field name="name">hr.payroll.register.payment.wizard.form</field>
<field name="model">hr.payroll.register.payment.wizard</field>
<field name="arch" type="xml">
<form string="Register Payment">
<sheet>
<field name="id" invisible="1"/>
<div class="oe_title">
<h1>Draft Payment</h1>
</div>
<group>
<group>
<field name="partner_id" required="1" context="{'default_is_company': True, 'default_supplier': True}"/>
<field name="journal_id" widget="selection"/>
<field name="hide_payment_method" invisible="1"/>
<field name="payment_method_id" widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)]}"/>
<label for="amount"/>
<div name="amount_div" class="o_row">
<field name="amount"/>
<field name="currency_id" options="{'no_create': True, 'no_open': True}" groups="base.group_multi_currency"/>
</div>
</group>
<group>
<field name="payment_date"/>
<field name="communication"/>
</group>
</group>
</sheet>
<footer>
<button string='Validate' name="payroll_post_payment" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action to launch Wizard for register payment -->
<record id="hr_payroll_register_payment_wizard_action" model="ir.actions.act_window">
<field name="name">Register Payment</field>
<field name="res_model">hr.payroll.register.payment.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="hr_payroll_register_payment_view_form"/>
<field name="target">new</field>
<field name="context">{'default_payment_type': 'inbound'}</field>
<field name="domain">[('partner_type', '=', 'customer')]</field>
</record>
<!-- Button on Payslip to launch Wizard for register payment -->
<record id="hr_payslip_form" model="ir.ui.view">
<field name="name">hr.payslip.form</field>
<field name="model">hr.payslip</field>
<field name="inherit_id" ref="hr_payroll.view_hr_payslip_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='refund_sheet']" position="before">
<button name="%(hr_payroll_payment.hr_payroll_register_payment_wizard_action)d" type="action" string="Register Payment" class="oe_highlight" attrs="{'invisible': ['|', ('state', '!=', 'done'), ('is_paid', '=', True)]}" groups="account.group_account_user"/>
</xpath>
<xpath expr="//field[@name='credit_note']" position="after">
<field name="is_paid" readonly="1"/>
</xpath>
</field>
</record>
</odoo>