BaobabConduit.py 28.6 KB
Newer Older
Kevin Deldycke's avatar
Kevin Deldycke committed
1 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
#                    Kevin Deldycke <kevin@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.
#
##############################################################################

from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5Type.Utils import convertToUpperCase
from Products.CMFCore.utils import getToolByName
from Acquisition import aq_base, aq_inner, aq_chain, aq_acquire

import datetime

from zLOG import LOG



class BaobabConduit(ERP5Conduit):

  global property_map

  # Declarative security
  security = ClassSecurityInfo()


50
  ### This data structure associate a xml property to an ERP5 object property in certain conditions
Kevin Deldycke's avatar
Kevin Deldycke committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  property_map = \
    [ { 'xml_property' : 'nom'
      , 'erp5_property': 'first_name'
      , 'conditions'   : {'erp5_portal_type':'Person'}
      }
    , { 'xml_property' : 'nom'
      , 'erp5_property': 'title'
      , 'conditions'   : {'erp5_portal_type':'Organisation'}
      }
    , { 'xml_property' : 'adresse'
      , 'erp5_property': 'default_address_street_address'
      , 'conditions'   : [{'erp5_portal_type':'Organisation'}
                         ,{'erp5_portal_type':'Person'}]
      }
    , { 'xml_property' : 'zone_residence'
      , 'erp5_property': 'default_address_region'
      , 'conditions'   : [{'erp5_portal_type':'Organisation'}
                         ,{'erp5_portal_type':'Person'}]
      }
    , { 'xml_property' : 'titre'
      , 'erp5_property': 'prefix'
      , 'conditions'   : {'erp5_portal_type':'Person'}
      }
    , { 'xml_property' : 'telephone'
      , 'erp5_property': 'default_telephone_number'
      , 'conditions'   : [{'erp5_portal_type':'Organisation'}
                         ,{'erp5_portal_type':'Person'}]
      }
    , { 'xml_property' : 'telex'
      , 'erp5_property': 'default_fax_number'
      , 'conditions'   : [{'erp5_portal_type':'Organisation'}
                         ,{'erp5_portal_type':'Person'}]
      }
    , { 'xml_property' : 'prenom'
      , 'erp5_property': 'last_name'
      , 'conditions'   : {'erp5_portal_type':'Person'}
      }
    , { 'xml_property' : 'date_naissance'
      , 'erp5_property': 'birthday'
      , 'conditions'   : {'erp5_portal_type':'Person'}
      }
    , { 'xml_property' : 'code_bic'
      , 'erp5_property': 'bic_code'
      , 'conditions'   : {'erp5_portal_type':'Organisation'}
      }
96

Kevin Deldycke's avatar
Kevin Deldycke committed
97 98 99 100
    , { 'xml_property' : 'intitule'
      , 'erp5_property': 'title'
      , 'conditions'   : {'erp5_portal_type':'Bank Account'}
      }
101

Kevin Deldycke's avatar
Kevin Deldycke committed
102 103 104 105 106 107 108 109
    , { 'xml_property' : 'montant_maxi'
      , 'erp5_property': 'operation_upper_limit'
      , 'conditions'   : {'erp5_portal_type':'Agent Privilege'}
      }
    , { 'xml_property' : 'description'
      , 'erp5_property': 'description'
      , 'conditions'   : {'erp5_portal_type':'Agent Privilege'}
      }
110 111 112

    , { 'xml_property' : 'inventory_title'
      , 'erp5_property': 'title'
113
      , 'conditions'   : {'erp5_portal_type':'Cash Inventory Group'}
114
      }
Kevin Deldycke's avatar
Kevin Deldycke committed
115 116 117 118 119 120 121 122 123
    ]

  """
    Methods below are tools to use the property_map.
  """

  security.declarePrivate('buildConditions')
  def buildConditions(self, object):
    """
124
      Build a condition dictionnary
Kevin Deldycke's avatar
Kevin Deldycke committed
125 126 127 128 129 130 131 132
    """
    dict = {}
    dict['erp5_portal_type'] = object.getPortalType()
    return dict

  security.declarePrivate('findPropertyMapItem')
  def findPropertyMapItem(self, xml_property_name, conditions):
    """
133
      Find the property_map item that match conditions
Kevin Deldycke's avatar
Kevin Deldycke committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    """
    for item in property_map:
      if item['xml_property'] == xml_property_name:
        c = item['conditions']
        if type(c) == type([]):
          if conditions in c:
            return item
        else:
          if conditions == c:
            return item
    return None



  security.declareProtected(Permissions.ModifyPortalContent, 'constructContent')
  def constructContent(self, object, object_id, docid, portal_type):
    """
151 152
      This is a redefinition of the original ERP5Conduit.constructContent function to
      create Baobab objects.
Kevin Deldycke's avatar
Kevin Deldycke committed
153
    """
