Commit 3a79775e authored by Xiaowu Zhang's avatar Xiaowu Zhang Committed by Titouan Soulard

builder: add security stock management

use  "stock definition supply" which overwrite default parameter in
purchase supply for the date included in "valid from" et "valid until"
if the value is not defined in "stock defintion supply", the default
parameter is used
parent 00f9d57b
......@@ -300,62 +300,73 @@ class BuilderMixin(XMLObject, Amount, Predicate):
portal = self.getPortalObject()
if from_date is None:
from_date = DateTime().earliestTime()
# Initiate Conditions taken from Yusei T. Original Script
# XXX to be cleaned
min_inventory = supply.getMinStock()
#resource related variable
resource_value = supply.getResourceValue()
default_quantity_unit_value = resource_value.getDefaultQuantityUnitValue()
order_quantity_unit_value = supply.getOrderQuantityUnitValue()
flow_quantity_unit_value = supply.getFlowQuantityUnitValue()
time_quantity_unit_value = supply.getTimeQuantityUnitValue()
time_second_ratio = resource_value.getQuantityUnitDefinitionRatio(portal.portal_categories.quantity_unit.time.second)
min_delay = supply.getMinDelay()
max_delay = supply.getMaxDelay()
min_order_delay = supply.getMinOrderDelay()
max_order_delay = supply.getMaxOrderDelay()
min_order = supply.getMinOrderQuantity()
max_order = supply.getMaxOrderQuantity()
# Initiate conversions
# XXX To be cleaned
min_delay_second = 0
max_delay_second = 0
min_order_delay_second = 0
max_order_delay_second = 0
min_order_in_default_quantity_unit = 0
max_order_in_default_quantity_unit = float('inf')
default_quantity_unit_relative_url = default_quantity_unit_value.getCategoryRelativeUrl()
if time_quantity_unit_value is not None:
time_second_conversion_ratio = resource_value.getQuantityUnitDefinitionRatio(time_quantity_unit_value) / time_second_ratio
if min_delay:
min_delay_second = min_delay * time_second_conversion_ratio
if max_delay:
max_delay_second = max_delay * time_second_conversion_ratio
if min_order_delay:
min_order_delay_second = min_order_delay * time_second_conversion_ratio
if max_delay:
max_order_delay_second = max_order_delay * time_second_conversion_ratio
if order_quantity_unit_value is not None:
order_quantity_unit_relative_url = order_quantity_unit_value.getCategoryRelativeUrl()
order_quantity_unit_default_quantity_unit_conversion_ratio = resource_value.convertQuantity(1, order_quantity_unit_relative_url, default_quantity_unit_relative_url)
if min_order:
min_order_in_default_quantity_unit = min_order * order_quantity_unit_default_quantity_unit_conversion_ratio
if max_order:
max_order_in_default_quantity_unit = max_order * order_quantity_unit_default_quantity_unit_conversion_ratio
else:
def getCorrectSupplyParameter(selected_supply, default_supply, method_id):
if selected_supply == default_supply:
return getattr(default_supply, method_id)()
selected_supply_method = getattr(selected_supply, method_id)
default_supply_method = getattr(default_supply, method_id)
return selected_supply_method() or default_supply_method()
def getMinMaxDelayAndOrderDelay(selected_supply, default_supply):
time_quantity_unit_value = getCorrectSupplyParameter(selected_supply, default_supply, 'getTimeQuantityUnitValue')
min_delay_second = 0
max_delay_second = 0
min_order_delay_second = 0
max_order_delay_second = 0
if time_quantity_unit_value is not None:
min_delay = getCorrectSupplyParameter(selected_supply, default_supply, 'getMinDelay')
max_delay = getCorrectSupplyParameter(selected_supply, default_supply, 'getMaxDelay')
min_order_delay = getCorrectSupplyParameter(selected_supply, default_supply, 'getMinOrderDelay')
max_order_delay = getCorrectSupplyParameter(selected_supply, default_supply, 'getMaxOrderDelay')
time_second_conversion_ratio = resource_value.getQuantityUnitDefinitionRatio(time_quantity_unit_value) / time_second_ratio
if min_delay:
min_delay_second = min_delay * time_second_conversion_ratio
if max_delay:
max_delay_second = max_delay * time_second_conversion_ratio
if min_order_delay:
min_order_delay_second = min_order_delay * time_second_conversion_ratio
if max_delay:
max_order_delay_second = max_order_delay * time_second_conversion_ratio
return min_delay_second, max_delay_second, min_order_delay_second, max_order_delay_second
min_delay_second, max_delay_second, min_order_delay_second, max_order_delay_second = getMinMaxDelayAndOrderDelay(supply, supply)
def getOrderQuantityUnitDefaultQuantityUnitConversionRatio(selected_supply, default_supply):
order_quantity_unit_value = getCorrectSupplyParameter(selected_supply, default_supply, 'getOrderQuantityUnitValue')
order_quantity_unit_default_quantity_unit_conversion_ratio = 1
if flow_quantity_unit_value is not None:
flow_quantity_unit_relative_url = flow_quantity_unit_value.getCategoryRelativeUrl()
flow_quantity_unit_default_quantity_unit_conversion_ratio = resource_value.convertQuantity(1, flow_quantity_unit_relative_url, default_quantity_unit_relative_url)
default_quantity_unit_flow_quantity_unit_conversion_ratio = 1 / flow_quantity_unit_default_quantity_unit_conversion_ratio
else:
#min_order_in_default_quantity_unit = 0
#max_order_in_default_quantity_unit = float('inf')
if order_quantity_unit_value is not None:
order_quantity_unit_relative_url = order_quantity_unit_value.getCategoryRelativeUrl()
order_quantity_unit_default_quantity_unit_conversion_ratio = resource_value.convertQuantity(1, order_quantity_unit_relative_url, default_quantity_unit_relative_url)
"""
those are not used yet
min_order = supply.getMinOrderQuantity()
max_order = supply.getMaxOrderQuantity()
if min_order:
min_order_in_default_quantity_unit = min_order * order_quantity_unit_default_quantity_unit_conversion_ratio
if max_order:
max_order_in_default_quantity_unit = max_order * order_quantity_unit_default_quantity_unit_conversion_ratio
"""
return order_quantity_unit_default_quantity_unit_conversion_ratio
order_quantity_unit_default_quantity_unit_conversion_ratio = getOrderQuantityUnitDefaultQuantityUnitConversionRatio(supply, supply)
def getDefaultQuantityUnitFlowQuantityUnitConversionRatio(selected_supply, default_supply):
flow_quantity_unit_value = getCorrectSupplyParameter(selected_supply, default_supply, 'getFlowQuantityUnitValue')
default_quantity_unit_flow_quantity_unit_conversion_ratio = 1
if flow_quantity_unit_value is not None:
flow_quantity_unit_relative_url = flow_quantity_unit_value.getCategoryRelativeUrl()
flow_quantity_unit_default_quantity_unit_conversion_ratio = resource_value.convertQuantity(1, flow_quantity_unit_relative_url, default_quantity_unit_relative_url)
default_quantity_unit_flow_quantity_unit_conversion_ratio = 1 / flow_quantity_unit_default_quantity_unit_conversion_ratio
return default_quantity_unit_flow_quantity_unit_conversion_ratio
default_quantity_unit_flow_quantity_unit_conversion_ratio = getDefaultQuantityUnitFlowQuantityUnitConversionRatio(supply, supply)
def getPreviousValidDate(date):
# We suppose the system has not been configured to handled per hour commands
......@@ -366,23 +377,29 @@ class BuilderMixin(XMLObject, Amount, Predicate):
factor=-1)).earliestTime()
# Function to define the minimal quantity to be ordered
def minimalQuantity(quantity, date):
def minimalQuantity(selected_supply,default_supply, quantity, date):
# Initiate variables to match original script from Yusei T.
# XXX To be cleaned
delay_second = max_delay_second or min_delay_second or 0
if selected_supply != default_supply:
local_min_delay_second, local_max_delay_second, local_min_order_delay_second, local_max_order_delay_second = getMinMaxDelayAndOrderDelay(selected_supply, default_supply)
local_order_quantity_unit_default_quantity_unit_conversion_ratio = getOrderQuantityUnitDefaultQuantityUnitConversionRatio(selected_supply, default_supply)
local_order_quantity_unit_value = getCorrectSupplyParameter(selected_supply, default_supply, 'getOrderQuantityUnitValue')
else:
local_min_delay_second, local_max_delay_second, local_min_order_delay_second, local_max_order_delay_second = min_delay_second, max_delay_second, min_order_delay_second, max_order_delay_second
local_order_quantity_unit_default_quantity_unit_conversion_ratio = order_quantity_unit_default_quantity_unit_conversion_ratio
local_order_quantity_unit_value = original_order_quantity_unit_value
delay_second = local_max_delay_second or local_min_delay_second or 0
limit_date = getPreviousValidDate(date)
start_date = getPreviousValidDate(
addToDate(limit_date, second=-delay_second)
)
stop_date = addToDate(start_date, second=delay_second).earliestTime()
order_delay_second = max_order_delay_second or min_order_delay_second or 0
order_delay_second = local_max_order_delay_second or local_min_order_delay_second or 0
effective_date = addToDate(start_date, second=-order_delay_second)
order_quantity = ceil(quantity / order_quantity_unit_default_quantity_unit_conversion_ratio)
quantity = order_quantity * order_quantity_unit_default_quantity_unit_conversion_ratio
return order_quantity, order_quantity_unit_value, effective_date, start_date, stop_date, quantity
order_quantity = ceil(quantity / local_order_quantity_unit_default_quantity_unit_conversion_ratio)
quantity = order_quantity * local_order_quantity_unit_default_quantity_unit_conversion_ratio
return order_quantity, local_order_quantity_unit_value, effective_date, start_date, stop_date, quantity
resource_portal_type = resource_value.getPortalType()
def newMovement(effective_date, start_date, stop_date, quantity, quantity_unit):
......@@ -486,17 +503,42 @@ class BuilderMixin(XMLObject, Amount, Predicate):
node_uid=supply.getDestinationUid()
) + history_list
min_stock_value = supply.getMinOrderQuantity() / default_quantity_unit_flow_quantity_unit_conversion_ratio
factor = supply.getMinFlow()
next_period_history_list = []
#self.log(limit_date_list)
def chooseCorrectSupply(default_supply,start_date_range_min,start_date_range_max):
search_dict = {
'predicate.start_date_range_min':{'query':start_date_range_min, 'range':'ngt'},
'predicate.start_date_range_max':{'query':start_date_range_max, 'range':'nlt'},
}
stock_definition_supply_list = portal.portal_catalog(
portal_type=('Purchase Supply Cell', 'Purchase Supply Line'),
strict_resource_uid=resource_value.getUid(),
default_ledger_uid=portal.portal_categories.ledger.stock.definition.getUid(),
validation_state='validated',
**search_dict
)
if len(stock_definition_supply_list):
return stock_definition_supply_list[0]
return default_supply
original_min_stock_value = supply.getMinOrderQuantity() / default_quantity_unit_flow_quantity_unit_conversion_ratio
original_factor = supply.getMinFlow()
original_order_quantity_unit_value = supply.getOrderQuantityUnitValue()
# Create a movement per period
for period_start_date in limit_date_list:
# Prepare history list of the current period
next_period_start_date = DateTime(supply.getNextPeriodicalDate(
period_start_date,
next_start_date=period_start_date)).earliestTime()
selected_supply = chooseCorrectSupply(default_supply = supply, start_date_range_min = period_start_date, start_date_range_max = next_period_start_date)
#we found a stock definition supply
if selected_supply != supply:
min_stock_value = getCorrectSupplyParameter(selected_supply, supply, 'getMinOrderQuantity') / getDefaultQuantityUnitFlowQuantityUnitConversionRatio(selected_supply, supply)
factor = getCorrectSupplyParameter(selected_supply, supply, 'getMinFlow')
else:
min_stock_value = original_min_stock_value
factor = original_factor
period_history_list = []
if next_period_history_list and\
......@@ -548,7 +590,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
if (week_consumption!= 0 or factor) and future_inventory_to_date < min_inventory:
quantity = min_inventory - future_inventory_to_date
ordered_quantity, ordered_unit, effective_date, start_date, delivery_date, quantity = minimalQuantity(quantity, period_start_date)
ordered_quantity, ordered_unit, effective_date, start_date, delivery_date, quantity = minimalQuantity(selected_supply, supply, quantity, period_start_date)
# XXX CLN This is very naive, it has to be optimized
if start_date > supply.getStartDateRangeMax():
break
......
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