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