reception_index.js 20.6 KB
Newer Older
1 2
var orders = [],
    order = {
3 4
        'id' : null
    },
5
    table_orders = null,
6 7 8
    callback_update = false,
    callback_report = false,
    selection_type = null,
9
    order_groups = {
10
        _id: 'grouped_orders',
11 12 13
        groups: []
    },
    dbc = null,
14 15
    sync = null,
    fingerprint = null;
16

17 18 19

/* UTILS */

20 21
/**
 * Difference between two dates
Damien Moulard committed
22 23
 * @param {Date} date1
 * @param {Date} date2
24 25
 * @returns difference object
 */
Damien Moulard committed
26 27
function dates_diff(date1, date2) {
    var diff = {};
28
    var tmp = date2 - date1;
Damien Moulard committed
29

30 31
    tmp = Math.floor(tmp/1000);
    diff.sec = tmp % 60;
Damien Moulard committed
32

33 34
    tmp = Math.floor((tmp-diff.sec)/60);
    diff.min = tmp % 60;
Damien Moulard committed
35

36 37
    tmp = Math.floor((tmp-diff.min)/60);
    diff.hours = tmp % 24;
Damien Moulard committed
38

39 40
    tmp = Math.floor((tmp-diff.hours)/24);
    diff.days = tmp;
Damien Moulard committed
41

42 43 44
    return diff;
}

45 46 47 48
/**
 * Wait for both ajax callbacks for reloading to avoid a js error
 *   -> reloading when ajax call not answered causes a popup to appear, which can be confusing
 */
49 50 51 52 53
function reload() {
    if (callback_update && callback_report)
        document.location.reload();
}

54 55
/**
 * Check for concurent access to same order before going to reception page.
Damien Moulard committed
56
 * @param {Int} id
57 58 59
 */
function check_before_goto(id) {
    const order_doc_id = 'order_' + id;
Damien Moulard committed
60

61 62
    dbc.get(order_doc_id).then((doc) => {
        if (doc.last_update.fingerprint !== null && doc.last_update.fingerprint !== fingerprint) {
Damien Moulard committed
63 64
            time_diff = dates_diff(new Date(doc.last_update.timestamp), new Date());
            diff_str = ``;
65 66

            if (time_diff.days !== 0) {
Damien Moulard committed
67
                diff_str += `${time_diff.days} jour(s), `;
68 69
            }
            if (time_diff.hours !== 0) {
Damien Moulard committed
70
                diff_str += `${time_diff.hours} heure(s), `;
71 72
            }
            if (time_diff.min !== 0) {
Damien Moulard committed
73
                diff_str += `${time_diff.min} min, `;
74
            }
Damien Moulard committed
75
            diff_str += `${time_diff.sec}s`;
76 77

            let modal_order_access = $('#templates #modal_order_access');
Damien Moulard committed
78

79 80 81 82 83 84 85 86 87 88 89 90 91
            modal_order_access.find(".order_last_update").text(diff_str);

            openModal(
                modal_order_access.html(),
                () => {
                    goto(id);
                },
                'Valider'
            );
        } else {
            goto(id);
        }
    })
Damien Moulard committed
92 93 94
        .catch((err) => {
            console.log(err);
        });
95 96
}

97 98 99 100
function goto(id) {
    document.location.href = "produits/" + id;
}

101
/**
102
 * Go to Products page for an existing group
103
 * @param {int} group_index index of group in groups array
104
 */
105 106 107 108 109 110 111 112
function group_goto(group_index) {
    // Make sure a couchdb document exists for all group's orders
    for (let i in order_groups.groups[group_index]) {
        let order_data = null;

        // Find order data
        for (let order of orders) {
            if (order.id == order_groups.groups[group_index][i]) {
Damien Moulard committed
113
                order_data = order;
114 115 116
            }
        }

117
        create_order_doc(order_data);
118 119
    }

120
    // go to first order
121
    check_before_goto(order_groups.groups[group_index][0]);
122 123
}

