[MERGE] merged the branch of psi with payslip run feature (+add required=True on name field of payslip.run)
bzr revid: qdp-launchpad@openerp.com-20110512074918-7h5qqgj4an2smayy
This commit is contained in:
@@ -49,6 +49,7 @@ Generic Payroll system.
|
||||
],
|
||||
'update_xml': [
|
||||
'security/hr_security.xml',
|
||||
'wizard/hr_payroll_payslips_by_employees.xml',
|
||||
'hr_payroll_view.xml',
|
||||
'hr_payroll_workflow.xml',
|
||||
'hr_payroll_sequence.xml',
|
||||
|
||||
@@ -202,6 +202,29 @@ class one2many_mod2(fields.one2many):
|
||||
res[r[self._fields_id]].append( r['id'] )
|
||||
return res
|
||||
|
||||
class hr_payslip_run(osv.osv):
|
||||
|
||||
_name = 'hr.payslip.run'
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'slip_ids': fields.one2many('hr.payslip', 'payslip_run_id', 'Payslips', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'state': fields.selection([
|
||||
('draft', 'Draft'),
|
||||
('close', 'Close'),
|
||||
], 'State', select=True, readonly=True)
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
}
|
||||
|
||||
def draft_payslip_run(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||
|
||||
def close_payslip_run(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||
|
||||
hr_payslip_run()
|
||||
|
||||
class hr_payslip(osv.osv):
|
||||
'''
|
||||
Pay Slip
|
||||
@@ -213,18 +236,19 @@ class hr_payslip(osv.osv):
|
||||
def _get_lines_salary_rule_category(self, cr, uid, ids, field_names, arg=None, context=None):
|
||||
result = {}
|
||||
if not ids: return result
|
||||
for id in ids:
|
||||
result.setdefault(id, [])
|
||||
cr.execute('''SELECT pl.slip_id, pl.id FROM hr_payslip_line AS pl \
|
||||
LEFT JOIN hr_salary_rule_category AS sh on (pl.category_id = sh.id) \
|
||||
WHERE pl.slip_id in %s \
|
||||
GROUP BY pl.slip_id, pl.sequence, pl.id ORDER BY pl.sequence''',(tuple(ids),))
|
||||
res = cr.fetchall()
|
||||
for r in res:
|
||||
result.setdefault(r[0], [])
|
||||
result[r[0]].append(r[1])
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'struct_id': fields.many2one('hr.payroll.structure', 'Structure', help='Defines the rules that have to be applied to this payslip, accordingly to the contract chosen. If you let empty the field contract, this field isn\'t mandatory anymore and thus the rules applied will be all the rules set on the structure of all contracts of the employee valid for the chosen period'),
|
||||
'struct_id': fields.many2one('hr.payroll.structure', 'Structure', readonly=True, states={'draft': [('readonly', False)]}, help='Defines the rules that have to be applied to this payslip, accordingly to the contract chosen. If you let empty the field contract, this field isn\'t mandatory anymore and thus the rules applied will be all the rules set on the structure of all contracts of the employee valid for the chosen period'),
|
||||
'name': fields.char('Description', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'number': fields.char('Reference', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'employee_id': fields.many2one('hr.employee', 'Employee', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
@@ -245,15 +269,16 @@ class hr_payslip(osv.osv):
|
||||
\n* If the salary is paid then state is set to \'Paid Salary\'.\
|
||||
\n* The \'Reject\' state is used when user cancel payslip.'),
|
||||
# 'line_ids': fields.one2many('hr.payslip.line', 'slip_id', 'Payslip Line', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'line_ids': one2many_mod2('hr.payslip.line', 'slip_id', 'Payslip Line',readonly=True),
|
||||
'line_ids': one2many_mod2('hr.payslip.line', 'slip_id', 'Payslip Lines', readonly=True, states={'draft':[('readonly',False)]}),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'worked_days_line_ids': fields.one2many('hr.payslip.worked_days', 'payslip_id', 'Payslip Worked Days', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'input_line_ids': fields.one2many('hr.payslip.input', 'payslip_id', 'Payslip Inputs', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'paid': fields.boolean('Made Payment Order ? ', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'note': fields.text('Description'),
|
||||
'note': fields.text('Description', readonly=True, states={'draft':[('readonly',False)]}),
|
||||
'contract_id': fields.many2one('hr.contract', 'Contract', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'details_by_salary_rule_category': fields.function(_get_lines_salary_rule_category, method=True, type='one2many', relation='hr.payslip.line', string='Details by Salary Rule Category'),
|
||||
'credit_note': fields.boolean('Credit Note', help="Indicates this payslip has a refund of another"),
|
||||
'payslip_run_id': fields.many2one('hr.payslip.run', 'Payslip Run', readonly=True, states={'draft': [('readonly', False)]}),
|
||||
}
|
||||
_defaults = {
|
||||
'date_from': lambda *a: time.strftime('%Y-%m-01'),
|
||||
@@ -401,7 +426,7 @@ class hr_payslip(osv.osv):
|
||||
for payslip in self.browse(cr, uid, ids, context=context):
|
||||
#delete old payslip lines
|
||||
old_slipline_ids = slip_line_pool.search(cr, uid, [('slip_id', '=', payslip.id)], context=context)
|
||||
old_slipline_ids
|
||||
# old_slipline_ids
|
||||
if old_slipline_ids:
|
||||
slip_line_pool.unlink(cr, uid, old_slipline_ids, context=context)
|
||||
if payslip.contract_id:
|
||||
@@ -587,26 +612,29 @@ class hr_payslip(osv.osv):
|
||||
#defaults
|
||||
res = {'value':{
|
||||
'line_ids':[],
|
||||
'input_line_ids': [],
|
||||
'worked_days_line_ids': [],
|
||||
#'details_by_salary_head':[], TODO put me back
|
||||
'name':'',
|
||||
'contract_id': False,
|
||||
'struct_id': False,
|
||||
}
|
||||
}
|
||||
}
|
||||
if not employee_id:
|
||||
return res
|
||||
ttyme = datetime.fromtimestamp(time.mktime(time.strptime(date_from, "%Y-%m-%d")))
|
||||
employee_id = empolyee_obj.browse(cr, uid, employee_id, context=context)
|
||||
res['value'].update({
|
||||
'name': _('Salary Slip of %s for %s') % (employee_id.name, tools.ustr(ttyme.strftime('%B-%Y'))),
|
||||
'company_id': employee_id.company_id.id
|
||||
})
|
||||
'name': _('Salary Slip of %s for %s') % (employee_id.name, tools.ustr(ttyme.strftime('%B-%Y'))),
|
||||
'company_id': employee_id.company_id.id
|
||||
})
|
||||
|
||||
if not context.get('contract', False):
|
||||
#fill with the first contract of the employee
|
||||
contract_ids = self.get_contract(cr, uid, employee_id, date_from, date_to, context=context)
|
||||
res['value'].update({
|
||||
'struct_id': contract_ids and contract_obj.read(cr, uid, contract_ids[0], ['struct_id'], context=context)['struct_id'][0] or False,
|
||||
'contract_id': contract_ids and contract_ids[0] or False,
|
||||
'struct_id': contract_ids and contract_obj.read(cr, uid, contract_ids[0], ['struct_id'], context=context)['struct_id'][0] or False,
|
||||
'contract_id': contract_ids and contract_ids[0] or False,
|
||||
})
|
||||
else:
|
||||
if contract_id:
|
||||
@@ -614,7 +642,10 @@ class hr_payslip(osv.osv):
|
||||
contract_ids = [contract_id]
|
||||
#fill the structure with the one on the selected contract
|
||||
contract_record = contract_obj.browse(cr, uid, contract_id, context=context)
|
||||
res['value'].update({'struct_id': contract_record.struct_id.id, 'contract_id': contract_id})
|
||||
res['value'].update({
|
||||
'struct_id': contract_record.struct_id.id,
|
||||
'contract_id': contract_id
|
||||
})
|
||||
else:
|
||||
#if we don't give the contract, then the input to fill should be for all current contracts of the employee
|
||||
contract_ids = self.get_contract(cr, uid, employee_id, date_from, date_to, context=context)
|
||||
@@ -627,7 +658,7 @@ class hr_payslip(osv.osv):
|
||||
res['value'].update({
|
||||
'worked_days_line_ids': worked_days_line_ids,
|
||||
'input_line_ids': input_line_ids,
|
||||
})
|
||||
})
|
||||
return res
|
||||
|
||||
def onchange_contract_id(self, cr, uid, ids, date_from, date_to, employee_id=False, contract_id=False, context=None):
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
<field name="model">hr.payslip</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="blue:state in ('confirm','hr_check','accont_check');black:state in ('new');gray:state in('cancel')" string="Payslip">
|
||||
<tree colors="blue:state in ('confirm','hr_check','accont_check');black:state in ('new');gray:state in('cancel')" string="Payslips">
|
||||
<field name="number"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="name"/>
|
||||
@@ -260,7 +260,7 @@
|
||||
</field>
|
||||
</page>
|
||||
<!-- TODO: put me back -->
|
||||
<page string="Details By Salary Rule Category">
|
||||
<page string="Details By Salary Rule Category">
|
||||
<field name="details_by_salary_rule_category" context="{'group_by':'category_id'}" domain="[('appears_on_payslip', '=', True)]" nolabel="1">
|
||||
<tree string="Payslip Lines" colors="blue:total == 0">
|
||||
<field name="category_id"/>
|
||||
@@ -318,6 +318,7 @@
|
||||
<separator colspan="4" string="Other Information"/>
|
||||
<group col="5" colspan="2">
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
<field name="payslip_run_id" domain="[('state','=','draft')]"/>
|
||||
<field name="paid" readonly="1"/>
|
||||
</group>
|
||||
<newline/>
|
||||
@@ -620,6 +621,61 @@
|
||||
|
||||
<act_window domain="[('slip_id', '=', active_id)]" id="act_payslip_lines" name="Payslip Lines" res_model="hr.payslip.line" src_model="hr.payslip"/>
|
||||
|
||||
<record id="hr_payslip_run_filter" model="ir.ui.view">
|
||||
<field name="name">hr.payslip.run.search</field>
|
||||
<field name="model">hr.payslip.run</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Payslips Group">
|
||||
<field name="name"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_payslip_run_tree" model="ir.ui.view">
|
||||
<field name="name">hr.payslip.run.tree</field>
|
||||
<field name="model">hr.payslip.run</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Payslips Run">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_payslip_run_form" model="ir.ui.view">
|
||||
<field name="name">hr.payslip.run.form</field>
|
||||
<field name="model">hr.payslip.run</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Payslips Run">
|
||||
<group col="6" colspan="6">
|
||||
<field name="name"/>
|
||||
</group>
|
||||
<notebook colspan="6">
|
||||
<page string="Payslips">
|
||||
<field name="slip_ids" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="6" colspan="6">
|
||||
<field name="state"/>
|
||||
<button name="%(action_hr_payslip_by_employees)d" type="action" states="draft" icon="gtk-execute" string="Generate Payslips" />
|
||||
<button name="close_payslip_run" type="object" icon="gtk-jump-to" string="Close" states="draft"/>
|
||||
<button string="Set to Draft" icon="terp-stock_effects-object-colorize" name="draft_payslip_run" type="object" states="close"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_payslip_run_tree" model="ir.actions.act_window">
|
||||
<field name="name">Payslips Run</field>
|
||||
<field name="res_model">hr.payslip.run</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="hr_payslip_run_tree"/>
|
||||
<field name="search_view_id" ref="hr_payslip_run_filter"/>
|
||||
</record>
|
||||
<menuitem action="action_hr_payslip_run_tree" id="menu_hr_payslip_run" parent="menu_hr_root_payroll"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
"access_hr_payroll_structure_manager","hr.payroll.structure.manager","model_hr_payroll_structure","base.group_hr_manager",1,1,1,1
|
||||
"access_hr_payslip_worked_days ","hr.payslip.worked_days","model_hr_payslip_worked_days","base.group_hr_manager",1,1,1,1
|
||||
"access_hr_salary_rule","hr.salary.rule","model_hr_salary_rule","base.group_hr_manager",1,1,1,1
|
||||
"access_hr_payslip_run","hr.payslip.run","model_hr_payslip_run","base.group_hr_manager",1,1,1,1
|
||||
"access_hr_payslip_input","hr.payslip.input","model_hr_payslip_input","base.group_hr_manager",1,1,1,1
|
||||
"access_hr_rule_input","hr.rule.input","model_hr_rule_input","base.group_hr_manager",1,1,1,1
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#-*- coding:utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# d$
|
||||
#
|
||||
@@ -24,5 +24,5 @@
|
||||
import hr_payroll_employees_detail
|
||||
#import hr_payroll_create_analytic
|
||||
import hr_payroll_year_salary
|
||||
|
||||
import hr_payroll_payslips_by_employees
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
from datetime import datetime
|
||||
from dateutil import relativedelta
|
||||
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
class hr_payslip_employees(osv.osv_memory):
|
||||
|
||||
_name ='hr.payslip.employees'
|
||||
_description = 'Generate payslips for all selected employees'
|
||||
_columns = {
|
||||
'employee_ids': fields.many2many('hr.employee', 'hr_employee_group_rel', 'payslip_id', 'employee_id', 'Employees'),
|
||||
}
|
||||
|
||||
def compute_sheet(self, cr, uid, ids, context=None):
|
||||
emp_pool = self.pool.get('hr.employee')
|
||||
slip_pool = self.pool.get('hr.payslip')
|
||||
slip_ids = []
|
||||
if context is None:
|
||||
context = {}
|
||||
data = self.read(cr, uid, ids, context=context)[0]
|
||||
if not data['employee_ids']:
|
||||
raise osv.except_osv(_("Warning !"), _("You must select employee(s) to generate payslip(s)"))
|
||||
for emp in emp_pool.browse(cr, uid, data['employee_ids'], context=context):
|
||||
slip_data = slip_pool.onchange_employee_id(cr, uid, [], time.strftime('%Y-%m-01'), str(datetime.now() + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10], emp.id, contract_id=False, context=context)
|
||||
res = {
|
||||
'employee_id': emp.id,
|
||||
'name': slip_data['value'].get('name', False),
|
||||
'struct_id': slip_data['value'].get('struct_id', False),
|
||||
'contract_id': slip_data['value'].get('contract_id', False),
|
||||
'payslip_run_id': context.get('active_id', False),
|
||||
'input_line_ids': [(0, 0, x) for x in slip_data['value'].get('input_line_ids', False)],
|
||||
'worked_days_line_ids': [(0, 0, x) for x in slip_data['value'].get('worked_days_line_ids', False)]
|
||||
}
|
||||
slip_ids.append(slip_pool.create(cr, uid, res, context=context))
|
||||
slip_pool.compute_sheet(cr, uid, slip_ids, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
hr_payslip_employees()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_hr_payslip_by_employees" model="ir.ui.view">
|
||||
<field name="name">hr_payroll_payslip_employees</field>
|
||||
<field name="model">hr.payslip.employees</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Payslips by Employees">
|
||||
<group colspan="4" >
|
||||
<separator string="Payslips by Employees" colspan="4"/>
|
||||
<label colspan="4" nolabel="1" string="This wizard will generate payslips for all selected employee(s)" />
|
||||
<newline/>
|
||||
<field name="employee_ids" nolabel="1"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-execute" string="Generate" name="compute_sheet" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_payslip_by_employees" model="ir.actions.act_window">
|
||||
<field name="name">Generate Payslips</field>
|
||||
<field name="res_model">hr.payslip.employees</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_hr_payslip_by_employees"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user