154 155 156 157 158
    erp5_site_path        = object.absolute_url(relative=1)
    person_module         = object.person
    organisation_module   = object.organisation
    cash_inventory_module = object.cash_inventory_module
    currency_cash_module  = object.currency_cash_module
Kevin Deldycke's avatar
Kevin Deldycke committed
159 160 161

    subobject = None

162 163 164
    # Function to search the parent object where the new content must be construct.
    # Given parameter is the special encoded portal type that represent the path to
    #   the wanted destination.
Kevin Deldycke's avatar
Kevin Deldycke committed
165 166 167 168 169 170
    def findObjectFromSpecialPortalType(special_portal_type):
      source_portal_type = special_portal_type.split('_')[0]
      construction_location = '/'.join(special_portal_type.split('_')[1:][::-1])
      parent_object = None
      for search_folder in ('person', 'organisation'):
        path = '/' + search_folder + '/' + construction_location
171
        parent_object_path = erp5_site_path + path
Kevin Deldycke's avatar
Kevin Deldycke committed
172
        try:
173
          parent_object = object.restrictedTraverse(parent_object_path)
Kevin Deldycke's avatar
Kevin Deldycke committed
174
        except:
175 176 177 178
          LOG( 'BaobabConduit:'
             , 100
             , "parent object of '%s' not found in %s" % (source_portal_type, parent_object_path)
             )
Kevin Deldycke's avatar
Kevin Deldycke committed
179
      if parent_object == None:
180 181 182 183
        LOG( 'BaobabConduit:'
           , 100
           , "parent object of '%s' not found !" % (source_portal_type)
           )
Kevin Deldycke's avatar
Kevin Deldycke committed
184
      else:
185 186 187 188
        LOG( 'BaobabConduit:'
           , 0
           , "parent object of '%s' found (%s)" % (source_portal_type, repr(parent_object))
           )
Kevin Deldycke's avatar
Kevin Deldycke committed
189 190
      return parent_object

191
    ### handle client objects
Kevin Deldycke's avatar
Kevin Deldycke committed
192 193
    if portal_type.startswith('Client'):
      if portal_type[-3:] == 'PER':
194 195 196
        subobject = person_module.newContent( portal_type = 'Person'
                                            , id          = object_id
                                            )
Kevin Deldycke's avatar
Kevin Deldycke committed
197 198
        subobject.setCareerRole('client')
      else:
199 200 201
        subobject = organisation_module.newContent( portal_type = 'Organisation'
                                                  , id          = object_id
                                                  )
Kevin Deldycke's avatar
Kevin Deldycke committed
202 203
        subobject.setRole('client')

204
    ### handle bank account objects
Kevin Deldycke's avatar
Kevin Deldycke committed
205 206 207 208
    elif portal_type.startswith('Compte'):
      owner = findObjectFromSpecialPortalType(portal_type)
      if owner == None: return None
      subobject = owner.newContent( portal_type = 'Bank Account'
209 210
                                  , id          = object_id
                                  )
Kevin Deldycke's avatar
Kevin Deldycke committed
211 212 213
      # set the bank account owner as agent with no-limit privileges (only for persons)
      if owner.getPortalType() == 'Person':
        new_agent = subobject.newContent( portal_type = 'Agent'
214 215
                                        , id          = 'owner'
                                        )
