intermediate draft

This commit is contained in:
msyu 2025-06-06 06:03:11 +03:00
parent 529334d03b
commit 118012e17e
9 changed files with 394 additions and 107 deletions

229
agreement.cfm Normal file
View File

@ -0,0 +1,229 @@
<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="agreement" key="undefined" pageInfoOut="pageInfo"/><!--- для составного ключа key бесполезен, но инициализировать пустой строкой не получается из-за cfparam name="#ATTRIBUTES.key#" default="-1" в prepare_detail --->
<cfparam name="contract_id" type="integer"/>
<cfquery name="qInitVersion"><!--- *** надо бы только при сохранении, а так возможен конфликт --->
select coalesce(max(agreement_version)+1,0) as next_version
from agreement
where contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#contract_id#"/>
</cfquery>
<d:bean readonly=#!pageInfo.writePermitted()# table="#pageInfo.entity#" datasource="#request.DS#" output="d" status="status">
<d:param field="contract_id" type="integer" key/><!--- поле с атрибутом key не участвует в update --->
<!--- формировать номер версии нам придется самостоятельно --->
<d:param field="agreement_version" type="integer" key init=#qInitVersion.next_version#/><!--- поле с атрибутом key не участвует в update --->
<d:param field="agreement" type="varchar" size="255" preprocessor=#cleanInput# init=#qInitVersion.next_version#/>
<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="descr" type="varchar" preprocessor=#plain2HtmClean#/>
<d:param field="creator_id" type="integer" value="#request.usr_id#" skipUpdate/>
<d:param field="updater_id" type="integer" value="#request.usr_id#" />
<d:param field="dt_created" type="timestamp" value="#Now()#" skipUpdate/>
<d:param field="dt_updated" type="timestamp" value="#Now()#"/>
</d:bean>
<m:dispatch_detail
usePRG="No"<!---*** --->
pageInfo=#pageInfo#
id=""<!--- для составного ключа --->
queryString="contract_id=#d.contract_id#&agreement_version=#d.agreement_version#"
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 agreement e
left outer join usr a on (e.creator_id=a.usr_id)
left outer join usr m on (e.updater_id=m.usr_id)
where e.contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#d.contract_id# null=#!isValid('integer',d.contract_id)#/>
AND e.agreement_version=<cfqueryparam cfsqltype="cf_sql_integer" value=#d.agreement_version# null=#!isValid('integer',d.agreement_version)#/>
</cfquery>
<cfquery name="qContract" datasource="#request.DS#">
select d.contract_id, d.contract, d.dt_contract, c.contragent_id, c.contragent
from contract d
left outer join contragent c on (d.contragent_id=c.contragent_id)
where d.contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contract_id#"/>
</cfquery>
</m:silent><!---
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput>
Соглашение
<cfif d.agreement_version GE 0>
<b>#d.agreement#</b>
[#d.agreement_version#]
</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="contract_id" value="#d.contract_id#"/>
<input type="hidden" name="agreement_version" value="#d.agreement_version#"/>
<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">Договор</div>
<div class="td">
<a href="contract.cfm?contract_id=#d.contract_id#&#tr.fwx#">#qContract.contract# #dateFormat(qContract.dt_contract,'DD.MM.YYYY')#</a>
а как у нас поведет себя трек для составных ключей?
</div>
</div>
<div class="tr">
<div class="th">Номер версии</div>
<div class="td">
#d.agreement_version# (некорректно, в одном месте версией называется номер, а в другом сущность, и это отразилось в именовании таблиц и полей)
</div>
</div>
<div class="tr">
<div class="th">Соглашение (номер для печати)</div>
<div class="td">
<input type="text" name="agreement" value="#d.agreement#" size="15"/>
</div>
</div>
<div class="tr">
<div class="th">Дата соглашения</div>
<div class="td">
<input type="date" name="dt_agreement" id="dt_agreement" value="#dateFormat(d.dt_agreement,'YYYY-MM-DD')#"/>
<button type="button" onclick="document.getElementById('dt_agreement').value='#DateFormat(Now(), 'YYYY-MM-DD')#';">Сегодня</button>
<i>для упрощения можно позволить соглашению иметь обратную силу - то есть просто не проверять, что дата изменения строки спецификации не раньше даты соглашения</i>
</div>
</div>
<div class="tr">
<div class="th">Действует</div>
<div class="td">
<input type="checkbox" name="is_actual" value="1"<cfif d.is_actual GT 0> checked</cfif>/>
<i>если соглашение действует, это означает ровно то, что его правки учитываются при формировании спецификации на любую дату</i>
</div>
</div>
<div class="tr">
<div class="th">Описание</div>
<div class="td">
<textarea name="descr" rows="3" cols="100">#request.htm2plain(d.descr)#</textarea>
</div>
</div>
<div class="tr">
<div class="th">Создано</div>
<div class="td">
#dateFormat(d.dt_created,'DD.MM.YYYY')# #timeFormat(d.dt_created,'HH:MM')#
#qDecoration.creator# <cfif len(qDecoration.creator_shortname)>(#qDecoration.creator_shortname#)</cfif>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Изменено
#dateFormat(d.dt_updated,'DD.MM.YYYY')# #timeFormat(d.dt_updated,'HH:MM')#
#qDecoration.updater# <cfif len(qDecoration.updater_shortname)>(#qDecoration.updater_shortname#)</cfif>
</div>
</div>
</div>
Соглашение просто объединяет правки строк спецификации в пакет и оформляет их документом (в случае с допником). То есть версии строк существуют не сами по себе, а связаны с конкретным соглашением. Между прочим, это означает, что в рамках одного доп. соглашения мы не можем сделать 2 изменения строки, например 2 разные цены с разных дат - нужно оформлять отдельными допниками.
Можно назвать нулевое соглашение базовым, а остальные дополнительными. (наверное, можно было бы синтезировать базовое соглашение с NULL номером)
Есть ли понятие текущего соглашения?
Есть ли понятие действующего соглашения, или у нас все действуют, или строки из недействующего соглашения не должны участвовать в цепочке (тогда, видимо, не удастся активировать соглашение задним числом, цепочка может разрушиться)
Если к соглашению нет измененных строк спецификации, в нем нет большого смысла (но изменения строк надо к чему-то приписывать).
Надо было начать с моделирования данных в таблицах, до интерфейса?
</cfoutput>
<layout:page section="extension" closeForm="Yes"/>
<!--- <cfif d.agreement_id GT 0>
<cfquery name="qItem" datasource="#request.DS#">
select
i.agreement_item_uid
,s.svc_id
,s.svc
,s.code
,(select count(*) from agreement_item_version siv where siv.agreement_item_uid=i.agreement_item_uid) as item_version_count
from agreement_item i
left outer join svc s on (i.svc_id=s.svc_id)
where i.agreement_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.agreement_id#"/>
order by 1
</cfquery>
<cfoutput>
<p>
Строки спецификации (#qItem.recordCount#)
<cfif pageInfo.writePermitted()>
<cfoutput>
<cfset addUrl="agreement_item.cfm?agreement_item_uid=&agreement_id=#d.agreement_id#&#tr.fwx#"/>
<button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'">
<a href="#addUrl#">Создать</a>
</button>
</cfoutput>
</cfif>
</p>
</cfoutput>
<table class="worktable">
<thead>
<tr>
<th></th>
<th>Ключ строки</th>
<th>Услуга</th>
<th>Код услуги</th>
<th>Версий</th>
<!--- <th>Компонентов</th> --->
<th></th>
</tr>
</thead>
<cfoutput query="qItem">
<tr>
<td>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="agreement_item" key="agreement_item_uid" id=#agreement_item_uid# fwx=#tr.fwx#/>
</td>
<td>#agreement_item_uid#</td>
<td>#svc#</td>
<td>#code#</td>
<td>#item_version_count#</td>
<td class="c">
<c:link_del canWrite=#pageInfo.writePermitted()# entity="agreement_item" id=#agreement_item_uid# fwx=#tr.fwx#/>
</td>
</tr>
</cfoutput>
</table>
</cfif> --->
<layout:page section="footer"/>

View File

@ -30,6 +30,8 @@
<d:param field="dt_updated" type="timestamp" value="#Now()#"/> <d:param field="dt_updated" type="timestamp" value="#Now()#"/>
</d:bean> </d:bean>
<!--- Вероятно, вместе с договором можно сразу создавать базовое соглашение, или базовую версию --->
<m:dispatch_detail <m:dispatch_detail
usePRG="No"<!---*** ---> usePRG="No"<!---*** --->
pageInfo=#pageInfo# pageInfo=#pageInfo#
@ -146,6 +148,7 @@
s.specification_id s.specification_id
,s.specification ,s.specification
,(select count(*) from specification_item i where i.specification_id=s.specification_id) as item_cnt ,(select count(*) from specification_item i where i.specification_id=s.specification_id) as item_cnt
,(select count(*) from specification_version v where v.specification_id=s.specification_id) as version_cnt
from specification s from specification s
where s.contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contract_id#"/> where s.contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contract_id#"/>
order by 1 order by 1
@ -162,13 +165,14 @@
</button> </button>
</cfoutput> </cfoutput>
</cfif> </cfif>
Как правило, в договоре 1 спецификация, а ее версии определяются дополнительными соглашениями
<table class="worktable"> <table class="worktable">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th>Номер спецификации</th> <th>Номер спецификации</th>
<th>Строк</th> <th>Строк</th>
<th>Версий</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@ -181,12 +185,67 @@
<td class="c"> <td class="c">
<cfif item_cnt GT 0>#item_cnt#</cfif> <cfif item_cnt GT 0>#item_cnt#</cfif>
</td> </td>
<td class="c">
<cfif version_cnt GT 0>#version_cnt#</cfif>
</td>
<td class="c"> <td class="c">
<c:link_del canWrite=#pageInfo.writePermitted()# entity="specification" id=#specification_id# fwx=#tr.fwx#/> <c:link_del canWrite=#pageInfo.writePermitted()# entity="specification" id=#specification_id# fwx=#tr.fwx#/>
</td> </td>
</tr> </tr>
</cfoutput> </cfoutput>
</table> </table>
<cfquery name="qAgreement">
select
a.contract_id
,a.agreement_version
,a.agreement
,a.dt_agreement
,a.is_actual
from agreement a
where a.contract_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contract_id#" null=#!isValid('integer', d.contract_id)#/>
order by 1
</cfquery>
<cfoutput>
<h4>Соглашения (#qAgreement.recordCount#)</h4>
</cfoutput>
<cfif pageInfo.writePermitted()>
<cfoutput>
<cfset addUrl="agreement.cfm?contract_id=#d.contract_id#&#tr.fwx#"/>
<button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'">
<a href="#addUrl#">Создать</a>
</button>
</cfoutput>
</cfif>
<table class="worktable">
<thead>
<tr>
<th></th>
<th>Номер соглашения (версия)</th>
<th>Название</th>
<th>Дата</th>
<th>Действует</th>
<th></th>
</tr>
</thead>
<cfoutput query="qAgreement">
<tr>
<td>
<a href="agreement.cfm?contract_id=#contract_id#&agreement_version=#agreement_version#&#tr.fwx#"><img src="img/edit.gif"/></a>
</td>
<td class="r">#agreement_version#</td>
<td>#agreement#</td>
<td>#dateFormat(dt_agreement,'DD.MM.YYYY')#</td>
<td class="c"><cfif is_actual GT 0><img src="img/ok.png"/></cfif></td>
<td class="c">
<a href="agreement_del.cfm?contract_id=#contract_id#&agreement_version=#agreement_version#&#tr.fwx#"><img src="img/del.gif"/></a>
</td>
</tr>
</cfoutput>
</table>
любопытное последствие использования составного ключа: отпадает желание делать для сущности самостоятельный реестр (может быть, только если есть явная сущность-владелец, как договор для соглашения)
</cfif> </cfif>
<layout:page section="extension" closeForm="Yes"/> <!--- *** правильно так? ---> <layout:page section="extension" closeForm="Yes"/> <!--- *** правильно так? --->

View File

@ -68,7 +68,7 @@ create table agreement (
--agreement_id int GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY --agreement_id int GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY
--, --,
contract_id int NOT NULL contract_id int NOT NULL
,agreement_version int NOT NULL ,agreement_version int NOT NULL -- именование построено не так, как для версии строки спецификации
,agreement varchar(255) NULL -- название соглашения ,agreement varchar(255) NULL -- название соглашения
,dt_agreement timestamptz NOT NULL -- формальная дата, не связана с версионностью (может быть, порядок) ,dt_agreement timestamptz NOT NULL -- формальная дата, не связана с версионностью (может быть, порядок)
,is_actual boolean NOT NULL -- считаем, что на договор 1 действующее соглашение - которые до него, те устарели, которые после, те в проекте ,is_actual boolean NOT NULL -- считаем, что на договор 1 действующее соглашение - которые до него, те устарели, которые после, те в проекте
@ -101,6 +101,7 @@ insert into specification (specification,contract_id) values ('first spec',1);
-- на соглашение должна быть одна актуальная версия спецификации -- на соглашение должна быть одна актуальная версия спецификации
-- может, она не очень-то и нужна, у нее полей-то только описание, а оно не очень нужно, а ключ составной и распространяется дальше
drop table if exists specification_version CASCADE; drop table if exists specification_version CASCADE;
create table specification_version ( create table specification_version (
specification_id int specification_id int

View File

@ -8,16 +8,16 @@
<cfif structKeyExists(ATTRIBUTES,"id")> <cfif structKeyExists(ATTRIBUTES,"id")>
<cfset id=#ATTRIBUTES.id#/> <cfset id=#ATTRIBUTES.id#/><!--- for composite key you can set ATTRIBUTES.id to "" and use ATTRIBUTES.queryString --->
<cfelse> <cfelse>
<cfparam name="ATTRIBUTES.data" type="struct"/> <cfparam name="ATTRIBUTES.data" type="struct"/>
<cfset id=#ATTRIBUTES.data[ATTRIBUTES.pageInfo.entity &"_id"]#/> <cfset id=#ATTRIBUTES.data[ATTRIBUTES.pageInfo.entity &"_id"]#/><!--- так себе идея --->
</cfif> </cfif>
<cfparam name="ATTRIBUTES.defaultBackUrl" type="string" default="#ATTRIBUTES.pageInfo.entity#_ls.cfm"/> <cfparam name="ATTRIBUTES.defaultBackUrl" type="string" default="#ATTRIBUTES.pageInfo.entity#_ls.cfm"/>
<cfparam name="ATTRIBUTES.queryString" type="string" default="#ATTRIBUTES.pageInfo.key#=#id#"/><!---works only for entities with simple integer primary key---> <cfparam name="ATTRIBUTES.queryString" type="string" default="#ATTRIBUTES.pageInfo.key#=#id#"/><!---works only for entities with simple integer primary key--->
<cfparam name="ATTRIBUTES.trackOut" type="string" default=""/> <cfparam name="ATTRIBUTES.trackOut" type="string" default=""/>
<cfparam name="ATTRIBUTES.idAttributesOut" type="string" default=""/><!---works only for entities with simple integer primary key---> <cfparam name="ATTRIBUTES.idAttributesOut" type="string" default=""/><!--- cfqueryparam attribute collection, works only for entities with simple integer primary key--->
<m:track <m:track
thisURL="#request.thisPage#?#ATTRIBUTES.queryString#" thisURL="#request.thisPage#?#ATTRIBUTES.queryString#"
@ -28,7 +28,7 @@
<!--- route ---> <!--- route --->
<cfif ATTRIBUTES.usePRG AND !ATTRIBUTES.status.errorState> <cfif ATTRIBUTES.usePRG AND !ATTRIBUTES.status.errorState>
<!--- PRG pattern---> <!--- PRG pattern--->
<cfif structKeyExists(CALLER, "save")> <cfif structKeyExists(CALLER, "save")><!--- *** такое через атрибуты передать сложно, поэтому так неопрятно (кривое решение тянет за собой другие) --->
<m:location url="#tr.selfUrl#"/> <m:location url="#tr.selfUrl#"/>
</cfif> </cfif>
</cfif> </cfif>

View File

@ -1,6 +1,6 @@
<cfcomponent displayname="Generic Page Info" output="true"> <cfcomponent displayname="Generic Page Info" output="true">
<cfproperty name="entity" type="string"/> <cfproperty name="entity" type="string"/>
<cfproperty name="key" type="string"/> <cfproperty name="key" type="string"/><!--- 2025-06-05 06:31:27 разрешим ему быть списком через запятую или пустой строкой ---><!--- повсеместно используется в конструкции where e.#pageInfo.key#=<cfqueryparam attributeCollection=#id#/>, для составного ключа придется написать что-то более сложное --->
<cfproperty name="status" type="struct"/> <cfproperty name="status" type="struct"/>
<cfproperty name="track" type="struct"/> <cfproperty name="track" type="struct"/>
<cfproperty name="permission" type="integer"/> <cfproperty name="permission" type="integer"/>
@ -11,7 +11,7 @@
<cffunction name="init" access="public"> <cffunction name="init" access="public">
<cfargument name="entity" type="string" required="true"/> <cfargument name="entity" type="string" required="true"/>
<cfargument name="key" type="string" default="#arguments.entity#_id"/> <cfargument name="key" type="string" default="#arguments.entity#_id"/><!--- 2025-06-05 06:31:27 разрешим ему быть списком через запятую или пустой строкой, для составных ключей --->
<cfargument name="track" type="struct" required="true"/> <cfargument name="track" type="struct" required="true"/>
<cfset this.entity=arguments.entity/> <cfset this.entity=arguments.entity/>

View File

@ -1,4 +1,7 @@
<cfsilent></cfsilent><!--- prepare environment ---><!--- v02 17:35 28.06.2018---><!---14:55 29.06.2018 bug fixed---> <cfsilent></cfsilent><!--- prepare environment --->
<!--- v02 17:35 28.06.2018--->
<!---14:55 29.06.2018 bug fixed--->
<!---v03 2025-06-05 06:25 added ATTRIBUTES.defaultBackUrl--->
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfparam name="ATTRIBUTES.entity" type="string"/> <cfparam name="ATTRIBUTES.entity" type="string"/>
@ -8,7 +11,9 @@
<cfparam name="ATTRIBUTES.formEncType" type="string" default=""/> <cfparam name="ATTRIBUTES.formEncType" type="string" default=""/>
<cfparam name="ATTRIBUTES.trackOut" type="string" default="tr"/> <cfparam name="ATTRIBUTES.trackOut" type="string" default="tr"/>
<cfparam name="ATTRIBUTES.defaultBackUrl" default="#ATTRIBUTES.entity#_ls.cfm"/>
<cfparam name="ATTRIBUTES.thisUrl" default=""/> <cfparam name="ATTRIBUTES.thisUrl" default=""/>
<!--- заново конструируем Url текущей страницы, без трека --->
<cfif len(ATTRIBUTES.thisUrl) EQ 0><!--- наугад используем типовое соглашение---> <cfif len(ATTRIBUTES.thisUrl) EQ 0><!--- наугад используем типовое соглашение--->
<cfparam name="#ATTRIBUTES.key#" default="-1"/> <cfparam name="#ATTRIBUTES.key#" default="-1"/>
<cfset id=evaluate("#ATTRIBUTES.key#")/><!---*** неизящно, зато безопасно---><!--- *** как-то не слишком безопасно ---> <cfset id=evaluate("#ATTRIBUTES.key#")/><!---*** неизящно, зато безопасно---><!--- *** как-то не слишком безопасно --->
@ -18,7 +23,7 @@
<m:ac obj="#ATTRIBUTES.accessObject#" permissionOut="permission"/> <m:ac obj="#ATTRIBUTES.accessObject#" permissionOut="permission"/>
<cfset permission=2/><!--- *** ---> <cfset permission=2/><!--- *** --->
<m:track thisUrl="#ATTRIBUTES.thisUrl#" defaultBackUrl="#ATTRIBUTES.entity#_ls.cfm" output="track"/> <m:track thisUrl="#ATTRIBUTES.thisUrl#" defaultBackUrl="#ATTRIBUTES.defaultBackUrl#" output="track"/>
<cfset pageInfo=CreateObject("component","detail_page_info").init("#ATTRIBUTES.entity#","#ATTRIBUTES.key#",#track#,"#permission#","frm",#request.thisPage#,"POST","#ATTRIBUTES.formEncType#")/> <cfset pageInfo=CreateObject("component","detail_page_info").init("#ATTRIBUTES.entity#","#ATTRIBUTES.key#",#track#,"#permission#","frm",#request.thisPage#,"POST","#ATTRIBUTES.formEncType#")/>

View File

@ -179,7 +179,7 @@
<th>Ключ строки</th> <th>Ключ строки</th>
<th>Услуга</th> <th>Услуга</th>
<th>Код услуги</th> <th>Код услуги</th>
<!--- <th>Стоимость</th> ---> <th>Версий</th>
<!--- <th>Компонентов</th> ---> <!--- <th>Компонентов</th> --->
<th></th> <th></th>
</tr> </tr>
@ -187,13 +187,12 @@
<cfoutput query="qItem"> <cfoutput query="qItem">
<tr> <tr>
<td> <td>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="specification_item" id=#specification_item_uid# fwx=#tr.fwx#/> <c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="specification_item" key="specification_item_uid" id=#specification_item_uid# fwx=#tr.fwx#/>
</td> </td>
<td>#specification_item_uid#</td> <td>#specification_item_uid#</td>
<td>#svc#</td> <td>#svc#</td>
<td class="r">#quantity#</td> <td>#code#</td>
<td class="r">#price#</td> <td>#item_version_count#</td>
<td class="c">#item_version_count#</td>
<td class="c"> <td class="c">
<c:link_del canWrite=#pageInfo.writePermitted()# entity="specification_item" id=#specification_item_uid# fwx=#tr.fwx#/> <c:link_del canWrite=#pageInfo.writePermitted()# entity="specification_item" id=#specification_item_uid# fwx=#tr.fwx#/>
</td> </td>

View File

@ -50,7 +50,6 @@
where s.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.svc_id#" null=#!isNumeric(d.svc_id)#/> where s.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.svc_id#" null=#!isNumeric(d.svc_id)#/>
</cfquery> </cfquery>
<!--- decoration ---> <!--- decoration --->
<cfquery name="qDecoration" datasource="#request.DS#"> <cfquery name="qDecoration" datasource="#request.DS#">
select select
@ -90,7 +89,6 @@
<div class="detail"> <div class="detail">
<div class="tr"> <div class="tr">
<div class="th">Спецификация (номер)</div> <div class="th">Спецификация (номер)</div>
<div class="td"> <div class="td">
@ -98,6 +96,13 @@
</div> </div>
</div> </div>
<div class="tr">
<div class="th">Ключ строки</div>
<div class="td">
#d.specification_item_uid# <i>стабильный идентификатор строки</i>
</div>
</div>
<div class="tr"> <div class="tr">
<div class="th">Услуга</div> <div class="th">Услуга</div>
<div class="td"> <div class="td">
@ -117,16 +122,14 @@
class="" class=""
onchange="submit();" onchange="submit();"
/> />
<cfif d.svc_id GT 0> <!--- <cfif d.svc_id GT 0>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="svc" id=#d.svc_id# fwx=#tr.fwx#/> <c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="svc" id=#d.svc_id# fwx=#tr.fwx#/>
</cfif> </cfif> --->
при наличии версий предлагается исключить изменение
</div> </div>
</div> </div>
<!--- <div class="tr">
<div class="tr">
<div class="th">Создано</div> <div class="th">Создано</div>
<div class="td"> <div class="td">
#dateFormat(d.dt_created,'DD.MM.YYYY')# #timeFormat(d.dt_created,'HH:MM')# #dateFormat(d.dt_created,'DD.MM.YYYY')# #timeFormat(d.dt_created,'HH:MM')#
@ -136,8 +139,9 @@
#dateFormat(d.dt_updated,'DD.MM.YYYY')# #timeFormat(d.dt_updated,'HH:MM')# #dateFormat(d.dt_updated,'DD.MM.YYYY')# #timeFormat(d.dt_updated,'HH:MM')#
#qDecoration.updater# <cfif len(qDecoration.updater_shortname)>(#qDecoration.updater_shortname#)</cfif> #qDecoration.updater# <cfif len(qDecoration.updater_shortname)>(#qDecoration.updater_shortname#)</cfif>
</div> </div>
</div> </div> --->
</div> </div>
тут можно было бы отобразить начало и конец истории строки/инстанса
</cfoutput> </cfoutput>
@ -167,15 +171,15 @@
<cfoutput> <cfoutput>
<p> <p>
Версии (#qSpecificationItemVersion.recordCount#) Версии (#qSpecificationItemVersion.recordCount#) (история инстанса)
<!---<cfif pageInfo.writePermitted()> <cfif pageInfo.writePermitted()>
<cfoutput> <cfoutput>
<cfset addUrl="specification_item_param.cfm?specification_item_param=-1&specification_item_id=#d.specification_item_id#&#tr.fwx#"/> <cfset addUrl="specification_item_version.cfm?agreement_version=-1&specification_item_uid=#d.specification_item_uid#&#tr.fwx#"/>
<button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'"> <button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'">
<a href="#addUrl#">Создать</a> <a href="#addUrl#">Создать</a>
</button> </button> вопрос, где мы возьмем agreement_version? Или соглашение создавать автоматически?
</cfoutput> </cfoutput>
</cfif>---> </cfif>
</p> </p>
</cfoutput> </cfoutput>
<table class="worktable"> <table class="worktable">

View File

@ -15,13 +15,18 @@
<cfreturn htmlEditFormat(s)/> <cfreturn htmlEditFormat(s)/>
</cffunction> </cffunction>
<m:prepare_detail entity="specification_item" key="specification_item_uid" pageInfoOut="pageInfo"/> <m:prepare_detail entity="specification_item_version" key="specification_item_uid" pageInfoOut="pageInfo"/>
<!--- так, а у нас ключ составной --->
<d:bean readonly=#!pageInfo.writePermitted()# table="#pageInfo.entity#" datasource="#request.DS#" output="d" status="status"> <d:bean readonly=#!pageInfo.writePermitted()# table="#pageInfo.entity#" datasource="#request.DS#" output="d" status="status">
<d:param field="specification_item_uid" type="guid" key autoincrement/> <d:param field="specification_item_uid" type="guid" key/>
<d:param field="specification_id" type="integer" required/> <d:param field="agreement_version" type="integer" key/>
<d:param field="svc_id" type="integer" required/>
<!--- <d:param field="specification_item" type="varchar" size="1023" preprocessor=#cleanInput#/> можно было оставить здесь ---> <d:param field="specification_item_version" type="varchar" size="1023" preprocessor=#cleanInput#/>
<d:param field="quantity" type="numeric"/>
<d:param field="price" type="numeric"/>
<d:param field="dt_from" type="timestamp" format="yyyy-MM-dd" forNull="" init="#Now()#"/> <!--- !!! Important yyyy-MM-dd NOT YYYY-MM-DD --->
<d:param field="dt_to" type="timestamp" format="yyyy-MM-dd" forNull="" init="#Now()#"/> <!--- !!! Important yyyy-MM-dd NOT YYYY-MM-DD --->
<d:param field="creator_id" type="integer" value="#request.usr_id#" skipUpdate/> <d:param field="creator_id" type="integer" value="#request.usr_id#" skipUpdate/>
<d:param field="updater_id" type="integer" value="#request.usr_id#" /> <d:param field="updater_id" type="integer" value="#request.usr_id#" />
@ -32,34 +37,38 @@
<m:dispatch_detail <m:dispatch_detail
usePRG="No"<!---*** ---> usePRG="No"<!---*** --->
pageInfo=#pageInfo# pageInfo=#pageInfo#
id="#d.specification_item_uid#" id=""
queryString="#request.thisPage#?specification_item_uid=#d.specification_item_uid#&agreement_version=#d.agreement_version#"
defaultBackUrl="specification_item.cfm?specification_item_uid=#d.specification_item_uid#"
status=#pageInfo.status# status=#pageInfo.status#
trackOut="tr" trackOut="tr"
idAttributesOut="id" idAttributesOut="id"
/> />
<cfquery name="qSpecification" datasource="#request.DS#"> <!--- контекст строки всегда известен при создании версии, полный ключ не нужен для него - соответственно, джойн с основной таблицей. При этом мы собираем неверсионную часть данных, а версионная образует параллельную ветку --->
select s.specification_id, s.specification <!--- можно обратить внимание на то, что это один джойн, который растет сверху вниз (возможно, ветвится), добавляются таблицы и поля. На самом деле джойны внешние только для удобства отладки - так ошибки виднее --->
from specification s <cfquery name="qSpecificationItem" datasource="#request.DS#">
where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.specification_id#" null=#!isNumeric(d.specification_id)#/> select s.specification_id, s.specification, i.svc_id, d.contract, d.dt_contract, k.contragent, v.svc
from specification_item i
left join specification s on (i.specification_id=s.specification_id)
left join contract d on (s.contract_id=d.contract_id)
left join contragent k on (d.contragent_id=k.contragent_id)
left join svc v on (i.svc_id=v.svc_id)
where i.specification_item_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#d.specification_item_uid#" null=#!IsValid('guid',d.specification_item_uid)#/>
</cfquery> </cfquery>
<cfquery name="qSvc" datasource="#request.DS#">
select s.svc, s.code, s.measure_id
from svc s
where s.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.svc_id#" null=#!isNumeric(d.svc_id)#/>
</cfquery>
<!--- <cfquery name="qCost" datasource="#request.DS#"> <!--- <cfquery name="qCost" datasource="#request.DS#">
select sum(sip.price*sip.quantity) as cost select sum(sip.price*sip.quantity) as cost
from specification_item_param sip from specification_item_version_param sip
where sip.specification_item_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.specification_item_id#" null=#!isNumeric(d.specification_item_id)#/> where sip.specification_item_version_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.specification_item_version_id#" null=#!isNumeric(d.specification_item_version_id)#/>
</cfquery> ---> </cfquery> --->
<!--- <cfquery name="qSpecificationItemParam" datasource="#request.DS#"> <!--- <cfquery name="qSpecificationItemParam" datasource="#request.DS#">
select select
sip.specification_item_param_id sip.specification_item_version_param_id
,sp.service_param_id ,sp.service_param_id
,sp.param_id ,sp.param_id
,sip.price ,sip.price
@ -73,8 +82,8 @@
,m.measure_short ,m.measure_short
,spp.min_price ,spp.min_price
from service_param sp from service_param sp
left outer join specification_item_param sip left outer join specification_item_version_param sip
on (sp.service_param_id=sip.service_param_id AND sip.specification_item_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.specification_item_id#"/>) on (sp.service_param_id=sip.service_param_id AND sip.specification_item_version_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.specification_item_version_id#"/>)
left outer join param p on (sp.param_id=p.param_id) left outer join param p on (sp.param_id=p.param_id)
left outer join abstract_service_param_class ac on (sp.abstract_service_param_class_id=ac.abstract_service_param_class_id) left outer join abstract_service_param_class ac on (sp.abstract_service_param_class_id=ac.abstract_service_param_class_id)
left outer join param_class c on (ac.param_class_id=c.param_class_id) left outer join param_class c on (ac.param_class_id=c.param_class_id)
@ -90,10 +99,11 @@
<cfquery name="qDecoration" datasource="#request.DS#"> <cfquery name="qDecoration" datasource="#request.DS#">
select select
a.login as creator, a.shortname as creator_shortname, m.login as updater, m.shortname as updater_shortname a.login as creator, a.shortname as creator_shortname, m.login as updater, m.shortname as updater_shortname
from specification_item e from specification_item_version e
left outer join usr a on (e.creator_id=a.usr_id) left outer join usr a on (e.creator_id=a.usr_id)
left outer join usr m on (e.updater_id=m.usr_id) left outer join usr m on (e.updater_id=m.usr_id)
where e.specification_item_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#d.specification_item_uid# null=#!isValid('guid',d.specification_item_uid)#/> where e.specification_item_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#d.specification_item_uid# null=#!isValid('guid',d.specification_item_uid)#/>
AND e.agreement_version=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.agreement_version#" null=#!isValid('integer',d.agreement_version)#/>
</cfquery> </cfquery>
</m:silent><!--- </m:silent><!---
@ -105,10 +115,8 @@
---><layout:page section="header" pageInfo=#pageInfo#> ---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title"> <layout:attribute name="title">
<cfoutput> <cfoutput>
Строка спецификации (экземпляр услуги) Версия строки спецификации
<cfif len(d.specification_item_uid)> [#d.specification_item_uid#]:[#d.agreement_version#]
[#d.specification_item_uid#]
</cfif>
</cfoutput> </cfoutput>
</layout:attribute> </layout:attribute>
</layout:page> </layout:page>
@ -119,7 +127,7 @@
<cfoutput> <cfoutput>
<input type="hidden" name="specification_item_uid" value="#d.specification_item_uid#"/> <input type="hidden" name="specification_item_uid" value="#d.specification_item_uid#"/>
<input type="hidden" name="specification_id" value="#d.specification_id#"/> <input type="hidden" name="agreement_version" value="#d.agreement_version#"/>
<input type="hidden" name="track" value="#tr.self#"/> <input type="hidden" name="track" value="#tr.self#"/>
<input type="hidden" name="pass" value=""/><!--- pass marker to prevent save on submit ---> <input type="hidden" name="pass" value=""/><!--- pass marker to prevent save on submit --->
@ -129,79 +137,61 @@
<div class="tr"> <div class="tr">
<div class="th">Спецификация (номер)</div> <div class="th">Спецификация (номер)</div>
<div class="td"> <div class="td">
<a href="specification.cfm?specification_id=#d.specification_id#&#tr.fwx#">#qSpecification.specification#</a> <a href="specification.cfm?specification_id=#qSpecificationItem.specification_id#&#tr.fwx#">#qSpecificationItem.specification#</a>
</div> </div>
</div> </div>
<div class="tr"> <div class="tr">
<div class="th">Услуга</div> <div class="th">Услуга</div>
<div class="td"> <div class="td">
<cfquery name="qList" datasource="#request.DS#"> <a href="svc.cfm?svc_id=#qSpecificationItem.svc_id#&#tr.fwx#">[#d.specification_item_uid#] #qSpecificationItem.svc#</a>
select s.svc_id, s.code
from svc s
order by 2
</cfquery>
<c:combo
query=#qList#
combo="svc_id"
id="svc_id"
key="svc_id"
selected="#d.svc_id#"
displayf="##code## ##svc##
empty=""
class=""
onchange="submit();"
/>
<cfif d.service_id GT 0>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="svc" id=#d.svc_id# fwx=#tr.fwx#/>
</cfif>
</div> </div>
</div> </div>
<!--- <div class="tr"> <div class="tr">
<div class="th">Версия</div>
<div class="td">
<!--- <a href="svc.cfm?svc_id=#qSpecificationItem.svc_id#&#tr.fwx#">[#d.specification_item_uid#] #qSpecificationItem.svc#</a> --->
#d.agreement_version#
</div>
</div>
<div class="tr">
<div class="th">Имя для печати</div> <div class="th">Имя для печати</div>
<div class="td"> <div class="td">
<cfset m_specification_item=#d.specification_item#/> <!--- <cfset m_specification_item_version=#d.specification_item_version#/>
<cfif len(m_specification_item) EQ 0 AND d.service_id GT 0> <cfif len(m_specification_item_version) EQ 0 AND d.service_id GT 0>
<cfif len(qService.modifier)> <cfif len(qService.modifier)>
<cfset m_specification_item="#qService.abstract_service# - #qService.modifier#."/> <cfset m_specification_item_version="#qService.abstract_service# - #qService.modifier#."/>
<cfelse> <cfelse>
<cfset m_specification_item="#qService.abstract_service#."/> <cfset m_specification_item_version="#qService.abstract_service#."/>
</cfif> </cfif>
<cfloop query="qSpecificationItemParam"> <cfloop query="qSpecificationItemParam">
<cfif qSpecificationItemParam.quantity GT 0> <cfif qSpecificationItemParam.quantity GT 0>
<!--- <cfif len(qSpecificationItemParam.param_class)>
<cfset m_param_name="#qSpecificationItemParam.param_class#/#qSpecificationItemParam.param#"/>
<cfelse>
<cfset m_param_name="#qSpecificationItemParam.param#"/>
</cfif> --->
<cfset m_param_name="#qSpecificationItemParam.param_short#"/> <cfset m_param_name="#qSpecificationItemParam.param_short#"/>
<cfset m_specification_item="#m_specification_item# #m_param_name# #qSpecificationItemParam.quantity# #qSpecificationItemParam.measure_short#;"/> <cfset m_specification_item_version="#m_specification_item_version# #m_param_name# #qSpecificationItemParam.quantity# #qSpecificationItemParam.measure_short#;"/>
</cfif> </cfif>
</cfloop> </cfloop>
</cfif> --->
</cfif> <textarea name="specification_item_version" id="specification_item_version" rows="2" cols="90" style="width:99%;"/><cfif len(d.specification_item_version)>#d.specification_item_version#<cfelse>#qSpecificationItem.svc#</cfif></textarea>
<button type="button" onclick="document.getElementById('specification_item_version').value='';submit();">Сформировать</button>
<textarea name="specification_item" id="specification_item" rows="3" cols="90" style="width:99%;"/>#m_specification_item#</textarea> </div>
<button type="button" onclick="document.getElementById('specification_item').value='';submit();">Сформировать</button>
</div> </div>
</div> --->
<div class="tr"> <div class="tr">
<div class="th">Количество</div> <div class="th">Количество</div>
<div class="td"> <div class="td">
<input type="text" name="quantity" value="#request.roundSafe(d.quantity,qService.precision)#" size="5" class="r"/><!---*** Халява с точностью ---><!--- <cftry>#round(d.quantity,qService.precision)#<cfcatch type="ANY"></cfcatch></cftry> ---> <input type="text" name="quantity" value="#d.quantity#" size="5" class="r"/><!---*** Халява с точностью ---><!--- <cftry>#round(d.quantity,qService.precision)#<cfcatch type="ANY"></cfcatch></cftry> --->
</div> </div>
</div> </div>
<div class="tr"> <div class="tr">
<div class="th">Стоимость</div> <div class="th">Цена</div>
<div class="td"> <div class="td">
<input type="text" name="price" id="price" value="#d.price#" size="15" class="r"/> <input type="text" name="price" id="price" value="#d.price#" size="10" class="r"/>
<i>подставить сумму по позициям: </i> <!--- <i>подставить сумму по позициям: </i>
<b><a onclick="document.getElementById('price').value='#qCost.cost#';return false;" style="cursor:pointer;">#qCost.cost#</a></b> <b><a onclick="document.getElementById('price').value='#qCost.cost#';return false;" style="cursor:pointer;">#qCost.cost#</a></b> --->
</div> </div>
</div> </div>
@ -222,13 +212,13 @@
<layout:page section="extension" closeForm="Yes"/> <layout:page section="extension" closeForm="Yes"/>
<cfif d.specification_item_id GT 0> <cfif len(d.specification_item_uid) AND d.agreement_version GT 0>
<cfoutput> <cfoutput>
<p> <p>
Компоненты (#qSpecificationItemParam.recordCount#) Компоненты (#qSpecificationItemParam.recordCount#)
<!---<cfif pageInfo.writePermitted()> <!---<cfif pageInfo.writePermitted()>
<cfoutput> <cfoutput>
<cfset addUrl="specification_item_param.cfm?specification_item_param=-1&specification_item_id=#d.specification_item_id#&#tr.fwx#"/> <cfset addUrl="specification_item_version_param.cfm?specification_item_version_param=-1&specification_item_version_id=#d.specification_item_version_id#&#tr.fwx#"/>
<button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'"> <button type="button" class="maincontrol" onclick="document.location.href='#addUrl#'">
<a href="#addUrl#">Создать</a> <a href="#addUrl#">Создать</a>
</button> </button>
@ -252,13 +242,13 @@
<cfoutput query="qSpecificationItemParam"> <cfoutput query="qSpecificationItemParam">
<tr> <tr>
<td> <td>
<cfif specification_item_param_id GT 0> <cfif specification_item_version_param_id GT 0>
<a href="specification_item_param.cfm?specification_item_param_id=#specification_item_param_id#&#tr.fwx#"> <a href="specification_item_version_param.cfm?specification_item_version_param_id=#specification_item_version_param_id#&#tr.fwx#">
<img src="img/edit.gif"/> <img src="img/edit.gif"/>
</a> </a>
</cfif> </cfif>
<!--- <cfif NOT (specification_item_param_id GT 0)> ---> <!--- <cfif NOT (specification_item_version_param_id GT 0)> --->
<a href="specification_item_param.cfm?service_param_id=#service_param_id#&specification_item_id=#d.specification_item_id#&#tr.fwx#"> <a href="specification_item_version_param.cfm?service_param_id=#service_param_id#&specification_item_version_id=#d.specification_item_version_id#&#tr.fwx#">
<img src="img/add.gif"/> <img src="img/add.gif"/>
</a> </a>
</td> </td>
@ -275,8 +265,8 @@
<td class="r">#min_price#</td> <td class="r">#min_price#</td>
<td class="r">#price#</td> <td class="r">#price#</td>
<td class="c"> <td class="c">
<cfif specification_item_param_id GT 0> <cfif specification_item_version_param_id GT 0>
<c:link_del canWrite=#pageInfo.writePermitted()# entity="specification_item_param" id=#specification_item_param_id# fwx=#tr.fwx#/> <c:link_del canWrite=#pageInfo.writePermitted()# entity="specification_item_version_param" id=#specification_item_version_param_id# fwx=#tr.fwx#/>
</cfif> </cfif>
</td> </td>
</tr> </tr>