# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
##############################################################################
 
import transaction
import functools
from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.SlapOS.tests.testSlapOSMixin import \
  testSlapOSMixin, withAbort
import os
import tempfile
from DateTime import DateTime
from Products.ERP5Type.DateUtils import addToDate, getClosestDate
from zExceptions import Unauthorized
 
class Simulator:
  def __init__(self, outfile, method, to_return=None):
    self.outfile = outfile
    open(self.outfile, 'w').write(repr([]))
    self.method = method
    self.to_return = to_return
 
  def __call__(self, *args, **kwargs):
    """Simulation Method"""
    old = open(self.outfile, 'r').read()
    if old:
      l = eval(old)
    else:
      l = []
    l.append({'recmethod': self.method,
      'recargs': args,
      'reckwargs': kwargs})
    open(self.outfile, 'w').write(repr(l))
    return self.to_return
 
def simulateByEditWorkflowMark(script_name):
  def wrapper(func):
    @functools.wraps(func)
    def wrapped(self, *args, **kwargs):
      if script_name in self.portal.portal_skins.custom.objectIds():
        raise ValueError('Precondition failed: %s exists in custom' % script_name)
      createZODBPythonScript(self.portal.portal_skins.custom,
                          script_name,
                          '*args, **kwargs',
                          '# Script body\n'
  """context.portal_workflow.doActionFor(context, action='edit_action', comment='Visited by %s') """%script_name )
      transaction.commit()
      try:
        func(self, *args, **kwargs)
      finally:
        if script_name in self.portal.portal_skins.custom.objectIds():
          self.portal.portal_skins.custom.manage_delObjects(script_name)
        transaction.commit()
    return wrapped
  return wrapper
 
def simulateByTitlewMark(script_name):
  def wrapper(func):
    @functools.wraps(func)
    def wrapped(self, *args, **kwargs):
      if script_name in self.portal.portal_skins.custom.objectIds():
        raise ValueError('Precondition failed: %s exists in custom' % script_name)
      createZODBPythonScript(self.portal.portal_skins.custom,
                          script_name,
                          '*args, **kwargs',
                          '# Script body\n'
"""
if context.getTitle() == 'Not visited by %s':
  context.setTitle('Visited by %s')
""" %(script_name, script_name))
      transaction.commit()
      try:
        func(self, *args, **kwargs)
      finally:
        if script_name in self.portal.portal_skins.custom.objectIds():
          self.portal.portal_skins.custom.manage_delObjects(script_name)
        transaction.commit()
    return wrapped
  return wrapper
 