Kevin Deldycke's avatar
Kevin Deldycke committed
216 217 218 219 220 221 222 223 224 225 226 227
        new_agent.setAgent(owner.getRelativeUrl())
        privileges = ( 'circularization'
                     , 'cash_out'
                     , 'withdrawal_and_payment'
                     , 'account_document_view'
                     , 'signature'
                     , 'treasury'
                     )
        for privilege in privileges:
          new_priv = new_agent.newContent(portal_type = 'Agent Privilege')
          new_priv.setAgentPrivilege(privilege)

228
    ### handle agent objects
Kevin Deldycke's avatar
Kevin Deldycke committed
229 230 231 232
    elif portal_type.startswith('Mandataire'):
      dest = findObjectFromSpecialPortalType(portal_type)
      if dest == None: return None
      subobject = dest.newContent( portal_type = 'Agent'
233 234
                                 , id          = object_id
                                 )
Kevin Deldycke's avatar
Kevin Deldycke committed
235 236 237
      # try to get the agent in the person module
      person = findObjectFromSpecialPortalType('Person_' + object_id)
      if person == None:
238 239 240
        person = person_module.newContent( portal_type = 'Person'
                                         , id          = object_id + 'a'
                                         )
Kevin Deldycke's avatar
Kevin Deldycke committed
241 242
      subobject.setAgent(person.getRelativeUrl())

243
    ### handle privilege objects
Kevin Deldycke's avatar
Kevin Deldycke committed
244 245 246 247
    elif portal_type.startswith('Pouvoir'):
      dest = findObjectFromSpecialPortalType(portal_type)
      if dest == None: return None
      subobject = dest.newContent( portal_type = 'Agent Privilege'
248 249 250
                                 , id          = object_id
                                 )

251
    ### handle inventory objects
252 253
    elif portal_type == 'Cash Inventory':
      if cash_inventory_module == None: return None
254
      subobject = cash_inventory_module.newContent( portal_type = 'Cash Inventory Group'
255 256 257
                                                  , id          = object_id
                                                  )

258
    ### handle inventory details objects
259
    elif portal_type == 'Cash Inventory Detail':
260
      if currency_cash_module == None: return None
261
      # get currency and vault informations by analizing the id
262
      id_items = object_id.split('_')
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
      if len(id_items) != 5:
        LOG( 'BaobabConduit:'
           , 100
           , "Cash Inventory Detail object has a wrong id (%s) !" % (object_id)
           )
        return None
      cell_id        = id_items[0]
      agency_code    = id_items[1]
      inventory_code = id_items[2]
      vault_code     = id_items[3]
      currency_id    = id_items[4]
      # get the path to the vault_code
      vault_path = self.getVaultPathFromCodification( object         = object
                                                    , agency_code    = agency_code
                                                    , inventory_code = inventory_code
                                                    , vault_code     = vault_code
                                                    )
      if vault_path in (None, ''):
        LOG( 'BaobabConduit:'
           , 100
           , "can't find a path to the vault '%s/%s/%s' !" % (agency_code, inventory_code, vault_code)
           )
285
        return None
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
      # try to find an existing inventory with the same price currency and vault
      inventory_list = object.contentValues(filter={'portal_type': 'Cash Inventory'})
      new_inventory = None
      for inventory in inventory_list:
        inventory_currency = inventory.getPriceCurrencyId()
        inventory_vault    = inventory.getDestination()
        if inventory_currency not in (None, '') and \
           inventory_vault    not in (None, '') and \
           inventory_currency == currency_id    and \
           inventory_vault    == vault_path     :
          new_inventory = inventory
          LOG( 'BaobabConduit:'
             , 0
             , "previous Cash Inventory found (%s) !" % (repr(new_inventory))
             )
          break
      # no previous inventory found, create one
      if new_inventory == None:
        new_inventory = object.newContent(portal_type = 'Cash Inventory')
        new_inventory.setPriceCurrency('currency/' + currency_id)
        new_inventory.setDestination(vault_path)
      subobject = new_inventory

    return subobject


