Commit 129d3d5d authored by Romain Courteaud's avatar Romain Courteaud

slapos_subscription_request: increase use cases for Subscription Change Request

- change instance tree owner
- change paying organisation (switch b2b)
- change payable to free
- change payable price

It can be used on a submitted Subscription Request or a validate Open Sale Order
parent 895b5c4b
...@@ -9,21 +9,27 @@ portal = context.getPortalObject() ...@@ -9,21 +9,27 @@ portal = context.getPortalObject()
assert subscription_change_request.getPortalType() == 'Subscription Change Request' assert subscription_change_request.getPortalType() == 'Subscription Change Request'
assert subscription_change_request.getSimulationState() == 'submitted' assert subscription_change_request.getSimulationState() == 'submitted'
subscription_change_request.reindexObject(activate_kw=activate_kw) ###############################################################################################
### Check the causality to change
previous_subscription_request = subscription_change_request.getCausalityValue(portal_type='Subscription Request')
previous_open_order = subscription_change_request.getCausalityValue(portal_type='Open Sale Order')
def invalidate(document, comment): if previous_subscription_request is not None:
context.validate() # it will be an subscription request
context.invalidate(comment=comment) if previous_subscription_request.getSimulationState() != 'submitted':
return subscription_change_request.cancel(comment='Can only change submitted Subscription Request')
previous_causality_to_compare = previous_subscription_request
# Subscription Change Request will change an ongoing Open Sale Order elif previous_open_order is not None:
open_sale_order = subscription_change_request.getCausalityValue(portal_type='Open Sale Order') # it must be an open sale order
if (open_sale_order is None) or (open_sale_order.getValidationState() != 'validated'): if previous_open_order.getValidationState() != 'validated':
return invalidate(subscription_change_request, 'No Open Sale Order to update') return subscription_change_request.cancel(comment='No Open Sale Order to update')
# Search the line/cell # Search the line/cell
open_order_movement = None open_order_movement = None
open_order_movement_list = open_sale_order.contentValues(portal_type='Open Sale Order Line') open_order_movement_list = previous_open_order.contentValues(portal_type='Open Sale Order Line')
if len(open_order_movement_list) == 1: if len(open_order_movement_list) == 1:
open_order_movement = open_order_movement_list[0] open_order_movement = open_order_movement_list[0]
open_order_movement_list = open_order_movement.contentValues(portal_type='Open Sale Order Cell') open_order_movement_list = open_order_movement.contentValues(portal_type='Open Sale Order Cell')
if 1 < len(open_order_movement_list): if 1 < len(open_order_movement_list):
...@@ -31,48 +37,107 @@ if len(open_order_movement_list) == 1: ...@@ -31,48 +37,107 @@ if len(open_order_movement_list) == 1:
elif 1 == len(open_order_movement_list): elif 1 == len(open_order_movement_list):
open_order_movement = open_order_movement_list[0] open_order_movement = open_order_movement_list[0]
if open_order_movement is None: if open_order_movement is None:
return invalidate(subscription_change_request, 'Can not find the open order movement') return subscription_change_request.cancel(comment='Can not find the open order movement')
previous_causality_to_compare = open_order_movement
else:
return subscription_change_request.cancel(comment='Unknown causality')
###############################################################################################
### Check the supported scenario:
### - change instance tree owner
### - change paying organisation (switch b2b)
### - change payable to free
### - change payable price
identical_order_base_category_list = [ identical_order_base_category_list = [
'specialise',
# 'destination', # 'destination',
# 'destination_section', # 'destination_section',
# 'destination_decisition', # 'destination_decision',
'destination_project', 'destination_project',
'source',
'source_section',
'source_project',
'price_currency',
'resource', 'resource',
'variation_category_list', 'variation_category_list',
'quantity_unit', 'quantity_unit',
'quantity', 'quantity',
'price' 'ledger',
'source',
# 'source_section',
'source_project',
'price_currency',
# 'price'
# 'specialise'
] ]
edit_kw = {
'causality': subscription_change_request.getRelativeUrl()
}
is_owner_change_needed = False
if previous_causality_to_compare.getDestination() != subscription_change_request.getDestination():
# change instance tree owner
identical_order_base_category_list.extend(['source_section', 'price'])
edit_kw['destination'] = subscription_change_request.getDestination(None)
edit_kw['destination_section'] = subscription_change_request.getDestinationSection()
edit_kw['destination_decision'] = subscription_change_request.getDestinationDecision()
edit_kw['specialise'] = subscription_change_request.getSpecialise(None)
is_owner_change_needed = True
elif previous_causality_to_compare.getDestinationSection() != subscription_change_request.getDestinationSection():
# change paying organisation (switch b2b)
identical_order_base_category_list.extend(['destination', 'destination_decision', 'source_section', 'price'])
edit_kw['destination_section'] = subscription_change_request.getDestinationSection()
edit_kw['specialise'] = subscription_change_request.getSpecialise()
elif (previous_causality_to_compare.getSourceSection(None) is not None) and \
(previous_causality_to_compare.getPrice() != subscription_change_request.getPrice()):
# change a payable price
identical_order_base_category_list.extend(['destination', 'destination_section', 'destination_decision'])
edit_kw['price'] = subscription_change_request.getPrice()
edit_kw['specialise'] = subscription_change_request.getSpecialise()
if 0 < subscription_change_request.getPrice():
# change the price
identical_order_base_category_list.extend(['source_section'])
else:
# change to free
if subscription_change_request.getSourceSection() is not None:
return subscription_change_request.cancel(comment='Can only change payable Subscription Request to free')
else:
return subscription_change_request.cancel(comment='Unsupported changes')
###############################################################################################
### Check that other properties do not contain unexpected changes
for changed_key, changed_value in edit_kw.items():
if changed_value is None:
# Ensure new values are not empty
return subscription_change_request.cancel(comment='Unhandled requested changes on: %s' % changed_key)
for identical_order_base_category in identical_order_base_category_list: for identical_order_base_category in identical_order_base_category_list:
if open_order_movement.getProperty(identical_order_base_category) != subscription_change_request.getProperty(identical_order_base_category): edit_kw[identical_order_base_category] = subscription_change_request.getProperty(identical_order_base_category)
return invalidate(subscription_change_request, 'Unhandled requested changes on: %s' % identical_order_base_category) if previous_causality_to_compare.getProperty(identical_order_base_category) != edit_kw[identical_order_base_category]:
return subscription_change_request.cancel(comment='Unhandled requested changes on: %s' % identical_order_base_category)
# Ensure the subscribed item is the same # Ensure the subscribed item is the same
subscribed_item = open_order_movement.getAggregateValue(portal_type=['Instance Tree', 'Compute Node', 'Project']) # (done separatly, because open order cell have multiple aggregated items
if subscription_change_request.getAggregateUid() != subscribed_item.getUid(): subscribed_item = previous_causality_to_compare.getAggregateValue(portal_type=['Instance Tree', 'Compute Node', 'Project'])
return invalidate(subscription_change_request, 'Unhandled requested changes on: aggregate') if subscription_change_request.getAggregateUid() == subscribed_item.getUid():
edit_kw['aggregate'] = subscription_change_request.getAggregate()
else:
return subscription_change_request.cancel(comment='Unhandled requested changes on: aggregate')
# Ensure destination is different
if subscription_change_request.getDestination() == open_sale_order.getDestination():
return invalidate(subscription_change_request, 'Expected change on: destination')
# Change Subscripted Item user if needed ###############################################################################################
subscribed_item = open_order_movement.getAggregateValue(portal_type=['Instance Tree', 'Compute Node', 'Project']) ### change item owner if needed
if subscribed_item is None: if is_owner_change_needed:
if subscribed_item is None:
raise NotImplementedError('Unsupported subscribed item') raise NotImplementedError('Unsupported subscribed item')
elif subscribed_item.getPortalType() == 'Compute Node': elif subscribed_item.getPortalType() == 'Compute Node':
# No user is set on Compute Node # No user is set on Compute Node
pass pass
elif subscribed_item.getPortalType() == 'Instance Tree': elif subscribed_item.getPortalType() == 'Instance Tree':
# Check if user does not already have a instance tree with the same title # Check if user does not already have a instance tree with the same title
# to prevent breaking slapos's request # to prevent breaking slapos's request
existing_instance_tree = portal.portal_catalog.getResultValue( existing_instance_tree = portal.portal_catalog.getResultValue(
...@@ -81,27 +146,48 @@ elif subscribed_item.getPortalType() == 'Instance Tree': ...@@ -81,27 +146,48 @@ elif subscribed_item.getPortalType() == 'Instance Tree':
destination_section__uid=subscription_change_request.getDestinationUid() destination_section__uid=subscription_change_request.getDestinationUid()
) )
if existing_instance_tree is not None: if existing_instance_tree is not None:
return invalidate(subscription_change_request, 'Instance Tree with the same title found: %s' % existing_instance_tree.getRelativeUrl()) return subscription_change_request.cancel(comment='Instance Tree with the same title found: %s' % existing_instance_tree.getRelativeUrl())
subscribed_item.edit(destination_section=subscription_change_request.getDestination()) subscribed_item.edit(destination_section=subscription_change_request.getDestination())
elif subscribed_item.getPortalType() == 'Project': elif subscribed_item.getPortalType() == 'Project':
subscribed_item.edit(destination=subscription_change_request.getDestination()) subscribed_item.edit(destination=subscription_change_request.getDestination())
else: else:
raise NotImplementedError('Not implemented subscribed item') raise NotImplementedError('Not implemented subscribed item')
# Create new Open Sale Order
next_open_sale_order = subscription_change_request.SubscriptionRequest_createOpenSaleOrder()
current_date = getClosestDate(target_date=next_open_sale_order.getCreationDate(), precision='day')
# XXX Compensation ###############################################################################################
open_sale_order.OpenSaleOrder_archiveIfUnusedItem(check_unused_item=False) ### Create the new Subscription Request
# if we want to always activate a discount as soon as an open order is archived (outside subscription change request)
# it is needed to call OpenSaleOrderCell_createDiscountSalePackingList is an interaction workflow portal_type = 'Subscription Request'
# with more extra checks. new_subscription_request = portal.getDefaultModuleValue(portal_type).newContent(
open_order_movement.OpenSaleOrderCell_createDiscountSalePackingList( portal_type=portal_type,
# follow Resource_createSubscriptionRequest
start_date=subscription_change_request.getStartDate(),
effective_date=subscription_change_request.getEffectiveDate(),
activate_kw=activate_kw,
**edit_kw
)
new_subscription_request.submit(comment='Replacing %s' % subscription_change_request.getRelativeUrl())
# Compensation
if previous_subscription_request:
previous_subscription_request.cancel(comment='Replaced by %s' % new_subscription_request.getRelativeUrl())
previous_subscription_request.reindexObject(activate_kw=activate_kw)
elif previous_open_order:
current_date = getClosestDate(target_date=new_subscription_request.getCreationDate(), precision='day')
previous_open_order.OpenSaleOrder_archiveIfUnusedItem(check_unused_item=False)
# if we want to always activate a discount as soon as an open order is archived (outside subscription change request)
# it is needed to call OpenSaleOrderCell_createDiscountSalePackingList is an interaction workflow
# with more extra checks.
open_order_movement.OpenSaleOrderCell_createDiscountSalePackingList(
current_date, current_date,
'transfer discount from %s to %s' % (open_sale_order.getReference(), next_open_sale_order.getReference()), 'transfer discount from %s to %s' % (previous_open_order.getReference(), new_subscription_request.getReference()),
subscription_change_request subscription_change_request
)#, activate_kw=activate_kw) )#, activate_kw=activate_kw)
else:
raise NotImplementedError('Do not know how to compensate')
return invalidate(subscription_change_request, 'New open order: %s' % next_open_sale_order.getRelativeUrl()) subscription_change_request.reindexObject(activate_kw=activate_kw)
subscription_change_request.validate()
return subscription_change_request.invalidate(comment='New subscription request: %s' % new_subscription_request.getRelativeUrl())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment