From ff8f63be18fb0d63a4dc35d1396e8ec676ecabea Mon Sep 17 00:00:00 2001 From: Kevin Deldycke <kevin@nexedi.com> Date: Tue, 24 Oct 2006 14:42:37 +0000 Subject: [PATCH] Support dynamic update of gross salary calculation on pay sheet preview git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@10913 20353a03-c40f-0410-a6d1-a30d3c3de9de --- .../PaySheetTransaction_initializePreview.xml | 129 +++++++++++++----- ...ransaction_preCalculation_l10n_fr_2006.xml | 47 +++++-- .../PaySheetTransaction_updateCalculation.xml | 41 ++++-- 3 files changed, 164 insertions(+), 53 deletions(-) diff --git a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_initializePreview.xml b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_initializePreview.xml index 8937fce59c..e47c1d2e72 100644 --- a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_initializePreview.xml +++ b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_initializePreview.xml @@ -68,15 +68,19 @@ </item> <item> <key> <string>_body</string> </key> - <value> <string>"""\n + <value> <string encoding="cdata"><![CDATA[ + +"""\n This script create the data structure of the pay sheet preview (= the PaySheetTransaction_viewPreview fast input).\n Then it fill this data structure with rates and amounts of money from the localized pre calculation script.\n """\n \n -import random\n from Products.ERP5Type.Document import newTempBase\n from string import zfill\n \n +# Get Precision\n +precision = context.getResourceValue().getQuantityPrecision()\n +r_ = lambda x: context.Base_getRoundValue(x, precision)\n \n \n ##########################\n @@ -107,7 +111,6 @@ for service in service_module.objectValues():\n # TODO: Use a validation workflow on Payroll Service and check the validity of a Service there\n base_categories = service.getVariationBaseCategoryList()\n if \'salary_range\' in base_categories and \'tax_category\' in base_categories:\n - # XXX add "and service.getId() != \'labour\':" ??\n paysheet_services.append(service)\n \n # Create the pre-calculation data structure\n @@ -142,7 +145,71 @@ for service in paysheet_services:\n \n \n #########################################\n -# This part of the script select the right localized version of PaySheetTransaction_preCalculation_l10n script.\n +# Get new values that came from "Update" action on Pay Sheet fast input.\n +# Currently we only keep fixed values which are part of the gross salary and addendum calculation.\n +#\n +# IDEA: Compare values from preCalculation script (rates and base) with the updated listbox\n +# to keep user-defined values. Then merge them with current one. This is a good idea but\n +# the decision algorithm must be smart.\n +#########################################\n +\n +UPDATE_SCRIPT = \'PaySheetTransaction_updateCalculation\'\n +# Get the updated listbox\n +selection_params = context.portal_selections.getSelectionParams(UPDATE_SCRIPT)\n +# Reset the selection (defensive strategy)\n +context.portal_selections.setSelectionParamsFor(UPDATE_SCRIPT, {})\n +updated_listbox = []\n +if selection_params.has_key(\'updated_listbox\'):\n + updated_listbox = selection_params[\'updated_listbox\']\n +\n +\n +# Scan the listbox and look for complementary lines to add to the gross salary\n +new_gross_salary = 0.0\n +for line in updated_listbox:\n + salary_range = line[\'salary_range\']\n + if salary_range not in [None, \'\'] and salary_range.startswith(\'salary_range/france/fixed/gross\'):\n + # Get the employee or employer share as part of the multiline gross salary\n + # The payroll service "setup convention" require that the fixed value should be defined on \'employer_share\'\n + share_value = line[\'employer_share\']\n + if share_value not in [None, \'\']:\n + new_gross_salary = r_(new_gross_salary + r_(share_value))\n +\n +if new_gross_salary > 0.0:\n + # Don\'t forget to add the base salary\n + new_gross_salary = r_(new_gross_salary + r_(context.getGrossSalary()))\n +else:\n + new_gross_salary = None\n +\n +\n +# Everything which is part of gross salary and addendum calculation should be kept untouched.\n +# To keep thoses value, we should use the same dict format as in preCalculation script.\n +update_kw = {}\n +for line in updated_listbox:\n + salary_range = line[\'salary_range\']\n + service_id = line[\'service_id\']\n + employee_share = line[\'employee_share\']\n + employer_share = line[\'employer_share\']\n + base = line[\'base\']\n + if salary_range not in [None, \'\'] and \\\n + service_id not in [None, \'\'] and \\\n + base not in [None, \'\'] and \\\n + (salary_range.startswith(\'salary_range/france/fixed/gross\') or \\\n + salary_range.startswith(\'salary_range/france/fixed/addendum\') ) and \\\n + (employee_share not in [None, \'\'] or employer_share not in [None, \'\']):\n + salary_range_id = salary_range.split(\'/\')[-1]\n + line_uid = "%s/%s" % (service_id, salary_range_id)\n + new_dict = { \'employer_share\': employer_share\n + , \'employee_share\': employee_share\n + , \'base\' : base\n + }\n + update_kw[line_uid] = new_dict\n +\n +\n +\n +#########################################\n +# This part of the script select the right localized version of\n +# PaySheetTransaction_preCalculation_l10n script.\n +#\n # TODO: implement here a generic method to get the right precalculation script automaticcaly.\n #########################################\n \n @@ -155,16 +222,19 @@ script_name = \'_\'.join([ "PaySheetTransaction_preCalculation_l10n"\n , year\n ])\n calculation_method = getattr(context, script_name)\n +pre_calculation = calculation_method(gross_salary=new_gross_salary)\n \n -pre_calculation = calculation_method()\n -\n -# Merge pre_calculation and preview line dict\n +# Merge pre_calculation and preview line dict, or finaly override value from the update dict\n preview_line_keys = d.items()[0][1].keys()\n for k in pre_calculation.keys():\n if k in d.keys():\n for required_key in preview_line_keys:\n + # Merge\n if not pre_calculation[k].has_key(required_key):\n pre_calculation[k][required_key] = d[k][required_key]\n + # Override\n + if update_kw.has_key(k) and update_kw[k].has_key(required_key):\n + pre_calculation[k][required_key] = update_kw[k][required_key]\n else:\n context.log( "PaySheetTransaction_initializePreview"\n , "Preview line key \'%s\' not found in default services" % k\n @@ -172,22 +242,6 @@ for k in pre_calculation.keys():\n # Remove line\n del pre_calculation[k]\n \n -# Because all rates in the localized file are written in percents, we must convert them in pure floats.\n -for preview_line_uid in pre_calculation.keys():\n - # Only \'Fixed\' (or \'Forfait\' in french) base are expressed in percents\n - # TODO: base this test on "/forfait" string is bad. A more generic way must be found.\n - preview_line = pre_calculation[preview_line_uid]\n - if not preview_line_uid.endswith(\'/forfait\'):\n - # Fix percents\n - for share_type in [\'employer_share\', \'employee_share\']:\n - share_value = preview_line[share_type]\n - if share_value not in (\'\', None):\n - preview_line[share_type] = share_value / 100.0\n - # Normalize the value of \'Fixed\' (or \'Forfait\' in french) base to 1.0\n - else:\n - preview_line[\'base\'] = 1.0\n - pre_calculation[preview_line_uid] = preview_line\n -\n # Create a preview line for every salary_range value of the service\n portal_object = context.getPortalObject()\n preview_line_list = []\n @@ -215,7 +269,9 @@ for (preview_line_id, preview_line_item) in pre_calculation.items():\n \n # return the list of preview lines\n return preview_line_list\n -</string> </value> + + +]]></string> </value> </item> <item> <key> <string>_code</string> </key> @@ -272,14 +328,15 @@ return preview_line_list\n <value> <tuple> <string>kw</string> - <string>random</string> <string>Products.ERP5Type.Document</string> <string>newTempBase</string> <string>string</string> <string>zfill</string> - <string>d</string> <string>_getattr_</string> <string>context</string> + <string>precision</string> + <string>r_</string> + <string>d</string> <string>erp5site</string> <string>hasattr</string> <string>service_module</string> @@ -296,26 +353,36 @@ return preview_line_list\n <string>None</string> <string>preview_line_uid</string> <string>_write_</string> + <string>UPDATE_SCRIPT</string> + <string>selection_params</string> + <string>updated_listbox</string> + <string>_getitem_</string> + <string>new_gross_salary</string> + <string>line</string> + <string>share_value</string> + <string>update_kw</string> + <string>service_id</string> + <string>employee_share</string> + <string>employer_share</string> + <string>base</string> + <string>salary_range_id</string> + <string>line_uid</string> + <string>new_dict</string> <string>country</string> <string>year</string> <string>script_name</string> <string>getattr</string> <string>calculation_method</string> <string>pre_calculation</string> - <string>_getitem_</string> <string>preview_line_keys</string> <string>k</string> <string>required_key</string> - <string>preview_line</string> - <string>share_type</string> - <string>share_value</string> <string>portal_object</string> <string>preview_line_list</string> <string>num</string> <string>INT_LEN</string> <string>preview_line_id</string> <string>preview_line_item</string> - <string>service_id</string> <string>o</string> </tuple> </value> diff --git a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_preCalculation_l10n_fr_2006.xml b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_preCalculation_l10n_fr_2006.xml index 9b7d463253..e2758a434f 100644 --- a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_preCalculation_l10n_fr_2006.xml +++ b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_preCalculation_l10n_fr_2006.xml @@ -73,6 +73,9 @@ """\n This script define all rates to apply in 2006 to calculate an entire paysheet\n according french fiscal & social rules for a SME.\n +\n + This script accept gross_salary parameter to override the default one.\n + This is helpfull in case of update made on PaySheetTransaction_viewPreview fast input.\n """\n \n kw = {}\n @@ -89,8 +92,10 @@ paysheet_type = paysheet.getPortalType()\n employee = paysheet.getDestinationSectionValue()\n company = paysheet.getSourceSectionValue()\n \n -# Get Paysheet datas\n -gross_salary = abs(paysheet.getGrossSalary())\n +# Use the gross salary given as parameter or not\n +if gross_salary == None:\n + gross_salary = abs(paysheet.getGrossSalary())\n +\n start_date = paysheet.getStartDate()\n stop_date = paysheet.getStopDate()\n \n @@ -410,7 +415,6 @@ if executive:\n comp_date = DateTime(start_date.year(), 3, 31)\n while comp_date < comp_date:\n comp_date = DateTime(comp_date.year() + 1, 3, 31)\n -context.log("kev date", repr(comp_date))\n if executive and start_date <= comp_date <= stop_date:\n kw[\'apec/forfait\'] = \\\n { \'employer_share\': 3.72\n @@ -513,6 +517,25 @@ kw[\'precarite/gross\'] = \\\n , \'base\' : 1.0\n }\n \n +\n +# Normalize\n +for line_key in kw.keys():\n + # Only \'variable\' contribution are expressed in percents of a base\n + line = kw[line_key]\n + # \'Fixed\' contributions\n + if line_key.endswith(\'/gross\') or \\\n + line_key.endswith(\'/forfait\'):\n + # Defensive programming: be sure conventions are respected\n + kw[line_key][\'base\'] = 1.0\n + # \'Variable\' contributions\n + else:\n + # All rates in this script are written in percents, we must convert them in pure floats.\n + for share_type in [\'employer_share\', \'employee_share\']:\n + share_value = line[share_type]\n + if share_value not in [\'\', None]:\n + # Fix percents\n + kw[line_key][share_type] = share_value / 100.0\n +\n return kw\n @@ -544,7 +567,7 @@ return kw\n </item> <item> <key> <string>_params</string> </key> - <value> <string></string> </value> + <value> <string>gross_salary=None</string> </value> </item> <item> <key> <string>errors</string> </key> @@ -564,12 +587,13 @@ return kw\n <dictionary> <item> <key> <string>co_argcount</string> </key> - <value> <int>0</int> </value> + <value> <int>1</int> </value> </item> <item> <key> <string>co_varnames</string> </key> <value> <tuple> + <string>gross_salary</string> <string>kw</string> <string>_getattr_</string> <string>context</string> @@ -577,8 +601,8 @@ return kw\n <string>paysheet_type</string> <string>employee</string> <string>company</string> + <string>None</string> <string>abs</string> - <string>gross_salary</string> <string>start_date</string> <string>stop_date</string> <string>ceiling_salary_list</string> @@ -605,16 +629,19 @@ return kw\n <string>DateTime</string> <string>old_limit</string> <string>comp_type</string> - <string>None</string> <string>employer_rate</string> <string>employee_rate</string> <string>fngs_employer_rate</string> <string>employee_share_rate</string> <string>employer_share_rate</string> <string>comp_date</string> - <string>repr</string> <string>col_agr</string> <string>syntec_rate</string> + <string>_getiter_</string> + <string>line_key</string> + <string>line</string> + <string>share_type</string> + <string>share_value</string> </tuple> </value> </item> @@ -626,7 +653,9 @@ return kw\n <item> <key> <string>func_defaults</string> </key> <value> - <none/> + <tuple> + <none/> + </tuple> </value> </item> <item> diff --git a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_updateCalculation.xml b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_updateCalculation.xml index 03b9275d41..a1947cbc1f 100644 --- a/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_updateCalculation.xml +++ b/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_updateCalculation.xml @@ -68,22 +68,29 @@ </item> <item> <key> <string>_body</string> </key> - <value> <string>return context.REQUEST.RESPONSE.redirect(\'%s/PaySheetTransaction_viewPreview?portal_status_message=Base+Salary+updated.\' % context.absolute_url())\n + <value> <string encoding="cdata"><![CDATA[ + +"""\n + This script get the new listbox content and save it in a selection to let the\n + listbox script (PaySheetTransaction_initializePreview) recalculate necessary contributions.\n +"""\n \n -# Get all cells which are needed to calculate the base_salary\n +portal = context.getPortalObject()\n +N_ = portal.Base_translateString\n \n -# Scan the listbox and look for complementary lines to add to the gross salary\n -#for user_line in listbox:\n - # if user_line[\'base\'] not in (None, \'\'):\n - # Get the base salary if given by the user\n - # base = r_(user_line[\'base\'])\n +# Save listbox dict in a selection for recalculation\n +if len(listbox) > 0:\n + # XXX Don\'t know how the selection is supposed to behave in case of simultaneous\n + # pay sheet edition by the same user.\n + context.portal_selections.setSelectionParamsFor(script.id, {\'updated_listbox\': listbox})\n \n -# IDEA: compare normal _initializePreview returned rates and base with the current one and keep user-defined values. Then merge them with current one.\n -# This is the only solution to mimic real user interaction without AJAX/DHTML-like UI.\n -\n -# Recalculate the preview with new base_salary\n -#std_lines = context.PaySheetTransaction_initializePreview()\n -</string> </value> +from ZTUtils import make_query\n +params = { \'portal_status_message\': N_(\'Gross Salary and Depending Contributions Updated.\')}\n +redirect_url = \'%s/%s?%s\' % (context.absolute_url(), \'PaySheetTransaction_viewPreview\', make_query(params))\n +return context.REQUEST.RESPONSE.redirect(redirect_url)\n + + +]]></string> </value> </item> <item> <key> <string>_code</string> </key> @@ -135,6 +142,14 @@ <string>kw</string> <string>_getattr_</string> <string>context</string> + <string>portal</string> + <string>N_</string> + <string>len</string> + <string>script</string> + <string>ZTUtils</string> + <string>make_query</string> + <string>params</string> + <string>redirect_url</string> </tuple> </value> </item> -- 2.30.9