PerformanceData

 avatar
unknown
perl
a month ago
192 kB
2
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;
Leave a Comment