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
3 years ago
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
],
...
...
This diff is collapsed.
Click to expand it.
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
:
...
...
This diff is collapsed.
Click to expand it.
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
;}
...
...
This diff is collapsed.
Click to expand it.
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
()
{
...
...
This diff is collapsed.
Click to expand it.
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
:
...
...
This diff is collapsed.
Click to expand it.
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>
...
...
This diff is collapsed.
Click to expand it.
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