Commit a72bfb41 by François C.

Merge branch 'products_get_average_sales' into 'dev_cooperatic'

Add LaCagetteProducts api function to retrieve product template sales data (for order help process)

See merge request !7
parents 0aed72a2 1c4e9b3f
# -*- coding: utf-8 -*-
from openerp import _, api, models, fields
import datetime
import numpy
class LaCagetteProducts(models.Model):
_name = "lacagette.products"
......@@ -70,6 +72,10 @@ class LaCagetteProducts(models.Model):
@api.model
def get_simple_list(self, data={}):
"""Retrieve products simple list.
@data: list of parameters (only_purchase_ok)
@return: list (with list key or error key)
"""
res = {}
try:
sql = """
......@@ -101,3 +107,142 @@ class LaCagetteProducts(models.Model):
res['error'] = str(e)
return res
def _compte_consecutive_non_sale_days(self, sale_days, days):
"""
@sale_days : list of sale days
@days: list of full period days (except excluded one, such as sundays)
@return : integer days to remove from days number to compute average
"""
minimum_significative_consecutive_days = 5 # arbitrary set (TODO ? : set it in odoo parameters)
consecutive_found = [] # each serie is added to compute total of them
missing_days = []
for d in days:
if not (d in sale_days):
missing_days.append(d)
current_consecutive_number = 1
for i in range(len(missing_days)):
if i > 0:
current_day = datetime.datetime.strptime(missing_days[i], "%Y-%m-%d")
previous_day = datetime.datetime.strptime(missing_days[i-1], "%Y-%m-%d")
if (current_day - previous_day).days == 1:
current_consecutive_number += 1
else:
if current_consecutive_number >= minimum_significative_consecutive_days:
consecutive_found.append(current_consecutive_number)
current_consecutive_number = 1
return int(numpy.sum(consecutive_found))
def _compute_product_template_sales_average(self, ids, days, result):
res = []
products_qtys = {} # used to compute totals and sigma
products_discounts = {} # used to compute totals
products_sums = {} # used to sum daily sales quantity
found_ids = [] # used to set not found product results to 0
products_sale_days = {} # used to compute consecutive non sale days (to fit average)
for p in result:
pid = p['tpl_id']
found_ids.append(pid)
if not (pid in products_sale_days):
products_sale_days[pid] = [p['day']]
else:
products_sale_days[pid].append(p['day'])
if not (pid in products_qtys):
products_qtys[pid] = [p['qtys']]
else:
products_qtys[pid].append(p['qtys'])
if not (pid in products_discounts):
products_discounts[pid] = [p['discounts']]
else:
products_discounts[pid].append(p['discounts'])
if not (pid in products_sums):
products_sums[pid] = {'total_qty': p['qtys'], 'total_discount': p['discounts']}
else:
products_sums[pid]['total_qty'] += p['qtys']
products_sums[pid]['total_discount'] += p['discounts']
for i in ids:
average_qty = average_discount = sigma = 0
vpc = 1 # Void PerCent (percant of non sales days)
if (i in found_ids):
days_nb_to_remove = self._compte_consecutive_non_sale_days(products_sale_days[i], days)
significative_days = len(days) - days_nb_to_remove
if significative_days > 0:
average_qty = round(numpy.sum(products_qtys[i])/significative_days, 2)
average_discount = round(numpy.sum(products_discounts[i])/significative_days, 2)
# to compute sigma, add 0 for non_sales_days
void = []
for j in range(len(days) - len(products_sale_days[i])):
void.append(0)
sigma = round(numpy.std(products_qtys[i] + void), 2)
vpc = round((float(len(days)) - len(products_sale_days[i]))/len(days), 2)
res.append({'id': i, 'average_qty': average_qty, 'average_discount': average_discount, 'sigma': sigma, 'vpc': vpc})
return res
@api.model
def get_template_products_sales_average(self, params={}):
"""Retrieve products sales average.
@params: list of parameters ('ids', 'period', excluded_days)
@return: list (with list key or error key)
"""
res = {}
if 'ids' in params:
ids = list(filter(lambda x: isinstance(x, int), params['ids']))
if len(ids) > 0:
today = datetime.date.today()
excluded_days = [0]
if 'excluded_days' in params:
excluded_days = params['excluded_days']
if 'to' in params:
dto = params['to']
else:
dto = today - datetime.timedelta(1)
dto = dto.strftime("%Y-%m-%d")
if 'from' in params:
dfrom = params['from']
else:
dfrom = today - datetime.timedelta(50)
dfrom = dfrom.strftime("%Y-%m-%d")
try:
sql = """
SELECT
TO_CHAR(create_date, 'YYYY-MM-DD') as day,
(SELECT product_tmpl_id FROM product_product WHERE id = pol.product_id) as tpl_id,
SUM(qty) as qtys, SUM(discount) as discounts
FROM pos_order_line pol
WHERE
qty != 0
AND
product_id
IN (
SELECT id FROM product_product
WHERE product_tmpl_id IN %s
)
AND
create_date > %s AND create_date < %s
GROUP BY day, tpl_id
"""
self.env.cr.execute(sql, [tuple(ids), dfrom, dto])
req_res = self.env.cr.dictfetchall()
sql_dates = """
SELECT date_trunc('day', dd):: date as ddate, extract(DOW FROM dd) as dow
FROM generate_series
( '""" + dfrom + """'::timestamp
, '""" + dto + """'::timestamp
, '1 day'::interval) dd
"""
self.env.cr.execute(sql_dates)
days = list(filter(lambda x: not (x['dow'] in excluded_days), self.env.cr.dictfetchall()))
days = map(lambda x: x['ddate'], days)
res['list'] = self._compute_product_template_sales_average(ids, days, req_res)
except Exception as e:
res['error'] = str(e)
else:
res['error'] = "No valid ids found"
else:
res['error'] = "ids list key is missing"
return res
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