124 125
/**
 * Create a couchdb document for an order if it doesn't exist
Damien Moulard committed
126
 * @param {Object} order_data
127
 * @param {Boolean} goto if true, go to order page
128
 */
129 130
function create_order_doc(order_data, go_to_order = false) {
    const order_doc_id = 'order_' + order_data.id;
131

132 133
    dbc.get(order_doc_id).then(() => {
        if (go_to_order === true) {
134
            check_before_goto(order_data.id);
135 136
        }
    })
Damien Moulard committed
137
        .catch(function (err) {
138
        // Create if doesn't exist
Damien Moulard committed
139 140 141 142
            if (err.status === 404) {
                let order_doc = { ...order_data };

                order_doc._id = order_doc_id;
143 144
                order_doc.last_update = {
                    timestamp: Date.now(),
Damien Moulard committed
145
                    fingerprint: fingerprint
146 147 148 149 150
                };

                dbc.put(order_doc).then(() => {
                    if (go_to_order === true) {
                        goto(order_data.id);
151
                    }
Damien Moulard committed
152 153 154 155 156 157 158 159 160 161
                })
                    .catch((err) => {
                        error = {
                            msg: 'Erreur dans la creation de la commande dans couchdb',
                            ctx: 'create_order_doc',
                            details: err
                        };
                        report_JS_error(error, 'reception');
                        console.log(error);
                    });
Damien Moulard committed
162 163
            }
        });
164
}
165 166 167

/* ACTIONS */

168 169 170
/**
 * Validate all prices of an order
 */
Damien Moulard committed
171
function validatePrices() {
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    // Loading on
    openModal();

    var update_data = {
        'update_type' : 'br_valid',
        'orders' : {}
    };

    update_data.orders[order['id']] = { 'po' : [] };

    $.ajax({
        type: "PUT",
        url: "/reception/update_orders",
        dataType: "json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(update_data),
Damien Moulard committed
189
        success: function() {
190 191 192 193
            // Remove order
            dbc.get(`order_${order['id']}`).then((doc) => {
                return dbc.remove(doc);
            })
Damien Moulard committed
194 195 196 197 198
                .then(() => {
                    callback_update = true;
                    reload();
                })
                .catch((err) => {
199
                // No doc found
Damien Moulard committed
200 201 202
                    console.log(err);
                    reload();
                });
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
        },
        error: function() {
            closeModal();
            alert('Erreur dans la validation des prix');
        }
    });

    // Send changes between BC and BR
    order['updated_products'] = [];

    var updates = {
        'group_amount_total' : order['amount_total'],
        'update_type' : 'br_vaid',
        'updated_products' : [],
        'user_comments': "",
        'orders' : [order]
    };

    $.ajax({
        type: "POST",
        url: "/reception/save_error_report",
        dataType: "json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(updates),
Damien Moulard committed
228
        success: function() {
229 230 231 232 233 234 235 236 237 238 239 240
            callback_report = true;
            reload();
        },
        error: function() {
            closeModal();
            alert('Erreur dans l\'envoi du rapport.');
            err = {msg: 'Erreur dans l\'envoi du rapport.', ctx: 'validatePrices'};
            report_JS_error(err, 'reception');
        }
    });
}

241 242
/**
 * Action fired when orders are grouped (new group)
Damien Moulard committed
243
 * @returns
244
 */
245
function group_action() {
246
    let pswd = prompt('Merci de demander à un.e salarié.e le mot de passe pour fusionner ces commandes.');
247

248 249 250 251
    // Minimum security level
    if (pswd == merge_orders_pswd) {
        let selected_data = table_orders.rows('.selected').data();
        let group_ids = [];
252

253 254 255
        for (let i = 0; i < selected_data.length; i++) {
            // Select group orders id
            group_ids.push(selected_data[i].id);
256

257 258 259
            // Create doc for each group order if doesn't exist
            create_order_doc(selected_data[i]);
        }
260

261
        group_ids.sort();
Damien Moulard committed
262

263 264 265 266 267 268
        // Save group
        order_groups.groups.push(group_ids);
        dbc.put(order_groups, (err) => {
            if (!err) {
                goto(group_ids[0]);
            } else {
Damien Moulard committed
269
                alert("Une erreur est survenue lors de la création du groupe. Veuillez ré-essayer plus tard svp.");
270 271 272
                console.log(err);
            }
        });
273 274

    } else if (pswd == null) {
275
        return;
276 277 278 279 280
    } else {
        alert('Mauvais mot de passe !');
    }
}

