This commit is contained in:
msyu 2025-06-18 09:56:04 +03:00
parent 96c669df04
commit a07522702c
8 changed files with 262 additions and 13 deletions

View File

@ -69,7 +69,7 @@
<!--- <cfset this.datasources["#this.datasource#"]=getDS("#this.datasource#","datasource_#this.datasource#")/> --->
<cfset request.RECORDS_PER_PAGE=500/>
<cfset request.APP_VERSION="0.00.001"/>
<cfset request.APP_VERSION="0.00.002"/>
<cflock scope="application" type="readonly" timeout=3>
<cfset request.APP_NAME=this.Name/>

View File

@ -32,6 +32,7 @@
<d:param field="dt_agreement" type="timestamp" format="yyyy-MM-dd" init=#Now()#/>
<d:param field="is_actual" type="bit" init="0" default="0"/>
<d:param field="deal_uid" type="guid" skipInsert skipUpdate/>
<d:param field="probability_perc" type="integer" forNull="" init=100/>
<d:param field="descr" type="varchar" preprocessor=#plain2HtmClean#/>
<d:param field="creator_id" type="integer" value="#request.usr_id#" skipUpdate/>
@ -77,7 +78,7 @@
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput>
Соглашение
Соглашение (сделка)
<cfif d.agreement_version GE 0>
<b>#d.agreement#</b>
[#d.agreement_version#]
@ -121,6 +122,13 @@
<div class="td">
#d.deal_uid#
</div>
</div>
<div class="tr">
<div class="th">Вероятность</div>
<div class="td">
<input type="text" name="probability_perc" value="#d.probability_perc#" size="3"/>
</div>
</div>
<div class="tr">

View File

@ -24,6 +24,7 @@
<d:field title="contract_id" cfSqlType="CF_SQL_INTEGER">a.contract_id</d:field>
<d:field title="Н-р согл." cfSqlType="CF_SQL_INTEGER">a.agreement_version</d:field>
<d:field title="Ключ сделки">a.deal_uid</d:field>
<d:field title="Вероятность">a.probability_perc</d:field>
<d:field title="Соглашение">a.agreement</d:field>
<d:field title="Дата соглашения">a.dt_agreement</d:field>
<d:field title="Описание">a.descr</d:field>
@ -112,6 +113,7 @@ select count(*) as cnt from agreement where 1=1
</c:column>
<c:column width="2%" field="agreement_version"><c:td class="r"/></c:column>
<c:column width="12%" field="deal_uid"/>
<c:column width="3%" field="probability_perc"/>
<c:column width="7%" field="f_contract"/>
<c:column width="5%" field="dt_contract" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="10%" field="contragent"/>

View File

@ -1,6 +1,8 @@
/*
Ñïåöèôèêàöèè ñ âåðñèîííîñòüþ
Темпоральность задействована для 2 сущностей, разная:
История инстанса - начало оказания, изменение количества и цены, завершение
История сделки - как меняется со временем состав сделки, сумма и вероятность. В теперешней выгрузке эта вторая темпоральность не просматривается
*/
/*
@ -101,6 +103,7 @@ create table agreement (
,dt_agreement timestamptz NOT NULL -- ôîðìàëüíàÿ äàòà, íå ñâÿçàíà ñ âåðñèîííîñòüþ (ìîæåò áûòü, ïîðÿäîê)
,is_actual boolean NOT NULL -- ñ÷èòàåì, ÷òî íà äîãîâîð 1 äåéñòâóþùåå ñîãëàøåíèå - êîòîðûå äî íåãî, òå óñòàðåëè, êîòîðûå ïîñëå, òå â ïðîåêòå
,deal_uid uuid NOT NULL DEFAULT gen_random_uuid() -- ýòî ìîã áûòü ïåðâè÷íûé êëþ÷, ïîêà îí íå èñïîëüçóåòñÿ - òîëüêî èìèòèðóåò êëþ÷ ñäåëêè
,probability_perc int NULL
,descr text NULL
,dt_created timestamptz NOT NULL default CURRENT_TIMESTAMP --
@ -110,6 +113,7 @@ create table agreement (
,CONSTRAINT PK_agreement PRIMARY KEY (contract_id, agreement_version)
);
ALTER TABLE agreement OWNER TO dbo;
--ALTER TABLE agreement ADD probability_perc int NULL;
insert into agreement (contract_id,agreement_version,dt_agreement,is_actual) values (1,0,CURRENT_TIMESTAMP,true);
-- alter table agreement add deal_uid uuid NOT NULL DEFAULT gen_random_uuid();
CREATE INDEX IF NOT EXISTS UX_deal_uid ON agreement(deal_uid);

View File

@ -1,4 +1,25 @@
2025-06-17 09:07:46
2025-06-16 10:58:02
select
a.deal_uid
,k.contract
,a.agreement_version
,k.contragent_id
,case when a.agreement_version = 0 then 'New sale' else 'Up sale' as deal_type
from specification_item_version siv
join specification_item si on (siv.specification_item_uid=si.specification_item_uid)
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)
join contract k on s.contract_id=k.contract_id
change:
new
change quantity+dicount
delete
change quantity
change dicount
git remote add origin https://gitea.services.ngcloud.ru/smishchuk/spec.git
root@dat-n-smishch1 MINGW64 /d/wwwroot/spec (master)
@ -20,6 +41,10 @@ origin gitea@gitea.services.ngcloud.ru:smishchuk/spec.git (push)
Локально, чтобы не загаживать окружение, поместим переменные окружения в реестр [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lucee] "Environment"
Опубликовал на тестовой платформе
выпустил багфикс
2025-06-14 11:02:46
Центральный селект
select * from specification_item_version siv
@ -31,6 +56,7 @@ join agreement a on (s.contract_id=a.contract_id AND siv.agreement_version=a.agr
Как вообще учитывать дату в диффе? Или никак, просто передавать.
*** Вероятно, dt_from или dt_to должны быть заполнены (check)
16:12 12.06.2025
Предлагается использовать конечную дату только для завершения действия всей строки спеки. Тогда ее просто убрать из версии? Некорректно, она же возникает в какой-то версии.
Если захочется делать одним соглашением 2 изменения строки, можно соглашению сделать суррогатный ключ, а номер соглашения для версии строки убрать из первичного ключа

View File

@ -15,6 +15,7 @@
<c:menu_item acl="" page="contract_ls.cfm" label="Договоры"/>
<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>

View File

@ -53,16 +53,7 @@
trackOut="tr"
idAttributesOut="id"
/>
<!--- <m:dispatch_detail
usePRG="No"<!---*** --->
pageInfo=#pageInfo#
id=""
queryString="specification_item_uid=#specification_item_uid#"
defaultBackUrl="specification.cfm?specification_id=#d.specification_item_id#"
status=#pageInfo.status#
trackOut="tr"
idAttributesOut="id"
/> --->
<!--- decoration --->
<cfquery name="qDecoration" datasource="#request.DS#">

217
specification_item_ls.cfm Normal file
View File

@ -0,0 +1,217 @@
<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="specification_item" 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.specification_item_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 /*переделать выборку версий через group by*/
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
<d:field title="contract_id" cfSqlType="CF_SQL_INTEGER">a.contract_id</d:field>
<d:field title="Н-р согл." cfSqlType="CF_SQL_INTEGER">a.agreement_version</d:field>
<d:field title="Ключ сделки">a.deal_uid</d:field>
<d:field title="Вероятность">a.probability_perc</d:field>
<d:field title="Соглашение">a.agreement</d:field>
<d:field title="Тип сделки">case when a.agreement_version = 0 then 'New sale' else 'Up sale' end as deal_type</d:field>
<!--- <d:field title="Дата соглашения">a.dt_specification_item</d:field> --->
<!--- <d:field title="Описание">a.descr</d:field> --->
<d:field title="Спецификация">s.specification</d:field>
<d:field>si.specification_id</d:field>
<d:field title="Договор">d.contract</d:field>
<d:field title="Дата договора">d.dt_contract</d:field>
<d:field title="Контрагент">k.contragent</d:field>
<d:field title="Ключ строки">siv.specification_item_uid</d:field>
<d:field title="Сервис">svc.svc</d:field>
<d:field title="svc_id">si.svc_id</d:field>
<d:field title="Ц/обр">si.pricing_model_id</d:field>
<d:field title="Код">svc.code</d:field>
<d:field title="Дата с">siv.dt_from</d:field>
<d:field title="Дата по">siv.dt_to</d:field>
<d:field title="Кол-во">siv.quantity</d:field>
<d:field title="Цена">siv.price</d:field>
<d:field title="Кол-во прошлое">ver.quantity as quantity_prev</d:field>
<d:field title="Цена прошлая">ver.price as price_prev</d:field>
<d:field title="Версия прошлая">ver.agreement_version as version_prev</d:field>
<d:field title="Изменение стоимости">COALESCE(siv.price*siv.quantity,0) - COALESCE(ver.price*ver.quantity,0) as cost_diff</d:field>
<d:field title="Изменение с вер.">(COALESCE(siv.price*siv.quantity,0) - COALESCE(ver.price*ver.quantity,0))*a.probability_perc/100 as cost_diff_prob</d:field>
</d:field_set>
from specification_item_version siv
join specification_item si on (siv.specification_item_uid=si.specification_item_uid)
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)
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 (select
siv1.agreement_version
,siv1.specification_item_uid
,a1.agreement
,a1.contract_id
,a1.dt_agreement
,a1.is_actual
,siv1.specification_item_version
,siv1.quantity
,siv1.price
,siv1.dt_from
,siv1.dt_to
,ii1.specification_id
from specification_item_version siv1
join specification_item ii1 on (siv1.specification_item_uid=ii1.specification_item_uid)
join specification is1 on (ii1.specification_id=is1.specification_id)
join agreement a1 on (siv1.agreement_version=a1.agreement_version AND is1.contract_id=a1.contract_id)
) ver on (si.specification_item_uid=ver.specification_item_uid AND ver.specification_id=s.specification_id
AND ver.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
AND ia.agreement_version < a.agreement_version
)
)
where 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
)
<!--- 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 specification_item 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">
<!---skip filter link, filter is not implemented--->
<!---<layout:language_switch/>--->
</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_deal_uid')/>
<cfset titleMap.f_deal_uid=titleMap.deal_uid/>
<cfset queryAddColumn(qRead,'f_contract')/>
<cfset titleMap.f_contract=titleMap.contract/>
<cfset queryAddColumn(qRead,'f_specification')/>
<cfset titleMap.f_specification=titleMap.specification/>
<cfset queryAddColumn(qRead,'f_version_prev')/>
<cfset titleMap.f_version_prev=titleMap.version_prev/>
<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#><!--- *** Здесь некомфортное дублирование startRow, maxRows с вызовом c:table ниже, причем в c:table оно закопано в модуль, и аргументы называются по-разному... но мы хотим немного сэкономить и не обрабатывать весь резалтсет --->
<!--- *** тут можно было бы спокойно использовать суррогатный альтернативный ключ, но хочется проверить, как будет работать track на составном ключе. Кстати, я все равно его использую как ancor name --->
<cfsavecontent variable="qRead.f_link_view_edit">
<a href="specification_item_version.cfm?specification_item_uid=#specification_item_uid#&agreement_version=#agreement_version#&#tr.fwx#" name="#specification_item_uid#" <cfif pageInfo.writePermitted()>title="редактировать" class="edit"<cfelse>title="просмотр" class="view"</cfif>></a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_deal_uid">
<a href="agreement.cfm?contract_id=#contract_id#&agreement_version=#agreement_version#&#tr.fwx#">#deal_uid#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_contract">
<a href="contract.cfm?contract_id=#contract_id#&#tr.fwx#">#contract# #dateformat(dt_contract,"YYYY-MM-DD")#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_specification">
<a href="specification.cfm?specification_id=#specification_id#&#tr.fwx#">#specification#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_version_prev">
<a href="specification_item_version.cfm?specification_item_uid=#specification_item_uid#&agreement_version=#agreement_version#&#tr.fwx#">#version_prev#</a>
</cfsavecontent>
<cfsavecontent variable="qRead.f_link_del">
<cfif pageInfo.writePermitted()><a href="specification_item_version_del.cfm?specification_item_uid=#specification_item_uid#&agreement_version=#agreement_version#&#tr.fwx#" class="del" title="удалить"></a></cfif>
</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:th><!--- <a href="specification_item.cfm?contract_id=&specification_item_version="><img src="img/add.gif"/></a> ---></c:th>
<c:td field="f_link_view_edit" class="c"/>
</c:column>
<c:column width="12%" field="f_deal_uid"/>
<c:column width="3%" field="probability_perc"><c:td class="r"/></c:column>
<c:column width="2%" field="f_specification"/>
<c:column width="5%" field="f_contract"/>
<!--- <c:column width="5%" field="dt_contract" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column> --->
<c:column width="7%" field="contragent"/>
<c:column width="7%" field="svc"/>
<c:column width="5%" field="dt_from" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="5%" field="dt_to" formatter=#function(dt){return dateformat(dt,"YYYY-MM-DD");}#><c:td class="c"/></c:column>
<c:column width="3%" field="agreement_version"><c:td class="c"/></c:column>
<c:column width="3%" field="quantity"><c:td class="r"/></c:column>
<c:column width="3%" field="price"><c:td class="r"/></c:column>
<c:column width="3%" field="f_version_prev"><c:td class="c"/></c:column>
<c:column width="3%" field="quantity_prev"><c:td class="r"/></c:column>
<c:column width="3%" field="price_prev"><c:td class="r"/></c:column>
<c:column width="3%" field="cost_diff"><c:td class="r"/></c:column>
<c:column width="3%" field="cost_diff_prob"><c:td class="r"/></c:column>
<c:column width="1%" sortable="false">
<c:td field="f_link_del" class="c"/>
</c:column>
</c:table>
<cfoutput>#gridFooter#</cfoutput>
Расчета по дням тут нет.
Дата по на самом деле нигде не используется.
Важное допущение: вероятность прошлой сделки принимается за 100% (то есть изменения имеют смысл только к действующему договору)
</cfif>
<layout:page section="footer"/>