Commit a82672f8 by Damien Moulard

make a product available for a supplier

parent d8d04777
...@@ -22,8 +22,12 @@ ...@@ -22,8 +22,12 @@
.product_not_from_supplier { .product_not_from_supplier {
background-color: #e7e9ed; background-color: #e7e9ed;
cursor: pointer;
} }
.product_name, .supplier_name {
font-weight: bold;
}
#suppliers_container { #suppliers_container {
display: flex; display: flex;
......
...@@ -3,6 +3,9 @@ var suppliers_list = [], ...@@ -3,6 +3,9 @@ var suppliers_list = [],
selected_suppliers = [], selected_suppliers = [],
products = []; products = [];
/* CALLS TO SERVER */
/** /**
* Add a supplier to the selected suppliers list. * Add a supplier to the selected suppliers list.
* *
...@@ -66,6 +69,56 @@ function add_supplier() { ...@@ -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 * Remove a supplier from the selected list & its associated products
* *
* @param {int} supplier_id * @param {int} supplier_id
...@@ -156,7 +209,7 @@ function display_suppliers() { ...@@ -156,7 +209,7 @@ function display_suppliers() {
for (supplier of selected_suppliers) { for (supplier of selected_suppliers) {
let template = $("#templates #supplier_pill"); 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}`); template.find(".remove_supplier_icon").attr('id', `remove_supplier_${supplier.id}`);
supplier_container.append(template.html()); supplier_container.append(template.html());
...@@ -184,12 +237,20 @@ function display_suppliers() { ...@@ -184,12 +237,20 @@ function display_suppliers() {
/* DATATABLE */ /* DATATABLE */
/** /**
* @param {array} product_ids if set, return formatted data for these products only
* @returns Array of formatted data for datatable data setup * @returns Array of formatted data for datatable data setup
*/ */
function prepare_datatable_data() { function prepare_datatable_data(product_ids = []) {
let data = []; let data = [];
let products_to_format = []
for (product of products) { 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_to_format) {
let item = { let item = {
id: product.id, id: product.id,
name: product.name, name: product.name,
...@@ -250,18 +311,21 @@ function prepare_datatable_columns() { ...@@ -250,18 +311,21 @@ function prepare_datatable_columns() {
}, },
]; ];
for (supplier of selected_suppliers) { for (const supplier of selected_suppliers) {
columns.push({ columns.push({
data: supplier_column_name(supplier), data: supplier_column_name(supplier),
title: supplier.display_name, title: supplier.display_name,
width: "8%", width: "8%",
className:"dt-body-center supplier_input_cell", className: `dt-body-center supplier_input_cell`,
render: function (data, type, full) { render: (data, type, full) => {
const base_id = `product_${full.id}_supplier_${supplier.id}`;
if (data === false) { if (data === false) {
return "X"; return `<div id="${base_id}_cell_content" class="cell_content">X</div>`;
} else { } else {
const input_id = `product_${full.id}_supplier_${supplier.id}_qty_input`; return `<div id="${base_id}_cell_content" class="cell_content">
return `<input type="number" class="product_qty_input" id=${input_id} value=${data}>`; <input type="number" class="product_qty_input" id="${base_id}_qty_input" value=${data}>
</div>`;
} }
} }
}); });
...@@ -311,6 +375,7 @@ function display_products() { ...@@ -311,6 +375,7 @@ function display_products() {
createdRow: function( row, data, dataIndex ) { createdRow: function( row, data, dataIndex ) {
for (const cell_node of row.cells) { for (const cell_node of row.cells) {
const cell = $(cell_node); const cell = $(cell_node);
if (cell.hasClass("supplier_input_cell")) { if (cell.hasClass("supplier_input_cell")) {
if (cell.text() == "X") { if (cell.text() == "X") {
cell.addClass( 'product_not_from_supplier' ); cell.addClass( 'product_not_from_supplier' );
...@@ -344,6 +409,36 @@ function display_products() { ...@@ -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; return 0;
} }
...@@ -393,6 +488,4 @@ $(document).ready(function() { ...@@ -393,6 +488,4 @@ $(document).ready(function() {
e.preventDefault(); e.preventDefault();
add_supplier(); add_supplier();
}); });
// TODO: on click on 'X' change to input, make product available for this supplier
}); });
...@@ -12,4 +12,5 @@ urlpatterns = [ ...@@ -12,4 +12,5 @@ urlpatterns = [
url(r'^helper$', views.helper), url(r'^helper$', views.helper),
url(r'^get_suppliers$', views.get_suppliers), url(r'^get_suppliers$', views.get_suppliers),
url(r'^get_supplier_products$', views.get_supplier_products), url(r'^get_supplier_products$', views.get_supplier_products),
url(r'^associate_supplier_to_product$', views.associate_supplier_to_product),
] ]
...@@ -45,6 +45,18 @@ def get_supplier_products(request): ...@@ -45,6 +45,18 @@ def get_supplier_products(request):
else: else:
return JsonResponse({'res': res}) 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): def export_one(request, oid):
msg = '' msg = ''
try: try:
......
...@@ -127,6 +127,27 @@ class CagetteProduct(models.Model): ...@@ -127,6 +127,27 @@ class CagetteProduct(models.Model):
res = api.create('product.supplier.shortage', f) res = api.create('product.supplier.shortage', f)
return res 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): class CagetteProducts(models.Model):
"""Initially used to make massive barcode update.""" """Initially used to make massive barcode update."""
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
<div id="supplier_pill"> <div id="supplier_pill">
<div class="supplier_pill"> <div class="supplier_pill">
<div class="supplier_name_container"> <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> <i class="fas fa-times remove_supplier_icon"></i>
</div> </div>
</div> </div>
...@@ -47,12 +47,21 @@ ...@@ -47,12 +47,21 @@
<div id="modal_remove_supplier"> <div id="modal_remove_supplier">
<h3>Attention !</h3> <h3>Attention !</h3>
<p> <p>
Vous vous apprêtez à supprimer le fournisseur <span class="supplier_name"></span>.<br/> Vous vous apprêtez à supprimer le fournisseur <span class="supplier_name"></span> de la sélection.<br/>
Les produits associés à ce fournisseur uniquement seront supprimés.<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. Les données renseignées dans la colonne de ce fournisseur seront perdues.
</p> </p>
<p>Êtez-vous sûr ?</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/> <hr/>
</div> </div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment