This question has been flagged
16 Replies
9102 Views

Hi, I have installed hr and hr_paroll module in my Database

1 )Is there any option in payroll for giving advance salary to employees ?

2) How to deduct the Given Advance salary from the Monthly payment slip ?

Thanks
Avatar
Discard

the modules fails at this line *seq_id = employee.company_id.hr_loan_seq.id* where can i find hr_loan_seq.id?

Hi, why did u commen #store = {'hr.expense.line': (_get_loan_reimbursement_from_expense_lines, None, 50)}), if i remove the # i recieve an eror "SyntaxError: invalid syntax" under "="sign. moreover there is an extra bracket ")" before the comma. from what i understood in ur code it creats a line in expense, i want the loan to be shown in the expense but it doesnt show. and if i removed the # plus the ) which is before this line, i recieve error duplicated functions..

Best Answer

Hi;

Actually, in my knowledge, there is no such option nor modules giving this functionality in OpenERP addons and extra-addons.

But there is a work from Argilsoft, included in a vertical solution module, which fulfill your needs.

Let me few hours, i will post the code after some modifications.

Best regards.

Sorry for the delay.

on reflection, it's better to inherit from hr_expense_line.

The .py file

code for hr_expense_loan.py:

from openerp.osv import osv, fields

import time

from datetime import datetime, date

from openerp.tools.translate import _

from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, float_compare

import decimal_precision as dp

import netsvc

class hr_expense_line(osv.osv):

_inherit = 'hr.expense.line' _columns = { 'loan_id' : fields.many2one('hr.expense.loan', 'Loan', required=False), }

class hr_expense_loan(osv.osv):

_name = 'hr.expense.loan' _inherit = ['mail.thread', 'ir.needaction_mixin'] _description = 'HR Loan Management' def _balance(self, cr, uid, ids, field_name, args, context=None): res = {} for record in self.browse(cr, uid, ids, context=context): cr.execute('select sum(coalesce(price_total, 0.0))::float from hr_expense_line where loan_id = %s' % (record.id)) data = filter(None, map(lambda x:x[0], cr.fetchall())) or [0.0] res[record.id] = { 'balance' : record.amount + data[0], 'paid' : not (record.amount + data[0]) > 0, } return res def _get_loan_reimbursement_from_expense_lines(self, cr, uid, ids, context=None): expense_line = {} for line in self.pool.get('hr.expense.line').browse(cr, uid, ids, context=context): expense_line[line.loan_id.id] = True expense_line_ids = [] if expense_line: expense_line_ids = self.pool.get('hr.expense.loan').search(cr, uid, [('id','in',expense_line.keys())], context=context) return expense_line_ids _columns = { 'name' : fields.char('Name', size=64, select=True, readonly=True), 'description' : fields.char('Description', size=128, select=True, required=True, readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'date' : fields.date('Date', required=True, select=True, readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'employee_id' : fields.many2one('hr.employee', 'Employee', required=True, domain=[('hr_employee', '=', 'employee')] , readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'expense_line_ids' : fields.one2many('hr.expense.line', 'loan_id', 'Expense Line', readonly=True), 'state' : fields.selection([ ('draft', 'Draft'), ('approved', 'Approved'), ('confirmed', 'Confirmed'), ('closed', 'Closed'), ('cancel', 'Cancelled') ], 'State', readonly=True, help="State of the Driver Loan. ", select=True), 'reimbursement_method' : fields.selection([ ('weekly', 'Weekly'), ('fortnightly', 'Fortnightly'), ('monthly', 'Monthly'), ], 'Reimbursement Method', readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}, help="""Select Loan Recovery Method:

- Weekly: Reimbursement will be applied every week, considering only 4 weeks in each month

  • Fortnightly: Reimbursement will be applied forthnightly, considering only 2 reimbursement in each month, applied the 14th and 28th day of the month.

  • Monthy: Reimbursement will be applied only once a month, applied the 28th day of the month. . """, select=True, required=True),

    'reimbursement_type' : fields.selection([ ('fixed', 'Fixed'), ('percent', 'Loan Percentage'), ], 'Reimbursement Type', readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}, required=True, help="""Select Loan Recovery Type:

  • Fixed: Reimbursement will a fixed amount

  • Percent: Reimbursement will be a percentage of total Loan Amount """, select=True),

    'notes' : fields.text('Notes'), 'origin' : fields.char('Source Document', size=64, help="Reference of the document that generated this Expense Record", readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'amount' : fields.float('Amount', digits_compute=dp.get_precision('Sale Price'), required=True, readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'percent_reimbursement' : fields.float('Percent (%)', digits_compute=dp.get_precision('Sale Price'), required=False, help="Please set percent as 10.00%", readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'fixed_reimbursement' : fields.float('Fixed Reimbursement', digits_compute=dp.get_precision('Sale Price'), required=False, readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}), 'balance' : fields.function(_balance, method=True, digits_compute=dp.get_precision('Sale Price'), string='Balance', type='float', multi=True, store={ 'hr.expense.loan': (lambda self, cr, uid, ids, c={}: ids, ['notes', 'amount','state','expense_line_ids'], 10), 'hr.expense.line': (_get_loan_reimbursement_from_expense_lines, ['product_uom_qty', 'price_unit'], 10), }), #store = {'hr.expense.line': (_get_loan_reimbursement_from_expense_lines, None, 50)}), 'paid' : fields.function(_balance, method=True, string='Paid', type='boolean', multi=True, store={ 'hr.expense.loan': (lambda self, cr, uid, ids, c={}: ids, ['notes','amount','state','expense_line_ids'], 10), 'hr.expense.line': (_get_loan_reimbursement_from_expense_lines, ['product_uom_qty', 'price_unit'], 10), }), #store = {'hr.expense.line': (_get_loan_reimbursement_from_expense_lines, None, 50)}), 'product_id' : fields.many2one('product.product', 'Reimbursement Product', readonly=True, states={'draft':[('readonly',False)], 'approved':[('readonly',False)]}, required=True, domain=[('hr_employee_category', '=', ('salary_reimbursement'))], ondelete='restrict'), #'shop_id' : fields.related('employee_id', 'shop_id', type='many2one', relation='sale.shop', string='Shop', store=True, readonly=True), 'company_id' : fields.related('shop_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), 'create_uid' : fields.many2one('res.users', 'Created by', readonly=True), 'create_date' : fields.datetime('Creation Date', readonly=True, select=True), 'cancelled_by' : fields.many2one('res.users', 'Cancelled by', readonly=True), 'date_cancelled': fields.datetime('Date Cancelled', readonly=True), 'approved_by' : fields.many2one('res.users', 'Approved by', readonly=True), 'date_approved' : fields.datetime('Date Approved', readonly=True), 'confirmed_by' : fields.many2one('res.users', 'Confirmed by', readonly=True), 'date_confirmed': fields.datetime('Date Confirmed', readonly=True), 'closed_by' : fields.many2one('res.users', 'Closed by', readonly=True), 'date_closed' : fields.datetime('Date Closed', readonly=True),

    }

    _defaults = {

    'date' : lambda *a: time.strftime(DEFAULT_SERVER_DATE_FORMAT), 'state' : lambda *a: 'draft',

    }

    _sql_constraints = [

    ('name_uniq', 'unique(name)', 'Loan record must be unique !'),

    ]

    def create(self, cr, uid, vals, context=None):

    values = vals if 'employee_id' in vals and vals['employee_id']: employee = self.pool.get('hr.employee').browse(cr, uid, [vals['employee_id']])[0] seq_id = employee.company_id.hr_loan_seq.id if seq_id: seq_number = self.pool.get('ir.sequence').get_id(cr, uid, seq_id) values['name'] = seq_number else: raise osv.except_osv(_('Loan Sequence Error !'), _('You have not defined Loan Sequence for company ' + employee.company_id.name)) return super(hr_expense_loan, self).create(cr, uid, values, context=context)

    def action_approve(self, cr, uid, ids, context=None):

    for rec in self.browse(cr, uid, ids, context=context): if rec.amount <= 0.0: raise osv.except_osv( _('Could not approve Loan !'), _('Amount must be greater than zero.')) self.write(cr, uid, ids, {'state':'approved', 'approved_by' : uid,'date_approved':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) for (id,name) in self.name_get(cr, uid, ids): message = _("Loan '%s' is set to Approved.") % name self.log(cr, uid, id, message) return True

    def action_confirm(self, cr, uid, ids, context=None):

    for rec in self.browse(cr, uid, ids, context=context): self.write(cr, uid, ids, {'state':'confirmed', 'confirmed_by' : uid,'date_confirmed':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) for (id,name) in self.name_get(cr, uid, ids): message = _("Loan '%s' is set to Confirmed.") % name self.log(cr, uid, id, message) return True

    def action_cancel(self, cr, uid, ids, context=None):

    for rec in self.browse(cr, uid, ids, context=context): self.write(cr, uid, ids, {'state':'cancel', 'cancelled_by' : uid,'date_cancelled':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) for (id,name) in self.name_get(cr, uid, ids): message = _("Loan '%s' is set to Cancel.") % name self.log(cr, uid, id, message) return True

    def action_close(self, cr, uid, ids, context=None):

    for rec in self.browse(cr, uid, ids, context=context): self.write(cr, uid, ids, {'state':'closed', 'closed_by' : uid,'date_closed':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) for (id,name) in self.name_get(cr, uid, ids): message = _("Loan '%s' is set to Closed even when it is not paid.") % name if rec.balance > 0.0 else _("Loan '%s' is set to Closed.") % name self.log(cr, uid, id, message) return True

    def get_loan_reimbursement(self, cr, uid, employee_id, expense_id, context=None):

    expense_line_obj = self.pool.get('hr.expense.line') expense_obj = self.pool.get('hr.expense') res = expense_line_obj.search(cr, uid, [('expense_id', '=', expense_id),('control','=', 1),('loan_id','!=',False)]) print "res: ", res if len(res): loan_ids = [] expense_line_ids = [] for x in expense_obj.browse(cr, uid, [expense_id])[0].expense_line: if x.loan_id.id: loan_ids.append(x.loan_id.id) expense_line_ids.append(x.id) if len(loan_ids): expense_line_obj.unlink(cr, uid, expense_line_ids) self.write(cr, uid,loan_ids, {'state':'confirmed', 'closed_by' : False, 'date_closed':False} ) prod_obj = self.pool.get('product.product') loan_ids = self.search(cr, uid, [('employee_id', '=', employee_id),('state','=','confirmed'),('balance', '>', 0.0)]) for rec in self.browse(cr, uid, loan_ids, context=context): cr.execute('select date from hr_expense_line where loan_id = %s order by date desc limit 1' % (rec.id)) data = filter(None, map(lambda x:x[0], cr.fetchall())) date = data[0] if data else rec.date date_liq = expense_obj.read(cr, uid, [expense_id], ['date'])[0]['date'] print "date_liq: ", date_liq dur = datetime.strptime(date_liq, '%Y-%m-%d') - datetime.strptime(date, '%Y-%m-%d') product = prod_obj.browse(cr, uid, [rec.product_id.id])[0] xfactor = 7 if rec.reimbursement_method == 'weekly' else 14.0 if rec.reimbursement_method == 'fortnightly' else 28.0 rango = 1 if not int(dur.days / xfactor) else int(dur.days / xfactor) + 1 balance = rec.balance while rango and balance: rango -= 1 reimbursement = rec.fixed_reimbursement if rec.reimbursement_type == 'fixed' else rec.amount *rec.percent_reimbursement / 100.0 reimbursement = balance if reimbursement > balance else reimbursement balance -= reimbursement xline = { 'expense_id' : expense_id, 'line_type' : product_category, 'name' : product.name + ' - ' + rec.name, 'sequence' : 100, 'product_id' : product.id, 'product_uom' : product.uom_id.id, 'product_uom_qty' : 1, 'price_unit' : reimbursement * -1.0, 'control' : True, 'loan_id' : rec.id, } res = expense_line_obj.create(cr, uid, xline) if reimbursement >= rec.balance: self.write(cr, uid, [rec.id], {'state':'closed', 'closed_by' :uid,'date_closed':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) for (id,name) in self.name_get(cr, uid, [rec.id]): message = _("Loan '%s' has been Closed.") % rec.name self.log(cr, uid, id, message) return

The VIEW

hr_expense_loan_view.xml

<openerp> <data>

<record id="view_hr_expense_loan_tree" model="ir.ui.view"> <field name="name">hr.expense.loan.tree</field> <field name="model">hr.expense.loan</field> <field name="type">tree</field> <field name="priority">2</field> <field name="arch" type="xml"> <tree string="Drivers Loans" colors="red:state=='draft';gray:state=='cancel';green:state=='approve';blue:state=='confirm';"> <field name="name"/> <field name="date"/> <field name="employee_id"/> <field name="product_id"/> <field name="amount" sum="Amount"/> <field name="balance" sum="Balance"/>
<field name="paid"/> <field name="state"/> </tree> </field> </record>

<record id="view_hr_expense_loan_form" model="ir.ui.view"> <field name="name">hr.expense.loan.form</field> <field name="model">hr.expense.loan</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Employee Loans" version="7.0"> <header> <button name="action_approve" states="draft" string="Approve" type="object" icon="gtk-go-forward" groups="hr_loan.group_expense_loan_approve" class="oe_highlight"/> <button name="action_confirm" states="approved" string="Confirm" type="object" icon="gtk-goto-last" groups="hr_loan.group_expense_loan_confirm" class="oe_highlight"/> <button name="action_close" states="confirmed" string="Close" type="object" icon="gtk-ok" groups="hr_loan.group_expense_loan_close" /> <button name="action_cancel" states="draft,approved" string="Cancel" type="object" icon="gtk-cancel" groups="hr_loan.group_expense_loan_cancel"/> <field name="state" widget="statusbar" statusbar_visible="draft,approved,confirmed,closed"/> </header> <sheet> <h1> <label string="Loan"/> <field name="name" class="oe_inline" readonly="1"/> </h1> <group col="4"> <field name="date"/> <field name="origin"/> </group> <field name="company_id" invisible="1"/> <!--<field name="shop_id" invisible="1"/>--> <notebook> <page string="Loan Details"> <group colspan="4" col="4"> <field name="employee_id" colspan="4" context="{'hr_employee_category': 'employee','hr_employee_category': False}" domain="[('hr_employee','=', False),('hr_employee_category','=','employee')]" /> <field name="product_id" colspan="4"/> <field name="amount" /> <newline /> <field name="reimbursement_method"/> <newline /> <field name="reimbursement_type"/> <newline /> <field name="percent_reimbursement" attrs="{'required':[('reimbursement_type','=','percent')],'invisible':[('reimbursement_type','!=','percent')]}"/> <newline /> <field name="fixed_reimbursement" attrs="{'required':[('reimbursement_type','=','fixed')],'invisible':[('reimbursement_type','!=','fixed')]}"/> <newline /> <field name="description" colspan="4" /> <separator string="Balance" colspan="4"/> <field name="balance" /> <field name="paid" /> </group> </page> <page string="Notes"> <field colspan="4" name="notes" nolabel="1"/> </page> <page string="Loan Expense Lines"> <group col="4"> <field name="expense_line_ids" colspan="4" nolabel="1"> <tree> <field name="expense_id" /> <!--<field name="date" />--> <field name="product_id" /> <field name="name" /> <!--<field name="price_total" />--> </tree> </field> </group> </page> <page string="Log"> <group colspan="4" col="4"> <field name="create_uid" readonly="1" /> <field name="create_date" readonly="1" /> <field name="approved_by" readonly="1" /> <field name="date_approved" readonly="1" /> <field name="confirmed_by" readonly="1" /> <field name="date_confirmed" readonly="1" /> <field name="closed_by" readonly="1" /> <field name="date_closed" readonly="1" /> <field name="cancelled_by" readonly="1" /> <field name="date_cancelled" readonly="1" /> </group> </page> </notebook> </sheet> <div class="oe_chatter"> <field name="message_follower_ids" widget="mail_followers"/> <field name="message_ids" widget="mail_thread" placeholder="Share a message..."/> </div> </form> </field> </record> <record id="view_hr_expense_loan_filter" model="ir.ui.view"> <field name="name">tms.expense.loan.filter</field> <field name="model">tms.expense.loan</field> <field name="type">search</field> <field name="arch" type="xml"> <search string="Search Loans"> <filter icon="terp-gtk-media-pause" string="Draft" domain="[('state','=','draft')]"/> <filter icon="terp-gtk-jump-to-ltr" string="Approved" domain="[('state','=','approved')]"/> <filter icon="terp-check" string="Confirmed" domain="[('state','=','confirmed')]"/> <filter icon="terp-check" string="Not Paid" domain="[('paid','=',0)]"/> <filter icon="terp-check" string="Paid" domain="[('paid','=',1)]"/> <newline/> <field name="name" select="1"/> <field name="employee_id" /> <field name="product_id" /> <field name="date" string="Expense date" /> <newline/> <group expand="0" string="Group By..." > <filter string="Employee" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/> <filter string="Product" icon="terp-personal" domain="[]" context="{'group_by':'product_id'}"/> <filter string="Paid" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'paid'}"/> <separator orientation="vertical"/> <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/> <filter string="Expense Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}"/> </group> </search> </field> </record> <record model="ir.ui.view" id="view_hr_expense_loan_graph"> <field name="name">hr.expense.loan.graph</field> <field name="model">hr.expense.loan</field> <field name="type">graph</field> <field name="arch" type="xml"> <graph string="Expense" type="bar"> <field name="product_id"/> <field name="amount" operator="+"/> </graph> </field> </record> <record id="action_hr_expense_loan_form" model="ir.actions.act_window"> <field name="name">Employees Loans</field> <field name="type">ir.actions.act_window</field> <field name="res_model">hr.expense.loan</field> <field name="view_type">form</field> <field name="view_mode">tree,form,graph</field> <field name="search_view_id" ref="view_tms_expense_loan_filter"/> <field name="help">Employee Loans</field> </record> <!--<menuitem action="action_hr_expense_loan_form" id="menu_hr_expense_loan" parent="menu_hr_config_employeess" sequence="40" />--> <menuitem action="action_hr_expense_loan_form" id="hr_menu_hr_expense_loan" parent="hr.menu_hr_main" sequence="90" /> </data>

</openerp>

The Secutity

hr_loan_security.xml

<openerp> <data noupdate="0">

<record model="ir.module.category" id="hr_loan.module_category_hr_loan_management"> <field name="name">HR LOAN</field> <field name="description">Helps you manage HR loans.</field> <field name="sequence">2</field> </record>

<record id="hr_loan.group_expense_loan_approve" model="res.groups"> <field name="name">Can Approve Driver Loans</field> <field name="category_id" ref="hr_loan.module_category_hr_loan_management"/> <field name="comment">The user will be able to Approve Employees Loans Records.</field> </record> <record id="hr_loan.group_expense_loan_confirm" model="res.groups"> <field name="name">Can Confirm Employees Loans</field> <field name="category_id" ref="hr_loan.module_category_hr_loan_management"/> <field name="comment">The user will be able to Confirm Employees Loans Records.</field> </record> <record id="hr_loan.group_expense_loan_cancel" model="res.groups"> <field name="name">Can Cancel Employees Loans</field> <field name="category_id" ref="hr_loan.module_category_hr_loan_management"/> <field name="comment">The user will be able to Cancel Employees Loans Records.</field> </record> <record id="hr_loan.group_expense_loan_close" model="res.groups"> <field name="name">Can Close Employees Loans</field> <field name="category_id" ref="hr_loan.module_category_hr_loan_management"/> <field name="comment">The user will be able to Set to Draft Employees Loans Records.</field> </record>

</data>

</openerp>

If you can test.

Waiting for your feedback.

The last thing to do is the salary computation::

For this you can create a rule, let' call it "Salary after Reimbursement", by substracting the value of the field "balance" from the salary received.

CREDIT

All credit goes to Argilsoft.

The __openerp__.py file

{
"name" : "Loan Management",

"version" : "1.0", "category" : "HR", 'complexity' : "normal", "author" : "", "website" : "", "depends" : ["base", "hr", "hr_contract"], "summary" : "Management for Employee Loans", "description" : """

Management for Employee Loans

""",

"data" : [ 'security/hr_loan_security.xml', 'hr_expense_loan_view.xml', ], "application": False, "installable": True

And last the __init__.py file

import hr_expense_loan

Avatar
Discard
Best Answer

Hello,

You can use https://www.odoo.com/apps/modules/10.0/employee_advance_salary/.

Regards,

Probuse Consulting Service Pvt Ltd

www.probuse.com


Avatar
Discard
Best Answer

@Med Said BARA, do you have the cleaned files for this module, when i copy your code its all in one line and doesnt execute.

Avatar
Discard
Best Answer

Here might be a trick: You can charge zero salary. Then by supplier payment click reconcile this liability and for the difference amount(full salary advance) choose reconcile payment balance. choose the salary advance account and confirm. The result is: The payment goes to salary advance account.

As for the deduction: When you open the supplier payment doducment you will see the advance given. Click to reconcile this advance by zero payment and choose the account you want.

Avatar
Discard
Best Answer

you have to make a new module and inherit the hr_payroll module .

have to make a new advance salary field

and at monthly payment you have to make a calculation to subtract the advance salary amount.

Avatar
Discard
Author

If you don't mind post the code .Please help me to correct my requirements.

Author

I want the requirement.pls rply

Author

Is any dependency module for this hr_expense_loan.py

I've posted the __openerp__ and the __init__ files. There is no other requirements. I just have to clean the views.

make a new module and inherit hr_payroll

make field advance salary and in a hr_payroll

i will check it and replay you

You have to create a folder hr_loan for the module , and then put the files in this folder, create a subfolder "security" under it and put the hr_loan_security.xml in this subfolder. I've tested on my side and it works. I have to clean the files from unneeded data.

Best Answer

tell me how to do the payment of the loan?

Avatar
Discard