diff --git a/Constants.py b/Constants.py index b319d41..e799f8d 100644 --- a/Constants.py +++ b/Constants.py @@ -1,7 +1,7 @@ from enum import Enum # Variable Constants for MainDriver.py -HELP_SITE = "https://git.library.upei.ca/mbelvadi/COUNTER-5-Report-Tool/wiki" +HELP_SITE = "https://github.com/CS-4820-Library-Project/COUNTER-5-Report-Tool/wiki" # region Variable Constants for ManageDB @@ -427,6 +427,7 @@ CURRENCY_LIST = ('USD', 'EUR', 'JPY', 'GBP', 'CHF', 'CAD', 'AUD') JSON_FILTER = ('JSON files (*.dat)',) TSV_FILTER = ('TSV files (*.tsv)',) CSV_FILTER = ('CSV files (*.csv)',) +TSV_AND_CSV_FILTER = ('Report files (*.csv *.tsv)',) EXCEL_FILTER = ('Excel files (*.xlsx)',) # endregion @@ -607,3 +608,36 @@ VENDORS_FILE_PATH = VENDORS_FILE_DIR + VENDORS_FILE_NAME EXPORT_VENDORS_FILE_NAME = "exported_vendor_data.tsv" # endregion + + +# region Variable Constants for ImportFile +COUNTER_4_REPORT_EQUIVALENTS = { + "BR1": "TR, TR_B1", + "BR1, BR2": "TR, TR_B1", + "BR1, BR2, BR3, JR1, JR2": "TR, TR_B1, TR_B2, TR_J1, TR_J2", + "BR2": "TR, TR_B1", + "BR3": "TR, TR_B2", + "DB1": "DR, DR_D1", + "DB1, DB2": "DR, DR_D1, DR_D2", + "DB2": "DR, DR_D2", + "JR1": "TR, TR_J1", + "JR1, JR2": "TR, TR_J1, TR_J2", + "JR2": "TR, TR_J2", + "PR1": "PR, PR_P1" +} + +COUNTER_5_REPORT_EQUIVALENTS = { + "TR_B1": "BR1, BR2", + "TR_B2": "BR3", + "TR_J1": "JR1", + "TR_J2": "JR2", + "TR": "BR1, BR2, BR3, JR1, JR2", + "DR_D1": "DB1", + "DR_D2": "DB2", + "DR": "DB1, DB2", + "JR1": "TR_J1", + "JR2": "TR_J2", + "PR_P1": "PR1", + "PR": "PR1" +} +# endregion diff --git a/Costs.py b/Costs.py index 1206d28..65fa9f2 100644 --- a/Costs.py +++ b/Costs.py @@ -148,7 +148,7 @@ class CostsController: self.names = [result[0] for result in names_results] else: self.names = [] - if self.settings.show_debug_messages: print(names_results) + # if self.settings.show_debug_messages: print(names_results) costs_sql_text, costs_data = ManageDB.get_names_with_costs_sql_text(self.report_parameter, self.vendor_parameter, diff --git a/Counter4.py b/Counter4.py new file mode 100644 index 0000000..7a8c3cb --- /dev/null +++ b/Counter4.py @@ -0,0 +1,477 @@ +import csv +from datetime import datetime, timezone +from os import path, makedirs + +from PyQt5.QtCore import QDate + +import GeneralUtils +from Constants import COUNTER_4_REPORT_EQUIVALENTS, COUNTER_5_REPORT_EQUIVALENTS, MajorReportType +from FetchData import ReportRow, ReportHeaderModel, TypeValueModel, NameValueModel, ReportWorker +from ManageVendors import Vendor + + +class Counter4ReportHeader: + def __init__(self, report_type: str, customer: str, institution_id: str, reporting_period: str, date_run: str): + self.report_type = report_type + self.customer = customer + self.institution_id = institution_id + self.reporting_period = reporting_period + self.date_run = date_run + + +class Counter4ReportModel: + def __init__(self, report_header: Counter4ReportHeader, header_list: list, row_dicts: list): + self.report_header = report_header + self.header_list = header_list + self.row_dicts = row_dicts + + +class Counter4To5Converter: + def __init__(self, vendor: Vendor, c4_report_types: str, file_paths: list, save_dir: str, date: QDate): + self.vendor = vendor + self.c4_report_types = c4_report_types + self.file_paths = file_paths + self.save_dir = save_dir + self.begin_date = QDate(date.year(), 1, 1) + self.end_date = QDate(date.year(), 12, 31) + self.target_c5_report_types = self.get_c5_equivalent(c4_report_types) + + self.final_rows_dict = {} + + def do_conversion(self) -> dict: + file_paths = {} + report_rows_dict = {} # {report_type: report_rows_dict} + c4_report_types_processed = [] + c4_customer = "" + c4_institution_id = "" + for file_path in self.file_paths: + report_model = self.c4_file_to_c4_model(file_path) + c4_report_header = report_model.report_header + short_c4_report_type = self.get_short_c4_report_type(c4_report_header.report_type) + if short_c4_report_type not in self.c4_report_types: + continue + + c4_report_types_processed.append(short_c4_report_type) + c4_customer = c4_report_header.customer + c4_institution_id = c4_report_header.institution_id + report_rows = self.c4_model_to_rows(report_model) + report_rows_dict[short_c4_report_type] = report_rows + + if not c4_report_types_processed: + raise Exception("No valid COUNTER 4 report selected for this operation") + + # Create a final COUNTER 5 file for each target c5 report type + for c5_report_type in self.target_c5_report_types.split(", "): + required_c4_report_types = self.get_c4_equivalent(c5_report_type).split(", ") + c4_report_types_used = [] + c5_report_type_rows = [] + + # Fill up c5_report_type_rows with rows from required_c4_report_types + for c4_report_type in required_c4_report_types: + if c4_report_type in report_rows_dict: + c5_report_type_rows += report_rows_dict[c4_report_type] + c4_report_types_used.append(c4_report_type) + + if not c4_report_types_used: # If no c4 file for this c5 report type is available + continue + + # Sort the rows + c5_major_report_type = GeneralUtils.get_major_report_type(c5_report_type) + c5_report_type_rows = ReportWorker.sort_rows(c5_report_type_rows, c5_major_report_type) + + # Create header for this report + c5_report_header = self.get_c5_report_header(c5_report_type, + ", ".join(c4_report_types_used), + c4_customer, + c4_institution_id) + + # Create the c5 file + file_path = self.create_c5_file(c5_report_header, c5_report_type_rows) + file_paths[c5_report_type] = file_path + + return file_paths + + def c4_file_to_c4_model(self, file_path: str) -> Counter4ReportModel: + file = open(file_path, 'r', encoding="utf-8") + + extension = file_path[-4:] + delimiter = "" + if extension == ".csv": + delimiter = "," + elif extension == ".tsv": + delimiter = "\t" + + # Process process report header into model + csv_reader = csv.reader(file, delimiter=delimiter) + + report_type = "" + customer = "" + institution_id = "" + reporting_period = "" + date_run = "" + + curr_line = 1 + last_header_line = 7 + + for row in csv_reader: + if curr_line == 1: + report_type = row[0] + elif curr_line == 2: + customer = row[0] + elif curr_line == 3: + institution_id = row[0] + elif curr_line == 4 and row[0].lower() != "period covered by report:": + file.close() + raise Exception("'Period covered by Report:' missing from header line 4") + elif curr_line == 5: + reporting_period = row[0] + elif curr_line == 6 and row[0].lower() != "date run:": + file.close() + raise Exception("'Date run:' missing from header line 6") + elif curr_line == 7: + date_run = row[0] + is_valid_date = QDate().fromString(date_run, "yyyy-MM-dd").isValid() or \ + QDate().fromString(date_run, "MM-dd-yy").isValid() or \ + QDate().fromString(date_run, "M-d-yy").isValid() + if not is_valid_date: + file.close() + raise Exception("Invalid date on line 7") + + curr_line += 1 + + if curr_line > last_header_line: + break + + if curr_line <= last_header_line: + file.close() + raise Exception("Not enough lines in report header") + + report_header = Counter4ReportHeader(report_type, customer, institution_id, reporting_period, date_run) + + # Process process report rows into model + csv_dict_reader = csv.DictReader(file, delimiter=delimiter) + header_dict = csv_dict_reader.fieldnames + row_dicts = [] + + for row in csv_dict_reader: + row_dicts.append(row) + + report_model = Counter4ReportModel(report_header, header_dict, row_dicts) + + file.close() + + return report_model + + def c4_model_to_rows(self, report_model: Counter4ReportModel) -> list: + short_c4_report_type = self.get_short_c4_report_type(report_model.report_header.report_type) + c4_major_report_type = self.get_c4_major_report_type(short_c4_report_type) + report_rows_dict = {} # {name, metric_type: report_row} + + for row_dict in report_model.row_dicts: + report_row = self.convert_c4_row_to_c5(short_c4_report_type, row_dict) + + if report_row.total_count == 0: # Exclude rows with reporting total of 0 + continue + + if c4_major_report_type == MajorReportType.DATABASE: + if report_row.database.lower().startswith("total for all"): # Exclude total rows + continue + + if (report_row.database, report_row.metric_type) not in report_rows_dict: + report_rows_dict[report_row.database, report_row.metric_type] = report_row + else: + existing_row: ReportRow = report_rows_dict[report_row.database, report_row.metric_type] + existing_metric_type_total = existing_row.total_count + new_metric_type_total = report_row.total_count + + if existing_row.metric_type == "Total_Item_Investigations": + if new_metric_type_total > existing_metric_type_total: + report_rows_dict[report_row.database, report_row.metric_type] = report_row + + elif c4_major_report_type == MajorReportType.TITLE: + if report_row.title.lower().startswith("total for all"): # Exclude total rows + continue + + if (report_row.title, report_row.metric_type) not in report_rows_dict: + report_rows_dict[report_row.title, report_row.metric_type] = report_row + else: + existing_row: ReportRow = report_rows_dict[report_row.title, report_row.metric_type] + existing_metric_type_total = existing_row.total_count + new_metric_type_total = report_row.total_count + + if existing_row.metric_type == "Total_Item_Investigations": + if new_metric_type_total > existing_metric_type_total: + report_rows_dict[report_row.title, report_row.metric_type] = report_row + + elif c4_major_report_type == MajorReportType.PLATFORM: + report_rows_dict[report_row.platform, report_row.metric_type] = report_row + + return list(report_rows_dict.values()) + + def convert_c4_row_to_c5(self, c4_report_type: str, row_dict: dict) -> ReportRow: + report_row = ReportRow(self.begin_date, self.end_date) + c4_major_report_type = self.get_c4_major_report_type(c4_report_type) + + if c4_major_report_type == MajorReportType.DATABASE: + if "Database" in row_dict: + report_row.database = row_dict["Database"] + if "Publisher" in row_dict: + report_row.publisher = row_dict["Publisher"] + if "Platform" in row_dict: + report_row.platform = row_dict["Platform"] + + # Metric type + if c4_report_type == "DB1": + if "User Activity" in row_dict: + ua = row_dict["User Activity"] + if ua == "Regular Searches": + report_row.metric_type = "Searches_Regular" + elif "federated and automated" in ua: # Searches-federated and automated + report_row.metric_type = "Searches_Automated" + elif ua == "Result Clicks" or ua == "Record Views": + report_row.metric_type = "Total_Item_Investigations" + elif c4_report_type == "DB2": + adc = None + if "Access Denied Category" in row_dict: + adc = row_dict["Access Denied Category"] + elif "Access denied category" in row_dict: + adc = row_dict["Access denied category"] + + if adc: + if "limit exceded" in adc or "limit exceeded" in adc: + report_row.metric_type = "Limit_Exceeded" + elif "not licenced" in adc or "not licensed" in adc: + report_row.metric_type = "No_License" + + elif c4_major_report_type == MajorReportType.TITLE: + if "" in row_dict: + report_row.title = row_dict[""] + if "Title" in row_dict: + report_row.title = row_dict["Title"] + if "Journal" in row_dict: + report_row.title = row_dict["Journal"] + if "Publisher" in row_dict: + report_row.publisher = row_dict["Publisher"] + if "Platform" in row_dict: + report_row.platform = row_dict["Publisher"] + if "Book DOI" in row_dict: + report_row.doi = row_dict["Book DOI"] + if "Journal DOI" in row_dict: + report_row.doi = row_dict["Journal DOI"] + if "Proprietary Identifier" in row_dict: + report_row.proprietary_id = row_dict["Proprietary Identifier"] + if "ISBN" in row_dict: + report_row.isbn = row_dict["ISBN"] + if "ISSN" in row_dict: + report_row.online_issn = row_dict["ISSN"] + if "Print ISSN" in row_dict: + report_row.print_issn = row_dict["Print ISSN"] + if "Online ISSN" in row_dict: + report_row.print_issn = row_dict["Online ISSN"] + + # Metric type + if c4_report_type == "BR1": + report_row.metric_type = "Unique_Title_Requests" + elif c4_report_type == "BR2" or c4_report_type == "JR1": + report_row.metric_type = "Total_Item_Requests" + elif c4_report_type == "BR3" or c4_report_type == "JR2": + adc = None + if "Access Denied Category" in row_dict: + adc = row_dict["Access Denied Category"] + elif "Access denied category" in row_dict: + adc = row_dict["Access denied category"] + + if adc: + if "limit exceded" in adc or "limit exceeded" in adc: + report_row.metric_type = "Limit_Exceeded" + elif "not licenced" in adc or "not licensed" in adc: + report_row.metric_type = "No_License" + + elif c4_major_report_type == MajorReportType.PLATFORM: + if "Platform" in row_dict: + report_row.platform = row_dict["Platform"] + if "Publisher" in row_dict: + report_row.publisher = row_dict["Publisher"] + + # Metric type + if c4_report_type == "PR1": + if "User Activity" in row_dict: + ua = row_dict["User Activity"] + if ua == "Regular Searches": + report_row.metric_type = "Searches_Regular" + elif ua == "Searches-federated and automated": + report_row.metric_type = "Searches_Automated" + elif ua == "Result Clicks" or ua == "Record Views": + report_row.metric_type = "Total_Item_Investigations" + + if "Reporting Period Total" in row_dict: + if row_dict["Reporting Period Total"]: + report_row.total_count = int(row_dict["Reporting Period Total"]) + else: + report_row.total_count = 0 + + # Month Columns + year = int(self.begin_date.toString("yyyy")) + year2 = int(self.begin_date.toString("yy")) + for i in range(0, 12): + month = QDate(year, i + 1, 1).toString("MMM") + month_year = f"{month}-{year}" + month_year2 = f"{month}-{year2}" + year_month = f"{year}-{month}" + year_month2 = f"{year2}-{month}" + month_value = "" + if month_year in row_dict: + month_value = row_dict[month_year] + elif month_year2 in row_dict: + month_value = row_dict[month_year2] + elif year_month in row_dict: + month_value = row_dict[year_month] + elif year_month2 in row_dict: + month_value = row_dict[year_month2] + + if month_value: + report_row.month_counts[month_year] = int(month_value) + + return report_row + + def get_c5_report_header(self, target_c5_report_type, c4_report_types: str, customer: str, + institution_id: str) -> ReportHeaderModel: + return ReportHeaderModel(self.get_long_c5_report_type(target_c5_report_type), + target_c5_report_type, + "5", + customer, + [TypeValueModel("Institution_ID", institution_id)], + self.get_c5_header_report_filters(target_c5_report_type), + [], + [], + self.get_c5_header_created(), + self.get_c5_header_created_by(c4_report_types)) + + def create_c5_file(self, c5_report_header: ReportHeaderModel, report_rows: list) -> str: + c5_report_type = c5_report_header.report_id + file_path = self.save_dir + f"temp_converted_c5_file_{c5_report_type}.tsv" + + if not path.isdir(self.save_dir): + makedirs(self.save_dir) + + file = open(file_path, 'w', encoding="utf-8", newline='') + + ReportWorker.add_report_header_to_file(c5_report_header, file, True) + ReportWorker.add_report_rows_to_file(c5_report_type, report_rows, self.begin_date, self.end_date, + file, False) + + file.close() + + return file_path + + @staticmethod + def get_short_c4_report_type(long_c4_report_type: str) -> str: + short_report_type = "" + if "Book Report 1 (R4)" in long_c4_report_type: + short_report_type = "BR1" + elif "Book Report 2 (R4)" in long_c4_report_type: + short_report_type = "BR2" + elif "Book Report 3 (R4)" in long_c4_report_type: + short_report_type = "BR3" + elif "Database Report 1 (R4)" in long_c4_report_type: + short_report_type = "DB1" + elif "Database Report 2 (R4)" in long_c4_report_type: + short_report_type = "DB2" + elif "Journal Report 1 (R4)" in long_c4_report_type: + short_report_type = "JR1" + elif "Journal Report 2 (R4)" in long_c4_report_type: + short_report_type = "JR2" + elif "Platform Report 1 (R4)" in long_c4_report_type: + short_report_type = "PR1" + + return short_report_type + + @staticmethod + def get_long_c5_report_type(short_c5_report_type: str) -> str: + long_c5_report_type = "" + if short_c5_report_type == "DR": + long_c5_report_type = "Database Master Report" + elif short_c5_report_type == "DR_D1": + long_c5_report_type = "Database Search and Item Usage" + elif short_c5_report_type == "DR_D2": + long_c5_report_type = "Database Access Denied" + elif short_c5_report_type == "TR": + long_c5_report_type = "Title Master Report" + elif short_c5_report_type == "TR_B1": + long_c5_report_type = "Book Requests (Excluding OA_Gold)" + elif short_c5_report_type == "TR_B2": + long_c5_report_type = "Book Access Denied" + elif short_c5_report_type == "TR_J1": + long_c5_report_type = "Journal Requests (Excluding OA_Gold)" + elif short_c5_report_type == "TR_J2": + long_c5_report_type = "Journal Access Denied" + elif short_c5_report_type == "PR_P1": + long_c5_report_type = "Platform Usage" + + return long_c5_report_type + + def get_c5_header_report_filters(self, target_c5_report_type: str) -> list: + filters = [] + if target_c5_report_type == "DR_D1": + filters = [NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Searches_Automated|Searches_Federated|Searches_Regular|" + "Total_Item_Investigations|Total_Item_Requests")] + elif target_c5_report_type == "DR_D2": + filters = [NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Limit_Exceeded|No_License")] + elif target_c5_report_type == "PR_P1": + filters = [NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Searches_Platform|Total_Item_Requests|Unique_Item_Requests|" + "Unique_Title_Requests")] + elif target_c5_report_type == "TR_B1": + filters = [NameValueModel("Data_Type", "Book"), + NameValueModel("Access_Type", "Controlled"), + NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Total_Item_Requests|Unique_Title_Requests")] + elif target_c5_report_type == "TR_B2": + filters = [NameValueModel("Data_Type", "Book"), + NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Limit_Exceeded|No_License")] + elif target_c5_report_type == "TR_J1": + filters = [NameValueModel("Data_Type", "Journal"), + NameValueModel("Access_Type", "Controlled"), + NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Total_Item_Requests|Unique_Item_Requests")] + elif target_c5_report_type == "TR_J2": + filters = [NameValueModel("Data_Type", "Journal"), + NameValueModel("Access_Method", "Regular"), + NameValueModel("Metric_Type", "Limit_Exceeded|No_License")] + + filters += [NameValueModel("Begin_Date", self.begin_date.toString("yyyy-MM-dd")), + NameValueModel("End_Date", self.end_date.toString("yyyy-MM-dd"))] + + return filters + + @staticmethod + def get_c5_header_created() -> str: + return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + def get_c5_header_created_by(self, short_c4_report_type: str) -> str: + return f"COUNTER 5 Report Tool, converted from {self.vendor.name} COP4 {short_c4_report_type}" + + @staticmethod + def get_c5_equivalent(counter4_report_type: str) -> str: + return COUNTER_4_REPORT_EQUIVALENTS[counter4_report_type] + + @staticmethod + def get_c4_equivalent(counter5_report_type: str) -> str: + return COUNTER_5_REPORT_EQUIVALENTS[counter5_report_type] + + @staticmethod + def get_c4_major_report_type(c4_report_type: str) -> MajorReportType: + """Returns a major report type that a report type falls under""" + + if c4_report_type == "DB1" or c4_report_type == "DB2": + return MajorReportType.DATABASE + + elif c4_report_type == "BR1" or c4_report_type == "BR2" or c4_report_type == "BR3" \ + or c4_report_type == "JR1" or c4_report_type == "JR2": + return MajorReportType.TITLE + + elif c4_report_type == "PR1": + return MajorReportType.PLATFORM \ No newline at end of file diff --git a/FetchData.py b/FetchData.py index 1d3aaf6..cb09ccc 100644 --- a/FetchData.py +++ b/FetchData.py @@ -191,7 +191,7 @@ class ReportModel(JsonModel): report_header = ReportHeaderModel.from_json(json_dict["Report_Header"]) report_type = report_header.report_id - major_report_type = get_major_report_type(report_type) + major_report_type = GeneralUtils.get_major_report_type(report_type) report_header.major_report_type = major_report_type report_items = [] @@ -509,23 +509,6 @@ def get_models(model_key: str, model_type, json_dict: dict) -> list: return models -def get_major_report_type(report_type: str) -> MajorReportType: - """Returns a major report type that a report type falls under""" - if report_type == "PR" or report_type == "PR_P1": - return MajorReportType.PLATFORM - - elif report_type == "DR" or report_type == "DR_D1" or report_type == "DR_D2": - return MajorReportType.DATABASE - - elif report_type == "TR" or report_type == "TR_B1" or report_type == "TR_B2" \ - or report_type == "TR_B3" or report_type == "TR_J1" or report_type == "TR_J2" \ - or report_type == "TR_J3" or report_type == "TR_J4": - return MajorReportType.TITLE - - elif report_type == "IR" or report_type == "IR_A1" or report_type == "IR_M1": - return MajorReportType.ITEM - - def get_month_years(begin_date: QDate, end_date: QDate) -> list: """Returns a list of month-year (MMM-yyyy) strings within a date range""" month_years = [] @@ -623,19 +606,6 @@ class ReportRow: self.month_counts = {} - # This only works with 12 months - # for i in range(12): - # curr_date: QDate - # if QDate(begin_date.year(), i + 1, 1) < begin_date: - # curr_date = QDate(end_date.year(), i + 1, 1) - # else: - # curr_date = QDate(begin_date.year(), i + 1, 1) - # - # self.month_counts[curr_date.toString("MMM-yyyy")] = 0 - # - # self.total_count = 0 - - # This works with more than 12 months for month_year_str in get_month_years(begin_date, end_date): self.month_counts[month_year_str] = 0 @@ -1513,18 +1483,8 @@ class FetchSpecialReportsController(FetchReportsAbstract): """ if date_type == "begin_date": self.begin_date = QDate(date.year(),self.begin_date.month(),self.begin_date.day()) - # if self.begin_date.year() != self.end_date.year(): - # self.end_date.setDate(self.begin_date.year(), - # self.end_date.month(), - # self.end_date.day()) - # self.end_date_edit.setDate(self.end_date) elif date_type == "end_date": self.end_date = QDate(date.year(),self.end_date.month(),self.end_date.day()) - # if self.end_date.year() != self.begin_date.year(): - # self.begin_date.setDate(self.end_date.year(), - # self.begin_date.month(), - # self.begin_date.day()) - # self.begin_date_edit.setDate(self.begin_date) def on_date_month_changed(self, month: int, date_type: str): """Handles the signal emitted when a date's month is changed @@ -2068,7 +2028,7 @@ class ReportWorker(QObject): attributes_to_show += f"|{option_name}" attr_count += 1 elif self.is_yearly and self.is_master: - major_report_type = get_major_report_type(self.report_type) + major_report_type = GeneralUtils.get_major_report_type(self.report_type) if major_report_type == MajorReportType.PLATFORM: attributes_to_show = "|".join(PLATFORM_REPORTS_ATTRIBUTES) elif major_report_type == MajorReportType.DATABASE: @@ -2460,7 +2420,8 @@ class ReportWorker(QObject): report_rows = self.sort_rows(report_rows, major_report_type) self.save_tsv_files(report_model.report_header, report_rows) - def sort_rows(self, report_rows: list, major_report_type: MajorReportType) -> list: + @staticmethod + def sort_rows(report_rows: list, major_report_type: MajorReportType) -> list: """Sorts the rows of the report :param report_rows: The report's rows @@ -2507,7 +2468,8 @@ class ReportWorker(QObject): else: self.add_report_header_to_file(report_header, file, True) - if not self.add_report_rows_to_file(report_type, report_rows, file, False): + if not self.add_report_rows_to_file(report_type, report_rows, self.begin_date, self.end_date, file, False, + self.is_special, self.special_options): self.process_result.completion_status = CompletionStatus.WARNING file.close() @@ -2528,12 +2490,13 @@ class ReportWorker(QObject): protected_file_path = f"{protected_file_dir}{file_name}" protected_file = open(protected_file_path, 'w', encoding="utf-8", newline='') self.add_report_header_to_file(report_header, protected_file, True) - self.add_report_rows_to_file(report_type, report_rows, protected_file, True) + self.add_report_rows_to_file(report_type, report_rows, self.begin_date, self.end_date, protected_file, True) protected_file.close() self.process_result.protected_file_path = protected_file_path - def add_report_header_to_file(self, report_header: ReportHeaderModel, file, include_attributes: bool): + @staticmethod + def add_report_header_to_file(report_header: ReportHeaderModel, file, include_attributes: bool): """Adds the report header to a TSV file :param report_header: The report header model @@ -2580,21 +2543,28 @@ class ReportWorker(QObject): tsv_writer.writerow(["Created_By", report_header.created_by]) tsv_writer.writerow([]) - def add_report_rows_to_file(self, report_type: str, report_rows: list, file, include_all_attributes: bool) -> bool: + @staticmethod + def add_report_rows_to_file(report_type: str, report_rows: list, begin_date: QDate, end_date: QDate, file, + include_all_attributes: bool, is_special: bool = False, + special_options: SpecialReportOptions = None) -> bool: """Adds the report's rows to a TSV file :param report_type: The report type :param report_rows: The report's rows + :param begin_date: The first date in the report + :param end_date: The last date in the report :param file: The TSV file to write to :param include_all_attributes: Option to include all possible attributes for this report type to the report + :param is_special: If this is a special report + :param special_options: The special options if this is a special report """ column_names = [] row_dicts = [] if report_type == "PR": column_names += ["Platform"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: column_names.append("Data_Type") if special_options_dict["access_method"][0]: column_names.append("Access_Method") elif include_all_attributes: @@ -2604,8 +2574,8 @@ class ReportWorker(QObject): row: ReportRow for row in report_rows: row_dict = {"Platform": row.platform} - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: row_dict["Data_Type"] = row.data_type if special_options_dict["access_method"][0]: row_dict["Access_Method"] = row.access_method @@ -2635,8 +2605,8 @@ class ReportWorker(QObject): elif report_type == "DR": column_names += ["Database", "Publisher", "Publisher_ID", "Platform", "Proprietary_ID"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: column_names.append("Data_Type") if special_options_dict["access_method"][0]: column_names.append("Access_Method") elif include_all_attributes: @@ -2651,8 +2621,8 @@ class ReportWorker(QObject): "Platform": row.platform, "Proprietary_ID": row.proprietary_id} - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: row_dict["Data_Type"] = row.data_type if special_options_dict["access_method"][0]: row_dict["Access_Method"] = row.access_method @@ -2687,8 +2657,8 @@ class ReportWorker(QObject): elif report_type == "TR": column_names += ["Title", "Publisher", "Publisher_ID", "Platform", "DOI", "Proprietary_ID", "ISBN", "Print_ISSN", "Online_ISSN", "URI"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: column_names.append("Data_Type") if special_options_dict["section_type"][0]: column_names.append("Section_Type") if special_options_dict["yop"][0]: column_names.append("YOP") @@ -2714,8 +2684,8 @@ class ReportWorker(QObject): "Online_ISSN": row.online_issn, "URI": row.uri} - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["data_type"][0]: row_dict["Data_Type"] = row.data_type if special_options_dict["section_type"][0]: row_dict["Section_Type"] = row.section_type if special_options_dict["yop"][0]: row_dict["YOP"] = row.yop @@ -2851,8 +2821,8 @@ class ReportWorker(QObject): elif report_type == "IR": column_names += ["Item", "Publisher", "Publisher_ID", "Platform"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["authors"][0]: column_names.append("Authors") if special_options_dict["publication_date"][0]: column_names.append("Publication_Date") if special_options_dict["article_version"][0]: column_names.append("Article_version") @@ -2861,8 +2831,8 @@ class ReportWorker(QObject): column_names.append("Publication_Date") column_names.append("Article_version") column_names += ["DOI", "Proprietary_ID", "ISBN", "Print_ISSN", "Online_ISSN", "URI"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["include_parent_details"][0]: column_names += ["Parent_Title", "Parent_Authors", "Parent_Publication_Date", "Parent_Article_Version", "Parent_Data_Type", "Parent_DOI", @@ -2901,8 +2871,8 @@ class ReportWorker(QObject): "Online_ISSN": row.online_issn, "URI": row.uri} - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if special_options_dict["authors"][0]: row_dict["Authors"] = row.authors if special_options_dict["publication_date"][0]: row_dict["Publication_Date"] = row.publication_date if special_options_dict["article_version"][0]: row_dict["Article_version"] = row.article_version @@ -3028,12 +2998,12 @@ class ReportWorker(QObject): column_names += ["Metric_Type", "Reporting_Period_Total"] - if self.is_special: - special_options_dict = self.special_options.__dict__ + if is_special: + special_options_dict = special_options.__dict__ if not special_options_dict["exclude_monthly_details"][0]: - column_names += get_month_years(self.begin_date, self.end_date) + column_names += get_month_years(begin_date, end_date) else: - column_names += get_month_years(self.begin_date, self.end_date) + column_names += get_month_years(begin_date, end_date) tsv_dict_writer = csv.DictWriter(file, column_names, delimiter='\t') tsv_dict_writer.writeheader() diff --git a/GeneralUtils.py b/GeneralUtils.py index a06f61e..56afef2 100644 --- a/GeneralUtils.py +++ b/GeneralUtils.py @@ -7,6 +7,7 @@ from typing import Sequence, Any from os import path, makedirs, system from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog from PyQt5.QtCore import QDate +from Constants import * main_window: QWidget = None @@ -66,7 +67,7 @@ def open_file_or_dir(target_path: str): def choose_file(name_filters) -> str: file_path = "" - dialog = QFileDialog(main_window, directory=".") + dialog = QFileDialog(main_window) dialog.setFileMode(QFileDialog.ExistingFile) dialog.setNameFilters(name_filters) if dialog.exec_(): @@ -75,9 +76,20 @@ def choose_file(name_filters) -> str: return file_path +def choose_files(name_filters) -> list: + file_paths = [] + dialog = QFileDialog(main_window) + dialog.setFileMode(QFileDialog.ExistingFiles) + dialog.setNameFilters([x for x in name_filters]) + if dialog.exec_(): + file_paths = dialog.selectedFiles() + + return file_paths + + def choose_directory() -> str: dir_path = "" - dialog = QFileDialog(main_window, directory=".") + dialog = QFileDialog(main_window) dialog.setFileMode(QFileDialog.Directory) if dialog.exec_(): dir_path = dialog.selectedFiles()[0] + "/" @@ -87,7 +99,7 @@ def choose_directory() -> str: def choose_save(name_filters) -> str: file_path = "" - dialog = QFileDialog(main_window, directory=".") + dialog = QFileDialog(main_window) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setNameFilters(name_filters) @@ -125,6 +137,23 @@ def get_other_file_name(vendor_name: str, report_type: str, begin_date: QDate, e return f"{vendor_name}_{report_type}_{begin_date.toString('yyyy-MMM')}_{end_date.toString('yyyy-MMM')}.tsv" +def get_major_report_type(report_type: str) -> MajorReportType: + """Returns a major report type that a report type falls under""" + if report_type == "PR" or report_type == "PR_P1": + return MajorReportType.PLATFORM + + elif report_type == "DR" or report_type == "DR_D1" or report_type == "DR_D2": + return MajorReportType.DATABASE + + elif report_type == "TR" or report_type == "TR_B1" or report_type == "TR_B2" \ + or report_type == "TR_B3" or report_type == "TR_J1" or report_type == "TR_J2" \ + or report_type == "TR_J3" or report_type == "TR_J4": + return MajorReportType.TITLE + + elif report_type == "IR" or report_type == "IR_A1" or report_type == "IR_M1": + return MajorReportType.ITEM + + def save_data_as_tsv(file_name: str, data: Sequence[Any]): """Saves data in a TSV file diff --git a/ImportFile.py b/ImportFile.py index f237334..d935f79 100644 --- a/ImportFile.py +++ b/ImportFile.py @@ -4,17 +4,19 @@ import shutil import platform import ctypes import csv +from tempfile import TemporaryDirectory from os import path, makedirs -from PyQt5.QtCore import QModelIndex, QDate, Qt -from PyQt5.QtWidgets import QWidget, QDialog, QDialogButtonBox +from PyQt5.QtCore import QDate, Qt +from PyQt5.QtWidgets import QWidget, QDialog, QDialogButtonBox, QLabel from PyQt5.QtGui import QStandardItemModel, QStandardItem from PyQt5 import QtWidgets import GeneralUtils from Constants import * +from Counter4 import Counter4To5Converter from ui import ImportReportTab, ReportResultWidget from ManageVendors import Vendor -from FetchData import ALL_REPORTS, CompletionStatus +from FetchData import CompletionStatus from Settings import SettingsModel from ManageDB import UpdateDatabaseWorker @@ -25,6 +27,7 @@ class ProcessResult: :param vendor: The target vendor :param report_type: The target report type """ + def __init__(self, vendor: Vendor, report_type: str): self.vendor = vendor self.report_type = report_type @@ -35,6 +38,10 @@ class ProcessResult: self.file_path = "" +def get_c5_equivalent(counter4_report_type: str) -> str: + return COUNTER_4_REPORT_EQUIVALENTS[counter4_report_type] + + class ImportReportController: """Controls the Import Report tab @@ -43,6 +50,7 @@ class ImportReportController: :param import_report_widget: The import report widget. :param import_report_ui: The UI for the import_report_widget. """ + def __init__(self, vendors: list, settings: SettingsModel, import_report_widget: QWidget, import_report_ui: ImportReportTab.Ui_import_report_tab): @@ -51,43 +59,75 @@ class ImportReportController: self.vendors = vendors self.date = QDate.currentDate() self.selected_vendor_index = -1 - self.selected_report_type_index = -1 - self.selected_file_path: str = "" + self.selected_c5_report_type_index = -1 + self.selected_c4_report_type_index = -1 + self.c5_selected_file_path: str = "" + self.c4_selected_file_paths: list = [] self.settings = settings self.result_dialog = None # endregion # region Vendors - self.vendor_list_view = import_report_ui.vendors_list_view_import - self.vendor_list_model = QStandardItemModel(self.vendor_list_view) - self.vendor_list_view.setModel(self.vendor_list_model) - self.vendor_list_view.clicked.connect(self.on_vendor_selected) + self.vendor_combo_box = import_report_ui.vendor_combo_box + self.vendor_list_model = QStandardItemModel(self.vendor_combo_box) + self.vendor_combo_box.setModel(self.vendor_list_model) + self.vendor_combo_box.currentIndexChanged.connect(self.on_vendor_selected) self.update_vendors_ui() + self.selected_vendor_index = self.vendor_combo_box.currentIndex() # endregion - # region Report Types - self.report_type_list_view = import_report_ui.report_types_list_view_import - self.report_type_list_model = QStandardItemModel(self.report_type_list_view) - self.report_type_list_view.setModel(self.report_type_list_model) - self.report_type_list_view.clicked.connect(self.on_report_type_selected) + # region Counter 5 + self.c5_report_type_combo_box = import_report_ui.c5_report_type_combo_box + self.c5_report_type_model = QStandardItemModel(self.c5_report_type_combo_box) + self.c5_report_type_combo_box.setModel(self.c5_report_type_model) + self.c5_report_type_combo_box.currentIndexChanged.connect(self.on_c5_report_type_selected) + for report_type in ALL_REPORTS: item = QStandardItem(report_type) item.setEditable(False) - self.report_type_list_model.appendRow(item) + self.c5_report_type_model.appendRow(item) + + self.selected_c5_report_type_index = self.c5_report_type_combo_box.currentIndex() + + self.c5_select_file_btn = import_report_ui.c5_select_file_button + self.c5_select_file_btn.clicked.connect(self.on_c5_select_file_clicked) + + self.c5_selected_file_edit = import_report_ui.c5_selected_file_edit + + self.c5_import_report_button = import_report_ui.c5_import_report_button + self.c5_import_report_button.clicked.connect(self.on_c5_import_clicked) # endregion - # region Others - self.year_date_edit = import_report_ui.report_year_date_edit - self.year_date_edit.setDate(self.date) - self.year_date_edit.dateChanged.connect(self.on_date_changed) + # region Counter 4 + self.c4_report_type_combo_box = import_report_ui.c4_report_type_combo_box + self.c4_report_type_model = QStandardItemModel(self.c4_report_type_combo_box) + self.c4_report_type_combo_box.setModel(self.c4_report_type_model) + self.c4_report_type_combo_box.currentIndexChanged.connect(self.on_c4_report_type_selected) + self.c4_report_type_equiv_label = import_report_ui.c4_report_type_equiv_label - self.select_file_btn = import_report_ui.select_file_button - self.select_file_btn.clicked.connect(self.on_select_file_clicked) + for report_type in COUNTER_4_REPORT_EQUIVALENTS.keys(): + item = QStandardItem(report_type) + item.setEditable(False) + self.c4_report_type_model.appendRow(item) + + self.selected_c4_report_type_index = self.c4_report_type_combo_box.currentIndex() + self.c4_report_type_equiv_label.setText(get_c5_equivalent(self.c4_report_type_combo_box.currentText())) - self.selected_file_edit = import_report_ui.selected_file_edit + self.c4_select_file_btn = import_report_ui.c4_select_file_button + self.c4_select_file_btn.clicked.connect(self.on_c4_select_file_clicked) + + self.c4_selected_files_frame = import_report_ui.c4_selected_files_frame + self.c4_selected_files_frame_layout = self.c4_selected_files_frame.layout() + + self.c4_import_report_button = import_report_ui.c4_import_report_button + self.c4_import_report_button.clicked.connect(self.on_c4_import_clicked) - self.import_report_button = import_report_ui.import_report_button - self.import_report_button.clicked.connect(self.on_import_clicked) + # endregion + + # region Date + self.year_date_edit = import_report_ui.report_year_date_edit + self.year_date_edit.setDate(self.date) + self.year_date_edit.dateChanged.connect(self.on_date_changed) # endregion def on_vendors_changed(self, vendors: list): @@ -95,9 +135,9 @@ class ImportReportController: :param vendors: An updated list of the system's vendors """ - self.selected_vendor_index = -1 self.update_vendors(vendors) self.update_vendors_ui() + self.selected_vendor_index = self.vendor_combo_box.currentIndex() def update_vendors(self, vendors: list): """ Updates the local copy of vendors that support report import @@ -114,54 +154,135 @@ class ImportReportController: item.setEditable(False) self.vendor_list_model.appendRow(item) - def on_vendor_selected(self, model_index: QModelIndex): + def on_vendor_selected(self, index: int): """Handles the signal emitted when a vendor is selected""" - self.selected_vendor_index = model_index.row() + self.selected_vendor_index = index - def on_report_type_selected(self, model_index: QModelIndex): + def on_c5_report_type_selected(self, index: int): """Handles the signal emitted when a report type is selected""" - self.selected_report_type_index = model_index.row() + self.selected_c5_report_type_index = index + + def on_c4_report_type_selected(self, index: int): + """Handles the signal emitted when a report type is selected""" + self.selected_c4_report_type_index = index + self.c4_report_type_equiv_label.setText(get_c5_equivalent(self.c4_report_type_combo_box.currentText())) def on_date_changed(self, date: QDate): """Handles the signal emitted when the target date is changed""" self.date = date - def on_select_file_clicked(self): + def on_c5_select_file_clicked(self): """Handles the signal emitted when the select file button is clicked""" file_path = GeneralUtils.choose_file(TSV_FILTER + CSV_FILTER) if file_path: - self.selected_file_path = file_path - self.selected_file_edit.setText(file_path) + self.c5_selected_file_path = file_path + file_name = file_path.split("/")[-1] + self.c5_selected_file_edit.setText(file_name) - def on_import_clicked(self): + def on_c4_select_file_clicked(self): + """Handles the signal emitted when the select file button is clicked""" + file_paths = GeneralUtils.choose_files(TSV_AND_CSV_FILTER) + if file_paths: + self.c4_selected_file_paths = file_paths + file_names = [file_path.split("/")[-1] for file_path in file_paths] + + # Remove existing options from ui + for i in reversed(range(self.c4_selected_files_frame_layout.count())): + widget = self.c4_selected_files_frame_layout.itemAt(i).widget() + # remove it from the layout list + self.c4_selected_files_frame_layout.removeWidget(widget) + # remove it from the gui + widget.deleteLater() + + # Add new file names + for file_name in file_names: + label = QLabel(file_name) + self.c4_selected_files_frame_layout.addWidget(label) + + def on_c5_import_clicked(self): """Handles the signal emitted when the import button is clicked""" if self.selected_vendor_index == -1: GeneralUtils.show_message("Select a vendor") return - elif self.selected_report_type_index == -1: + elif self.selected_c5_report_type_index == -1: GeneralUtils.show_message("Select a report type") return - elif self.selected_file_path == "": + elif self.c5_selected_file_path == "": GeneralUtils.show_message("Select a file") return vendor = self.vendors[self.selected_vendor_index] - report_type = ALL_REPORTS[self.selected_report_type_index] + report_type = ALL_REPORTS[self.selected_c5_report_type_index] - process_result = self.import_report(vendor, report_type) - self.show_result(process_result) + process_result = self.import_report(vendor, report_type, self.c5_selected_file_path) + self.show_results([process_result]) + + def on_c4_import_clicked(self): + """Handles the signal emitted when the import button is clicked""" + if self.selected_vendor_index == -1: + GeneralUtils.show_message("Select a vendor") + return + elif not self.c4_selected_file_paths: + GeneralUtils.show_message("Select a file") + return - def import_report(self, vendor: Vendor, report_type: str) -> ProcessResult: + vendor = self.vendors[self.selected_vendor_index] + report_types = get_c5_equivalent(self.c4_report_type_combo_box.currentText()) + + # Check if target C5 file already exists + existing_report_types = [] + for report_type in report_types.split(", "): + if self.check_if_c5_report_exists(vendor.name, report_type): + existing_report_types.append(report_type) + + # Confirm overwrite + if existing_report_types: + if not GeneralUtils.ask_confirmation(f"COUNTER 5 [{', '.join(existing_report_types)}] already exist in the " + "database for this vendor, do you want to overwrite them?"): + return + + with TemporaryDirectory("") as dir_path: + converter = Counter4To5Converter(self.vendors[self.selected_vendor_index], + self.c4_report_type_combo_box.currentText(), + self.c4_selected_file_paths, + dir_path + path.sep, + self.year_date_edit.date()) + try: + c5_file_paths = converter.do_conversion() + except Exception as e: + process_result = ProcessResult(vendor, report_types) + process_result.completion_status = CompletionStatus.FAILED + process_result.message = "Error converting file. " + str(e) + self.show_results([process_result]) + return + + if not c5_file_paths: # If nothing was processed + process_result = ProcessResult(vendor, report_types) + process_result.completion_status = CompletionStatus.FAILED + process_result.message = "No COUNTER 5 report was created, make sure the COUNTER 4 input files are " \ + "correct" + self.show_results([process_result]) + return + + process_results = [] + for report_type in c5_file_paths: + file_path = c5_file_paths[report_type] + process_result = self.import_report(vendor, report_type, file_path) + process_results.append(process_result) + + self.show_results(process_results) + + def import_report(self, vendor: Vendor, report_type: str, origin_file_path: str) -> ProcessResult: """ Imports the selected file using the selected parameters :param vendor: The target vendor :param report_type: The target report type + :param origin_file_path: The path of the file to be imported :raises Exception: If anything goes wrong while importing the report """ process_result = ProcessResult(vendor, report_type) try: - dest_file_dir = GeneralUtils.get_yearly_file_dir(self.settings.yearly_directory, vendor.name, self.date) dest_file_name = GeneralUtils.get_yearly_file_name(vendor.name, report_type, self.date) dest_file_path = f"{dest_file_dir}{dest_file_name}" @@ -171,8 +292,8 @@ class ImportReportController: makedirs(dest_file_dir) # Validate report header - delimiter = DELIMITERS[self.selected_file_path[-4:].lower()] - file = open(self.selected_file_path, 'r', encoding='utf-8-sig') + delimiter = DELIMITERS[origin_file_path[-4:].lower()] + file = open(origin_file_path, 'r', encoding='utf-8-sig') reader = csv.reader(file, delimiter=delimiter, quotechar='\"') if file.mode == 'r': header = {} @@ -199,7 +320,7 @@ class ImportReportController: raise Exception('Could not open file') # Copy selected_file_path to dest_file_path - self.copy_file(self.selected_file_path, dest_file_path) + self.copy_file(origin_file_path, dest_file_path) process_result.file_dir = dest_file_dir process_result.file_name = dest_file_name @@ -214,7 +335,7 @@ class ImportReportController: ctypes.windll.kernel32.SetFileAttributesW(PROTECTED_DATABASE_FILE_DIR, 2) # Hide folder protected_file_path = f"{protected_file_dir}{dest_file_name}" - self.copy_file(self.selected_file_path, protected_file_path) + self.copy_file(origin_file_path, protected_file_path) # Add file to database database_worker = UpdateDatabaseWorker([{'file': protected_file_path, @@ -229,56 +350,63 @@ class ImportReportController: return process_result + def check_if_c5_report_exists(self, vendor_name, report_type) -> bool: + protected_file_dir = f"{PROTECTED_DATABASE_FILE_DIR}{self.date.toString('yyyy')}/{vendor_name}/" + protected_file_name = GeneralUtils.get_yearly_file_name(vendor_name, report_type, self.date) + protected_file_path = f"{protected_file_dir}{protected_file_name}" + + return path.isfile(protected_file_path) + def copy_file(self, origin_path: str, dest_path: str): """Copies a file from origin_path to dest_path""" shutil.copy2(origin_path, dest_path) - def show_result(self, process_result: ProcessResult): + def show_results(self, process_results: list): """Shows the result of the import process to the user - :param process_result: The result of the import process + :param process_results: The results of the import process """ self.result_dialog = QDialog(self.import_report_widget, flags=Qt.WindowCloseButtonHint) self.result_dialog.setWindowTitle("Import Result") vertical_layout = QtWidgets.QVBoxLayout(self.result_dialog) vertical_layout.setContentsMargins(5, 5, 5, 5) - report_result_widget = QWidget(self.result_dialog) - report_result_ui = ReportResultWidget.Ui_ReportResultWidget() - report_result_ui.setupUi(report_result_widget) + for process_result in process_results: + report_result_widget = QWidget(self.result_dialog) + report_result_ui = ReportResultWidget.Ui_ReportResultWidget() + report_result_ui.setupUi(report_result_widget) - button_box = QtWidgets.QDialogButtonBox(QDialogButtonBox.Ok, self.result_dialog) - button_box.setCenterButtons(True) - button_box.accepted.connect(self.result_dialog.accept) + vendor = process_result.vendor + report_type = process_result.report_type - vendor = process_result.vendor - report_type = process_result.report_type + report_result_ui.report_type_label.setText(f"{vendor.name} - {report_type}") + report_result_ui.success_label.setText(process_result.completion_status.value) - report_result_ui.report_type_label.setText(f"{vendor.name} - {report_type}") - report_result_ui.success_label.setText(process_result.completion_status.value) + if process_result.completion_status == CompletionStatus.SUCCESSFUL: + report_result_ui.message_label.hide() + report_result_ui.retry_frame.hide() - if process_result.completion_status == CompletionStatus.SUCCESSFUL: - report_result_ui.message_label.hide() - report_result_ui.retry_frame.hide() + report_result_ui.file_label.setText(f"Saved as: {process_result.file_name}") + report_result_ui.file_label.mousePressEvent = \ + lambda event, file_path = process_result.file_path: GeneralUtils.open_file_or_dir(file_path) - report_result_ui.file_label.setText(f"Saved as: {process_result.file_name}") - report_result_ui.file_label.mousePressEvent = \ - lambda event: GeneralUtils.open_file_or_dir(process_result.file_path) + report_result_ui.folder_button.clicked.connect( + lambda: GeneralUtils.open_file_or_dir(process_result.file_dir)) - report_result_ui.folder_button.clicked.connect( - lambda: GeneralUtils.open_file_or_dir(process_result.file_dir)) + report_result_ui.success_label.setText("Successful!") + report_result_ui.retry_frame.hide() - report_result_ui.success_label.setText("Successful!") - report_result_ui.retry_frame.hide() + elif process_result.completion_status == CompletionStatus.FAILED: + report_result_ui.file_frame.hide() + report_result_ui.retry_frame.hide() - elif process_result.completion_status == CompletionStatus.FAILED: - report_result_ui.file_frame.hide() - report_result_ui.retry_frame.hide() + report_result_ui.message_label.setText(process_result.message) - report_result_ui.message_label.setText(process_result.message) + vertical_layout.addWidget(report_result_widget) - vertical_layout.addWidget(report_result_widget) + button_box = QtWidgets.QDialogButtonBox(QDialogButtonBox.Ok, self.result_dialog) + button_box.setCenterButtons(True) + button_box.accepted.connect(self.result_dialog.accept) vertical_layout.addWidget(button_box) - self.result_dialog.show() - + self.result_dialog.show() diff --git a/ManageDB.py b/ManageDB.py index 4c8166c..6626284 100644 --- a/ManageDB.py +++ b/ManageDB.py @@ -398,7 +398,7 @@ def read_report_file(file_name: str, vendor: str, year: int) -> Union[Tuple[str, :param vendor: the vendor name of the data in the file :param year: the year of the data in the file :returns: (file_name, report, values) a Tuple with the file name, the kind of report, and the data from the file""" - if ManageDBSettingsHandler.settings.show_debug_messages: print('READ ' + file_name) + # if ManageDBSettingsHandler.settings.show_debug_messages: print('READ ' + file_name) delimiter = DELIMITERS[file_name[-4:].lower()] file = open(file_name, 'r', encoding='utf-8-sig') reader = csv.reader(file, delimiter=delimiter, quotechar='\"') @@ -411,13 +411,13 @@ def read_report_file(file_name: str, vendor: str, year: int) -> Union[Tuple[str, header[key] = cells[1].strip() else: header[key] = None - if ManageDBSettingsHandler.settings.show_debug_messages: print(header) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(header) for row in range(BLANK_ROWS): next(reader) column_headers = next(reader) column_headers = list(map((lambda column_header: column_header.lower()), column_headers)) # reads column headers - if ManageDBSettingsHandler.settings.show_debug_messages: print(column_headers) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(column_headers) values = [] for cells in list(reader): for month in MONTHS: # makes value from each month with metric > 0 for each row @@ -458,7 +458,7 @@ def read_costs_file(file_name: str) -> Union[Sequence[Dict[str, Any]], None]: column_headers = next(reader) column_headers = list(map((lambda column_header: column_header.lower()), column_headers)) # reads column headers - if ManageDBSettingsHandler.settings.show_debug_messages: print(column_headers) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(column_headers) values = [] for cells in list(reader): value = {} @@ -843,9 +843,9 @@ def run_sql(connection: sqlite3.Connection, sql_text: str, data: Sequence[Sequen :param emit_signal: whether to emit a signal upon completion""" try: cursor = connection.cursor() - if ManageDBSettingsHandler.settings.show_debug_messages: print(sql_text) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(sql_text) if data is not None: - if ManageDBSettingsHandler.settings.show_debug_messages: print(data) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(data) cursor.executemany(sql_text, data) else: cursor.execute(sql_text) @@ -866,9 +866,9 @@ def run_select_sql(connection: sqlite3.Connection, sql_text: str, data: Sequence :returns: a list of rows that return from the statement""" try: cursor = connection.cursor() - if ManageDBSettingsHandler.settings.show_debug_messages: print(sql_text) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(sql_text) if data is not None: - if ManageDBSettingsHandler.settings.show_debug_messages: print(data) + # if ManageDBSettingsHandler.settings.show_debug_messages: print(data) cursor.execute(sql_text, data) else: cursor.execute(sql_text) diff --git a/README.md b/README.md index 473bff1..017b730 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The project is written with Python 3.7. The PyQt GUI framework is used to create - Urvesh Boodhun uboodhun@upei.ca - Ziheng Huang Zihhuang@upei.ca -## Download Project +## Download Project https://github.com/CS-4820-Library-Project/COUNTER-5-Report-Tool/releases ## Developer Documentation @@ -37,9 +37,9 @@ https://github.com/CS-4820-Library-Project/COUNTER-5-Report-Tool/blob/master/doc - Click Browse - Browse to where python is downloaded, by default: C:\Users\USER_NAME\AppData\Local\Programs\Python\Python38 -- Add another variable in the same way that we just did. +- Add another variable in the same way that we just did. - Except this time set the filepath to C:\Users\apjm4\AppData\Local\Programs\Python\Python38\Scripts -Python should now be accessible in Windows Command Prompt. +Python should now be accessible in Windows Command Prompt. Open command prompt and type Python --version. This should return the version of python that is installed. If not the path may be wrong or python was not installed correctly. @@ -78,3 +78,5 @@ type pip -v into command prompt, this should return the version of PIP that is i - Choose Existing environment and set the location to anaconda_install_location/python.exe, OK, OK - Allow the IDE to complete set up then launch the program from MainDriver.py. There should be a play icon next to the line "if __name__ == "__main__":" - We Good To Go! + + diff --git a/Search.py b/Search.py index a69e910..7d21fd3 100644 --- a/Search.py +++ b/Search.py @@ -246,7 +246,7 @@ class SearchController: results = ManageDB.run_select_sql(connection, sql_text, data) connection.close() results.insert(0, headers) - if self.settings.show_debug_messages: print(results) + # if self.settings.show_debug_messages: print(results) save_data_as_tsv(file_name, results) if self.open_results_folder_checkbox.isChecked(): open_file_or_dir(os.path.dirname(file_name)) diff --git a/Visual.py b/Visual.py index 23880ad..14e8adc 100644 --- a/Visual.py +++ b/Visual.py @@ -201,7 +201,7 @@ class VisualController: self.names = [result[0] for result in names_results] else: self.names = [] - if self.settings.show_debug_messages: print(names_results) + # if self.settings.show_debug_messages: print(names_results) costs_sql_text, costs_data = ManageDB.get_names_with_costs_sql_text(self.report_parameter.currentText(), self.vendor_parameter, @@ -212,7 +212,7 @@ class VisualController: self.costs_names = [result[0] for result in costs_results] else: self.costs_names = [] - if self.settings.show_debug_messages: print(costs_results) + # if self.settings.show_debug_messages: print(costs_results) connection.close() model = QStandardItemModel() @@ -267,15 +267,15 @@ class VisualController: if self.monthly_radio.isChecked() and message == "": # sql query to get search results sql_text, data = ManageDB.monthly_chart_search_sql_text(report, start_year, end_year, name, metric, vendor) - print(sql_text) # testing + # print(sql_text) # testing headers = tuple([field['name'] for field in ManageDB.get_monthly_chart_report_fields_list(report)]) connection = ManageDB.create_connection(DATABASE_LOCATION) if connection is not None: self.results = ManageDB.run_select_sql(connection, sql_text, data) - print(self.results) + # print(self.results) self.results.insert(0, headers) - print(self.results) + # print(self.results) connection.close() else: print('Error, no connection') @@ -289,15 +289,15 @@ class VisualController: if self.yearly_radio.isChecked() and message == "": # sql query to get search results sql_text, data = ManageDB.yearly_chart_search_sql_text(report, start_year, end_year, name, metric, vendor) - print(sql_text) # testing + # print(sql_text) # testing headers = tuple([field['name'] for field in ManageDB.get_yearly_chart_report_fields_list(report)]) connection = ManageDB.create_connection(DATABASE_LOCATION) if connection is not None: self.results = ManageDB.run_select_sql(connection, sql_text, data) - print(self.results) + # print(self.results) self.results.insert(0, headers) - print(self.results) + # print(self.results) connection.close() else: print('Error, no connection') @@ -311,15 +311,15 @@ class VisualController: if self.costRatio_radio.isChecked() and message == "": # sql query to get search results sql_text, data = ManageDB.cost_chart_search_sql_text(report, start_year, end_year, name, metric, vendor) - print(sql_text) # testing + # print(sql_text) # testing headers = tuple([field['name'] for field in ManageDB.get_cost_chart_report_fields_list(report)]) connection = ManageDB.create_connection(DATABASE_LOCATION) if connection is not None: self.results = ManageDB.run_select_sql(connection, sql_text, data) - print(self.results) + # print(self.results) self.results.insert(0, headers) - print(self.results) + # print(self.results) connection.close() else: print('Error, no connection') @@ -381,9 +381,9 @@ class VisualController: data1.append(self.results[i][j]) self.data.append(data1) # testing to make sure its working good - print(self.data[0]) # this is the first column in the excel file/vertical axis data in the chart - print(self.data[1]) - print(len(self.data)) + # print(self.data[0]) # this is the first column in the excel file/vertical axis data in the chart + # print(self.data[1]) + # print(len(self.data)) self.chart_type() def process_yearly_data(self): @@ -404,9 +404,9 @@ class VisualController: self.data.append(data2) # testing to make sure its working good - print(self.data[0]) # this is the first column in the excel file/vertical axis data in the chart - print(self.data[1]) - print(len(self.data)) + # print(self.data[0]) # this is the first column in the excel file/vertical axis data in the chart + # print(self.data[1]) + # print(len(self.data)) self.chart_type() def process_cost_ratio_data(self): @@ -471,8 +471,8 @@ class VisualController: self.legendEntry.append(self.metric.currentText()) # testing to see data in array of array - print(self.data[0]) # first column in excel (year) - print(self.data[1]) # second column (cost per metric) + # print(self.data[0]) # first column in excel (year) + # print(self.data[1]) # second column (cost per metric) # print(self.data[2]) # third column (cost) # print(self.data[4]) # fourth column (total) # print(len(self.data)) #testing @@ -481,8 +481,8 @@ class VisualController: def process_top_X_data(self): """Invoked when calculation type: top # is selected""" m = len(self.results) - #print(self.results) - print(m) + # print(self.results) + # print(m) self.temp_results = [] self.legendEntry = [] # legend entry data @@ -491,8 +491,8 @@ class VisualController: for i in range(1, m): self.temp_results.append(self.results[i]) self.temp_results = sorted(self.temp_results, key=itemgetter(4)) - print(len(self.temp_results)) - print(self.temp_results) + # print(len(self.temp_results)) + # print(self.temp_results) n = len(self.temp_results) # data is an array with the sorted usage figures @@ -509,7 +509,7 @@ class VisualController: data = self.temp_results[i][0] data1.append(data) self.data.append(data1) - print(data1) + # print(data1) # get all reporting total metri = self.temp_results[0][3] @@ -518,7 +518,7 @@ class VisualController: metri = self.temp_results[i][3] data2.append(metri) self.data.append(data2) - print(data2) + # print(data2) # get all ranking rank = self.temp_results[0][4] diff --git a/executables/Linux/Counter 5 Report Tool.zip b/executables/Linux/Counter 5 Report Tool.zip index ed5c54e..7796e3e 100644 Binary files a/executables/Linux/Counter 5 Report Tool.zip and b/executables/Linux/Counter 5 Report Tool.zip differ diff --git a/executables/Windows/COUNTER 5 Report Tool.zip b/executables/Windows/COUNTER 5 Report Tool.zip index fcd6b66..b8a461d 100644 Binary files a/executables/Windows/COUNTER 5 Report Tool.zip and b/executables/Windows/COUNTER 5 Report Tool.zip differ diff --git a/executables/macOS/Counter 5 Report Tool.zip b/executables/macOS/Counter 5 Report Tool.zip index 5410f30..d4be501 100644 Binary files a/executables/macOS/Counter 5 Report Tool.zip and b/executables/macOS/Counter 5 Report Tool.zip differ diff --git a/images/import-report-updated.png b/images/import-report-updated.png new file mode 100644 index 0000000..500fa2d Binary files /dev/null and b/images/import-report-updated.png differ diff --git a/tests/test_ImportFile.py b/tests/test_ImportFile.py index 38d476c..5cae88f 100644 --- a/tests/test_ImportFile.py +++ b/tests/test_ImportFile.py @@ -105,9 +105,9 @@ def test_on_report_type_selected(controller_v): index_to_select = 3 model_index = QStandardItemModel.createIndex(QStandardItemModel(), index_to_select, 0) - controller_v.on_report_type_selected(model_index) + controller_v.on_c5_report_type_selected(model_index) - assert controller_v.selected_report_type_index == index_to_select + assert controller_v.selected_c5_report_type_index == index_to_select def test_on_date_changed(controller_v): @@ -119,38 +119,38 @@ def test_on_date_changed(controller_v): def test_on_import_clicked(controller_v): # No vendor selected - controller_v.on_import_clicked() + controller_v.on_c5_import_clicked() controller_v.selected_vendor_index = 1 # No report type selected - controller_v.on_import_clicked() - controller_v.selected_report_type_index = 1 + controller_v.on_c5_import_clicked() + controller_v.selected_c5_report_type_index = 1 vendor = controller_v.vendors[controller_v.selected_vendor_index] - report_type = ALL_REPORTS[controller_v.selected_report_type_index] + report_type = ALL_REPORTS[controller_v.selected_c5_report_type_index] file_dir = f"{controller_v.settings.yearly_directory}{controller_v.date.toString('yyyy')}/{vendor.name}/" file_name = f"{controller_v.date.toString('yyyy')}_{vendor.name}_{report_type}.tsv" file_path = file_dir + file_name # No file selected - controller_v.on_import_clicked() + controller_v.on_c5_import_clicked() # Invalid file selected - controller_v.selected_file_path = "./data/invalid_file" - controller_v.on_import_clicked() + controller_v.c5_selected_file_path = "./data/invalid_file" + controller_v.on_c5_import_clicked() # Valid file selected - controller_v.selected_file_path = "./data/test_file_for_import.tsv" - controller_v.on_import_clicked() + controller_v.c5_selected_file_path = "./data/test_file_for_import.tsv" + controller_v.on_c5_import_clicked() assert path.isfile(file_path) def test_import_file(controller_v): controller_v.selected_vendor_index = 1 - controller_v.selected_report_type_index = 1 + controller_v.selected_c5_report_type_index = 1 vendor = controller_v.vendors[controller_v.selected_vendor_index] - report_type = ALL_REPORTS[controller_v.selected_report_type_index] + report_type = ALL_REPORTS[controller_v.selected_c5_report_type_index] file_dir = f"{controller_v.settings.yearly_directory}{controller_v.date.toString('yyyy')}/{vendor.name}/" file_name = f"{controller_v.date.toString('yyyy')}_{vendor.name}_{report_type}.tsv" file_path = file_dir + file_name @@ -159,11 +159,11 @@ def test_import_file(controller_v): assert controller_v.import_report(vendor, report_type).completion_status == CompletionStatus.FAILED # Invalid file selected - controller_v.selected_file_path = "./data/invalid_file" + controller_v.c5_selected_file_path = "./data/invalid_file" assert controller_v.import_report(vendor, report_type).completion_status == CompletionStatus.FAILED # Valid file selected - controller_v.selected_file_path = "./data/test_file_for_import.tsv" + controller_v.c5_selected_file_path = "./data/test_file_for_import.tsv" assert controller_v.import_report(vendor, report_type).completion_status == CompletionStatus.SUCCESSFUL assert path.isfile(file_path) diff --git a/ui/ImportReportTab.py b/ui/ImportReportTab.py index ca29e54..df73959 100644 --- a/ui/ImportReportTab.py +++ b/ui/ImportReportTab.py @@ -2,28 +2,25 @@ # Form implementation generated from reading ui file 'ImportReportTab.ui' # -# Created by: PyQt5 UI code generator 5.9.2 +# Created by: PyQt5 UI code generator 5.12.3 # # WARNING! All changes made in this file will be lost! + from PyQt5 import QtCore, QtGui, QtWidgets + class Ui_import_report_tab(object): def setupUi(self, import_report_tab): import_report_tab.setObjectName("import_report_tab") - import_report_tab.resize(1008, 530) + import_report_tab.resize(1007, 467) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/ui/resources/tab_icons/import_report_icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) import_report_tab.setWindowIcon(icon) self.verticalLayout = QtWidgets.QVBoxLayout(import_report_tab) self.verticalLayout.setObjectName("verticalLayout") - self.frame = QtWidgets.QFrame(import_report_tab) - self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame.setObjectName("frame") - self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame) - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.frame_21 = QtWidgets.QFrame(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + self.frame_21 = QtWidgets.QFrame(import_report_tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.frame_21.sizePolicy().hasHeightForWidth()) @@ -31,109 +28,70 @@ class Ui_import_report_tab(object): self.frame_21.setMinimumSize(QtCore.QSize(200, 0)) self.frame_21.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_21.setObjectName("frame_21") - self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.frame_21) - self.verticalLayout_12.setObjectName("verticalLayout_12") + self.gridLayout = QtWidgets.QGridLayout(self.frame_21) + self.gridLayout.setHorizontalSpacing(20) + self.gridLayout.setObjectName("gridLayout") self.label_18 = QtWidgets.QLabel(self.frame_21) + self.label_18.setMinimumSize(QtCore.QSize(200, 0)) font = QtGui.QFont() - font.setFamily("Segoe UI") - font.setPointSize(11) font.setBold(True) font.setWeight(75) self.label_18.setFont(font) self.label_18.setObjectName("label_18") - self.verticalLayout_12.addWidget(self.label_18) - self.vendors_list_view_import = QtWidgets.QListView(self.frame_21) - font = QtGui.QFont() - font.setFamily("Segoe UI") - font.setPointSize(11) - self.vendors_list_view_import.setFont(font) - self.vendors_list_view_import.setAlternatingRowColors(True) - self.vendors_list_view_import.setObjectName("vendors_list_view_import") - self.verticalLayout_12.addWidget(self.vendors_list_view_import) - self.horizontalLayout_2.addWidget(self.frame_21) - self.frame_20 = QtWidgets.QFrame(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_20.sizePolicy().hasHeightForWidth()) - self.frame_20.setSizePolicy(sizePolicy) - self.frame_20.setMinimumSize(QtCore.QSize(200, 0)) - self.frame_20.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_20.setObjectName("frame_20") - self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.frame_20) - self.verticalLayout_11.setObjectName("verticalLayout_11") - self.label_17 = QtWidgets.QLabel(self.frame_20) + self.gridLayout.addWidget(self.label_18, 0, 0, 1, 1) + self.vendor_combo_box = QtWidgets.QComboBox(self.frame_21) + self.vendor_combo_box.setObjectName("vendor_combo_box") + self.gridLayout.addWidget(self.vendor_combo_box, 1, 0, 1, 1) + self.label_19 = QtWidgets.QLabel(self.frame_21) + self.label_19.setMinimumSize(QtCore.QSize(100, 0)) font = QtGui.QFont() - font.setFamily("Segoe UI") - font.setPointSize(11) font.setBold(True) font.setWeight(75) - self.label_17.setFont(font) - self.label_17.setObjectName("label_17") - self.verticalLayout_11.addWidget(self.label_17) - self.report_types_list_view_import = QtWidgets.QListView(self.frame_20) - font = QtGui.QFont() - font.setFamily("Segoe UI") - font.setPointSize(11) - self.report_types_list_view_import.setFont(font) - self.report_types_list_view_import.setAlternatingRowColors(True) - self.report_types_list_view_import.setObjectName("report_types_list_view_import") - self.verticalLayout_11.addWidget(self.report_types_list_view_import) - self.horizontalLayout_2.addWidget(self.frame_20) - self.frame_22 = QtWidgets.QFrame(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_22.sizePolicy().hasHeightForWidth()) - self.frame_22.setSizePolicy(sizePolicy) - self.frame_22.setMinimumSize(QtCore.QSize(200, 0)) - self.frame_22.setObjectName("frame_22") - self.verticalLayout_13 = QtWidgets.QVBoxLayout(self.frame_22) - self.verticalLayout_13.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_13.setObjectName("verticalLayout_13") - self.frame_17 = QtWidgets.QFrame(self.frame_22) + self.label_19.setFont(font) + self.label_19.setObjectName("label_19") + self.gridLayout.addWidget(self.label_19, 0, 1, 1, 1) + self.report_year_date_edit = QtWidgets.QDateEdit(self.frame_21) + self.report_year_date_edit.setObjectName("report_year_date_edit") + self.gridLayout.addWidget(self.report_year_date_edit, 1, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 0, 2, 2, 1) + self.verticalLayout.addWidget(self.frame_21) + self.frame = QtWidgets.QFrame(import_report_tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth()) + self.frame.setSizePolicy(sizePolicy) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.frame_17 = QtWidgets.QFrame(self.frame) self.frame_17.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_17.setObjectName("frame_17") self.verticalLayout_24 = QtWidgets.QVBoxLayout(self.frame_17) self.verticalLayout_24.setObjectName("verticalLayout_24") - self.label_16 = QtWidgets.QLabel(self.frame_17) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label_16.sizePolicy().hasHeightForWidth()) - self.label_16.setSizePolicy(sizePolicy) + self.label_2 = QtWidgets.QLabel(self.frame_17) font = QtGui.QFont() font.setBold(True) font.setWeight(75) - self.label_16.setFont(font) - self.label_16.setObjectName("label_16") - self.verticalLayout_24.addWidget(self.label_16) - self.frame_19 = QtWidgets.QFrame(self.frame_17) - self.frame_19.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_19.setObjectName("frame_19") - self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.frame_19) - self.horizontalLayout_13.setObjectName("horizontalLayout_13") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_13.addItem(spacerItem) - self.label_19 = QtWidgets.QLabel(self.frame_19) - self.label_19.setMinimumSize(QtCore.QSize(100, 0)) - self.label_19.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.label_19.setObjectName("label_19") - self.horizontalLayout_13.addWidget(self.label_19) - self.report_year_date_edit = QtWidgets.QDateEdit(self.frame_19) - self.report_year_date_edit.setObjectName("report_year_date_edit") - self.horizontalLayout_13.addWidget(self.report_year_date_edit) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_13.addItem(spacerItem1) - self.verticalLayout_24.addWidget(self.frame_19) - self.verticalLayout_13.addWidget(self.frame_17) - self.frame_18 = QtWidgets.QFrame(self.frame_22) - self.frame_18.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_18.setObjectName("frame_18") - self.verticalLayout_25 = QtWidgets.QVBoxLayout(self.frame_18) - self.verticalLayout_25.setObjectName("verticalLayout_25") - self.label_36 = QtWidgets.QLabel(self.frame_18) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + self.label_2.setFont(font) + self.label_2.setObjectName("label_2") + self.verticalLayout_24.addWidget(self.label_2) + self.frame_2 = QtWidgets.QFrame(self.frame_17) + self.frame_2.setObjectName("frame_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.frame_2) + self.gridLayout_2.setHorizontalSpacing(20) + self.gridLayout_2.setObjectName("gridLayout_2") + self.label_17 = QtWidgets.QLabel(self.frame_2) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_17.setFont(font) + self.label_17.setObjectName("label_17") + self.gridLayout_2.addWidget(self.label_17, 0, 0, 1, 1) + self.label_36 = QtWidgets.QLabel(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_36.sizePolicy().hasHeightForWidth()) @@ -143,66 +101,229 @@ class Ui_import_report_tab(object): font.setWeight(75) self.label_36.setFont(font) self.label_36.setObjectName("label_36") - self.verticalLayout_25.addWidget(self.label_36) - self.frame_38 = QtWidgets.QFrame(self.frame_18) + self.gridLayout_2.addWidget(self.label_36, 0, 1, 1, 1) + self.frame_38 = QtWidgets.QFrame(self.frame_2) self.frame_38.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_38.setObjectName("frame_38") self.horizontalLayout_15 = QtWidgets.QHBoxLayout(self.frame_38) self.horizontalLayout_15.setObjectName("horizontalLayout_15") - self.select_file_button = QtWidgets.QPushButton(self.frame_38) + self.c5_selected_file_edit = QtWidgets.QLineEdit(self.frame_38) + self.c5_selected_file_edit.setReadOnly(True) + self.c5_selected_file_edit.setObjectName("c5_selected_file_edit") + self.horizontalLayout_15.addWidget(self.c5_selected_file_edit) + self.c5_select_file_button = QtWidgets.QPushButton(self.frame_38) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.select_file_button.sizePolicy().hasHeightForWidth()) - self.select_file_button.setSizePolicy(sizePolicy) - self.select_file_button.setObjectName("select_file_button") - self.horizontalLayout_15.addWidget(self.select_file_button) - self.selected_file_edit = QtWidgets.QLineEdit(self.frame_38) - self.selected_file_edit.setReadOnly(True) - self.selected_file_edit.setObjectName("selected_file_edit") - self.horizontalLayout_15.addWidget(self.selected_file_edit) - self.verticalLayout_25.addWidget(self.frame_38) - self.verticalLayout_13.addWidget(self.frame_18) - self.frame_24 = QtWidgets.QFrame(self.frame_22) - self.frame_24.setFrameShape(QtWidgets.QFrame.StyledPanel) + sizePolicy.setHeightForWidth(self.c5_select_file_button.sizePolicy().hasHeightForWidth()) + self.c5_select_file_button.setSizePolicy(sizePolicy) + self.c5_select_file_button.setObjectName("c5_select_file_button") + self.horizontalLayout_15.addWidget(self.c5_select_file_button) + self.gridLayout_2.addWidget(self.frame_38, 1, 1, 1, 1) + self.c5_report_type_combo_box = QtWidgets.QComboBox(self.frame_2) + self.c5_report_type_combo_box.setObjectName("c5_report_type_combo_box") + self.gridLayout_2.addWidget(self.c5_report_type_combo_box, 1, 0, 1, 1, QtCore.Qt.AlignTop) + self.verticalLayout_24.addWidget(self.frame_2) + self.frame_25 = QtWidgets.QFrame(self.frame_17) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_25.sizePolicy().hasHeightForWidth()) + self.frame_25.setSizePolicy(sizePolicy) + self.frame_25.setObjectName("frame_25") + self.gridLayout_8 = QtWidgets.QGridLayout(self.frame_25) + self.gridLayout_8.setObjectName("gridLayout_8") + self.c5_import_report_button = QtWidgets.QPushButton(self.frame_25) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.c5_import_report_button.sizePolicy().hasHeightForWidth()) + self.c5_import_report_button.setSizePolicy(sizePolicy) + self.c5_import_report_button.setObjectName("c5_import_report_button") + self.gridLayout_8.addWidget(self.c5_import_report_button, 0, 0, 1, 1) + self.verticalLayout_24.addWidget(self.frame_25) + spacerItem1 = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding) + self.verticalLayout_24.addItem(spacerItem1) + self.horizontalLayout.addWidget(self.frame_17) + self.frame_18 = QtWidgets.QFrame(self.frame) + self.frame_18.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_18.setObjectName("frame_18") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_18) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.label_3 = QtWidgets.QLabel(self.frame_18) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_3.setFont(font) + self.label_3.setObjectName("label_3") + self.verticalLayout_3.addWidget(self.label_3) + self.frame_3 = QtWidgets.QFrame(self.frame_18) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth()) + self.frame_3.setSizePolicy(sizePolicy) + self.frame_3.setObjectName("frame_3") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_3) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.frame_4 = QtWidgets.QFrame(self.frame_3) + self.frame_4.setObjectName("frame_4") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_4) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_20 = QtWidgets.QLabel(self.frame_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_20.sizePolicy().hasHeightForWidth()) + self.label_20.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_20.setFont(font) + self.label_20.setObjectName("label_20") + self.verticalLayout_2.addWidget(self.label_20) + self.c4_report_type_combo_box = QtWidgets.QComboBox(self.frame_4) + self.c4_report_type_combo_box.setObjectName("c4_report_type_combo_box") + self.verticalLayout_2.addWidget(self.c4_report_type_combo_box) + self.label_21 = QtWidgets.QLabel(self.frame_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_21.sizePolicy().hasHeightForWidth()) + self.label_21.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_21.setFont(font) + self.label_21.setObjectName("label_21") + self.verticalLayout_2.addWidget(self.label_21) + self.c4_report_type_equiv_label = QtWidgets.QLabel(self.frame_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.c4_report_type_equiv_label.sizePolicy().hasHeightForWidth()) + self.c4_report_type_equiv_label.setSizePolicy(sizePolicy) + self.c4_report_type_equiv_label.setObjectName("c4_report_type_equiv_label") + self.verticalLayout_2.addWidget(self.c4_report_type_equiv_label) + spacerItem2 = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_2.addItem(spacerItem2) + self.horizontalLayout_2.addWidget(self.frame_4) + self.frame_5 = QtWidgets.QFrame(self.frame_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_5.sizePolicy().hasHeightForWidth()) + self.frame_5.setSizePolicy(sizePolicy) + self.frame_5.setObjectName("frame_5") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_5) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label_37 = QtWidgets.QLabel(self.frame_5) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_37.sizePolicy().hasHeightForWidth()) + self.label_37.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_37.setFont(font) + self.label_37.setObjectName("label_37") + self.verticalLayout_4.addWidget(self.label_37) + self.c4_files_frame = QtWidgets.QFrame(self.frame_5) + self.c4_files_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.c4_files_frame.setObjectName("c4_files_frame") + self.horizontalLayout_16 = QtWidgets.QHBoxLayout(self.c4_files_frame) + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + self.scrollArea = QtWidgets.QScrollArea(self.c4_files_frame) + self.scrollArea.setMinimumSize(QtCore.QSize(200, 100)) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 198, 18)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollAreaWidgetContents_2.sizePolicy().hasHeightForWidth()) + self.scrollAreaWidgetContents_2.setSizePolicy(sizePolicy) + self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_2) + self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.c4_selected_files_frame = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) + self.c4_selected_files_frame.setObjectName("c4_selected_files_frame") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.c4_selected_files_frame) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.verticalLayout_6.addWidget(self.c4_selected_files_frame) + self.scrollArea.setWidget(self.scrollAreaWidgetContents_2) + self.horizontalLayout_16.addWidget(self.scrollArea) + self.c4_select_file_button = QtWidgets.QPushButton(self.c4_files_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.c4_select_file_button.sizePolicy().hasHeightForWidth()) + self.c4_select_file_button.setSizePolicy(sizePolicy) + self.c4_select_file_button.setObjectName("c4_select_file_button") + self.horizontalLayout_16.addWidget(self.c4_select_file_button) + self.verticalLayout_4.addWidget(self.c4_files_frame) + self.horizontalLayout_2.addWidget(self.frame_5, 0, QtCore.Qt.AlignTop) + self.verticalLayout_3.addWidget(self.frame_3) + self.frame_24 = QtWidgets.QFrame(self.frame_18) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_24.sizePolicy().hasHeightForWidth()) + self.frame_24.setSizePolicy(sizePolicy) self.frame_24.setObjectName("frame_24") self.gridLayout_7 = QtWidgets.QGridLayout(self.frame_24) self.gridLayout_7.setObjectName("gridLayout_7") - self.import_report_button = QtWidgets.QPushButton(self.frame_24) + self.c4_import_report_button = QtWidgets.QPushButton(self.frame_24) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.import_report_button.sizePolicy().hasHeightForWidth()) - self.import_report_button.setSizePolicy(sizePolicy) - self.import_report_button.setMaximumSize(QtCore.QSize(180, 16777215)) - self.import_report_button.setObjectName("import_report_button") - self.gridLayout_7.addWidget(self.import_report_button, 0, 0, 1, 1) - self.verticalLayout_13.addWidget(self.frame_24) - self.horizontalLayout_2.addWidget(self.frame_22) + sizePolicy.setHeightForWidth(self.c4_import_report_button.sizePolicy().hasHeightForWidth()) + self.c4_import_report_button.setSizePolicy(sizePolicy) + self.c4_import_report_button.setObjectName("c4_import_report_button") + self.gridLayout_7.addWidget(self.c4_import_report_button, 0, 0, 1, 1) + self.verticalLayout_3.addWidget(self.frame_24) + spacerItem3 = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem3) + self.horizontalLayout.addWidget(self.frame_18) self.verticalLayout.addWidget(self.frame) self.label = QtWidgets.QLabel(import_report_tab) self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem4) self.retranslateUi(import_report_tab) QtCore.QMetaObject.connectSlotsByName(import_report_tab) - import_report_tab.setTabOrder(self.vendors_list_view_import, self.report_types_list_view_import) - import_report_tab.setTabOrder(self.report_types_list_view_import, self.report_year_date_edit) - import_report_tab.setTabOrder(self.report_year_date_edit, self.selected_file_edit) - import_report_tab.setTabOrder(self.selected_file_edit, self.import_report_button) + import_report_tab.setTabOrder(self.c5_selected_file_edit, self.c4_import_report_button) def retranslateUi(self, import_report_tab): _translate = QtCore.QCoreApplication.translate import_report_tab.setWindowTitle(_translate("import_report_tab", "Import Report")) self.label_18.setText(_translate("import_report_tab", "Select Vendor")) - self.label_17.setText(_translate("import_report_tab", "Select Report Type")) - self.label_16.setText(_translate("import_report_tab", "Date")) self.label_19.setText(_translate("import_report_tab", "Report Year")) self.report_year_date_edit.setDisplayFormat(_translate("import_report_tab", "yyyy")) - self.label_36.setText(_translate("import_report_tab", "Target Report File")) - self.select_file_button.setText(_translate("import_report_tab", "Select File")) - self.import_report_button.setText(_translate("import_report_tab", "Import Selected Report")) + self.label_2.setText(_translate("import_report_tab", "COUNTER 5")) + self.label_17.setText(_translate("import_report_tab", "Select Report Type")) + self.label_36.setText(_translate("import_report_tab", "Source Report File")) + self.c5_select_file_button.setText(_translate("import_report_tab", "Select File")) + self.c5_import_report_button.setText(_translate("import_report_tab", "Import Selected Report")) + self.label_3.setText(_translate("import_report_tab", "COUNTER 4 (Converts to COUNTER 5)")) + self.label_20.setText(_translate("import_report_tab", "Counter 4 Report Type")) + self.label_21.setText(_translate("import_report_tab", "Counter 5 Equivalent(s)")) + self.c4_report_type_equiv_label.setText(_translate("import_report_tab", "TextLabel")) + self.label_37.setText(_translate("import_report_tab", "Source Report File(s)")) + self.c4_select_file_button.setText(_translate("import_report_tab", "Select File(s)")) + self.c4_import_report_button.setText(_translate("import_report_tab", "Import Selected Report(s)")) self.label.setText(_translate("import_report_tab", "Note: Only yearly reports (all available data for one calender year) should be imported. Imported reports are added to the search database.")) - import Resources_rc diff --git a/ui/ImportReportTab.ui b/ui/ImportReportTab.ui index b831e8f..111959c 100644 --- a/ui/ImportReportTab.ui +++ b/ui/ImportReportTab.ui @@ -6,8 +6,8 @@ 0 0 - 1008 - 530 + 1007 + 467 @@ -19,146 +19,153 @@ - + + + + 0 + 0 + + + + + 200 + 0 + + QFrame::StyledPanel - - - - - - 0 - 0 - - + + + 20 + + + 200 0 - - QFrame::StyledPanel + + + 75 + true + + + + Select Vendor - - - - - - Segoe UI - 11 - 75 - true - - - - Select Vendor - - - - - - - - Segoe UI - 11 - - - - true - - - - - - - - - 0 - 0 - - + + + + + - 200 + 100 0 + + + 75 + true + + + + Report Year + + + + + + + yyyy + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + QFrame::StyledPanel - + - + - Segoe UI - 11 75 true - Select Report Type - - - - - - - - Segoe UI - 11 - - - - true + COUNTER 5 - - - - - - - - 0 - 0 - - - - - 200 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - QFrame::StyledPanel - - - - + + + + 20 + + + + + + 75 + true + + + + Select Report Type + + + + + - + 0 0 @@ -170,61 +177,201 @@ - Date + Source Report File - - + + QFrame::StyledPanel - + - - - Qt::Horizontal + + + true - - - 40 - 20 - + + + + + + + 0 + 0 + - + + Select File + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + Import Selected Report + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + + + QFrame::StyledPanel + + + + + + + 0 + 0 + + + + + 75 + true + + + + COUNTER 4 (Converts to COUNTER 5) + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + - - - - 100 - 0 - + + + + 0 + 0 + + + + + 75 + true + - Report Year + Counter 4 Report Type - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Counter 5 Equivalent(s) - - - yyyy + + + + 0 + 0 + + + + TextLabel - + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 0 + 0 @@ -232,58 +379,105 @@ - - - - - - - QFrame::StyledPanel - - - - + + 0 0 - - - 75 - true - - - - Target Report File - - - - - - - QFrame::StyledPanel - - + - + - + 0 0 + + + 75 + true + + - Select File + Source Report File(s) - - - true + + + QFrame::StyledPanel + + + + + + 200 + 100 + + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 198 + 18 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + Select File(s) + + + + @@ -294,32 +488,42 @@ - - QFrame::StyledPanel + + + 0 + 0 + - + 0 0 - - - 180 - 16777215 - - - Import Selected Report + Import Selected Report(s) + + + + Qt::Vertical + + + + 0 + 0 + + + + @@ -336,14 +540,24 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + - vendors_list_view_import - report_types_list_view_import - report_year_date_edit - selected_file_edit - import_report_button + c5_selected_file_edit + c4_import_report_button diff --git a/ui/VisualTab.py b/ui/VisualTab.py index 6d2b79a..619be62 100644 --- a/ui/VisualTab.py +++ b/ui/VisualTab.py @@ -2,38 +2,25 @@ # Form implementation generated from reading ui file 'VisualTab.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt5 UI code generator 5.9.2 # # WARNING! All changes made in this file will be lost! - from PyQt5 import QtCore, QtGui, QtWidgets - class Ui_visual_tab(object): def setupUi(self, visual_tab): visual_tab.setObjectName("visual_tab") - visual_tab.resize(1177, 690) + visual_tab.resize(692, 488) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/ui/resources/tab_icons/visual_icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) visual_tab.setWindowIcon(icon) self.verticalLayout = QtWidgets.QVBoxLayout(visual_tab) self.verticalLayout.setObjectName("verticalLayout") - self.search_parameters_frame_2 = QtWidgets.QFrame(visual_tab) + self.search_initial_parameters_frame_2 = QtWidgets.QFrame(visual_tab) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.search_parameters_frame_2.sizePolicy().hasHeightForWidth()) - self.search_parameters_frame_2.setSizePolicy(sizePolicy) - self.search_parameters_frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.search_parameters_frame_2.setFrameShadow(QtWidgets.QFrame.Raised) - self.search_parameters_frame_2.setObjectName("search_parameters_frame_2") - self.verticalLayout_22 = QtWidgets.QVBoxLayout(self.search_parameters_frame_2) - self.verticalLayout_22.setObjectName("verticalLayout_22") - self.search_initial_parameters_frame_2 = QtWidgets.QFrame(self.search_parameters_frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.search_initial_parameters_frame_2.sizePolicy().hasHeightForWidth()) self.search_initial_parameters_frame_2.setSizePolicy(sizePolicy) self.search_initial_parameters_frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) @@ -74,15 +61,8 @@ class Ui_visual_tab(object): self.gridLayout_6.addItem(spacerItem, 1, 1, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) self.gridLayout_6.addItem(spacerItem1, 1, 3, 1, 1) - self.verticalLayout_22.addWidget(self.search_initial_parameters_frame_2) - self.verticalLayout.addWidget(self.search_parameters_frame_2) - self.frame_14 = QtWidgets.QFrame(visual_tab) - self.frame_14.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_14.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_14.setObjectName("frame_14") - self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.frame_14) - self.horizontalLayout_14.setObjectName("horizontalLayout_14") - self.frame_15 = QtWidgets.QFrame(self.frame_14) + self.verticalLayout.addWidget(self.search_initial_parameters_frame_2) + self.frame_15 = QtWidgets.QFrame(visual_tab) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -91,44 +71,8 @@ class Ui_visual_tab(object): self.frame_15.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_15.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_15.setObjectName("frame_15") - self.gridLayout_13 = QtWidgets.QGridLayout(self.frame_15) - self.gridLayout_13.setObjectName("gridLayout_13") - self.frame_2 = QtWidgets.QFrame(self.frame_15) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) - self.frame_2.setSizePolicy(sizePolicy) - self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_2.setObjectName("frame_2") - self.visual_name_label = QtWidgets.QLabel(self.frame_2) - self.visual_name_label.setEnabled(True) - self.visual_name_label.setGeometry(QtCore.QRect(50, 80, 97, 21)) - self.visual_name_label.setObjectName("visual_name_label") - self.visual_metric_parameter_label = QtWidgets.QLabel(self.frame_2) - self.visual_metric_parameter_label.setGeometry(QtCore.QRect(50, 130, 213, 20)) - self.visual_metric_parameter_label.setObjectName("visual_metric_parameter_label") - self.metric_Type_comboBox = QtWidgets.QComboBox(self.frame_2) - self.metric_Type_comboBox.setGeometry(QtCore.QRect(140, 130, 921, 26)) - self.metric_Type_comboBox.setObjectName("metric_Type_comboBox") - self.visual_vendor_parameter_label = QtWidgets.QLabel(self.frame_2) - self.visual_vendor_parameter_label.setGeometry(QtCore.QRect(50, 30, 61, 20)) - self.visual_vendor_parameter_label.setObjectName("visual_vendor_parameter_label") - self.visual_vendor_parameter_combobox = QtWidgets.QComboBox(self.frame_2) - self.visual_vendor_parameter_combobox.setGeometry(QtCore.QRect(140, 30, 921, 26)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.visual_vendor_parameter_combobox.sizePolicy().hasHeightForWidth()) - self.visual_vendor_parameter_combobox.setSizePolicy(sizePolicy) - self.visual_vendor_parameter_combobox.setObjectName("visual_vendor_parameter_combobox") - self.visual_name_parameter_combobox = QtWidgets.QComboBox(self.frame_2) - self.visual_name_parameter_combobox.setEnabled(True) - self.visual_name_parameter_combobox.setGeometry(QtCore.QRect(140, 80, 921, 28)) - self.visual_name_parameter_combobox.setEditable(True) - self.visual_name_parameter_combobox.setObjectName("visual_name_parameter_combobox") - self.gridLayout_13.addWidget(self.frame_2, 5, 0, 1, 3) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_15) + self.verticalLayout_2.setObjectName("verticalLayout_2") self.frame = QtWidgets.QFrame(self.frame_15) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -138,9 +82,10 @@ class Ui_visual_tab(object): self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setObjectName("horizontalLayout") self.frame_18 = QtWidgets.QFrame(self.frame) self.frame_18.setEnabled(True) - self.frame_18.setGeometry(QtCore.QRect(10, 10, 136, 161)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -172,8 +117,8 @@ class Ui_visual_tab(object): self.radioButton_4 = QtWidgets.QRadioButton(self.frame_18) self.radioButton_4.setObjectName("radioButton_4") self.verticalLayout_28.addWidget(self.radioButton_4) + self.horizontalLayout.addWidget(self.frame_18) self.frame_options = QtWidgets.QFrame(self.frame) - self.frame_options.setGeometry(QtCore.QRect(150, 10, 141, 161)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -182,8 +127,9 @@ class Ui_visual_tab(object): self.frame_options.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_options.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_options.setObjectName("frame_options") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_options) + self.verticalLayout_3.setObjectName("verticalLayout_3") self.label_46 = QtWidgets.QLabel(self.frame_options) - self.label_46.setGeometry(QtCore.QRect(10, 10, 121, 21)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -194,21 +140,22 @@ class Ui_visual_tab(object): self.label_46.setFont(font) self.label_46.setTextFormat(QtCore.Qt.AutoText) self.label_46.setObjectName("label_46") + self.verticalLayout_3.addWidget(self.label_46) self.monthly_radioButton = QtWidgets.QRadioButton(self.frame_options) - self.monthly_radioButton.setGeometry(QtCore.QRect(10, 40, 112, 20)) self.monthly_radioButton.setObjectName("monthly_radioButton") + self.verticalLayout_3.addWidget(self.monthly_radioButton) self.yearly_radioButton = QtWidgets.QRadioButton(self.frame_options) - self.yearly_radioButton.setGeometry(QtCore.QRect(10, 70, 112, 20)) self.yearly_radioButton.setObjectName("yearly_radioButton") + self.verticalLayout_3.addWidget(self.yearly_radioButton) self.topnum_radioButton = QtWidgets.QRadioButton(self.frame_options) - self.topnum_radioButton.setGeometry(QtCore.QRect(10, 100, 112, 20)) self.topnum_radioButton.setObjectName("topnum_radioButton") + self.verticalLayout_3.addWidget(self.topnum_radioButton) self.costratio_radioButton = QtWidgets.QRadioButton(self.frame_options) - self.costratio_radioButton.setGeometry(QtCore.QRect(10, 130, 112, 20)) self.costratio_radioButton.setObjectName("costratio_radioButton") + self.verticalLayout_3.addWidget(self.costratio_radioButton) + self.horizontalLayout.addWidget(self.frame_options) self.option_frame = QtWidgets.QFrame(self.frame) self.option_frame.setEnabled(True) - self.option_frame.setGeometry(QtCore.QRect(293, 10, 151, 161)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -217,8 +164,9 @@ class Ui_visual_tab(object): self.option_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.option_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.option_frame.setObjectName("option_frame") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.option_frame) + self.verticalLayout_6.setObjectName("verticalLayout_6") self.edit_cost_ratio_frame = QtWidgets.QFrame(self.option_frame) - self.edit_cost_ratio_frame.setGeometry(QtCore.QRect(10, 10, 131, 81)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -227,8 +175,9 @@ class Ui_visual_tab(object): self.edit_cost_ratio_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.edit_cost_ratio_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.edit_cost_ratio_frame.setObjectName("edit_cost_ratio_frame") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.edit_cost_ratio_frame) + self.verticalLayout_4.setObjectName("verticalLayout_4") self.label_47 = QtWidgets.QLabel(self.edit_cost_ratio_frame) - self.label_47.setGeometry(QtCore.QRect(10, 10, 183, 15)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -239,11 +188,12 @@ class Ui_visual_tab(object): self.label_47.setFont(font) self.label_47.setTextFormat(QtCore.Qt.AutoText) self.label_47.setObjectName("label_47") + self.verticalLayout_4.addWidget(self.label_47) self.cost_ratio_option_combobox = QtWidgets.QComboBox(self.edit_cost_ratio_frame) - self.cost_ratio_option_combobox.setGeometry(QtCore.QRect(0, 30, 121, 26)) self.cost_ratio_option_combobox.setObjectName("cost_ratio_option_combobox") + self.verticalLayout_4.addWidget(self.cost_ratio_option_combobox) + self.verticalLayout_6.addWidget(self.edit_cost_ratio_frame) self.edit_top_num_frame = QtWidgets.QFrame(self.option_frame) - self.edit_top_num_frame.setGeometry(QtCore.QRect(10, 90, 131, 61)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -252,8 +202,9 @@ class Ui_visual_tab(object): self.edit_top_num_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.edit_top_num_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.edit_top_num_frame.setObjectName("edit_top_num_frame") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.edit_top_num_frame) + self.verticalLayout_5.setObjectName("verticalLayout_5") self.label_48 = QtWidgets.QLabel(self.edit_top_num_frame) - self.label_48.setGeometry(QtCore.QRect(10, 10, 183, 15)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -264,12 +215,14 @@ class Ui_visual_tab(object): self.label_48.setFont(font) self.label_48.setTextFormat(QtCore.Qt.AutoText) self.label_48.setObjectName("label_48") + self.verticalLayout_5.addWidget(self.label_48) self.top_num_spinbox = QtWidgets.QSpinBox(self.edit_top_num_frame) - self.top_num_spinbox.setGeometry(QtCore.QRect(10, 30, 101, 24)) self.top_num_spinbox.setMaximum(999) self.top_num_spinbox.setObjectName("top_num_spinbox") + self.verticalLayout_5.addWidget(self.top_num_spinbox) + self.verticalLayout_6.addWidget(self.edit_top_num_frame) + self.horizontalLayout.addWidget(self.option_frame) self.frame_16 = QtWidgets.QFrame(self.frame) - self.frame_16.setGeometry(QtCore.QRect(460, 10, 601, 161)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -298,9 +251,47 @@ class Ui_visual_tab(object): self.label_36 = QtWidgets.QLabel(self.frame_16) self.label_36.setObjectName("label_36") self.gridLayout_14.addWidget(self.label_36, 2, 0, 1, 1) - self.gridLayout_13.addWidget(self.frame, 0, 0, 1, 3) - self.horizontalLayout_14.addWidget(self.frame_15) - self.verticalLayout.addWidget(self.frame_14) + self.horizontalLayout.addWidget(self.frame_16) + self.verticalLayout_2.addWidget(self.frame) + self.frame_2 = QtWidgets.QFrame(self.frame_15) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) + self.frame_2.setSizePolicy(sizePolicy) + self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_2.setObjectName("frame_2") + self.gridLayout = QtWidgets.QGridLayout(self.frame_2) + self.gridLayout.setObjectName("gridLayout") + self.visual_vendor_parameter_label = QtWidgets.QLabel(self.frame_2) + self.visual_vendor_parameter_label.setObjectName("visual_vendor_parameter_label") + self.gridLayout.addWidget(self.visual_vendor_parameter_label, 0, 0, 1, 1) + self.visual_vendor_parameter_combobox = QtWidgets.QComboBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.visual_vendor_parameter_combobox.sizePolicy().hasHeightForWidth()) + self.visual_vendor_parameter_combobox.setSizePolicy(sizePolicy) + self.visual_vendor_parameter_combobox.setObjectName("visual_vendor_parameter_combobox") + self.gridLayout.addWidget(self.visual_vendor_parameter_combobox, 0, 1, 1, 1) + self.visual_name_label = QtWidgets.QLabel(self.frame_2) + self.visual_name_label.setEnabled(True) + self.visual_name_label.setObjectName("visual_name_label") + self.gridLayout.addWidget(self.visual_name_label, 1, 0, 1, 1) + self.visual_name_parameter_combobox = QtWidgets.QComboBox(self.frame_2) + self.visual_name_parameter_combobox.setEnabled(True) + self.visual_name_parameter_combobox.setEditable(True) + self.visual_name_parameter_combobox.setObjectName("visual_name_parameter_combobox") + self.gridLayout.addWidget(self.visual_name_parameter_combobox, 1, 1, 1, 1) + self.visual_metric_parameter_label = QtWidgets.QLabel(self.frame_2) + self.visual_metric_parameter_label.setObjectName("visual_metric_parameter_label") + self.gridLayout.addWidget(self.visual_metric_parameter_label, 2, 0, 1, 1) + self.metric_Type_comboBox = QtWidgets.QComboBox(self.frame_2) + self.metric_Type_comboBox.setObjectName("metric_Type_comboBox") + self.gridLayout.addWidget(self.metric_Type_comboBox, 2, 1, 1, 1) + self.verticalLayout_2.addWidget(self.frame_2) + self.verticalLayout.addWidget(self.frame_15) self.search_control_frame_2 = QtWidgets.QFrame(visual_tab) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -351,9 +342,6 @@ class Ui_visual_tab(object): self.search_start_year_parameter_dateedit_2.setDisplayFormat(_translate("visual_tab", "yyyy")) self.search_start_year_parameter_label_2.setText(_translate("visual_tab", "Start Year")) self.search_end_year_parameter_dateedit_2.setDisplayFormat(_translate("visual_tab", "yyyy")) - self.visual_name_label.setText(_translate("visual_tab", "Database")) - self.visual_metric_parameter_label.setText(_translate("visual_tab", "Metric Type ")) - self.visual_vendor_parameter_label.setText(_translate("visual_tab", "Vendor")) self.label_45.setText(_translate("visual_tab", "Select Chart Type")) self.radioButton_3.setText(_translate("visual_tab", "Vertical Bar")) self.radioButton.setText(_translate("visual_tab", "Horizontal Bar")) @@ -368,7 +356,11 @@ class Ui_visual_tab(object): self.label_44.setText(_translate("visual_tab", "Vertical Axis Title")) self.label_43.setText(_translate("visual_tab", "Horizontal Axis Title")) self.label_36.setText(_translate("visual_tab", "Chart Title")) + self.visual_vendor_parameter_label.setText(_translate("visual_tab", "Vendor")) + self.visual_name_label.setText(_translate("visual_tab", "Database")) + self.visual_metric_parameter_label.setText(_translate("visual_tab", "Metric Type ")) self.open_folder_checkBox.setText(_translate("visual_tab", "Open Folder")) self.create_chart_button.setText(_translate("visual_tab", "Create Chart")) self.open_file_checkBox.setText(_translate("visual_tab", "Open File")) + import Resources_rc diff --git a/ui/VisualTab.ui b/ui/VisualTab.ui index cce375e..82eeda0 100644 --- a/ui/VisualTab.ui +++ b/ui/VisualTab.ui @@ -6,8 +6,8 @@ 0 0 - 1177 - 690 + 692 + 488 @@ -19,7 +19,7 @@ - + 0 @@ -32,127 +32,115 @@ QFrame::Raised - - - + + + + + Report + + + + + + + End Year + + + + + + + yyyy + + + + + - + 0 0 - - QFrame::StyledPanel + + Start Year - - QFrame::Raised + + + + + + + 0 + 0 + + + + + + + + QDateTimeEdit::YearSection + + + yyyy - - - - - Report - - - - - - - End Year - - - - - - - yyyy - - - - - - - - 0 - 0 - - - - Start Year - - - - - - - - 0 - 0 - - - - - - - - QDateTimeEdit::YearSection - - - yyyy - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + - + + + + 0 + 0 + + QFrame::StyledPanel QFrame::Raised - + - + - + 0 0 @@ -163,9 +151,12 @@ QFrame::Raised - - - + + + + + true + 0 @@ -178,96 +169,56 @@ QFrame::Raised - - - true - - - - 50 - 80 - 97 - 21 - - - - Database - - - - - - 50 - 130 - 213 - 20 - - - - Metric Type - - - - - - 140 - 130 - 921 - 26 - - - - - - - 50 - 30 - 61 - 20 - - - - Vendor - - - - - - 140 - 30 - 921 - 26 - - - - - 0 - 0 - - - - - - true - - - - 140 - 80 - 921 - 28 - - - - true - - + + + + + + 0 + 0 + + + + + Arial + + + + Select Chart Type + + + Qt::AutoText + + + + + + + Vertical Bar + + + + + + + Horizontal Bar + + + + + + + Line + + + + - - + + - + 0 0 @@ -278,230 +229,9 @@ QFrame::Raised - - - true - - - - 10 - 10 - 136 - 161 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - Arial - - - - Select Chart Type - - - Qt::AutoText - - - - - - - Vertical Bar - - - - - - - Horizontal Bar - - - - - - - Line - - - - - - - - - 150 - 10 - 141 - 161 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 121 - 21 - - - - - 0 - 0 - - - - - Arial - - - - Calculation Type - - - Qt::AutoText - - - - - - 10 - 40 - 112 - 20 - - - - Monthly - - - - - - 10 - 70 - 112 - 20 - - - - Yearly - - - - - - 10 - 100 - 112 - 20 - - - - Top # - - - - - - 10 - 130 - 112 - 20 - - - - Cost Ratio - - - - - - true - - - - 293 - 10 - 151 - 161 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 131 - 81 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 183 - 15 - - + + + 0 @@ -514,145 +244,269 @@ - Cost Ratio Option + Calculation Type Qt::AutoText - - - - 0 - 30 - 121 - 26 - + + + + + Monthly + + + + + + + Yearly + + + + + + + Top # - - - - - 10 - 90 - 131 - 61 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 183 - 15 - + + + + + Cost Ratio + + + + + + + + + true + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + - + 0 0 - - - Arial - + + QFrame::StyledPanel - - Top # + + QFrame::Raised - - Qt::AutoText + + + + + + 0 + 0 + + + + + Arial + + + + Cost Ratio Option + + + Qt::AutoText + + + + + + + + + + + + + + 0 + 0 + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + Arial + + + + Top # + + + Qt::AutoText + + + + + + + 999 + + + + - - - - 10 - 30 - 101 - 24 - + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + Vertical Axis Title - - 999 + + + + + + Horizontal Axis Title - - - - - - 460 - 10 - 601 - 161 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - - - - - - Vertical Axis Title - - - - - - - Horizontal Axis Title - - - - - - - Chart Title - - - - - + + + + + Chart Title + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Vendor + + + + + + + + 0 + 0 + + + + + + + + true + + + Database + + + + + + + true + + + true + + + + + + + Metric Type + + + + + + + + + diff --git a/vendor-lists/template-vendor-lists b/vendor-lists/template-vendor-lists new file mode 100644 index 0000000..6c990b0 --- /dev/null +++ b/vendor-lists/template-vendor-lists @@ -0,0 +1 @@ +Two files provided here, each designed to be starting points for populating your vendors data. One includes only vendors known to be coounter 5 compliant, the other also includes vendors thought to be still only counter 4 compliant (for use with the Import Report function). diff --git a/vendor-lists/vendors-template-R5-only.tsv b/vendor-lists/vendors-template-R5-only.tsv new file mode 100644 index 0000000..bbcd041 --- /dev/null +++ b/vendor-lists/vendors-template-R5-only.tsv @@ -0,0 +1,115 @@ +name base_url customer_id requestor_id api_key platform is_non_sushi description companies +DeGruyter (Walter De Gruyter) https:/ams.degruyter.com/rest/COUNTER/v5/reports REQUIRED REQUIRED True Manual COUNTER 5 import; service@degruyter.com +Edward Elgar Publishing https:/ams.elgaronline.com/rest/COUNTER/v5/reports REQUIRED REQUIRED True Manual COUNTER 5 import; info@e-elgar.co.uk +Academy of Management https://journals.aom.org/reports REQUIRED False +American Chemical Society https://pubs.acs.org/reports REQUIRED False +Adam Matthew Digital https://www.counter.amdigital.co.uk/CounterSushi5Api/reports REQUIRED REQUIRED False Adam Matthews primary historical document collections +Akademiai Kiado https://ams.akjournals.com/rest/COUNTER/v5/reports REQUIRED REQUIRED False Changed SUSHI R5 providers April 2020 Sheridan PubFactory +Alexander Street Press https://pqbi.prod.proquest.com/release/sushi/asp/sushi/reports REQUIRED REQUIRED False +Allen Press HEPG Journals https://hepgjournals.org/reports REQUIRED REQUIRED False Atypon +Allen Press Pinnacle https://pinnacle.allenpress.com/reports REQUIRED False Atypon +Allen Press Pinnacle (AAIDD) https://www.aaiddjournals.org/reports REQUIRED False Atypon +American College of Physicians (ACP) https://sitemaster.annals.org/sushi/reports REQUIRED False +American Economic Association (AEA) https://pubs.aeaweb.org/reports REQUIRED False +American Heart Association https://www.ahajournals.org/reports REQUIRED False +American Institute of Aeronautics & Astronautics https://arc.aiaa.org/reports REQUIRED False +American Mathematical Society https://counter.ams.org/counter/r5/reports REQUIRED REQUIRED False +American Medical Association https://sitemaster.jamanetwork.com/sushi/reports REQUIRED False +American Meteorological Society https://journals.ametsoc.org/reports REQUIRED False +American Physical Society https://inqwell.squidsolutions.com/release/aps/sushi/reports REQUIRED False +American Physiological Society https://www.physiology.org/reports REQUIRED REQUIRED False Atypon +American Psychiatric Publishing https://www.psychiatryonline.org/reports REQUIRED False +American Public Health Association https://ajph.aphapublications.org/reports REQUIRED False +American Roentgen Ray Society https://www.ajronline.org/reports REQUIRED REQUIRED False Atypon +American Society for Cell Biology https://www.molbiolcell.org/reports REQUIRED False +American Society Of Civil Engineers (ASCE) https://ascelibrary.org/reports REQUIRED False +American Society of Clinical Oncology (ASCO) https://ascopubs.org/reports REQUIRED False +American Society of Mechanical Engineers (ASME) https://sitemaster.asmedigitalcollection.asme.org/sushi/reports REQUIRED REQUIRED REQUIRED False Silverchair +American Speech-Language-Hearing Association https://pubs.asha.org/reports REQUIRED False +American Thoracic Society https://www.atsjournals.org/reports REQUIRED False +American Veterinary Medical Association https://avmajournals.avma.org/reports REQUIRED REQUIRED False Atypon +Annual Reviews https://www.annualreviews.org/reports REQUIRED REQUIRED False +AOTA (American Occupational Therapy Association) https://sitemaster.ajot.aota.org/sushi/reports REQUIRED False +APS (American Physical Society) https://inqwell.squidsolutions.com/release/aps/sushi/reports REQUIRED REQUIRED False +Berghahn Journals https://ams.berghahnjournals.com/rest/COUNTER/v5/reports REQUIRED False +BioOne https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +BIR (The British Institute of Radiology) https://www.birpublications.org/reports REQUIRED False +Brepols Online https://www.brepolsonline.net/reports REQUIRED False +Brill https://ams.brill.com/rest/COUNTER/v5/reports REQUIRED REQUIRED False +British Medical Journals (BMJ) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Cambridge Core https://event-aggregation-api-prod-platform.prod.aop.cambridge.org/reports REQUIRED REQUIRED False +Cambridge University Press http:/counter5.cambridge.org/reports REQUIRED False +Chemical Society of Japan https://www.journal.csj.jp/reports REQUIRED False +CREDO https://search.credoreference.com/reports REQUIRED REQUIRED False +CSIRO (Commonwealth Scientific and Industrial Research Organisation) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +DesLibris https://connect.liblynx.com/sushi/r5/reports REQUIRED REQUIRED REQUIRED False LibLynx +Duke University Press (Euclid) https://sitemaster.read.dukeupress.edu/sushi/reports REQUIRED REQUIRED REQUIRED False +Duncker & Humblot https://elibrary.duncker-humblot.com/sushi/reports REQUIRED REQUIRED REQUIRED False +EBSCOhost https://sushi.ebscohost.com/R5/reports REQUIRED REQUIRED False Converted to COUNTER 5 back to Jan 2018 +Edinburgh University Press https://www.euppublishing.com/reports REQUIRED False +Elsevier Engineering Village https://api.elsevier.com/sushi/reports REQUIRED REQUIRED ev False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Elsevier Scopus https://api.elsevier.com/sushi/reports REQUIRED REQUIRED sc False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Elsevier ScienceDirect https://api.elsevier.com/sushi/reports REQUIRED REQUIRED sd False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Emerald Insight https://connect.liblynx.com/sushi/r5/reports REQUIRED REQUIRED REQUIRED False Liblynx +FASEB https://www.fasebj.org/reports REQUIRED False +Future Medicine https://www.futuremedicine.com/reports REQUIRED False +Gale https://sushi5.galegroup.com/sushi/reports REQUIRED REQUIRED False +GeoscienceWorld https://sitemaster.geoscienceworld.org/sushi/reports REQUIRED REQUIRED REQUIRED False Silverchair +Guilford Press https://guilfordjournals.com/reports REQUIRED False +Harvard Education Publishing Group https://hepgjournals.org/reports REQUIRED False Atypon +Health Affairs https://www.healthaffairs.org/reports REQUIRED False +HighWire Press https://hwdpapi.highwire.org/sushi/reports REQUIRED REQUIRED REQUIRED False "Requester ID, Customer ID and Api_Key are required. API key is the institution's primary e-mail address associated with the HighWire Portal account, followed by ""|"", and then the portal password. For example, +API key: user@highwire.org|Us3rPW +Requester ID: user/email account registered with HighWire +Customer ID: user/email account registered with HighWire" +ICE Virtual Library (Institution of Civil Engineers) https://www.icevirtuallibrary.com/reports REQUIRED False +IEEE Xplore https://c5sushi.mpsinsight.com/c5sushi/services/reports REQUIRED REQUIRED False MPS Insight +IGI Global https://sushi5.igi-global.com/reports REQUIRED REQUIRED True As of April 2020 SUSHI server not compliant, use manual download/import +Inderscience https://inderscienceonline.com/reports REQUIRED False +INFORMS https://pubsonline.informs.org/reports REQUIRED False +Ingentaconnect https://www.ingentaconnect.com/sushiadmin/statistics/sushi/reports REQUIRED REQUIRED False Ingenta Connect hosts journals for various publishers +Journal of Neurosurgery (JNS) https://ams.thejns.org/rest/COUNTER/v5/reports REQUIRED False +Journal of Orthopaedic & Sports Physical Therapy (JOSPT) https://www.jospt.org/reports REQUIRED False +Journal of Studies on Alcohol and Drugs / Rutgers University Press (JSAD) https://www.jsad.com/reports REQUIRED False +JSTOR https://www.jstor.org/sushi/reports REQUIRED REQUIRED False Books and Journals +Karger https://counter.karger.com/reports REQUIRED False +Liverpool University Press https://online.liverpooluniversitypress.co.uk/reports REQUIRED False +Mark Allen Group https://www.magonlinelibrary.com/reports REQUIRED REQUIRED False Atypon +Mary Ann Liebert https://www.liebertpub.com/reports REQUIRED REQUIRED False Atypon +MathSciNet (American Mathematical Society) https://mathscinet.ams.org/counter/r5/reports REQUIRED REQUIRED False +McGraw-Hill https://www.mhebooklibrary.com/reports REQUIRED False +MGG Online https://www.mgg-online.com/mgg/sushi/reports REQUIRED False +Microbiology Society True C5 but not sushi yet as of March 2020 +MIT Press https://www.mitpressjournals.org/reports REQUIRED REQUIRED False Atypon +Morgan and Claypook Publishers https://www.morganclaypool.com/reports REQUIRED False +NEJM (New England Journal of Medicine) https://www.nejm.org/reports REQUIRED False +Newsbank https://stats.newsbank.com/sushi_r5/servlet/reports REQUIRED False +NRC Press https://www.nrcresearchpress.com/reports REQUIRED False +OECD iLibrary https://www.oecd-ilibrary.org/counter5/sushi/reports REQUIRED False +Ovid https://stats.ovid.com/C5/sushi/reports REQUIRED REQUIRED False +Oxford (Books) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Oxford (Journals) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Philosophy Documentation Centre https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Physical Society of Japan https://journals.jps.jp/reports REQUIRED False +Project HOPE (Health Affairs) https://hope.atyponinsights.com/counter5/reports REQUIRED False Atypon +Project MUSE https://about.muse.jhu.edu/lib/counter5/sushi/reports REQUIRED REQUIRED False +ProQuest https://sushi.proquest.com/counter/r5/reports REQUIRED REQUIRED False +ProQuest Ebook Central https://pqbi.prod.proquest.com/release/sushi/ebooks/r5/reports REQUIRED REQUIRED True As of April 2020, SUSHI server not providing reliable data (reported to Project COUNTER) so consider this one non-SUSHI until reported fixed. +Royal Society https://royalsocietypublishing.org/reports REQUIRED False +Royal Society of Chemistry https://c5sushi.mpsinsight.com/c5sushi/services/reports REQUIRED REQUIRED False +RSNA (Radiological Society of North America) https://pubs.rsna.org/reports REQUIRED False +SAGE Ebooks (Sage SecureCenter) https://securecenter.sagepub.com/SushiService/reports REQUIRED False +SAGE Journals https://journals.sagepub.com/reports REQUIRED REQUIRED False +Scitation - AIP (American Institute of Physics) https://www.scitation.org/reports REQUIRED False +SIAM (Society for Industrial and Applied Mathematics) https://epubs.siam.org/reports REQUIRED False +Society of Exploration Geophysicists https://library.seg.org/reports REQUIRED False +Springer Nature https://counter.public.springernature.app/reports REQUIRED REQUIRED False +Taylor & Francis Ebooks (Books) https://api.taylorandfrancis.com/v2/counterreports/reports REQUIRED False +Taylor & Francis Online (Journals) https://www.tandfonline.com/reports REQUIRED REQUIRED False +UCLA Journals https://uclajournals.org/reports REQUIRED False +University of Chicago Press https://www.journals.uchicago.edu/reports REQUIRED REQUIRED False +University of Toronto Press https://www.utpjournals.press/reports REQUIRED REQUIRED False +Vandenhoeck & Ruprecht https://www.vr-elibrary.de/reports REQUIRED False +Wiley Online Library https://onlinelibrary.wiley.com/reports REQUIRED REQUIRED False Books and journals Atypon +World Bank https://elibrary.worldbank.org/reports REQUIRED False +World Scientific https://www.worldscientific.com/reports REQUIRED False \ No newline at end of file diff --git a/vendor-lists/vendors-template-with-r4-vendors.tsv b/vendor-lists/vendors-template-with-r4-vendors.tsv new file mode 100644 index 0000000..d2bcf9f --- /dev/null +++ b/vendor-lists/vendors-template-with-r4-vendors.tsv @@ -0,0 +1,183 @@ +name base_url customer_id requestor_id api_key platform is_non_sushi description companies +AACCI (American Association of Cereal Chemists International) True BR2, JR5, JR1GOA, JR1, PR1, BR3 +AAIDD (American Association of Intellectual and Developmental Disabilities) True JR5, JR1GOA, JR1, PR1, BR3 +ABC-CLIO True Counter 4 only for import conversion; DB1 +Academy of Management https://journals.aom.org/reports REQUIRED False +Accessible Archives True +ACM Digital Library (Association for Computing Machinery) True +American Chemical Society https://pubs.acs.org/reports REQUIRED False +ACSESS Digital Library (American Society of Agronomy, Crop Science Society of America, and Soil Science Society of America (ASA, CSSA & SSSA)) True +Adam Matthew Digital https://www.counter.amdigital.co.uk/CounterSushi5Api/reports REQUIRED REQUIRED False Adam Matthews primary historical document collections +AIAA (American Institute of Aeronautics and Astronautics) True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, JR1a, PR1, BR3 +Akademiai Kiado https://ams.akjournals.com/rest/COUNTER/v5/reports REQUIRED REQUIRED False Changed SUSHI R5 providers April 2020 Sheridan PubFactory +Alexander Street Press https://pqbi.prod.proquest.com/release/sushi/asp/sushi/reports REQUIRED REQUIRED False +Allen Press HEPG Journals https://hepgjournals.org/reports REQUIRED REQUIRED False Atypon +Allen Press Pinnacle https://pinnacle.allenpress.com/reports REQUIRED False Atypon +Allen Press Pinnacle (AAIDD) https://www.aaiddjournals.org/reports REQUIRED False Atypon +American College of Physicians (ACP) https://sitemaster.annals.org/sushi/reports REQUIRED False +American Economic Association (AEA) https://pubs.aeaweb.org/reports REQUIRED False +American Heart Association https://www.ahajournals.org/reports REQUIRED False +American Institute of Aeronautics & Astronautics https://arc.aiaa.org/reports REQUIRED False +American Mathematical Society https://counter.ams.org/counter/r5/reports REQUIRED REQUIRED False +American Medical Association https://sitemaster.jamanetwork.com/sushi/reports REQUIRED False +American Mental Health Counselors Association True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +American Meteorological Society https://journals.ametsoc.org/reports REQUIRED False +American Physical Society https://inqwell.squidsolutions.com/release/aps/sushi/reports REQUIRED False +American Physiological Society https://www.physiology.org/reports REQUIRED REQUIRED False Atypon +American Podiatric Medical Association True Counter 4 only for import conversion; JR1, JR2, JR1GOA, JR5, BR3, PR1 +American Psychiatric Publishing https://www.psychiatryonline.org/reports REQUIRED False +American Public Health Association https://ajph.aphapublications.org/reports REQUIRED False +American Roentgen Ray Society https://www.ajronline.org/reports REQUIRED REQUIRED False Atypon +American Society for Cell Biology https://www.molbiolcell.org/reports REQUIRED False +American Society Of Civil Engineers (ASCE) https://ascelibrary.org/reports REQUIRED False +American Society of Clinical Oncology (ASCO) https://ascopubs.org/reports REQUIRED False +American Society of Mechanical Engineers (ASME) https://sitemaster.asmedigitalcollection.asme.org/sushi/reports REQUIRED REQUIRED REQUIRED False Silverchair +American Society of Tropical Medicine and Hygiene True +American Speech-Language-Hearing Association https://pubs.asha.org/reports REQUIRED False +American Thoracic Society https://www.atsjournals.org/reports REQUIRED False +American Veterinary Medical Association https://avmajournals.avma.org/reports REQUIRED REQUIRED False Atypon +AMSUS (The Society of Federal Health Professionals) True Counter 4 only for import conversion; JR5, JR1, PR1 +Annual Reviews https://www.annualreviews.org/reports REQUIRED REQUIRED False +AOTA (American Occupational Therapy Association) https://sitemaster.ajot.aota.org/sushi/reports REQUIRED False +APA PsycNET True +APS (American Physical Society) https://inqwell.squidsolutions.com/release/aps/sushi/reports REQUIRED REQUIRED False +APS (American Phytopathological Society) True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +ASA (American Statistical Association) True Counter 4 only for import conversion; JR1, DB1 +ASM (American Society for Microbiology) True Counter 4 only for import conversion; BR2, JR1GOA, JR1, PR1, BR3 +Berghahn Journals https://ams.berghahnjournals.com/rest/COUNTER/v5/reports REQUIRED False +BioMed Central True Counter 4 only for import conversion; JR5, JR1GOA, JR1 +BioOne https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +BIR (The British Institute of Radiology) https://www.birpublications.org/reports REQUIRED False +Bone & Joint Publishing True +Brepols Online https://www.brepolsonline.net/reports REQUIRED False +Brill https://ams.brill.com/rest/COUNTER/v5/reports REQUIRED REQUIRED False +Britannica True +British Institute of Radiology True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +British Medical Journals (BMJ) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Cambridge Core https://event-aggregation-api-prod-platform.prod.aop.cambridge.org/reports REQUIRED REQUIRED False +Cambridge University Press http:/counter5.cambridge.org/reports REQUIRED False +Canadian Science Publishing True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +CFA Publications True Counter 4 only for import conversion; JR5, JR1, PR1 +Chemical Society of Japan https://www.journal.csj.jp/reports REQUIRED False +Corrosion (The Journal of Science & Engineering) True Counter 4 only for import conversion; JR5, JR1GOA, JR1 +CRCnetBase (CRC netBase) True Counter 4 only for import conversion; BR2, PR1, BR3 +CREDO https://search.credoreference.com/reports REQUIRED REQUIRED False +CSIRO (Commonwealth Scientific and Industrial Research Organisation) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +DeGruyter (Walter De Gruyter) https:/ams.degruyter.com/rest/COUNTER/v5/reports REQUIRED REQUIRED True Manual COUNTER 5 import; service@degruyter.com +DesLibris https://connect.liblynx.com/sushi/r5/reports REQUIRED REQUIRED REQUIRED False LibLynx +Duke University Press (Euclid) https://sitemaster.read.dukeupress.edu/sushi/reports REQUIRED REQUIRED REQUIRED False +Duncker & Humblot https://elibrary.duncker-humblot.com/sushi/reports REQUIRED REQUIRED REQUIRED False +EBSCOhost https://sushi.ebscohost.com/R5/reports REQUIRED REQUIRED False Converted to COUNTER 5 back to 2018 +Edinburgh University Press https://www.euppublishing.com/reports REQUIRED False +EDP Sciences (Astronomy and Astrophysics) True +Edward Elgar Publishing https:/ams.elgaronline.com/rest/COUNTER/v5/reports REQUIRED REQUIRED True Manual COUNTER 5 import; info@e-elgar.co.uk +Elsevier Engineering Village https://api.elsevier.com/sushi/reports REQUIRED REQUIRED ev False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Elsevier Scopus https://api.elsevier.com/sushi/reports REQUIRED REQUIRED sc False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Elsevier ScienceDirect https://api.elsevier.com/sushi/reports REQUIRED REQUIRED sd False Checks IP range must be on campus; also have to re-run every new report - always error on first try +Emerald Insight https://connect.liblynx.com/sushi/r5/reports REQUIRED REQUIRED REQUIRED False Liblynx +EMS (European Mathematical Society) True Counter 4 only for import conversion; JR1:R3 +Endocrine Society Journals True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, JR1a, BR3 +Families in Society True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +FASEB https://www.fasebj.org/reports REQUIRED False +Future Medicine https://www.futuremedicine.com/reports REQUIRED False +Future Science True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +Gale https://sushi5.galegroup.com/sushi/reports REQUIRED REQUIRED False +GeoscienceWorld https://sitemaster.geoscienceworld.org/sushi/reports REQUIRED REQUIRED REQUIRED False Silverchair +Guilford Press https://guilfordjournals.com/reports REQUIRED False +Hanser True Counter 4 only for import conversion; BR2, JR5, JR1, PR1, BR3 +Harvard Education Publishing Group https://hepgjournals.org/reports REQUIRED False Atypon +Health Affairs https://www.healthaffairs.org/reports REQUIRED False +HighWire Press https://hwdpapi.highwire.org/sushi/reports REQUIRED REQUIRED REQUIRED False "API key is the institution's primary e-mail address associated with the HighWire Portal account, followed by ""|"", and then the portal password. For example, +API key: user@highwire.org|Us3rPW +Requester ID: user/email account registered with HighWire +Customer ID: user/email account registered with HighWire" +Hogrefe True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +Human Kinetics True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +ICE Virtual Library (Institution of Civil Engineers) https://www.icevirtuallibrary.com/reports REQUIRED False +Idunn True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +IEEE Xplore https://c5sushi.mpsinsight.com/c5sushi/services/reports REQUIRED REQUIRED False MPS Insight +IET (Institution of Engineering and Technology) True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, BR1, PR1, BR3 +IGI Global https://sushi5.igi-global.com/reports REQUIRED REQUIRED True As of April 2020 SUSHI server not compliant, use manual download/import +IMF (International Monetary Fund) True Counter 4 only for import conversion; DB1 +INA (Irish Newspaper Archives) True +Inderscience https://inderscienceonline.com/reports REQUIRED False +Informit True Counter 4 only for import conversion; BR2, JR5, JR1, BR1 +INFORMS https://pubsonline.informs.org/reports REQUIRED False +Ingentaconnect https://www.ingentaconnect.com/sushiadmin/statistics/sushi/reports REQUIRED REQUIRED False Ingenta Connect hosts journals for various publishers +IOS Press - CAB Journals & eBooks True +IOS Press (formerly MetaPress) True Counter 4 only for import conversion; BR2, JR1, BR1, DB1, PR1, BR3 +John Benjamins True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +Journal of Clinical Psychiatry True +Journal of Coastal research True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +Journal of Graduate Medical Education True Counter 4 only for import conversion; JR1 +Journal of Marketing Research True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +Journal of Neurosurgery (JNS) https://ams.thejns.org/rest/COUNTER/v5/reports REQUIRED False +Journal of Oral Implantology True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +Journal of Orthopaedic & Sports Physical Therapy (JOSPT) https://www.jospt.org/reports REQUIRED False +Journal of Parasitology True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +Journal of Periodontology Online True Counter 4 only for import conversion; JR5, JR1, PR1 +Journal of Studies on Alcohol and Drugs / Rutgers University Press (JSAD) https://www.jsad.com/reports REQUIRED False +Journal of the Physical Society of Japan True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +JSTOR https://www.jstor.org/sushi/reports REQUIRED REQUIRED False Books and Journals +Karger https://counter.karger.com/reports REQUIRED False +Kluwer Law International True +Liverpool University Press https://online.liverpooluniversitypress.co.uk/reports REQUIRED False +Mark Allen Group https://www.magonlinelibrary.com/reports REQUIRED REQUIRED False Atypon +Mary Ann Liebert https://www.liebertpub.com/reports REQUIRED REQUIRED False Atypon +MathSciNet (American Mathematical Society) https://mathscinet.ams.org/counter/r5/reports REQUIRED REQUIRED False +McGraw-Hill https://www.mhebooklibrary.com/reports REQUIRED False +MGG Online https://www.mgg-online.com/mgg/sushi/reports REQUIRED False +Microbiology Society True Counter 4 only for import conversion; C5 but not sushi yet as of March 2020 +Military Medicine True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +MIT Press https://www.mitpressjournals.org/reports REQUIRED REQUIRED False Atypon +MLA (Modern Language Association) True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +Morgan and Claypook Publishers https://www.morganclaypool.com/reports REQUIRED False +NEJM (New England Journal of Medicine) https://www.nejm.org/reports REQUIRED False +Newsbank https://stats.newsbank.com/sushi_r5/servlet/reports REQUIRED False +NRC Press https://www.nrcresearchpress.com/reports REQUIRED False +OECD iLibrary https://www.oecd-ilibrary.org/counter5/sushi/reports REQUIRED False +OSA InfoBase (Optics InfoBase) True +Ovid https://stats.ovid.com/C5/sushi/reports REQUIRED REQUIRED False +Oxford (Books) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Oxford (Journals) https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Philosophy Documentation Centre https://sushi5.scholarlyiq.com/counter/r5/reports REQUIRED REQUIRED False ScholarlyIQ +Physical Society of Japan https://journals.jps.jp/reports REQUIRED False +Physicians Postgraduate Press True +Practical Action Publishing True Counter 4 only for import conversion; JR1, PR1, JR2, BR2, BR3 +Professional School Counseling True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +Project HOPE (Health Affairs) https://hope.atyponinsights.com/counter5/reports REQUIRED False Atypon +Project MUSE https://about.muse.jhu.edu/lib/counter5/sushi/reports REQUIRED REQUIRED False +ProQuest https://sushi.proquest.com/counter/r5/reports REQUIRED REQUIRED False +ProQuest Ebook Central https://pqbi.prod.proquest.com/release/sushi/ebooks/r5/reports REQUIRED REQUIRED True As of April 2020, SUSHI server not providing reliable data (reported to Project COUNTER) so consider this one non-SUSHI until reported fixed. +Psychiatry Online True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, BR1, JR1a, PR1, BR3 +Radiation Research True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +RCN (Royal College of Nursing) True +Royal College of Surgeons of England True Counter 4 only for import conversion; JR1, PR1 +Royal Society https://royalsocietypublishing.org/reports REQUIRED False +Royal Society of Chemistry https://c5sushi.mpsinsight.com/c5sushi/services/reports REQUIRED REQUIRED False +RSNA (Radiological Society of North America) https://pubs.rsna.org/reports REQUIRED False +SAGE Ebooks (Sage SecureCenter) https://securecenter.sagepub.com/SushiService/reports REQUIRED False +SAGE Journals https://journals.sagepub.com/reports REQUIRED REQUIRED False +Science Societies True +Scitation - AIP (American Institute of Physics) https://www.scitation.org/reports REQUIRED False +SEG (Society of Exploration Geophysicists) True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +SFAA (Society for Applied Anthropology) True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +SIAM (Society for Industrial and Applied Mathematics) https://epubs.siam.org/reports REQUIRED False +Society of Exploration Geophysicists https://library.seg.org/reports REQUIRED False +SPIE (Society of Photo-Optical Instrumentation Engineers) True +Springer Nature https://counter.public.springernature.app/reports REQUIRED REQUIRED False +Taylor & Francis Ebooks (Books) https://api.taylorandfrancis.com/v2/counterreports/reports REQUIRED False +Taylor & Francis Online (Journals) https://www.tandfonline.com/reports REQUIRED REQUIRED False +The Cleft Palate - Craniofacial Journal True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1, BR3 +Thieme Planta Medica True Counter 4 only for import conversion; JR5, JR1GOA, JR1, PR1 +Transportation Research Board True Counter 4 only for import conversion; JR5, JR1, PR1, BR3 +UCLA Journals https://uclajournals.org/reports REQUIRED False +University of Chicago Press https://www.journals.uchicago.edu/reports REQUIRED REQUIRED False +University of Texas Press True Counter 4 only for import conversion; JR1 +University of Toronto Press https://www.utpjournals.press/reports REQUIRED REQUIRED False +UNWTO (United Nations World Tourism Organization) True Counter 4 only for import conversion; BR2, JR5, JR1, PR1 +Vandenhoeck & Ruprecht https://www.vr-elibrary.de/reports REQUIRED False +Wageningen Academic Publishers True Counter 4 only for import conversion; BR2, JR5, JR1GOA, JR1, PR1, BR3 +Wiley Online Library https://onlinelibrary.wiley.com/reports REQUIRED REQUIRED False Books and journals Atypon +World Bank https://elibrary.worldbank.org/reports REQUIRED False +World Scientific https://www.worldscientific.com/reports REQUIRED False \ No newline at end of file