Commit 9ee93048 authored by Xiaowu Zhang's avatar Xiaowu Zhang

erp5_trade: customise sale order report

parent 7cb707a2
from Products.ERP5Form.Report import ReportSection
from Products.ERP5Type.DateUtils import getIntervalListBetweenDates
from DateTime import DateTime
params, stat_columns, selection_columns = context.OrderModule_getOrderReportParameterDict()
context.REQUEST.set('stat_columns', stat_columns)
result=[]
request = container.REQUEST
# list only if user has a login defined
aggregation_level = request.get('aggregation_level')
from_date = request.get('from_date')
to_date = request.get('at_date')
group_by = request.get('group_by')
quantity_unit = request.get('quantity_unit')
simulation_state = request.get('simulation_state', ())
# define some parameter dependings on module
if "Sale" in context.getPortalType():
report_type = "sale"
line_portal_type = "Sale Order Line"
doc_portal_type = "Sale Order"
elif "Purchase" in context.getPortalType():
report_type = "purchase"
line_portal_type = "Purchase Order Line"
doc_portal_type = "Purchase Order"
elif request.get('order_report_document_portal_type'):
doc_portal_type = request.get('order_report_document_portal_type')
if doc_portal_type == 'Purchase Invoice Transaction':
line_portal_type = 'Invoice Line'
report_type = 'purchase'
elif doc_portal_type == 'Sale Invoice Transaction':
line_portal_type = 'Invoice Line'
report_type = 'sale'
else:
raise ValueError, "unknown document portal type for report %s" % doc_portal_type
else:
raise ValueError, "unknown type for report"
selection_columns = [('group_by', "Group by")]
if from_date is None:
# get the minimum start date in catalog
from Products.ZSQLCatalog.SQLCatalog import Query, NegatedQuery
kw = {"delivery.start_date" : None, "key":"DefaultKey"}
q = NegatedQuery(Query(**kw))
select_expression = "MIN(delivery.start_date)"
group_by = "delivery.start_date"
from_date = DateTime()
result_list = context.portal_catalog(
select_expression=select_expression,
group_by_expression=group_by,
simulation_state=simulation_state,
portal_type=doc_portal_type,
query=q,
limit=1)
if result_list:
from_date = DateTime(result_list[0][2])
# get period list between given date
interval_list_dict = getIntervalListBetweenDates(from_date=from_date, to_date=to_date,
keys={'year':aggregation_level=="year",
'month':aggregation_level=="month",
'week' : aggregation_level=="week",
'day':aggregation_level=="day"})
interval_list = interval_list_dict[aggregation_level]
# FIXME: translate column names
# list columns of the listbox
interval_column_list = []
if group_by == "client":
interval_column_list.extend([("Amount %s" %x,"Amount %s" %x) for x in interval_list])
selection_columns = [('client', "Client")]
stat_columns = [('client', "client")]
total_column_list = [('total amount', 'Total Amount'),]
total_stat_list = [('total amount', 'total amount'),]
else:
if group_by == "product":
selection_columns = [('product_reference', "Product Reference", ), ('product', "Product")]
stat_columns = [('product', "product")]
elif group_by == "function":
function_title = context.AccountingTransactionLine_getFunctionBaseCategoryTitle()
selection_columns = [('product', function_title)]
stat_columns = [('product', "product")]
else:
selection_columns = [('client', "Client"), ('product_reference', "Product Reference", ), ('product', "Product")]
stat_columns = [('client', "client"), ('product', "product")]
for x in interval_list:
interval_column_list.extend([("Amount %s" %x,"Amount %s" %x), ("Quantity %s" %x,"Quantity %s" %x)])
if not quantity_unit:
interval_column_list.extend([("Quantity Unit %s" %x,"Quantity Unit %s" %x)])
total_column_list = [('total amount', 'Total Amount'),('total quantity', 'Total Quantity')]
total_stat_list = [('total amount', 'total amount'),('total quantity', 'total quantity')]
selection_columns.extend(interval_column_list)
selection_columns.extend(total_column_list)
params=dict(period_list=interval_list, report_type=report_type,
doc_portal_type=doc_portal_type, line_portal_type=line_portal_type,
simulation_state=simulation_state)
# stat columns of the listbox
stat_columns = stat_columns + interval_column_list + total_stat_list
context.REQUEST.set('stat_columns', stat_columns)
result.append(ReportSection(
path=context.getPhysicalPath(),
selection_columns=selection_columns,
listbox_display_mode='FlatListMode',
selection_params=params,
form_id='OrderModule_viewOrderStatList'))
return result
from Products.PythonScripts.standard import Object
from json import loads
from Products.ZSQLCatalog.SQLCatalog import Query
portal = context.getPortalObject()
category_tool = portal.portal_categories
request = container.REQUEST
from_date = request.get('from_date', None)
to_date = request.get('at_date', None)
aggregation_level = request.get('aggregation_level', None)
report_group_by = request.get('group_by', None)
quantity_unit = request.get('quantity_unit', None)
active_process_path = request.get('active_process')
# We have to sum product_dict and client_dict from the results of active process
def _addDict(global_dict, local_dict, only_amount=False):
if report_group_by == "both" and not only_amount:
# we have client -> product -> period -> amount
for local_title, local_product_dict in local_dict.iteritems():
product_dict = global_dict.setdefault(local_title, {})
for local_product, local_period_dict in local_product_dict.iteritems():
period_dict = product_dict.setdefault(local_product, {})
for period, local_amount_dict in local_period_dict.iteritems():
amount_dict = period_dict.setdefault(period, {'amount' : 0, 'quantity' : 0, 'quantity_unit' : ''})
amount_dict['amount'] = amount_dict['amount'] + local_amount_dict['amount']
amount_dict['quantity'] = amount_dict['quantity'] + local_amount_dict['quantity']
amount_dict['quantity_unit'] = local_amount_dict['quantity_unit']
else:
# We have client or product -> period -> amount
for local_title, local_period_dict in local_dict.iteritems():
period_dict = global_dict.setdefault(local_title, {})
for period, local_amount_dict in local_period_dict.iteritems():
amount_dict = period_dict.setdefault(period, {'amount' : 0, 'quantity' : 0, 'quantity_unit' : ''})
amount_dict['amount'] = amount_dict['amount'] + local_amount_dict['amount']
if not only_amount:
amount_dict['quantity'] = amount_dict['quantity'] + local_amount_dict['quantity']
amount_dict['quantity_unit'] = local_amount_dict['quantity_unit']
product_dict = {}
# get all category
incoterm = request.get('incoterm', None)
section_category = request.get('section_category', None)
order = request.get('order', None)
delivery_mode = request.get('delivery_mode', None)
catalog_params = {}
resource_title_dict = {}
# get all organisations for the selected section category
if section_category:
group_uid = category_tool.getCategoryValue(section_category).getUid()
organisation_uid_list = [x.uid for x in portal.portal_catalog(
portal_type="Organisation",
default_group_uid=group_uid)]
if report_type == "sale":
catalog_params['default_source_section_uid'] = organisation_uid_list or -1
elif report_type:
catalog_params['default_destination_section_uid'] = organisation_uid_list or -1
# add category params if defined
if incoterm not in ('', None):
incoterm_uid = category_tool.incoterm.restrictedTraverse(incoterm).getUid()
catalog_params['default_incoterm_uid'] = incoterm_uid
if order not in ('', None):
order_uid = category_tool.order.restrictedTraverse(order).getUid()
catalog_params['default_order_uid'] = order_uid
if delivery_mode not in ('', None):
delivery_mode_uid = category_tool.delivery_mode.restrictedTraverse(delivery_mode).getUid()
catalog_params['default_delivery_mode_uid'] = delivery_mode_uid
# compute sql params, we group and order by date and portal type
if aggregation_level == "year":
date_format = "%Y"
elif aggregation_level == "month":
date_format = "%Y-%m"
elif aggregation_level == "week":
date_format = "%Y-%U"
elif aggregation_level == "day":
date_format = "%Y-%m-%d"
params = {"delivery.start_date":(from_date, to_date)}
query=None
if from_date is not None and to_date is not None:
params = {"delivery.start_date":(from_date, to_date)}
query = Query(range="minngt", **params)
elif from_date is not None:
params = {"delivery.start_date":from_date}
query = Query(range="min", **params)
elif to_date is not None:
params = {"delivery.start_date":to_date}
query = Query(range="ngt", **params)
sort_on_list = [ ('delivery.destination_section_uid', 'ASC'), ('delivery.start_date','ASC')]
if request.get('use_selection'):
selection_name = request['selection_name']
result_list = \
context.portal_selections.callSelectionFor(request['selection_name'])
else:
result_list = context.portal_catalog.searchResults(limit=None,query=query,
portal_type=doc_portal_type,
simulation_state=simulation_state,
sort_on=sort_on_list,
**catalog_params)
# we build two dict, one that store amount per period per client
# and another that either store amount per period per product and per client
# or only amount per period per product dependings on choosen group by
client_dict = {}
if active_process_path:
active_process = portal.restrictedTraverse(active_process_path)
for result in active_process.getResultList():
if result.summary:
continue
detail = loads(result.detail)
if detail['type'] == "result":
result_product_dict = detail['product_dict']
result_client_dict = detail["client_dict"]
product_dict = {}
for result in result_list:
result = result.getObject()
period = result.getStartDate()
if period is not None:
period = period.strftime(date_format)
if report_group_by in ("client", "both"):
# client_title -> period -> amount
if report_type == "sale":
client_title = result.getDestinationSectionTitle()
else:
continue
if not len(client_dict) and len(result_client_dict):
client_dict = result_client_dict.copy()
client_title = result.getSourceSectionTitle()
# FIXME: if two clients have the same title, do we want to group ?
if not client_dict.has_key(client_title):
client_dict[client_title] = {}
if client_dict[client_title].has_key(period):
client_dict[client_title][period]['amount'] = client_dict[client_title][period]['amount'] + result.getTotalPrice()
else:
_addDict(client_dict, result_client_dict, only_amount=True)
if not len(product_dict) and len(result_product_dict):
product_dict = result_product_dict.copy()
client_dict[client_title][period] = {'amount' : result.getTotalPrice()}
if not product_dict.has_key(client_title):
line_dict = product_dict[client_title] = {}
else:
_addDict(product_dict, result_product_dict)
else:
raise ValueError("No active process found to process report")
line_dict = product_dict[client_title]
else:
line_dict = product_dict
if report_group_by != "client":
# client_title -> product_title -> period -> amount/quantity...
# or product_title -> period -> amount/quantity...
for line in result.contentValues(filter = {'portal_type':line_portal_type}):
# Filter by quantity_unit
if quantity_unit:
if line.getQuantityUnit() != quantity_unit:
continue
# FIXME: if two resources have the same title, do we want to group ?
if report_group_by == "function":
if report_type == "sale":
product_title = line.getSourceFunctionTitle()
else:
product_title = line.getDestinationFunctionTitle()
else:
product_title = line.getResourceTitle()
resource_title_dict[product_title] = line.getResourceReference()
if not line_dict.has_key(product_title):
line_dict[product_title] = {period :{"amount" : line.getTotalPrice(),
"quantity" : line.getTotalQuantity(),
"quantity_unit" : line.getQuantityUnitTranslatedTitle()}}
else:
if not line_dict[product_title].has_key(period):
line_dict[product_title][period] = {"amount" : line.getTotalPrice(),
"quantity" : line.getTotalQuantity(),
"quantity_unit" : line.getQuantityUnitTranslatedTitle()}
else:
line_dict[product_title][period]['amount'] = line_dict[product_title][period]['amount'] + line.getTotalPrice()
line_dict[product_title][period]['quantity'] = line_dict[product_title][period]['quantity'] + line.getTotalQuantity()
def sortProduct(a, b):
return cmp(a['product'], b['product'])
period_counter_dict = {}
line_list = []
append = line_list.append
......@@ -84,6 +173,7 @@ if len(client_dict):
period_counter_dict['total amount'] = period_counter_dict['total amount'] + line_total_amount
else:
period_counter_dict['total amount'] = line_total_amount
append(obj)
if report_group_by == "both":
product_lines_list = []
......@@ -93,6 +183,7 @@ if len(client_dict):
for product_title in line_product_dict.keys():
obj = Object(uid="new_")
obj['product'] = product_title
obj['product_reference'] = resource_title_dict.get(product_title)
line_total_amount = 0
line_total_quantity = 0
for period in period_list:
......@@ -109,18 +200,18 @@ if len(client_dict):
line_product_dict[product_title][period]['amount']
else:
period_counter_dict['Amount %s' %(period)] = line_product_dict[product_title][period]['amount']
if quantity_unit:
if period_counter_dict.has_key('Quantity %s' %(period)):
period_counter_dict['Quantity %s' %(period)] = period_counter_dict['Quantity %s' %(period)] + \
line_product_dict[product_title][period]['quantity']
else:
period_counter_dict['Quantity %s' %(period)] = line_product_dict[product_title][period]['quantity']
else:
obj['Amount %s' %(period)] = 0
obj['Quantity %s' %(period)] = 0
obj['Quantity Unit %s' %(period)] = ""
obj['total quantity'] = line_total_quantity
obj['total amount'] = round(line_total_amount, 2)
# total for stat line
......@@ -144,6 +235,8 @@ else:
for product_title in product_dict.keys():
obj = Object(uid="new_")
obj['product'] = product_title
obj['product_reference'] = resource_title_dict.get(product_title)
line_total_amount = 0
line_total_quantity = 0
for period in period_list:
......@@ -168,6 +261,7 @@ else:
obj['Amount %s' %(period)] = 0
obj['Quantity %s' %(period)] = 0
obj['Quantity Unit %s' %(period)] = ""
obj['total quantity'] = line_total_quantity
obj['total amount'] = round(line_total_amount,2)
# total for stat line
......@@ -181,12 +275,16 @@ else:
else:
period_counter_dict['total quantity'] = line_total_quantity
append(obj)
line_list.sort(sortProduct)
obj = Object(uid="new_")
obj["client"] = 'Total'
for k,v in period_counter_dict.items():
if "mount" in k:
v = round(v, 2)
obj[k] = v
request.set('stat_line', [obj,])
return line_list
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