[Erp5-report] r27024 - /erp5/trunk/products/ERP5/tests/testNewPayroll.py
nobody at svn.erp5.org
nobody at svn.erp5.org
Mon May 18 14:33:06 CEST 2009
Author: fabien
Date: Mon May 18 14:33:06 2009
New Revision: 27024
URL: http://svn.erp5.org?rev=27024&view=rev
Log:
payroll is still under refactoring to use BPM. This test file test this new version. In the future, testNewPayroll and testPayroll will be merged.
Added:
erp5/trunk/products/ERP5/tests/testNewPayroll.py
Added: erp5/trunk/products/ERP5/tests/testNewPayroll.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testNewPayroll.py?rev=27024&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/tests/testNewPayroll.py (added)
+++ erp5/trunk/products/ERP5/tests/testNewPayroll.py [utf8] Mon May 18 14:33:06 2009
@@ -1,0 +1,408 @@
+##############################################################################
+#
+# Copyright (c) 2009-2010 Nexedi SA and Contributors. All Rights Reserved.
+# Fabien Morin <fabien.morin at gmail.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility 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
+# guarantees 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.ERP5Type.tests.ERP5TypeTestCase import ERP5ReportTestCase
+from AccessControl.SecurityManagement import newSecurityManager
+from Testing import ZopeTestCase
+import transaction
+from Products.CMFCore.utils import getToolByName
+
+
+class TestNewPayrollMixin(ERP5ReportTestCase):
+ price_currency = 'currency_module/EUR'
+
+ def getTitle(self):
+ return "Payroll"
+
+ def setSystemPreference(self):
+ preference_tool = getToolByName(self.portal, 'portal_preferences')
+ system_preference_list = preference_tool.contentValues(
+ portal_type='System Preference')
+ if len(system_preference_list) > 1:
+ raise AttributeError('More than one System Preference, cannot test')
+ if len(system_preference_list) == 0:
+ system_preference = preference_tool.newContent(
+ portal_type='System Preference')
+ else:
+ system_preference = system_preference_list[0]
+ system_preference.edit(
+ preferred_invoicing_resource_use_category_list = \
+ ['payroll/tax'],
+ preferred_normal_resource_use_category_list = \
+ ['payroll/base_salary'],
+ priority = 1)
+ if system_preference.getPreferenceState() == 'disabled':
+ system_preference.enable()
+
+ def afterSetUp(self):
+ """Prepare the test."""
+ self.portal = self.getPortal()
+ self.organisation_module = self.portal.organisation_module
+ self.person_module = self.portal.person_module
+ self.payroll_service_module = self.portal.payroll_service_module
+ self.paysheet_model_module = self.portal.paysheet_model_module
+ self.validateRules()
+ self.createCategories()
+ self.createCurrencies()
+
+ self.login()
+
+ # creation of payroll services
+ self.urssaf_id = 'sickness_insurance'
+ self.labour_id = 'labour'
+
+ self.urssaf_slice_list = ['salary_range/france/slice_a',
+ 'salary_range/france/slice_b',
+ 'salary_range/france/slice_c']
+
+ self.urssaf_share_list = ['tax_category/employee_share',
+ 'tax_category/employer_share']
+
+ self.payroll_service_organisation = self.createOrganisation(title='URSSAF')
+ self.urssaf = self.createPayrollService(id=self.urssaf_id,
+ title='State Insurance',
+ product_line='state_insurance',
+ variation_base_category_list=['tax_category', 'salary_range'],
+ variation_category_list=self.urssaf_slice_list + \
+ self.urssaf_share_list,
+ use='payroll/tax')
+
+ self.labour = self.createPayrollService(id=self.labour_id,
+ title='Labour',
+ product_line='labour',
+ use='payroll/base_salary')
+ self.setSystemPreference()
+
+ def _safeTic(self):
+ """Like tic, but swallowing errors, usefull for teardown"""
+ try:
+ transaction.commit()
+ self.tic()
+ except RuntimeError:
+ pass
+
+ def beforeTearDown(self):
+ """Clear everything for next test."""
+ self._safeTic()
+ for module in [ 'organisation_module',
+ 'person_module',
+ 'currency_module',
+ 'payroll_service_module',
+ 'paysheet_model_module',
+ 'accounting_module']:
+ folder = getattr(self.getPortal(), module, None)
+ if folder:
+ [x.unindexObject() for x in folder.objectValues()]
+ self._safeTic()
+ folder.manage_delObjects([x.getId() for x in folder.objectValues()])
+ self._safeTic()
+ # cancel remaining messages
+ activity_tool = self.getPortal().portal_activities
+ for message in activity_tool.getMessageList():
+ activity_tool.manageCancel(message.object_path, message.method_id)
+ ZopeTestCase._print('\nCancelling active message %s.%s()\n'
+ % (message.object_path, message.method_id) )
+ transaction.commit()
+
+ def login(self):
+ uf = self.getPortal().acl_users
+ uf._doAddUser('admin', '', ['Manager', 'Assignee', 'Assignor',
+ 'Associate', 'Auditor', 'Author'], [])
+ user = uf.getUserById('admin').__of__(uf)
+ newSecurityManager(None, user)
+
+ def createCategories(self):
+ """Create the categories for our test. """
+ # create categories
+ for cat_string in self.getNeededCategoryList() :
+ base_cat = cat_string.split("/")[0]
+ # if base_cat not exist, create it
+ if getattr(self.getPortal().portal_categories, base_cat, None) == None:
+ self.getPortal().portal_categories.newContent(\
+ portal_type='Base Category',
+ id=base_cat)
+ transaction.commit()
+ self.tic()
+ path = self.getPortal().portal_categories[base_cat]
+ for cat in cat_string.split("/")[1:] :
+ if not cat in path.objectIds() :
+ path = path.newContent(
+ portal_type='Category',
+ id=cat,
+ title=cat.replace('_', ' ').title(),)
+ else:
+ path = path[cat]
+ transaction.commit()
+ self.tic()
+ # check categories have been created
+ for cat_string in self.getNeededCategoryList() :
+ self.assertNotEquals(None,
+ self.getCategoryTool().restrictedTraverse(cat_string),
+ cat_string)
+
+ def getNeededCategoryList(self):
+ """return a list of categories that should be created."""
+ return ('region/europe/west/france',
+ 'salary_range/france/forfait',
+ 'salary_range/france/slice_a',
+ 'salary_range/france/slice_b',
+ 'salary_range/france/slice_c',
+ 'tax_category/employer_share',
+ 'tax_category/employee_share',
+ 'base_amount/deductible_tax',
+ 'base_amount/non_deductible_tax',
+ 'base_amount/bonus',
+ 'base_amount/base_salary',
+ 'base_amount/net_salary',
+ 'grade/worker',
+ 'grade/engineer',
+ 'quantity_unit/time/month',
+ 'group/demo_group',
+ 'product_line/base_salary',
+ 'product_line/payroll_tax_1',
+ 'product_line/payroll_tax_2',
+ 'use/payroll',
+ 'use/payroll/tax',
+ 'use/payroll/base_salary',
+ )
+
+ def createCurrencies(self):
+ """Create some currencies.
+ This script will reuse existing currencies, because we want currency ids
+ to be stable, as we use them as categories.
+ """
+ currency_module = self.getCurrencyModule()
+ if not hasattr(currency_module, 'EUR'):
+ self.EUR = currency_module.newContent(
+ portal_type = 'Currency',
+ reference = "EUR", id = "EUR", base_unit_quantity=0.001 )
+ self.USD = currency_module.newContent(
+ portal_type = 'Currency',
+ reference = "USD", id = "USD" )
+ self.YEN = currency_module.newContent(
+ portal_type = 'Currency',
+ reference = "YEN", id = "YEN" )
+ transaction.commit()
+ self.tic()
+ else:
+ self.EUR = currency_module.EUR
+ self.USD = currency_module.USD
+ self.YEN = currency_module.YEN
+
+ def getBusinessTemplateList(self):
+ """ """
+ return ('erp5_base', 'erp5_pdm', 'erp5_trade', 'erp5_accounting',
+ 'erp5_invoicing', 'erp5_payroll', 'erp5_mrp', 'erp5_bpm')
+
+ def createPerson(self, title,
+ career_subordination_value=None, career_grade=None, **kw):
+ """
+ Create some Pesons so that we have something to feed.
+ """
+ person_module = self.portal.getDefaultModule(portal_type='Person')
+ person = person_module.newContent(portal_type='Person')
+ person.edit(
+ title=title,
+ career_subordination_value=career_subordination_value,
+ career_grade=career_grade)
+ transaction.commit()
+ self.tic()
+ return person
+
+ def createOrganisation(self, title, **kw):
+ organisation = self.organisation_module.newContent( \
+ portal_type='Organisation',
+ title=title)
+ transaction.commit()
+ self.tic()
+ return organisation
+
+ def createPayrollService(self, id='', title='',
+ variation_base_category_list=None,
+ variation_category_list=None, product_line=None, **kw):
+
+ if variation_category_list == None:
+ variation_category_list=[]
+ if variation_base_category_list == None:
+ variation_category_list=[]
+ if hasattr(self.payroll_service_module, id):
+ self.payroll_service_module.manage_delObjects([id])
+ payroll_service = self.payroll_service_module.newContent(
+ title=title,
+ portal_type='Payroll Service',
+ id=id,
+ quantity_unit='time/month',
+ product_line=product_line,
+ **kw)
+ payroll_service.setVariationBaseCategoryList(variation_base_category_list)
+ payroll_service.setVariationCategoryList(variation_category_list)
+ transaction.commit()
+ self.tic()
+ return payroll_service
+
+ def createModel(self, title='',
+ person_title='', person_career_grade='',
+ organisation_title='',
+ variation_settings_category_list=None,
+ price_currency=''):
+ """
+ Create a model
+ """
+ if variation_settings_category_list == None:
+ variation_settings_category_list = []
+ organisation = self.createOrganisation(organisation_title)
+ person = self.createPerson(title=person_title,
+ career_subordination_value=organisation,
+ career_grade=person_career_grade)
+ paysheet_model = self.paysheet_model_module.newContent( \
+ portal_type='Pay Sheet Model')
+ paysheet_model.edit(\
+ title=title,
+ variation_settings_category_list=['salary_range/france',],
+ destination_section_value=organisation,
+ source_section_value=person,)
+ paysheet_model.setPriceCurrency(price_currency)
+ transaction.commit()
+ self.tic()
+ return paysheet_model
+
+class TestNewPayroll(TestNewPayrollMixin):
+
+ def test_01_basicPaySheetCalculation(self):
+ '''
+ test applyTransformation method. It should create new movements
+ '''
+ model = self.createModel('Homer Model', 'Homer Simpson', 'worker',
+ 'Nexedi', [], self.price_currency)
+
+ share_list = ['tax_category/employee_share',
+ 'tax_category/employer_share']
+
+ # add a model line
+ model_line1 = model.newContent(portal_type='Pay Sheet Model Line',
+ title='Urssaf',
+ int_index=2,
+ resource_value=self.urssaf,
+ variation_category_list=share_list,
+ source_value=self.payroll_service_organisation,
+ base_application_list=[ 'base_amount/base_salary'],
+ base_contribution_list=['base_amount/deductible_tax'])
+ # if the line has cells with different tax categories, new properties are
+ # added to this line.
+ model_line1.setResourceValue(self.urssaf)
+ model_line1.setVariationCategoryList(['tax_category/employee_share',
+ 'tax_category/employer_share'])
+ transaction.commit()
+ self.tic()
+
+ # create movement
+ cell1 = model_line1.newCell('tax_category/employee_share',
+ portal_type='Pay Sheet Cell',
+ base_id='movement',
+ mapped_value_property_list=('quantity', 'price'),)
+ cell1.edit(price=0.1, tax_category='employee_share')
+
+ cell2 = model_line1.newCell('tax_category/employer_share',
+ portal_type='Pay Sheet Cell',
+ base_id='movement',
+ mapped_value_property_list=('quantity', 'price'),)
+ cell2.edit(price=0.5, tax_category='employer_share')
+ transaction.commit()
+ self.tic()
+
+ # create paysheet
+ paysheet_module = self.portal.getDefaultModule(\
+ portal_type='Pay Sheet Transaction')
+ paysheet = paysheet_module.newContent(\
+ portal_type='Pay Sheet Transaction',
+ title='test 1',
+ specialise_value=model,
+ source_section_value=model.getSourceSectionValue(),
+ destination_section_value=model.getDestinationSectionValue())
+ paysheet.setPriceCurrency('currency_module/EUR')
+ transaction.commit()
+ self.tic()
+
+ # add an input line (the salary) in the paysheet
+ labour_line = paysheet.newContent(portal_type='Pay Sheet Line',
+ resource_value=self.labour,
+ source_section_value=model.getSourceSectionValue(),
+ destination_section_value=model.getDestinationSectionValue(),
+ int_index=1,
+ price=20,
+ quantity=150,
+ base_application_list=[],
+ base_contribution_list=['base_amount/base_salary',
+ 'base_amount/gross_salary'])
+ self.assertEqual(labour_line.getTotalPrice(), 3000.0)
+
+ # check updateAggregatedMovement method return
+ movement_dict = model.updateAggregatedAmountList(context=paysheet)
+ movement_to_delete = movement_dict['movement_to_delete']
+ movement_to_add = movement_dict['movement_to_add']
+ self.assertEquals(len(movement_to_delete), 0)
+ self.assertEquals(len(movement_to_add), 2)
+
+ # calculate the pay sheet
+ paysheet.applyTransformation()
+ transaction.commit()
+ self.tic()
+
+ # check lines were created
+ paysheet_line_list = paysheet.contentValues(portal_type='Pay Sheet Line')
+ self.assertEqual(len(paysheet_line_list), 2)
+ self.assertEqual(len(paysheet.getMovementList(portal_type=\
+ 'Pay Sheet Cell')), 2)
+
+ # check the amount in the cells of the created paysheet lines
+ for paysheet_line in paysheet_line_list:
+ service = paysheet_line.getResourceId()
+ if service == self.urssaf_id:
+ cell1 = paysheet_line.getCell('tax_category/employee_share')
+ self.assertEquals(cell1.getQuantity(), 3000)
+ self.assertEquals(cell1.getPrice(), 0.1)
+ cell2 = paysheet_line.getCell('tax_category/employer_share')
+ self.assertEquals(cell2.getQuantity(), 3000)
+ self.assertEquals(cell2.getPrice(), 0.5)
+ elif service == self.labour_id:
+ self.assertEqual(paysheet_line.getTotalPrice(), 3000.0)
+ else:
+ self.fail("Unknown service for line %s" % paysheet_line)
+
+ # check that after the line creation, updateAggregatedAmountList return
+ # nothing
+ movement_dict = model.updateAggregatedAmountList(context=paysheet)
+ movement_to_delete = movement_dict['movement_to_delete']
+ movement_to_add = movement_dict['movement_to_add']
+ self.assertEquals(len(movement_to_delete), 0)
+ self.assertEquals(len(movement_to_add), 0)
+
+import unittest
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestNewPayroll))
+ return suite
More information about the Erp5-report
mailing list