Commit 93cbcdb0 authored by Kevin Deldycke's avatar Kevin Deldycke

Update french paysheet rates.

Add comments and TODOs.
Clean file.
Normalize "fixed/forfait" datas.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@10825 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent a34d3c0b
......@@ -74,6 +74,14 @@
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
\n
\n
\n
##########################\n
# This part of the script define usefull variables to help us calculate dynamic rates and contributions.\n
# This part depend mostly of the current localisation.\n
##########################\n
\n
global paysheet\n
paysheet = context.getObject()\n
paysheet_type = paysheet.getPortalType()\n
......@@ -86,9 +94,6 @@ gross_salary = abs(paysheet.getGrossSalary())\n
start_date = paysheet.getStartDate()\n
stop_date = paysheet.getStopDate()\n
\n
\n
### This part of the script define usefull variables to help us calculate dynamic rates\n
\n
# Each year, look at http://www.urssaf.fr to complete the table\n
ceiling_salary_list = { 2003: 2432.0\n
, 2004: 2476.0\n
......@@ -161,56 +166,82 @@ else:\n
comp_type = \'new\'\n
\n
\n
### This part of the script aggregate base salary and rates.\n
\n
default = {}\n
##########################\n
# This part of the script create the data structure designed to hold the result of pre calculation.\n
# TODO: This part must be generic to be moved outside this localized script. Probably in PaySheetTransaction_preCalculation.\n
##########################\n
\n
# Initialize all variables to None\n
paysheet_services = []\n
erp5site = context.portal_url.getPortalObject()\n
# \'d\' is the dict which contain the default values of the Pay Sheet fast input\n
d = {}\n
\n
# during 06/2005 service module has been renamed service_module\n
# During 06/2005 service module has been renamed service_module\n
# both names are supported\n
# XXX This should definitly use portal_catalog !!!\n
if hasattr(erp5site, \'payroll_service_module\') :\n
# XXX The following code will be deprecated when the Payroll Service portal type will be used\n
erp5site = context.portal_url.getPortalObject()\n
if hasattr(erp5site, \'payroll_service_module\'):\n
service_module = erp5site.payroll_service_module\n
elif hasattr(erp5site, \'service_module\') :\n
elif hasattr(erp5site, \'service_module\'):\n
service_module = erp5site.service_module\n
else :\n
else:\n
service_module = erp5site.service\n
\n
# Check service validity\n
# TODO: Use a validation workflow on Payroll Service and check the validity of a Service there\n
# TODO: Only choose services of the current localisation.\n
paysheet_services = []\n
for service in service_module.objectValues():\n
base_cat = service.getVariationRangeBaseCategoryList()\n
if \'tax_category\' in base_cat and \'salary_range\' in base_cat:\n
paysheet_services.append(service)\n
for serv in paysheet_services:\n
cat_list = serv.getCategoryList()\n
tax_cat = []\n
range_cat = []\n
for cat in cat_list:\n
if str(cat).find(\'tax_category\') != -1:\n
tax_cat.append(cat)\n
if str(cat).find(\'salary_range\') != -1:\n
range_cat.append(cat)\n
for base in range_cat:\n
mycategory = context.portal_categories.resolveCategory(base)\n
if mycategory is None:\n
context.log("PaySheetTransaction_preCalculation", "WARNING! Category not found: %s" % base)\n
\n
\n
for service in paysheet_services:\n
# XXX Is there a better way to get categorylist ? Something like getCategoryList(base=\'tax_category\') will be nice to have.\n
service_categories = service.getCategoryList()\n
tax_categories = []\n
salary_range_categories = []\n
for category in service_categories:\n
if category.startswith(\'tax_category/\'): tax_categories.append(category)\n
elif category.startswith(\'salary_range/\'): salary_range_categories.append(category)\n
for salary_range in salary_range_categories:\n
salary_range_object = context.portal_categories.resolveCategory(salary_range)\n
if salary_range_object is None:\n
context.log( "PaySheetTransaction_preCalculation"\n
, "WARNING! Category not found: %s" % salary_range\n
)\n
else:\n
new_name = serv.getId() + \'/\' + mycategory.getId()\n
default[new_name] = { \'employer_rate\': None\n
, \'employee_rate\': None\n
, \'base\' : None\n
}\n
preview_line_uid = "%s/%s" % (service.getId(), salary_range_object.getId())\n
d[preview_line_uid] = { \'employer_rate\': None\n
, \'employee_rate\': None\n
, \'base\' : None\n
}\n
\n
\n
\n
##########################\n
# This part of the script calculate the default salaey range and rates.\n
# This part is the core of the script: all rates and amounts are defined below.\n
#\n
# Here is a model of a line definition:\n
# d[\'payroll_service_id/salary_range_category_id\'] = \\\n
# { \'employer_rate\' : employer_rate_in_percent\n
# , \'employee_rate\' : employee_rate_in_percent\n
# , \'base\' : contribution_base_in_currency\n
# }\n
# Rates and base must be floats.\n
# Be carefull: Rates are not in percents !\n
##########################\n
\n
# Sickness insurance = Assurance maladie\n
if executive:\n
employer_rate = None\n
employee_rate = 1.15\n
employee_rate = 0.85\n
else:\n
employer_rate = 13.10\n
employee_rate = 0.75\n
default[\'sickness_insurance/salaire_brut\'] = \\\n
d[\'sickness_insurance/salaire_brut\'] = \\\n
{ \'employer_rate\' : employer_rate\n
, \'employee_rate\' : employee_rate\n
, \'base\' : gross_salary\n
......@@ -218,18 +249,18 @@ default[\'sickness_insurance/salaire_brut\'] = \\\n
\n
# Old-age insurance = Assurance vieillesse\n
if executive:\n
default[\'oldage_insurance/salaire_plafonne\'] = \\\n
d[\'oldage_insurance/salaire_plafonne\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : 6.65\n
, \'base\' : limited_salary\n
}\n
else:\n
default[\'oldage_insurance/salaire_brut\'] = \\\n
d[\'oldage_insurance/salaire_brut\'] = \\\n
{ \'employer_rate\' : 1.60\n
, \'employee_rate\' : 0.10\n
, \'base\' : gross_salary\n
}\n
default[\'oldage_insurance/salaire_plafonne\'] = \\\n
d[\'oldage_insurance/salaire_plafonne\'] = \\\n
{ \'employer_rate\' : 8.30\n
, \'employee_rate\' : 6.65\n
, \'base\' : limited_salary\n
......@@ -237,7 +268,7 @@ else:\n
\n
# Family benefits = Allocations familliale\n
if not executive:\n
default[\'family_benefits/salaire_brut\'] = \\\n
d[\'family_benefits/salaire_brut\'] = \\\n
{ \'employer_rate\' : 5.40\n
, \'employee_rate\' : None\n
, \'base\' : gross_salary\n
......@@ -245,7 +276,7 @@ if not executive:\n
\n
# Industrial accident = Accidents du travail\n
if not executive:\n
default[\'industrial_accident/salaire_brut\'] = \\\n
d[\'industrial_accident/salaire_brut\'] = \\\n
{ \'employer_rate\' : 1.10\n
, \'employee_rate\' : None\n
, \'base\' : gross_salary\n
......@@ -253,13 +284,13 @@ if not executive:\n
\n
# Lodging helps = Aide au logemenent\n
# if company_size > 9:\n
# default[\'lodging_helps/salaire_brut\'] = \\\n
# d[\'lodging_helps/salaire_brut\'] = \\\n
# { \'employer_rate\' : 0.40\n
# , \'employee_rate\' : None\n
# , \'base\' : gross_salary\n
# }\n
# else:\n
# default[\'lodging_helps/salaire_plafonne\'] = \\\n
# d[\'lodging_helps/salaire_plafonne\'] = \\\n
# { \'employer_rate\' : 0.10\n
# , \'employee_rate\' : None\n
# , \'base\' : limited_salary\n
......@@ -268,33 +299,33 @@ if not executive:\n
# Transport payment\n
# TODO: rate depending of the town, 1.80 is the \'default\' value (when the town isn\'t referenced by laws)\n
if company_size > 9:\n
default[\'transport_payment/salaire_brut\'] = \\\n
d[\'transport_payment/salaire_brut\'] = \\\n
{ \'employer_rate\' : 1.80\n
, \'employee_rate\' : None\n
, \'base\' : gross_salary\n
}\n
\n
# CSG\n
default[\'csg_deductible/salaire_brut_csg\'] = \\\n
d[\'csg_deductible/salaire_brut_csg\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : 5.10\n
, \'base\' : 0.97 * gross_salary\n
}\n
default[\'csg_non_deductible/salaire_brut_csg\'] = \\\n
d[\'csg_non_deductible/salaire_brut_csg\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : 2.9\n
, \'base\' : 0.97 * gross_salary\n
}\n
\n
# CRDS\n
# default[\'crds/salaire_brut_crds\'] = \\\n
# d[\'crds/salaire_brut_crds\'] = \\\n
# { \'employer_rate\' : None\n
# , \'employee_rate\' : 0.50\n
# , \'base\' : 0.97 * gross_salary\n
# }\n
\n
# Unemployment insurance = Assurance chomage\n
default[\'unemployment_insurance/salaire_brut\'] = \\\n
d[\'unemployment_insurance/salaire_brut\'] = \\\n
{ \'employer_rate\' : 4.04\n
, \'employee_rate\' : 2.44\n
, \'base\' : gross_salary\n
......@@ -305,7 +336,7 @@ default[\'unemployment_insurance/salaire_brut\'] = \\\n
fngs_employer_rate = 0.25\n
if start_date >= DateTime(2006, 7, 1):\n
fngs_employer_rate = 0.15\n
default[\'fngs/salaire_brut\'] = \\\n
d[\'fngs/salaire_brut\'] = \\\n
{ \'employer_rate\' : fngs_employer_rate\n
, \'employee_rate\' : None\n
, \'base\' : gross_salary\n
......@@ -314,7 +345,7 @@ default[\'fngs/salaire_brut\'] = \\\n
# ARRCO\n
if not executive:\n
if salary_slices.has_key(\'1\'):\n
default[\'arrco/tranche_1\'] = \\\n
d[\'arrco/tranche_1\'] = \\\n
{ \'employer_rate\' : 4.5\n
, \'employee_rate\' : 3.0\n
, \'base\' : salary_slices[\'1\']\n
......@@ -326,14 +357,13 @@ if not executive:\n
else:\n
employee_share_rate = 8.0\n
employer_share_rate = 12.0\n
\n
default[\'arrco/tranche_2\'] = \\\n
d[\'arrco/tranche_2\'] = \\\n
{ \'employer_rate\' : employer_share_rate\n
, \'employee_rate\' : employee_share_rate\n
, \'base\' : salary_slices[\'2\']\n
}\n
elif salary_slices.has_key(\'A\'):\n
default[\'arrco/tranche_a\'] = \\\n
d[\'arrco/tranche_a\'] = \\\n
{ \'employer_rate\' : 4.5\n
, \'employee_rate\' : 3.0\n
, \'base\' : salary_slices[\'A\']\n
......@@ -342,26 +372,26 @@ elif salary_slices.has_key(\'A\'):\n
# AGFF\n
if executive:\n
if salary_slices.has_key(\'A\'):\n
default[\'agff_tranche_a/tranche_a\'] = \\\n
d[\'agff_tranche_a/tranche_a\'] = \\\n
{ \'employer_rate\' : 1.20\n
, \'employee_rate\' : 0.80\n
, \'base\' : salary_slices[\'A\']\n
}\n
if salary_slices.has_key(\'B\'):\n
default[\'agff_tranche_b/tranche_b\'] = \\\n
d[\'agff_tranche_b/tranche_b\'] = \\\n
{ \'employer_rate\' : 1.30\n
, \'employee_rate\' : 0.90\n
, \'base\' : salary_slices[\'B\']\n
}\n
else:\n
if salary_slices.has_key(\'1\'):\n
default[\'agff_tranche_a/tranche_1\'] = \\\n
d[\'agff_tranche_a/tranche_1\'] = \\\n
{ \'employer_rate\' : 1.20\n
, \'employee_rate\' : 0.80\n
, \'base\' : salary_slices[\'1\']\n
}\n
if salary_slices.has_key(\'2\'):\n
default[\'agff_tranche_b/tranche_2\'] = \\\n
d[\'agff_tranche_b/tranche_2\'] = \\\n
{ \'employer_rate\' : 1.30\n
, \'employee_rate\' : 0.90\n
, \'base\' : salary_slices[\'2\']\n
......@@ -371,14 +401,14 @@ else:\n
# TODO: fix the repartition of share rate in case of slice C\n
if executive:\n
if salary_slices.has_key(\'B\'):\n
default[\'argic/tranche_b\'] = \\\n
d[\'argic/tranche_b\'] = \\\n
{ \'employer_rate\' : 12.60\n
, \'employee_rate\' : 7.70\n
, \'base\' : salary_slices[\'B\']\n
}\n
if salary_slices.has_key(\'C\'):\n
# free repartition (20.30% to share between employee & employer)\n
default[\'argic/tranche_c\'] = \\\n
d[\'argic/tranche_c\'] = \\\n
{ \'employer_rate\' : 10.15\n
, \'employee_rate\' : 10.15\n
, \'base\' : salary_slices[\'C\']\n
......@@ -387,19 +417,19 @@ if executive:\n
# CET\n
if executive:\n
if salary_slices.has_key(\'A\'):\n
default[\'cet/tranche_a\'] = \\\n
d[\'cet/tranche_a\'] = \\\n
{ \'employer_rate\' : 0.22\n
, \'employee_rate\' : 0.13\n
, \'base\' : salary_slices[\'A\']\n
}\n
if salary_slices.has_key(\'B\'):\n
default[\'cet/tranche_b\'] = \\\n
d[\'cet/tranche_b\'] = \\\n
{ \'employer_rate\' : 0.22\n
, \'employee_rate\' : 0.13\n
, \'base\' : salary_slices[\'B\']\n
}\n
if salary_slices.has_key(\'C\'):\n
default[\'cet/tranche_c\'] = \\\n
d[\'cet/tranche_c\'] = \\\n
{ \'employer_rate\' : 0.22\n
, \'employee_rate\' : 0.13\n
, \'base\' : salary_slices[\'C\']\n
......@@ -407,7 +437,7 @@ if executive:\n
\n
# Life insurance = Assurance vie\n
# if executive == True and salary_slices.has_key(\'A\'):\n
# default[\'life_insurance/tranche_a\'] = \\\n
# d[\'life_insurance/tranche_a\'] = \\\n
# { \'employer_rate\' : 1.5\n
# , \'employee_rate\' : None\n
# , \'base\' : salary_slices[\'A\']\n
......@@ -415,36 +445,36 @@ if executive:\n
\n
# APEC forfaitaire\n
if executive:\n
default[\'apec/forfait\'] = \\\n
d[\'apec/forfait\'] = \\\n
{ \'employer_rate\' : 3.72\n
, \'employee_rate\' : 2.49\n
, \'base\' : 100.0\n
, \'base\' : 1.0\n
}\n
if salary_slices.has_key(\'B\'):\n
default[\'apec/tranche_b\'] = \\\n
d[\'apec/tranche_b\'] = \\\n
{ \'employer_rate\' : 0.036\n
, \'employee_rate\' : 0.024\n
, \'base\' : salary_slices[\'B\']\n
}\n
\n
# Retirement = Retraite forfaitaire\n
# Retirement = Retraite Cadre forfaitaire\n
if executive:\n
default[\'cavcic/forfait\'] = \\\n
{ \'employer_rate\' : 34.58\n
, \'employee_rate\' : 20.75\n
, \'base\' : 100.0\n
d[\'cavcic/forfait\'] = \\\n
{ \'employer_rate\' : 35.62\n
, \'employee_rate\' : 21.21\n
, \'base\' : 1.0\n
}\n
\n
# construction tax\n
# if company_size > 9:\n
# default[\'construction_tax/salaire_brut\'] = \\\n
# d[\'construction_tax/salaire_brut\'] = \\\n
# { \'employer_rate\' : 0.45\n
# , \'employee_rate\' : None\n
# , \'base\' : gross_salary\n
# }\n
\n
# training tax\n
# default[\'training_tax/salaire_brut\'] = \\\n
# d[\'training_tax/salaire_brut\'] = \\\n
# { \'employer_rate\' : 0.50\n
# , \'employee_rate\' : None\n
# , \'base\' : gross_salary\n
......@@ -455,7 +485,7 @@ if executive:\n
# rate = 0.15\n
# else:\n
# rate = 1.5\n
# default[\'courses_tax/salaire_brut\'] = \\\n
# d[\'courses_tax/salaire_brut\'] = \\\n
# { \'employer_rate\' : rate\n
# , \'employee_rate\' : None\n
# , \'base\' : gross_salary\n
......@@ -471,7 +501,7 @@ if col_agr not in (None, \'\') and \'syntec\' in col_agr.lower():\n
syntec_rate = 0.96\n
if employee.getMaritalStatusId() == \'married\':\n
syntec_rate *= 2\n
default[\'syntec_insurance/salaire_plafonne_syntec\'] = \\\n
d[\'syntec_insurance/salaire_plafonne_syntec\'] = \\\n
{ \'employer_rate\' : syntec_rate\n
, \'employee_rate\' : syntec_rate\n
, \'base\' : ceiling_salary\n
......@@ -483,33 +513,47 @@ if col_agr not in (None, \'\') and \'syntec\' in col_agr.lower():\n
# * non-working days (= absences)\n
# Thanks to this, the accountant has the freedom to add the missing amount of money\n
# that this script can\'t guess.\n
default[\'retenue_maladie/forfait\'] = \\\n
d[\'retenue_maladie/forfait\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : None\n
, \'base\' : 100.0\n
, \'base\' : 1.0\n
}\n
default[\'primes/forfait\'] = \\\n
d[\'primes/forfait\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : None\n
, \'base\' : 100.0\n
, \'base\' : 1.0\n
}\n
default[\'absences/forfait\'] = \\\n
d[\'absences/forfait\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : None\n
, \'base\' : 100.0\n
, \'base\' : 1.0\n
}\n
\n
# Also add a brand new line for "Reduction Fillon", a negative contribution.\n
# This tax can be calculated automaticcaly.\n
# Because of lack of time we just let the accountant do the work.\n
# See coresponding service description for more details.\n
default[\'reduction_fillon_forfait/forfait\'] = \\\n
d[\'reduction_fillon_forfait/forfait\'] = \\\n
{ \'employer_rate\' : None\n
, \'employee_rate\' : None\n
, \'base\' : 100.0\n
, \'base\' : 1.0\n
}\n
\n
return default\n
# Because all rates above are written in percents, we must convert them in pure floats.\n
# TODO: this part is generic, so move it to PaySheetTransaction_preCalculation script.\n
for line_id in d.keys():\n
# Only \'Fixed\' (or \'Forfait\' in french) base are expressed in percents\n
if not line_id.endswith(\'/forfait\'):\n
# Fix percents\n
for share_type in [\'employer_rate\', \'employee_rate\']:\n
share_value = d[line_id][share_type]\n
if share_value not in (\'\', None):\n
d[line_id][share_type] = share_value / 100.0\n
# Normalize the value of \'Fixed\' (or \'Forfait\' in french) base to 1.0\n
else:\n
d[line_id][\'base\'] = 1.0\n
\n
return d\n
]]></string> </value>
......@@ -600,24 +644,22 @@ return default\n
<string>DateTime</string>
<string>old_limit</string>
<string>comp_type</string>
<string>default</string>
<string>paysheet_services</string>
<string>d</string>
<string>erp5site</string>
<string>hasattr</string>
<string>service_module</string>
<string>paysheet_services</string>
<string>_getiter_</string>
<string>service</string>
<string>base_cat</string>
<string>serv</string>
<string>cat_list</string>
<string>tax_cat</string>
<string>range_cat</string>
<string>cat</string>
<string>str</string>
<string>base</string>
<string>mycategory</string>
<string>service_categories</string>
<string>tax_categories</string>
<string>salary_range_categories</string>
<string>category</string>
<string>salary_range</string>
<string>salary_range_object</string>
<string>None</string>
<string>new_name</string>
<string>preview_line_uid</string>
<string>employer_rate</string>
<string>employee_rate</string>
<string>fngs_employer_rate</string>
......@@ -625,6 +667,9 @@ return default\n
<string>employer_share_rate</string>
<string>col_agr</string>
<string>syntec_rate</string>
<string>line_id</string>
<string>share_type</string>
<string>share_value</string>
</tuple>
</value>
</item>
......
2006-10-19 Kevin
* Update french paysheet rates.
2006-10-18 Kevin
* Add new french payroll services.
* Do not display base and rate for "forfait" services.
......
21
\ No newline at end of file
10
\ No newline at end of file
0.1.11
\ No newline at end of file
0.1.12
\ No newline at end of file
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