diff --git a/product/Coramy/skins/coramy_erp5/ActivityTool_postError.py b/product/Coramy/skins/coramy_erp5/ActivityTool_postError.py new file mode 100755 index 0000000000000000000000000000000000000000..b75c1d3d851018b36cac13559b26c52c7ca48cd3 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/ActivityTool_postError.py @@ -0,0 +1,10 @@ +## Script (Python) "ActivityTool_postError" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters=error +##title= +## +context.portal_activities.setTitle(context.portal_activities.title + '\p' + error) diff --git a/product/Coramy/skins/coramy_erp5/AppliedRule_cleanOrphanedOrder.py b/product/Coramy/skins/coramy_erp5/AppliedRule_cleanOrphanedOrder.py new file mode 100755 index 0000000000000000000000000000000000000000..ffd276bbadadb9180cd534c3d62d1982918d8198 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/AppliedRule_cleanOrphanedOrder.py @@ -0,0 +1,49 @@ +## Script (Python) "AppliedRule_cleanOrphanedOrder" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters= +##title= +## +# Use this script to test if simulation state is acceptable + +def hasDelivery(ps_item): + for m in ps_item.objectValues(): + if len(m.getCategoryMembershipList('delivery')) > 0: + return 1 + for a in m.objectValues(): + if hasDelivery(a): + return 1 + return 0 + +def getDeliveryList(ps_item): + result = {} + for m in ps_item.objectValues(): + for d in m.getDeliveryValueList(): + if d is not None: + result[d.getRelativeUrl()] = 1 + for a in m.objectValues(): + result.update( getDeliveryList(a)) + return result + +# ---------------------------------------------------------- +# First make sure all simulation movements point to an order + +ar = context +r = ar.getSpecialiseValue() +if r is not None: + if r.getPortalType() == "Order Rule": + if ar.getCausalityValue() is None: + # Additional test need to check this is an order rule + print " Applied Rule %s has no order" % ar.getId() + print " Previously was: %s" % ar.getCausality() + if hasDelivery(ar): + print " Applied Rule %s has some delivered movements" % ar.getId() + print " deliveries: %s" % ' '.join(getDeliveryList(ar).keys()) + elif ar.getId() not in ('zero_stock', ): + print " Delete %s" % ar.getId() + context.portal_simulation.deleteContent(ar.getId()) + +return printed diff --git a/product/Coramy/skins/coramy_erp5/DateTime_getFormattedDate.py b/product/Coramy/skins/coramy_erp5/DateTime_getFormattedDate.py new file mode 100755 index 0000000000000000000000000000000000000000..08492d117d425a60512b041822f1eb0976633ae2 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/DateTime_getFormattedDate.py @@ -0,0 +1,15 @@ +## Script (Python) "DateTime_getFormattedDate" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters=date_time=None +##title= +## +from DateTime import DateTime + +if date_time == None : + date_time = DateTime() + +return "%2.2d/%2.2d/%s" % (date_time.day(), date_time.month(), date_time.year()) diff --git a/product/Coramy/skins/coramy_erp5/Delivery_reindexAll.py b/product/Coramy/skins/coramy_erp5/Delivery_reindexAll.py new file mode 100755 index 0000000000000000000000000000000000000000..344d84d944df6ac4e016b35bec308a259e4e8a93 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Delivery_reindexAll.py @@ -0,0 +1,31 @@ +## Script (Python) "Delivery_reindexAll" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters= +##title= +## +error_list = [] +return_list = [] + +context.portal_catalog.catalog_object(context.portal_categories,None) + +base_url = '/'.join(context.getPhysicalPath()) + +print "#### Indexing categories ####" +for id in list(context.portal_categories.objectIds()): + context.portal_activities.newMessage('SQLDict', '%s/portal_categories/%s' % (base_url, id), {}, 'recursiveImmediateReindexObject') + +# We index simulation first to make sure we can calculate tests +print "#### Indexing simulation ####" +for id in list(context.portal_simulation.objectIds()): + context.portal_activities.newMessage('SQLDict', '%s/portal_simulation/%s' % (base_url, id), {}, 'immediateReindexObject') + +for folder in context.portal_url.getPortalObject().objectValues(("ERP5 Folder",)): + print "#### Indexing contents inside folder %s ####" % folder.id + for id in list(folder.objectIds()): + context.portal_activities.newMessage('SQLDict', '%s/%s/%s' % (base_url, folder.getId(), id), {}, 'recursiveImmediateReindexObject') + +return printed diff --git a/product/Coramy/skins/coramy_erp5/Delivery_rescueOrphanedMovement.py b/product/Coramy/skins/coramy_erp5/Delivery_rescueOrphanedMovement.py new file mode 100755 index 0000000000000000000000000000000000000000..2fc0aaa54020640252787416c79da8e42c55f67b --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Delivery_rescueOrphanedMovement.py @@ -0,0 +1,39 @@ +## Script (Python) "Delivery_rescueOrphanedMovement" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters=fix=0 +##title= +## +# Example code: + +order_uid_list = context.getCausalityUidList() # XXX We may need to filter portal_type + +# Check each existing movement in delivery +attached_to_movement = [] +for m in context.getMovementList(): + # simulation_movement = m.getDeliveryRelatedValueList() + # Is there any orphaned movement + result = context.Delivery_zGetOrphanedMovementList(order_uid_list = order_uid_list, + resource_uid = m.getResourceUid(), + variation_text = m.getVariationText()) + if len(result) > 0: + for orphaned in result: + print "Found orphaned movement %s attached to %s" % (orphaned.relative_url, m.getRelativeUrl()) + attached_to_movement.append(orphaned.relative_url) + if fix: + simulation_movement = orphaned.getObject() + quantity = simulation_movement.getQuantity() + simulation_movement.setDeliveryValue(m) + m.setQuantity(quantity) + print " Fixed orphaned movement %s attached to %s with quantity %s" % (orphaned.relative_url, m.getRelativeUrl(), quantity) + +# Check each orphaned movement +result = context.Delivery_zGetOrphanedMovementList( order_uid_list = order_uid_list ) +for orphaned in result: + if orphaned.relative_url not in attached_to_movement: + print "Found orphaned movement %s which required new line/cell" % orphaned.relative_url + +return printed diff --git a/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedMovementList.zsql b/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedMovementList.zsql new file mode 100755 index 0000000000000000000000000000000000000000..285e2953edf12ea0460d3681979003f7dc650e57 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedMovementList.zsql @@ -0,0 +1,52 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:1000 +max_cache:100 +cache_time:0 +class_name:ZSQLBrain +class_file:zsqlbrain.py +</dtml-comment> +<params>order_uid_list:list +resource_uid +variation_text</params> +SELECT + catalog.*, + movement.quantity, + movement.target_quantity, + movement.resource_uid, + movement.variation_text, + movement.source_uid, + movement.destination_uid, + movement.start_date, + movement.stop_date, + movement.target_start_date, + movement.target_stop_date +FROM + movement AS related_order_line, + movement, + catalog AS related_order, + category AS movement_c, + catalog LEFT JOIN category ON (category.uid=catalog.uid + AND category.base_category_uid = <dtml-var "portal_categories.delivery.getUid()">) + LEFT JOIN catalog as related_delivery ON related_delivery.uid = category.category_uid +WHERE + related_delivery.uid is NULL +AND + catalog.portal_type = "Simulation Movement" +AND + catalog.uid = movement_c.uid +AND + movement_c.category_uid = related_order_line.uid +AND + movement_c.base_category_uid = <dtml-var "portal_categories.order.getUid()"> +AND + related_order_line.delivery_uid = related_order.uid +AND + catalog.uid = movement.uid +AND + related_order.simulation_state = 'confirmed' +<dtml-if order_uid_list>AND <dtml-in order_uid_list>related_order.uid = <dtml-sqlvar sequence-item type="int"> <dtml-if sequence-end><dtml-else> OR </dtml-if> </dtml-in> +</dtml-if><dtml-if resource_uid>AND movement.resource_uid = <dtml-sqlvar resource_uid type="int"> +</dtml-if><dtml-if variation_text>AND movement.variation_text = <dtml-sqlvar variation_text type="string"> +</dtml-if> \ No newline at end of file diff --git a/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedProductionMovementList.zsql b/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedProductionMovementList.zsql new file mode 100755 index 0000000000000000000000000000000000000000..4b38a89197c72cb2df180e99aee54272f1a281ac --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Delivery_zGetOrphanedProductionMovementList.zsql @@ -0,0 +1,54 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:10000 +max_cache:100 +cache_time:0 +class_name:ZSQLBrain +class_file:zsqlbrain.py +</dtml-comment> +<params>order_uid_list:list +resource_uid +variation_text</params> +SELECT + catalog.*, + movement.quantity, + movement.target_quantity, + movement.resource_uid, + movement.variation_text, + movement.source_uid, + movement.destination_uid, + movement.start_date, + movement.stop_date, + movement.target_start_date, + movement.target_stop_date +FROM + movement , + catalog AS related_order, + catalog AS resource, + catalog AS parent, + catalog LEFT JOIN category ON (category.uid=catalog.uid + AND category.base_category_uid = <dtml-var "portal_categories.delivery.getUid()">) + LEFT JOIN catalog as related_delivery ON related_delivery.uid = category.category_uid +WHERE + related_delivery.uid is NULL +AND + catalog.portal_type = "Simulation Movement" +AND + movement.delivery_uid = related_order.uid +AND + catalog.uid = movement.uid +AND + related_order.simulation_state = 'confirmed' +AND + movement.resource_uid = resource.uid +AND + catalog.parent_uid = parent.uid +AND ((parent.id = "default_transformation_sourcing_rule" +AND (resource.portal_type = "Composant" OR resource.portal_type = "Tissu")) +OR (parent.id = "default_transformation_rule" +AND (resource.portal_type = "Modele" OR resource.portal_type = "Composant" OR resource.portal_type = "Tissu" OR resource.portal_type = "Category"))) +<dtml-if order_uid_list>AND <dtml-in order_uid_list>related_order.uid = <dtml-sqlvar sequence-item type="int"> <dtml-if sequence-end><dtml-else> OR </dtml-if> </dtml-in> +</dtml-if><dtml-if resource_uid>AND movement.resource_uid = <dtml-sqlvar resource_uid type="int"> +</dtml-if><dtml-if variation_text>AND movement.variation_text = <dtml-sqlvar variation_text type="string"> +</dtml-if> \ No newline at end of file diff --git a/product/Coramy/skins/coramy_erp5/Movement_search.zsql b/product/Coramy/skins/coramy_erp5/Movement_search.zsql new file mode 100755 index 0000000000000000000000000000000000000000..15dcc8a1276f0f7160127990192717ad3b1b8d68 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Movement_search.zsql @@ -0,0 +1,34 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:1000 +max_cache:100 +cache_time:0 +class_name:ZSQLBrain +class_file:zsqlbrain.py +</dtml-comment> +<params>resource_uid +variation_text +source_uid +destination_uid +start_date +stop_date +target_start_date +target_stop_date</params> +SELECT + catalog.* +FROM + catalog, movement +WHERE + catalog.uid = movement.uid +AND movement.is_accountable = 1 +AND catalog.portal_type <> "Simulation Movement" +<dtml-if resource_uid>AND movement.resource_uid = <dtml-sqlvar resource_uid type="int"> +</dtml-if><dtml-if variation_text>AND movement.variation_text = <dtml-sqlvar variation_text type="string"> +</dtml-if><dtml-if source_uid>AND movement.source_uid = <dtml-sqlvar source_uid type="int"> +</dtml-if><dtml-if destination_uid>AND movement.destination_uid = <dtml-sqlvar destination_uid type="int"> +</dtml-if><dtml-if start_date>AND movement.start_date = <dtml-sqlvar start_date type="string"> +</dtml-if><dtml-if stop_date>AND movement.stop_date = <dtml-sqlvar stop_date type="string"> +</dtml-if><dtml-if target_start_date>AND movement.start_date = <dtml-sqlvar target_start_date type="string"> +</dtml-if><dtml-if target_stop_date>AND movement.stop_date = <dtml-sqlvar target_stop_date type="string"> +</dtml-if> \ No newline at end of file diff --git a/product/Coramy/skins/coramy_erp5/Order_cleanDuplicates.py b/product/Coramy/skins/coramy_erp5/Order_cleanDuplicates.py new file mode 100755 index 0000000000000000000000000000000000000000..b98de568d051e0733dd605f86d6d1b1a1844934c --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/Order_cleanDuplicates.py @@ -0,0 +1,73 @@ +## Script (Python) "Order_cleanDuplicates" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters= +##title= +## +# Use this script to test if simulation state is acceptable + +def hasDelivery(ps_item): + for m in ps_item.objectValues(): + if len(m.getCategoryMembershipList('delivery')) > 0: + return 1 + for a in m.objectValues(): + if hasDelivery(a): + return 1 + return 0 + +def getDeliveryList(ps_item): + result = {} + for m in ps_item.objectValues(): + for d in m.getDeliveryValueList(): + if d is not None: + result[d.getRelativeUrl()] = 1 + for a in m.objectValues(): + result.update( getDeliveryList(a)) + return result + +of = context +if of.getSimulationState() not in ('draft', 'cancelled', 'auto_planned'): + ps = of.getCausalityRelatedValueList(portal_type="Applied Rule") + if len(ps) == 0: + print " Missing PS for Order %s of type %s" % (of.getId(), of.getPortalType()) + print " Reexpand order %s" % of.getId() + of.edit() + elif len(ps) > 1: + print " Too many PS for Order %s of type %s" % (of.getId(), of.getPortalType()) + no_delivery = [] + delivery = [] + for ps_item in ps: + if hasDelivery(ps_item): + print " PS %s has some delivered movements" % ps_item.getId() + delivery.append(ps_item) + else: + print " PS %s has no delivered movements" % ps_item.getId() + no_delivery.append(ps_item) + # manage_delObjects + if len(delivery) > 0: + # Only erase no_delivery if one item has delivery + for ps_item in no_delivery: + print " Delete PS %s" % ps_item.getId() + parent = ps_item.aq_parent + parent.deleteContent(ps_item.getId()) + else: + # Keep at least one + for ps_item in no_delivery[1:]: + print " Delete PS %s" % ps_item.getId() + id = ps_item.getId() + parent = ps_item.aq_parent + parent.deleteContent(ps_item.getId()) + if len(delivery) > 1: + # We erase the Applied Rule but keep + # some excessive packing lists which may have been generated + # THIS BREAKS CONSISTENCY + for ps_item in delivery[1:]: + print " Delete PS %s with BREAKS CONSISTENCY" % ps_item.getId() + id = ps_item.getId() + parent = ps_item.aq_parent + #parent.deleteContent(ps_item.getId()) + +return printed diff --git a/product/Coramy/skins/coramy_erp5/PortalSimulation_cleanup.py b/product/Coramy/skins/coramy_erp5/PortalSimulation_cleanup.py new file mode 100755 index 0000000000000000000000000000000000000000..a0832c7e2919e8012086b29c0e84e2a873e4a49e --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/PortalSimulation_cleanup.py @@ -0,0 +1,36 @@ +## Script (Python) "PortalSimulation_cleanup" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters= +##title= +## +process = context.portal_activities.newActiveProcess() +base_url = '/'.join(context.portal_url.getPortalObject().getPhysicalPath()) + +# ---------------------------------------------------------- +# First make sure all simulation movements point to an order + +print "-- Checking simulation" +for id in context.portal_simulation.objectIds(): + print " AppliedRule_cleanOrphadedOrder %s" % id + context.portal_activities.newMessage('SQLDict', '%s/portal_simulation/%s' % (base_url, id), process, {}, 'AppliedRule_cleanOrphanedOrder') + +# ---------------------------------------------------------- +# Next make sure all orders in > planned state have at most one applied rule + +for module_id in ('ordre_fabrication','commande_achat','commande_vente',): + for id in context[module_id].objectIds(): + print " Order_cleanDuplicates %s/%s" % (module_id , id) + context.portal_activities.newMessage('SQLDict', '%s/%s/%s' % (base_url, module_id, id), process, {}, 'Order_cleanDuplicates') + +# ---------------------------------------------------------- +# Next make sure all movements in a delivery of material point to simulation + + +# ---------------------------------------------------------- +# Next make sure all movements in a delivery of material point to simulation + +return printed diff --git a/product/Coramy/skins/coramy_erp5/PortalSimulation_rescueOrphaned.py b/product/Coramy/skins/coramy_erp5/PortalSimulation_rescueOrphaned.py new file mode 100755 index 0000000000000000000000000000000000000000..79b148698a93431b12fcc743d62abb4c005603e5 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/PortalSimulation_rescueOrphaned.py @@ -0,0 +1,276 @@ +## Script (Python) "PortalSimulation_rescueOrphaned" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters= +##title= +## +exception_order = ['303',] + +orphaned_delivery_related_list = {} +orphaned_delivery_related_quantity = {} +exception_order = ['303',] + +orphaned_delivery_related_list = {} +has_delivery_rule_related_list = {} +orphaned_delivery_related_quantity = {} +orphaned_delivery_related_target_quantity = {} +orphaned_delivery_list = {} +orphaned_delivery_quantity = {} +orphaned_delivery_target_quantity = {} +build_delivery_list = [] + +m_list = list(context.Delivery_zGetOrphanedProductionMovementList()) + list(context.Delivery_zGetOrphanedMovementList()) +#m_list = context.Delivery_zGetOrphanedProductionMovementList() +#m_list = context.Delivery_zGetOrphanedMovementList() +for b in m_list: + m = b.getObject() + if m.getDeliveryValue() is None: + # Only process orphaned + if m.getNetConvertedTargetQuantity() is None: + return "Error for target_quantity on %s" % m.getRelativeUrl() + if m.getNetConvertedQuantity() is None: + return "Error for quantity on %s" % m.getRelativeUrl() + ra = m.getRootAppliedRule() + order = ra.getCausalityValue() # Order + if order is not None: + order_id = order.getId() + order_relative_url = order.getRelativeUrl() + else: + order_id = 'UNKNOWN ORDER' + order_relative_url = None + if order_id not in exception_order: + print "Trying to fix order %s: %s" % (order_relative_url , b.path) + candidates = context.Movement_search(resource_uid = b.resource_uid, variation_text = b.variation_text, + source_uid = m.getSourceUid(), destination_uid = m.getDestinationUid()) + found_candidate = 0 + if len(candidates) > 0: + for dm in candidates: + dm_object = dm.getObject() + if dm_object is not None: + if order_relative_url in dm_object.getDeliveryValue().getCausalityList(): + is_orphaned = not dm_object.isSimulated() + quantity_difference = dm_object.getNetConvertedQuantity() - m.getNetConvertedQuantity() + target_quantity_difference = dm_object.getNetConvertedTargetQuantity() - m.getNetConvertedTargetQuantity() + is_identical = quantity_difference == 0 + # We must test here is this object has a delivery rule attached to + # we may have to remove some delivery rules... + simulation_m = dm_object.getDeliveryRelatedValueList() + if len(simulation_m) == 1: + if simulation_m[0].getRootAppliedRule().getDefaultCausalityValue().getPortalType() == "Delivery Rule": + has_delivery_rule = 0 + else: + has_delivery_rule = 1 + else: + has_delivery_rule = 0 + print " found related %s orphaned: %s order: %s identical: %s drule: %s delivery q/t: %s %s simulation q/t: %s %s" % ( + dm_object.getRelativeUrl(), + is_orphaned, + dm_object.getCausalityList(), + is_identical, + has_delivery_rule, + dm_object.getNetConvertedQuantity(), + dm_object.getNetConvertedTargetQuantity(), + m.getNetConvertedQuantity(), + m.getNetConvertedTargetQuantity(), ) + if is_orphaned or has_delivery_rule: + # Only orphaned movements are good candidates + found_candidate = 1 + # Build dm_object to m mapping + if not orphaned_delivery_related_list.has_key(dm_object): + orphaned_delivery_related_list[dm_object] = [] + has_delivery_rule_related_list[dm_object] = [] + orphaned_delivery_related_quantity[dm_object] = 0.0 + orphaned_delivery_related_target_quantity[dm_object] = 0.0 + if m not in orphaned_delivery_related_list[dm_object]: + # Do not count twice + orphaned_delivery_related_list[dm_object].append(m) + if has_delivery_rule: has_delivery_rule_related_list[dm_object].append(m) + orphaned_delivery_related_quantity[dm_object] = orphaned_delivery_related_quantity[dm_object] + m.getNetConvertedQuantity() + orphaned_delivery_related_target_quantity[dm_object] = orphaned_delivery_related_target_quantity[dm_object] + \ + m.getNetConvertedTargetQuantity() + # Build m to dm_object mapping + if not orphaned_delivery_list.has_key(m): + orphaned_delivery_list[m] = [] + orphaned_delivery_quantity[m] = 0.0 + orphaned_delivery_target_quantity[m] = 0.0 + if dm_object not in orphaned_delivery_list[m]: + # Do not count twice + orphaned_delivery_list[m].append(dm_object) + orphaned_delivery_quantity[m] = orphaned_delivery_quantity[m] + dm_object.getNetConvertedQuantity() # Quantity is likely 0 + orphaned_delivery_target_quantity[m] = orphaned_delivery_target_quantity[m] + \ + dm_object.getNetConvertedTargetQuantity() # Quantity is likely 0 + if not found_candidate: + # Best solution is probably to create a new delivery + if order is not None: + for delivery in order.getCausalityRelatedValueList(portal_type=("Sales Packing List", "Purchase Packing List", + "Production Report", "Production Packing List", "Sale Packing List" )): + print " portential delivery %s" % delivery.getRelativeUrl() + else: + print " no order found" + build_delivery_list.append(m) + +print "=======================================================" +print "N to 1 aggregates" +for dm_object in orphaned_delivery_related_list.keys(): + if dm_object.getNetConvertedQuantity() == orphaned_delivery_related_quantity[dm_object]: + print " Found matching N(%s) quantity to 1 quantity aggregate for %s" % ( + len(orphaned_delivery_related_list[dm_object]), dm_object.getRelativeUrl()) + for m in orphaned_delivery_related_list[dm_object]: + print " #### attaching %s to %s" % (m.getRelativeUrl() , dm_object.getRelativeUrl()) + #m.setDeliveryValue(dm_object) + del orphaned_delivery_list[m] # Not needed anylonger since we found a solution + del orphaned_delivery_quantity[m] # Not needed anylonger since we found a solution + elif dm_object.getNetConvertedTargetQuantity() == orphaned_delivery_related_target_quantity[dm_object]: + print " Found matching N(%s) target_quantity to 1 target_quantity aggregate for %s" % ( + len(orphaned_delivery_related_list[dm_object]), dm_object.getRelativeUrl()) + print " #### updating quantity of %s" % dm_object.getRelativeUrl() + #dm_object.setNetConvertedQuantity(orphaned_delivery_related_quantity[dm_object]) # Update quantity to meet simulation + for m in orphaned_delivery_related_list[dm_object]: + print " #### attaching %s to %s" % (m.getRelativeUrl() , dm_object.getRelativeUrl()) + #m.setDeliveryValue(dm_object) + del orphaned_delivery_list[m] # Not needed anylonger since we found a solution + del orphaned_delivery_quantity[m] # Not needed anylonger since we found a solution + elif dm_object.getNetConvertedQuantity() == 0 and dm_object.getNetConvertedTargetQuantity() != 0: + # Probably delivery relation renamed at some point + print " Found zeroed N(%s) to 1 aggregate for %s" % ( + len(orphaned_delivery_related_list[dm_object]), dm_object.getRelativeUrl()) + print " #### updating quantity of %s" % dm_object.getRelativeUrl() + #dm_object.setNetConvertedQuantity(orphaned_delivery_related_quantity[dm_object]) # Update quantity to meet simulation + for m in orphaned_delivery_related_list[dm_object]: + print " #### attaching %s to %s" % (m.getRelativeUrl() , dm_object.getRelativeUrl()) + #m.setDeliveryValue(dm_object) + del orphaned_delivery_list[m] # Not needed anylonger since we found a solution + del orphaned_delivery_quantity[m] # Not needed anylonger since we found a solution + else: + print " Found non matching N(%s) to 1 aggregate for %s delivery q/t: %s %s simulation q/t: %s %s" % ( + len(orphaned_delivery_related_list[dm_object]), + dm_object.getRelativeUrl(), + dm_object.getNetConvertedQuantity(), dm_object.getNetConvertedTargetQuantity(), + orphaned_delivery_related_quantity[dm_object], orphaned_delivery_related_target_quantity[dm_object]) + print " #### updating quantity of %s" % dm_object.getRelativeUrl() + #dm_object.setNetConvertedQuantity(orphaned_delivery_related_quantity[dm_object]) # Update quantity to meet simulation + for m in orphaned_delivery_related_list[dm_object]: + print " #### attaching %s to %s" % (m.getRelativeUrl() , dm_object.getRelativeUrl()) + #m.setDeliveryValue(dm_object) + del orphaned_delivery_list[m] # Not needed anylonger since we found a solution + del orphaned_delivery_quantity[m] # Not needed anylonger since we found a solution + +print "=======================================================" +print "1 to N > 1 aggregates" +for m in orphaned_delivery_list.keys(): + if len(orphaned_delivery_list[m]) > 1: + # 1 to 1 should be already processed at this point + if m.getNetConvertedQuantity() == orphaned_delivery_target_quantity[m]: + print " Found matching 1 to N(%s) aggregate for %s" % (len(orphaned_delivery_list[m]), m.getRelativeUrl()) + dm_object = orphaned_delivery_list[m][0] + print " #### attaching %s to %s q/t: %s %s" % (m.getRelativeUrl(), dm_object.getRelativeUrl(), + dm_object.getNetConvertedQuantity(), dm_object.getNetConvertedTargetQuantity()) + # XXX What about quantity_unit +# m.edit( +# target_start_date = dm_object.getTargetStartDate(), +# target_stop_date = dm_object.getTargetStopDate(), +# start_date = dm_object.getStartDate(), +# stop_date = dm_object.getStopDate(), +# quantity = dm_object.getQuantity(), +# target_quantity = dm_object.getTargetQuantity(), +# delivery = dm_object.getRelativeUrl(), +# ) + for i in range(len(orphaned_delivery_list[m]) - 1): + new_id = "%s_fixsplit_%s" % (m.getId(), i) + dm_object = orphaned_delivery_list[m][i+1] + print " #### creating new simulation movement %s attached to %s q/t: %s %s" % (new_id, dm_object.getRelativeUrl(), + dm_object.getNetConvertedQuantity(), + dm_object.getNetConvertedTargetQuantity()) + # XXX What about quantity_unit +# new_movement = m.aq_parent.newContent(portal_type = "Simulation Movement", +# id = new_id, +# efficiency = m.getEfficiency(), +# target_efficiency = m.getTargetEfficiency(), +# target_start_date = dm_object.getTargetStartDate(), +# target_stop_date = dm_object.getTargetStopDate(), +# start_date = dm_object.getStartDate(), +# stop_date = dm_object.getStopDate(), +# quantity = dm_object.getQuantity(), +# target_quantity = dm_object.getTargetQuantity(), +# delivery = dm_object.getRelativeUrl(), +# source = m.getSource(), +# destination = m.getDestination(), +# source_section = m.getSourceSection(), +# destination_section = m.getDestinationSection(), +# order = m.getOrder() +# ) + else: + print " Found non matching 1 to N(%s) aggregate for %s delivery q/t: %s %s simulation q/t: %s %s" % ( + len(orphaned_delivery_list[m]), m.getRelativeUrl(), + orphaned_delivery_quantity[m], orphaned_delivery_target_quantity[m], + m.getNetConvertedQuantity(), m.getNetConvertedTargetQuantity(), + ) + dm_object = orphaned_delivery_list[m][0] + print " #### attaching %s to %s q/t: %s %s" % (m.getRelativeUrl(), dm_object.getRelativeUrl(), + dm_object.getNetConvertedQuantity(), dm_object.getNetConvertedTargetQuantity()) + # XXX What about quantity_unit +# m.edit( +# target_start_date = dm_object.getTargetStartDate(), +# target_stop_date = dm_object.getTargetStopDate(), +# start_date = dm_object.getStartDate(), +# stop_date = dm_object.getStopDate(), +# quantity = dm_object.getQuantity(), +# target_quantity = dm_object.getTargetQuantity(), +# delivery = dm_object.getRelativeUrl(), +# ) + for i in range(len(orphaned_delivery_list[m]) - 1): + new_id = "%s_fixsplit_%s" % (m.getId(), i) + dm_object = orphaned_delivery_list[m][i+1] + print " #### creating new simulation movement %s attached to %s q/t: %s %s" % (new_id, dm_object.getRelativeUrl(), + dm_object.getNetConvertedQuantity(), + dm_object.getNetConvertedTargetQuantity()) + # XXX What about quantity_unit +# new_movement = m.aq_parent.newContent(portal_type = "Simulation Movement", +# id = new_id, +# efficiency = m.getEfficiency(), +# target_efficiency = m.getTargetEfficiency(), +# target_start_date = dm_object.getTargetStartDate(), +# target_stop_date = dm_object.getTargetStopDate(), +# start_date = dm_object.getStartDate(), +# stop_date = dm_object.getStopDate(), +# quantity = dm_object.getQuantity(), +# target_quantity = dm_object.getTargetQuantity(), +# delivery = dm_object.getRelativeUrl(), +# source = m.getSource(), +# destination = m.getDestination(), +# source_section = m.getSourceSection(), +# destination_section = m.getDestinationSection(), +# order = m.getOrder() +# ) + +print "=======================================================" +print "New deliveries" + +#root_group = context.portal_simulation.collectMovement(build_delivery_list) +#delivery_list = context.portal_simulation.buildDeliveryList(root_group) +#for delivery in delivery_list: +# print "New delivery %s for causality %s" % (delivery.getRelativeUrl(), ' '.join(delivery.getCausalityList())) + +print '\n'.join(map(lambda x:x.getRelativeUrl(), build_delivery_list)) + +print "=======================================================" +print "Reexpand delivery rules (and delete duplicate delivery relations)" +for arb in context.portal_rules.default_delivery_rule.getSpecialiseRelatedValueList(): + ar = arb.getObject() + before = len(ar.objectIds()) + #ar.expand() + after = len(ar.objectIds()) + print " reexpand %s before: %s after: %s" % (ar.getRelativeUrl(), before, after) + + +print "=======================================================" +print "TODO" + +print " compare quantities in simulation and deliveries" + + + +return printed diff --git a/product/Coramy/skins/coramy_erp5/PortalSimulation_zGetResourceList.zsql b/product/Coramy/skins/coramy_erp5/PortalSimulation_zGetResourceList.zsql new file mode 100755 index 0000000000000000000000000000000000000000..d5c8a69176a780a9e73af0f5ae1ca9a73a807c4d --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/PortalSimulation_zGetResourceList.zsql @@ -0,0 +1,23 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:1000 +max_cache:100 +cache_time:0 +class_name: +class_file: +</dtml-comment> +<params>section +strict_membership</params> +SELECT DISTINCT + movement.resource_uid, + movement.variation_text +FROM + movement, stock, catalog as section, category +WHERE + stock.uid = movement.uid +AND stock.section_uid = section.uid +AND section.uid = category.category_uid +AND category.base_category_uid = <dtml-sqlvar "portal_categories.group.getUid()" type="int"> +AND section.relative_url = <dtml-sqlvar section type="string"> +<dtml-if strict_membership>AND category.strict_membership=1</dtml-if> \ No newline at end of file diff --git a/product/Coramy/skins/coramy_erp5/base_folder_workflow_action.form b/product/Coramy/skins/coramy_erp5/base_folder_workflow_action.form new file mode 100755 index 0000000000000000000000000000000000000000..b0b584d3df52026f57fc536711b7ccedc751bac6 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/base_folder_workflow_action.form @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="iso-8859-1"?> + +<form> + <title>Validate</title> + <name>base_folder_workflow_action</name> + <action>folder_workflow_status_modify</action> + <enctype></enctype> + <method>POST</method> + <pt>form_view_dialog</pt> + + <groups> + <group> + <title>Default</title> + <fields> + + <field><id>my_comment</id> <type>TextAreaField</type> + <values> + <alternate_name></alternate_name> + <css_class></css_class> + <default></default> + <description></description> + <external_validator></external_validator> + <extra></extra> + <height type="int">5</height> + <hidden type="int">0</hidden> + <max_length></max_length> + <max_linelength></max_linelength> + <max_lines></max_lines> + <required type="int">0</required> + <title>Commentaires</title> + <width type="int">40</width> + </values> + <tales> + <default>python:''</default> + </tales> + <messages> + <message name="external_validator_failed">The input failed the external validator.</message> + <message name="required_not_found">Input is required but no input given.</message> + <message name="too_many_lines">You entered too many lines.</message> + <message name="line_too_long">A line was too long.</message> + <message name="too_long">You entered too many characters.</message> + </messages> + </field> + </fields> + </group> + <group> + <title>hidden</title> + <fields> + + <field><id>my_workflow_action</id> <type>StringField</type> + <values> + <alternate_name></alternate_name> + <css_class></css_class> + <default></default> + <description></description> + <display_maxwidth></display_maxwidth> + <display_width type="int">20</display_width> + <external_validator></external_validator> + <extra></extra> + <hidden type="int">1</hidden> + <max_length></max_length> + <required type="int">0</required> + <title>x</title> + <truncate type="int">0</truncate> + </values> + <tales> + <default>python:here.REQUEST.workflow_action</default> + </tales> + <messages> + <message name="external_validator_failed">The input failed the external validator.</message> + <message name="required_not_found">Input is required but no input given.</message> + <message name="too_long">Too much input was given.</message> + </messages> + </field> + <field><id>my_workflow_id</id> <type>StringField</type> + <values> + <alternate_name></alternate_name> + <css_class></css_class> + <default></default> + <description></description> + <display_maxwidth></display_maxwidth> + <display_width type="int">20</display_width> + <external_validator></external_validator> + <extra></extra> + <hidden type="int">1</hidden> + <max_length></max_length> + <required type="int">0</required> + <title>x</title> + <truncate type="int">0</truncate> + </values> + <tales> + <default>python:here.REQUEST.workflow_id</default> + </tales> + <messages> + <message name="external_validator_failed">The input failed the external validator.</message> + <message name="required_not_found">Input is required but no input given.</message> + <message name="too_long">Too much input was given.</message> + </messages> + </field> + </fields> + </group> + </groups> +</form> \ No newline at end of file diff --git a/product/Coramy/skins/coramy_erp5/folder_workflow_status_modify.py b/product/Coramy/skins/coramy_erp5/folder_workflow_status_modify.py new file mode 100755 index 0000000000000000000000000000000000000000..7d3a65eb85ac87bcd83b5824aabe1c47a1df27a5 --- /dev/null +++ b/product/Coramy/skins/coramy_erp5/folder_workflow_status_modify.py @@ -0,0 +1,77 @@ +## Script (Python) "folder_workflow_status_modify" +##bind container=container +##bind context=context +##bind namespace= +##bind script=script +##bind subpath=traverse_subpath +##parameters=form_id,dialog_id,selection_name +##title= +## +from Products.Formulator.Errors import ValidationError, FormValidationError + +request=context.REQUEST +error_message = '' + +try: + # Validate the form + form = getattr(context,dialog_id) + form.validate_all_to_request(request) + kw = {} + for f in form.get_fields(): + k = f.id + k = k[3:] + v = getattr(request,k,None) + if v is not None: + kw[k] = v + selection_list = context.portal_selections.callSelectionFor(selection_name, context=context) + for selection_item in selection_list: + o = selection_item.getObject() + workflow_action = kw['workflow_action'] + action_list = o.portal_workflow.getActionsFor(o) + action_list = filter(lambda x:x.has_key('id'), action_list ) + action_id_list = map(lambda x:x['id'], action_list) + if workflow_action in action_id_list: + o.portal_workflow.doActionFor( + o, + workflow_action, + wf_id=kw['workflow_id'], + **kw) + + # We will check if there's an error_message + history_data = None + try: + history_data = o.portal_workflow.getInfoFor(ob=o, name='history') + except: + pass + redirect_url = None + if history_data is not None: + last_history_data = history_data[len(history_data)-1] + this_error = last_history_data.get('error_message') + if this_error != None and this_error != '': + error_message += this_error + "-" + +except FormValidationError, validation_errors: + # Pack errors into the request + field_errors = form.ErrorFields(validation_errors) + request.set('field_errors', field_errors) + return form(request) +except ValueError, value_error: + # Pack errors into the request + redirect_url = '%s/%s?%s%s' % ( context.absolute_url(), form_id + , 'portal_status_message=',value_error + ) + + context.REQUEST[ 'RESPONSE' ].redirect( redirect_url ) +else: + + if error_message != None and error_message != '': + redirect_url = '%s/%s?%s' % ( context.absolute_url(), form_id + , 'portal_status_message=%s' % error_message + ) + pass + if redirect_url is None: + redirect_url = '%s/%s?%s' % ( context.absolute_url(), form_id + , 'portal_status_message=Status+changed.' + ) + + context.REQUEST[ 'RESPONSE' ].redirect( redirect_url ) diff --git a/product/Coramy/skins/coramy_list_method/PieceTissu_searchConsumedList.zsql b/product/Coramy/skins/coramy_list_method/PieceTissu_searchConsumedList.zsql new file mode 100755 index 0000000000000000000000000000000000000000..c6cb7d4d2bce14bd80159cb02368175aeeaba0f3 --- /dev/null +++ b/product/Coramy/skins/coramy_list_method/PieceTissu_searchConsumedList.zsql @@ -0,0 +1,25 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:100000 +max_cache:10 +cache_time:60 +class_name: +class_file: +</dtml-comment> +<params></params> +SELECT DISTINCT + distinct item.uid +FROM + catalog AS item + +LEFT JOIN category +ON (category.category_uid=item.uid +AND category.base_category_uid = <dtml-var "portal_categories.aggregate.getUid()">) + +LEFT JOIN stock +ON (stock.uid = category.uid) + +WHERE item.portal_type = "Piece Tissu" +AND stock.node_uid = <dtml-var "portal_categories.site.Stock_MP.Gravelines.getUid()"> +AND stock.quantity < 0 \ No newline at end of file diff --git a/product/Coramy/skins/coramy_list_method/PieceTissu_searchRemainingList.zsql b/product/Coramy/skins/coramy_list_method/PieceTissu_searchRemainingList.zsql new file mode 100755 index 0000000000000000000000000000000000000000..ad5cc057091e81ee23150f189318ae5991443ae2 --- /dev/null +++ b/product/Coramy/skins/coramy_list_method/PieceTissu_searchRemainingList.zsql @@ -0,0 +1,18 @@ +<dtml-comment> +title: +connection_id:MySQL +max_rows:500 +max_cache:100 +cache_time:60 +class_name:ZSQLBrain +class_file:zsqlbrain.py +</dtml-comment> +<params></params> +SELECT + * +FROM + catalog +WHERE +portal_type = "Piece Tissu" +<dtml-in PieceTissu_searchConsumedList>AND uid <> <dtml-sqlvar uid type="int"> +</dtml-in> \ No newline at end of file