##############################################################################
#
# Copyright (c) 2008 Nexedi SA and Contributors. All Rights Reserved.
#          Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################

import unittest

import transaction
from DateTime import DateTime

from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase

class TradeConditionTestCase(ERP5TypeTestCase):
  """Tests for Trade Conditions and Tax
  """
  def getBusinessTemplateList(self):
    return ('erp5_base', 'erp5_pdm', 'erp5_trade', 'erp5_accounting',
            'erp5_invoicing', 'erp5_tax_resource', 'erp5_discount_resource',
            'erp5_legacy_tax_system', 'erp5_simplified_invoicing',)

  size_category_list = ['small', 'big']
  def afterSetUp(self):
    self.validateRules()
    for category_id in self.size_category_list:
      self.portal.portal_categories.size.newContent(id=category_id,
                                                    title=category_id)
    self.base_amount = self.portal.portal_categories.base_amount
    self.tax = self.portal.tax_module.newContent(
                                    portal_type='Tax',
                                    title='Tax')
    self.discount = self.portal.discount_module.newContent(
                                    portal_type='Discount',
                                    title='Discount')
    self.client = self.portal.organisation_module.newContent(
                                    portal_type='Organisation',
                                    title='Client')
    self.vendor = self.portal.organisation_module.newContent(
                                    portal_type='Organisation',
                                    title='Vendor')
    self.resource = self.portal.product_module.newContent(
                                    portal_type='Product',
                                    title='Resource')
    self.currency = self.portal.currency_module.newContent(
                                    portal_type='Currency',
                                    title='Currency')
    self.trade_condition_module = self.portal.getDefaultModule(
                                      self.trade_condition_type)
    self.trade_condition = self.trade_condition_module.newContent(
                            portal_type=self.trade_condition_type,
                            title='Trade Condition')
    self.order_module = self.portal.getDefaultModule(
                                      self.order_type)
    self.order = self.order_module.newContent(
                            portal_type=self.order_type,
                            created_by_builder=1,
                            title='Order')

  def beforeTearDown(self):
    transaction.abort()
    for module in (self.portal.tax_module,
                   self.portal.organisation_module,
                   self.portal.currency_module,
                   self.portal.product_module,
                   self.portal.accounting_module,
                   self.portal.account_module,
                   self.portal.portal_simulation,
                   self.trade_condition_module,
                   self.order_module,
                   self.portal.portal_categories.base_amount,
                   self.portal.portal_categories.size,
      ):
      module.manage_delObjects(list(module.objectIds()))
    transaction.commit()
    self.tic()


