Files
payg/payg.cfm
T
2025-08-17 22:23:10 +03:00

594 lines
24 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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="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)/>
<!--- Нужно еще применить политики бесплатного минимума --->
<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, 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, 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))
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>
<cfquery name="qSivAge" datasource="dwh">
select max(dt_load) as dt_load from elma.deals_services
</cfquery>
<!--- здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет) --->
<cfif isDefined("DEBUG")>
<cfdump var=#qSpec#/>
<cfflush/>
</cfif>
<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#/> --->
<cfquery name="qComputingAge" datasource="billing-vc">
select max(capacity_resource.timestamp) as dt_load from ngcloud_ru.capacity_resource
</cfquery>
<!--- переделать 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>
<cfquery name="qStorageAge" datasource="billing-vc">
select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage
</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="qS3VolAge" datasource="billing-s3">
select max(timestamp_addition) as dt_load from s3billing.bucket_stat
</cfquery>
<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>
<cfquery name="qS3OpsTrfAge" datasource="billing-s3">
select max(time) as dt_load from s3billing.usage_bucket_by_user
</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-m', 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-m', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric 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
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
</cfquery>
<cfif isDefined("DEBUG")>
<cfdump var=#qUnifiedMetric#/>
<cfflush/>
</cfif>
<cfquery name="qCharge" dbType="query">
SELECT
s.wz
,s.code
,s.price
,s.discount
,s.contragent, s.contragent_uid
,s.contract,s.contract_uid
,s.deal, s.deal_uid
,s.additional_agreement, s.additional_agreement_uid
,s.abstract_service
,s.modifier
,user_description
,s.ed_izm
,s.line_key, s.dt_from, s.dt_to
,s.deal,s.abstract_service,s.modifier,s.user_description
,m.raw_metric
,m.metric
,m.chargeable_metric
,s.price*(100-s.discount)/100 as discounted_price
,s.price*(100-s.discount)/100*m.chargeable_metric as charge
FROM qSpec as s, qUnifiedMetric as m WHERE s.wz=m.wz AND s.code=m.code
order by s.wz, s.code
</cfquery>
<!--- looks like QoQ does not support join syntax, at least of Lucee 5.4--->
<layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Отчет по PAYG</b></cfoutput>
</layout:attribute>
<layout:attribute name="controls">
<!---skip filter link, filter is not implemented--->
<!---<layout:language_switch/>--->
</layout:attribute>
</layout:page>
Внимание! округление вверх при расчете метрик get, put S3. Расчетные суммы могут содержать погрешности округления, поэтому окончательный расчет стоимости (количество * цену) должен выполняться в бухгалтерской программе.
<b>Если у клиента больше 1 действующего допника с услугами PAYG, то данные в отчете могут быть замножены, в этом случае считать вручную</b>
<br/>
Даты актуальности пока проверять вручную
<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>
</cfoutput>
<!--- <cfdump var=#dt_start#/>
<cfdump var=#dt_finish#/>
<cfdump var=#hours#/> --->
<table class="worktable">
<thead>
<td width="1%"></td>
<td width="3%">WZ</td>
<td width="5%">Артикул</td>
<td width="3%">Цена без НДС проверить</td>
<td width="3%">Кол-во (метрика)</td>
<td width="3%">Ед.изм.</td>
<td width="3%">Ст-ть</td>
<td width="3%">&nbsp;&nbsp;&nbsp;</td>
<td width="6%">Дата НОУ</td>
<td width="6%">Дата оконч.</td>
<td width="3%">Ключ строки</td>
<td width="3%">GPL без НДС проверить</td>
<td width="3%">Скидка%</td>
<td width="3%">Сырая метрика</td>
<td width="3%">Приведен&shy;ная метрика</td>
<td width="7%">Контрагент</td>
<td width="3%">Договор</td>
<td width="3%">Допник</td>
<td width="3%">Сделка</td>
<td width="10%">Услуга</td>
<td width="8%">Клиентс. назв.</td>
</thead>
<cfoutput query="qCharge" group="wz">
<cfset var acc=0/>
<cfoutput>
<cfset acc=acc+charge/>
<tr>
<td>#currentRow#</a></td>
<td><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a></td>
<td>#code#</td>
<td class="r">#discounted_price#</td>
<td class="r">#chargeable_metric#</td>
<td>#ed_izm#</td>
<td class="r">#charge#</td>
<td></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">#price#</td>
<td class="r">#discount#</td>
<td class="r" style="color:lightgray">#raw_metric#</td>
<td class="r">#metric#</td>
<td><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#contragent#</a></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>
<td>#abstract_service# #modifier#</td>
<td>#user_description#</td>
</tr>
</cfoutput>
<tr>
<td></td>
<td colspan="5" class="b"><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a> #contragent#</td>
<td colspan="1" class="r b">#NumFmt(acc,2)#</td>
<td colspan="14"></td>
</tr>
</cfoutput>
</table>
<!--- <cfdump var=#qCharge#/> --->
<layout:page section="footer"/>
<!---
--->
<!--- --,m.*
--,s.price*(100-s.discount)/100 as discounted_price
-- --->
<!--- В одном месте 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'); --->