281
/* DISPLAY */
282

283 284
/**
 * Display the order groups.
Damien Moulard committed
285
 * Remove the grouped orders from the order table to prevent grouping in multiple groups.
286 287 288
 */
function display_grouped_orders() {
    if (table_orders !== null) {
289
        $('#groups_items').empty();
290
        let groups_display_content = "<ul>";
Damien Moulard committed
291

292 293
        for (let group_index in order_groups.groups) {
            let group_orders = [];
Damien Moulard committed
294

295 296 297 298 299 300
            // Extract every order in the groups from the orders table
            for (group_order_id of order_groups.groups[group_index]) {
                // Look for order in datatable"
                for (let i = 0; i < table_orders.rows().data().length; i++) {
                    if (group_order_id == table_orders.rows(i).data()[0].id) {
                        var order = table_orders.rows(i).data()[0];
Damien Moulard committed
301

302
                        group_orders.push(order);
Damien Moulard committed
303

304 305 306 307 308 309
                        // remove table row
                        table_orders.rows(i).remove()
                            .draw();
                    }
                }
            }
Damien Moulard committed
310

311 312 313
            // Display group
            document.getElementById("container_groups").hidden = false;
            let group_row = `<li class="group_line"> Commandes de `;
Damien Moulard committed
314

315 316 317 318 319 320 321
            for (let i in group_orders) {
                if (i == group_orders.length-1) { // last element of list
                    group_row += "<b>" + group_orders[i].partner + "</b> du " + group_orders[i].date_order + " : ";
                } else {
                    group_row += "<b>" + group_orders[i].partner + "</b> du " + group_orders[i].date_order + ", ";
                }
            }
Damien Moulard committed
322

323 324 325 326 327 328 329 330 331
            if (group_orders[0].reception_status == 'False') {
                group_row += "<button class='btn--primary' onClick='group_goto("
                    + group_index
                    + ")'>Compter les produits</button>";
            } else {
                group_row += "<button class='btn--success' onClick='group_goto("
                    + group_index
                    + ")'>Mettre à jour les prix</button>";
            }
Damien Moulard committed
332

333 334 335 336 337 338 339
            group_row += "</li>";
            groups_display_content += group_row;
        }
        $('#container_groups').show();
        $('#groups_items').append(groups_display_content);
    }
}
340

341 342 343 344
/**
 * Display the main orders table
 */
