--select * from tms_app_loaninstallmentfundingrequest --
with loan_on_day_status as (
select id as loan_id,
(
select status_id
from loan_app_loanstatushistroy
where day <= {'date':'date'} and status_type = 0 and loan_app_loanstatushistroy.loan_id = loan_app_loan.id
order by loan_id, updated_at desc
limit 1
) as blnk_status,
(
select day
from loan_app_loanstatushistroy
where day <= {'date':'date'} and status_type = 0 and loan_app_loanstatushistroy.loan_id = loan_app_loan.id
order by loan_id, updated_at desc
limit 1
) as blnk_status_day,
(
select status_id
from loan_app_loanstatushistroy
where day <= {'date':'date'} and status_type = 1 and loan_app_loanstatushistroy.loan_id = loan_app_loan.id
order by loan_id, updated_at desc
limit 1
) as fra_status
from loan_app_loan
order by loan_id
),
latest_payment_status as (
select distinct on (nli.installment_extension_id) installment_extension_id as installment_id, status as payment_status, nli.day
from new_lms_installmentpaymentstatushistory nli
where day <= {'date':'date'}
order by nli.installment_extension_id, nli.day desc, nli.id desc
)
,
-- without bv
off_bal_installments as (
select lai.id
from loan_app_installment lai
inner join tms_app_loanmerchantbatch talmb on talmb.loan_id = lai.loan_id and talmb.bond_id = 16
union
select talifr.installment_id as id
from tms_app_loaninstallmentfundingrequest talifr
where talifr.onbalance = false and assignment_day <= {'date':'date'}
),
on_bal_installments as (
select id
from loan_app_installment
except
select id
from off_bal_installments
)
,
targeted_loans as (
select distinct lai.loan_id as loan_id
from loan_app_installment lai
inner join on_bal_installments obi on obi.id = lai.id
)
,
remaining_principal as (
select lal.id, coalesce(sum(lai.principal_expected) filter (where nlie.principal_paid_at is null or cast(principal_paid_at as date) > {'date':'date'}
or
( cast(principal_paid_at as date) < lai.day and (nlie.payment_status not in (2,3,4,16) and lds.blnk_status not in (1,6,8,15,16) or
(nlie.payment_status = 6 ) ))
and {'date':'date'} < lai.day
), 0) as enr,
coalesce( sum(lai.principal_expected) filter ( where lps.payment_status in (5,6) and nlie.is_long_term=false and (nlie.status_id <> 7 or (nlie.status_id = 7 and (is_principal_paid=false or (principal_paid_at::date > {'date':'date'})))) and ((( nlie.status_id=7 or nlie.long_to_short_term_date < {'date':'date'}) and nlie.long_to_short_term_date < {'date':'date'} ) or nlie.long_to_short_term_date is null)
),0) as undue_principle,
coalesce( sum(lai.principal_expected) filter (
where
lps.payment_status = 0 and {'date':'date'} >= nlie.due_to_overdue_date
and (((nlie.status_id=7 or nlie.long_to_short_term_date < {'date':'date'}) and nlie.long_to_short_term_date < {'date':'date'} ) or nlie.long_to_short_term_date is null) and (is_principal_paid=false or (principal_paid_at::date > {'date':'date'}))
) ,0) as overdue_principle,
coalesce( sum(lai.principal_expected) filter (
where
(lps.payment_status = 4 and (nlie.is_principal_paid = false or nlie.principal_paid_at > {'date':'date'}) ) or (lps.payment_status = 0 and {'date':'date'} < nlie.due_to_overdue_date )
-- )
) ,0) as due_principle,
coalesce(
sum(lai.principal_expected) filter (
where
(nlie.is_long_term = true or (nlie.is_long_term = false and nlie.long_to_short_term_date >= {'date':'date'}))
and (nlie.is_principal_paid = false or cast(nlie.principal_paid_at as date) > {'date':'date'} )
),
0
) as long_term_principle
from loan_app_loan lal
inner join loan_on_day_status lds on lds.loan_id = lal.id
inner join loan_app_installment lai on lai.loan_id = lal.id
inner join latest_payment_status lps on lps.installment_id = lai.id
inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
inner join on_bal_installments obi on obi.id = lai.id
where lds.blnk_status not in (12,13)
group by lal.id
)
,
provisions as (
select lal.id, coalesce(sum(lai.principal_expected) filter (where nlie.principal_paid_at is null or cast(principal_paid_at as date) > {'date':'date'}
or
( cast(principal_paid_at as date) < lai.day and (nlie.payment_status not in (2,3,4,16) and lds.blnk_status not in (1,6,8,15,16) or
(nlie.payment_status = 6 and lds.blnk_status not in (1,6,8,15,16) ) ))
and {'date':'date'} < lai.day
), 0) as enr
from loan_app_loan lal
inner join loan_app_installment lai on lai.loan_id = lal.id
inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
inner join loan_on_day_status lds on lds.loan_id = lal.id
group by lal.id
)
,
late_fees as (
select lal.id, sum(nlilf.amount) filter(
where nlilf.day < {'date':'date'} and lds.blnk_status not in (7,17)
and (nlilf.is_cancelled = false or cast(nlilf.cancellation_date as date) > {'date':'date'}) and nlilf.is_disabled = false
and (nlilf.is_partially_cancelled = false or nlilf.partially_cancelled_date > {'date':'date'})
and (nlilf.is_paid = false or cast(nlilf.paid_at as date) > {'date':'date'})
)as total_late_fees,
sum(nlilf.amount) filter
(where lds.blnk_status <> 7 and ((nlilf.day<{'date':'date'} and {'date':'date'}<'2025-09-30' and (select count(*) from loan_app_loanstatushistroy where loan_id=lal.id and
status_type=0 and day <={'date':'date'} and status_id =3 and day < '2025-09-30') >0 and (nlilf.is_paid=false or nlilf.paid_at::date>{'date':'date'})) or ((nlilf.is_marginalized = true
and cast(nlilf.marginalization_date as date) <= {'date':'date'}) or (
nlilf.is_marginalized = false
and cast(nlilf.marginalization_date as date) is not null
and cast(nlilf.marginalization_date as date) <= {'date':'date'}
and cast(nlilf.unmarginalization_date as date) > {'date':'date'}) ))and (nlilf.is_cancelled =false or (nlilf.is_cancelled =true and nlilf.cancellation_date> {'date':'date'})) )
as marginalized
from new_lms_installmentlatefees nlilf
inner join loan_app_installment lai on lai.id = nlilf .installment_extension_id
inner join loan_app_loan lal on lal.id = lai.loan_id
inner join on_bal_installments obi on obi.id = lai.id
inner join loan_on_day_status lds on lds.loan_id = lal.id
group by lal.id
)
,
accrued_interest as(
select lai.loan_id as id, sum((
case when nlie.payment_status in (0,2) and nlie.partial_accrual_date <= {'date':'date'} then (
(case when nlie.accrual_date <= {'date':'date'} then nlie.actual_accrued_amount else 0 end) + nlie.partial_accrual_amount - (case when cast(nlie.interest_paid_at as date) <= {'date':'date'} then nlie.actual_interest_paid else 0 end) + nlie.settlement_accrual_interest_amount + nlie.faulty_accrued_amount
)
when nlie.payment_status in (4) and nlie.partial_accrual_date <= {'date':'date'} then
(nlie.partial_accrual_amount + (case when nlie.accrual_date <= {'date':'date'} then nlie.actual_accrued_amount else 0 end)
)
when nlie.payment_status in (1)then
(
(case when nlie.partial_accrual_date <= {'date':'date'} then nlie.partial_accrual_amount else 0 end)
+ (case when nlie.accrual_date <= {'date':'date'} then nlie.actual_accrued_amount - nlie.actual_interest_paid + nlie.faulty_accrued_amount else 0 end)
)
when nlie.payment_status in (3,16) then
case when nlie.partial_accrual_date <= {'date':'date'} then nlie.partial_accrual_amount else 0 end
+ (case when nlie.accrual_date <= {'date':'date'} then nlie.actual_accrued_amount else 0 end)
+ case when cast(nlie.settlement_accrual_interest_date as date) <= {'date':'date'} then nlie.settlement_accrual_interest_amount else 0 end
- (case when cast(nlie.interest_paid_at as date) <= {'date':'date'} then nlie.actual_interest_paid else 0 end)
end
))
as accrued_interest
from loan_app_installment lai
inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
inner join loan_app_loan lal on lal.id = lai.loan_id
group by lai.loan_id
)
,
decomposed_interests as(
select lai.loan_id ,
sum(case when nlie.due_to_overdue_date <= {'date':'date'} and (lds.blnk_status <> 7 or ( lds.blnk_status = 7 and nlie.due_to_overdue_date < lds.blnk_status_day))
and (nlie.is_interest_paid = false or cast(nlie.interest_paid_at as date) > {'date':'date'}) and lds.blnk_status not in (6,8,12,13,15,16)
then lai.interest_expected + round(case when extra_interest_paid_at<= {'date':'date'} then 0 else nlie.first_installment_interest_adjustment end,2) end) as overdue_interest,
sum(case when {'date':'date'} >= nlie.undue_to_due_date and {'date':'date'} <= nlie.grace_date and (nlie.is_interest_paid = false or cast(nlie.interest_paid_at as date) > {'date':'date'}) and lds.blnk_status not in (6,8,12,13,15,16) then lai.interest_expected + round(nlie.first_installment_interest_adjustment,2) else 0 end) as due_nonpaid_interest
from loan_app_installment lai
inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
inner join loan_app_loan lal on lal.id = lai.loan_id
inner join loan_on_day_status lds on lds.loan_id = lal.id
inner join on_bal_installments obi on obi.id = lai.id
where lds.blnk_status not in (7,12,13)
group by lai.loan_id
-- select lai.loan_id ,
-- sum(case when nlie.due_to_overdue_date <= {'date':'date'}
-- and (nlie.is_interest_paid = false or nlie.interest_paid_at::date > {'date':'date'}) and lds.blnk_status not in (6,8,12,13,15)
-- then lai.interest_expected end) as overdue_interest,
-- sum(
-- case
-- when
-- {'date':'date'} >= nlie.undue_to_due_date and {'date':'date'} < nlie.due_to_overdue_date
-- and (nlie.is_interest_paid = false or nlie.interest_paid_at::date > {'date':'date'})
-- and lds.blnk_status not in (6,7,8,12,13,15)
-- then lai.interest_expected
-- else 0
-- end
-- ) as due_nonpaid_interest
-- from loan_app_installment lai
-- inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
-- inner join loan_app_loan lal on lal.id = lai.loan_id
-- inner join on_bal_installments obi on obi.id = lai.id
-- inner join loan_on_day_status lds on lds.loan_id = lal.id
-- where lds.blnk_status not in (12,13)
-- group by lai.loan_id
)
,
undue_interest as (
with installments_details as (
select
lai.id as "installment_id",
lai.loan_id,
lal.status_id,
nli.accrual_date,
lal.first_accrual_adjustment_date,
nli.is_extra_interest_paid,
nli.payment_status,
nli.first_installment_interest_adjustment,
nli.actual_interest_paid,
nli.settlement_accrual_interest_amount,
nli.settlement_accrual_interest_date,
nli.expected_partial_accrual_amount,
lai.interest_expected,
lai.day,
nli.interest_paid_at,
nli.partial_accrual_date,
lai."period",
nli.expected_accrual_amount,
nli.extra_interest_paid_at,
nli.undue_to_due_date
from new_lms_installmentextension nli
inner join loan_app_installment lai on nli.installment_ptr_id = lai.id
inner join loan_app_loan lal on lal.id = lai.loan_id
inner join on_bal_installments obi on obi.id = lai.id
)
,
init_accrual as(
select installments_details.loan_id lalid1, sum(first_installment_interest_adjustment) first_accrual_adjustment
from installments_details
inner join latest_payment_status lps on lps.installment_id = installments_details."installment_id"
inner join loan_on_day_status lods on installments_details.loan_id = lods.loan_id
where
(lps.payment_status in (5,6) or(lps.payment_status in (4,7) and lods.blnk_status in (11,14,7,15) and accrual_date > {'date':'date'}) or (lps.payment_status=10 and extra_interest_paid_at::date > {'date':'date'}) or (lps.payment_status in (3,16) and accrual_date > {'date':'date'} and extra_interest_paid_at::date > {'date':'date'})) and first_installment_interest_adjustment > 0
and (lods.blnk_status not in (8,15,16) or (lods.blnk_status in (8,15,16) and is_extra_interest_paid = true and extra_interest_paid_at::date > {'date':'date'})) and first_accrual_adjustment_date <= {'date':'date'}
and (partial_accrual_date > {'date':'date'} or (partial_accrual_date = {'date':'date'} and EXTRACT('DAY' FROM undue_to_due_date) = 1)) and lps.payment_status not in (12,13)
group by installments_details.loan_id
)
,
next_inst as(
select lalid3, insts from (
select nli.loan_id lalid3, (expected_accrual_amount) insts, lods.blnk_status status_on_day,
(select status from new_lms_installmentpaymentstatushistory where installment_extension_id=nli.installment_id and day <={'date':'date'} order by id desc limit 1) as last_status,
undue_to_due_date, interest_paid_at
from installments_details nli
inner join loan_on_day_status lods on nli.loan_id = lods.loan_id
where accrual_date = {'date':'date'}
and (lods.blnk_status not in (15,7)
or (lods.blnk_status = 15 and (settlement_accrual_interest_amount = 0 or settlement_accrual_interest_amount <> 0 and settlement_accrual_interest_date::date > {'date':'date'}))
or (lods.blnk_status = 7 and lods.blnk_status_day > accrual_date )
) ) s
where last_status not in (1,2,3,7,12)
or
(last_status = 2
and (interest_paid_at::date < undue_to_due_date or (interest_paid_at is null and status_on_day <>15))
)
or (last_status = 7 and (select status_id from loan_app_loan where id = lalid3) <>15)
)
,
next_partial_only as (
select lalid4, insts from (
select nli.loan_id lalid4, expected_partial_accrual_amount + (case when nli.is_extra_interest_paid=true and nli.extra_interest_paid_at::date <={'date':'date'} then 0 else
round(first_installment_interest_adjustment,2) end) insts,
(select status from new_lms_installmentpaymentstatushistory where installment_extension_id=nli.installment_id and day <={'date':'date'} order by id desc limit 1) as last_status,
undue_to_due_date, interest_paid_at
from installments_details nli
inner join loan_on_day_status lods on nli.loan_id = lods.loan_id
where
(select nlish.status_id from new_lms_installmentstatushistory nlish where nlish.installment_id = nli.installment_id and day <= {'date':'date'} and status_type = 1 order by id desc limit 1) <> 7
and partial_accrual_date <= {'date':'date'}
and day > cast({'date':'date'} as date) + interval '1 day'
and (lods.blnk_status <> 15 or (lods.blnk_status = 15
and (settlement_accrual_interest_amount = 0 or settlement_accrual_interest_amount <> 0 and cast(settlement_accrual_interest_date as date) > {'date':'date'}))
)
)
s where last_status not in (1,2,3,7,12)
or (last_status = 2
and (cast(interest_paid_at as date) < undue_to_due_date or (interest_paid_at is null and (select blnk_status from loan_on_day_status where loan_id = lalid4) <>15)))
or (last_status = 7 and (select blnk_status from loan_on_day_status where loan_id = lalid4) <>15)
)
,
old_first_accrual_in_partial as(
select lalid5, insts from (
select loan_id lalid5, (expected_partial_accrual_amount) insts,
(select status from new_lms_installmentpaymentstatushistory where installment_extension_id=nli.installment_id and day <={'date':'date'} order by id desc limit 1) as last_status
from installments_details nli
where accrual_date = {'date':'date'} and expected_partial_accrual_amount <> 0 and (status_id not in (8,16) or (status_id in (8,16) and payment_status not in (3,16)))
) s where last_status not in (12,13)
)
SELECT loan, sum(undue_balance) as undue_balance
FROM(
select lalid1 loan, first_accrual_adjustment undue_balance from init_accrual
UNION ALL
select lalid3 loan, insts undue_balance from next_inst
UNION ALL
select lalid4 loan, insts undue_balance from next_partial_only
UNION ALL
select lalid5 loan, insts undue_balance from old_first_accrual_in_partial
) s group by s.loan
)
,
marginalized_interest as(
select lai.loan_id ,
sum(
case
-- the first 2 lines here are to get all the marginalization that was done before applying 90 days marginalization on 30-09-2025
when lds.blnk_status > 2 and lai.day <={'date':'date'} and {'date':'date'} < '2025-09-30' and (nlie.is_interest_paid=false or nlie.interest_paid_at::date > {'date':'date'}) then lai.interest_expected + round(nlie.first_installment_interest_adjustment,2)
when nlie.partial_accrual_date<={'date':'date'} and lai.day > {'date':'date'} and lds.blnk_status > 2 and {'date':'date'} < '2025-09-30' and (nlie.is_interest_paid=false or nlie.interest_paid_at::date > {'date':'date'}) then expected_partial_accrual_amount
when is_marginalized=true and marginalization_date <= {'date':'date'} then lai.interest_expected + round(nlie.first_installment_interest_adjustment,2)
when is_partially_marginalized=true and partial_marginalization_date <= {'date':'date'} then expected_partial_accrual_amount
when is_marginalized=false and marginalization_date <= {'date':'date'} and unmarginalization_date > {'date':'date'} then lai.interest_expected + round(nlie.first_installment_interest_adjustment,2)
when is_partially_marginalized=false and partial_marginalization_date <= {'date':'date'} and unmarginalization_date > {'date':'date'} then expected_partial_accrual_amount
else 0
end
)as marginalized_interest
-- sum(
-- (
-- case when nlie.partial_marginalization_date is not null and (nlie.is_partially_marginalized = true or nlie.unmarginalization_date::date > {'date':'date'}) and nlie.partial_marginalization_date::date < {'date':'date'}
-- then nlie.partial_accrual_amount else 0 end
-- )
-- +(
-- case when nlie.marginalization_date is not null and (nlie.is_marginalized = true or nlie.unmarginalization_date::date > {'date':'date'}) and nlie.marginalization_date::date < {'date':'date'}
-- then nlie.actual_accrued_amount + (
-- case when (nlie.partial_marginalization_date::date is null or nlie.unmarginalization_date::date < nlie.marginalization_date) and nlie.is_partially_marginalized = False
-- then nlie.partial_accrual_amount else 0 end
-- ) else 0 end
-- )
-- ) as marginalized_interest
from loan_app_installment lai
inner join new_lms_installmentextension nlie on nlie.installment_ptr_id = lai.id
inner join on_bal_installments obi on obi.id = lai.id
inner join loan_on_day_status lds on lds.loan_id = lai.loan_id
where lds.blnk_status <> 7
group by lai.loan_id
)
,
main_query as (
select lal.id
,
-- (case when lds.blnk_status=7 then coalesce(rp.enr,0) else
(coalesce((coalesce(rp.undue_principle,0)+coalesce(rp.overdue_principle,0)+coalesce(rp.due_principle,0)+coalesce(rp.long_term_principle,0)),0))as ENR,
coalesce(rp.undue_principle,0) as "Loans receivable undue, (gross)",
coalesce(rp.overdue_principle,0) as "Loans receivable overdue, (gross)",
coalesce(rp.due_principle,0) as "Loans receivable due, (gross)",
coalesce(rp.long_term_principle,0) as "Long term loans receivables",
coalesce(di.due_nonpaid_interest,0) as "Accrued interest income receivable, due (gross)",
coalesce(ui.undue_balance,0) as "Accrued interest income receivable, undue (gross)",
coalesce(mi.marginalized_interest,0) as "Marginalized interest income receivable",
coalesce(lf.total_late_fees,0) as total_late_fees,
coalesce(lf.marginalized,0) as "Marginalized late repayment fee income receivable",
round(lap.percentage * coalesce((coalesce(rp.undue_principle,0)+coalesce(rp.overdue_principle,0)+coalesce(rp.due_principle,0)+coalesce(rp.long_term_principle,0)),0) / 100,2) as "Impairment provisions, On-balance sheet",
coalesce(di.overdue_interest,0) as "Accrued interest income receivable, overdue (gross)",
lalsb.name as blnk_status,
lalsf.name as fra_status,
lal.principle as loan_amount,
lal.yearly_interest,
lal.loan_booking_day,
lal.period_installment,
lal.num_months,
--case when talmb.bond_id = 15 then 'securitized' when talmb.bond_id = 16 then 'BV' else 'On Balance' end as portfolio,
cac.id as customer,
case when cac.limit_source = 1 then 'Banked' when cac.limit_source = 2 then 'Unbanked' end as limit_source,
concat(cac.first_name,' ',cac.last_name) as customer_name,
cac.phone_number,
nllc.starting_day_of_the_month as cycle_day,
cacr.name as rank
, cam3.name_ar as product_type
from loan_app_loan lal
inner join targeted_loans tl on tl.loan_id = lal.id
inner join loan_on_day_status lds on lds.loan_id = lal.id
left join loan_app_loanstatus lalsb on lalsb.id = lds.blnk_status
left join loan_app_loanstatus lalsf on lalsf.id = lds.fra_status
inner join crm_app_customer cac on cac.id = lal.customer_id
inner join new_lms_loancycle nllc on nllc.id = cac.first_loan_cycle_id
inner join crm_app_customerrank cacr on cacr.id = cac.rank_id
inner join loan_app_provision lap on lap.status_id = lds.fra_status
left join crm_app_merchant cam2 on cam2.id = lal.merchant_id
left join crm_app_merchantcategory cam3 on cam3.id = cam2.category_id
left join tms_app_loanmerchantbatch talmb on talmb.loan_id = lal.id
left join remaining_principal rp on rp.id = lal.id
left join late_fees lf on lf.id = lal.id
--left join accrued_interest ai on ai.id = lal.id
left join undue_interest ui on ui.loan = lal.id
left join marginalized_interest mi on mi.loan_id = lal.id
left join decomposed_interests di on di.loan_id = lal.id
where lal.loan_booking_day <= {'date':'date'} -- and lal.id = 82651
and lds.blnk_status in (1,2,3,4,5,7,9,10,11,14)
order by lal.id
)
select * from main_query
-- where id=70956
-- where id=56112
-- where id=64241
-- where id=94804
-- where id in (84682,85806,99194,100129,102323,102391,102439,104335,124645,93773,94804)
--where enr <> 0 and total_late_fees <> 0