Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
third-party
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cooperatic-foodcoops
third-party
Commits
8a03b3b5
Commit
8a03b3b5
authored
Apr 28, 2021
by
François
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Modifications pour boutique en ligne plus paramétrable
parent
b6bf8444
Pipeline
#885
passed with stage
in 21 seconds
Changes
6
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
152 additions
and
61 deletions
+152
-61
mail.py
outils/mail.py
+5
-2
models.py
shop/models.py
+25
-11
shop.css
shop/static/css/shop.css
+4
-1
shop.js
shop/static/js/shop.js
+60
-7
views.py
shop/views.py
+53
-39
index.html
templates/shop/index.html
+5
-1
No files found.
outils/mail.py
View file @
8a03b3b5
...
...
@@ -22,7 +22,7 @@ class CagetteMail:
html_message
=
html_msg
)
@staticmethod
def
sendCartValidation
(
email
,
cart
):
def
sendCartValidation
(
email
,
cart
,
mode
=
"shop"
):
"""Used by Shop"""
from
django.core.mail
import
send_mail
from
django.utils.html
import
strip_tags
...
...
@@ -43,7 +43,10 @@ class CagetteMail:
html_msg
=
render_to_string
(
mail_template
,
ctx
)
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
,
settings
.
DEFAULT_FROM_EMAIL
,
[
email
],
...
...
shop/models.py
View file @
8a03b3b5
...
...
@@ -47,7 +47,11 @@ def get_all_children(branch):
children
+=
get_all_children
(
c
)
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 to handle cagette Shop."""
...
...
@@ -62,7 +66,7 @@ class CagetteShop(models.Model):
def
filter_products_according_settings
(
pdts
):
res
=
pdts
try
:
conditions
=
get
t
attr
(
settings
,
'SHOP_LIMIT_PRODUCTS'
,
[])
conditions
=
getattr
(
settings
,
'SHOP_LIMIT_PRODUCTS'
,
[])
filtered
=
[]
for
p
in
pdts
:
keep_it
=
True
...
...
@@ -124,13 +128,14 @@ class CagetteShop(models.Model):
fields
=
[
'parent_id'
,
'name'
]
res
=
api
.
search_read
(
'product.category'
,
[],
fields
)
tree
=
build_tree_from_categories
(
res
)
except
:
pass
except
Exception
as
e
:
coop_logger
.
error
(
'get_product_categories :
%
s'
,
str
(
e
))
return
tree
@staticmethod
def
get_cat_children_ids
(
categ_id
):
cat_ids
=
[
categ_id
]
tree
=
CagetteShop
.
get_product_categories
()
branch
=
None
for
cats
in
tree
:
...
...
@@ -159,15 +164,23 @@ class CagetteShop(models.Model):
return
children
@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
):
res
=
{}
try
:
pdts
=
[]
limit_conditions
=
[]
try
:
limit_conditions
=
settings
.
SHOP_LIMIT_PRODUCTS
except
:
pass
limit_conditions
=
getattr
(
settings
,
'SHOP_LIMIT_PRODUCTS'
,
[])
api
=
OdooAPI
()
cat_ids
=
CagetteShop
.
get_cat_children_ids
(
categ_id
)
# removed ['qty_available', '>', 0]
...
...
@@ -183,6 +196,7 @@ class CagetteShop(models.Model):
res
[
'pdts'
]
=
CagetteShop
.
filter_products_according_settings
(
pdts
)
except
Exception
as
e
:
coop_logger
.
error
(
'get_category_products
%
s
%
s'
,
categ_id
,
str
(
e
))
res
[
'error'
]
=
str
(
e
)
return
res
...
...
@@ -239,7 +253,7 @@ class CagetteShop(models.Model):
@staticmethod
def
registrerCart
(
cart
,
partner_id
):
def
registrerCart
(
cart
,
partner_id
,
mode
=
"shop"
):
result
=
{}
try
:
cart
[
'submitted_time'
]
=
time
.
time
()
...
...
@@ -260,7 +274,7 @@ class CagetteShop(models.Model):
if
result
:
try
:
from
outils.mail
import
CagetteMail
CagetteMail
.
sendCartValidation
(
partner
[
'email'
],
cart
)
CagetteMail
.
sendCartValidation
(
partner
[
'email'
],
cart
,
mode
)
except
Exception
as
e
:
coop_logger
.
error
(
"Shop, registrerCart :
%
s,
%
s"
,
str
(
e
),
str
(
cart
))
except
Exception
as
e
:
...
...
shop/static/css/shop.css
View file @
8a03b3b5
...
...
@@ -252,7 +252,10 @@ li.tab { border-right: 1px solid white; }
#my-orders-sumup
.date
{
text-align
:
left
;
padding
:
0
4px
;}
#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
;}
#survey_link
{
text-decoration
:
none
;}
...
...
shop/static/js/shop.js
View file @
8a03b3b5
...
...
@@ -26,6 +26,7 @@ var main_content = $('#main-content'),
dragSrcEl
=
null
,
forbidden_slots
=
[],
closing_dates
=
[],
my_sent_orders
=
[],
right_column
=
$
(
'#right-column'
),
visit_mode
=
false
,
timer
=
null
;
...
...
@@ -717,7 +718,7 @@ var addProductToCart = function() {
var
msg
=
""
;
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
;
}
var
u
=
p_div
.
find
(
'.unit'
).
text
()
...
...
@@ -757,7 +758,7 @@ var addProductToCart = function() {
}
}
if
(
typeof
answer
.
warning
!==
"undefined"
)
{
if
(
answer
.
warning
==
"max_qty"
)
if
(
answer
.
warning
==
"max_qty"
&&
stock_warning
==
true
)
msg
=
too_much
;
}
});
...
...
@@ -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
ul
=
catdiv
.
find
(
'ul'
);
$
.
each
(
children
,
function
(
i
,
e
)
{
if
(
excluded_cat
.
indexOf
(
e
.
id
)
<
0
)
{
if
(
shouldCategoryBeShown
(
e
.
id
)
)
{
var
li
=
$
(
'<li>'
).
addClass
(
"nav-item"
);
// Remove TVA in cat name
...
...
@@ -1092,7 +1110,6 @@ var getCategChildren = function() {
if
(
typeof
category_elts
[
cat_id
]
==
"undefined"
)
{
try
{
$
.
ajax
({
//url :'/shop/get_categ_products',
url
:
'/shop/get_cat_children'
,
data
:
{
id
:
cat_id
},
dataType
:
'json'
...
...
@@ -1236,12 +1253,13 @@ var displaySentOrders = function() {
}
}
else
if
(
typeof
rData
.
res
.
data
.
orders
!=
"undefined"
)
{
if
(
rData
.
res
.
data
.
orders
.
length
>
0
)
{
my_sent_orders
=
rData
.
res
.
data
.
orders
;
var
eye
=
'<i class="fas fa-eye fl"></i>'
;
var
delete_icon
=
'<i class="fas fa-trash fr"></i>'
;
var
edit
=
'<i class="fas fa-edit"></i>'
;
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>"
;
if
(
o
.
state
==
"init"
||
o
.
state
==
"validating"
)
bdate_content
+=
" "
+
edit
;
...
...
@@ -1267,7 +1285,8 @@ var displaySentOrders = function() {
.
text
(
o
.
products
.
length
);
var
td4
=
$
(
'<td>'
).
addClass
(
'amount'
)
.
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'
)
.
html
(
actions_content
);
...
...
@@ -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
clicked
=
$
(
this
);
var
clicked_tr
=
clicked
.
closest
(
'tr'
),
...
...
@@ -1561,15 +1610,19 @@ valid_cart.click(function() {
$
(
'#get_my_bought_products'
).
click
(
loadAllAvailableBoughtProducts
);
$
(
document
).
on
(
'change'
,
'[name^="bday"]'
,
filterHourOptions
);
$
(
document
).
on
(
'change'
,
'[name="bhour"]'
,
adaptTimeGivenForValidationMsg
);
$
(
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'
,
'.product button'
,
addProductToCart
);
$
(
document
).
on
(
'click'
,
'.forbidden-slots .fs-close'
,
closeForbiddenList
);
$
(
document
).
on
(
'click'
,
'td.date .fa-edit'
,
changeBestDate
);
$
(
document
).
on
(
'click'
,
'td.actions .fa-eye'
,
showSentCart
);
$
(
document
).
on
(
'click'
,
'td.actions .fa-trash'
,
destroySentCart
);
if
(
shop_mode
==
'shop'
)
$
(
document
).
on
(
'change'
,
'[name^="bday"]'
,
filterHourOptions
);
$
(
document
).
on
(
'click'
,
'.new-order'
,
function
()
{
...
...
shop/views.py
View file @
8a03b3b5
...
...
@@ -13,44 +13,23 @@ def shop_index(request):
def
delivery_index
(
request
):
return
index
(
request
,
mode
=
'delivery'
)
def
index
(
request
,
mode
=
"shop"
):
template
=
loader
.
get_template
(
'shop/index.html'
)
credentials
=
CagetteMember
.
get_credentials
(
request
)
shop_settings
=
CagetteShop
.
get_shop_settings
()
def
_get_index_context
(
credentials
,
shop_settings
,
mode
):
context
=
{
'title'
:
'Commande / Réservation'
,
'mode'
:
mode
,
'COMPANY_NAME'
:
settings
.
COMPANY_NAME
,
'SHOP_CATEGORIES'
:
settings
.
SHOP_CATEGORIES
,
'EXCLUDE_SHOP_CATEGORIES'
:
settings
.
EXCLUDE_SHOP_CATEGORIES
,
'MIN_DELAY_FOR_SLOT'
:
settings
.
MIN_DELAY_FOR_SLOT
,
'HOURS_FOR_VALIDATION'
:
settings
.
HOURS_FOR_VALIDATION_SHOP
}
'header_img'
:
getattr
(
settings
,
'SHOP_HEADER_IMG'
,
'/static/img/header.jpg'
)
}
if
'capital_message'
in
shop_settings
:
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
):
# Visitor has not been identified
template
=
loader
.
get_template
(
'website/connect.html'
)
context
[
'msg'
]
=
''
if
'msg'
in
credentials
:
context
[
'msg'
]
=
credentials
[
'msg'
]
context
[
'password_placeholder'
]
=
'Mot de passe'
context
[
'password_notice'
]
=
"Par défaut, la date de naissance (jjmmaaaa)"
context
[
'with_shop_header'
]
=
True
try
:
context
[
'header_img'
]
=
settings
.
SHOP_HEADER_IMG
except
:
context
[
'header_img'
]
=
'/static/img/header.jpg'
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'
):
context
[
'SHOP_CAN_BUY'
]
=
settings
.
SHOP_CAN_BUY
context
[
'DELIVERY_CAN_BUY'
]
=
False
...
...
@@ -58,22 +37,53 @@ def index(request, mode="shop"):
context
[
'SHOP_CAN_BUY'
]
=
False
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
()
context
[
'discounted_pdts'
]
=
d_p_pdts
[
'discounted'
]
context
[
'promoted_pdts'
]
=
d_p_pdts
[
'promoted'
]
context
[
'survey_link'
]
=
''
if
hasattr
(
settings
,
'SHOP_EXTRA_MENUS'
):
context
[
'extra_menus'
]
=
settings
.
SHOP_EXTRA_MENUS
if
hasattr
(
settings
,
'SHOP_SURVEY_LINK'
):
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
cat_nb_pdts
=
CagetteShop
.
get_categories_nb_of_products
()
if
'error'
in
cat_nb_pdts
:
context
[
'cat_nb_pdts'
]
=
None
else
:
context
[
'cat_nb_pdts'
]
=
cat_nb_pdts
# if 'coop_state' in credentials and not (credentials['coop_state'] in allowed_states):
# allowed = False
...
...
@@ -119,6 +129,7 @@ def get_categ_products(request):
result
[
'error'
]
=
'Authentification non valide'
return
JsonResponse
({
'res'
:
result
})
def
search_product
(
request
):
result
=
{}
credentials
=
CagetteMember
.
get_credentials
(
request
)
...
...
@@ -177,7 +188,10 @@ def cart(request):
credentials
=
CagetteMember
.
get_credentials
(
request
)
if
'success'
in
credentials
:
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
:
result
[
'error'
]
=
str
(
e
)
else
:
...
...
templates/shop/index.html
View file @
8a03b3b5
...
...
@@ -436,7 +436,7 @@
</p>
<p>
{% 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%}
</p>
<p>
...
...
@@ -500,6 +500,10 @@
{
%
if
SHOP_OPENING_START_DATE
%
}
const
opening_start_date
=
new
Date
(
'{{SHOP_OPENING_START_DATE}}'
)
{
%
endif
%
}
{
%
if
cat_nb_pdts
%
}
const
cat_nb_pdts
=
{{
cat_nb_pdts
|
safe
}}
{
%
endif
%
}
const
stock_warning
=
{{
SHOP_STOCK_WARNING
|
safe
}}
</script>
<script
src=
"{% static 'js/all_common.js' %}?v="
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/shop.js' %}?v="
></script>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment