PROJECT_MOVED -> https://lab.nexedi.com/nexedi/erp5
[erp5.git] / product / ERP5Banking / tests / TestERP5BankingMixin.py
1 #############################################################################
2 #
3 # Copyright (c) 2006-2010 Nexedi SA and Contributors. All Rights Reserved.
4 # Aurelien Calonne <aurel@nexedi.com>
5 #
6 # WARNING: This program as such is intended to be used by professional
7 # programmers who take the whole responsability of assessing all potential
8 # consequences resulting from its eventual inadequacies and bugs
9 # End users who are looking for a ready-to-use solution with commercial
10 # garantees and support are strongly adviced to contract a Free Software
11 # Service Company
12 #
13 # This program is Free Software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; either version 2
16 # of the License, or (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #
27 ##############################################################################
28
29 from DateTime import DateTime
30 from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
31
32 def isSameSet(a, b):
33 for i in a:
34 if i not in b:
35 return False
36 for i in b:
37 if i not in a:
38 return False
39 return len(a) == len(b)
40
41 class TestERP5BankingMixin(ERP5TypeTestCase):
42 """
43 Mixin class for unit test of banking operations
44 """
45
46 def getBusinessTemplateList(self):
47 """
48 Return the list of business templates we need to run the test.
49 This method is called during the initialization of the unit test by
50 the unit test framework in order to know which business templates
51 need to be installed to run the test on.
52 """
53 return ('erp5_core_proxy_field_legacy',
54 'erp5_base',
55 'erp5_pdm',
56 'erp5_trade',
57 'erp5_accounting',
58 'erp5_banking_core',
59 'erp5_banking_inventory',
60 'erp5_banking_cash',
61 'erp5_banking_check',
62 )
63
64 def enableLightInstall(self):
65 """
66 Return if we should do a light install (1) or not (0)
67 Light install variable is used at installation of categories in business template
68 to know if we wrap the category or not, if 1 we don't use and installation is faster
69 """
70 return 1 # here we want a light install for a faster installation
71
72 def enableActivityTool(self):
73 """
74 Return if we should create (1) or not (0) an activity tool
75 This variable is used at the creation of the site to know if we use
76 the activity tool or not
77 """
78 return 1 # here we want to use the activity tool
79
80 def checkUserFolderType(self):
81 """
82 Check the type of user folder to let the test working with both NuxUserGroup and PAS.
83 """
84 self.user_folder = self.getUserFolder()
85 self.PAS_installed = 0
86 if self.user_folder.meta_type == 'Pluggable Auth Service':
87 # we use PAS
88 self.PAS_installed = 1
89
90 def updateRoleMappings(self, portal_type_list=None):
91 """Update the local roles in existing objects.
92 """
93 portal_catalog = self.portal.portal_catalog
94 for portal_type in portal_type_list:
95 for brain in portal_catalog(portal_type = portal_type):
96 obj = brain.getObject()
97 userdb_path, user_id = obj.getOwnerTuple()
98 obj.assignRoleToSecurityGroup(user_name = user_id)
99
100 def assignPASRolesToUser(self, user_name, role_list):
101 """
102 Assign a list of roles to one user with PAS.
103 """
104 for role in role_list:
105 if role not in self.user_folder.zodb_roles.listRoleIds():
106 self.user_folder.zodb_roles.addRole(role)
107 self.user_folder.zodb_roles.assignRoleToPrincipal(role, user_name)
108
109 def createManagerAndLogin(self):
110 """
111 Create a simple user in user_folder with manager rights.
112 This user will be used to initialize data in the method afterSetup
113 """
114 self.getUserFolder()._doAddUser('manager', '', ['Manager'], [])
115 self.login('manager')
116
117 def createERP5Users(self, user_dict):
118 """
119 Create all ERP5 users needed for the test.
120 ERP5 user = Person object + Assignment object in erp5 person_module.
121 """
122 for user_login, user_data in user_dict.items():
123 user_roles = user_data[0]
124 # Create the Person.
125 main_site = '/'.join(user_data[4].split('/')[0:2])
126 person = self.person_module.newContent(id=user_login,
127 portal_type='Person', reference=user_login, career_role="internal",
128 site=main_site)
129 # Create the Assignment.
130 assignment = person.newContent( portal_type = 'Assignment'
131 , destination_value = user_data[1]
132 , function = "function/%s" %user_data[2]
133 , group = "group/%s" %user_data[3]
134 , site = "%s" %user_data[4]
135 , start_date = '01/01/1900'
136 , stop_date = '01/01/2900'
137 )
138 if self.PAS_installed and len(user_roles) > 0:
139 # In the case of PAS, if we want global roles on user, we have to do it manually.
140 self.assignPASRolesToUser(user_login, user_roles)
141 elif not self.PAS_installed:
142 # The user_folder counterpart of the erp5 user must be
143 # created manually in the case of NuxUserGroup.
144 self.user_folder.userFolderAddUser( name = user_login
145 , password = ''
146 , roles = user_roles
147 , domains = []
148 )
149 # User assignment to security groups is also required, but is taken care of
150 # by the assignment workflow when NuxUserGroup is used and
151 # by ERP5Security PAS plugins in the context of PAS use.
152 assignment.open()
153
154 if self.PAS_installed:
155 # reindexing is required for the security to work
156 self.tic()
157
158
159
160 def getUserFolder(self):
161 return self.getPortal().acl_users
162
163 def getPersonModule(self):
164 return self.getPortal().person_module
165
166 def getOrganisationModule(self):
167 return self.getPortal().organisation_module
168
169 def getCurrencyCashModule(self):
170 return self.getPortal().currency_cash_module
171
172 def getCashInventoryModule(self):
173 return self.getPortal().cash_inventory_module
174
175 def getBankAccountInventoryModule(self):
176 return self.getPortal().bank_account_inventory_module
177
178 def getCurrencyModule(self):
179 return self.getPortal().currency_module
180
181 def getCategoryTool(self):
182 return self.getPortal().portal_categories
183
184 def getWorkflowTool(self):
185 return self.getPortal().portal_workflow
186
187 def getSimulationTool(self):
188 return self.getPortal().portal_simulation
189
190 def getCheckPaymentModule(self):
191 return self.getPortal().check_payment_module
192
193 def getStopPaymentModule(self):
194 return self.getPortal().stop_payment_module
195
196 def getCheckDepositModule(self):
197 return self.getPortal().check_deposit_module
198
199 def getCheckbookModule(self):
200 return self.getPortal().checkbook_module
201
202 def getCheckbookModelModule(self):
203 return self.getPortal().checkbook_model_module
204
205 def getCheckbookReceptionModule(self):
206 return self.getPortal().checkbook_reception_module
207
208 def getCheckbookVaultTransferModule(self):
209 return self.getPortal().checkbook_vault_transfer_module
210
211 def getCheckbookUsualCashTransferModule(self):
212 return self.getPortal().checkbook_usual_cash_transfer_module
213
214 def getCheckbookDeliveryModule(self):
215 return self.getPortal().checkbook_delivery_module
216
217 def getCheckModule(self):
218 return self.getPortal().check_module
219
220 def getAccountingDateModule(self):
221 return self.getPortal().accounting_date_module
222
223 def getCounterDateModule(self):
224 return self.getPortal().counter_date_module
225
226 def getCounterModule(self):
227 return self.getPortal().counter_module
228
229 def getCashMovementModule(self):
230 return self.getPortal().cash_movement_module
231
232 def getCashMovementNewNotEmittedModule(self):
233 return self.getPortal().cash_movement_new_not_emitted_module
234
235 def getMonetaryReceptionModule(self):
236 return self.getPortal().monetary_reception_module
237
238 def getMonetaryIssueModule(self):
239 return self.getPortal().monetary_issue_module
240
241 def getAccountingCancellationModule(self):
242 return self.getPortal().accounting_cancellation_module
243
244 def getCashBalanceRegulationModule(self):
245 return self.getPortal().cash_balance_regulation_module
246
247 def getCashSortingModule(self):
248 return self.getPortal().cash_sorting_module
249
250 def getCashExchangeModule(self):
251 return self.getPortal().cash_exchange_module
252
253 def getCashToCurrencyPurchaseModule(self):
254 return self.getPortal().cash_to_currency_purchase_module
255
256 def getClassificationSurveyModule(self):
257 return self.getPortal().classification_survey_module
258
259 def getCounterRenderingModule(self):
260 return self.getPortal().counter_rendering_module
261
262 def getDestructionSurveyModule(self):
263 return self.getPortal().destruction_survey_module
264
265 def getForeignCashReceptionModule(self):
266 return self.getPortal().foreign_cash_reception_module
267
268 def getInternalMoneyDepositModule(self):
269 return self.getPortal().internal_money_deposit_module
270
271 def getInternalMoneyPaymentModule(self):
272 return self.getPortal().internal_money_payment_module
273
274 def getMonetaryDestructionModule(self):
275 return self.getPortal().monetary_destruction_module
276
277 def getMonetaryRecallModule(self):
278 return self.getPortal().monetary_recall_module
279
280 def getMonetarySurveyModule(self):
281 return self.getPortal().monetary_survey_module
282
283 def getMoneyDepositModule(self):
284 return self.getPortal().money_deposit_module
285
286 def getMoneyDepositRenderingModule(self):
287 return self.getPortal().money_deposit_rendering_module
288
289 def getMutilatedBanknoteModule(self):
290 return self.getPortal().mutilated_banknote_module
291
292 def getTravelerCheckPurchaseModule(self):
293 return self.getPortal().traveler_check_purchase_module
294
295 def getTravelerCheckSaleModule(self):
296 return self.getPortal().traveler_check_sale_module
297
298 def getUsualCashRenderingModule(self):
299 return self.getPortal().usual_cash_rendering_module
300
301 def getUsualCashTransferModule(self):
302 return self.getPortal().usual_cash_transfer_module
303
304 def getVaultTransferModule(self):
305 return self.getPortal().vault_transfer_module
306
307 def createCurrency(self, currency_list=(('EUR', 'Euro', 1/652., 1/650., 'USD'), ('USD', 'USD', 652, 650., 'EUR')), only_currency=False):
308 # create the currency document for euro inside the currency module
309 #currency_list = (('EUR', 'Euro', 1/650., 'USD'), ('USD', 'Dollar', 650., 'EUR'))
310 # first create currency
311 for currency_id, title, base_price, cell_price, price_currency in currency_list:
312 self._maybeNewContent(self.getCurrencyModule(), id=currency_id,
313 title=title, reference=currency_id)
314
315 if only_currency:
316 return
317
318 # second, create exchange lines
319 for currency_id, title, base_price, cell_price, price_currency in currency_list:
320 currency = self.getCurrencyModule()[currency_id]
321 exchange_line = None
322 exchange_line = currency.newContent(portal_type='Currency Exchange Line',
323 start_date='01/01/1900', stop_date='01/01/2900',
324 base_price=base_price,
325 currency_exchange_type_list=['currency_exchange_type/sale',
326 'currency_exchange_type/purchase',
327 'currency_exchange_type/transfer'],
328 )
329 exchange_line.setPriceCurrencyValue(self.getCurrencyModule()[price_currency])
330 cell_list = exchange_line.objectValues()
331 self.assertEqual(len(cell_list), 3)
332 for cell in cell_list:
333 cell.setBasePrice(cell_price)
334
335 exchange_line.confirm()
336 exchange_line.validate()
337
338
339
340 def _createBanknotesAndCoins(self):
341 """
342 Create some banknotes and coins
343 """
344 # Define static values (only use prime numbers to prevent confusions like 2 * 6 == 3 * 4)
345 # variation list is the list of years for banknotes and coins
346 self.variation_list = ('variation/1992', 'variation/2003')
347 self.usd_variation_list = ('variation/not_defined', )
348 # quantity of banknotes of 10000 :
349 self.quantity_10000 = {}
350 # 2 banknotes of 10000 for the year 1992
351 self.quantity_10000[self.variation_list[0]] = 2
352 # 3 banknotes of 10000 for the year of 2003
353 self.quantity_10000[self.variation_list[1]] = 3
354
355 # quantity of coin of 200
356 self.quantity_200 = {}
357 # 5 coins of 200 for the year 1992
358 self.quantity_200[self.variation_list[0]] = 5
359 # 7 coins of 200 for the year 2003
360 self.quantity_200[self.variation_list[1]] = 7
361
362 # quantity of coin of 100
363 self.quantity_100 = {}
364 # 5 coins of 100 for the year 1992
365 self.quantity_100[self.variation_list[0]] = 4
366 # 7 coins of 100 for the year 2003
367 self.quantity_100[self.variation_list[1]] = 6
368
369 # quantity of banknotes of 5000
370 self.quantity_5000 = {}
371 # 11 banknotes of 5000 for hte year 1992
372 self.quantity_5000[self.variation_list[0]] = 11
373 # 13 banknotes of 5000 for the year 2003
374 self.quantity_5000[self.variation_list[1]] = 13
375
376 # quantity of usd banknote of 200
377 self.quantity_usd_200 = {}
378 # 2 banknotes of 200
379 self.quantity_usd_200['variation/not_defined'] = 2
380 # quantity of usd banknote of 100
381 self.quantity_usd_100 = {}
382 # 2 banknotes of 100
383 self.quantity_usd_100['variation/not_defined'] = 2
384 # quantity of usd banknote of 50
385 self.quantity_usd_50 = {}
386 # 3 banknotes of 50
387 self.quantity_usd_50['variation/not_defined'] = 3
388 # quantity of usd banknote of 20
389 self.quantity_usd_20 = {}
390 # 5 banknotes of 20
391 self.quantity_usd_20['variation/not_defined'] = 5
392
393 # Now create required category for banknotes and coin
394 self.cash_status_base_category = getattr(self.category_tool, 'cash_status')
395 # add the category valid in cash_status which define status of banknotes and coin
396 self.cash_status_valid = self._maybeNewContent(self.cash_status_base_category, id='valid', portal_type='Category')
397 self.cash_status_to_sort = self._maybeNewContent(self.cash_status_base_category, id='to_sort', portal_type='Category')
398 self.cash_status_cancelled = self._maybeNewContent(self.cash_status_base_category, id='cancelled', portal_type='Category')
399 self.cash_status_not_defined = self._maybeNewContent(self.cash_status_base_category, id='not_defined', portal_type='Category')
400 self.cash_status_mutilated = self._maybeNewContent(self.cash_status_base_category, id='mutilated', portal_type='Category')
401 self.cash_status_retired = self._maybeNewContent(self.cash_status_base_category, id='retired', portal_type='Category')
402 self.cash_status_new_not_emitted = self._maybeNewContent(self.cash_status_base_category, id='new_not_emitted', portal_type='Category')
403 self.cash_status_mixed = self._maybeNewContent(self.cash_status_base_category, id='mixed', portal_type='Category')
404
405 self.emission_letter_base_category = getattr(self.category_tool, 'emission_letter')
406 # add the category k in emission letter that will be used fo banknotes and coins
407 self.emission_letter_p = self._maybeNewContent(self.emission_letter_base_category, id='p', portal_type='Category')
408 self.emission_letter_s = self._maybeNewContent(self.emission_letter_base_category, id='s', portal_type='Category')
409 self.emission_letter_b = self._maybeNewContent(self.emission_letter_base_category, id='b', portal_type='Category')
410 self.emission_letter_k = self._maybeNewContent(self.emission_letter_base_category, id='k', portal_type='Category')
411 self.emission_letter_mixed = self._maybeNewContent(self.emission_letter_base_category, id='mixed', portal_type='Category')
412 self.emission_letter_not_defined = self._maybeNewContent(self.emission_letter_base_category, id='not_defined', portal_type='Category')
413
414 self.variation_base_category = getattr(self.category_tool, 'variation')
415 # add the category 1992 in variation
416 self.variation_1992 = self._maybeNewContent(self.variation_base_category, id='1992', portal_type='Category')
417 # add the category 2003 in variation
418 self.variation_2003 = self._maybeNewContent(self.variation_base_category, id='2003', portal_type='Category')
419 # add the category not_defined in variation
420 self.variation_not_defined = self._maybeNewContent(self.variation_base_category, id='not_defined',
421 portal_type='Category')
422
423 # Now create required category for region and coin
424 self.region_base_category = getattr(self.category_tool, 'region')
425 # add the category valid in cash_status which define status of banknotes and coin
426 self.region_france = self._maybeNewContent(self.region_base_category, id='france', title="France", portal_type='Category')
427 self.region_spain = self._maybeNewContent(self.region_base_category, id='spain', title="Spain", portal_type='Category')
428
429 # Create Resources Document (Banknotes & Coins)
430 # get the currency cash module
431 self.currency_cash_module = self.getCurrencyCashModule()
432 # Create Resources Document (Banknotes & Coins)
433 self.createCurrency()
434 self.currency_1 = self.currency_module['EUR']
435 # create document for banknote of 10000 euros from years 1992 and 2003
436 self.billet_10000 = self.currency_cash_module.newContent(id='billet_10000',
437 portal_type='Banknote', base_price=10000,
438 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
439 quantity_unit_value=self.unit)
440 # create document for banknote of 500 euros from years 1992 and 2003
441 self.billet_5000 = self.currency_cash_module.newContent(id='billet_5000',
442 portal_type='Banknote', base_price=5000,
443 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
444 quantity_unit_value=self.unit)
445 # create document for coin of 200 euros from years 1992 and 2003
446 self.piece_200 = self.currency_cash_module.newContent(id='piece_200',
447 portal_type='Coin', base_price=200,
448 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
449 quantity_unit_value=self.unit)
450 # create document for coin of 200 euros from years 1992 and 2003
451 self.piece_100 = self.currency_cash_module.newContent(id='piece_100',
452 portal_type='Coin', base_price=100,
453 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
454 quantity_unit_value=self.unit)
455 # create document for banknote of 200 euros from years 1992 and 2003
456 self.billet_200 = self.currency_cash_module.newContent(id='billet_200',
457 portal_type='Banknote', base_price=200,
458 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
459 quantity_unit_value=self.unit)
460 # create document for banknote of 200 euros from years 1992 and 2003
461 self.billet_100 = self.currency_cash_module.newContent(id='billet_100',
462 portal_type='Banknote', base_price=100,
463 price_currency_value=self.currency_1, variation_list=('1992', '2003'),
464 quantity_unit_value=self.unit)
465 # Create Resources Document (Banknotes & Coins) in USD
466 self.currency_2 = self.currency_module['USD']
467 # create document for banknote of 100 USD
468 self.usd_billet_100 = self.currency_cash_module.newContent(id='usd_billet_100',
469 portal_type='Banknote', base_price=100,
470 price_currency_value=self.currency_2, variation_list=('not_defined', ),
471 quantity_unit_value=self.unit)
472 # create document for banknote of 200 USD
473 self.usd_billet_200 = self.currency_cash_module.newContent(id='usd_billet_200',
474 portal_type='Banknote', base_price=200,
475 price_currency_value=self.currency_2, variation_list=('not_defined', ),
476 quantity_unit_value=self.unit)
477 # create document for banknote of 50 USD
478 self.usd_billet_50 = self.currency_cash_module.newContent(id='usd_billet_50',
479 portal_type='Banknote', base_price=50,
480 price_currency_value=self.currency_2, variation_list=('not_defined', ),
481 quantity_unit_value=self.unit)
482 # create document for banknote of 20 USD
483 self.usd_billet_20 = self.currency_cash_module.newContent(id='usd_billet_20',
484 portal_type='Banknote', base_price=20,
485 price_currency_value=self.currency_2, variation_list=('not_defined', ),
486 quantity_unit_value=self.unit)
487
488 def _maybeNewContent(self, container, id, **kw):
489 try:
490 result = container[id]
491 except KeyError:
492 result = container.newContent(id=id, **kw)
493 return result
494
495 def createFunctionGroupSiteCategory(self, no_site=0, site_list=None):
496 """
497 Create site group function category that can be used for security
498 """
499 if site_list is None:
500 site_list = ["paris", 'madrid', 'siege']
501
502 # add category unit in quantity_unit which is the unit that will be used for banknotes and coins
503 self.variation_base_category = getattr(self.category_tool, 'quantity_unit')
504 self.unit = self._maybeNewContent(self.variation_base_category, id='unit', title='Unit')
505
506 self._maybeNewContent(self.category_tool.role, id='internal', portal_type='Category')
507
508 # add category for currency_exchange_type
509 self.currency_exchange_type = getattr(self.category_tool, 'currency_exchange_type')
510 self._maybeNewContent(self.currency_exchange_type, id='sale')
511 self._maybeNewContent(self.currency_exchange_type, id='purchase')
512 self._maybeNewContent(self.currency_exchange_type, id='transfer')
513
514 # get the base category function
515 self.function_base_category = getattr(self.category_tool, 'function')
516 # add category banking in function which will hold all functions neccessary in a bank (at least for this unit test)
517 self.banking = self._maybeNewContent(self.function_base_category, id='banking', portal_type='Category', codification='BNK')
518 self.caissier_principal = self._maybeNewContent(self.banking, id='caissier_principal', portal_type='Category', codification='CCP')
519 self.controleur_caisse = self._maybeNewContent(self.banking, id='controleur_caisse', portal_type='Category', codification='CCT')
520 self.void_function = self._maybeNewContent(self.banking, id='void_function', portal_type='Category', codification='VOID')
521 self.gestionnaire_caisse_courante = self._maybeNewContent(self.banking, id='gestionnaire_caisse_courante', portal_type='Category', codification='CCO')
522 self.gestionnaire_caveau = self._maybeNewContent(self.banking, id='gestionnaire_caveau', portal_type='Category', codification='CCV')
523 self.caissier_particulier = self._maybeNewContent(self.banking, id='caissier_particulier', portal_type='Category', codification='CGU')
524 self.controleur_caisse_courante = self._maybeNewContent(self.banking, id='controleur_caisse_courante', portal_type='Category', codification='CCC')
525 self.controleur_caveau = self._maybeNewContent(self.banking, id='controleur_caveau', portal_type='Category', codification='CCA')
526 self.comptable = self._maybeNewContent(self.banking, id='comptable', portal_type='Category', codification='FXF')
527 self.commis_comptable = self._maybeNewContent(self.banking, id='commis_comptable', portal_type='Category', codification='CBM')
528 self.commis_caisse = self._maybeNewContent(self.banking, id='commis_caisse', portal_type='Category', codification='CCM')
529 self.chef_section_comptable = self._maybeNewContent(self.banking, id='chef_section_comptable', portal_type='Category', codification='CSB')
530 self.chef_comptable = self._maybeNewContent(self.banking, id='chef_comptable', portal_type='Category', codification='CCB')
531 self.chef_de_tri = self._maybeNewContent(self.banking, id='chef_de_tri', portal_type='Category', codification='CTR')
532 self.chef_caisse = self._maybeNewContent(self.banking, id='chef_caisse', portal_type='Category', codification='CCP')
533 self.chef_section = self._maybeNewContent(self.banking, id='chef_section', portal_type='Category', codification='FXS')
534 self.chef_section_financier = self._maybeNewContent(self.banking, id='chef_section_financier', portal_type='Category', codification='FXA')
535 self.financier_a = self._maybeNewContent(self.banking, id='financier_a', portal_type='Category', codification='FNA')
536 self.financier_b = self._maybeNewContent(self.banking, id='financier_b', portal_type='Category', codification='FNB')
537 self.chef_financier = self._maybeNewContent(self.banking, id='chef_financier', portal_type='Category', codification='FCF')
538 self.admin_local = self._maybeNewContent(self.banking, id='administrateur_local', portal_type='Category', codification='ADL')
539 self.agent_saisie_sref = self._maybeNewContent(self.banking, id='agent_saisie_sref', portal_type='Category', codification='SSREF')
540 self.chef_sref = self._maybeNewContent(self.banking, id='chef_sref', portal_type='Category', codification='CSREF')
541 self.analyste_sref = self._maybeNewContent(self.banking, id='analyste_sref', portal_type='Category', codification='ASREF')
542 self.gestionnaire_devise_a = self._maybeNewContent(self.banking, id='gestionnaire_cours_devise_a', portal_type='Category', codification='GCA')
543 self.gestionnaire_devise_b = self._maybeNewContent(self.banking, id='gestionnaire_cours_devise_b', portal_type='Category', codification='GCB')
544 self.comptable_inter_site = self._maybeNewContent(self.banking, id='comptable_inter_site', portal_type='Category', codification='FXFIS')
545
546 # get the base category group
547 self.group_base_category = getattr(self.category_tool, 'group')
548 self.baobab_group = self._maybeNewContent(self.group_base_category, id='baobab', portal_type='Category', codification='BAOBAB')
549 # get the base category site
550 self.site_base_category = getattr(self.category_tool, 'site')
551 # add the category testsite in the category site which hold vaults situated in the bank
552 self.testsite = self._maybeNewContent(self.site_base_category, id='testsite', portal_type='Category', codification='TEST')
553 site_reference_from_codification_dict = {
554 'P10': ('FR', '000', '11111', '000000000000', '25'),
555 'S10': ('SP', '000', '11111', '000000000000', '08'),
556 'HQ1': ('FR', '000', '11112', '000000000000', '69'),
557 }
558 site_region_from_codification_dict = {
559 'P10': 'france', # paris
560 'S10': 'spain', # madrid
561 'HQ1': 'france', # main
562 }
563 self.paris = self._maybeNewContent(self.testsite, id='paris', portal_type='Category', codification='P10', vault_type='site')
564 self.madrid = self._maybeNewContent(self.testsite, id='madrid', portal_type='Category', codification='S10', vault_type='site')
565 self.siege = self._maybeNewContent(self.site_base_category, id='siege', portal_type='Category', codification='HQ1', vault_type='site')
566 created_site_list = [self.paris, self.madrid, self.siege]
567
568 self._createBanknotesAndCoins()
569
570 if len(site_list) != 0:
571 for site in site_list:
572 if isinstance(site, tuple):
573 container = self.site_base_category
574 if len(site) > 2:
575 for category_id in site[2].split('/'):
576 contained = getattr(container, category_id, None)
577 if contained is None:
578 contained = self._maybeNewContent(container, id=category_id, portal_type='Category')
579 container = contained
580 if len(site) > 3:
581 site_reference_from_codification_dict[site[1]] = site[3]
582 if len(site) > 4:
583 site_region_from_codification_dict[site[1]] = site[4]
584 codification = site[1]
585 site = site[0]
586 if site not in ("paris", 'madrid', 'siege'):
587 site = self._maybeNewContent(container, id=site, portal_type='Category', codification=codification, vault_type='site')
588 created_site_list.append(site)
589
590 # Create organisation + bank account for each site category.
591 organisation_module = self.organisation_module
592 newContent = organisation_module.newContent
593 for site in created_site_list:
594 codification = site.getCodification()
595 organisation_id = 'site_%s' % (codification, )
596 try:
597 organisation_module[organisation_id]
598 except KeyError:
599 organisation = newContent(
600 portal_type='Organisation',
601 id=organisation_id,
602 site=site.getRelativeUrl(),
603 region=site_region_from_codification_dict.get(codification),
604 group='baobab',
605 role='internal',
606 function='banking')
607 site_reference = site_reference_from_codification_dict.get(codification)
608 if site_reference is not None:
609 self.createBankAccount(
610 person=organisation,
611 account_id='account_%s' % (codification, ),
612 currency=self.currency_1,
613 amount=0,
614 bank_country_code=site_reference[0],
615 bank_code=site_reference[1],
616 branch=site_reference[2],
617 bank_account_number=site_reference[3],
618 bank_account_key=site_reference[4],
619 )
620
621 self.vault_type_base_category = getattr(self.category_tool, 'vault_type')
622 site_vault_type = self._maybeNewContent(self.vault_type_base_category, id='site')
623 surface_vault_type = self._maybeNewContent(site_vault_type, 'surface')
624 bi_vault_type = self._maybeNewContent(surface_vault_type, 'banque_interne')
625 co_vault_type = self._maybeNewContent(surface_vault_type, 'caisse_courante')
626 de_co_vault_type = self._maybeNewContent(co_vault_type, 'encaisse_des_devises')
627 guichet_bi_vault_type = self._maybeNewContent(bi_vault_type, 'guichet')
628 gp_vault_type = self._maybeNewContent(surface_vault_type, 'gros_paiement')
629 guichet_gp_vault_type = self._maybeNewContent(gp_vault_type, 'guichet')
630 gv_vault_type = self._maybeNewContent(surface_vault_type, 'gros_versement')
631 guichet_gv_vault_type = self._maybeNewContent(gv_vault_type, 'guichet')
632 op_vault_type = self._maybeNewContent(surface_vault_type, 'operations_diverses')
633 guichet_op_vault_type = self._maybeNewContent(op_vault_type, 'guichet')
634 caveau_vault_type = self._maybeNewContent(site_vault_type, 'caveau')
635 auxiliaire_vault_type = self._maybeNewContent(caveau_vault_type, 'auxiliaire')
636 self._maybeNewContent(auxiliaire_vault_type, 'auxiliaire_vault_type')
637 self._maybeNewContent(auxiliaire_vault_type, 'encaisse_des_devises')
638 externe = self._maybeNewContent(auxiliaire_vault_type, 'encaisse_des_externes')
639 self._maybeNewContent(externe, 'transit')
640 self._maybeNewContent(caveau_vault_type, 'reserve')
641 serre = self._maybeNewContent(caveau_vault_type, 'serre')
642 self._maybeNewContent(serre, 'transit')
643 self._maybeNewContent(serre, 'retire')
644 salle_tri = self._maybeNewContent(surface_vault_type, 'salle_tri')
645
646 if not no_site:
647 destination_site_list = [x.getId() for x in created_site_list]
648 for c in created_site_list: #self.testsite.getCategoryChildValueList():
649 # create bank structure for each agency
650 site = c.getId()
651 # surface
652 surface = self._maybeNewContent(c, id='surface', portal_type='Category', codification='', vault_type='site/surface')
653 caisse_courante = self._maybeNewContent(surface, id='caisse_courante', portal_type='Category', codification='', vault_type='site/surface/caisse_courante')
654 self._maybeNewContent(caisse_courante, id='encaisse_des_billets_et_monnaies', portal_type='Category', codification='', vault_type='site/surface/caisse_courante')
655 self._maybeNewContent(caisse_courante, id='billets_mutiles', portal_type='Category', codification='', vault_type='site/surface/caisse_courante')
656 self._maybeNewContent(caisse_courante, id='billets_macules', portal_type='Category', codification='', vault_type='site/surface/caisse_courante')
657 encaisse_des_devises = self._maybeNewContent(caisse_courante, id='encaisse_des_devises', portal_type='Category', codification='', vault_type='site/surface/caisse_courante/encaisse_des_devises')
658 # create counter for surface
659 for s in ['banque_interne', 'gros_versement', 'gros_paiement']:
660 vault_codification = c.getCodification()
661 if s == 'banque_interne':
662 vault_codification += 'BI'
663 elif s == 'gros_versement':
664 vault_codification += 'GV'
665 elif s == 'gros_paiement':
666 vault_codification += 'GP'
667 s = self._maybeNewContent(surface, id='%s' % (s, ), portal_type='Category', codification=vault_codification, vault_type='site/surface/%s' % (s, ))
668 for ss in ['guichet_1', 'guichet_2']:
669 final_vault_codification = vault_codification + ss[-1]
670 ss = self._maybeNewContent(s, id='%s' % (ss, ), portal_type='Category', codification=final_vault_codification, vault_type='site/surface/%s/guichet' % (s.getId(), ))
671 for sss in ['encaisse_des_billets_et_monnaies']:
672 sss = self._maybeNewContent(ss, id='%s' % (sss, ), portal_type='Category', codification='', vault_type='site/surface/%s/guichet' % (s.getId(), ))
673 for ssss in ['entrante', 'sortante']:
674 self._maybeNewContent(sss, id='%s' % (ssss, ), portal_type='Category', codification='', vault_type='site/surface/%s/guichet' % (s.getId(), ))
675 for sss in ['encaisse_des_devises']:
676 sss = self._maybeNewContent(ss, id='%s' % (sss, ), portal_type='Category', codification='', vault_type='site/surface/%s/guichet' % (s.getId(), ))
677 for currency in ['usd']:
678 currency_cat = self._maybeNewContent(sss, id='%s' % (currency, ), portal_type='Category', codification='', vault_type='site/surface/%s' % (ss.getId(), ))
679 for ssss in ['entrante', 'sortante']:
680 self._maybeNewContent(currency_cat, id='%s' % (ssss, ), portal_type='Category', codification='', vault_type='site/surface/%s/guichet' % (s.getId(), ))
681 # create sort room
682 salle_tri = self._maybeNewContent(surface, id='salle_tri', portal_type='Category', codification='', vault_type='site/surface/salle_tri')
683 for ss in ['encaisse_des_billets_et_monnaies', 'encaisse_des_billets_recus_pour_ventilation', 'encaisse_des_differences', 'encaisse_des_externes']:
684 ss = self._maybeNewContent(salle_tri, id='%s' % (ss, ), portal_type='Category', codification='', vault_type='site/surface/salle_tri')
685 if 'ventilation' in ss.getId():
686 for country in destination_site_list:
687 if country[0] != c.getCodification()[0]:
688 self._maybeNewContent(ss, id='%s' % (country, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
689 # caveau
690 caveau = self._maybeNewContent(c, id='caveau', portal_type='Category', codification='', vault_type='site/caveau')
691 for s in ['auxiliaire', 'reserve', 'serre']:
692 s = self._maybeNewContent(caveau, id='%s' % (s, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s, ))
693 if s.getId() == 'serre':
694 for ss in ['encaisse_des_billets_neufs_non_emis', 'encaisse_des_billets_retires_de_la_circulation', 'encaisse_des_billets_detruits', 'encaisse_des_billets_neufs_non_emis_en_transit_allant_a']:
695 ss = self._maybeNewContent(s, id='%s' % (ss, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
696 if 'transit' in ss.getId():
697 for country in destination_site_list:
698 if country[0] != c.getCodification()[0]:
699 self._maybeNewContent(ss, id='%s' % (country, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
700
701 else:
702 for ss in ['encaisse_des_billets_et_monnaies', 'encaisse_des_externes',
703 'encaisse_des_billets_recus_pour_ventilation', 'encaisse_des_devises']:
704 ss = self._maybeNewContent(s, id='%s' % (ss, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
705 if 'ventilation' in ss.getId():
706 for country in destination_site_list:
707 if country[0] != c.getCodification()[0]:
708 self._maybeNewContent(ss, id='%s' % (country, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
709 if 'devises' in ss.getId():
710 for currency in ['eur', 'usd']:
711 self._maybeNewContent(ss, id='%s' % (currency, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (ss.getId(), ))
712 if 'encaisse_des_externes' in ss.getId():
713 self._maybeNewContent(ss, id='transit', portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
714 #if ss.getId()=='encaisse_des_devises':
715 # for
716 if s.getId() == 'auxiliaire':
717 for ss in ['encaisse_des_billets_a_ventiler_et_a_detruire', 'encaisse_des_billets_ventiles_et_detruits', 'billets_detenus_par_des_tiers', 'encaisse_des_billets_recus_pour_ventilation_venant_de']:
718 self._maybeNewContent(s, id='%s' % (ss, ), portal_type='Category', codification='', vault_type='site/caveau/%s' % (s.getId(), ))
719 # Create forreing currency entries in encaisse_des_devises.
720 for currency in ['usd', ]:
721 self._maybeNewContent(caisse_courante.encaisse_des_devises, id=currency, portal_type='Category', codification='', vault_type='site/surface/caisse_courante/encaisse_des_devises')
722
723 return created_site_list
724
725 def _openDate(self, date=None, site=None, id=None, open=True, container=None,
726 portal_type=None, force_check=0):
727 if date is None:
728 date = DateTime().Date()
729 if not isinstance(date, str):
730 date = date.Date()
731 if site is None:
732 site = self.testsite
733 date_object = container.newContent(id=id, portal_type=portal_type,
734 site_value = site, start_date = date)
735 if open:
736 if force_check and date_object.getPortalType() == 'Counter Date':
737 self.workflow_tool.doActionFor(date_object, 'open_action',
738 wf_id='counter_date_workflow',
739 your_check_date_is_today=0)
740 else:
741 date_object.open()
742 setattr(self, id, date_object)
743 date_object.assignRoleToSecurityGroup()
744
745 def openAccountingDate(self, date=None, site=None, id='accounting_date_1', open=True):
746 """
747 open an accounting date for the given date
748 by default use the current date
749 """
750 self._openDate(date=date, site=site, id=id, open=open, container=self.getAccountingDateModule(), portal_type='Accounting Date')
751
752 def openCounterDate(self, date=None, site=None, id='counter_date_1', open=True, force_check=0):
753 """
754 open a couter date for the given date
755 by default use the current date
756 """
757 self._openDate(date=date, site=site, id=id, open=open,
758 container=self.getCounterDateModule(),
759 portal_type='Counter Date',
760 force_check=force_check)
761
762 def openCounter(self, site=None, id='counter_1'):
763 """
764 open a counter for the givent site
765 """
766 # create a counter
767 counter_module = self.getCounterModule()
768 while "guichet" not in site.getId():
769 site = site.getParentValue()
770 counter = counter_module.newContent(id=id, site_value=site)
771 # open it
772 counter.open()
773
774 def closeCounterDate(self, id):
775 """
776 close the counter date
777 """
778 module = self.getCounterDateModule()
779 counter_date = module[id]
780 counter_date.close()
781
782 def initDefaultVariable(self):
783 """
784 init some default variable use in all test
785 """
786 # the erp5 site
787 self.portal = self.getPortal()
788
789 # Make sure movement table does not exist
790 sql_connection = self.getSQLConnection()
791 sql_connection.manage_test("DROP TABLE IF EXISTS movement")
792 # Delete also all ZSQL Methods related to movement table
793 catalog = self.portal.portal_catalog.getSQLCatalog()
794 for zsql in ["z0_drop_movement", "z0_uncatalog_movement",
795 "z_catalog_movement_list", "z_create_movement", ]:
796 if catalog._getOb(zsql, None) is not None:
797 catalog.manage_delObjects(ids=[zsql])
798
799 # Update properties of catalog
800 sql_catalog_object_list = list(catalog.sql_catalog_object_list)
801 sql_uncatalog_object = list(catalog.sql_uncatalog_object)
802 sql_clear_catalog = list(catalog.sql_clear_catalog)
803 sql_search_tables = list(catalog.sql_search_tables)
804
805 if "z_catalog_movement_list" in sql_catalog_object_list:
806 sql_catalog_object_list.remove("z_catalog_movement_list")
807 if "z0_uncatalog_movement" in sql_uncatalog_object:
808 sql_uncatalog_object.remove("z0_uncatalog_movement")
809 if "z0_drop_movement" in sql_clear_catalog:
810 sql_clear_catalog.remove("z0_drop_movement")
811 if "z_create_movement" in sql_clear_catalog:
812 sql_clear_catalog.remove("z_create_movement")
813 if "movement" in sql_search_tables:
814 sql_search_tables.remove("movement")
815
816 catalog.sql_catalog_object_list = tuple(sql_catalog_object_list)
817 catalog.sql_uncatalog_object = tuple(sql_uncatalog_object)
818 catalog.sql_clear_catalog = tuple(sql_clear_catalog)
819 catalog.sql_search_tables = tuple(sql_search_tables)
820
821 # the default currency for the site
822 if not self.portal.hasProperty('reference_currency_id'):
823 self.portal.manage_addProperty('reference_currency_id', 'EUR', type='string')
824 # not working days
825 if not self.portal.hasProperty('not_working_days'):
826 self.portal.manage_addProperty('not_working_days', '', type='string')
827 else:
828 self.portal.not_working_days = ''
829 setattr(self.portal, 'functionnal_test_mode', 1)
830 # the person module
831 self.person_module = self.getPersonModule()
832 # the organisation module
833 self.organisation_module = self.getOrganisationModule()
834 # the category tool
835 self.category_tool = self.getCategoryTool()
836 # the workflow tool
837 self.workflow_tool = self.getWorkflowTool()
838 # nb use for bank account inventory
839 self.account_inventory_number = 0
840 # the cash inventory module
841 self.cash_inventory_module = self.getCashInventoryModule()
842 # the bank inventory module
843 self.bank_account_inventory_module = self.getBankAccountInventoryModule()
844 # simulation tool
845 self.simulation_tool = self.getSimulationTool()
846 # get the currency module
847 self.currency_module = self.getCurrencyModule()
848 self.checkbook_model_module = self.portal.checkbook_model_module
849 # a default date
850 self.date = DateTime()
851
852 def setDocumentSourceReference(self, doc):
853 """
854 Compute and set the source reference for a document
855 """
856 # document must have a date defined
857 if doc.getStartDate() is None:
858 doc.edit(start_date=DateTime())
859 # call script to set source reference
860 doc.Baobab_getUniqueReference()
861
862
863 def createPerson(self, id, first_name, last_name, site=None):
864 """
865 Create a person
866 """
867 if site is None:
868 site = "testsite/paris"
869 return self.person_module.newContent(id = id,
870 portal_type = 'Person',
871 first_name = first_name,
872 last_name = last_name,
873 site=site)
874
875
876 def createBankAccount(self, person, account_id, currency, amount, inv_date=None, **kw):
877 """
878 Create and initialize a bank account for a person
879 """
880 if not kw.has_key('bank_country_code'):
881 kw['bank_country_code'] = 'k'
882 if not kw.has_key('bank_code'):
883 kw['bank_code'] = '1234'
884 if not kw.has_key('branch'):
885 kw['branch'] = '12345'
886 if not kw.has_key('bank_account_number'):
887 kw['bank_account_number'] = '123456789012'
888 if not kw.has_key('bank_account_key'):
889 kw['bank_account_key'] = '12'
890 if not kw.has_key('internal_bank_account_number'):
891 kw['internal_bank_account_number'] = 'k%11s' % (12341234512 + self.account_inventory_number, )
892 #kw['internal_bank_account_number'] = 'k12341234512'
893 bank_account = person.newContent(id = account_id,
894 portal_type = 'Bank Account',
895 price_currency_value = currency,
896 **kw)
897 if not kw.has_key('reference') and bank_account.getReference() is None:
898 # If there is no automatic getter-time calculation of the reference and
899 # no reference has been explicitely set, generate one composed of all
900 # bank codes and a static prefix - to avoid collisions as much as
901 # possible.
902 bank_account.edit(reference='ref_%s%s%s%s%s' % (kw['bank_country_code'],
903 kw['bank_code'], kw['branch'], kw['bank_account_number'],
904 kw['bank_account_key']))
905
906 # validate this bank account for payment
907 bank_account.validate()
908 if amount:
909 # we need to put some money on this bank account
910 self.createBankAccountInventory(bank_account, amount, inv_date=inv_date)
911 return bank_account
912
913 def createBankAccountInventory(self, bank_account, amount, inv_date=None):
914 if not hasattr(self, 'bank_account_inventory'):
915 self.bank_account_inventory = self.bank_account_inventory_module.newContent(id='account_inventory_group',
916 portal_type='Bank Account Inventory Group',
917 site_value=self.testsite,
918 stop_date=DateTime().Date())
919
920 if inv_date is None:
921 inv_date = DateTime()
922 inventory = self.bank_account_inventory.newContent(id=bank_account.getInternalBankAccountNumber(),
923 portal_type='Bank Account Inventory',
924 destination_payment_value=bank_account,
925 stop_date=inv_date)
926 account_inventory_line_id = 'account_inventory_line_%s' % (self.account_inventory_number, )
927 inventory_line = inventory.newContent(id=account_inventory_line_id,
928 portal_type='Bank Account Inventory Line',
929 resource_value=bank_account.getPriceCurrencyValue(),
930 quantity=amount)
931
932
933 # deliver the inventory
934 if inventory.getSimulationState()!='delivered':
935 inventory.deliver()
936
937 self.account_inventory_number += 1
938
939 def createCheckbook(self, id, vault, bank_account, min, max, date=None):
940 """
941 Create a checkbook for the given bank account
942 """
943 if date is None:
944 date = DateTime().Date()
945 return self.checkbook_module.newContent(
946 id=id,
947 portal_type='Checkbook',
948 destination_value=vault,
949 destination_payment_value=bank_account,
950 reference_range_min=min,
951 reference_range_max=max,
952 start_date=date,
953 )
954
955 def createCheckbookModel(self, id, check_model, reference=None,
956 unique_per_account=True):
957 """
958 Create a checkbook for the given bank account
959 with 3 variations
960 """
961 model = self.checkbook_model_module.newContent(
962 id=id,
963 portal_type='Checkbook Model',
964 title='Generic',
965 account_number_enabled=True,
966 reference=reference,
967 composition=check_model.getRelativeUrl(),
968 unique_per_account=unique_per_account,
969 )
970 model.newContent(id='variant_1', portal_type='Checkbook Model Check Amount Variation',
971 quantity=50, title='50')
972 model.newContent(id='variant_2', portal_type='Checkbook Model Check Amount Variation',
973 quantity=100, title='100')
974 model.newContent(id='variant_3', portal_type='Checkbook Model Check Amount Variation',
975 quantity=200, title='200')
976 return model
977
978
979 def createCheckModel(self, id, reference='CCOP', unique_per_account=True):
980 """
981 Create a checkbook for the given bank account
982 """
983 return self.checkbook_model_module.newContent(
984 id=id,
985 portal_type='Check Model',
986 title='Check',
987 reference=reference,
988 account_number_enabled=True,
989 unique_per_account=unique_per_account,
990 )
991
992 def createCheckAndCheckbookModel(self):
993 """
994 create default checkbook and check models
995 """
996 self.check_model = self.createCheckModel(id='check_model')
997 self.check_model_1 = self.check_model
998 self.check_model_2 = self.createCheckModel(id='check_model_2', reference='CCCO')
999 self.check_model_1_2 = self.createCheckModel(
1000 id='check_model_1_2',
1001 reference='CCOP',
1002 unique_per_account=False,
1003 )
1004 self.check_model_2_2 = self.createCheckModel(
1005 id='check_model_2_2',
1006 reference='CCCO',
1007 unique_per_account=False,
1008 )
1009 self.checkbook_model = self.createCheckbookModel(
1010 id='checkbook_model', check_model=self.check_model)
1011 self.checkbook_model_1 = self.checkbook_model
1012 self.checkbook_model_2 = self.createCheckbookModel(
1013 id='checkbook_model_2', check_model=self.check_model_2)
1014 self.checkbook_model_1_2 = self.createCheckbookModel(
1015 id='checkbook_model_1_2',
1016 check_model=self.check_model_1_2,
1017 unique_per_account=False,
1018 )
1019 self.checkbook_model_2_2 = self.createCheckbookModel(
1020 id='checkbook_model_2_2',
1021 check_model=self.check_model_2_2,
1022 unique_per_account=False,
1023 )
1024
1025 def createCheck(self, id, reference, checkbook, bank_account=None,
1026 resource_value=None, destination_value=None):
1027 """
1028 Create Check in a checkbook
1029 """
1030 check = checkbook.newContent(id=id,
1031 portal_type = 'Check',
1032 reference=reference,
1033 destination_payment_value=bank_account,
1034 resource_value=resource_value,
1035 destination_value=destination_value
1036 )
1037
1038 # mark the check as issued
1039 check.confirm()
1040 return check
1041
1042 def createTravelerCheckModel(self, id):
1043 """
1044 Create a checkbook for the given bank account
1045 """
1046 model = self.checkbook_model_module.newContent(id = id,
1047 title = 'USD Traveler Check',
1048 portal_type = 'Check Model',
1049 fixed_price = 1
1050 )
1051 variation = model.newContent(id='variant_1',
1052 portal_type='Check Model Type Variation',
1053 price=50)
1054 model.setPriceCurrency(self.currency_2.getRelativeUrl())
1055 return model
1056
1057 def createCashContainer(self, document, container_portal_type, global_dict, line_list, delivery_line_type='Cash Delivery Line'):
1058 """
1059 Create a cash container
1060 global_dict has keys :
1061 emission_letter, variation, cash_status, resource
1062 line_list is a list od dict with keys:
1063 reference, range_start, range_stop, quantity, aggregate
1064 """
1065 # Container Creation
1066 base_list = ('emission_letter', 'variation', 'cash_status')
1067 category_list = ('emission_letter/'+global_dict['emission_letter'], 'variation/'+global_dict['variation'], 'cash_status/'+global_dict['cash_status'] )
1068 resource_total_quantity = 0
1069 # create cash container
1070 for line_dict in line_list:
1071 movement_container = document.newContent(portal_type = container_portal_type
1072 , reindex_object = 1
1073 , reference = line_dict['reference']
1074 , cash_number_range_start = line_dict['range_start']
1075 , cash_number_range_stop = line_dict['range_stop']
1076 )
1077 if line_dict.has_key('aggregate'):
1078 movement_container.setAggregateValueList([line_dict['aggregate'], ])
1079 # create a cash container line
1080 container_line = movement_container.newContent(portal_type = 'Container Line'
1081 , reindex_object = 1
1082 , resource_value = global_dict['resource']
1083 , quantity = line_dict['quantity']
1084 )
1085 container_line.setResourceValue(global_dict['resource'])
1086 container_line.setVariationCategoryList(category_list)
1087 container_line.updateCellRange(script_id='CashDetail_asCellRange', base_id="movement")
1088 for key in container_line.getCellKeyList(base_id='movement'):
1089 if isSameSet(key, category_list):
1090 cell = container_line.newCell(*key)
1091 cell.setCategoryList(category_list)
1092 cell.setQuantity(line_dict['quantity'])
1093 cell.setMappedValuePropertyList(['quantity', 'price'])
1094 cell.setMembershipCriterionBaseCategoryList(base_list)
1095 cell.setMembershipCriterionCategoryList(category_list)
1096 cell.edit(force_update = 1,
1097 price = container_line.getResourceValue().getBasePrice())
1098
1099
1100 resource_total_quantity += line_dict['quantity']
1101 # create cash delivery movement
1102 movement_line = document.newContent(id = "movement"
1103 , portal_type = delivery_line_type
1104 , resource_value = global_dict['resource']
1105 , quantity_unit_value = self.getCategoryTool().quantity_unit.unit
1106 )
1107 movement_line.setVariationBaseCategoryList(base_list)
1108 movement_line.setVariationCategoryList(category_list)
1109 movement_line.updateCellRange(script_id="CashDetail_asCellRange", base_id="movement")
1110 for key in movement_line.getCellKeyList(base_id='movement'):
1111 if isSameSet(key, category_list):
1112 cell = movement_line.newCell(*key)
1113 cell.setCategoryList(category_list)
1114 cell.setQuantity(resource_total_quantity)
1115 cell.setMappedValuePropertyList(['quantity', 'price'])
1116 cell.setMembershipCriterionBaseCategoryList(base_list)
1117 cell.setMembershipCriterionCategoryList(category_list)
1118 cell.edit(force_update = 1,
1119 price = movement_line.getResourceValue().getBasePrice())
1120
1121
1122 def createCashInventory(self, source, destination, currency, line_list=[], extra_id='',
1123 reset_quantity=0, start_date=None, quantity_factor=1):
1124 """
1125 Create a cash inventory group
1126 """
1127 # we need to have a unique inventory group id by destination
1128
1129 inventory_group_id = 'inventory_group_%s_%s%s' % \
1130 (destination.getParentValue().getUid(), destination.getId(), extra_id)
1131 if start_date is None:
1132 start_date = DateTime()-1
1133 if not hasattr(self, inventory_group_id):
1134 inventory_group = self.cash_inventory_module.newContent(id=inventory_group_id,
1135 portal_type='Cash Inventory Group',
1136 destination_value=destination,
1137 start_date=start_date)
1138 setattr(self, inventory_group_id, inventory_group)
1139 else:
1140 inventory_group = getattr(self, inventory_group_id)
1141
1142 # get/create the inventory based on currency
1143 inventory_id = '%s_inventory_%s' % (inventory_group_id, currency.getId())
1144 if not hasattr(self, inventory_id):
1145 inventory = inventory_group.newContent(id=inventory_id,
1146 portal_type='Cash Inventory',
1147 price_currency_value=currency)
1148 setattr(self, inventory_id, inventory)
1149 else:
1150 inventory = getattr(self, inventory_id)
1151
1152 # line data are given by a list of dict, dicts must have this key :
1153 # id : line id
1154 # resource : banknote or coin
1155 # variation_id : list of variation id
1156 # variation_value : list of variation value (must be in the same order as variation_id
1157 # quantity
1158 for line in line_list:
1159 variation_list = line.get('variation_list', None)
1160 self.addCashLineToDelivery(inventory,
1161 line['id'],
1162 "Cash Inventory Line",
1163 line['resource'],
1164 line['variation_id'],
1165 line['variation_value'],
1166 line['quantity'],
1167 variation_list=variation_list,
1168 reset_quantity=reset_quantity,
1169 quantity_factor=quantity_factor)
1170 # deliver the inventory
1171 if inventory.getSimulationState()!='delivered':
1172 inventory.deliver()
1173 return inventory_group
1174
1175
1176 def addCashLineToDelivery(self, delivery_object, line_id, line_portal_type, resource_object,
1177 variation_base_category_list, variation_category_list, resource_quantity_dict,
1178 variation_list=None, reset_quantity=0, quantity_factor=1):
1179 """
1180 Add a cash line to a delivery
1181 """
1182 base_id = 'movement'
1183 line_kwd = {'base_id':base_id}
1184 # create the cash line
1185 line = delivery_object.newContent( id = line_id
1186 , portal_type = line_portal_type
1187 , resource_value = resource_object # banknote or coin
1188 , quantity_unit_value = self.unit
1189 )
1190 # set base category list on line
1191 line.setVariationBaseCategoryList(variation_base_category_list)
1192 # set category list line
1193 line.setVariationCategoryList(variation_category_list)
1194 line.updateCellRange(script_id='CashDetail_asCellRange', base_id=base_id)
1195 cell_range_key_list = line.getCellRangeKeyList(base_id=base_id)
1196 if cell_range_key_list <> [[None, None]] :
1197 for k in cell_range_key_list:
1198 category_list = filter(lambda k_item: k_item is not None, k)
1199 c = line.newCell(*k, **line_kwd)
1200 mapped_value_list = ['price', 'quantity']
1201 c.edit( membership_criterion_category_list = category_list
1202 , mapped_value_property_list = mapped_value_list
1203 , category_list = category_list
1204 , force_update = 1
1205 )
1206 # set quantity on cell to define quantity of bank notes / coins
1207 if variation_list is None:
1208 variation_list = self.variation_list
1209 for variation in variation_list:
1210 v1, v2 = variation_category_list[:2]
1211 cell = line.getCell(v1, variation, v2)
1212 if cell is not None:
1213 quantity = resource_quantity_dict[variation]
1214 if reset_quantity:
1215 quantity = 0
1216 cell.setQuantity(quantity*quantity_factor)
1217
1218
1219 def checkResourceCreated(self):
1220 """
1221 Check that all have been create after setup
1222 """
1223 # check that Categories were created
1224 self.assertEqual(self.paris.getPortalType(), 'Category')
1225
1226 # check that Resources were created
1227 # check portal type of billet_10000
1228 self.assertEqual(self.billet_10000.getPortalType(), 'Banknote')
1229 # check value of billet_10000
1230 self.assertEqual(self.billet_10000.getBasePrice(), 10000)
1231 # check currency value of billet_10000
1232 self.assertEqual(self.billet_10000.getPriceCurrency(), 'currency_module/EUR')
1233 # check years of billet_10000
1234 self.assertEqual(self.billet_10000.getVariationList(), ['1992', '2003'])
1235
1236 # check portal type of billet_5000
1237 self.assertEqual(self.billet_5000.getPortalType(), 'Banknote')
1238 # check value of billet_5000
1239 self.assertEqual(self.billet_5000.getBasePrice(), 5000)
1240 # check currency value of billet_5000
1241 self.assertEqual(self.billet_5000.getPriceCurrency(), 'currency_module/EUR')
1242 # check years of billet_5000
1243 self.assertEqual(self.billet_5000.getVariationList(), ['1992', '2003'])
1244
1245 # check portal type of billet_200
1246 self.assertEqual(self.billet_200.getPortalType(), 'Banknote')
1247 # check value of billet_200
1248 self.assertEqual(self.billet_200.getBasePrice(), 200)
1249 # check currency value of billet_200
1250 self.assertEqual(self.billet_200.getPriceCurrency(), 'currency_module/EUR')
1251 # check years of billet_200
1252 self.assertEqual(self.billet_200.getVariationList(), ['1992', '2003'])
1253
1254 def resetInventory(self,
1255 sequence=None, line_list=None, sequence_list=None, extra_id=None,
1256 destination=None, currency=None, start_date=None, **kwd):
1257 """
1258 Make sure we can not close the counter date
1259 when there is still some operations remaining
1260 """
1261 if extra_id is not None:
1262 extra_id = '_reset_%s' % extra_id
1263 else:
1264 extra_id = '_reset'
1265 # Before the test, we need to input the inventory
1266 self.createCashInventory(source=None, destination=destination, currency=currency,
1267 line_list=line_list, extra_id=extra_id, reset_quantity=1,
1268 start_date=start_date)
1269
1270 def stepDeleteResetInventory(self, sequence=None, sequence_list=None, **kwd):
1271 """
1272 Make sure we can not close the counter date
1273 when there is still some operations remaining
1274 """
1275 inventory_module = self.getPortal().cash_inventory_module
1276 to_delete_id_list = [x for x in inventory_module.objectIds()
1277 if x.find('reset')>=0]
1278 inventory_module.manage_delObjects(ids=to_delete_id_list)
1279