Commit 7b60a5d4 by Damien Moulard

select products & generate inventory

parent a82672f8
Pipeline #987 failed with stage
in 18 seconds
......@@ -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,36 +127,54 @@ class CagetteInventory(models.Model):
api = OdooAPI()
ids = []
order = ['', '']
user = partner = ''
fields = ['create_uid', 'product_id', 'partner_id']
cond = [['id', 'in', line_ids]]
if (line_type == 'cpo'):
model = 'computed.purchase.order.line'
fields += ['computed_purchase_order_id']
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:
model = 'purchase.order.line'
fields += ['order_id']
fields = ['create_uid', 'product_id', 'partner_id']
cond = [['id', 'in', line_ids]]
if (line_type == 'cpo'):
model = 'computed.purchase.order.line'
fields += ['computed_purchase_order_id']
else:
model = 'purchase.order.line'
fields += ['order_id']
lines = api.search_read(model, cond, fields)
if len(lines) == len(line_ids):
for l in lines:
ids.append(l['product_id'][0])
user = l['create_uid'][1]
if (line_type == 'cpo'):
order = l['computed_purchase_order_id']
if line_type == 'product_templates':
ids.append(l['id'])
else:
order = l['order_id']
partner = l['partner_id'][1]
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']
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]
partners.append(cpo[0]['partner_id'][1])
file_data = {
'order': order[1],
'user': user,
'partner': partner,
'partners': partners,
'inventory_status': '',
'products': ids
}
......
......@@ -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",
......
......@@ -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))
......
.page_body{
position: relative;
}
#form_container {
margin-top: 30px;
}
......@@ -7,7 +11,7 @@
}
#products_table_filter input{
height: 50px;
height: 40px;
}
#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;
}
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();
});
});
......@@ -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>
......
......@@ -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>
......
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