PaySheetTransaction.py 9.74 KB
Newer Older
1
# -*- coding: utf-8 -*-
Yoshinori Okuji's avatar
Yoshinori Okuji committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

30

Yoshinori Okuji's avatar
Yoshinori Okuji committed
31
from AccessControl import ClassSecurityInfo
32
from Products.ERP5Type import Permissions, PropertySheet
33
from Products.ERP5.Document.Invoice import Invoice
Yoshinori Okuji's avatar
Yoshinori Okuji committed
34

Fabien Morin's avatar
Fabien Morin committed
35 36
#XXX TODO: review naming of new methods

37
class PaySheetTransaction(Invoice):
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  """
  A paysheet will store data about the salary of an employee
  """
  meta_type = 'ERP5 Pay Sheet Transaction'
  portal_type = 'Pay Sheet Transaction'
  add_permission = Permissions.AddPortalContent

  # Declarative security
  security = ClassSecurityInfo()
  security.declareObjectProtected(Permissions.AccessContentsInformation)

  # Default Properties
  property_sheets = ( PropertySheet.Base
                    , PropertySheet.SimpleItem
                    , PropertySheet.CategoryCore
                    , PropertySheet.Task
                    , PropertySheet.Arrow
                    , PropertySheet.Delivery
                    , PropertySheet.Movement
                    , PropertySheet.Amount
                    , PropertySheet.XMLObject
                    , PropertySheet.TradeCondition
                    , PropertySheet.DefaultAnnotationLine
                    )


64
  security.declareProtected(Permissions.AccessContentsInformation,
Fabien Morin's avatar
Fabien Morin committed
65
                            'getRatioQuantityFromReference')
66 67 68 69 70
  def getRatioQuantityFromReference(self, ratio_reference=None):
    """
    return the ratio value correponding to the ratio_reference,
    None if ratio_reference not found
    """
71 72
    # get ratio lines
    portal_type_list = ['Pay Sheet Model Ratio Line']
Fabien Morin's avatar
Fabien Morin committed
73 74 75
    object_ratio_list = self.contentValues(portal_type=portal_type_list)
    # look for ratio lines on the paysheet
    if object_ratio_list:
76 77 78
      for obj in object_ratio_list:
        if obj.getReference() == ratio_reference:
          return obj.getQuantity()
Fabien Morin's avatar
Fabien Morin committed
79
    # if not find in the paysheet, look on dependence tree
80
    sub_object_list = self.getInheritedObjectValueList(portal_type_list)
81
    object_ratio_list = sub_object_list
82 83 84
    for document in object_ratio_list:
      if document.getReference() == ratio_reference:
        return document.getQuantity()
Fabien Morin's avatar
typo  
Fabien Morin committed
85
    return None
86 87

  security.declareProtected(Permissions.AccessContentsInformation,
Fabien Morin's avatar
Fabien Morin committed
88
                            'getRatioQuantityList')
89 90 91 92 93 94
  def getRatioQuantityList(self, ratio_reference_list):
    """
    Return a list of reference_ratio_list correponding values.
    reference_ratio_list is a list of references to the ratio lines
    we want to get.
    """
95
    if not isinstance(ratio_reference_list, (list, tuple)):
96 97 98 99
      return [self.getRatioQuantityFromReference(ratio_reference_list)]
    return [self.getRatioQuantityFromReference(reference) \
        for reference in ratio_reference_list]

100
  security.declareProtected(Permissions.AccessContentsInformation,
Fabien Morin's avatar
Fabien Morin committed
101
                            'getAnnotationLineFromReference')
102
  def getAnnotationLineFromReference(self, reference=None):
103 104
    """Return the annotation line corresponding to the reference.
    Returns None if reference not found
105
    """
Fabien Morin's avatar
Fabien Morin committed
106
    # look for annotation lines on the paysheet
107
    annotation_line_list = self.contentValues(portal_type=['Annotation Line'])
Fabien Morin's avatar
Fabien Morin committed
108 109
    if annotation_line_list:
      for annotation_line in annotation_line_list:
110
        if (annotation_line.getReference() or annotation_line.getId()) == reference :
Fabien Morin's avatar
Fabien Morin committed
111 112
          return annotation_line
    # if not find in the paysheet, look on dependence tree
113
    for annotation_line in self.getInheritedObjectValueList(['Annotation Line']):
114
      if (annotation_line.getReference() or annotation_line.getId()) == reference:
115
        return annotation_line
Fabien Morin's avatar
typo  
Fabien Morin committed
116
    return None
