Commit 8a03b3b5 by François

Modifications pour boutique en ligne plus paramétrable

parent b6bf8444
...@@ -22,7 +22,7 @@ class CagetteMail: ...@@ -22,7 +22,7 @@ class CagetteMail:
html_message=html_msg) html_message=html_msg)
@staticmethod @staticmethod
def sendCartValidation(email, cart): def sendCartValidation(email, cart, mode="shop"):
"""Used by Shop""" """Used by Shop"""
from django.core.mail import send_mail from django.core.mail import send_mail
from django.utils.html import strip_tags from django.utils.html import strip_tags
...@@ -43,7 +43,10 @@ class CagetteMail: ...@@ -43,7 +43,10 @@ class CagetteMail:
html_msg = render_to_string(mail_template, ctx) html_msg = render_to_string(mail_template, ctx)
msg = strip_tags(html_msg) msg = strip_tags(html_msg)
send_mail("Votre commande en ligne à " + settings.COMPANY_NAME, subject_prefix = "Votre commande en ligne à "
if mode == "delivery":
subject_prefix = "Votre demande de livraison à "
send_mail(subject_prefix + settings.COMPANY_NAME,
msg, msg,
settings.DEFAULT_FROM_EMAIL, settings.DEFAULT_FROM_EMAIL,
[email], [email],
......
...@@ -47,7 +47,11 @@ def get_all_children(branch): ...@@ -47,7 +47,11 @@ def get_all_children(branch):
children += get_all_children(c) children += get_all_children(c)
return children return children
def get_all_children_ids(branch):
ids = []
for c in get_all_children(branch):
ids.append(c['id'])
return ids
class CagetteShop(models.Model): class CagetteShop(models.Model):
"""Class to handle cagette Shop.""" """Class to handle cagette Shop."""
...@@ -62,7 +66,7 @@ class CagetteShop(models.Model): ...@@ -62,7 +66,7 @@ class CagetteShop(models.Model):
def filter_products_according_settings(pdts): def filter_products_according_settings(pdts):
res = pdts res = pdts
try: try:
conditions = gettattr(settings, 'SHOP_LIMIT_PRODUCTS', []) conditions = getattr(settings, 'SHOP_LIMIT_PRODUCTS', [])
filtered = [] filtered = []
for p in pdts: for p in pdts:
keep_it = True keep_it = True
...@@ -124,13 +128,14 @@ class CagetteShop(models.Model): ...@@ -124,13 +128,14 @@ class CagetteShop(models.Model):
fields = ['parent_id', 'name'] fields = ['parent_id', 'name']
res = api.search_read('product.category', [], fields) res = api.search_read('product.category', [], fields)
tree = build_tree_from_categories(res) tree = build_tree_from_categories(res)
except: except Exception as e:
pass coop_logger.error('get_product_categories : %s', str(e))
return tree return tree
@staticmethod @staticmethod
def get_cat_children_ids(categ_id): def get_cat_children_ids(categ_id):
cat_ids = [categ_id] cat_ids = [categ_id]
tree = CagetteShop.get_product_categories() tree = CagetteShop.get_product_categories()
branch = None branch = None
for cats in tree: for cats in tree:
...@@ -159,15 +164,23 @@ class CagetteShop(models.Model): ...@@ -159,15 +164,23 @@ class CagetteShop(models.Model):
return children return children
@staticmethod @staticmethod
def get_categories_nb_of_products():
"""Needs lacagette_categories Odoo module to be activated"""
res = {}
try:
api = OdooAPI()
res = api.execute('lacagette.categories', 'get_all_with_products_count', {})
except Exception as e:
coop_logger.error('get_categories_nb_of_products %s', str(e))
res['error'] = str(e)
return res
@staticmethod
def get_category_products(categ_id): def get_category_products(categ_id):
res = {} res = {}
try: try:
pdts = [] pdts = []
limit_conditions = [] limit_conditions = getattr(settings, 'SHOP_LIMIT_PRODUCTS', [])
try:
limit_conditions = settings.SHOP_LIMIT_PRODUCTS
except:
pass
api = OdooAPI() api = OdooAPI()
cat_ids = CagetteShop.get_cat_children_ids(categ_id) cat_ids = CagetteShop.get_cat_children_ids(categ_id)
# removed ['qty_available', '>', 0] # removed ['qty_available', '>', 0]
...@@ -183,6 +196,7 @@ class CagetteShop(models.Model): ...@@ -183,6 +196,7 @@ class CagetteShop(models.Model):
res['pdts'] = CagetteShop.filter_products_according_settings(pdts) res['pdts'] = CagetteShop.filter_products_according_settings(pdts)
except Exception as e: except Exception as e:
coop_logger.error('get_category_products %s %s', categ_id, str(e))
res['error'] = str(e) res['error'] = str(e)
return res return res
...@@ -239,7 +253,7 @@ class CagetteShop(models.Model): ...@@ -239,7 +253,7 @@ class CagetteShop(models.Model):
@staticmethod @staticmethod
def registrerCart(cart, partner_id): def registrerCart(cart, partner_id, mode="shop"):
result = {} result = {}
try: try:
cart['submitted_time'] = time.time() cart['submitted_time'] = time.time()
...@@ -260,7 +274,7 @@ class CagetteShop(models.Model): ...@@ -260,7 +274,7 @@ class CagetteShop(models.Model):
if result: if result:
try: try:
from outils.mail import CagetteMail from outils.mail import CagetteMail
CagetteMail.sendCartValidation(partner['email'], cart) CagetteMail.sendCartValidation(partner['email'], cart, mode)
except Exception as e: except Exception as e:
coop_logger.error("Shop, registrerCart : %s, %s", str(e), str(cart)) coop_logger.error("Shop, registrerCart : %s, %s", str(e), str(cart))
except Exception as e: except Exception as e:
......
...@@ -252,7 +252,10 @@ li.tab { border-right: 1px solid white; } ...@@ -252,7 +252,10 @@ li.tab { border-right: 1px solid white; }
#my-orders-sumup .date {text-align: left;padding: 0 4px;} #my-orders-sumup .date {text-align: left;padding: 0 4px;}
#my-orders-sumup tbody tr:hover {background-color: #b3b7c4;} #my-orders-sumup tbody tr:hover {background-color: #b3b7c4;}
td.actions .fa-trash, td.actions .fa-paper-plane, td.date .fa-edit {cursor: pointer;} td.actions .fa-trash,
td.actions .fa-eye,
td.actions .fa-paper-plane,
td.date .fa-edit {cursor: pointer;}
.no-action-available-msg {margin-top: 15px;} .no-action-available-msg {margin-top: 15px;}
#survey_link {text-decoration: none;} #survey_link {text-decoration: none;}
......
...@@ -26,6 +26,7 @@ var main_content = $('#main-content'), ...@@ -26,6 +26,7 @@ var main_content = $('#main-content'),
dragSrcEl = null, dragSrcEl = null,
forbidden_slots = [], forbidden_slots = [],
closing_dates = [], closing_dates = [],
my_sent_orders = [],
right_column = $('#right-column'), right_column = $('#right-column'),
visit_mode = false, visit_mode = false,
timer = null; timer = null;
...@@ -717,7 +718,7 @@ var addProductToCart = function() { ...@@ -717,7 +718,7 @@ var addProductToCart = function() {
var msg = ""; var msg = "";
var too_much = "Vous avez pris plus de produit que le stock indicatif.\nVous n'aurez peut-être pas toute la quantité."; var too_much = "Vous avez pris plus de produit que le stock indicatif.\nVous n'aurez peut-être pas toute la quantité.";
if (parseFloat(qty) > available_qty) { if (parseFloat(qty) > available_qty && stock_warning == true) {
msg = too_much; msg = too_much;
} }
var u = p_div.find('.unit').text() var u = p_div.find('.unit').text()
...@@ -757,7 +758,7 @@ var addProductToCart = function() { ...@@ -757,7 +758,7 @@ var addProductToCart = function() {
} }
} }
if (typeof answer.warning !== "undefined") { if (typeof answer.warning !== "undefined") {
if (answer.warning == "max_qty") if (answer.warning == "max_qty" && stock_warning == true)
msg = too_much; msg = too_much;
} }
}); });
...@@ -1059,11 +1060,28 @@ var loadAllAvailableBoughtProducts = function() { ...@@ -1059,11 +1060,28 @@ var loadAllAvailableBoughtProducts = function() {
} }
}; };
var shouldCategoryBeShown = function (cat_id) {
let answer = true;
if (excluded_cat.indexOf(cat_id) > -1) {
answer = false;
}
if (typeof cat_nb_pdts != "undefined") {
let list = cat_nb_pdts.list;
let cat_ids = Object.keys(list).map(x => parseInt(x,10));
//cat_ids is now an array of category ids which have product
if (cat_ids.indexOf(cat_id) < 0) {
// cat_id is corresponding to a category which have no product
answer = false;
}
}
return answer;
}
var appendChildrenCatToMenu = function (catdiv, children) { var appendChildrenCatToMenu = function (catdiv, children) {
var ul = catdiv.find('ul'); var ul = catdiv.find('ul');
$.each(children, function(i, e) { $.each(children, function(i, e) {
if (excluded_cat.indexOf(e.id) < 0) { if (shouldCategoryBeShown(e.id)) {
var li = $('<li>').addClass("nav-item"); var li = $('<li>').addClass("nav-item");
// Remove TVA in cat name // Remove TVA in cat name
...@@ -1092,7 +1110,6 @@ var getCategChildren = function() { ...@@ -1092,7 +1110,6 @@ var getCategChildren = function() {
if (typeof category_elts[cat_id] == "undefined") { if (typeof category_elts[cat_id] == "undefined") {
try { try {
$.ajax({ $.ajax({
//url :'/shop/get_categ_products',
url : '/shop/get_cat_children', url : '/shop/get_cat_children',
data: {id: cat_id}, data: {id: cat_id},
dataType: 'json' dataType: 'json'
...@@ -1236,12 +1253,13 @@ var displaySentOrders = function() { ...@@ -1236,12 +1253,13 @@ var displaySentOrders = function() {
} }
} else if (typeof rData.res.data.orders != "undefined") { } else if (typeof rData.res.data.orders != "undefined") {
if (rData.res.data.orders.length > 0) { if (rData.res.data.orders.length > 0) {
my_sent_orders = rData.res.data.orders;
var eye = '<i class="fas fa-eye fl"></i>'; var eye = '<i class="fas fa-eye fl"></i>';
var delete_icon = '<i class="fas fa-trash fr"></i>'; var delete_icon = '<i class="fas fa-trash fr"></i>';
var edit = '<i class="fas fa-edit"></i>'; var edit = '<i class="fas fa-edit"></i>';
var show_no_action_available_msg = false; var show_no_action_available_msg = false;
$.each(rData.res.data.orders, function(i, o) { $.each(my_sent_orders, function(i, o) {
var bdate_content = "<span>" + o.best_date + "</span>"; var bdate_content = "<span>" + o.best_date + "</span>";
if (o.state == "init" || o.state == "validating") bdate_content += " " + edit; if (o.state == "init" || o.state == "validating") bdate_content += " " + edit;
...@@ -1267,7 +1285,8 @@ var displaySentOrders = function() { ...@@ -1267,7 +1285,8 @@ var displaySentOrders = function() {
.text(o.products.length); .text(o.products.length);
var td4 = $('<td>').addClass('amount') var td4 = $('<td>').addClass('amount')
.text(parseFloat(o.total).toFixed(2)); .text(parseFloat(o.total).toFixed(2));
//var td5 = $('<td>').addClass('actions').html(eye + ' ' + delete_icon)
actions_content = eye + ' ' + actions_content;
var td5 = $('<td>').addClass('actions') var td5 = $('<td>').addClass('actions')
.html(actions_content); .html(actions_content);
...@@ -1374,6 +1393,36 @@ var changeBestDate = function() { ...@@ -1374,6 +1393,36 @@ var changeBestDate = function() {
}; };
var showSentCart = function() {
let clicked = $(this),
clicked_tr = clicked.closest('tr'),
id = clicked_tr.data('id'),
content = $('<div>'),
table = $('<table>');
let header = $('<tr><th>Article</th><th>Qté</th><th>Prix Total (T.T.C)</th></tr>');
let bottom_msg = $('<p>').html("<em>Contenu non modifiable.</em>")
table.append(header);
$.each(my_sent_orders, function(i,e) {
if (e._id == id) {
$.each(e.products, function (j,p) {
let tr = $('<tr>'),
name = $('<td>').text(p.name),
qty = $('<td>').text(p.qty),
total = $('<td>').text(p.total)
tr.append(name);
tr.append(qty);
tr.append(total);
table.append(tr);
})
}
})
content.append(table);
content.append(bottom_msg);
displayMsg(content.html());
}
var destroySentCart = function() { var destroySentCart = function() {
var clicked = $(this); var clicked = $(this);
var clicked_tr = clicked.closest('tr'), var clicked_tr = clicked.closest('tr'),
...@@ -1561,15 +1610,19 @@ valid_cart.click(function() { ...@@ -1561,15 +1610,19 @@ valid_cart.click(function() {
$('#get_my_bought_products').click(loadAllAvailableBoughtProducts); $('#get_my_bought_products').click(loadAllAvailableBoughtProducts);
$(document).on('change', '[name^="bday"]', filterHourOptions);
$(document).on('change', '[name="bhour"]', adaptTimeGivenForValidationMsg); $(document).on('change', '[name="bhour"]', adaptTimeGivenForValidationMsg);
$(document).on('click', '#alim_categ > div, #non_alim_categ > div', getCategChildren); $(document).on('click', '#alim_categ > div, #non_alim_categ > div', getCategChildren);
$(document).on('click', '#alim_categ ul li span, #non_alim_categ ul li span', getCategProducts); $(document).on('click', '#alim_categ ul li span, #non_alim_categ ul li span', getCategProducts);
$(document).on('click', '.product button', addProductToCart); $(document).on('click', '.product button', addProductToCart);
$(document).on('click', '.forbidden-slots .fs-close', closeForbiddenList); $(document).on('click', '.forbidden-slots .fs-close', closeForbiddenList);
$(document).on('click', 'td.date .fa-edit', changeBestDate); $(document).on('click', 'td.date .fa-edit', changeBestDate);
$(document).on('click', 'td.actions .fa-eye', showSentCart);
$(document).on('click', 'td.actions .fa-trash', destroySentCart); $(document).on('click', 'td.actions .fa-trash', destroySentCart);
if (shop_mode == 'shop')
$(document).on('change', '[name^="bday"]', filterHourOptions);
$(document).on( $(document).on(
'click', '.new-order', 'click', '.new-order',
function() { function() {
......
...@@ -13,44 +13,23 @@ def shop_index(request): ...@@ -13,44 +13,23 @@ def shop_index(request):
def delivery_index(request): def delivery_index(request):
return index(request, mode='delivery') return index(request, mode='delivery')
def index(request, mode="shop"): def _get_index_context(credentials, shop_settings, mode):
template = loader.get_template('shop/index.html')
credentials = CagetteMember.get_credentials(request)
shop_settings = CagetteShop.get_shop_settings()
context = {'title': 'Commande / Réservation', context = {'title': 'Commande / Réservation',
'mode': mode, 'mode': mode,
'COMPANY_NAME': settings.COMPANY_NAME, 'COMPANY_NAME': settings.COMPANY_NAME,
'SHOP_CATEGORIES': settings.SHOP_CATEGORIES, 'header_img': getattr(settings, 'SHOP_HEADER_IMG', '/static/img/header.jpg')
'EXCLUDE_SHOP_CATEGORIES': settings.EXCLUDE_SHOP_CATEGORIES, }
'MIN_DELAY_FOR_SLOT': settings.MIN_DELAY_FOR_SLOT,
'HOURS_FOR_VALIDATION': settings.HOURS_FOR_VALIDATION_SHOP}
if 'capital_message' in shop_settings: if 'capital_message' in shop_settings:
context['capital_message'] = shop_settings['capital_message'] context['capital_message'] = shop_settings['capital_message']
allowed_states = ["up_to_date", "alert", "delay"]
# Uncomment if 'coop_state' in credentials .... etc
# to prevent other states people to use the shop
allowed = True
if ('failure' in credentials): if ('failure' in credentials):
# Visitor has not been identified
template = loader.get_template('website/connect.html')
context['msg'] = '' context['msg'] = ''
if 'msg' in credentials: if 'msg' in credentials:
context['msg'] = credentials['msg'] context['msg'] = credentials['msg']
context['password_placeholder'] = 'Mot de passe' context['password_placeholder'] = 'Mot de passe'
context['password_notice'] = "Par défaut, la date de naissance (jjmmaaaa)" context['password_notice'] = "Par défaut, la date de naissance (jjmmaaaa)"
context['with_shop_header'] = True context['with_shop_header'] = True
try:
context['header_img'] = settings.SHOP_HEADER_IMG
except:
context['header_img'] = '/static/img/header.jpg'
else: else:
if hasattr(settings, 'SHOP_OPENING'):
context['SHOP_OPENING'] = settings.SHOP_OPENING
if hasattr(settings, 'SHOP_SLOT_SIZE'):
context['SHOP_SLOT_SIZE'] = settings.SHOP_SLOT_SIZE
if hasattr(settings, 'SHOP_OPENING_START_DATE'):
context['SHOP_OPENING_START_DATE'] = settings.SHOP_OPENING_START_DATE
if mode == 'shop' and hasattr(settings, 'SHOP_CAN_BUY'): if mode == 'shop' and hasattr(settings, 'SHOP_CAN_BUY'):
context['SHOP_CAN_BUY'] = settings.SHOP_CAN_BUY context['SHOP_CAN_BUY'] = settings.SHOP_CAN_BUY
context['DELIVERY_CAN_BUY'] = False context['DELIVERY_CAN_BUY'] = False
...@@ -58,22 +37,53 @@ def index(request, mode="shop"): ...@@ -58,22 +37,53 @@ def index(request, mode="shop"):
context['SHOP_CAN_BUY'] = False context['SHOP_CAN_BUY'] = False
context['DELIVERY_CAN_BUY'] = settings.DELIVERY_CAN_BUY context['DELIVERY_CAN_BUY'] = settings.DELIVERY_CAN_BUY
context['SHOP_CATEGORIES'] = getattr(settings, 'SHOP_CATEGORIES', [])
context['EXCLUDE_SHOP_CATEGORIES'] = getattr(settings, 'EXCLUDE_SHOP_CATEGORIES', [])
context['MIN_DELAY_FOR_SLOT'] = getattr(settings, 'MIN_DELAY_FOR_SLOT', 30)
context['HOURS_FOR_VALIDATION'] = getattr(settings, 'HOURS_FOR_VALIDATION_SHOP', 2)
context['SHOP_OPENING'] = getattr(settings, 'SHOP_OPENING', {})
context['SHOP_SLOT_SIZE'] = getattr(settings, 'SHOP_SLOT_SIZE', 15)
context['SHOP_OPENING_START_DATE'] = getattr(settings, 'SHOP_OPENING_START_DATE', None)
context['survey_link'] = getattr(settings, 'SHOP_SURVEY_LINK', '')
context['extra_menus'] = getattr(settings, 'SHOP_EXTRA_MENUS', None)
context['SHOW_SUBSTITUTION_OPTION'] = getattr(settings, 'SHOW_SUBSTITUTION_OPTION', False)
context['CART_VALIDATION_BOTTOM_MSG'] = getattr(settings, 'CART_VALIDATION_BOTTOM_MSG', "")
context['SHOP_BOTTOM_VALIDATION_MSG'] = getattr(settings, 'SHOP_BOTTOM_VALIDATION_MSG',\
"Si vous arrivez avec un retard de plus d'une heure, la commande pourrait ne plus être disponible.")
stock_warning = getattr(settings, 'SHOP_STOCK_WARNING', True)
if stock_warning is True:
context['SHOP_STOCK_WARNING'] = 'true'
else:
context['SHOP_STOCK_WARNING'] = 'false'
return context
def index(request, mode="shop"):
template = loader.get_template('shop/index.html')
credentials = CagetteMember.get_credentials(request)
shop_settings = CagetteShop.get_shop_settings()
allowed_states = ["up_to_date", "alert", "delay"]
# Uncomment if 'coop_state' in credentials .... etc
# to prevent other states people to use the shop
allowed = True
context = _get_index_context(credentials, shop_settings, mode)
if ('failure' in credentials):
# Visitor has not been identified
template = loader.get_template('website/connect.html')
else:
d_p_pdts = CagetteShop.get_promoted_and_discounted_products() d_p_pdts = CagetteShop.get_promoted_and_discounted_products()
context['discounted_pdts'] = d_p_pdts['discounted'] context['discounted_pdts'] = d_p_pdts['discounted']
context['promoted_pdts'] = d_p_pdts['promoted'] context['promoted_pdts'] = d_p_pdts['promoted']
context['survey_link'] = '' cat_nb_pdts = CagetteShop.get_categories_nb_of_products()
if 'error' in cat_nb_pdts:
if hasattr(settings, 'SHOP_EXTRA_MENUS'): context['cat_nb_pdts'] = None
context['extra_menus'] = settings.SHOP_EXTRA_MENUS else:
if hasattr(settings, 'SHOP_SURVEY_LINK'): context['cat_nb_pdts'] = cat_nb_pdts
context['survey_link'] = settings.SHOP_SURVEY_LINK
context['SHOW_SUBSTITUTION_OPTION'] = True
if hasattr(settings, 'SHOW_SUBSTITUTION_OPTION'):
if settings.SHOW_SUBSTITUTION_OPTION is False:
del context['SHOW_SUBSTITUTION_OPTION']
if hasattr(settings, 'CART_VALIDATION_BOTTOM_MSG'):
context['CART_VALIDATION_BOTTOM_MSG'] = settings.CART_VALIDATION_BOTTOM_MSG
# if 'coop_state' in credentials and not (credentials['coop_state'] in allowed_states): # if 'coop_state' in credentials and not (credentials['coop_state'] in allowed_states):
# allowed = False # allowed = False
...@@ -119,6 +129,7 @@ def get_categ_products(request): ...@@ -119,6 +129,7 @@ def get_categ_products(request):
result['error'] = 'Authentification non valide' result['error'] = 'Authentification non valide'
return JsonResponse({'res': result}) return JsonResponse({'res': result})
def search_product(request): def search_product(request):
result = {} result = {}
credentials = CagetteMember.get_credentials(request) credentials = CagetteMember.get_credentials(request)
...@@ -177,7 +188,10 @@ def cart(request): ...@@ -177,7 +188,10 @@ def cart(request):
credentials = CagetteMember.get_credentials(request) credentials = CagetteMember.get_credentials(request)
if 'success' in credentials: if 'success' in credentials:
try: try:
result['cart'] = CagetteShop.registrerCart(cart, request.COOKIES['id']) mode = "shop"
if 'type' in cart:
mode = cart['type']
result['cart'] = CagetteShop.registrerCart(cart, request.COOKIES['id'], mode)
except Exception as e: except Exception as e:
result['error'] = str(e) result['error'] = str(e)
else: else:
......
...@@ -436,7 +436,7 @@ ...@@ -436,7 +436,7 @@
</p> </p>
<p> <p>
{% if mode == 'shop' %} {% if mode == 'shop' %}
<strong><i>Si vous arrivez avec un retard de plus d'une heure, la commande pourrait ne plus être disponible.</i></strong> <strong><i>{{SHOP_BOTTOM_VALIDATION_MSG}}</i></strong>
{%endif%} {%endif%}
</p> </p>
<p> <p>
...@@ -500,6 +500,10 @@ ...@@ -500,6 +500,10 @@
{%if SHOP_OPENING_START_DATE%} {%if SHOP_OPENING_START_DATE%}
const opening_start_date = new Date('{{SHOP_OPENING_START_DATE}}') const opening_start_date = new Date('{{SHOP_OPENING_START_DATE}}')
{%endif%} {%endif%}
{%if cat_nb_pdts%}
const cat_nb_pdts = {{cat_nb_pdts|safe}}
{%endif%}
const stock_warning = {{SHOP_STOCK_WARNING|safe}}
</script> </script>
<script src="{% static 'js/all_common.js' %}?v="></script> <script src="{% static 'js/all_common.js' %}?v="></script>
<script type="text/javascript" src="{% static 'js/shop.js' %}?v="></script> <script type="text/javascript" src="{% static 'js/shop.js' %}?v="></script>
......
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