Files
contractor/apply_events.cfm
T

189 lines
11 KiB
Plaintext

<cfsetting showdebugoutput="no" enablecfoutputonly="true">
<cfheader name="Content-Type" value="application/json; charset=utf-8">
<cfparam name="url.contract_id" default="">
<cfparam name="url.mode" default="partial">
<cfset body = toString(getHttpRequestData().content)>
<cfset data = deserializeJSON(body)>
<cfset ops = structKeyExists(data, "ops") ? data.ops : []>
<cfset supplementId = structKeyExists(data, "supplement_id") ? data.supplement_id : "">
<cfset result = {ok: false, error: ""}>
<cftry>
<cfif NOT len(url.contract_id)>
<cfset result.error = "contract_id required">
<cfelseif NOT len(supplementId)>
<cfset result.error = "supplement_id required (JSON body)">
<cfelse>
<cftransaction>
<cfset seq = 0>
<cfquery name="sq" datasource="baza">
SELECT COALESCE(MAX(seq), 0) as m FROM spec_events
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfset seq = sq.m>
<!--- full_replace: явные DELETE для аудита --->
<cfif url.mode EQ "full_replace">
<cfquery name="curRows" datasource="baza">
SELECT name_hash, name, price, qty, sum, date_start
FROM spec_current
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfloop query="curRows">
<cfset seq++>
<cfquery datasource="baza">
INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#supplementId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#seq#" cfsqltype="cf_sql_integer">,
'DELETE',
<cfqueryparam value="#curRows.name_hash#" cfsqltype="cf_sql_varchar">,
'full_replace',
'applied'
)
</cfquery>
</cfloop>
<cfquery datasource="baza">
DELETE FROM spec_current WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
</cfquery>
</cfif>
<!--- Применить операции --->
<cfset summary = {added: 0, updated: 0, deleted: 0, unresolved: 0}>
<cfloop array="#ops#" index="op">
<cfset seq++>
<cfset action = op.action>
<cfif action EQ "ADD">
<cfset nr = op.new_row>
<cfset nm = structKeyExists(nr, 'name') ? nr.name : ''>
<cfset pr = (structKeyExists(nr, 'price') AND len(nr.price)) ? nr.price : ''>
<cfset qt = (structKeyExists(nr, 'qty') AND len(nr.qty)) ? nr.qty : ''>
<cfset sm = (structKeyExists(nr, 'sum') AND len(nr.sum)) ? nr.sum : ''>
<cfset ds = (structKeyExists(nr, 'date_start') AND len(nr.date_start)) ? nr.date_start : ''>
<cfquery name="evt" datasource="baza">
INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#supplementId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#seq#" cfsqltype="cf_sql_integer">,
'ADD',
<cfqueryparam value="#serializeJSON(nr)#" cfsqltype="cf_sql_varchar">::jsonb,
<cfqueryparam value="#structKeyExists(op,'comment') ? op.comment : ''#" cfsqltype="cf_sql_varchar">,
'applied'
)
RETURNING id
</cfquery>
<cfquery datasource="baza">
INSERT INTO spec_current (contract_id, name_hash, name, price, qty, sum, date_start, last_event_id)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
md5(lower(trim(<cfqueryparam value="#nm#" cfsqltype="cf_sql_varchar">)) || coalesce(<cfqueryparam value="#ds#" cfsqltype="cf_sql_varchar">, '')),
<cfqueryparam value="#nm#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#pr#" cfsqltype="cf_sql_float" null="#len(pr) EQ 0#">,
<cfqueryparam value="#qt#" cfsqltype="cf_sql_float" null="#len(qt) EQ 0#">,
<cfqueryparam value="#sm#" cfsqltype="cf_sql_float" null="#len(sm) EQ 0#">,
<cfqueryparam value="#ds#" cfsqltype="cf_sql_varchar" null="#len(ds) EQ 0#">,
<cfqueryparam value="#evt.id#" cfsqltype="cf_sql_varchar">
)
</cfquery>
<cfset summary.added++>
<cfelseif action EQ "UPDATE">
<cfset th = op.target_hash>
<cfquery name="old" datasource="baza">
SELECT price, qty, sum, date_start FROM spec_current
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
AND name_hash = <cfqueryparam value="#th#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfif old.recordCount EQ 0>
<cfthrow message="UPDATE target not found: #th#">
</cfif>
<cfset nv = structKeyExists(op, 'new_values') ? op.new_values : {}>
<cfset newPrice = structKeyExists(nv, 'price') AND len(nv.price) ? nv.price : old.price>
<cfset newQty = structKeyExists(nv, 'qty') AND len(nv.qty) ? nv.qty : old.qty>
<cfset newSum = structKeyExists(nv, 'sum') AND len(nv.sum) ? nv.sum : old.sum>
<cfset newDate = structKeyExists(nv, 'date_start') AND len(nv.date_start) ? nv.date_start : old.date_start>
<cfquery name="evt" datasource="baza">
INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, new_values, comment, status)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#supplementId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#seq#" cfsqltype="cf_sql_integer">,
'UPDATE',
<cfqueryparam value="#th#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#serializeJSON(nv)#" cfsqltype="cf_sql_varchar">::jsonb,
<cfqueryparam value="#structKeyExists(op,'comment') ? op.comment : ''#" cfsqltype="cf_sql_varchar">,
'applied'
)
RETURNING id
</cfquery>
<cfquery datasource="baza">
UPDATE spec_current SET
price = <cfqueryparam value="#newPrice#" cfsqltype="cf_sql_float" null="#NOT len(newPrice)#">,
qty = <cfqueryparam value="#newQty#" cfsqltype="cf_sql_float" null="#NOT len(newQty)#">,
sum = <cfqueryparam value="#newSum#" cfsqltype="cf_sql_float" null="#NOT len(newSum)#">,
date_start = <cfqueryparam value="#newDate#" cfsqltype="cf_sql_varchar" null="#NOT len(newDate)#">,
last_event_id = <cfqueryparam value="#evt.id#" cfsqltype="cf_sql_varchar">,
updated_at = now()
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
AND name_hash = <cfqueryparam value="#th#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfset summary.updated++>
<cfelseif action EQ "DELETE">
<cfset th = op.target_hash>
<cfquery datasource="baza">
INSERT INTO spec_events (contract_id, supplement_id, seq, action, target_hash, comment, status)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#supplementId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#seq#" cfsqltype="cf_sql_integer">,
'DELETE',
<cfqueryparam value="#th#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#structKeyExists(op,'comment') ? op.comment : ''#" cfsqltype="cf_sql_varchar">,
'applied'
)
</cfquery>
<cfquery datasource="baza">
DELETE FROM spec_current
WHERE contract_id = <cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">
AND name_hash = <cfqueryparam value="#th#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfset summary.deleted++>
<cfelseif action EQ "UNRESOLVED">
<cfquery datasource="baza">
INSERT INTO spec_events (contract_id, supplement_id, seq, action, new_values, comment, status)
VALUES (
<cfqueryparam value="#url.contract_id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#supplementId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#seq#" cfsqltype="cf_sql_integer">,
'UNRESOLVED',
<cfqueryparam value="#serializeJSON(structKeyExists(op,'new_values') ? op.new_values : {})#" cfsqltype="cf_sql_varchar">::jsonb,
<cfqueryparam value="#structKeyExists(op,'reason') ? op.reason : ''#" cfsqltype="cf_sql_varchar">,
'pending'
)
</cfquery>
<cfset summary.unresolved++>
</cfif>
</cfloop>
<cfset result = {ok: true, contract_id: url.contract_id, supplement_id: supplementId, summary: summary}>
</cftransaction>
</cfif>
<cfcatch>
<cfset result = {ok: false, error: cfcatch.message, detail: cfcatch.detail}>
</cfcatch>
</cftry>
<cfoutput>#serializeJSON(result)#</cfoutput>