############################################################################## # # Copyright (c) 2009 Nexedi KK and Contributors. All Rights Reserved. # Tatuya Kamada <tatuya@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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, # USA. # ############################################################################## """ Tests invoice and invoice transaction creation from simulation. Most test-cases are based on the testInvoice.py. """ from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase from AccessControl.SecurityManagement import newSecurityManager from DateTime import DateTime from Products.ERP5Type.tests.Sequence import SequenceList from Products.ERP5.tests.testInvoice import TestSaleInvoiceMixin from Products.ERP5.tests.utils import newSimulationExpectedFailure class TestAdvancedInvoice(TestSaleInvoiceMixin, ERP5TypeTestCase): """Test methods for sale and purchase invoice. Subclasses must defines portal types to use. """ quiet = 1 RUN_ALL_TESTS = 1 PACKING_LIST_DEFAULT_SEQUENCE = \ """ stepCreateEntities stepCreateCurrency stepCreateSaleInvoiceTransactionRule stepCreateOrder stepSetOrderProfile stepSetOrderPriceCurrency stepCreateNotVariatedResource stepTic stepCreateOrderLine stepSetOrderLineResource stepSetOrderLineDefaultValues stepOrderOrder stepTic stepCheckDeliveryBuilding stepConfirmOrder stepTic stepPackingListBuilderAlarm stepTic stepCheckOrderRule stepCheckOrderSimulation stepCheckDeliveryBuilding stepAddPackingListContainer stepAddPackingListContainerLine stepSetContainerLineFullQuantity stepTic stepCheckPackingListIsPacked """ INVOICE_DEFAULT_SEQUENCE = PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepStartPackingList stepTic stepInvoiceBuilderAlarm stepTic stepStartRelatedInvoice stepTic """ TWO_PACKING_LIST_DEFAULT_SEQUENCE = \ """ stepCreateEntities stepCreateCurrency stepCreateSaleInvoiceTransactionRule stepCreateOrder stepSetOrderProfile stepSetOrderPriceCurrency stepCreateNotVariatedResource stepTic stepCreateOrderLine stepSetOrderLineResource stepSetOrderLineDefaultValues stepOrderOrder stepTic stepCheckDeliveryBuilding stepConfirmOrder stepTic stepPackingListBuilderAlarm stepTic stepCheckOrderRule stepCheckOrderSimulation stepCheckDeliveryBuilding stepDecreasePackingListLineQuantity stepCheckPackingListIsCalculating stepTic stepCheckPackingListIsDiverged stepSplitAndDeferPackingList stepTic stepCheckPackingListIsSolved stepCheckPackingListSplitted stepAddPackingListContainer stepAddPackingListContainerLine stepSetContainerLineFullQuantity stepTic stepCheckPackingListIsPacked stepDefineNewPackingListContainer stepTic stepCheckNewPackingListIsPacked """ invoice_portal_type = 'Sale Invoice' invoice_line_portal_type = 'Invoice Line' invoice_cell_portal_type = 'Invoice Cell' invoice_module_name = 'sale_invoice_module' invoice_transaction_line_portal_type = 'Sale Invoice Transaction Line' def getBusinessTemplateList(self): return ('erp5_core_proxy_field_legacy', 'erp5_base', 'erp5_pdm', 'erp5_simulation', 'erp5_trade', 'erp5_accounting', 'erp5_invoicing', 'erp5_advanced_invoicing', 'erp5_apparel', 'erp5_project', 'erp5_configurator_standard_trade_template', 'erp5_configurator_standard_invoicing_template', 'erp5_configurator_standard_accounting_template', 'erp5_configurator_standard_solver', 'erp5_simulation_test') def stepStartRelatedInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue( portal_type=self.invoice_portal_type) self.assertNotEquals(invoice, None) invoice.start() self.assertEquals('started', invoice.getSimulationState()) def stepAddInvoiceTransactionLines(self, sequence=None, sequence_list=[]): """ add some invoice and accounting lines to the invoice """ invoice = sequence.get('invoice') invoice.newContent(portal_type=self.invoice_line_portal_type, resource_value=sequence.get('resource'), quantity=3, price=555) invoice_transaction = invoice.getCausalityRelatedValue() invoice_transaction.newContent(portal_type=self.invoice_transaction_line_portal_type, id ='receivable', source='account_module/customer', destination='account_module/supplier', quantity=-1665) invoice_transaction.newContent(portal_type='Sale Invoice Transaction Line', id='income', source='account_module/sale', destination='account_module/purchase', quantity=1665) def stepAddInvoiceLinesManyTransactions(self, sequence=None, sequence_list=[]): """ add some invoice and accounting lines to the invoice """ invoice = sequence.get('invoice') invoice_line = invoice.newContent(portal_type='Invoice Line') invoice_line.edit(resource_value=sequence.get('resource'), quantity=3, price=555) invoice_transaction = invoice.getCausalityRelatedValue() transaction_line_1 = invoice_transaction.newContent(portal_type=self.invoice_transaction_line_portal_type) transaction_line_2 = invoice_transaction.newContent(portal_type=self.invoice_transaction_line_portal_type) self.tic() transaction_line_1.edit(id ='receivable', source='account_module/customer', destination='account_module/supplier', quantity=-1665) transaction_line_2.edit( id='income', source='account_module/sale', destination='account_module/purchase', quantity=1665) def stepChangeQuantityDoubledOnInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue(portal_type=self.invoice_portal_type) self.assertNotEquals(invoice, None) invoice_line_list = invoice.getMovementList() self.assertEquals(1, len(invoice_line_list)) invoice_line = invoice_line_list[0] new_quantity = invoice_line.getQuantity() * 2 invoice_line.setQuantity(new_quantity) sequence.edit(invoice_line_doubled_quantity=new_quantity) def stepAcceptDecisionOnInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue(portal_type=self.invoice_portal_type) builder_list = invoice.getBuilderList() self.assertEquals(1, len(builder_list)) divergence_list = invoice.getDivergenceList() for builder in builder_list: builder.solveDivergence(invoice.getRelativeUrl(), divergence_to_accept_list=divergence_list) def stepCheckDivergenceOnInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue(portal_type=self.invoice_portal_type) self.assertEquals('solved', invoice.getCausalityState()) new_quantity = sequence.get('invoice_line_doubled_quantity') self.assertEquals([], invoice.getDivergenceList()) invoice_line_list = invoice.getMovementList() self.assertEquals(1, len(invoice_line_list)) invoice_line = invoice_line_list[0] self.assertEquals(new_quantity, invoice_line.getQuantity()) self.assertEquals(new_quantity, invoice_line.getDeliveryRelatedValue(portal_type='Simulation Movement' ).getQuantity()) def stepCheckDivergedOnPackingList(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') self.assertEquals('diverged', packing_list.getCausalityState()) def stepCheckSolvedOnPackingList(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') self.assertEquals('solved', packing_list.getCausalityState()) def stepCheckDivergedQuantityOnInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue(portal_type=self.invoice_portal_type) self.assertTrue(invoice.isDivergent()) divergence_list = invoice.getDivergenceList() self.assertEquals(1, len(divergence_list)) divergence = divergence_list[0] self.assertEquals('quantity', divergence.tested_property) def stepCheckDivergedQuantityOnPackingList(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') divergence_list = packing_list.getDivergenceList() self.assertEquals(1, len(divergence_list)) divergence = divergence_list[0] self.assertEquals('quantity', divergence.tested_property) def stepAdoptPrevisionOnPackingList(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') divergence_list = packing_list.getDivergenceList() for builder in packing_list.getBuilderList(): builder.solveDivergence(packing_list.getRelativeUrl(), divergence_to_adopt_list=divergence_list) def stepAdoptPrevisionOnInvoice(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue() divergence_list = invoice.getDivergenceList() builder_list = invoice.getBuilderList() self.assertEquals(1, len(builder_list)) for builder in builder_list: builder.solveDivergence(invoice.getRelativeUrl(), divergence_to_adopt_list=divergence_list) def test_CreatingAccountingTransactionThroughInvoice(self, quiet=quiet, run=RUN_ALL_TESTS): """test creating simple invoice and accounting transaction""" if not run: return sequence_list = SequenceList() sequence = sequence_list.addSequenceString(self.INVOICE_DEFAULT_SEQUENCE) sequence_list.play(self, quiet=quiet) packing_list = sequence.get('packing_list') self.assertEquals('solved', packing_list.getCausalityState()) invoice = packing_list.getCausalityRelatedValue() self.assertEquals(self.invoice_portal_type, invoice.getPortalType()) self.assertEquals('solved', invoice.getCausalityState()) self.assertEquals([], invoice.getDivergenceList()) invoice_transaction = invoice.getCausalityRelatedValue() self.assertNotEquals(invoice_transaction, None) self.assertEquals('draft', invoice_transaction.getCausalityState()) def test_AcceptQuantityDivergenceOnInvoiceWithStoppedPackingList(self, quiet=quiet, run=RUN_ALL_TESTS): """Accept divergence with stopped packing list""" if not run: return sequence_list = SequenceList() sequence = sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepTic stepSetReadyPackingList stepTic stepStartPackingList stepStopPackingList stepTic stepInvoiceBuilderAlarm stepTic stepChangeQuantityDoubledOnInvoice stepTic stepCheckDivergedQuantityOnInvoice stepAcceptDecisionOnInvoice stepTic stepCheckDivergenceOnInvoice stepCheckSolvedOnPackingList """) sequence_list.play(self, quiet=quiet) packing_list = sequence.get('packing_list') self.assertEquals([], packing_list.getDivergenceList()) self.assertEquals('solved', packing_list.getCausalityState()) @newSimulationExpectedFailure def test_AdoptQuantityDivergenceOnInvoiceLineWithStoppedPackingList(self, quiet=quiet, run=RUN_ALL_TESTS): """Adopt quantity with stopped packing list""" if not run: return sequence_list = SequenceList() sequence = sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepStartPackingList stepStopPackingList stepTic stepInvoiceBuilderAlarm stepTic stepChangeQuantityDoubledOnInvoice stepTic stepCheckDivergedQuantityOnInvoice stepAdoptPrevisionOnInvoice stepTic """) sequence_list.play(self, quiet=quiet) packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue() self.assertEquals([], invoice.getDivergenceList()) self.assertEquals('solved', invoice.getCausalityState()) self.assertEquals(1, len(invoice.getMovementList(portal_type=self.invoice_line_portal_type))) invoice_line = invoice.getMovementList(portal_type=self.invoice_line_portal_type)[0] self.assertEquals(99.0, invoice_line.getQuantity()) self.assertEquals(555.0, invoice_line.getPrice()) self.assertEquals(99.0, invoice_line.getDeliveryRelatedValue(portal_type='Simulation Movement' ).getQuantity()) self.assertEquals([], packing_list.getDivergenceList()) self.assertEquals('solved', packing_list.getCausalityState()) def test_PackingListEditAndInvoiceRule(self, quiet=quiet, run=RUN_ALL_TESTS): """ Delivery Rule should not be applied on packing list lines created\ from Order. """ if not run: return if not quiet: self.logMessage('Packing List Edit') sequence_list = SequenceList() sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepEditPackingList stepCheckDeliveryRuleNotAppliedOnPackingListEdit stepCheckInvoicesConsistency """) sequence_list.play(self, quiet=quiet) def test_InvoiceViewAsODT(self): """Create ODT printout """ resource = self.portal.getDefaultModule( self.resource_portal_type).newContent( portal_type=self.resource_portal_type, title='Resource',) client = self.portal.organisation_module.newContent( portal_type='Organisation', title='Client') vendor = self.portal.organisation_module.newContent( portal_type='Organisation', title='Vendor') invoice = self.portal.getDefaultModule(self.invoice_portal_type).newContent( portal_type=self.invoice_portal_type, specialise=self.business_process, start_date=DateTime(2008, 12, 31), title='Invoice', source_value=vendor, source_section_value=vendor, destination_value=client, destination_section_value=client) line = invoice.newContent(portal_type=self.invoice_line_portal_type, resource_value=resource, quantity=10, price=3) invoice.confirm() self.tic() odt = invoice.Invoice_viewAsODT() from Products.ERP5OOo.tests.utils import Validator odf_validator = Validator() err_list = odf_validator.validate(odt) if err_list: self.fail(''.join(err_list)) class TestAdvancedSaleInvoice(TestAdvancedInvoice): quiet = 1 RUN_ALL_TESTS = 1 login = TestAdvancedInvoice.login def afterSetUp(self): super(TestAdvancedSaleInvoice, self).afterSetUp() # register builders for advanced invoicing. business_process = self.portal.unrestrictedTraverse( 'business_process_module/erp5_default_business_process', None) if business_process is not None: business_process.invoice.setDeliveryBuilderList([ 'portal_deliveries/advanced_purchase_invoice_builder', 'portal_deliveries/advanced_sale_invoice_builder', ]) business_process.account.setDeliveryBuilderList([ 'portal_deliveries/advanced_purchase_invoice_transaction_builder', 'portal_deliveries/advanced_sale_invoice_transaction_builder', ]) # This is quite ugly, we should use late import/export functions of generators self.portal.erp5_sql_transactionless_connection.manage_test( "delete from portal_ids where \ id_group='Accounting_Transaction_Module-Sale_Invoice_Transaction'") self.commit() def stepCheckInvoicesAndTransactionsConsistency(self, sequence=None, sequence_list=None, **kw): """ - to check transaction lines match invoice lines """ invoice_list = self.getPortal()[self.invoice_module_name].objectValues() for invoice in invoice_list: state_list = \ list(self.getPortal().getPortalCurrentInventoryStateList()) state_list.append('cancelled') if invoice.getSimulationState() in state_list: invoice_line_list = invoice.contentValues( portal_type=self.invoice_line_portal_type) expected_price = 0.0 for line in invoice_line_list: expected_price += line.getTotalPrice() invoice_transaction = invoice.getCausalityRelatedValue() if invoice_transaction.getSimulationState() in state_list: invoice_transaction_line_list = invoice_transaction.contentValues( portal_type=self.invoice_transaction_line_portal_type) self.assertEquals(3, len(invoice_transaction_line_list)) for line_id, line_source, line_dest, line_ratio in \ self.transaction_line_definition_list: for line in invoice_transaction.contentValues( portal_type=self.invoice_transaction_line_portal_type): if line.getSource() == 'account_module/%s' % line_source and \ line.getDestination() == 'account_module/%s' % line_dest: break else: self.fail('No line found that matches %s' % line_id) resource_precision = line.getResourceValue().getQuantityPrecision() self.assertEquals(round(line.getQuantity(), resource_precision), round(expected_price * line_ratio, resource_precision)) def stepRemoveDateMovementGroupForAdvancedTransactionBuilder(self, sequence=None, sequence_list=None, **kw): """ Remove DateMovementGroup """ portal = self.getPortal() builder = portal.portal_deliveries.advanced_sale_invoice_transaction_builder delivery_movement_group_list = builder.getDeliveryMovementGroupList() uf = self.getPortal().acl_users uf._doAddUser('admin', '', ['Manager'], []) user = uf.getUserById('admin').__of__(uf) newSecurityManager(None, user) for movement_group in delivery_movement_group_list: if movement_group.getPortalType() == 'Property Movement Group': # it contains 'start_date' and 'stop_date' only, so we remove # movement group itself. builder.deleteContent(movement_group.getId()) builder.newContent( portal_type = 'Parent Explanation Movement Group', collect_order_group='delivery', int_index=len(delivery_movement_group_list)+1 ) user = uf.getUserById('test_invoice_user').__of__(uf) newSecurityManager(None, user) def test_01_TwoInvoicesFromTwoPackingList(self, quiet=quiet, run=RUN_ALL_TESTS): """ This test was created for the following bug: - an order is created and confirmed - the packing list is split - the 2 packing list are delivered (at different date) - 2 invoices are built, then we set the same date on both of them - the accounting rules are generated and put in only one invoice !!, so we have an invoice with twice the number of accounting rules and an invoice with no accounting rules. both invoices are wrong """ if not run: return if not quiet: self.logMessage('Two Invoices from Two Packing List') sequence_list = SequenceList() sequence_list.addSequenceString( self.TWO_PACKING_LIST_DEFAULT_SEQUENCE + """ stepSetReadyPackingList stepSetReadyNewPackingList stepTic stepStartPackingList stepStartNewPackingList stepTic stepInvoiceBuilderAlarm stepTic stepCheckTwoInvoices stepRemoveDateMovementGroupForAdvancedTransactionBuilder stepStartTwoInvoices stepTic stepCheckInvoicesAndTransactionsConsistency """) sequence_list.play(self, quiet=quiet) def test_02_InvoiceDeletePackingListLine(self, quiet=quiet, run=RUN_ALL_TESTS): """ Checks that deleting a Packing List Line still creates a correct Invoice """ if not run: return if not quiet: self.logMessage('Packing List Line Delete') sequence_list = SequenceList() for base_sequence in (self.PACKING_LIST_TWO_LINES_DEFAULT_SEQUENCE, ) : sequence_list.addSequenceString( base_sequence + """ stepDeletePackingListLine stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """) sequence_list.play(self, quiet=quiet) def test_03_InvoiceDecreaseQuantity(self, quiet=quiet, run=RUN_ALL_TESTS): """ Change the quantity of a Invoice Line, check that the invoice is divergent, then split and defer, and check everything is solved """ if not run: return if not quiet: self.logMessage('Invoice Decrease Qantity') sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepDecreaseInvoiceLineQuantity stepCheckInvoiceIsDivergent stepCheckInvoiceIsCalculating stepTic stepCheckInvoiceIsDiverged stepSplitAndDeferInvoice stepTic stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepCheckInvoiceSplitted stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """ self.playSequence(sequence, quiet=quiet) @newSimulationExpectedFailure def test_04_InvoiceChangeStartDateFail(self, quiet=quiet, run=RUN_ALL_TESTS): """ Change the start_date of a Invoice Line, check that the invoice is divergent, then accept decision, and check Packing list is divergent """ if not run: return if not quiet: self.logMessage('Invoice Change Sart Date') sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepChangeInvoiceStartDate stepCheckInvoiceIsDivergent stepCheckInvoiceIsCalculating stepTic stepCheckInvoiceIsDiverged stepUnifyStartDateWithDecisionInvoice stepTic stepCheckInvoiceNotSplitted stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepCheckPackingListIsDivergent """ self.playSequence(sequence, quiet=quiet) def test_05_AcceptDecisionOnPackingList(self, quiet=quiet, run=RUN_ALL_TESTS): """ - Increase or Decrease the quantity of a Packing List line - Accept Decision on Packing List - Packing List must not be divergent and use new quantity - Invoice must not be divergent and use new quantity """ if not run: return if not quiet: self.logMessage('InvoiceAcceptDecisionOnPackingList') end_sequence = \ """ stepSetContainerFullQuantity stepCheckPackingListIsCalculating stepTic stepCheckPackingListIsDiverged stepAcceptDecisionQuantity stepTic stepCheckPackingListIsSolved stepCheckPackingListNotSplitted stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepStopPackingList stepTic stepDeliverPackingList stepTic stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule stepStartInvoice stepTic stepStopInvoice stepTic stepDeliverInvoice stepTic stepCheckInvoiceNotSplitted stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """ mid_sequence_list = [""" stepCheckInvoicingRule stepDecreasePackingListLineQuantity """, """ stepCheckInvoicingRule stepIncreasePackingListLineQuantity """] sequence_list = SequenceList() for seq in mid_sequence_list: sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ seq + end_sequence sequence_list.addSequenceString(sequence) sequence_list.play(self, quiet=quiet) def test_06_AcceptDecisionOnPackingListAndInvoice(self, quiet=quiet, run=RUN_ALL_TESTS): """ - Increase or Decrease the quantity of a Packing List line - Accept Decision on Packing List - Packing List must not be divergent and use new quantity - Put old quantity on Invoice - Accept Decision on Invoice - Packing List must not be divergent and use new quantity - Invoice must not be divergent and use old quantity """ if not run: return if not quiet: self.logMessage('InvoiceAcceptDecisionOnPackingListAndInvoice') mid_sequence = \ """ stepSetContainerFullQuantity stepCheckPackingListIsCalculating stepTic stepCheckPackingListIsDiverged stepAcceptDecisionQuantity stepTic stepCheckPackingListIsSolved stepCheckPackingListNotSplitted stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepStopPackingList stepTic stepDeliverPackingList stepTic stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule """ end_sequence = \ """ stepCheckInvoiceIsDiverged stepAcceptDecisionQuantityInvoice stepTic stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepStartInvoice stepTic stepStopInvoice stepTic stepDeliverInvoice stepTic stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule stepCheckInvoiceNotSplitted stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """ mid_sequence_list = [(""" stepCheckInvoicingRule stepDecreasePackingListLineQuantity """, """ stepIncreaseInvoiceLineQuantity stepTic """), (""" stepCheckInvoicingRule stepIncreasePackingListLineQuantity """, """ stepDecreaseInvoiceLineQuantity stepTic """)] sequence_list = SequenceList() for seq1, seq2 in mid_sequence_list: sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ seq1 + mid_sequence + seq2 + end_sequence sequence_list.addSequenceString(sequence) sequence_list.play(self, quiet=quiet) def test_07_SplitAndDeferInvoice(self, quiet=quiet, run=RUN_ALL_TESTS): """ - Accept Order, Accept Packing List - Decrease quantity on Invoice - Split and defer Invoice - Accept Invoice - Accept splitted Invoice - Packing List must not be divergent and use old quantity - Invoice must not be divergent and use new quantity - splitted Invoice must not be divergent and use old - new quantity """ if not run: return if not quiet: self.logMessage('InvoiceSplitAndDeferInvoice') sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepStopPackingList stepTic stepDeliverPackingList stepTic stepCheckPackingListIsSolved stepCheckPackingListNotSplitted stepDecreaseInvoiceLineQuantity stepCheckInvoiceIsDivergent stepCheckInvoiceIsCalculating stepTic stepCheckInvoiceIsDiverged stepSplitAndDeferInvoice stepTic stepStartInvoice stepTic stepStopInvoice stepTic stepDeliverInvoice stepTic stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepCheckInvoiceSplitted stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule stepSwitchInvoices stepStartInvoice stepTic stepStopInvoice stepTic stepDeliverInvoice stepTic stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """ self.playSequence(sequence, quiet=quiet) def test_08_AcceptDecisionOnInvoice(self, quiet=quiet, run=RUN_ALL_TESTS): """ - Accept Order, Accept Packing List - Increase or Decrease quantity on Invoice - Accept Decision on Invoice - Accept Invoice - Packing List must not be divergent and use old quantity - Invoice must not be divergent and use new quantity """ if not run: return if not quiet: self.logMessage('InvoiceAcceptDecisionOnInvoice') mid_sequence = \ """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepCheckInvoiceTransactionRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepStopPackingList stepTic stepDeliverPackingList stepTic stepCheckPackingListIsSolved stepCheckPackingListNotSplitted """ end_sequence = \ """ stepCheckInvoiceIsDivergent stepCheckInvoiceIsCalculating stepTic stepCheckInvoiceIsDiverged stepAcceptDecisionQuantityInvoice stepTic stepStartInvoice stepTic stepStopInvoice stepTic stepDeliverInvoice stepTic stepCheckPackingListIsNotDivergent stepCheckPackingListIsSolved stepCheckInvoiceTransactionRule stepCheckInvoiceNotSplitted stepCheckInvoiceIsNotDivergent stepCheckInvoiceIsSolved stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency """ mid_sequence_list = [""" stepDecreaseInvoiceLineQuantity """, """ stepIncreaseInvoiceLineQuantity """] sequence_list = SequenceList() for seq in mid_sequence_list: sequence = self.PACKING_LIST_DEFAULT_SEQUENCE + \ mid_sequence + seq + end_sequence sequence_list.addSequenceString(sequence) sequence_list.play(self, quiet=quiet) def test_09_Reference(self, quiet=quiet, run=RUN_ALL_TESTS): if not run: return if not quiet: self.logMessage('test Reference') # A reference is set automatically on Sale Invoice Transaction supplier = self.portal.organisation_module.newContent( portal_type='Organisation', title='Supplier') client = self.portal.organisation_module.newContent( portal_type='Organisation', title='Client') currency = self.portal.currency_module.newContent( portal_type='Currency') invoice = self.portal.accounting_module.newContent( portal_type='Sale Invoice Transaction', start_date=DateTime(), price_currency_value=currency, resource_value=currency, source_section_value=supplier, destination_section_value=client) self.portal.portal_workflow.doActionFor(invoice, 'confirm_action') # We could generate a better reference here. self.assertEquals('1', invoice.getReference()) def test_10_ManuallyAddedMovements(self, quiet=quiet, run=RUN_ALL_TESTS): """ Checks that adding invoice lines and accounting lines to one invoice generates correct simulation """ if not run: return if not quiet: self.logMessage('Invoice with Manually Added Movements') sequence_list = SequenceList() sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency stepStartInvoice stepTic stepAddInvoiceTransactionLines stepTic stepCheckSimulationTrees """) sequence_list.play(self, quiet=quiet) def test_11_ManuallyAddedMovementsManyTransactions(self, quiet=quiet, run=RUN_ALL_TESTS): """ Checks that adding invoice lines and accounting lines generates correct simulation In this case checks what is happening, where movements are added in one transaction and edited in another """ if not run: return if not quiet: self.logMessage('Invoice with Manually Added Movements in separate transactions') sequence_list = SequenceList() sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepRebuildAndCheckNothingIsCreated stepCheckInvoicesConsistency stepTic stepCheckInvoiceIsSolved stepStartInvoice stepTic stepAddInvoiceLinesManyTransactions stepTic stepCheckSimulationTrees """) sequence_list.play(self, quiet=quiet) def test_12_compareInvoiceAndPackingList(self, quiet=quiet, run=RUN_ALL_TESTS): """ Checks that a Simple Invoice is created from a Packing List """ if not run: return if not quiet: self.logMessage('Compare Simple Invoice and Packing List') sequence_list = SequenceList() sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepSetReadyPackingList stepTic stepStartPackingList stepCheckInvoicingRule stepTic stepInvoiceBuilderAlarm stepTic stepCheckInvoiceBuilding stepCheckInvoicesConsistency stepCheckPackingListInvoice """) sequence_list.play(self, quiet=quiet) @newSimulationExpectedFailure def test_13_acceptQuantityDivergenceOnInvoiceWithStartedPackingList( self, quiet=quiet, run=RUN_ALL_TESTS): if not run: return if not quiet: self.logMessage('Accept Quantity Divergence on Invoice') sequence_list = SequenceList() sequence = sequence_list.addSequenceString( self.PACKING_LIST_DEFAULT_SEQUENCE + """ stepSetReadyPackingList stepTic stepStartPackingList stepTic stepInvoiceBuilderAlarm stepTic stepChangeQuantityDoubledOnInvoice stepTic stepCheckDivergedQuantityOnInvoice stepAcceptDecisionOnInvoice stepTic stepCheckDivergenceOnInvoice stepCheckDivergedOnPackingList stepCheckDivergedQuantityOnPackingList stepAdoptPrevisionOnPackingList stepTic """) sequence_list.play(self, quiet=quiet) packing_list = sequence.get('packing_list') invoice = packing_list.getCausalityRelatedValue(portal_type=self.invoice_portal_type) self.assertEquals('solved', packing_list.getCausalityState()) self.assertEquals('solved', invoice.getCausalityState()) class TestAdvancedPurchaseInvoice(TestAdvancedInvoice): """Tests for purchase invoice. """ resource_portal_type = 'Product' order_portal_type = 'Purchase Order' order_line_portal_type = 'Purchase Order Line' order_cell_portal_type = 'Purchase Order Cell' packing_list_portal_type = 'Purchase Packing List' packing_list_line_portal_type = 'Purchase Packing List Line' packing_list_cell_portal_type = 'Purchase Packing List Cell' invoice_portal_type = 'Purchase Invoice' invoice_transaction_line_portal_type = 'Purchase Invoice Transaction Line' invoice_line_portal_type = 'Invoice Line' invoice_cell_portal_type = 'Invoice Cell' invoice_module_name = 'sale_invoice_module' login = TestAdvancedInvoice.login PACKING_LIST_DEFAULT_SEQUENCE = \ """ stepCreateEntities stepCreateCurrency stepCreateSaleInvoiceTransactionRule stepCreateOrder stepSetOrderProfile stepSetOrderPriceCurrency stepCreateNotVariatedResource stepTic stepCreateOrderLine stepSetOrderLineResource stepSetOrderLineDefaultValues stepOrderOrder stepTic stepCheckDeliveryBuilding stepConfirmOrder stepTic stepPackingListBuilderAlarm stepTic stepCheckOrderRule stepCheckOrderSimulation stepCheckDeliveryBuilding stepTic """ INVOICE_DEFAULT_SEQUENCE = PACKING_LIST_DEFAULT_SEQUENCE + \ """ stepReceivePackingList stepTic stepInvoiceBuilderAlarm stepTic stepStartRelatedInvoice stepTic """ def stepReceivePackingList(self, sequence=None, sequence_list=None, **kw): packing_list = sequence.get('packing_list') packing_list.setReady() packing_list.start() packing_list.stop() self.assertEquals('stopped', packing_list.getSimulationState()) self.commit() class TestWorkflow(SecurityTestCase): def getBusinessTemplateList(self): return ('erp5_core', 'erp5_base', 'erp5_pdm', 'erp5_trade', 'erp5_accounting', 'erp5_invoicing', 'erp5_advanced_invoicing') def afterSetUp(self): skin_folder = self.portal.portal_skins.custom security_mapping_script_id = 'ERP5Type_getSecurityMapping' if getattr(skin_folder, security_mapping_script_id, None) is None: skin_folder.manage_addProduct['PythonScripts'].manage_addPythonScript(id=security_mapping_script_id) skin_folder[security_mapping_script_id].ZPythonScript_edit('', 'return (("ERP5Type_getSecurityCategoryFromAssignment", ["function"]),)') role_list = [ {'role_name_list': ('Assignee',), 'role_category_list': ('function/assignee',)}, {'role_name_list': ('Assignor',), 'role_category_list': ('function/assignor',)}, {'role_name_list': ('Auditor',), 'role_category_list': ('function/auditor',)}, {'role_name_list': ('Author',), 'role_category_list': ('function/author',)}, {'role_name_list': ('Associate',), 'role_category_list': ('function/associate',)}, {'role_name_list': ('Manager',), 'role_category_list': ('function/manager',)}, ] sale_invoice_type = self.portal.portal_types['Sale Invoice'] if len(sale_invoice_type.contentIds(filter={'portal_type': 'Role Infomation'})) == 0: for role in role_list: type_document = sale_invoice_type.newContent(portal_type='Role Information') type_document.edit(**role) self.tic() for role in role_list: for role_category in role['role_category_list']: category_id_list = role_category.split('/')[1:] node = self.portal.portal_categories.function while category_id_list: category_id = category_id_list.pop(0) if node.get(category_id, None) is None: node = node.newContent(id=category_id, portal_type='Category') else: node = node.get(category_id) self.tic() person_list = [ {'id': 'other'}, {'id': 'assignee', 'assignment_list': ({'function': 'assignee'},)}, {'id': 'assignor', 'assignment_list': ({'function': 'assignor'},)}, {'id': 'associate', 'assignment_list': ({'function': 'associate'},)}, {'id': 'auditor', 'assignment_list': ({'function': 'auditor'},)}, {'id': 'author', 'assignment_list': ({'function': 'author'},)}, {'id': 'manager', 'assignment_list': ({'function': 'manager'},)}, ] person_module = self.portal.person_module for person in person_list: if person_module.get(person['id'], None) is None: person_document = person_module.newContent(id=person['id'], portal_type='Person') person_document.edit(reference=person['id']) for assignment in person.get('assignment_list', []): assignment_document = person_document.newContent(portal_type='Assignment') assignment_document.edit(function=assignment['function']) self.portal.portal_workflow.doActionFor(assignment_document, 'open_action') self.tic() setattr(self, person['id'], person_document) def test_autoplanned(self): sale_invoice = self.portal.getDefaultModule('Sale Invoice').newContent(portal_type='Sale Invoice') self.assertEquals(sale_invoice.getSimulationState(), 'draft') sale_invoice.autoPlan() self.assertEquals(sale_invoice.getSimulationState(), 'auto_planned') # other as anonymous username = self.other.getReference() self.failIfUserCanAccessDocument(username, sale_invoice) self.failIfUserCanAddDocument(username, sale_invoice) self.failIfUserCanDeleteDocument(username, sale_invoice) self.failIfUserCanModifyDocument(username, sale_invoice) self.failIfUserCanViewDocument(username, sale_invoice) # assignee username = self.assignee.getReference() self.assertUserCanAccessDocument(username, sale_invoice) self.assertUserCanAddDocument(username, sale_invoice) self.assertUserCanDeleteDocument(username, sale_invoice) self.assertUserCanModifyDocument(username, sale_invoice) self.assertUserCanViewDocument(username, sale_invoice) # assignor username = self.assignor.getReference() self.assertUserCanAccessDocument(username, sale_invoice) self.assertUserCanAddDocument(username, sale_invoice) self.assertUserCanDeleteDocument(username, sale_invoice) self.assertUserCanModifyDocument(username, sale_invoice) self.assertUserCanViewDocument(username, sale_invoice) # associate username = self.associate.getReference() self.assertUserCanAccessDocument(username, sale_invoice) self.assertUserCanAddDocument(username, sale_invoice) self.assertUserCanDeleteDocument(username, sale_invoice) self.assertUserCanModifyDocument(username, sale_invoice) self.assertUserCanViewDocument(username, sale_invoice) # auditor username = self.auditor.getReference() self.assertUserCanAccessDocument(username, sale_invoice) self.failIfUserCanAddDocument(username, sale_invoice) self.failIfUserCanDeleteDocument(username, sale_invoice) self.failIfUserCanModifyDocument(username, sale_invoice) self.assertUserCanViewDocument(username, sale_invoice) # author username = self.author.getReference() self.failIfUserCanAccessDocument(username, sale_invoice) self.failIfUserCanAddDocument(username, sale_invoice) self.failIfUserCanDeleteDocument(username, sale_invoice) self.failIfUserCanModifyDocument(username, sale_invoice) self.failIfUserCanViewDocument(username, sale_invoice) # manager username = self.manager.getReference() self.assertUserCanAccessDocument(username, sale_invoice) self.assertUserCanAddDocument(username, sale_invoice) self.assertUserCanDeleteDocument(username, sale_invoice) self.assertUserCanModifyDocument(username, sale_invoice) self.assertUserCanViewDocument(username, sale_invoice) portal_workflow = self.portal.portal_workflow action_ids = [action['id'] for action in portal_workflow.listActionInfos(object=sale_invoice) if action['category'] == 'workflow'] self.assertSameSet(('confirm_action', 'plan_action',), action_ids) import unittest def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestAdvancedSaleInvoice)) suite.addTest(unittest.makeSuite(TestAdvancedPurchaseInvoice)) suite.addTest(unittest.makeSuite(TestWorkflow)) return suite