fix(bookkeeping): classify template audit evidence (#1594)

This commit is contained in:
Mattsson
2026-08-13 18:58:09 +02:00
committed by GitHub
parent d02fd82191
commit e494662530
4 changed files with 489 additions and 98 deletions
+94 -56
View File
@@ -1,68 +1,106 @@
-- Read-only classifier probes for scripts/audit-template-misbookings.sql.
-- Expected result: four rows, each with actual_result = expected_result.
-- Read-only evidence-classifier probes for audit-template-misbookings.sql.
-- Expected result: eight rows, each with passed = true.
with probe_lines(probe, account_number, debit_amount) as (
with probes(
probe,
defect,
source_type,
review_priority,
line_count,
observed_vat_rate,
document_has_12pct_vat,
document_has_25pct_vat,
expected_classification
) as (
values
('hotel_on_5820', '5820', 1000.00::numeric),
('hotel_on_5820', '2641', 120.00::numeric),
('car_hire_on_5820', '5820', 1000.00::numeric),
('car_hire_on_5820', '2641', 250.00::numeric),
('representation_25_multi_line', '6072', 60.00::numeric),
('representation_25_multi_line', '6072', 40.00::numeric),
('representation_25_multi_line', '2641', 10.00::numeric),
('representation_25_multi_line', '2641', 15.00::numeric),
('representation_25_with_extra_vat', '6072', 100.00::numeric),
('representation_25_with_extra_vat', '2641', 25.00::numeric),
('representation_25_with_extra_vat', '2641', 20.00::numeric),
('representation_12', '6072', 100.00::numeric),
('representation_12', '2641', 12.00::numeric)
),
probe_context(probe, transaction_description, expected_result) as (
values
('hotel_on_5820', 'Scandic Stockholm', 'high_hotel_counterparty_on_car_hire_account'),
('car_hire_on_5820', 'Hertz rental car', 'manual_review_5820_no_corroborating_signal'),
('representation_25_multi_line', 'Customer dinner', 'high_vat_is_25pct_of_6072_cost'),
('representation_25_with_extra_vat', 'Mixed expense voucher', 'manual_review_6072_with_vat'),
('representation_12', 'Customer dinner', 'manual_review_6072_with_vat')
),
line_groups as (
select probe, account_number, sum(debit_amount) as debit_amount
from probe_lines
group by probe, account_number
(
'exact_hotel_template_shape',
'travel_hotel_5820', 'manual',
'high_hotel_counterparty_on_car_hire_account',
3, 0.12::numeric, false, false, 'confirmed_correction'
),
(
'car_hire_with_25pct_vat',
'travel_hotel_5820', 'manual',
'manual_review_5820_no_corroborating_signal',
3, 0.25::numeric, false, false, 'false_positive'
),
(
'hotel_shape_without_hotel_evidence',
'travel_hotel_5820', 'manual',
'medium_12pct_vat_on_car_hire_account',
3, 0.12::numeric, false, false, 'insufficient_evidence'
),
(
'imported_representation_signature',
'representation_25pct_vat', 'import',
'high_vat_is_25pct_of_6072_cost',
3, 0.25::numeric, false, false, 'false_positive'
),
(
'live_representation_without_underlag',
'representation_25pct_vat', 'manual',
'high_vat_is_25pct_of_6072_cost',
3, 0.25::numeric, false, false, 'insufficient_evidence'
),
(
'live_representation_with_25pct_underlag',
'representation_25pct_vat', 'manual',
'high_vat_is_25pct_of_6072_cost',
3, 0.25::numeric, false, true, 'false_positive'
),
(
'live_representation_with_12pct_vat',
'representation_25pct_vat', 'manual',
'manual_review_6072_with_vat',
3, 0.12::numeric, true, false, 'false_positive'
),
(
'mixed_representation_without_underlag',
'representation_25pct_vat', 'manual',
'manual_review_6072_with_vat',
4, 0.18::numeric, false, false, 'insufficient_evidence'
)
),
classified as (
select
context.probe,
context.expected_result,
probe.*,
case
when hotel.debit_amount is not null
and context.transaction_description ~* '(hotel|hotell|scandic|elite|best western|nordic choice|clarion|quality inn|radisson|booking\.com|airbnb|logi|övernattning)'
then 'high_hotel_counterparty_on_car_hire_account'
when hotel.debit_amount is not null
and abs(coalesce(vat.debit_amount, 0) - hotel.debit_amount * 0.12) < 0.02
then 'medium_12pct_vat_on_car_hire_account'
when hotel.debit_amount is not null
then 'manual_review_5820_no_corroborating_signal'
when representation.debit_amount is not null
and abs(coalesce(vat.debit_amount, 0) - representation.debit_amount * 0.25) < 0.02
then 'high_vat_is_25pct_of_6072_cost'
when representation.debit_amount is not null and vat.debit_amount is not null
then 'manual_review_6072_with_vat'
else 'absent'
end as actual_result
from probe_context context
left join line_groups hotel
on hotel.probe = context.probe and hotel.account_number = '5820'
left join line_groups representation
on representation.probe = context.probe and representation.account_number = '6072'
left join line_groups vat
on vat.probe = context.probe and vat.account_number = '2641'
when source_type in ('import', 'correction') then 'false_positive'
when defect = 'representation_25pct_vat'
and review_priority = 'high_vat_is_25pct_of_6072_cost'
and document_has_25pct_vat
and not document_has_12pct_vat
then 'false_positive'
when defect = 'representation_25pct_vat'
and review_priority = 'high_vat_is_25pct_of_6072_cost'
then 'insufficient_evidence'
when defect = 'representation_25pct_vat'
and observed_vat_rate between 0.119 and 0.121
then 'false_positive'
when defect = 'representation_25pct_vat'
and document_has_12pct_vat
and not document_has_25pct_vat
then 'false_positive'
when defect = 'representation_25pct_vat' then 'insufficient_evidence'
when defect = 'travel_hotel_5820'
and line_count = 3
and observed_vat_rate between 0.119 and 0.121
and review_priority = 'high_hotel_counterparty_on_car_hire_account'
then 'confirmed_correction'
when defect = 'travel_hotel_5820'
and line_count = 3
and observed_vat_rate between 0.119 and 0.121
then 'insufficient_evidence'
else 'false_positive'
end as actual_classification
from probes probe
)
select
probe,
expected_result,
actual_result,
actual_result = expected_result as passed
expected_classification,
actual_classification,
actual_classification = expected_classification as passed
from classified
order by probe;