Commit 211407a7 authored by Jérome Perrin's avatar Jérome Perrin

Add documents, rules and test for new tax system.

Update some rules to expand base_contribution in simulation, and add corresponding movement groups.
Add a new movement group 'tax_movement'
TradeCondition now subclass Delivery, because it contains movements (Tax Model Line)


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@20467 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 8ff90971
......@@ -132,6 +132,8 @@ class DeliveryRule(Rule):
quantity_unit=deliv_mvt.getQuantityUnit(),
price=deliv_mvt.getPrice(),
price_currency=deliv_mvt.getPriceCurrency(),
base_contribution_list=deliv_mvt.getBaseContributionList(),
base_application_list=deliv_mvt.getBaseApplicationList(),
)
elif sim_mvt in existing_movement_list:
if sim_mvt not in immutable_movement_list:
......@@ -158,6 +160,8 @@ class DeliveryRule(Rule):
quantity_unit=deliv_mvt.getQuantityUnit(),
price=deliv_mvt.getPrice(),
price_currency=deliv_mvt.getPriceCurrency(),
base_contribution_list=deliv_mvt.getBaseContributionList(),
base_application_list=deliv_mvt.getBaseApplicationList(),
force_update=1)
else:
# modification disallowed, must compensate
......
......@@ -97,6 +97,7 @@ class InvoicingRule(Rule):
'resource': context_movement.getResource(),
'variation_category_list': context_movement.getVariationCategoryList(),
'variation_property_dict': context_movement.getVariationPropertyDict(),
'base_contribution_list': context_movement.getBaseContributionList(),
'aggregate_list': context_movement.getAggregateList(),
'quantity': context_movement.getCorrectedQuantity(),
'quantity_unit': context_movement.getQuantityUnit(),
......
......@@ -106,6 +106,9 @@ class OrderRule(DeliveryRule):
order_movement_dict[order_movement.getPath()] = s_m
# Create or modify movements
for movement in order_movement_list:
# FIXME: to be improved later
if movement.getPortalType() not in ('Tax Line', ):
continue
related_order = order_movement_dict.get(movement.getPath(), None)
if related_order is None:
related_order = movement.getOrderRelatedValue()
......@@ -181,6 +184,7 @@ class OrderRule(DeliveryRule):
'resource',
'variation_category_list',
'variation_property_dict',
'base_contribution_list',
'aggregate_list',
'price',
'price_currency',
......
##############################################################################
#
# 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.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.DeliveryLine import DeliveryLine
class TaxLine(DeliveryLine):
""" Tax Line
"""
meta_type = 'ERP5 Tax Line'
portal_type = 'Tax Line'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces
__implements__ = ( Interface.Variated, )
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.Amount
, PropertySheet.Task
, PropertySheet.Arrow
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.VariationRange
, PropertySheet.ItemAggregation
, PropertySheet.Reference
, PropertySheet.SortIndex
)
security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable')
def isAccountable(self):
""" """
return 1 # XXX not sure
security.declareProtected(Permissions.AccessContentsInformation,
'hasCellContent')
def hasCellContent(self, base_id='movement'):
"""Tax line does not contain cell
"""
return 0
security.declareProtected(Permissions.AccessContentsInformation,
'isMovement' )
def isMovement(self):
"""Tax lines are movements
"""
return 1
##############################################################################
#
# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.com>
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Rule import Rule
from Products.ERP5.Document.DeliveryRule import DeliveryRule
class TaxRule(DeliveryRule):
"""
"""
# CMF Type Definition
meta_type = 'ERP5 Tax Rule'
portal_type = 'Tax Rule'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
__implements__ = ( Interface.Predicate,
Interface.Rule )
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Task
)
security.declareProtected(Permissions.ModifyPortalContent, 'expand')
def expand(self, applied_rule, force=0, **kw):
""" """
movement_type = 'Simulation Movement'
immutable_movement_list = []
parent_simulation_movement = applied_rule.getParentValue()
order_movement = parent_simulation_movement.getDefaultOrderValue()
order_movement_dict = {}
for s_m in applied_rule.objectValues():
order_movement_dict.setdefault(s_m.getOrder(), []).append(s_m)
order_movement_total_price = order_movement.getTotalPrice()
parent_simulation_movement_total_price = \
parent_simulation_movement.getTotalPrice()
# XXX round
if order_movement_total_price != 0 and \
parent_simulation_movement_total_price != 0:
ratio = parent_simulation_movement_total_price / \
order_movement_total_price
for tax_movement in order_movement\
.DeliveryMovement_getCorrespondingTaxLineList():
existing_simulation_movement_list = order_movement_dict.get(
tax_movement.getRelativeUrl(), [])
property_dict = dict()
for prop in ('price', 'base_application_list',
'base_contribution_list', 'resource'):
property_dict[prop] = tax_movement.getProperty(prop)
property_dict['quantity'] = tax_movement.getQuantity() * ratio
if not existing_simulation_movement_list:
applied_rule.newContent(
portal_type=movement_type,
order_value=tax_movement,
order_ratio=1,
delivery_ratio=1,
deliverable=1,
**property_dict )
else:
for existing_simulation_movement in \
existing_simulation_movement_list:
existing_simulation_movement.edit(**property_dict)
# Pass to base class
Rule.expand(self, applied_rule, force=force, **kw)
......@@ -32,8 +32,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Path import Path
from Products.ERP5.Document.Delivery import Delivery
class TradeCondition(Path):
class TradeCondition(Delivery, Path):
"""
Trade Conditions are used to store the conditions (payment, logistic,...)
which should be applied (and used in the orders) when two companies make
......
......@@ -92,6 +92,9 @@ portal_invoice_movement_type_list = (
'Pay Sheet Cell',
)
portal_tax_movement_type_list = ( 'Tax Line', 'Discount Line',
'Pay Sheet Line', )
portal_order_movement_type_list = (
'Purchase Order Line',
'Purchase Order Cell',
......
......@@ -609,6 +609,16 @@ class ERP5Site(FolderMixIn, CMFSite):
return self._getPortalGroupedTypeList('invoice_movement') or \
self._getPortalConfiguration('portal_invoice_movement_type_list')
security.declareProtected(Permissions.AccessContentsInformation,
'getPortalTaxMovementTypeList')
def getPortalTaxMovementTypeList(self):
"""
Return tax movement types.
"""
return self._getPortalGroupedTypeList('tax_movement') or \
self._getPortalConfiguration('portal_tax_movement_type_list')
security.declareProtected(Permissions.AccessContentsInformation,
'getPortalOrderMovementTypeList')
def getPortalOrderMovementTypeList(self):
......
......@@ -1177,6 +1177,18 @@ class RequirementMovementGroup(RootMovementGroup):
def test(self,movement):
return self.getRequirementList(movement) == self.requirement_list
class BaseContributionMovementGroup(PropertyMovementGroup):
""" Group movements that have the same base contributions."""
_property = 'base_contribution_list'
class BaseApplicationMovementGroup(PropertyMovementGroup):
""" Group movements that have the same base applications."""
_property = 'base_application_list'
class PriceCurrencyMovementGroup(PropertyMovementGroup):
""" Group movements that have the same price currency."""
_property = 'price_currency'
class QuantityUnitMovementGroup(PropertyMovementGroup):
""" Group movements that have the same quantity unit."""
_property = 'quantity_unit'
......
......@@ -126,6 +126,7 @@ class Amount:
)
_categories = ('resource', 'quantity_unit',
'base_application', 'base_contribution',
# Acquired categories
'product_line', )
......@@ -182,6 +182,7 @@ class Resource:
_categories = ( 'source', 'destination', 'quantity_unit', 'price_unit',
'weight_unit', 'length_unit', 'height_unit', 'width_unit',
'volume_unit',
'base_contribution',
'price_currency', 'source_price_currency',
'destination_price_currency', 'product_line',
'industrial_phase')
......
##############################################################################
#
# 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
from DateTime import DateTime
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
try:
from transaction import get as get_transaction
except ImportError:
pass
class TradeConditionTestCase(ERP5TypeTestCase):
"""Tests for Trade Conditions and Tax
"""
def getBusinessTemplateList(self):
return ('erp5_base', 'erp5_pdm', 'erp5_trade', 'erp5_accounting', 'erp5_invoicing')
def setUp(self):
ERP5TypeTestCase.setUp(self)
for rule in self.portal.portal_rules.contentValues():
if rule.getPortalType() != 'Payment Rule':
rule.validate() # XXX this should be enabled !
self.base_amount = self.portal.portal_categories.base_amount
self.tax = self.portal.tax_module.newContent(
portal_type='Tax',
title='Tax')
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 tearDown(self):
get_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.product_line):
module.manage_delObjects(list(module.objectIds()))
if 'test_invoice_transaction_rule' in self.portal.portal_rules.objectIds():
self.portal.portal_rules.manage_delObjects('test_invoice_transaction_rule')
get_transaction().commit()
self.tic()
ERP5TypeTestCase.tearDown(self)
class AccountingBuildTestCase(TradeConditionTestCase):
"""Same as TradeConditionTestCase, but with a rule to generate
accounting.
"""
def setUp(self):
TradeConditionTestCase.setUp(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()
dummy_resource = self.portal.portal_categories.product_line.newContent(
id='dummy_resource',
title='Dummy Resource')
self.resource.setProductLineValue(dummy_resource)
dummy_tax = self.portal.portal_categories.product_line.newContent(
id='dummy_tax',
title='Dummy Tax')
# FIXME: tax should not have a product line
self.tax.setProductLineValue(dummy_tax)
itr = self.portal.portal_rules.newContent(
portal_type='Invoice Transaction Rule',
reference='default_invoice_transaction_rule',
id='test_invoice_transaction_rule',
title='Transaction Rule',
test_method_id='SimulationMovement_testInvoiceTransactionRule',
version=100)
predicate = itr.newContent(portal_type='Predicate',)
predicate.edit(
string_index='resource_type',
title='Resource Product',
int_index=1,
membership_criterion_base_category_list=['product_line',],
membership_criterion_category_list=['product_line/dummy_resource'],)
predicate = itr.newContent(portal_type='Predicate')
predicate.edit(
string_index='resource_type',
title='Resource Tax',
int_index=2,
membership_criterion_base_category_list=['product_line',],
membership_criterion_category_list=['product_line/dummy_tax'],)
get_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()
get_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_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_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_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_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()
class TestTaxLineCalculation(TradeConditionTestCase):
"""Test calculating Tax Lines.
"""
def test_simple_tax_model_line_calculation(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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.order.Order_applyTradeCondition(self.trade_condition, force=1)
# this creates a tax line, with quantity 0, and it will be updated when
# needed
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(0, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
order_line = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=10,
price=10,)
# now tax lines are updated
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(20, tax_line.getTotalPrice())
def test_tax_model_line_calculation_with_two_lines(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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.order.Order_applyTradeCondition(self.trade_condition, force=1)
# this creates a tax line, with quantity 0, and it will be updated when
# needed
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(0, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
order_line_1 = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=3,
price=10,)
order_line_2 = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=7,
price=10,)
# now tax lines are updated
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(20, tax_line.getTotalPrice())
order_line_1_tax_line_list = \
order_line_1.DeliveryMovement_getCorrespondingTaxLineList()
self.assertEquals(1, len(order_line_1_tax_line_list))
tax_line = order_line_1_tax_line_list[0]
self.assertEquals(30, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(6, tax_line.getTotalPrice())
order_line_2_tax_line_list = \
order_line_2.DeliveryMovement_getCorrespondingTaxLineList()
self.assertEquals(1, len(order_line_2_tax_line_list))
tax_line = order_line_2_tax_line_list[0]
self.assertEquals(70, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(14, tax_line.getTotalPrice())
def test_tax_on_tax(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
base_2 = self.base_amount.newContent(
portal_type='Category',
title='Base 2')
tax2 = self.portal.tax_module.newContent(
portal_type='Tax',
title='Tax 2')
self.resource.setBaseContributionValue(base_1)
tax_model_line = self.trade_condition.newContent(
portal_type='Tax Model Line',
base_application_value=base_1,
base_contribution_value=base_2,
float_index=1,
efficiency=0.2,
resource_value=self.tax)
tax_model_line = self.trade_condition.newContent(
portal_type='Tax Model Line',
base_application_value=base_2,
float_index=2,
efficiency=0.5,
resource_value=tax2)
self.order.Order_applyTradeCondition(self.trade_condition, force=1)
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(2, len(tax_line_list))
tax_line1 = [tl for tl in tax_line_list if
tl.getResourceValue() == self.tax][0]
self.assertEquals(0, tax_line1.getQuantity())
self.assertEquals(0.2, tax_line1.getPrice())
self.assertEquals(1, tax_line1.getFloatIndex())
self.assertEquals([base_1], tax_line1.getBaseApplicationValueList())
self.assertEquals([base_2], tax_line1.getBaseContributionValueList())
tax_line2 = [tl for tl in tax_line_list if
tl.getResourceValue() == tax2][0]
self.assertEquals(0, tax_line2.getQuantity())
self.assertEquals(0.5, tax_line2.getPrice())
self.assertEquals(2, tax_line2.getFloatIndex())
self.assertEquals([base_2], tax_line2.getBaseApplicationValueList())
order_line = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=3,
price=10,)
self.assertEquals(30, tax_line1.getQuantity())
self.assertEquals((30*0.2), tax_line2.getQuantity())
order_line.setQuantity(5)
self.assertEquals(50, tax_line1.getQuantity())
self.assertEquals((50*0.2), tax_line2.getQuantity())
def test_update_order_line_quantity_update_tax_line(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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.order.Order_applyTradeCondition(self.trade_condition, force=1)
# this creates a tax line, with quantity 0, and it will be updated when
# needed
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(0, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
order_line = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=10,
price=10,)
# tax lines are updated
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(20, tax_line.getTotalPrice())
# change the quantity on order_line,
order_line.setQuantity(20)
# the tax line is updated
self.assertEquals(200, tax_line.getQuantity())
self.assertEquals(40, tax_line.getTotalPrice())
def test_order_cell_and_tax_line(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(base_1)
# make a resource with size variation
self.portal.portal_categories.size.newContent(id='small', title='Small')
self.portal.portal_categories.size.newContent(id='big', title='Big')
self.resource.setVariationBaseCategoryList(('size',))
self.resource.setVariationCategoryList(('size/big', 'size/small'))
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.order.Order_applyTradeCondition(self.trade_condition, force=1)
# this creates a tax line, with quantity 0, and it will be updated when
# needed
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(0, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
order_line = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,)
order_line.setVariationCategoryList(('size/big', 'size/small'))
order_line.updateCellRange(base_id='movement')
cell_red = order_line.newCell('size/big',
portal_type=self.order_cell_type,
base_id='movement')
cell_red.setMappedValuePropertyList(['quantity', 'price'])
cell_red.setPrice(5)
cell_red.setQuantity(10)
cell_blue = order_line.newCell('size/small',
portal_type=self.order_cell_type,
base_id='movement')
cell_blue.setMappedValuePropertyList(['quantity', 'price'])
cell_blue.setPrice(2)
cell_blue.setQuantity(25)
self.assertEquals(100, order_line.getTotalPrice(fast=0))
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
# TODO: discuss this behaviour, and what about getTotalNetPrice ?
#self.assertEquals(120, self.order.getTotalPrice(fast=0))
def test_hierarchical_order_line_and_tax_line(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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.order.Order_applyTradeCondition(self.trade_condition, force=1)
# this creates a tax line, with quantity 0, and it will be updated when
# needed
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(0, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
order_line = self.order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,)
suborder_line1 = order_line.newContent(
portal_type=self.order_line_type,
quantity=4,
price=5)
suborder_line2 = order_line.newContent(
portal_type=self.order_line_type,
quantity=2,
price=40)
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(0.2, tax_line.getPrice())
def test_base_contribution_pseudo_acquisition(self):
base_1 = self.base_amount.newContent(portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValueList((base_1,))
line = self.order.newContent(portal_type=self.order_line_type)
self.assertEquals([], line.getBaseContributionValueList())
line.setResourceValue(self.resource)
self.assertEquals([base_1], line.getBaseContributionValueList())
line.setBaseContributionValueList([])
self.assertEquals([], line.getBaseContributionValueList())
def test_multiple_order_line_multiple_tax_line(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
base_2 = self.base_amount.newContent(
portal_type='Category',
title='Base 2')
self.resource.setBaseContributionValueList((base_1, base_2))
tax_model_line_1 = self.trade_condition.newContent(
portal_type='Tax Model Line',
base_application_value=base_1,
float_index=1,
efficiency=0.1,
resource_value=self.tax)
tax_model_line_2 = self.trade_condition.newContent(
portal_type='Tax Model Line',
base_application_value=base_2,
float_index=2,
efficiency=0.2,
resource_value=self.tax)
tax_model_line_1_2 = self.trade_condition.newContent(
portal_type='Tax Model Line',
base_application_value_list=(base_1, base_2),
float_index=3,
efficiency=0.3,
resource_value=self.tax)
self.order.Order_applyTradeCondition(self.trade_condition, force=1)
line_1 = self.order.newContent(
portal_type=self.order_line_type,
quantity=1, price=1,
resource_value=self.resource,
base_contribution_value_list=(base_1,))
# -> tax_model_line_1 and tax_model_line_1_2 are applicable
line_2 = self.order.newContent(
portal_type=self.order_line_type,
quantity=2, price=2,
resource_value=self.resource,
base_contribution_value_list=(base_2,))
# -> tax_model_line_2 and tax_model_line_1_2 are applicable
line_3 = self.order.newContent(
portal_type=self.order_line_type,
quantity=3, price=3,
resource_value=self.resource,
base_contribution_value_list=(base_1, base_2))
# -> tax_model_line_1, tax_model_line_2 and tax_model_line_1_2 are applicable
# (but they are not applied twice)
tax_line_list = self.order.contentValues(portal_type='Tax Line')
self.assertEquals(3, len(tax_line_list))
tax_line_1 = [x for x in tax_line_list if x.getPrice() == 0.1][0]
tax_line_2 = [x for x in tax_line_list if x.getPrice() == 0.2][0]
tax_line_3 = [x for x in tax_line_list if x.getPrice() == 0.3][0]
self.assertEquals(sum([line_1.getTotalPrice(),
line_3.getTotalPrice()]), tax_line_1.getQuantity())
self.assertEquals(sum([line_2.getTotalPrice(),
line_3.getTotalPrice()]), tax_line_2.getQuantity())
self.assertEquals(sum([line_1.getTotalPrice(),
line_2.getTotalPrice(),
line_3.getTotalPrice()]), tax_line_3.getQuantity())
# TODO: test DeliveryMovement_getCorrespondingTaxLineList
tax_movement_list = line_1.DeliveryMovement_getCorrespondingTaxLineList()
self.assertEquals(2, len(tax_movement_list))
tax_1_movement = [m for m in tax_movement_list if m.getPrice() == 0.1][0]
# self.assertEquals(
class TestTaxLineOrderSimulation(TradeConditionTestCase):
"""Test Simulation of Tax Lines on Orders
"""
def test_tax_line_simulation(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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)
order = self.order
order.Order_applyTradeCondition(self.trade_condition, force=1)
order.setSourceSectionValue(self.vendor)
order.setSourceValue(self.vendor)
order.setDestinationSectionValue(self.client)
order.setDestinationValue(self.client)
order.setStartDate(DateTime(2001, 1, 1))
order_line = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=10,
price=10,)
order.plan()
order.confirm()
self.assertEquals('confirmed', order.getSimulationState())
get_transaction().commit()
self.tic()
related_applied_rule_list = order.getCausalityRelatedValueList(
portal_type='Applied Rule')
self.assertEquals(1, len(related_applied_rule_list))
root_applied_rule = related_applied_rule_list[0]
simulation_movement_list = root_applied_rule.contentValues(
portal_type='Simulation Movement')
self.assertEquals(1, len(simulation_movement_list))
level2_applied_rule_list = simulation_movement_list[0].contentValues()
self.assertEquals(2, len(level2_applied_rule_list))
# first test the invoice movement, they should have base_contribution set
# correctly
invoice_rule_list = [ar for ar in level2_applied_rule_list if
ar.getSpecialiseValue().getPortalType() == 'Invoicing Rule']
self.assertEquals(1, len(invoice_rule_list))
invoice_simulation_movement_list = invoice_rule_list[0].contentValues()
self.assertEquals(1, len(invoice_simulation_movement_list))
invoice_simulation_movement = invoice_simulation_movement_list[0]
self.assertEquals(self.resource,
invoice_simulation_movement.getResourceValue())
self.assertEquals([base_1],
invoice_simulation_movement.getBaseContributionValueList())
# now test the tax movement
applied_tax_rule_list = [ar for ar in level2_applied_rule_list if
ar.getSpecialiseValue().getPortalType() == 'Tax Rule']
self.assertEquals(1, len(applied_tax_rule_list))
tax_simulation_movement_list = applied_tax_rule_list[0].contentValues()
self.assertEquals(1, len(tax_simulation_movement_list))
tax_simulation_movement = tax_simulation_movement_list[0]
self.assertEquals(self.tax, tax_simulation_movement.getResourceValue())
self.assertEquals([base_1],
tax_simulation_movement.getBaseApplicationValueList())
self.assertEquals(100, tax_simulation_movement.getQuantity())
self.assertEquals(0.2, tax_simulation_movement.getPrice())
# reexpand and check nothing changed
root_applied_rule.expand()
applied_tax_rule_list = [ar for ar in level2_applied_rule_list if
ar.getSpecialiseValue().getPortalType() == 'Tax Rule']
self.assertEquals(1, len(applied_tax_rule_list))
tax_simulation_movement_list = applied_tax_rule_list[0].contentValues()
self.assertEquals(1, len(tax_simulation_movement_list))
tax_simulation_movement = tax_simulation_movement_list[0]
self.assertEquals(self.tax, tax_simulation_movement.getResourceValue())
self.assertEquals([base_1],
tax_simulation_movement.getBaseApplicationValueList())
self.assertEquals(100, tax_simulation_movement.getQuantity())
self.assertEquals(0.2, tax_simulation_movement.getPrice())
def test_2_tax_lines_simulation(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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)
order = self.order
order.Order_applyTradeCondition(self.trade_condition, force=1)
order.setSourceSectionValue(self.vendor)
order.setSourceValue(self.vendor)
order.setDestinationSectionValue(self.client)
order.setDestinationValue(self.client)
order.setStartDate(DateTime(2001, 1, 1))
order_line1 = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=2,
price=15,)
order_line2 = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=7,
price=10,)
order.plan()
order.confirm()
self.assertEquals('confirmed', order.getSimulationState())
get_transaction().commit()
self.tic()
related_applied_rule_list = order.getCausalityRelatedValueList(
portal_type='Applied Rule')
self.assertEquals(1, len(related_applied_rule_list))
root_applied_rule = related_applied_rule_list[0]
simulation_movement_list = root_applied_rule.contentValues(
portal_type='Simulation Movement')
self.assertEquals(2, len(simulation_movement_list))
# line 1
line1_simulation_movement_list = [sm for sm in simulation_movement_list
if sm.getOrderValue() == order_line1]
self.assertEquals(1, len(line1_simulation_movement_list))
simulation_movement = line1_simulation_movement_list[0]
self.assertEquals(2.0, simulation_movement.getQuantity())
applied_tax_rule_list = [ar for ar in simulation_movement.objectValues()
if ar.getSpecialiseValue().getPortalType() == 'Tax Rule']
self.assertEquals(1, len(applied_tax_rule_list))
tax_simulation_movement_list = applied_tax_rule_list[0].contentValues()
self.assertEquals(1, len(tax_simulation_movement_list))
tax_simulation_movement = tax_simulation_movement_list[0]
self.assertEquals(self.tax, tax_simulation_movement.getResourceValue())
self.assertEquals([base_1],
tax_simulation_movement.getBaseApplicationValueList())
self.assertEquals(30, tax_simulation_movement.getQuantity())
self.assertEquals(0.2, tax_simulation_movement.getPrice())
# line 2
line2_simulation_movement_list = [sm for sm in simulation_movement_list
if sm.getOrderValue() == order_line2]
self.assertEquals(1, len(line2_simulation_movement_list))
simulation_movement = line2_simulation_movement_list[0]
self.assertEquals(7., simulation_movement.getQuantity())
applied_tax_rule_list = [ar for ar in simulation_movement.objectValues()
if ar.getSpecialiseValue().getPortalType() == 'Tax Rule']
self.assertEquals(1, len(applied_tax_rule_list))
tax_simulation_movement_list = applied_tax_rule_list[0].contentValues()
self.assertEquals(1, len(tax_simulation_movement_list))
tax_simulation_movement = tax_simulation_movement_list[0]
self.assertEquals(self.tax, tax_simulation_movement.getResourceValue())
self.assertEquals([base_1],
tax_simulation_movement.getBaseApplicationValueList())
self.assertEquals(70, tax_simulation_movement.getQuantity())
self.assertEquals(0.2, tax_simulation_movement.getPrice())
def test_tax_line_build(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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)
order = self.order
order.Order_applyTradeCondition(self.trade_condition, force=1)
order.setSourceSectionValue(self.vendor)
order.setSourceValue(self.vendor)
order.setDestinationSectionValue(self.client)
order.setDestinationValue(self.client)
order.setPriceCurrencyValue(self.currency)
order.setStartDate(DateTime(2001, 1, 1))
order_line = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=2,
price=15,)
order.plan()
order.confirm()
self.assertEquals('confirmed', order.getSimulationState())
get_transaction().commit()
self.tic()
related_delivery = order.getCausalityRelatedValue(
portal_type=('Purchase Packing List', 'Sale Packing List'))
self.assertNotEquals(related_delivery, None)
related_delivery.setReady()
related_delivery.start()
related_delivery.stop()
related_delivery.deliver()
self.assertEquals('delivered', related_delivery.getSimulationState())
get_transaction().commit()
self.tic()
related_invoice = related_delivery.getCausalityRelatedValue(
portal_type=('Purchase Invoice Transaction',
'Sale Invoice Transaction'))
self.assertNotEquals(related_invoice, None)
invoice_line_list = related_invoice.contentValues(
portal_type='Invoice Line')
tax_line_list = related_invoice.contentValues(
portal_type='Tax Line')
self.assertEquals(1, len(invoice_line_list))
invoice_line = invoice_line_list[0]
self.assertEquals(2, invoice_line.getQuantity())
self.assertEquals(15, invoice_line.getPrice())
self.assertEquals(self.resource, invoice_line.getResourceValue())
self.assertEquals([base_1], invoice_line.getBaseContributionValueList())
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(30, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals([base_1], tax_line.getBaseApplicationValueList())
self.assertEquals([], tax_line.getBaseContributionValueList())
self.assertEquals('solved', related_invoice.getCausalityState())
# Of course, this invoice does not generate simulation again
self.assertEquals([], related_invoice.getCausalityRelatedValueList(
portal_type='Applied Rule'))
def test_tax_line_merged_build(self):
# an order with 2 lines and 1 tax line will later be built in an invoice
# with 2 lines and 1 tax line
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(base_1)
resource2 = self.portal.product_module.newContent(
portal_type='Product',
title='Resource 2',
base_contribution_value_list=[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)
order = self.order
order.Order_applyTradeCondition(self.trade_condition, force=1)
order.setSourceSectionValue(self.vendor)
order.setSourceValue(self.vendor)
order.setDestinationSectionValue(self.client)
order.setDestinationValue(self.client)
order.setPriceCurrencyValue(self.currency)
order.setStartDate(DateTime(2001, 1, 1))
order_line1 = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=2,
price=15,)
order_line2 = order.newContent(
portal_type=self.order_line_type,
resource_value=resource2,
quantity=7,
price=10,)
# check existing tax line
tax_line_list = order.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals(2*15 + 7*10, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
order.plan()
order.confirm()
self.assertEquals('confirmed', order.getSimulationState())
get_transaction().commit()
self.tic()
related_delivery = order.getCausalityRelatedValue(
portal_type=('Purchase Packing List', 'Sale Packing List'))
self.assertNotEquals(related_delivery, None)
related_delivery.setReady()
related_delivery.start()
related_delivery.stop()
related_delivery.deliver()
self.assertEquals('delivered', related_delivery.getSimulationState())
get_transaction().commit()
self.tic()
related_invoice = related_delivery.getCausalityRelatedValue(
portal_type=('Purchase Invoice Transaction',
'Sale Invoice Transaction'))
self.assertNotEquals(related_invoice, None)
invoice_line_list = related_invoice.contentValues(
portal_type='Invoice Line')
tax_line_list = related_invoice.contentValues(
portal_type='Tax Line')
self.assertEquals(2, len(invoice_line_list))
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(100, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals([base_1], tax_line.getBaseApplicationValueList())
self.assertEquals([], tax_line.getBaseContributionValueList())
self.assertEquals('solved', related_invoice.getCausalityState())
def test_tax_line_updated_on_invoice_line_change(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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)
order = self.order
order.Order_applyTradeCondition(self.trade_condition, force=1)
order.setSourceSectionValue(self.vendor)
order.setSourceValue(self.vendor)
order.setDestinationSectionValue(self.client)
order.setDestinationValue(self.client)
order.setPriceCurrencyValue(self.currency)
order.setStartDate(DateTime(2001, 1, 1))
order_line = order.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=2,
price=15,)
order.plan()
order.confirm()
self.assertEquals('confirmed', order.getSimulationState())
get_transaction().commit()
self.tic()
related_delivery = order.getCausalityRelatedValue(
portal_type=('Purchase Packing List', 'Sale Packing List'))
self.assertNotEquals(related_delivery, None)
related_delivery.setReady()
related_delivery.start()
related_delivery.stop()
related_delivery.deliver()
self.assertEquals('delivered', related_delivery.getSimulationState())
get_transaction().commit()
self.tic()
related_invoice = related_delivery.getCausalityRelatedValue(
portal_type=('Purchase Invoice Transaction',
'Sale Invoice Transaction'))
self.assertNotEquals(related_invoice, None)
self.assertEquals('solved', related_invoice.getCausalityState())
invoice_line_list = related_invoice.contentValues(
portal_type='Invoice Line')
tax_line_list = related_invoice.contentValues(
portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
self.assertEquals(30, tax_line.getQuantity())
self.assertEquals(0.2, tax_line.getPrice())
self.assertEquals(self.tax, tax_line.getResourceValue())
self.assertEquals([base_1], tax_line.getBaseApplicationValueList())
self.assertEquals([], tax_line.getBaseContributionValueList())
self.assertEquals(1, len(invoice_line_list))
invoice_line = invoice_line_list[0]
# change a total price on the invoice_line,
invoice_line.setQuantity(3)
get_transaction().commit()
self.tic()
# it will be reflected on the tax line
self.assertEquals(45, tax_line.getQuantity())
self.assertTrue(tax_line.isDivergent())
# and the invoice is diverged
self.assertEquals('diverged', related_invoice.getCausalityState())
class TestTaxLineInvoiceSimulation(AccountingBuildTestCase):
"""Test Simulation of Tax Lines on Invoices
"""
def test_tax_line_simulation(self):
base_1 = self.base_amount.newContent(
portal_type='Category',
title='Base 1')
self.resource.setBaseContributionValue(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)
invoice = self.order
invoice.Order_applyTradeCondition(self.trade_condition, force=1)
invoice.setSourceSectionValue(self.vendor)
invoice.setSourceValue(self.vendor)
invoice.setDestinationSectionValue(self.client)
invoice.setDestinationValue(self.client)
invoice.setStartDate(DateTime(2001, 1, 1))
invoice.setPriceCurrencyValue(self.currency)
invoice_line = invoice.newContent(
portal_type=self.order_line_type,
resource_value=self.resource,
quantity=10,
price=10,)
tax_line_list = invoice.contentValues(portal_type='Tax Line')
self.assertEquals(1, len(tax_line_list))
tax_line = tax_line_list[0]
invoice.plan()
invoice.confirm()
self.assertEquals('confirmed', invoice.getSimulationState())
get_transaction().commit()
self.tic()
related_applied_rule_list = invoice.getCausalityRelatedValueList(
portal_type='Applied Rule')
self.assertEquals(1, len(related_applied_rule_list))
root_applied_rule = related_applied_rule_list[0]
simulation_movement_list = root_applied_rule.contentValues(
portal_type='Simulation Movement')
self.assertEquals(2, len(simulation_movement_list))
tax_simulation_movement_list = [m for m in simulation_movement_list
if m.getOrderValue() == tax_line]
self.assertEquals(1, len(tax_simulation_movement_list))
tax_simulation_movement = tax_simulation_movement_list[0]
self.assertEquals([base_1],
tax_simulation_movement.getBaseApplicationValueList())
self.assertEquals(100, tax_simulation_movement.getQuantity())
self.assertEquals(0.2, tax_simulation_movement.getPrice())
self.assertEquals(self.currency,
tax_simulation_movement.getPriceCurrencyValue())
invoice_simulation_movement_list = [m for m in simulation_movement_list
if m.getOrderValue() == invoice_line]
self.assertEquals(1, len(invoice_simulation_movement_list))
invoice_simulation_movement = invoice_simulation_movement_list[0]
self.assertEquals([base_1],
invoice_simulation_movement.getBaseContributionValueList())
self.assertEquals(10, invoice_simulation_movement.getQuantity())
self.assertEquals(10, invoice_simulation_movement.getPrice())
self.assertEquals(self.currency,
invoice_simulation_movement.getPriceCurrencyValue())
self.assertEquals(self.resource,
invoice_simulation_movement.getResourceValue())
invoice.start()
self.assertEquals('started', invoice.getSimulationState())
get_transaction().commit()
self.tic()
accounting_line_list = invoice.getMovementList(
portal_type=('Sale Invoice Transaction Line',
'Purchase Invoice Transaction Line'))
self.assertEquals(3, len(accounting_line_list))
receivable_line = [l for l in accounting_line_list if
l.getSourceValue() == self.receivable_account][0]
self.assertEquals(self.payable_account,
receivable_line.getDestinationValue())
self.assertEquals(120, receivable_line.getSourceDebit())
tax_line = [l for l in accounting_line_list if
l.getSourceValue() == self.collected_tax_account][0]
self.assertEquals(self.refundable_tax_account,
tax_line.getDestinationValue())
self.assertEquals(20, tax_line.getSourceCredit())
self.assertEquals('solved', invoice.getCausalityState())
class DiscountCalculation:
"""Test Calculating Discount
"""
def test_simple_discount_model_line_calculation(self):
discount_line =self.trade_condition.newContent(
portal_type='Discount Model Line')
class TestWithSaleOrder:
order_type = 'Sale Order'
order_line_type = 'Sale Order Line'
order_cell_type = 'Sale Order Cell'
trade_condition_type = 'Sale Trade Condition'
class TestWithPurchaseOrder:
order_type = 'Purchase Order'
order_line_type = 'Purchase Order Line'
order_cell_type = 'Purchase Order Cell'
trade_condition_type = 'Purchase Trade Condition'
class TestWithSaleInvoice:
order_type = 'Sale Invoice Transaction'
order_line_type = 'Invoice Line'
order_cell_type = 'Invoice Cell'
trade_condition_type = 'Sale Trade Condition'
class TestWithPurchaseInvoice:
order_type = 'Purchase Invoice Transaction'
order_line_type = 'Invoice Line'
order_cell_type = 'Invoice Cell'
trade_condition_type = 'Purchase Trade Condition'
class TestApplyTradeConditionSaleOrder(
TestApplyTradeCondition, TestWithSaleOrder):
pass
class TestApplyTradeConditionPurchaseOrder(
TestApplyTradeCondition, TestWithPurchaseOrder):
pass
class TestTaxLineCalculationSaleOrder(
TestTaxLineCalculation, TestWithSaleOrder):
pass
class TestTaxLineCalculationPurchaseOrder(
TestTaxLineCalculation, TestWithPurchaseOrder):
pass
class TestTaxLineCalculationSaleInvoice(
TestTaxLineCalculation, TestWithSaleInvoice):
def not_available(self):
pass
test_hierarchical_order_line_and_tax_line = not_available
class TestTaxLineCalculationPurchaseInvoice(
TestTaxLineCalculation, TestWithPurchaseInvoice):
def not_available(self):
pass
test_hierarchical_order_line_and_tax_line = not_available
class TestTaxLineOrderSimulationSaleOrder(
TestTaxLineOrderSimulation, TestWithSaleOrder):
pass
class TestTaxLineOrderSimulationPurchaseOrder(
TestTaxLineOrderSimulation, TestWithPurchaseOrder):
pass
class TestTaxLineInvoiceSimulationPurchaseInvoice(
TestTaxLineInvoiceSimulation, TestWithPurchaseInvoice):
pass
class TestTaxLineInvoiceSimulationSaleInvoice(
TestTaxLineInvoiceSimulation, TestWithSaleInvoice):
pass
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestApplyTradeConditionSaleOrder))
suite.addTest(unittest.makeSuite(TestApplyTradeConditionPurchaseOrder))
suite.addTest(unittest.makeSuite(TestTaxLineCalculationSaleOrder))
suite.addTest(unittest.makeSuite(TestTaxLineCalculationPurchaseOrder))
suite.addTest(unittest.makeSuite(TestTaxLineCalculationSaleInvoice))
suite.addTest(unittest.makeSuite(TestTaxLineCalculationPurchaseInvoice))
suite.addTest(unittest.makeSuite(TestTaxLineOrderSimulationSaleOrder))
suite.addTest(unittest.makeSuite(TestTaxLineOrderSimulationPurchaseOrder))
suite.addTest(unittest.makeSuite(TestTaxLineInvoiceSimulationPurchaseInvoice))
suite.addTest(unittest.makeSuite(TestTaxLineInvoiceSimulationSaleInvoice))
return suite
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment