PerformanceData
unknown
perl
a year ago
192 kB
6
Indexable
package Athena::P4P::App::PerformanceData;
use Athena::Policy;
use Athena::Conf::AthenaNet;
use Cache;
use Global;
use AthenaDate;
use Athena::Util::Database;
use Clinical::P4P::Provider;
use Clinical::P4P::Log;
use DateTime;
use Athena::P4P::Persistence::QPP;
use YAML::XS;
use Try::Tiny;
use Athena::Util::JSON;
use Athena::P4P::Persistence::QPP::API;
use Athena::Util::List qw(InList);
use Athena::P4P::App::Rolling90Days;
use SQL::Select;
# This constant hashref does not use the MIPS_[A-Z]+_PROGRAM_ID constants
# because we want to wean the code off of them. Ultimately this hashref
# will go away too when the program relationships can be queried from
# the database.
#
# DO NOT USE THIS CONSTANT DIRECTLY.
# Call the wrapper functions GetMIPSProgram, GetMIPSProgramList, GetMIPSProgramYearList,
# GetMIPSCategory, GetMIPSCategoryMap, GetMIPSProgramsByCategory, and GetMIPSEntityType instead.
use constant _MIPS_PROGRAM_DATA => {
2017 => {
ACI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Advancing Care Information (ACI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3876,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3119,
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3878,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3205,
}
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3880,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3152,
},
},
},
},
},
2018 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3877,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3791,
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3875,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3796,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 3879,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 3797,
},
},
},
},
},
2019 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4240,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4236,
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4237,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4219,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4194,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4238,
},
},
},
},
},
2020 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4704,
},
NINETYDAYS => {
P4PPROGRAMID => 5277,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4683,
},
NINETYDAYS => {
P4PPROGRAMID => 5278,
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4670,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4682,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4680,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4660,
},
},
},
},
},
2021 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5216,
},
NINETYDAYS => {
P4PPROGRAMID => "5617,5620,5621,5623",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5239,
},
NINETYDAYS => {
P4PPROGRAMID => "5618,5619,5622,5624",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5185,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5230,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5260,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5215,
},
},
},
},
},
2022 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5808,
},
NINETYDAYS => {
P4PPROGRAMID => "5907,5914,5919,5921,6400,6377,6265,6386,6398,6243,6403,6330,6342,6291,6339,6258,6379,6367,6415,6308,6407,6397,6418,6417,6387,6304,6358,6327,6279,6351,6277,6299,6406,6250,6337,6380,6354,6390,6378,6368,6385,6350,6347,6319,6315,6302,6411,6361,6284,6314,6375,6309,6324,6270,6345,6262,6261,6372,6248,6306,6249,6311,6334,6283,6329,6303,6266,6399,6323,6413,6384,6408,6335,6313,6281,6333,6297,6275,6253,6357,6370,6364,6376,6288,6289,6356,6414,6338,6272,6466,6463,6461,6464,6462,6460,6458,6465,6459,6467",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5803,
},
NINETYDAYS => {
P4PPROGRAMID => "5910,5912,5915,5920,6325,6402,6352,6343,6396,6305,6366,6293,6355,6241,6273,6381,6373,6238,6316,6260,6393,6296,6346,6320,6405,6383,6328,6295,6239,6344,6267,6278,6286,6395,6326,6412,6321,6401,6240,6294,6388,6245,6404,6301,6058,6256,6371,6242,6392,6287,6247,6391,6254,6389,6365,6282,6382,6349,6300,6257,6374,6331,6271,6362,6264,6360,6322,6276,6251,6274,6341,6318,6336,6268,6252,6246,6259,6394,6410,6363,6292,6263,6285,6409,6353,6280,6298,6269,6312,6244,6310,6416,6307,6359,6317,6255,6332,6369,6348,6290,6340",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5794,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5799,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 5821,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 5824,
},
},
},
},
},
2023 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6218,
},
NINETYDAYS => {
P4PPROGRAMID => "6099,6111,6140,6151,6659,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6191,
},
NINETYDAYS => {
P4PPROGRAMID => "6106,6135,6149,6213,6658,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6843,6892,6893,6894,6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6931,6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6838,6839,6840,6841,6920,6842,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6159,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6110,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6156,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6078,
},
},
},
},
},
2024 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6802,
},
NINETYDAYS => {
P4PPROGRAMID => "6786,6788,6739",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6728,
},
NINETYDAYS => {
P4PPROGRAMID => "6756,6758,6783",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6777,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6733,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 6730,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 6729,
},
},
},
},
},
2025 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 7566,
},
NINETYDAYS => {
P4PPROGRAMID => "7739,7740,7741",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 7576,
},
NINETYDAYS => {
P4PPROGRAMID => "7745,7746,7747",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 7598,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 7595,
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 7569,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 7568,
},
},
},
},
},
};
use constant _MVP_PROGRAM_DATA => {
2023 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6543,6590,6589",
},
NINETYDAYS => {
P4PPROGRAMID => "6548,6549,6550,6551,6570,6572,6575,6576,6571,6573,6574,6577",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6542,6587,6588",
},
NINETYDAYS => {
P4PPROGRAMID => "6544,6545,6546,6547,6578,6579,6582,6569,6591,6580,6581,6568",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6559,6562,6561"
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6558,6563,6560"
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6541,6567,6586",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6539,6566,6585",
},
},
},
},
},
2024 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6772,7464,7471,7478",
},
NINETYDAYS => {
P4PPROGRAMID => "6773,6774,6776",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6763,7459,7467,7475",
},
NINETYDAYS => {
P4PPROGRAMID => "6765,6767,6769",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6796,7399,7401,7403"
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6794,7398,7400,7402"
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "6798,7421,7423,7441",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "6797,7420,7422,7440",
},
},
},
},
},
2025 => {
PI => {
POSSIBLESCORE => 100,
DISPLAYTEXT => 'Promoting Interoperability (PI)',
DISPLAYORDER => 2,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "7579,7582,7586,7590",
},
NINETYDAYS => {
P4PPROGRAMID => "7748,7749,7719,7750,7720,7718,7721,7722",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "7567,7581,7585,7589",
},
NINETYDAYS => {
P4PPROGRAMID => "7755,7752,7754,7756,7751,7753,7757,7758",
},
},
},
},
IA => {
POSSIBLESCORE => 40,
DISPLAYTEXT => 'Improvement Activities (IA)',
DISPLAYORDER => 3,
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "7630,7621,7624,7628"
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "7627,7620,7626,7623"
},
},
},
},
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => "7602,7584,7573,7605",
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => "7601,7577,7572,7604",
},
},
},
},
},
};
use constant _MIPS_QUALITY_FOR_QMASS_PROGRAM_DATA => {
Quality => {
POSSIBLESCORE => 60,
DISPLAYTEXT => 'Quality',
DISPLAYORDER => 1,
SUBMISSONMETHODS => [qw( EHR REGISTRY )],
ENTITYTYPE => {
GROUP => {
FULLYEAR => {
P4PPROGRAMID => 4497,
},
},
INDIVIDUAL => {
FULLYEAR => {
P4PPROGRAMID => 4496,
},
},
},
},
};
# Both ACI and PI has to co exsist here as they are exclusively part or 2017 and 2018 program
use constant MIPS_CATEGORIES => {
Quality => 1,
ACI => 1,
IA => 1,
PI => 1,
};
use constant DIMENSIONS => [
{
FILTERKEY => 'year',
DISPLAYNAME => 'Year',
OPTIONS => sub {
my ($dbh) = @_;
return [
map {
{
OptionName => $_,
OptionID => $_,
}
} @{ GetMIPSProgramYearList($dbh) }
];
}
},
{
FILTERKEY => 'category',
DISPLAYNAME => 'Category',
OPTIONS => sub {
my ($dbh) = @_;
my @program_ids_by_category_year;
foreach my $year (@{ GetMIPSProgramYearList($dbh) }) {
my %program_ids_by_category = ();
foreach my $category (@{ _SupportedCategoriesForYear({
YEAR => $year,
}) }) {
my $program_ids = Athena::P4P::App::PerformanceData::GetMIPSProgramList($dbh, {
CATEGORY => $category,
YEARS => [$year],
});
if (! defined $program_ids_by_category{$category}) {
$program_ids_by_category{$category} = $program_ids;
}
else {
push @{ $program_ids_by_category{$category} }, @$program_ids;
}
}
push @program_ids_by_category_year, map {
{
Year => $year,
OptionName => $_,
OptionID => [ sort { $a <=> $b }
@{
$program_ids_by_category{$_}
}
],
}
} keys %program_ids_by_category;
}
return \@program_ids_by_category_year;
},
},
{
FILTERKEY => 'provider.npi',
DISPLAYNAME => 'Provider',
OPTIONS => sub {
my ($dbh) = @_;
return [ map {
{
OptionName => $_->{PROVIDERNAME},
OptionID => $_->{NPI},
}
} @{ Athena::P4P::App::PerformanceData::GetProviderDimensionValues($dbh) || [] } ];
},
},
{
FILTERKEY => 'provider.federalidnumber',
DISPLAYNAME => 'TIN',
OPTIONS => sub {
my ($dbh) = @_;
return [ map {
{
OptionName => $_->{NAME},
OptionID => $_->{FEDERALIDNUMBER},
}
} @{ Athena::P4P::App::PerformanceData::GetFederalIDNumberDimensionValues($dbh) || [] } ];
},
},
];
use constant DEFAULT_MAX_POINTS => 10;
use constant MAX_ROWS_TO_RETURN => 200;
use constant DEFAULT_ORDER_BY => [
{
SortKey => 'MEASUREPOINTS',
Direction => 'ASC',
},
];
# Both ACI and PI has to co exsist here as they are exclusively part or 2017 and 2018 program
use constant SUBMISSION_METHODS_FOR_PROGRAM => {
ACI => [],
IA => [],
PI => [],
Quality => [qw( EHR REGISTRY )],
};
# GetMIPSPerformanceData accepts a list of keys to order by; this hashref
# maps each key to the columns of p4pmeasureperformance that we should use
# order by when passed that key. Keys that correspond directly to columns
# of p4pmeasureperformance are not included here. See the block comment for
# GetMIPSPerformanceData for more details on sorting.
use constant SORT_KEYS_TO_COLUMNS => {
PROVIDERNAME => ['PROVIDERPLCLASTNAME', 'PROVIDERPLCFIRSTNAME'],
MEASUREPOINTS => ['WEIGHTEDMEASUREPOINTS'],
RELATIVEPERFORMANCE => ['RELATIVEPERFORMANCE'],
ROUNDEDPERCENTAGE => ['ROUNDEDPERFORMANCERATE'],
SORTEDNUMERATOR => ['SORTEDNUMERATOR'],
};
use constant UNIQUE_MEASURE_PERFORMANCE_COLUMNS => [qw(
P4PPROGRAMID
CRITERIACODE
NPI
PROVIDERID
FEDERALIDNUMBER
)];
use constant P4PMEASUREPERFORMANCE_COLUMNS => [qw(
PROVIDERID
FEDERALIDNUMBER
P4PPROGRAMID
P4PMEASUREID
P4PMEASURESUBSCRIPTIONID
NPI
CATEGORY
MEASURENAME
CRITERIACODE
PROVIDERPLCFIRSTNAME
PROVIDERPLCLASTNAME
DENOMINATOR
NUMERATOR
EXCLUDED
PERFORMANCERATE
ROUNDEDPERFORMANCERATE
WEIGHTEDMEASUREPOINTS
MAXPOINTS
DISPLAYPERFORMANCERATE
ISINVERSEMEASURE
PROGRAMKEY
STATUS
SUBGROUPID
)];
use Athena::P4P::App::ProgramDefinition;
use Athena::RolloutToggle;
use Athena::ServiceBus::Dispatcher;
use Athena::Util::Assert;
use Athena::Util::Hash;
use Athena::Util::List;
use Athena::Util::Text;
use Athena::Util::SQL qw( ProcessTable );
use Athena::Util::Hash qw( HashGroupBy );
use AthenaSecurity;
use Clinical::P4P::Attestation;
use Clinical::P4P::Blacklist;
use Clinical::P4P::Persistence::MultiProviderSubmission;
use Clinical::P4P::Persistence::ProgramSubmission;
use Clinical::P4P::ReportingPeriod;
use Clinical::P4P::Submission::MIPSACIModifiedStage2;
use Clinical::P4P::Submission::MIPSQuality;
use Clinical::P4P::Submission::Utils::MIPSSnapshotAssessment;
use Athena::P4P::Persistence::ProgramEligibility;
use Clinical::P4P::Utils;
use Clinical::P4P::Utils::Practice;
use Clinical::P4P::Submission;
use Global;
use List::AllUtils;
use List::Util;
use List::Util qw(max min);
use SQL::Select;
use SQL;
################################################################################
# GetDimensions
#
# Description:
# Get a list of supported dimensions.
#
# Return Value:
# Reference to a list of hashrefs with the following keys:
#
# DisplayName - String, the name of the dimension to be displayed in the UI.
# FilterKey - String representing the dimension.
################################################################################
sub GetDimensions {
return [ map {
{
DisplayName => $_->{DISPLAYNAME},
FilterKey => $_->{FILTERKEY},
}
} @{ DIMENSIONS() } ];
}
###############################################################################
# GetDimensionValues
#
# Description:
# Retrieve the option values for the various filters supported by the MIPS
# dashboard.
#
# Parameters:
# Required:
# FILTERKEY String
#
# Returns:
# Dies if passed an unrecognized FILTERKEY, otherwise returns a listref of
# hashrefs each with the following keys:
# FilterKey
# OptionName
# OptionID
###############################################################################
sub GetDimensionValues {
my ($dbh, $args) = @_;
my $filter_key = $args->{FILTERKEY};
my ($dimension) = grep { $filter_key eq $_->{FILTERKEY} } @{ DIMENSIONS() };
unless ($dimension) {
die "$filter_key is an unrecognized filter type";
}
my $options_spec = $dimension->{OPTIONS};
# The OPTIONS key may be a subroutine reference or a value.
# Return the result of the subroutine or the value as
# appropriate.
my $options = (ref $options_spec eq 'CODE')
? $options_spec->($dbh)
: $options_spec;
return [ map { {
FilterKey => $filter_key,
%{ $_ },
} } @$options ];
}
###############################################################################
# GetMIPSProgramYearList
#
# Description:
# Retrieve the valid MIPS program years supported by the MIPS dashboard.
#
# Parameters:
# Required:
# None.
# Optional:
# None.
#
# Returns:
# An arrayref of program years (e.g., [2017, 2018]).
###############################################################################
sub GetMIPSProgramYearList {
my ($dbh, $is_mvp) = @_;
# TODO: Use a query to get the program years.
my @program_years;
my $render_2025_dropdown = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CLQI_6580_2025_YOY_ROLLOVER',
USERNAME => $Global::session{USERNAME},
}) eq 'ON';
if ($render_2025_dropdown) {
if($is_mvp) {
@program_years = reverse sort { $a <=> $b } keys %{ _MVP_PROGRAM_DATA() };
}
else {
@program_years = reverse sort { $a <=> $b } keys %{ _MIPS_PROGRAM_DATA() };
}
}
else {
my %programdata = %{_MIPS_PROGRAM_DATA()};
delete $programdata{'2025'};
@program_years = reverse sort { $a <=> $b } keys %programdata;
}
return \@program_years;
}
###############################################################################
# GetProviderDimensionValues
#
# Description:
# Gets values for the Provider filter for the MIPS dashboard.
#
# Parameters:
# Required:
# None.
# Optional:
# YEARS ArrayRef A list of MIPS program years. Defaults to [2017].
# ENTITYTYPES ArrayRef A list of entity types: INDIVIDUAL, GROUP, or both.
# Defaults to ['INDIVIDUAL'].
#
# Returns:
# Listref of hashrefs each with the following keys
# NPI
# PROVIDERNAME
###############################################################################
sub GetProviderDimensionValues {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
YEARS
ENTITYTYPES
)],
);
my $entity_types = $args->{ENTITYTYPES} // ['INDIVIDUAL'];
my $providersql = Clinical::P4P::Persistence::MultiProviderSubmission->ProvidersWithDenormalizedDataSQL({
# Should be the same list of providers in all three programs.
P4PPROGRAMIDS => GetMIPSProgramList($dbh, {
ENTITYTYPES => $entity_types,
}),
INCLUDEFEDERALIDNUMBERS => 1,
});
my $npicategoryid = BusCall::Provider::GetProviderNumberCategoryID($dbh, {
KEY => 'NPI',
});
my @dimensionvalues = SQL::Select->new(
)->SelectAndGroupBy(
"provider.id providerid",
"providerswithdata.federalidnumber",
"providernumber.providernumber npi",
"provider.plclastname || ', ' || provider.plcfirstname providername",
)->From(
["(??) providerswithdata", $providersql],
"provider",
"providernumber",
)->Joins(
"providerswithdata.providerid = provider.id",
"providernumber.providerid = provider.id",
)->Where(
"provider.deleted is null",
"providernumber.deleted is null",
["providernumber.providernumbercategoryid = ?", $npicategoryid],
)->TableHash($dbh);
my $isenabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_REPRESENTATIVE_PROVIDER_LOGIC_UPDATE',
}) eq 'ON';
if ($isenabled) {
@dimensionvalues = @{Athena::P4P::App::PerformanceData::GetRepresentativeProviderNameBasedClinicalEncouterY($dbh,{
DATAS => \@dimensionvalues,
})};
}
# Add option for all providers
unshift @dimensionvalues, {
NPI => 'TINONLY',
PROVIDERNAME => 'All',
};
return \@dimensionvalues;
}
################################################################################
# GetMIPSCategoryDataModels
#
# Description:
# Builds data models for MIPS category scores shown in the MIPS dashboard.
#
# Parameters:
# YEARS - ArrayRef of Program years
# CATEGORYSCORES (optional) - ArrayRef of category score data.
#
# Returns:
# Ordered ArrayRef of HashRefs containing
# CATEGORY (String)
# DISPLAYTEXT (String)
# DISPLAYORDER (Integer)
# P4PPROGRAMID (Integer)
# POSSIBLESCORE (Integer)
# SCORE (optional) (Number)
# FINALSCORE (optional) (Number)
# SCALEDSCORE (optional) (Number)
# REPORTINGPERIOD (optional) (string)
################################################################################
sub GetMIPSCategoryDataModels {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
YEARS
)],
[qw(
CATEGORYSCORES
FEDERALIDNUMBER
P4PPROGRAMIDS
PROVIDERID
)],
);
my $years = $args->{YEARS};
my $category_scores = $args->{CATEGORYSCORES};
# For now we only support a single year at a time. We may need to figure
# this out once we decide how we are handling multiple-years on the front-end.
my $year = $years->[0];
# Build array of category data for given year
my $program_year_data = _MIPS_PROGRAM_DATA()->{$year};
my @category_data = map {
{
POSSIBLESCORE => $program_year_data->{$_}->{POSSIBLESCORE},
DISPLAYTEXT => $program_year_data->{$_}->{DISPLAYTEXT},
DISPLAYORDER => $program_year_data->{$_}->{DISPLAYORDER},
CATEGORY => $_,
SCORE => undef,
SCALEDSCORE => undef,
SCOREPREVIEWATHENA => undef,
P4PPROGRAMID => undef,
REPORTINGPERIOD => undef,
};
} keys %$program_year_data;
# Build a map for easier lookup
my %score_data = map {
$_->{CATEGORY} => $_,
} @$category_scores;
# Merge scores into category data
my $enabledversion = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DISPLAY_MAX_SCORES_FROM_CMS',
}) eq 'ON';
if($enabledversion) {
@category_data = map {
my $scores = $score_data{$_->{CATEGORY}} // {};
my $model = {
%{ $_ },
SCORE => $scores->{SCORE},
FINALSCORE => $scores->{FINALSCORE},
SCALEDSCORE => $scores->{SCALEDSCORE},
SCOREPREVIEWATHENA => $scores->{SCOREPREVIEWATHENA},
P4PPROGRAMID => $scores->{P4PPROGRAMID},
};
my $possiblescore;
if ($scores->{WEIGHT} ne undef) {
$possiblescore = $scores->{WEIGHT};
} elsif($_->{CATEGORY} eq 'IA') {
$possiblescore = 15;
}elsif($_->{CATEGORY} eq 'Quality' ) {
if($year >= 2022) {
$possiblescore = 30;
} elsif($year >= 2021) {
$possiblescore = 40;
} else {
$possiblescore = 45;
}
} else {
$possiblescore = 25;
}
$model->{POSSIBLESCORE} = $possiblescore;
$model;
} @category_data;
} else {
@category_data = map {
my $scores = $score_data{$_->{CATEGORY}} // {};
my $model = {
%{ $_ },
SCORE => $scores->{SCORE},
FINALSCORE => $scores->{FINALSCORE},
SCALEDSCORE => $scores->{SCALEDSCORE},
SCOREPREVIEWATHENA => $scores->{SCOREPREVIEWATHENA},
P4PPROGRAMID => $scores->{P4PPROGRAMID},
};
$model;
} @category_data;
}
# CLQI-4516 from 2022 program years, Display Reporting Period for MIPS PI
if ($year >= 2022) {
foreach my $categorydata (@category_data) {
if ($categorydata->{CATEGORY} eq 'PI') {
# Use Enrolled PI program to fetch Reporting period, if Category score detail not
# have program id.
if ($categorydata->{P4PPROGRAMID} eq '') {
my $enrolled_program_list = Athena::P4P::App::PerformanceData::GetEnrolledPrograms($dbh, {
P4PPROGRAMIDS => $args->{P4PPROGRAMIDS},
PROVIDERID => $args->{PROVIDERID},
FEDERALIDNUMBER =>$args->{FEDERALIDNUMBER},
});
foreach my $enrolledprogram (@{$enrolled_program_list}) {
if(Athena::P4P::App::PerformanceData::GetMIPSCategory($dbh, $enrolledprogram->{P4PPROGRAMID}) eq 'PI') {
$categorydata->{P4PPROGRAMID} = $enrolledprogram->{P4PPROGRAMID};
last;
}
}
}
if ($categorydata->{P4PPROGRAMID} ne '') {
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => $categorydata->{P4PPROGRAMID},
});
my $startdate = AthenaDate::FormatDate($reporting_period->{PROGRAMSTART}, 'mm-dd-yyyy');
my $enddate = AthenaDate::FormatDate($reporting_period->{PROGRAMEND}, 'mm-dd-yyyy');
$categorydata->{REPORTINGPERIOD} = " : $startdate to $enddate";
}
$categorydata->{PIREQUIREMENT} = '';
if ($categorydata->{P4PPROGRAMID} ne '') {
my $registry_requirement_not_met = _GetPHRStatusForPIRequirementAlert($dbh, {
FEDERALIDNUMBER => $args->{FEDERALIDNUMBER},
P4PPROGRAMID => $categorydata->{P4PPROGRAMID},
PROVIDERID => $args->{PROVIDERID},
});
$categorydata->{PIREQUIREMENT} = "UNMET" if ($registry_requirement_not_met);
}
}
}
}
return \@category_data;
}
###############################################################################
# _GetPHRStatusForPIRequirementAlert
#
# Description:
# Checks whether Immunization Registry and Electronic Case Registry has been
# satisfied or not for a given entity, based on that, PI Requirement UnMet
# popup will be displayed in MIPS dashboard.
#
# Parameters:
# Required:
# FEDERALIDNUMBER - TIN of the provider for whom to request details.
# P4PPROGRAMID - P4P Program ID.
# Optional:
# PROVIDERID - ID of provider to request details for.
#
# Returns:
# Boolean: 0 or 1.
###############################################################################
sub _GetPHRStatusForPIRequirementAlert {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
FEDERALIDNUMBER
P4PPROGRAMID
)],
[qw(
PROVIDERID
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $provider_id = $args->{PROVIDERID};
my @phrregistries = ('Immunization Registry', 'Electronic Case Registry Reporting');
my $phrregistrysatisfactionstatussql = SQL::Select->new(
)->Select(
"p4pmeasureperformance.measurename",
"p4pmeasureperformance.status",
)->From(
"p4pmeasureperformance",
)->Where(
"p4pmeasureperformance.deleted is null",
["p4pmeasureperformance.federalidnumber = ?", $federal_id_number],
["p4pmeasureperformance.p4pprogramid = ?", $p4p_program_id],
["p4pmeasureperformance.measurename in (??)", \@phrregistries]
);
if ($provider_id) {
$phrregistrysatisfactionstatussql->Where(
["p4pmeasureperformance.providerid = ?", $provider_id],
);
}
my @phrresgistrysatisfactionstatus = $phrregistrysatisfactionstatussql->TableHash($dbh);
my %registrysatisfactionstatus;
foreach my $measure (@phrresgistrysatisfactionstatus) {
$registrysatisfactionstatus{$measure->{MEASURENAME}} = $measure->{STATUS};
}
if (($registrysatisfactionstatus{'Immunization Registry'} eq 'Satisfied' ||
$registrysatisfactionstatus{'Immunization Registry'} eq 'Excluded')
&& ($registrysatisfactionstatus{'Electronic Case Registry Reporting'} eq 'Satisfied'
|| $registrysatisfactionstatus{'Electronic Case Registry Reporting'} eq 'Excluded')
) {
return 0;
}
return 1;
}
###############################################################################
# GetReportCardDetails
#
# Description:
# Gets performance details for the MIPS dashboard based on the selected provider/TIN.
#
# Parameters:
# Required:
# FEDERALIDNUMBER - TIN of the provider for whom to request details.
# YEARS - ArrayRef of MIPS program years.
# Optional:
# PROVIDERID - ID of provider to request details for.
#
# Returns:
# HashRef containing the following keys:
#
# PROVIDERNAME - String - the name of the provider, per the Provider Subsystem
# or
# MEDICALGROUPNAME - String - name of the medical group.
#
# COMPOSITEPERFORMANCESCORE - Integer - the CPS of the provider, per CMS
# FINALCOMPOSITEPERFORMANCESCORE - Integer - the final, post submission,
# CPS of the provider, per CMS.
#
# CATEGORYSCORES - Arrayref of hashrefs - score data for each category.
# CATEGORY (String)
# DISPLAYTEXT (String)
# DISPLAYORDER (Integer)
# P4PPROGRAMID (Integer)
# POSSIBLESCORE (Integer)
# SCORE (optional) (Number)
# FINALSCORE (optional) (Number) - final score for the category after submission.
# SCALEDSCORE (optional) (Number)
###############################################################################
sub GetReportCardDetails {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
FEDERALIDNUMBER
YEARS
)],
[qw(
PROVIDERID
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $years = $args->{YEARS};
my $entity_types = $args->{PROVIDERID} ? ['INDIVIDUAL'] : ['GROUP'];
my $provider_name;
my $medical_group_name;
if (
$provider_id
) {
# Pull the provider name from the Provider subsystem
my $isenabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_REPRESENTATIVE_PROVIDER_LOGIC_UPDATE',
}) eq 'ON';
if ($isenabled) {
$provider_name = Clinical::P4P::Utils::GetMIPSProviderName($dbh, {
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
YEAR => $years->[0],
});
}
else {
$provider_name = BusCall::Provider::GetProviderName($dbh, {
PROVIDERID => $provider_id,
});
}
}
else {
$medical_group_name = Clinical::P4P::Utils::Practice::GetMedicalGroupNameByTIN($dbh, {
FEDERALIDNUMBER => $federal_id_number,
});
}
my $p4p_program_ids = GetMIPSProgramList($dbh, {
YEARS => $years,
ENTITYTYPES => $entity_types,
});
# Pull the composite performance score from CMS
my @performance_score_data = @{Clinical::P4P::Persistence::ProgramSubmission::GetPerformanceScores($dbh, {
# In the future, we may want to pass this list of program ids through from the front
# end, once the MIPS Dashboard will need to represent 2017 or 2018
P4PPROGRAMIDS => $p4p_program_ids,
# Limit to just this provider/TIN
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
})};
my $composite_performance_score;
my $final_composite_performance_score;
my $score_updated_date;
my $category_score_list;
my $error_msg;
my $bonus_points;
my $max_total_score;
my $score_preview_athena;
if (scalar @performance_score_data > 0) {
$composite_performance_score = $performance_score_data[0]->{COMPOSITESCORE};
$final_composite_performance_score = $performance_score_data[0]->{FINALCOMPOSITESCORE};
$score_updated_date = $performance_score_data[0]->{SCOREDATETIME};
$category_score_list = $performance_score_data[0]->{CATEGORYSCORES};
$error_msg = $performance_score_data[0]->{ERRORMESSAGE};
$bonus_points = $performance_score_data[0]->{BONUSPOINTS};
$max_total_score = $performance_score_data[0]->{MAXTOTALSCORE};
$score_preview_athena = $performance_score_data[0]->{SCOREPREVIEWATHENA};
}
my $category_data = GetMIPSCategoryDataModels($dbh,{
YEARS => $years,
CATEGORYSCORES => $category_score_list,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMIDS => $p4p_program_ids
});
my $show_mips_internal_scoring_legend = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_INTERNAL_SCORING',
USERNAME => $Global::session{USERNAME},
}) eq 'ON';
my $shouldshowqrdaimportmessage = _GetMIPSMessageForQRDA1Import($dbh,{
FEDERALIDNUMBER => $federal_id_number,
YEARS => $years,
PROVIDERID => $provider_id,
});
my @results;
my $show_mips_eligibility_info = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'ELIGIBILITY_INFO_MIPS_DASHBOARD',
}) eq 'ON';
if($show_mips_eligibility_info) {
my $eligibilitystatussql = Athena::P4P::Persistence::ProgramEligibility::GetMIPSEligibilityStatus($dbh,{
FEDERALIDNUMBER => $federal_id_number,
YEAR => $years->[0],
PROVIDERID => $provider_id,
});
@results = $eligibilitystatussql->TableHash($dbh);
}
my $is_small_practice_enabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CLQI_6298_SMALL_PRACTICE_MIPS',
}) eq 'ON';
my $small_practicioner_value;
if($is_small_practice_enabled && (scalar @performance_score_data > 0) && $years->[0] >= 2024) {
$small_practicioner_value = $performance_score_data[0]->{ISSMALLPRACTICEELIGIBLE} ne undef && $performance_score_data[0]->{ISSMALLPRACTICEELIGIBLE} eq '1' ? 'Y' : 'N';
}
my $show_tinor_subid_mipsdb = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DB_TINOR_SUBID_DPLY',
}) eq 'ON';
my $tinoverrideapplicable = 'false';
my $tinoverride;
my $qppsubmissionid;
if($show_tinor_subid_mipsdb) {
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => @$p4p_program_ids[0],
});
$tinoverride = Athena::P4P::Persistence::QPP::GetTINOverride($dbh, {
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
EFFECTIVEDATE => $reporting_period->SubmissionEnd(),
});
$tinoverrideapplicable = $tinoverride == $federal_id_number ? 'false' : 'true';
my $program_submission = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => @$p4p_program_ids[0],
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
# The submission number (while often 1) is used for things below
my $submission_number = $program_submission->CurrentSubmissionNumber() || 1;
my @qpp_submissions = Athena::P4P::Persistence::QPP::GetQPPSubmissions($dbh, {
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
PROGRAMYEAR => $reporting_period->ProgramYear(),
SUBMISSIONNUMBER => $submission_number,
REQUESTTYPE => 'FINALSCORING',
STATUS => 'SUCCESS',
});
if($qpp_submissions[0] != undef) {
$qppsubmissionid = $qpp_submissions[0]->{QPPSUBMISSIONID};
}
}
#submission status
my $submission_status = undef;
my $programinfo;
my $currentdate = AthenaDate::AthenaToday();
my $submissionwindowended = 0;
my $submission_status_substate = undef;
my $programs = Clinical::P4P::Utils::GetProgramInfo($dbh);
if ( ($programs->{@$p4p_program_ids[0]}))
{
$programinfo = $programs->{@$p4p_program_ids[0]};
$submissionwindowended = AthenaDate::Date1IsLaterThanDate2($currentdate, AthenaDate::AddDays($programinfo->{REPORTINGPERIODEND} , $programinfo->{SUBMISSIONWINDOW}));
}
$submission_status_substate = GetSubmissionStatus($dbh, {
P4PPROGRAMID => @$p4p_program_ids[0],
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
});
$submission_status = 'Processing';
# if qpp id is available it means submission is successful
# qpp id can be there for Unknown status as we submit only Quality EHR
my $isallcategorysubmitted = IsAllMIPSCategerorySubmitted($dbh, {
P4PPROGRAMID => @$p4p_program_ids[0],
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
});
if($qppsubmissionid && $isallcategorysubmitted) {
#check if all categories are submitted
if($isallcategorysubmitted) {
$submission_status = 'Submitted';
}
}
if(!$isallcategorysubmitted) {
if(!$submissionwindowended) {
if($submission_status_substate eq 'UNKNOWN_ELIGIBILITY_STATUS' || $submission_status_substate eq 'NOT_OPTED_IN_ELIGIBILITY_STATUS'
|| $submission_status_substate eq 'COMPOSITE_SCORE_THRESHOLD' || $submission_status_substate eq 'NPI_TIN_MISMATCH_ELIGIBILITY_STATUS'
|| $submission_status_substate eq 'INELIGIBLE_ELIGIBILITY_STATUS') {
$submission_status = 'Pending Action';
}
}
#outside submission window
else{
if($submission_status_substate eq 'UNKNOWN_ELIGIBILITY_STATUS' || $submission_status_substate eq 'NOT_OPTED_IN_ELIGIBILITY_STATUS'
|| $submission_status_substate eq 'NPI_TIN_MISMATCH_ELIGIBILITY_STATUS' || $submission_status_substate eq 'INELIGIBLE_ELIGIBILITY_STATUS') {
$submission_status = 'Requirement unmet';
}
elsif($submission_status_substate eq 'COMPOSITE_SCORE_THRESHOLD') {
$submission_status = 'Not Submitted';
}
}
}
if($years->[0] >= 2023 && $qppsubmissionid && $error_msg ne undef && scalar @$error_msg > 0){
$submission_status = 'Submission Failed';
}
return {
( $provider_name
? ( PROVIDERNAME => $provider_name )
: ()
),
( $medical_group_name
? ( MEDICALGROUPNAME => $medical_group_name )
: ()
),
COMPOSITEPERFORMANCESCORE => $composite_performance_score,
FINALCOMPOSITEPERFORMANCESCORE => $final_composite_performance_score,
# DateTime String in iso8601
SCORELASTUPDATED => $score_updated_date,
# Send back an array so that the front end is certain an array exists
CATEGORYSCORES => $category_data,
SHOULDSHOWQRDAIMPORTMESSAGE => ($shouldshowqrdaimportmessage)?'true':'false',
SHOULDSHOWSMALLPRACTICEMESSAGE => ($is_small_practice_enabled) && $small_practicioner_value eq 'Y' ? 'true' : 'false',
ERRORMESSAGE => $error_msg,
BONUSPOINTS => $bonus_points ? $bonus_points : undef,
MAXTOTALSCORE => $max_total_score,
SCOREPREVIEWATHENA => $score_preview_athena,
ELIGIBILITY => $results[0]->{MIPSELIGIBILITYSTATUS},
ELIGIBILITYSTATUSOVERRIDDEN => $results[0]->{ELIGIBILITYSTATUSOVERRIDDEN},
YEAR => $years->[0],
SHOWMIPSINTERNALSCORINGLEGEND => ( $show_mips_internal_scoring_legend ) ? 'true' : 'false',
SHOWTINOVERRIDEMESSAGE => $tinoverrideapplicable,
TINOVERRIDE => $tinoverride,
QPPSUBMISSIONID => $qppsubmissionid,
SUBMISSIONSTATUS => $submission_status,
SUBMISSIONSTATUSSUBSTATE => $submission_status_substate,
SHOWQPPSCORESTATUSMESSAGE => _CheckFinalScoringStatus({FINALCOMPOSITEPERFORMANCESCORE => $final_composite_performance_score,
CATEGORYSCORES => $category_data,
QPPSUBMISSIONID => $qppsubmissionid,
SUBMISSIONSTATUS => $submission_status,
PROGRAMYEAR => $years->[0]})
};
}
###############################################################################
# GetSmallPracticeData
#
# Description:
# Gets the small practice details for the MIPS dashboard/ QPP Scoring based on the selected provider/TIN.
#
# Parameters:
# Required:
# FEDERALIDNUMBER - TIN of the provider for whom to request details.
# YEARS - ArrayRef of MIPS program years.
# Optional:
# PROVIDERID - ID of provider to request details for.
#
# Returns:
# HashRef containing the following keys:
#
# boolean flag
###############################################################################
sub GetSmallPracticeData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
FEDERALIDNUMBER
YEAR
P4PPROGRAMID
)],
[qw(
PROVIDERID
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $year = $args->{YEAR};
my $p4pprogramid = $args->{P4PPROGRAMID};
my $eligibilitystatussql = Athena::P4P::Persistence::ProgramEligibility::GetSmallPracticeTableData($dbh,{
FEDERALIDNUMBER => $federal_id_number,
YEAR => $year,
PROVIDERID => $provider_id,
});
my @small_practicioner_value = $eligibilitystatussql->TableHash($dbh);
if (scalar @small_practicioner_value < 1) {
return 'N';
}
if ($provider_id eq undef) {
my @claimbasedproviders = @{Clinical::P4P::Utils::GetClaimBasedLogic($dbh, {P4PPROGRAMID => $p4pprogramid})->{$federal_id_number} || []};
if (scalar @claimbasedproviders > 15 || scalar @claimbasedproviders == 0) {
return 'N';
}
else {
foreach my $claimbasedprovider(@claimbasedproviders) {
if (scalar (grep {($_->{GROUPSMALLGROUPPRACTITIONERYN} eq undef || $_->{GROUPSMALLGROUPPRACTITIONERYN} eq 'N') && $_->{PROVIDERID} eq $claimbasedprovider} @small_practicioner_value) > 0 ) {
return 'N';
}
}
}
return 'Y';
}
else {
return $small_practicioner_value[0]->{INDIVSMALLGROUPPRACTITIONERYN} eq undef ? 'N' : $small_practicioner_value[0]->{INDIVSMALLGROUPPRACTITIONERYN};
}
}
sub _CheckFinalScoringStatus {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
PROGRAMYEAR
FINALCOMPOSITEPERFORMANCESCORE
QPPSUBMISSIONID
SUBMISSIONSTATUS
CATEGORYSCORES
)],
);
my $final_composite_performance_score = $args->{FINALCOMPOSITEPERFORMANCESCORE};
my $category_data = $args->{CATEGORYSCORES};
my $year = $args->{PROGRAMYEAR};
my $qppsubmissionid = $args->{QPPSUBMISSIONID};
my $submission_status = $args->{SUBMISSIONSTATUS};
my $showbanner = 'false';
my $finalscore = 'false';
if($category_data ne undef){
foreach my $category (@$category_data) {
if($category->{FINALSCORE} ne undef){
$finalscore = 'true';
}
}
}
if($submission_status eq 'Submission Failed'){
return 'true';
}
if($year >= 2023 && $qppsubmissionid ne undef
&& $final_composite_performance_score eq undef && $finalscore eq 'true'){
return 'true';
}
return $showbanner;
}
###############################################################################
# GetFederalIDNumberDimensionValues
#
# Description:
# Retrieve the values for the TIN filter for the MIPS dashbaord.
#
# Parameters:
# Required:
# None.
# Optional:
# YEARS ArrayRef A list of MIPS program years. Defaults to [2017].
# ENTITYTYPES ArrayRef A list of entity types: INDIVIDUAL, GROUP, or both.
# Defaults to ['INDIVIDUAL'].
# Returns:
# Listref of hashrefs each with the following keys
# FEDERALIDNUMBER
# NAME
###############################################################################
sub GetFederalIDNumberDimensionValues {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
YEARS
ENTITYTYPES
)],
);
my $entity_types = $args->{ENTITYTYPES} // ['INDIVIDUAL'];
my $providersql = Clinical::P4P::Persistence::MultiProviderSubmission->ProvidersWithDenormalizedDataSQL({
INCLUDEFEDERALIDNUMBERS => 1,
# Should be the same list of providers in all three programs.
P4PPROGRAMIDS => GetMIPSProgramList($dbh, {
ENTITYTYPES => $entity_types,
}),
});
my @dimensionvalues = SQL::Select->new(
)->SelectAndGroupBy(
"providerswithdata.federalidnumber",
"providerswithdata.federalidnumber as name",
)->From(
["(??) providerswithdata", $providersql],
)->TableHash($dbh);
return \@dimensionvalues;
}
###############################################################################
# GetMIPSPerformanceData
#
# Description:
# Retrieves measure-level aggregated performance data for the MIPS program.
#
# Parameters:
# Required:
# None.
# Optional:
# ORDERBY Arrayref Sort the results by the following keys. Keys can either be
# directly column names in p4pmeasureperformance, or keys of
# SORT_KEYS_TO_COLUMNS() which maps keys to column names in
# p4pmeasureperformance.
# FEDERALIDNUMBERS Arrayref Only retrieve data related to these TINs
# NPIS Arrayref Only retrieve data for providers with these NPIs
# P4PPROGRAMIDS Arrayref Only retrieve data related to these programs.
# NOROWLIMIT Boolean Don't limit the returned results to MAX_ROWS_TO_RETURN() rows
# YEARS Arrayref The MIPS program years that apply. Defaults to [2017].
# ENTITYTYPES Arrayref A list containing INDIVIDUAL, GROUP, or both. Defaults to ['INDIVIDUAL'].
#
# Returns:
# Listref of hashrefs each with the following keys
# CATEGORY
# DENOMINATOR
# EXCLUDED
# FEDERALIDNUMBER
# MEASURENAME
# NUMERATOR
# PERFORMANCERATE
# PROVIDERID
# PROVIDERNAME
###############################################################################
sub GetMIPSPerformanceData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
FEDERALIDNUMBERS
NOROWLIMIT
NPIS
ORDERBY
P4PPROGRAMIDS
YEARS
ENTITYTYPES
)],
);
my $no_row_limit = $args->{NOROWLIMIT};
my $years = $args->{YEARS} // [2017];
my $entity_types = $args->{ENTITYTYPES} // ['INDIVIDUAL', 'GROUP'];
my $federal_id_numbers = $args->{FEDERALIDNUMBERS};
# Get programids for current filters
my $filtered_program_ids = GetMIPSProgramList($dbh, {
YEARS => $years,
ENTITYTYPES => $entity_types,
FEDERALIDNUMBERS => $federal_id_numbers,
});
# If program ids were passed in, we want to filter them based on our list of
# program ids already filtered by other args (years, entity types, tins)
if($args->{P4PPROGRAMIDS}) {
$filtered_program_ids = [ Athena::Util::List::GetIntersection(
$args->{P4PPROGRAMIDS},
$filtered_program_ids
) ];
}
my $sql_args = Athena::Util::Hash::HashSlice($args,
[qw(
FEDERALIDNUMBERS
NPIS
ORDERBY
)]
);
$sql_args->{P4PPROGRAMIDS} = $filtered_program_ids;
my $sql = _MIPSPerformanceDataSQL($dbh, $sql_args);
if (!$no_row_limit) {
$sql = SQL::Select->Limit($sql, MAX_ROWS_TO_RETURN());
}
my @data = $sql->TableHash($dbh);
my $resultdata;
my $isenabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_REPRESENTATIVE_PROVIDER_LOGIC_UPDATE',
}) eq 'ON';
if ($isenabled && scalar @data > 0) {
$resultdata = Athena::P4P::App::PerformanceData::GetRepresentativeProviderNameBasedClinicalEncouterY($dbh, {
DATAS => \@data,
YEAR => $years->[0],
});
return $resultdata;
}
else {
return \@data;
}
}
###############################################################################
# GetMIPSPerformanceDataWithRowCount
#
# Description:
# Retrieves measure-level aggregated performance data for the MIPS program along
# with a boolean indicating whether or not more rows exist.
#
# Parameters:
# Required:
# None.
# Optional:
# ORDERBY Listref Sort the results by the following columns
# FEDERALIDNUMBERS Listref Only retrieve data related to these TINs
# NPIS Listref Only retrieve data for providers with these NPIs
# P4PPROGRAMIDS Listref Only retrieve data related to these programs.
# YEARS Listref Only retrieve data related to these program years.
#
# Returns:
# Hashref with the following keys
# DATA Listref See GetMIPSPerformanceData
# HASMORERESULTS Boolean
###############################################################################
sub GetMIPSPerformanceDataWithRowCount {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
FEDERALIDNUMBERS
NPIS
ORDERBY
P4PPROGRAMIDS
YEARS
)],
);
my $p4p_program_ids = $args->{P4PPROGRAMIDS};
my $years = $args->{YEARS};
my $federal_id_numbers = $args->{FEDERALIDNUMBERS};
my $npis = $args->{NPIS};
my @results = @{ GetMIPSPerformanceData($dbh, $args) || [] };
my $row_count;
if (@results >= MAX_ROWS_TO_RETURN()) {
# Get program ids associated with the specified year.
$p4p_program_ids ||= GetMIPSProgramList($dbh, {
YEARS => $years,
FEDERALIDNUMBERS => $federal_id_numbers,
});
$row_count = _GetMIPSPerformanceDataRowCount($dbh, {
NPIS => $npis,
FEDERALIDNUMBERS => $federal_id_numbers,
P4PPROGRAMIDS => $p4p_program_ids,
});
}
@results = @{_AddReferenceMeasureNameForIA($dbh, {DATA=>\@results})} if grep { $_->{CATEGORY} eq 'IA' } @results;
my $enabledversion = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DASHBOARD_RELATIVE_PERFORMANCE',
}) eq 'ON';
return {
DATA => \@results,
MIPSDASHBOARDRELATIVEPERFORMANCE => $enabledversion,
HASMORERESULTS => $row_count > MAX_ROWS_TO_RETURN(),
};
}
################################################################################
# _MIPSPerformanceDataSQL
#
# Description:
# Version 2 of this function. Meant to improve performance by querying denormalized
# table.
# Generate SQL for MIPS measure performance data.
#
# Parameters:
# A reference to a hash of parameters:
#
# Required:
# P4PPROGRAMIDS - Listref, only retrieve data related to these programs.
#
# Optional:
# ORDERBY - Listref, order the results by the following columns in the
# specified order.
#
# FEDERALIDNUMBERS - Listref, only retrieve data related to these TINs.
#
# NPIS - Listref, only retrieve data for providers with these
# NPIs. TINONLY is a special value, and will filter
# down to TIN enrollments.
#
# Return Value:
# A SQL::Select object representing the query.
################################################################################
sub _MIPSPerformanceDataSQL {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMIDS
)],
[qw(
FEDERALIDNUMBERS
NPIS
ORDERBY
P4PPROGRAMIDS
)],
);
my @orderby = @{ $args->{ORDERBY} || DEFAULT_ORDER_BY() };
my $federalidnumbers = $args->{FEDERALIDNUMBERS};
my $npis = $args->{NPIS};
my $p4pprogramids = $args->{P4PPROGRAMIDS};
my $relativeperformanceenabledversion = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DASHBOARD_RELATIVE_PERFORMANCE',
}) eq 'ON';
my @orderbysql;
foreach my $orderby (@orderby) {
my $sortkey = $orderby->{SortKey};
my $direction = $orderby->{Direction};
my @columns = @{ SORT_KEYS_TO_COLUMNS()->{$sortkey} || [$sortkey] };
if($relativeperformanceenabledversion) {
push @orderbysql, (map { if ($_ ne 'SORTEDNUMERATOR' && $_ ne 'RELATIVEPERFORMANCE') { "performancedata.$_ $direction" } else { "$_ $direction" } } @columns);
} else {
push @orderbysql, (map { "performancedata.$_ $direction" } @columns);
}
}
my $render_2021_dropdown = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DASHBOARD_2021_DROPDOWN',
}) eq 'ON';
my $sql = SQL::Select->new(
)->Select(
"performancedata.providerid",
"performancedata.federalidnumber",
"performancedata.denominator",
"performancedata.numerator",
"performancedata.excluded",
"performancedata.performancerate",
"performancedata.roundedperformancerate roundedpercentage",
"performancedata.maxpoints",
"performancedata.p4pprogramid",
"performancedata.criteriacode",
"performancedata.p4pmeasuresubscriptionid",
"performancedata.category",
"performancedata.npi",
"performancedata.displayperformancerate displayperformancerate",
"performancedata.isinversemeasure isinversemeasure",
"case
when
performancedata.providerplclastname is not null
and performancedata.providerplcfirstname is not null
then performancedata.providerplclastname || ', ' || performancedata.providerplcfirstname
else 'All'
end providername",
"CASE
WHEN (performancedata.status = 'In Progress') THEN 'Not Satisfied'
ELSE performancedata.status
END status"
)->From(
"p4pmeasureperformance performancedata",
)->Where(
["performancedata.p4pprogramid in (??)", $p4pprogramids],
)->OrderBy(@orderbysql);
if ( $federalidnumbers ) {
$sql->Where(
["performancedata.federalidnumber in (??)", $federalidnumbers],
);
}
if($render_2021_dropdown) {
$sql->Select(
"CASE WHEN (performancedata.criteriacode like '%TASKCOMPLETION_SECURITYRISKRADIO%') THEN 'Security Risk Assessment'
ELSE performancedata.measurename
END AS measurename",
);
$sql->Where(
["performancedata.criteriacode not like '%MEASURE_QUERYPDMP%'"],
);
} else {
$sql->Select(
"CASE WHEN (performancedata.criteriacode = 'TASKCOMPLETION_SECURITYRISKRADIO') THEN 'Security Risk Assessment'
ELSE performancedata.measurename
END AS measurename",
);
$sql->Where(
["performancedata.criteriacode != 'MEASURE_QUERYPDMP'"],
);
}
if ( $npis ) {
my $npi_clause = ["performancedata.npi in (??)", $npis];
# TINONLY means we should looking for null NPIs, corresponding
# to group enrollments.
if (
List::AllUtils::any { $_ eq 'TINONLY' } @{ $npis || [] }
) {
$npi_clause = SQL->Or(
$npi_clause,
"performancedata.npi is null",
);
}
$sql->Where(
$npi_clause,
);
}
my $is_createencounter_toggle_enabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'QMII-7607-discount-createencounter',
}) eq 'ON';
my $enrolledproviderssql = GetTINswithClinicalproviders("Athena::P4P::App::PerformanceData",{
CREATEENCOUNTERTOGGLE => $is_createencounter_toggle_enabled,
});
$sql->Where(SQL->Or(
SQL->And(
["performancedata.federalidnumber in (??)", $enrolledproviderssql],
'performancedata.providerid is null',
),
"performancedata.providerid is not null",
));
my $isrollouttoggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CORRECT_SUBMISSIONSCORE_ON_MIPSDB',
}) eq 'ON';
if ($isrollouttoggleon) {
$sql->Select(
"CASE
WHEN (exists (select 1
from
p4psubmissiondata p4psubmissiondata,
p4psubmission p4psubmission,
p4psubmissiongroup p4psubmissiongroup
where
( p4psubmissiondata.key = 'FINALCOMPOSITESCORE' and p4psubmissiondata.value = 0)
AND ( p4psubmissiongroup.p4pprogramid = performancedata.p4pprogramid )
AND ( p4psubmissiongroup.federalidnumber = performancedata.federalidnumber )
AND ( p4psubmissiongroup.providerid = performancedata.providerid )
AND ( p4psubmissiongroup.id = p4psubmission.p4psubmissiongroupid )
AND ( p4psubmissiondata.p4psubmissionid = p4psubmission.id)
)) THEN 0
ELSE performancedata.weightedmeasurepoints
END measurepoints"
);
} else {
$sql->Select(
"performancedata.weightedmeasurepoints measurepoints",
);
}
if ( $relativeperformanceenabledversion ) {
$sql->Select(
"case
when
p4pnetworkperformance.averagemeasureperformance is null
and performancedata.p4pmeasuresubscriptionid is not null
then -1
else p4pnetworkperformance.averagemeasureperformance
end relativeperformance",
"numerator as sortednumerator"
);
$sql->From("p4pnetworkperformance p4pnetworkperformance");
$sql->Where(
'p4pnetworkperformance.p4pmeasuresubscriptionid(+) = performancedata.p4pmeasuresubscriptionid',
);
}
return $sql;
}
###########################################################################
# GetTINswithClinicalproviders
#
# Description:
# Gets a SQL object that gets TINs with clinicals providers
# a clinicals provider is defined as provider.createencounteratcheckinyn = Y, has a username, and NPI
#
# Parameters:
# Required:
# None.
# Optional:
# None.
#
# Return Value:
# SQL::Select object
###########################################################################
sub GetTINswithClinicalproviders {
my ($class, $args) = @_;
my $is_createencounter_toggle_enabled = $args->{CREATEENCOUNTERTOGGLE};
my $enrolledproviderssql = SQL::Select->new()->Distinct(
)->Select(
'medicalgroup.federalidnumber providertin',
)->From(
'provider',
'medicalgroup',
'providernumber',
)->Joins(
'provider.medicalgroupid = medicalgroup.id (+)',
'providernumber.providerid = provider.id'
)->Where(
'provider.username is not null',
'provider.deleted is null',
'providernumber.providernumbercategoryid = 454',
'providernumber.providernumber is not null',
'providernumber.deleted is null',
'medicalgroup.federalidnumber is not null',
);
if(!$is_createencounter_toggle_enabled){
$enrolledproviderssql->Where(
['provider.createencounteroncheckinyn = ?', 'Y'],
);
}
return $enrolledproviderssql;
}
################################################################################
# FetchMIPSMeasurePerformanceData
#
# Description:
# Gets measure performance data for various MIPS programs for purposes of
# denormalizing to the p4pmeasureperformance table.
#
# Required Parameters:
# P4PPROGRAMID. Integer. Program to get measure performance data for.
#
# Optional Parameters:
# PROVIDERID Integer.
# FEDERALIDNUMBER String.
#
# Return value:
# Arrayref of hashrefs containing P4PMEASUREPERFORMANCE columns as keys:
# PROVIDERID
# NPI
# FEDERALIDNUMBER
# DENOMINATOR
# NUMERATOR
# EXCLUDED
# PERFORMANCERATE
# ROUNDEDPERFORMANCERATE
# WEIGHTEDMEASUREPOINTS
# MAXPOINTS
# P4PPROGRAMID
# P4PMEASURESUBSCRIPTIONID
# CRITERIACODE
# MEASURENAME
# CATEGORY
# PROVIDERPLCFIRSTNAME
# PROVIDERPLCLASTNAME
################################################################################
sub FetchMIPSMeasurePerformanceData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
)],
[qw(
FEDERALIDNUMBER
PROVIDERID
ISMVP
)],
);
my $p4p_program_id = $args->{P4PPROGRAMID};
my $provider_id = $args->{PROVIDERID};
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $is_mvp = $args->{ISMVP} || 0;
my $npi_category_id = BusCall::Provider::GetNPIProviderNumberCategory();
my $context_id = Athena::Util::Database::SessionInfo($dbh)->{context};
my @npis;
if (
$provider_id
) {
my $npi_info = BusCall::Provider::GetProviderNumbers($dbh, {
PROVIDERIDS => [ $provider_id ],
CATEGORYIDS => [ $npi_category_id ],
ALLDEPARTMENTS => 1,
});
@npis = map { $_->{PROVIDERNUMBER} } @$npi_info;
}
my $start = time();
my @p4p_measure_performance_rows = _MIPSMeasurePerformanceSQL($dbh, {
P4PPROGRAMID => $p4p_program_id,
NPIS => @npis ? \@npis : undef,
FEDERALIDNUMBERS => $federal_id_number ? [ $federal_id_number ] : undef,
ISMVP => $is_mvp,
})->TableHash($dbh);
my $program_definitions_by_id = Athena::P4P::App::ProgramDefinition->new({
DBH => $dbh,
})->GetProgramDefinition({
P4PPROGRAMIDS => [$p4p_program_id],
});
my $timetofetchdata = time() - $start;
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} FetchMIPSMeasurePerformanceData _MIPSMeasurePerformanceSQL ',
$timetofetchdata,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4p_program_id,
},
});
my $augmented_data = _AugmentWithMaxPoints({
PROGRAMDEFINITIONSBYID => $program_definitions_by_id,
DATA => \@p4p_measure_performance_rows,
});
my $fetch_criteria_info_enabled = GetMIPSACIToggleStatus($dbh, { P4PPROGRAMID => $p4p_program_id, ISMVP => $is_mvp, });
my $mipscategory = $is_mvp ? GetMVPCategory($dbh, $p4p_program_id) : GetMIPSCategory($dbh, $p4p_program_id);
my $is_mips_ia = $mipscategory eq 'IA' ;
if ($fetch_criteria_info_enabled) {
$start = time();
$augmented_data = _AugmentWithCriteriaInfo($dbh, {
P4PPROGRAMID => $p4p_program_id,
DATA => $augmented_data,
FEDERALIDNUMBERS => $federal_id_number,
PROVIDERID => $provider_id,
ISMVP => $is_mvp,
});
$timetofetchdata = time() - $start;
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} FetchMIPSMeasurePerformanceData _AugmentWithCriteriaInfo ',
$timetofetchdata,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4p_program_id,
},
});
}
elsif($is_mips_ia){
$start = time();
$augmented_data = _GetMIPSIAMeasures($dbh, {
P4PPROGRAMID => $p4p_program_id,
FEDERALIDNUMBERS => $federal_id_number,
PROVIDERID => $provider_id,
ISMVP => $is_mvp,
});
$timetofetchdata = time() - $start;
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} FetchMIPSMeasurePerformanceData _GetMIPSIAMeasures ',
$timetofetchdata,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4p_program_id,
},
});
}
return $augmented_data;
}
################################################################################
# WriteMIPSMeasurePerformanceData
#
# Description:
# Writes the measure performance data retrieved by FetchMIPSMeasurePerformanceData
# to P4PMEASUREPERFORMANCE. Removes any rows from P4PMEASUREPERFORMANCE that
# are no longer relevant (assumes that the Fetch function passes along ALL
# currently-relevant entries in the table).
#
# Required Parameters:
# DATA - Arrayref - List of hashrefs containing rows to insert into P4PMEASUREPERFORMANCE.
# Should be return value of FetchMIPSMeasurePerformanceData.
#
# P4PPROGRAMID - Integer - Used to remove denormalized data for this program ID
# that was not otherwise being updated per $args->{DATA}.
# USERNAME - String - Username to make DB commits with.
#
# Optional Parameters:
# PROVIDERID Integer. Only update this provider
# FEDERALIDNUMBER String. Only update this TIN. Note: if FEDERALIDNUMBER
# is provided but PROVIDERID is not, that is interpretted to indicate
# that only the Group associated with that TIN should be updated.
#
# Return value:
# None.
################################################################################
sub WriteMIPSMeasurePerformanceData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
DATA
P4PPROGRAMID
USERNAME
)],
[qw(
PROVIDERID
FEDERALIDNUMBER
ISMVP
)],
);
my $data = $args->{DATA};
my $username = $args->{USERNAME};
my $federalidnumber = $args->{FEDERALIDNUMBER};
my $providerid = $args->{PROVIDERID};
my $p4pprogramid = $args->{P4PPROGRAMID};
my $is_mvp = $args->{ISMVP} || 0;
my $is_mips_phr_enabled = GetMIPSACIToggleStatus($dbh, { P4PPROGRAMID => $p4pprogramid, ISMVP => $is_mvp, });
my $context_id = Athena::Util::Database::SessionInfo($dbh)->{context};
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => $p4pprogramid,
});
my $program_year = $reporting_period->{PROGRAMYEAR};
my $subgroupid;
my $is_subgrp_toggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CLQI_5651_MVP_SUBGRP',
}) eq 'ON';
my $is_subgroup;
my $subgroup_map = BusCall::P4P::GetSubGroupMap($dbh);
my $subgroup_programids = $subgroup_map->{SUBGROUPPROGRAMIDS}{$program_year};
if(Athena::Util::List::InList($p4pprogramid, @$subgroup_programids)){
$is_subgroup = 1;
}
if($is_subgrp_toggleon && $is_subgroup){
$subgroupid = Clinical::P4P::Utils::GetSubgroupId($dbh,{
P4PPROGRAMID => $p4pprogramid,
});
}
# Turn our DATA into a hash so that we can more easily search through it.
my %hasheddata;
foreach my $datum (@$data) {
my $key = join(':', map { $datum->{$_} } @{_GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
})
});
$hasheddata{$key} = 1;
}
# Retrieve all information currently in the denormalized table for this program ID
my @selectcolumns = map { 'p4pmeasureperformance.' . $_ } @{_GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
})
};
my $start = time();
my $existingdatasql = SQL::Select->new(
)->Select(
'p4pmeasureperformance.id',
@selectcolumns,
)->From(
'p4pmeasureperformance',
)->Where(
['p4pmeasureperformance.p4pprogramid = ?', $p4pprogramid],
);
if (
$providerid
) {
$existingdatasql->Where(
['p4pmeasureperformance.providerid = ?', $providerid],
);
}
if (
$federalidnumber
) {
$existingdatasql->Where(
['p4pmeasureperformance.federalidnumber = ?', $federalidnumber],
);
if (
! $providerid
) {
# If provider ID is not specified, but a TIN was,
# we only want to look at data for the Group submission
# associated with this TIN.
$existingdatasql->Where(
'p4pmeasureperformance.providerid is null',
);
}
}
my @existingdata = $existingdatasql->TableHash($dbh);
my $timetogetexistingdata = time() - $start;
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} Time taken to get existing data - complete - complete',
$timetogetexistingdata,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
},
});
# For every existing row in the table, see if the passed-in DATA had an update
# for this row, as identified by the same set of uniquely-identifying attributes.
# If no match is found, this represents a state such as a provider no longer being
# enrolled in a measure, so mark this row for deletion.
my @rowstodelete;
foreach my $existingdatum (@existingdata) {
my $key = join(':', map { $existingdatum->{$_} } @{_GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
})
});
if (!$hasheddata{$key}) {
push @rowstodelete, $existingdatum;
}
}
my $is_optimize_write_measureperf_enabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'QPSU-4241-SUBMISSION-CHECK-DB-62-FIX',
}) eq 'ON';
if(!$is_optimize_write_measureperf_enabled) {
if (@$data) {
_MergeNewWithExistingData($dbh, {
DATA => $data,
ISMIPSPHRENABLED => $is_mips_phr_enabled,
P4PPROGRAMID => $p4pprogramid,
USERNAME => $username,
SUBGROUPID => $subgroupid,
});
}
}
else {
# We are going to do a Merge in case of group programs because providerid which is a part of the primary key will be null in this case and hence update will not work on this case
# in case of individuals we will do an Update and Add by determining which operation needs to be done
my $entitytype = $is_mvp ? Athena::P4P::App::PerformanceData::GetMVPEntityType($dbh, $p4pprogramid) : Athena::P4P::App::PerformanceData::GetMIPSEntityType($dbh, $p4pprogramid);
# Merge the adds & updates, if there is any data to merge
if (@$data && $entitytype eq 'GROUP') {
_MergeNewWithExistingData($dbh, {
DATA => $data,
ISMIPSPHRENABLED => $is_mips_phr_enabled,
P4PPROGRAMID => $p4pprogramid,
USERNAME => $username,
SUBGROUPID => $subgroupid,
});
}
else {
# Update and add
my %existinghasheddata;
my @rowstoupdate;
my @rowstoadd;
foreach my $existingdatum (@existingdata) {
my $key = join(':', map { $existingdatum->{$_} } @{_GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
})
});
$existinghasheddata{$key} = 1;
}
foreach my $datum (@$data) {
my $key = join(':', map { $datum->{$_} } @{_GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
})
});
if($subgroupid ne undef){
$datum->{SUBGROUPID} = $subgroupid;
}
if(!$existinghasheddata{$key}) {
push @rowstoadd, $datum;
}
else {
push @rowstoupdate,$datum;
}
}
my $rowsaffectedthroughupdate = 0;
my $rowsaffectedthroughadd = 0;
if (@rowstoupdate) {
while(@rowstoupdate) {
my @newdata = splice (@rowstoupdate, 0, 500);
my $begin = time();
$rowsaffectedthroughupdate += Athena::Util::SQL::ProcessTable($dbh, {
OPERATION => 'Update',
COLUMNNAMES => P4PMEASUREPERFORMANCE_COLUMNS(),
PRIMARYKEY => _GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
}),
TABLENAME => 'P4PMEASUREPERFORMANCE',
TABLEROWS => \@newdata,
USERNAME => $username,
});
my $timetakenforupdate = time() - $begin;
my $count = scalar(@newdata);
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} Time taken for update - complete - complete',
$timetakenforupdate,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'No of records for update::'.$count,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
}
}
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'Total records for update::'.$rowsaffectedthroughupdate,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
# Add necessary rows
if (@rowstoadd) {
while(@rowstoadd) {
my @newdata = splice (@rowstoadd, 0, 500);
my $begin = time();
$rowsaffectedthroughadd += Athena::Util::SQL::ProcessTable($dbh, {
OPERATION => 'Add',
PRIMARYKEY => _GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
}),
COLUMNNAMES => P4PMEASUREPERFORMANCE_COLUMNS(),
TABLENAME => 'P4PMEASUREPERFORMANCE',
TABLEROWS => \@newdata,
USERNAME => $username,
});
my $timetakenforupdate = time() - $begin;
my $count = scalar(@newdata);
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} Time taken for add - complete - complete',
$timetakenforupdate,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'No of records for add::'.$count,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
}
}
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'Total records for add::'.$rowsaffectedthroughadd,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
}
}
# Delete unnecessary rows
Athena::Util::SQL::ProcessTable($dbh, {
OPERATION => 'Delete',
TABLENAME => 'P4PMEASUREPERFORMANCE',
TABLEROWS => \@rowstodelete,
USERNAME => $username,
});
return;
}
################################################################################
# _MIPSMeasurePerformanceSQL
#
# Description:
# Creates an SQL object with measure performance data, starting from the
# MeasureDataSQL to pull submission table data for certain keys and adding in
# some other useful fields.
#
# Required Parameters:
#
# P4PPROGRAMID Integer. Program to get measure performance data for.
#
# Optional Parameters:
#
# NPIS Arrayref. NPIs for which to retreive data
# FEDERALIDNUMBERS Arrayref. TINs for which to retreive data
#
# Return value:
# An SQL::Select object.
################################################################################
sub _MIPSMeasurePerformanceSQL {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
)],
[qw(
NPIS
FEDERALIDNUMBERS
ISMVP
)],
);
my $p4pprogramid = $args->{P4PPROGRAMID};
my $npis = $args->{NPIS};
my $federalidnumbers = $args->{FEDERALIDNUMBERS};
my $is_mvp = $args->{ISMVP} || 0;
my $npicategoryid = BusCall::Provider::GetNPIProviderNumberCategory();
my @keys;
my $fetch_mips_aci_phr_enabled = GetMIPSACIToggleStatus($dbh, { P4PPROGRAMID => $p4pprogramid, ISMVP => $is_mvp, });
my $mipscategory = $is_mvp ? GetMVPCategory($dbh, $p4pprogramid) : GetMIPSCategory($dbh, $p4pprogramid);
my $is_mips_ia = $mipscategory eq 'IA';
if ($fetch_mips_aci_phr_enabled || $is_mips_ia ) {
@keys = qw(
DENOMINATOR
EXCLUDED
NUMERATOR
PERFORMANCERATE
ROUNDEDPERFORMANCERATE
WEIGHTEDMEASUREPOINTS
FINALMEASUREPOINTS
DISPLAYPERFORMANCERATE
ISINVERSEMEASURE
STATUS
MAXPOINTS
);
} else {
@keys = qw(
DENOMINATOR
EXCLUDED
NUMERATOR
PERFORMANCERATE
ROUNDEDPERFORMANCERATE
WEIGHTEDMEASUREPOINTS
FINALMEASUREPOINTS
DISPLAYPERFORMANCERATE
ISINVERSEMEASURE
MAXPOINTS
);
}
my $sql = Clinical::P4P::Persistence::MultiProviderSubmission->GetMeasureDataSQL({
INCLUDEFEDERALIDNUMBERS => 1,
INCLUDEPROGRAMIDS => 1,
INCLUDEPROVIDERIDS => 1,
KEYS => \@keys,
P4PPROGRAMID => $p4pprogramid,
});
my $category = $is_mvp ? GetMVPCategory($dbh, $p4pprogramid) : GetMIPSCategory($dbh, $p4pprogramid);
my $get_measure_data_index = "index(pd P4PDENORMENROLL_PRGPRFESUBME)";
if (defined Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_outer}) {
$get_measure_data_index = Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_outer};
}
my $performancedatasql = SQL::Select->new(
)->Distinct(
)->Select(
"performancedata.providerid",
"providernumber.providernumber npi",
"performancedata.federalidnumber",
"performancedata.denominator",
"performancedata.numerator",
"performancedata.excluded",
"performancedata.performancerate",
"performancedata.roundedperformancerate",
"performancedata.p4pprogramid",
"performancedata.p4pmeasuresubscriptionid",
"performancedata.criteriacode",
"performancedata.displayperformancerate",
"performancedata.isinversemeasure",
"p4pmeasure.id p4pmeasureid",
"p4pmeasure.shortname measurename",
["? category", $category],
"provider.plcfirstname providerplcfirstname",
"provider.plclastname providerplclastname",
)->From(
["(??) performancedata", $sql],
"p4pmeasure",
"p4pdenormalizedenrollment pd",
"provider",
"providernumber",
)->Joins(
"performancedata.p4pmeasureid = p4pmeasure.id",
"performancedata.p4pprogramid = pd.p4pprogramid",
"performancedata.p4pmeasuresubscriptionid = pd.p4pmeasuresubscriptionid",
"performancedata.providerid = provider.id (+)",
"provider.id = providernumber.providerid (+)",
)->Where(
["performancedata.p4pprogramid = ?", $p4pprogramid],
SQL->Or(
"performancedata.providerid is null",
"performancedata.providerid = pd.providerid",
),
SQL->Or(
"pd.federalidnumber is null",
"performancedata.federalidnumber = pd.federalidnumber",
),
"nvl(pd.hiddenyn, 'N') = 'N'",
"providernumber.deleted (+) is null",
"pd.deleted is null",
"pd.guidelines = '0'",
["providernumber.providernumbercategoryid (+) = ?", $npicategoryid],
);
if($get_measure_data_index ne 'OFF') {
$performancedatasql->Hints(
$get_measure_data_index,
);
}
if ($fetch_mips_aci_phr_enabled || $is_mips_ia) {
$performancedatasql->Select(
"performancedata.status",
);
}
$performancedatasql->Select(
# Prefer final scores over preview scores.
Athena::Util::Text::OneLine(qq{
nvl(
performancedata.finalmeasurepoints,
performancedata.weightedmeasurepoints
) weightedmeasurepoints
}),
);
if (
$npis
) {
$performancedatasql->Where(
["providernumber.providernumber in (??)", $npis],
);
}
if (
$federalidnumbers
) {
$performancedatasql->Where(
["performancedata.federalidnumber in (??)", $federalidnumbers],
);
if (
! $npis
) {
# If NPIs are not specified but TINs are, then assume we're
# only looking for Group performance data.
$performancedatasql->Where(
"performancedata.providerid is null",
);
}
}
my $enabledversion = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_DISPLAY_MAX_SCORES_FROM_CMS',
}) eq 'ON';
if ( $enabledversion ) {
$performancedatasql->Select(
"performancedata.maxpoints",
);
}
return $performancedatasql;
}
sub _AugmentWithMaxPoints {
my ($args) = @_;
my $program_definitions_by_id = $args->{PROGRAMDEFINITIONSBYID};
my $data = $args->{DATA};
foreach my $row (@$data) {
my $program_id = $row->{P4PPROGRAMID};
my $measure_subscription_id = $row->{P4PMEASURESUBSCRIPTIONID};
my $criteria_code = $row->{CRITERIACODE};
my $program_definition = $program_definitions_by_id->{$program_id};
my $measure = $program_definition->MeasureByP4PMeasureSubscriptionID($measure_subscription_id);
if ($measure) {
my $criterion = List::Util::first {
$_->CriteriaCode() eq $criteria_code
} @{ $measure->Criteria() };
if ($criterion) {
my $points_multiplier = $criterion->PointsMultiplier();
$row->{MAXPOINTS} = $row->{MAXPOINTS} ? $row->{MAXPOINTS} : DEFAULT_MAX_POINTS() * $points_multiplier;
}
}
}
return $data;
}
##########################################################################################
# _AugmentWithCriteriaInfo
#
# Description:
# Add PHR related submission data to be stored in p4pmeasureperformance
#
# Parameters:
# Required:
# None
# Optional:
# NPIS ListRef[String] NPI numbers to filter to. TINONLY is a special
# value, and will filter down to TIN enrollments.
# P4PPROGRAMID ListRef[Integer]
# FEDERALIDNUMBERS ListRef[String]
# PROVIDERID ListRef[Integer]
# DATA ListRef[String]
#
# Return Value:
# ListRef[String]
##########################################################################################
sub _AugmentWithCriteriaInfo {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
NPIS
FEDERALIDNUMBERS
PROVIDERID
P4PPROGRAMID
DATA
ISMVP
)],
);
my $p4pprogramid = $args->{P4PPROGRAMID};
my $data = $args->{DATA};
my $provider_id = $args->{PROVIDERID};
my $federal_id_number = $args->{FEDERALIDNUMBERS};
my $is_mvp = $args->{ISMVP} || 0;
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => $p4pprogramid,
});
my $program_year = $reporting_period->{PROGRAMYEAR};
my @keys = qw(
DENOMINATOR
EXCLUDED
NUMERATOR
PERFORMANCERATE
ROUNDEDPERFORMANCERATE
FINALMEASUREPOINTS
WEIGHTEDMEASUREPOINTS
DISPLAYPERFORMANCERATE
ISINVERSEMEASURE
STATUS
MAXPOINTS
);
my $mipscategory = $is_mvp ? GetMVPCategory($dbh, $p4pprogramid) : GetMIPSCategory($dbh, $p4pprogramid);
my $entitytype = $is_mvp ? GetMVPEntityType($dbh, $p4pprogramid) : GetMIPSEntityType($dbh, $p4pprogramid);
my $get_measure_data_index = "index(pde P4PDENORMENROLL_PRGPRFESUBME)";
if (defined Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_ctr_info}) {
$get_measure_data_index = Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_ctr_info};
}
my $sql = Clinical::P4P::Persistence::MultiProviderSubmission->GetMeasureDataSQL({
INCLUDEFEDERALIDNUMBERS => 1,
INCLUDEPROGRAMIDS => 1,
INCLUDEPROVIDERIDS => 1,
INCLUDEPHRDATA => 1,
P4PPROGRAMID => $p4pprogramid,
PROGRAMCATEGORY => $mipscategory,
KEYS => \@keys,
ENTITYTYPE => $entitytype,
EXCLUDEENROLLMENTCHECK => 1,
});
if (
$provider_id
) {
$sql->Where(
["p4psubmissiongroup.providerid in (??)", $provider_id ],
);
}
elsif (
$federal_id_number
) {
$sql->Where(
["p4psubmissiongroup.federalidnumber in (??)", $federal_id_number ],
);
}
my @allmeasuredata;
if($program_year > 2022){
# 1.All taskcompletion measures now have a dummy p4pmeasure id and they are also enrolled , hence we can now filter by enrollment
# 2. Some measures like PDMP , MDD have one measure and one taskcompletion measure in such cases enrolment in on the measure and to determine enrolment
# we are using the ARGUMENTS.P4PMEASUREID in p4ppdcriteriadata
my $performancedatasql = SQL::Select->new(
)->Distinct(
)->Select(
"performancedata.*",
)->From(
["(??) performancedata", $sql],
"p4pdenormalizedenrollment pde",
"p4ppdcriteria",
"p4ppdcriteriadata",
)->Where(
["pde.p4pprogramid in (??)", $p4pprogramid],
"performancedata.p4pprogramid = pde.p4pprogramid",
SQL->Or(
"performancedata.providerid is null",
"performancedata.providerid = pde.providerid",
),
SQL->Or(
"pde.federalidnumber is null",
"performancedata.federalidnumber = pde.federalidnumber",
),
"p4ppdcriteria.id = p4ppdcriteriadata.p4ppdcriteriaid",
"performancedata.p4ppdcriteriaid = p4ppdcriteria.id",
SQL->Or(
"performancedata.p4pmeasuresubscriptionid = pde.p4pmeasuresubscriptionid",
"performancedata.p4pmeasuresubscriptionid is null AND p4ppdcriteriadata.key = 'ARGUMENTS.P4PMEASUREID' AND pde.p4pmeasureid = p4ppdcriteriadata.value ",
),
"nvl(pde.hiddenyn, 'N') = 'N'",
"pde.deleted is null",
"pde.guidelines = '0'",
);
if($get_measure_data_index ne 'OFF') {
$performancedatasql->Hints(
$get_measure_data_index,
);
}
@allmeasuredata = $performancedatasql->TableHash($dbh);
} else{
@allmeasuredata = $sql->TableHash($dbh);
}
@allmeasuredata = grep { (!($_->{PROGRAMKEY} =~ /EXCLUSION/ || $_->{PROGRAMKEY} =~ /PRE/ || $_->{PROGRAMKEY} =~ /PROD/) && ( $_->{STATUS} eq 'Satisfied' || $_->{STATUS} eq 'In Progress' || $_->{STATUS} eq 'Excluded')) } @allmeasuredata;
# In case of PI we have _MIPSMeasurePerformanceSQL which fetches all the enrolled measures, because now all PI taskcompletion measures have a dummy measure id
# we already have these taskcompletion information.Only in case of PDMP we need to do this check
@$data = grep {!( $_->{P4PMEASURESUBSCRIPTIONID} ne undef && $_->{CRITERIACODE} =~ /^TASKCOMPLETION/ ) } @$data;
my $phrdata = _GetCombinedPhrMeasures($dbh, {
MEASUREDATA => \@allmeasuredata,
P4PPROGRAMID => $p4pprogramid,
ENTITYTYPE => $entitytype,
});
push @$phrdata, @$data;
foreach my $datahash(@$phrdata){
if($datahash->{FINALMEASUREPOINTS} && $datahash->{FINALMEASUREPOINTS} ne undef){
$datahash->{WEIGHTEDMEASUREPOINTS} = $datahash->{FINALMEASUREPOINTS};
}
}
return $phrdata;
}
##########################################################################################
# _GetCombinedPhrMeasures
#
# Description:
# Checks the max satisfying count for PHR measures
# and
#
# Parameters:
# Required:
# MEASUREDATA : the list of PHR measures
# P4PPROGRAMID : MIPS PI Program id
# ENTITYTYPE : GROUP / INDIVIDUAL
# Optional:
# None
#
# Return Value:
# Combined Measures details with status
##########################################################################################
sub _GetCombinedPhrMeasures {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
MEASUREDATA
P4PPROGRAMID
ENTITYTYPE
)],
[qw(
)],
);
my $measure_data = $args->{MEASUREDATA};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $entity_type = $args->{ENTITYTYPE};
my $program_definition = BusCall::P4P::GetProgramDefinition($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my @measure_results;
my %measure_data_by_providerid_or_tin;
if( $entity_type eq 'INDIVIDUAL'){
%measure_data_by_providerid_or_tin = Athena::Util::Hash::HashGroupBy(['PROVIDERID'], @$measure_data);
}
else{
%measure_data_by_providerid_or_tin = Athena::Util::Hash::HashGroupBy(['FEDERALIDNUMBER'], @$measure_data);
}
foreach my $providerid_or_tin (sort keys %measure_data_by_providerid_or_tin) {
my $measuredata = $measure_data_by_providerid_or_tin{$providerid_or_tin};
my %measure_data_by_program_key = Athena::Util::Hash::HashGroupBy(['PROGRAMKEY'], @$measuredata);
foreach my $program_key (sort keys %measure_data_by_program_key) {
my $pd_measure = $program_definition->MeasureByProgramKeys()->{$program_key};
my $measure_result = Athena::P4P::App::PerformanceData::GetMIPSMeasureSubmissionData({
MEASUREDATA => $measure_data_by_program_key{$program_key},
PDMEASURE => $pd_measure,
});
my $eachmeasuredata = $measure_data_by_program_key{$program_key}[0];
if (
$measure_result->{ISCOMBINEDPERFORMANCEMEASURE} && $measure_result->{MAXIMUMSATISFYINGREGISTRIES}
) {
my $satisfying_count = 0;
foreach my $sub_measure ( @{ $measure_result->{VALUES} || [] } ) {
if (
$sub_measure->{BOOLEANSATISFIED}
) {
$satisfying_count++;
}
}
if (
$satisfying_count >= $measure_result->{MAXIMUMSATISFYINGREGISTRIES}
) {
$eachmeasuredata->{STATUS} = 'Satisfied';
}
else{
$eachmeasuredata->{STATUS} = 'In Progress';
}
}
$eachmeasuredata->{PROGRAMKEY} = $program_key;
if( $entity_type eq 'INDIVIDUAL'){
$eachmeasuredata->{PROVIDERID} = $providerid_or_tin;
}
else{
$eachmeasuredata->{FEDERALIDNUMBER} = $providerid_or_tin;
}
push @measure_results, $eachmeasuredata;
}
}
return \@measure_results;
}
##########################################################################################
# _GetMIPSPerformanceDataRowCount
#
# Description:
# Gets a count of the number of measure performance rows for a specified set of filters.
#
# Helper function for GetMIPSPerformanceDataWithRowCount.
#
# Parameters:
# Required:
# None
# Optional:
# NPIS ListRef[String] NPI numbers to filter to. TINONLY is a special
# value, and will filter down to TIN enrollments.
# P4PPROGRAMIDS ListRef[Integer]
# FEDERALIDNUMBERS ListRef[String]
#
# Return Value:
# Integer - row count.
##########################################################################################
sub _GetMIPSPerformanceDataRowCount {
my ($dbh, $args) = @_;
my $npis = $args->{NPIS};
my $sql = SQL->Select(
'count(p4pmeasureperformance.id)',
)->From(
'p4pmeasureperformance',
);
if ($args->{P4PPROGRAMIDS}) {
$sql->Where(['p4pmeasureperformance.p4pprogramid in (??)', $args->{P4PPROGRAMIDS}]);
}
if (
$npis
) {
my $npi_clause = ["p4pmeasureperformance.npi in (??)", $npis];
# TINONLY means we should looking for null NPIs, corresponding
# to group enrollments.
if (
List::AllUtils::any { $_ eq 'TINONLY' } @{ $npis || [] }
) {
$npi_clause = SQL->Or(
$npi_clause,
"p4pmeasureperformance.npi is null",
);
}
$sql->Where(
$npi_clause,
);
}
if ($args->{FEDERALIDNUMBERS}) {
$sql->Where(['p4pmeasureperformance.federalidnumber in (??)', $args->{FEDERALIDNUMBERS}]);
}
my ($count) = $sql->ColumnValues($dbh);
return $count;
}
################################################################################
# GetMIPSSubmissionData
#
# Description:
# Gets measure performance data for various MIPS programs along with metadata
# necessary to include when submitting these measures to CMS.
#
# Parameters:
# Required:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# Optional:
# PROVIDERID Scalar ID of the provider for whom to retreive data
# MIPSCOMPONENTS Arrayref Only retrieve data related to these MIPS components.
# Must valid components (categories) for that program year.
# Defaults to all valid components.
# YEAR Integer The program year that applies. Defaults to 2017.
# ENTITYTYPE String INDIVIDUAL or GROUP. Defaults to INDIVIDUAL.
# ROLLING90DAYREQUEST Boolean.
#
# Returns:
# Hashref with the following structure
# [mips component name] => [
# arrayref of measure results
# ]
#
# See GetMIPSComponentSubmissionData for the structure of the arrayref of
# measure results
################################################################################
sub GetMIPSSubmissionData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
FEDERALIDNUMBER
)],
[qw(
MIPSCOMPONENTS
PROVIDERID
YEAR
ENTITYTYPE
ROLLING90DAYREQUEST
WINDOWSTART
P4PPROGRAMID
ISMVP
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $year = $args->{YEAR} // 2017;
_AssertValidYear($year);
my $is_mvp = $args->{ISMVP} || 0;
my $mips_components = $args->{MIPSCOMPONENTS} || _SupportedCategoriesForYear({
YEAR => $year,
ISMVP => $is_mvp,
});
my $provider_id = $args->{PROVIDERID};
my $entity_type = $args->{ENTITYTYPE};
my $rolling90dayrequest = $args->{ROLLING90DAYREQUEST};
my $windowstart = $args->{WINDOWSTART};
my $programid = $args->{P4PPROGRAMID};
if (
! defined $entity_type
) {
# Default entity_type to INDIVIDUAL if a provider is specified,
# otherwise assume we're dealing with a group.
if (
$provider_id
) {
$entity_type = 'INDIVIDUAL';
}
else {
$entity_type = 'GROUP';
}
}
_AssertValidEntityType($entity_type);
my %result_structure;
my $component_data;
my $istoggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => "CLQI_2022_MIPS_ROLLING_90_DAYS",
}) eq "ON";
foreach my $mips_component (@$mips_components) {
my $p4p_program_id = GetMIPSProgram($dbh, {
CATEGORY => $mips_component,
YEAR => $year,
ENTITYTYPE => $entity_type,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
ISMVP => $is_mvp,
});
$p4p_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $p4p_program_id,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
ENTITYTYPE => $entity_type,
MIPSCOMPONENT => $mips_component,
YEAR => $year,
ISMVP => $is_mvp,
});
if ($rolling90dayrequest && $istoggleon){
$component_data = Athena::P4P::App::PerformanceData::GetMIPSComponentSubmissionData($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $programid,
PROVIDERID => $provider_id,
ROLLING90DAYREQUEST => $rolling90dayrequest,
WINDOWSTART => $windowstart,
});
} else {
$component_data = Athena::P4P::App::PerformanceData::GetMIPSComponentSubmissionData($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
ROLLING90DAYREQUEST => $rolling90dayrequest,
WINDOWSTART => $windowstart,
});
}
$result_structure{$mips_component} = $component_data;
}
return \%result_structure;
}
################################################################################
# GetMIPSComponentSubmissionData
#
# Description:
# Gets measure performance data for a single component of MIPS along with metadata
# necessary to include when submitting these measures to CMS.
#
# Parameters:
# Required:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# P4PPROGRAMID Scalar The p4pprogramid for the MIPS component
# for which to retreive data.
# Optional:
# PROVIDERID Scalar Provider for whom to retreive data
#
# Returns:
# Arrayref of results for each measure in which the TIN or provider is enrolled.
# Each element of the array is a hashref as returned by GetMIPSMeasureSubmissionData.
################################################################################
sub GetMIPSComponentSubmissionData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
FEDERALIDNUMBER
P4PPROGRAMID
)],
[qw(
PROVIDERID
ROLLING90DAYREQUEST
WINDOWSTART
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $rolling90dayrequest = $args->{ROLLING90DAYREQUEST};
my $windowstart = $args->{WINDOWSTART};
my $program_definition = BusCall::P4P::GetProgramDefinition($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my $measure_data;
my $istoggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => "CLQI_2022_MIPS_ROLLING_90_DAYS",
}) eq "ON";
my %measure_data_by_program_key;
if ( $rolling90dayrequest && $istoggleon) {
$measure_data = Athena::P4P::App::Rolling90Days::GetMeasureDataForRolling90Days($dbh,{
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
WINDOWSTART => $windowstart,
});
%measure_data_by_program_key = Athena::Util::Hash::HashGroupBy(['KEY'], @$measure_data);
} else {
$measure_data = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
})->GetMeasureData({
KEYS => [qw(
DENOMEX
DENOMINATOR
ENROLLED
EXCLUDED
IPP
NUMERATOR
STATUS
)],
}) || [];
# We only want to submit measures for which the provider is actually enrolled
my @enrolled_measures = grep { $_->{ENROLLED} } @$measure_data;
%measure_data_by_program_key = Athena::Util::Hash::HashGroupBy(['PROGRAMKEY'], @enrolled_measures);
}
my @measure_results;
foreach my $program_key (sort keys %measure_data_by_program_key) {
my $pd_measure = $program_definition->MeasureByProgramKeys()->{$program_key};
# If we have data for the provider that is not recognized as a measure in the program
# definition, we'll just skip that element rather than ISE.
next unless $pd_measure;
my $measure_result = Athena::P4P::App::PerformanceData::GetMIPSMeasureSubmissionData({
MEASUREDATA => $measure_data_by_program_key{$program_key},
PDMEASURE => $pd_measure,
});
push @measure_results, $measure_result;
}
return \@measure_results;
}
################################################################################
# GetMIPSMeasureSubmissionData
#
# Description:
# Gets measure performance data for a single program definition measure along with
# metadata necessary for submitting the measure to CMS.
#
# Parameters:
# Required:
# MEASUREDATA Hashref mapping PROGRAMKEY to an array of results for the
# measure's criteria
# PDMEASURE Athena::P4P::Entity::ProgramDefinition::Measure
# Optional:
# None.
#
# Returns:
# Hashref with the following keys:
# HASMULTIPLEPERFORMANCERATES: Boolean indicating whether the measure is a
# multiPerformanceRate measure
# ISBOOLEANMEASURE: Boolean indicating a boolean metric type.
# ISCOMBINEDPERFORMANCEMEASURE:Boolean indicating the measure criteria's performance
# should be combined for submission.
# QPPMEASUREID: The CMS QPP identifier for the measure
# PROGRAMKEY: The athena-defined program key for the program
# definition measure
# SUBMISSIONMETHOD: The submission method of the measure; will generally
# only be populated for Quality component measures
# VALUES: An arrayref of the form returned by GetMIPSCriteriaSubmissionData
################################################################################
sub GetMIPSMeasureSubmissionData {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
MEASUREDATA
PDMEASURE
)],
[qw(
)],
);
my @measure_data = @{ $args->{MEASUREDATA} || [] };
my $pd_measure = $args->{PDMEASURE};
my $performance_values = Athena::P4P::App::PerformanceData::GetMIPSCriteriaSubmissionData({
CRITERIADATA => \@measure_data,
PDCRITERIA => $pd_measure->Criteria(),
ISBOOLEANMEASURE => $pd_measure->IsBooleanMeasure(),
});
return {
HASMULTIPLEPERFORMANCERATES => $pd_measure->HasMultiplePerformanceRates(),
ISBOOLEANMEASURE => $pd_measure->IsBooleanMeasure(),
ISCOMBINEDPERFORMANCEMEASURE => $pd_measure->IsCombinedPerformanceMeasure(),
QPPMEASUREID => $pd_measure->QPPMeasureID,
PROGRAMKEY => $pd_measure->ProgramKey(),
SUBMISSIONMETHOD => $pd_measure->SubmissionMethod(),
MAXIMUMSATISFYINGREGISTRIES => $pd_measure->MaximumSatisfyingRegistries(),
REQUIREDSUBMEASURES => $pd_measure->RequiredSubMeasures(),
VALUES => $performance_values,
};
}
################################################################################
# GetMIPSCriteriaSubmissionData
#
# Description:
# Gets performance data for all multiple criteria of a single program definition
# measure, along with metadata necessary for submitting the data to CMS.
#
# Parameters:
# Required:
# CRITERIADATA Arrayref of hashrefs, each representing a provider's performance
# rate in a particular criterion
# PDCRITERION Arrayref[Athena::P4P::Entity::ProgramDefinition::Criteria]
#
# Optional:
# ISBOOLEANMEASURE Boolean, indicates that this PD should return a boolean
# value as opposed to numeric NUMERATOR, DENOMINATOR, etc.
#
# Returns:
# Arrayref, where each element is a hashref in the format returned by
# GetMIPSCriterionSubmissionData.
################################################################################
sub GetMIPSCriteriaSubmissionData {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
CRITERIADATA
PDCRITERIA
)],
[qw(
ISBOOLEANMEASURE
)],
);
my @criteria_data = @{ $args->{CRITERIADATA} };
my @pd_criteria = @{ $args->{PDCRITERIA} };
my %criteria_by_code = map {
$_->CriteriaCode() => $_
} @pd_criteria;
my @measure_values;
foreach my $criterion_data (@criteria_data) {
my $pd_criterion = $criteria_by_code{$criterion_data->{CRITERIACODE}};
# If we have data for the provider that is not recognized as a criterion in the program
# definition, we'll just skip that element rather than ISE.
next unless (
$pd_criterion
# An indication that this is not a particular stratification layer
&& $pd_criterion->IsTotalPerformanceRate()
);
push @measure_values, Athena::P4P::App::PerformanceData::GetMIPSCriterionSubmissionData({
CRITERIONDATA => $criterion_data,
PDCRITERION => $pd_criterion,
ISBOOLEANMEASURE => $args->{ISBOOLEANMEASURE},
});
}
return \@measure_values;
}
################################################################################
# GetMIPSCriterionSubmissionData
#
# Description:
# Gets measure performance data for a single program definition criterion along with
# metadata necessary for submitting the measure to CMS.
#
# Parameters:
# Required:
# CRITERIONDATA Hashref of a provider's performance rate in a particular criterion
# PDCRITERION Athena::P4P::Entity::ProgramDefinition::Criteria
#
# Optional:
# ISBOOLEANMEASURE Boolean, indicates that this PD should return a boolean
# value as opposed to numeric NUMERATOR, DENOMINATOR, etc.
#
# Returns:
# Hashref with the following keys:
# QPPSTRATUMNAME: The CMS QPP identifier for the stratum (will be
# null for measures that have only a single performance rate)
# CRITERIACODE: The athena-defined critera code for the program definition
# measure criterion
#
# The following keys report any populations computed by the submission check:
# NUMERATOR
# DENOMINATOR
# EXCLUDED
# DENOMEX
# IPP
################################################################################
sub GetMIPSCriterionSubmissionData {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
CRITERIONDATA
PDCRITERION
)],
[qw(
ISBOOLEANMEASURE
)],
);
my $criterion_data = $args->{CRITERIONDATA};
my $pd_criterion = $args->{PDCRITERION};
my $is_boolean_measure = $args->{ISBOOLEANMEASURE};
# Metadata about the particular criterion result
my %criterion_result = (
CRITERIACODE => $criterion_data->{CRITERIACODE},
QPPSTRATUMNAME => $pd_criterion->QPPStratumName() || '',
);
if ($is_boolean_measure) {
# Boolean Measures have no numeric fields, just true or false.
$criterion_result{BOOLEANSATISFIED} = $criterion_data->{STATUS} eq 'Satisfied'
? 1
: '';
}
else {
# Non-boolean measures need to send different buckets of numeric data.
my @numeric_fields = qw(
NUMERATOR
DENOMINATOR
EXCLUDED
DENOMEX
IPP
);
# Include each relevant performance rate, assigning 0 if there is no data
foreach my $field (@numeric_fields) {
$criterion_result{$field} = $criterion_data->{$field} || 0;
}
}
return \%criterion_result;
}
################################################################################
# GetMIPSSubmissionReadiness
#
# Description:
# Given a provider and/or TIN, this function figures out for each MIPS component
# and -- where applicable -- submission method, whether or not that component
# and submission method are ready to be submitted officially for scoring. This
# takes into account:
# 1) Whether the enrolled entity has been blacklisted
# 2) Whether the enrolled entity's data has been snapshotted and attested (either
# by the provider or by Athena)
# 3) Whether the component & submission method have met minimum reporting
# requirements
# 4) Whether the component & submission method have not yet been submitted already
#
# Parameters:
# Required:
# YEAR Scalar Year to check the submission readiness for.
# At least one of:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# PROVIDERID Scalar ID of the provider for whom to retreive data
#
# Optional:
# MIPSCOMPONENTS Arrayref Only retrieve data related to these MIPS components.
# Must be a valid component (category) for that program year.
# Defaults to all valid components.
#
# Returns:
# Hashref, where the keys are uppercased concatenations of the MIPS component name
# and -- where applicable -- an underscore and the submission method (e.g., QUALITY_EHR).
# The values are Boolean, representing whether or not that component
# (and submission method) are ready for submission.
#
################################################################################
sub GetMIPSSubmissionReadiness {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
YEAR
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
MIPSCOMPONENTS
ISMVP
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $year = $args->{YEAR};
my $mips_components = $args->{MIPSCOMPONENTS} || _SupportedCategoriesForYear({
YEAR => $year,
});
my $provider_id = $args->{PROVIDERID};
my $eligibilitycheckcalled = 0;
my $eligibile_to_submit = 1;
my $mipseligibilitystatus;
my $iseligibleforsubmission = 1;
my $composite_score_threshold = 81;
my $return_status_quality;
if (defined Athena::Conf::AthenaNet::InternalServices('qupro')->{composite_score_threshold}){
$composite_score_threshold = Athena::Conf::AthenaNet::InternalServices('qupro')->{composite_score_threshold};
}
my %return_structure;
my $submission_blocking_reason = '';
foreach my $mips_component (@$mips_components) {
next if ! $mips_component;
$eligibile_to_submit = 1;
my $p4p_program_id = Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => $mips_component,
YEAR => $year,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
ISMVP => $args->{ISMVP},
});
$p4p_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $p4p_program_id,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $mips_component,
YEAR => $year,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
ISMVP => $args->{ISMVP},
});
Athena::Util::Assert::Assert($p4p_program_id, "$mips_component is not a valid MIPS component");
# Get all expected keys for this MIPS component
my @satisfied_component_keys = @{
Athena::P4P::App::PerformanceData::GetSatisfiedComponentKeys({ MIPSCOMPONENT => $mips_component })
};
# Next, get the attestation status required for submitting this component
my $submission_module = Clinical::P4P::Utils::GetProgramModule($dbh, {
P4PPROGRAMID => $p4p_program_id,
TYPE => 'Submission',
});
my $component_key_attestation_status_required = $submission_module->GetAttestationStatusClassForSubmission($dbh, {
COMPONENTKEYS => \@satisfied_component_keys,
});
my $program_submission = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
if (
$program_submission->NoDenormalizedData()
) {
# If the submission object does not exist in the database,
# it is not ready to submit.
next;
}
# The submission number (while often 1) is used for things below
my $submission_number = $program_submission->CurrentSubmissionNumber() || 1;
# Pull Metadata regarding whether we've tried to submit this via QPP
# (only saved for Quality currently, so attached to the submission module)
my $qpp_submission_metadata = {};
my @qpp_submission_metadata_keys = @{$submission_module->GetQPPSubmissionMetaDataKeys() || []};
my $submit_category_key = uc($mips_component)."_COMPOSITESCORE_OVERRIDE";
push (@qpp_submission_metadata_keys, $submit_category_key);
if (@qpp_submission_metadata_keys) {
$qpp_submission_metadata = $program_submission->GetMetaData({
SUBMISSIONNUMBER => $submission_number,
KEYS => \@qpp_submission_metadata_keys,
});
}
my $submit_category_data = 1;
#submit data if ( composite score >= threshold ) OR user has opted For it
my @p4p_program_ids = ($p4p_program_id); # Pull the composite performance score from CMS
my @performance_score_data = @{Clinical::P4P::Persistence::ProgramSubmission::GetPerformanceScores($dbh, {
# In the future, we may want to pass this list of program ids through from the front
# end, once the MIPS Dashboard will need to represent 2017 or 2018
P4PPROGRAMIDS => \@p4p_program_ids,
# Limit to just this provider/TIN
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
})};
my $composite_score ;
if (scalar @performance_score_data > 0) {
$composite_score = $performance_score_data[0]->{COMPOSITESCORE};
}
my $programs = Clinical::P4P::Utils::GetProgramInfo($dbh);
my $programinfo = $programs->{$p4p_program_id};
$submit_category_data = ($programinfo->{BEGINSNAPSHOTTINGYN} eq 'Y') ? 0 : 1;
$submission_blocking_reason = ($programinfo->{BEGINSNAPSHOTTINGYN} eq 'Y') ? 'COMPOSITE_SCORE_THRESHOLD' : '';
if( (defined $composite_score && $composite_score >= $composite_score_threshold ) ||
(defined $qpp_submission_metadata->{$submit_category_key} && $qpp_submission_metadata->{$submit_category_key} eq 'Y' ) ){
$submit_category_data = 1;
$submission_blocking_reason = '';
}
if(! $eligibilitycheckcalled) {
$eligibilitycheckcalled = 1;
$mipseligibilitystatus = _GetEligibilityStatus($dbh, {
YEAR => $year,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
});
my @submissioneligiblestatuses = ('Eligible','Opted-in','QP','MIPS APM', 'Ineligible', 'Unknown');
if (defined Athena::Conf::AthenaNet::ExternalServices('qpp')->{submission_eligible_statuses}) {
@submissioneligiblestatuses = @{Athena::Conf::AthenaNet::ExternalServices('qpp')->{submission_eligible_statuses}};
}
if( InList($mipseligibilitystatus , @submissioneligiblestatuses)) {
# eligible for submission
$iseligibleforsubmission = 1;
}
elsif($mipseligibilitystatus eq 'Opt-in') {
my $metadata = $program_submission->GetMetaData ({
KEYS => [qw(
OPTINSTATUS
)],
});
if($metadata->{OPTINSTATUS} eq 'true') {
$iseligibleforsubmission = 1;
} else {
$iseligibleforsubmission = 0;
}
}
else {
$iseligibleforsubmission = 0;
}
if($mipseligibilitystatus eq 'Unknown') {
#if eligibility status is Unknow only CQM's should not be submitted
#the error message should showup only if we are submitting any CQM's
my $p4p_program_id_quality = Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => 'Quality',
YEAR => $year,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
$p4p_program_id_quality = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $p4p_program_id_quality,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => 'Quality',
YEAR => $year,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
my $program_submission_quality = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $p4p_program_id_quality,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
if (! $program_submission_quality->NoDenormalizedData()) {
my $attestationmodule = Clinical::P4P::Utils::GetProgramModule($dbh, {
P4PPROGRAMID => $p4p_program_id_quality,
TYPE => 'Attestation',
});
my $reporting_period = $program_submission_quality->ReportingPeriod();
my $attestation_deadline = $attestationmodule->GetAttestationDeadline({
REPORTINGPERIOD => $reporting_period,
});
$return_status_quality = $attestationmodule->GetAttestationRequiredStatus($dbh, {
SUBMISSIONOBJECT => $program_submission_quality,
ATTESTATIONDEADLINE => $attestation_deadline,
});
}
}
}
#if the return status is nonedtoattest that means we are not submitting any CQM's and hence error message need not be shown
#any other status other than noneedtoattest we need to show the unknown error message because we are submitting CQM's in those cases
if($mipseligibilitystatus eq 'Unknown' && $return_status_quality ne undef && $return_status_quality ne 'NoNeedToAttest' ) {
$submission_blocking_reason = 'UNKNOWN_ELIGIBILITY_STATUS';
}
if(!$iseligibleforsubmission && ($mipseligibilitystatus eq 'Error in NPI' || $mipseligibilitystatus eq 'Ineligible' || $mipseligibilitystatus eq 'Opt-in') ) {
if ($mipseligibilitystatus eq 'Opt-in') {
$submission_blocking_reason = 'NOT_OPTED_IN_ELIGIBILITY_STATUS';
} elsif ($mipseligibilitystatus eq 'Error in NPI') {
$submission_blocking_reason = 'NPI_TIN_MISMATCH_ELIGIBILITY_STATUS';
} elsif ($mipseligibilitystatus eq 'Ineligible') {
$submission_blocking_reason = 'INELIGIBLE_ELIGIBILITY_STATUS';
}
}
$program_submission->UpdateMetaData({
USERNAME => $Global::session{USERNAME},
DATA => {
SUBMISSION_BLOCKING_REASON => $submission_blocking_reason,
},
});
# Evaluate whether this provider has been blacklisted from submission.
my $is_blacklisted = Clinical::P4P::Blacklist::IsBlacklisted($dbh, {
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
SUBMISSIONNUMBER => $submission_number,
})->{BLACKLISTED};
# Determine which components have met minimum reporting requirements.
my $satisfied_components = Athena::P4P::App::PerformanceData::GetSatisfiedComponents($dbh, {
PROGRAMSUBMISSION => $program_submission,
ISMVP => $args->{ISMVP},
});
# Get the status of this program
my $status_hash = $program_submission->GetStatusBySubmissionNumber({
SUBMISSIONNUMBER => $submission_number,
}) || {};
my $program_status = $status_hash->{STATUS};
my $qpp_conf = Athena::Conf::AthenaNet::ExternalServices('qpp');
my $start_submission = exists($qpp_conf->{munge_pii}) && $qpp_conf->{munge_pii} eq '1' ? 0 : 1;
foreach my $key (@satisfied_component_keys) {
# Evaluate if this component satisfies status & metadata submission criteria
my $in_acceptable_status = _InAcceptableStatusForSubmission($dbh, {
COMPONENT => $key,
PROGRAMSTATUS => $program_status,
QPPSUBMISSIONMETADATA => $qpp_submission_metadata,
REQUIREDSTATUSCLASS => $component_key_attestation_status_required->{$key},
});
if($key eq 'QUALITY_REGISTRY' && $mipseligibilitystatus eq 'Unknown') {
$eligibile_to_submit = 0;
}
elsif(!$iseligibleforsubmission){
$eligibile_to_submit = 0;
}
# Put everything together to evaluate if this program component is ready for submission
$return_structure{$key} = (
!$is_blacklisted
&& $in_acceptable_status
&& $satisfied_components->{$key}
&& $submit_category_data
&& $eligibile_to_submit
&& $start_submission
) ? '1' : '';
}
}
return \%return_structure;
}
################################################################################
# _InAcceptableStatusForSubmission
#
# Description:
# Evaluates whether the given component is eligible to be submitted based on
# the status of the program. This looks at a few criteria:
# 1) The program status is not SUBMITTED
# 2) If QPP Metadata exists for this component, then that it doesn't indicate
# that there has been a successful QPP submission already
# 3) That the program status has attained a minimally-required status
# as necessitated for this component.
#
# Parameters:
# Required:
#
# COMPONENT - string - the key of a component (see GetSatisfiedComponentKeys)
#
# PROGRAMSTATUS - string - the status of the current program submission
#
# QPPSUBMISSIONMETADATA - hashref of data returned by GetMetaData representing
# QPP Submission information for this component
#
# REQUIREDSTATUSCLASS - string - the minimally-required status needed for
# submission by this component
#
# Returns:
# Boolean. True represents that this component is eligible for submission based
# on the passed-in information; false represents that this component is ineligible
# for submission.
################################################################################
sub _InAcceptableStatusForSubmission {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
COMPONENT
PROGRAMSTATUS
QPPSUBMISSIONMETADATA
REQUIREDSTATUSCLASS
)],
[qw(
)],
);
my $component = $args->{COMPONENT};
my $program_status = $args->{PROGRAMSTATUS};
my $qpp_submission_metadata = $args->{QPPSUBMISSIONMETADATA};
my $required_status_class = $args->{REQUIREDSTATUSCLASS};
my $in_acceptable_status;
# If the program was already SUBMITTED, it should never be submitted again, as
# this is a final state
if ($program_status ne 'SUBMITTED') {
my $metadata_key = $component . '_SUBMISSION';
# If the whole program isn't fully SUBMITTED, but there is metadata supporting
# that this particular submission method was successful, the data should not
# be submitted again for this submission method. That is, continue evaluating
# for submission readiness if there is no metadata or if the metadata shows
# that submission was not successful.
if ($qpp_submission_metadata->{ $metadata_key } ne 'SUCCESS') {
# If we've gotten this far, then we know the program and/or submission method
# has not yet been submitted.
# See if the program is in a minimally-acceptable status (depending on the
# program and submission method, that it was snapshotted and/or attested)
$in_acceptable_status = $Clinical::P4P::Attestation::AttestationStatuses{$required_status_class}->{$program_status};
}
}
return $in_acceptable_status;
}
################################################################################
# GetSatisfiedComponents
#
# Description:
# Given a program submission object, determines which components of MIPS
# have met minimum reporting requirements. The computation of whether a component
# has met minimum requirements only happens at snapshotting, so the results will
# not be useful for a component that has not snapshotted.
#
# Parameters:
# Required:
# PROGRAMSUBMISSION - a Clinical::P4P::Persistence::ProgramSubmission object
#
# Returns:
# Hashref, where the keys are uppercased concatenations of the MIPS component name
# and an underscore and the submission method (e.g., QUALITY_EHR) as returned by
# GetSatisfiedComponentKeys.
# The values are Boolean, representing whether or not that component
# (and submission method) has met minimum reporting requirements.
################################################################################
sub GetSatisfiedComponents {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
PROGRAMSUBMISSION
)],
[qw(
ISMVP
)],
);
my $program_submission = $args->{PROGRAMSUBMISSION};
my $is_mvp = $args->{ISMVP} || 0;
my $mips_component = $is_mvp ? Athena::P4P::App::PerformanceData::GetMVPCategory($dbh, $program_submission->P4PProgramID()) : Athena::P4P::App::PerformanceData::GetMIPSCategory($dbh, $program_submission->P4PProgramID());
Athena::Util::Assert::Assert(
$mips_component,
'The supplied program submission does not represent a valid MIPS component',
);
# Get all expected keys for this MIPS component
my @result_keys = @{
Athena::P4P::App::PerformanceData::GetSatisfiedComponentKeys({ MIPSCOMPONENT => $mips_component })
};
# Use the metadata to evaluate if all minimum reporting requirements were met for the program.
# The following code makes an assumption that there is only one piece of metadata
# being stored for this key. The structure of $metadata may be unexpected if in
# the future it returns more information under the exact same keys.
my $metadata = $program_submission->GetMetaData({
KEYS => \@result_keys,
}) || {};
# The following code makes an assumption that all programs will continue to store
# metadata indicating that minimum reporting requirements have been met. This is
# definitely true for Quality, but would need to be verified for future programs (ACI, IA)
my %return_structure;
foreach my $key (@result_keys) {
my $met_minimum_requirements = $metadata->{$key} && $metadata->{$key} eq 'MinRequirementsMet';
$return_structure{$key} = !!$met_minimum_requirements;
}
return \%return_structure;
}
################################################################################
# GetSatisfiedComponentKeys
#
# Description:
# Given a MIPS component, returns the submission data keys that store whether
# the component has met minimum reporting requirements.
#
# For components that have only a single submission method, the key will just
# be the MIPS component name. The Quality program throws a wrench into simply using
# the component name, since we need to know about how to submit EHR and REGISTRY
# separately. We'll create keys that are a concatenation of the mips component name
# and the submission method, all upper-cased to avoid confusion.
#
# Parameters:
# Required:
# MIPSCOMPONENT String MIPS component for which to retreive keys. Must be
# a key in SUBMISSION_METHODS_FOR_PROGRAM().
# Optional:
# None.
#
# Returns:
# Arrayref of strings, each string being a key in the program's submission data
# that indicates whether minimum reporting requirements were met for that component
# and submission method.
################################################################################
sub GetSatisfiedComponentKeys {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
MIPSCOMPONENT
)],
[qw(
)],
);
my $mips_component = $args->{MIPSCOMPONENT};
Athena::Util::Assert::Assert(
exists SUBMISSION_METHODS_FOR_PROGRAM()->{$mips_component},
'MIPSCOMPONENT must be a valid key in SUBMISSION_METHODS_FOR_PROGRAM()',
);
my @submission_methods = @{SUBMISSION_METHODS_FOR_PROGRAM()->{$mips_component} || []};
my @result_keys = @submission_methods
? map {uc($mips_component . "_" . $_)} @submission_methods
: ($mips_component);
return \@result_keys;
}
##########################################################################################
# GetMIPSProgramsByCategory
#
# Description:
# MIPS programs are organized into triplets - a Quality Program, an ACI program, and
# an IA program. Given one program in the triplet, this returns a HashRef that specifies
# all three and their categories.
#
# Parameters:
# Required:
# P4PPROGRAMID Integer Id of one of the programs in the triplet.
# Optional:
# None.
#
# Return Value:
# HashRef of the form:
# <category, e.g. 'Quality' or 'ACI'> => <p4p program id>
##########################################################################################
sub GetMIPSProgramsByCategory {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
)],
[qw(
ISMVP
)],
);
my $p4p_program_id = $args->{P4PPROGRAMID};
my $is_mvp = $args->{ISMVP} || 0;
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my $year = $reporting_period->ProgramYear();
my $is_subgrp_toggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CLQI_5651_MVP_SUBGRP',
}) eq 'ON';
my $is_subgroup;
my $subgroup_programids = Clinical::P4P::Utils::GetSubGroupMap($dbh)->{SUBGROUPPROGRAMIDS}{$year};
if(Athena::Util::List::InList($p4p_program_id, @$subgroup_programids) && $is_subgrp_toggleon){
$is_subgroup = 1;
}
my $entity_type = $is_mvp ? GetMVPEntityType($dbh, $p4p_program_id) : GetMIPSEntityType($dbh, $p4p_program_id);
if (! $entity_type) {
# If we cannot derive an entity type, we were given an invalid MIPS Program.
# Therefore we should return nothing.
return {};
}
my $aci_pi_category = 'PI';
if (
$year == 2017
) {
$aci_pi_category = 'ACI';
}
return {
$aci_pi_category => $is_subgroup ?
Athena::P4P::App::PerformanceData::GetSubGroupProgramByCategory($dbh,{
CATEGORY => 'PI',
}) :
Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => $aci_pi_category,
YEAR => $year,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp,
}),
Quality => $is_subgroup ?
Athena::P4P::App::PerformanceData::GetSubGroupProgramByCategory($dbh,{
CATEGORY => 'Quality',
}) :
Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => 'Quality',
YEAR => $year,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp,
}),
IA => $is_subgroup ?
Athena::P4P::App::PerformanceData::GetSubGroupProgramByCategory($dbh,{
CATEGORY => 'IA',
}) :
Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => 'IA',
YEAR => $year,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp,
}),
};
}
##########################################################################################
# _GetMIPSCategoryMap
#
# Description:
# Returns a hashref that maps each MIPS program ID to a MIPS category (Quality, IA, or ACI)
#
# Parameters:
# None.
#
# Return Value:
# Hashref of entries of the form P4PROGRAMID => Category, e.g.,
# {
# 3119 => "ACI",
# 3152 => "Quality",
# 3205 => "IA",
# 3791 => "ACI",
# 3796 => "IA",
# 3797 => "Quality"
# }
##########################################################################################
sub _GetMIPSCategoryMap {
my ($dbh, $is_mvp) = @_;
my $years = GetMIPSProgramYearList($dbh, $is_mvp);
my %category_map = ();
foreach my $year (@$years) {
my @categories = @{ _AllCategoriesForYear( {
YEAR => $year,
ISMVP => $is_mvp,
}) };
foreach my $category (@categories) {
my @entity_types = @{
_AllEntityTypesForYearAndCategory({
YEAR => $year,
CATEGORY => $category,
ISMVP => $is_mvp
})
};
foreach my $entity_type (@entity_types) {
my $program_id = _GetProgramIDForYearCategoryEntityType($dbh, {
YEAR => $year,
CATEGORY => $category,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp
});
foreach my $programid (@$program_id) {
$category_map{$programid} = $category if defined $programid;
}
}
}
}
my $subgroup_categorymap = Clinical::P4P::Utils::GetSubGroupMap($dbh);
foreach my $programid (keys %{$subgroup_categorymap->{CATEGORYMAP}}){
$category_map{$programid} = $subgroup_categorymap->{CATEGORYMAP}{$programid};
}
return \%category_map;
}
# Save the MIPS category map for use in GetMIPSCategory.
my $mips_category_map = \&_GetMIPSCategoryMap;
##########################################################################################
# GetMIPSCategory
#
# Description:
# Returns the MIPS category (Quality, IA, or ACI) for a given MIPS program
#
# Parameters:
# Required:
# $dbh Database handle
# $p4p_program_id Integer P4P program ID
#
# Optional:
# None.
#
# Return Value:
# The MIPS category that corresponds to the program ID.
# For example, GetMIPSCategory($dbh, 3152) returns 'Quality'.
##########################################################################################
sub GetMIPSCategory {
my ($dbh, $p4p_program_id) = @_;
Athena::Util::Assert::Assert(defined $p4p_program_id, 'The p4p_program_id argument is required.');
return $mips_category_map->($dbh)->{$p4p_program_id};
}
##########################################################################################
# GetMVPCategory
#
# Description:
# Returns the MVP category (Quality, IA, or ACI) for a given MVP program
#
# Parameters:
# Required:
# $dbh Database handle
# $p4p_program_id Integer P4P program ID
#
# Optional:
# None.
#
# Return Value:
# The MVP category that corresponds to the program ID.
# For example, GetMVPCategory($dbh, 3152) returns 'Quality'.
##########################################################################################
sub GetMVPCategory {
my ($dbh, $p4p_program_id) = @_;
my $is_mvp = 1;
Athena::Util::Assert::Assert(defined $p4p_program_id, 'The p4p_program_id argument is required.');
return $mips_category_map->($dbh, $is_mvp)->{$p4p_program_id};
}
##########################################################################################
# _GetMIPSEntityTypeMap
#
# Description:
# Returns a hashref that maps each MIPS program ID to an entity type (INDIVIDUAL or GROUP)
#
# Parameters:
# None.
#
# Return Value:
# Hashref of entries of the form P4PROGRAMID => Category, e.g.,
# {
# 3119 => "INDIVIDUAL",
# 3152 => "INDIVIDUAL",
# -3152 => "GROUP",
# }
##########################################################################################
sub _GetMIPSEntityTypeMap {
my ($dbh, $is_mvp) = @_;
my $years = GetMIPSProgramYearList($dbh, $is_mvp);
my %entity_map = ();
foreach my $year (@$years) {
my @categories = @{ _AllCategoriesForYear({
YEAR => $year,
ISMVP => $is_mvp,
}) };
foreach my $category (@categories) {
my @entity_types = @{
_AllEntityTypesForYearAndCategory({
YEAR => $year,
CATEGORY => $category,
ISMVP => $is_mvp
})
};
foreach my $entity_type (@entity_types) {
my $program_id = _GetProgramIDForYearCategoryEntityType($dbh, {
YEAR => $year,
CATEGORY => $category,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp
});
foreach my $programid (@$program_id) {
$entity_map{$programid} = $entity_type if defined $programid;
}
}
}
}
my $subgroup_entitymap = Clinical::P4P::Utils::GetSubGroupMap($dbh);
foreach my $programid (keys %{$subgroup_entitymap->{ENTITYMAP}}){
$entity_map{$programid} = $subgroup_entitymap->{ENTITYMAP}{$programid};
}
return \%entity_map;
}
# Save the MIPS entity type map for use in GetMIPSEntityType.
my $mips_entity_map = \&_GetMIPSEntityTypeMap;
##########################################################################################
# GetMIPSEntityType
#
# Description:
# Returns the MIPS entity type (INDIVIDUAL or GROUP) for a given MIPS program
#
# Parameters:
# Required:
# $dbh Database handle
# $p4p_program_id Integer P4P program ID
#
# Optional:
# None.
#
# Return Value:
# The MIPS entity type that corresponds to the program ID.
# For example, GetMIPSCategory($dbh, 3152) returns 'INDIVIDUAL'.
##########################################################################################
sub GetMIPSEntityType {
my ($dbh, $p4p_program_id) = @_;
Athena::Util::Assert::Assert(defined $p4p_program_id, 'The p4p_program_id argument is required.');
return $mips_entity_map->($dbh)->{$p4p_program_id};
}
##########################################################################################
# GetMVPEntityType
#
# Description:
# Returns the MIPS entity type (INDIVIDUAL or GROUP) for a given MVP program
#
# Parameters:
# Required:
# $dbh Database handle
# $p4p_program_id Integer P4P program ID
#
# Optional:
# None.
#
# Return Value:
# The MVP entity type that corresponds to the program ID.
# For example, GetMVPCategory($dbh, 3152) returns 'INDIVIDUAL'.
##########################################################################################
sub GetMVPEntityType {
my ($dbh, $p4p_program_id) = @_;
my $is_mvp = 1;
Athena::Util::Assert::Assert(defined $p4p_program_id, 'The p4p_program_id argument is required.');
return $mips_entity_map->($dbh, $is_mvp)->{$p4p_program_id};
}
##########################################################################################
# GetMIPSProgramList
#
# Description:
# Returns all the MIPS programs filtered by various criteria :
# - MIPS category (e.g., Quality, ACI, or IA)
# - Provider IDs
# - Federal ID numbers (TINs)
# - Program years
# - Entity type
#
# Parameters:
# Required:
# None.
#
# Optional:
# CATEGORY String The MIPS category (Quality, ACI, or IA)
#
# FEDERALIDNUMBERS Arrayref The TINs whose MIPS programs should be returned
# and/or
# PROVIDERIDS Arrayref The providers whose MIPS programs should be returned
#
# YEARS Arrayref The MIPS program years that apply
# ENTITYTYPES Arrayref A list containing INDIVIDUAL, GROUP, or both.
#
# Return Value:
# Arrayref of P4P program IDs for the MIPS programs selected.
##########################################################################################
sub GetMIPSProgramList {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[],
[qw(
CATEGORY
PROVIDERIDS
FEDERALIDNUMBERS
YEARS
ENTITYTYPES
ISMVP
)],
);
my $category_arg = $args->{CATEGORY};
Athena::Util::Assert::Assert(! defined $category_arg || _IsMIPSCategory($category_arg), "$category_arg is not a valid MIPS category.");
my $provider_ids = $args->{PROVIDERIDS};
my $federal_id_numbers = $args->{FEDERALIDNUMBERS};
my $is_mvp = $args->{ISMVP} || 0;
my $valid_program_years = GetMIPSProgramYearList($dbh, $is_mvp);
my $years = $args->{YEARS} // $valid_program_years;
$years = $valid_program_years if scalar @$years == 0;
Athena::Util::Assert::Assert(ref $years eq 'ARRAY', 'The YEARS argument, if provided, must either be undef or an arrayref.');
my @entity_types_arg = @{$args->{ENTITYTYPES} // []};
my %program_ids = ();
foreach my $year (@$years) {
_AssertValidYear($year);
my @categories = defined $category_arg
? ( $category_arg )
: @{_AllCategoriesForYear({
YEAR => $year,
ISMVP => $is_mvp,
})};
foreach my $category (@categories) {
my @entity_types = scalar @entity_types_arg
? @entity_types_arg
: @{
_GetApplicableEntityTypes($dbh, {
YEAR => $year,
CATEGORY => $category,
PROVIDERIDS => $provider_ids,
FEDERALIDNUMBERS => $federal_id_numbers,
ISMVP => $is_mvp,
})
};
foreach my $entity_type (@entity_types) {
_AssertValidEntityType($entity_type);
my $program_id = _GetProgramIDForYearCategoryEntityType($dbh, {
YEAR => $year,
CATEGORY => $category,
ENTITYTYPE => $entity_type,
ISMVP => $is_mvp,
});
foreach my $programid (@$program_id) {
$program_ids{$programid} = 1 if defined $programid;
}
}
}
}
return [ sort { $a <=> $b } keys %program_ids ];
}
##########################################################################################
# GetSubGroupProgramByCategory
#
# Description:
# Returns the MIPS program associated with a MIPS category (e.g., Quality, ACI,
# or IA).
#
##########################################################################################
sub GetSubGroupProgramByCategory {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
CATEGORY
)],
);
my $category = $args->{CATEGORY};
my @programids_bycategory;
my $subgroup_category_map = Clinical::P4P::Utils::GetSubGroupMap($dbh);
foreach my $programid (sort keys %{$subgroup_category_map->{CATEGORYMAP}}){
if($subgroup_category_map->{CATEGORYMAP}{$programid} eq $category){
push(@programids_bycategory,$programid);
}
}
return \@programids_bycategory;
}
##########################################################################################
# GetMIPSProgram
#
# Description:
# Returns the MIPS program associated with a MIPS category (e.g., Quality, ACI,
# or IA).
#
# Parameters:
# Required:
# CATEGORY String The MIPS category (Quality, ACI, or IA)
# YEAR Integer The program year that applies
#
# Optional:
# FEDERALIDNUMBER String The TIN whose MIPS programs should be returned
# and/or
# PROVIDERID Integer The provider whose MIPS programs should be returned
#
# ENTITYTYPE String INDIVIDUAL or GROUP. Defaults to INDIVIDUAL if neither
# PROVIDERID or FEDERALIDNUMBER is provided.
#
# Return Value:
# The P4P program ID for the MIPS program
##########################################################################################
sub GetMIPSProgram {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
CATEGORY
YEAR
)],
[qw(
PROVIDERID
FEDERALIDNUMBER
ENTITYTYPE
ISMVP
)],
);
my $category = $args->{CATEGORY};
my $provider_id = $args->{PROVIDERID};
my $provider_ids = defined $provider_id ? [ $provider_id ] : [];
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $federal_id_numbers = defined $federal_id_number ? [ $federal_id_number ] : [];
my $is_mvp = $args->{ISMVP} || 0;
my $entity_type;
if (defined $provider_id || defined $federal_id_number) {
$entity_type = $args->{ENTITYTYPE};
}
else {
$entity_type = $args->{ENTITYTYPE} // 'INDIVIDUAL';
}
_AssertValidEntityType($entity_type) if defined $entity_type;
my $entity_types = defined $entity_type ? [ $entity_type ] : [];
my $year = $args->{YEAR};
_AssertValidYear($year);
my $years = defined $year ? [ $year ] : [];
my $program_ids = GetMIPSProgramList($dbh, {
CATEGORY => $category,
PROVIDERIDS => $provider_ids,
FEDERALIDNUMBERS => $federal_id_numbers,
YEARS => $years,
ENTITYTYPES => $entity_types,
ISMVP => $is_mvp,
});
return $program_ids;
}
# Utility functions
# Is the category name a valid MIPS category?
sub _IsMIPSCategory {
my ($category) = @_;
return MIPS_CATEGORIES()->{$category};
}
# Is the year valid?
sub _AssertValidYear {
my ($year) = @_;
# Assert does not fire correctly if the boolean regex match expression below is
# provided as the first argument. Assigning it to another variable first is a
# workaround.
my $valid_year = $year =~ /^\d{4}$/;
Athena::Util::Assert::Assert($valid_year, "The YEAR parameter '$year' is not in YYYY format.");
return;
}
# Is the entity type valid?
sub _AssertValidEntityType {
my ($entity_type) = @_;
Athena::Util::Assert::Assert($entity_type eq 'INDIVIDUAL' || $entity_type eq 'GROUP',
"The entity type '$entity_type' is not 'INDIVIDUAL' or 'GROUP'.");
return;
}
# Get all categories for a year.
sub _AllCategoriesForYear {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
qw(
YEAR
),
],
[
qw(
ISMVP
)
],
);
my $year = $args->{YEAR};
my $is_mvp = $args->{ISMVP};
my $year_data;
if($is_mvp) {
$year_data = _MVP_PROGRAM_DATA()->{$year};
}
else {
$year_data = _MIPS_PROGRAM_DATA()->{$year};
}
return [ keys %$year_data ];
}
# Get all supported categories for a year.
sub _SupportedCategoriesForYear {
my ($args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
qw(
YEAR
),
],
[
qw(
ISMVP
)
],
);
my $year = $args->{YEAR};
my $is_mvp = $args->{ISMVP};
return _AllCategoriesForYear({
YEAR => $year,
ISMVP => $is_mvp,
});
}
# Get all entity types for a year and category.
sub _AllEntityTypesForYearAndCategory {
my ($args) = @_;
my $year = $args->{YEAR};
my $category = $args->{CATEGORY};
my $is_mvp = $args->{ISMVP};
return if ! defined $year || ! defined $category;
my $entity_type_data = _GetEntityTypeData({
YEAR => $year,
CATEGORY => $category,
ISMVP => $is_mvp
});
return [] if ! defined $entity_type_data;
return [ keys %$entity_type_data ];
}
# Gets the entity type data for a year and category.
sub _GetEntityTypeData {
my ($args) = @_;
my $year = $args->{YEAR};
my $category = $args->{CATEGORY};
my $is_mvp = $args->{ISMVP};
return if ! defined $year || ! defined $category;
my $year_data;
if($is_mvp) {
$year_data = _MVP_PROGRAM_DATA()->{$year};
}
else {
$year_data = _MIPS_PROGRAM_DATA()->{$year};
}
return if ! defined $year_data;
my $category_data = $year_data->{$category};
return if ! defined $category_data;
my $entity_type_data = $category_data->{ENTITYTYPE};
return if ! defined $entity_type_data;
return $entity_type_data;
}
# Get the program ID for the year, category, and entity type. Note that the FULLYEAR reporting period is hardcoded for now.
sub _GetProgramIDForYearCategoryEntityType {
my ($dbh, $args) = @_;
my $year = $args->{YEAR};
my $category = $args->{CATEGORY};
my $entity_type = $args->{ENTITYTYPE};
my $is_mvp = $args->{ISMVP};
return if ! defined $year || ! defined $category || ! defined $entity_type;
if($year == 2019 && $category eq 'Quality') {
my $mips_quality_programid = _GetMIPSQMassQualityProgramIds({
CATEGORY => $category,
ENTITYTYPE => $entity_type,
});
return [$mips_quality_programid];
}
my $entity_type_data = _GetEntityTypeData({
YEAR => $year,
CATEGORY => $category,
ISMVP => $is_mvp
});
return if ! defined $entity_type_data;
my $entity_type_instance = $entity_type_data->{$entity_type};
return if ! defined $entity_type_instance;
my $full_year_data = $entity_type_instance->{FULLYEAR};
my $ninety_days = $entity_type_instance->{NINETYDAYS};
return if ! defined $full_year_data && ! $ninety_days;
my @ninetydayslist = split(m/[,]/, $ninety_days->{P4PPROGRAMID});
my @programids;
if($is_mvp) {
my @fullyeardatalist = split(m/[,]/, $full_year_data->{P4PPROGRAMID});
@programids = (@fullyeardatalist, @ninetydayslist );
}
else {
@programids = ($full_year_data->{P4PPROGRAMID}, @ninetydayslist );
}
return \@programids;
}
# Returns the entity types that apply to the parameters.
sub _GetApplicableEntityTypes {
my ($dbh, $args) = @_;
my @federal_id_numbers = @{ $args->{FEDERALIDNUMBERS} // [] };
my @provider_ids = @{ $args->{PROVIDERIDS} // [] };
my $is_mvp = $args->{ISMVP} || 0;
my $entity_types;
if (@provider_ids) {
$entity_types = [ 'INDIVIDUAL'];
}
elsif (@federal_id_numbers) {
$entity_types = [ 'GROUP' ];
}
else {
$entity_types = _AllEntityTypesForYearAndCategory({
YEAR => $args->{YEAR},
CATEGORY => $args->{CATEGORY},
ISMVP => $is_mvp,
});
}
return $entity_types;
}
################################################################################
# GetMIPSSubmissionStatuses
#
# Description:
# Gets the submission status for each MIPS component for a provider or TIN, as
# well as whether each component is in a status where it can be unsnapshotted.
#
# Also returns a flag indicating whether the supplied username has permission
# to undo snapshots. If the user does not have said permission, the hash of
# submission statuses will be empty.
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose MIPS statuses should be returned
# and/or
# PROVIDERID The provider whose MIPS statuses should be returned
#
# P4PPROGRAMID The id of one of the MIPS programs in the year for
# which we are fetching data
# USERNAME The username whose unsnapshot permission should be checked
#
# Returns:
# Hashref with the following keys:
#
# COMPONENTS A hashref of the form returned by _GetMIPSComponentStatuses.
# Will by an empty hashref if the user does not have permission
# to undo snapshots.
# UNDOSNAPSHOTPERMISSION True if the user has permissions to undo snapshots
################################################################################
sub GetMIPSSubmissionStatuses {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
{
ONEPLUS => [qw(
FEDERALIDNUMBER
PROVIDERID
)],
},
'P4PPROGRAMID',
'USERNAME',
],
[],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $provider_id = $args->{PROVIDERID};
my $username = $args->{USERNAME};
my $undo_snapshot_permission = AthenaSecurity::ResourceSecure($dbh, {
RESOURCE => 'CLINICALSP4PCONTENT',
USERNAME => $username,
});
my $is_mips_aci_nada_enabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CLQP_MIPS_ACI_NADA_2018',
}) eq 'ON';
if ($undo_snapshot_permission) {
my $component_statuses = Athena::P4P::App::PerformanceData::_GetMIPSComponentStatuses($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
});
if ($is_mips_aci_nada_enabled) {
my $legacy_statuses = Athena::P4P::App::PerformanceData::HandleMIPSLegacyData($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
});
return {
COMPONENTS => $component_statuses,
LEGACYCOMPONENTS => $legacy_statuses,
UNDOSNAPSHOTPERMISSION => 1,
};
} else {
return {
COMPONENTS => $component_statuses,
UNDOSNAPSHOTPERMISSION => 1,
};
}
}
else {
if ($is_mips_aci_nada_enabled) {
return {
COMPONENTS => {},
LEGACYCOMPONENTS => {},
UNDOSNAPSHOTPERMISSION => 0,
};
} else {
return {
COMPONENTS => {},
UNDOSNAPSHOTPERMISSION => 0,
};
}
}
}
################################################################################
# _GetMIPSComponentStatuses
#
# Description:
# Gets the submission status for each MIPS component for a provider or TIN,
# as well as whether each component is in a status where it can be unsnapshotted.
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose MIPS statuses should be returned
# and/or
# PROVIDERID The provider whose MIPS statuses should be returned
#
# P4PPROGRAMID The id of one of the MIPS programs in the year
# for which we are fetching data
#
# Returns:
# Hashref where each key is a MIPS component (Quality, IA, ACI)
# and each value is a hashref of the form returned by _GetMIPSComponentStatus
################################################################################
sub _GetMIPSComponentStatuses {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
{
ONEPLUS => [qw(
FEDERALIDNUMBER
PROVIDERID
)],
},
'P4PPROGRAMID',
],
[],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $program_id_by_category = Athena::P4P::App::PerformanceData::GetMIPSProgramsByCategory($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my %return_structure;
my $programid;
foreach my $category (sort keys %$program_id_by_category) {
$programid = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $program_id_by_category->{$category},
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $category,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
$return_structure{$category} = Athena::P4P::App::PerformanceData::_GetMIPSComponentStatus($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $programid || $program_id_by_category->{$category},
PROVIDERID => $provider_id,
});
}
return \%return_structure;
}
################################################################################
# _GetMIPSComponentStatus
#
# Description:
# Gets the submission status for a single MIPS component for a provider/TIN, as
# well as whether the status is such that it can be unsnapshotted.
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose status should be returned
# and/or
# PROVIDERID The provider whose status should be returned
#
# P4PPROGRAMID The id of the p4p program for which to get the status
#
# Returns:
# Hashref of the form
# {
# P4PPROGRAMID => The id of the p4p program (same as input parameter)
# STATUS => The status of the provider or TIN's submission for
# this component
# SUBMISSIONNUMBER => The current submission number of the submission
# ALLOWUNDOSNAPSHOT => True if the status is one where unsnapshotting is
# allowed
# }
################################################################################
sub _GetMIPSComponentStatus {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
{
ONEPLUS => [qw(
FEDERALIDNUMBER
PROVIDERID
)],
},
'P4PPROGRAMID',
],
[],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $program_submission = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
my $submission_number = $program_submission->CurrentSubmissionNumber() || 1;
my $status_hash = $program_submission->GetStatusBySubmissionNumber({
SUBMISSIONNUMBER => $submission_number,
}) || {};
my $status = $status_hash->{STATUS};
my $allow_undo = $Clinical::P4P::Attestation::AttestationStatuses{SNAPSHOTTED}->{ $status } ? 1 : 0;
my $error;
my $qpp_submission;
my $isrollouttoggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'CORRECT_SUBMISSIONSCORE_ON_MIPSDB',
}) eq 'ON';
my $isblacklistrulerollouttoggleon = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'QPSU_MIPS_DB_BlCKLIST_OPTIN',
}) eq 'ON';
my $blacklistrulenameandid;
if($isblacklistrulerollouttoggleon) {
my $is_blacklisted = Clinical::P4P::Blacklist::IsBlacklisted($dbh, {
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
SUBMISSIONNUMBER => $submission_number,
});
my @blacklistruleids;
my %p4pblacklistrulenamesbyid;
my @p4pblacklistrulenames;
# if blacklisted get the details
if($is_blacklisted->{BLACKLISTED}) {
if($is_blacklisted->{BLACKLISTRULEID}) {
@blacklistruleids = @{$is_blacklisted->{BLACKLISTRULEID}};
%p4pblacklistrulenamesbyid = SQL::Select->new(
)->Select(
"p4pblacklistrule.id",
"p4pblacklistrule.name",
)->From(
"p4pblacklistrule",
)->Where(
"p4pblacklistrule.deleted is null",
['p4pblacklistrule.id in (??)', \@blacklistruleids],
)->ColumnValues($dbh);
foreach my $blacklistruleid (@blacklistruleids) {
my $blacklistrulename = $p4pblacklistrulenamesbyid{$blacklistruleid};
$blacklistrulename = $blacklistrulename . ' (' . $blacklistruleid . ')';
push @p4pblacklistrulenames, $blacklistrulename;
}
}
if($is_blacklisted->{DEFAULTTOBLACKLIST}) {
push @p4pblacklistrulenames, 'Default To Blacklist is true';
}
$blacklistrulenameandid = join(
',',
@p4pblacklistrulenames
);
}
}
if($isrollouttoggleon) {
my @qpp_submissions = Athena::P4P::Persistence::QPP::GetQPPSubmissions($dbh, {
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
SUBMISSIONNUMBER => $submission_number,
REQUESTTYPE => 'FINALSCORING',
STATUS => 'SUCCESS',
});
$qpp_submission = $qpp_submissions[0];
my $error_message = $qpp_submission->{ERRORMESSAGE};
my $response = $qpp_submission->{RESPONSE};
if ($response ne undef) {
my $parsed_response = Athena::P4P::Persistence::QPP::ParseQPPResponse({
RESPONSE => YAML::XS::Load($response),
});
$error = !$parsed_response->{PARSEDCONTENT}->{data}->{score}->{value} ? $parsed_response->{PARSEDCONTENT}->{data}->{score}->{errors} : '';
}
if($isblacklistrulerollouttoggleon) {
#if there are no submission with FINALSCORING we want to check if there is a SUBMISSION request with opt-in error
if(!@qpp_submissions) {
@qpp_submissions = Athena::P4P::Persistence::QPP::GetQPPSubmissions($dbh, {
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
SUBMISSIONNUMBER => $submission_number,
REQUESTTYPE => 'SUBMISSION',
STATUS => 'FAILINVESTIGATE',
RESPONSECODE => 422,
});
#if a 422 error exists then check if it is not a validation error as we can have a SUBMISSION request with a validation error (preview env) and we don't want to show this
if(@qpp_submissions && $qpp_submissions[0]->{ERRORMESSAGE} && index($qpp_submissions[0]->{ERRORMESSAGE},'ValidationError') == -1) {
$qpp_submission = $qpp_submissions[0];
}
}
}
}
return {
ALLOWUNDOSNAPSHOT => $allow_undo,
P4PPROGRAMID => $p4p_program_id,
STATUS => $status,
ERRORMSG => $qpp_submission->{ERRORMESSAGE} ? $qpp_submission->{ERRORMESSAGE} : $error,
SUBMISSIONNUMBER => $submission_number,
BLACKLISTRULENAMEANDID => $blacklistrulenameandid ? $blacklistrulenameandid : undef,
};
}
################################################################################
# GetMIPSLegacyStatuses
#
# Description:
# Gets the legacy status for each MIPS component for a provider or TIN, as
# well as whether each component is in a status where it can be unsnapshotted.
#
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose MIPS statuses should be returned
# and/or
# PROVIDERID The provider whose MIPS statuses should be returned
#
# P4PPROGRAMID The id of one of the MIPS programs in the year for
# which we are fetching data
# USERNAME The username whose unsnapshot permission should be checked
#
# Returns:
# Hashref with the following keys:
#
# COMPONENTS A hashref of the form returned by _GetMIPSComponentStatuses.
# Will by an empty hashref if the user does not have permission
# to undo snapshots.
# UNDOSNAPSHOTPERMISSION True if the user has permissions to undo snapshots
################################################################################
sub GetMIPSLegacyStatuses {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
{
ONEPLUS => [qw(
FEDERALIDNUMBER
PROVIDERID
)],
},
'P4PPROGRAMID',
'USERNAME',
],
[],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $provider_id = $args->{PROVIDERID};
my $username = $args->{USERNAME};
my $undo_snapshot_permission = AthenaSecurity::ResourceSecure($dbh, {
RESOURCE => 'CLINICALSP4PCONTENT',
USERNAME => $username,
});
if ($undo_snapshot_permission) {
my $legacy_statuses = Athena::P4P::App::PerformanceData::HandleMIPSLegacyData($dbh, {
FEDERALIDNUMBER => $federal_id_number,
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
});
return {
LEGACYCOMPONENTS => $legacy_statuses,
UNDOSNAPSHOTPERMISSION => 1,
};
}
else {
return {
LEGACYCOMPONENTS => {},
UNDOSNAPSHOTPERMISSION => 0,
};
}
}
################################################################################
# FindDefaultYear
#
# Description:
# Gets the mips program ids and finds the active programs
#
# Returns:
# YEAR => The min year of active program
################################################################################
sub FindDefaultYear {
my ($dbh) = @_;
my @p4p_program_ids = Athena::P4P::App::PerformanceData::GetMIPSProgramList($dbh, {
ENTITYTYPES => ['INDIVIDUAL'],
});
my @active_programs = @{
Clinical::P4P::Submission::GetActiveSubmissionPrograms($dbh, {
P4PPROGRAMIDS => @p4p_program_ids,
IGNOREREPORTINGPERIOD => 0,
})
|| []
};
my @p4p_active_program_years = map { $_->{YEAR} } @active_programs;
return min( @p4p_active_program_years);
}
################################################################################
# _GetUniqueMeasurePerformanceColumns
#
# Description:
# Returns the appropriate columns required from P4PMEASUREPERFORMANCE
#
# Returns:
# A list of column names
################################################################################
sub _GetUniqueMeasurePerformanceColumns {
my ($dbh, $args) = @_;
my $is_mips_phr_enabled = $args->{MIPS_PHR_TOGGLE};
if (
$is_mips_phr_enabled
) {
return UNIQUE_MEASURE_PERFORMANCE_COLUMNS();
} else {
return [@{ UNIQUE_MEASURE_PERFORMANCE_COLUMNS() }, 'P4PMEASUREID'];
}
}
################################################################################
# GetMIPSACIToggleStatus
#
# Description:
# Returns the appropriate status of rollout toggle for ACI category
#
# Returns:
# TRUE/FALSE
################################################################################
sub GetMIPSACIToggleStatus {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
)],
[qw(
ISMVP
)],
);
my $p4pprogramid = $args->{P4PPROGRAMID};
my $is_mvp = $args->{ISMVP} || 0;
my $category = $is_mvp ? GetMVPCategory($dbh, $p4pprogramid) : GetMIPSCategory($dbh, $p4pprogramid);
my $is_mips_phr_enabled = $category eq 'PI';
return $is_mips_phr_enabled;
}
################################################################################
# HandleMIPSLegacyData
#
# Description:
# Gets the legacy status for each MIPS component for a provider or TIN,
# as well as whether each component is in a status where it can be unsnapshotted.
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose MIPS statuses should be returned
# and/or
# PROVIDERID The provider whose MIPS statuses should be returned
#
# P4PPROGRAMID The id of one of the MIPS programs in the year
# for which we are fetching data
#
# Returns:
# Hashref where each key is a MIPS component (Quality, IA, ACI)
################################################################################
sub HandleMIPSLegacyData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
{
ONEPLUS => [qw(
FEDERALIDNUMBER
PROVIDERID
)],
},
'P4PPROGRAMID',
],
[],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $program_id_by_category = Athena::P4P::App::PerformanceData::GetMIPSProgramsByCategory($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my %return_structure;
foreach my $category (sort keys %$program_id_by_category) {
$program_id_by_category->{$category} = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $program_id_by_category->{$category},
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $category,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
my $program_submission = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $program_id_by_category->{$category},
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
$return_structure{$category} = Clinical::P4P::Submission::Utils::MIPSSnapshotAssessment::GetLegacyReportingDetails($dbh, {
P4PPROGRAMID => $program_id_by_category->{$category},
SUBMISSIONNUMBER => $program_submission->CurrentSubmissionNumber() || 1,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id
});
$return_structure{$category}->{P4PPROGRAMID} = $program_id_by_category->{$category};
$return_structure{$category}->{SUBMISSIONNUMBER} = $program_submission->CurrentSubmissionNumber() || 1;
if (!$return_structure{$category}->{LEGACYDATAREQUIREDYN}) {
$return_structure{$category}->{LEGACYDATAREQUIREDYN} = 'N';
}
}
return \%return_structure;
}
################################################################################
# _GetMIPSQMassQualityProgramIds
#
# Description:
# Gets the program id from the above defined constant for MIPS Quality with QMaas
# and returns based on given entity_type
#
# Parameters:
# Required:
# ENTITYTYPE The type of the program , GROUP or INDIVIDUAL
#
# CATEGORY The category of the MIPS Program
#
# Returns:
# The Program of the MIPS Quality (Group or INDIVIDUAL)
################################################################################
sub _GetMIPSQMassQualityProgramIds {
my ($args) = @_;
my $entity_type = $args->{ENTITYTYPE};
my $category = $args->{CATEGORY};
my $category_data = _MIPS_QUALITY_FOR_QMASS_PROGRAM_DATA()->{$category};
return if ! defined $category_data;
my $entity_type_data = $category_data->{ENTITYTYPE};
return if ! defined $entity_type_data;
my $entity_type_instance = $entity_type_data->{$entity_type};
return if ! defined $entity_type_instance;
my $full_year_data = $entity_type_instance->{FULLYEAR};
return if ! defined $full_year_data;
return $full_year_data->{P4PPROGRAMID};
}
################################################################################
# _GetMIPSMessageForQRDA1Import
#
# Description:
# Identify if we have to show the message on MIPS dashboard of full data, The message will not be shown if
# either of : isqrdaimportdone, isstartlaterthanfced and issnapshotbufferover is true else message
# will be shown on MIPS Dashboard to let the user know that Athena doesnt have their full data
#
# Parameters:
# Required:
# FEDERALIDNUMBER
# YEARS
# Optional:
# PROVIDERID
#
# Returns:
# The boolean value 0 or 1
################################################################################
sub _GetMIPSMessageForQRDA1Import {
my ( $dbh, $args ) = @_;
Athena::Util::Assert::AssertFields(
$args,
[
qw(
FEDERALIDNUMBER
YEARS
)
],
[
qw(
PROVIDERID
)
],
);
my $provider_id = $args->{PROVIDERID};
my $year = $args->{YEARS}->[0];
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $entity_type = ($provider_id ne undef)?'INDIVIDUAL':'GROUP';
my $p4p_program_id = GetMIPSProgram($dbh,
{
CATEGORY => 'Quality',
YEAR => $year,
ENTITYTYPE => $entity_type,
FEDERALIDNUMBER => $args->{FEDERALIDNUMBER},
PROVIDERID => $provider_id,
}
);
$p4p_program_id = @$p4p_program_id[0];
my $is_registered_in_no_ecqm = 1;
if($p4p_program_id) {
my $submissionenrollmentdata = Clinical::P4P::Submission::GetSubmissionEnrollmentData($dbh, {
FEDERALIDNUMBERS => [ $federal_id_number ],
P4PPROGRAMIDS => [ $p4p_program_id ],
PROVIDERIDS => $provider_id ? [ $provider_id ] : undef,
CHECKFIRSTENCOUNTERDATE => 1,
});
if($submissionenrollmentdata->{ENROLLMENTDATA}->{$p4p_program_id}) {
my %measure_subscription_ids = %{ $submissionenrollmentdata->{ENROLLMENTDATA}->{$p4p_program_id}->{$federal_id_number}->{$provider_id || -1} };
my $programdefinitionbyp4pprogramid = BusCall::P4P::GetProgramDefinition($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
foreach my $measure_details(@{ $programdefinitionbyp4pprogramid->{Measures} }){
my $program_criterias = $measure_details->{Criteria};
for my $criteria(@$program_criterias) {
if ($criteria->{ReportingType} eq "EHR" && $measure_subscription_ids{$criteria->{P4PMeasureSubscriptionID}} == 1) {
$is_registered_in_no_ecqm = 0;
last;
}
}
last if($is_registered_in_no_ecqm == 0);
}
}
}
my ($first_encounter_date_data) = @{Clinical::P4P::Provider::GetP4PProviderData($dbh, {
INCLUDEDUPLICATEPROVIDERS => 1,
KEY => 'FIRSTENCOUNTERDATE',
MIN => 1,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
})};
my $reportingperiodstartdate;
my $reportingperiodend;
my $snapshotbuffer;
my $beginsnapshotting;
my $programs = Clinical::P4P::Utils::GetProgramInfo($dbh);
my $programinfo;
if ( ($programs->{$p4p_program_id}) && $first_encounter_date_data && $first_encounter_date_data->{VALUE})
{
$programinfo = $programs->{$p4p_program_id};
$reportingperiodstartdate = $programinfo->{REPORTINGPERIODSTART};
$reportingperiodend = $programinfo->{REPORTINGPERIODEND};
$beginsnapshotting = $programinfo->{BEGINSNAPSHOTTINGYN};
if ( $reportingperiodstartdate && $reportingperiodend && $beginsnapshotting eq 'Y')
{
my $isqrdaimportdone = Clinical::P4P::ReportingPeriod::IsQrdaImported($dbh,
{
P4PPROGRAMID => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number
});
my $currentdate = AthenaDate::AthenaToday();
my $isstartlaterthanfced = AthenaDate::Date1IsLaterThanOrEqualToDate2( $reportingperiodstartdate,$first_encounter_date_data->{VALUE} );
return ( $isstartlaterthanfced || $isqrdaimportdone || $is_registered_in_no_ecqm ) ? 0 : 1;
}
}
}
##########################################################################################
# _GetMIPSIAMeasures
#
# Description:
# Add MIPS IA related submission data to be stored in p4pmeasureperformance
#
# Parameters:
# Required:
# None
# Optional:
# NPIS ListRef[String] NPI numbers to filter to. TINONLY is a special
# value, and will filter down to TIN enrollments.
# P4PPROGRAMID ListRef[Integer]
# FEDERALIDNUMBERS ListRef[String]
# PROVIDERID ListRef[Integer]
#
# Return Value:
# ListRef[String]
##########################################################################################
sub _GetMIPSIAMeasures{
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
)],
[qw(
NPIS
FEDERALIDNUMBERS
PROVIDERID
P4PPROGRAMID
ISMVP
)],
);
my $p4pprogramid = $args->{P4PPROGRAMID};
my $data = $args->{DATA};
my $provider_id = $args->{PROVIDERID};
my $federal_id_number = $args->{FEDERALIDNUMBERS};
my @keys = qw(
DENOMINATOR
EXCLUDED
NUMERATOR
PERFORMANCERATE
ROUNDEDPERFORMANCERATE
FINALMEASUREPOINTS
WEIGHTEDMEASUREPOINTS
DISPLAYPERFORMANCERATE
ISINVERSEMEASURE
STATUS
MAXPOINTS
);
my $reporting_period = Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => $p4pprogramid,
});
my $program_year = $reporting_period->{PROGRAMYEAR};
my $is_mvp = $args->{ISMVP} || 0;
my $mipscategory = $is_mvp ? GetMVPCategory($dbh, $p4pprogramid) : GetMIPSCategory($dbh, $p4pprogramid);
my $entitytype = $is_mvp ? GetMVPEntityType($dbh, $p4pprogramid) : GetMIPSEntityType($dbh, $p4pprogramid);
my $get_measure_data_index = "index(pdm P4PDENORMENROLL_PRGPRFESUBME)";
if (defined Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_ia_measure}) {
$get_measure_data_index = Athena::Conf::AthenaNet::InternalServices('qupro')->{get_measure_data_index_ia_measure};
}
my $sql = Clinical::P4P::Persistence::MultiProviderSubmission->GetMeasureDataSQL({
INCLUDEFEDERALIDNUMBERS => 1,
INCLUDEPROGRAMIDS => 1,
INCLUDEPROVIDERIDS => 1,
P4PPROGRAMID => $p4pprogramid,
PROGRAMCATEGORY => $mipscategory,
KEYS => \@keys,
ENTITYTYPE => $entitytype,
});
if (
$provider_id
) {
$sql->Where(
["p4psubmissiongroup.providerid in (??)", $provider_id ],
);
}
elsif (
$federal_id_number
) {
$sql->Where(
["p4psubmissiongroup.federalidnumber in (??)", $federal_id_number ],
);
}
my @allmeasuredata;
if($program_year > 2022){
# 1.All taskcompletion measures now have a dummy p4pmeasure id and they are also enrolled , hence we can now filter by enrollment
# 2. Some measures like PDMP , MDD have one measure and one taskcompletion measure in such cases enrolment in on the measure and to determine enrolment
# we are using the ARGUMENTS.P4PMEASUREID in p4ppdcriteriadata
my $performancedatasql = SQL::Select->new(
)->Distinct(
)->Select(
"performancedata.*",
)->From(
["(??) performancedata", $sql],
"p4pdenormalizedenrollment pdm",
"p4ppdcriteria",
"p4ppdcriteriadata",
)->Where(
["pdm.p4pprogramid in (??)", $p4pprogramid ],
"performancedata.p4pprogramid = pdm.p4pprogramid",
SQL->Or(
"performancedata.providerid is null",
"performancedata.providerid = pdm.providerid",
),
SQL->Or(
"pdm.federalidnumber is null",
"performancedata.federalidnumber = pdm.federalidnumber",
),
"p4ppdcriteria.id = p4ppdcriteriadata.p4ppdcriteriaid",
"performancedata.p4ppdcriteriaid = p4ppdcriteria.id",
SQL->Or(
"performancedata.p4pmeasuresubscriptionid = pdm.p4pmeasuresubscriptionid",
"performancedata.p4pmeasuresubscriptionid is null AND p4ppdcriteriadata.key = 'ARGUMENTS.P4PMEASUREID' AND pdm.p4pmeasureid = p4ppdcriteriadata.value ",
),
"nvl(pdm.hiddenyn, 'N') = 'N'",
"pdm.deleted is null",
"pdm.guidelines = '0'",
);
if($get_measure_data_index ne 'OFF') {
$performancedatasql->Hints(
$get_measure_data_index,
);
}
@allmeasuredata = $performancedatasql->TableHash($dbh);
} else{
@allmeasuredata = $sql->TableHash($dbh);
}
@allmeasuredata = grep {$_->{P4PMEASURESUBSCRIPTIONID} ne undef || $_->{CRITERIACODE} =~ /^TASKCOMPLETION/ } @allmeasuredata;
my $mips_ia_data = \@allmeasuredata;
return $mips_ia_data;
}
##########################################################################################
# _AddReferenceMeasureNameForIA
#
# Description:
# Adds reference measure name with IA measure and remove the HIE: Clinical Information Reconciliation and
# Documentation of current medications measures from input list
#
# Parameters:
# Required:
# DATA : Measure hash
# Optional:
# None
#
# Return Value:
# ListRef[String]
##########################################################################################
sub _AddReferenceMeasureNameForIA{
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
DATA
)],
[qw(
)],
);
my @results = @{$args->{DATA}};
my @iaresults = grep { $_->{CATEGORY} eq 'IA' } @results;
my $programdefinition = BusCall::P4P::GetProgramDefinition($dbh, {
P4PPROGRAMID => $iaresults[0]->{P4PPROGRAMID},
});
my $measures = $programdefinition->Measures();
my @criterias = map {@{ $_->Criteria() || [] }} @{$measures};
foreach my $record(@iaresults) {
my @criteriacode = grep {
$_->CriteriaCode() eq $record->{CRITERIACODE}
} @criterias;
my @method = map {
$_->Method()
} @criteriacode;
if(scalar @method > 0 and $method[0] ne undef){
my @p4p_measure_ids = map {
$_->P4PMeasureID()
} @method;
my @referencemeasurename = map {
$_->MeasureName()
} grep {
$_->P4PMeasureID() eq $p4p_measure_ids[0];
} @criterias;
$record->{REFERENCEMEASURENAME} = $referencemeasurename[0];
}
}
return \@results;
}
################################################################################
# GetEnrolledPrograms
#
# Description:
# Gets where the provider is enrolled in both PI program
#
# Parameters:
# Required:
# FEDERALIDNUMBER The TIN whose MIPS statuses should be returned
# and/or
# PROVIDERID The provider whose MIPS statuses should be returned
#
# P4PPROGRAMIDS The ids of the MIPS PI programs in the year
# for which we are fetching data
#
# Returns:
# boolean value 1 if enrolled in both PI program else 0
################################################################################
sub GetEnrolledPrograms {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMIDS
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
ALLDUPLICATES
)],
);
my @p4p_program_ids = @{$args->{P4PPROGRAMIDS}};
my $providerid = $args->{PROVIDERID};
my $federalidnumber = $args->{FEDERALIDNUMBER};
my $includeallduplicates = $args->{ALLDUPLICATES};
my $npitinprovidermap;
my @duplicateproviderids;
push (@duplicateproviderids, $providerid);
if($includeallduplicates && $providerid) {
$npitinprovidermap = Clinical::P4P::Provider::GetNPITINProviderMap($dbh, {
ALLDUPLICATES => 1,
});
@duplicateproviderids = @{$npitinprovidermap->{ $providerid }{ $federalidnumber } };
}
my $enrolledproviderssql = SQL::Select->new(
)->Distinct(
)->Select(
'vp4penrollment.p4pprogramid',
)->From(
'vp4penrollment',
'provider',
'medicalgroup',
)->Joins(
'vp4penrollment.providerid = provider.id',
'provider.medicalgroupid = medicalgroup.id (+)',
)->Where(
['vp4penrollment.p4pprogramid in (??)', \@p4p_program_ids ],
'provider.username is not null',
'provider.deleted is null',
);
# Restriction by TIN pre-empts restriction by provider.
if (
$federalidnumber
) {
$enrolledproviderssql->Where(
['medicalgroup.federalidnumber = ?', $federalidnumber],
);
}
if (
$providerid && !$includeallduplicates
) {
$enrolledproviderssql->Where(
['provider.id = ? ', $providerid]
);
} elsif ($providerid && $includeallduplicates) {
$enrolledproviderssql->Where(
['provider.id IN (??) ', \@duplicateproviderids]
);
}
my @enrolledproviders = $enrolledproviderssql->TableHash($dbh);
return \@enrolledproviders;
}
################################################################################
# GetProgramIDForSubmission
#
# Description:
# Returns the program id from the list of programids
#
# Parameters:
# Required:
# P4PPROGRAMIDS
# ENTITYTYPE
# MIPSCOMPONENT
#
#
# Returns:
# program id for the given year , category and entitytype
################################################################################
sub GetProgramIDForSubmission {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMIDS
ENTITYTYPE
MIPSCOMPONENT
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
YEAR
ISMVP
)],
);
my $p4p_program_id = $args->{P4PPROGRAMIDS};
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $entity_type = $args->{ENTITYTYPE};
my $provider_id = $args->{PROVIDERID};
my $mips_component = $args->{MIPSCOMPONENT};
my $is_mvp = $args->{ISMVP} || 0;
my $year = $args->{YEAR} ? $args->{YEAR} : Clinical::P4P::ReportingPeriod::Get($dbh, {
P4PPROGRAMID => @$p4p_program_id[0],
})->ProgramYear();
if ($mips_component eq 'PI' || $is_mvp ) {
my $enrolled_program_list = Athena::P4P::App::PerformanceData::GetEnrolledPrograms($dbh, {
P4PPROGRAMIDS => $p4p_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
ALLDUPLICATES => 1,
});
my $pi_data = Athena::P4P::App::PerformanceData::_GetEntityTypeData({YEAR=>$year, CATEGORY=> $mips_component, ENTITYTYPE => $entity_type, ISMVP => $is_mvp});
$p4p_program_id = $pi_data->{$entity_type}->{FULLYEAR}->{P4PPROGRAMID};
my $is_mips_pi_90_days_enabled = Athena::RolloutToggle::GetEnabledVersion($dbh, {
KEY => 'MIPS_PI_QTLY',
}) eq 'ON';
if ($is_mips_pi_90_days_enabled) {
my @ninetydayslist = split(m/[,]/, $pi_data->{$entity_type}->{NINETYDAYS}->{P4PPROGRAMID});
my @fullyearlist;
if($is_mvp) {
@fullyearlist = split(m/[,]/, $p4p_program_id);
push (@ninetydayslist, @fullyearlist);
}
foreach my $ninetyday (@ninetydayslist) {
if (grep {$_->{P4PPROGRAMID} eq $ninetyday } @$enrolled_program_list) {
$p4p_program_id = $ninetyday;
last;
}
}
if($is_mvp && scalar @$enrolled_program_list == 0) {
$p4p_program_id = $fullyearlist[0];
}
}
else {
if (grep {$_->{P4PPROGRAMID} eq $pi_data->{$entity_type}->{NINETYDAYS}->{P4PPROGRAMID} } @$enrolled_program_list) {
$p4p_program_id = $pi_data->{$entity_type}->{NINETYDAYS}->{P4PPROGRAMID};
}
}
}
else {
$p4p_program_id = @$p4p_program_id[0];
}
return $p4p_program_id;
}
################################################################################
# GetRepresentativeProviderNameBasedClinicalEncouterY
#
# Description:
# Returns the listref of hashrefs of those providers whose minm providerids has
# ClinicalEncouterCheckYN is set to Y for the given NPI
# Parameters:
# Required:
# DATAS listref of hashrefs of MIPS PerformanceData
#
#
#
# Returns:
# listref of hashrefs of MIPS PerformanceData with updated provider name
################################################################################
sub GetRepresentativeProviderNameBasedClinicalEncouterY {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields($args,
[qw(
DATAS
)], [qw(
VALIDATEENROLLMENTSTATUS
YEAR
)],
);
my $datas = $args->{DATAS};
my $year = $args->{YEAR};
my $validateenrollmentstatus = $args->{VALIDATEENROLLMENTSTATUS};
my %groupbydata = Athena::Util::Hash::HashGroupBy(['NPI'], @{$datas});
my @npis = keys %groupbydata;
my %providerinfo = %{Clinical::P4P::Utils::GetRepresentativeProviderInfo($dbh,{
NPIS => \@npis,
YEAR => $year,
})};
my @updatedlist;
foreach my $data (@$datas) {
if (exists($providerinfo{$data->{NPI}}{$data->{FEDERALIDNUMBER}}[0]->{PROVIDERID})) {
if (
$providerinfo{$data->{NPI}}{$data->{FEDERALIDNUMBER}}[0]->{PROVIDERID} ne $data->{PROVIDERID}
) {
$data->{PROVIDERNAME} = $providerinfo{$data->{NPI}}{$data->{FEDERALIDNUMBER}}[0]->{PROVIDERNAME};
}
push (@updatedlist, $data);
}
elsif (($validateenrollmentstatus ? ($data->{PROVIDERNAME} eq 'All' && $data->{NPI} eq undef && $data->{ENROLLMENTSTATUS} eq '1') : ($data->{PROVIDERNAME} eq 'All' && $data->{NPI} eq undef))) {
push (@updatedlist, $data);
}
}
return \@updatedlist;
}
################################################################################
# _GetEligibilityStatus
#
# Description:
# Evaluates whether the given entity is eligible for submission based on
# the eligibility status of the entity.
#
# Parameters:
# Required:
#
# YEAR Scalar Year to check the eligibilty for.
# At least one of:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# PROVIDERID Scalar ID of the provider for whom to retreive data
#
#
# Returns:
# String. A string that represents the current status of eligibility.
################################################################################
sub _GetEligibilityStatus {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
YEAR
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $performance_year = $args->{YEAR};
# get eligibility status for this entity
my $eligibilitystatussql = Athena::P4P::Persistence::ProgramEligibility::GetMIPSEligibilityStatus($dbh,{
FEDERALIDNUMBER => $federal_id_number,
YEAR => $performance_year,
PROVIDERID => $provider_id,
});
my $iseligible;
my @results = $eligibilitystatussql->TableHash($dbh);
my $mipseligibilitystatus = $results[0]->{MIPSELIGIBILITYSTATUS};
return $mipseligibilitystatus;
}
################################################################################
# _UpdateMetadataForEligibilityStatus
#
# Update the eligibility status.
#
# Parameters:
# Required:
#
# YEAR Scalar Year to check the eligibilty for.
# MIPSCOMPONENT String Component to retreive eligibilty.
# At least one of:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# PROVIDERID Scalar ID of the provider for whom to retreive data
# SUBMISSIONBLOCKINGREASON String Submission blocking reason
#
# Returns:
# String submission blocking reason.
################################################################################
sub _UpdateMetadataForEligibilityStatus {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
YEAR
MIPSCOMPONENT
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
SUBMISSIONBLOCKINGREASON
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $year = $args->{YEAR};
my $mips_component = $args->{MIPSCOMPONENT};
my $submission_blocking_reason = $args->{SUBMISSIONBLOCKINGREASON} || '';
my $username = $Global::session{USERNAME} || 'ATHENA';
my $p4p_program_id = Athena::P4P::App::PerformanceData::GetMIPSProgram($dbh, {
CATEGORY => $mips_component,
YEAR => $year,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
$p4p_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $p4p_program_id,
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $mips_component,
YEAR => $year,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
# MIPS is actually represented by 3 separate programs -
# quality, ACI and IA. We want to replicate the composite score
# across all three program submission object, and store the category scores
# in the appropriate submission objects.
my $mips_program_ids_by_category = Athena::P4P::App::PerformanceData::GetMIPSProgramsByCategory($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my $category_program_id;
foreach my $category ( keys %{ $mips_program_ids_by_category } ) {
$category_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $mips_program_ids_by_category->{$category},
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $category,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
my $category_submission_object = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $category_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
# If the submission object does not exist for some reason, move on.
next if $category_submission_object->NoDenormalizedData();
my $lower_case_category = lc $category;
$category_submission_object->UpdateMetaData({
USERNAME => $username,
DATA => {
SUBMISSION_BLOCKING_REASON => $submission_blocking_reason,
},
});
}
return $submission_blocking_reason;
}
################################################################################
# GetSubmissionStatus
#
# Update the eligibility status.
#
# Parameters:
# Required:
#
# P4PPROGRAMID Integer P4P Program associated with the category.
# At least one of:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# PROVIDERID Scalar ID of the provider for whom to retreive data
#
# Returns:
# String submission blocking reason.
################################################################################
sub GetSubmissionStatus {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $mips_program_ids_by_category = Athena::P4P::App::PerformanceData::GetMIPSProgramsByCategory($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my $submission_blocking_reason = '';
my $category_program_id;
foreach my $category ( keys %{ $mips_program_ids_by_category } ) {
$category_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $mips_program_ids_by_category->{$category},
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $category,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
my $category_submission_object = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $category_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
# If the submission object does not exist for some reason, move on.
next if $category_submission_object->NoDenormalizedData();
my $lower_case_category = lc $category;
my $metadata = $category_submission_object->GetMetaData ({
KEYS => [qw(
SUBMISSION_BLOCKING_REASON
)],
});
$submission_blocking_reason = $metadata->{SUBMISSION_BLOCKING_REASON};
if($submission_blocking_reason ne '') {
last;
}
}
return $submission_blocking_reason;
}
################################################################################
# IsAllMIPSCategerorySubmitted
#
# Update the eligibility status.
#
# Parameters:
# Required:
#
# P4PPROGRAMID Integer P4P Program associated with the category.
# At least one of:
# FEDERALIDNUMBER Scalar TIN for which to retreive data
# PROVIDERID Scalar ID of the provider for whom to retreive data
#
# Returns:
# Boolean if all categories are submitted or not.
################################################################################
sub IsAllMIPSCategerorySubmitted {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
P4PPROGRAMID
),
{
ONEPLUS => [qw(
PROVIDERID
FEDERALIDNUMBER
)],
}],
[qw(
)],
);
my $federal_id_number = $args->{FEDERALIDNUMBER};
my $provider_id = $args->{PROVIDERID};
my $p4p_program_id = $args->{P4PPROGRAMID};
my $mips_program_ids_by_category = Athena::P4P::App::PerformanceData::GetMIPSProgramsByCategory($dbh, {
P4PPROGRAMID => $p4p_program_id,
});
my $isallmipscategorysubmitted = 1;
my $category_program_id;
foreach my $category ( keys %{ $mips_program_ids_by_category } ) {
$category_program_id = Athena::P4P::App::PerformanceData::GetProgramIDForSubmission($dbh, {
P4PPROGRAMIDS => $mips_program_ids_by_category->{$category},
FEDERALIDNUMBER => $federal_id_number,
PROVIDERID => $provider_id,
MIPSCOMPONENT => $category,
ENTITYTYPE => $provider_id ? 'INDIVIDUAL' : 'GROUP',
});
my $category_submission_object = Clinical::P4P::Persistence::ProgramSubmission->new({
DBH => $dbh,
P4PPROGRAMID => $category_program_id,
PROVIDERID => $provider_id,
FEDERALIDNUMBER => $federal_id_number,
});
# If the submission object does not exist for some reason, move on.
next if $category_submission_object->NoDenormalizedData();
my $submission_number = $category_submission_object->CurrentSubmissionNumber() || 1;
my $status_hash = $category_submission_object->GetStatusBySubmissionNumber({
SUBMISSIONNUMBER => $submission_number,
}) || {};
my $program_status = $status_hash->{STATUS};
if($program_status ne 'SUBMITTED') {
$isallmipscategorysubmitted = 0;
#break if we get any category submission status as not submitted
last;
}
}
return $isallmipscategorysubmitted;
}
################################################################################
# _MergeNewWithExistingData
#
# Call merge operation for merging new measure performance with existing data.
#
# Required Parameters:
# DATA - Arrayref - List of hashrefs containing rows to insert into P4PMEASUREPERFORMANCE.
# Should be return value of FetchMIPSMeasurePerformanceData.
#
# P4PPROGRAMID - Integer - Used to remove denormalized data for this program ID
# that was not otherwise being updated per $args->{DATA}.
# USERNAME - String - Username to make DB commits with.
#
# Returns:
# void.
################################################################################
sub _MergeNewWithExistingData {
my ($dbh, $args) = @_;
Athena::Util::Assert::AssertFields(
$args,
[qw(
DATA
P4PPROGRAMID
USERNAME
)],
[qw(
ISMIPSPHRENABLED
SUBGROUPID
)],
);
my $data = $args->{DATA};
my $username = $args->{USERNAME};
my $p4pprogramid = $args->{P4PPROGRAMID};
my $context_id = Athena::Util::Database::SessionInfo($dbh)->{context};
my $is_mips_phr_enabled = $args->{ISMIPSPHRENABLED} || undef;
my $subgroupid = $args->{SUBGROUPID};
while(@$data) {
my $newdata = [splice @$data, 0, 100];
if($subgroupid ne undef){
foreach my $datum (@$newdata) {
$datum->{SUBGROUPID} = $subgroupid;
}
}
my $begin = time();
Athena::Util::SQL::ProcessTable($dbh, {
OPERATION => 'Merge',
TABLENAME => 'P4PMEASUREPERFORMANCE',
TABLEROWS => $newdata,
USERNAME => $username,
COLUMNNAMES => P4PMEASUREPERFORMANCE_COLUMNS(),
UNIQUECOLUMNNAMES => _GetUniqueMeasurePerformanceColumns($dbh, {
MIPS_PHR_TOGGLE => $is_mips_phr_enabled
}),
});
my $timetakenformerge = time() - $begin;
my $count = scalar(@$newdata);
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'{%.3f} Time taken for merge - complete - complete',
$timetakenformerge,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
Clinical::P4P::Log::Log($dbh, {
LEVEL => 'performance',
MESSAGE => sprintf(
'No of records for merge::'.$count,
),
SCRIBEIDENTIFIER => 'p4psubmissionlogs',
TAGS => {
CONTEXTID => $context_id,
P4PPROGRAMID => $p4pprogramid,
},
});
}
}
1;
Editor is loading...
Leave a Comment