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
01f05447
Commit
01f05447
authored
Dec 17, 2021
by
François C.
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'tickets_1929_1934' into dev_cooperatic
parents
db2d1ac2
799fe052
Pipeline
#1669
passed with stage
in 1 minute 31 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
153 additions
and
78 deletions
+153
-78
oders_helper_style.css
orders/static/css/oders_helper_style.css
+9
-0
orders_helper.js
orders/static/js/orders_helper.js
+57
-60
models.py
products/models.py
+36
-2
urls.py
products/urls.py
+1
-0
views.py
products/views.py
+37
-10
helper.html
templates/orders/helper.html
+13
-6
No files found.
orders/static/css/oders_helper_style.css
View file @
01f05447
...
@@ -367,6 +367,15 @@
...
@@ -367,6 +367,15 @@
width
:
90%
;
width
:
90%
;
}
}
/* product actions modal*/
.npa-options
{
width
:
fit-content
;
text-align
:
left
;
margin
:
auto
;
}
.npa-options
label
{
display
:
block
;
}
/* - Orders created screen */
/* - Orders created screen */
.order_created_header
{
.order_created_header
{
...
...
orders/static/js/orders_helper.js
View file @
01f05447
...
@@ -688,35 +688,32 @@ function _compute_total_values_by_supplier() {
...
@@ -688,35 +688,32 @@ function _compute_total_values_by_supplier() {
/* - PRODUCT */
/* - PRODUCT */
/**
function
save_products_npa_minimal_stock
(
product
,
inputs
)
{
* Update 'purchase_ok' of a product
let
actions
=
{
npa
:
[],
minimal_stock
:
0
,
id
:
product
.
id
,
name
:
product
.
name
};
*
inputs
.
each
(
function
(
i
,
e
)
{
* @param {int} p_id product id
const
input
=
$
(
e
)
* @param {Boolean} npa value to set purchase_ok to
if
(
input
.
attr
(
'type'
)
==
'checkbox'
)
{
*/
if
(
input
.
prop
(
'checked'
)
==
true
)
{
function
set_product_npa
(
p_id
,
npa
)
{
actions
.
npa
.
push
(
input
.
val
())
openModal
();
}
}
else
if
(
input
.
attr
(
'name'
)
==
"minimal_stock"
)
{
const
data
=
{
actions
.
minimal_stock
=
input
.
val
()
product_tmpl_id
:
p_id
,
}
purchase_ok
:
!
npa
});
};
// Fetch supplier products
$
.
ajax
({
$
.
ajax
({
type
:
"POST"
,
type
:
"POST"
,
url
:
"/products/update_
product_purchase_o
k"
,
url
:
"/products/update_
npa_and_minimal_stoc
k"
,
dataType
:
"json"
,
dataType
:
"json"
,
traditional
:
true
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
contentType
:
"application/json; charset=utf-8"
,
data
:
JSON
.
stringify
(
data
),
data
:
JSON
.
stringify
(
actions
),
success
:
()
=>
{
success
:
()
=>
{
const
index
=
products
.
findIndex
(
p
=>
p
.
id
==
p
_
id
);
const
index
=
products
.
findIndex
(
p
=>
p
.
id
==
p
roduct
.
id
);
// Give time for modal to fade
// Give time for modal to fade
setTimeout
(
function
()
{
setTimeout
(
function
()
{
$
(
".actions_buttons_area .right_action_buttons"
).
notify
(
$
(
".actions_buttons_area .right_action_buttons"
).
notify
(
"
Produit passé en NPA
!"
,
"
Actions enregistrées
!"
,
{
{
elementPosition
:
"bottom right"
,
elementPosition
:
"bottom right"
,
className
:
"success"
,
className
:
"success"
,
...
@@ -724,19 +721,21 @@ function set_product_npa(p_id, npa) {
...
@@ -724,19 +721,21 @@ function set_product_npa(p_id, npa) {
}
}
);
);
},
500
);
},
500
);
products
[
index
].
minimal_stock
=
actions
.
minimal_stock
;
// Remove NPA products
if
(
actions
.
npa
.
length
>
0
)
{
products
.
splice
(
index
,
1
);
// Remove NPA products
update_main_screen
();
products
.
splice
(
index
,
1
);
update_cdb_order
();
update_main_screen
();
update_cdb_order
();
}
closeModal
();
closeModal
();
},
},
error
:
function
(
data
)
{
error
:
function
(
data
)
{
let
msg
=
"erreur serveur lors de la sauvegarde
du NPA
"
.
let
msg
=
"erreur serveur lors de la sauvegarde"
.
msg
+=
` (product_tmpl_id:
${
p
_
id
}
)`
;
msg
+=
` (product_tmpl_id:
${
p
roduct
.
id
}
)`
;
err
=
{
msg
:
msg
,
ctx
:
's
et_product_npa
'
};
err
=
{
msg
:
msg
,
ctx
:
's
ave_products_npa_minimal_stock
'
};
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
}
}
...
@@ -747,8 +746,10 @@ function set_product_npa(p_id, npa) {
...
@@ -747,8 +746,10 @@ function set_product_npa(p_id, npa) {
update_main_screen
();
update_main_screen
();
}
}
});
});
}
}
/* - INVENTORY */
/* - INVENTORY */
/**
/**
...
@@ -1327,8 +1328,8 @@ function prepare_datatable_columns() {
...
@@ -1327,8 +1328,8 @@ function prepare_datatable_columns() {
{
{
data
:
"id"
,
data
:
"id"
,
title
:
`<div id="table_header_select_all" class="txtcenter">
title
:
`<div id="table_header_select_all" class="txtcenter">
<
span class="select_all_text">Sélectionner</span
>
<
!--<span class="select_all_text">Sélectionner</span>--
>
<label for="select_all_products_cb">
-
Tout</label>
<label for="select_all_products_cb">Tout</label>
<input type="checkbox" class="select_product_cb" id="select_all_products_cb" name="select_all_products_cb" value="all">
<input type="checkbox" class="select_product_cb" id="select_all_products_cb" name="select_all_products_cb" value="all">
</div>`
,
</div>`
,
className
:
"dt-body-center"
,
className
:
"dt-body-center"
,
...
@@ -1453,12 +1454,11 @@ function prepare_datatable_columns() {
...
@@ -1453,12 +1454,11 @@ function prepare_datatable_columns() {
});
});
columns
.
push
({
columns
.
push
({
data
:
"purchase_ok"
,
title
:
``
,
title
:
`NPA`
,
className
:
"dt-body-center"
,
className
:
"dt-body-center"
,
orderable
:
false
,
orderable
:
false
,
render
:
function
(
data
)
{
render
:
function
(
data
)
{
return
`<
input type="checkbox" class="product_npa_cb" value="purchase_ok"
${
data
?
''
:
'checked'
}
>`
;
return
`<
button type="button" class="btn--primary product_actions">Actions</button
>`
;
},
},
width
:
"4%"
width
:
"4%"
});
});
...
@@ -1625,7 +1625,6 @@ function display_products(params) {
...
@@ -1625,7 +1625,6 @@ function display_products(params) {
// On arrow up pressed, focus next row input
// On arrow up pressed, focus next row input
let
next_input
=
$
(
this
).
closest
(
"tr"
).
prev
().
find
(
".product_qty_input"
);
let
next_input
=
$
(
this
).
closest
(
"tr"
).
prev
().
find
(
".product_qty_input"
);
next_input
;
next_input
.
focus
();
next_input
.
focus
();
// Scroll to a position where the target input is not hidden by the sticky suppliers container
// Scroll to a position where the target input is not hidden by the sticky suppliers container
...
@@ -1652,6 +1651,31 @@ function display_products(params) {
...
@@ -1652,6 +1651,31 @@ function display_products(params) {
// On enter pressed, focus previous row input
// On enter pressed, focus previous row input
$
(
this
).
closest
(
"tr"
).
next
().
find
(
".product_qty_input"
).
focus
();
$
(
this
).
closest
(
"tr"
).
next
().
find
(
".product_qty_input"
).
focus
();
}
}
})
.
on
(
'click'
,
'tbody td .product_actions'
,
function
(
e
){
// Save / unsave selected row
const
p_id
=
products_table
.
row
(
$
(
this
).
closest
(
'tr'
)).
data
().
id
;
const
product
=
products
.
find
(
p
=>
p
.
id
==
p_id
);
let
modal_product_actions
=
$
(
'#templates #modal_product_actions'
);
modal_product_actions
.
find
(
".product_name"
).
text
(
product
.
name
);
//modal_product_actions.find(".product_npa").text(null ? 'Ne Pas Acheter' : 'Peut Être Acheté');
openModal
(
modal_product_actions
.
html
(),
()
=>
{
if
(
is_time_to
(
'validate_product_actions'
))
{
save_products_npa_minimal_stock
(
product
,
modal
.
find
(
'input'
));
}
},
'Valider'
,
false
);
modal
.
find
(
'input[name="minimal_stock"]'
).
val
(
product
.
minimal_stock
)
});
});
// Associate product to supplier on click on 'X' in the table
// Associate product to supplier on click on 'X' in the table
...
@@ -1783,34 +1807,7 @@ function display_products(params) {
...
@@ -1783,34 +1807,7 @@ function display_products(params) {
}
}
});
});
// Set product is NPA (Ne Pas Acheter)
$
(
'#products_table'
).
on
(
'click'
,
'tbody td .product_npa_cb'
,
function
()
{
// Save / unsave selected row
const
p_id
=
products_table
.
row
(
$
(
this
).
closest
(
'tr'
)).
data
().
id
;
const
npa
=
this
.
checked
;
const
product
=
products
.
find
(
p
=>
p
.
id
==
p_id
);
let
modal_product_npa
=
$
(
'#templates #modal_product_npa'
);
modal_product_npa
.
find
(
".product_name"
).
text
(
product
.
name
);
modal_product_npa
.
find
(
".product_npa"
).
text
(
npa
?
'Ne Pas Acheter'
:
'Peut Être Acheté'
);
openModal
(
modal_product_npa
.
html
(),
()
=>
{
if
(
is_time_to
(
'validate_set_product_npa'
))
{
set_product_npa
(
p_id
,
npa
);
}
},
'Valider'
,
false
,
true
,
()
=>
{
this
.
checked
=
!
this
.
checked
;
}
);
});
return
0
;
return
0
;
}
}
...
...
products/models.py
View file @
01f05447
...
@@ -7,6 +7,7 @@ import csv
...
@@ -7,6 +7,7 @@ import csv
import
tempfile
import
tempfile
import
pymysql.cursors
import
pymysql.cursors
import
datetime
import
datetime
import
re
vcats
=
[]
vcats
=
[]
...
@@ -252,7 +253,39 @@ class CagetteProduct(models.Model):
...
@@ -252,7 +253,39 @@ class CagetteProduct(models.Model):
return
res
return
res
@staticmethod
def
update_npa_and_minimal_stock
(
data
):
"""Update NPA (ne pas acheter) and minimal stock data"""
res
=
{}
try
:
api
=
OdooAPI
()
f
=
{
'minimal_stock'
:
data
[
'minimal_stock'
]}
if
'simple-npa'
in
data
[
'npa'
]:
f
[
'purchase_ok'
]
=
0
if
'npa-in-name'
in
data
[
'npa'
]:
# Add [NPA] in product name if needed
f
[
'name'
]
=
data
[
'name'
]
if
(
'[NPA]'
in
data
[
'name'
])
else
data
[
'name'
]
+
" [NPA]"
f
[
'purchase_ok'
]
=
0
elif
'[NPA]'
in
data
[
'name'
]:
# Remove [NPA] from name
f
[
'name'
]
=
re
.
sub
(
r'( \[NPA\])'
,
''
,
data
[
'name'
])
current_name
=
data
[
'name'
]
if
(
'name'
not
in
f
)
else
f
[
'name'
]
if
'fds-in-name'
in
data
[
'npa'
]:
f
[
'name'
]
=
current_name
if
'[FDS]'
in
data
[
'name'
]
else
current_name
+
" [FDS]"
f
[
'purchase_ok'
]
=
0
elif
'[FDS]'
in
current_name
:
f
[
'name'
]
=
re
.
sub
(
r'( \[FDS\])'
,
''
,
current_name
)
if
len
(
data
[
'npa'
])
==
0
:
f
[
'purchase_ok'
]
=
1
res
[
"update"
]
=
api
.
update
(
'product.template'
,
data
[
'id'
],
f
)
except
Exception
as
e
:
res
[
"error"
]
=
str
(
e
)
coop_logger
.
error
(
"update_npa_and_minimal_stock :
%
s
%
s"
,
str
(
e
),
str
(
data
))
return
res
class
CagetteProducts
(
models
.
Model
):
class
CagetteProducts
(
models
.
Model
):
"""Initially used to make massive barcode update."""
"""Initially used to make massive barcode update."""
...
@@ -578,7 +611,8 @@ class CagetteProducts(models.Model):
...
@@ -578,7 +611,8 @@ class CagetteProducts(models.Model):
"uom_id"
,
"uom_id"
,
"purchase_ok"
,
"purchase_ok"
,
"supplier_taxes_id"
,
"supplier_taxes_id"
,
"product_variant_ids"
"product_variant_ids"
,
"minimal_stock"
]
]
c
=
[[
'id'
,
'in'
,
ptids
],
[
'purchase_ok'
,
'='
,
True
]]
c
=
[[
'id'
,
'in'
,
ptids
],
[
'purchase_ok'
,
'='
,
True
]]
products_t
=
api
.
search_read
(
'product.template'
,
c
,
f
)
products_t
=
api
.
search_read
(
'product.template'
,
c
,
f
)
...
...
products/urls.py
View file @
01f05447
...
@@ -11,6 +11,7 @@ urlpatterns = [
...
@@ -11,6 +11,7 @@ urlpatterns = [
url
(
r'^update_product_stock$'
,
views
.
update_product_stock
),
url
(
r'^update_product_stock$'
,
views
.
update_product_stock
),
url
(
r'^update_product_purchase_ok$'
,
views
.
update_product_purchase_ok
),
url
(
r'^update_product_purchase_ok$'
,
views
.
update_product_purchase_ok
),
url
(
r'^update_product_internal_ref$'
,
views
.
update_product_internal_ref
),
url
(
r'^update_product_internal_ref$'
,
views
.
update_product_internal_ref
),
url
(
r'^update_npa_and_minimal_stock$'
,
views
.
update_npa_and_minimal_stock
),
url
(
r'^labels_appli_csv(\/?[a-z]*)$'
,
views
.
labels_appli_csv
,
name
=
'labels_appli_csv'
),
url
(
r'^labels_appli_csv(\/?[a-z]*)$'
,
views
.
labels_appli_csv
,
name
=
'labels_appli_csv'
),
url
(
r'^label_print/([0-9]+)/?([0-9\.]*)/?([a-z]*)/?([0-9]*)$'
,
views
.
label_print
),
url
(
r'^label_print/([0-9]+)/?([0-9\.]*)/?([a-z]*)/?([0-9]*)$'
,
views
.
label_print
),
url
(
r'^shelf_labels$'
,
views
.
shelf_labels
),
# massive print
url
(
r'^shelf_labels$'
,
views
.
shelf_labels
),
# massive print
...
...
products/views.py
View file @
01f05447
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
from
outils.common_imports
import
*
from
outils.common_imports
import
*
from
outils.for_view_imports
import
*
from
outils.for_view_imports
import
*
from
members.models
import
CagetteUser
from
products.models
import
CagetteProduct
from
products.models
import
CagetteProduct
from
products.models
import
CagetteProducts
from
products.models
import
CagetteProducts
from
inventory.models
import
CagetteInventory
from
inventory.models
import
CagetteInventory
...
@@ -105,25 +106,51 @@ def update_product_stock(request):
...
@@ -105,25 +106,51 @@ def update_product_stock(request):
def
update_product_purchase_ok
(
request
):
def
update_product_purchase_ok
(
request
):
res
=
{}
res
=
{}
data
=
json
.
loads
(
request
.
body
.
decode
())
is_connected_user
=
CagetteUser
.
are_credentials_ok
(
request
)
if
is_connected_user
is
True
:
data
=
json
.
loads
(
request
.
body
.
decode
())
res
=
CagetteProduct
.
update_product_purchase_ok
(
data
[
"product_tmpl_id"
],
data
[
"purchase_ok"
])
res
=
CagetteProduct
.
update_product_purchase_ok
(
data
[
"product_tmpl_id"
],
data
[
"purchase_ok"
])
if
(
'error'
in
res
):
if
(
'error'
in
res
):
return
JsonResponse
(
res
,
status
=
500
)
return
JsonResponse
(
res
,
status
=
500
)
else
:
return
JsonResponse
({
"res"
:
res
})
else
:
else
:
return
JsonResponse
(
{
"res"
:
res
}
)
return
JsonResponse
(
res
,
status
=
403
)
def
update_product_internal_ref
(
request
):
def
update_product_internal_ref
(
request
):
res
=
{}
res
=
{}
data
=
json
.
loads
(
request
.
body
.
decode
())
is_connected_user
=
CagetteUser
.
are_credentials_ok
(
request
)
if
is_connected_user
is
True
:
data
=
json
.
loads
(
request
.
body
.
decode
())
res
=
CagetteProduct
.
update_product_internal_ref
(
data
[
"product_tmpl_id"
],
data
[
"default_code"
])
res
=
CagetteProduct
.
update_product_internal_ref
(
data
[
"product_tmpl_id"
],
data
[
"default_code"
])
if
(
'error'
in
res
):
if
(
'error'
in
res
):
return
JsonResponse
(
res
,
status
=
500
)
return
JsonResponse
(
res
,
status
=
500
)
else
:
return
JsonResponse
({
"res"
:
res
})
else
:
else
:
return
JsonResponse
({
"res"
:
res
})
return
JsonResponse
(
res
,
status
=
403
)
def
update_npa_and_minimal_stock
(
request
):
res
=
{}
is_connected_user
=
CagetteUser
.
are_credentials_ok
(
request
)
if
is_connected_user
is
True
:
try
:
data
=
json
.
loads
(
request
.
body
.
decode
())
res
=
CagetteProduct
.
update_npa_and_minimal_stock
(
data
)
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
coop_logger
.
error
(
"Update npa and minimal stock :
%
s"
,
res
[
'error'
])
if
(
'error'
in
res
):
return
JsonResponse
(
res
,
status
=
500
)
else
:
return
JsonResponse
({
"res"
:
res
})
else
:
return
JsonResponse
(
res
,
status
=
403
)
def
labels_appli_csv
(
request
,
params
):
def
labels_appli_csv
(
request
,
params
):
"""Generate files to put in DAV directory to be retrieved by scales app."""
"""Generate files to put in DAV directory to be retrieved by scales app."""
...
...
templates/orders/helper.html
View file @
01f05447
...
@@ -275,14 +275,21 @@
...
@@ -275,14 +275,21 @@
<hr/>
<hr/>
</div>
</div>
<div
id=
"modal_product_
npa
"
>
<div
id=
"modal_product_
actions
"
>
<h3>
Attention !
</h3>
Actions sur
<h3><span
class=
"product_name"
></span>
</h3>
<p>
<p>
Vous vous apprêtez à passer le produit
<span
class=
"product_name"
></span>
en
<span
class=
"product_npa"
></span>
.
<br/>
<h4>
NPA
</h4>
Dès que vous aurez cliqué sur "Valider", le produit sera retiré du tableau et l'information sera enregistrée dans Odoo.
<div
class=
"npa-options"
>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"simple-npa"
/>
Mettre le produit en NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"npa-in-name"
/>
Mettre le produit en NPA et afficher NPA
</label>
<label><input
type=
"checkbox"
name=
"npa-actions"
value=
"fds-in-name"
/>
Mettre le produit en NPA et afficher FDS
</label>
</div>
</p>
</p>
<p>
Êtez-vous sûr ?
</p>
<p>
<hr/>
<h4>
Stock minimum
</h4>
<input
type=
"number"
name=
"minimal_stock"
value=
""
/>
</p>
</div>
</div>
<div
id=
"modal_create_order"
>
<div
id=
"modal_create_order"
>
...
...
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