function display_orders_table() {
345 346 347 348 349
    if (table_orders) {
        table_orders.clear().destroy();
        $('#orders').empty();
    }

350
    table_orders = $('#orders').DataTable({
351
        data: orders,
352 353 354 355 356
        columns:[
            {
                data:"id",
                title:"Sélectionner",
                className:"dt-body-center",
Damien Moulard committed
357
                render: function (data) {
358 359 360 361 362 363 364 365 366
                    return '<input type="checkbox" id="select_bc_'+data+'" value="'+data+'">';
                },
                width: "4%",
                orderable: false
            },
            {data:"date_order", "title":"Date Commande", "width": "8%", "className":"dt-body-center"},
            {
                data:"partner",
                title:"Fournisseur",
Damien Moulard committed
367
                render: function (data, type, full) {
368 369 370 371 372 373 374
                    // Add tooltip with PO over partner name
                    return '<div class="tooltip">' + data + ' <span class="tooltiptext">' + full.name + '</span> </div>';
                }
            },
            {
                data:"reception_status",
                className:"dt-body-center",
Damien Moulard committed
375
                render: function (data) {
376 377 378 379 380 381 382 383 384 385 386 387 388
                    if (data == "qty_valid") {
                        return "<span class='btn--danger'>Pas de prix sur le bon de livraison</span>";
                    } else {
                        return "";
                    }
                },
                orderable: false,
                width: "20%"
            },
            {
                data:"reception_status",
                title:"Statut",
                className:"dt-body-center",
Damien Moulard committed
389
                render: function (data) {
390

391
                    switch (data) {
Damien Moulard committed
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
                    case 'qty_valid':
                        return "<span class='btn--success'>Mettre à jour les prix</span>";
                    case 'br_valid':
                        return "<span class='btn'><i class='far fa-check-circle'></i> Réception OK</span>";
                    case 'False':
                        return "<span class='btn--primary'>Compter les produits</span>";

                    case 'done':
                        return "<span class='btn'><i class='far fa-check-circle'></i> Terminé</span>";
                    case 'uprice_valid':
                        return "<span class='btn--primary'>Mise à jour du prix OK</span>";
                    case "valid_pending":
                        return "<span class='btn--info'>En attente de validation</span>";

                    case 'legacy':
                        return "<span class='btn--success'>Legacy</span>";
                    case 'error_pack_op':
                        return "<span class='btn--danger'>Erreur pack operations</span>";

                    case 'error_transfer':
                        return "<span class='btn--danger'>Erreur de transfert</span>";
                    case 'error_picking':
                        return "<span class='btn--danger'>Erreur validation quantité</span>";
                    case '/error_uprice':
                        return "<span class='btn--danger'>Erreur mise à jour du prix</span>";

                    default:
                        return "<span class='btn--warning'>Status inconnu : " + data + "</span>";
420 421 422
                    }
                },
                width: "20%"
423
            } //error_transfert ou error_pack_op
424 425 426 427 428 429 430 431 432
        ],
        dom: 'rtip',
        order: [
            [
                1,
                "asc"
            ]
        ],
        iDisplayLength: 25,
433
        language: {url : '/static/js/datatables/french.json'}
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    });

    // Set rows event on click
    $('#orders').on('click', 'tbody td', function () {
        var row_data = table_orders.row($(this)).data();

        // Click on row, except cells with button
        if (this.cellIndex < 3 || this.cellIndex == 3 && row_data.reception_status != "qty_valid") {
            // Set row as selected
            $(this.parentElement).toggleClass('selected');
            if (this.parentElement.classList.contains('selected')) {
                document.getElementById("select_bc_"+row_data.id).checked = true;
            } else {
                document.getElementById("select_bc_"+row_data.id).checked = false;
            }

            // Get selected rows
            var selected_data = table_orders.rows('.selected').data();

            // if some rows already selected
            if (selected_data.length > 0) {
                // If one row selected, set selection type
                if (selected_data.length == 1) {
                    // set selection type (in case of first select)
                    selection_type = selected_data[0].reception_status;

                    // Can't group 1 order
                    document.getElementById("group_action").hidden = true;
                } else {
                    // block selection if trying to select a BC with different status
                    if (row_data.reception_status != selection_type) {
                        // unselect
                        $(this.parentElement).toggleClass('selected');
                        document.getElementById("select_bc_"+row_data.id).checked = false;

                        alert('Vous ne pouvez pas grouper des commandes qui ont un statut différent.');
                    } else {
                        //display 'group action' button
                        document.getElementById("group_action").hidden = false;

                        // 'group action' button styling, according to orders status
                        if (selected_data[0].reception_status == 'False') {
                            document.getElementById('group_action').classList.remove('btn--success');
                            document.getElementById('group_action').classList.add('btn--primary');
                            document.getElementById('group_action').innerHTML = 'Compter les produits des commandes sélectionnées';
                        } else {
                            document.getElementById('group_action').classList.remove('btn--primary');
                            document.getElementById('group_action').classList.add('btn--success');
                            document.getElementById('group_action').innerHTML = 'Mettre à jour les prix des commandes sélectionnées';
                        }
                    }
                }

            } else {
                selection_type = null;
                document.getElementById("group_action").hidden = true;
            }
Damien Moulard committed
491
        } else if (this.cellIndex == 4) { // Click on last cell button -> go to products page
492
            // Click action only for specific reception status
493
            if (row_data.reception_status == "qty_valid" || row_data.reception_status == "False") {
494 495
                // Use couchdb to pass order data to next page
                create_order_doc(row_data, true);
496
            }
Damien Moulard committed
497 498
        } else if (this.cellIndex == 3 && row_data.reception_status == "qty_valid") {
            // If 'update prices' step, click on before-last cell -> validate all prices
499 500 501 502 503 504 505 506 507 508 509
            order = row_data;
            openModal($('#modal_no_prices').html(), validatePrices, 'Confirmer', false);
        }
    });

    // Search input
    $('#search_input').on('keyup', function () {
        table_orders
            .search(jQuery.fn.DataTable.ext.type.search.string(this.value))
            .draw();
    });
510 511 512 513 514 515 516
}


$(document).ready(function() {
    openModal();
    $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });

517
    fingerprint = new Fingerprint({canvas: true}).get();
518

Damien Moulard committed
519
    // Init couchdb
520 521 522 523 524 525
    dbc = new PouchDB(couchdb_dbname),
    sync = PouchDB.sync(couchdb_dbname, couchdb_server, {
        live: true,
        retry: true,
        auto_compaction: false
    });
526

527
    // On distant changes
Damien Moulard committed
528
    sync.on('change', function (info) {
Damien Moulard committed
529
        // If important data changed somewhere else, update local data
530
        let need_to_reload = false;
Damien Moulard committed
531

532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
        if (info.direction === "pull") {
            for (let doc of info.change.docs) {
                if (doc._id === "grouped_orders") {
                    // If groups doc changed, update local groups
                    need_to_reload = true;
                    order_groups = doc;
                } else if ("_deleted" in doc && doc._deleted === true) {
                    // If order was deleted, delete it locally
                    try {
                        const deleted_order_id = parseInt(doc._id.split('_')[1]);
                        let index = orders.findIndex(order => order.id == deleted_order_id);

                        if (index !== -1) {
                            orders.splice(index, 1);
                            need_to_reload = true;
                        }
                    } catch (error) {
                        console.log(error);
                    }
                } else {
                    // Find updated order in local orders & update it if reception status changed
                    let index = orders.findIndex(order => order.id == doc.id);
Damien Moulard committed
554

555 556 557 558 559 560 561 562 563 564 565 566 567
                    if (index !== -1 && orders[index].reception_status !== doc.reception_status) {
                        orders[index] = doc;
                        need_to_reload = true;
                        break;
                    }
                }
            }
        }

        if (need_to_reload) {
            display_orders_table();
            display_grouped_orders();
        }
Damien Moulard committed
568 569 570 571
    }).on('error', function (err) {
        console.log(err);
    });

572 573 574 575
    // Get or create order groups doc
    dbc.get("grouped_orders").then((doc) => {
        order_groups = doc;
    })
Damien Moulard committed
576 577 578
        .catch(function (err) {
            console.log(err);
            if (err.status === 404) {
579
            // Create if doesn't exist
Damien Moulard committed
580 581 582 583 584 585 586 587 588 589
                dbc.put(order_groups, (err, result) => {
                    if (!err) {
                        order_groups._rev = result.rev;
                    } else {
                        console.log("document pour les groupes déjà créé");
                        console.log(err);
                    }
                });
            }
        });
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    // Set date format for DataTable so date ordering can work
    $.fn.dataTable.moment('D/M/Y');

    // Get orders
    $.ajax({
        type: 'GET',
        url: "/reception/get_list_orders",
        dataType:"json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        success: function(data) {
            orders = data.data;
            display_orders_table();
            display_grouped_orders();
            closeModal();
        },
        error: function(data) {
            err = {msg: "erreur serveur lors de la récupération des commandes", ctx: 'get_list_orders'};
            if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
                err.msg += ' : ' + data.responseJSON.error;
            }
            report_JS_error(err, 'orders');
613

614 615 616 617
            closeModal();
            alert('Erreur lors de la récupération des commandes, rechargez la page plus tard.');
        }
    });
618
});