[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:
Quentin (OpenERP)
2011-05-12 09:49:18 +02:00
7 changed files with 206 additions and 17 deletions
+1
View File
@@ -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',
+44 -13
View File
@@ -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):
+58 -2
View File
@@ -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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
10 access_hr_payroll_structure_manager hr.payroll.structure.manager model_hr_payroll_structure base.group_hr_manager 1 1 1 1
11 access_hr_payslip_worked_days hr.payslip.worked_days model_hr_payslip_worked_days base.group_hr_manager 1 1 1 1
12 access_hr_salary_rule hr.salary.rule model_hr_salary_rule base.group_hr_manager 1 1 1 1
13 access_hr_payslip_run hr.payslip.run model_hr_payslip_run base.group_hr_manager 1 1 1 1
14 access_hr_payslip_input hr.payslip.input model_hr_payslip_input base.group_hr_manager 1 1 1 1
15 access_hr_rule_input hr.rule.input model_hr_rule_input base.group_hr_manager 1 1 1 1
+2 -2
View File
@@ -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>