class TestInstanceInvoicingAlarm(testSlapOSMixin):
  @withAbort
  def test_noSaleOrderPackingList_newSoftwareInstance(self):
    """
    Be sure no delivery is created synchronously (break old code behaviour)
    """
    self.software_instance_request_kw = dict(
      software_release=self.generateNewSoftwareReleaseUrl(),
      software_type=self.generateNewSoftwareType(),
      instance_xml=self.generateSafeXml(),
      sla_xml=self.generateSafeXml(),
      shared=False,
    )
    instance = self.portal.software_instance_module.template_software_instance\
        .Base_createCloneDocument(batch_mode=1)
    instance.edit(title="TESTSI-%s" % self.generateNewId())
    instance.requestStart(**self.software_instance_request_kw)
 
    self.assertEqual(None, instance.getCausalityValue())
 
  @withAbort
  def test_noSaleOrderPackingList_newSlaveInstance(self):
    """
    Be sure no delivery is created synchronously (break old code behaviour)
    """
    self.slave_instance_request_kw = dict(
      software_release=self.generateNewSoftwareReleaseUrl(),
      software_type=self.generateNewSoftwareType(),
      instance_xml=self.generateSafeXml(),
      sla_xml=self.generateSafeXml(),
      shared=True,
    )
 
    instance = self.portal.software_instance_module.template_slave_instance\
        .Base_createCloneDocument(batch_mode=1)
    instance.edit(title="TESTSI-%s" % self.generateNewId())
    instance.requestStart(**self.slave_instance_request_kw)
    self.tic()
 
    self.assertEqual(None, instance.getCausalityValue())
 
  @simulateByEditWorkflowMark('Instance_solveInvoicingGeneration')
  def test_alarm_findSoftwareInstance(self):
    new_id = self.generateNewId()
    instance = self.portal.software_instance_module.newContent(
      portal_type='Software Instance',
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      ssl_certificate="foo",
      ssl_key="bar",
      )
 
    self.tic()
 
    self.portal.portal_alarms\
        .slapos_instance_invoicing\
        .activeSense()
    self.tic()
    self.assertEqual(
        'Visited by Instance_solveInvoicingGeneration',
        instance.workflow_history['edit_workflow'][-1]['comment'])
 
  @simulateByEditWorkflowMark('Instance_solveInvoicingGeneration')
  def test_alarm_findSlaveInstance(self):
    new_id = self.generateNewId()
    instance = self.portal.software_instance_module.newContent(
      portal_type='Slave Instance',
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      )
 
    self.tic()
 
    self.portal.portal_alarms\
        .slapos_instance_invoicing\
        .activeSense()
    self.tic()
    self.assertEqual(
        'Visited by Instance_solveInvoicingGeneration',
        instance.workflow_history['edit_workflow'][-1]['comment'])
 
  @withAbort
  def test_solved_instance(self):
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
    )
 
    request_time = DateTime('2012/01/01')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroyed',
        'time': request_time,
        'action': 'request_instance'
    })
    self.portal.portal_workflow._jumpToStateFor(instance, 'solved')
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertEqual(None, instance.getCausalityValue())
 
  @withAbort
  def test_instance_in_draft_state(self):
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Stay in draft',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'draft',
        'time': DateTime(),
        'action': 'foo_transition'
    })
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertEqual(None, instance.getCausalityValue())
 
  @withAbort
  def test_instance_in_unknown_state(self):
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Stay in unknown state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'unknown_state',
        'time': DateTime(),
        'action': 'foo_transition'
    })
 
    self.assertRaises(AssertionError, instance.Instance_solveInvoicingGeneration) 
 
  @withAbort
  def test_instance_in_early_destroyed_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    start_date = instance.workflow_history\
      ['instance_slap_interface_workflow'][0]['time']
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in destroyed state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(2, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 2)
    self.check_instance_movement(setup_line, instance, subscription, 1)
    self.check_instance_movement(destroy_line, instance, subscription, 1)
 
  def check_instance_delivery(self, delivery, start_date, stop_date, 
                              person, line_count):
    packing_list_line = delivery.contentValues(
      portal_type='Sale Packing List Line')
    self.assertEqual(len(packing_list_line), line_count)
    self.assertEqual(delivery.getDestinationValue(), person)
    self.assertEqual(delivery.getDestinationDecisionValue(), person)
    self.assertEqual(delivery.getSpecialise(), 'sale_trade_condition_module'
        '/slapos_consumption_trade_condition')
    self.assertEqual(delivery.getStopDate(), stop_date)
    self.assertEqual(delivery.getStartDate(), start_date)
    self.assertEqual(delivery.getSimulationState(), 'delivered')
    self.assertEqual(delivery.getCausalityState(), 'building')
 
    # Hardcoded, but, no idea how to not make it...
    setup_line = ([None]+[x for x in packing_list_line \
      if x.getResource() == 'service_module/slapos_instance_setup'])[-1]
    destroy_line = ([None]+[x for x in packing_list_line \
      if x.getResource() == 'service_module/slapos_instance_cleanup'])[-1]
    update_line = ([None]+[x for x in packing_list_line \
      if x.getResource() == 'service_module/slapos_instance_update'])[-1]
    return setup_line, update_line, destroy_line
 
  def check_instance_movement(self, movement, instance, 
                              subscription, quantity):
    self.assertEqual(movement.getQuantity(), quantity)
    self.assertSameSet(movement.getAggregateValueList(),
                       [instance, subscription])
    self.assertEqual(len(movement.contentValues()), 0)
 
  @withAbort
  def test_instance_create_non_destroyed_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    start_date = instance.workflow_history\
      ['instance_slap_interface_workflow'][0]['time']
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in start state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(2, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 1)
    self.check_instance_movement(setup_line, instance, subscription, 1)
 
  @withAbort
  def test_instance_create_non_destroyed_with_update_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    start_date = instance.workflow_history\
      ['instance_slap_interface_workflow'][0]['time']
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-1,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-2,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in start state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(4, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 2)
    self.check_instance_movement(setup_line, instance, subscription, 1)
    self.check_instance_movement(update_line, instance, subscription, 2)
 
  @withAbort
  def test_instance_create_destroyed_with_update_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    start_date = instance.workflow_history\
      ['instance_slap_interface_workflow'][0]['time']
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-1,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-2,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in destroy state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(4, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 3)
    self.check_instance_movement(setup_line, instance, subscription, 1)
    self.check_instance_movement(update_line, instance, subscription, 1)
    self.check_instance_movement(destroy_line, instance, subscription, 1)
 
  @withAbort
  def test_instance_update_non_destroyed_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    previous_delivery = self.portal.sale_packing_list_module.newContent(
      portal_type='Sale Packing List')
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
      invoicing_synchronization_pointer=2,
      causality_value=previous_delivery,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-1,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-2,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in start state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
    start_date = stop_date-1
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(4, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 1)
    self.check_instance_movement(update_line, instance, subscription, 2)
 
  @withAbort
  def test_instance_update_destroyed_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    previous_delivery = self.portal.sale_packing_list_module.newContent(
      portal_type='Sale Packing List')
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
      invoicing_synchronization_pointer=2,
      causality_value=previous_delivery,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-1,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'foo_state',
        'time': stop_date-2,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in start state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
    start_date = stop_date-1
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(4, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 2)
    self.check_instance_movement(update_line, instance, subscription, 1)
    self.check_instance_movement(destroy_line, instance, subscription, 1)
 
  @withAbort
  def test_instance_update_already_destroyed(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    previous_delivery = self.portal.sale_packing_list_module.newContent(
      portal_type='Sale Packing List')
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
      invoicing_synchronization_pointer=2,
      causality_value=previous_delivery,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date-1,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Update',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date-2,
        'action': 'foo_transition'
    })
    instance.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Directly in start state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date,
        'action': 'foo_transition'
    })
    start_date = stop_date-1
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(4, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, start_date, stop_date, person, 1)
    self.check_instance_movement(update_line, instance, subscription, 2)
 
  @withAbort
  def test_instance_in_only_destroyed_state(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(
      reference='TESTHS-%s' % self.generateNewId(),
      destination_section_value=person)
    instance = self.portal.software_instance_module\
        .template_slave_instance.Base_createCloneDocument(batch_mode=1)
    new_id = self.generateNewId()
    instance.edit(
      title="Instance %s" % new_id,
      reference="TESTINST-%s" % new_id,
      destination_reference="TESTINST-%s" % new_id,
      specialise_value=subscription,
    )
    self.portal.portal_workflow._jumpToStateFor(instance, 'diverged')
    stop_date = DateTime('2222/11/15')
    instance.workflow_history['instance_slap_interface_workflow'] = [{
        'comment':'Directly in destroyed state',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': stop_date,
        'action': 'foo_transition'
    }]
 
    instance.Instance_solveInvoicingGeneration()
    self.assertEqual(instance.getCausalityState(), 'solved')
    self.assertNotEqual(None, instance.getCausalityValue())
    self.assertEqual(1, instance.getInvoicingSynchronizationPointer())
    delivery = instance.getCausalityValue()
 
    setup_line, update_line, destroy_line =\
      self.check_instance_delivery(delivery, stop_date, stop_date, person, 1)
    self.check_instance_movement(update_line, instance, subscription, 1)
 
class TestOpenSaleOrderAlarm(testSlapOSMixin):
  def test_noOSO_newPerson(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
 
    self.assertEqual(None, self.portal.portal_catalog.getResultValue(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    ))
 
  def test_noOSO_after_fixConsistency(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    person.fixConsistency()
    self.tic()
 
    self.assertEqual(None, self.portal.portal_catalog.getResultValue(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    ))
 
  def test_OSO_after_Person_updateOpenSaleOrder(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
 
    person.Person_storeOpenSaleOrderJournal()
    self.tic()
 
    open_sale_order_list = self.portal.portal_catalog(
        validation_state='validated',
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
    # No need to create any open order without hosting subscription
    self.assertEqual(0, len(open_sale_order_list))
 
  @simulateByEditWorkflowMark('HostingSubscription_requestUpdateOpenSaleOrder')
  def test_alarm_HS_diverged(self):
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId())
    self.tic()
 
    self.portal.portal_alarms\
        .slapos_request_update_hosting_subscription_open_sale_order\
        .activeSense()
    self.tic()
    self.assertEqual(
        'Visited by HostingSubscription_requestUpdateOpenSaleOrder',
        subscription.workflow_history['edit_workflow'][-1]['comment'])
 
class TestHostingSubscription_requestUpdateOpenSaleOrder(testSlapOSMixin):
  def test_REQUEST_disallowed(self):
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    self.assertRaises(
      Unauthorized,
      subscription.HostingSubscription_requestUpdateOpenSaleOrder,
      REQUEST={})
 
  def test_solved_HostingSubscription(self):
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    self.portal.portal_workflow._jumpToStateFor(subscription, 'solved')
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
  def test_empty_HostingSubscription(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(1,len(open_sale_order_list))
    open_sale_order = open_sale_order_list[0].getObject()
    self.assertEqual('validated', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    line = open_sale_order_line_list[0].getObject()
 
    self.assertEqual(subscription.getRelativeUrl(), line.getAggregate())
    open_sale_order_line_template = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())
    self.assertEqual(open_sale_order_line_template.getResource(),
        line.getResource())
    self.assertTrue(all([q in line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(DateTime().earliestTime(), line.getStartDate())
    self.assertEqual(min(DateTime().day(), 28),
                     subscription.getPeriodicityMonthDay())
    start_date = addToDate(line.getStartDate(), to_add={'month': 1})
    start_date = addToDate(start_date, to_add={'second': -1})
    while start_date.day() >= 28:
      start_date = addToDate(start_date, to_add={'day': -1})
    self.assertEqual(start_date, line.getStopDate())
 
  def test_usualLifetime_HostingSubscription(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        title='Test Title %s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
 
    request_time = DateTime('2012/01/01')
    subscription.workflow_history['instance_slap_interface_workflow'] = [{
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': request_time,
        'action': 'request_instance'
    }]
    subscription.edit(periodicity_month_day_list=[])
    subscription.fixConsistency()
    self.assertEqual(subscription.getPeriodicityMonthDay(), 1)
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(1, len(open_sale_order_list))
    open_sale_order = open_sale_order_list[0].getObject()
    self.assertEqual('validated', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    line = open_sale_order_line_list[0].getObject()
 
    # calculate stop date to be after now, begin with start date with precision
    # of month
    now = DateTime()
    now = now.toZone(request_time.timezone())
    stop_date = getClosestDate(target_date=now, precision='month')
    stop_date = addToDate(stop_date, to_add={'second': -1})
    self.assertEqual(stop_date, line.getStopDate())
 
    self.assertEqual(subscription.getRelativeUrl(), line.getAggregate())
    open_sale_order_line_template = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())
    self.assertTrue(all([q in line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        line.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time, line.getStartDate())
    self.assertEqual(stop_date, line.getStopDate())
 
    destroy_time = DateTime('2112/02/01')
    subscription.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': destroy_time,
        'action': 'request_destroy'
    })
    subscription.diverge()
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(2, len(open_sale_order_list))
    validated_open_sale_order_list = [q for q in open_sale_order_list
        if q.getValidationState() == 'validated']
    archived_open_sale_order_list = [q for q in open_sale_order_list
        if q.getValidationState() == 'archived']
    self.assertEqual(1, len(validated_open_sale_order_list))
    self.assertEqual(1, len(archived_open_sale_order_list))
    validated_open_sale_order = validated_open_sale_order_list[0].getObject()
    archived_open_sale_order = archived_open_sale_order_list[0]\
        .getObject()
    self.assertEqual(open_sale_order.getRelativeUrl(),
        archived_open_sale_order.getRelativeUrl())
 
    validated_line_list = validated_open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
    archived_line_list = archived_open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
    self.assertEqual(0, len(validated_line_list))
    self.assertEqual(1, len(archived_line_list))
 
    archived_line = archived_line_list[0].getObject()
 
    self.assertEqual(line.getRelativeUrl(), archived_line.getRelativeUrl())
 
    self.assertEqual(subscription.getRelativeUrl(),
        archived_line.getAggregate())
    self.assertTrue(all([q in archived_line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        archived_line.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time, archived_line.getStartDate())
    self.assertEqual(DateTime('2112/02/02'), line.getStopDate())
 
  def test_lateAnalysed_HostingSubscription(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        title='Test Title %s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
 
    subscription.workflow_history['instance_slap_interface_workflow'] = []
    request_time = DateTime('2012/01/01')
    subscription.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': request_time,
        'action': 'request_instance'
    })
 
    destroy_time = DateTime('2012/02/01')
    subscription.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'destroy_requested',
        'time': destroy_time,
        'action': 'request_destroy'
    })
    subscription.edit(periodicity_month_day_list=[])
    subscription.fixConsistency()
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(2, len(open_sale_order_list))
    open_sale_order = [x for x in open_sale_order_list \
                       if x.getValidationState() != 'validated'][0].getObject()
    self.assertEqual('archived', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    line = open_sale_order_line_list[0].getObject()
 
    self.assertEqual(subscription.getRelativeUrl(), line.getAggregate())
    open_sale_order_line_template = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())
    self.assertTrue(all([q in line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        line.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time, line.getStartDate())
 
    self.assertEqual(DateTime('2012/02/02'), line.getStopDate())
 
    new_open_sale_order = [x for x in open_sale_order_list \
                           if x.getValidationState() == 'validated'][0].getObject()
    self.assertEqual('validated', new_open_sale_order.getValidationState())
    open_sale_order_line_list = new_open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
    self.assertEqual(0, len(open_sale_order_line_list))
 
  def test_two_HostingSubscription(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        title='Test Title %s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
 
    request_time = DateTime('2012/01/01')
    subscription.workflow_history['instance_slap_interface_workflow'] = [{
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': request_time,
        'action': 'request_instance'
    }]
    subscription.edit(periodicity_month_day_list=[])
    subscription.fixConsistency()
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(1, len(open_sale_order_list))
    open_sale_order = open_sale_order_list[0].getObject()
    self.assertEqual('validated', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    line = open_sale_order_line_list[0].getObject()
 
    self.assertEqual(subscription.getRelativeUrl(), line.getAggregate())
    open_sale_order_line_template = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())
    self.assertTrue(all([q in line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        line.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time, line.getStartDate())
 
    # calculate stop date to be after now, begin with start date with precision
    # of month
    stop_date = request_time
    next_stop_date = stop_date
    now = DateTime()
    while next_stop_date < now:
      stop_date = next_stop_date
      next_stop_date = addToDate(stop_date, to_add={'month': 1})
    stop_date = addToDate(stop_date, to_add={'second': -1})
    self.assertEqual(stop_date, line.getStopDate())
 
    subscription2 = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription2.edit(reference='TESTHS-%s' % self.generateNewId(),
        title='Test Title %s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription2, 'validated')
 
    request_time_2 = DateTime('2012/08/01')
    subscription2.workflow_history['instance_slap_interface_workflow'] = [{
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': request_time_2,
        'action': 'request_instance'
    }]
    subscription2.edit(periodicity_month_day_list=[])
    subscription2.fixConsistency()
    self.tic()
 
    subscription2.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(1, len(open_sale_order_list))
    validated_open_sale_order_list = [q for q in open_sale_order_list
        if q.getValidationState() == 'validated']
    archived_open_sale_order_list = [q for q in open_sale_order_list
        if q.getValidationState() == 'archived']
    self.assertEqual(1, len(validated_open_sale_order_list))
    self.assertEqual(0, len(archived_open_sale_order_list))
    validated_open_sale_order = validated_open_sale_order_list[0].getObject()
 
    validated_line_list = validated_open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
    self.assertEqual(2, len(validated_line_list))
 
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
 
    stop_date_2 = request_time_2
    next_stop_date_2 = stop_date_2
    now = DateTime()
    while next_stop_date_2 < now:
      stop_date_2 = next_stop_date_2
      next_stop_date_2 = addToDate(stop_date_2, to_add={'month': 1})
    stop_date_2 = addToDate(stop_date_2, to_add={'second': -1})
 
    validated_line_1 = [q for q in validated_line_list if q.getAggregate() == \
        subscription.getRelativeUrl()][0]
    validated_line_2 = [q for q in validated_line_list if q.getAggregate() == \
        subscription2.getRelativeUrl()][0]
 
    self.assertTrue(all([q in validated_line_1.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        validated_line_1.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time, validated_line_1.getStartDate())
    self.assertEqual(stop_date, validated_line_1.getStopDate())
 
    self.assertTrue(all([q in validated_line_2.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getResource(),
        validated_line_2.getResource())
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(request_time_2, validated_line_2.getStartDate())
    self.assertEqual(stop_date_2, validated_line_2.getStopDate())
 
  def test_hosting_subscription_start_date_not_changed(self):
    # if there was no request_instance the getCreationDate has been used
    # but if request_instance appeared start_date is not changed
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
 
    request_time = DateTime('2112/01/01')
    subscription.workflow_history['instance_slap_interface_workflow'].append({
        'comment':'Simulated request instance',
        'error_message': '',
        'actor': 'ERP5TypeTestCase',
        'slap_state': 'start_requested',
        'time': request_time,
        'action': 'request_instance'
    })
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(1, len(open_sale_order_list))
    open_sale_order = open_sale_order_list[0].getObject()
    self.assertEqual('validated', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    line = open_sale_order_line_list[0].getObject()
    self.assertEqual(subscription.getCreationDate().earliestTime(),
                     line.getStartDate())
 
  def test_hosting_subscription_diverged_to_solve(self):
    # check that HS becomes solved even if not modification is needed on open
    # order
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
    self.assertEqual(subscription.getCausalityState(), 'diverged')
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    self.portal.portal_workflow._jumpToStateFor(subscription, 'diverged')
    subscription.reindexObject()
    self.assertEqual(subscription.getCausalityState(), 'diverged')
    self.assertEqual(subscription.getSlapState(), 'draft')
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
  def test_empty_destroyed_HostingSubscription(self):
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    self.tic()
    subscription = self.portal.hosting_subscription_module\
        .template_hosting_subscription.Base_createCloneDocument(batch_mode=1)
    subscription.edit(reference='TESTHS-%s' % self.generateNewId(),
        destination_section=person.getRelativeUrl())
    self.portal.portal_workflow._jumpToStateFor(subscription, 'validated')
    self.portal.portal_workflow._jumpToStateFor(subscription, 'destroy_requested')
    self.tic()
 
    subscription.HostingSubscription_requestUpdateOpenSaleOrder()
    self.tic()
    self.assertEqual(subscription.getCausalityState(), 'solved')
 
    open_sale_order_list = self.portal.portal_catalog(
        portal_type='Open Sale Order',
        default_destination_uid=person.getUid()
    )
 
    self.assertEqual(2,len(open_sale_order_list))
    open_sale_order = [x for x in open_sale_order_list \
                       if x.getValidationState() != 'validated'][0].getObject()
    self.assertEqual('archived', open_sale_order.getValidationState())
 
    open_sale_order_line_list = open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
 
    self.assertEqual(1, len(open_sale_order_line_list))
    effective_date = open_sale_order.getEffectiveDate()
    line = open_sale_order_line_list[0].getObject()
 
    self.assertEqual(subscription.getRelativeUrl(), line.getAggregate())
    open_sale_order_line_template = self.portal.restrictedTraverse(
        self.portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())
    self.assertEqual(open_sale_order_line_template.getResource(),
        line.getResource())
    self.assertTrue(all([q in line.getCategoryList() \
        for q in open_sale_order_line_template.getCategoryList()]))
    self.assertEqual(open_sale_order_line_template.getQuantity(),
        line.getQuantity())
    self.assertEqual(open_sale_order_line_template.getPrice(),
        line.getPrice())
    self.assertEqual(DateTime().earliestTime(), line.getStartDate())
    self.assertEqual(addToDate(line.getStartDate(), to_add={'day': 1}),
                     line.getStopDate())
 
    new_open_sale_order = [x for x in open_sale_order_list \
                           if x.getValidationState() == 'validated'][0].getObject()
    self.assertEqual('validated', new_open_sale_order.getValidationState())
    new_effective_date = new_open_sale_order.getEffectiveDate()
    open_sale_order_line_list = new_open_sale_order.contentValues(
        portal_type='Open Sale Order Line')
    self.assertEqual(0, len(open_sale_order_line_list))
    self.assertTrue(new_effective_date > effective_date,
                    "%s <= %s" % (new_effective_date, effective_date))
 
class TestSlapOSTriggerBuildAlarm(testSlapOSMixin):
  @simulateByTitlewMark('SimulationMovement_buildSlapOS')
  def test_SimulationMovement_withoutDelivery(self):
    applied_rule = self.portal.portal_simulation.newContent(
        portal_type='Applied Rule')
    simulation_movement = applied_rule.newContent(
        portal_type='Simulation Movement',
        title='Not visited by SimulationMovement_buildSlapOS')
    self.tic()
 
    self.portal.portal_alarms.slapos_trigger_build.activeSense()
    self.tic()
 
    self.assertEqual(
        'Visited by SimulationMovement_buildSlapOS',
        simulation_movement.getTitle())
 
  @simulateByTitlewMark('SimulationMovement_buildSlapOS')
  def test_SimulationMovement_withDelivery(self):
    delivery = self.portal.sale_packing_list_module.newContent(
        portal_type='Sale Packing List')
    delivery_line = delivery.newContent(portal_type='Sale Packing List Line')
    applied_rule = self.portal.portal_simulation.newContent(
        portal_type='Applied Rule')
    simulation_movement = applied_rule.newContent(
        portal_type='Simulation Movement',
        delivery=delivery_line.getRelativeUrl(),
        title='Shall be visited by SimulationMovement_buildSlapOS')
    self.tic()
 
    self.portal.portal_alarms.slapos_trigger_build.activeSense()
    self.tic()
 
    self.assertNotEqual(
        'Not visited by SimulationMovement_buildSlapOS',
        simulation_movement.getTitle())
 
  @withAbort
  def test_SimulationMovement_buildSlapOS(self):
    business_process = self.portal.business_process_module.newContent(
        portal_type='Business Process')
    root_business_link = business_process.newContent(
        portal_type='Business Link')
    business_link = business_process.newContent(portal_type='Business Link')
 
    root_applied_rule = self.portal.portal_simulation.newContent(
        portal_type='Applied Rule')
    simulation_movement = root_applied_rule.newContent(
        causality=root_business_link.getRelativeUrl(),
        portal_type='Simulation Movement')
 
    applied_rule = simulation_movement.newContent(portal_type='Applied Rule')
    lower_simulation_movement = applied_rule.newContent(
        causality=business_link.getRelativeUrl(),
        portal_type='Simulation Movement')
 
    build_simulator = tempfile.mkstemp()[1]
    activate_simulator = tempfile.mkstemp()[1]
    try:
      from Products.CMFActivity.ActiveObject import ActiveObject
      ActiveObject.original_activate = ActiveObject.activate
      ActiveObject.activate = Simulator(activate_simulator, 'activate',
          root_applied_rule)
      from Products.ERP5.Document.BusinessLink import BusinessLink
      BusinessLink.original_build = BusinessLink.build
      BusinessLink.build = Simulator(build_simulator, 'build')
 
      simulation_movement.SimulationMovement_buildSlapOS(tag='root_tag')
 
      build_value = eval(open(build_simulator).read())
      activate_value = eval(open(activate_simulator).read())
 
      self.assertEqual([{
        'recmethod': 'build',
        'recargs': (),
        'reckwargs': {'path': '%s/%%' % root_applied_rule.getPath(),
        'activate_kw': {'tag': 'root_tag'}}}],
        build_value
      )
      self.assertEqual([{
        'recmethod': 'activate',
        'recargs': (),
        'reckwargs': {'tag': 'build_in_progress_%s_%s' % (
            root_business_link.getUid(), root_applied_rule.getUid()),
          'after_tag': 'root_tag', 'activity': 'SQLQueue'}}],
        activate_value)
 
      open(build_simulator, 'w').truncate()
      open(activate_simulator, 'w').truncate()
 
      lower_simulation_movement.SimulationMovement_buildSlapOS(tag='lower_tag')
      build_value = eval(open(build_simulator).read())
      activate_value = eval(open(activate_simulator).read())
 
      self.assertEqual([{
        'recmethod': 'build',
        'recargs': (),
        'reckwargs': {'path': '%s/%%' % root_applied_rule.getPath(),
        'activate_kw': {'tag': 'lower_tag'}}}],
        build_value
      )
      self.assertEqual([{
        'recmethod': 'activate',
        'recargs': (),
        'reckwargs': {'tag': 'build_in_progress_%s_%s' % (
            business_link.getUid(), root_applied_rule.getUid()),
          'after_tag': 'lower_tag', 'activity': 'SQLQueue'}}],
        activate_value)
 
    finally:
      ActiveObject.activate = ActiveObject.original_activate
      delattr(ActiveObject, 'original_activate')
      BusinessLink.build = BusinessLink.original_build
      delattr(BusinessLink, 'original_build')
      if os.path.exists(build_simulator):
        os.unlink(build_simulator)
      if os.path.exists(activate_simulator):
        os.unlink(activate_simulator)
 
  @withAbort
  def test_SimulationMovement_buildSlapOS_withDelivery(self):
    delivery = self.portal.sale_packing_list_module.newContent(
        portal_type='Sale Packing List')
    delivery_line = delivery.newContent(portal_type='Sale Packing List Line')
    business_process = self.portal.business_process_module.newContent(
        portal_type='Business Process')
    root_business_link = business_process.newContent(
        portal_type='Business Link')
    business_link = business_process.newContent(portal_type='Business Link')
 
    root_applied_rule = self.portal.portal_simulation.newContent(
        portal_type='Applied Rule')
    simulation_movement = root_applied_rule.newContent(
        causality=root_business_link.getRelativeUrl(),
        delivery=delivery_line.getRelativeUrl(),
        portal_type='Simulation Movement')
 
    applied_rule = simulation_movement.newContent(portal_type='Applied Rule')
    lower_simulation_movement = applied_rule.newContent(
        causality=business_link.getRelativeUrl(),
        delivery=delivery_line.getRelativeUrl(),
        portal_type='Simulation Movement')
 
    build_simulator = tempfile.mkstemp()[1]
    activate_simulator = tempfile.mkstemp()[1]
    try:
      from Products.CMFActivity.ActiveObject import ActiveObject
      ActiveObject.original_activate = ActiveObject.activate
      ActiveObject.activate = Simulator(activate_simulator, 'activate',
          root_applied_rule)
      from Products.ERP5.Document.BusinessLink import BusinessLink
      BusinessLink.original_build = BusinessLink.build
      BusinessLink.build = Simulator(build_simulator, 'build')
 
      simulation_movement.SimulationMovement_buildSlapOS(tag='root_tag')
 
      build_value = eval(open(build_simulator).read())
      activate_value = eval(open(activate_simulator).read())
 
      self.assertEqual([], build_value)
      self.assertEqual([], activate_value)
 
      open(build_simulator, 'w').write(repr([]))
      open(activate_simulator, 'w').write(repr([]))
 
      lower_simulation_movement.SimulationMovement_buildSlapOS(tag='lower_tag')
      build_value = eval(open(build_simulator).read())
      activate_value = eval(open(activate_simulator).read())
 
      self.assertEqual([], build_value)
      self.assertEqual([], activate_value)
 
    finally:
      ActiveObject.activate = ActiveObject.original_activate
      delattr(ActiveObject, 'original_activate')
      BusinessLink.build = BusinessLink.original_build
      delattr(BusinessLink, 'original_build')
      if os.path.exists(build_simulator):
        os.unlink(build_simulator)
      if os.path.exists(activate_simulator):
        os.unlink(activate_simulator)
 
class TestSlapOSManageBuildingCalculatingDeliveryAlarm(testSlapOSMixin):
  @simulateByTitlewMark('Delivery_manageBuildingCalculatingDelivery')
  def _test(self, state, message):
    delivery = self.portal.sale_packing_list_module.newContent(
        title='Not visited by Delivery_manageBuildingCalculatingDelivery',
        portal_type='Sale Packing List')
    self.portal.portal_workflow._jumpToStateFor(delivery, state)
    self.tic()
 
    self.portal.portal_alarms.slapos_manage_building_calculating_delivery\
        .activeSense()
    self.tic()
 
    self.assertEqual(message, delivery.getTitle())
 
  def test_building(self):
    self._test('building', 'Visited by Delivery_manageBuildingCalculatingDelivery')
 
  def test_calculating(self):
    self._test('calculating', 'Visited by Delivery_manageBuildingCalculatingDelivery')
 
  def test_diverged(self):
    self._test('diverged', 'Not visited by Delivery_manageBuildingCalculatingDelivery')
 
  def test_solved(self):
    self._test('solved', 'Not visited by Delivery_manageBuildingCalculatingDelivery')
 
  @withAbort
  def _test_Delivery_manageBuildingCalculatingDelivery(self, state, empty=False):
    delivery = self.portal.sale_packing_list_module.newContent(
        title='Not visited by Delivery_manageBuildingCalculatingDelivery',
        portal_type='Sale Packing List')
    self.portal.portal_workflow._jumpToStateFor(delivery, state)
 
    updateCausalityState_simulator = tempfile.mkstemp()[1]
    updateSimulation_simulator = tempfile.mkstemp()[1]
    try:
      from Products.ERP5.Document.Delivery import Delivery
      Delivery.original_updateCausalityState = Delivery\
          .updateCausalityState
      Delivery.updateCausalityState = Simulator(
          updateCausalityState_simulator, 'updateCausalityState')
      Delivery.updateSimulation = Simulator(
          updateSimulation_simulator, 'updateSimulation')
 
      delivery.Delivery_manageBuildingCalculatingDelivery()
 
      updateCausalityState_value = eval(open(updateCausalityState_simulator).read())
      updateSimulation_value = eval(open(updateSimulation_simulator).read())
 
      if empty:
        self.assertEqual([], updateCausalityState_value)
        self.assertEqual([], updateSimulation_value)
      else:
        self.assertEqual([{
          'recmethod': 'updateCausalityState',
          'recargs': (),
          'reckwargs': {'solve_automatically': True}}],
          updateCausalityState_value
        )
        self.assertEqual([{
          'recmethod': 'updateSimulation',
          'recargs': (),
          'reckwargs': {'expand_root': 1, 'expand_related': 1}}],
          updateSimulation_value
        )
    finally:
      Delivery.updateCausalityState = Delivery.original_updateCausalityState
      delattr(Delivery, 'original_updateCausalityState')
      if os.path.exists(updateCausalityState_simulator):
        os.unlink(updateCausalityState_simulator)
      if os.path.exists(updateSimulation_simulator):
        os.unlink(updateSimulation_simulator)
 
  def test_Delivery_manageBuildingCalculatingDelivery_calculating(self):
    self._test_Delivery_manageBuildingCalculatingDelivery('calculating')
 
  def test_Delivery_manageBuildingCalculatingDelivery_building(self):
    self._test_Delivery_manageBuildingCalculatingDelivery('building')
 
  def test_Delivery_manageBuildingCalculatingDelivery_solved(self):
    self._test_Delivery_manageBuildingCalculatingDelivery('solved', True)
 
  def test_Delivery_manageBuildingCalculatingDelivery_diverged(self):
    self._test_Delivery_manageBuildingCalculatingDelivery('diverged', True)
 
class TestSlapOSConfirmedDeliveryMixin:
  def _test(self, simulation_state, causality_state, specialise, positive,
      delivery_date=DateTime('2012/04/22'),
      accounting_date=DateTime('2012/04/28')):
    @simulateByTitlewMark(self.script)
    def _real(self, simulation_state, causality_state, specialise, positive,
          delivery_date,
          accounting_date):
      not_visited = 'Not visited by %s' % self.script
      visited = 'Visited by %s' % self.script
      module = self.portal.getDefaultModule(portal_type=self.portal_type)
      delivery = module.newContent(title=not_visited, start_date=delivery_date,
          portal_type=self.portal_type, specialise=specialise)
      _jumpToStateFor = self.portal.portal_workflow._jumpToStateFor
      _jumpToStateFor(delivery, simulation_state)
      _jumpToStateFor(delivery, causality_state)
      self.tic()
 
      alarm = getattr(self.portal.portal_alarms, self.alarm)
      alarm.activeSense(params=dict(accounting_date=accounting_date))
      self.tic()
 
      if positive:
        self.assertEqual(visited, delivery.getTitle())
      else:
        self.assertEqual(not_visited, delivery.getTitle())
    _real(self, simulation_state, causality_state, specialise, positive,
        delivery_date, accounting_date)
 
  def test_typical(self):
    self._test('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', True)
 
  def test_bad_specialise(self):
    self._test('confirmed', 'solved', None, False)
 
  def test_bad_simulation_state(self):
    self._test('started', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', False)
 
  def test_bad_causality_state(self):
    self._test('confirmed', 'calculating',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', False)
 
  @withAbort
  def _test_script(self, simulation_state, causality_state, specialise,
        destination_state, consistency_failure=False):
    module = self.portal.getDefaultModule(portal_type=self.portal_type)
    delivery = module.newContent(portal_type=self.portal_type,
        specialise=specialise, start_date=DateTime())
    _jumpToStateFor = self.portal.portal_workflow._jumpToStateFor
    _jumpToStateFor(delivery, simulation_state)
    _jumpToStateFor(delivery, causality_state)
    def checkConsistency(*args, **kwargs):
      if consistency_failure:
        return ['bad']
      else:
        return []
    try:
      from Products.ERP5Type.Core.Folder import Folder
      Folder.original_checkConsistency = Folder.checkConsistency
      Folder.checkConsistency = checkConsistency
      getattr(delivery, self.script)()
    finally:
      Folder.checkConsistency = Folder.original_checkConsistency
      delattr(Folder, 'original_checkConsistency')
    self.assertEqual(destination_state, delivery.getSimulationState())
 
  def test_script_typical(self):
    self._test_script('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        self.destination_state)
 
  def test_script_bad_specialise(self):
    self._test_script('confirmed', 'solved', None, 'confirmed')
 
  def test_script_bad_simulation_state(self):
    self._test_script('started', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'started')
 
  def test_script_bad_causality_state(self):
    self._test_script('confirmed', 'building',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'confirmed')
 
  def test_script_bad_consistency(self):
    self._test_script('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'confirmed', True)
 
class TestSlapOSStartConfirmedAggregatedSalePackingListAlarm(
      testSlapOSMixin, TestSlapOSConfirmedDeliveryMixin):
  destination_state = 'started'
  script = 'Delivery_startConfirmedAggregatedSalePackingList'
  portal_type = 'Sale Packing List'
  alarm = 'slapos_start_confirmed_aggregated_sale_packing_list'
 
  def test_previous_month(self):
    self._test('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        True, delivery_date=DateTime("2012/03/22"),
        accounting_date=DateTime('2012/04/28'))
 
  def test_next_month(self):
    self._test('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        False, delivery_date=DateTime("2012/05/22"),
        accounting_date=DateTime('2012/04/28'))
 
  def test_same_month_early(self):
    self._test('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        False, delivery_date=DateTime("2012/04/22"),
        accounting_date=DateTime('2012/04/23'))
 
  def test_start_date_is_resetted(self):
    delivery = self.portal.sale_packing_list_module.newContent(
      portal_type="Sale Packing List",
      start_date=DateTime("2012/04/22"),
      specialise='sale_trade_condition_module/slapos_aggregated_trade_condition',
      source='organisation_module/slapos',
      source_section='organisation_module/slapos',
      destination='organisation_module/slapos',
      destination_section='organisation_module/slapos',
      destination_decision='organisation_module/slapos',
      price_currency='currency_module/EUR',
      )
    movement = delivery.newContent(
      portal_type="Sale Packing List Line",
      resource='service_module/slapos_instance_setup',
      quantity=0,
      price=0,
      )
    self.portal.portal_workflow._jumpToStateFor(delivery, 'solved')
    self.portal.portal_workflow._jumpToStateFor(delivery, 'confirmed')
    delivery.Delivery_startConfirmedAggregatedSalePackingList()
    self.assertEquals(delivery.getStartDate(),
                      DateTime().earliestTime())
    self.assertEquals(delivery.getStopDate(),
                      DateTime().earliestTime())
    self.assertEquals(delivery.getSimulationState(), 'started')
 
class TestSlapOSDeliverStartedAggregatedSalePackingListAlarm(
      testSlapOSMixin):
  destination_state = 'delivered'
  script = 'Delivery_deliverStartedAggregatedSalePackingList'
  portal_type = 'Sale Packing List'
  alarm = 'slapos_deliver_started_aggregated_sale_packing_list'
 
  def _test(self, simulation_state, causality_state, specialise, positive,
      delivery_date=DateTime('2012/04/22'),
      accounting_date=DateTime('2012/04/28')):
    @simulateByTitlewMark(self.script)
    def _real(self, simulation_state, causality_state, specialise, positive,
          delivery_date,
          accounting_date):
      not_visited = 'Not visited by %s' % self.script
      visited = 'Visited by %s' % self.script
      module = self.portal.getDefaultModule(portal_type=self.portal_type)
      delivery = module.newContent(title=not_visited, start_date=delivery_date,
          portal_type=self.portal_type, specialise=specialise)
      _jumpToStateFor = self.portal.portal_workflow._jumpToStateFor
      _jumpToStateFor(delivery, simulation_state)
      _jumpToStateFor(delivery, causality_state)
      self.tic()
 
      alarm = getattr(self.portal.portal_alarms, self.alarm)
      alarm.activeSense(params=dict(accounting_date=accounting_date))
      self.tic()
 
      if positive:
        self.assertEqual(visited, delivery.getTitle())
      else:
        self.assertEqual(not_visited, delivery.getTitle())
    _real(self, simulation_state, causality_state, specialise, positive,
        delivery_date, accounting_date)
 
  def test_typical(self):
    self._test('started', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', True)
 
  def test_bad_specialise(self):
    self._test('started', 'solved', None, False)
 
  def test_bad_simulation_state(self):
    self._test('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', False)
 
  def test_bad_causality_state(self):
    self._test('started', 'calculating',
        'sale_trade_condition_module/slapos_aggregated_trade_condition', False)
 
  @withAbort
  def _test_script(self, simulation_state, causality_state, specialise,
        destination_state, consistency_failure=False):
    module = self.portal.getDefaultModule(portal_type=self.portal_type)
    delivery = module.newContent(portal_type=self.portal_type,
        specialise=specialise, start_date=DateTime())
    _jumpToStateFor = self.portal.portal_workflow._jumpToStateFor
    _jumpToStateFor(delivery, simulation_state)
    _jumpToStateFor(delivery, causality_state)
    def checkConsistency(*args, **kwargs):
      if consistency_failure:
        return ['bad']
      else:
        return []
    try:
      from Products.ERP5Type.Core.Folder import Folder
      Folder.original_checkConsistency = Folder.checkConsistency
      Folder.checkConsistency = checkConsistency
      getattr(delivery, self.script)()
    finally:
      Folder.checkConsistency = Folder.original_checkConsistency
      delattr(Folder, 'original_checkConsistency')
    self.assertEqual(destination_state, delivery.getSimulationState())
 
  def test_script_typical(self):
    self._test_script('started', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        self.destination_state)
 
  def test_script_bad_specialise(self):
    self._test_script('started', 'solved', None, 'started')
 
  def test_script_bad_simulation_state(self):
    self._test_script('confirmed', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'confirmed')
 
  def test_script_bad_causality_state(self):
    self._test_script('started', 'building',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'started')
 
  def test_script_bad_consistency(self):
    self._test_script('started', 'solved',
        'sale_trade_condition_module/slapos_aggregated_trade_condition',
        'started', True)
 
class TestSlapOSStopConfirmedAggregatedSaleInvoiceTransactionAlarm(
      testSlapOSMixin, TestSlapOSConfirmedDeliveryMixin):
  destination_state = 'stopped'
  script = 'Delivery_stopConfirmedAggregatedSaleInvoiceTransaction'
  portal_type = 'Sale Invoice Transaction'
  alarm = 'slapos_stop_confirmed_aggregated_sale_invoice_transaction'
 
class TestSlapOSUpdateOpenSaleOrderPeriod(testSlapOSMixin):
 
  def createOpenOrder(self):
    open_order = self.portal.open_sale_order_module\
        .slapos_accounting_open_sale_order_template.Base_createCloneDocument(batch_mode=1)
    open_order.edit(
        title=self.generateNewSoftwareTitle(),
        reference="TESTHS-%s" % self.generateNewId(),
    )
    open_order.order()
    open_order.validate()
    return open_order
 
  def test_updatePeriod_REQUEST_disallowed(self):
    self.assertRaises(
      Unauthorized,
      self.portal.OpenSaleOrder_updatePeriod,
      REQUEST={})
 
  def _simulatePerson_storeOpenSaleOrderJournal(self):
    script_name = 'Person_storeOpenSaleOrderJournal'
    if script_name in self.portal.portal_skins.custom.objectIds():
      raise ValueError('Precondition failed: %s exists in custom' % script_name)
    createZODBPythonScript(self.portal.portal_skins.custom,
                        script_name,
                        '*args, **kwargs',
                        '# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by Person_storeOpenSaleOrderJournal') """ )
    transaction.commit()
 
  def _dropPerson_storeOpenSaleOrderJournal(self):
    script_name = 'Person_storeOpenSaleOrderJournal'
    if script_name in self.portal.portal_skins.custom.objectIds():
      self.portal.portal_skins.custom.manage_delObjects(script_name)
    transaction.commit()
 
  def test_updatePeriod_no_person(self):
    open_order = self.createOpenOrder()
    open_order.OpenSaleOrder_updatePeriod()
 
  def test_updatePeriod_validated(self):
    open_order = self.createOpenOrder()
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    open_order.edit(
      destination_decision_value=person,
    )
 
    self._simulatePerson_storeOpenSaleOrderJournal()
    try:
      open_order.OpenSaleOrder_updatePeriod()
    finally:
      self._dropPerson_storeOpenSaleOrderJournal()
    self.assertEqual(
        'Visited by Person_storeOpenSaleOrderJournal',
        person.workflow_history['edit_workflow'][-1]['comment'])
 
  def test_updatePeriod_invalidated(self):
    open_order = self.createOpenOrder()
    person = self.portal.person_module.template_member\
        .Base_createCloneDocument(batch_mode=1)
    open_order.edit(
      destination_decision_value=person,
    )
    open_order.invalidate()
 
    self._simulatePerson_storeOpenSaleOrderJournal()
    try:
      open_order.OpenSaleOrder_updatePeriod()
    finally:
      self._dropPerson_storeOpenSaleOrderJournal()
    self.assertNotEqual(
        'Visited by Person_storeOpenSaleOrderJournal',
        person.workflow_history['edit_workflow'][-1]['comment'])
 
  def _simulateOpenSaleOrder_updatePeriod(self):
    script_name = 'OpenSaleOrder_updatePeriod'
    if script_name in self.portal.portal_skins.custom.objectIds():
      raise ValueError('Precondition failed: %s exists in custom' % script_name)
    createZODBPythonScript(self.portal.portal_skins.custom,
                        script_name,
                        '*args, **kwargs',
                        '# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by OpenSaleOrder_updatePeriod') """ )
    transaction.commit()
 
  def _dropOpenSaleOrder_updatePeriod(self):
    script_name = 'OpenSaleOrder_updatePeriod'
    if script_name in self.portal.portal_skins.custom.objectIds():
      self.portal.portal_skins.custom.manage_delObjects(script_name)
    transaction.commit()
 
  def test_alarm(self):
    open_order = self.createOpenOrder()
    open_order.newContent(portal_type="Open Sale Order Line")
    self.tic()
    self._simulateOpenSaleOrder_updatePeriod()
    try:
      self.portal.portal_alarms.slapos_update_open_sale_order_period.activeSense()
      self.tic()
    finally:
      self._dropOpenSaleOrder_updatePeriod()
    self.assertEqual(
        'Visited by OpenSaleOrder_updatePeriod',
        open_order.workflow_history['edit_workflow'][-1]['comment'])
 
  def test_alarm_invalidated(self):
    open_order = self.createOpenOrder()
    open_order.newContent(portal_type="Open Sale Order Line")
    open_order.invalidate()
    self.tic()
    self._simulateOpenSaleOrder_updatePeriod()
    try:
      self.portal.portal_alarms.slapos_update_open_sale_order_period.activeSense()
      self.tic()
    finally:
      self._dropOpenSaleOrder_updatePeriod()
    self.assertNotEqual(
        'Visited by OpenSaleOrder_updatePeriod',
        open_order.workflow_history['edit_workflow'][-1]['comment'])
 
  def test_alarm_no_line(self):
    open_order = self.createOpenOrder()
    self.tic()
    self._simulateOpenSaleOrder_updatePeriod()
    try:
      self.portal.portal_alarms.slapos_update_open_sale_order_period.activeSense()
      self.tic()
    finally:
      self._dropOpenSaleOrder_updatePeriod()
    self.assertNotEqual(
        'Visited by OpenSaleOrder_updatePeriod',
        open_order.workflow_history['edit_workflow'][-1]['comment'])
 
class TestSlapOSReindexOpenSaleOrder(testSlapOSMixin):
 
  def createOpenOrder(self):
    open_order = self.portal.open_sale_order_module\
        .slapos_accounting_open_sale_order_template.\
          Base_createCloneDocument(batch_mode=1)
    open_order.edit(
        title=self.generateNewSoftwareTitle(),
        reference="TESTHS-%s" % self.generateNewId(),
    )
    return open_order
 
  def _simulateOpenSaleOrder_reindexIfIndexedBeforeLine(self):
    script_name = 'OpenSaleOrder_reindexIfIndexedBeforeLine'
    if script_name in self.portal.portal_skins.custom.objectIds():
      raise ValueError('Precondition failed: %s exists in custom' % script_name)
    createZODBPythonScript(self.portal.portal_skins.custom,
                        script_name,
                        '*args, **kwargs',
                        '# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by OpenSaleOrder_reindexIfIndexedBeforeLine') """ )
    transaction.commit()
 
  def _dropOpenSaleOrder_reindexIfIndexedBeforeLine(self):
    script_name = 'OpenSaleOrder_reindexIfIndexedBeforeLine'
    if script_name in self.portal.portal_skins.custom.objectIds():
      self.portal.portal_skins.custom.manage_delObjects(script_name)
    transaction.commit()
 
  def test_alarm(self):
    open_order = self.createOpenOrder()
    open_order.newContent(portal_type="Open Sale Order Line")
    self.tic()
    self._simulateOpenSaleOrder_reindexIfIndexedBeforeLine()
    try:
      self.portal.portal_alarms.slapos_reindex_open_sale_order.activeSense()
      self.tic()
    finally:
      self._dropOpenSaleOrder_reindexIfIndexedBeforeLine()
    self.assertEqual(
        'Visited by OpenSaleOrder_reindexIfIndexedBeforeLine',
        open_order.workflow_history['edit_workflow'][-1]['comment'])
 
  def test_alarm_no_line(self):
    open_order = self.createOpenOrder()
    self.tic()
    self._simulateOpenSaleOrder_reindexIfIndexedBeforeLine()
    try:
      self.portal.portal_alarms.slapos_reindex_open_sale_order.activeSense()
      self.tic()
    finally:
      self._dropOpenSaleOrder_reindexIfIndexedBeforeLine()
    self.assertNotEqual(
        'Visited by OpenSaleOrder_reindexIfIndexedBeforeLine',
        open_order.workflow_history['edit_workflow'][-1]['comment'])
 
class TestSlapOSGeneratePackingListFromTioXML(testSlapOSMixin):
 
  def createTioXMLFile(self):
    document = self.portal.consumption_document_module.newContent(
      title=self.generateNewId(),
      reference="TESTTIOCONS-%s" % self.generateNewId(),
    )
    return document
 
  def _simulateComputerConsumptionTioXMLFile_solveInvoicingGeneration(self):
    script_name = 'ComputerConsumptionTioXMLFile_solveInvoicingGeneration'
    if script_name in self.portal.portal_skins.custom.objectIds():
      raise ValueError('Precondition failed: %s exists in custom' % script_name)
    createZODBPythonScript(self.portal.portal_skins.custom,
                        script_name,
                        '*args, **kwargs',
                        '# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by ComputerConsumptionTioXMLFile_solveInvoicingGeneration') """ )
    transaction.commit()
 
  def _dropComputerConsumptionTioXMLFile_solveInvoicingGeneration(self):
    script_name = 'ComputerConsumptionTioXMLFile_solveInvoicingGeneration'
    if script_name in self.portal.portal_skins.custom.objectIds():
      self.portal.portal_skins.custom.manage_delObjects(script_name)
    transaction.commit()
 
  def test_alarm(self):
    document = self.createTioXMLFile()
    document.submit()
    self.tic()
    self._simulateComputerConsumptionTioXMLFile_solveInvoicingGeneration()
    try:
      self.portal.portal_alarms.\
        slapos_accounting_generate_packing_list_from_tioxml.activeSense()
      self.tic()
    finally:
      self._dropComputerConsumptionTioXMLFile_solveInvoicingGeneration()
    self.assertEqual(
        'Visited by ComputerConsumptionTioXMLFile_solveInvoicingGeneration',
        document.workflow_history['edit_workflow'][-1]['comment'])
 
  def test_alarm_not_submitted(self):
    document = self.createTioXMLFile()
    self.tic()
    self._simulateComputerConsumptionTioXMLFile_solveInvoicingGeneration()
    try:
      self.portal.portal_alarms.\
        slapos_accounting_generate_packing_list_from_tioxml.activeSense()
      self.tic()
    finally:
      self._dropComputerConsumptionTioXMLFile_solveInvoicingGeneration()
    self.assertNotEqual(
        'Visited by ComputerConsumptionTioXMLFile_solveInvoicingGeneration',
        document.workflow_history['edit_workflow'][-1]['comment'])