class AccountingBuildTestCase(TradeConditionTestCase):
  """Same as TradeConditionTestCase, but with a rule to generate
  accounting.
  """
  def afterSetUp(self):
    TradeConditionTestCase.afterSetUp(self)
    self.receivable_account = self.portal.account_module.newContent(
                                    id='receivable',
                                    title='Receivable',
                                    account_type='asset/receivable')
    self.payable_account = self.portal.account_module.newContent(
                                    id='payable',
                                    title='Payable',
                                    account_type='liability/payable')
    self.income_account = self.portal.account_module.newContent(
                                    id='income',
                                    title='Income',
                                    account_type='income')
    self.expense_account = self.portal.account_module.newContent(
                                    id='expense',
                                    title='Expense',
                                    account_type='expense')
    self.collected_tax_account = self.portal.account_module.newContent(
                                    id='collected_tax',
                                    title='Collected Tax',
                                    account_type='liability/payable/collected_vat')
    self.refundable_tax_account = self.portal.account_module.newContent(
                                    id='refundable_tax',
                                    title='Refundable Tax',
                                    account_type='asset/receivable/refundable_vat')

    for account in self.portal.account_module.contentValues():
      self.assertNotEquals(account.getAccountTypeValue(), None)
      account.validate()
    
    itr = self.portal.portal_rules.newContent(
                        portal_type='Invoice Transaction Simulation Rule',
                        reference='default_invoice_transaction_rule',
                        id='test_invoice_transaction_rule',
                        title='Transaction Rule',
                        test_method_id='SimulationMovement_testInvoiceTransactionSimulationRule',
                        version=100)
    predicate = itr.newContent(portal_type='Predicate',)
    predicate.edit(
            string_index='resource_type',
            title='Resource Product',
            int_index=1,
            test_method_id='SimulationMovement_isDeliveryMovement' )
    predicate = itr.newContent(portal_type='Predicate')
    predicate.edit(
            string_index='resource_type',
            title='Resource Tax',
            int_index=2,
            test_method_id='SimulationMovement_isTaxMovement' )
    transaction.commit()
    self.tic()
    accounting_rule_cell_list = itr.contentValues(
                            portal_type='Accounting Rule Cell')
    self.assertEquals(2, len(accounting_rule_cell_list))
    product_rule_cell = itr._getOb("movement_0")
    self.assertEquals(product_rule_cell.getTitle(), 'Resource Product')
    product_rule_cell.newContent(
                         portal_type='Accounting Transaction Line',
                         source_value=self.receivable_account,
                         destination_value=self.payable_account,
                         quantity=-1)
    product_rule_cell.newContent(
                         portal_type='Accounting Transaction Line',
                         source_value=self.income_account,
                         destination_value=self.expense_account,
                         quantity=1)
    
    tax_rule_cell = itr._getOb("movement_1")
    self.assertEquals(tax_rule_cell.getTitle(), 'Resource Tax')
    tax_rule_cell.newContent(
                         portal_type='Accounting Transaction Line',
                         source_value=self.receivable_account,
                         destination_value=self.payable_account,
                         quantity=-1)
    tax_rule_cell.newContent(
                         portal_type='Accounting Transaction Line',
                         source_value=self.collected_tax_account,
                         destination_value=self.refundable_tax_account,
                         quantity=1)
    itr.validate()
    transaction.commit()
    self.tic()

  def beforeTearDown(self):
    TradeConditionTestCase.beforeTearDown(self)
    self.portal.portal_rules.manage_delObjects('test_invoice_transaction_rule')
    transaction.commit()
    self.tic()

