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
7b60a5d4
Commit
7b60a5d4
authored
May 28, 2021
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
select products & generate inventory
parent
a82672f8
Pipeline
#987
failed with stage
in 18 seconds
Changes
7
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
260 additions
and
45 deletions
+260
-45
models.py
inventory/models.py
+24
-6
custom_lists.js
inventory/static/js/custom_lists.js
+16
-2
views.py
inventory/views.py
+16
-2
oders_helper_style.css
orders/static/css/oders_helper_style.css
+25
-3
orders_helper.js
orders/static/js/orders_helper.js
+165
-31
custom_lists.html
templates/inventory/custom_lists.html
+1
-1
helper.html
templates/orders/helper.html
+13
-0
No files found.
inventory/models.py
View file @
7b60a5d4
...
...
@@ -52,7 +52,7 @@ class CagetteInventory(models.Model):
file_data
=
json
.
load
(
json_file
)
date_time
=
datetime
.
fromtimestamp
(
int
(
filename
))
d
=
date_time
.
strftime
(
"
%
m/
%
d
/
%
Y,
%
H:
%
M"
)
d
=
date_time
.
strftime
(
"
%
d/
%
m
/
%
Y,
%
H:
%
M"
)
file_data
[
'id'
]
=
int
(
filename
)
file_data
[
'datetime_created'
]
=
d
...
...
@@ -113,7 +113,7 @@ class CagetteInventory(models.Model):
return
file_data
[
'inventory_status'
]
@staticmethod
def
create_custom_inv_file
(
line_ids
,
line_type
):
def
create_custom_inv_file
(
line_ids
,
line_type
,
default_partners_id
=
[]
):
res
=
{}
try
:
...
...
@@ -127,7 +127,22 @@ class CagetteInventory(models.Model):
api
=
OdooAPI
()
ids
=
[]
order
=
[
''
,
''
]
user
=
partner
=
''
user
=
''
partners
=
[]
if
len
(
default_partners_id
)
>
0
:
f
=
[
'name'
]
c
=
[[
'id'
,
'in'
,
default_partners_id
]]
partners_name
=
api
.
search_read
(
'res.partner'
,
c
,
f
)
for
p
in
partners_name
:
partners
.
append
(
p
[
'name'
])
if
line_type
==
'product_templates'
:
fields
=
[
'id'
]
cond
=
[[
'product_tmpl_id'
,
'in'
,
line_ids
]]
model
=
'product.product'
user
=
"api"
else
:
fields
=
[
'create_uid'
,
'product_id'
,
'partner_id'
]
cond
=
[[
'id'
,
'in'
,
line_ids
]]
if
(
line_type
==
'cpo'
):
...
...
@@ -139,24 +154,27 @@ class CagetteInventory(models.Model):
lines
=
api
.
search_read
(
model
,
cond
,
fields
)
if
len
(
lines
)
==
len
(
line_ids
):
for
l
in
lines
:
if
line_type
==
'product_templates'
:
ids
.
append
(
l
[
'id'
])
else
:
ids
.
append
(
l
[
'product_id'
][
0
])
user
=
l
[
'create_uid'
][
1
]
if
(
line_type
==
'cpo'
):
order
=
l
[
'computed_purchase_order_id'
]
else
:
order
=
l
[
'order_id'
]
partner
=
l
[
'partner_id'
][
1
]
partners
.
append
(
l
[
'partner_id'
][
1
])
if
(
line_type
==
'cpo'
):
# partner_id isn't defined
f
=
[
'partner_id'
]
c
=
[[
'id'
,
'='
,
int
(
order
[
0
])]]
cpo
=
api
.
search_read
(
'computed.purchase.order'
,
c
,
f
)
if
len
(
cpo
)
>
0
:
partner
=
cpo
[
0
][
'partner_id'
][
1
]
partner
s
.
append
(
cpo
[
0
][
'partner_id'
][
1
])
file_data
=
{
'order'
:
order
[
1
],
'user'
:
user
,
'partner
'
:
partner
,
'partner
s'
:
partners
,
'inventory_status'
:
''
,
'products'
:
ids
}
...
...
inventory/static/js/custom_lists.js
View file @
7b60a5d4
...
...
@@ -4,6 +4,13 @@ var shelfs_table = null,
function
init_datatable
()
{
// For a smooth migration...
for
(
const
i
in
lists
)
{
if
((
'partners'
in
lists
[
i
])
===
false
)
{
lists
[
i
][
'partners'
]
=
[
lists
[
i
][
'partner'
]]
}
}
return
$
(
'#lists'
).
DataTable
({
data
:
lists
,
// data passed at page loading
rowId
:
'id'
,
...
...
@@ -17,8 +24,15 @@ function init_datatable() {
}
},
{
data
:
"partner"
,
title
:
"Fournisseur"
data
:
"partners"
,
title
:
"Fournisseur(s)"
,
render
:
function
(
data
)
{
res
=
""
;
for
(
const
i
in
data
)
{
res
+=
`
${
data
[
i
]}
<br/>`
;
}
return
res
;
}
},
{
data
:
"order"
,
...
...
inventory/views.py
View file @
7b60a5d4
...
...
@@ -43,7 +43,6 @@ def custom_list_inventory(request, id):
products
=
CagetteInventory
.
get_custom_list_products
(
id
)
if
'error'
in
products
:
print
(
products
)
products
[
'data'
]
=
[]
context
=
{
'title'
:
'Inventaire'
,
...
...
@@ -112,10 +111,25 @@ def do_custom_list_inventory(request):
def
generate_inventory_list
(
request
):
"""Responding to Odoo ajax call (no csrf)."""
res
=
{}
default_partners_id
=
[]
try
:
lines
=
json
.
loads
(
request
.
POST
.
get
(
'lines'
))
ltype
=
request
.
POST
.
get
(
'type'
)
res
=
CagetteInventory
.
create_custom_inv_file
(
lines
,
ltype
)
except
Exception
as
e
:
try
:
# POST.get() returns None when request from django
data
=
json
.
loads
(
request
.
body
.
decode
())
lines
=
data
[
"lines"
]
ltype
=
data
[
"type"
]
if
"partners_id"
in
data
:
default_partners_id
=
data
[
"partners_id"
]
except
Exception
as
ee
:
res
[
'error'
]
=
str
(
ee
)
coop_looger
.
error
(
"generate_inventory_list :
%
s"
,
str
(
e
))
return
JsonResponse
(
res
,
status
=
500
)
try
:
res
=
CagetteInventory
.
create_custom_inv_file
(
lines
,
ltype
,
default_partners_id
)
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
coop_looger
.
error
(
"generate_inventory_list :
%
s"
,
str
(
e
))
...
...
orders/static/css/oders_helper_style.css
View file @
7b60a5d4
.page_body
{
position
:
relative
;
}
#form_container
{
margin-top
:
30px
;
}
...
...
@@ -7,7 +11,7 @@
}
#products_table_filter
input
{
height
:
5
0px
;
height
:
4
0px
;
}
#supplier_input
{
...
...
@@ -29,6 +33,21 @@
font-weight
:
bold
;
}
#table_header_select_all
{
display
:
flex
;
align-content
:
center
;
justify-content
:
center
;
flex-wrap
:
wrap
;
}
#table_header_select_all
input
{
margin-left
:
5px
;
}
.select_product_cb
{
cursor
:
pointer
;
}
#suppliers_container
{
display
:
flex
;
justify-content
:
center
;
...
...
@@ -56,5 +75,8 @@
cursor
:
pointer
;
}
#actions_buttons_area
{
position
:
absolute
;
top
:
0
;
right
:
0
;
}
orders/static/js/orders_helper.js
View file @
7b60a5d4
var
suppliers_list
=
[],
products_table
=
null
,
products
=
[]
selected_suppliers
=
[],
products
=
[];
/* CALLS TO SERVER */
selected_rows
=
[];
/**
* Add a supplier to the selected suppliers list.
...
...
@@ -69,13 +67,34 @@ function add_supplier() {
}
/**
* Remove a supplier from the selected list & its associated products
*
* @param {int} supplier_id
*/
function
remove_supplier
(
supplier_id
)
{
// Remove from suppliers list
selected_suppliers
=
selected_suppliers
.
filter
(
supplier
=>
supplier
.
id
!=
supplier_id
);
// Remove the supplier from the products suppliers list
for
(
const
i
in
products
)
{
products
[
i
].
suppliers
=
products
[
i
].
suppliers
.
filter
(
supplier
=>
supplier
.
id
!=
supplier_id
);
}
// Remove products only associated to this product
products
=
products
.
filter
(
product
=>
product
.
suppliers
.
length
>
0
);
update_display
();
}
/**
* Send to server the association product-supplier
*
* @param {object} product
* @param {object} supplier
* @param {node} cell product's row in datatable
*/
function
save_supplier_product_association
(
product
,
supplier
,
cell
)
{
function
save_supplier_product_association
(
product
,
supplier
,
cell
)
{
openModal
();
const
data
=
{
...
...
@@ -119,26 +138,6 @@ function save_supplier_product_association(product, supplier, cell) {
}
/**
* Remove a supplier from the selected list & its associated products
*
* @param {int} supplier_id
*/
function
remove_supplier
(
supplier_id
)
{
// Remove from suppliers list
selected_suppliers
=
selected_suppliers
.
filter
(
supplier
=>
supplier
.
id
!=
supplier_id
);
// Remove the supplier from the products suppliers list
for
(
const
i
in
products
)
{
products
[
i
].
suppliers
=
products
[
i
].
suppliers
.
filter
(
supplier
=>
supplier
.
id
!=
supplier_id
);
}
// Remove products only associated to this product
products
=
products
.
filter
(
product
=>
product
.
suppliers
.
length
>
0
);
update_display
();
}
/**
* When products are fetched, save them and the relation with the supplier.
* If product already saved, add the supplier to its suppliers list.
* Else, add product with supplier.
...
...
@@ -221,7 +220,6 @@ function display_suppliers() {
const
supplier_id
=
el_id
[
el_id
.
length
-
1
];
let
modal_remove_supplier
=
$
(
'#templates #modal_remove_supplier'
);
modal_remove_supplier
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
openModal
(
...
...
@@ -285,7 +283,16 @@ function prepare_datatable_columns() {
{
data
:
"id"
,
title
:
"id"
,
visible
:
false
,
title
:
` <div id="table_header_select_all">
Tout
<input type="checkbox" class="select_product_cb" id="select_all_products_cb" value="all">
</div>`
,
className
:
"dt-body-center"
,
orderable
:
false
,
render
:
function
(
data
)
{
return
`<input type="checkbox" class="select_product_cb" id="select_product_
${
data
}
" value="
${
data
}
">`
;
},
width
:
"4%"
,
},
{
data
:
"default_code"
,
...
...
@@ -315,7 +322,7 @@ function prepare_datatable_columns() {
columns
.
push
({
data
:
supplier_column_name
(
supplier
),
title
:
supplier
.
display_name
,
width
:
"
8
%"
,
width
:
"
10
%"
,
className
:
`dt-body-center supplier_input_cell`
,
render
:
(
data
,
type
,
full
)
=>
{
const
base_id
=
`product_
${
full
.
id
}
_supplier_
${
supplier
.
id
}
`
;
...
...
@@ -411,8 +418,6 @@ function display_products() {
// Associate product to supplier on click on 'X' in the table
$
(
'#products_table'
).
on
(
'click'
,
'tbody .product_not_from_supplier'
,
function
()
{
// todo istimeto
// Get supplier & product id
const
el_id
=
$
(
this
).
children
().
first
().
attr
(
'id'
)
.
split
(
'_'
);
...
...
@@ -423,7 +428,6 @@ function display_products() {
const
supplier
=
selected_suppliers
.
find
(
s
=>
s
.
id
==
supplier_id
)
let
modal_attach_product_to_supplier
=
$
(
'#templates #modal_attach_product_to_supplier'
);
modal_attach_product_to_supplier
.
find
(
".product_name"
).
text
(
product
.
name
);
modal_attach_product_to_supplier
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
...
...
@@ -439,15 +443,141 @@ function display_products() {
);
});
// Select row(s) on checkbox change
$
(
'#products_table'
).
on
(
'click'
,
'thead th #select_all_products_cb'
,
function
()
{
if
(
this
.
checked
)
{
selected_rows
=
[]
products_table
.
rows
().
every
(
function
()
{
const
node
=
$
(
this
.
node
());
node
.
addClass
(
'selected'
);
node
.
find
(
".select_product_cb"
).
first
().
prop
(
"checked"
,
true
);
// Save selected rows in case the table is updated
selected_rows
.
push
(
this
.
data
().
id
)
});
}
else
{
unselect_all_rows
()
}
});
$
(
'#products_table'
).
on
(
'click'
,
'tbody td .select_product_cb'
,
function
()
{
$
(
this
).
closest
(
'tr'
).
toggleClass
(
'selected'
);
// Save / unsave selected row
p_id
=
products_table
.
row
(
$
(
this
).
closest
(
'tr'
)).
data
().
id
;
if
(
this
.
checked
)
{
selected_rows
.
push
(
p_id
)
}
else
{
const
i
=
selected_rows
.
findIndex
(
id
=>
id
==
p_id
)
selected_rows
.
splice
(
i
,
1
)
}
});
return
0
;
}
/**
* Unselect all rows from datatable.
*/
function
unselect_all_rows
()
{
products_table
.
rows
().
every
(
function
()
{
const
node
=
$
(
this
.
node
());
node
.
removeClass
(
'selected'
);
node
.
find
(
".select_product_cb"
).
first
().
prop
(
"checked"
,
false
);
});
selected_rows
=
[]
}
/**
* Update DOM display
*/
function
update_display
()
{
// Remove listener before recreating them
$
(
'#products_table'
).
off
(
'click'
,
'tbody .product_not_from_supplier'
);
$
(
'#products_table'
).
off
(
'click'
,
'thead th #select_all_products_cb'
);
$
(
'#products_table'
).
off
(
'click'
,
'tbody td .select_product_cb'
);
display_suppliers
();
display_products
();
// Re-select previously selected rows
if
(
selected_rows
.
length
>
0
)
{
products_table
.
rows
().
every
(
function
()
{
if
(
selected_rows
.
includes
(
this
.
data
().
id
))
{
const
node
=
$
(
this
.
node
());
node
.
addClass
(
'selected'
);
node
.
find
(
".select_product_cb"
).
first
().
prop
(
"checked"
,
true
);
}
});
}
}
function
generate_inventory
()
{
if
(
products_table
!==
null
)
{
const
selected_data
=
products_table
.
rows
(
'.selected'
).
data
();
if
(
selected_data
.
length
==
0
)
{
alert
(
"Veuillez sélectionner les produits à inventorier en cochant les cases sur la gauche du tableau."
)
}
else
{
data
=
{
lines
:
[],
partners_id
:
[],
type
:
'product_templates'
}
for
(
var
i
=
0
;
i
<
selected_data
.
length
;
i
++
)
{
const
product
=
products
.
find
(
p
=>
p
.
id
==
selected_data
[
i
].
id
)
data
.
lines
.
push
(
product
.
id
);
for
(
const
supplier
of
product
.
suppliers
)
{
if
(
data
.
partners_id
.
indexOf
(
supplier
.
id
)
===
-
1
)
{
data
.
partners_id
.
push
(
supplier
.
id
)
}
}
}
let
modal_create_inventory
=
$
(
'#templates #modal_create_inventory'
);
modal_create_inventory
.
find
(
".inventory_products_count"
).
text
(
data
.
lines
.
length
);
openModal
(
modal_create_inventory
.
html
(),
()
=>
{
$
.
ajax
({
type
:
"POST"
,
url
:
"/inventory/generate_inventory_list"
,
dataType
:
"json"
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
data
:
JSON
.
stringify
(
data
),
success
:
()
=>
{
unselect_all_rows
();
// Give time for modal to fade
setTimeout
(
function
(){
$
.
notify
(
"Inventaire créé !"
,
{
globalPosition
:
"top left"
,
className
:
"success"
}
);
},
500
);
},
error
:
function
(
data
)
{
let
msg
=
"erreur serveur lors de la création de l'inventaire"
.
err
=
{
msg
:
msg
,
ctx
:
'generate_inventory'
};
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
}
report_JS_error
(
err
,
'orders'
);
alert
(
"Erreur lors de la création de l'inventaire. Réessayez plus tard."
);
}
});
},
'Valider'
,
);
}
}
}
$
(
document
).
ready
(
function
()
{
...
...
@@ -488,4 +618,8 @@ $(document).ready(function() {
e
.
preventDefault
();
add_supplier
();
});
$
(
"#do_inventory"
).
on
(
"click"
,
function
(
e
)
{
generate_inventory
();
});
});
templates/inventory/custom_lists.html
View file @
7b60a5d4
...
...
@@ -34,7 +34,7 @@
</div>
<script
type=
"text/javascript"
>
lists
=
{{
lists
|
safe
}}
var
lists
=
{{
lists
|
safe
}}
</script>
<script
src=
"{% static "
js
/
all_common
.
js
"
%}?
v=
"></script>
<script src="
{%
static
"
js
/
common
.
js
"
%}?
v=
"></script>
...
...
templates/orders/helper.html
View file @
7b60a5d4
...
...
@@ -10,10 +10,15 @@
{% block additionnal_scripts %}
<script
type=
"text/javascript"
src=
"{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}?v="
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/datatables/jquery.dataTables.min.js' %}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/notify.min.js' %}?v="
></script>
{% endblock %}
{% block content %}
<div
class=
"page_body"
>
<div
id=
"actions_buttons_area"
>
<button
type=
"button"
class=
'btn--primary'
id=
"do_inventory"
>
Faire un inventaire
</button>
</div>
<div
class=
"header txtcenter"
>
<h1>
Aide à la commande
</h1>
</div>
...
...
@@ -64,6 +69,14 @@
<p>
Êtez-vous sûr ?
</p>
<hr/>
</div>
<div
id=
"modal_create_inventory"
>
<p>
Vous vous apprêtez à créer un inventaire de
<span
class=
"inventory_products_count"
></span>
produits.
</p>
<p>
Êtez-vous sûr ?
</p>
<hr/>
</div>
</div>
<script
src=
"{% static "
js
/
all_common
.
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