Commit c9527c73 authored by Fabien Morin's avatar Fabien Morin

add int_index on Pay Sheet Model Line. Now the calclation will be made in the order of

the Pay Sheet Model Lines int_index. int_index have been added in the Pay Sheet
Line in order to be displayed in a particular order on the paysheet.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@17693 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent c2deeef2
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Invoice import Invoice from Products.ERP5.Document.Invoice import Invoice
from zLOG import LOG
class PaySheetTransaction(Invoice): class PaySheetTransaction(Invoice):
""" """
...@@ -278,31 +279,6 @@ class PaySheetTransaction(Invoice): ...@@ -278,31 +279,6 @@ class PaySheetTransaction(Invoice):
column, row = getDictList(['tax_category', 'base_amount']) column, row = getDictList(['tax_category', 'base_amount'])
base_amount_table = getEmptyTwoDimentionalTable(nb_columns=len(column), base_amount_table = getEmptyTwoDimentionalTable(nb_columns=len(column),
nb_rows=len(row)) nb_rows=len(row))
# XXX currently, there is a problem not resolved yet :
# if a tax_category have a base_application ('non_deductible_tax','bonus')
# and if a bonus have a base_application ('base_salary',), calculation
# must be made in a particular order, and sometimes, it's possible to
# have circular dependencies and so, impossible to resove this cases.
# The best, will to do calculation with understanding dependencies and
# raise an error if there is circular dependence. Currently, caluls are
# made in a paticular order defined by the list order_of_calculation
# so dependencies are not taken into account.
# And result are wrong in some cases.
# solutions :
# 1 - do calculation without any order and redo evry calculs while a value
# in the base_amount_table have changed. This is a little slow but safe.
# 2 - determine an order using dependencies graph, but this solution
# is not evolutive and safe, because it not take into account the new
# categories
# 3 - add an order field in paysheet lines and model lines : the user
# must determine an order manually and it will be easy to apply it
# in my opinion, the best solution for the accountant is the first, but it
# will be slow, the easier is the 3.
# It's important to do calculation in a precise order,
# most of time, a tax could depend on base_salary and bonus,
# so they must be calculated before
def sortByIntIndex(a, b): def sortByIntIndex(a, b):
return cmp(a.getIntIndex(), return cmp(a.getIntIndex(),
...@@ -311,13 +287,10 @@ class PaySheetTransaction(Invoice): ...@@ -311,13 +287,10 @@ class PaySheetTransaction(Invoice):
base_amount_list = self.portal_categories['base_amount'].contentValues() base_amount_list = self.portal_categories['base_amount'].contentValues()
base_amount_list.sort(sortByIntIndex) base_amount_list.sort(sortByIntIndex)
order_of_calculation = [x.getRelativeUrl() for x in base_amount_list]
#order_of_calculation = ('base_amount/base_salary', 'base_amount/bonus',
# 'base_amount/non_deductible_tax',
# 'base_amount/deductible_tax')
# it's important to get the editable lines to know if they contribute to # it's important to get the editable lines to know if they contribute to
# a base_amount (this is required to do the calcul later # a base_amount (this is required to do the calcul later)
# get edited lines: # get edited lines:
paysheetline_list = self.contentValues(portal_type = ['Pay Sheet Line']) paysheetline_list = self.contentValues(portal_type = ['Pay Sheet Line'])
...@@ -342,152 +315,135 @@ class PaySheetTransaction(Invoice): ...@@ -342,152 +315,135 @@ class PaySheetTransaction(Invoice):
# get not editables model lines # get not editables model lines
model = self.getSpecialiseValue() model = self.getSpecialiseValue()
model_line_list = model.contentValues(portal_type='Pay Sheet Model Line') model_line_list = model.contentValues(portal_type='Pay Sheet Model Line',
sort_on='int_index')
model_line_list = [line for line in model_line_list if not line.getEditable()]
pay_sheet_line_list = [] pay_sheet_line_list = []
employee_tax_amount = 0 employee_tax_amount = 0
# initilise a dict with model_line relative url and 0 value to know
# if a contribution have already been calculated
already_calculate = dict([[model_line.getRelativeUrl(), 0] \
for model_line in model_line_list])
# main loop : find all informations and create cell and PaySheetLines # main loop : find all informations and create cell and PaySheetLines
for base_ordered in order_of_calculation: for model_line in model_line_list:
for model_line in model_line_list: cell_list = []
# test with predicate if this model line could be applied
# get only not editables model lines if not model_line.test(self,):
if model_line.getEditable(): # This line should not be used
continue continue
if model_line.getResourceValue().getBaseAmountList(base=1) and \
base_ordered not in \ service = model_line.getResourceValue()
model_line.getResourceValue().getBaseAmountList(base=1): title = model_line.getTitleOrId()
continue id = model_line.getId()
if already_calculate[model_line.getRelativeUrl()]: res = service.getRelativeUrl()
continue if model_line.getDescription():
else: desc = ''.join(model_line.getDescription())
already_calculate[model_line.getRelativeUrl()] = 1 # if the model_line description is empty, the payroll service
# this prevent to calculate two times the same model line if it's # description is used
# resource have many Base Participation, it will be calculate else: desc = ''.join(service.getDescription())
# many times.
variation_share_list = model_line.getVariationCategoryList(\
cell_list = [] base_category_list=['tax_category',])
# test with predicate if this model line could be applied variation_slice_list = model_line.getVariationCategoryList(\
if not model_line.test(self,): base_category_list=['salary_range',])
# This line should not be used
continue for share in variation_share_list:
base_application = None
service = model_line.getResourceValue() for slice in variation_slice_list:
title = model_line.getTitleOrId()
id = model_line.getId() #get the amount of application for this line
res = service.getRelativeUrl() base_application_list = model_line.getBaseAmountList(base=1)
if model_line.getDescription(): if base_application is None:
desc = ''.join(model_line.getDescription()) base_application = 0
# if the model_line description is empty, the payroll service for base in model_line.getBaseAmountList(base=1):
# description is used if base_amount_table[column[share]][row[base]] is not None:
else: desc = ''.join(service.getDescription()) base_application += \
base_amount_table[column[share]][row[base]]
variation_share_list = model_line.getVariationCategoryList(\
base_category_list=['tax_category',])
variation_slice_list = model_line.getVariationCategoryList(\
base_category_list=['salary_range',])
for share in variation_share_list:
base_application = None
for slice in variation_slice_list:
#get the amount of application for this line
base_application_list = model_line.getBaseAmountList(base=1)
if base_application is None:
base_application = 0
for base in model_line.getBaseAmountList(base=1):
if base_amount_table[column[share]][row[base]] is not None:
base_application += \
base_amount_table[column[share]][row[base]]
cell = model_line.getCell(slice, share)
if cell is not None: cell = model_line.getCell(slice, share)
# get the slice :
model_slice = None if cell is not None:
model_slice = model_line.getParentValue().getCell(slice) # get the slice :
quantity = 0.0 model_slice = None
price = 0.0 model_slice = model_line.getParentValue().getCell(slice)
if model_slice is not None: quantity = 0.0
model_slice_min = model_slice.getQuantityRangeMin() price = 0.0
model_slice_max = model_slice.getQuantityRangeMax() if model_slice is not None:
quantity = cell.getQuantity() model_slice_min = model_slice.getQuantityRangeMin()
price = cell.getPrice() model_slice_max = model_slice.getQuantityRangeMax()
quantity = cell.getQuantity()
###################### price = cell.getPrice()
# calculation part : #
###################### ######################
script_name = model.getLocalizedCalculationScriptId() # calculation part : #
if script_name is None or \ ######################
getattr(self, script_name, None) is None: script_name = model.getLocalizedCalculationScriptId()
# if no calculation script found, use a default method : if script_name is None or \
if not quantity: getattr(self, script_name, None) is None:
if base_application <= model_slice_max: # if no calculation script found, use a default method :
quantity = base_application if not quantity:
else: if base_application <= model_slice_max:
quantity = model_slice_max quantity = base_application
else:
quantity = model_slice_max
else:
localized_calculation_script = getattr(self, script_name,
None)
quantity, price = localized_calculation_script(\
paysheet=self,
model_slice_min = model_slice_min,
model_slice_max=model_slice_max,
quantity=quantity,
price=price,
model_line=model_line)
# Cell creation :
# Define an empty new cell
new_cell = { 'axe_list' : [share, slice]
, 'quantity' : quantity
, 'price' : price
}
cell_list.append(new_cell)
#XXX this is a hack to have the net salary
base_list = model_line.getResourceValue().getBaseAmountList()
if price is not None and 'employee_share' in share and\
not ('base_salary' in base_list or\
'bonus' in base_list or\
'gross_salary' in base_list):
employee_tax_amount += round((price * quantity), precision)
# update base participation
base_participation_list = service.getBaseAmountList(base=1)
for base_participation in base_participation_list:
old_val = \
base_amount_table[column[share]][row[base_participation]]
if quantity:
if old_val is not None:
new_val = old_val + quantity
else: else:
localized_calculation_script = getattr(self, script_name, new_val = quantity
None) if price:
quantity, price = localized_calculation_script(\
paysheet=self,
model_slice_min = model_slice_min,
model_slice_max=model_slice_max,
quantity=quantity,
price=price,
model_line=model_line)
# Cell creation :
# Define an empty new cell
new_cell = { 'axe_list' : [share, slice]
, 'quantity' : quantity
, 'price' : price
}
cell_list.append(new_cell)
#XXX this is a hack to have the net salary
if price is not None and 'employee_share' in share and\
base_ordered not in ('base_salary', 'bonus') :
employee_tax_amount += round((price * quantity), precision)
# update base participation
base_participation_list = service.getBaseAmountList(base=1)
for base_participation in base_participation_list:
old_val = \
base_amount_table[column[share]][row[base_participation]]
if quantity:
if old_val is not None: if old_val is not None:
new_val = old_val + quantity new_val = round((old_val + quantity*price), precision)
else: base_amount_table[column[share]][row[base_participation]]= \
new_val = quantity new_val
if price: base_amount_table[column[share]][row[base_participation]] = \
if old_val is not None: new_val
new_val = round((old_val + quantity*price), precision)
base_amount_table[column[share]][row[base_participation]]= \ # decrease the base_application used for this model line
new_val if cell is not None :
base_amount_table[column[share]][row[base_participation]] = \ base_application -= quantity
new_val
if cell_list:
# decrease the base_application used for this model line if # create the PaySheetLine
if cell is not None : pay_sheet_line = self.createPaySheetLine(
base_application -= quantity title = title,
id = id,
if cell_list: res = res,
# create the PaySheetLine desc = desc,
pay_sheet_line = self.createPaySheetLine( cell_list = cell_list,
title = title, )
id = id, pay_sheet_line_list.append(pay_sheet_line)
res = res,
desc = desc,
cell_list = cell_list,
)
pay_sheet_line_list.append(pay_sheet_line)
# create a line of the total tax payed by the employee # create a line of the total tax payed by the employee
# this hack permit to calculate the net salary # this hack permit to calculate the net salary
......
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