Commit fce63fb7 authored by Kevin Deldycke's avatar Kevin Deldycke

A very alpha version of the Payroll report. Consider this as a prototype or a...

A very alpha version of the Payroll report. Consider this as a prototype or a mockup, not a bullet-proof feature for production environment.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@7711 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 027f6053
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.CMFCore.ActionInformation</string>
<string>ActionInformation</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_report</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>payroll_report</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>25.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payroll Report</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<tuple>
<string>Products.CMFCore.Expression</string>
<string>Expression</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/AccountingTransactionModule_viewPayrollReportDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -70,128 +70,116 @@ ...@@ -70,128 +70,116 @@
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[ <value> <string encoding="cdata"><![CDATA[
"""\n
WARNING: Please don\'t use this report as model.\n
This report is a quick and dirty mockup, a protoype\n
not intended to be used in production environment.\n
"""\n
\n
import DateTime\n import DateTime\n
portal_catalog = context.getPortalObject().portal_catalog\n portal = context.getPortalObject()\n
portal_catalog = portal.portal_catalog\n
N_ = portal.Base_translateString\n
\n \n
query = {\n year = int(year)\n
"portal_type" : "Pay Sheet Transaction",\n
"simulation_state" : ["confirmed", "stopped", "delivered", "draft", "planned"],\n
"delivery.stop_date" : ">2004-12-31",\n
"delivery.start_date" : "<2005-12-31",\n
"sort_on" : ("delivery.start_date", "ASC")\n
}\n
\n \n
if 0 :\n query = { \'portal_type\' : \'Pay Sheet Transaction\'\n
print portal_catalog(src__ = 1, **query)\n , \'simulation_state\' : [\'confirmed\', \'stopped\', \'delivered\']\n
return printed\n , \'delivery.stop_date\' : \'>%s-12-31\' % (year - 1)\n
, \'delivery.start_date\': \'<%s-12-31\' % (year)\n
, \'sort_on\' : (\'delivery.start_date\', \'ASC\')\n
}\n
\n
# if 0:\n
# print portal_catalog(src__ = 1, **query)\n
# return printed\n
\n \n
\n \n
# DATA GATHERING part\n # DATA GATHERING part\n
\n \n
paysheet_par_person = {}\n paysheet_par_person = {}\n
\n \n
for ps in portal_catalog( **query ) :\n for ps in portal_catalog(**query):\n
ps = ps.getObject()\n ps = ps.getObject()\n
# Quick hack to fix some problems on a local site\n # Quick hack to fix some problems on a local site\n
# if ps.getStopDate()<DateTime.DateTime("2006-01-01"):\n # if ps.getStopDate()<DateTime.DateTime("2006-01-01"):\n
# print "<a href=\\"%s\\">%s</a> candidate to be updated (%s -> %s)<br>" % (ps.getPath(),ps.getDestinationSection(),ps.getSource(),ps.getDestination())\n # print "<a href=\\"%s\\">%s</a> candidate to be updated (%s -> %s)<br>" % (ps.getPath(),ps.getDestinationSection(),ps.getSource(),ps.getDestination())\n
# #ps.setSource(ps.getSourceSection())\n # #ps.setSource(ps.getSourceSection())\n
# #ps.setDestination(ps.getDestinationSection())\n # #ps.setDestination(ps.getDestinationSection())\n
if not paysheet_par_person.has_key(ps.getDestinationSection()) :\n if not paysheet_par_person.has_key(ps.getDestinationSection()):\n
paysheet_par_person[ps.getDestinationSection()] = []\n paysheet_par_person[ps.getDestinationSection()] = []\n
paysheet_par_person[ps.getDestinationSection()].append(ps)\n paysheet_par_person[ps.getDestinationSection()].append(ps)\n
\n \n
gathered_data = {}\n gathered_data = {}\n
\n \n
for p, paysheets in paysheet_par_person.items() :\n for p, paysheets in paysheet_par_person.items():\n
gathered_data[p] = {}\n gathered_data[p] = {}\n
for paysheet in paysheets :\n for paysheet in paysheets:\n
start_month = paysheet.start_date.month() - 1\n start_month = paysheet.start_date.month() - 1\n
if not gathered_data[p].has_key(start_month) :\n if not gathered_data[p].has_key(start_month):\n
gathered_data[p][start_month] = {}\n gathered_data[p][start_month] = {}\n
if gathered_data[p][start_month].has_key("salary") :\n if gathered_data[p][start_month].has_key("salary"):\n
if not gathered_data[p][start_month].has_key("duplicates") :\n if not gathered_data[p][start_month].has_key("duplicates"):\n
gathered_data[p][start_month]["duplicates"] = []\n gathered_data[p][start_month]["duplicates"] = []\n
gathered_data[p][start_month]["duplicates"].append(paysheet)\n gathered_data[p][start_month]["duplicates"].append(paysheet)\n
else :\n else :\n
# get the taxable salary\n # Get paysheet details\n
ps_details = paysheet.PaySheetTransaction_getDetails()\n ps_details = paysheet.PaySheetTransaction_getDetails()\n
salary_value = ps_details[salary_type]\n salary_value = ps_details[salary_type]\n
# Round the value the same way it is printed by PaySheetTransaction_viewPaySheetTransactionAsPDF.\n # Render the value the same way it is printed by PaySheetTransaction_viewPaySheetTransactionAsPDF.\n
# In fact the rounding must be done by PaySheetTransaction_getDetails to homogenize the value in the paysheet module.\n
gathered_data[p][start_month]["salary"] = float(\'%.2f\' % salary_value)\n gathered_data[p][start_month]["salary"] = float(\'%.2f\' % salary_value)\n
gathered_data[p][start_month]["url"] = paysheet.getPath()\n gathered_data[p][start_month]["url"] = paysheet.getPath()\n
gathered_data[p][start_month]["state"] = paysheet.getSimulationState()\n gathered_data[p][start_month]["state"] = paysheet.getSimulationState()\n
\n \n
# DISPLAY part\n # Sort by person name\n
\n sorted_data = {}\n
print """\n for person_path, paysheet_dict in gathered_data.items():\n
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n person_title = context.restrictedTraverse(person_path).getTitle()\n
"DTD/xhtml1-strict.dtd">\n sorted_data[(person_path, person_title)] = paysheet_dict\n
<html>\n items = sorted_data.items()\n
<head>\n items.sort(lambda x, y: cmp(x[0][1], y[0][1]))\n
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />\n gathered_data = [item for item in items]\n
<title>R\xc3\xa9capitulatif des salaires bruts</title>\n
<style>\n
a {text-decoration : none;}\n
a:hover {text-decoration : underline;}\n
\n \n
.warning {color: #f00;}\n
.warning a:link {color: #f00;}\n
.warning a:visited {color: #f00;}\n
.warning a:hover {color: #f00;}\n
\n \n
table {\n # REPORT part\n
border-collapse : collapse;\n # TODO: separate the rendering part and the logical part\n
}\n # TODO: use true ERP5 report\n
th, td {\n
border : 1px solid #CCC;\n
}\n
\n \n
td {\n print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">\n
text-align : right;\n <html><head>\n
}\n <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>\n
\n <title>%s</title>\n
th.total {\n <style>\n
background : #999;\n a {text-decoration: none}\n
}\n a:hover {text-decoration: underline}\n
\n .warning,\n
th.error {\n .warning a:link,\n
background : #F00;\n .warning a:visited,\n
}\n .warning a:hover {color: #f00}\n
table {border-collapse: collapse}\n
th, td {border: 1px solid #ccc}\n
td {text-align: right}\n
th.total {background: #999}\n
th.error {background: #f00}\n
</style>\n </style>\n
</head>\n </head><body>""" % (N_(\'Payroll Report\'))\n
<body>"""\n
\n \n
print "<h1>Annual %s Report</h1>" % (salary_type.replace(\'_\', \' \').title())\n print "<h1>%s</h1>" % N_("Annual ${report_type} Report", mapping={\'report_type\': unicode(salary_type.replace(\'_\', \' \').title(), \'utf8\')})\n
print "<h2>Fiscal year 2005</h2>"\n
\n \n
print """\n print "<h2>%s</h2>" % N_("Fiscal year ${year}", mapping={\'year\': unicode(str(year), \'utf8\')})\n
<table>\n \n
<tr>\n print "<table><tr><th></th>"\n
<th></th>\n month_list = [\'January\', \'February\', \'March\', \'April\', \'May\', \'June\', \'July\', \'August\', \'September\', \'October\', \'November\', \'December\']\n
<th>janvier</th>\n for month in month_list:\n
<th>fevrier</th>\n print "<th>%s</th>" % (N_(month))\n
<th>mars</th>\n print "<th class=\'total\'>%s</th></tr>" % (N_(\'Total\'))\n
<th>avril</th>\n
<th>mai</th>\n
<th>juin</th>\n
<th>juillet</th>\n
<th>aout</th>\n
<th>septembre</th>\n
<th>october</th>\n
<th>novembre</th>\n
<th>decembre</th>\n
<th class="total">Total</th>\n
</tr>\n
"""\n
\n \n
total = 0\n total = 0\n
monthly_total = {}\n monthly_total = {}\n
\n \n
for person_path, person_dict in gathered_data.items() :\n for ((person_path, person_title), person_dict) in gathered_data:\n
person_total = 0\n person_total = 0\n
print "<tr><td><a href=\\"%s\\">%s</a></td>" % (person_path, context.restrictedTraverse(person_path).getTitle())\n print "<tr><td><a href=\\"%s\\">%s</a></td>" % (person_path, person_title)\n
for month in range(12) :\n for month in range(12) :\n
print "<td>"\n print "<td>"\n
if person_dict.has_key(month) :\n if person_dict.has_key(month) :\n
...@@ -208,24 +196,20 @@ for person_path, person_dict in gathered_data.items() :\n ...@@ -208,24 +196,20 @@ for person_path, person_dict in gathered_data.items() :\n
print "<td>%s</td></tr>" % person_total\n print "<td>%s</td></tr>" % person_total\n
total += person_total\n total += person_total\n
\n \n
print "<th class=\\"total\\">Total</th>"\n print "<th class=\'total\'>%s</th>" % (N_(\'Total\'))\n
check_total = 0\n check_total = 0\n
for month in range(12) :\n for month in range(12):\n
print "<td>"\n print "<td>"\n
if monthly_total.has_key(month) :\n if monthly_total.has_key(month):\n
print monthly_total[month]\n print monthly_total[month]\n
check_total += monthly_total[month]\n check_total += monthly_total[month]\n
print "</td>"\n print "</td>"\n
\n \n
print "<th class=\\""\n print "<th class=\'"\n
if check_total != total :\n if check_total != total:\n
print "error"\n print "error"\n
print \'\\">%s</th>\' % total\n print "\'>%s</th>" % total\n
print """\n print "</table></body></html>"\n
</table>\n
</body>\n
</html>\n
"""\n
\n \n
return printed\n return printed\n
...@@ -242,15 +226,9 @@ return printed\n ...@@ -242,15 +226,9 @@ return printed\n
<key> <string>_filepath</string> </key> <key> <string>_filepath</string> </key>
<value> <string>Script (Python):/nexedi/portal_skins/erp5_payroll/AccountingTransactionModule_viewAnnualSalaryReport</string> </value> <value> <string>Script (Python):/nexedi/portal_skins/erp5_payroll/AccountingTransactionModule_viewAnnualSalaryReport</string> </value>
</item> </item>
<item>
<key> <string>_owner</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>salary_type="gross_salary"</string> </value> <value> <string>year, salary_type="gross_salary"</string> </value>
</item> </item>
<item> <item>
<key> <string>errors</string> </key> <key> <string>errors</string> </key>
...@@ -270,19 +248,23 @@ return printed\n ...@@ -270,19 +248,23 @@ return printed\n
<dictionary> <dictionary>
<item> <item>
<key> <string>co_argcount</string> </key> <key> <string>co_argcount</string> </key>
<value> <int>1</int> </value> <value> <int>2</int> </value>
</item> </item>
<item> <item>
<key> <string>co_varnames</string> </key> <key> <string>co_varnames</string> </key>
<value> <value>
<tuple> <tuple>
<string>year</string>
<string>salary_type</string> <string>salary_type</string>
<string>_print_</string> <string>_print_</string>
<string>_print</string> <string>_print</string>
<string>DateTime</string> <string>DateTime</string>
<string>_getattr_</string> <string>_getattr_</string>
<string>context</string> <string>context</string>
<string>portal</string>
<string>portal_catalog</string> <string>portal_catalog</string>
<string>N_</string>
<string>int</string>
<string>query</string> <string>query</string>
<string>paysheet_par_person</string> <string>paysheet_par_person</string>
<string>_getiter_</string> <string>_getiter_</string>
...@@ -298,13 +280,23 @@ return printed\n ...@@ -298,13 +280,23 @@ return printed\n
<string>ps_details</string> <string>ps_details</string>
<string>salary_value</string> <string>salary_value</string>
<string>float</string> <string>float</string>
<string>sorted_data</string>
<string>person_path</string>
<string>paysheet_dict</string>
<string>person_title</string>
<string>items</string>
<string>append</string>
<string>$append0</string>
<string>item</string>
<string>unicode</string>
<string>str</string>
<string>month_list</string>
<string>month</string>
<string>total</string> <string>total</string>
<string>monthly_total</string> <string>monthly_total</string>
<string>person_path</string>
<string>person_dict</string> <string>person_dict</string>
<string>person_total</string> <string>person_total</string>
<string>range</string> <string>range</string>
<string>month</string>
<string>dup_ps</string> <string>dup_ps</string>
<string>check_total</string> <string>check_total</string>
</tuple> </tuple>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.PythonScripts.PythonScript</string>
<string>PythonScript</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Python_magic</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[
REPORT_SCRIPT = "AccountingTransactionModule_viewAnnualSalaryReport"\n
\n
request = context.REQUEST\n
\n
year = request[\'report_year\']\n
type = request[\'report_type\']\n
\n
context.REQUEST.RESPONSE.redirect("%s/%s?year=%s&salary_type=%s" % ( context.getPath()\n
, REPORT_SCRIPT\n
, year\n
, type\n
))\n
]]></string> </value>
</item>
<item>
<key> <string>_code</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_filepath</string> </key>
<value> <string>Script (Python):/nexedi/portal_skins/erp5_payroll/AccountingTransactionModule_viewPayrollReport</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>errors</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>func_code</string> </key>
<value>
<object>
<klass>
<global name="FuncCode" module="Shared.DC.Scripts.Signature"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>REPORT_SCRIPT</string>
<string>_getattr_</string>
<string>context</string>
<string>request</string>
<string>_getitem_</string>
<string>year</string>
<string>type</string>
</tuple>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>func_defaults</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AccountingTransactionModule_viewPayrollReport</string> </value>
</item>
<item>
<key> <string>warnings</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.ERP5Form.Form</string>
<string>ERP5Form</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__ac_local_roles__</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>AccountingTransactionModule_viewPayrollReport</string> </value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>Default</string>
<string>left</string>
<string>bottom</string>
<string>diabled</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>Default</string> </key>
<value>
<list>
<string>my_report_year</string>
<string>my_report_type</string>
</list>
</value>
</item>
<item>
<key> <string>bottom</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>diabled</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AccountingTransactionModule_viewPayrollReportDialog</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>AccountingTransactionModule_viewPayrollReportDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payroll Report</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.StandardFields</string>
<string>RadioField</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_report_type</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>unknown_selection</string> </key>
<value> <string>You selected an item that was not in the list.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string>gross_salary</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list>
<tuple>
<string>Gross Salary (default)</string>
<string>gross_salary</string>
</tuple>
<tuple>
<string>Net Salary</string>
<string>net_salary</string>
</tuple>
<tuple>
<string>Taxable Net Salary</string>
<string>taxable_net_salary</string>
</tuple>
<tuple>
<string>Employee Share</string>
<string>total_employee_share</string>
</tuple>
<tuple>
<string>Taxable Employee Share</string>
<string>total_taxable_employee_share</string>
</tuple>
<tuple>
<string>Employer Share</string>
<string>total_employer_share</string>
</tuple>
<tuple>
<string>Ceiling Salary</string>
<string>ceiling_salary</string>
</tuple>
<tuple>
<string>CSG Salary</string>
<string>csg_salary</string>
</tuple>
<tuple>
<string>Slice A Salary</string>
<string>slice_a_salary</string>
</tuple>
<tuple>
<string>Slice B Salary</string>
<string>slice_b_salary</string>
</tuple>
<tuple>
<string>Slice C Salary</string>
<string>slice_c_salary</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string>vertical</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Report Type</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.StandardFields</string>
<string>IntegerField</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_report_year</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>integer_out_of_range</string> </key>
<value> <string>The integer you entered was out of range.</string> </value>
</item>
<item>
<key> <string>not_integer</string> </key>
<value> <string>You did not enter an integer.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>display_maxwidth</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>end</string> </key>
<value> <int>9999</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>start</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Report Year</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<tuple>
<string>Products.Formulator.TALESField</string>
<string>TALESMethod</string>
</tuple>
<none/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.portal_preferences.getPreferredAccountingTransactionAtDate().year()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -85,8 +85,8 @@ paysheet_cat = {}\n ...@@ -85,8 +85,8 @@ paysheet_cat = {}\n
object_list = []\n object_list = []\n
\n \n
# get all Pay Sheet Line\n # get all Pay Sheet Line\n
gross_salary = 0.0\n gross_salary = 0.0\n
net_salary = 0.0\n net_salary = 0.0\n
for object in context.objectValues():\n for object in context.objectValues():\n
if object.getPortalType()==\'Pay Sheet Line\':\n if object.getPortalType()==\'Pay Sheet Line\':\n
# get the gross salary\n # get the gross salary\n
...@@ -105,6 +105,53 @@ net_salary = r_(-net_salary)\n ...@@ -105,6 +105,53 @@ net_salary = r_(-net_salary)\n
\n \n
total_employee_share = r_(gross_salary - net_salary)\n total_employee_share = r_(gross_salary - net_salary)\n
\n \n
\n
# Get the CSG salary\n
# This is only used for report\n
csg_salary = r_(0.97 * gross_salary)\n
\n
# Calculate the ceiling salary\n
# This is only used for report\n
ceiling_salary = 0.0\n
ceiling_salary_list = { 2003 : 2432.0\n
, 2004 : 2476.0\n
, 2005 : 2516.0\n
, 2006 : 2589.0\n
}\n
# the default ceiling salary is the last one\n
paysheet_year = context.getStartDate().year()\n
ceiling_salary_available_years = ceiling_salary_list.keys()\n
if paysheet_year not in ceiling_salary_available_years:\n
paysheet_year = ceiling_salary_available_years[-1]\n
salary_limit = ceiling_salary_list[paysheet_year]\n
# limited salary = salaire plafonnee\n
if gross_salary < salary_limit:\n
ceiling_salary = gross_salary\n
else:\n
ceiling_salary = salary_limit\n
\n
# Get the list of all slice the employee fall in\n
# This is only used for report\n
slice_a_salary = 0.0\n
slice_b_salary = 0.0\n
slice_c_salary = 0.0\n
# "Char" slice type\n
slice_a_value = salary_limit\n
slice_b_value = salary_limit * 4\n
slice_c_value = salary_limit * 8\n
if gross_salary < slice_a_value:\n
slice_a_salary = gross_salary\n
else:\n
slice_a_salary = slice_a_value\n
if gross_salary < slice_b_value:\n
slice_b_salary = float(gross_salary) - float(slice_a_value)\n
else:\n
slice_b_salary = slice_b_value\n
if gross_salary < slice_c_value:\n
slice_c_salary = float(gross_salary) - float(slice_b_value)\n
else:\n
slice_c_salary = slice_c_value\n
\n
# Sort the list by id since lines are already ordered by id.\n # Sort the list by id since lines are already ordered by id.\n
object_list.sort(lambda x, y: cmp(int(x.getId()), int(y.getId())))\n object_list.sort(lambda x, y: cmp(int(x.getId()), int(y.getId())))\n
for pay_sheet_line in object_list:\n for pay_sheet_line in object_list:\n
...@@ -115,6 +162,7 @@ for pay_sheet_line in object_list:\n ...@@ -115,6 +162,7 @@ for pay_sheet_line in object_list:\n
if not variation in range_variation: # Extra checking because\n if not variation in range_variation: # Extra checking because\n
# get VariationCategoryList returns\n # get VariationCategoryList returns\n
# the same 1 items 2 times\n # the same 1 items 2 times\n
# This is normally no longer true, I fix this bug years ago (!)\n
range_variation += [variation]\n range_variation += [variation]\n
for range in range_variation:\n for range in range_variation:\n
pay_sheet_dict = {}\n pay_sheet_dict = {}\n
...@@ -132,11 +180,13 @@ for pay_sheet_line in object_list:\n ...@@ -132,11 +180,13 @@ for pay_sheet_line in object_list:\n
# Hack not to display prime and ser\n # Hack not to display prime and ser\n
if cell_total_price != 0 or cell.getResourceId() not in (\'primes\', \'retenue_maladie\'):\n if cell_total_price != 0 or cell.getResourceId() not in (\'primes\', \'retenue_maladie\'):\n
if category.find(\'employee_share\') >= 0:\n if category.find(\'employee_share\') >= 0:\n
pay_sheet_dict[\'base\'] = -cell_quantity # change the sign for the beautification effect\n pay_sheet_dict[\'base\'] = -cell_quantity # change the sign to beautify\n
pay_sheet_dict[\'employee_share\'] = -cell_total_price\n pay_sheet_dict[\'employee_share\'] = -cell_total_price\n
pay_sheet_dict[\'employee_share_rate\'] = cell_price * 100\n pay_sheet_dict[\'employee_share_rate\'] = cell_price * 100\n
# here we decide if a resource is taxable\n # here we decide if a resource is taxable\n
if str(pay_sheet_line.getResource())[-14:] == \'non_deductible\' or str(pay_sheet_line.getResource())[-4:] == \'crds\' or str(pay_sheet_line.getResource())[-7:] == \'taxable\':\n if str(pay_sheet_line.getResource())[-14:] == \'non_deductible\' or \\\n
str(pay_sheet_line.getResource())[-4:] == \'crds\' or \\\n
str(pay_sheet_line.getResource())[-7:] == \'taxable\':\n
pay_sheet_dict[\'taxable\'] = \'yes\'\n pay_sheet_dict[\'taxable\'] = \'yes\'\n
elif str(pay_sheet_line.getResource())[-10:] == \'deductible\':\n elif str(pay_sheet_line.getResource())[-10:] == \'deductible\':\n
pay_sheet_dict[\'taxable\'] = \'no\'\n pay_sheet_dict[\'taxable\'] = \'no\'\n
...@@ -182,6 +232,11 @@ paysheet_transactions = accounting_folder.searchFolder(portal_type=\'Pay Sheet T ...@@ -182,6 +232,11 @@ paysheet_transactions = accounting_folder.searchFolder(portal_type=\'Pay Sheet T
# initialize every yearly variable\n # initialize every yearly variable\n
yearly_net_salary = 0.0\n yearly_net_salary = 0.0\n
yearly_gross_salary = 0.0\n yearly_gross_salary = 0.0\n
yearly_csg_salary = 0.0\n
yearly_ceiling_salary = 0.0\n
yearly_slice_a_salary = 0.0\n
yearly_slice_b_salary = 0.0\n
yearly_slice_c_salary = 0.0\n
yearly_employee_share = 0.0\n yearly_employee_share = 0.0\n
yearly_employer_share = 0.0\n yearly_employer_share = 0.0\n
yearly_taxable_net_salary = 0.0\n yearly_taxable_net_salary = 0.0\n
...@@ -222,6 +277,11 @@ for paysheet_obj in paysheet_transactions:\n ...@@ -222,6 +277,11 @@ for paysheet_obj in paysheet_transactions:\n
# sum of yearly values\n # sum of yearly values\n
yearly_net_salary = r_(yearly_net_salary + r_(old_ps[\'net_salary\']))\n yearly_net_salary = r_(yearly_net_salary + r_(old_ps[\'net_salary\']))\n
yearly_gross_salary = r_(yearly_gross_salary + r_(old_ps[\'gross_salary\']))\n yearly_gross_salary = r_(yearly_gross_salary + r_(old_ps[\'gross_salary\']))\n
yearly_csg_salary = r_(yearly_csg_salary + r_(old_ps[\'csg_salary\']))\n
yearly_ceiling_salary = r_(yearly_ceiling_salary + r_(old_ps[\'ceiling_salary\']))\n
yearly_slice_a_salary = r_(yearly_slice_a_salary + r_(old_ps[\'slice_a_salary\']))\n
yearly_slice_b_salary = r_(yearly_slice_b_salary + r_(old_ps[\'slice_b_salary\']))\n
yearly_slice_c_salary = r_(yearly_slice_c_salary + r_(old_ps[\'slice_c_salary\']))\n
yearly_employee_share = r_(yearly_employee_share + r_(old_ps[\'total_employee_share\']))\n yearly_employee_share = r_(yearly_employee_share + r_(old_ps[\'total_employee_share\']))\n
yearly_employer_share = r_(yearly_employer_share + r_(old_ps[\'total_employer_share\']))\n yearly_employer_share = r_(yearly_employer_share + r_(old_ps[\'total_employer_share\']))\n
yearly_taxable_net_salary = r_(yearly_taxable_net_salary + r_(old_ps[\'taxable_net_salary\']))\n yearly_taxable_net_salary = r_(yearly_taxable_net_salary + r_(old_ps[\'taxable_net_salary\']))\n
...@@ -229,6 +289,11 @@ for paysheet_obj in paysheet_transactions:\n ...@@ -229,6 +289,11 @@ for paysheet_obj in paysheet_transactions:\n
# save the total share values in the exported dict\n # save the total share values in the exported dict\n
details[\'net_salary\'] = net_salary\n details[\'net_salary\'] = net_salary\n
details[\'gross_salary\'] = gross_salary\n details[\'gross_salary\'] = gross_salary\n
details[\'csg_salary\'] = csg_salary\n
details[\'ceiling_salary\'] = ceiling_salary\n
details[\'slice_a_salary\'] = slice_a_salary\n
details[\'slice_b_salary\'] = slice_b_salary\n
details[\'slice_c_salary\'] = slice_c_salary\n
details[\'paysheet_categories\'] = paysheet_cat\n details[\'paysheet_categories\'] = paysheet_cat\n
details[\'total_employee_share\'] = total_employee_share\n details[\'total_employee_share\'] = total_employee_share\n
details[\'total_employer_share\'] = total_employer_share\n details[\'total_employer_share\'] = total_employer_share\n
...@@ -238,6 +303,11 @@ details[\'taxable_net_salary\'] = r_(total_taxable_employee_share + r_ ...@@ -238,6 +303,11 @@ details[\'taxable_net_salary\'] = r_(total_taxable_employee_share + r_
# don\'t forget to add the current values to the yearly sum\n # don\'t forget to add the current values to the yearly sum\n
details[\'yearly_net_salary\'] = r_(yearly_net_salary + r_(details[\'net_salary\']))\n details[\'yearly_net_salary\'] = r_(yearly_net_salary + r_(details[\'net_salary\']))\n
details[\'yearly_gross_salary\'] = r_(yearly_gross_salary + r_(details[\'gross_salary\']))\n details[\'yearly_gross_salary\'] = r_(yearly_gross_salary + r_(details[\'gross_salary\']))\n
details[\'yearly_csg_salary\'] = r_(yearly_csg_salary + r_(details[\'csg_salary\']))\n
details[\'yearly_ceiling_salary\'] = r_(yearly_ceiling_salary + r_(details[\'ceiling_salary\']))\n
details[\'yearly_slice_a_salary\'] = r_(yearly_slice_a_salary + r_(details[\'slice_a_salary\']))\n
details[\'yearly_slice_b_salary\'] = r_(yearly_slice_b_salary + r_(details[\'slice_b_salary\']))\n
details[\'yearly_slice_c_salary\'] = r_(yearly_slice_c_salary + r_(details[\'slice_c_salary\']))\n
details[\'yearly_employee_share\'] = r_(yearly_employee_share + r_(details[\'total_employee_share\']))\n details[\'yearly_employee_share\'] = r_(yearly_employee_share + r_(details[\'total_employee_share\']))\n
details[\'yearly_employer_share\'] = r_(yearly_employer_share + r_(details[\'total_employer_share\']))\n details[\'yearly_employer_share\'] = r_(yearly_employer_share + r_(details[\'total_employer_share\']))\n
details[\'yearly_taxable_net_salary\'] = r_(yearly_taxable_net_salary + r_(details[\'taxable_net_salary\']))\n details[\'yearly_taxable_net_salary\'] = r_(yearly_taxable_net_salary + r_(details[\'taxable_net_salary\']))\n
...@@ -257,12 +327,6 @@ return details\n ...@@ -257,12 +327,6 @@ return details\n
<key> <string>_filepath</string> </key> <key> <string>_filepath</string> </key>
<value> <string>Script (Python):/nexedi/portal_skins/erp5_payroll/PaySheetTransaction_getDetails</string> </value> <value> <string>Script (Python):/nexedi/portal_skins/erp5_payroll/PaySheetTransaction_getDetails</string> </value>
</item> </item>
<item>
<key> <string>_owner</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -306,6 +370,20 @@ return details\n ...@@ -306,6 +370,20 @@ return details\n
<string>object</string> <string>object</string>
<string>cell</string> <string>cell</string>
<string>total_employee_share</string> <string>total_employee_share</string>
<string>csg_salary</string>
<string>ceiling_salary</string>
<string>ceiling_salary_list</string>
<string>paysheet_year</string>
<string>ceiling_salary_available_years</string>
<string>_getitem_</string>
<string>salary_limit</string>
<string>slice_a_salary</string>
<string>slice_b_salary</string>
<string>slice_c_salary</string>
<string>slice_a_value</string>
<string>slice_b_value</string>
<string>slice_c_value</string>
<string>float</string>
<string>pay_sheet_line</string> <string>pay_sheet_line</string>
<string>variation_list</string> <string>variation_list</string>
<string>range_variation</string> <string>range_variation</string>
...@@ -318,7 +396,6 @@ return details\n ...@@ -318,7 +396,6 @@ return details\n
<string>cell_price</string> <string>cell_price</string>
<string>cell_quantity</string> <string>cell_quantity</string>
<string>cell_total_price</string> <string>cell_total_price</string>
<string>_getitem_</string>
<string>str</string> <string>str</string>
<string>None</string> <string>None</string>
<string>key</string> <string>key</string>
...@@ -330,6 +407,11 @@ return details\n ...@@ -330,6 +407,11 @@ return details\n
<string>paysheet_transactions</string> <string>paysheet_transactions</string>
<string>yearly_net_salary</string> <string>yearly_net_salary</string>
<string>yearly_gross_salary</string> <string>yearly_gross_salary</string>
<string>yearly_csg_salary</string>
<string>yearly_ceiling_salary</string>
<string>yearly_slice_a_salary</string>
<string>yearly_slice_b_salary</string>
<string>yearly_slice_c_salary</string>
<string>yearly_employee_share</string> <string>yearly_employee_share</string>
<string>yearly_employer_share</string> <string>yearly_employer_share</string>
<string>yearly_taxable_net_salary</string> <string>yearly_taxable_net_salary</string>
......
2006-06-13 Kevin
* Add a very alpha version of the Payroll report.
2006-06-12 Kevin 2006-06-12 Kevin
* Update maintainer list. * Update maintainer list.
* Re-order tabs thanks to priorities. * Re-order tabs thanks to priorities.
......
Accounting Transaction Module | payroll_report
Pay Sheet Cell | history Pay Sheet Cell | history
Pay Sheet Cell | metadata Pay Sheet Cell | metadata
Pay Sheet Cell | print_pdf Pay Sheet Cell | print_pdf
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment