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): ...@@ -132,6 +132,8 @@ class DeliveryRule(Rule):
quantity_unit=deliv_mvt.getQuantityUnit(), quantity_unit=deliv_mvt.getQuantityUnit(),
price=deliv_mvt.getPrice(), price=deliv_mvt.getPrice(),
price_currency=deliv_mvt.getPriceCurrency(), price_currency=deliv_mvt.getPriceCurrency(),
base_contribution_list=deliv_mvt.getBaseContributionList(),
base_application_list=deliv_mvt.getBaseApplicationList(),
) )
elif sim_mvt in existing_movement_list: elif sim_mvt in existing_movement_list:
if sim_mvt not in immutable_movement_list: if sim_mvt not in immutable_movement_list:
...@@ -158,6 +160,8 @@ class DeliveryRule(Rule): ...@@ -158,6 +160,8 @@ class DeliveryRule(Rule):
quantity_unit=deliv_mvt.getQuantityUnit(), quantity_unit=deliv_mvt.getQuantityUnit(),
price=deliv_mvt.getPrice(), price=deliv_mvt.getPrice(),
price_currency=deliv_mvt.getPriceCurrency(), price_currency=deliv_mvt.getPriceCurrency(),
base_contribution_list=deliv_mvt.getBaseContributionList(),
base_application_list=deliv_mvt.getBaseApplicationList(),
force_update=1) force_update=1)
else: else:
# modification disallowed, must compensate # modification disallowed, must compensate
......
...@@ -97,6 +97,7 @@ class InvoicingRule(Rule): ...@@ -97,6 +97,7 @@ class InvoicingRule(Rule):
'resource': context_movement.getResource(), 'resource': context_movement.getResource(),
'variation_category_list': context_movement.getVariationCategoryList(), 'variation_category_list': context_movement.getVariationCategoryList(),
'variation_property_dict': context_movement.getVariationPropertyDict(), 'variation_property_dict': context_movement.getVariationPropertyDict(),
'base_contribution_list': context_movement.getBaseContributionList(),
'aggregate_list': context_movement.getAggregateList(), 'aggregate_list': context_movement.getAggregateList(),
'quantity': context_movement.getCorrectedQuantity(), 'quantity': context_movement.getCorrectedQuantity(),
'quantity_unit': context_movement.getQuantityUnit(), 'quantity_unit': context_movement.getQuantityUnit(),
......
...@@ -106,6 +106,9 @@ class OrderRule(DeliveryRule): ...@@ -106,6 +106,9 @@ class OrderRule(DeliveryRule):
order_movement_dict[order_movement.getPath()] = s_m order_movement_dict[order_movement.getPath()] = s_m
# Create or modify movements # Create or modify movements
for movement in order_movement_list: 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) related_order = order_movement_dict.get(movement.getPath(), None)
if related_order is None: if related_order is None:
related_order = movement.getOrderRelatedValue() related_order = movement.getOrderRelatedValue()
...@@ -181,6 +184,7 @@ class OrderRule(DeliveryRule): ...@@ -181,6 +184,7 @@ class OrderRule(DeliveryRule):
'resource', 'resource',
'variation_category_list', 'variation_category_list',
'variation_property_dict', 'variation_property_dict',
'base_contribution_list',
'aggregate_list', 'aggregate_list',
'price', 'price',
'price_currency', '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 ...@@ -32,8 +32,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Path import Path 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,...) Trade Conditions are used to store the conditions (payment, logistic,...)
which should be applied (and used in the orders) when two companies make which should be applied (and used in the orders) when two companies make
......
...@@ -92,6 +92,9 @@ portal_invoice_movement_type_list = ( ...@@ -92,6 +92,9 @@ portal_invoice_movement_type_list = (
'Pay Sheet Cell', 'Pay Sheet Cell',
) )
portal_tax_movement_type_list = ( 'Tax Line', 'Discount Line',
'Pay Sheet Line', )
portal_order_movement_type_list = ( portal_order_movement_type_list = (
'Purchase Order Line', 'Purchase Order Line',
'Purchase Order Cell', 'Purchase Order Cell',
......
...@@ -609,6 +609,16 @@ class ERP5Site(FolderMixIn, CMFSite): ...@@ -609,6 +609,16 @@ class ERP5Site(FolderMixIn, CMFSite):
return self._getPortalGroupedTypeList('invoice_movement') or \ return self._getPortalGroupedTypeList('invoice_movement') or \
self._getPortalConfiguration('portal_invoice_movement_type_list') 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, security.declareProtected(Permissions.AccessContentsInformation,
'getPortalOrderMovementTypeList') 'getPortalOrderMovementTypeList')
def getPortalOrderMovementTypeList(self): def getPortalOrderMovementTypeList(self):
......
...@@ -1177,6 +1177,18 @@ class RequirementMovementGroup(RootMovementGroup): ...@@ -1177,6 +1177,18 @@ class RequirementMovementGroup(RootMovementGroup):
def test(self,movement): def test(self,movement):
return self.getRequirementList(movement) == self.requirement_list 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): class QuantityUnitMovementGroup(PropertyMovementGroup):
""" Group movements that have the same quantity unit.""" """ Group movements that have the same quantity unit."""
_property = 'quantity_unit' _property = 'quantity_unit'
......
...@@ -126,6 +126,7 @@ class Amount: ...@@ -126,6 +126,7 @@ class Amount:
) )
_categories = ('resource', 'quantity_unit', _categories = ('resource', 'quantity_unit',
'base_application', 'base_contribution',
# Acquired categories # Acquired categories
'product_line', ) 'product_line', )
...@@ -182,6 +182,7 @@ class Resource: ...@@ -182,6 +182,7 @@ class Resource:
_categories = ( 'source', 'destination', 'quantity_unit', 'price_unit', _categories = ( 'source', 'destination', 'quantity_unit', 'price_unit',
'weight_unit', 'length_unit', 'height_unit', 'width_unit', 'weight_unit', 'length_unit', 'height_unit', 'width_unit',
'volume_unit', 'volume_unit',
'base_contribution',
'price_currency', 'source_price_currency', 'price_currency', 'source_price_currency',
'destination_price_currency', 'product_line', 'destination_price_currency', 'product_line',
'industrial_phase') 'industrial_phase')
......
This diff is collapsed.
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