Формирование сводного отчета о фактическом потреблении ресурсов и их стоимости#
Для формирования сводного отчета необходимо выполнить следующие действия:
Выбрать пункт основного меню слева Провайдер — Компании.
Выбрать компанию и нажать на кнопку Изменить.
В окрывшемся окне Редактирование компании в поле Шаблон акта отображается наименование шаблона, заданного для печати. Если шаблон не задан, выбрать шаблон Русский акт или УПД из списка шаблонов.
Перейти в пункт основного меню слева Настройки — Шаблоны документов.
В открывшемся окне Шаблоны документов выбрать ранее заданный шаблон и нажать на кнопку Изменить.
В открывшемся окне Редактирование шаблона документа очистить содержание блока Содержимое шаблона документа и вставить нижеприведенный фрагмент кода.
Фрагмент кода
<% /* ------------------------------------------------------------------ Отчет о фактическом потреблении ресурсов и их стоимости (сводный) ------------------------------------------------------------------ */ function findu(data) { return (data && data != '') ? data : ''; } function obj(v) { if (v && v.constructor === Array) { for (var i = v.length - 1; i >= 0; i--) { if (v[i] && typeof v[i] == 'object') { return v[i]; } } return {}; } return (v && typeof v == 'object') ? v : {}; } function rusdate(date) { if (!date || date == '') { return ''; } var month = { '01': 'января', '02': 'февраля', '03': 'марта', '04': 'апреля', '05': 'мая', '06': 'июня', '07': 'июля', '08': 'августа', '09': 'сентября','10': 'октября','11': 'ноября', '12': 'декабря' }; var c = date.split(' ')[0].split('-'); return c[2] + ' ' + month[c[1]] + ' ' + c[0] + ' г.'; } function rusdatemonth(date) { if (!date || date == '') { return ''; } var month = { '01': 'январь', '02': 'февраль', '03': 'март', '04': 'апрель', '05': 'май', '06': 'июнь', '07': 'июль', '08': 'август', '09': 'сентябрь','10': 'октябрь','11': 'ноябрь', '12': 'декабрь' }; var c = date.split(' ')[0].split('-'); return month[c[1]]; } function rusdatetime(date) { if (!date || date == '') { return ''; } var parts = date.split(' '); var c = parts[0].split('-'); return c[2] + '.' + c[1] + '.' + c[0] + (parts[1] ? ' ' + parts[1] : ''); } function money(n) { var v = parseFloat(n); if (isNaN(v)) { return '-'; } var s = v.toFixed(2).split('.'); return s[0].replace(/\B(?=(\d{3})+(?!\d))/g, ' ') + ',' + s[1]; } function num(n) { var v = parseFloat(n); return isNaN(v) ? '-' : String(v); } function itemList(invoice) { if (!invoice.items || !invoice.items.item) { return []; } return [].concat(invoice.items.item); } function serviceName(item) { var name = String(item.name).replace(/\s+/g, ' ').trim(); if (name.indexOf(' - ') > -1) { return name.split(' - ')[0].trim(); } var m = name.match(/^([^#(,]+)/); return m ? m[1].trim() : name; } function resourceName(item) { var name = String(item.name).replace(/\s+/g, ' ').trim(); var tail = name.match(/\(([^()]*#\d+[^()]*)\)\s*$/); if (tail) { return tail[1].trim(); } var body = name.indexOf(' - ') > -1 ? name.split(' - ').slice(1).join(' - ') : name; body = body.replace(/\s*\([^()]*\)/g, ' '); body = body.split(',')[0]; return body.replace(/\s+/g, ' ').trim(); } function resourceId(item) { var name = String(item.name).replace(/\s+/g, ' ').trim(); var m = name.match(/#\s*(\d+)/); if (m) { return m[1]; } m = name.match(/\(([^()]+)\)/); return m ? m[1].trim() : '-'; } function vdcRef(item) { var name = String(item.name).replace(/\s+/g, ' ').trim(); var ref = ''; var paren = name.match(/\(([^()]*#\s*\d+[^()]*)\)/); if (paren) { ref = paren[1].trim(); } else { ref = name.split(',')[0].trim(); } var m = ref.match(/#\s*(\d+)/); var id = m ? m[1] : ''; var title = ref.replace(/\s*#\s*\d+.*$/, '').trim(); return { id: id, name: title, ref: ref }; } function isAddon(item) { return /дополнительн/i.test(String(item.name)); } function addonMeasure(item) { var name = String(item.name).replace(/\s+/g, ' ').trim(); var idx = name.indexOf(' - '); if (idx < 0) { return null; } var after = name.slice(idx + 3).split('(')[0].trim(); /* "112 ГиБ" */ var m = after.match(/^([\d]+(?:[.,][\d]+)?)\s*(.*)$/); if (!m) { return null; } var qty = parseFloat(m[1].replace(',', '.')); return { qty: isNaN(qty) ? null : qty, unit: (m[2] || '').trim() }; } function unitName(item) { if (isAddon(item)) { var a = addonMeasure(item); if (a && a.unit) { return a.unit; } } var name = String(item.name); var m = name.match(/,\s*([^,]+)\s*$/); if (m && !/#/.test(m[1])) { return m[1].trim(); } return 'шт.'; } function itemCost(item) { return parseFloat(item.notaxamount) || 0; } function itemQty(item) { /* доп. услуга -> количество из наименования, иначе из <quantity> */ if (isAddon(item)) { var a = addonMeasure(item); if (a && a.qty != null && a.qty != 0) { return a.qty; } } var q = parseFloat(item.quantity); return (isNaN(q) || q == 0) ? 1 : q; } function itemPrice(item) { return itemCost(item) / itemQty(item); } var VDC_TITLES = { 'vds': 'Виртуальный дата-центр (VDC)', 'vdc': 'Виртуальный дата-центр (VDC)' }; function buildVdcList(invoice) { var items = itemList(invoice); var order = [], map = {}; for (var i = 0; i < items.length; i++) { var it = items[i]; var key, title, id; if (findu(it.vdc_id) != '') { key = 'id:' + it.vdc_id; id = String(it.vdc_id); title = findu(it.vdc_name) != '' ? it.vdc_name : id; } else { var r = vdcRef(it); if (r.id != '') { key = 'num:' + r.id; id = r.id; title = r.name != '' ? r.name : ('№ ' + r.id); } else { var st = findu(it.servicetype) != '' ? String(it.servicetype) : 'other'; key = 'type:' + st; id = '-'; title = VDC_TITLES[st] || st; } } if (!map[key]) { map[key] = { name: title, id: id, items: [], cost: 0 }; order.push(key); } map[key].items.push(it); map[key].cost += itemCost(it); } var res = []; for (var j = 0; j < order.length; j++) { res.push(map[order[j]]); } return res; } /* --- Сводка по услугам ------------------------------------------------ */ function buildServiceList(invoice) { var items = itemList(invoice); var order = [], map = {}; for (var i = 0; i < items.length; i++) { var it = items[i]; var key = serviceName(it); if (!map[key]) { map[key] = { name: key, qty: 0, cost: 0, unit: unitName(it) }; order.push(key); } map[key].qty += itemQty(it); map[key].cost += itemCost(it); } var res = []; for (var j = 0; j < order.length; j++) { var s = map[order[j]]; s.price = s.qty ? s.cost / s.qty : 0; res.push(s); } return res; } function contractNumber(invoice) { if (invoice.contracts && invoice.contracts.contract) { var list = [].concat(invoice.contracts.contract), out = []; for (var i = 0; i < list.length; i++) { out.push(list[i].number + (findu(list[i].signdate) != '' ? ' от ' + rusdate(list[i].signdate) : '')); } if (out.length) { return out.join(', '); } } return findu(invoice.contract) != '' ? invoice.contract : '-'; } var customer = obj(invoice.customer); var company = obj(invoice.company); var services = buildServiceList(invoice); var vdcs = buildVdcList(invoice); var servicesTotal = 0; for (var si = 0; si < services.length; si++) { servicesTotal += services[si].cost; } var vdcTotal = 0; for (var vi = 0; vi < vdcs.length; vi++) { vdcTotal += vdcs[vi].cost; } var grandTotal = (findu(invoice.notaxamount) != '' && invoice.notaxamount != '-') ? parseFloat(invoice.notaxamount) : servicesTotal; %> <style media="screen, print" type="text/css"> @page { margin: 0.5cm 0.5cm 0.5cm 0.5cm; } #res-report .page-a4-landscape { margin: 0px; width: 29.7cm; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 8pt; color: #000; } #res-report table.rep { border-collapse: collapse; clear: left; margin: 0px; width: 100%; } #res-report table.rep.grid { border: solid 1px #000; } #res-report td { font-size: 8pt; padding: 2px 3px 2px 4px; vertical-align: top; } #res-report th { font-size: 8pt; padding: 2px 3px; text-align: center; border: solid 1px #000; font-weight: bold; } #res-report td.b { border: solid 1px #000; } #res-report td.bt { border-top: solid 1px #000; } #res-report td.br { border-right: solid 1px #000; } #res-report td.bb { border-bottom: solid 1px #000; } #res-report td.bl { border-left: solid 1px #000; } #res-report td.tright { text-align: right; } #res-report td.tcenter { text-align: center; } #res-report td.bold { font-weight: bold; } #res-report td.small { font-size: 6pt; } #res-report .title { font-size: 10pt; font-weight: bold; text-align: center; padding: 6px 0px 10px 0px; } #res-report .caption { font-size: 10pt; font-weight: bold; text-align: center; padding-bottom: 8px; } #res-report .hdr-lbl { text-align: right; white-space: nowrap; padding-right: 4px; } #res-report .hdr-val { text-align: left; } #res-report .box { border: solid 1px #000; min-width: 8cm; height: 0.55cm; } #res-report .section { padding: 10px 0px 3px 0px; font-weight: bold; } #res-report .spacer { height: 0.5cm; } </style> <div id="res-report"> <center> <div class="page-a4-landscape"> <div class="caption">Макет отчета (сводный)</div> <!-- ================= Шапка отчета ================= --> <table class="rep grid"> <tr> <td colspan="2" class="title"> Отчет о фактическом потреблении ресурсов и их стоимости за <%= findu(invoice.cdate) != '' ? rusdatemonth(invoice.cdate) : 'месяц' %> <%= findu(invoice.cdate) != '' ? invoice.cdate.split('-')[0] : '20__' %> (сводный) </td> </tr> <tr> <td class="hdr-lbl" style="width: 50%;">Аккаунт:</td> <td class="hdr-val"><%= findu(customer.account) %></td> </tr> <tr> <td class="hdr-lbl">Отчетный период:</td> <td class="hdr-val"><%= rusdatetime(invoice.fromdate) %> – <%= rusdatetime(invoice.todate) %></td> </tr> <tr> <td class="hdr-lbl">Компания:</td> <td class="hdr-val"><%= findu(customer.name) %></td> </tr> <tr> <td class="hdr-lbl">Номер договора:</td> <td class="hdr-val"><%= contractNumber(invoice) %></td> </tr> <tr> <td class="hdr-lbl">Дата/время формирования отчета:</td> <td class="hdr-val"><%= rusdatetime(invoice.cdate) %></td> </tr> <tr> <td class="hdr-lbl bold">Итого за начислено за период, руб. без НДС:</td> <td class="hdr-val"> <table class="rep"><tr><td class="b bold" style="width: 8cm;"><%= money(grandTotal) %></td><td></td></tr></table> </td> </tr> </table> <div class="spacer"></div> <!-- ================= Сводка по услугам ================= --> <table class="rep grid"> <tr> <th style="width: 40%;">Наименование услуги</th> <th style="width: 9%;">Цена</th> <th style="width: 9%;">Количество</th> <th style="width: 7%;">Ед.изм.</th> <th style="width: 13%;">Стоимость без НДС, руб.</th> </tr> <% for (var i = 0; i < services.length; i++) { %> <tr> <td class="b"><%= services[i].name %></td> <td class="b tright"><%= money(services[i].price) %></td> <td class="b tcenter"><%= num(services[i].qty) %></td> <td class="b tcenter"><%= services[i].unit %></td> <td class="b tright"><%= money(services[i].cost) %></td> </tr> <% } %> <tr> <td class="b tright bold" colspan="4">Итого по услугам:</td> <td class="b tright bold"><%= money(servicesTotal) %></td> </tr> </table> <div class="spacer"></div> <!-- ================= Сводка по дата-центрам (VDC) ================= --> <table class="rep grid"> <tr> <th style="width: 40%;">Наименование дата-центра (VDC)</th> <th style="width: 32%;">Идентификатор дата-центра (VDC)</th> <th style="width: 14%;"> </th> <th style="width: 14%;">Стоимость без НДС, руб.</th> </tr> <% for (var v = 0; v < vdcs.length; v++) { %> <tr> <td class="b"><%= vdcs[v].name %></td> <td class="b tcenter"><%= vdcs[v].id %></td> <td class="b"></td> <td class="b tright"><%= money(vdcs[v].cost) %></td> </tr> <% } %> <tr> <td class="b tright bold" colspan="3">Итого по дата-центрам (VDC):</td> <td class="b tright bold"><%= money(vdcTotal) %></td> </tr> </table> <!-- ================= Детализация по каждому VDC ================= --> <% for (var v = 0; v < vdcs.length; v++) { %> <% var vitems = vdcs[v].items; %> <table class="rep"> <tr> <td class="section"><%= v + 1 %>. Детализация услуг по дата-центру (VDC): <%= vdcs[v].name %> (<%= vdcs[v].id %>)</td> </tr> </table> <table class="rep grid"> <tr> <th style="width: 26%;">Наименование услуги</th> <th style="width: 24%;">Наименование ресурса</th> <th style="width: 14%;">Идентификатор ресурса</th> <th style="width: 9%;">Цена</th> <th style="width: 9%;">Количество</th> <th style="width: 7%;">Ед.изм.</th> <th style="width: 13%;">Стоимость без НДС, руб.</th> </tr> <% for (var i = 0; i < vitems.length; i++) { %> <tr> <td class="b"><%= serviceName(vitems[i]) %></td> <td class="b"><%= resourceName(vitems[i]) %></td> <td class="b tcenter"><%= resourceId(vitems[i]) %></td> <td class="b tright"><%= money(itemPrice(vitems[i])) %></td> <td class="b tcenter"><%= num(itemQty(vitems[i])) %></td> <td class="b tcenter"><%= unitName(vitems[i]) %></td> <td class="b tright"><%= money(itemCost(vitems[i])) %></td> </tr> <% } %> <tr> <td class="b tright bold" colspan="6">Итого по дата-центру (VDC):</td> <td class="b tright bold"><%= money(vdcs[v].cost) %></td> </tr> </table> <% } %> </div> </center> </div>
Нажать на кнопку Сохранить.
Перейти в пункт основного меню слева Финансы — Акт вып. работ.
В открывшемся окне Акты выполненных работ выбрать акт и нажать на кнопку Печать или Скачать.
После выполнения вышеописанных действий откроется отчет следующего вида: