diff --git a/commands/Import — копия.php b/commands/Import — копия.php new file mode 100644 index 0000000..5593ee9 --- /dev/null +++ b/commands/Import — копия.php @@ -0,0 +1,90 @@ +where('is_active', '=', 1)->get(); + $end_date = date('m/d/Y H:i:s', strtotime($input['end_date']) + 86399); + $start_date = date('m/d/Y H:i:s', strtotime($input['start_date'])); + foreach ($terminals as $terminal) { + $url = $HRCPortalURL . 'api/cloud/list?api=2.0&project_code=hrc&code=' . $terminal['key'] . '&folder=' . $folder; + $search = curl_init(); + + curl_setopt_array($search, array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => false, + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + )); + $search_response = curl_exec($search); + curl_close($search); + $responses = json_decode($search_response, TRUE)['files']; + + foreach ($responses as $key => $response) { + if (array_key_exists('filename', $response)) { + $fulldate = date_parse_from_format('d-m-Y-H-i-s', $response['filename']); + $fulldate = mktime($fulldate['hour'], $fulldate['minute'], $fulldate['second'], $fulldate['month'], $fulldate['day'], $fulldate['year']); + if ($fulldate >= strtotime($start_date) && $fulldate <= strtotime($end_date)) { + $out[] = date('d-m-Y-H-i-s', $fulldate); + } + } + } + if (!isset($out)) { + return [ + 'status' => 'success', + 'message' => 'shifts not found', + ]; + } else { + foreach ($out as $filename) { + $date_file = date('Y-m-d', $filename); + //$path = '/backup/' . $filename . '.xml'; + $path = '/Резервная%20копия/' . $date_file . '/exchange/' . $date_file . '/exchange/' . $filename . '.xml'; + $download_url = $HRCPortalURL . 'api/cloud/download?api=2.0&project_code=hrc&code=' . $terminal['key'] . '&path=' . $path; + $download = curl_init(); + + curl_setopt_array($download, array( + CURLOPT_URL => $download_url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => false, + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + )); + $download_response = curl_exec($download); + curl_close($download); + $file = json_decode($download_response, TRUE)['content']; + $params = array('code' => $terminal['key'], 'name' => $filename . '.xml', 'folder' => 'exchange', 'content' => $file, 'project_code' => 'hrc', 'api' => '2.0'); + $upload = curl_init(); + curl_setopt_array($upload, array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_URL => $HRCPortalURL . 'api/cloud/upload', + CURLOPT_SSL_VERIFYHOST => 0, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params, + )); + $upload_response = curl_exec($upload); + curl_close($upload); + } + return [ + 'status' => 'success', + 'start_date' => strtotime($start_date), + 'end_date' => strtotime($end_date), + ]; + } + } + } +} \ No newline at end of file diff --git a/commands/TopDishesNewYear.php b/commands/TopDishesNewYear.php new file mode 100644 index 0000000..5033a20 --- /dev/null +++ b/commands/TopDishesNewYear.php @@ -0,0 +1,125 @@ +where('is_active', '=', 1)->first(); + $dirname = __DIR__ . "\\..\\..\\..\\Exchange\\" . $terminal['key'] . "\\"; + $filename = "newyear.json"; + if (!is_dir($dirname)) { + mkdir($dirname, 0777); + } + if (!file_exists($dirname . $filename)) { + $info = ExchangeItems::where('menu_code', '>', 0) + ->where('real_price', '>', 1) + ->where('created_at', '>=', '2021-10-01 00:00:00') + ->where('created_at', '<', '2021-12-31 23:59:59') + ->get() + ->unique('menu_code'); + $count = ExchangeItems::where('menu_code', '>', 0)->where('created_at', '>=', '2021-10-01 00:00:00')->where('created_at', '<', '2021-12-31 23:59:59')->count(); + if ($count > 0) { + foreach ($info as $key => $value) { + $out[] = $value; + } + foreach ($out as $key => $item) { + $dishInfo = Dishes::where('code', '=', $item['menu_code']) + ->where('legacy_code', '=', $item['dishes_code']) +// ->where('is_history', '=', 0) + ->first(); + $onlineDishInfo = ExchangeItems::where('menu_code', '=', $item['menu_code']) + ->where('dishes_code', '=', $item['dishes_code']) + ->where('created_at', '>=', '2021-10-01 00:00:00') + ->where('created_at', '<', '2021-12-31 23:59:59') + ->first(); + $dishName = $dishInfo['name']; + $dishCount = ExchangeItems::where('menu_code', '=', $item['menu_code']) + ->where('created_at', '>=', '2021-10-01 00:00:00') + ->where('created_at', '<', '2021-12-31 23:59:59') + ->sum('count'); + $dishSum = $onlineDishInfo['real_price'] * $dishCount; + if ($dishSum > 0) { + $dishTotalCost = round(($onlineDishInfo['special_price'] * $dishCount), 2); + $dishPercent = round((100 - ((($dishSum - $dishTotalCost) * 100) / $dishSum)), 2); + $dishProfit = $dishSum - $dishTotalCost; + } else { + $dishTotalCost = 0; + $dishPercent = 0; + $dishProfit = 0; + } + $dishes[] = array('name' => $dishName, 'count' => intval($dishCount), 'sum' => intval($dishSum), 'totalCost' => intval($dishTotalCost), 'percentProffit' => $dishPercent, 'proffit' => $dishProfit); + } + for ($i = 0; $i < count($dishes); $i++) { + $sortkey[$i] = $dishes[$i]['count']; + } + arsort($sortkey); + foreach ($sortkey as $key => $key) { + $sorted[] = $dishes[$key]; + } + $sorted = array_slice($sorted, 0, 3); + //End top dishes counter + + //Start top day + //SELECT COUNT(`code`) AS `orders_counter`, `shift_id` FROM `exchange_orders` WHERE `is_closed` > 0 AND `opened` > '2021-01-01 00:00:00' GROUP BY `shift_id` ORDER BY `orders_counter` desc + $shifts = ExchangeOrders::where('is_closed', '>', 0) + ->where('opened', '>', '2021-01-01 00:00:00') + ->get() + ->unique('shift_id'); + foreach ($shifts as $key => $shift) { + $shift_id = $shift['shift_id']; + $shift_order_count = ExchangeOrders::where('shift_id', '=', $shift_id)->count(); + $shift_order_sum = ExchangeOrders::where('shift_id', '=', $shift_id)->sum('order_sum'); + $shift_date = ExchangeOrders::where('shift_id', '=', $shift_id)->first(); + $tr_m = ['Нулябрь' /* для сдвига индекса на +1*/, 'Января', 'Февраля', 'Марта', 'Апреля', 'Мая', 'Июня', 'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря']; + $exp_date = getdate(strtotime($shift_date['opened'])); + $full_datedate = sprintf( + '%d %s %d', + $exp_date['mday'], + $tr_m[$exp_date['mon']], + $exp_date['year'] + ); + $shift_counter[] = array('shift_id' => $shift_id, 'count' => $shift_order_count, 'date' => $full_datedate, 'sum' => $shift_order_sum); + } + for ($i = 0; $i < count($shift_counter); $i++) { + $shift_counter_sortkey[$i] = $shift_counter[$i]['count']; + } + arsort($shift_counter_sortkey); + foreach ($shift_counter_sortkey as $key => $key) { + $shift_counter_sorted[] = $shift_counter[$key]; + } + $shift_counter_sorted = array_slice($shift_counter_sorted, 0, 1); + //End top day + + //Return data + $data = [ + 'status' => 'success', + 'count' => $count, + 'dishes' => $sorted, + 'top_shift' => $shift_counter_sorted, + ]; + $handle = fopen($dirname . $filename, 'w+'); + fputs($handle, json_encode($data)); + fclose($handle); + return $data; + } else { + return [ + 'status' => 'success', + 'count' => 0, + 'dishes' => [], + ]; + } + } else { + $data = json_decode(file_get_contents($dirname . $filename), true); + return $data; + } + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 85bb73c..af7ee00 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "hrc-admin/hello-world", - "version": "2.2", + "version": "2.3", "require": { "horeca/admin-php-module-core": "dev-master" }, diff --git a/models/ExchangeItems.php b/models/ExchangeItems.php new file mode 100644 index 0000000..0bb71f3 --- /dev/null +++ b/models/ExchangeItems.php @@ -0,0 +1,9 @@ + payment.name); + $scope.payments.data = data.payments.map(payment => payment.value); + }); + + smartRequest.get('dashboard/online/orders', function (data) { + var total = data.wait_count + data.closed_count + data.deleted_count + data.returned_count; + + $scope.orders_closed.percent = $scope.calcPercentageForGroupOrders(total, data.closed_count); + $scope.orders_closed.total = data.closed_count; + $scope.orders_closed.sum = data.closed_sum; + + $scope.orders_waited.percent = $scope.calcPercentageForGroupOrders(total, data.wait_count); + $scope.orders_waited.total = data.wait_count; + $scope.orders_waited.sum = data.wait_sum; + + $scope.orders_deleted.percent = $scope.calcPercentageForGroupOrders(total, data.deleted_count); + $scope.orders_deleted.total = data.deleted_count; + $scope.orders_deleted.sum = data.deleted_sum; + + $scope.orders_returned.percent = $scope.calcPercentageForGroupOrders(total, data.returned_count); + $scope.orders_returned.total = data.returned_count; + $scope.orders_returned.sum = data.returned_sum; + }); + + smartRequest.get('dashboard/online/middle', function (data) { + $scope.middle = data.middle_check; + }); + + smartRequest.get('dashboard/online/total', function (data) { + $scope.total = data.total; + }); + + smartRequest.get('dashboard/online/staff', function (data) { + $scope.personals = data.staff; + }); + + smartRequest.get('v1/topdishes', function (data) { + $scope.dishes = data.dishes; + }); + + smartRequest.get('dashboard/online/folders', function (data) { + $scope.folders.labels = data.folders.map(folder => folder.name); + $scope.folders.data = data.folders.map(folder => Math.roundClearNG(folder.count)); + }); + + smartRequest.get('dashboard/online/printers', function (data) { + $scope.printers.labels = []; + $scope.printers.data = []; + + for (var i = 0; i < data.printers.length; i++) { + $scope.printers.labels.push(data.printers[i].name); + $scope.printers.data.push(Math.roundClearNG(data.printers[i].count, -2)); + } + }); + + smartRequest.get('dashboard/online/tables', function (data) { + $scope.tables = data.tables; + }); + + smartRequest.get('dashboard/online/menu', function (data) { + $scope.menus.labels = []; + $scope.menus.data = []; + + for (var i = 0; i < data.menus.length; i++) { + $scope.menus.labels.push(data.menus[i].menu_name); + $scope.menus.data.push(Math.roundClearNG(data.menus[i].count, -2)); + } + }); + + smartRequest.get('dashboard/online/profit', function (data) { + $scope.profit = data.profit; + }); + + smartRequest.get('dashboard/online/guests', function (data) { + $scope.guests = data.guestsCount; + $scope.namedGuests = data.namedGuests; + $scope.sumNamedGuests = data.totalSum; + }); + + smartRequest.get('dashboard/online/deleted', function (data) { + $scope.deleted = Math.roundNG(data.count, -2); + $scope.deleted_sum = Math.roundNG(data.sum, -2); + }); + + smartRequest.get('dashboard/online/discount', function (data) { + $scope.discounts = Math.roundNG(data.count, -2); + $scope.discounts_sum = Math.roundNG(data.sum, -2); + $scope.tot_disc_sum = Math.roundNG(data.total_sum, -2); + }); + + smartRequest.get('dashboard/online/guests/median', function (data) { + $scope.medianGuests.labels = []; + $scope.medianGuests.data = [[]]; + + var tempData = []; + var tempTime = []; + for (var i = 0; i < data.data.length; i++) { + var newDate = $scope.getMomentDate(data.data[i].time); + + tempData.push(parseInt(data.data[i].count)); + tempTime.push(newDate); + + var indexTime = $scope.getIntervals(tempTime[i], $scope.medianGuests.labels); + + if (indexTime == -1) { + $scope.medianGuests.labels.push(tempTime[i]); + $scope.medianGuests.data[0].push(tempData[i]); + } else { + $scope.medianGuests.data[0][indexTime] += tempData[i]; + } + } + }); + + smartRequest.get('dashboard/online/finance/median', function (data) { + $scope.medianFinance.labels = []; + $scope.medianFinance.data = [[], [], []]; + + var tempSum = []; + var tempTotalCost = []; + var tempProffit = []; + var tempTime = []; + + for (var i = 0; i < data.data.length; i++) { + var newDate = $scope.getMomentDate(data.data[i].time); + + tempSum.push(data.data[i].sum); + tempTotalCost.push(data.data[i].totalCost); + var proffit = parseFloat((tempSum[i] - tempTotalCost[i]).toFixed(2)); + tempProffit.push(proffit); + tempTime.push(newDate); + + var indexTime = $scope.getIntervals(tempTime[i], $scope.medianFinance.labels); + + $scope.fillMedianFinance(indexTime, tempTime[i], tempSum[i], tempTotalCost[i], tempProffit[i]); + } + + for (var i = 0; i < $scope.medianFinance.data.length; i++) { + for (var j = 0; j < $scope.medianFinance.data[i].length; j++) { + var data = $scope.medianFinance.data[i][j]; + data = Math.round(data * 100) / 100; + $scope.medianFinance.data[i][j] = data; + } + } + }); + + $scope.checkUpdate(); + }; + + $scope.update(); + + $scope.ping = function () { + let stop = $interval(function () { + if($location.url() == '/dashboard') { + smartRequest.get('dashboard/ping', function (data) { + $scope.need_update = data.data.update; + + if (!$scope.need_update) { + $scope.update(); + $interval.cancel(stop); + } + }); + } + }, 10000); + }; + + $scope.ping(); + + $scope.all_widgets = []; + $scope.add = function () { + smartRequest.get('settings/widgets/all', function (data) { + $scope.all_widgets = data.widgets; + }); + + $('#add-widget').modal(); + }; + + $scope.calcPercentageForGroupOrders = function (total, countOrdersGroup) { + return total > 0 ? Math.round(countOrdersGroup * 100 / total) : 0; + }; + + + $scope.addWidget = function () { + $('#add-widget').modal('toggle'); + + smartRequest.post('settings/widgets/enable', { + code: $scope.add_widget_code + }, function (data) { + $scope.update(); + }); + }; + + $scope.deleteWidget = function (code) { + smartRequest.post('settings/widgets/disable', { + code: code + }, function (data) { + $scope.update(); + }); + }; + + $scope.getMomentDate = function (date_str) { + var date = moment(date_str, 'DD.MM.YYYY HH:mm:ss'); + var remainder = 30 - (date.minute() % 30); + return moment(date).add(remainder, 'minutes').set('second', 0); + }; + + $scope.getIntervals = function (momentTime, array) { + for (var i = 0; i < array.length; i++) { + var time = array[i]; + if (time.get('hour') == momentTime.get('hour') && time.get('minute') == momentTime.get('minute')) { + return i; + } + } + return -1; + }; + + + $scope.fillMedianFinance = function (index, time, sum, totalCost, proffit) { + if (index == -1) { + $scope.pushToMedianFinance(time, sum, totalCost, proffit); + } else { + $scope.incMedianFinance(index, sum, totalCost, proffit); + } + }; + + $scope.pushToMedianFinance = function (time, sum, totalCost, proffit) { + $scope.medianFinance.labels.push(time); + $scope.medianFinance.data[0].push(sum); + $scope.medianFinance.data[1].push(totalCost); + $scope.medianFinance.data[2].push(proffit); + }; + + $scope.incMedianFinance = function (index, sum, totalCost, proffit) { + $scope.medianFinance.data[0][index] += sum; + $scope.medianFinance.data[1][index] += totalCost; + $scope.medianFinance.data[2][index] += proffit; + }; + + $scope.getMore = function (code) { + smartRequest.get('dashboard/more/' + code, function (data) { + $scope.moreData = data; + $('#get-more-' + code).modal(); + }); + }; + + $scope.getItems = function (modal, order) { + $('#get-more-' + modal).modal('toggle'); + smartRequest.get('dashboard/' + modal + '/items?order=' + order.number, function (data) { + $scope.order = data; + $('#items-' + modal).modal('toggle'); + }); + }; + + $scope.returnModal = function (name) { + $('#items-' + name).on('hidden.bs.modal', function (event) { + $('#get-more-' + name).modal('show'); + }); + }; + + $scope.getStaffMore = function (staff) { + smartRequest.get('dashboard/more/staff?code=' + staff.code, function (data) { + $scope.staff = data; + $('#get-more-staff').modal('toggle'); + }); + }; + + $scope.getTableMore = function (table) { + smartRequest.get('dashboard/more/table?place=' + table.place_name + '&table=' + table.table_name, function (data) { + $scope.table_ord = data; + $('#get-more-table').modal('toggle'); + }); + }; + + $scope.getClosedDate = function (closeTime) { + if (closeTime == '30.12.1899') + return $scope.NOT_CLOSED; + return closeTime; + }; + + $scope.getBackClass = function (percentProffit) { + if (percentProffit <= 25) { + return 'green-600'; + } else if (percentProffit <= 35) { + return 'green'; + } else if (percentProffit <= 50) { + return ''; + } else if (percentProffit <= 100) { + return 'red'; + } + }; + + var declOfNum = function (titles, number) { + number = Math.abs(number); + var cases = [2, 0, 1, 1, 1, 2]; + return function (number) { + return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]]; + }; + }; + + $scope.GetCountNamedGuests = declOfNum(['именованный гость', 'именованных гостя', 'именованных гостей']); + $scope.GetCountDeletedPositions = declOfNum(['позиций', 'позиции', 'позиций']); + $scope.GetCountTotalOrders = declOfNum(['заказ', 'заказа', 'заказов']); + } + +})(); diff --git a/web/menu_min.js b/web/menu_min.js index e69de29..25e3f5d 100644 --- a/web/menu_min.js +++ b/web/menu_min.js @@ -0,0 +1,9 @@ +group_name: 'HRC', +item: [ + { + name: 'Рабочий стол', + url: 'app.dashboard', + icon: 'dashboard', + order: 0 + } +]; \ No newline at end of file diff --git a/web/routes_min.js b/web/routes_min.js index 43e4b7d..38b3a09 100644 --- a/web/routes_min.js +++ b/web/routes_min.js @@ -1,3 +1,11 @@ +{ + code: 'app.dashboard', + url: '/dashboard', + templateUrl: '../views/dashboard/dashboard.html', + data : { title: 'Рабочий стол' }, + controller: 'DashboardCtrl', + resolve: ['scripts/controllers/dashboard.js', 'chart'] +}, { code: 'app.v1.reimport', url: '/v1/reimport', diff --git a/web/views/dashboard/add.html b/web/views/dashboard/add.html new file mode 100644 index 0000000..087796e --- /dev/null +++ b/web/views/dashboard/add.html @@ -0,0 +1,19 @@ +
| ФИО | +Количество заказов | +Сумма, BYN | +
| + {{ personal.name }} + | +{{ personal.orders_count }} | +{{ personal.orders_sum | curr}} | +
| + | Кол-во | +Сумма,
+ BYN |
+ Total cost,
+ BYN |
+ Total cost /
+ Сумма |
+ Прибыль,
+ BYN |
+
|---|---|---|---|---|---|
| + {{ dish.name }} + | +{{ dish.count }} | +{{ dish.sum | curr}} | +{{ dish.totalCost | curr}} | +{{ dish.percentProffit }} % | +{{ dish.proffit | curr}} | +
Занятых столов нет
+ +| Зал | +Номер стола | +Количество заказов | +Сумма, BYN | +
|---|---|---|---|
| + {{ table.place_name }} + | ++ {{ table.table_name }} + | +{{ table.guests_count }} | +{{ table.sum | curr}} | +