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
a1086686
Commit
a1086686
authored
Jun 22, 2022
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[REC] create add products modal & make qties required
parent
e13eb617
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
284 additions
and
46 deletions
+284
-46
reception_style.css
reception/static/css/reception_style.css
+51
-0
reception_produits.js
reception/static/js/reception_produits.js
+205
-46
views.py
reception/views.py
+1
-0
reception_produits.html
templates/reception/reception_produits.html
+27
-0
No files found.
reception/static/css/reception_style.css
View file @
a1086686
...
...
@@ -215,6 +215,57 @@ tr.odd td.row_product_no_qty {
display
:
none
;
}
.search_products_to_add_area
{
margin
:
2rem
0
;
}
.search_product_input
{
width
:
60%
;
}
.autocomplete_dropdown
{
z-index
:
10000001
!important
;
}
.products_lines
{
display
:
none
;
}
.products_lines_title
{
margin
:
3rem
0
2rem
0
;
}
.add_product_line
{
display
:
flex
;
align-items
:
center
;
margin
:
1rem
0
;
}
.add_product_line_item
{
width
:
45%
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
}
.product_qty_input_alert
{
color
:
#c9302c
;
font-size
:
1.4rem
;
display
:
none
;
}
.remove_line
{
width
:
10%
;
color
:
#c9302c
;
cursor
:
pointer
;
}
.product_already_selected
,
.product_already_selected
:hover
{
background-color
:
#acb3c2
;
}
/* Accordion style */
/* Style the buttons that are used to open and close the accordion panel */
...
...
reception/static/js/reception_produits.js
View file @
a1086686
...
...
@@ -13,7 +13,6 @@ Sémantiquement, ici :
* Associative array of current order(s)
* If more than 1 element: group of orders
* If 1 element: single order
* -> check for Object.keys(orders).length to know if we're in a group case
*/
var
orders
=
{},
group_ids
=
[];
...
...
@@ -31,7 +30,9 @@ var reception_status = null,
validProducts
=
[],
// Keep record of directly validated products
updateType
=
""
,
// step 1: qty_valid; step2: br_valid
barcodes
=
null
,
// Barcodes stored locally
priceToWeightIsCorrect
=
true
;
priceToWeightIsCorrect
=
true
,
suppliers_products
=
[],
// All products of current order(s) supplier(s)
products_to_add
=
[];
// Products to add to order
var
dbc
=
null
,
sync
=
null
,
...
...
@@ -43,6 +44,28 @@ function back() {
document
.
location
.
href
=
"/reception"
;
}
/**
* Dingle order or grouped orders?
* @returns Boolean
*/
function
is_grouped_order
()
{
return
Object
.
keys
(
orders
).
length
>
1
;
}
/**
* Get distinct suppliers id of current orders
* @returns Boolean
*/
function
get_suppliers_id
()
{
let
suppliers_id
=
[];
for
(
var
order_id
in
orders
)
{
if
(
'partner_id'
in
orders
[
order_id
])
{
// for versions transition
suppliers_id
.
push
(
orders
[
order_id
].
partner_id
);
}
}
return
suppliers_id
;
}
/** Search if the product being edited is already in the updated products.
* Returns its index or -1.
*/
...
...
@@ -239,7 +262,7 @@ function resetPopUpButtons() {
document
.
querySelector
(
'#modal_closebtn_bottom'
).
style
.
backgroundColor
=
""
;
}
/*
INIT
*/
/*
FETCH SERVER DATA
*/
// Get order(s) data from server
function
fetch_data
()
{
...
...
@@ -331,6 +354,74 @@ function fetch_data() {
}
}
// Load barcodes at page loading, then barcodes are stored locally
var
get_barcodes
=
async
function
()
{
if
(
barcodes
==
null
)
barcodes
=
await
init_barcodes
();
};
// Get labels to print for current orders from server
function
get_pdf_labels
()
{
try
{
if
(
is_time_to
(
'print_pdf_labels'
,
10000
))
{
// Concatenate orders id into a string, separated with comas, to retrieve
oids
=
group_ids
.
join
(
','
);
// Send request & diret download pdf
var
filename
=
"codebarres_"
+
group_ids
[
0
]
+
".pdf"
;
$
.
ajax
({
url
:
"../../orders/get_pdf_labels?oids="
+
oids
,
success
:
download
.
bind
(
true
,
"pdf"
,
filename
)
});
}
else
{
alert
(
"Vous avez cliqué il y a moins de 10s... Patience, la demande est en cours de traitement."
);
}
}
catch
(
e
)
{
err
=
{
msg
:
e
.
name
+
' : '
+
e
.
message
,
ctx
:
'get_pdf_labels'
};
console
.
error
(
err
);
report_JS_error
(
err
,
'reception'
);
}
}
/**
* Get products of order(s) supplier(s) if not already fetched
*/
function
fetch_suppliers_products
()
{
if
(
suppliers_products
.
length
===
0
)
{
openModal
();
let
suppliers_id
=
get_suppliers_id
();
// Fetch supplier products
$
.
ajax
({
type
:
'GET'
,
url
:
"/orders/get_supplier_products"
,
data
:
{
sids
:
suppliers_id
},
dataType
:
"json"
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
success
:
function
(
data
)
{
suppliers_products
=
data
.
res
.
products
;
closeModal
();
set_add_products_modal
();
},
error
:
function
(
data
)
{
err
=
{
msg
:
"erreur serveur lors de la récupération des produits du fournisseur"
,
ctx
:
'get_supplier_products'
};
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
}
report_JS_error
(
err
,
'reception'
);
closeModal
();
alert
(
'Erreur lors de la récupération des produits, réessayer plus tard.'
);
}
});
}
else
{
set_add_products_modal
();
}
}
/* LISTS HANDLING */
...
...
@@ -385,7 +476,7 @@ function initLists() {
let
columns_processed
=
[];
// In case of group orders, add "Order" as first column for ordering
if
(
Object
.
keys
(
orders
).
length
>
1
)
{
if
(
is_grouped_order
()
)
{
columns_to_process
.
push
({
data
:
"order_key"
,
title
:
"n°"
,
className
:
"dt-body-center"
,
width
:
"20px"
...
...
@@ -1223,30 +1314,6 @@ function setAllQties() {
/* ACTIONS */
// Get labels to print for current orders from server
function
get_pdf_labels
()
{
try
{
if
(
is_time_to
(
'print_pdf_labels'
,
10000
))
{
// Concatenate orders id into a string, separated with comas, to retrieve
oids
=
group_ids
.
join
(
','
);
// Send request & diret download pdf
var
filename
=
"codebarres_"
+
group_ids
[
0
]
+
".pdf"
;
$
.
ajax
({
url
:
"../../orders/get_pdf_labels?oids="
+
oids
,
success
:
download
.
bind
(
true
,
"pdf"
,
filename
)
});
}
else
{
alert
(
"Vous avez cliqué il y a moins de 10s... Patience, la demande est en cours de traitement."
);
}
}
catch
(
e
)
{
err
=
{
msg
:
e
.
name
+
' : '
+
e
.
message
,
ctx
:
'get_pdf_labels'
};
console
.
error
(
err
);
report_JS_error
(
err
,
'reception'
);
}
}
function
print_product_labels
()
{
try
{
if
(
is_time_to
(
'print_pdt_labels'
,
10000
))
{
...
...
@@ -1551,7 +1618,7 @@ function send() {
}
// Set order(s) name in popup DOM
if
(
Object
.
keys
(
orders
).
length
===
1
)
{
// Single order
if
(
is_grouped_order
()
===
false
)
{
// Single order
document
.
getElementById
(
"order_ref"
).
innerHTML
=
orders
[
Object
.
keys
(
orders
)[
0
]].
name
;
}
else
{
// group
document
.
getElementById
(
"success_order_name_container"
).
hidden
=
true
;
...
...
@@ -1633,7 +1700,7 @@ function send() {
let
couchdb_update_data
=
Object
.
values
(
orders
);
// We're in a group, remove it & update groups doc
if
(
Object
.
keys
(
orders
).
length
>
1
)
{
if
(
is_grouped_order
()
)
{
let
groups_doc
=
doc
;
let
first_order_id
=
parseInt
(
Object
.
keys
(
orders
)[
0
]);
...
...
@@ -1709,6 +1776,41 @@ function confirm_all_left_is_good() {
closeModal
();
}
function
saveErrorReport
()
{
user_comments
=
document
.
getElementById
(
"error_report"
).
value
;
// Save comments in all orders
for
(
order_id
of
Object
.
keys
(
orders
))
{
orders
[
order_id
].
user_comments
=
user_comments
;
update_distant_order
(
order_id
);
}
document
.
getElementById
(
"search_input"
).
focus
();
}
/**
* Check if all qty inputs are set, if so do add products
*/
function
add_products_action
()
{
let
qty_inputs
=
$
(
"#modal .products_lines"
).
find
(
".product_qty_input"
);
let
has_empty_qty_input
=
false
;
for
(
let
qty_input
of
qty_inputs
)
{
if
(
$
(
qty_input
).
val
()
===
""
)
{
has_empty_qty_input
=
true
$
(
qty_input
).
siblings
(
".product_qty_input_alert"
).
show
();
}
else
{
$
(
qty_input
).
siblings
(
".product_qty_input_alert"
).
hide
();
}
}
if
(
qty_inputs
.
length
>
0
&&
has_empty_qty_input
===
false
)
{
// TODO do add products
}
}
/* DOM */
function
openFAQ
()
{
openModal
(
$
(
"div#modal_FAQ_content"
).
html
(),
function
()
{},
'Compris !'
,
true
,
false
);
}
...
...
@@ -1733,25 +1835,83 @@ function openErrorReport() {
textarea
.
setSelectionRange
(
textarea
.
value
.
length
,
textarea
.
value
.
length
);
}
function
saveErrorReport
()
{
user_comments
=
document
.
getElementById
(
"error_report"
).
value
;
/**
* Set the autocomplete on add products modal, search product input.
* If extists, destroys instance and recreate it.
* Filter autocomplete data by removing products already selected.
*/
function
set_products_autocomplete
()
{
let
autocomplete_products
=
suppliers_products
.
filter
(
p
=>
products_to_add
.
findIndex
(
pta
=>
pta
.
name
===
p
.
name
)
===
-
1
);
// Save comments in all orders
for
(
order_id
of
Object
.
keys
(
orders
))
{
orders
[
order_id
].
user_comments
=
user_comments
;
update_distant_order
(
order_id
);
try
{
$
(
"#modal .search_product_input"
).
autocomplete
(
"destroy"
);
}
catch
(
error
)
{
// autocomplete not set yet, do nothing
}
document
.
getElementById
(
"search_input"
).
focus
();
}
$
(
"#modal .search_product_input"
).
autocomplete
({
source
:
autocomplete_products
.
map
(
p
=>
p
.
name
),
classes
:
{
"ui-autocomplete"
:
"autocomplete_dropdown"
},
delay
:
0
});
// Load barcodes at page loading, then barcodes are stored locally
var
get_barcodes
=
async
function
()
{
if
(
barcodes
==
null
)
barcodes
=
await
init_barcodes
();
};
$
(
".autocomplete_dropdown"
).
off
(
"click"
);
// todo + enter
$
(
".autocomplete_dropdown"
).
on
(
"click"
,
(
e
)
=>
{
let
product_name
=
e
.
target
.
textContent
;
// extra secutiry but shouldn't happen
if
(
products_to_add
.
findIndex
(
p
=>
p
.
name
===
product_name
)
===
-
1
)
{
let
product
=
suppliers_products
.
find
(
p
=>
p
.
name
===
product_name
);
products_to_add
.
push
(
product
);
// Reset search elements
$
(
".autocomplete_dropdown"
).
hide
();
$
(
"#modal .search_product_input"
).
val
(
''
);
set_products_autocomplete
();
// Display
let
add_product_template
=
$
(
"#add_product_line_template"
);
add_product_template
.
find
(
".product_name"
).
text
(
product_name
);
$
(
"#modal .products_lines"
).
append
(
add_product_template
.
html
());
if
(
products_to_add
.
length
===
1
)
{
$
(
"#modal .products_lines"
).
show
();
}
function
add_products_action
()
{
$
(
".remove_line_icon"
).
off
(
"click"
);
$
(
".remove_line_icon"
).
on
(
"click"
,
remove_product_line
);
}
});
}
/**
* Remove product from list of products to add & remove line from DOM
* @param {Event} e
*/
function
remove_product_line
(
e
)
{
let
product_line
=
$
(
e
.
target
).
closest
(
".add_product_line"
);
let
product_name
=
product_line
.
find
(
".product_name"
).
text
();
let
product_to_add_index
=
products_to_add
.
findIndex
(
p
=>
p
.
name
===
product_name
);
products_to_add
.
splice
(
product_to_add_index
,
1
);
product_line
.
remove
();
set_products_autocomplete
();
}
/**
* Set & display the modal to search products
*/
function
set_add_products_modal
()
{
let
add_products_modal
=
$
(
"#modal_add_products"
);
openModal
(
add_products_modal
.
html
(),
add_products_action
,
'Ajouter les produits'
,
false
);
set_products_autocomplete
();
}
/**
...
...
@@ -1779,7 +1939,7 @@ function init_dom(partners_display_data) {
});
// Grouped orders
if
(
Object
.
keys
(
orders
).
length
>
1
)
{
if
(
is_grouped_order
()
)
{
$
(
'#partner_name'
).
html
(
Object
.
keys
(
orders
).
length
+
" commandes"
);
// Display order data for each order
...
...
@@ -1932,8 +2092,7 @@ function init_dom(partners_display_data) {
// Minimum security level
if
(
pswd
==
add_products_pswd
)
{
console
.
log
(
'ok'
);
// TODO
fetch_suppliers_products
();
}
else
if
(
pswd
==
null
)
{
return
;
}
else
{
...
...
reception/views.py
View file @
a1086686
...
...
@@ -60,6 +60,7 @@ def get_list_orders(request):
"id"
:
order
[
"id"
],
"name"
:
order
[
"name"
],
"date_order"
:
order
[
"date_order"
],
"partner_id"
:
order
[
"partner_id"
][
0
],
"partner"
:
order
[
"partner_id"
][
1
],
"date_planned"
:
order
[
"date_planned"
],
"amount_untaxed"
:
round
(
order
[
"amount_untaxed"
],
2
),
...
...
templates/reception/reception_produits.html
View file @
a1086686
...
...
@@ -4,6 +4,7 @@
{% block additionnal_css %}
<link
rel=
"stylesheet"
href=
"{% static 'css/datatables/jquery.dataTables.css' %}"
>
<link
rel=
"stylesheet"
href=
"{% static 'css/reception_style.css' %}"
>
<link
rel=
"stylesheet"
href=
"{% static 'jquery-ui-1.12.1/jquery-ui.min.css' %}"
>
{% endblock %}
{% block additionnal_scripts %}
...
...
@@ -11,6 +12,7 @@
<script
type=
"text/javascript"
src=
"{% static 'js/datatables/jquery.dataTables.min.js' %}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/datatables/dataTables.plugins.js' %}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/jquery.pos.js' %}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}?v=1651853225"
></script>
{% endblock %}
{% block content %}
...
...
@@ -188,6 +190,31 @@
est bien
<b><span
id=
"price_to_verify"
></span></b>
euros/Kg ?
</p>
<input
type=
"number"
name=
"Prix au Kilo"
id=
"new_price_to_weight"
>
</div>
<div
id=
"modal_add_products"
>
<h3>
Ajouter des produits à la commande
</h3>
<div
class=
"search_products_to_add_area"
>
<input
type=
"text"
class=
"search_product_input"
name=
"search_product_input"
placeholder=
"Rechercher un produit..."
>
</div>
<div
class=
"products_lines"
>
<p
class=
"products_lines_title"
>
Liste des produits qui seront ajoutés à la commande.
<b>
Vous devez renseigner une quantité pour chaque produit.
</b>
</p>
</div>
<hr
/>
</div>
<div
id=
"add_product_line_template"
>
<div
class=
"add_product_line"
>
<div
class=
"product_name add_product_line_item"
></div>
<div
class=
"product_qty add_product_line_item"
>
<input
type=
"number"
autocomplete=
"off"
class=
"product_qty_input input_small"
placeholder=
"Quantité"
>
<i
class=
"product_qty_input_alert"
>
Vous devez renseigner une quantité
</i>
</div>
<div
class=
"remove_line"
>
<i
class=
"fas fa-times fa-lg remove_line_icon"
></i>
</div>
</div>
</div>
</div>
<br/>
</div>
...
...
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