Commit 980ce468 authored by Fabien Morin's avatar Fabien Morin

many code have moved to TradeModelLine and TradeCondition remove it from PaySheetTransaction.

Add applyTransformation method wich call the delivery builder to create all the paysheet lines using movements returned by updateAggregatedAmountList


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@27413 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 324f3b9a
...@@ -39,7 +39,6 @@ class PaySheetTransaction(Invoice): ...@@ -39,7 +39,6 @@ class PaySheetTransaction(Invoice):
""" """
A paysheet will store data about the salary of an employee A paysheet will store data about the salary of an employee
""" """
meta_type = 'ERP5 Pay Sheet Transaction' meta_type = 'ERP5 Pay Sheet Transaction'
portal_type = 'Pay Sheet Transaction' portal_type = 'Pay Sheet Transaction'
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
...@@ -68,7 +67,6 @@ class PaySheetTransaction(Invoice): ...@@ -68,7 +67,6 @@ class PaySheetTransaction(Invoice):
# Declarative Interface # Declarative Interface
__implements__ = ( ) __implements__ = ( )
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getRatioQuantityFromReference') 'getRatioQuantityFromReference')
def getRatioQuantityFromReference(self, ratio_reference=None): def getRatioQuantityFromReference(self, ratio_reference=None):
...@@ -79,13 +77,11 @@ class PaySheetTransaction(Invoice): ...@@ -79,13 +77,11 @@ class PaySheetTransaction(Invoice):
# get ratio lines # get ratio lines
portal_type_list = ['Pay Sheet Model Ratio Line'] portal_type_list = ['Pay Sheet Model Ratio Line']
object_ratio_list = self.contentValues(portal_type=portal_type_list) object_ratio_list = self.contentValues(portal_type=portal_type_list)
# look for ratio lines on the paysheet # look for ratio lines on the paysheet
if object_ratio_list: if object_ratio_list:
for obj in object_ratio_list: for obj in object_ratio_list:
if obj.getReference() == ratio_reference: if obj.getReference() == ratio_reference:
return obj.getQuantity() return obj.getQuantity()
# if not find in the paysheet, look on dependence tree # if not find in the paysheet, look on dependence tree
sub_object_list = self.getInheritedObjectValueList(portal_type_list) sub_object_list = self.getInheritedObjectValueList(portal_type_list)
object_ratio_list = sub_object_list object_ratio_list = sub_object_list
...@@ -140,379 +136,62 @@ class PaySheetTransaction(Invoice): ...@@ -140,379 +136,62 @@ class PaySheetTransaction(Invoice):
return [self.getAnnotationLineFromReference(reference) \ return [self.getAnnotationLineFromReference(reference) \
for reference in reference_list] for reference in reference_list]
security.declareProtected(Permissions.AddPortalContent,
'createPaySheetLine')
def createPaySheetLine(self, cell_list, title='', resource='',
description='', base_contribution_list=None, int_index=None,
categories=None, **kw):
'''
This function register all paysheet informations in paysheet lines and
cells. Select good cells only
'''
if not resource:
raise ValueError, "Cannot create Pay Sheet Line without resource"
good_cell_list = []
for cell in cell_list:
if cell['quantity'] or cell['price']:
good_cell_list.append(cell)
if len(good_cell_list) == 0:
return
# Get all variation categories used in cell_list
var_cat_list = []
for cell in good_cell_list:
# Don't add a variation category if already in it
for category in cell['category_list']:
if category not in var_cat_list:
var_cat_list.append(category)
resource_value = self.getPortalObject().unrestrictedTraverse(resource)
# Add a new Pay Sheet Line
payline = self.newContent(
portal_type='Pay Sheet Line',
title=title,
description=description,
destination=self.getSourceSection(),
resource_value=resource_value,
destination_section=self.getDestinationSection(),
variation_base_category_list=('tax_category',
'salary_range'),
variation_category_list=var_cat_list,
base_contribution_list=base_contribution_list,
int_index=int_index,
**kw)
# add cells categories to the Pay Sheet Line
# it's a sort of inheritance of sub-object data
if categories:
categories_list = payline.getCategoryList()
categories_list.extend(categories)
# XXX editing categories directly is wrong !
payline.edit(categories=categories_list)
base_id = 'movement'
a = payline.updateCellRange(base_id=base_id)
# create cell_list
for cell in good_cell_list:
paycell = payline.newCell(base_id=base_id, *cell['category_list'])
paycell.edit(mapped_value_property_list=('price', 'quantity'),
force_update=1,
**cell)
return payline
security.declareProtected(Permissions.AccessContentsInformation,
'getEditableModelLineAsDict')
def getEditableModelLineAsDict(self, listbox, paysheet):
'''
listbox is composed by one line for each slice of editables model_lines
this script will return editable model lines as a dict with the
properties that could/have be modified.
'''
portal = paysheet.getPortalObject()
model_line_dict = {}
for line in listbox:
model_line_url = line['model_line']
model_line = portal.restrictedTraverse(model_line_url)
salary_range_relative_url=line['salary_range_relative_url']
if salary_range_relative_url == '':
salary_range_relative_url='no_slice'
# if this is the first slice of the model_line, create the dict
if not model_line_dict.has_key(model_line_url):
model_line_dict[model_line_url] = {'int_index' :\
model_line.getIntIndex()}
model_line_dict[model_line_url][salary_range_relative_url] = {}
slice_dict = model_line_dict[model_line_url][salary_range_relative_url]
for tax_category in model_line.getTaxCategoryList():
if line.has_key('%s_quantity' % tax_category) and \
line.has_key('%s_price' % tax_category):
slice_dict[tax_category] = dict(
quantity=line['%s_quantity' % tax_category],
price=line['%s_price' % tax_category],)
else:
LOG('ERP5', INFO, 'No attribute %s_quantity or %s_price for model_line %s' %
( tax_category, tax_category, model_line_url ))
return model_line_dict
security.declareProtected(Permissions.AccessContentsInformation,
'getNotEditableModelLineAsDict')
def getNotEditableModelLineAsDict(self, paysheet):
'''
return the not editable lines as dict
'''
model = paysheet.getSpecialiseValue().getEffectiveModel(paysheet)
def sortByIntIndex(a, b):
return cmp(a.getIntIndex(), b.getIntIndex())
# get model lines
portal_type_list = ['Pay Sheet Model Line']
sub_object_list = paysheet.getInheritedObjectValueList(portal_type_list)
sub_object_list.sort(sortByIntIndex)
model_line_list = sub_object_list
model_line_dict = {}
for model_line in model_line_list:
model_line_url = model_line.getRelativeUrl()
cell_list = model_line.contentValues(portal_type='Pay Sheet Cell')
for cell in cell_list:
salary_range_relative_url = \
cell.getVariationCategoryList(base_category_list='salary_range')
tax_category = cell.getTaxCategory()
if len(salary_range_relative_url):
salary_range_relative_url = salary_range_relative_url[0]
else:
salary_range_relative_url = 'no_slice'
# if this is the first slice of the model_line, create the dict
if not model_line_dict.has_key(model_line_url):
model_line_dict[model_line_url] = {'int_index' :\
model_line.getIntIndex()}
model_line_dict[model_line_url][salary_range_relative_url] = {}
slice_dict = model_line_dict[model_line_url][salary_range_relative_url]
slice_dict[tax_category] = dict(quantity=cell.getQuantity(),
price=cell.getPrice())
return model_line_dict
security.declareProtected(Permissions.ModifyPortalContent,
'createPaySheetLineList')
def createPaySheetLineList(self, listbox=None, batch_mode=0, **kw):
'''Create all Pay Sheet Lines (editable or not)
parameters :
- batch_mode :if batch_mode is enabled (=1) then there is no preview view,
and editable lines are considered as not editable lines.
This is usefull to generate all PaySheet of a company.
Modification values can be made on each paysheet after, by
using the "Calculation of the Pay Sheet Transaction"
action button. (concerned model lines must be editable)
'''
paysheet = self
if not batch_mode and listbox is not None:
model_line_dict = paysheet.getEditableModelLineAsDict(listbox=listbox,
paysheet=paysheet)
# Get Precision
precision = paysheet.getPriceCurrencyValue().getQuantityPrecision()
# in this dictionary will be saved the current amount corresponding to
# the tuple (tax_category, base_amount) :
# current_amount = base_amount_dict[base_amount][share]
base_amount_dict = {}
model = paysheet.getSpecialiseValue().getEffectiveModel(paysheet)
def sortByIntIndex(a, b):
return cmp(a.getIntIndex(), b.getIntIndex())
# get model lines
portal_type_list = ['Pay Sheet Model Line']
sub_object_list = paysheet.getInheritedObjectValueList(portal_type_list)
sub_object_list.sort(sortByIntIndex)
model_line_list = sub_object_list
pay_sheet_line_list = []
# main loop : find all informations and create cell and PaySheetLines
for model_line in model_line_list:
cell_list = []
# test with predicate if this model line could be applied
if not model_line.test(paysheet,):
# This model_line should not be applied
LOG('ERP5', DEBUG, 'createPaySheetLineList: Model Line %s (%s) will'
' not be applied, because predicates does not match' %
( model_line.getTitle(), model_line.getRelativeUrl() ))
continue
service = model_line.getResourceValue()
if service is None:
raise ValueError, 'Model Line %s has no resource' % (
model_line.getRelativeUrl())
title = model_line.getTitleOrId()
int_index = model_line.getFloatIndex()
resource = service.getRelativeUrl()
base_contribution_list = model_line.getBaseContributionList()
# get the service provider, either on the model line, or using the
# annotation line reference.
source_section = None
source_annotation_line_reference = \
model_line.getSourceAnnotationLineReference()
if model_line.getSource():
source_section = model_line.getSource()
elif source_annotation_line_reference:
annotation_line = paysheet.getAnnotationLineFromReference(source_annotation_line_reference)
if annotation_line is not None:
source_section = annotation_line.getSource()
if model_line.getDescription():
desc = model_line.getDescription()
# if the model_line description is empty, the payroll service
# description is used
else:
desc = service.getDescription()
base_category_list = model_line.getVariationBaseCategoryList()
category_list_list = []
for base_cat in base_category_list:
category_list = model_line.getVariationCategoryList(
base_category_list=base_cat)
category_list_list.append(category_list)
cartesian_product = cartesianProduct(category_list_list)
share = None
slice = 'no_slice'
indice = 0
categories = []
for cell_coordinates in cartesian_product:
indice += 1
cell = model_line.getCell(*cell_coordinates)
if cell is None:
LOG('ERP5', INFO, "Can't find the cell corresponding to those cells"
" coordinates : %s" % cell_coordinates)
# XXX is it enough to log ?
continue
if len(cell.getVariationCategoryList(\
base_category_list='tax_category')):
share = cell.getVariationCategoryList(\
base_category_list='tax_category')[0]
if len(cell.getVariationCategoryList(\
base_category_list='salary_range')):
slice = cell.getVariationCategoryList(\
base_category_list='salary_range')[0]
# get the edited values if this model_line is editable
# and replace the original cell values by this ones
if model_line.isEditable() and not batch_mode:
tax_category = cell.getTaxCategory()
# get the dict who contain modified values
line_dict = model_line_dict[model_line.getRelativeUrl()]
def getModifiedCell(cell, slice_dict, tax_category):
'''
return a cell with the edited values (contained in slice_dict)
'''
if slice_dict:
if slice_dict.has_key(tax_category):
if slice_dict[tax_category].has_key('quantity'):
cell = cell.asContext(\
quantity=slice_dict[tax_category]['quantity'])
if slice_dict[tax_category].has_key('price'):
cell = cell.asContext(price=slice_dict[tax_category]['price'])
return cell
cell = getModifiedCell(cell, line_dict[slice], tax_category)
######################
# calculation part : #
######################
# get script in this order
# 1 - model_line script
# 2 - model script
# 3 - get the default calculation script
# get the model line script
script_name = model_line.getCalculationScriptId()
if script_name is None:
# if model line script is None, get the default model script
script_name = model.getDefaultCalculationScriptId()
if script_name is None:
# if no calculation script found, use a default script :
script_name = 'PaySheetTransaction_defaultCalculationScript'
if getattr(paysheet, script_name, None) is None:
raise ValueError, "Unable to find `%s` calculation script" % \
script_name
calculation_script = getattr(paysheet, script_name, None)
quantity=0
price=0
cell_dict = calculation_script(base_amount_dict=base_amount_dict,
cell=cell,)
cell_dict.update({'category_list': cell_coordinates})
if cell_dict.has_key('categories'):
for cat in cell_dict['categories']:
if cat not in categories:
categories.append(cat)
quantity = cell_dict['quantity']
price = cell_dict['price']
if quantity and price:
cell_list.append(cell_dict)
# update the base_contribution
for base_contribution in base_contribution_list:
if quantity:
if base_amount_dict.has_key(base_contribution) and \
base_amount_dict[base_contribution].has_key(share):
old_val = base_amount_dict[base_contribution][share]
else:
old_val = 0
new_val = old_val + quantity
if not base_amount_dict.has_key(base_contribution):
base_amount_dict[base_contribution]={}
if price:
new_val = round((old_val + quantity*price), precision)
base_amount_dict[base_contribution][share] = new_val
if cell_list and model_line.isCreatePaysheetLine():
# create the PaySheetLine
pay_sheet_line = paysheet.createPaySheetLine(
title=title,
resource=resource,
source_section=source_section,
int_index=int_index,
desc=desc,
base_contribution_list=base_contribution_list,
cell_list=cell_list,
categories=categories)
pay_sheet_line_list.append(pay_sheet_line)
# this script is used to add a line that permit to have good accounting
# lines
post_calculation_script = paysheet._getTypeBasedMethod('postCalculation')
if post_calculation_script:
post_calculation_script()
return pay_sheet_line_list
def getInheritedObjectValueList(self, portal_type_list, property_list=()): def getInheritedObjectValueList(self, portal_type_list, property_list=()):
'''Return a list of all subobjects of the herited model (incuding the '''Return a list of all subobjects of the herited model (incuding the
dependencies). dependencies).
If property_list is provided, only subobjects with at least one of those If property_list is provided, only subobjects with at least one of those
properties is defined will be taken into account properties will be taken into account
''' '''
model = self.getSpecialiseValue().getEffectiveModel(self) model = self.getSpecialiseValue().getEffectiveModel(\
model_reference_dict = model.getInheritanceModelReferenceDict( start_date=self.getStartDate(),
stop_date=self.getStopDate())
model_reference_dict = model.getInheritanceReferenceDict(
portal_type_list=portal_type_list, portal_type_list=portal_type_list,
property_list=property_list) property_list=property_list)
sub_object_list = [] sub_object_list = []
traverse = self.getPortalObject().unrestrictedTraverse traverse = self.getPortalObject().unrestrictedTraverse
for model_url, id_list in model_reference_dict.items(): for model_url, id_list in model_reference_dict.items():
model = traverse(model_url) model = traverse(model_url)
sub_object_list.extend([model._getOb(x) for x in id_list]) sub_object_list.extend([model._getOb(x) for x in id_list])
return sub_object_list return sub_object_list
def applyTransformation(self):
'''use a delivery builder to create all the paysheet lines using
movements return by updateAggregatedAmountList
'''
portal = self.getPortalObject()
paysheet_model = self.getSpecialiseValue()
movement_dict = paysheet_model.updateAggregatedAmountList(context=self)
for movement in movement_dict['movement_to_delete_list']:
parent = movement.getParentValue()
parent.manage_delObjects(movement.getId())
business_process_list = paysheet_model.findSpecialiseValueList(\
context=paysheet_model,
portal_type_list=['Business Process'])
if len(business_process_list):
# XXX currently, we consider that is to complicated to use more than one
# Business Process, so we take the first (wich is the nearest from
# the paysheet)
business_process = business_process_list[0]
movement_list_trade_phase_dic = {}
for movement in movement_dict['movement_to_add_list']:
trade_phase = movement.getTradePhase()
if not movement_list_trade_phase_dic.has_key(trade_phase):
movement_list_trade_phase_dic[trade_phase] = []
movement_list_trade_phase_dic[trade_phase].append(movement)
for trade_phase in movement_list_trade_phase_dic.keys():
builder_list = []
business_path_list = business_process.getPathValueList(trade_phase=\
trade_phase)
if len(business_path_list) > 1:
raise NotImplementedError, 'For now, payroll can not support more '\
'than one business_path with same trade_phase. '\
'%s have same trade_phase' % repr(business_path_list)
if len(business_path_list) == 1:
business_path = business_path_list[0]
builder_list = [portal.restrictedTraverse(url) for url in\
business_path.getDeliveryBuilderList()]
for builder in builder_list:
builder.build(delivery_relative_url_list=[self.getRelativeUrl(),],
movement_list = movement_list_trade_phase_dic[trade_phase])
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