<?xml version="1.0"?>
<ZopeData>
  <record id="1" aka="AAAAAAAAAAE=">
    <pickle>
      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
    </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 encoding="cdata"><![CDATA[

from Products.ERP5Type.DateUtils import addToDate, getClosestDate\n
from DateTime import DateTime\n
\n
portal = context.getPortalObject()\n
now = DateTime()\n
person = context\n
tag = \'%s_%s\' % (person.getUid(), script.id)\n
activate_kw = {\'tag\': tag}\n
if portal.portal_activities.countMessageWithTag(tag) > 0:\n
  # nothing to do\n
  return\n
\n
def newOpenOrder(open_sale_order):\n
  open_order_edit_kw = {\n
    \'effective_date\': now,\n
    \'activate_kw\': activate_kw,\n
  }\n
  if open_sale_order is None:\n
    open_sale_order_template = portal.restrictedTraverse(\n
        portal.portal_preferences.getPreferredOpenSaleOrderTemplate())\n
    new_open_sale_order = open_sale_order_template.Base_createCloneDocument(batch_mode=1)\n
    open_order_edit_kw.update({\n
      \'destination\': person.getRelativeUrl(),\n
      \'destination_decision\': person.getRelativeUrl(),\n
      \'title\': "%s SlapOS Subscription" % person.getTitle(),\n
    })\n
  else:\n
    new_open_sale_order = open_sale_order.Base_createCloneDocument(batch_mode=1)\n
    open_sale_order.setExpirationDate(now, activate_kw=activate_kw)\n
  new_open_sale_order.edit(**open_order_edit_kw)\n
  new_open_sale_order.order(activate_kw=activate_kw)\n
  new_open_sale_order.validate(activate_kw=activate_kw)\n
  return new_open_sale_order\n
\n
def storeWorkflowComment(document, comment):\n
  portal.portal_workflow.doActionFor(document, \'edit_action\', comment=comment)\n
\n
def calculateOpenOrderLineStopDate(open_order_line, hosting_subscription):\n
  end_date = hosting_subscription.HostingSubscription_calculateSubscriptionStopDate()\n
  if end_date is None: \n
    # Be sure that start date is different from stop date\n
    next_stop_date = hosting_subscription.getNextPeriodicalDate(hosting_subscription.HostingSubscription_calculateSubscriptionStartDate())\n
    current_stop_date = next_stop_date\n
    while next_stop_date < now:\n
      # Return result should be < now, it order to provide stability in simulation (destruction if it happen should be >= now)\n
      current_stop_date = next_stop_date\n
      next_stop_date = \\\n
         hosting_subscription.getNextPeriodicalDate(current_stop_date)\n
    return addToDate(current_stop_date, to_add={\'second\': -1})\n
  else:\n
    stop_date = end_date\n
  return stop_date\n
\n
# Prevent concurrent transaction to update the open order\n
context.serialize()\n
\n
# First, check the existing open order. Does some lines need to be removed, updated?\n
open_sale_order_list = portal.portal_catalog(\n
  default_destination_uid=person.getUid(),\n
  portal_type="Open Sale Order",\n
  validation_state="validated",\n
  limit=2,\n
)\n
open_sale_order_count = len(open_sale_order_list)\n
if open_sale_order_count == 0:\n
  open_sale_order = None\n
elif open_sale_order_count == 1:\n
  open_sale_order = open_sale_order_list[0].getObject()\n
else:\n
  raise ValueError, "Too many open order \'%s\' found: %s" % (person.getRelativeUrl(), [x.path for x in open_sale_order_list])\n
\n
delete_line_list = []\n
add_line_list = []\n
\n
updated_hosting_subscription_dict = {}\n
deleted_hosting_subscription_dict = {}\n
\n
if open_sale_order is not None:\n
  for open_order_line in open_sale_order.contentValues(\n
                           portal_type=\'Open Sale Order Line\'):\n
    current_start_date = open_order_line.getStartDate()\n
    current_stop_date = open_order_line.getStopDate()\n
\n
    # Prevent mistakes\n
    assert current_start_date is not None\n
    assert current_stop_date is not None\n
    assert current_start_date < current_stop_date\n
\n
    hosting_subscription = open_order_line.getAggregateValue(portal_type=\'Hosting Subscription\')\n
    assert current_start_date == hosting_subscription.HostingSubscription_calculateSubscriptionStartDate()\n
\n
    # First check if the hosting subscription has been correctly simulated (this script may run only once per year...)\n
    stop_date = calculateOpenOrderLineStopDate(open_order_line, hosting_subscription)\n
    if current_stop_date != stop_date:\n
      # Bingo, new subscription to generate\n
      open_order_line.edit(\n
        stop_date=stop_date,\n
        activate_kw=activate_kw)\n
      storeWorkflowComment(open_order_line,\n
                           \'Stop date updated to %s\' % stop_date)\n
\n
    if hosting_subscription.getSlapState() == \'destroy_requested\':\n
      # Line should be deleted\n
      assert hosting_subscription.getCausalityState() == \'diverged\'\n
      delete_line_list.append(open_order_line.getId())\n
      hosting_subscription.converge(comment="Last open order: %s" % open_order_line.getRelativeUrl())\n
      deleted_hosting_subscription_dict[hosting_subscription.getRelativeUrl()] = None\n
      updated_hosting_subscription_dict[hosting_subscription.getRelativeUrl()] = None\n
\n
    elif (hosting_subscription.getCausalityState() == \'diverged\'):\n
      hosting_subscription.converge(comment="Nothing to do on open order.")\n
      updated_hosting_subscription_dict[hosting_subscription.getRelativeUrl()] = None\n
\n
# Time to check the open order line to add (remaining diverged Hosting\n
# Subscription normally)\n
for hosting_subscription in portal.portal_catalog(\n
    portal_type=\'Hosting Subscription\',\n
    default_destination_section_uid=context.getUid(),\n
    causality_state="diverged"):\n
  hosting_subscription = hosting_subscription.getObject()\n
  if hosting_subscription.getCausalityState() == \'diverged\':\n
    # Simply check that it has never been simulated\n
    assert len(portal.portal_catalog(\n
      portal_type=\'Open Sale Order Line\',\n
      default_aggregate_uid=hosting_subscription.getUid(),\n
      limit=1)) == 0\n
\n
    # Let\'s add\n
    add_line_list.append(hosting_subscription)\n
  else:\n
    # Should be in the list of lines to remove\n
    assert (hosting_subscription.getRelativeUrl() in deleted_hosting_subscription_dict) or \\\n
      (hosting_subscription.getRelativeUrl() in updated_hosting_subscription_dict)\n
\n
manual_archive = False\n
if (add_line_list):\n
  # No need to create a new open order to add lines\n
  if open_sale_order is None:\n
    open_sale_order = newOpenOrder(None)\n
    manual_archive = True\n
\n
  open_order_explanation = ""\n
  # Add lines\n
  added_line_list = []\n
  open_sale_order_line_template = portal.restrictedTraverse(\n
      portal.portal_preferences.getPreferredOpenSaleOrderLineTemplate())\n
  for hosting_subscription in add_line_list:\n
    open_sale_order_line = open_sale_order_line_template.Base_createCloneDocument(batch_mode=1,\n
        destination=open_sale_order)\n
    start_date = hosting_subscription.HostingSubscription_calculateSubscriptionStartDate()\n
    open_sale_order_line.edit(\n
      activate_kw=activate_kw,\n
      title=hosting_subscription.getTitle(),\n
      start_date=start_date,\n
      stop_date=calculateOpenOrderLineStopDate(open_sale_order_line, hosting_subscription),\n
      aggregate_value=hosting_subscription,\n
      )\n
    storeWorkflowComment(open_sale_order_line, "Created for %s" % hosting_subscription.getRelativeUrl())\n
    if (hosting_subscription.getSlapState() == \'destroy_requested\'):\n
      # Added line to delete immediately\n
      delete_line_list.append(open_sale_order_line.getId())\n
      hosting_subscription.converge(comment="Last open order: %s" % open_sale_order_line.getRelativeUrl())\n
    else:\n
      hosting_subscription.converge(comment="First open order: %s" % open_sale_order_line.getRelativeUrl())\n
    added_line_list.append(open_sale_order_line.getId())\n
  open_order_explanation += "Added %s." % str(added_line_list)\n
\n
new_open_sale_order = None\n
if (delete_line_list):\n
  # All Verifications done. Time to clone/create open order\n
  new_open_sale_order = newOpenOrder(open_sale_order)\n
  if manual_archive == True:\n
    open_sale_order.archive()\n
\n
  open_order_explanation = ""\n
  # Remove lines\n
  new_open_sale_order.deleteContent(delete_line_list)\n
  open_order_explanation += "Removed %s." % str(delete_line_list)\n
\n
  storeWorkflowComment(new_open_sale_order, open_order_explanation)\n


]]></string> </value>
        </item>
        <item>
            <key> <string>_params</string> </key>
            <value> <string></string> </value>
        </item>
        <item>
            <key> <string>id</string> </key>
            <value> <string>Person_storeOpenSaleOrderJournal</string> </value>
        </item>
      </dictionary>
    </pickle>
  </record>
</ZopeData>
