(function () { 'use strict'; angular .module('app', ['ui.bootstrap', 'ui.utils']) .controller('ReportsCtrl', ReportsCtrl); ReportsCtrl.$inject = ['$scope', 'smartRequest', 'Notification']; function ReportsCtrl($scope, smartRequest, Notification) { Number.prototype.toDivide = function () { var float = String(this.toFixed(2)); if (float.length <= 6) return float; var space = 0; var number = ''; for (var i = float.length - 1; i >= 0; i--) { if (space == 3) { number = ' ' + number; space = 0; } number = float.charAt(i) + number; space++; } return number; }; var date = new Date(); var formatted = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear(); date.setDate(date.getDate() - 1); var formatted_yesterday = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear(); $scope.report_delete = []; $scope.report_realisation = []; $scope.start_date = formatted_yesterday; $scope.end_date = formatted; $scope.report_id = 'realisation'; $scope.history = []; $scope.statistic = {}; $scope.staffs = []; $scope.printers = []; $scope.dataTableOpt = { "aoSearchCols": [ null ], "oLanguage": { "sUrl": 'https://cdn.datatables.net/plug-ins/1.13.3/i18n/ru.json' }, "searching": false, "paging": false, "info": false, "order": [[1, 'desc']], }; $scope.update = function () { smartRequest.get('v1/reports', function (data) { $scope.history = data.reports; $('.modal-body').scrollTop(0); }); smartRequest.get('v1/settings?code=11', function (data) { $scope.delete_shift_value = data.value; }); }; $scope.deleteReport = function (report) { $('#preload-modal').modal(); Notification.primary('Дождитесь удаления! Страница обновится автоматически.'); smartRequest.post('v1/deletedata', { value: 'delete_report', report_id: report.id }, function (data) { $scope.status = data.status; $scope.message = data.message; if (data.status == 'success') { Notification.success(data.message); setTimeout(function () { //location.reload(); $scope.update(); $('#preload-modal').modal('hide'); }, 1000); } if ($scope.status == 'error') { Notification.error(data.message); } }); }; $scope.closeModal = function (modalName) { $scope.modalName = '#' + modalName; $('.modal-body').scrollTop(0); $($scope.modalName).modal('dispose'); return true; }; $scope.prevModal = function (modalFromName, modalToName) { $scope.modal_from = '#' + modalFromName; $scope.modal_to = '#' + modalToName; $($scope.modal_from).modal('hide'); $($scope.modal_to).modal('toggle'); }; $scope.nextModal = function (modalFromName, modalToName) { $scope.modal_from = '#' + modalFromName; $scope.modal_to = '#' + modalToName; $($scope.modal_from).modal('hide'); $($scope.modal_to).modal('toggle'); }; $scope.getOrders = function (discount_id, modalFromName, modalToName) { $scope.discount_id = discount_id; $scope.orders_list = $scope.orders_info[discount_id].orders; $scope.nextModal(modalFromName, modalToName); }; $scope.getItems = function (order_id, opened, closed, modalFromName, modalToName) { smartRequest.get('v1/clientorderinfo?order_id=' + order_id + '&opened=' + opened + '&closed=' + closed, function (data) { $scope.order_info = data.info; $scope.nextModal(modalFromName, modalToName); }); }; $scope.reportDiscounts = function () { $('#preload-modal').modal(); Notification.primary('Отчет формируется. Ожидайте.'); smartRequest.get('v1/datareport?type=discounts&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.orders_info = data.orders_info; $scope.orders_count = data.orders_count; $scope.orders_full_sum = data.orders_full_sum; $scope.orders_sale_sum = data.orders_sale_sum; $scope.orders_order_sum = data.orders_order_sum; $('#preload-modal').modal('hide'); $('#report-discounts').modal(); $scope.update(); }); }; $scope.reportDelete = function () { $('#preload-modal').modal(); Notification.primary('Отчет формируется. Ожидайте.'); smartRequest.get('v1/datareport?type=deleted&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.report_delete = data.orders; $scope.totalSum = data.totalSum; $scope.totalCount = data.totalCount; $('#preload-modal').modal('hide'); if ($scope.totalCount > 0) { $('#report-delete').modal(); } else { Notification.error(data.message); } $scope.update(); }); }; $scope.reportRealisation = function () { $('#preload-modal').modal(); Notification.primary('Отчет формируется. Ожидайте.'); smartRequest.get('v1/datareport?type=realisation&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.update(); $scope.report_realisation = data.printers; $scope.return_printers = data.ret_prints; $scope.report_realisation.total_count = data.total_count; $scope.report_realisation.total_sum = data.total_sum; $('#preload-modal').modal('hide'); $('#report-realisation').modal(); }); }; $scope.drawTable = function (data) { var collapsedGroups = []; var groupParent = []; var counter = 1; $.fn.dataTable.moment('YYYY-MM-DD HH:mm:ss'); $scope.table = $('#table_orders').DataTable({ data: data, destroy: true, columns: [ {data: 'shift_id', title: 'Смена'},//hide {data: 'work_place', title: 'Раб.место'},//hide {data: 'place_name', title: 'Зал'},//hide {data: 'table_name', title: 'Стол'},//hide { data: 'staff_name', title: 'Смена/Зал/Стол/Заказ/Персонал', searchBuilderTitle: 'Персонал', class: 'order_id' }, {data: 'client_name', title: 'Клиент', class: 'order_id'}, {data: 'item_name', title: 'Товар'}, {data: 'order_code', title: 'Заказ'},//hide {data: 'item_time', title: 'Время'}, { data: 'printer_name', title: 'МП', searchBuilderTitle: 'Место приготовления', class: 'order_id' }, { data: 'item_count', title: 'Кол-во', render: function (data, type, row) { return DataTable.render.number(' ', '.', 3, '', '').display(data); } }, {data: 'item_real_price', title: 'Цена', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, {data: 'item_sale_price', title: 'Сумма', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, {data: 'item_special_price', title: 'Себест.', searchBuilderTitle: 'Себестоимость'}, { data: 'item_cash', title: 'Нал.', searchBuilderTitle: 'Оплата наличными', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, { data: 'item_credit', title: 'Кред.карта', searchBuilderTitle: 'Оплата кредитной картой', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, { data: 'item_presale', title: 'Аванс', searchBuilderTitle: 'Зачет аванса', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, {data: 'item_clearing', title: 'Б/н', searchBuilderTitle: 'Оплата безналичными', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, {data: 'item_discount_sum', title: 'Скидка, BYN', searchBuilderTitle: 'Сумма скидки', render: function (data, type, row) { return DataTable.render.number(' ', '.', 2, '', '').display(data); } }, {data: 'item_discount_value', title: 'Скидка, %', searchBuilderTitle: '% скидки'}, { data: 'order_opened', title: 'Время открытия заказа', searchBuilderTitle: 'Время открытия заказа' },//hide { data: 'order_closed', title: 'Время закрытия заказа', searchBuilderTitle: 'Время закрытия заказа' },//hide {data: 'order_check_number', searchBuilderTitle: 'Номер чека'},//hide { data: 'shift_opened', title: 'Время открытия смены', searchBuilderTitle: 'Время открытия смены' },//hide { data: 'shift_closed', title: 'Время закрытия смены', searchBuilderTitle: 'Время закрытия смены' },//hide ], order: [[0, 'asc'], [1, 'asc'], [2, 'asc'], [3, 'asc'], [7, 'asc']], columnDefs: [{ targets: [0, 1, 2, 3, 7, 20, 21, 22, 23, 24], visible: false }], stripeClasses: [], fixedHeader: true, scrollCollapse: false, paging: false, searching: true, responsive: false, dom: 'QBfrtip', searchBuilder: { columns: [0, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] }, buttons: [{ text: 'Excel', action: function (e, dt, node, conf) { $scope.exportTableToExcel('table_orders', 'extend-realisation'); } }], language: { url: "https://cdn.datatables.net/plug-ins/1.13.3/i18n/ru.json", }, rowGroup: { dataSrc: ['shift_id', 'place_name', 'table_name', 'order_code'], startRender: function (rows, group, level) { groupParent[level] = group; var groupAll = ''; var name = ''; var check_text = ''; $scope.opened = ''; $scope.closed = ''; $scope.check_number = null; for (var i = 0; i < level; i++) { groupAll += groupParent[i]; if (collapsedGroups[groupAll]) { return; } } groupAll += group; if ((typeof (collapsedGroups[groupAll]) == 'undefined') || (collapsedGroups[groupAll] === null)) { if (level === 3) { collapsedGroups[groupAll] = true; } else { collapsedGroups[groupAll] = false; } } //True = Start collapsed. False = Start expanded. var collapsed = collapsedGroups[groupAll]; rows.nodes().each(function (r) { r.style.display = (collapsed ? 'none' : ''); }); if (level === 0) { name = 'Смена №'; $scope.opened = ''; $scope.closed = ''; $scope.total_item_count = 0; $scope.total_item_real_price = 0; $scope.total_item_sale_price = 0; $scope.total_item_special_price = 0; $scope.total_item_cash = 0; $scope.total_item_credit = 0; $scope.total_item_clearing = 0; $scope.total_item_presale = 0; $scope.total_item_discount_sum = 0; rows.rows().data().filter(function (value, index) { if (parseInt(value['shift_id']) === parseInt(groupAll)) { $scope.opened = value['shift_opened']; $scope.closed = value['shift_closed']; if (rows.rows(index, {page: 'current'}).data()[0]) { $scope.total_item_count += value['item_count']; $scope.total_item_real_price += value['item_real_price']; $scope.total_item_sale_price += value['item_sale_price']; $scope.total_item_special_price += value['item_special_price']; $scope.total_item_cash += value['item_cash']; $scope.total_item_credit += value['item_credit']; $scope.total_item_clearing += value['item_clearing']; $scope.total_item_presale += value['item_presale']; $scope.total_item_discount_sum += value['item_discount_sum']; } } }); return $('') .append('' + name + group + ' ' + '(Открыта: ' + $scope.opened + ' Закрыта: ' + $scope.closed + ')') .append('' + DataTable.render.number(' ', '.', 3, '', '').display($scope.total_item_count) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_real_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_sale_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_special_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_cash) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_credit) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_presale) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_clearing) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_discount_sum) + '') .append('') .attr('data-name', groupAll) .toggleClass('collapsed', collapsed); } if (level === 1) { $scope.total_item_count = 0; $scope.total_item_real_price = 0; $scope.total_item_sale_price = 0; $scope.total_item_special_price = 0; $scope.total_item_cash = 0; $scope.total_item_credit = 0; $scope.total_item_clearing = 0; $scope.total_item_presale = 0; $scope.total_item_discount_sum = 0; rows.rows().data().filter(function (value, index) { if (value['shift_id'] + value['place_name'] === groupAll) { if (rows.rows(index, {page: 'current'}).data()[0]) { $scope.total_item_count += value['item_count']; $scope.total_item_real_price += value['item_real_price']; $scope.total_item_sale_price += value['item_sale_price']; $scope.total_item_special_price += value['item_special_price']; $scope.total_item_cash += value['item_cash']; $scope.total_item_credit += value['item_credit']; $scope.total_item_clearing += value['item_clearing']; $scope.total_item_presale += value['item_presale']; $scope.total_item_discount_sum += value['item_discount_sum']; } } }); return $('') .append('' + name + group + '') .append('' + DataTable.render.number(' ', '.', 3, '', '').display($scope.total_item_count) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_real_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_sale_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_special_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_cash) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_credit) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_presale) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_clearing) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_discount_sum) + '') .append('') .attr('data-name', groupAll) .toggleClass('collapsed', collapsed); } if (level === 2) { name = 'Стол №'; $scope.total_item_count = 0; $scope.total_item_real_price = 0; $scope.total_item_sale_price = 0; $scope.total_item_special_price = 0; $scope.total_item_cash = 0; $scope.total_item_credit = 0; $scope.total_item_clearing = 0; $scope.total_item_presale = 0; $scope.total_item_discount_sum = 0; rows.rows().data().filter(function (value, index) { if (value['shift_id'] + value['place_name'] + value['table_name'] === groupAll) { if (rows.rows(index, {page: 'current'}).data()[0]) { $scope.total_item_count += value['item_count']; $scope.total_item_real_price += value['item_real_price']; $scope.total_item_sale_price += value['item_sale_price']; $scope.total_item_special_price += value['item_special_price']; $scope.total_item_cash += value['item_cash']; $scope.total_item_credit += value['item_credit']; $scope.total_item_clearing += value['item_clearing']; $scope.total_item_presale += value['item_presale']; $scope.total_item_discount_sum += value['item_discount_sum']; } } }); return $('') .append('' + name + group + '') .append('' + DataTable.render.number(' ', '.', 3, '', '').display($scope.total_item_count) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_real_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_sale_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_special_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_cash) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_credit) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_presale) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_clearing) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_discount_sum) + '') .append('') .attr('data-name', groupAll) .toggleClass('collapsed', collapsed); } if (level === 3) { name = 'Заказ №'; check_text = ' Чек №' $scope.total_item_count = 0; $scope.total_item_real_price = 0; $scope.total_item_sale_price = 0; $scope.total_item_special_price = 0; $scope.total_item_cash = 0; $scope.total_item_credit = 0; $scope.total_item_clearing = 0; $scope.total_item_presale = 0; $scope.total_item_discount_sum = 0; rows.rows().data().filter(function (value, index) { if (value['shift_id'] + value['place_name'] + value['table_name'] + value['order_code'] === groupAll) { $scope.opened = value['order_opened']; $scope.closed = value['order_closed']; $scope.check_number = value['order_check_number']; if (rows.rows(index, {page: 'current'}).data()[0]) { $scope.total_item_count += value['item_count']; $scope.total_item_real_price += value['item_real_price']; $scope.total_item_sale_price += value['item_sale_price']; $scope.total_item_special_price += value['item_special_price']; $scope.total_item_cash += value['item_cash']; $scope.total_item_credit += value['item_credit']; $scope.total_item_clearing += value['item_clearing']; $scope.total_item_presale += value['item_presale']; $scope.total_item_discount_sum += value['item_discount_sum']; } } }); return $('') .append('' + name + group + ' ' + '(Открыт: ' + $scope.opened + ' Закрыт: ' + $scope.closed + ($scope.check_number === 0 ? '' : check_text + $scope.check_number) + ')') .append('' + DataTable.render.number(' ', '.', 3, '', '').display($scope.total_item_count) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_real_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_sale_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_special_price) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_cash) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_credit) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_presale) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_clearing) + '') .append('' + DataTable.render.number(' ', '.', 2, '', '').display($scope.total_item_discount_sum) + '') .append('') .attr('data-name', groupAll) .toggleClass('collapsed', collapsed); } }, initComplete: function () { counter = 1; } } }).on('draw', function () { counter = 1; }); $('#table_orders tbody').on('click', 'tr.dtrg-start', function () { var name = $(this).data('name'); collapsedGroups[name] = !collapsedGroups[name]; $scope.table.draw(false); }); }; $scope.reportRealisationConstruct = function () { $('#preload-modal').modal(); Notification.primary('Отчет формируется. Пожалуйста, дождитесь загрузки!'); smartRequest.get('v1/datareport?type=report_construct&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.construct_data = data.data; $scope.drawTable($scope.construct_data); $scope.update(); Notification.success('Отчет сформирован, ожидайте загрузки!'); $('#report-construct').modal(); $('#preload-modal').modal('hide'); }); }; function getEndingDigit(inputString) { const regex = /\d+$/; if (regex.test(inputString)) { const match = inputString.match(regex); return match[0].replace(/\D/g, ''); } return null; } function autofitColumns(worksheet) { let objectMaxLength = []; const letters = []; const [startLetter, endLetter] = worksheet['!ref']?.replace(/\d/, '').split(':'); const startCode = startLetter.charCodeAt(0); const endCode = endLetter.charCodeAt(0) + 1; for (let code = startCode; code < endCode; code++) { const letter = String.fromCharCode(code); letters.push(letter); } letters.forEach((c) => { const cellHeader = c; const maxCellLengthForWholeColumn = Array.from( {length: getEndingDigit(worksheet['!ref'])}, (_, i) => i ).reduce((acc, i) => { const cell = worksheet[`${cellHeader}${i + 1}`]; if (!cell) return acc; const charLength = cell.v.length + 1; return acc > charLength ? acc : charLength; }, 0); objectMaxLength.push({width: maxCellLengthForWholeColumn + 2}); }); worksheet['!cols'] = objectMaxLength; return worksheet; } $scope.exportTableToExcel = function (tableID, filename = 'table') { const table = document.getElementById(tableID); const wb = XLSX.utils.table_to_book(table, {raw: true, sheet: 'SheetJS'}); let ws = wb.Sheets['SheetJS']; ws = autofitColumns(ws); console.log(ws); // Set date and time format for the 4th column (index 3) const dateFormat = 'yyyy-mm-dd hh:mm:ss'; const range = XLSX.utils.decode_range(ws['!ref']); for (let row = range.s.r; row <= range.e.r; row++) { const cellRef = XLSX.utils.encode_cell({r: row, c: 3}); // 4th column (index 3) const cell = ws[cellRef]; if (cell && cell.t === 'n' && isExcelDate(cell.v)) { cell.z = dateFormat; } } const firstRowRange = {s: {r: 0, c: range.s.c}, e: {r: 0, c: range.e.c}}; for (let rowNum = firstRowRange.s.r; rowNum <= firstRowRange.e.r; rowNum++) { for (let colNum = firstRowRange.s.c; colNum <= firstRowRange.e.c; colNum++) { const cellAddress = XLSX.utils.encode_cell({r: rowNum, c: colNum}); const cell = ws[cellAddress]; if (cell && cell.s) { cell.s.fill = { fgColor: {rgb: "FFFF00"} }; } } } const wbout = XLSX.write(wb, {bookType: 'xlsx', type: 'array', cellStyles: true}); const blob = new Blob([wbout], {type: 'application/octet-stream'}); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `${filename}.xlsx`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } function isExcelDate(value) { return value >= 0 && value < 2958466.99999999; } $scope.reportStatistic = function () { smartRequest.get('v1/datareport?type=statistic&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.fiscal = data.fiscal; $scope.realisation = data.realisation; $scope.returns = data.returns; $scope.cancellations = data.cancellations; $scope.statistic = data.statistic; $scope.presales = data.presales; $scope.payments = data.payments; $('#report-statistic').modal(); $scope.update(); }); }; $scope.reportStaff = function () { smartRequest.get('v1/datareport?type=staff&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.staffs = data.staffs; $('#report-staff').modal(); $scope.update(); }); }; $scope.reportPay = function () { smartRequest.get('v1/datareport?type=payment&start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.printers = data.items; $('#report-payment').modal(); $scope.update(); }); }; $scope.reportOut = function () { smartRequest.get('v1/outorders?start_date=' + encodeURIComponent($scope.start_date) + '&end_date=' + encodeURIComponent($scope.end_date), function (data) { $scope.orders = data.orders; $scope.total = data.total; $('#report-out').modal(); $scope.update(); }); }; $scope.createReport = function () { switch ($scope.report_id) { case 'deleted': $scope.reportDelete(); break; case 'realisation': $scope.reportRealisation(); break; case 'reportRealisationConstruct': $scope.reportRealisationConstruct(); break; case 'statistics': $scope.reportStatistic(); break; case 'staff': $scope.reportStaff(); break; case 'pay': $scope.reportPay(); break; case 'out': $scope.reportOut(); break; case 'discounts': $scope.reportDiscounts(); break; } }; $scope.archiveReport = function (type, start_date, end_date) { $scope.report_id = type; $scope.start_date = start_date; $scope.end_date = end_date; $scope.createReport(); }; $scope.popup = function (data) { var mywindow = window.open(); mywindow.document.write(data); mywindow.print(); mywindow.close(); }; $scope.printElem = function (elem) { console.log(elem); $scope.popup($('
').append($(elem).clone()).html()); }; $scope.update(); } })();