class TestApplyTradeCondition(TradeConditionTestCase):
  """Tests Applying Trade Conditions
  """
  def test_apply_trade_condition_set_categories(self):
    self.trade_condition.setSourceSectionValue(self.vendor)
    self.trade_condition.setDestinationSectionValue(self.client)
    self.trade_condition.setSourceValue(self.vendor)
    self.trade_condition.setDestinationValue(self.client)
    self.trade_condition.setPriceCurrencyValue(self.currency)
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    self.assertEquals(self.vendor, self.order.getSourceSectionValue())
    self.assertEquals(self.vendor, self.order.getSourceValue())
    self.assertEquals(self.client, self.order.getDestinationSectionValue())
    self.assertEquals(self.client, self.order.getDestinationValue())
    self.assertEquals(self.currency, self.order.getPriceCurrencyValue())

  def test_apply_trade_condition_keep_categories(self):
    # source section & source are set on the order, not on the TC
    self.order.setSourceSectionValue(self.vendor)
    self.order.setSourceValue(self.vendor)

    self.trade_condition.setSourceSectionValue(None)
    self.trade_condition.setSourceValue(None)
    self.trade_condition.setDestinationSectionValue(self.client)
    self.trade_condition.setDestinationValue(self.client)
    self.trade_condition.setPriceCurrencyValue(self.currency)
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    # Applying the TC keeps values on the order
    self.assertEquals(self.vendor, self.order.getSourceSectionValue())
    self.assertEquals(self.vendor, self.order.getSourceValue())
    self.assertEquals(self.client, self.order.getDestinationSectionValue())
    self.assertEquals(self.client, self.order.getDestinationValue())
    self.assertEquals(self.currency, self.order.getPriceCurrencyValue())

  def test_apply_trade_condition_set_categories_with_hierarchy(self):
    trade_condition_source = self.trade_condition_module.newContent(
                            portal_type=self.trade_condition.getPortalType(),
                            title='Trade Condition Source',
                            source_value=self.vendor,
                            source_section_value=self.vendor)
    trade_condition_dest = self.trade_condition_module.newContent(
                            portal_type=self.trade_condition.getPortalType(),
                            title='Trade Condition Destination',
                            destination_value=self.client,
                            destination_section_value=self.client,
                            price_currency_value=self.currency,
                            # also set a source, it should not be used
                            source_value=self.client)
    self.trade_condition.setSpecialiseValueList(
        (trade_condition_source, trade_condition_dest))

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    self.assertEquals(self.vendor, self.order.getSourceSectionValue())
    self.assertEquals(self.vendor, self.order.getSourceValue())
    self.assertEquals(self.client, self.order.getDestinationSectionValue())
    self.assertEquals(self.client, self.order.getDestinationValue())
    self.assertEquals(self.currency, self.order.getPriceCurrencyValue())

  def test_apply_trade_condition_copy_subobjects(self):
    self.trade_condition.setPaymentConditionTradeDate('custom')
    self.trade_condition.setPaymentConditionPaymentDate(DateTime(2001, 01, 01))
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    self.assertEquals('custom', self.order.getPaymentConditionTradeDate())
    self.assertEquals(DateTime(2001, 01, 01),
                      self.order.getPaymentConditionPaymentDate())

  def test_apply_twice_trade_condition_copy_subobjects(self):
    self.trade_condition.setPaymentConditionTradeDate('custom')
    self.trade_condition.setPaymentConditionPaymentDate(DateTime(2001, 01, 01))
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    self.assertEquals(1, len(self.order.contentValues(
                                portal_type='Payment Condition')))
    self.assertEquals('custom', self.order.getPaymentConditionTradeDate())
    self.assertEquals(DateTime(2001, 01, 01),
                      self.order.getPaymentConditionPaymentDate())
    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    self.assertEquals(1, len(self.order.contentValues(
                                portal_type='Payment Condition')))

  def test_apply_trade_condition_copy_subobjects_with_hierarchy(self):
    other_trade_condition = self.trade_condition_module.newContent(
                            portal_type=self.trade_condition.getPortalType(),
                            title='Other Trade Condition')
    other_trade_condition.setPaymentConditionTradeDate('custom')
    other_trade_condition.setPaymentConditionPaymentDate(
                                              DateTime(2001, 01, 01))

    self.trade_condition.setSpecialiseValue(other_trade_condition)
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    self.assertEquals('custom', self.order.getPaymentConditionTradeDate())
    self.assertEquals(DateTime(2001, 01, 01),
                      self.order.getPaymentConditionPaymentDate())

  def test_apply_trade_condition_twice_update_order(self):
    self.trade_condition.setSourceSectionValue(self.vendor)
    self.trade_condition.setDestinationSectionValue(self.client)
    self.trade_condition.setSourceValue(self.vendor)
    self.trade_condition.setDestinationValue(self.client)
    self.trade_condition.setPriceCurrencyValue(self.currency)
    self.trade_condition.setPaymentConditionTradeDate('custom')
    self.trade_condition.setPaymentConditionPaymentDate(DateTime(2001, 01, 01))
    self.order.setSpecialiseValue(self.trade_condition)

    self.order.Order_applyTradeCondition(self.trade_condition, force=1)
    
    self.assertEquals(self.vendor, self.order.getSourceSectionValue())
    self.assertEquals(self.vendor, self.order.getSourceValue())
    self.assertEquals(self.client, self.order.getDestinationSectionValue())
    self.assertEquals(self.client, self.order.getDestinationValue())
    self.assertEquals(self.currency, self.order.getPriceCurrencyValue())
    self.assertEquals('custom', self.order.getPaymentConditionTradeDate())
    self.assertEquals(DateTime(2001, 01, 01),
                      self.order.getPaymentConditionPaymentDate())

    new_vendor = self.portal.organisation_module.newContent(
                    portal_type='Organisation',
                    title='New vendor')
    new_trade_condition = self.trade_condition_module.newContent(
                    portal_type=self.trade_condition_type,
                    source_section_value=new_vendor,
                    payment_condition_trade_date='custom',
                    payment_condition_payment_date=DateTime(2002, 2, 2))

    self.order.Order_applyTradeCondition(new_trade_condition, force=1)
    self.assertEquals(new_vendor, self.order.getSourceSectionValue())
    self.assertEquals(self.vendor, self.order.getSourceValue())
    self.assertEquals(self.client, self.order.getDestinationSectionValue())
    self.assertEquals(self.client, self.order.getDestinationValue())
    self.assertEquals(self.currency, self.order.getPriceCurrencyValue())
    self.assertEquals('custom', self.order.getPaymentConditionTradeDate())
    self.assertEquals(DateTime(2002, 02, 02),
                      self.order.getPaymentConditionPaymentDate())


  def test_tax_model_line_consistency(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    tax_model_line = self.trade_condition.newContent(
                  portal_type='Tax Model Line',
                  base_application_value=base_1,
                  float_index=1,
                  efficiency=0.2,
                  resource_value=self.tax)
    self.assertEquals([], tax_model_line.checkConsistency())
    self.assertEquals([], self.trade_condition.checkConsistency())
  
  def test_discount_model_line_consistency(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    discount_model_line = self.trade_condition.newContent(
                  portal_type='Discount Model Line',
                  base_application_value=base_1,
                  float_index=1,
                  efficiency=0.2,
                  resource_value=self.discount)
    self.assertEquals([], discount_model_line.checkConsistency())
    self.assertEquals([], self.trade_condition.checkConsistency())

  def test_view_tax_model_line(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    tax_model_line = self.trade_condition.newContent(
                  portal_type='Tax Model Line',
                  base_application_value=base_1,
                  float_index=1,
                  efficiency=0.2,
                  resource_value=self.tax)
    # TODO: fail if a field has an error
    tax_model_line.view()
    self.trade_condition.TradeCondition_viewTax()

  def test_view_discount_model_line(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    discount_model_line = self.trade_condition.newContent(
                  portal_type='Discount Model Line',
                  base_application_value=base_1,
                  float_index=1,
                  efficiency=0.2,
                  resource_value=self.discount)
    # TODO: fail if a field has an error
    discount_model_line.view()
    self.trade_condition.TradeCondition_viewDiscount()

  def test_tax_line_consistency(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    tax_line = self.order.newContent(
                        portal_type='Tax Line',
                        resource_value=self.tax,
                        base_application_value=base_1,
                        quantity=0,
                        efficiency=5.5)
    self.assertEquals([], tax_line.checkConsistency())

  def test_view_tax_line(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    tax_line = self.order.newContent(
                        portal_type='Tax Line',
                        resource_value=self.tax,
                        base_application_value=base_1,
                        quantity=0,
                        efficiency=5.5)
    # TODO: fail if a field has an error
    tax_line.view()
    self.order.Delivery_viewTax()

  def test_discount_line_consistency(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    discount_line = self.order.newContent(
                        portal_type='Discount Line',
                        resource_value=self.discount,
                        base_application_value=base_1,
                        quantity=0,
                        efficiency=5.5)
    self.assertEquals([], discount_line.checkConsistency())

  def test_view_discount_line(self):
    base_1 = self.base_amount.newContent(
                          portal_type='Category',
                          title='Base 1')
    discount_line = self.order.newContent(
                        portal_type='Discount Line',
                        resource_value=self.discount,
                        base_application_value=base_1,
                        quantity=0,
                        efficiency=5.5)
    # TODO: fail if a field has an error
    discount_line.view()
    self.order.Delivery_viewDiscount()


class TestTradeConditionSupplyLine(TradeConditionTestCase):
  """A trade condition can contain supply line and those supply lines are used
  in priority, for example to calculate the price
  """
  def test_category_acquisition(self):
    self.trade_condition.setSourceValue(self.vendor)
    self.trade_condition.setSourceSectionValue(self.vendor)
    self.trade_condition.setDestinationValue(self.client)
    self.trade_condition.setDestinationSectionValue(self.client)
    self.trade_condition.setPriceCurrencyValue(self.currency)

    supply_line = self.trade_condition.newContent(
                                    portal_type=self.supply_line_type)

    self.assertEquals(self.vendor, supply_line.getSourceValue())
    self.assertEquals(self.vendor, supply_line.getSourceSectionValue())
    self.assertEquals(self.client, supply_line.getDestinationValue())
    self.assertEquals(self.client, supply_line.getDestinationSectionValue())
    self.assertEquals(self.currency, supply_line.getPriceCurrencyValue())

  def test_movement_price_assignment(self):
    # supply line from the trade condition apply to the movements in order
    # where this trade condition is used
    supply_line = self.trade_condition.newContent(
                                    portal_type=self.supply_line_type,
                                    resource_value=self.resource,
                                    base_price=123)

    self.order.setSpecialiseValue(self.trade_condition)
    transaction.commit()
    self.tic()

    line = self.order.newContent(portal_type=self.order_line_type,
                                 resource_value=self.resource,
                                 quantity=1)
    self.assertEquals(123, line.getPrice())

  def test_supply_line_priority(self):
    # supply lines from related trade condition should have priority over
    # supply lines from supply modules
    other_supply = self.portal.getDefaultModule(self.supply_type
                             ).newContent(portal_type=self.supply_type,
                                          resource_value=self.resource,
                                          source_section_value=self.vendor,
                                          destination_section_value=self.client)
    other_supply_line = other_supply.newContent(
                                    portal_type=self.supply_line_type,
                                    base_price=1)
    supply_line = self.trade_condition.newContent(
                                    portal_type=self.supply_line_type,
                                    resource_value=self.resource,
                                    base_price=2)
    self.order.setSpecialiseValue(self.trade_condition)
    self.order.setSourceSectionValue(self.vendor)
    self.order.setDestinationSectionValue(self.vendor)
    transaction.commit()
    self.tic()

    line = self.order.newContent(portal_type=self.order_line_type,
                                 resource_value=self.resource,
                                 quantity=1)
    # using the supply line inside trade condition
    self.assertEquals(2, line.getPrice())

  # TODO: move to testSupplyLine ! (which does not exist yet)
  def test_supply_line_section(self):
    # if a supply lines defines a section, it has priority over supply lines
    # not defining sections
    other_entity = self.portal.organisation_module.newContent(
                                      portal_type='Organisation',
                                      title='Other')
    supply = self.portal.getDefaultModule(self.supply_type
                             ).newContent(portal_type=self.supply_type,
                                          resource_value=self.resource,)
    supply_line = supply.newContent(
                                    portal_type=self.supply_line_type,
                                    base_price=1)

    other_supply = self.portal.getDefaultModule(self.supply_type
                             ).newContent(portal_type=self.supply_type,
                                          resource_value=self.resource,
                                          destination_section_value=self.client,
                                          source_section_value=self.vendor)
    other_supply_line = other_supply.newContent(
                                    portal_type=self.supply_line_type,
                                    base_price=2)

    self.order.setSourceSectionValue(self.vendor)
    self.order.setDestinationSectionValue(self.client)
    transaction.commit()
    self.tic()

    line = self.order.newContent(portal_type=self.order_line_type,
                                 resource_value=self.resource,
                                 quantity=1)
    # using the supply line with section defined
    self.assertEquals(2, line.getPrice())


class TestEffectiveTradeCondition(TradeConditionTestCase):
  """Tests for getEffectiveModel
  
  XXX open questions:
   - should getEffectiveModel take validation state into account ? if yes, how
     to do it in generic/customizable way ?
   - would getEffectiveModel(at_date) be enough ?
  """
  def test_getEffectiveModel(self):
    # getEffectiveModel returns the model with highest version
    reference = self.id()
    self.trade_condition.setReference(reference)
    self.trade_condition.setVersion('001')
    self.trade_condition.setEffectiveDate('2009/01/01')
    self.trade_condition.setExpirationDate('2009/12/31')
    other_trade_condition = self.trade_condition_module.newContent(
                            portal_type=self.trade_condition.getPortalType(),
                            title='Other Trade Condition',
                            reference=reference,
                            effective_date='2009/01/01',
                            expiration_date='2009/12/31',
                            version='002')
    transaction.commit()
    self.tic()
    
    self.assertEquals(other_trade_condition,
        self.trade_condition.getEffectiveModel(
                    start_date=DateTime('2009/06/01'),
                    stop_date=DateTime('2009/06/01')))

    # outside date range: should it raise or return nothing ?
    self.assertRaises(Exception,
        self.trade_condition.getEffectiveModel,
                    start_date=DateTime('2008/06/01'),
                    stop_date=DateTime('2008/06/01'))
    self.assertRaises(Exception,
        self.trade_condition.getEffectiveModel,
                    start_date=DateTime('2010/06/01'),
                    stop_date=DateTime('2010/06/01'))

  def test_getEffectiveModel_return_self(self):
    # getEffectiveModel returns the trade condition if it's effective
    self.trade_condition.setReference(self.id())
    self.trade_condition.setEffectiveDate('2009/01/01')
    self.trade_condition.setExpirationDate('2009/12/31')
    transaction.commit()
    self.tic()
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel(
                    start_date=DateTime('2009/06/01'),
                    stop_date=DateTime('2009/06/01')))

  def test_getEffectiveModel_without_dates(self):
    # a trade condition without effective / expiration date is effective
    self.trade_condition.setReference(self.id())
    self.trade_condition.setEffectiveDate(None)
    self.trade_condition.setExpirationDate(None)
    transaction.commit()
    self.tic()
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel(
                    start_date=DateTime('2009/06/01'),
                    stop_date=DateTime('2009/06/01')))

    self.trade_condition.setEffectiveDate(None)
    self.trade_condition.setExpirationDate('2009/12/31')
    transaction.commit()
    self.tic()
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel(
                    start_date=DateTime('2009/06/01'),
                    stop_date=DateTime('2009/06/01')))

    self.trade_condition.setEffectiveDate('2009/01/01')
    self.trade_condition.setExpirationDate(None)
    transaction.commit()
    self.tic()
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel(
                    start_date=DateTime('2009/06/01'),
                    stop_date=DateTime('2009/06/01')))

    
  def test_getEffectiveModel_return_self_when_no_reference(self):
    # when no reference defined, getEffectiveModel returns the trade condition.
    self.trade_condition.setReference(None)
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel())
    self.assertEquals(self.trade_condition,
        self.trade_condition.getEffectiveModel(start_date=DateTime(),
                                               stop_date=DateTime()))



class TestWithSaleOrder:
  order_type = 'Sale Order'
  order_line_type = 'Sale Order Line'
  order_cell_type = 'Sale Order Cell'
  trade_condition_type = 'Sale Trade Condition'
  supply_type = 'Sale Supply'
  supply_line_type = 'Sale Supply Line'

class TestWithPurchaseOrder:
  order_type = 'Purchase Order'
  order_line_type = 'Purchase Order Line'
  order_cell_type = 'Purchase Order Cell'
  trade_condition_type = 'Purchase Trade Condition'
  supply_type = 'Purchase Supply'
  supply_line_type = 'Purchase Supply Line'

class TestWithSaleInvoice:
  order_type = 'Sale Invoice Transaction'
  order_line_type = 'Invoice Line'
  order_cell_type = 'Invoice Cell'
  trade_condition_type = 'Sale Trade Condition'
  supply_type = 'Sale Supply'
  supply_line_type = 'Sale Supply Line'

class TestWithPurchaseInvoice:
  order_type = 'Purchase Invoice Transaction'
  order_line_type = 'Invoice Line'
  order_cell_type = 'Invoice Cell'
  trade_condition_type = 'Purchase Trade Condition'
  supply_type = 'Purchase Supply'
  supply_line_type = 'Purchase Supply Line'


class TestApplyTradeConditionSaleOrder(
      TestApplyTradeCondition, TestWithSaleOrder):
  pass
class TestApplyTradeConditionPurchaseOrder(
      TestApplyTradeCondition, TestWithPurchaseOrder):
  pass

class TestTradeConditionSupplyLineSaleOrder(
      TestTradeConditionSupplyLine, TestWithSaleOrder):
  pass
class TestTradeConditionSupplyLinePurchaseOrder(
      TestTradeConditionSupplyLine, TestWithPurchaseOrder):
  pass
class TestTradeConditionSupplyLineSaleInvoice(
      TestTradeConditionSupplyLine, TestWithSaleInvoice):
  pass
class TestTradeConditionSupplyLinePurchaseInvoice(
      TestTradeConditionSupplyLine, TestWithPurchaseInvoice):
  pass

class TestEffectiveSaleTradeCondition(
            TestEffectiveTradeCondition,
            TestWithSaleOrder):
  pass
class TestEffectivePurchaseTradeCondition(
            TestEffectiveTradeCondition,
            TestWithPurchaseOrder):
  pass

def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestApplyTradeConditionSaleOrder))
  suite.addTest(unittest.makeSuite(TestApplyTradeConditionPurchaseOrder))
  suite.addTest(unittest.makeSuite(TestTradeConditionSupplyLineSaleOrder))
  suite.addTest(unittest.makeSuite(TestTradeConditionSupplyLinePurchaseOrder))
  suite.addTest(unittest.makeSuite(TestTradeConditionSupplyLineSaleInvoice))
  suite.addTest(unittest.makeSuite(TestTradeConditionSupplyLinePurchaseInvoice))
  suite.addTest(unittest.makeSuite(TestEffectiveSaleTradeCondition))
  suite.addTest(unittest.makeSuite(TestEffectivePurchaseTradeCondition))
  return suite