312

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
  security.declareProtected(Permissions.ModifyPortalContent, 'editDocument')
  def editDocument(self, object=None, **kw):
    """
      This function transfer datas from the dictionary to the baobab document
      object given in parameters.
    """

    if object == None: return

    """
      Write here the code that require to combine more than one property from
      the **kw dictionnary in order to put the right value in object attributes.
    """

    ### Cash Inventory objects needs two properties to generate the vault path
    if object.getPortalType() == 'Cash Inventory Group':
      vault_path = self.getVaultPathFromCodification( object         = object
                                                    , agency_code    = kw['agency_code']
                                                    , inventory_code = kw['inventory_code']
                                                    )
      LOG('KevLogggg>>>>',0,repr(object))
      object.setDestination(vault_path)

    ### Cash Inventory Detail objects needs all properties to create and update the cell matrix
    if object.getPortalType() == 'Cash Inventory':
      quantity      = None
      cell_id       = None
      resource_type = None
      base_price    = None
      currency_name = None
      for k,v in kw.items():
        if k == 'quantity'     : quantity      = float(v)
        if k == 'cell_id'      : cell_id       = v
        if k == 'currency_type': resource_type = v
        if k == 'price'        : base_price    = float(v)
        if k == 'currency'     : currency_name = v
      # try to find an existing line with the same resource as the current cell
350 351 352 353 354
      if resource_type in ['BIL']:
        currency_portal_type = 'Banknote'
      elif resource_type in ['MON']:
        currency_portal_type = 'Coin'
      else:
355 356 357 358
        LOG( 'BaobabConduit:'
           , 100
           , "Cash Inventory Detail resource type can't be guess (%s) !" % (resource_type)
           )
359 360 361 362 363
        return None
      # get the list of existing currency to find the currency of the line
      line_currency_cash = None
      currency_cash_list = currency_cash_module.contentValues(filter={'portal_type': currency_portal_type})
      for currency_cash in currency_cash_list:
364 365 366 367 368 369
        if base_price    not in (None, '')                    and \
           currency_name not in (None, '')                    and \
           currency_cash.getBasePrice()       == base_price   and \
           currency_cash.getPriceCurrencyId() == currency_name:
          line_currency_cash = currency_cash
          break
370 371
      # no currency found
      if line_currency_cash == None:
372 373 374 375
        LOG( 'BaobabConduit:'
           , 100
           , "Currency '%s %s' not found for the Cash Inventory Detail !" % (base_price, currency_name)
           )
376
        return None
377
      # search for lines
378 379 380 381 382 383 384 385
      inventory_lines = object.contentValues(filter={'portal_type': 'Cash Inventory Line'})
      new_line = None
      for line in inventory_lines:
        if line.getResourceValue() == line_currency_cash:
          new_line = line
          break
      # no previous line found, create one
      if new_line == None:
386
        new_line = object.newContent(portal_type = 'Cash Inventory Line')
387 388 389 390 391 392
        new_line.setResourceValue(line_currency_cash)
        new_line.setPrice(line_currency_cash.getBasePrice())
#         new_line.setVariationBaseCategoryList([ 'cash_status'
#                                               , 'emission_letter'
#                                               , 'variation'
#                                               ])
393
      # get matrix variation values
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
      category_list = []
      base_cat_map = { 'variation'  : 'variation'
                     , 'letter_code': 'emission_letter'
                     , 'status_code': 'cash_status'
                     }
      for base_key in base_cat_map.keys():
        if base_key in kw.keys() and kw[base_key] not in ('', None):
          if base_key == 'status_code':
            status_table = { 'TVA' : 'valid'
                           , 'NEE' : 'new_emitted'
                           , 'NEU' : 'new_not_emitted'
                           , 'RTC' : 'retired'
                           , 'ATR' : 'to_sort'
                           , 'MUT' : 'mutilated'
                           , 'EAV' : 'to_ventilate'
                           , 'TRC' : 'to_sort'
                           , 'ARE' : 'to_sort'
                           }
            category = status_table[kw[base_key]]
          else:
            category = kw[base_key]
        else:
          category = 'not_defined'
        category_list.append(base_cat_map[base_key] + '/' + category)
418 419
      # update the matrix with this cell
      self.updateCashInventoryMatrix( line               = new_line
420 421 422 423 424
                                    , cell_category_list = category_list
                                    , quantity           = quantity
                                    , cell_description   = cell_id
                                    )