117 118

  security.declareProtected(Permissions.AccessContentsInformation,
Fabien Morin's avatar
Fabien Morin committed
119
                            'getAnnotationLineListList')
120
  def getAnnotationLineListList(self, reference_list):
121
    """Return a list of annotation lines corresponding to the reference_list
Fabien Morin's avatar
Fabien Morin committed
122
    reference_list is a list of references to the Annotation Line we want
123 124
    to get.
    """
125
    if not isinstance(reference_list, (list, tuple)):
126 127 128
      return [self.getAnnotationLineFromReference(reference_list)]
    return [self.getAnnotationLineFromReference(reference) \
        for reference in reference_list]
129

Fabien Morin's avatar
Fabien Morin committed
130 131
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getInheritedObjectValueList')
132
  def getInheritedObjectValueList(self, portal_type_list, property_list=()):
133
    '''Return a list of all subobjects of the herited model (incuding the
134 135
      dependencies).
      If property_list is provided, only subobjects with at least one of those
136
      properties will be taken into account
137
    '''
138
    model = self.getSpecialiseValue()
139
    sub_object_list = []
140 141
    if model is not None:
      # if there is an effective model
142
      model_reference_dict = model.getInheritanceReferenceDict(self,
143 144 145 146 147 148
                                     portal_type_list=portal_type_list,
                                     property_list=property_list)
      traverse = self.getPortalObject().unrestrictedTraverse
      for model_url, id_list in model_reference_dict.items():
        model = traverse(model_url)
        sub_object_list.extend([model._getOb(x) for x in id_list])
149 150
    return sub_object_list

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
  security.declarePrivate('updateAggregatedAmountList')
  def updateAggregatedAmountList(self, *args, **kw):
    amount_dict = dict(((x.reference, tuple(x.getVariationCategoryList())), x)
                       for x in self.getAggregatedAmountList(*args, **kw))
    movement_to_delete_list = []
    for movement in self.getMovementList():
      if movement.getBaseApplication():
        amount = amount_dict.pop((movement.getProperty('reference'),
                                  tuple(movement.getVariationCategoryList())),
                                 None)
        if amount is None:
          movement_to_delete_list.append(movement)
        else:
          movement.edit(**dict((x, amount.getProperty(x))
              for x in ('price', 'resource', 'quantity',
                        'base_application_list', 'base_contribution_list')))

    return {'movement_to_delete_list': movement_to_delete_list,
            'movement_to_add_list': amount_dict.values()}

Fabien Morin's avatar
Fabien Morin committed
171 172
  security.declareProtected(Permissions.ModifyPortalContent,
                            'applyTransformation')
173
  def applyTransformation(self):
Fabien Morin's avatar
Fabien Morin committed
174
    '''use a delivery builder to create all the paysheet lines using
175 176 177 178
      movements return by updateAggregatedAmountList
    '''
    portal = self.getPortalObject()
    paysheet_model = self.getSpecialiseValue()
179
    movement_dict = self.updateAggregatedAmountList()
180 181
    for movement in movement_dict['movement_to_delete_list']:
      parent = movement.getParentValue()
182 183
      if parent.getPortalType() == 'Pay Sheet Line':
        parent.manage_delObjects(movement.getId())
Fabien Morin's avatar
Fabien Morin committed
184 185 186
      if len(parent.contentValues(portal_type='Pay Sheet Cell')) == 0:
        # the line contain no movements, remove it
        self.manage_delObjects(parent.getId())
187 188
    business_process_list = paysheet_model.findEffectiveSpecialiseValueList(
        self, portal_type_list=['Business Process'])
189 190 191 192 193 194 195
    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']:
196 197 198 199 200 201
        if movement.getTotalPrice() != 0:
          # remove movement with 0 total_price
          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)
202
      for trade_phase in movement_list_trade_phase_dic.keys():
203
        business_link_list = business_process.getPathValueList(trade_phase=\
204
            trade_phase)
205 206 207 208 209
        # XXX-Aurel
        # must convert amount into simulation movement
        # by calling method BusinessProcess.getTradePhaseMovementList
        # for now delivery builder will fail because it calls setDeliveryValue
        # which does not exists on amount
210
        for business_link in business_link_list:
211
          builder_list = [portal.restrictedTraverse(url) for url in\
212
                          business_link.getDeliveryBuilderList()]
213 214 215
          for builder in builder_list:
            builder.build(delivery_relative_url_list=[self.getRelativeUrl(),],
                      movement_list = movement_list_trade_phase_dic[trade_phase])