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
a82672f8
Commit
a82672f8
authored
May 28, 2021
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make a product available for a supplier
parent
d8d04777
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
156 additions
and
17 deletions
+156
-17
models.py
orders/models.py
+1
-2
oders_helper_style.css
orders/static/css/oders_helper_style.css
+4
-0
orders_helper.js
orders/static/js/orders_helper.js
+104
-11
urls.py
orders/urls.py
+1
-0
views.py
orders/views.py
+12
-0
models.py
products/models.py
+21
-0
helper.html
templates/orders/helper.html
+13
-4
No files found.
orders/models.py
View file @
a82672f8
...
...
@@ -279,4 +279,4 @@ class CagetteSuppliers(models.Model):
c
=
[[
'supplier'
,
'='
,
1
],
[
'parent_id'
,
'='
,
False
]]
res
=
api
.
search_read
(
'res.partner'
,
c
,
f
)
return
res
\ No newline at end of file
return
res
orders/static/css/oders_helper_style.css
View file @
a82672f8
...
...
@@ -22,8 +22,12 @@
.product_not_from_supplier
{
background-color
:
#e7e9ed
;
cursor
:
pointer
;
}
.product_name
,
.supplier_name
{
font-weight
:
bold
;
}
#suppliers_container
{
display
:
flex
;
...
...
orders/static/js/orders_helper.js
View file @
a82672f8
...
...
@@ -3,6 +3,9 @@ var suppliers_list = [],
selected_suppliers
=
[],
products
=
[];
/* CALLS TO SERVER */
/**
* Add a supplier to the selected suppliers list.
*
...
...
@@ -66,6 +69,56 @@ function add_supplier() {
}
/**
* 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
)
{
openModal
();
const
data
=
{
product_tmpl_id
:
product
.
id
,
supplier_id
:
supplier
.
id
}
// Fetch supplier products
$
.
ajax
({
type
:
"POST"
,
url
:
"/orders/associate_supplier_to_product"
,
dataType
:
"json"
,
traditional
:
true
,
contentType
:
"application/json; charset=utf-8"
,
data
:
JSON
.
stringify
(
data
),
success
:
()
=>
{
// Save relation locally
save_supplier_products
(
supplier
,
[
product
])
// Update table
$
(
cell
).
removeClass
(
"product_not_from_supplier"
)
const
row
=
$
(
cell
).
closest
(
"tr"
)
const
new_row_data
=
prepare_datatable_data
([
product
.
id
])[
0
]
products_table
.
row
(
row
).
data
(
new_row_data
).
draw
()
closeModal
();
},
error
:
function
(
data
)
{
let
msg
=
"erreur serveur lors de la sauvegarde de l'association product/supplier"
.
msg
+=
` (product_tmpl_id:
${
product
.
id
}
; supplier_id:
${
supplier
.
id
}
)`
err
=
{
msg
:
msg
,
ctx
:
'save_supplier_product_association'
};
if
(
typeof
data
.
responseJSON
!=
'undefined'
&&
typeof
data
.
responseJSON
.
error
!=
'undefined'
)
{
err
.
msg
+=
' : '
+
data
.
responseJSON
.
error
;
}
report_JS_error
(
err
,
'orders'
);
closeModal
();
alert
(
'Erreur lors de la sauvegarde de l
\'
association. Veuillez ré-essayer plus tard.'
);
}
});
}
/**
* Remove a supplier from the selected list & its associated products
*
* @param {int} supplier_id
...
...
@@ -156,7 +209,7 @@ function display_suppliers() {
for
(
supplier
of
selected_suppliers
)
{
let
template
=
$
(
"#templates #supplier_pill"
);
template
.
find
(
".supplier_name"
).
text
(
supplier
.
display_name
);
template
.
find
(
".
pill_
supplier_name"
).
text
(
supplier
.
display_name
);
template
.
find
(
".remove_supplier_icon"
).
attr
(
'id'
,
`remove_supplier_
${
supplier
.
id
}
`
);
supplier_container
.
append
(
template
.
html
());
...
...
@@ -184,12 +237,20 @@ function display_suppliers() {
/* DATATABLE */
/**
* @param {array} product_ids if set, return formatted data for these products only
* @returns Array of formatted data for datatable data setup
*/
function
prepare_datatable_data
()
{
function
prepare_datatable_data
(
product_ids
=
[]
)
{
let
data
=
[];
let
products_to_format
=
[]
if
(
product_ids
.
length
>
0
)
{
products_to_format
=
products
.
filter
(
p
=>
product_ids
.
includes
(
p
.
id
));
}
else
{
products_to_format
=
products
;
}
for
(
product
of
products
)
{
for
(
product
of
products
_to_format
)
{
let
item
=
{
id
:
product
.
id
,
name
:
product
.
name
,
...
...
@@ -250,18 +311,21 @@ function prepare_datatable_columns() {
},
];
for
(
supplier
of
selected_suppliers
)
{
for
(
const
supplier
of
selected_suppliers
)
{
columns
.
push
({
data
:
supplier_column_name
(
supplier
),
title
:
supplier
.
display_name
,
width
:
"8%"
,
className
:
"dt-body-center supplier_input_cell"
,
render
:
function
(
data
,
type
,
full
)
{
className
:
`dt-body-center supplier_input_cell`
,
render
:
(
data
,
type
,
full
)
=>
{
const
base_id
=
`product_
${
full
.
id
}
_supplier_
${
supplier
.
id
}
`
;
if
(
data
===
false
)
{
return
"X"
;
return
`<div id="
${
base_id
}
_cell_content" class="cell_content">X</div>`
;
}
else
{
const
input_id
=
`product_
${
full
.
id
}
_supplier_
${
supplier
.
id
}
_qty_input`
;
return
`<input type="number" class="product_qty_input" id=
${
input_id
}
value=
${
data
}
>`
;
return
`<div id="
${
base_id
}
_cell_content" class="cell_content">
<input type="number" class="product_qty_input" id="
${
base_id
}
_qty_input" value=
${
data
}
>
</div>`
;
}
}
});
...
...
@@ -311,6 +375,7 @@ function display_products() {
createdRow
:
function
(
row
,
data
,
dataIndex
)
{
for
(
const
cell_node
of
row
.
cells
)
{
const
cell
=
$
(
cell_node
);
if
(
cell
.
hasClass
(
"supplier_input_cell"
))
{
if
(
cell
.
text
()
==
"X"
)
{
cell
.
addClass
(
'product_not_from_supplier'
);
...
...
@@ -344,6 +409,36 @@ 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
(
'_'
);
const
product_id
=
el_id
[
1
];
const
supplier_id
=
el_id
[
3
];
const
product
=
products
.
find
(
p
=>
p
.
id
==
product_id
)
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
);
const
cell
=
this
openModal
(
modal_attach_product_to_supplier
.
html
(),
()
=>
{
save_supplier_product_association
(
product
,
supplier
,
cell
);
},
'Valider'
,
false
);
});
return
0
;
}
...
...
@@ -393,6 +488,4 @@ $(document).ready(function() {
e
.
preventDefault
();
add_supplier
();
});
// TODO: on click on 'X' change to input, make product available for this supplier
});
orders/urls.py
View file @
a82672f8
...
...
@@ -12,4 +12,5 @@ urlpatterns = [
url
(
r'^helper$'
,
views
.
helper
),
url
(
r'^get_suppliers$'
,
views
.
get_suppliers
),
url
(
r'^get_supplier_products$'
,
views
.
get_supplier_products
),
url
(
r'^associate_supplier_to_product$'
,
views
.
associate_supplier_to_product
),
]
orders/views.py
View file @
a82672f8
...
...
@@ -45,6 +45,18 @@ def get_supplier_products(request):
else
:
return
JsonResponse
({
'res'
:
res
})
def
associate_supplier_to_product
(
request
):
""" This product is now supplied by this supplier """
res
=
{}
try
:
data
=
json
.
loads
(
request
.
body
.
decode
())
res
=
CagetteProduct
.
associate_supplier_to_product
(
data
[
"product_tmpl_id"
],
data
[
"supplier_id"
])
except
Exception
as
e
:
res
[
"error"
]
=
str
(
e
)
return
JsonResponse
(
res
,
status
=
500
)
return
JsonResponse
({
'res'
:
res
})
def
export_one
(
request
,
oid
):
msg
=
''
try
:
...
...
products/models.py
View file @
a82672f8
...
...
@@ -127,6 +127,27 @@ class CagetteProduct(models.Model):
res
=
api
.
create
(
'product.supplier.shortage'
,
f
)
return
res
@staticmethod
def
associate_supplier_to_product
(
product_tmpl_id
,
partner_id
):
api
=
OdooAPI
()
f
=
[
"id"
,
"standard_price"
,
"purchase_ok"
]
c
=
[[
'product_tmpl_id'
,
'='
,
product_tmpl_id
]]
res_products
=
api
.
search_read
(
'product.product'
,
c
,
f
)
product
=
res_products
[
0
]
f
=
{
'product_tmpl_id'
:
product_tmpl_id
,
'product_id'
:
product
[
"id"
],
'name'
:
partner_id
,
'product_purchase_ok'
:
product
[
"purchase_ok"
],
'price'
:
product
[
"standard_price"
],
# By default, use product price
'base_price'
:
product
[
"standard_price"
],
}
res
=
api
.
create
(
'product.supplierinfo'
,
f
)
return
res
class
CagetteProducts
(
models
.
Model
):
"""Initially used to make massive barcode update."""
...
...
templates/orders/helper.html
View file @
a82672f8
...
...
@@ -38,7 +38,7 @@
<div
id=
"supplier_pill"
>
<div
class=
"supplier_pill"
>
<div
class=
"supplier_name_container"
>
<span
class=
"supplier_name"
></span>
<span
class=
"
pill_
supplier_name"
></span>
<i
class=
"fas fa-times remove_supplier_icon"
></i>
</div>
</div>
...
...
@@ -47,12 +47,21 @@
<div
id=
"modal_remove_supplier"
>
<h3>
Attention !
</h3>
<p>
Vous vous apprêtez à supprimer le fournisseur
<span
class=
"supplier_name"
></span>
.
<br/>
Les produits associés
à ce fournisseur uniquement seront supprimés
.
<br/>
Vous vous apprêtez à supprimer le fournisseur
<span
class=
"supplier_name"
></span>
de la sélection
.
<br/>
Les produits associés
uniquement à ce fournisseur seront supprimés du tableau
.
<br/>
Les données renseignées dans la colonne de ce fournisseur seront perdues.
</p>
<p>
Êtez-vous sûr ?
</p>
<ul
id=
"list_unprocessable_porducts"
></ul>
<hr/>
</div>
<div
id=
"modal_attach_product_to_supplier"
>
<h3>
Attention !
</h3>
<p>
Vous vous apprêtez à associer le produit
<span
class=
"product_name"
></span>
au fournisseur
<span
class=
"supplier_name"
></span>
.
<br/>
L'association sera sauvegardée dès que vous aurez cliqué sur "Valider".
<br/>
</p>
<p>
Êtez-vous sûr ?
</p>
<hr/>
</div>
</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