425 426 427 428 429 430 431 432 433

    """
      Here we use 2 generic way to update object properties :
        1. We try to use the property_map mapping to migrate a value from a property
             to another;
        2. If the latter fail, we try to find a method with a pre-defined name in
             this script to handle the value.
    """

Kevin Deldycke's avatar
Kevin Deldycke committed
434 435 436 437 438 439
    # Set properties of the destination baobab object
    for k,v in kw.items():
      # Try to find a translation rule in the property_map
      cond = self.buildConditions(object)
      map_item = self.findPropertyMapItem(k, cond)

440 441
      ### There is a translation rule, so call the right setProperty() method
      if map_item != None:
Kevin Deldycke's avatar
Kevin Deldycke committed
442
        method_id = "set" + convertToUpperCase(map_item['erp5_property'])
443 444 445 446
        LOG( 'BaobabConduit:'
           , 0
           , "try to call object method %s on %s" % (repr(method_id), repr(object))
           )
Kevin Deldycke's avatar
Kevin Deldycke committed
447 448 449 450 451
        if v not in ('', None):
          if hasattr(object, method_id):
            method = getattr(object, method_id)
            method(v)
          else:
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
            LOG( 'BaobabConduit:'
               , 100
               , 'property map item don\'t match object properties'
               )

      ### No translation rule found, try to find a hard-coded translation method in the conduit
      else:
        method_id = "edit%s%s" % (kw['type'], convertToUpperCase(k))
        LOG( 'BaobabConduit:'
           , 0
           , "try to call conduit method %s on %s" % (repr(method_id), repr(object))
           )
        if v not in ('', None):
          if hasattr(self, method_id):
            method = getattr(self, method_id)
            method(object, v)
          else:
            LOG( 'BaobabConduit:'
               , 100
               , "there is no method to handle <%s>%s</%s> data" % (k,repr(v),k)
               )

Kevin Deldycke's avatar
Kevin Deldycke committed
474 475 476 477



  """
478 479 480 481
    All functions below are defined to set a document's property to a value
    given in parameters.
    The name of those functions are chosen to help the transfert of datas
    from a given XML format to standard Baobab objects.
Kevin Deldycke's avatar
Kevin Deldycke committed
482 483
  """

484 485
  ### Client-related-properties functions

Kevin Deldycke's avatar
Kevin Deldycke committed
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
  def editClientCategorie(self, document, value):
    if document.getPortalType() == 'Organisation':
      id_table = { 'BIF': 'institution/world/bank'
                 , 'PFR': 'institution/world/institution'
                 , 'ICU': 'institution/local/common'
                 , 'BET': 'institution/local/institution'
                 , 'ETF': 'institution/local/bank'
                 , 'BTR': 'treasury/national'
                 , 'ORP': 'treasury/other'
                 , 'ORI': 'organism/international'
                 , 'ORR': 'organism/local'
                 , 'COR': 'intermediaries'
                 , 'DIV': 'depositories/various'
                 , 'DER': 'depositories/savings'
                 , 'DAU': 'depositories/other'
                 }
      document.setActivity('banking_finance/' + id_table[value])
    else:
504
      LOG('BaobabConduit:', 0, 'Person\'s category ignored')
Kevin Deldycke's avatar
Kevin Deldycke committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520

  def editClientNatureEconomique(self, document, value):
    if document.getPortalType() == 'Organisation':
      # build the economical class category path
      c = ''
      path = ''
      for i in value[1:]:
        c += i
        if c == '13':
          path += '/S13'
          if value != 'S13':
            path += '/' + value
          break
        path += '/S' + c
      document.setEconomicalClass(path)
    else:
521 522 523 524
      LOG( 'BaobabConduit inconsistency:'
         , 200
         , 'a non-Organisation client can\'t have an economical class'
         )
Kevin Deldycke's avatar
Kevin Deldycke committed
525 526 527 528 529 530 531 532 533 534

  def editClientSituationMatrimoniale(self, document, value):
    if document.getPortalType() == 'Person':
      id_table = { 'VEU' : 'widowed'
                 , 'DIV' : 'divorced'
                 , 'MAR' : 'married'
                 , 'CEL' : 'never_married'
                 }
      document.setMaritalStatus(id_table[value])
    else:
535 536 537 538
      LOG( 'BaobabConduit inconsistency:'
         , 200
         , 'a non-Person client can\'t have a marital status'
         )
Kevin Deldycke's avatar
Kevin Deldycke committed
539 540 541



542 543
  ### BankAccount-related-properties functions

Kevin Deldycke's avatar
Kevin Deldycke committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
  def editCompteDevise(self, document, value):
    document.setPriceCurrency('currency/' + value)

  def editCompteDateOuverture(self, document, value):
    if document.getStopDate() in ('', None):
      document.setStopDate(str(datetime.datetime.max))
    document.setStartDate(value)

  def editCompteDateFermeture(self, document, value):
    if document.getStartDate() in ('', None):
      document.setStartDate(str(datetime.datetime.min))
    document.setStopDate(value)

  def editCompteNumero(self, document, value):
    document.setBankCode(value[0])
    document.setBranch(value[1:3])
    document.setBankAccountNumber(value)



564 565
  ### Agent-related-properties functions

Kevin Deldycke's avatar
Kevin Deldycke committed
566 567 568 569
  def editMandataireNom(self, document, value):
    old_value = document.getAgentValue().getFirstName()
    new_value = value
    if old_value != new_value:
570 571 572 573
      LOG( 'BaobabConduit:'
         , 200
         , 'old value of agent first name (%s) was replaced by a new one (%s)' % (old_value, new_value)
         )
Kevin Deldycke's avatar
Kevin Deldycke committed
574 575 576 577 578 579
      document.getAgentValue().setFirstName(new_value)

  def editMandatairePrenom(self, document, value):
    old_value = document.getAgentValue().getLastName()
    new_value = value
    if old_value != new_value:
580 581 582 583
      LOG( 'BaobabConduit:'
         , 200
         , 'old value of agent last name (%s) was replaced by a new one (%s)' % (old_value, new_value)
         )
Kevin Deldycke's avatar
Kevin Deldycke committed
584 585 586 587
      document.getAgentValue().setLastName(new_value)

  def editMandataireService(self, document, value):
    assignment = document.getAgentValue().newContent( portal_type = 'Assignment'
588 589
                                                    , id          = 'service'
                                                    )
Kevin Deldycke's avatar
Kevin Deldycke committed
590 591 592 593 594 595 596 597 598 599 600
    assignment.setGroup(value)
    return

  def editMandataireFonction(self, document, value):
    document.getAgentValue().setDefaultCareerGrade(value)
    return

  def editMandataireTelephone(self, document, value):
    old_value = document.getAgentValue().getDefaultTelephoneNumber()
    new_value = value
    if old_value != new_value:
601 602 603 604
      LOG( 'BaobabConduit:'
         , 200
         , "old value of agent's telephone (%s) was replaced by a new one (%s)" % (old_value, new_value)
         )
Kevin Deldycke's avatar
Kevin Deldycke committed
605 606 607 608 609 610 611 612 613
      document.getAgentValue().setDefaultTelephoneNumber(new_value)

  def editMandataireDateCreation(self, document, value):
    if document.getStopDate() in ('', None):
      document.setStopDate(str(datetime.datetime.max))
    document.setStartDate(value)



614 615
  ### AgentPrivilege-related-properties functions

Kevin Deldycke's avatar
Kevin Deldycke committed
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
  def editPouvoirCategorie(self, document, value):
    id_table = { 'COM' : 'clearing'
               , 'CIR' : 'circularization'
               , 'REM' : 'cash_out'
               , 'RET' : 'withdrawal_and_payment'
               , 'RTE' : 'account_document_view'
               , 'SIG' : 'signature'
               , 'TRE' : 'treasury'
               }
    document.setAgentPrivilege(id_table[value])

  def editPouvoirDateDebut(self, document, value):
    if document.getStopDate() in ('', None):
      document.setStopDate(str(datetime.datetime.max))
    document.setStartDate(value)

  def editPouvoirDateFin(self, document, value):
    if document.getStartDate() in ('', None):
      document.setStartDate(str(datetime.datetime.min))
635 636 637 638
    document.setStopDate(value)



639 640 641
  ### CashInventory-related-properties functions

  def editCashInventoryGroupInventoryDate(self, document, value):
