Commit 31d11fae authored by Julien Muchembled's avatar Julien Muchembled

Make TestTradeModelLine.test_TradeModelRuleSimulationExpand work

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@37558 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 85fccaff
...@@ -71,7 +71,7 @@ if delivery_movement is not None and (\n ...@@ -71,7 +71,7 @@ if delivery_movement is not None and (\n
and delivery_movement.getPortalType() not in movement.getPortalTaxMovementTypeList()):\n and delivery_movement.getPortalType() not in movement.getPortalTaxMovementTypeList()):\n
return False\n return False\n
\n \n
return rule.getMatchingCell(movement) is not None\n return True\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
...@@ -117,6 +117,7 @@ return rule.getMatchingCell(movement) is not None\n ...@@ -117,6 +117,7 @@ return rule.getMatchingCell(movement) is not None\n
<string>parent_rule</string> <string>parent_rule</string>
<string>delivery_movement</string> <string>delivery_movement</string>
<string>None</string> <string>None</string>
<string>True</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="Folder" module="OFS.Folder"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>business_template_skin_layer_priority</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>float</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>business_template_skin_layer_priority</string> </key>
<value> <float>30.0</float> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_legacy</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>movement = context\n
\n
parent = movement.getParentValue()\n
if parent.getPortalType() != \'Applied Rule\':\n
return False\n
\n
parent_rule = parent.getSpecialiseValue()\n
if parent_rule.getPortalType() not in (\'Invoice Root Simulation Rule\',\n
\'Invoice Simulation Rule\',\n
\'Trade Model Simulation Rule\'):\n
return False\n
\n
delivery_movement = movement.getDeliveryValue()\n
if delivery_movement is not None and (\n
delivery_movement.getPortalType() not in movement.getPortalInvoiceMovementTypeList()\n
and delivery_movement.getPortalType() not in movement.getPortalTaxMovementTypeList()):\n
return False\n
\n
return rule.getMatchingCell(movement) is not None\n
</string> </value>
</item>
<item>
<key> <string>_code</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>rule</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>func_code</string> </key>
<value>
<object>
<klass>
<global name="FuncCode" module="Shared.DC.Scripts.Signature"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>rule</string>
<string>context</string>
<string>movement</string>
<string>_getattr_</string>
<string>parent</string>
<string>False</string>
<string>parent_rule</string>
<string>delivery_movement</string>
<string>None</string>
</tuple>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>func_defaults</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SimulationMovement_testInvoiceTransactionSimulationRule</string> </value>
</item>
<item>
<key> <string>warnings</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -99,6 +99,10 @@ ...@@ -99,6 +99,10 @@
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
<value> <string>Invoice Transaction Simulation Rule</string> </value> <value> <string>Invoice Transaction Simulation Rule</string> </value>
</item> </item>
<item>
<key> <string>same_total_quantity</string> </key>
<value> <int>0</int> </value>
</item>
<item> <item>
<key> <string>test_method_id</string> </key> <key> <string>test_method_id</string> </key>
<value> <value>
......
...@@ -704,6 +704,11 @@ class BusinessProcess(Path, XMLObject): ...@@ -704,6 +704,11 @@ class BusinessProcess(Path, XMLObject):
id_index += 1 id_index += 1
movement = newTempMovement(trade_model_path, '%s_%s' % (base_id, id_index)) movement = newTempMovement(trade_model_path, '%s_%s' % (base_id, id_index))
kw = self._getPropertyAndCategoryDict(explanation, amount, trade_model_path, delay_mode=delay_mode) kw = self._getPropertyAndCategoryDict(explanation, amount, trade_model_path, delay_mode=delay_mode)
try:
kw['trade_phase'], = \
set(trade_phase).intersection(trade_model_path.getTradePhaseList())
except ValueError:
pass
kw.update(update_property_dict) kw.update(update_property_dict)
movement._edit(**kw) movement._edit(**kw)
business_link = self.getBusinessLinkValueList(trade_phase=trade_phase, context=movement) business_link = self.getBusinessLinkValueList(trade_phase=trade_phase, context=movement)
...@@ -714,6 +719,9 @@ class BusinessProcess(Path, XMLObject): ...@@ -714,6 +719,9 @@ class BusinessProcess(Path, XMLObject):
# result can not be empty # result can not be empty
if not result: raise ValueError("A Business Process can not erase amounts") if not result: raise ValueError("A Business Process can not erase amounts")
if not explanation.getSpecialiseValue().getSameTotalQuantity():
return result
# Sort movement list and make sure the total is equal to total_quantity # Sort movement list and make sure the total is equal to total_quantity
total_quantity = amount.getQuantity() total_quantity = amount.getQuantity()
current_quantity = 0 current_quantity = 0
...@@ -799,9 +807,6 @@ class BusinessProcess(Path, XMLObject): ...@@ -799,9 +807,6 @@ class BusinessProcess(Path, XMLObject):
property_dict['causality'] = trade_model_path.getRelativeUrl() # XXX-JPS Will not work if we do not use real object property_dict['causality'] = trade_model_path.getRelativeUrl() # XXX-JPS Will not work if we do not use real object
#(ie. if we use kind of 'temp') #(ie. if we use kind of 'temp')
# Set trade_phase to the trade phase of trade_model_path
property_dict['trade_phase'] = trade_model_path.getTradePhase()
return property_dict return property_dict
# IBusinessProcess global API # IBusinessProcess global API
......
...@@ -94,26 +94,8 @@ class InvoiceTransactionSimulationRule(RuleMixin, ...@@ -94,26 +94,8 @@ class InvoiceTransactionSimulationRule(RuleMixin,
return (movement.getSource() is None or movement.getDestination() is None) return (movement.getSource() is None or movement.getDestination() is None)
class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin): class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin):
def getGeneratedMovementList(self, movement_list=None, rounding=False):
"""
Input movement list comes from order
XXX This implementation is very primitive, and does not support BPM,
i.e. business paths are not taken into account.
"""
ret = []
rule = self._rule
# input_movement, business_path = rule._getInputMovementAndPathTupleList(
# applied_rule)[0]
input_movement = self._applied_rule.getParentValue()
parent_movement = self._applied_rule.getParentValue()
# Find a matching cell
cell = rule._getMatchingCell(input_movement)
if cell is not None: def _getUpdatePropertyDict(self, input_movement):
for accounting_rule_cell_line in cell.objectValues():
# get the resource (in that order): # get the resource (in that order):
# * resource from the invoice (using deliveryValue) # * resource from the invoice (using deliveryValue)
# * price_currency from the invoice # * price_currency from the invoice
...@@ -121,16 +103,17 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin): ...@@ -121,16 +103,17 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin):
# deliveryValue # deliveryValue
# * price_currency from the top level simulation movement's # * price_currency from the top level simulation movement's
# orderValue # orderValue
resource = None
invoice_line = input_movement.getDeliveryValue() invoice_line = input_movement.getDeliveryValue()
if invoice_line is not None : if invoice_line is None:
resource = None
else:
invoice = invoice_line.getExplanationValue() invoice = invoice_line.getExplanationValue()
resource = invoice.getProperty('resource', resource = invoice.getProperty('resource',
invoice.getProperty('price_currency', None)) invoice.getProperty('price_currency', None))
if resource is None : if resource is None:
# search the resource on parents simulation movement's deliveries # search the resource on parents simulation movement's deliveries
simulation_movement = parent_movement simulation_movement = input_movement
portal_simulation = self._applied_rule.getPortalObject().portal_simulation portal_simulation = input_movement.getPortalObject().portal_simulation
while resource is None and \ while resource is None and \
simulation_movement != portal_simulation : simulation_movement != portal_simulation :
delivery = simulation_movement.getDeliveryValue() delivery = simulation_movement.getDeliveryValue()
...@@ -146,6 +129,40 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin): ...@@ -146,6 +129,40 @@ class InvoiceTransactionRuleMovementGenerator(MovementGeneratorMixin):
resource = order.getProperty('price_currency', None) resource = order.getProperty('price_currency', None)
simulation_movement = simulation_movement\ simulation_movement = simulation_movement\
.getParentValue().getParentValue() .getParentValue().getParentValue()
return {'delivery': None, 'resource': resource, 'price': 1}
def _getInputMovementList(self, movement_list=None, rounding=False):
simulation_movement = self._applied_rule.getParentValue()
input_movement = simulation_movement.asContext(
quantity=simulation_movement.getCorrectedQuantity() *
simulation_movement.getPrice(0.0))
# XXX trade_phase category should be added to Simulation Movements
input_movement._setCategoryMembership('trade_phase',
('default/accounting',))
return (input_movement,)
# TODO: add support for assert prices (see old code below)
def __getGeneratedMovementList(self, movement_list=None, rounding=False):
"""
Input movement list comes from order
XXX This implementation is very primitive, and does not support BPM,
i.e. business paths are not taken into account.
"""
ret = []
rule = self._rule
# input_movement, business_path = rule._getInputMovementAndPathTupleList(
# applied_rule)[0]
input_movement = self._applied_rule.getParentValue()
parent_movement = self._applied_rule.getParentValue()
# Find a matching cell
cell = rule._getMatchingCell(input_movement)
if cell is not None:
for accounting_rule_cell_line in cell.objectValues():
if resource is None : if resource is None :
# last resort : get the resource from the rule # last resort : get the resource from the rule
resource = accounting_rule_cell_line.getResource() \ resource = accounting_rule_cell_line.getResource() \
......
...@@ -134,5 +134,8 @@ class PaymentRuleMovementGenerator(MovementGeneratorMixin): ...@@ -134,5 +134,8 @@ class PaymentRuleMovementGenerator(MovementGeneratorMixin):
ret.append(simulation_movement) ret.append(simulation_movement)
return ret return ret
def _getUpdatePropertyDict(self, input_movement):
return {'delivery': None}
def _getInputMovementList(self, movement_list=None, rounding=None): def _getInputMovementList(self, movement_list=None, rounding=None):
return [self._applied_rule.getParentValue(),] return [self._applied_rule.getParentValue(),]
...@@ -89,6 +89,11 @@ class TradeModelSimulationRule(RuleMixin, MovementCollectionUpdaterMixin, Predic ...@@ -89,6 +89,11 @@ class TradeModelSimulationRule(RuleMixin, MovementCollectionUpdaterMixin, Predic
class TradeModelRuleMovementGenerator(MovementGeneratorMixin): class TradeModelRuleMovementGenerator(MovementGeneratorMixin):
def _getUpdatePropertyDict(self, input_movement):
return {'delivery': None,
# XXX shouldn't we create a tester for price instead ?
'price': input_movement.getPrice()}
def _getInputMovementList(self, movement_list=None, rounding=False): def _getInputMovementList(self, movement_list=None, rounding=False):
simulation_movement = self._applied_rule.getParentValue() simulation_movement = self._applied_rule.getParentValue()
trade_model = simulation_movement.asComposedDocument() trade_model = simulation_movement.asComposedDocument()
......
...@@ -43,6 +43,13 @@ class Rule: ...@@ -43,6 +43,13 @@ class Rule:
'default' : [], 'default' : [],
'multivalued' : 1, 'multivalued' : 1,
'mode' : 'w' }, 'mode' : 'w' },
{ 'id' : 'same_total_quantity',
'default' : 'Automatically fix quantities of generated movements'
' so that total quantity is the same as input'
' movement',
'type' : 'boolean',
'default' : True,
'mode' : 'w' },
) )
_categories = ('trade_phase', ) _categories = ('trade_phase', )
...@@ -76,8 +76,55 @@ class TestBPMMixin(ERP5TypeTestCase): ...@@ -76,8 +76,55 @@ class TestBPMMixin(ERP5TypeTestCase):
def createBusinessProcess(self, **kw): def createBusinessProcess(self, **kw):
module = self.portal.getDefaultModule( module = self.portal.getDefaultModule(
portal_type=self.business_process_portal_type) portal_type=self.business_process_portal_type)
return module.newContent(portal_type=self.business_process_portal_type, business_process = module.newContent(
portal_type=self.business_process_portal_type, **kw)
trade_phase = self.getCategoryTool().trade_phase
self.createTradeModelPath(business_process,
reference='default_path',
trade_phase_value_list=[x for x in trade_phase.default.objectValues()
if x.getId() != 'accounting'],
trade_date='trade_phase/default/order')
kw = dict(business_process=business_process,
trade_phase='default/accounting',
trade_date='trade_phase/default/order',
membership_criterion_base_category='resource_use')
self.createTradeModelPath(reference='acounting_tax1',
efficiency=-1,
source_value=self.receivable_account,
destination_value=self.payable_account,
membership_criterion_category='resource_use/use/tax',
**kw)
self.createTradeModelPath(reference='acounting_tax2',
efficiency=1,
source_value=self.collected_tax_account,
destination_value=self.refundable_tax_account,
membership_criterion_category='resource_use/use/tax',
**kw)
self.createTradeModelPath(reference='acounting_discount1',
efficiency=-1,
source_value=self.receivable_account,
destination_value=self.payable_account,
membership_criterion_category='resource_use/use/discount',
**kw)
self.createTradeModelPath(reference='acounting_discount2',
efficiency=1,
source_value=self.income_account,
destination_value=self.expense_account,
membership_criterion_category='resource_use/use/discount',
**kw)
self.createTradeModelPath(reference='acounting_normal1',
efficiency=-1,
source_value=self.receivable_account,
destination_value=self.payable_account,
membership_criterion_category='resource_use/use/normal',
**kw)
self.createTradeModelPath(reference='acounting_normal2',
efficiency=1,
source_value=self.income_account,
destination_value=self.expense_account,
membership_criterion_category='resource_use/use/normal',
**kw) **kw)
return business_process
@reindex @reindex
def createBusinessLink(self, business_process=None, **kw): def createBusinessLink(self, business_process=None, **kw):
...@@ -103,7 +150,6 @@ class TestBPMMixin(ERP5TypeTestCase): ...@@ -103,7 +150,6 @@ class TestBPMMixin(ERP5TypeTestCase):
portal_type='Applied Rule') portal_type='Applied Rule')
return applied_rule.newContent(portal_type='Simulation Movement') return applied_rule.newContent(portal_type='Simulation Movement')
@reindex
def createAndValidateAccount(self, account_id, account_type): def createAndValidateAccount(self, account_id, account_type):
account_module = self.portal.account_module account_module = self.portal.account_module
account = account_module.newContent(portal_type='Account', account = account_module.newContent(portal_type='Account',
...@@ -113,7 +159,7 @@ class TestBPMMixin(ERP5TypeTestCase): ...@@ -113,7 +159,7 @@ class TestBPMMixin(ERP5TypeTestCase):
account.validate() account.validate()
return account return account
def createInvoiceTransactionRule(self): def createAndValidateAccounts(self):
self.receivable_account = self.createAndValidateAccount('receivable', self.receivable_account = self.createAndValidateAccount('receivable',
'asset/receivable') 'asset/receivable')
self.payable_account = self.createAndValidateAccount('payable', self.payable_account = self.createAndValidateAccount('payable',
...@@ -126,90 +172,17 @@ class TestBPMMixin(ERP5TypeTestCase): ...@@ -126,90 +172,17 @@ class TestBPMMixin(ERP5TypeTestCase):
'refundable_tax', 'refundable_tax',
'asset/receivable/refundable_vat') 'asset/receivable/refundable_vat')
itr = self.portal.portal_rules.newContent(
portal_type='Invoice Transaction Simulation Rule',
reference='default_invoice_transaction_rule',
id='test_invoice_transaction_simulation_rule',
title='Transaction Simulation Rule',
test_method_id=
'SimulationMovement_testInvoiceTransactionSimulationRule',
version=100)
predicate = itr.newContent(portal_type='Predicate',)
predicate.edit(
string_index='use',
title='tax',
int_index=1,
membership_criterion_base_category='resource_use',
membership_criterion_category='resource_use/use/tax')
predicate = itr.newContent(portal_type='Predicate',)
predicate.edit(
string_index='use',
title='discount',
int_index=2,
membership_criterion_base_category='resource_use',
membership_criterion_category='resource_use/use/discount')
predicate = itr.newContent(portal_type='Predicate',)
predicate.edit(
string_index='use',
title='normal',
int_index=3,
membership_criterion_base_category='resource_use',
membership_criterion_category='resource_use/use/normal')
transaction.commit()
self.tic()
accounting_rule_cell_list = itr.contentValues(
portal_type='Accounting Rule Cell')
self.assertEquals(3, len(accounting_rule_cell_list))
tax_rule_cell = itr._getOb("movement_0")
self.assertEquals(tax_rule_cell.getTitle(), '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)
discount_rule_cell = itr._getOb("movement_1")
self.assertEquals(discount_rule_cell.getTitle(), 'discount')
discount_rule_cell.newContent(
portal_type='Accounting Transaction Line',
source_value=self.receivable_account,
destination_value=self.payable_account,
quantity=-1)
discount_rule_cell.newContent(
portal_type='Accounting Transaction Line',
source_value=self.income_account,
destination_value=self.expense_account,
quantity=1)
normal_rule_cell = itr._getOb("movement_2")
self.assertEquals(normal_rule_cell.getTitle(), 'normal')
normal_rule_cell.newContent(
portal_type='Accounting Transaction Line',
source_value=self.receivable_account,
destination_value=self.payable_account,
quantity=-1)
normal_rule_cell.newContent(
portal_type='Accounting Transaction Line',
source_value=self.income_account,
destination_value=self.expense_account,
quantity=1)
itr.validate()
def afterSetUp(self): def afterSetUp(self):
rule_tool = self.getRuleTool() rule_tool = self.getRuleTool()
for rule in rule_tool.contentValues( for rule in rule_tool.contentValues(
portal_type=rule_tool.getPortalRuleTypeList()): portal_type=rule_tool.getPortalRuleTypeList()):
if rule.getId().startswith('new_') and \ if (rule.getId().startswith('new_') and
rule.getValidationState() != 'validated': # XXX disable temporarily broken payment rule
rule.getId() != 'new_payment_simulation_rule' and
rule.getValidationState() != 'validated'):
rule.validate() rule.validate()
self.createCategories() self.createCategories()
self.createInvoiceTransactionRule() self.createAndValidateAccounts()
self.stepTic() self.stepTic()
def beforeTearDown(self): def beforeTearDown(self):
...@@ -220,9 +193,6 @@ class TestBPMMixin(ERP5TypeTestCase): ...@@ -220,9 +193,6 @@ class TestBPMMixin(ERP5TypeTestCase):
for table in 'message', 'message_queue': for table in 'message', 'message_queue':
activity_connection.manage_test( activity_connection.manage_test(
'delete from %s where processing_node=-2' % table) 'delete from %s where processing_node=-2' % table)
# remove not needed rules
self.portal.portal_rules.manage_delObjects(
ids=['test_invoice_transaction_simulation_rule'])
self.stepTic() self.stepTic()
class TestBPMImplementation(TestBPMMixin): class TestBPMImplementation(TestBPMMixin):
......
...@@ -229,6 +229,7 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -229,6 +229,7 @@ class TestTradeModelLine(TestTradeModelLineMixin):
sequence.edit(business_link=None, business_link_taxing=business_link) sequence.edit(business_link=None, business_link_taxing=business_link)
def stepCreateTradeModelPath(self, sequence): def stepCreateTradeModelPath(self, sequence):
return
trade_phase = self.getCategoryTool().trade_phase trade_phase = self.getCategoryTool().trade_phase
sequence.set('trade_model_path_default', self.createTradeModelPath( sequence.set('trade_model_path_default', self.createTradeModelPath(
sequence.get('business_process'), sequence.get('business_process'),
......
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