21 with asymmetric time and local version
This commit is contained in:
+75
-33
@@ -10,6 +10,17 @@
|
||||
<cfreturn (a GT 0)? a : ""/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="myNumFmt">
|
||||
<cfargument name="a"/>
|
||||
<cfreturn (isNumeric(a))? numberFormat(a,",.00") : ""/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="safeNum">
|
||||
<cfargument name="a"/>
|
||||
<cfreturn (isNumeric(a))? a : 0/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<m:prepare_ls entity="specification_item" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
|
||||
|
||||
<m:filter_settings target="#pageInfo.entity#_ls">
|
||||
@@ -70,39 +81,64 @@ from (
|
||||
select
|
||||
DATE_TRUNC('month', dayscale.dt)::date as m
|
||||
,0
|
||||
,sum(siv.price*siv.quantity*a.probability_perc/100/dayscale.days
|
||||
/*,sum(siv.price*siv.quantity*a.probability_perc/100/dayscale.days
|
||||
+ COALESCE(siv0.price*siv0.quantity*(100-a.probability_perc)/100/dayscale.days, 0)
|
||||
)
|
||||
from
|
||||
(SELECT dd::date as dt, DATE_PART('days',
|
||||
DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL
|
||||
) days FROM generate_series
|
||||
( '2023-01-01'::timestamp
|
||||
, '2029-12-31'::timestamp
|
||||
, '1 day'::interval) dd) dayscale
|
||||
join specification_item_version siv on (dayscale.dt >= siv.dt_from AND (siv.dt_to >= dayscale.dt OR siv.dt_to IS NULL))
|
||||
)*/
|
||||
,COALESCE(sum(
|
||||
case when (siv.dt_to > dayscale.dt OR siv.dt_to IS NULL) then
|
||||
siv.price*siv.quantity*COALESCE(
|
||||
case when a.is_actual then 100 else a.probability_perc end
|
||||
,0)/100/dayscale.days
|
||||
/*до окончания свежей сделки она суммируется с прошлой актуальной по правилу вероятностей, считая вероятность актуальной за сделки за 1*/
|
||||
else 0 /*по окончании свежей сделки она дает нулевой вклад*/
|
||||
end
|
||||
),0)
|
||||
+ COALESCE(sum(
|
||||
case when (siv0.dt_to > dayscale.dt OR siv0.dt_to IS NULL) then 0 else
|
||||
siv0.price*siv0.quantity*(100-COALESCE(
|
||||
case when a.is_actual then 100 else a.probability_perc end
|
||||
,0))/100/dayscale.days
|
||||
/*по окончании свежей сделки*/
|
||||
end
|
||||
),0)
|
||||
from (SELECT dd::date as dt
|
||||
, DATE_PART('days', DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL) days
|
||||
FROM generate_series(
|
||||
'2023-01-01'::timestamp
|
||||
,'2029-12-31'::timestamp
|
||||
,'1 day'::interval) dd
|
||||
) dayscale
|
||||
left outer join specification_item_version siv on (dayscale.dt >= siv.dt_from /*AND (siv.dt_to > dayscale.dt OR siv.dt_to IS NULL)*/
|
||||
AND siv.agreement_version=(select max(iiv.agreement_version) from specification_item_version iiv
|
||||
join specification_item ii on (iiv.specification_item_uid=ii.specification_item_uid)
|
||||
join specification isp on (ii.specification_id=isp.specification_id)
|
||||
join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version)
|
||||
where iiv.specification_item_uid=siv.specification_item_uid
|
||||
AND (dayscale.dt >= iiv.dt_from /*AND (iiv.dt_to > dayscale.dt OR iiv.dt_to IS NULL)*/)))
|
||||
/*AND ia.is_actual*/ /*свежее соглашение не обязано быть действующим*/
|
||||
join specification_item si on (siv.specification_item_uid=si.specification_item_uid AND si.pricing_model_id in (2,3))
|
||||
join specification s on (si.specification_id=s.specification_id )
|
||||
join agreement a on (s.contract_id=a.contract_id AND siv.agreement_version=a.agreement_version AND a.agreement_version=(select max(iiv.agreement_version) from specification_item_version iiv
|
||||
join specification_item ii on (iiv.specification_item_uid=ii.specification_item_uid)
|
||||
join specification isp on (ii.specification_id=isp.specification_id)
|
||||
join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version)
|
||||
where iiv.specification_item_uid=si.specification_item_uid
|
||||
--AND ia.is_actual
|
||||
))
|
||||
join specification s on (si.specification_id=s.specification_id)
|
||||
join agreement a on (s.contract_id=a.contract_id AND a.agreement_version=siv.agreement_version)
|
||||
join contract d on s.contract_id=d.contract_id
|
||||
join contragent k on d.contragent_id=k.contragent_id
|
||||
join svc on (si.svc_id=svc.svc_id)
|
||||
left outer join agreement a0 on (s.contract_id=a0.contract_id /*AND siv.agreement_version=a0.agreement_version*/ AND a0.agreement_version=(select max(iiv.agreement_version) from specification_item_version iiv
|
||||
join specification_item ii on (iiv.specification_item_uid=ii.specification_item_uid)
|
||||
join specification isp on (ii.specification_id=isp.specification_id)
|
||||
join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version)
|
||||
where iiv.specification_item_uid=si.specification_item_uid
|
||||
AND ia.agreement_version < a.agreement_version
|
||||
AND ia.is_actual
|
||||
))
|
||||
-- находим предыдущее действующее соглашение
|
||||
-- если свежее соглашение действует, то впр
|
||||
-- нам нужно, чтобы в прошлом (до dt_from свежего соглашения) свежак был прозрачен,
|
||||
-- а в будущем (после dt_to) факт перетирался свежим соглашением
|
||||
left outer join agreement a0 on (s.contract_id=a0.contract_id AND a0.agreement_version=(
|
||||
select max(iiv.agreement_version) from specification_item_version iiv
|
||||
join specification_item ii on (iiv.specification_item_uid=ii.specification_item_uid)
|
||||
join specification isp on (ii.specification_id=isp.specification_id)
|
||||
join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version)
|
||||
where iiv.specification_item_uid=si.specification_item_uid
|
||||
AND ia.agreement_version < siv.agreement_version
|
||||
AND ia.is_actual /*именно действующее соглашение, принимаемое за факт*/
|
||||
)
|
||||
)
|
||||
left outer join specification_item_version siv0 on (siv0.specification_item_uid=si.specification_item_uid
|
||||
AND siv0.agreement_version=a0.agreement_version)
|
||||
AND siv0.agreement_version=a0.agreement_version AND (dayscale.dt >= siv0.dt_from /*AND (siv0.dt_to > dayscale.dt OR siv0.dt_to IS NULL)*/)
|
||||
)
|
||||
where 1=1 <m:filter_build filter=#pageInfo.settings.filter#/>
|
||||
group by DATE_TRUNC('month', dayscale.dt)
|
||||
) install_fix_payg
|
||||
@@ -142,8 +178,7 @@ select count(*) as cnt from specification_item where 1=1
|
||||
<a href="?output_xls" title="экспорт в Excel" style="margin:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
|
||||
<a href="?output_json" title="экспорт в json" style="margin:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
|
||||
<br/>
|
||||
Месяцы с нулевой суммой не показаны
|
||||
|
||||
Месяцы без данных не показаны. Вариант с локальной рабочей версией строки (инстанса)
|
||||
<table class="worktable">
|
||||
|
||||
<thead>
|
||||
@@ -152,15 +187,22 @@ select count(*) as cnt from specification_item where 1=1
|
||||
<th>Инсталл</th>
|
||||
<th>Ежемес</th>
|
||||
<th>Выручка</th>
|
||||
<th>Прирост</th>
|
||||
<th>Прирост ежемес</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<cfset income_old=0/>
|
||||
<cfset income_recurring_old=0/>
|
||||
<cfoutput query="qRead">
|
||||
<tr>
|
||||
<td class="c">#dateFormat(m,"MM.YYYY")#</td>
|
||||
<td class="r">#nFmt(income_install)#</td>
|
||||
<td class="r">#nFmt(income_recurring)#</td>
|
||||
<td class="r">#nFmt(income)#</td>
|
||||
<td class="r">#myNumFmt(income_install)#</td>
|
||||
<td class="r">#myNumFmt(income_recurring)#</td>
|
||||
<td class="r">#myNumFmt(income)#</td>
|
||||
<td class="r">#myNumFmt(safeNum(income) - income_old)#</td>
|
||||
<cfset income_old = safeNum(income)/>
|
||||
<td class="r">#myNumFmt(income_recurring-income_recurring_old)#</td>
|
||||
<cfset income_recurring_old = safeNum(income_recurring)/>
|
||||
</tr>
|
||||
</cfoutput>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user