642 643 644 645 646 647 648 649 650
    if value in ('', None):
      date = str(datetime.datetime.max)
    else:
      # Convert french date to strandard date
      date_items = value.split('/')
      day   = date_items[0]
      month = date_items[1]
      year  = date_items[2]
      date  = '/'.join([year, month, day])
651 652
    document.setStopDate(date)

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
  def getVaultPathFromCodification(self, object, agency_code=None, inventory_code=None, vault_code=None):
    if agency_code in (None, ''):
      return None
    category_tool = object.portal_categories
    # Get the site path to agency
    agency_path = None
    site_base_object = category_tool.resolveCategory('site')
    for site_item in site_base_object.getCategoryChildLogicalPathItemList(base=1)[1:]:
      site_path = site_item[1]
      site_object = category_tool.resolveCategory(site_path)
      if site_object.getPortalType() == 'Category':
        site_code = site_object.getCodification()
        if site_code not in (None, '') and site_code.upper() == agency_code.upper():
          agency_path = site_path
          break
    if inventory_code in (None, ''):
      return agency_path
    # Get the site path corresponding to the inventory type
    inventory_path = None
    agency_site_object = site_object
    for agency_sub_item in agency_site_object.getCategoryChildLogicalPathItemList(base=1)[1:]:
      agency_sub_item_path   = agency_sub_item[1]
      agency_sub_item_object = category_tool.resolveCategory(agency_sub_item_path)
      vault_type_path        = 'vault_type/' + agency_sub_item_object.getVaultType()
      vault_type_object      = category_tool.resolveCategory(vault_type_path)
      vault_type_code        = vault_type_object.getCodification()
      if vault_type_code not in (None, '') and vault_type_code.upper() == inventory_code.upper():
        inventory_path = agency_sub_item_path
        break
    if vault_code in (None, ''):
      return inventory_path
    # Get the site path corresponding to the vault code
    vault_path = None
    vault_site_object = agency_sub_item_object
    for vault_sub_item in vault_site_object.getCategoryChildLogicalPathItemList(base=1)[1:]:
      vault_sub_item_path   = vault_sub_item[1]
      vault_sub_item_object = category_tool.resolveCategory(vault_sub_item_path)
      vault_sub_item_code   = vault_sub_item_object.getCodification()
      if vault_sub_item_code not in (None, '') and vault_sub_item_code.upper() == vault_code.upper():
        vault_path = vault_sub_item_path
        break
    return vault_path



  ### CashInventoryDetail-related-properties functions
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728

  def updateCashInventoryMatrix(self, line, cell_category_list, quantity, cell_description):
    # save line current properties value
    line_category_list = line.getVariationCategoryList()
    # set the new_line_category_list
    new_line_category_list = []
    for category in cell_category_list + line_category_list:
      if category not in new_line_category_list:
        new_line_category_list.append(category)
    # update the line
    line.setVariationCategoryList(new_line_category_list)
    # update the cell range
    base_id = 'movement'
    # cell_category_list must have the same base_category order of cell_range base category, so sort the category list   ->>>>>> must be verified
    base_category_list = [ 'cash_status'
                         , 'emission_letter'
                         , 'variation'
                         ]
    cell_category_list.sort()
    cell_range = []
    new_base_category_list = []
    for base_category in base_category_list:
      base_group = []
      for category in new_line_category_list:
        if category.startswith(base_category + '/') and category not in base_group:
          base_group.append(category)
      if len(base_group) > 0:
        new_base_category_list.append(base_category)
      cell_range.append(base_group)
    line.setVariationBaseCategoryList(new_base_category_list)
729
    line.setCellRange(base_id = base_id, *cell_range)
730 731 732 733 734 735 736 737 738 739 740 741
    # create the cell
    kwd = { 'base_id'    : base_id
          , 'portal_type': 'Cash Inventory Cell'
          }
    new_cell = line.newCell(*cell_category_list, **kwd)
    new_cell.edit( mapped_value_property_list         = ('price', 'inventory')
                 , force_update                       = 1
                 , inventory                          = quantity
                 , membership_criterion_category_list = cell_category_list
                 , category_list                      = cell_category_list
                 , description                        = cell_description
                 )