Compare commits

...
45 Commits
Author SHA1 Message Date
smishchuk 7ac2c85238 064 interface improvements 2026-07-28 14:28:27 +03:00
smishchuk d9de157635 064 queries optimized 2026-07-28 13:14:02 +03:00
smishchuk 164771bf78 063 cache bug fix 2026-07-28 10:59:21 +03:00
smishchuk 86500c8630 062 ­ excel fix 2026-07-27 10:42:56 +03:00
smishchuk b7d030567f 061 cfflush fix for file export 2026-07-27 10:36:31 +03:00
smishchuk 132acd7287 060 cyrillic fix 2026-07-26 23:33:20 +03:00
smishchuk 274643ed28 059 inmem full join with spec 2026-07-26 23:01:27 +03:00
smishchuk 59bf109ba5 058 manager 2026-07-22 13:27:09 +03:00
smishchuk 228023ba49 057 orrganization_status 2026-07-02 19:34:41 +03:00
smishchuk 6c952ca443 056 bugfix vms_on 2026-07-01 20:59:45 +03:00
smishchuk 8c5ddd2ae4 055 vm storage comments 2026-07-01 18:01:20 +03:00
smishchuk b7bc2388be 055 vm storage 2026-07-01 17:56:25 +03:00
smishchuk 07c09ba782 054 vsan free 2026-07-01 17:13:43 +03:00
smishchuk a2625d125f 054 minor fix 2026-06-30 21:26:01 +03:00
smishchuk 02e5a63572 052 capacity section 2026-06-30 17:41:10 +03:00
smishchuk 0b33a5a29e 052 capacity section 2026-06-30 17:40:26 +03:00
smishchuk 776abc1cc3 52 utilization and bugfixes 2026-06-29 16:11:34 +03:00
smishchuk 1f7ea5c3b1 051 cloud_capacity division by zero 2026-06-18 11:41:59 +03:00
smishchuk f1e4ee238e 50 comments 2026-05-07 10:31:26 +03:00
smishchuk 373514da34 49 promised removed from report 2026-05-06 21:17:16 +03:00
smishchuk df4abb6969 48 null bug fix 2026-05-06 21:15:12 +03:00
smishchuk fcde490da1 047 versioning fix 2026-04-29 12:42:04 +03:00
smishchuk 2a3cf0482f 046 versioning fixes 2026-04-28 13:28:26 +03:00
smishchuk c9a229cc8e 045 gpu 2026-04-17 15:02:54 +03:00
smishchuk 2e0b71cf3f tests found 2026-04-15 14:07:39 +03:00
smishchuk ade4071eb8 43 speed and filter and totals 2026-04-13 23:18:41 +03:00
smishchuk 515b6cd90d 042 visual improvements 2026-04-07 20:44:04 +03:00
smishchuk aca4f461d5 041 shy in excel export fix 2026-04-07 19:55:22 +03:00
smishchuk 721a4da90d 040 maajor improvements 2026-04-07 19:46:43 +03:00
smishchuk a35f5a3ba2 039 cpu usage fix sockets discarded 2026-04-07 10:35:46 +03:00
smishchuk 990d678c14 038 cpu usage resaerch 2026-04-07 08:35:08 +03:00
smishchuk 8137eeb219 037 improvements 2026-04-06 15:47:56 +03:00
smishchuk 20fe4ad2fc 036 cache, capacity 2026-04-03 20:26:40 +03:00
smishchuk 05afe5d68c 035 table margins 2026-04-03 10:31:18 +03:00
smishchuk 77bbc60fed 034 alpha 2026-04-03 09:58:39 +03:00
smishchuk 353f5ce5c2 033 improvements 2026-04-02 18:31:08 +03:00
smishchuk 997813d115 032 zero quantity components filtered out 2026-03-30 13:24:19 +03:00
smishchuk ccf511afe5 031 minor improvement 2026-03-30 10:41:34 +03:00
smishchuk e1ca12fb2e 030 change version select fix dt_to add sort 2026-03-30 10:27:28 +03:00
smishchuk e303bbdd03 018 select fix dt_to 2026-03-30 09:05:59 +03:00
smishchuk 8187db1ea3 029 reconciliation 2026-03-25 14:08:34 +03:00
smishchuk 6d06a68ad8 028 ds fix 2025-12-12 12:34:11 +03:00
smishchuk fc3eb36c7c 127 fix 2025-12-11 16:25:15 +03:00
smishchuk c7986e3385 126 tenant metadata 2025-12-11 15:39:53 +03:00
smishchuk ce44051801 025 interface imptovements 2025-10-14 15:14:14 +03:00
40 changed files with 4077 additions and 817 deletions
+37 -30
View File
@@ -6,7 +6,7 @@
<!--- Set up the application. --->
<cfset this.Name = "PAYG" />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 3, 0 ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 1, 0, 0 ) />
<cfset this.sessionmanagement="Yes"/>
<cfset this.clientmanagement="No"/>
<cfset this.sessiontimeout=CreateTimeSpan(0, 0, 120, 0)/>
@@ -22,15 +22,26 @@
<cfset this.datasources["#this.datasource#"]=getDS("#this.datasource#","ds_#this.datasource#")/>
<cfset this.datasources["billing-vc"]=getDS("billing-vc","ds_billing_vc")/>
<cfset this.datasources["billing-s3"]=getDS("billing-s3","ds_billing_s3")/>
<!--- но датасорцы таинственно прочухались с прошлым пушем, без переноса инициализации в псевдоконструктор --->
<!--- а потом опять... --->
<cfset this.datasources["inmem"] = {
class: "org.hsqldb.jdbcDriver",
// Внимание наjdbc:hsqldb:mem:
connectionString: "jdbc:hsqldb:mem:lucee_mem;shutdown=false",
username: "sa",
password: "",
// Защита от "висяка" и исчезновения базы:
// заставляем Lucee держать минимум 1 коннект открытым всегда
connectionLimit: 5,
connectionMin: 1
}
/><!--- inmemory DB --->
<cfset COOKIEENCKEY = "PREVED!Y2"/>
<!--- Define the page request properties. --->
<cfsetting
requesttimeout="20"
requesttimeout="45"
showdebugoutput="false"
enablecfoutputonly="false"
/>
@@ -68,8 +79,6 @@
The API token is available in your personal configuration page. Click your name on the top right corner on every page, then click "Configure" to see your API token. (The URL $root/me/configure is a good shortcut.) You can also change your API token from here.
--->
<cfset request.UNDEFINED_USR_ID=-1/>
<!--- request.ROOT_USR_ID=1 not used --->
<cfset request.ANONYMOUS_USR_ID=2/>
@@ -77,35 +86,35 @@
<!--- global settings --->
<!--- <cfdump var=#GetApplicationSettings()#/> --->
<!--- <cfif !structKeyExists(GetApplicationSettings().datasources,"#this.datasource#")>
<cfset this.datasources["#this.datasource#"]=getDS("#this.datasource#","ds_#this.datasource#")/>
</cfif>
<!--- неуклюжий выверт для локальной отладки --->
<cfif !structKeyExists(this.datasources,"billing-vc")>
<cfset this.datasources["billing-vc"]=getDS("billing-vc","ds_billing_vc")/>
</cfif>
<cfif !structKeyExists(this.datasources,"billing-s3")>
<cfset this.datasources["billing-s3"]=getDS("billing-s3","ds_billing_s3")/>
</cfif> --->
<!--- <cfdump var=#this.datasources#/> --->
<cfset request.RECORDS_PER_PAGE=500/>
<cfset request.APP_VERSION="0.00.025"/>
<cfset request.APP_VERSION="0.00.065"/>
<cfset request.STAND=getStand()/>
<cflock scope="application" type="readonly" timeout=3>
<cfset request.APP_NAME=this.Name/>
</cflock>
<!--- <cfdump var=#GetApplicationSettings()#/> --->
<!--- неуклюжий выверт для локальной отладки --->
<!--- <cfif !structKeyExists(GetApplicationSettings().datasources,"#this.datasource#")>
<cfset this.datasources["#this.datasource#"]=getDS("#this.datasource#","ds_#this.datasource#")/>
</cfif>
<cfif !structKeyExists(this.datasources,"billing-vc")>
<cfset this.datasources["billing-vc"]=getDS("billing-vc","ds_billing_vc")/>
</cfif>
<cfif !structKeyExists(this.datasources,"billing-s3")>
<cfset this.datasources["billing-s3"]=getDS("billing-s3","ds_billing_s3")/>
</cfif> --->
<!--- <cfset this.datasources["#this.datasource#"]=getDS("#this.datasource#","ds_#this.datasource#")/>
<cfset this.datasources["billing-vc"]=getDS("billing-vc","ds_billing_vc")/>
<cfset this.datasources["billing-s3"]=getDS("billing-s3","ds_billing_s3")/> --->
<!--- <cfdump var=#this.datasources#/> --->
<!--- application constants --->
<!---<cfset request.SMTP_SERVER="172.16.16.16"/>
@@ -262,8 +271,6 @@
</cfif>
</cfif>
<cfreturn />
</cffunction>
+98
View File
@@ -0,0 +1,98 @@
component {
/**
* HSQL 1.8
* Принимает Lucee Query, создает в HSQL временную таблицу и льет в нее данные
* @name Имя таблицы, которое ты хочешь использовать в SQL
* @data Сам запрос (результат queryExecute или cfhttp)
* @dsn Имя datasource для HSQL (по умолчанию "inmem")
*/
public string function register(required string name, required query data, string dsn = "inmem") {
var cols = arguments.data.columnList;
var meta = getMetaData(arguments.data);
//writedump(meta);
var colDefs = [];
var colTypes = {};
var params = [];
// 1. Генерируем "CREATE TEMP TABLE name (col1 TYPE, col2 TYPE...)"
for (var i = 1; i <= arrayLen(meta); i++) {
var colName = meta[i].name;
// Маппинг типов Lucee -> типы H2
var dbType = mapType(meta[i].typeName);
arrayAppend(colDefs, "#colName# #dbType#");
colTypes[colName] = meta[i].typeName;
}
//writedump(colDefs);
//var checkSql = "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_TABLES WHERE TABLE_NAME = '#ucase(arguments.name)#';"
//var res = queryExecute(checkSql, {}, { datasource: arguments.dsn });
//if (res.recordCount EQ 0) {
var createSql = "DROP TABLE IF EXISTS #arguments.name#;
CREATE TEMPORARY TABLE #arguments.name#(#arrayToList(colDefs, ', ')#) ON COMMIT PRESERVE ROWS";
queryExecute(createSql, {}, { datasource: arguments.dsn });
//}
// 2. Цикл вставки
var insertSql = "INSERT INTO #arguments.name# (#cols#) VALUES (#repeatString("?,", listLen(cols)-1)#?)";
for (var row in arguments.data) {
var rowData = [];
for (var col in cols) {
arrayAppend(rowData, formatValue(row[col], colTypes[col]));
}
queryExecute(insertSql, rowData, { datasource: arguments.dsn });
}
return arguments.name;
}
/**
* Удалить временные таблицы (опционально, база сама почистит при закрытии коннекта)
*/
public void function drop(required string names, string dsn = "inmem") {
var list = arguments.names;
if (!isArray(list)) list = [list];
for (var name in list) {
queryExecute("DROP TABLE IF EXISTS #name#", {}, { datasource: arguments.dsn });
}
}
// --- Вспомогательная функция маппинга типов ---
private string function mapType(required string luceeType) {
switch (arguments.luceeType) {
case "VARCHAR": case "CHAR": case "LONGVARCHAR": return "LONGVARCHAR";
case "INTEGER": case "BIGINT": case "SMALLINT": case "TINYINT": return "INT";
case "DOUBLE": case "FLOAT": case "REAL": return "DOUBLE";
case "BOOLEAN": case "BIT": return "BIT";
case "DECIMAL": case "NUMERIC": return "DECIMAL(20,6)";
default: return "LONGVARCHAR"; // И тут тоже
}
}
private function formatValue(required any val, required string targetType) {
var isTextType = listFindNoCase("VARCHAR,CHAR,LONGVARCHAR", arguments.targetType);
// 1. Обработка пустых значений
if (isNull(arguments.val) || (isSimpleValue(arguments.val) && len(trim(arguments.val)) == 0)) {
// Если это текстовое поле — сохраняем пустую строку как есть
if (isTextType) {
return "";
}
// Для чисел, дат и булев — отдаем настоящий SQL NULL
return javaCast("null", "");
}
// 2. Форматирование непустых дат
if (listFindNoCase("DATE,TIMESTAMP,TIME", arguments.targetType)) {
return dateFormat(arguments.val, "yyyy-mm-dd") & " " & timeFormat(arguments.val, "HH:mm:ss");
}
// 3. Числа и непустой текст отдаем как есть
return arguments.val;
}
}
+3 -2
View File
@@ -27,6 +27,7 @@
<d:param field="__deletedAt" type="timestamp" forNull=""/> --->
<d:param field="documents" type="ARRAY" forNull=""/>
<d:param field="contract_uid" type="uuid" forNull=""/>
<d:param field="__index" type="integer" forNull="" default="0" init="0"/>
<d:param field="index" type="integer" forNull="" default="0" init="0"/>
<!--- <d:param field="services" type="ARRAY" forNull=""/> --->
<d:param field="is_actual" type="bit" forNull=""/>
@@ -93,7 +94,7 @@
<div class="tr">
<div class="th">__id</div>
<div class="td">#d.__id#</div>
<div class="td">#d.__id# &nbsp;&nbsp;&nbsp;__index #d.__index#</div>
</div>
<div class="tr">
@@ -296,7 +297,7 @@
<td class="c">#dateFormat(date_nop,'YYYY-MM-DD')#</td>
<td class="c">#dateFormat(date_end,'YYYY-MM-DD')#</td>
<td class="c"><cfif is_easy GT 0>Простая<cfelse>Композитная</cfif></td>
<td class="c">#params#</td>
<td>#params#</td>
</tr>
</cfoutput>
</table>
+5 -4
View File
@@ -52,7 +52,7 @@
</cftry>
<cfquery name="qCountTotal" datasource="#request.DS#">
select count(*) as cnt from elma.aggrements d where 1=1
select count(*) as cnt from elma.additional_agreements d where 1=1
</cfquery>
</m:silent><!---
@@ -114,6 +114,7 @@ select count(*) as cnt from elma.aggrements d where 1=1
<cfsavecontent variable="qRead.f_contragent">
<a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#contragent#</a>
<a href="contragent_rpt.cfm?__id=#company_uid#&#tr.fwx#" style="float:right"><img src="img/view.gif" title="сводка по контрагенту"/></a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_deal">
@@ -136,9 +137,9 @@ select count(*) as cnt from elma.aggrements d where 1=1
<c:column width="10%" field="f_deal"/>
<c:column width="15%" field="f_contragent"/>
<c:column width="5%" field="wz"/>
<c:column width="10%" field="date_of_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="10%" field="date_end_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="10%" field="type_of_agreement"><c:td class="l"/></c:column>
<c:column width="5%" field="date_of_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="5%" field="date_end_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="7%" field="type_of_agreement"><c:td class="l"/></c:column>
</c:table>
+148
View File
@@ -0,0 +1,148 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent><m:silent silent="No">
<cffunction name="hideNonPositive">
<cfargument name="a"/>
<cfreturn (a GT 0)? a : ""/>
</cffunction>
<m:prepare_ls entity="additional_agreement" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<!--- <m:filter_settings target="#pageInfo.entity#_ls">
<m:filterparam filter=#filter# param="quickfilter" ftype="string" prefix="%" suffix="%" expression="((p.project like ?) OR (p.customer like ?) OR (p.customer_alias like ?) OR (p.contract_class_type like ?) OR (p.division like ?) OR (p.performer_short like ?))" default=""/>
</m:filter_settings> --->
<!--- <cfset pageInfo.settings.filter=#filter#/> --->
<cftry>
<cfquery name="qRead" datasource="#request.DS#">
select
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
<d:field title="ID" cfSqlType="CF_SQL_OTHER">a.__id</d:field>
<d:field title="Внут.номер">g.agreement_id</d:field>
<d:field title="Доп.соглашение">a.__name</d:field>
<d:field title="Версия">a.index</d:field>
<d:field title="Сделка">d.__name as deal</d:field>
<d:field title="Сделка">d.__id as deal_uid</d:field>
<d:field title="Договор">g.__name as contract</d:field>
<d:field title="Договор">g.__id as contract_uid</d:field>
<d:field title="company_uid">g.company_uid</d:field>
<d:field title="Контрагент">k.__name as contragent</d:field>
<d:field title="WZ">k.id_klienta as wz</d:field>
<d:field title="Дата договора">g.date_of_aggrement</d:field>
<d:field title="Дата окончания">g.date_end_aggrement</d:field>
<d:field title="Тип договора">g.type_of_agreement</d:field>
</d:field_set>
from elma.additional_agreements a
left outer join elma.additional_agreements b on (b.__id=ANY(a.base_by))
left outer join elma.aggrements g on (a.contract_uid=g.__id)
left outer join elma.deals d on (a.deal_uid=d.__id)
left outer join elma.companies k on (g.company_uid=k.__id)
where 1=1 <m:filter_build filter=#pageInfo.settings.filter#/>
order by <m:order_build sortArray=#pageInfo.settings.sort.sortArray# fieldCount=#fieldCount#/>
</cfquery>
<cfcatch type="database">
<m:ls_catch catch=#cfcatch# status=#pageInfo.status#/>
</cfcatch>
</cftry>
<cfquery name="qCountTotal" datasource="#request.DS#">
select count(*) as cnt from elma.aggrements d where 1=1
</cfquery>
</m:silent><!---
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
---><cfif isDefined("output_xls")>
<layout:xml qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
<cfabort/>
</cfif><cfif isDefined("output_json")>
<layout:json qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
<cfabort/>
</cfif><!---
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Дополнительные соглашения</b></cfoutput>
</layout:attribute>
<!--- <layout:attribute name="controls"></layout:attribute> --->
</layout:page>
<cfif pageInfo.readPermitted() AND !pageInfo.status.errorState>
<layout:grid_summary
recordCount=#qRead.recordCount#
totalCount=#qCountTotal.cnt#
footerOut="gridFooter"
excelLink="Yes"
jsonLink="Yes"
/>
<!--- так довольно громоздко, но можно обойтись без Dynamic Evaluation --->
<cfset queryAddColumn(qRead,'f_link_view_edit')/>
<cfset titleMap.f_link_view_edit={ordinal=#StructCount(titleMap)+1#}/><!--- *** Это легко забыть, потому что TitleMap никак не сцеплен с qRead. Напрашивается: упаковать их в одну обертку (но тогда обращение станет длиннее). Еще идея - назвать qRead и TitleMap так, чтобы была видна их связь. --->
<!--- <cfdump var=#titleMap#/> --->
<cfset queryAddColumn(qRead,'f_contract')/>
<cfset titleMap.f_contract=titleMap.contract/>
<cfset queryAddColumn(qRead,'f_contragent')/>
<cfset titleMap.f_contragent=titleMap.contragent/>
<cfset queryAddColumn(qRead,'f_deal')/>
<cfset titleMap.f_deal=titleMap.deal/>
<cfset queryAddColumn(qRead,'f_link_del')/>
<cfset titleMap.f_link_del={ordinal=0}/>
<!--- <cfdump var=#titleMap#/> --->
<cfoutput query=#qRead# startRow=#pageInfo.nStart# maxRows=#pageInfo.recordsPerPage#>
<cfsavecontent variable="qRead.f_link_view_edit">
<a href="additional_agreement.cfm?__id=#__id#&#tr.fwx#" name="#__id#" title="просмотр" class="view"></a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_contract">
<a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#contract#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_contragent">
<a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#contragent#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_deal">
<a href="deal.cfm?__id=#deal_uid#&#tr.fwx#">#deal#</a>
</cfsavecontent>
</cfoutput>
<c:table query=#qRead# recordsPerPage=#pageInfo.recordsPerPage# nStart=#pageInfo.nStart# titleMap=#titleMap# sortArray=#pageInfo.settings.sort.sortArray# class="worktable wide">
<c:column width="1%" sortable="false"><!---*** class="c" не пробрасывается --->
<c:td field="f_link_view_edit" class="c"/>
</c:column>
<c:column width="10%" field="__id"><c:td class="l"/></c:column>
<c:column width="3%" field="index"/>
<c:column width="15%" field="__name"/>
<c:column width="15%" field="f_contract"/>
<c:column width="6%" field="agreement_id"/>
<c:column width="10%" field="f_deal"/>
<c:column width="15%" field="f_contragent"/>
<c:column width="5%" field="wz"/>
<c:column width="10%" field="date_of_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="10%" field="date_end_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="10%" field="type_of_agreement"><c:td class="l"/></c:column>
</c:table>
<cfoutput>#gridFooter#</cfoutput>
</cfif>
<layout:page section="footer"/>
+697
View File
@@ -0,0 +1,697 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent>
<!--- этого можно было не делать, ошибка возникала при вычитании нулла в cfm --->
<cffunction name="safeCompareNum" returntype="boolean">
<cfargument name="n1" type="any"/>
<cfargument name="operator" type="string"/>
<cfargument name="n2" type="any" default=0/>
<cfif NOT isNumeric(arguments.n1) OR NOT isNumeric(arguments.n2)>
<cfreturn false/>
</cfif>
<cfswitch expression=#arguments.operator#>
<cfcase value="GT">
<cfreturn (n1 GT n2)/>
</cfcase>
<cfcase value="LT">
<cfreturn (n1 LT n2)/>
</cfcase>
<cfcase value="EQ,IS">
<cfreturn (n1 EQ n2)/>
</cfcase>
<cfcase value="NEQ">
<cfreturn (n1 NEQ n2)/>
</cfcase>
<cfcase value="GE,GTE">
<cfreturn (n1 GE n2)/>
</cfcase>
<cfcase value="LE,LTE">
<cfreturn (n1 LE n2)/>
</cfcase>
<cfdefaultcase>
<cfreturn false/>
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction name="safeNumberFormat" returntype="string">
<cfargument name="num" type="any"/>
<cfargument name="format" type="string"/>
<cfif NOT isNumeric(arguments.num)>
<cfreturn ""/>
</cfif>
<cftry>
<cfreturn numberFormat(arguments.num, arguments.format)/>
<cfcatch type="any">
<cfreturn ""/>
</cfcatch>
</cftry>
</cffunction>
<m:prepare_ls entity="cloud_capacity" settingsKey="cloud_capacity" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<cfquery name="qTS">
select
(select max(ts) from vmreports.compute) as ts_compute
,(select max(ts) from vmreports.host) as ts_host
</cfquery>
<!--- по результатам разбора ошибок.
1. Обрамлять минус пробелами (а то читал gb_provisioned-vm_ram_alloc как одно имя переменной
2. Всю арифметику делать в запросе - SQL работает с нуллами гораздо лучше CFML, в котором они превращаются в пустые строки, провоцируя ошибки --->
<cfquery name="qRead">
with
<!--- capacity as (
select "Cluster" as cluster, count(*) as hosts, sum(cores) as cores, round(sum(ghz)::numeric,1) as ghz, round(sum(ram)) as ram
from (
select "Cluster", "Host"
, avg("Host_CPU_Cores") as cores, avg("Host_CPU_Cores"*"Host_CPU_Speed") as ghz, avg("Host_RAM"*.85) as ram
from vmreports.compute
where ts=(select max(ts) from vmreports.compute)
group by "Cluster","Host"
order by "Cluster","Host"
) host
group by "Cluster"), --->
usage as (
select
c."Cluster" as cluster
,count(c."UUID_VM") as vms
,sum(c."VM_vCPU_count") as vm_cores
,sum(c."VM_vCPU_count"*c."VM_is_ON") as vm_cores_on
,sum(c."VM_vCPU_count"*c."VDC_CPU_Speed") as vm_ghz
,sum(c."VM_vCPU_count"*c."VDC_CPU_Speed"*c."VM_is_ON") as vm_ghz_on
,sum(c."VM_CPU_Reserv_GHz") as vm_ghz_reserved
,sum(c."VM_vCPU_count"*c."VDC_CPU_Speed"*c."VM_CPU_Reserv_perc"/100) as vm_ghz_reserved_c
,sum(c."VM_vCPU_count"*c."VDC_CPU_Speed"*(case when c."VM_CPU_Reserv_perc" IS null then 20 when c."VM_CPU_Reserv_perc"<=20 then 20 else c."VM_CPU_Reserv_perc" end)/100) as vm_ghz_promised
-- promised - зарезервированные ГГц, если включить минимальное согласованное резервирование
,sum(c."VM_RAM_Allocated"*c."VM_is_ON") as vm_ram_alloc_on
,sum(c."VM_RAM_Allocated") as vm_ram_alloc
,sum(c."VM_RAM_Used") as vm_ram_used
,sum(c."VM_CPU_Used_AVG") as vm_ghz_usage
,sum(c."VM_is_ON") as vms_on
,sum(s."Disk_Allocated") as disk_allocated
,sum(s."Disk_Used") as disk_used
,sum(CASE WHEN c."Organization_Status"='prod' THEN c."VM_CPU_Used_AVG" ELSE 0 END ) as ghz_used_prod
,sum(CASE WHEN c."Organization_Status"='prod' THEN c."VM_RAM_Used" ELSE 0 END ) as ram_used_prod
,sum(CASE WHEN c."Organization_Status"='prod' THEN s."Disk_Used" ELSE 0 END ) as disk_used_prod
from vmreports.compute c
left outer join vmreports.storage s on(c."UUID_VM"=s."VM_UUID")
where c.ts=(select max(ts) from vmreports.compute)
AND s.ts=(select max(ts) from vmreports.storage)
group by c."Cluster"),
cluster_stat as (
SELECT
h."Cluster" as cluster
,h."Cluster_v2" as cluster_v2
,m.models
,COUNT(*) as hosts_total
,COUNT(*)-1 as hosts_ha /*не вполне корректно, хосты разного размера, отказ по-разному влияет*/
,sum(CASE WHEN "Maintenance"='inMaintenance' THEN 1 ELSE 0 END) as hosts_in_maintenance
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN 1 ELSE 0 END) as hosts_in_service
,sum("CPU_Cores") as cores
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Cores" ELSE 0 END) as cores_in_service
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Cores"*"CPU_Speed" ELSE 0 END) as ghz_in_service
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPUtoVM" ELSE 0 END) as ghz_provisioned
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "RAMtoVM" ELSE 0 END) as gb_provisioned
--,sum("CPU_Used_AVG") as host_ghz_usage
--,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Used_AVG" ELSE 0 END) as host_ghz_usage
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Used" ELSE 0 END) as host_ghz_usage
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "RAM_Total" ELSE 0 END) as ram_in_service
,avg(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Speed" ELSE 0 END) as ghz
,max("CPUtoVM") as ghz_subtract_ha
,max("RAMtoVM") as gb_subtract_ha
,sum("RAM_Total")/sum("CPU_Cores") as gb_per_core
,CASE WHEN sum("CPU_Cores"*"CPU_Speed") > 0 THEN sum("CPU_Used_AVG")/sum("CPU_Cores"*"CPU_Speed")*100 ELSE NULL END as cpu_usage_perc
FROM vmreports.host h
LEFT OUTER JOIN (
SELECT hi."Cluster", STRING_AGG(DISTINCT hi."Model" || ' [' || (hi.cnt::text) || '] ',', ') as models
FROM (
SELECT hii."Cluster", hii."Model", count(hii."Model") as cnt
FROM vmreports.host hii
WHERE hii.ts=(SELECT max(ts) FROM vmreports.host)
GROUP BY hii."Cluster", hii."Model"
) hi GROUP BY hi."Cluster"
) m ON (h."Cluster"=m."Cluster")
WHERE ts=(SELECT max(ts) FROM vmreports.host)
GROUP BY h."Cluster", h."Cluster_v2", m.models
ORDER BY h."Cluster"
),
cluster_naming (cluster,commercial_name) AS (VALUES
('cl01-vsan','msk1, Intel Cascade Lake 2,9 ГГц')
,('cl02','msk1, Intel Cascade Lake 3,1 ГГц')
,('cl04-vsan','msk1, AMD Milan 2,8 ГГц')
,('cl05-1c','msk1, AMD Raphael 4,5 ГГц')
,('cl06-vsan','msk1, Intel Ice Lake 2,8 ГГц')
,('cl07-vsan','msk1, AMD Genoa 4,0 ГГц')
),
vsan as (
SELECT "ClusterNew" as cluster_v2, "Total" as total, "Usable" as usable, "Used" as used, "EffectiveFree" as effective_free
FROM vmreports.vsan_storage
WHERE ts=(SELECT max(ts) FROM vmreports.vsan_storage)
)
select
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
<d:field title="cluster v1">h.cluster as cluster_v1</d:field>
<d:field title="cluster v2">h.cluster_v2</d:field>
<d:field title="Коммерческое название">n.commercial_name</d:field>
<d:field title="Models">h.models</d:field>
<d:field title="Hosts total" cfSqlType="CF_SQL_INTEGER">coalesce(h.hosts_total,0) as hosts_total</d:field>
<d:field title="Hosts HA" cfSqlType="CF_SQL_INTEGER">coalesce(h.hosts_ha,0) as hosts_ha</d:field>
<d:field title="Hosts in mainte nance" cfSqlType="CF_SQL_INTEGER">coalesce(h.hosts_in_maintenance,0) as hosts_in_maintenance</d:field>
<d:field title="Hosts in service" cfSqlType="CF_SQL_INTEGER">coalesce(h.hosts_in_service,0) as hosts_in_service</d:field>
<d:field title="Cores Total" cfSqlType="CF_SQL_INTEGER">coalesce(h.cores,0) as cores</d:field>
<d:field title="Cores in service" cfSqlType="CF_SQL_INTEGER">coalesce(h.cores_in_service,0) as cores_in_service</d:field>
<d:field title="GHz in service" cfSqlType="CF_SQL_NUMERIC">coalesce(h.ghz_in_service,0) as ghz_in_service</d:field>
<d:field title="Host GHz used" cfSqlType="CF_SQL_NUMERIC">coalesce(h.host_ghz_usage,0) as host_ghz_usage</d:field>
<d:field title="Payload GHz used" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ghz_usage,0) as vm_ghz_usage</d:field>
<d:field title="CPU freq GHz" cfSqlType="CF_SQL_NUMERIC">coalesce(h.ghz,0) as ghz</d:field>
<d:field title="RAM GB in service" cfSqlType="CF_SQL_NUMERIC">coalesce(h.ram_in_service,0) as ram_in_service</d:field>
<d:field title="Host CPU usage %" cfSqlType="CF_SQL_NUMERIC">coalesce(h.cpu_usage_perc,0) as cpu_usage_perc</d:field>
<!--- <d:field title="Hosts in use">h.hosts</d:field> --->
<d:field title="Cores Total" cfSqlType="CF_SQL_INTEGER">coalesce(h.cores,0) as cores_total</d:field>
<!--- <d:field title="GHz Capacity">c.ghz as GHz_Capacity</d:field> --->
<d:field title="GHz Provisioned" cfSqlType="CF_SQL_NUMERIC">coalesce(h.ghz_provisioned - CASE WHEN hosts_in_maintenance > 0 THEN 0 ELSE h.ghz_subtract_ha END,0) as GHz_Provisioned</d:field><!--- за вычетом согласованных резервов на хосте и на HA --->
<d:field title="GB Provisioned" cfSqlType="CF_SQL_NUMERIC">coalesce(h.gb_provisioned - CASE WHEN hosts_in_maintenance > 0 THEN 0 ELSE h.gb_subtract_ha END,0) as GB_Provisioned</d:field><!--- за вычетом согласованных резервов на хосте и на HA --->
<d:field title="Payload GHz reserved" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ghz_reserved,0) as vm_ghz_reserved</d:field>
<d:field title="GHz обещанные" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ghz_promised,0) as vm_ghz_promised</d:field>
<d:field title="CPU GHz provision rate %" cfSqlType="CF_SQL_NUMERIC">coalesce(round((u.vm_ghz_promised/h.ghz_provisioned)::numeric,2)*100,0) as GHz_provision_rate</d:field>
<d:field title="Payload RAM GB alloc" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ram_alloc,0) as vm_ram_alloc</d:field>
<d:field title="Payload RAM GB alloc ВКЛ" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ram_alloc_on,0) as vm_ram_alloc_on</d:field>
<d:field title="Payload RAM GB used" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ram_used,0) as vm_ram_used</d:field>
<d:field title="RAM alloc %" cfSqlType="CF_SQL_NUMERIC">coalesce(round((u.vm_ram_alloc/h.gb_provisioned)::numeric,2)*100,0) as GB_alloc_perc</d:field>
<d:field title="RAM usage %" cfSqlType="CF_SQL_NUMERIC">coalesce(round((u.vm_ram_used/h.gb_provisioned)::numeric,2)*100,0) as GB_usage_perc</d:field>
<d:field title="Пере подписка vCPU" cfSqlType="CF_SQL_NUMERIC">coalesce(round((u.vm_cores/h.cores)::numeric,1),0) as oversubscription</d:field><!--- не только по включенным --->
<d:field title="Payload cores" cfSqlType="CF_SQL_INTEGER">coalesce(u.vm_cores,0) as vm_cores</d:field>
<d:field title="Payload cores ВКЛ" cfSqlType="CF_SQL_INTEGER">coalesce(u.vm_cores_on,0) as vm_cores_on</d:field>
<d:field title="VMs" cfSqlType="CF_SQL_INTEGER">coalesce(u.vms,0) as vms</d:field>
<d:field title="VMs ВКЛ" cfSqlType="CF_SQL_INTEGER">coalesce(u.vms_on,0) as vms_on</d:field>
<d:field title="Payload CPU Usage %" cfSqlType="CF_SQL_NUMERIC">coalesce(u.vm_ghz_usage/h.ghz_in_service*100,0) as vm_cpu_usage_perc</d:field>
<d:field title="GB/pCore" cfSqlType="CF_SQL_NUMERIC">coalesce(h.gb_per_core,0) as gb_per_core</d:field>
<d:field title="vSAN Total" cfSqlType="CF_SQL_NUMERIC">coalesce(s.total,0) as total</d:field>
<d:field title="vSAN Usable" cfSqlType="CF_SQL_NUMERIC">coalesce(s.usable,0) as usable</d:field>
<d:field title="vSAN Used" cfSqlType="CF_SQL_NUMERIC">coalesce(s.used,0) as used</d:field>
<d:field title="vSAN Effective Free" cfSqlType="CF_SQL_NUMERIC">coalesce(s.effective_free,0) as effective_free</d:field>
<d:field title="Disk Allocated" cfSqlType="CF_SQL_NUMERIC">coalesce(u.disk_allocated,0) as disk_allocated</d:field>
<d:field title="Disk Used" cfSqlType="CF_SQL_NUMERIC">coalesce(u.disk_used,0) as disk_used</d:field>
<d:field title="GHz Used Prod" cfSqlType="CF_SQL_NUMERIC">coalesce(u.ghz_used_prod,0) as ghz_used_prod</d:field>
<d:field title="RAM Used Prod" cfSqlType="CF_SQL_NUMERIC">coalesce(u.ram_used_prod,0) as ram_used_prod</d:field>
<d:field title="Disk Used Prod" cfSqlType="CF_SQL_NUMERIC">coalesce(u.disk_used_prod,0) as disk_used_prod</d:field>
</d:field_set>
from cluster_stat h
left outer join usage u on (h.cluster=u.cluster)
left outer join cluster_naming n on (h.cluster=n.cluster)
left outer join vsan s on (h.cluster_v2=s.cluster_v2)
where 1=1 <!--- <m:filter_build filter=#pageInfo.settings.filter#/> --->
order by <m:order_build sortArray=#pageInfo.settings.sort.sortArray# fieldCount=#fieldCount#/>
</cfquery>
<cfquery name="qTotal" dbtype="query">
select
sum(hosts_total) as hosts_total
,sum(hosts_ha) as hosts_ha
,sum(hosts_in_maintenance) as hosts_in_maintenance
,sum(host_ghz_usage) as host_ghz_usage
,sum(cores_total) as cores_total
,sum(cores_in_service) as cores_in_service
,sum(ghz_in_service) as ghz_in_service
,sum(ghz_provisioned) as ghz_provisioned
,sum(ram_in_service) as ram_in_service
,sum(gb_provisioned) as gb_provisioned
,sum(cores_in_service) as cores_in_service
,sum(vm_cores) as vm_cores
,sum(vm_cores_on) as vm_cores_on
,sum(vm_ghz_usage) as vm_ghz_usage
,sum(vm_ghz_reserved) as vm_ghz_reserved
,sum(vm_ghz_promised) as vm_ghz_promised
,sum(vm_ram_alloc) as vm_ram_alloc
,sum(vm_ram_alloc_on) as vm_ram_alloc_on
,sum(vm_ram_used) as vm_ram_used
,sum(vms) as vms
,sum(vms_on) as vms_on
,sum(cores*ghz)/sum(cores) as ghz <!--- рискованно все же делить --->
,sum(disk_allocated) as disk_allocated
,sum(disk_used) as disk_used
,sum(usable) as usable
,sum(ghz_used_prod) as ghz_used_prod
,sum(ram_used_prod) as ram_used_prod
,sum(disk_used_prod) as disk_used_prod
from qRead
</cfquery>
<cfif isDefined("output_xls")>
<layout:xml qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
<cfabort/>
</cfif><cfif isDefined("output_json")>
<layout:json qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
<cfabort/>
</cfif>
<layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Cloud Capacity</b></cfoutput>
</layout:attribute>
<layout:attribute name="controls"><!--- empty to remove controls (filter link) ---></layout:attribute>
</layout:page>
<cfoutput query="qTS">
<h3 style="display:inline-block; margin-right:2em;">Актуальность данных</h3>
<b>VM:</b> <span <cfif dateDiff("h",ts_compute,Now()) GT 24> class="err"</cfif>>#dateFormat(ts_compute,"YYYY-MM-DD")# #timeFormat(ts_compute,"HH:MM")#</span>
<b>Хосты:</b> <span <cfif dateDiff("h",ts_host,Now()) GT 24> class="err"</cfif>>#dateFormat(ts_host,"YYYY-MM-DD")# #timeFormat(ts_host,"HH:MM")#</span>
</cfoutput>
<h3>Свободно</h3>
<table class="worktable">
<!--- <thead> --->
<layout:grid_head titleMap=#titleMap# sortArray=#pageInfo.settings.sort.sortArray#>
<!--- <tr> --->
<th width="5%" rowspan="2"><layout:column_head name="cluster_v1"/></th>
<th width="5%" rowspan="2"><layout:column_head name="cluster_v2"/></th>
<th width="10%" rowspan="2"><layout:column_head name="commercial_name"/></th>
<th width="3%" rowspan="2"><layout:column_head name="hosts_total"/></th>
<th colspan="7">Свободно</th>
<th width="3%" rowspan="2">ВМ размещено</th>
<!--- </tr> --->
</layout:grid_head>
<tr>
<th width="5%">RAM GB by alloc</th>
<th width="5%">RAM GB by usage</th>
<th width="5%">CPU GHz (текущий резерв)</th>
<th width="5%">Ядра 20% (текущий резерв)</th>
<th width="5%">Ядра 50% (текущий резерв)</th>
<th width="5%">Ядра 80% (текущий резерв)</th>
<th width="5%">vSAN GB (alloc)</th>
</tr>
<!--- </thead> --->
<!--- <tbody> --->
<cfoutput query="qRead">
<tr>
<td>#cluster_v1#</td>
<td>#cluster_v2#</td>
<td style="font-size:130%">#commercial_name#</td>
<!--- <td class="r" style="font-size:120%">#numberFormat(ghz,".0")#</td> --->
<td class="r">#hosts_total#</td>
<td class="r<cfif safeCompareNum(gb_provisioned - vm_ram_alloc, "LE", 0)> err</cfif>" style="font-size:130%">
#safeNumberFormat(gb_provisioned-vm_ram_alloc,"0")#</td>
<td class="r<cfif safeCompareNum(gb_provisioned - vm_ram_used, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat(gb_provisioned - vm_ram_used,"0")#</td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_reserved, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat(ghz_provisioned-vm_ghz_reserved,".0")#</td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_reserved, "LE", 0)> err</cfif>" style="font-size:130%"><cfif ghz GT 0>#safeNumberFormat((ghz_provisioned-vm_ghz_reserved)/ghz/0.2,"0")#</cfif></td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_reserved, "LE", 0)> err</cfif>" style="font-size:130%"><cfif ghz GT 0>#safeNumberFormat((ghz_provisioned-vm_ghz_reserved)/ghz/0.5,"0")#</cfif></td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_reserved, "LE", 0)> err</cfif>" style="font-size:130%"><cfif ghz GT 0>#safeNumberFormat((ghz_provisioned-vm_ghz_reserved)/ghz/0.8,"0")#</cfif></td>
<td class="r" style="font-size:130%">#safeNumberFormat(effective_free,"0")#</td>
<!--- <td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_promised, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat(ghz_provisioned-vm_ghz_promised,".0")#</td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_promised, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat((ghz_provisioned-vm_ghz_promised)/ghz/0.2,"0")#</td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_promised, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat((ghz_provisioned-vm_ghz_promised)/ghz/0.5,"0")#</td>
<td class="r<cfif safeCompareNum(ghz_provisioned - vm_ghz_promised, "LE", 0)> err</cfif>" style="font-size:130%">#safeNumberFormat((ghz_provisioned-vm_ghz_promised)/ghz/0.8,"0")#</td> --->
<td class="r">#vms#</td>
</tr>
</cfoutput>
<!--- </tbody> --->
</table>
<!--- <i>Жесткий резерв - если включим минимальное резервирование 20%</i><br/>
<i>Доступная память указана по выделенному объему (используется меньше, доступно больше)</i><br/> --->
<i>Емкость HA вычитается из Capacity, если нет хостов в Maintenance, в противном случае вычитается ресурс хостов в Maintenance. За объем для HA принимается размер наибольшего хоста в кластере по каждому ресурсу (поэтому при выводе в Maintenance маленького хоста расчетная емкость может временно увеличиться, но это только если хосты в кластере разные. Понятнее будет, если мы как резерв будем брать максимальное значение из наибольшего хоста и суммы выведенных в Maintenance хостов)</i>
<h3>Использование подробно</h3>
<layout:grid_summary
recordCount=#qRead.recordCount#
footerOut="gridFooter"
excelLink="Yes"
jsonLink="Yes"
/>
<table class="worktable">
<thead>
<layout:grid_head titleMap=#titleMap# sortArray=#pageInfo.settings.sort.sortArray#>
<th width="5%"><layout:column_head name="cluster_v1"/></th>
<th width="5%"><layout:column_head name="cluster_v2"/></th>
<th width="7%"><layout:column_head name="commercial_name"/></th>
<th width="15%"><layout:column_head name="models"/></th>
<th width="3%"><layout:column_head name="ghz"/></th>
<th width="3%"><layout:column_head name="hosts_total"/></th>
<th width="3%"><layout:column_head name="hosts_ha"/></th>
<th width="3%"><layout:column_head name="hosts_in_maintenance"/></th>
<!--- <th width="3%"><layout:column_head name="hosts_in_service"/></th>
<th width="3%"><layout:column_head name="ram_in_service"/></th>
<th width="3%"><layout:column_head name="cores_in_service"/></th>
<th width="3%"><layout:column_head name="ghz_in_service"/></th> --->
<th width="3%"><layout:column_head name="host_ghz_usage"/></th>
<th width="3%"><layout:column_head name="vm_ghz_usage"/></th>
<th width="3%"><layout:column_head name="cpu_usage_perc"/></th>
<th width="3%"><layout:column_head name="vm_cpu_usage_perc"/></th>
<th width="3%"><layout:column_head name="oversubscription"/></th>
<th width="3%"><layout:column_head name="cores_total"/></th>
<th width="3%"><layout:column_head name="ghz_provisioned"/></th>
<th width="3%"><layout:column_head name="vm_ghz_reserved"/></th>
<th width="3%"><layout:column_head name="vm_ghz_promised"/></th>
<th width="3%"><layout:column_head name="vm_cores"/></th>
<th width="3%"><layout:column_head name="GHz_provision_rate"/></th>
<th width="3%"><layout:column_head name="gb_provisioned"/></th>
<th width="3%"><layout:column_head name="vm_ram_alloc"/></th>
<th width="3%"><layout:column_head name="vm_ram_used"/></th>
<th width="3%"><layout:column_head name="GB_alloc_perc"/></th>
<th width="3%"><layout:column_head name="GB_usage_perc"/></th>
<th width="3%">ВМ шт.</th>
<th width="10%">Средняя ВМ</th>
</layout:grid_head>
</thead>
<cfoutput query="qRead">
<tr>
<td>#cluster_v1#</td>
<td>#cluster_v2#</td>
<td>#commercial_name#</td>
<td>#models#</td>
<td class="r">#numberFormat(ghz,".0")#</td>
<td class="r">#hosts_total#</td>
<td class="r">#hosts_ha#</td>
<td class="r"><cfif hosts_in_maintenance NEQ 0>#hosts_in_maintenance#</cfif></td> <!--- style="background:lightcoral" --->
<!--- <td class="r">#hosts_in_service#</td>
<td class="r">#numberFormat(ram_in_service,"0")#</td>
<td class="r">#cores_in_service#</td>
<td class="r">#numberFormat(ghz_in_service,".0")#</td> --->
<td class="r">#numberFormat(host_ghz_usage,".0")#</td>
<td class="r">#numberFormat(vm_ghz_usage,".0")#</td>
<td class="c" style="font-size:130%;">#numberFormat(cpu_usage_perc,"0")#</td>
<td class="c" style="font-size:130%;">#numberFormat(vm_cpu_usage_perc,"0")#</td>
<td class="r">#oversubscription#</td>
<td class="r">#cores_total#</td>
<td class="r">#numberFormat(ghz_provisioned,".0")#</td>
<td class="r">#numberFormat(vm_ghz_reserved,".0")#</td>
<td class="r">#numberFormat(vm_ghz_promised,".0")#</td>
<td class="r">#vm_cores#</td>
<td class="r">#numberFormat(GHz_provision_rate,"0")#</td>
<td class="r">#numberFormat(gb_provisioned,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc,"0")#</td>
<td class="r">#numberFormat(vm_ram_used,"0")#</td>
<td class="r">#numberFormat(GB_alloc_perc,"0")#</td>
<td class="r">#numberFormat(GB_usage_perc,"0")#</td>
<td class="r">#vms#</td>
<td class="r"><!--- <cftry>
#numberFormat(vm_cores/vms,".0")#&nbsp;core
#numberFormat(vm_ghz_usage/vms_on,".0")#&nbsp;GHz
#numberFormat(vm_ghz_usage/vm_cores_on/ghz*100,"0")#%
#numberFormat(vm_ram_alloc/vms,".0")#(#numberFormat(vm_ram_used/vms_on,".0")#)&nbsp;GB
#numberFormat(disk_allocated/vms,".0")#(#numberFormat(disk_used/vms,".0")#)&nbsp;GB
<cfcatch><cfdump var=#cfcatch#></cfcatch></cftry></td> --->
<cftry>
<cfif vms NEQ 0>#numberFormat(vm_cores/vms,".0")#<cfelse> ? </cfif> &nbsp;core
<cfcatch type="any"></cfcatch></cftry>
<cftry>
<cfif vms_on NEQ 0>#numberFormat(vm_ghz_usage/vms_on,".0")#<cfelse> ? </cfif>&nbsp;GHz
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vm_cores_on NEQ 0 AND ghz NEQ 0>#numberFormat(vm_ghz_usage/vm_cores_on/ghz*100,"0")#<cfelse> ? </cfif>%
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vms NEQ 0>#numberFormat(vm_ram_alloc/vms,".0")#<cfelse> ? </cfif>(<cfif vms_on NEQ 0>#numberFormat(vm_ram_used/vms_on,".0")#<cfelse>?</cfif>)&nbsp;GB
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vms NEQ 0>#numberFormat(disk_allocated/vms,".0")#(#numberFormat(disk_used/vms,".0")#)<cfelse> ? </cfif>&nbsp;GB
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
</td>
</tr>
</cfoutput>
<cfoutput query="qTotal">
<tr class="b">
<td colspan="4" class="r b"> Итого</td>
<td class="r">#numberFormat(ghz,".0")#</td>
<td class="r">#hosts_total#</td>
<td class="r">#hosts_ha#</td>
<td class="r">#hosts_in_maintenance#</td>
<!--- <td class="r"></td>
<td class="r">#numberFormat(ram_in_service,"0")#</td>
<td class="r">#cores_in_service#</td>
<td class="r">#numberFormat(ghz_in_service,".0")#</td> --->
<td class="r">#numberFormat(host_ghz_usage,".0")#</td>
<td class="r">#numberFormat(vm_ghz_usage,".0")#</td>
<td class="c" style="font-size:130%;">
<!--- <cftry>#numberFormat(vm_ghz_usage*100/ghz_in_service,"0")#<cfcatch type="any"></cfcatch></cftry> --->
</td>
<td class="r"><cftry>#numberFormat(vm_ghz_usage*100/ghz_in_service,"0")#<cfcatch type="any"></cfcatch></cftry></td>
<td class="r" style="font-size:130%;"><cfif cores_in_service NEQ 0>#numberFormat(vm_cores/cores_in_service,".0")#</cfif></td>
<td class="r">#numberFormat(cores_total,"0")#</td>
<td class="r">#numberFormat(ghz_provisioned,".0")#</td>
<td class="r">#numberFormat(vm_ghz_reserved,".0")#</td>
<td class="r">#numberFormat(vm_ghz_promised,".0")#</td>
<td class="r">#vm_cores#</td>
<td class="r"></td>
<td class="r">#numberFormat(gb_provisioned,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc,"0")#</td>
<td class="r">#numberFormat(vm_ram_used,"0")#</td>
<td class="r" style="font-size:130%;"><cfif ram_in_service NEQ 0>#numberFormat(vm_ram_alloc/ram_in_service*100,"0")#</cfif></td>
<td class="r" style="font-size:130%;"><cfif ram_in_service NEQ 0>#numberFormat(vm_ram_used/ram_in_service*100,"0")#</cfif></td>
<td class="r">#vms#</td>
<td class="r">
<cftry>
<cfif vms NEQ 0>#numberFormat(vm_cores/vms,".0")#<cfelse> ? </cfif> &nbsp;core
<cfcatch type="any"></cfcatch></cftry>
<cftry>
<cfif vms_on NEQ 0>#numberFormat(vm_ghz_usage/vms_on,".0")#<cfelse> ? </cfif>&nbsp;GHz
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vm_cores_on NEQ 0 AND ghz NEQ 0>#numberFormat(vm_ghz_usage/vm_cores_on/ghz*100,"0")#<cfelse> ? </cfif>%
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vms NEQ 0>#numberFormat(vm_ram_alloc/vms,".0")#<cfelse> ? </cfif>(<cfif vms_on NEQ 0>#numberFormat(vm_ram_used/vms_on,".0")#<cfelse>?</cfif>)&nbsp;GB
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
<cftry>
<cfif vms NEQ 0>#numberFormat(disk_allocated/vms,".0")#(#numberFormat(disk_used/vms,".0")#)<cfelse> ? </cfif>&nbsp;GB
<cfcatch type="any"><cfdump var=#cfcatch#></cfcatch></cftry>
</td>
</tr>
</cfoutput>
</table>
<!--- <cfdump var=#qTotal#/> --->
<i>Пока выводим избыточный набор колонок для контроля. Кроме того, еще не выбрали, какие колонки удобнее и релевантнее</i>
<br/>
<i>* CPU GHz provision rate % - отношение зарезервированной частоты (с учетом 20% резерва по умолчанию) к наличной частоте процессоров (считая выключенные ВМ - поэтому "мертвые" ВМ искажают статистику, кроме того, что занимают диск)</i>
<br/>
<i>* Для средней ВМ указана аллоцированная память, в скобках - используемая, далее аллоцированное дисковое пространство, в скобках используемое. Диск считается без разделения по политикам (2do). ГГц на ВМ, процент загрузки ядер (** проверить), используемая память - считается по включенным ВМ. Количество ядер, аллоцированная память и диск - по всем ВМ</i>
<br/>
<!--- <cfchart
format="png"
chartWidth="500"
chartHeight="300"
seriesplacement="stacked"
title="Population Distribution: Males vs Females"
scalefrom="-100"
scaleto="100"
labelformat="number">
<!--- Left Side: Males (Negative Values) --->
<cfchartseries type="bar" seriesLabel="Males" seriesColor="##3366CC">
<cfchartdata item="Age 0-10" value="-85">
<cfchartdata item="Age 11-20" value="-70">
<cfchartdata item="Age 21-30" value="-55">
</cfchartseries>
<!--- Right Side: Females (Positive Values) --->
<cfchartseries type="bar" seriesLabel="Females" seriesColor="##FF99CC">
<cfchartdata item="Age 0-10" value="82">
<cfchartdata item="Age 11-20" value="75">
<cfchartdata item="Age 21-30" value="60">
</cfchartseries>
</cfchart> --->
<h3>Техническая утилизация</h3>
<layout:grid_summary
recordCount=#qRead.recordCount#
footerOut="gridFooter"
excelLink="Yes"
jsonLink="Yes"
/>
<table class="worktable">
<thead>
<layout:grid_head titleMap=#titleMap# sortArray=#pageInfo.settings.sort.sortArray#>
<th width="5%"><layout:column_head name="cluster_v1"/></th>
<th width="5%"><layout:column_head name="cluster_v2"/></th>
<th width="10%"><layout:column_head name="commercial_name"/></th>
<th width="3%"><layout:column_head name="hosts_total"/></th>
<th width="3%"><layout:column_head name="ghz"/></th>
<th width="3%"><layout:column_head name="gb_per_core"/></th>
<th width="3%"><layout:column_head name="vms"/></th>
<th width="3%"><layout:column_head name="vms_on"/></th>
<th width="3%"><layout:column_head name="cpu_usage_perc"/></th>
<th width="3%"><layout:column_head name="vm_cpu_usage_perc"/></th>
<th width="3%"><layout:column_head name="oversubscription"/></th>
<th width="3%"><layout:column_head name="cores_total"/></th>
<th width="3%"><layout:column_head name="cores_in_service"/></th>
<th width="3%"><layout:column_head name="ghz_in_service"/></th>
<th width="3%"><layout:column_head name="ghz_provisioned"/></th>
<th width="3%"><layout:column_head name="vm_ghz_reserved"/></th>
<th width="3%"><layout:column_head name="vm_ghz_usage"/></th>
<th width="3%"><layout:column_head name="vm_cores"/></th>
<th width="3%"><layout:column_head name="vm_cores_on"/></th>
<th width="3%"><layout:column_head name="gb_provisioned"/></th>
<th width="3%"><layout:column_head name="vm_ram_alloc"/></th>
<th width="3%"><layout:column_head name="vm_ram_alloc_on"/></th>
<th width="3%"><layout:column_head name="vm_ram_used"/></th>
<th width="3%">RAM allloc %</th>
<th width="3%">RAM allloc ВКЛ %</th>
<th width="3%"><layout:column_head name="GB_usage_perc"/></th>
<th width="3%">Емкость vSAN GB</th>
<th width="3%">Свободно vSAN % alloc</th>
<th width="3%">Свободно vSAN % used</th>
<th width="3%"><layout:column_head name="ghz_used_prod"/></th>
<th width="3%"><layout:column_head name="ram_used_prod"/></th>
<th width="3%"><layout:column_head name="disk_used_prod"/></th>
</layout:grid_head>
</thead>
<cfoutput query="qRead">
<tr>
<td>#cluster_v1#</td>
<td>#cluster_v2#</td>
<td style="font-size:130%">#commercial_name#</td>
<td class="r">#hosts_total#</td>
<td class="r" style="font-size:120%">#numberFormat(ghz,".0")#</td>
<td class="r" style="font-size:120%">#numberFormat(gb_per_core,".0")#</td>
<td class="r" style="font-size:120%">#numberFormat(vms,"0")#</td>
<td class="r" style="font-size:120%">#numberFormat(vms_on,"0")#</td>
<td class="c" style="font-size:130%;">#numberFormat(cpu_usage_perc,"0")#</td>
<td class="c" style="font-size:130%;">#numberFormat(vm_cpu_usage_perc,"0")#</td>
<td class="r">#oversubscription#</td>
<td class="r">#cores_total#</td>
<td class="r">#cores_in_service#</td>
<td class="r">#safeNumberFormat(ghz_in_service,".0")#</td>
<td class="r">#numberFormat(ghz_provisioned,".0")#</td>
<td class="r">#numberFormat(vm_ghz_reserved,".0")#</td>
<td class="r">#numberFormat(vm_ghz_usage,".0")#</td>
<td class="r">#vm_cores#</td>
<td class="r">#vm_cores_on#</td>
<td class="r">#numberFormat(gb_provisioned,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc_on,"0")#</td>
<td class="r">#numberFormat(vm_ram_used,"0")#</td>
<!--- <td class="c" style="font-size:130%;"><cfif ram_in_service NEQ 0>#numberFormat(vm_ram_alloc/ram_in_service*100,"0")#</cfif></td> --->
<td class="c" style="font-size:130%;">#numberFormat(GB_alloc_perc,"0")#</td>
<td class="c" style="font-size:130%;"><cfif gb_provisioned NEQ 0>#numberFormat(vm_ram_alloc_on/gb_provisioned*100,"0")#</cfif></td>
<td class="c" style="font-size:130%;"><cfif gb_provisioned NEQ 0>#numberFormat(vm_ram_used/gb_provisioned*100,"0")#</cfif></td>
<td class="c" style="font-size:130%;">#safeNumberFormat(usable,"0")#</td>
<td class="c" style="font-size:130%;">
<cfif usable GT 0>
<cftry>
#numberFormat(effective_free/usable*100,"0")#
<cfcatch type="any"></cfcatch>
</cftry>
</cfif>
</td>
<td class="c" style="font-size:130%;">
<cfif usable GT 0>
<cftry>
#numberFormat((usable-used)/usable*100,"0")#
<cfcatch type="any"></cfcatch>
</cftry>
</cfif>
</td>
<td class="c">#safeNumberFormat(ghz_used_prod,".0")#</td>
<td class="c">#safeNumberFormat(ram_used_prod,"0")#</td>
<td class="c">#safeNumberFormat(disk_used_prod,"0")#</td>
</tr>
</cfoutput>
<cfoutput query="qTotal">
<tr class="b">
<td colspan="3" class="r b"> Итого</td>
<td class="r">#hosts_total#</td>
<td class="r" style="font-size:120%">#numberFormat(ghz,".0")#</td>
<td class="r" style="font-size:120%"></td>
<td class="r" style="font-size:120%">#numberFormat(vms,"0")#</td>
<td class="r" style="font-size:120%">#numberFormat(vms_on,"0")#</td>
<td class="c" style="font-size:130%;"></td>
<td class="c" style="font-size:130%;"></td>
<td class="r"></td>
<td class="r">#cores_total#</td>
<td class="r">#cores_in_service#</td>
<td class="r">#safeNumberFormat(ghz_in_service,".0")#</td>
<td class="r">#numberFormat(ghz_provisioned,".0")#</td>
<td class="r">#numberFormat(vm_ghz_reserved,".0")#</td>
<td class="r">#numberFormat(vm_ghz_usage,".0")#</td>
<td class="r">#vm_cores#</td>
<td class="r">#vm_cores_on#</td>
<td class="r">#numberFormat(gb_provisioned,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc,"0")#</td>
<td class="r">#numberFormat(vm_ram_alloc_on,"0")#</td>
<td class="r">#numberFormat(vm_ram_used,"0")#</td>
<td class="c" style="font-size:130%;"></td>
<td class="c" style="font-size:130%;"></td>
<td class="c" style="font-size:130%;"></td>
<td class="c" style="font-size:130%;">#safeNumberFormat(usable,"0")#</td>
<td class="c" style="font-size:130%;">
<cfif usable GT 0>
<cftry>
#numberFormat(effective_free/usable*100,"0")#
<cfcatch type="any"></cfcatch>
</cftry>
</cfif>
</td>
<td class="c" style="font-size:130%;">
<cfif usable GT 0>
<cftry>
#numberFormat((usable-used)/usable*100,"0")#
<cfcatch type="any"></cfcatch>
</cftry>
</cfif>
</td>
<td class="c">#safeNumberFormat(ghz_used_prod,".0")#</td>
<td class="c">#safeNumberFormat(ram_used_prod,"0")#</td>
<td class="c">#safeNumberFormat(disk_used_prod,"0")#</td>
</tr>
</cfoutput>
</table>
<cfdump var=#this.datasources[request.ds].connectionString#/>
<layout:page section="footer"/>
+5
View File
@@ -0,0 +1,5 @@
<cfdump var=#{
"Template Charset (File compilation)": getPageContext().getConfig().getTemplateCharset(),
"Web Charset (Forms, URLs, Responses)": getPageContext().getConfig().getWebCharset(),
"Resource Charset (File system reads/writes)": getPageContext().getConfig().getResourceCharset()
}#/>
+162 -14
View File
@@ -118,12 +118,15 @@
select
a.__id::text
,a.__name
,contract_uid::text
,is_actual
,last_aa
,index
,deal_uid::text
,base_by::text
,a.__index
,a.contract_uid::text
,a.is_actual
,a.last_aa
,a.index
,a.deal_uid::text
,a.base_by[1]::text as base_by_uid
,b.__name as base_by_name
,b.__index as base_by_index
,d.__name as deal
,d.__status_status as status_id
,s.status
@@ -131,6 +134,7 @@
from elma.additional_agreements a
left outer join elma.deals d on (a.deal_uid=d.__id)
left outer join s on (d.__status_status=s.status_id)
left outer join elma.additional_agreements b on (a.base_by[1]=b.__id)
where a.contract_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#d.__id#" null=#!isValid('guid',d.__id)#/>
order by 1
</cfquery>
@@ -143,10 +147,11 @@
<table class="worktable">
<thead>
<tr>
<th>__index</th>
<th>__id</th>
<th>__name</th>
<th>версия</th>
<th>contract_uid</th>
<!--- <th>contract_uid</th> --->
<th>is_actual</th>
<th>last_aa</th>
<th>deal_uid</th>
@@ -154,16 +159,19 @@
<th>status_id</th>
<th>status</th>
<th>вер-ть</th>
<th>base_by</th>
<th>base_by_index</th>
<th>base_by_uid</th>
<th>base_by_name</th>
</tr>
</thead>
<cfoutput query="qAdditionalAgreement">
<tr>
<td><a href="additional_agreement.cfm?__id=#__id#&#tr.fwx#">#__index#</a></td>
<td><a href="additional_agreement.cfm?__id=#__id#&#tr.fwx#">#__id#</a></td>
<td>#__name#</td>
<td class="c">#index#</td>
<td>#contract_uid#</td>
<!--- <td>#contract_uid#</td> --->
<td class="c">#is_actual#</td>
<td class="c">#last_aa#</td>
<td><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#">#deal_uid#</a></td>
@@ -171,14 +179,14 @@
<td class="c">#status_id#</td>
<td>#status#</td>
<td class="r">#probability_pc#</td>
<td>#base_by#</td>
<!--- <td class="c">
#dateFormat(dt_contract,'YYYY-MM-DD')#
</td> --->
<td class="r"><a href="additional_agreement.cfm?__id=#base_by_uid#&#tr.fwx#">#base_by_index#</a></td>
<td><a href="additional_agreement.cfm?__id=#base_by_uid#&#tr.fwx#">#base_by_uid#</a></td>
<td><a href="additional_agreement.cfm?__id=#base_by_uid#&#tr.fwx#">#base_by_name#</a></td>
</tr>
</cfoutput>
</table>
</cfif>
<br/>
Мы не показываем тут сделки, поскольку связь со сделкой у договора не прямая и не обязательная. Сделки относятся к контрагенту, а не к договору. Сделка может быть связана с договором через дополнительное соглашение (включая нулевое соглашение, по умолчанию)
<!--- <cfquery name="qDeal">
@@ -195,5 +203,145 @@
from elma.deals d limit 10
</cfquery> --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<cfquery name="qService">
with
status(status, status_id, probability_pc) as (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
)
select
siv.__id
,siv.__name
,siv.user_description
,siv.discount
,siv.cnt
,siv.modifier_code
,siv.abstractive_service_code
,siv.is_actual
,siv.type
,siv.hash
,siv.version
,siv.name_version
,siv.date_accept
,siv.__index
,siv.date_nop
,siv.date_end
,siv.is_easy
,siv.params::text
,a.__id::text as additional_agreement_uid
,a.__name as additional_agreement
,p.price
,p.cnt as p_cnt
,p.ed_izm
,p.code
,p.discount as p_discount
,p.__id as p_uid
,p.name
,s.probability_pc
,d.__index
,d.__id as deal_uid
from elma.deals_services siv
join elma.deals d on d.__id=ANY(siv.deal)
join status s on (d.__status_status=s.status_id)
join elma.service_parametrs p ON (p.__id = ANY (siv.params) AND p."__deletedAt" IS NULL)
left outer join elma.additional_agreements a on (a.__id=ANY(siv.additional_agreement))
where a.contract_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#d.__id#" null=#!isValid('guid',d.__id)#/>
and siv.is_actual
--and a.is_actual
and s.probability_pc > 0
order by siv.version::int
</cfquery>
<cfoutput>
<h4>Услуги (версии строк спецификации, только актуальные) (#qService.recordCount#) </h4>
</cfoutput>
<!--- <layout:render_query query=#qService#/> --->
<table class="worktable">
<thead>
<tr>
<th>__index</th>
<th>Код</th>
<th width="20%">user_description</th>
<th width="25%">Компоненты</th>
<th>Кол-во</th>
<th>Скидка</th>
<th width="5%">Сумма</th>
<th>type</th>
<th>is_actual</th>
<th>hash</th>
<th>version</th>
<th>name_version</th>
<th>date_accept</th>
<th>__index</th>
<th width="5%">date_nop</th>
<th width="5%">date_end</th>
<th>is_easy</th>
<th>Вер.%</th>
<th width="7%">additional_agreement</th>
</tr>
</thead>
<cfoutput query="qService" group="__index">
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="__id">#__index#</a></td>
<!--- <td class="c">#__name#</td> --->
<td class="l">
#abstractive_service_code#.#modifier_code#<!--- <cfswitch expression=#type#>
<cfcase value=1>-i</cfcase>
<cfcase value=2>-f</cfcase>
<cfcase value=3>-m</cfcase>
</cfswitch> --->
</td>
<td class="l">#user_description#</td>
<td>
<table>
<cfset cost=0/>
<cfoutput group="p_uid">
<cfif p_cnt NEQ 0>
<tr>
<td class="nw">#code#</td>
<td>#name#</td>
<td>#p_cnt#</td>
<td>#ed_izm#</td>
<td class="r nw">#nFmt(price,3)#</td>
<td class="r">#p_discount#%</td>
</tr>
<cfset cost+=price*p_cnt*(100-(isNumeric(p_discount)?p_discount:0))/100 />
</cfif>
</cfoutput>
</table>
</td>
<td class="c">#cnt#</td>
<td class="c">#discount#%</td>
<td class="r">#nFmt(cost*cnt*(100-(isNumeric(discount)?discount:0))/100)#</td>
<td class="c">#type#</td>
<td class="c">#is_actual#</td>
<td class="c">#hash#</td>
<td class="c">#version#</td>
<td class="c">#name_version#</td>
<td class="c">#date_accept#</td>
<td class="c">#__index#</td>
<td class="c">#dateFormat(date_nop,'YYYY-MM-DD')#</td>
<td class="c">#dateFormat(date_end,'YYYY-MM-DD')#</td>
<td class="c">#is_easy#</td>
<td class="c">#probability_pc#</td>
<!--- <td class="c">#additional_agreement_uid#</td> --->
<td><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
</tr>
</cfoutput>
</table>
</cfif><!--- len(d.__id) --->
<layout:page section="footer"/>
+3 -1
View File
@@ -30,6 +30,7 @@
<d:field title="Дата договора">d.date_of_aggrement</d:field>
<d:field title="Дата окончания">d.date_end_aggrement</d:field>
<d:field title="Тип договора">d.type_of_agreement</d:field>
<d:field title="Доп. соглашений">(select count(*) from elma.additional_agreements a where a.contract_uid=d.__id AND a."__deletedAt" IS NULL) as aa_cnt</d:field>
</d:field_set>
from elma.aggrements d
left outer join elma.companies k on (d.company_uid=k.__id)
@@ -102,7 +103,7 @@ select count(*) as cnt from elma.aggrements d where 1=1
</cfsavecontent>
<cfsavecontent variable="qRead.f_contragent">
<a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#contragent#</a>
<a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#contragent#</a> <a href="contragent_rpt.cfm?__id=#company_uid#&#tr.fwx#" style="float:right"><img src="img/view.gif" title="сводка по контрагенту"/></a>
</cfsavecontent>
</cfoutput>
@@ -120,6 +121,7 @@ select count(*) as cnt from elma.aggrements d where 1=1
<c:column width="10%" field="date_of_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#/>
<c:column width="10%" field="date_end_aggrement" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#/>
<c:column width="10%" field="type_of_agreement"><c:td class="l"/></c:column>
<c:column width="10%" field="aa_cnt"><c:td class="c"/></c:column>
</c:table>
+165 -133
View File
@@ -15,7 +15,7 @@
<cfreturn htmlEditFormat(s)/>
</cffunction>
<m:prepare_detail entity="contragent" accessObject="" key="contragent_id" pageInfoOut="pageInfo"/>
<m:prepare_detail entity="contragent" accessObject="" key="__id" pageInfoOut="pageInfo"/>
<d:bean readonly=true table="elma.companies" datasource="#request.DS#" output="d" status="status">
<d:param field="__id" type="uuid" key/>
@@ -85,7 +85,7 @@
<div class="tr">
<div class="th">__name</div>
<div class="td">#d.__name#</div>
<div class="td">#d.__name# <a href="contragent_rpt.cfm?__id=#d.__id#&#tr.fwx#">Сводка по потреблению</a></div>
</div>
<div class="tr">
@@ -121,12 +121,154 @@
</div>
</cfoutput>
сюда добавить сделок, договоров и т.д.
<layout:page section="extension" closeForm="Yes"/>
<cfif len(d.__id)>
<a href="#agreements" class="i">Договоры, допники, сделки - внизу</a>
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<cfquery name="qService">
with
status(status, status_id, probability_pc) as (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
)
select
siv.__id
,siv.__name
,siv.user_description
,siv.discount
,siv.cnt
,siv.modifier_code
,siv.abstractive_service_code
,siv.is_actual
,siv.type
,siv.hash
,siv.version
,siv.name_version
,siv.date_accept
,siv.__index
,siv.date_nop
,siv.date_end
,siv.is_easy
,siv.params::text
,a.__id::text as additional_agreement_uid
,a.__name as additional_agreement
,p.price
,p.cnt as p_cnt
,p.ed_izm
,p.code
,p.discount as p_discount
,p.__id as p_uid
,p.name
,s.probability_pc
,d.__index
,d.__id as deal_uid
from elma.deals_services siv
join elma.deals d on d.__id=ANY(siv.deal)
join status s on (d.__status_status=s.status_id)
join elma.service_parametrs p ON (p.__id = ANY (siv.params) AND p."__deletedAt" IS NULL)
left outer join elma.additional_agreements a on (a.__id=ANY(siv.additional_agreement))
where d._companies=<cfqueryparam cfsqltype="cf_sql_other" value="#d.__id#" null=#!isValid("guid",d.__id)#/>
AND siv.is_actual
--AND a.is_actual
AND s.probability_pc > 0
order by version::int
</cfquery>
<cfoutput>
<h4>Услуги (версии строк спецификации, только актуальные) <!--- (#qService.recordCount#) ---></h4>
</cfoutput>
<!--- <layout:render_query query=#qService#/> --->
<table class="worktable">
<thead>
<tr>
<th>__index</th>
<!--- <th>__name</th> --->
<th width="20%">user_description</th>
<th width="25%">Компоненты</th>
<th>Кол-во</th>
<th>Скидка%</th>
<th width="5%">Сумма</th>
<th>Код</th>
<th>type</th>
<th>is_actual</th>
<th>hash</th>
<th>version</th>
<th>name_version</th>
<th>date_accept</th>
<th>__index</th>
<th width="5%">date_nop</th>
<th width="5%">date_end</th>
<th>is_easy</th>
<th width="5%">Вер.%</th>
<th width="7%">additional_agreement</th>
</tr>
</thead>
<cfoutput query="qService" group="__index">
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="__id">#__index#</a></td>
<!--- <td class="c">#__name#</td> --->
<td class="l">#user_description#</td>
<td>
<table class="wide">
<cfset cost=0/>
<cfoutput group="p_uid">
<cfif p_cnt NEQ 0>
<tr>
<td class="nw">#code#</td>
<td>#name#</td>
<td>#p_cnt#</td>
<td>#ed_izm#</td>
<td class="r nw">#nFmt(price,3)#</td>
<td class="r">#p_discount#%</td>
</tr>
<cfset cost+=price*p_cnt*(100-(isNumeric(p_discount)?p_discount:0))/100 />
</cfif>
</cfoutput>
</table>
</td>
<td class="c">#cnt#</td>
<td class="c">#discount#%</td>
<td class="r">#nFmt(cost*cnt*(100-(isNumeric(discount)?discount:0))/100)#</td>
<td class="l">
#abstractive_service_code#.#modifier_code#<!--- <cfswitch expression=#type#>
<cfcase value=1>-i</cfcase>
<cfcase value=2>-f</cfcase>
<cfcase value=3>-m</cfcase>
</cfswitch> --->
</td>
<td class="c"<cfif type EQ 3> style="background:lightgreen"</cfif>>#type#</td>
<td class="c">#is_actual#</td>
<td class="c">#hash#</td>
<td class="c">#version#</td>
<td class="c">#name_version#</td>
<td class="c">#date_accept#</td>
<td class="c">#__index#</td>
<td class="c">#dateFormat(date_nop,'YYYY-MM-DD')#</td>
<td class="c<cfif isDate(date_end) AND date_end LT Now()> err</cfif>">#dateFormat(date_end,'YYYY-MM-DD')#</td>
<td class="c">#is_easy#</td>
<td class="c">#probability_pc#</td>
<!--- <td class="c">#additional_agreement_uid#</td> --->
<td class="c"><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
</tr>
</cfoutput>
</table>
<!--- ----------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------- --->
<cfquery name="qContract">
select
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
@@ -144,7 +286,7 @@
</cfquery>
<cfoutput>
<h4>Договоры (#qContract.recordCount#)</h4>
<h4><a name="agreements">Договоры</a> (#qContract.recordCount#)</h4>
</cfoutput>
<table class="worktable">
<thead>
@@ -179,10 +321,12 @@
component as (select siv.deal as deal_uids, siv.type, (siv.cnt*(100-COALESCE(siv.discount,0))/100*p.price*p.cnt*(100-COALESCE(p.discount,0))) as param_cost
from elma.deals_services siv
join elma.service_parametrs p on (p.__id = ANY(siv.params))
where p."__deletedAt" IS NULL AND siv."__deletedAt" IS NULL AND siv.is_actual
)
select
a.__id::text
,a.__name as additional_agreement
,a.__index
,a.contract_uid::text
,a.is_actual
,a.last_aa
@@ -197,16 +341,16 @@
,s.probability_pc
,u.__name as owner
,(select sum(param_cost)
from component
where d.__id = ANY(component.deal_uids) AND component.type IN (1)
from component p
where d.__id = p.deal_uids[1] AND p.type IN (1)
) as install
,(select sum(param_cost)
from component
where d.__id = ANY(component.deal_uids) AND component.type IN (2)
from component p
where d.__id = p.deal_uids[1] AND p.type IN (2)
) as periodical
,(select sum(param_cost)
from component
where d.__id = ANY(component.deal_uids) AND component.type IN (3)
from component p
where d.__id = p.deal_uids[1] AND p.type IN (3)
) as metered
from elma.additional_agreements a
join elma.aggrements c on (a.contract_uid=c.__id)
@@ -215,6 +359,7 @@
left outer join elma.comp_users_ext u on (d._owner=c.__id)
where c.company_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#d.__id# null=#!isValid("guid",d.__id)#/>
AND s.probability_pc > 0
order by a.__index
</cfquery>
@@ -228,6 +373,7 @@
<thead>
<tr>
<th>__id</th>
<th>__index</th>
<th>Доп. соглашение</th>
<th>Внут. н-р дог.</th>
<th>Дата договора</th>
@@ -243,6 +389,7 @@
<cfoutput query="qAdditionalAgreement">
<tr>
<td><a href="additional_agreement.cfm?__id=#__id#&#tr.fwx#">#__id#</a></td>
<td><a href="additional_agreement.cfm?__id=#__id#&#tr.fwx#">#__index#</a></td>
<td>#additional_agreement#</td>
<td><a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#agreement_id#</a></td>
<td>#dateFormat(date_of_aggrement,"YYYY-MM-DD")#</td>
@@ -250,9 +397,9 @@
<td>#status#</td>
<td>#probability_pc#</td>
<td>#owner#</td>
<td class="r">#nFmt(install)#</td>
<td class="r">#nFmt(periodical)#</td>
<td class="r">#nFmt(metered)#</td>
<td class="r nw">#nFmt(install)#</td>
<td class="r nw">#nFmt(periodical)#</td>
<td class="r nw">#nFmt(metered)#</td>
</tr>
</cfoutput>
</table>
@@ -270,6 +417,7 @@
component as (select siv.deal as deal_uids, siv.type, (siv.cnt*(100-COALESCE(siv.discount,0))/100*p.price*p.cnt*(100-COALESCE(p.discount,0))) as param_cost
from elma.deals_services siv
join elma.service_parametrs p on (p.__id = ANY(siv.params))
where p."__deletedAt" IS NULL AND siv."__deletedAt" IS NULL AND siv.is_actual
)
select
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
@@ -353,128 +501,12 @@
<td>#contract#</td>
<td><a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#agreement_id#</a></td>
<td>#dateFormat(date_of_aggrement,"YYYY-MM-DD")#</td>
<td class="r">#nFmt(install)#</td>
<td class="r">#nFmt(periodical)#</td>
<td class="r">#nFmt(metered)#</td>
<td class="r nw">#nFmt(install)#</td>
<td class="r nw">#nFmt(periodical)#</td>
<td class="r nw">#nFmt(metered)#</td>
</tr>
</cfoutput>
</table>
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<cfquery name="qService">
with
status(status, status_id, probability_pc) as (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
)
select
siv.__id
,siv.__name
,siv.user_description
,siv.discount
,siv.cnt
,siv.modifier_code
,siv.abstractive_service_code
,siv.is_actual
,siv.type
,siv.hash
,siv.version
,siv.name_version
,siv.date_accept
,siv.__index
,siv.date_nop
,siv.date_end
,siv.is_easy
,siv.params::text
,a.__id::text as additional_agreement_uid
,a.__name as additional_agreement
,(select
sum(siv.cnt*(100-COALESCE(siv.discount,0))/100*p.price*p.cnt*(100-COALESCE(p.discount,0))/100)
from elma.service_parametrs p
where p.__id = ANY (siv.params)
) as line_cost
,(select count(*)
from elma.service_parametrs p
where p.__id = ANY (siv.params)
) as param_cnt
,s.probability_pc
,d.__index
,d.__id as deal_uid
from elma.deals_services siv
join elma.deals d on d.__id=ANY(siv.deal)
join status s on (d.__status_status=s.status_id)
left outer join elma.additional_agreements a on (a.__id=ANY(siv.additional_agreement))
where d._companies=<cfqueryparam cfsqltype="cf_sql_other" value="#d.__id#" null=#!isValid("guid",d.__id)#/>
and siv.is_actual
order by version::int
</cfquery>
<cfoutput>
<h4>Услуги (версии строк спецификации, только актуальные) (#qService.recordCount#)</h4>
</cfoutput>
<!--- <layout:render_query query=#qService#/> --->
<table class="worktable">
<thead>
<tr>
<th>__index</th>
<!--- <th>__name</th> --->
<th width="12%">user_description</th>
<th>Кол-во</th>
<th>Скидка%</th>
<th width="5%">Сумма</th>
<th>Код</th>
<th>type</th>
<th>is_actual</th>
<th>hash</th>
<th>version</th>
<th>name_version</th>
<th>date_accept</th>
<th>__index</th>
<th width="5%">date_nop</th>
<th width="5%">date_end</th>
<th>is_easy</th>
<th>Компонентов</th>
<th width="12%">additional_agreement</th>
</tr>
</thead>
<cfoutput query="qService">
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="__id">#__index#</a></td>
<!--- <td class="c">#__name#</td> --->
<td class="l">#user_description#</td>
<td class="c">#cnt#</td>
<td class="c">#discount#</td>
<td class="r">#nFmt(line_cost)#</td>
<td class="l">
#abstractive_service_code#.#modifier_code#<!--- <cfswitch expression=#type#>
<cfcase value=1>-i</cfcase>
<cfcase value=2>-f</cfcase>
<cfcase value=3>-m</cfcase>
</cfswitch> --->
</td>
<td class="c">#type#</td>
<td class="c">#is_actual#</td>
<td class="c">#hash#</td>
<td class="c">#version#</td>
<td class="c">#name_version#</td>
<td class="c">#date_accept#</td>
<td class="c">#__index#</td>
<td class="c">#dateFormat(date_nop,'YYYY-MM-DD')#</td>
<td class="c">#dateFormat(date_end,'YYYY-MM-DD')#</td>
<td class="c">#is_easy#</td>
<td class="c">#param_cnt#</td>
<!--- <td class="c">#additional_agreement_uid#</td> --->
<td class="c"><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
</tr>
</cfoutput>
</table>
</cfif>
</cfif><!--- len(d.__id) --->
<layout:page section="footer"/>
+1 -1
View File
@@ -96,7 +96,7 @@ select count(*) as cnt from elma.companies where 1=1
</cfsavecontent>
<cfsavecontent variable="qRead.f_contragent">
<a href="contragent.cfm?__id=#__id#&#tr.fwx#">#__name#</a>
<a href="contragent.cfm?__id=#__id#&#tr.fwx#">#__name#</a> <a href="contragent_rpt.cfm?__id=#__id#&#tr.fwx#" style="float:right"><img src="img/view.gif" title="сводка по контрагенту"/></a>
</cfsavecontent>
</cfoutput>
+490
View File
@@ -0,0 +1,490 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent><m:silent silent="No">
<cffunction name="plain2HtmClean">
<cfargument name="s" type="string"/>
<cfreturn request.plain2htm(request.cleanHtm(s))/>
</cffunction>
<cffunction name="cleanInput">
<cfargument name="s" type="string"/>
<cfreturn htmlEditFormat(s)/>
</cffunction>
<m:prepare_detail entity="contragent" accessObject="" key="__id" pageInfoOut="pageInfo"/>
<d:bean readonly=true table="elma.companies" datasource="#request.DS#" output="d" status="status">
<d:param field="__id" type="uuid" key/>
<d:param field="__name" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="_inn" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="_kpp" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="id_klienta" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<!--- *** билдер показывает... <d:param field="wz_id" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/> --->
<!--- <d:param field="code_inn" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="code_kpp" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/> --->
</d:bean>
<m:dispatch_detail
usePRG="No"<!---*** --->
pageInfo=#pageInfo#
id="#d.__id#"
status=#pageInfo.status#
trackOut="tr"
idAttributesOut="id"
/>
<!--- decoration --->
<!--- <cfquery name="qDecoration" datasource="#request.DS#">
select
a.login as creator, a.shortname as creator_shortname, m.login as updater, m.shortname as updater_shortname
from contragent g
left outer join usr a on (g.creator_id=a.usr_id)
left outer join usr m on (g.updater_id=m.usr_id)
where g.contragent_id=<cfqueryparam attributeCollection=#id#/>
</cfquery> --->
</m:silent><!---
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput>
Отчет по контрагенту
<cfif len(d.__id)>
<b>#d.__name#</b>
[#d.__id#]
<b>#d.id_klienta#</b>
</cfif>
</cfoutput>
</layout:attribute>
</layout:page>
<!--- <cfif status.errorState GT 0>
<cfoutput><div class="err">#status.errorMessage#</div></cfoutput>
</cfif>
--->
<cfoutput>
<input type="hidden" name="__id" value="#d.__id#"/>
<input type="hidden" name="track" value="#tr.self#"/>
<input type="hidden" name="pass" value=""/><!--- pass marker to prevent save on submit --->
<div class="detail">
<div class="tr">
<div class="th">ID</div>
<div class="td">#d.__id#</div>
</div>
<div class="tr">
<div class="th">Контрагент</div>
<div class="td">#d.__name# <a href="contragent.cfm?__id=#d.__id#&#tr.fwx#">подробнее (из Элмы)...</a></div>
</div>
<div class="tr">
<div class="th">ИНН</div>
<div class="td">#d._inn#</div>
</div>
<div class="tr">
<div class="th">КПП</div>
<div class="td">#d._kpp#</div>
</div>
<div class="tr">
<div class="th">WZ</div>
<div class="td">#d.id_klienta#</div>
</div>
</div>
</cfoutput>
<layout:page section="extension" closeForm="Yes"/>
<cfif len(d.__id)>
<cfquery name="qService">
WITH
status(status, status_id, probability_pc)
AS (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
)
,line
AS (
SELECT siv.__id AS siv_uid
,siv.discount
,siv.type AS line_pricing_model_id
,siv.hash AS line_key
,siv.is_actual AS siv_is_actual
,siv.version::NUMERIC AS line_version
,siv.modifier_code
,siv.abstractive_service_code
,siv.__index AS siv_index
,d.__index AS deal_index
,d._companies
,a.index AS agreement_version
,siv.date_nop::DATE AS dt_from
,siv.date_end::DATE AS dt_to
,siv.is_easy AS is_simple
,siv.cnt
,s.probability_pc
,a.__id AS additional_agreement_uid
,a.contract_uid
,a.is_actual AS additional_agreement_is_actual
,a.deal_uid
,a.__name AS additional_agreement
,d.__name AS deal
,d.__status_status AS deal_status_id
,siv.user_description --
,siv.params
FROM elma.deals_services siv
JOIN elma.deals d ON (d.__id = ANY (siv.deal))
JOIN STATUS s ON (d.__status_status = s.status_id)
LEFT JOIN elma.additional_agreements a ON (a.__id = ANY (siv.additional_agreement))
WHERE siv.is_actual
AND siv."__deletedAt" IS NULL
AND d."__deletedAt" IS NULL
AND a."__deletedAt" IS NULL
AND s.probability_pc >= 50
--and a.is_actual *** возможно, схема версионности противоречива
AND siv.type IN (2, 3)
AND d._companies = <cfqueryparam cfsqltype="cf_sql_other" value=#d.__id#/><!--- '019503f2-5774-7768-b5c9-566a71daedaa' --->
)
,component
AS (
SELECT cnt
,code
,__id
,price
,ed_izm
,discount
,name
FROM elma.service_parametrs
WHERE "__deletedAt" IS NULL
)
,stair
AS (
SELECT *
FROM (
SELECT *
,MIN(dt_from) OVER (
PARTITION BY line_key ORDER BY deal_index DESC
) running_min_dt
,COALESCE((
LEAD(dt_from) OVER (
PARTITION BY line_key ORDER BY dt_from
,deal_index
)
), (
SELECT CURRENT_TIMESTAMP + INTERVAL '1 day'
)) dt_next
FROM line
WHERE probability_pc > 0
) t
WHERE t.dt_from = t.running_min_dt
--AND ( t.dt_to > CURRENT_TIMESTAMP OR t.dt_to IS NULL )
)
SELECT d.siv_uid::text as siv_uid
,d.siv_index
,d.deal
,d.user_description
,d.discount
,d.cnt
,d.modifier_code
,d.abstractive_service_code
,d.additional_agreement_is_actual
,d.line_pricing_model_id
,d.line_key
,d.deal_index
,d.dt_from
,d.dt_to
,d.dt_next
,d.is_simple
,d.additional_agreement_uid::text as additional_agreement_uid
,d.additional_agreement
,d.deal_index
,d.deal_uid::text as deal_uid
,s.probability_pc
,s.status_id
,s.STATUS
,p.price
,p.cnt as p_cnt
,p.ed_izm
,p.code
,p.discount as p_discount
,p.__id::text as p_uid
,p.name
FROM stair d
JOIN status s ON (d.deal_status_id = s.status_id)
LEFT JOIN LATERAL unnest(d.params) AS arr(param_id) ON TRUE
JOIN component p ON (p.__id = arr.param_id)
WHERE d.dt_from <= CURRENT_TIMESTAMP AND (CURRENT_TIMESTAMP < d.dt_next)
</cfquery>
<!--- <cfdump var=#qService#/> --->
<cfoutput>
<h3>Услуги по данным CRM (из DWH, версии строк спецификации, только актуальные на сегодня, сделки с вероятностью от 50% (начиная с тестирования) <!--- (#qService.recordCount#) ---></h3>
</cfoutput>
<table class="worktable">
<thead>
<tr>
<th width="3%">__index</th>
<th width="5%">Код</th>
<th width="20%">Пользовательское наименование</th>
<th width="30%">Компоненты</th>
<th width="3%">Кол-во</th>
<th width="5%">Сумма</th>
<th width="3%">Модель оплаты</th>
<th width="5%">Дата НОУ</th>
<th width="5%">date_end</th>
<th width="5%">Вер.%</th>
<th width="10%">Дополнительное соглашение</th>
<th width="5%">Ключ строки</th>
</tr>
</thead>
<cfoutput query="qService" group="siv_uid">
<tr<cfif NOT (left(abstractive_service_code,4) EQ "iaas" OR left(abstractive_service_code,7) EQ "paas.s3")> class="gray"</cfif>>
<td class="c"><a href="deal_service.cfm?__id=#siv_uid#&#tr.fwx#">#siv_index#</a></td>
<td class="l">#abstractive_service_code#<cfif len(modifier_code)>.#modifier_code#</cfif></td>
<td class="l">#user_description#</td>
<td style="padding:0; vertical-align:bottom;">
<table class="wide" style="height:100%">
<cfset cost = 0/>
<cfoutput group="p_uid">
<cfif p_cnt NEQ 0>
<tr>
<td class="nw">#code#</td>
<td>#name#</td>
<td class="r">#p_cnt#</td>
<td class="c">#ed_izm#</td>
<td class="r">#nFmt(price*p_cnt*(100-(isNumeric(p_discount)?p_discount:0))/100, 2)#</td>
</tr>
<cfset cost+=price*p_cnt*(100-(isNumeric(p_discount)?p_discount:0))/100 />
</cfif>
</cfoutput>
</table>
</td>
<td class="c">#cnt#</td>
<td class="r">#nFmt(cost*cnt*(100-(isNumeric(discount)?discount:0))/100)#</td>
<td class="c"<cfif line_pricing_model_id EQ 3> style="background:lightgreen;color:black;"</cfif>>
<cfswitch expression=#line_pricing_model_id#>
<cfcase value=1>install</cfcase>
<cfcase value=2>fix</cfcase>
<cfcase value=3>payg</cfcase>
</cfswitch> (#line_pricing_model_id#)
</td>
<!--- <td class="c">#is_actual#</td>
<td class="c">#__index#</td> --->
<td class="c">#dateFormat(dt_from,'YYYY-MM-DD')#</td>
<td class="c<cfif isDate(dt_to) AND dt_to LT Now()> err</cfif>">#dateFormat(dt_to,'YYYY-MM-DD')#</td>
<td class="c">#probability_pc#</td>
<td class="c"><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a> (#status_id# #status#)</td>
<td class="c">#line_key#</td>
</tr>
</cfoutput>
</table>
<!--- <i>отображаются позиции сделок, начиная с тестирования</i> --->
<h2>Текущее потребление по данным VmReports (VROPS)</h1>
<cfquery name="qCompute">
select
c."Organization_UUID"::text
,c."Organization"
,c."VDC"
,c."VDC_CPU_Reserv"
,"Cluster"
,round(sum(c."VM_RAM_Allocated")) as ram
,round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_RAM_Allocated" ELSE 0 END)) as ram_on
,round(sum(c."VM_vCPU_count")) as cpu
,round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_vCPU_count" ELSE 0 END)) as cpu_on
,round(avg(c."VDC_CPU_Speed")::numeric,1) as ghz
,min(c.ts) as ts
FROM vmreports.compute c
WHERE c.ts=(select max(ts) from vmreports.compute)
AND lower(c."WZ")=lower(<cfqueryparam cfsqltype="cf_sql_varchar" value="#d.id_klienta#"/>)
GROUP BY c."Organization_UUID", c."Organization", c."VDC", c."VDC_CPU_Reserv", c."Cluster"
</cfquery>
<cfquery name="qCompute_total" dbtype="query">
select
sum(ram) as ram
,sum(ram_on) as ram_on
,sum(cpu) as cpu
,sum(cpu_on) as cpu_on
FROM qCompute
</cfquery>
<h3>Compute факт <cfif len(qCompute.ts)><cfoutput>#dateFormat(qCompute.ts,'YYYY-MM-DD')# #timeFormat(qCompute.ts,'HH:MM:SS')#</cfoutput></cfif></h3>
<table class="worktable">
<thead>
<tr>
<th width="10%">Организация</th>
<th width="10%">VDC</th>
<th width="3%">Резерв %</th>
<th width="10%">Кластер</th>
<th width="3%">GHz</th>
<th width="5%">CPU cores</th>
<th width="5%">CPU_ON cores</th>
<th width="5%">RAM GB</th>
<th width="5%">RAM_ON GB</th>
</tr>
</thead>
<cfoutput query="qCompute">
<tr>
<td>#Organization#</td>
<td>#VDC#</td>
<td class="c">#VDC_CPU_Reserv#</td>
<td>#qCompute.Cluster#</td>
<td class="c">#ghz#</td>
<td class="r">#cpu#</td>
<td class="r">#cpu_on#</td>
<td class="r">#ram#</td>
<td class="r">#ram_on#</td>
</tr>
</cfoutput>
<cfoutput query="qCompute_total">
<tr>
<td colspan="5" class="r b">Итого:</td>
<td class="r b">#cpu#</td>
<td class="r b">#cpu_on#</td>
<td class="r b">#ram#</td>
<td class="r b">#ram_on#</td>
</tr>
</cfoutput>
</table>
<cfquery name="qStorage">
select
"Organization_UUID"::text
,"Organization"
,"VDC"
,"Cluster"
,"Storage_Policy"
,round(sum(c."Disk_Allocated")) as disk_alloc
,round(sum(c."Disk_Used")) as disk_used
,min(c.ts) as ts
FROM vmreports.storage c
WHERE c.ts=(select max(ts) from vmreports.storage)
AND lower(c."WZ")=lower(<cfqueryparam cfsqltype="cf_sql_varchar" value="#d.id_klienta#"/>)
GROUP BY c."Organization_UUID",c."Organization",c."VDC",c."Cluster",c."Storage_Policy"
</cfquery>
<cfquery name="qStorage_total" dbtype="query">
select
sum(disk_alloc) as disk_alloc
,sum(disk_used) as disk_used
FROM qStorage
</cfquery>
<h3>Storage факт <cfif len(qStorage.ts)><cfoutput>#dateFormat(qStorage.ts,'YYYY-MM-DD')# #timeFormat(qStorage.ts,'HH:MM:SS')#</cfoutput></cfif></h3>
<table class="worktable">
<thead>
<tr>
<th width="10%">Организация</th>
<!--- <th width="10%">Статус организации</th> --->
<th width="10%">VDC</th>
<th width="10%">Кластер</th>
<th width="10%">Политика хранения</th>
<th width="5%">Выделено GB</th>
<th width="5%">Используется GB</th>
</tr>
</thead>
<cfoutput query="qStorage">
<tr>
<td>#Organization#</td>
<td>#VDC#</td>
<td>#qCompute.Cluster#</td>
<td>#Storage_Policy#</td>
<td class="r">#disk_alloc#</td>
<td class="r">#disk_used#</td>
</tr>
</cfoutput>
<cfoutput query="qStorage_total">
<tr>
<td colspan="4" class="r b">Итого:</td>
<td class="r b">#disk_alloc#</td>
<td class="r b">#disk_used#</td>
</tr>
</cfoutput>
</table>
<cfquery name="qGpu">
select
"Object_UUID"::text
,"Org"
,"OrgStatus"
,"OrgVDC"
,(select STRING_AGG(DISTINCT "Cluster",',') FROM vmreports.compute c
WHERE ts=(select max(ts) from vmreports.compute)
AND g."Org"=c."Organization"
) as org_cluster
,"Name"
,"GPU"
,g.ts as ts
FROM vmreports.vm_gpu g
WHERE g.ts=(select max(ts) from vmreports.vm_gpu)
AND lower(g."ClientID")=lower(<cfqueryparam cfsqltype="cf_sql_varchar" value="#d.id_klienta#"/>)
</cfquery>
<h3>GPU факт <cfif len(qGpu.ts)><cfoutput>#dateFormat(qGpu.ts,'YYYY-MM-DD')# #timeFormat(qGpu.ts,'HH:MM:SS')#</cfoutput></cfif></h3>
<table class="worktable">
<thead>
<tr>
<th width="10%">Организация</th>
<th width="10%">Статус организации</th>
<th width="10%">VDC</th>
<th width="10%">Кластер</th>
<th width="10%">VM</th>
<th width="5%">GPU</th>
</tr>
</thead>
<cfoutput query="qGpu">
<tr>
<td>#Org#</td>
<td>#OrgStatus#</td>
<td>#OrgVDC#</td>
<td>#org_cluster#</td>
<td>#Name#</td>
<td>#GPU#</td>
</tr>
</cfoutput>
</table>
<!--- ----------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------- --->
<!--- <cfdump var=#qCompute#/>
<cfdump var=#qStorage#/> --->
</cfif><!--- len(d.__id) --->
<br/><br/>
добавить реестр GPU и VDC для поиска потеряшек
<layout:page section="footer"/>
+477
View File
@@ -0,0 +1,477 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent>
<m:prepare_ls entity="crm2cloud" settingsKey="crm2cloud" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<!--- *** нуждается в оптимизации, чтобы фильтр по контрагенту ускорял селект --->
<cfparam name="dt_report" default=#Now()#/>
<cfquery name="qRead" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
WITH
status(status, status_id, probability_pc) as
(
VALUES
('Закрыта неуспешно',7,0) ,
('Закрыта успешно',6,100) ,
('Договор подписан',5,100) ,
('Договор на подписании',15,90) ,
('Договор на согласовании',12,70),
('Тестирование',8,50) ,
('Отправлено ТКП',10,20) ,
('Внутреннее согласование',37,10),
('Проработка решения',4,10) ,
('Сбор потребностей',1,0)
)
-----------------------------
,line AS (
SELECT siv.__id AS siv_uid
,siv.discount
,siv.type AS line_pricing_model_id
,siv.HASH AS line_key
,siv.is_actual AS siv_is_actual
,siv.version::NUMERIC AS line_version
,d.__index AS deal_index
,d._companies
,a.INDEX AS agreement_version
,siv.date_nop::DATE AS dt_from
,siv.date_end::DATE AS dt_to
,siv.is_easy AS is_simple
,siv.cnt
,s.probability_pc
,a.__id AS agreement_uid
,a.contract_uid
,a.is_actual AS agreement_is_actual
,a.deal_uid
,d.__name AS deal
,d.__status_status AS deal_status_id
,siv.user_description
,siv.params
FROM elma.deals_services siv
JOIN elma.deals d ON (d.__id = ANY (siv.deal))
JOIN STATUS s ON (d.__status_status = s.status_id)
LEFT JOIN elma.additional_agreements a ON (a.__id = ANY (siv.additional_agreement))
WHERE siv.is_actual
AND siv."__deletedAt" IS NULL
AND d."__deletedAt" IS NULL
AND a."__deletedAt" IS NULL
AND s.probability_pc >= 50
--and a.is_actual
AND siv.type IN (2, 3)
)
-----------------------------
,component AS (
SELECT
-- price*cnt*(100.0-COALESCE(discount,0))/100.0 as cost ,
-- price ,
cnt
,code
,__id
FROM elma.service_parametrs
WHERE "__deletedAt" IS NULL
)
------------------------------
,stair AS (
SELECT *
FROM (
SELECT *
,MIN(dt_from) OVER (
PARTITION BY line_key ORDER BY deal_index DESC
) running_min_dt
,COALESCE((
LEAD(dt_from) OVER (
PARTITION BY line_key ORDER BY dt_from
,deal_index
)
), (
<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report+1#/>
<!--- CURRENT_TIMESTAMP + INTERVAL '1 day'--->
)) dt_next
FROM line
WHERE probability_pc > 0
) t
WHERE t.dt_from = t.running_min_dt
<!--- AND (t.dt_to > <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> OR t.dt_to IS NULL) --->
)
,line_expanded
AS (
SELECT line.*
,unnest(line.params) AS param_id
FROM line
)
-----------------------------
,alloc AS (
SELECT c."WZ" AS wz
,round(sum(c."VM_RAM_Allocated")) AS ram
,round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_RAM_Allocated" ELSE 0 END)) AS ram_on
,round(sum(c."VM_vCPU_count")) AS cpu
,round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_vCPU_count" ELSE 0 END)) AS cpu_on
,STRING_AGG(DISTINCT "Organization_Status",',') as organization_status
,COUNT(DISTINCT "Organization_UUID") as org_count
FROM vmreports.compute c
WHERE ts = (
SELECT max(ts)
FROM vmreports.compute
)
GROUP BY c."WZ"
)
,disk_alloc AS (
SELECT c."WZ" AS wz
,round(sum(c."Disk_Allocated")) AS disk_alloc
FROM vmreports.storage c
WHERE ts = (
SELECT max(ts)
FROM vmreports.storage
)
GROUP BY c."WZ"
)
-----------------------------
,sold_ram AS (
SELECT z.id_klienta AS WZ
,z.__name AS client
,z.__id AS company_uid
,round(sum(c.cnt * o.cnt)) AS quantity
,count(*) AS lines
,STRING_AGG(DISTINCT c.code, ', ' ORDER BY c.code) AS codes
FROM stair o
JOIN elma.companies z ON o._companies = z.__id
--LEFT JOIN component c on (c.__id = ANY (o.params))
LEFT JOIN line_expanded e ON o.siv_uid = e.siv_uid
LEFT JOIN component c ON c.__id = e.param_id
WHERE o.dt_from <= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/>
AND (<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> < o.dt_next)
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.ram-_'
AND (c.code LIKE 'iaas.ngc.%.ram-_' OR c.code LIKE 'iaas.dcp.%.ram-_')
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY z.id_klienta
,z.__id
,z.__name
)
------------------------------
,sold_cpu AS (
SELECT z.id_klienta AS WZ
,z.__name AS client
,z.__id AS company_uid
,round(sum(c.cnt * o.cnt)) AS quantity
,count(*) AS lines
,STRING_AGG(DISTINCT c.code, ', ' ORDER BY c.code) AS codes
FROM stair o
JOIN elma.companies z ON (o._companies = z.__id)
LEFT JOIN line_expanded e ON o.siv_uid = e.siv_uid
LEFT JOIN component c ON (c.__id = e.param_id)
WHERE o.dt_from <= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/>
AND (<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> < o.dt_next)
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.vcpu%-_'
AND (
c.code LIKE 'iaas.ngc.%.vcpu%-_'
OR c.code LIKE 'iaas.dcp.%.vcpu%-_'
)
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY z.id_klienta
,z.__id
,z.__name
)
---------------------------------
,sold_disk AS (
SELECT z.id_klienta AS WZ
,z.__name AS client
,z.__id AS company_uid
,round(sum(c.cnt * o.cnt)) AS quantity
,count(*) AS lines
,STRING_AGG(DISTINCT c.code, ', ' ORDER BY c.code) AS codes
FROM stair o
JOIN elma.companies z ON (o._companies = z.__id)
--LEFT JOIN component c ON c.__id = o.param_id
--LEFT JOIN component c on (c.__id = ANY (o.params))
LEFT JOIN line_expanded e ON o.siv_uid = e.siv_uid
LEFT JOIN component c ON c.__id = e.param_id
WHERE o.dt_from <= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/>
AND (<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> < o.dt_next)
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.(ssd|fstssd|sata)-_'
AND (
c.code LIKE 'iaas.ngc.%.ssd-_'
OR c.code LIKE 'iaas.dcp.%.ssd-_'
OR c.code LIKE 'iaas.ngc.%.fstssd-_'
OR c.code LIKE 'iaas.dcp.%.fstssd-_'
OR c.code LIKE 'iaas.ngc.%.sata-_'
OR c.code LIKE 'iaas.dcp.%.sata-_'
)
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY z.id_klienta
,z.__id
,z.__name
)
--------------------------------
,sold_gpu AS (
SELECT z.id_klienta AS WZ
,z.__name AS client
,z.__id AS company_uid
,round(sum(c.cnt * o.cnt)) AS quantity
,count(*) AS lines
,STRING_AGG(DISTINCT c.code, ', ' ORDER BY c.code) AS codes
FROM stair o
JOIN elma.companies z ON (o._companies = z.__id)
--LEFT JOIN component c ON c.__id = o.param_id
--LEFT JOIN component c on (c.__id = ANY (o.params))
LEFT JOIN line_expanded e ON o.siv_uid = e.siv_uid
LEFT JOIN component c ON c.__id = e.param_id
WHERE o.dt_from <= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/>
AND (<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> < o.dt_next)
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.vcpu%-_'
AND (
c.code LIKE 'iaas.ngc.%.gpu%-_'
OR c.code LIKE 'iaas.dcp.%.gpu%-_'
)
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY z.id_klienta
,z.__id
,z.__name
)
-------------------------------
,gpu_alloc AS (
SELECT c."ClientID" AS wz
,
-- json_agg("GPU") as gpu,
string_agg("GPU"::TEXT || ' ' || "OrgStatus", ', ') AS gpu
,count(*) AS gpu_alloc
FROM vmreports.vm_gpu c
WHERE ts = (
SELECT max(ts)
FROM vmreports.vm_gpu
)
GROUP BY c."ClientID"
)
--------------------------------
,deal_stat AS (
SELECT STRING_AGG(DISTINCT deal_status_id::TEXT, ', ' ORDER BY deal_status_id::TEXT) AS status_ids
,ARRAY_AGG(DISTINCT deal_status_id ORDER BY deal_status_id) AS ar_status_ids
,STRING_AGG(DISTINCT line_pricing_model_id::TEXT, ', ' ORDER BY line_pricing_model_id::TEXT) AS line_pricing_model_ids
,ARRAY_AGG(DISTINCT line_pricing_model_id ORDER BY line_pricing_model_id) AS ar_line_pricing_model_id
,z.id_klienta AS WZ
FROM stair d
--LEFT JOIN LATERAL unnest(d.params) AS arr(param_id) ON TRUE
--JOIN component p ON (p.__id = arr.param_id)
JOIN elma.companies z ON (d._companies = z.__id)
WHERE d.dt_from <= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/>
AND (<cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_report#/> < d.dt_next)
GROUP BY z.id_klienta
)
,manager AS (
select z.id_klienta as wz, u.__name as manager, u.email, u.__status_status as status
from elma.companies z
join elma.comp_users_ext u on (z.responsible=u.__id)
)
select
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
<d:field title="WZ Elma">r.wz as wz_sold</d:field>
<d:field title="Клиент">r.client as client_sold</d:field>
<d:field>r.company_uid</d:field>
<d:field title="WZ Cloud">a.wz as wz_alloc</d:field>
<d:field title="Manager">u.manager</d:field>
<d:field title="Manager Email">u.email</d:field>
<d:field title="Manager Status">u.status</d:field>
<d:field title="Статусы из VCD">a.organization_status</d:field><!--- список статусов через запятую --->
<d:field title="Статусы">ds.status_ids</d:field>
<d:field title="Модели оплаты">ds.line_pricing_model_ids</d:field>
<d:field title="Коды RAM">r.codes as ram_codes</d:field>
<d:field title="RAM GB Elma">r.quantity as ram_sold</d:field>
<d:field title="RAM Cloud">a.ram as ram_alloc</d:field>
<d:field title="RAM Cloud ON">a.ram_on as ram_alloc_on</d:field>
<d:field title="Коды CPU">c.codes as cpu_codes</d:field>
<d:field title="CPU Elma">c.quantity as cpu_sold</d:field>
<d:field title="CPU Cloud">a.cpu as cpu_alloc</d:field>
<d:field title="CPU Cloud ON">a.cpu_on as cpu_alloc_on</d:field>
<d:field title="Коды Дисков">d.codes as disk_codes</d:field>
<d:field title="Диски GB Elma">d.quantity as disk_sold</d:field>
<d:field title="Диски Cloud">da.disk_alloc</d:field>
<d:field title="Коды GPU">g.codes as gpu_codes</d:field>
<d:field title="GPU Elma">g.quantity as gpu_sold</d:field>
<d:field title="GPU Cloud">ga.gpu_alloc</d:field>
<d:field title="GPU">ga.gpu</d:field>
<d:field>z.__name as alloc_company</d:field>
<d:field>z.__id as alloc_company_uid</d:field>
<d:field>ds.ar_status_ids</d:field>
</d:field_set>
from sold_ram r
join deal_stat ds on (lower(r.wz)=lower(ds.wz))
join sold_cpu c on (lower(r.wz)=lower(c.wz))
left join sold_disk d on (lower(r.wz)=lower(d.wz))
left join sold_gpu g on (lower(r.wz)=lower(g.wz))
full join alloc a on (lower(r.wz)=lower(a.wz))
left join disk_alloc da on (a.wz=da.wz)
left join gpu_alloc ga on (a.wz=ga.wz)
left join elma.companies z on (lower(a.wz)=lower(z.id_klienta))
left join manager u on (lower(coalesce(r.wz,a.wz))=lower(u.wz))
where 1=1 <m:filter_build filter=#pageInfo.settings.filter#/>
order by <m:order_build sortArray=#pageInfo.settings.sort.sortArray# fieldCount=#fieldCount#/>
</cfquery>
<!--- <cfdump var=#qRead#> --->
<cfif isDefined("output_xls")>
<layout:xml qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
<cfabort/>
</cfif><cfif isDefined("output_json")>
<layout:json qRead=#qRead# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
<cfabort/>
</cfif><!---
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Сверка CRM - Cloud</b></cfoutput>
</layout:attribute>
</layout:page>
<!--- <cfdump var=#qRead# abort=true/> --->
<!---<cfoutput> <form method="post" action="">
Период с <input type="text" name="dt_start" value="#dateFormat(dt_start,'YYYY-MM-DD')#"/>
по <input type="text" name="dt_finish" value="#dateFormat(dt_finish,'YYYY-MM-DD')#"/>
<input type="submit" style="cursor:pointer;"/>
<input type="submit" name="DEBUG" value="DEBUG" style="cursor:pointer;"/>
</form> --->
<!--- Часов в периоде: <b>#hours#</b> Строк в отчете: <b>#qCharge.recordCount#</b><br/>
Актуальность данных:
VCD Computing: <b>#dateFormat(qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(qComputingAge.dt_load,'HH:MM:SS')#</b>
VCD Storage: <b>#dateFormat(qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(qStorageAge.dt_load,'HH:MM:SS')#</b>
S3 хранение: <b>#dateFormat(qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3VolAge.dt_load,'HH:MM:SS')#</b>
S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3OpsTrfAge.dt_load,'HH:MM:SS')#</b>
--->
<!--- <br/>
<a href="#request.thisPage#?output_xls" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
<a href="#request.thisPage#?output_json" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a></cfoutput>
<br/> --->
<layout:grid_summary
recordCount=#qRead.recordCount#
footerOut="gridFooter"
excelLink="Yes"
jsonLink="Yes"
/>
<table class="worktable">
<thead>
<layout:grid_head titleMap=#titleMap# sortArray=#pageInfo.settings.sort.sortArray#>
<th width="5%"><layout:column_head name="wz_sold"/></th>
<th width="10%"><layout:column_head name="client_sold"/></th>
<th width="5%"><layout:column_head name="wz_alloc"/></th>
<th width="5%"><layout:column_head name="manager"/></th>
<th width="3%"><layout:column_head name="status_ids"/></th>
<th width="5%"><layout:column_head name="organization_status"/></th>
<th width="3%"><layout:column_head name="line_pricing_model_ids"/></th>
<th width="10%"><layout:column_head name="cpu_codes"/></th>
<th width="3%"><layout:column_head name="cpu_sold"/></th>
<th width="3%"><layout:column_head name="cpu_alloc"/></th>
<th width="3%"><layout:column_head name="cpu_alloc_on"/></th>
<th width="10%"><layout:column_head name="ram_codes"/></th>
<th width="3%"><layout:column_head name="ram_sold"/></th>
<th width="3%"><layout:column_head name="ram_alloc"/></th>
<th width="3%"><layout:column_head name="ram_alloc_on"/></th>
<th width="10%"><layout:column_head name="disk_codes"/></th>
<th width="3%"><layout:column_head name="disk_sold"/></th>
<th width="3%"><layout:column_head name="disk_alloc"/></th>
<th width="10%"><layout:column_head name="gpu_codes"/></th>
<th width="3%"><layout:column_head name="gpu_sold"/></th>
<th width="3%"><layout:column_head name="gpu_alloc"/></th>
<th width="10%"><layout:column_head name="gpu"/></th>
<!--- <th width="3%"><layout:column_head name="disk_sold"/></th> --->
</layout:grid_head>
</thead>
<cfflush/>
<cfoutput query="qRead">
<tr>
<td>#wz_sold#</td>
<td>
<cfif len(wz_sold)>
<a href="contragent_rpt.cfm?__id=#company_uid#&#tr.fwx#">#client_sold#</a>
<cfelse>
<a href="contragent_rpt.cfm?__id=#alloc_company_uid#&#tr.fwx#">#alloc_company#</a>
</cfif>
</td>
<td>#wz_alloc#</td>
<td><a href="mailto:#email#"<cfif qRead.status NEQ 2> title="не работает"</cfif>><span<cfif qRead.status NEQ 2> class="err"</cfif>>#manager#</span></a></td>
<td>#status_ids#</td>
<td>#organization_status#</td>
<td>#line_pricing_model_ids#</td>
<td>#cpu_codes#</td>
<td class="r"<cfif len(wz_alloc)><cfif cpu_sold GT cpu_alloc> style="background:lightgreen;"</cfif><cfelse> style="background:yellow;"</cfif>>#cpu_sold#</td>
<td class="r"<cfif cpu_sold LT cpu_alloc> style="background:lightcoral;"</cfif>>#cpu_alloc#</td>
<td class="r"<cfif cpu_sold LT cpu_alloc_on> style="background:lightcoral;"</cfif>>#cpu_alloc_on#</td>
<td>#ram_codes#</td>
<td class="r"<cfif len(wz_alloc)><cfif ram_sold GT ram_alloc> style="background:lightgreen;"</cfif><cfelse> style="background:yellow;"</cfif>>#ram_sold#</td>
<td class="r"<cfif ram_sold LT ram_alloc> style="background:lightcoral;"</cfif>>#ram_alloc#</td>
<td class="r"<cfif ram_sold LT ram_alloc_on> style="background:lightcoral;"</cfif>>#ram_alloc_on#</td>
<td>#disk_codes#</td>
<td class="r"<cfif len(wz_alloc)><cfif disk_sold GT disk_alloc> style="background:lightgreen;"</cfif><cfelse> style="background:yellow;"</cfif>>#disk_sold#</td>
<td class="r"<cfif disk_sold LT disk_alloc> style="background:lightcoral;"</cfif>>#disk_alloc#</td>
<td>#gpu_codes#</td>
<td class="r"<cfif len(wz_alloc)><cfif gpu_sold GT gpu_alloc> style="background:lightgreen;"</cfif><cfelse> style="background:yellow;"</cfif>>#gpu_sold#</td>
<td class="r"<cfif gpu_sold LT gpu_alloc> style="background:lightcoral;"</cfif>>#gpu_alloc#</td>
<td>#gpu#</td>
</tr>
</cfoutput>
<cfquery name="qTotal" dbtype="query">
select
sum(cpu_sold) as cpu_sold
,sum(cpu_alloc) as cpu_alloc
,sum(cpu_alloc_on) as cpu_alloc_on
,sum(ram_sold) as ram_sold
,sum(ram_alloc) as ram_alloc
,sum(ram_alloc_on) as ram_alloc_on
,sum(disk_sold) as disk_sold
,sum(disk_alloc) as disk_alloc
,sum(gpu_sold) as gpu_sold
from qRead
</cfquery>
<cfoutput query="qTotal">
<tr class="b r">
<td colspan="7">Итого</td>
<td class="r"<cfif cpu_sold GT ram_alloc> style="background:lightgreen;"</cfif>>#cpu_sold#</td>
<td class="r"<cfif cpu_sold LT cpu_alloc> style="background:lightcoral;"</cfif>>#cpu_alloc#</td>
<td class="r"<cfif cpu_sold LT cpu_alloc_on> style="background:lightcoral;"</cfif>>#cpu_alloc_on#</td>
<td></td>
<td class="r"<cfif ram_sold GT ram_alloc> style="background:lightgreen;"</cfif>>#ram_sold#</td>
<td class="r"<cfif ram_sold LT ram_alloc> style="background:lightcoral;"</cfif>>#ram_alloc#</td>
<td class="r"<cfif ram_sold LT ram_alloc_on> style="background:lightcoral;"</cfif>>#ram_alloc_on#</td>
<td></td>
<td class="r"<cfif disk_sold GT disk_alloc> style="background:lightgreen;"</cfif>>#disk_sold#</td>
<td class="r"<cfif disk_sold LT disk_alloc> style="background:lightcoral;"</cfif>>#disk_alloc#</td>
<td></td>
<td class="r">#gpu_sold#</td>
</tr>
</cfoutput>
</table>
<layout:page section="footer"/>
+156
View File
@@ -0,0 +1,156 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent><m:silent silent="No">
<m:prepare_filter entity="crm2cloud" accessObject="" lsPage="crm2cloud" pageInfoOut="pageInfo" trackOut="tr"/>
<m:filter_settings target="crm2cloud"><!---*** вводит в заблуждение--->
<m:filterparam filter=#filter# param="contragent_id" ftype="guid" compare="EQ" field="z.__id" default=""/>
<m:filterparam filter=#filter# param="contragent" ftype="string" compare="LIKE%" field="z.__name" default=""/>
<m:filterparam filter=#filter# param="wz" ftype="string" compare="LIKE%" field="z.id_klienta" default=""/>
<m:filterparam filter=#filter# param="code" ftype="string" expression="(r.codes like ? OR r.codes like ? OR d.codes like ?)" suffix="%" prefix="%" default=""/>
<!--- <m:filterparam filter=#filter# param="status_id" ftype="numeric" expression="ds.ar_status_ids = ?" suffix="" prefix="" default=""/> --->
<!--- <m:filterparam filter=#filter# param="status_id" ftype="numeric" expression="(?=ANY(ds.ar_status_ids))" suffix="" prefix="" default=""/> --->
<m:filterparam filter=#filter# param="status_id_list" ftype="integer" list="Yes" expression="(ds.ar_status_ids && ARRAY[?])" suffix="" prefix="" default=""/>
<m:filterparam filter=#filter# param="line_pricing_model_id" ftype="numeric" expression="(?=ANY(ds.ar_line_pricing_model_id))" suffix="" prefix="" default=""/>
</m:filter_settings>
<cfif isDefined("resetAndClose") or isDefined("saveAndClose")>
<cflocation url="#tr.backUrl#" addtoken="No"/>
</cfif>
</m:silent><!--- ----------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title"><cfoutput>Сверка - фильтр</cfoutput></layout:attribute>
</layout:page>
<script type="text/javascript"/>
$(document).ready(function() {
try {
$("#contragent_id").searchable({maxMultiMatch: 50});
} catch (e) {alert(e)}
});
</script>
<cfoutput>
<input type="hidden" name="track" value="#tr.self#"/>
<div class="detail">
<div class="tr">
<div class="th"></div>
<div class="td">
<button type="button" name="reset" onClick="document.location.href='#request.thisPage#?reset=yes&track=#tr.self#'">#i18("Очистить","Clear")#</button>
</div>
</div>
<div class="tr">
<div class="th">Код артикула</div>
<div class="td">
<input type="text" name="code" value="#code#" size="50"/>
<i>#i18("по вхождению подстроки в любой из списков кодов","by substring")#</i>
</div>
</div>
<div class="tr">
<div class="th">Статус</div>
<div class="td">
<!--- *** костыль --->
<cfquery name="qStatus">
SELECT * from (
VALUES
--('Закрыта неуспешно',7,0) ,
('Закрыта успешно',6,100) ,
('Договор подписан',5,100) ,
('Договор на подписании',15,90) ,
('Договор на согласовании',12,70),
('Тестирование',8,50)
--('Отправлено ТКП',10,20) ,
--('Внутреннее согласование',37,10),
--('Проработка решения',4,10),
--('Сбор потребностей',1,0)
) as status (status, status_id, probability_pc)
ORDER BY probability_pc, status_id
</cfquery>
<c:combo
query=#qStatus#
combo="status_id_list"
id="status_id"
key="status_id"
displayf="##status## (##status_id##: ##probability_pc##%)"
selected=#status_id_list#
empty=""
multiple="multiple"
size="6"
/>
<i>для выбора нескольких значений используйте CTRL или SHIFT (для диапазона)</i>
</div>
</div>
<div class="tr">
<div class="th">Модель оплаты</div>
<div class="td">
<select name="line_pricing_model_id">
<option></option>
<option value="1"<cfif line_pricing_model_id EQ 1> selected</cfif>>1 install</option>
<option value=3""<cfif line_pricing_model_id EQ 2> selected</cfif>>2 fix</option>
<option value="3"<cfif line_pricing_model_id EQ 3> selected</cfif>>3 metered</option>
</select>
<i>по вхождению в список</i>
</div>
</div>
<div class="tr">
<div class="th">Контрагент</div>
<div class="td">
<input type="text" name="contragent" value="#contragent#" size="50"/>
<i>#i18("по вхождению подстроки","by substring")#</i>
</div>
</div>
<div class="tr">
<div class="th">WZ</div>
<div class="td">
<input type="text" name="wz" value="#wz#" size="50"/>
<i>#i18("по вхождению подстроки","by substring")#</i>
</div>
</div>
<div class="tr">
<div class="th">Контрагент</div>
<div class="td" style="vertical-align:top;">
<cfquery name="qList">
select __id::text as __id, __name, id_klienta
from elma.companies
order by __name
</cfquery>
<!--- <cfdump var=#qList#/> --->
<c:combo
query=#qList#
combo="contragent_id"
id="contragent_id"
key="__id"
displayf="##__name## ##id_klienta##"
selected=#contragent_id#
empty=""
/>
</div>
</div>
</div><!--- detail --->
</cfoutput>
<layout:page section="footer" closeForm="Yes"/>
<!--- <cfdump var=#filter#> --->
+14 -10
View File
@@ -257,18 +257,17 @@
<tr>
<th>__index</th>
<!--- <th>__name</th> --->
<th width="12%">user_description</th>
<th>Код</th><th>type</th><th width="12%">user_description</th>
<th>Кол-во</th>
<th>Скидка%</th>
<th width="5%">Сумма</th>
<th>Код</th>
<th>type</th>
<th>is_actual</th>
<th>hash</th>
<th>version</th>
<th>name_version</th>
<th>date_accept</th>
<th>__index</th>
<th width="5%">date_nop</th>
<th width="5%">date_end</th>
<th>is_easy</th>
@@ -281,10 +280,6 @@
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="__id">#__index#</a></td>
<!--- <td class="c">#__name#</td> --->
<td class="l">#user_description#</td>
<td class="c">#cnt#</td>
<td class="c">#discount#</td>
<td class="r">#nFmt(line_cost)#</td>
<td class="l">
#abstractive_service_code#.#modifier_code#<!--- <cfswitch expression=#type#>
<cfcase value=1>-i</cfcase>
@@ -292,13 +287,22 @@
<cfcase value=3>-m</cfcase>
</cfswitch> --->
</td>
<td class="c">#type#</td>
<td class="c">#type# (<cfswitch expression=#type#>
<cfcase value=1>i</cfcase>
<cfcase value=2>f</cfcase>
<cfcase value=3>m</cfcase>
</cfswitch>)</td>
<td class="l">#user_description#</td>
<td class="c">#cnt#</td>
<td class="c">#discount#</td>
<td class="r">#nFmt(line_cost)#</td>
<td class="c">#is_actual#</td>
<td class="c">#hash#</td>
<td class="c">#version#</td>
<td class="c">#name_version#</td>
<td class="c">#date_accept#</td>
<td class="c">#__index#</td>
<td class="c">#dateFormat(date_nop,'YYYY-MM-DD')#</td>
<td class="c">#dateFormat(date_end,'YYYY-MM-DD')#</td>
<td class="c"><cfif is_easy GT 0>Простая<cfelseif is_easy EQ 0>Композитная<cfelse>is_easy=#is_easy#</cfif></td>
+21
View File
@@ -13,6 +13,9 @@
<m:filterparam filter=#filter# param="contragent_id" ftype="guid" compare="EQ" field="k.__id" default=""/>
<m:filterparam filter=#filter# param="wz" ftype="string" compare="LIKE%" field="k.id_klienta" default=""/>
<m:filterparam filter=#filter# param="status_id" ftype="numeric" compare="EQ" field="d.__status_status" default=""/>
<m:filterparam filter=#filter# param="__index" ftype="numeric" compare="EQ" field="d.__index" default=""/>
<m:filterparam filter=#filter# param="probability_lt" ftype="numeric" compare="LT" field="s.probability_pc" default=""/>
<m:filterparam filter=#filter# param="probability_gt" ftype="numeric" compare="GT" field="s.probability_pc" default=""/>
</m:filter_settings>
<cfif isDefined("resetAndClose") or isDefined("saveAndClose")>
@@ -46,6 +49,14 @@ $(document).ready(function() {
</div>
</div>
<div class="tr">
<div class="th">Номер сделки</div>
<div class="td">
<input type="text" name="__index" value="#__index#" size="5"/>
<i></i>
</div>
</div>
<div class="tr">
<div class="th">Название сделки</div>
<div class="td">
@@ -117,6 +128,16 @@ $(document).ready(function() {
/>
</div>
</div>
<div class="tr">
<div class="th">Вероятность</div>
<div class="td">
<input type="text" name="probability_gt" value="#probability_gt#" size="3"/>
&lt; % &lt;
<input type="text" name="probability_lt" value="#probability_lt#" size="3"/>
</div>
</div>
</div><!--- detail --->
добавить сюда множественный выбор статуса
+4 -3
View File
@@ -52,9 +52,9 @@
where d.__id = ANY(siv.deal)
) as line_cnt
</d:field> --->
<!--- <d:field>(select count(*)
<!--- <d:field title="Строк">(select count(*)
from elma.deals_services siv
where d.__id = ANY(siv.deal) AND siv.is_actual
where d.__id = ANY(siv.deal) AND siv.is_actual AND siv."__deletedAt" IS NULL
) as line_cnt_actual
</d:field> --->
<!---<d:field>(select sum(param_cost)
@@ -157,7 +157,7 @@ select count(*) as cnt from elma.deals d where 1=1
</cfsavecontent>
<cfsavecontent variable="qRead.f_contragent">
<a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#contragent#</a>
<a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#contragent#</a> <a href="contragent_rpt.cfm?__id=#contragent_uid#&#tr.fwx#" style="float:right"><img src="img/view.gif" title="сводка по контрагенту"/></a>
</cfsavecontent>
</cfoutput>
@@ -176,6 +176,7 @@ select count(*) as cnt from elma.deals d where 1=1
<c:column width="3%" field="__status_status"><c:td class="c"/></c:column>
<c:column width="5%" field="status"><c:td class="c"/></c:column>
<c:column width="3%" field="probability_pc"><c:td class="c"/></c:column>
<!--- <c:column width="3%" field="line_cnt_actual"><c:td class="c"/></c:column> --->
<c:column width="5%" field="__createdAt" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="8%" field="owner"><c:td class="l"/></c:column>
<c:column width="5%" field="f_additional_agreement"><c:td class="l"/></c:column>
+84 -48
View File
@@ -145,17 +145,18 @@
from elma.service_parametrs p
join elma.deals_services siv on (p.__id = ANY (siv.params))
where siv.__id=<cfqueryparam cfsqltype="cf_sql_other" value=#d.__id# null=#!isValid("guid",d.__id)#/>
AND p."__deletedAt" IS NULL
</cfquery>
<b>#nFmt(qParamCost.line_cost)#</b> по строке, с количеством и скидкой (<b>#nFmt(qParamCost.param_cost)#</b> по компонентам)
</div>
</div>
<!---
<div class="tr">
<div class="th">Версия</div>
<div class="td">
#d.version# <i>вообще не понимаю, какой смысл вкладывается в эту цифру...</i>
</div>
</div>
</div> --->
<div class="tr">
<div class="th">Версии</div>
@@ -177,24 +178,24 @@
,(select
sum(siv.cnt*(100-COALESCE(siv.discount,0))/100*p.price*p.cnt*(100-COALESCE(p.discount,0))/100)
from elma.service_parametrs p
where p.__id = ANY (siv.params)
where p.__id = ANY (siv.params) AND p."__deletedAt" IS NULL
) as line_cost
from elma.deals_services siv
left outer join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
join elma.deals d on (d.__id = ANY(siv.deal))
left outer join status on (d.__status_status = status.status_id)
where hash=<cfqueryparam cfsqltype="cf_sql_varchar" value=#d.hash#/>
AND siv.is_actual
order by siv.__index, siv.version
AND siv."__deletedAt" IS NULL AND siv.is_actual
order by d.__index --siv.__index, siv.version
</cfquery>
<cfloop query=#qV#>
<cfif __id EQ toString(d.__id)>
<b>#aa_version#:#version#[#__index#]</b>
<cfelse>
<a href="deal_service.cfm?__id=#__id#&#tr.fwx#">#aa_version#:#version#[#__index#]</a>
<a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="версия_дс : версия_строки [индекс_сделки]">#aa_version#:#version#[#__index#]</a>
</cfif>
</cfloop>
(только актуальные и со сделкой)
(версия_дс : версия_строки [индекс_сделки], только актуальные и со сделкой)
</div>
</div>
@@ -241,10 +242,10 @@
</cfquery>
<!--- <cfdump var=#qDeal#/> --->
<cfif qDeal.recordCount>
<a href="deal.cfm?__id=#qDeal.__id#&#tr.fwx#">#qDeal.__id#</a> |
<a href="deal.cfm?__id=#qDeal.__id#&#tr.fwx#">#qDeal.__index# #qDeal.__id#</a> |
<a href="contragent.cfm?__id=#qDeal.contragent_uid#&#tr.fwx#">#qDeal.contragent# #qDeal.wz#</a> |
#qDeal.__name# |
_plannedDueDate: <cfif len(qDeal._plannedDueDate)><b>#dateFormat(qDeal._plannedDueDate,'DD.MM.YYYY')#</b><cfelse>--</cfif>
<!--- _plannedDueDate: <cfif len(qDeal._plannedDueDate)><b>#dateFormat(qDeal._plannedDueDate,'DD.MM.YYYY')#</b><cfelse>--</cfif> --->
<b>#qDeal.__status_status#: #qDeal.status# (#qDeal.probability_pc#%)</b>
</cfif>
</div>
@@ -256,12 +257,17 @@
<cfquery name="qAdditionalAgreement">
select
a.__id::text
,b.__id::text as base_by_uid
,a.__index
,a.__name as additional_agreement
,a2.__id::text as base_by_uid
,a2.__index
,a2.__name as base_by
,a.contract_uid::text
,a.is_actual
,a.last_aa
,a.deal_uid::text
,a2.deal_uid::text as deal2_uid
,d2.__name as deal2
,c.__name as contract
,c.agreement_id
,c.date_of_aggrement
@@ -270,23 +276,37 @@
,z.id_klienta as wz
from elma.deals_services siv
join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
join elma.additional_agreements b on (b.__id = ANY(a.base_by))
left outer join elma.additional_agreements a2 on (a2.__id = ANY(a.base_by))
left outer join elma.deals d2 on (a2.deal_uid = d2.__id)
left outer join elma.aggrements c on (a.contract_uid=c.__id)
left outer join elma.companies z on (c.company_uid=z.__id)
where siv.__id=<cfqueryparam cfsqltype="cf_sql_other" value=#d.__id# null=#!isValid("guid",d.__id)#/>
</cfquery>
<!--- <cfdump var=#qAdditionalAgreement#/> --->
<cfif len(qAdditionalAgreement.__id)>
<a href="additional_agreement.cfm?__id=#qAdditionalAgreement.__id#&#tr.fwx#">#qAdditionalAgreement.__id#</a> |
<a href="contragent.cfm?__id=#qAdditionalAgreement.contragent_uid#&#tr.fwx#">#qAdditionalAgreement.contragent# #qAdditionalAgreement.wz#</a> |
<a href="contract.cfm?__id=#qAdditionalAgreement.contract_uid#&#tr.fwx#">#qAdditionalAgreement.contract# (#qAdditionalAgreement.agreement_id#)
#dateFormat(qAdditionalAgreement.date_of_aggrement,"YYYY-MM-DD")#
<a href="additional_agreement.cfm?__id=#qAdditionalAgreement.__id#&#tr.fwx#">
#qAdditionalAgreement.__index# #qAdditionalAgreement.__id# #qAdditionalAgreement.additional_agreement#
</a> |
#qAdditionalAgreement.additional_agreement# |
<a href="contragent.cfm?__id=#qAdditionalAgreement.contragent_uid#&#tr.fwx#">
#qAdditionalAgreement.contragent# #qAdditionalAgreement.wz#
</a> |
Договор
<a href="contract.cfm?__id=#qAdditionalAgreement.contract_uid#&#tr.fwx#">
#qAdditionalAgreement.contract# (#qAdditionalAgreement.agreement_id#)
#dateFormat(qAdditionalAgreement.date_of_aggrement,"YYYY-MM-DD")#
</a>
<br/>
is_actual: <b>#qAdditionalAgreement.is_actual#</b>
last_aa: <b>#qAdditionalAgreement.last_aa#</b>
base_by: <a href="additional_agreement.cfm?__id=#qAdditionalAgreement.base_by_uid#&#tr.fwx#">#qAdditionalAgreement.base_by_uid#</a>
base_by: <a href="additional_agreement.cfm?__id=#qAdditionalAgreement.base_by_uid#&#tr.fwx#">
#qAdditionalAgreement.base_by_uid#
#qAdditionalAgreement.base_by#
</a>
(<a href="deal.cfm?__id=#qAdditionalAgreement.deal2_uid#&#tr.fwx#" title="сделка base_by">
#qAdditionalAgreement.deal2_uid#
#qAdditionalAgreement.deal2#
</a>)
</cfif>
</div>
</div>
@@ -369,8 +389,8 @@
<td class="c">#__index#</td>
<!--- <td class="c">#__name#</td> --->
<td class="c">#type#</td>
<td class="c">#code#</td>
<td class="c">#name#</td>
<td>#code#</td>
<td>#name#</td>
<td class="r">#cnt#</td>
<td class="c">#ed_izm#</td>
<td class="r">#price#</td>
@@ -414,16 +434,20 @@
left outer join elma.deals d on (d.__id = ANY(siv.deal))
left outer join status on (d.__status_status = status.status_id)
where hash=<cfqueryparam cfsqltype="cf_sql_varchar" value=#d.hash#/>
order by siv.__index, siv.version
order by d.__index desc
</cfquery>
<cfquery name="qVerActual" dbtype="query">
select * from qVer where is_actual > 0
</cfquery>
</cfquery> <!--- не повторяем сортировку, хотя это некорректно --->
<cfquery name="qVerDraft" dbtype="query">
select * from qVer where is_actual = 0 OR is_actual IS NULL
</cfquery><!--- не повторяем сортировку, хотя это некорректно --->
<cfoutput>
<h4>Версии строки (без черновиков) (#qVerActual.recordCount#)</h4>
<h4>Версии строки без черновиков (#qVerActual.recordCount#)</h4>
</cfoutput>
<table class="worktable">
@@ -431,47 +455,53 @@
<tr>
<th>Индекс версии</th>
<th>Создана</th>
<th>Версия доп.с.</th>
<th>Верс. доп.с.</th>
<th>Версия строки</th>
<th>is_actual</th>
<th>is actual</th>
<th>НОУ</th>
<th>КОУ</th>
<th>User Description</th>
<th>type</th>
<th>Кол-во</th>
<th>Скидка%</th>
<th>Скид&shy;ка%</th>
<th>Ст-ть</th>
<th>Сделка</th>
<th>Статус</th>
<th>Вер-ть</th>
<th>Вер.</th>
<th>Доп.с.</th>
</tr>
</thead>
<cfoutput query="qVerActual">
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="#__id#">#__index#</a></td>
<td class="c">#dateFormat(__createdAt,"YYYY-MM-DD")#</td>
<td class="c">
<cfif __id EQ toString(d.__id)>
<b>#__index#</b>
<cfelse>
<a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="#__id#">#__index#</a>
</cfif>
</td>
<td class="c nw">#dateFormat(__createdAt,"YYYY-MM-DD")#</td>
<td class="c">#aa_version#</td>
<td class="c">#version#</td>
<td class="c">#is_actual#</td>
<td class="c">#dateFormat(date_nop,"YYYY-MM-DD")#</td>
<td class="r">#dateFormat(date_end,"YYYY-MM-DD")#</td>
<td class="c">#user_description#</td>
<td class="c nw">#dateFormat(date_nop,"YYYY-MM-DD")#</td>
<td class="c nw">#dateFormat(date_end,"YYYY-MM-DD")#</td>
<td>#user_description#</td>
<td class="r">#type#</td>
<td class="c">#cnt#</td>
<td class="c">#discount#</td>
<td class="r">#nFmt(line_cost)#</td>
<td class="c"><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#" title="#deal_uid#">#deal#</a></td>
<td class="r nw">#nFmt(line_cost)#</td>
<td class="l"><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#" title="#deal_uid#">#deal#</a></td>
<td class="c">#__status_status#</td>
<td class="c">#probability_pc#</td>
<td class="c"><a href="additional_agreement.cfm?__id=#aa_uid#&#tr.fwx#" title="#aa_uid#">#additional_agreement#</a></td>
<td class="l"><a href="additional_agreement.cfm?__id=#aa_uid#&#tr.fwx#" title="#aa_uid#">#additional_agreement#</a></td>
</tr>
</cfoutput>
</table>
<cfoutput>
<h4>Версии строки (включая черновики) (#qVer.recordCount#)</h4>
<h4>Версии строки - черновики (#qVerDraft.recordCount#)</h4>
</cfoutput>
<table class="worktable">
@@ -479,40 +509,46 @@
<tr>
<th>Индекс версии</th>
<th>Создана</th>
<th>Версия доп.с.</th>
<th>Верс. доп.с.</th>
<th>Версия строки</th>
<th>is_actual</th>
<th>is actual</th>
<th>НОУ</th>
<th>КОУ</th>
<th>User Description</th>
<th>type</th>
<th>Кол-во</th>
<th>Скидка%</th>
<th>Скид&shy;ка%</th>
<th>Ст-ть</th>
<th>Сделка</th>
<th>Статус</th>
<th>Вер-ть</th>
<th>Вер.</th>
<th>Доп.с.</th>
</tr>
</thead>
<cfoutput query="qVer">
<cfoutput query="qVerDraft">
<tr>
<td class="c"><a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="#__id#">#__index#</a></td>
<td class="c">#dateFormat(__createdAt,"YYYY-MM-DD")#</td>
<td class="c">
<cfif __id EQ toString(d.__id)>
<b>#__index#</b>
<cfelse>
<a href="deal_service.cfm?__id=#__id#&#tr.fwx#" title="#__id#">#__index#</a>
</cfif>
</td>
<td class="c nw">#dateFormat(__createdAt,"YYYY-MM-DD")#</td>
<td class="c">#aa_version#</td>
<td class="c">#version#</td>
<td class="c">#is_actual#</td>
<td class="c">#dateFormat(date_nop,"YYYY-MM-DD")#</td>
<td class="r">#dateFormat(date_end,"YYYY-MM-DD")#</td>
<td class="c">#user_description#</td>
<td class="c nw">#dateFormat(date_nop,"YYYY-MM-DD")#</td>
<td class="c nw">#dateFormat(date_end,"YYYY-MM-DD")#</td>
<td class="l">#user_description#</td>
<td class="r">#type#</td>
<td class="c">#cnt#</td>
<td class="c">#discount#</td>
<td class="r">#nFmt(line_cost)#</td>
<td class="c"><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#" title="#deal_uid#">#deal#</a></td>
<td class="r nw">#nFmt(line_cost)#</td>
<td class="l"><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#" title="#deal_uid#">#deal#</a></td>
<td class="c">#__status_status#</td>
<td class="c">#probability_pc#</td>
<td class="c"><a href="additional_agreement.cfm?__id=#aa_uid#&#tr.fwx#" title="#aa_uid#">#additional_agreement#</a></td>
<td class="l"><a href="additional_agreement.cfm?__id=#aa_uid#&#tr.fwx#" title="#aa_uid#">#additional_agreement#</a></td>
</tr>
</cfoutput>
</table>
+19
View File
@@ -0,0 +1,19 @@
Все верно, это сам отчет по вм, чтобы он работал нужно еще передать ему resourceId= objUUID
его можно взять из отчета https://vao.mgmt.nubes.ru/suite-api/internal/views/d5bce32a-65c0-490b-87e2-835211697e59/data/export?resourceId=6f1e652e-cbb5-4940-bb07-e30805b9c992 поле objUUID
С уважением,
Крипитула Антон
Старший инженер
Моб. +7 (985) 418-55-64
akripitula@nubes.ru
@KripitulaAnton
nubes.ru
9 июня 2026 г., в 18:13, Мищук Сергей <smishchuk@nubes.ru> написал(а):
вроде нашел этот https://vao.mgmt.nubes.ru/suite-api/internal/views/89a1dded-e7d5-45ff-bd19-020991951d9a/data/export?resourceId=
+114
View File
@@ -0,0 +1,114 @@
with
status(status, status_id, probability_pc) as (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
)
,line_expanded as
(
SELECT
siv.__id as siv_uid ,
siv.discount ,
siv.type as line_pricing_model_id ,
siv.hash as line_key ,
siv.is_actual as siv_is_actual ,
siv.version::numeric as line_version ,
siv.modifier_code ,
siv.abstractive_service_code ,
d.__index as deal_index ,
d._companies ,
a.index as agreement_version ,
siv.date_nop::date as dt_from ,
siv.date_end::date as dt_to ,
siv.is_easy as is_simple ,
siv.cnt ,
s.probability_pc ,
a.__id as additional_agreement_uid ,
a.__name as additional_agreement ,
a.contract_uid ,
a.is_actual as additional_agreement_is_actual ,
a.deal_uid ,
d.__name as deal ,
d.__status_status as deal_status_id ,
siv.user_description
--,unnest(siv.params) as param_id
FROM elma.deals_services siv
JOIN elma.deals d on (d.__id = ANY(siv.deal))
JOIN status s on (d.__status_status=s.status_id)
LEFT JOIN elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
WHERE
siv.is_actual
AND siv."__deletedAt" IS NULL
and d."__deletedAt" IS NULL
and a."__deletedAt" IS NULL
and s.probability_pc >= 50
and siv.type IN (2,3)
),
component as
(
SELECT
cnt ,
code ,
__id,
price,
ed_izm,
discount,
name
FROM
elma.service_parametrs
where
"__deletedAt" IS NULL
),
stair as
(
select
*
FROM
(
SELECT
*,
MIN(dt_from) OVER (PARTITION BY line_key ORDER BY deal_index desc) running_min_dt
FROM
line_expanded
WHERE
probability_pc > 0
) t
WHERE
t.dt_from = t.running_min_dt
AND ( t.dt_to > CURRENT_TIMESTAMP OR t.dt_to IS NULL )
)
SELECT
d.siv_uid
,d.deal
,d.user_description
,d.discount
,d.cnt
,d.modifier_code
,d.abstractive_service_code
,d.siv_is_actual --
,d.line_pricing_model_id --
,d.line_key
,d.deal_index --
,d.dt_from --
,d.dt_to --
,d.is_simple --
--,d.params::text
,d.additional_agreement_uid
,d.additional_agreement
/*,p.price
,p.cnt as p_cnt
,p.ed_izm
,p.code
,p.discount as p_discount
,p.__id as p_uid
,p.name*/
,s.probability_pc
,s.status_id
,s.status
,d.deal_index
,d.deal_uid
FROM stair d
--left outer join component p on (d.param_id=p.__id)
JOIN status s on (d.deal_status_id=s.status_id)
where d._companies='019503f2-5774-7768-b5c9-566a71daedaa'
+455
View File
@@ -0,0 +1,455 @@
select * from
(
with
status(status, status_id, probability_pc) as
(
VALUES
('Закрыта неуспешно',7,0) ,
('Закрыта успешно',6,100) ,
('Договор подписан',5,100) ,
('Договор на подписании',15,90) ,
('Договор на согласовании',12,70),
('Тестирование',8,50) ,
('Отправлено ТКП',10,20) ,
('Внутреннее согласование',37,10),
('Проработка решения',4,10) ,
('Сбор потребностей',1,0)
),
line as
(
SELECT
siv.__id as siv_uid ,
siv.discount ,
siv.type as line_pricing_model_id ,
siv.hash as line_key ,
siv.is_actual as siv_is_actual ,
siv.version::numeric as line_version ,
d.__index as deal_index ,
d._companies ,
a.index as agreement_version ,
siv.date_nop::date as dt_from ,
siv.date_end::date as dt_to ,
siv.is_easy as is_simple ,
siv.cnt ,
s.probability_pc ,
a.__id as agreement_uid ,
a.contract_uid ,
a.is_actual as agreement_is_actual ,
a.deal_uid ,
d.__name as deal ,
d.__status_status as deal_status_id ,
siv.user_description ,
siv.params
FROM
elma.deals_services siv
JOIN elma.deals d on (d.__id = ANY(siv.deal))
JOIN status s on (d.__status_status=s.status_id)
LEFT JOIN elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
WHERE
siv.is_actual
AND siv."__deletedAt" IS NULL
and d."__deletedAt" IS NULL
and a."__deletedAt" IS NULL
and a.is_actual
and siv.type IN (2,3)
),
component as
(
SELECT
price*cnt*(100.0-COALESCE(discount,0))/100.0 as cost ,
price ,
cnt ,
code ,
__id
FROM
elma.service_parametrs
where
"__deletedAt" IS NULL
),
stair as
(
select
*
FROM
(
SELECT
*,
MIN(dt_from) OVER (PARTITION BY line_key ORDER BY deal_index desc) running_min_dt
FROM
line
WHERE
probability_pc > 0
) t
WHERE
t.dt_from = t.running_min_dt
AND t.dt_to > CURRENT_TIMESTAMP
OR t.dt_to IS NULL
),
alloc as
(
select
c."WZ" as wz ,
round(sum(c."VM_RAM_Allocated")) as ram ,
round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_RAM_Allocated" ELSE 0 END)) as ram_on ,
round(sum(c."VM_vCPU_count")) as cpu ,
round(sum(CASE WHEN "VM_is_ON" > 0 then c."VM_vCPU_count" ELSE 0 END)) as cpu_on
from
vmreports.compute c
where
ts= (select max(ts) from vmreports.compute)
group by c."WZ"
),
disk_alloc as
(
select
c."WZ" as wz ,
round(sum(c."Disk_Allocated")) as disk_alloc
from
vmreports.storage c
where
ts= (select max(ts) from vmreports.compute)
group by
c."WZ"
),
sold_ram as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
c.code SIMILAR TO 'iaas.(ngc|dcp).%.ram-_'
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
sold_cpu as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN
elma.companies z on (o._companies=z.__id)
LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
c.code SIMILAR TO 'iaas.(ngc|dcp).%.vcpu%-_'
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
sold_disk as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
c.code SIMILAR TO 'iaas.(ngc|dcp).%.(ssd|fstssd|sata)-_'
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
deal_stat as
(
select
STRING_AGG(distinct deal_status_id::text,', ' order by deal_status_id::text) as status_ids ,
STRING_AGG(distinct line_pricing_model_id::text,', ' order by line_pricing_model_id::text) as line_pricing_model_ids ,
z.id_klienta as WZ
from
line o
join elma.companies z on (o._companies=z.__id)
GROUP BY
z.id_klienta
)
select
r.wz as wz_sold ,
r.client as client_sold ,
r.company_uid ,
a.wz as wz_alloc ,
ds.status_ids ,
ds.line_pricing_model_ids ,
r.codes as ram_codes ,
r.quantity as ram_sold ,
a.ram as ram_alloc ,
a.ram_on as ram_alloc_on ,
c.codes as cpu_codes ,
c.quantity as cpu_sold ,
a.cpu as cpu_alloc ,
a.cpu_on as cpu_alloc_on ,
d.codes as disk_codes ,
d.quantity as disk_sold ,
da.disk_alloc ,
z.__name as alloc_company,
z.__id as alloc_company_uid
from
sold_ram r
join deal_stat ds on (lower(r.wz)=lower(ds.wz))
join sold_cpu c on (lower(r.wz)=lower(c.wz))
left join sold_disk d on (lower(r.wz)=lower(d.wz))
full join alloc a on (lower(r.wz)=lower(a.wz))
left join disk_alloc da on (a.wz=da.wz)
left join elma.companies z on (lower(a.wz)=lower(z.id_klienta))
)
intersect all
select * from
(
WITH
status(status, status_id, probability_pc) as
(
VALUES
('Закрыта неуспешно',7,0) ,
('Закрыта успешно',6,100) ,
('Договор подписан',5,100) ,
('Договор на подписании',15,90) ,
('Договор на согласовании',12,70),
('Тестирование',8,50) ,
('Отправлено ТКП',10,20) ,
('Внутреннее согласование',37,10),
('Проработка решения',4,10) ,
('Сбор потребностей',1,0)
),
line_expanded as
(
SELECT
siv.__id as siv_uid ,
siv.discount ,
siv.type as line_pricing_model_id ,
siv.hash as line_key ,
siv.is_actual as siv_is_actual ,
siv.version::numeric as line_version ,
d.__index as deal_index ,
d._companies ,
a.index as agreement_version ,
siv.date_nop::date as dt_from ,
siv.date_end::date as dt_to ,
siv.is_easy as is_simple ,
siv.cnt ,
s.probability_pc ,
a.__id as agreement_uid ,
a.contract_uid ,
a.is_actual as agreement_is_actual ,
a.deal_uid ,
d.__name as deal ,
d.__status_status as deal_status_id ,
siv.user_description ,
unnest(siv.params) as param_id
FROM
elma.deals_services siv
JOIN elma.deals d on (d.__id = ANY(siv.deal))
JOIN status s on (d.__status_status=s.status_id)
LEFT JOIN elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
WHERE
siv.is_actual
AND siv."__deletedAt" IS NULL
and d."__deletedAt" IS NULL
and a."__deletedAt" IS NULL
and a.is_actual
and siv.type IN (2,3)
),
component as
(
SELECT
price*cnt*(100.0-COALESCE(discount,0))/100.0 as cost ,
price ,
cnt ,
code ,
__id
FROM
elma.service_parametrs
where
"__deletedAt" IS NULL
),
stair as
(
select
*
FROM
(
SELECT
*,
MIN(dt_from) OVER (PARTITION BY line_key ORDER BY deal_index desc) running_min_dt
FROM
line_expanded
--line
WHERE
probability_pc > 0
) t
WHERE
t.dt_from = t.running_min_dt
AND t.dt_to > CURRENT_TIMESTAMP
OR t.dt_to IS NULL
),
alloc as
(
select
c."WZ" as wz ,
round(sum(c."VM_RAM_Allocated")) as ram ,
round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_RAM_Allocated" ELSE 0 END)) as ram_on ,
round(sum(c."VM_vCPU_count")) as cpu ,
round(sum(CASE WHEN "VM_is_ON" > 0 then c."VM_vCPU_count" ELSE 0 END)) as cpu_on
from
vmreports.compute c
where
ts= (select max(ts) from vmreports.compute)
group by c."WZ"
),
disk_alloc as
(
select
c."WZ" as wz ,
round(sum(c."Disk_Allocated")) as disk_alloc
from
vmreports.storage c
where
ts= (select max(ts) from vmreports.compute)
group by
c."WZ" ),
sold_ram as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN elma.companies z on o._companies=z.__id
LEFT JOIN component c on c.__id = o.param_id
--LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.ram-_'
(c.code LIKE 'iaas.ngc.%.ram-_' OR c.code LIKE 'iaas.dcp.%.ram-_')
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
sold_cpu as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN
elma.companies z on (o._companies=z.__id)
LEFT JOIN component c on c.__id = o.param_id
--LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.vcpu%-_'
(c.code LIKE 'iaas.ngc.%.vcpu%-_' OR c.code LIKE 'iaas.dcp.%.vcpu%-_')
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
sold_disk as
(
SELECT
z.id_klienta as WZ ,
z.__name as client ,
z.__id as company_uid,
round(sum(c.cnt*o.cnt)) as quantity ,
count(*) as lines ,
STRING_AGG(c.code,', ' order by c.code) as codes
FROM
stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT JOIN component c on c.__id = o.param_id
--LEFT JOIN component c on (c.__id = ANY (o.params))
WHERE
--c.code SIMILAR TO 'iaas.(ngc|dcp).%.(ssd|fstssd|sata)-_'
(c.code LIKE 'iaas.ngc.%.ssd-_' OR c.code LIKE 'iaas.dcp.%.ssd-_'
or c.code LIKE 'iaas.ngc.%.fstssd-_' OR c.code LIKE 'iaas.dcp.%.fstssd-_'
or c.code LIKE 'iaas.ngc.%.sata-_' OR c.code LIKE 'iaas.dcp.%.sata-_'
)
AND c.cnt <> 0
AND o.cnt <> 0
GROUP BY
z.id_klienta,
z.__id ,
z.__name
),
deal_stat as
(
select
STRING_AGG(distinct deal_status_id::text,', ' order by deal_status_id::text) as status_ids ,
STRING_AGG(distinct line_pricing_model_id::text,', ' order by line_pricing_model_id::text) as line_pricing_model_ids ,
z.id_klienta as WZ
from
line_expanded o
--line o
join elma.companies z on (o._companies=z.__id)
GROUP BY
z.id_klienta
)
select
r.wz as wz_sold ,
r.client as client_sold ,
r.company_uid ,
a.wz as wz_alloc ,
ds.status_ids ,
ds.line_pricing_model_ids ,
r.codes as ram_codes ,
r.quantity as ram_sold ,
a.ram as ram_alloc ,
a.ram_on as ram_alloc_on ,
c.codes as cpu_codes ,
c.quantity as cpu_sold ,
a.cpu as cpu_alloc ,
a.cpu_on as cpu_alloc_on ,
d.codes as disk_codes ,
d.quantity as disk_sold ,
da.disk_alloc ,
z.__name as alloc_company,
z.__id as alloc_company_uid
from
sold_ram r
join deal_stat ds on (lower(r.wz)=lower(ds.wz))
join sold_cpu c on (lower(r.wz)=lower(c.wz))
left join sold_disk d on (lower(r.wz)=lower(d.wz))
full join alloc a on (lower(r.wz)=lower(a.wz))
left join disk_alloc da on (a.wz=da.wz)
left join elma.companies z on (lower(a.wz)=lower(z.id_klienta))
)
+8
View File
@@ -0,0 +1,8 @@
CREATE INDEX ON ngcloud_ru.capacity_resource (timestamp);
CREATE INDEX ON ngcloud_ru.capacity_storage (timestamp);
CREATE INDEX ON s3billing.bucket_stat (timestamp_addition);
CREATE INDEX ON s3billing.usage_bucket_by_user (time);
CREATE INDEX ON gpu.vm (dt_load);
CREATE INDEX ON gpu.vm_power_state (ts);
+64
View File
@@ -0,0 +1,64 @@
with
capacity as (
select "Cluster" as cluster, count(*) as hosts, sum(cores) as cores, round(sum(ghz)) as ghz, round(sum(ram)) as ram
from (
select "Cluster", "Host"
, avg("Host_CPU_Cores") as cores, avg("Host_CPU_Cores"*"Host_CPU_Speed") as ghz, avg("Host_RAM"*.85) as ram
from vmreports.compute
where ts=(select max(ts) from vmreports.compute)
group by "Cluster","Host"
order by "Cluster","Host"
) host
group by "Cluster"),
usage as (
select "Cluster" as cluster
, sum("VM_vCPU_count") as vm_cores
, round(sum("VM_vCPU_count"*"VDC_CPU_Speed")) as vm_ghz
, round(sum("VM_CPU_Reserv_GHz")) as vm_ghz_reserved
, round(sum("VM_vCPU_count"*"VDC_CPU_Speed"*"VM_CPU_Reserv_perc"/100)) as vm_ghz_reserved_c
, round(sum("VM_vCPU_count"*"VDC_CPU_Speed"*(case when "VM_CPU_Reserv_perc" IS null then 20 when "VM_CPU_Reserv_perc"<=20 then 20 else "VM_CPU_Reserv_perc" end)/100)) as vm_ghz_promised
-- promised - зарезервированные ГГц, если включить минимальное согласованное резервирование
, round(sum("VM_RAM_Allocated")) as vm_ram_alloc
, round(sum("VM_RAM_Used")) as vm_ram_used
from vmreports.compute
where ts=(select max(ts) from vmreports.compute)
group by "Cluster"),
cluster_stat as (
SELECT
h."Cluster" as cluster
,h."Cluster_v2" as cluster_v2
,m.models
,COUNT(*) as hosts_total
,sum(CASE WHEN "Maintenance"='inMaintenance' THEN 1 ELSE 0 END) as hosts_in_maintenance
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN 1 ELSE 0 END) as hosts_in_service
,sum("CPU_Cores"*"CPU_Sockets") as cores
,sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Cores"*"CPU_Sockets" ELSE 0 END) as cores_in_service
,round(sum(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Cores"*"CPU_Sockets"*"CPU_Speed" ELSE 0 END)::numeric,1) as ghz_in_service
,round(avg(CASE WHEN "Maintenance"='notInMaintenance' THEN "CPU_Speed" ELSE 0 END)::numeric,1) as ghz
,CASE WHEN sum("CPU_Cores"*"CPU_Sockets") > 0 THEN round((sum("CPU_Used_AVG"*"CPU_Cores"*"CPU_Sockets")/sum("CPU_Cores"*"CPU_Sockets"))::numeric,0) ELSE NULL END as cpu_usage_perc
FROM vmreports.host h
LEFT OUTER JOIN (
SELECT hi."Cluster", STRING_AGG(DISTINCT hi."Model" || ' [' || (hi.cnt::text) || '] ',', ') as models
FROM (
SELECT hii."Cluster", hii."Model", count(hii."Model") as cnt
FROM vmreports.host hii
WHERE hii.ts=(SELECT max(ts) FROM vmreports.host)
GROUP BY hii."Cluster", hii."Model"
) hi GROUP BY hi."Cluster"
) m ON (h."Cluster"=m."Cluster")
WHERE ts=(SELECT max(ts) FROM vmreports.host)
GROUP BY h."Cluster", h."Cluster_v2", m.models
ORDER BY h."Cluster"
)
select h.cluster
,h.cluster_v2
,h.models
,c.hosts, c.cores as Cores_Capacity
, c.ghz as GHz_Capacity, u.vm_ghz_reserved, u.vm_ghz_promised, round((u.vm_ghz_promised/c.ghz)::numeric,2) as GHz_provision_rate
, c.ram as RAM_Capacity, u.vm_ram_alloc, u.vm_ram_used, round((u.vm_ram_alloc/c.ram)::numeric,2) as GB_provision_rate
from cluster_stat h
left outer join usage u on (h.cluster=u.cluster)
left outer join capacity c on (h.cluster=c.cluster)
+68
View File
@@ -0,0 +1,68 @@
drop table if exists vmreports.host;
create table vmreports.host(
"Name" varchar(255) NULL,
"Model" varchar(255) NULL,
"Cluster" varchar(255) NULL,
"Cluster_v2" varchar(255) NULL,
"Maintenance" varchar(255) NULL,
"CPU_Cores" float NULL,
"CPU_Sockets" float NULL,
"CPU_Speed" float NULL,
"RAM_Total" float NULL,
"RAM_Used" float NULL,
"CPU_Used" float NULL,
"CPU_Used_AVG" float NULL,
"CPU_Contention_95" float NULL,
"Object_UUID" uuid NOT NULL,
ts timestamptz NOT NULL
,CONSTRAINT PK_host PRIMARY KEY (ts, "Object_UUID")
);
grant all on vmreports.host to nifi;
--alter table vmreports.host ADD "Cluster_v2" varchar(255) NULL;
/*
{
"type": "record",
"name": "vmreports.host",
"namespace": "org.apache.nifi",
"fields": [
{"name":"Object_UUID", "type":{"type": "string", "logicalType": "uuid"}},
{"name":"ts","type":{"type": "long", "logicalType": "local-timestamp-millis"}},
{"name":"Name", "type":["string" ,"null"]},
{"name":"Model", "type":["string" ,"null"]},
{"name":"Cluster", "type":["string" ,"null"]},
{"name":"Cluster_v2", "type":["string" ,"null"]},
{"name":"Maintenance", "type":["string" ,"null"]},
{"name":"CPU_Cores", "type":["float" ,"null"]},
{"name":"CPU_Sockets", "type":["float" ,"null"]},
{"name":"CPU_Speed", "type":["float" ,"null"]},
{"name":"RAM_Total", "type":["float" ,"null"]},
{"name":"RAM_Used", "type":["float" ,"null"]},
{"name":"CPU_Used", "type":["float" ,"null"]},
{"name":"CPU_Used_AVG", "type":["float" ,"null"]},
{"name":"CPU_Contention_95", "type":["float" ,"null"]}
]
}
*/
/*
{
"*": {
"objId":"[&1].Name",
"1":"[&1].Model",
"2":"[&1].Cluster",
"3":"[&1].Cluster_v2",
"4":"[&1].Maintenance",
"5":"[&1].CPU_Cores",
"6":"[&1].CPU_Sockets",
"7":"[&1].CPU_Speed",
"8":"[&1].RAM_Total",
"9":"[&1].RAM_Used",
"10":"[&1].CPU_Used",
"11":"[&1].CPU_Used_AVG",
"12":"[&1].CPU_Contention_95",
"objUUID":"[&1].Object_UUID"
}
}
*/
+144
View File
@@ -0,0 +1,144 @@
WITH
status(status, status_id, probability_pc) as (VALUES
('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70),
('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0)
),
line as (
SELECT siv.__id as siv_uid, siv.discount, siv.type as line_pricing_model_id
,siv.hash as line_key, siv.is_actual as siv_is_actual
,siv.version::numeric as line_version
,d.__index as deal_index
,d._companies
,a.index as agreement_version
,siv.date_nop::date as dt_from
,siv.date_end::date as dt_to
,siv.is_easy as is_simple
,siv.cnt -- should mutiliply
,s.probability_pc
,a.__id as agreement_uid, a.contract_uid, a.is_actual as agreement_is_actual, a.deal_uid
,d.__name as deal, d.__status_status as deal_status_id
--,c.__name as contract
,siv.user_description
,siv.params
--,(SELECT sum(p.price*p.cnt*(100.0-COALESCE(p.discount,0.0))/100.0) FROM elma.service_parametrs p WHERE(p.__id = ANY (siv.params))) as cost
FROM elma.deals_services siv
JOIN elma.deals d on (d.__id = ANY(siv.deal))
JOIN status s on (d.__status_status=s.status_id)
LEFT OUTER JOIN elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement))
WHERE siv.is_actual AND siv."__deletedAt" IS NULL AND d."__deletedAt" IS NULL AND a."__deletedAt" IS NULL
AND a.is_actual
AND siv.type IN (2,3)
),
component as (
SELECT
price*cnt*(100.0-COALESCE(discount,0))/100.0 as cost
,price
,cnt
,code
,__id
FROM elma.service_parametrs
where "__deletedAt" IS NULL
),
stair as ( -- рабочая лесенка (инстансы строк, имеющие нетривиальную вероятность)
select * FROM (
SELECT *,
MIN(dt_from) OVER (PARTITION BY line_key ORDER BY deal_index desc) running_min_dt
FROM line --WHERE probability_pc > 0
) t
WHERE t.dt_from = t.running_min_dt
),
alloc as (select c."WZ" as wz
, round(sum(c."VM_RAM_Allocated")) as ram
, round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_RAM_Allocated" ELSE 0 END)) as ram_on
, round(sum(c."VM_vCPU_count")) as cpu
, round(sum(CASE WHEN "VM_is_ON" > 0 THEN c."VM_vCPU_count" ELSE 0 END)) as cpu_on
from vmreports.compute c
where ts=(select max(ts) from vmreports.compute)
group by c."WZ"
),
disk_alloc as (select c."WZ" as wz
, round(sum(c."Disk_Allocated")) as disk_alloc
from vmreports.storage c
where ts=(select max(ts) from vmreports.storage)
group by c."WZ"
),
sold_ram as (SELECT
z.id_klienta as WZ, z.__name as client, round(sum(c.cnt*o.cnt)) as quantity
,count(*) as lines, STRING_AGG(c.code,', ') as codes
/*,o.line_key, o.probability_pc, dt_next, o.deal_uid, o.deal, o.agreement_uid, o.line_pricing_model_id,o.dt_from, o.dt_to*/
FROM stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT OUTER JOIN component c on (c.__id = ANY (o.params))
WHERE c.code LIKE 'iaas.ngc.%.ram-_'
GROUP BY z.id_klienta, z.__name
),
sold_cpu as (SELECT
z.id_klienta as WZ, z.__name as client, round(sum(c.cnt*o.cnt)) as quantity
,count(*) as lines, STRING_AGG(c.code,', ') as codes
/*,o.line_key, o.probability_pc, dt_next, o.deal_uid, o.deal, o.agreement_uid, o.line_pricing_model_id,o.dt_from, o.dt_to*/
FROM stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT OUTER JOIN component c on (c.__id = ANY (o.params))
WHERE c.code LIKE 'iaas.ngc.%.vcpu-_'
GROUP BY z.id_klienta, z.__name
),
sold_disk as (SELECT
z.id_klienta as WZ, z.__name as client, round(sum(c.cnt*o.cnt)) as quantity
,count(*) as lines, STRING_AGG(c.code,', ') as codes
/*,o.line_key, o.probability_pc, dt_next, o.deal_uid, o.deal, o.agreement_uid, o.line_pricing_model_id,o.dt_from, o.dt_to*/
FROM stair o
JOIN elma.companies z on (o._companies=z.__id)
LEFT OUTER JOIN component c on (c.__id = ANY (o.params))
WHERE c.code SIMILAR TO 'iaas.ngc.%.(ssd|fstssd|sata)-_'
GROUP BY z.id_klienta, z.__name
),
deal_stat as (
select STRING_AGG(distinct deal_status_id::text,', ') as status_ids
, z.id_klienta as WZ
from line o join elma.companies z on (o._companies=z.__id)
GROUP BY z.id_klienta
)
select
r.wz as wz_sold,
r.client as client_sold,
a.wz as wz_alloc,
ds.status_ids,
r.codes as ram_codes,
r.quantity as ram_sold,
a.ram as ram_alloc,
a.ram_on as ram_alloc_on,
c.codes as cpu_codes,
c.quantity as cpu_sold,
a.cpu as cpu_alloc,
a.cpu_on as cpu_alloc_on,
d.quantity as disk_sold,
da.disk_alloc,
d.codes as disk_codes
from sold_ram r
join deal_stat ds on (r.wz=ds.wz)
join sold_cpu c on (r.wz=c.wz)
left join sold_disk d on (r.wz=d.wz)
full join alloc a on (r.wz=a.wz)
left join disk_alloc da on (a.wz=da.wz)
--where s.quantity=a.ram
order by 1,3
--select * from vmreports.compute where "WZ"='WZ01005'
--select * from vmreports.compute where "WZ"='WZ01038' AND
--select distinct "WZ" from vmreports.compute a where not exists (select * from elma.companies z where lower(trim(a."WZ"))=lower(trim(z.id_klienta)))
--select distinct "WZ" from vmreports.compute a where not exists (select * from elma.companies z where a."WZ"=z.id_klienta)
--select * from elma.companies where id_klienta='WZ00114'
--select * from vmreports.compute where "WZ"='WZ00114'
--select * from vmreports.compute where "WZ"='WZ00195'
--select d.* from elma.companies z join elma.deals d on (z.__id=d._companies) where id_klienta='WZ03378'
--select aa.* from elma.additional_agreements aa join elma.aggrements a on (aa.contract_uid=a.__id) join elma.companies z on (a.company_uid=z.__id)where id_klienta='WZ03378'
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
12:58 09.10.2025 дополнительное соглашение к сделке. Шедевр
+164
View File
@@ -0,0 +1,164 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent>
<m:prepare_ls entity="crm2cloud" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<cfquery name="qVM" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select "Name", "Object_UUID", "UUID_VM",
"VDC", "Organization_UUID", "Organization", "WZ", "Cluster", "Host",
"Host_Model", "CPU_Model", "Host_CPU_Cores", "Host_CPU_Sockets", "Host_CPU_Speed", "Host_RAM",
"Host_CPU_Used", "Host_CPU_Used_Avg",
"VDC_CPU_Reserv", "VDC_CPU_Speed",
"VM_vCPU_count", "VM_CPU_Used", "VM_CPU_Used_AVG", "VM_CPU_Reserv_GHz", "VM_CPU_Reserv_perc",
"VM_RAM_Allocated", "VM_RAM_Used",
"VM_is_ON",
k.__id as company_uid
from vmreports.compute c
left outer join elma.companies k ON (lower(k.id_klienta)=lower(c."WZ"))
where c.ts=(select max(ts) from vmreports.compute)
--order by "WZ"
</cfquery>
<!--- <cfdump var=#qVM# abort=true/> --->
<cfif isDefined("output_xls")>
<layout:xml qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
<cfabort/>
</cfif><cfif isDefined("output_json")>
<layout:json qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
<cfabort/>
</cfif><!---
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Сверка CRM - Cloud</b></cfoutput>
</layout:attribute>
<layout:attribute name="controls">
<!---skip filter link, filter is not implemented--->
<!---<layout:language_switch/>--->
</layout:attribute>
</layout:page>
<!--- <cfdump var=#qReconciliation# abort=true/> --->
<cfoutput>
<!--- <form method="post" action="">
Период с <input type="text" name="dt_start" value="#dateFormat(dt_start,'YYYY-MM-DD')#"/>
по <input type="text" name="dt_finish" value="#dateFormat(dt_finish,'YYYY-MM-DD')#"/>
<input type="submit" style="cursor:pointer;"/>
<input type="submit" name="DEBUG" value="DEBUG" style="cursor:pointer;"/>
</form> --->
<!--- Часов в периоде: <b>#hours#</b> Строк в отчете: <b>#qCharge.recordCount#</b><br/>
Актуальность данных:
VCD Computing: <b>#dateFormat(qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(qComputingAge.dt_load,'HH:MM:SS')#</b>
VCD Storage: <b>#dateFormat(qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(qStorageAge.dt_load,'HH:MM:SS')#</b>
S3 хранение: <b>#dateFormat(qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3VolAge.dt_load,'HH:MM:SS')#</b>
S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3OpsTrfAge.dt_load,'HH:MM:SS')#</b>
--->
<br/>
<a href="#request.thisPage#?output_xls" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
<a href="#request.thisPage#?output_json" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
</cfoutput>
<cfoutput><b>#qVM.recordCount#</b></cfoutput>
<table class="worktable">
<thead>
<tr>
<th width="5%">WZ</th>
<th width="5%">Имя</th>
<th width="5%">Уникальное имя</th>
<th width="3%">Organization</th>
<th width="3%">VDC</th>
<th width="3%">VDC CPU Reserv</th>
<th width="3%">VDC CPU Speed GHz</th>
<th width="3%">Cluster</th>
<th width="3%">Host</th>
<th width="7%">Host Model</th>
<th width="7%">CPU Model</th>
<th width="3%">Host CPU Cores</th>
<th width="3%">Host CPU Sockets</th>
<th width="3%">Host CPU Speed GHz</th>
<th width="3%">Host RAM GB</th>
<th width="3%">Host CPU Used</th>
<th width="3%">Host CPU Used_Avg</th>
<th width="3%">VM vCPU count</th>
<th width="3%">VM CPU Used</th>
<th width="3%">VM CPU Used AVG</th>
<th width="3%">VM CPU Reserv GHz</th>
<th width="3%">VM CPU Reserv perc</th>
<th width="3%">VM RAM Allocated GB</th>
<th width="3%">VM RAM Used GB</th>
<th width="3%">VM is ON</th>
</tr>
</thead>
<cfoutput query="qVM">
<tr>
<td><a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#WZ#</a><a href="contragent_rpt.cfm?__id=#company_uid#&#tr.fwx#" style="float:right"><img src="img/view.gif" title="сводка по контрагенту"/></a></td>
<td>#Name#</td>
<td>#UUID_VM#</td>
<td>#Organization#</td>
<td>#VDC#</td>
<td><cftry>#round(VDC_CPU_Reserv,3)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VDC_CPU_Speed,3)#<cfcatch></cfcatch></cftry></td>
<td>#qVM.Cluster#</td>
<td>#Host#</td>
<td>#Host_Model#</td>
<td>#CPU_Model#</td>
<td>#Host_CPU_Cores#</td>
<td>#Host_CPU_Sockets#</td>
<td>#round(Host_CPU_Speed,3)#</td>
<td>#round(Host_RAM)#</td>
<td><cftry>#round(Host_CPU_Used,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(Host_CPU_Used_Avg,1)#<cfcatch></cfcatch></cftry></td>
<td>#VM_vCPU_count#</td>
<td><cftry>#round(VM_CPU_Used,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VM_CPU_Used_AVG,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VM_CPU_Reserv_GHz,1)#<cfcatch></cfcatch></cftry></td>
<td>#VM_CPU_Reserv_perc#</td>
<td>#VM_RAM_Allocated#</td>
<td><cftry>#round(VM_RAM_Used)#<cfcatch></cfcatch></cftry></td>
<td>#VM_is_ON#</td>
<!--- <td><a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#client_sold#</a></td> --->
</tr>
</cfoutput>
</table>
<!--- <cfdump var=#qCharge#/> --->
<layout:page section="footer"/>
+8 -1
View File
@@ -29,7 +29,7 @@ function numFmt(num, decimalPlaces = 0){
request.numFmt = numFmt;
function nFmt(num, decimalPlaces = 2){
if (num EQ 0) return "";
if (num EQ 0 OR NOT isNumeric(num)) return "";
return numFmt(num, decimalPlaces);
}
request.nFmt = nFmt;
@@ -164,6 +164,13 @@ function roundSafe(a, precision) {
}
request.roundSafe = roundSafe;
function ceilingSafe(a) {
return (isNumeric(a)) ? ceiling(a) : a;
}
request.ceilingSafe = ceilingSafe;
function timeUnitLabel(n, value=0, locale="ru") {
var labels = ["сек.","мин.","ч.","д.","мес."];
if (n LE 5 AND n GE 1) {return labels[n];}
+6 -1
View File
@@ -12,15 +12,20 @@
<li class="menu-title">Реестры</li>
<c:menu_item acl="" page="deal_ls.cfm" label="Сделки"/>
<c:menu_item acl="" page="contract_ls.cfm" label="Договоры"/>
<c:menu_item acl="" page="additional_agreement_ls.cfm" label="Доп. соглашения"/>
<c:menu_item acl="" page="deal_ls.cfm" label="Сделки"/>
<c:menu_item acl="" page="vm_ls.cfm" label="VM"/>
<!---
<c:menu_item acl="" page="specification_ls.cfm" label="Спецификации"/>
<c:menu_item acl="" page="agreement_ls.cfm" label="Сделки"/>
<c:menu_item acl="" page="specification_item_ls.cfm" label="Экземпляры услуг"/>--->
<li class="menu-title">Отчеты</li>
<c:menu_item acl="" page="crm2cloud.cfm" label="CRM - Cloud"/>
<c:menu_item acl="" page="cloud_capacity.cfm" label="Cloud Capacity"/>
<c:menu_item acl="" page="payg.cfm" label="PAYG"/>
<!--- <c:menu_item acl="" page="detail_daily_rpt.cfm" label="Детализация по дням"/>
<c:menu_item acl="" page="income_daily_rpt.cfm" label="Выручка по дням"/>
+1 -1
View File
@@ -1 +1 @@
<cflocation url="payg.cfm" addtoken="No"/>
<cflocation url="contract_ls.cfm" addtoken="No"/>
-456
View File
@@ -1,456 +0,0 @@
<cfset dt_finish=createDateTime(year(Now()),month(Now()),1,0,0,0)/>
<cfset dt_start=dateAdd('m',-1,dt_finish)/>
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
Внимание! округление вверх при расчете метрик
<cfdump var=#dt_start#/>
<cfdump var=#dt_finish#/>
<cfdump var=#hours#/>
<!--- Нужно еще применить политики бесплатного минимума --->
<cfquery name="qCode" datasource="dwh">
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<!--- <cfdump var=#qCode#/> --->
<cfquery name="qSpec" datasource="dwh">
select k.id_klienta as wz, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, d.__name as deal, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description
,p.__name as metric, p.ed_izm
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by k.id_klienta, p.code
</cfquery>
<!--- здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет) --->
<cfdump var=#qSpec#/>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6%' then 'iaas.ngc.i28'
else '['||vdc.name||']' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
</cfquery>
<!--- <cfdump var=#qComputing#/> --->
<!--- переделать storage_profile_types с расшифровкой ssd, sata, можно прямо до каталожного кода --->
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29'
WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31'
WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28'
WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28'
ELSE '['||vdc.name||']' END
|| CASE
WHEN storage_profile_types.name ILIKE '%-SSD%' THEN '.ssd-m'
WHEN storage_profile_types.name ILIKE '%-SAS' THEN '.sas-m'
WHEN storage_profile_types.name ILIKE '%-SATA' THEN '.sata-m'
ELSE '.['|| storage_profile_types.name ||']' END
as code,
storage_profile_types.name, -- *** это не тип, а профайл
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<!--- <cfdump var=#qStorage#/> --->
<!---
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
HOT_FREE_LIMIT 1 10 1 100
--->
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
<cfquery name="qS3Vol" datasource="billing-s3">
select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
,round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
,greatest(round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>
/1024/1024/1024)-
case when bucket_stat.placement_id = 1 then 1 else 0 end, 0) as vol_GB_free_tier_subtracted /*считается не в точности так, как в функции*/
,case
when bucket_stat.placement_id = 1 then 'paas.s3.ceph'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_stat.placement_id,'FM9') ||']' end as code
--,bucket_stat.placement_id
,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ
from s3billing.bucket_stat
join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<!--- <cfdump var=#qS3Vol#/> --->
<cfquery name="qS3OpsTrf" datasource="billing-s3">
select
sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
) as get
,ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) as get_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 10 ELSE 0 END, 0
) as get_10k_free_tier_subtracted
,sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
) as put
,ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) as put_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 1 ELSE 0 END, 0
) as put_10k_free_tier_subtracted
,(sum(bytes_sent)) as bytes_sent
,ceil(sum(bytes_sent)/1024/1024/1024) as bytes_sent_GB
,greatest(ceil(sum(bytes_sent)/1024/1024/1024) - CASE WHEN bucket_info.placement_id = 1 THEN 100 ELSE 0 END, 0
) as bytes_sent_GB_free_tier_subtracted
,case
when bucket_info.placement_id = 1 then 'paas.s3.ceph'
when bucket_info.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_info.placement_id,'FM9') ||']' end as code --*** зачем делать там ключ bigint
,bucket_info.placement_id
--category.name, bucket_info.name
,'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, bucket_info.placement_id
order by user_info.name, bucket_info.placement_id;
</cfquery>
<!--- <cfdump var=#qS3OpsTrf#/> --->
<cfquery name="qUnifiedMetric" dbType="query">
select wz, code || '.cpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric from qComputing
union all
select wz, code || '.ram-m' as code, gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric from qComputing
union all
select wz, code, gb_h_used as raw_metric, gb_h_used as metric, gb_h_used as chargeable_metric from qStorage
union all
select wz, code || '.vol', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric from qS3Vol
union all
select wz, code || '.get', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.put', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.trf', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric from qS3OpsTrf
</cfquery>
<cfdump var=#qUnifiedMetric#/>
<cfquery name="qCharge" dbType="query">
SELECT
wz
,code
,price
,discount
,contragent
,contract
,deal
,abstract_service
,modifier
,user_description
,ed_izm
FROM qSpec as s, qUnifiedMetric as m WHERE s.wz=m.wz AND s.code=m.code
</cfquery>
<!--- looks like QoQ does not support join syntax, at least of Lucee 5.4--->
<cfdump var=#qCharge#/>
<!---
--->
<!--- --,m.*
--,s.price*(100-s.discount)/100 as discounted_price
--,s.price*(100-s.discount)/100*m.chargeable_metric as charge --->
<!--- В одном месте user_id int в другом owner varchar --->
<!---
задача (вызванная сыростью базы биллинга)
смапить код параметра с VDC (1:n)
iaas.ngc.i31.ram-m
iaas.ngc.a28.ram-m
cl01:
7 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 4 из 7 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl01-vsan:
16 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 9 из 16 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl02:
10 Huawei 2488H V5
4 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
2тб озу в каждом.
5 Huawei Atlas 800 (Model 3010)
2 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
1.5тб озу в каждом.
cl04-vsan:
10 Apex AR320-12
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
18 Apex AR320-12-E7543
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
cl05-1c:
1 Asus RS720A-E12-RS24U
2 процессора AMD EPYC 9274F 24 ядра 48 потоков каждый. 4.05 ГГц
1тб озу.
7 ручная сборка
MB Asus ProArt B650-Creator
Процессор AMD Ryzen 9 7950X 16 ядер 32 потока каждый. 4.5 ГГц
192гб озу каждый.
1 ручная сборка
процессор AMD Ryzen Threadripper PRO 5995WX 64 ядра 128 потоков каждый. 2.7 ГГц
512гб озу.
cl06-vsan:
15 R320
2 процессора Xeon(R) Gold 6342 24 ядра 48 потоков каждый. 2.8 ГГц
1тб озу каждый.
Xeon(R) Gold 6226R 2.9 ГГц
Xeon(R) Gold 6254 3.1 ГГц
AMD EPYC 7543 2.8 ГГц
AMD EPYC 9274F 4.05 ГГц
AMD Ryzen 9 7950X 4.5 ГГц
AMD Ryzen Threadripper PRO 5995WX 2.7 ГГц
Xeon(R) Gold 6342 2.8 ГГц --->
<!--- 2025-08-15 20:47:44 *** Операции S3 считаются не так, как написано в тарифе. Например, считается list. В тарифе вообще не описан минимальный лимит --->
<!--- BEGIN
RETURN QUERY
(
select
billing_per_user_fix_pl.placement as placement,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(size)/1024/1024/1024)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(size)/1024/1024/1024)
END) AS size_GB,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(get)/10000)-10,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(get)/10000)
END) AS get_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(put)/10000)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(put)/10000)
END) AS put_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) then greatest(ceil(sum(bytes_sent)/1024/1024/1024)-100,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(bytes_sent)/1024/1024/1024)
END) AS bytes_sent_GB
from s3billing.billing_per_user_fix_pl(_ds,_df,_user)
group by billing_per_user_fix_pl.placement
UNION all
select
'HOT_FREE_LIMIT' as placement,
'1' AS size_GB,
'10' AS get_10k,
'1' AS put_10k,
'100' AS bytes_sent_GB
);
END; --->
<!---
BEGIN
RETURN QUERY
SELECT
s3billing.bucket_info.name AS bucket_name,
(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement,
coalesce(round(sum(usage_rgw_main_size_actual)/
(SELECT (DATE_PART('day',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)*24+
DATE_PART('hour',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)))
)::numeric,0) AS size
,coalesce(s2.get, 0) AS get
,coalesce(s2.put, 0) AS put
,coalesce(s2.bytes_sent, 0) as bytes_sent
FROM s3billing.bucket_stat
INNER JOIN s3billing.placement ON s3billing.bucket_stat.placement_id=s3billing.placement.id
INNER JOIN s3billing.bucket_info ON s3billing.bucket_stat.bucket_id=s3billing.bucket_info.id
LEFT JOIN (
SELECT
s1.bucket_id AS bucket_id
,s1.bucket_name AS bucket_name,
(case
when ( s1.placement = 'default-placement') then 'HOT'
WHEN ( not s1.placement = 'default-placement' ) THEN s1.placement
end
) as placement
,coalesce(sum(s1.get) ,0) AS get
,coalesce(sum(s1.put) ,0) AS put
,coalesce(sum(s1.bytes_sent), 0) AS bytes_sent
FROM (
SELECT
s3billing.bucket_info.id AS bucket_id
,s3billing.bucket_info.name AS bucket_name
,(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement
,(CASE
WHEN ( s3billing.category.name LIKE 'get%'
OR s3billing.category.name LIKE 'head%'
OR s3billing.category.name LIKE 'options%'
) THEN coalesce(sum(ops), 0)
END) AS get
,(CASE
WHEN ( s3billing.category.name LIKE 'put%'
OR s3billing.category.name LIKE 'post%'
OR s3billing.category.name LIKE 'patch%'
OR s3billing.category.name LIKE 'list%'
) THEN coalesce(sum(ops), 0)
END) AS put
,coalesce(sum(usage_bucket_by_user.bytes_sent), 0) AS bytes_sent
FROM
s3billing.usage_bucket_by_user
INNER JOIN s3billing.bucket_info ON s3billing.usage_bucket_by_user.bucketid = s3billing.bucket_info.id
INNER JOIN s3billing.placement ON s3billing.bucket_info.placement_id = s3billing.placement.id
INNER JOIN s3billing.user_info ON s3billing.usage_bucket_by_user.user_id = s3billing.user_info.id
INNER JOIN s3billing.category ON s3billing.usage_bucket_by_user.category_id = s3billing.category.id
WHERE
s3billing.user_info.name=_user
AND s3billing.usage_bucket_by_user.time >=TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND s3billing.usage_bucket_by_user.time < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.category.name
,s3billing.bucket_info.id
) AS s1
GROUP BY
s1.bucket_name
,s1.bucket_id
,s1.placement
ORDER BY
s1.placement
,s1.bucket_name
) AS s2 ON s2.bucket_id = s3billing.bucket_stat.bucket_id
WHERE owner=_user
AND timestamp_addition >= TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND timestamp_addition < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.bucket_stat.bucket_id
,s2.get
,s2.put
,s2.bytes_sent
ORDER BY
s3billing.placement.name
,s3billing.bucket_info.name
;
END; --->
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
+3 -2
View File
@@ -1,12 +1,13 @@
<cfsilent>
<!--- v0.03 20260402--->
<cfimport prefix="m" taglib="../lib"/>
<cfimport prefix="c" taglib="../lib/controls"/>
<cfparam name="ATTRIBUTES.useSummary" default="yes"/>
<cfparam name="ATTRIBUTES.addtionalUrlParams" type="string" default=""/>
<cfparam name="ATTRIBUTES.self" default=""/>
<cfparam name="ATTRIBUTES.recordCount" default="0"/>
<cfparam name="ATTRIBUTES.totalCount" default="0"/>
<cfparam name="ATTRIBUTES.recordCount" default="-1"/>
<cfparam name="ATTRIBUTES.totalCount" default="-1"/>
<cfparam name="ATTRIBUTES.recordsPerPage" default="500"/>
<cfparam name="ATTRIBUTES.footerOut" default=""/>
<cfparam name="ATTRIBUTES.excelLink" default="No"/>
+2 -2
View File
@@ -7,7 +7,7 @@
<cfparam name="ATTRIBUTES.closeForm" type="boolean" default="No"/>
<cfparam name="title" default=""/><!---заголовок страницы, отображаемый в теле например, <h1>--->
<cfparam name="pageTitle" default="PAYG"/><!---заголовок окна браузера, в теге <title>--->
<cfparam name="pageTitle" default="Сверка"/><!---заголовок окна браузера, в теге <title>--->
<cfparam name="controls" default=""/>
</cfsilent><cfsilent>
@@ -126,7 +126,7 @@ select login, firstname, middlename, lastname from worker where id='#request.usr
<!--- <div style="width:20px; height:30px; margin: 5px; background: url('img/logo0.png') 0 0 no-repeat; background-size:contain; display:inline-block;"></div>--->
<div style="width:138px; height:30px; margin: 5px 0 0 5px; background: url('img/logo0.png') 0 0 no-repeat; background-size:contain; display:inline-block; -border:1px solid red;">
<p class="b r" style="color:white; margin:0 10px 10px 10px; font-size:130%;">
Отчет PAYG
Сверка CRM-Cloud
</p>
</div>
<p style="color:lightgray; margin:10px 12px; text-align:right;">
+4
View File
@@ -1,5 +1,6 @@
<!--- version 2.01---><!---15:25 31.01.2019--->
<!--- version 2.02---><!---2025-08-04 15:19:34 postgre specific ilike instead of like--->
<!--- version 2.03---><!---2026-04-27 ftype=integer support--->
<!--- build query filter string --->
<!--- пустые и некорректные значения параметров вызвыают пропуск параметра --->
<cfparam name="ATTRIBUTES.filter" type="struct"/>
@@ -34,6 +35,9 @@
<cfcase value="numeric">
<cfreturn "CF_SQL_NUMERIC"/>
</cfcase>
<cfcase value="integer">
<cfreturn "CF_SQL_INTEGER"/>
</cfcase>
<cfcase value="date,time,datetime">
<cfreturn "CF_SQL_TIMESTAMP"/>
</cfcase>
+8
View File
@@ -1,6 +1,7 @@
<!--- version 2.01---><!---15:25 31.01.2019--->
<!--- 2017.06.16 исправлен баг с очисткой при числовом значении по умолчанию --->
<!---v0.5 10:02 02.01.2019--->
<!---v0.6 2026-04-27 integer type support --->
<cfassociate basetag="cf_filter_settings"/>
<cfparam name="ATTRIBUTES.filter" type="struct" default=#getBaseTagData("CF_FILTER_SETTINGS",1).filter#/><!--- *** possible Railo bug, getBaseTagData works only with second parameter --->
<cfparam name="ATTRIBUTES.param" type="string"/>
@@ -74,6 +75,13 @@ arrayAppend(array,item) механически заменил на listAppend(li
</cfif>
</cfcase>
<cfcase value="integer">
<cfset element=trim(element)>
<cfif NOT isValid("integer", element)>
<cfset element=def/>
</cfif>
</cfcase>
<cfcase value="guid">
<cfset element=trim(element)>
<cfif NOT isValid('guid',element)>
+234 -89
View File
@@ -7,18 +7,16 @@
<m:prepare_ls entity="payg" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<!---
<cfparam name="dt_finish" type="date" default=#createDateTime(year(Now()),month(Now()),1,0,0,0)#/>
<cfparam name="dt_start" type="date" default=#dateAdd('m',-1,dt_finish)#/>
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
<cfparam name="dt_start" type="date" default=#dateAdd('m',-1,dt_finish)#/> --->
<cfparam name="dt_finish" type="date" default=#dateAdd('d',-1,createDateTime(year(Now()),month(Now()),1,0,0,0))#/>
<cfparam name="dt_start" type="date" default=#dateAdd('m',-1,createDateTime(year(Now()),month(Now()),1,0,0,0))#/>
<cfset hours=dateDiff('h', dt_start, dateAdd('d', 1, dt_finish))/>
<cfparam name="only_articles_in_spec" type="boolean" default=false/>
<!--- Нужно еще применить политики бесплатного минимума --->
<cfquery name="qCode" datasource="dwh">
<!--- *** коды лучше взять из каталога --->
<cfquery name="qCode" datasource="dwh" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
@@ -29,12 +27,28 @@
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<!--- <cfdump var=#qCode#/> --->
<cfoutput>qCode:#getTickCount()-request.startTickCount#</cfoutput>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfquery name="qSpec" datasource="dwh">
<!--- <cfdump var=#qCode#/> --->
<cfquery name="qContragent" datasource="dwh" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select k.id_klienta as wz, k.__id::text as contragent_uid, k.__name as contragent
from elma.companies k
where k."__deletedAt" IS NULL
</cfquery>
<cfoutput>qContragent:#getTickCount()-request.startTickCount#</cfoutput>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<!--- <cfif isDefined("DEBUG")>
<cfdump var=#qContragent#/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif> --->
<!--- нужны компании, которые есть в пейге --->
<cfquery name="qSpec" datasource="dwh" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select k.id_klienta as wz, k.__id::text as contragent_uid, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, a.__id::text as contract_uid, d.__name as deal, d.__id::text as deal_uid, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description, siv.hash as line_key
,siv.date_nop as dt_from, siv.date_end as dt_to
/*,p.__name as line_key*/, p.ed_izm, p.name as component, aa.__name as additional_agreement, aa.__id::text as additional_agreement_uid
,siv.date_nop as dt_from, siv.date_end as dt_to, siv.discount as service_discount, siv.cnt as service_quantity
/*,p.__name as line_key*/, p.ed_izm, p.name as component, p.type, aa.__name as additional_agreement, aa.__id::text as additional_agreement_uid
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
@@ -42,94 +56,124 @@
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
where p.type IN (2,3) AND aa.is_actual
AND siv.date_nop < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
AND (siv.date_end > <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/> OR siv.date_end IS NULL)
AND (siv.date_end > <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/> OR siv.date_end IS NULL)/*****/
order by k.id_klienta, p.code
</cfquery>
<cfquery name="qSivAge" datasource="dwh">
select max(dt_load) as dt_load from elma.deals_services
</cfquery>
<!--- здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет) --->
<cfoutput>qSpec:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qSpec#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<!--- siv means specification item version --->
<cfquery name="qSivAge" datasource="dwh" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select max(dt_load) as dt_load from elma.deals_services
</cfquery>
<cfoutput>qSivAge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
<cfquery name="qComputing" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select m.clientid as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6%' then 'iaas.ngc.i28'
WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29'
WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31'
WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28'
WHEN vdc.name LIKE '%-v1cl5%' THEN 'iaas.ngc.a45'
WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28'
WHEN vdc.name LIKE '%-v1cl7%' THEN 'iaas.ngc.a40' -- *** смапить все кластера
else '['||vdc.name||']' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
join ngcloud_ru.tenant t on (t.id=vdc.tenant_id)
left outer join
(select tenant_id, ts, metadata_id,
ROW_NUMBER() OVER (PARTITION BY tenant_id ORDER BY ts desc, metadata_id desc) as rn
from ngcloud_ru.tenant_metadata
) tm on (t.id = tm.tenant_id AND tm.rn = 1)
left outer join ngcloud_ru.metadata m on (tm.metadata_id=m.id)
where length(m.clientid) > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dateAdd("d",1,dt_finish)#/>
group by m.clientid, vdc.name
order by m.clientid, vdc.name;
</cfquery>
<cfoutput>qComputing:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qComputing#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfquery name="qComputingAge" datasource="billing-vc">
<cfquery name="qComputingAge" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select max(capacity_resource.timestamp) as dt_load from ngcloud_ru.capacity_resource
</cfquery>
<cfoutput>qComputingAge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<!--- переделать storage_profile_types с расшифровкой ssd, sata, можно прямо до каталожного кода --->
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
<cfquery name="qStorage" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select m.clientid as wz, vdc.name as vdc_name,
case
WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29'
WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31'
WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28'
WHEN vdc.name LIKE '%-v1cl5%' THEN 'iaas.ngc.a45'
WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28'
WHEN vdc.name LIKE '%-v1cl7%' THEN 'iaas.ngc.a40' -- *** смапить все кластера
ELSE '['||vdc.name||']' END
|| CASE
WHEN storage_profile_types.name ILIKE '%-SSD%' THEN '.ssd-m'
WHEN storage_profile_types.name ILIKE '%-SAS' THEN '.sas-m'
WHEN storage_profile_types.name ILIKE '%-SATA' THEN '.sata-m'
WHEN storage_profile_types.name ILIKE '%FASTSSD%' THEN '.fstssd-m'
WHEN storage_profile_types.name ILIKE '%SSD%' THEN '.ssd-m'
WHEN storage_profile_types.name ILIKE '%SAS%' THEN '.sas-m'
WHEN storage_profile_types.name ILIKE '%SATA%' THEN '.sata-m'
ELSE '.['|| storage_profile_types.name ||']' END
as code,
storage_profile_types.name, -- *** это не тип, а профайл
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
sum("limit")/1024./4./720. as gb_m_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4./720. as gb_m_used -- 720 это количество часов в условном месяце
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.tenant t on t.id=vdc.tenant_id
left outer join
(select tenant_id, ts, metadata_id,
ROW_NUMBER() OVER (PARTITION BY tenant_id ORDER BY ts desc, metadata_id desc) as rn
from ngcloud_ru.tenant_metadata
) tm on (t.id = tm.tenant_id AND tm.rn = 1)
left outer join ngcloud_ru.metadata m on (tm.metadata_id=m.id)
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
where length(m.clientid) > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<cfquery name="qStorageAge" datasource="billing-vc">
select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dateAdd("d",1,dt_finish)#/>
group by m.clientid, vdc.name, storage_profile_types.name
order by m.clientid, vdc.name, storage_profile_types.name;
</cfquery>
<cfoutput>qStorage:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qStorage#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfquery name="qStorageAge" datasource="billing-vc" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage
</cfquery>
<cfoutput>qStorageAge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<!---
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
HOT_FREE_LIMIT 1 10 1 100
--->
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
<cfquery name="qS3Vol" datasource="billing-s3">
<cfquery name="qS3Vol" datasource="billing-s3" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
,ceil(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
@@ -140,7 +184,7 @@ HOT_FREE_LIMIT 1 10 1 100
when bucket_stat.placement_id = 1 then 'paas.s3.ceph'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_stat.placement_id,'FM9') ||']' end as code
--,bucket_stat.placement_id
,bucket_stat.placement_id
,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ
from s3billing.bucket_stat
@@ -148,20 +192,24 @@ HOT_FREE_LIMIT 1 10 1 100
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dateAdd("d",1,dt_finish)#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<cfoutput>qS3Vol:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qS3Vol#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfquery name="qS3VolAge" datasource="billing-s3">
<cfquery name="qS3VolAge" datasource="billing-s3" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select max(timestamp_addition) as dt_load from s3billing.bucket_stat
</cfquery>
<cfoutput>qS3VolAge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfquery name="qS3OpsTrf" datasource="billing-s3">
select
sum(
@@ -232,59 +280,91 @@ select
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dateAdd("d",1,dt_finish)#/>
group by user_info.name, bucket_info.placement_id
order by user_info.name, bucket_info.placement_id;
</cfquery>
<cfoutput>qS3OpsTrf:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qS3OpsTrf#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfquery name="qS3OpsTrfAge" datasource="billing-s3">
<cfquery name="qS3OpsTrfAge" datasource="billing-s3" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select max(time) as dt_load from s3billing.usage_bucket_by_user
</cfquery>
<cfoutput>qS3OpsTrfAge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfquery name="qUnifiedMetric" dbType="query">
select wz, code || '.vcpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric from qComputing
select wz, code || '.vcpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric, 'core-h' as unit
from qComputing
union all
select wz, code || '.ram-m' as code, gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric from qComputing
select wz, code || '.ram-m', gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric, 'GByte-h' as unit
from qComputing
union all
select wz, code, gb_h_used as raw_metric, gb_h_used as metric, gb_h_used as chargeable_metric from qStorage
select wz, code, gb_m_used as raw_metric, gb_m_used as metric, gb_m_used as chargeable_metric, 'GByte-m' as unit
from qStorage
union all
select wz, code || '.vol-m', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric from qS3Vol
select wz, code || '.vol-m', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric, 'GByte-m' as unit
from qS3Vol
union all
select wz, code || '.get-m', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
select wz, code || '.get-m', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric, '10k' as unit
from qS3OpsTrf
union all
select wz, code || '.put-m', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
select wz, code || '.put-m', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric, '10k' as unit
from qS3OpsTrf
union all
select wz, code || '.trf-m', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric from qS3OpsTrf
select wz, code || '.trf-m', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric, 'GByte' as unit
from qS3OpsTrf
order by wz, code
</cfquery>
<cfoutput>qUnifiedMetric:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<cfdump var=#qUnifiedMetric#/>
<cfflush/>
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfquery name="qCharge" dbType="query">
<cfset db = new MemoryDbHelper()/>
<cfset db.register("qUnifiedMetric", qUnifiedMetric, "inmem")/>
<cfset db.register("qContragent", qContragent, "inmem")/>
<cfset db.register("qSpec", qSpec, "inmem")/>
<cfquery name="qCharge" datasource="inmem">
SELECT
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
<d:field title="WZ">s.wz</d:field>
<d:field title="Артикул">s.code</d:field>
<d:field title="Кол-во (метрика)" cfSqlType="CF_SQL_NUMERIC">m.chargeable_metric</d:field>
<d:field title="WZ">coalesce(coalesce(c.wz, m.wz), s.wz) as wz</d:field>
<d:field title="Артикул">coalesce(m.code, s.code) as code</d:field>
<d:field title="Артикул фикс">f.code as f_code</d:field>
<d:field title="Кол-во к оплате" cfSqlType="CF_SQL_NUMERIC">ceiling(m.chargeable_metric) as chargeable_metric</d:field>
<d:field title="Ед.изм.">m.unit</d:field>
<d:field title="Ед.изм.">s.ed_izm</d:field>
<d:field title="Цена &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.price*(100-s.discount)/100 as discounted_price</d:field>
<d:field title="Стоимость &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.price*(100-s.discount)/100*m.chargeable_metric as charge</d:field>
<d:field title="Цена &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.service_quantity*(100-s.service_discount)/100*s.price*(100-s.discount)/100 as discounted_price</d:field>
<d:field title="Стоимость &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.service_quantity*(100-s.service_discount)/100*s.price*(100-s.discount)/100*ceiling(m.chargeable_metric) as charge</d:field>
<d:field title="Дата НОУ" cfSqlType="CF_SQL_TIMESTAMP">s.dt_from</d:field>
<d:field title="Дата оконч." cfSqlType="CF_SQL_TIMESTAMP">s.dt_to</d:field>
<d:field title="Ключ строки">s.line_key</d:field>
<d:field title="GPL с НДС" cfSqlType="CF_SQL_NUMERIC">s.price</d:field>
<d:field title="Скидка%" cfSqlType="CF_SQL_NUMERIC">s.discount</d:field>
<d:field title="Сырая метрика" cfSqlType="CF_SQL_NUMERIC">m.raw_metric</d:field>
<d:field title="Приведен&shy;ная метрика" cfSqlType="CF_SQL_NUMERIC">m.metric</d:field>
<d:field title="Контрагент">s.contragent</d:field>
<d:field title="contragent_uid">s.contragent_uid</d:field>
<d:field title="Приведенная метрика" cfSqlType="CF_SQL_NUMERIC">m.metric</d:field>
<d:field title="Контрагент">coalesce(c.contragent,cs.contragent) as contragent</d:field>
<d:field title="contragent_uid">coalesce(c.contragent_uid,cs.contragent_uid) as contragent_uid</d:field>
<d:field title="Договор">s.contract</d:field>
<d:field title="contract_uid">s.contract_uid</d:field>
<d:field title="Допник">s.additional_agreement</d:field>
@@ -296,11 +376,30 @@ SELECT
<d:field title="Компонент">s.component</d:field>
<d:field title="Клиентс. назв.">s.user_description</d:field>
</d:field_set>
FROM qSpec as s, qUnifiedMetric as m WHERE s.wz=m.wz AND s.code=m.code
order by s.wz, s.code
FROM qUnifiedMetric m
FULL JOIN qSpec s ON (m.wz=s.wz AND m.code=s.code)
LEFT JOIN qSpec f ON (m.wz=f.wz AND m.code=f.code AND f.type=2)
LEFT JOIN qContragent c ON (m.wz=c.wz)
LEFT JOIN qContragent cs ON (s.wz=cs.wz) -- неуклюже, но иначе контрагент теряется
WHERE 1=1 AND s.type=3
<cfif only_articles_in_spec>
AND EXISTS(select * from qSpec qs where qs.wz=m.wz AND qs.type=3)
</cfif>
--AND s.wz='WZ01762'
<!---
AND 1=0
--->
ORDER BY wz,code
</cfquery>
<!--- looks like QoQ does not support join syntax, at least of Lucee 5.4--->
<!--- <cfdump var=#qCharge#/> --->
<cfoutput>qCharge:#getTickCount()-request.startTickCount#</cfoutput><cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
<cfif isDefined("DEBUG")>
<!--- <cfdump var=#qCharge#/> --->
<cfif !isDefined("output_xls") AND !isDefined("output_json")><cfflush/></cfif>
</cfif>
<cfif isDefined("output_xls")>
@@ -321,6 +420,8 @@ order by s.wz, s.code
</layout:attribute>
</layout:page>
Факт потребления по основной базе биллинга, спецификации из DWH. Без детализации по бакетам, VDC и т.д.
Все запросы кэшированы на 25 минут.<br/>
Внимание! округление вверх при расчете метрик get, put S3. Расчетные суммы могут содержать погрешности округления, поэтому окончательный расчет стоимости (количество * цену) должен выполняться в бухгалтерской программе.
<b>Если у клиента больше 1 действующего допника с услугами PAYG, то данные в отчете могут быть замножены, в этом случае считать вручную</b>
<br/>
@@ -329,6 +430,7 @@ order by s.wz, s.code
<form method="post" action="">
Период с <input type="text" name="dt_start" value="#dateFormat(dt_start,'YYYY-MM-DD')#"/>
по <input type="text" name="dt_finish" value="#dateFormat(dt_finish,'YYYY-MM-DD')#"/>
Только PAYG <input type="checkbox" name="only_articles_in_spec" value="1"<cfif only_articles_in_spec> checked</cfif>/>
<input type="submit" style="cursor:pointer;"/>
<input type="submit" name="DEBUG" value="DEBUG" style="cursor:pointer;"/>
</form>
@@ -380,20 +482,24 @@ S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-M
<cfset var acc=0/>
<tr>
<td bgcolor="##ccc"></td>
<td bgcolor="##ccc" colspan="5" class="b"><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a> #contragent#</td>
<td bgcolor="##ccc" colspan="5" class="b">
<a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a>
#contragent#
<a href="contragent_rpt.cfm?__id=#contragent_uid#&#tr.fwx#">(сводка)</a>
</td>
<td></td>
<td bgcolor="##ccc" colspan="99"></td>
</tr>
<cfoutput>
<cfset acc=acc+charge/>
<tr>
<cfset acc += (isNumeric(charge)) ? charge : 0/>
<tr<cfif !len(unit)> class="gray"</cfif>>
<td>#currentRow#</a></td>
<td>#code#</td>
<td class="r" style="font-size:120%; padding:0 1em;">#chargeable_metric#</td>
<td class="c" style="font-size:90%;">#ed_izm#</td>
<td class="r">#discounted_price#</td>
<td class="r">#charge#</td>
<td>#code# <cfif !len(metric) and len(f_code)>(#f_code#)</cfif></td>
<td class="r" style="font-size:120%; padding:0 1em;">#request.roundSafe(chargeable_metric,3)#</td>
<td class="c" style="font-size:90%;">#len(unit)?unit:'['& ed_izm &']'#</td>
<td class="r">#gaussianRoundSafe(discounted_price,2)#</td>
<td class="r">#gaussianRoundSafe(charge,2)#</td>
<td></td>
@@ -401,15 +507,15 @@ S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-M
<td>#component#</td>
<td>#user_description#</td>
<td class="r">#price#</td>
<td class="r">#gaussianRoundSafe(price,2)#</td>
<td class="r">#discount#</td>
<td class="r">#dateFormat(dt_from,'YYYY-MM-DD')#</td>
<td class="r">#dateFormat(dt_to,'YYYY-MM-DD')#</td>
<td class="r">#line_key#</td>
<td class="r" style="color:lightgray">#raw_metric#</td>
<td class="r">#metric#</td>
<td class="r" style="color:##bbb">#request.roundSafe(raw_metric,3)#</td>
<td class="r">#request.roundSafe(metric,3)#</td>
<td><a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#contract#</a></td>
<td><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
<td><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#">#deal#</a></td>
@@ -418,7 +524,7 @@ S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-M
<tr>
<td bgcolor="##eee" style="border-bottom:2px solid gray;"></td>
<td bgcolor="##eee" colspan="4" class="r" style="border-bottom:2px solid gray;"><b>Итого</b> <a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a> #contragent#:</td>
<td bgcolor="##eee" colspan="1" class="r b" style="border-bottom:2px solid gray;">#NumFmt(acc,2)#</td>
<td bgcolor="##eee" colspan="1" class="r b nw" style="border-bottom:2px solid gray;">#NumFmt(acc,2)#</td>
<td colspan="14" style="border-bottom:2px solid gray;"></td>
</tr >
</cfoutput>
@@ -426,8 +532,47 @@ S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-M
</table>
<!--- <cfdump var=#qCharge#/> --->
<cfdump var=#this.datasources[request.ds].connectionString#/>
<cfdump var=#this.datasources["billing-vc"].connectionString#/>
<cfdump var=#this.datasources["billing-s3"].connectionString#/>
<layout:page section="footer"/>
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
<!--- select t.id as tenant_id,
from ngcloud_ru.tenant t
left outer join
(select tenant_id, ts, metadata_id,
ROW_NUMBER() OVER (PARTITION BY tenant_id ORDER BY ts desc, metadata_id desc)
as rn
from ngcloud_ru.tenant_metadata) tm
on (t.id = tm.tenant_id AND tm.rn = 1)
left outer join ngcloud_ru.metadata m on (tm.metadata_id=m.id) --->
<cfscript>
string function gaussianRoundSafe(any num, numeric precision = 0, string default="") {
return (isNumeric(arguments.num)) ? gaussianRound(arguments.num, arguments.precision) : arguments.default;
}
function gaussianRound(numeric number, numeric precision = 0) {
var factor = 10 ^ precision;
var scaledNumber = number * factor;
var absScaled = abs(scaledNumber);
var sign = sgn(scaledNumber);
var floored = int(absScaled);
// If it's not ending in exactly .5, use standard rounding or precision scaling
if (absScaled - floored != 0.5) {
return round(number * factor) / factor;
}
// If it is exactly .5, round towards the nearest even number
if (floored % 2 != 0) {
// Nearest even is UP
return (floored + 1) * sign / factor;
} else {
// Nearest even is DOWN
return floored * sign / factor;
}
}
</cfscript>
+2
View File
@@ -246,6 +246,8 @@ button.maincontrol:hover {
.err {color: red;}
.warn {color: #f80;}
.gray, tr.gray td {color:lightgray;}
.gray a, tr.gray td a, tr.gray td a:link, tr.gray td a:visited {color: #aad;}
a.up {background: url('../img/up.gif') center right no-repeat; padding-right: 7px;}
a.add {background: url('../img/add.gif') center right no-repeat; width:13px; height:13px; display:inline-block;}
+20
View File
@@ -0,0 +1,20 @@
<cfquery name="qEq" datasource="cmdb">
select svc_id,svc,descr,dt_created,creator_id,DT_UPDATED, UPDATER_ID, IS_PRODUCTION_READY, CODE, MAN SVC_SHORT, RESOURCE_REALM_TYPE_ID, VERSION ,ORCHESTRATOR_NAME, SORT, SVC_GROUP_ID, ICON_SRC, SYNONYMS from svc limit 100;
</cfquery>
<!--- <cfdump var=#qEq#/> --->
<!--- <cfquery name="qt" datasource="inmem">
SELECT CURRENT_DATE FROM (VALUES(0));
</cfquery>
<cfdump var=#qt#/>--->
<cfset db = new MemoryDbHelper()/>
<!--- <cfset db.drop("eq")/> --->
<cfset db.register("eq", qEq, "inmem")/>
<cfquery name="qTest" datasource="inmem">
select * from eq
</cfquery>
<!---
<cfset db.drop("eq")/> --->
<cfdump var=#qTest#/>
+163
View File
@@ -0,0 +1,163 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent>
<m:prepare_ls entity="crm2cloud" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<cfquery name="qVM" cachedWithin=#createTimeSpan(0, 0, 25, 0)#>
select "Name", "Object_UUID", "UUID_VM",
"VDC", "Organization_UUID", "Organization", "WZ", "Cluster", "Host",
"Host_Model", "CPU_Model", "Host_CPU_Cores", "Host_CPU_Sockets", "Host_CPU_Speed", "Host_RAM",
"Host_CPU_Used", "Host_CPU_Used_Avg",
"VDC_CPU_Reserv", "VDC_CPU_Speed",
"VM_vCPU_count", "VM_CPU_Used", "VM_CPU_Used_AVG", "VM_CPU_Reserv_GHz", "VM_CPU_Reserv_perc",
"VM_RAM_Allocated", "VM_RAM_Used",
"VM_is_ON",
k.__id as company_uid
from vmreports.compute c
left outer join elma.companies k ON (lower(k.id_klienta)=lower(c."WZ"))
where c.ts=(select max(ts) from vmreports.compute)
--order by "WZ"
</cfquery>
<!--- <cfdump var=#qVM# abort=true/> --->
<cfif isDefined("output_xls")>
<layout:xml qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.xml"/>
<cfabort/>
</cfif><cfif isDefined("output_json")>
<layout:json qRead=#qCharge# titleMap=#titleMap# filename="#pageInfo.entity#.json"/>
<cfabort/>
</cfif><!---
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Сверка CRM - Cloud</b></cfoutput>
</layout:attribute>
<layout:attribute name="controls">
<!---skip filter link, filter is not implemented--->
<!---<layout:language_switch/>--->
</layout:attribute>
</layout:page>
<!--- <cfdump var=#qReconciliation# abort=true/> --->
<cfoutput>
<!--- <form method="post" action="">
Период с <input type="text" name="dt_start" value="#dateFormat(dt_start,'YYYY-MM-DD')#"/>
по <input type="text" name="dt_finish" value="#dateFormat(dt_finish,'YYYY-MM-DD')#"/>
<input type="submit" style="cursor:pointer;"/>
<input type="submit" name="DEBUG" value="DEBUG" style="cursor:pointer;"/>
</form> --->
<!--- Часов в периоде: <b>#hours#</b> Строк в отчете: <b>#qCharge.recordCount#</b><br/>
Актуальность данных:
VCD Computing: <b>#dateFormat(qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(qComputingAge.dt_load,'HH:MM:SS')#</b>
VCD Storage: <b>#dateFormat(qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(qStorageAge.dt_load,'HH:MM:SS')#</b>
S3 хранение: <b>#dateFormat(qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3VolAge.dt_load,'HH:MM:SS')#</b>
S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3OpsTrfAge.dt_load,'HH:MM:SS')#</b>
--->
<br/>
<a href="#request.thisPage#?output_xls" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
<a href="#request.thisPage#?output_json" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
</cfoutput>
<cfoutput><b>#qVM.recordCount#</b></cfoutput>
<table class="worktable" style="word-break:break-word">
<thead>
<tr>
<th width="3%">WZ</th>
<th width="5%">Имя</th>
<th width="7%">Уникальное имя</th>
<th width="3%">Organization</th>
<th width="5%">VDC</th>
<th width="3%">VDC CPU Reserv</th>
<th width="3%">VDC CPU Speed GHz</th>
<th width="3%">Cluster</th>
<th width="3%">Host</th>
<th width="5%">Host Model</th>
<th width="5%">CPU Model</th>
<th width="3%">Host CPU Cores</th>
<th width="3%">Host CPU Sockets</th>
<th width="3%">Host CPU Speed GHz</th>
<th width="3%">Host RAM GB</th>
<th width="3%">Host CPU Used</th>
<th width="3%">Host CPU Used_Avg</th>
<th width="3%">VM vCPU count</th>
<th width="3%">VM CPU Used</th>
<th width="3%">VM CPU Used AVG</th>
<th width="3%">VM CPU Reserv GHz</th>
<th width="3%">VM CPU Reserv perc</th>
<th width="3%">VM RAM Allocated GB</th>
<th width="3%">VM RAM Used GB</th>
<th width="2%">VM is ON</th>
</tr>
</thead>
<!--- <a href="contragent_rpt.cfm?__id=#company_uid#&#tr.fwx#" style="float:right;word-break:normal;" >--->
<cfoutput query="qVM">
<tr>
<td><a href="contragent.cfm?__id=#company_uid#&#tr.fwx#"style="word-break:normal;">#WZ#&nbsp;<img src="img/view.gif" title="сводка по контрагенту" style="display:inline;"/></a></td>
<td>#Name#</td>
<td>#UUID_VM#</td>
<td>#Organization#</td>
<td>#VDC#</td>
<td><cftry>#round(VDC_CPU_Reserv,3)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VDC_CPU_Speed,3)#<cfcatch></cfcatch></cftry></td>
<td>#qVM.Cluster#</td>
<td>#Host#</td>
<td>#Host_Model#</td>
<td>#CPU_Model#</td>
<td>#Host_CPU_Cores#</td>
<td>#Host_CPU_Sockets#</td>
<td>#round(Host_CPU_Speed,3)#</td>
<td>#round(Host_RAM)#</td>
<td><cftry>#round(Host_CPU_Used,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(Host_CPU_Used_Avg,1)#<cfcatch></cfcatch></cftry></td>
<td>#VM_vCPU_count#</td>
<td><cftry>#round(VM_CPU_Used,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VM_CPU_Used_AVG,1)#<cfcatch></cfcatch></cftry></td>
<td><cftry>#round(VM_CPU_Reserv_GHz,1)#<cfcatch></cfcatch></cftry></td>
<td>#VM_CPU_Reserv_perc#</td>
<td>#VM_RAM_Allocated#</td>
<td><cftry>#round(VM_RAM_Used)#<cfcatch></cfcatch></cftry></td>
<td>#VM_is_ON#</td>
<!--- <td><a href="contragent.cfm?__id=#company_uid#&#tr.fwx#">#client_sold#</a></td> --->
</tr>
</cfoutput>
</table>
<!--- <cfdump var=#qCharge#/> --->
<layout:page section="footer"/>