diff --git a/onprc_billing/resources/queries/onprc_billing/gdj_NewLeaseFeeCTE_original.sql b/onprc_billing/resources/queries/onprc_billing/gdj_NewLeaseFeeCTE_original.sql new file mode 100644 index 000000000..0f8e639ce --- /dev/null +++ b/onprc_billing/resources/queries/onprc_billing/gdj_NewLeaseFeeCTE_original.sql @@ -0,0 +1,364 @@ +PARAMETERS (StartDate TIMESTAMP, EndDate TIMESTAMP) +-- ======================================================== +-- This is the QUery using CTES that was AI Generated for revised lease fees +-- Date: 2025-11-22 +-- Step 1 Assignments has bene modified to use LabkeySQL structure. +-- THis was moved to the onprc_billing query section +-- Working thru each CTE for code updates - Works as Designed in Dev +-- ========================================================= +WITH +-- ========================================================= +-- 1) Base assignments in date range +--This was modified to use LabkeySQL structure. +-- 2025-11-24 Validation of this CTE +-- ========================================================= +assignments AS ( + SELECT + a.Id, + -- create an identifer as assignment ID + a.lsid as assignmentId, + a.date AS assignmentDate, + a.enddate AS assignmentEndDate, + a.project, + --Create a sub query for resource ID + (Select r.project.displayName from study.resourceAssigned r where r.id = a.id) as resourceCode, + a.assignCondition, + a.releaseCondition, + a.projectedRelease, + --Create a looklup for is a research project + Case when a.id in (Select ra.id from study.researchAssigned ra where ra.id = a.id) then 1 + Else 0 + End as isResearchAssignment, + -- a.isResearchAssignment, -- 1 = research, 0 = resource (or derive later) + (Select b.dam from study.birth b where b.id = a.id) as damId, -- dam of infant, if applicable + a.id.dataset.Demographics.gender as sex, + -- Using the release code assign a value for is terminal + Case when a.projectedReleaseCondition in (206,207) then 1 + Else 0 + End as isTerminalAssignment, -- 1 = terminal, 0 = non-terminal + a.container + FROM study.assignment a + WHERE a.date >= StartDate + AND a.date < EndDate +), +--Select * from assignment, + +-- ========================================================= +-- 2) Animal age / infant vs adult +-- (You may already have an ageAtTime dataset; this is illustrative) +-- change this to age in years +-- 2025-11-24 Starting Validation Review +-- ========================================================= +age_at_assignment AS ( + SELECT + aa.Id, + aa.assignmentId, + aa.assignmentDate, + aa.assignmentEndDate, + aa.project, + aa.resourceCode, + aa.assignCondition, + aa.releaseCondition, + aa.projectedRelease, + aa.damId, + aa.sex, + aa.isTerminalAssignment, + aa.isResearchAssignment, + aa.container, + d.birth, + -- change this to accepted Labkey Code + TIMESTAMPDIFF('SQL_TSI_day', d.birth, aa.assignmentDate) AS ageDays, + CASE + WHEN TIMESTAMPDIFF('SQL_TSI_YEAR', d.birth, aa.assignmentDate) <= 1 THEN 1 -- infant threshold example + ELSE 0 + END AS isInfant + FROM assignments aa + LEFT JOIN study.demographics d + ON d.Id = aa.Id +) +--Select * from age_at_assignment + +, + +-- ========================================================= +-- 3) PI purchase flag (for research assignments) +-- ========================================================= +pi_purchase AS ( + SELECT DISTINCT + f.Id, + f.value, + 1 AS hasPIPurchase + FROM study.flags f + WHERE f.flag.value = 'PI Purchased NHP' + --AND f.isActive = true +), + +assign_with_pi AS ( + SELECT + a.*, + p.value, + COALESCE(p.hasPIPurchase, 0) AS hasPIPurchase + FROM age_at_assignment a + LEFT JOIN pi_purchase p + ON a.Id = p.Id +) +--select * from pi_purchase + , + +-- ========================================================= +-- 4) Assignment length & condition change + --This is returening total days assigned to the project +-- ========================================================= +assignment_length AS ( + SELECT + a.*, + TIMESTAMPDIFF('SQL_TSI_day', a.assignmentDate, COALESCE(a.projectedRelease, a.assignmentenddate)) AS assignmentDays, + --DATEDIFF('day', a.assignmentDate, COALESCE(a.proposedReleaseDate, a.assignmentEndDate)) AS assignmentDays, + CASE + WHEN a.assignCondition = a.releaseCondition + OR a.releaseCondition IS NULL + THEN 0 + ELSE 1 + END AS hasConditionChange + FROM assign_with_pi a +) +-- select * from assignment_length + + , + +-- ========================================================= +-- 5) Resource type classification +-- ========================================================= +resource_type AS ( + SELECT + a.*, + CASE + WHEN a.resourceCode = '0300' THEN 'TMB' + WHEN a.resourceCode = '0456' THEN 'AGING' + WHEN a.resourceCode = '0833' THEN 'OBESE' + WHEN a.resourceCode = '0492-03' THEN 'SPF9' + WHEN a.resourceCode = '1092-50' THEN 'AMR' + WHEN a.resourceCode = '0492' THEN 'COLONY' + WHEN a.resourceCode = '0492-02' THEN 'U42' + WHEN a.resourceCode = '0492-45' THEN 'JMR' + ELSE 'OTHER' + END AS resourceGroup + FROM assignment_length a +) + -- select * from resource_type + + , + +-- ========================================================= +-- 6) Dam/resource match (for infant/resource rules) +-- You may need a proper housing/resource history join here. +-- ========================================================= +dam_resource AS ( + SELECT + r.Id, + r.assignmentId, + r.resourceCode AS damResourceCode + FROM resource_type r + WHERE r.damId IS NOT NULL + -- join to housing/resource assignments if needed +), + +with_dam_match AS ( + SELECT + a.*, + CASE + WHEN a.isInfant = 1 + AND dr.damResourceCode = a.resourceCode + THEN 1 + ELSE 0 + END AS infantSameDamResource + FROM resource_type a + LEFT JOIN dam_resource dr + ON dr.Id = a.damId + AND dr.assignmentId = a.assignmentId -- or appropriate key +) +-- Select * from with_dam_match + +, +-- ========================================================= +-- 7) Determine lease type (core rule engine) +-- ========================================================= +lease_type AS ( + SELECT + a.*, + + -- Main lease type decision + CASE + -- ------------------------------ + -- 1) Resource assignments + -- ------------------------------ + WHEN a.isResearchAssignment = 0 THEN + CASE + -- 1.1 Infant, dam in same resource → no lease + WHEN a.isInfant = 1 + AND a.infantSameDamResource = 1 + THEN 'NONE' + + -- 1.2 TMB (0300) + WHEN a.resourceGroup = 'TMB' THEN + CASE + -- TMB dam always charged a TMB lease + WHEN a.isInfant = 0 + AND a.sex = 'F' -- example for dam logic + THEN 'TMB_LEASE' + + -- infant from assigned TMB dam → no lease + WHEN a.isInfant = 1 + AND a.infantSameDamResource = 1 + THEN 'NONE' + + -- infant from unassigned TMB dam → P51 lease, credit TMB + WHEN a.isInfant = 1 + THEN 'P51_FULL' + + -- male assigned from TMB resource → P51 rate + WHEN a.sex = 'M' + THEN 'P51_FULL' + + -- day lease to TMB + ELSE 'DAY_LEASE' + END + + -- 1.3 Aging (0456) → no lease for assignments + WHEN a.resourceGroup = 'AGING' THEN 'NONE' + + -- 1.4 OBESE (0833) + WHEN a.resourceGroup = 'OBESE' THEN + CASE + WHEN a.assignmentDays BETWEEN 1 AND 14 + AND a.hasConditionChange = 0 + THEN 'OBESE_DAY' -- ONR01 + WHEN a.isTerminalAssignment = 1 + THEN 'OBESE_ADULT_TERM' -- ONR45 + ELSE 'OBESE_ADULT' -- ONR25 + END + + -- 1.5 SPF9 (0492-03) + WHEN a.resourceGroup = 'SPF9' + THEN 'SPF9_EXPANDED' + + -- 1.6 AMR (1092-50) – no lease when assigned to AMR + WHEN a.resourceGroup = 'AMR' + THEN 'NONE' + + -- 1.7 Colony / U42 / JMR / Other resource → P51 rules + ELSE 'P51_FULL' + END + + -- ------------------------------ + -- 2) Research assignments + -- ------------------------------ + ELSE + CASE + -- 2.1 PI Purchased → no lease + WHEN a.hasPIPurchase = 1 + THEN 'NONE' + + -- 2.2 One day – 14 days + WHEN a.assignmentDays BETWEEN 1 AND 14 THEN + CASE + WHEN a.hasConditionChange = 0 + THEN 'DAY_LEASE' + ELSE 'FULL_LEASE' + END + + -- 2.3 > 14 days → full lease + WHEN a.assignmentDays > 14 + THEN 'FULL_LEASE' + + ELSE 'NONE' + END + END AS leaseType + FROM with_dam_match a +) + --select * from lease_type + , +-- ++++++++ 2025-11-24 All CTEs above return results as expected +-- ========================================================= +-- 8) Map leaseType to itemCodes & credit aliases +-- ========================================================= +lease_mapping AS ( + SELECT + l.*, + + -- Item code mapping (example codes – replace with real ones) + CASE l.leaseType + WHEN 'DAY_LEASE' THEN 'DAY01' -- generic day lease + WHEN 'FULL_LEASE' THEN 'FULL01' + WHEN 'P51_FULL' THEN 'P51' + WHEN 'OBESE_DAY' THEN 'ONR01' + WHEN 'OBESE_ADULT' THEN 'ONR25' + WHEN 'OBESE_ADULT_TERM' THEN 'ONR45' + WHEN 'SPF9_EXPANDED' THEN 'SPF9X' + WHEN 'TMB_LEASE' THEN 'TMB01' + ELSE NULL + END AS leaseItemCode, + + -- Credit resource mapping + CASE + WHEN l.leaseType = 'NONE' THEN NULL + + -- Aging never gets credit; credit colony + WHEN l.resourceGroup = 'AGING' THEN 'COLONY_ALIAS' + + -- Obese always credits Obese resource + WHEN l.resourceGroup = 'OBESE' THEN 'OBESE_ALIAS' + + -- SPF9 credits U42e funding + WHEN l.resourceGroup = 'SPF9' THEN 'U42E_ALIAS' + + -- TMB credits TMB resource + WHEN l.resourceGroup = 'TMB' THEN 'TMB_ALIAS' + + -- AMR → credit colony or original resource + WHEN l.resourceGroup = 'AMR' THEN 'COLONY_ALIAS' + + -- Colony/U42/JMR map to their own aliases + WHEN l.resourceGroup = 'COLONY' THEN 'COLONY_ALIAS' + WHEN l.resourceGroup = 'U42' THEN 'U42_ALIAS' + WHEN l.resourceGroup = 'JMR' THEN 'JMR_ALIAS' + + -- fallback: credit the originating resource + ELSE 'ORIGIN_RESOURCE_ALIAS' + END AS creditAlias + FROM lease_type l +) +--Select * from lease_mapping +, +-- ========================================================= +-- 9) Final output +-- ========================================================= +final AS ( + SELECT + f.Id, + f.assignmentId, + f.assignmentDate, + f.assignmentEndDate, + f.project, + f.resourceCode, + f.resourceGroup, + f.isResearchAssignment, + f.isInfant, + f.assignmentDays, + f.hasConditionChange, + f.hasPIPurchase, + f.isTerminalAssignment, + f.leaseType, + f.leaseItemCode, + f.creditAlias, + CASE + WHEN f.leaseType = 'NONE' + THEN 'No lease per business rules' + ELSE ('Lease generated per leaseType=' || f.leaseType) + END AS leaseNote + FROM lease_mapping f +) + +SELECT * +FROM final +ORDER BY assignmentDate, Id, assignmentId; diff --git a/onprc_billing/resources/queries/onprc_billing/leaseFeeRates.sql b/onprc_billing/resources/queries/onprc_billing/leaseFeeRates.sql deleted file mode 100644 index 9ae0ec136..000000000 --- a/onprc_billing/resources/queries/onprc_billing/leaseFeeRates.sql +++ /dev/null @@ -1,366 +0,0 @@ - -/* - * Copyright (c) 2013 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -SELECT - t.id, - t.date, - t.enddate, - t.project, - t.account, - t.projectedReleaseCondition, - t.releaseCondition, - t.assignCondition, - t.releaseType, - t.ageAtTime, - t.category, - t.chargeId, - t.serviceCenter, - t.item, - - t.leaseCharge1, - t.leaseCharge2, - t.sourceRecord, - t.chargeCategory, - - round(CAST(CASE - WHEN t.displayName = javaConstant('org.labkey.onprc_ehr.ONPRC_EHRManager.BASE_GRANT_PROJECT') THEN 0 - --handle adjustments and non-adjustments separately - WHEN (t.isAdjustment IS NULL) THEN t.unitCost1 - --note: we take the amount that should have been paid and subtract what was predicted to have been paid - ELSE (t.unitCost3 - t.unitCost2) - END AS DOUBLE), 2) as unitCost, - CAST(CASE - --handle adjustments and non-adjustments separately - WHEN (t.isAdjustment IS NULL) THEN t.nihRate1 - --note: we take the amount that should have been paid and subtract what was predicted to have been paid - ELSE (t.nihRate3 - t.nihRate2) - END AS DOUBLE) as nihRate, - - t.unitCost1, - t.nihRate1, - t.unitCost2, - t.nihRate2, - t.unitCost3, - t.nihRate3, - - t.quantity, - t.creditAccount, - t.creditAccountId, - t.comment, - t.investigatorId, - t.isExemption, - t.isNonStandardRate, - t.lacksRate, - t.rateId, - t.exemptionId, - t.isMiscCharge, - t.isAdjustment, - t.isMissingAccount, - t.isMissingFaid, - t.isAcceptingCharges, - t.isExpiredAccount, - t.isOldCharge, - t.currentActiveAlias, - t.datefinalized, - t.enddatefinalized - - -FROM ( -SELECT - p.id, - p.date, - p.enddate, - p.project, - alias.alias as account, - p.project.displayName as displayName, - p.projectedReleaseCondition, - p.releaseCondition, - p.assignCondition, - p.releaseType, - p.ageAtTime, - p.category, - p.chargeId, - p.chargeId.departmentCode as serviceCenter, - p.chargeId.name as item, - - p.leaseCharge1, - p.leaseCharge2, - p.sourceRecord, - p.chargeCategory, - - --this is the cost of the original lease, based on projected release type - CAST(CASE - --order of priority for unit cost: - --project-level exemption: pay this value - WHEN (e.unitCost IS NOT NULL) THEN e.unitCost - --project-level multiplier: multiply NIH rate by this value - WHEN (pm.multiplier IS NOT NULL AND cr.unitCost IS NOT NULL) THEN (cr.unitCost * pm.multiplier) - --if there is not a known rate, we dont know what do to - WHEN (cr.unitCost IS NULL) THEN null - --for non-OGA aliases, we always use the NIH rate - WHEN (alias.category IS NOT NULL AND alias.category != 'OGA') THEN cr.unitCost - --if we dont know the aliasType, we also dont know what do to - WHEN (alias.aliasType.aliasType IS NULL) THEN null - --remove both subsidy and raise F&A if needed - WHEN (alias.aliasType.removeSubsidy = true AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN ((cr.unitCost / (1 - COALESCE(cr.subsidy, 0))) * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.indirectRate AS DOUBLE)) THEN ((1 + (CAST(ir.IndirectRate AS DOUBLE) / (1 + alias.faRate)))) ELSE 1 END)) - --remove subsidy only - WHEN (alias.aliasType.removeSubsidy = true AND alias.aliasType.canRaiseFA = false) THEN (cr.unitCost / (1 - COALESCE(cr.subsidy, 0))) - --raise F&A on ly - WHEN (alias.aliasType.removeSubsidy = false AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN (cr.unitCost * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.indirectRate AS DOUBLE)) THEN ((1 + (CAST(ir.indirectRate AS DOUBLE)))/(1+ alias.faRate)) ELSE 1 END)) - --the NIH rate - ELSE cr.unitCost - END AS DOUBLE) as unitCost1, - cr.unitCost as nihRate1, - - --for adjustments, this is the first lease charge - CAST(CASE - --order of priority for unit cost: - --project-level exemption: pay this value - WHEN (e2.unitCost IS NOT NULL) THEN e2.unitCost - --project-level multiplier: multiply NIH rate by this value - WHEN (pm.multiplier IS NOT NULL AND cr2.unitCost IS NOT NULL) THEN (cr2.unitCost * pm.multiplier) - --if there is not a known rate, we dont know what do to - WHEN (cr2.unitCost IS NULL) THEN null - --for non-OGA aliases, we always use the NIH rate - WHEN (alias.category IS NOT NULL AND alias.category != 'OGA') THEN cr2.unitCost - --if we dont know the aliasType, we also dont know what do to - WHEN (alias.aliasType.aliasType IS NULL) THEN null - --remove both subsidy and raise F&A if needed - WHEN (alias.aliasType.removeSubsidy = true AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN ((cr2.unitCost / (1 - COALESCE(cr2.subsidy, 0))) * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.indirectRate AS DOUBLE)) THEN (1 + (CAST(ir.indirectRate AS DOUBLE) / (1 + alias.faRate))) ELSE 1 END)) - --remove subsidy only - WHEN (alias.aliasType.removeSubsidy = true AND alias.aliasType.canRaiseFA = false) THEN (cr2.unitCost / (1 - COALESCE(cr2.subsidy, 0))) - --raise F&A only - WHEN (alias.aliasType.removeSubsidy = false AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN (cr2.unitCost * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.indirectRate AS DOUBLE)) THEN (1 + (CAST(ir.IndirectRate AS DOUBLE) / (1 + alias.faRate))) ELSE 1 END)) - --the NIH rate - ELSE cr2.unitCost - END AS DOUBLE) as unitCost2, - cr2.unitCost as nihRate2, - - --for adjustments, this is the second lease charge - CAST(CASE - --order of priority for unit cost: - --project-level exemption: pay this value - WHEN (e3.unitCost IS NOT NULL) THEN e3.unitCost - --project-level multiplier: multiply NIH rate by this value - WHEN (pm.multiplier IS NOT NULL AND cr3.unitCost IS NOT NULL) THEN (cr3.unitCost * pm.multiplier) - --if there is not a known rate, we dont know what do to - WHEN (cr3.unitCost IS NULL) THEN null - --for non-OGA aliases, we always use the NIH rate - WHEN (alias.category IS NOT NULL AND alias.category != 'OGA') THEN cr3.unitCost - --if we dont know the aliasType, we also dont know what do to - WHEN (alias.aliasType.aliasType IS NULL) THEN null - --remove both subsidy and raise F&A if needed - WHEN (alias.aliasType.removeSubsidy = true AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN ((cr3.unitCost / (1 - COALESCE(cr3.subsidy, 0))) * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.indirectRate AS DOUBLE)) THEN (1 + (CAST(ir.indirectRate AS DOUBLE) / ( 1 + alias.faRate))) ELSE 1 END)) - --remove subsidy only - WHEN (alias.aliasType.removeSubsidy = true AND alias.aliasType.canRaiseFA = false) THEN (cr3.unitCost / (1 - COALESCE(cr3.subsidy, 0))) - --raise F&A only - WHEN (alias.aliasType.removeSubsidy = false AND (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true)) THEN (cr3.unitCost * (CASE WHEN (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.IndirectRate AS DOUBLE)) THEN (1 + (CAST(ir.IndirectRate AS DOUBLE) / (1 + alias.faRate))) ELSE 1 END)) - --the NIH rate - ELSE cr3.unitCost - END AS DOUBLE) as unitCost3, - cr3.unitCost as nihRate3, - - p.quantity, - cast(ce.account as varchar(200)) as creditAccount, - ce.rowid as creditAccountId, - null as comment, - coalesce(alias.investigatorId, p.project.investigatorId) as investigatorId, - CASE - WHEN (e.rowid IS NOT NULL OR e2.rowid IS NOT NULL OR e3.rowid IS NOT NULL) THEN 'Y' - WHEN (pm.multiplier IS NOT NULL) THEN ('Multiplier: ' || CAST(pm.multiplier AS varchar(100))) - ELSE null - END as isExemption, - CASE - WHEN (e.unitCost IS NOT NULL) THEN null --ignore project-level exemptions - WHEN (cr.unitCost IS NULL) THEN null --will be flagged for other reasons - WHEN (pm.multiplier IS NOT NULL) THEN null --also ignore project-level multipliers - WHEN (alias.aliasType.aliasType IS NULL) THEN null --unknown alias type, will be flagged elsewhere - WHEN (alias.aliasType.removeSubsidy = true AND COALESCE(cr.subsidy, 0) > 0) THEN 'Removed NIH Subsidy' - WHEN (alias.aliasType.canRaiseFA = true AND p.chargeId.canRaiseFA = true AND (alias.faRate IS NOT NULL AND alias.faRate < CAST(ir.IndirectRate AS DOUBLE))) THEN ('Reduced F&A: ' || CAST(alias.faRate as varchar(20))) - ELSE null - END as isNonStandardRate, - CASE WHEN (alias.alias IS NOT NULL AND alias.aliasType.aliasType IS NULL) THEN ('Unknown Type: ' || alias.aliasType) ELSE null END as isUnknownAliasType, - CASE - --handle adjustments and non-adjustments separately - WHEN (p.isAdjustment IS NULL AND coalesce(e.unitCost, cr.unitCost) is null) THEN 'Y' - WHEN (p.isAdjustment IS NOT NULL AND (coalesce(e3.unitCost, cr3.unitCost) IS NULL OR coalesce(e2.unitCost, cr2.unitCost) IS NULL)) THEN 'Y' - ELSE null - END as lacksRate, - CASE - WHEN (p.category = 'Lease Fees' or p.category = 'Lease Setup Fee' or p.category = 'Lease Setup Fees') AND e.rowid IS NULL THEN cr.rowId - ELSE null - END as rateId, - CASE - WHEN (p.category = 'Lease Fees' or p.category = 'Lease Setup Fee' or p.category = 'Lease Setup Fees') THEN e.rowid - ELSE null - END as exemptionId, - null as isMiscCharge, - p.isAdjustment, - CASE WHEN alias.alias IS NULL THEN 'Y' ELSE null END as isMissingAccount, - CASE WHEN alias.fiscalAuthority.faid IS NULL THEN 'Y' ELSE null END as isMissingFaid, - CASE - WHEN alias.aliasEnabled IS NULL THEN 'N' - WHEN alias.aliasEnabled != 'Y' THEN 'N' - ELSE null - END as isAcceptingCharges, - CASE - WHEN (alias.budgetStartDate IS NOT NULL AND CAST(alias.budgetStartDate as date) > CAST(p.date as date)) THEN 'Prior To Budget Start' - WHEN (alias.budgetEndDate IS NOT NULL AND CAST(alias.budgetEndDate as date) < CAST(p.date as date)) THEN 'After Budget End' - WHEN (alias.projectStatus IS NOT NULL AND alias.projectStatus != 'ACTIVE' AND alias.projectStatus != 'No Cost Ext' AND alias.projectStatus != 'Partial Setup') THEN 'Grant Project Not Active' - ELSE null - END as isExpiredAccount, - - CASE WHEN (TIMESTAMPDIFF('SQL_TSI_DAY', p.date, curdate()) > 45) THEN 'Y' ELSE null END as isOldCharge, - p.project.account as currentActiveAlias, - p.datefinalized, - p.enddatefinalized - -FROM onprc_billing.leaseFees p - ---the primary charge. this will be based on transaction date -LEFT JOIN onprc_billing_public.chargeRates cr ON ( - CAST(p.assignmentStart AS DATE) >= CAST(cr.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= cr.enddateCoalesced OR cr.enddate IS NULL) AND - p.chargeId = cr.chargeId -) - -LEFT JOIN onprc_billing_public.chargeRateExemptions e ON ( - CAST(p.assignmentStart AS DATE) >= CAST(e.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= e.enddateCoalesced OR e.enddate IS NULL) AND - p.chargeId = e.chargeId AND - p.project = e.project -) - ---the original charge (for adjustments) ---NOTE: the adjustment will use the lease end as the transaction date; however, we need to calculate this unit cost ---based on the original date of assignment -LEFT JOIN onprc_billing_public.chargeRates cr2 ON ( - CAST(p.assignmentStart AS DATE) >= CAST(cr2.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= cr2.enddateCoalesced OR cr2.enddate IS NULL) AND - p.leaseCharge1 = cr2.chargeId -) - -LEFT JOIN onprc_billing_public.chargeRateExemptions e2 ON ( - CAST(p.assignmentStart AS DATE) >= CAST(e2.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= e2.enddateCoalesced OR e2.enddate IS NULL) AND - p.leaseCharge1 = e2.chargeId AND - p.project = e2.project -) ---EO original charge - ---the final charge (for adjustments) ---this is the what we should have charges, based on the true release condition. ---this is also based on the date of assignment, which will differ from transaction date -LEFT JOIN onprc_billing_public.chargeRates cr3 ON ( - CAST(p.assignmentStart AS DATE) >= CAST(cr3.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= cr3.enddateCoalesced OR cr3.enddate IS NULL) AND - p.leaseCharge2 = cr3.chargeId -) - -LEFT JOIN onprc_billing_public.chargeRateExemptions e3 ON ( - CAST(p.assignmentStart AS DATE) >= CAST(e3.startDate AS DATE) AND - (CAST(p.assignmentStart AS DATE) <= e3.enddateCoalesced OR e3.enddate IS NULL) AND - p.leaseCharge2 = e3.chargeId AND - p.project = e3.project -) - ---EO final charge - -LEFT JOIN onprc_billing_public.creditAccount ce ON ( - CAST(p.date AS DATE) >= CAST(ce.startDate AS DATE) AND - (CAST(p.date AS DATE) <= ce.enddateCoalesced OR ce.enddate IS NULL) AND - p.chargeId = ce.chargeId -) - -LEFT JOIN onprc_billing_public.projectAccountHistory aliasAtTime ON ( - aliasAtTime.project = p.project AND - aliasAtTime.startDate <= cast(p.date as date) AND - aliasAtTime.endDate >= cast(p.date as date) -) - -LEFT JOIN onprc_billing_public.aliases alias ON ( - aliasAtTime.account = alias.alias -) - -LEFT JOIN onprc_billing_public.projectMultipliers pm ON ( - CAST(p.date AS DATE) >= CASt(pm.startDate AS DATE) AND - (CAST(p.date AS DATE) <= pm.enddateCoalesced OR pm.enddate IS NULL) AND - alias.alias = pm.account -) -LEFT JOIN onprc_billing.ogaSynchIR ir - on ir.alias = alias.alias - -) t -where t.id.demographics.species Not IN ('Rabbit','Guinea Pig') -UNION ALL - ---add misc charges -SELECT - mc.id, - mc.date, - null as enddate, - mc.project, - mc.account, - null as projectedReleaseCondition, - null as releaseCondition, - null as assignCondition, - null as releaseType, - null as ageAtTime, - mc.category, - mc.chargeId, - mc.serviceCenter, - mc.item, - - null as leaseCharge1, - null as leaseCharge2, - mc.sourceRecord, - mc.chargeCategory, - - mc.unitcost, - mc.nihRate, - - null as unitCost1, - null as nihRate1, - null as unitCost2, - null as nihRate2, - null as unitCost3, - null as nihRate3, - - mc.quantity, - - mc.creditAccount, - mc.creditAccountId, - mc.comment, - mc.investigatorId, - mc.isExemption, - mc.isNonStandardRate, - mc.lacksRate, - mc.rateId, - mc.exemptionId, - 'Y' as isMiscCharge, - mc.isAdjustment, - mc.isMissingAccount, - mc.isMissingFaid, - mc.isAcceptingCharges, - mc.isExpiredAccount, - mc.isOldCharge, - mc.currentActiveAlias, - null as datefinalized, - null as enddatefinalized - -FROM onprc_billing.miscChargesFeeRateData mc -WHERE cast(mc.billingDate as date) >= CAST(StartDate as date) AND cast(mc.billingDate as date) <= CAST(EndDate as date) -AND mc.category IN ('Lease Fees', 'Lease Setup Fee', 'Lease Setup Fees') diff --git a/onprc_billing/resources/queries/onprc_billing/leasefeerates.sql b/onprc_billing/resources/queries/onprc_billing/leasefeerates.sql new file mode 100644 index 000000000..2c2c1bb74 --- /dev/null +++ b/onprc_billing/resources/queries/onprc_billing/leasefeerates.sql @@ -0,0 +1,321 @@ +PARAMETERS (StartDate TIMESTAMP, EndDate TIMESTAMP) + +WITH +-- ===================================================================================== +-- 1) Base Lease Fees +-- ===================================================================================== +base_lease AS ( + SELECT + p.id, + p.date, + p.enddate, + p.assignmentStart, + p.project, + p.project.displayName AS projectDisplayName, + p.projectedReleaseCondition, + p.releaseCondition, + p.assignCondition, + p.releaseType, + p.ageAtTime, + p.category, + p.chargeId, + p.leaseCharge1, + p.leaseCharge2, + p.sourceRecord, + p.chargeCategory, + p.quantity, + p.isAdjustment, + p.datefinalized, + p.enddatefinalized + FROM onprc_billing.leaseFees p + WHERE CAST(p.date AS DATE) + BETWEEN CAST(StartDate AS DATE) AND CAST(EndDate AS DATE) + AND p.category = 'Lease Fees' +), + +-- ===================================================================================== +-- 2) Alias / Account Context + +-- ===================================================================================== +alias_context AS ( + SELECT + bl.*, + da.DualProjectCategory, + da.project1 as InitialProject, + a.alias AS account, + a.category AS aliasCategory, + a.faRate AS faRate, + a.aliasType.aliasType AS aliasType, + a.aliasType.removeSubsidy AS removeSubsidy, + a.aliasType.canRaiseFA AS canRaiseFA, + a.fiscalAuthority.faid AS faid, + a.aliasEnabled AS aliasEnabled, + a.budgetStartDate AS budgetStartDate, + a.budgetEndDate AS budgetEndDate, + a.projectStatus AS projectStatus, + COALESCE(a.investigatorId, + bl.project.investigatorId) AS investigatorId + FROM base_lease bl + + LEFT JOIN onprc_billing_public.projectAccountHistory pah + ON pah.project = bl.project + AND pah.startDate <= CAST(bl.date AS DATE) + AND pah.endDate >= CAST(bl.date AS DATE) + LEFT JOIN onprc_billing_public.aliases a + ON pah.account = a.alias + Left JOIN study.dualAssigned da + on bl.id = da.id + AND da.dualendDate >= CAST(bl.date AS DATE) + AND da.dualstartDate <= CAST(bl.date AS DATE) + + +--Select * from alias_context +), +-- ===================================================================================== +-- 2a lookup to determine credit to for each lease fee +-- when an assignment creates a dual assignment and the original assignment is an + +-- 3) Rates / Exemptions / Multipliers / Indirect Rate +-- ===================================================================================== + +rate_context AS ( + SELECT + ac.*, + LI.project as CreditTo, + + cr.unitCost AS nihRate1, + cr.subsidy AS subsidy1, + e.unitCost AS exemptRate1, + e.rowid AS exemptionId1, + + cr2.unitCost AS nihRate2, + cr2.subsidy AS subsidy2, + e2.unitCost AS exemptRate2, + e2.rowid AS exemptionId2, + + cr3.unitCost AS nihRate3, + cr3.subsidy AS subsidy3, + e3.unitCost AS exemptRate3, + e3.rowid AS exemptionId3, + + pm.multiplier AS multiplier, + ir.indirectRate AS indirectRate + FROM alias_context ac + + LEFT JOIN onprc_billing_public.chargeRates cr + ON ac.assignmentStart >= cr.startDate + AND (ac.assignmentStart <= cr.enddateCoalesced OR cr.enddate IS NULL) + AND ac.chargeId = cr.chargeId + + LEFT JOIN onprc_billing_public.chargeRateExemptions e + ON ac.assignmentStart >= e.startDate + AND (ac.assignmentStart <= e.enddateCoalesced OR e.enddate IS NULL) + AND ac.chargeId = e.chargeId + AND ac.project = e.project + + LEFT JOIN onprc_billing_public.chargeRates cr2 + ON ac.assignmentStart >= cr2.startDate + AND (ac.assignmentStart <= cr2.enddateCoalesced OR cr2.enddate IS NULL) + AND ac.leaseCharge1 = cr2.chargeId + + LEFT JOIN onprc_billing_public.chargeRateExemptions e2 + ON ac.assignmentStart >= e2.startDate + AND (ac.assignmentStart <= e2.enddateCoalesced OR e2.enddate IS NULL) + AND ac.leaseCharge1 = e2.chargeId + AND ac.project = e2.project + + LEFT JOIN onprc_billing_public.chargeRates cr3 + ON ac.assignmentStart >= cr3.startDate + AND (ac.assignmentStart <= cr3.enddateCoalesced OR cr3.enddate IS NULL) + AND ac.leaseCharge2 = cr3.chargeId + + LEFT JOIN onprc_billing_public.chargeRateExemptions e3 + ON ac.assignmentStart >= e3.startDate + AND (ac.assignmentStart <= e3.enddateCoalesced OR e3.enddate IS NULL) + AND ac.leaseCharge2 = e3.chargeId + AND ac.project = e3.project + + LEFT JOIN onprc_billing_public.projectMultipliers pm + ON ac.date >= pm.startDate + AND (ac.date <= pm.enddateCoalesced OR pm.enddate IS NULL) + AND ac.account = pm.account + + LEFT JOIN onprc_billing.ogaSynchIR ir + ON ir.alias = ac.account + Left Join onprc_Billing.ProjectLeaseIncomeEligibility Li + on ac.InitialProject = Li.Project +), + + + -- ===================================================================================== +-- 4) Unit Cost Calculation (Parser-Safe) +-- ===================================================================================== +calculated_costs AS ( + SELECT + rc.*, + + CAST( + CASE + WHEN exemptRate1 IS NOT NULL THEN exemptRate1 + + WHEN multiplier IS NOT NULL AND nihRate1 IS NOT NULL + THEN (CAST(nihRate1 AS DOUBLE) * CAST(multiplier AS DOUBLE)) + + WHEN nihRate1 IS NULL THEN NULL + + WHEN aliasCategory IS NOT NULL AND aliasCategory <> 'OGA' + THEN nihRate1 + + WHEN aliasType IS NULL THEN NULL + + WHEN removeSubsidy = TRUE + AND canRaiseFA = TRUE + AND chargeId.canRaiseFA = TRUE + THEN ( + (CAST(nihRate1 AS DOUBLE) / NULLIF((1 - COALESCE(subsidy1, 0)), 0)) + * + ( + 1 + + CASE + WHEN faRate IS NOT NULL + AND indirectRate IS NOT NULL + AND faRate < CAST(indirectRate AS DOUBLE) + THEN (CAST(indirectRate AS DOUBLE) / (1 + faRate)) + ELSE 0 + END + ) + ) + + WHEN removeSubsidy = TRUE AND canRaiseFA = FALSE + THEN (CAST(nihRate1 AS DOUBLE) / NULLIF((1 - COALESCE(subsidy1, 0)), 0)) + + WHEN removeSubsidy = FALSE + AND canRaiseFA = TRUE + AND chargeId.canRaiseFA = TRUE + THEN ( + CAST(nihRate1 AS DOUBLE) + * + ( + 1 + + CASE + WHEN faRate IS NOT NULL + AND indirectRate IS NOT NULL + AND faRate < CAST(indirectRate AS DOUBLE) + THEN ((CAST(indirectRate AS DOUBLE) - faRate) / (1 + faRate)) + ELSE 0 + END + ) + ) + + ELSE nihRate1 + END + AS DOUBLE) AS unitCost + FROM rate_context rc +), +--Select * from calculated_costs +-- ===================================================================================== +-- 5) Final Lease Charges (Billing Review) +-- ===================================================================================== + + +lease_final AS ( + SELECT + id, + date AS assignmentStartDate, + enddate AS assignmentEndDate, + datefinalized AS dateFinalized, + project, + account, + projectedReleaseCondition, + releaseCondition, + assignCondition, + releaseType, + ageAtTime, + category, + chargeId, + chargeId.departmentCode AS serviceCenter, + chargeId.name AS item, + leaseCharge1.name as InitialLEaseType, + leaseCharge2.name as FinalLEaseType, + sourceRecord, + chargeCategory, +-- Add the action to get the correct alias for the credit account +-- This is based on whether there is a value in Credit to field + CAST(creditto as varchar) AS creditAccount, + CAST(NULL AS INTEGER) AS creditAccountId, + + unitCost, + quantity, + + CASE + WHEN isAdjustment IS NOT NULL + THEN ROUND(CAST(unitCost AS DOUBLE), 2) + ELSE + ROUND( + CAST(unitCost AS DOUBLE) + * COALESCE(CAST(quantity AS DOUBLE), 1), + 2 + ) + END AS totalCost, + + investigatorId, + + NULL AS isMiscCharge, + isAdjustment + FROM calculated_costs + WHERE id.demographics.species NOT IN ('Rabbit','Guinea Pig') +), + +-- ... existing code ... + +misc_charges AS ( + SELECT + mc.id, + mc.billingDate AS assignmentStartDate, + NULL AS assignmentEndDate, + NULL AS dateFinalized, + mc.project, + mc.account, + NULL AS projectedReleaseCondition, + NULL AS releaseCondition, + NULL AS assignCondition, + NULL AS releaseType, + NULL AS ageAtTime, + mc.category, + mc.chargeId, + mc.serviceCenter, + mc.item, + NULL AS leaseCharge1, + NULL AS leaseCharge2, + mc.sourceRecord, + mc.chargeCategory, + + mc.creditAccount AS creditAccount, + mc.creditAccountId AS creditAccountId, + + mc.unitCost, + mc.quantity, + + ROUND( + CAST(mc.unitCost AS DOUBLE) + * COALESCE(CAST(mc.quantity AS DOUBLE), 1), + 2 + ) AS totalCost, + + mc.investigatorId, + + 'Y' AS isMiscCharge, + mc.isAdjustment + FROM onprc_billing.miscChargesFeeRateData mc + WHERE CAST(mc.billingDate AS DATE) + BETWEEN CAST(StartDate AS DATE) AND CAST(EndDate AS DATE) + AND mc.category = 'Lease Fees' +) + +-- ... existing code ... +-- ===================================================================================== +-- FINAL BILLING-REVIEW OUTPUT +-- ===================================================================================== +SELECT * FROM lease_final +UNION ALL +SELECT * FROM misc_charges; diff --git a/onprc_billing/resources/schemas/dbscripts/sqlserver/onprc_billing-25.006-25.007.sql b/onprc_billing/resources/schemas/dbscripts/sqlserver/onprc_billing-25.006-25.007.sql new file mode 100644 index 000000000..33347b754 --- /dev/null +++ b/onprc_billing/resources/schemas/dbscripts/sqlserver/onprc_billing-25.006-25.007.sql @@ -0,0 +1,8 @@ +CREATE TABLE onprc_billing.ProjectLeaseIncomeEligibility ( + rowId INT IDENTITY(1,1) NOT NULL, + project INT NOT NULL, + startDate DATE NOT NULL, + endDate DATE NULL, + comment NVARCHAR(4000) NULL, + CONSTRAINT PK_ProjectLeaseIncomeEligibility PRIMARY KEY (rowId) +); \ No newline at end of file diff --git a/onprc_billing/resources/schemas/onprc_billing.xml b/onprc_billing/resources/schemas/onprc_billing.xml index 2bb09f73b..d425c2afa 100644 --- a/onprc_billing/resources/schemas/onprc_billing.xml +++ b/onprc_billing/resources/schemas/onprc_billing.xml @@ -1641,4 +1641,21 @@ +