Skip to content

Commit 28318f7

Browse files
authored
Merge pull request #117 from QuanMPhm/115/prepayment_proc
Implemented processor for prepayments
2 parents 5c7290d + e95349a commit 28318f7

12 files changed

+799
-32
lines changed

process_report/invoices/NERC_total_invoice.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ class NERCTotalInvoice(invoice.Invoice):
3030
invoice.SU_HOURS_FIELD,
3131
invoice.SU_TYPE_FIELD,
3232
invoice.RATE_FIELD,
33+
invoice.GROUP_NAME_FIELD,
34+
invoice.GROUP_INSTITUTION_FIELD,
35+
invoice.GROUP_BALANCE_FIELD,
3336
invoice.COST_FIELD,
37+
invoice.GROUP_BALANCE_USED_FIELD,
3438
invoice.CREDIT_FIELD,
3539
invoice.CREDIT_CODE_FIELD,
3640
invoice.BALANCE_FIELD,

process_report/invoices/billable_invoice.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ class BillableInvoice(invoice.Invoice):
3131
invoice.SU_HOURS_FIELD,
3232
invoice.SU_TYPE_FIELD,
3333
invoice.RATE_FIELD,
34+
invoice.GROUP_NAME_FIELD,
35+
invoice.GROUP_INSTITUTION_FIELD,
36+
invoice.GROUP_BALANCE_FIELD,
3437
invoice.COST_FIELD,
38+
invoice.GROUP_BALANCE_USED_FIELD,
3539
invoice.CREDIT_FIELD,
3640
invoice.CREDIT_CODE_FIELD,
3741
invoice.BALANCE_FIELD,

process_report/invoices/bu_internal_invoice.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ class BUInternalInvoice(invoice.Invoice):
1515
invoice.INVOICE_DATE_FIELD,
1616
invoice.PI_FIELD,
1717
"Project",
18+
invoice.GROUP_NAME_FIELD,
19+
invoice.GROUP_INSTITUTION_FIELD,
20+
invoice.GROUP_BALANCE_FIELD,
1821
invoice.COST_FIELD,
22+
invoice.GROUP_BALANCE_USED_FIELD,
1923
invoice.CREDIT_FIELD,
2024
invoice.SUBSIDY_FIELD,
2125
invoice.PI_BALANCE_FIELD,

process_report/invoices/invoice.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212
PI_2ND_USED = "2nd Month Used"
1313
###
1414

15+
### Prepay files fields
16+
PREPAY_MONTH_FIELD = "Month"
17+
PREPAY_CREDIT_FIELD = "Credit"
18+
PREPAY_DEBIT_FIELD = "Debit"
19+
PREPAY_GROUP_NAME_FIELD = "Group Name"
20+
PREPAY_GROUP_CONTACT_FIELD = "Group Contact Email"
21+
PREPAY_MANAGED_FIELD = "MGHPCC Managed"
22+
PREPAY_PROJECT_FIELD = "Project"
23+
PREPAY_START_DATE_FIELD = "Start Date"
24+
PREPAY_END_DATE_FIELD = "End Date"
25+
###
26+
1527
### Invoice field names
1628
INVOICE_DATE_FIELD = "Invoice Month"
1729
PROJECT_FIELD = "Project - Allocation"
@@ -21,6 +33,10 @@
2133
INVOICE_ADDRESS_FIELD = "Invoice Address"
2234
INSTITUTION_FIELD = "Institution"
2335
INSTITUTION_ID_FIELD = "Institution - Specific Code"
36+
GROUP_NAME_FIELD = "Prepaid Group Name"
37+
GROUP_INSTITUTION_FIELD = "Prepaid Group Institution"
38+
GROUP_BALANCE_FIELD = "Prepaid Group Balance"
39+
GROUP_BALANCE_USED_FIELD = "Prepaid Group Used"
2440
SU_HOURS_FIELD = "SU Hours (GBhr or SUhr)"
2541
SU_TYPE_FIELD = "SU Type"
2642
SU_CHARGE_FIELD = "SU Charge"
@@ -38,6 +54,7 @@
3854
MISSING_PI_FIELD = "Missing PI"
3955
PI_BALANCE_FIELD = "PI Balance"
4056
PROJECT_NAME_FIELD = "Project"
57+
GROUP_MANAGED_FIELD = "MGHPCC Managed"
4158
###
4259

4360

process_report/invoices/pi_specific_invoice.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ class PIInvoice(invoice.Invoice):
2727
invoice.SU_HOURS_FIELD,
2828
invoice.SU_TYPE_FIELD,
2929
invoice.RATE_FIELD,
30+
invoice.GROUP_NAME_FIELD,
31+
invoice.GROUP_INSTITUTION_FIELD,
32+
invoice.GROUP_BALANCE_FIELD,
3033
invoice.COST_FIELD,
34+
invoice.GROUP_BALANCE_USED_FIELD,
3135
invoice.CREDIT_FIELD,
3236
invoice.CREDIT_CODE_FIELD,
3337
invoice.BALANCE_FIELD,

process_report/process_report.py

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
validate_billable_pi_processor,
2424
new_pi_credit_processor,
2525
bu_subsidy_processor,
26+
prepayment_processor,
2627
)
2728

2829
### PI file field names
@@ -54,8 +55,8 @@
5455
###
5556

5657
PI_S3_FILEPATH = "PIs/PI.csv"
57-
5858
ALIAS_S3_FILEPATH = "PIs/alias.csv"
59+
PREPAY_DEBITS_S3_FILEPATH = "Prepay/prepay_debits.csv"
5960

6061

6162
logger = logging.getLogger(__name__)
@@ -77,6 +78,14 @@ def load_alias(alias_file):
7778
return alias_dict
7879

7980

81+
def load_prepay_csv(prepay_credits_path, prepay_projects_path, prepay_contacts_path):
82+
return (
83+
pandas.read_csv(prepay_credits_path),
84+
pandas.read_csv(prepay_projects_path),
85+
pandas.read_csv(prepay_contacts_path),
86+
)
87+
88+
8089
def get_iso8601_time():
8190
return datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
8291

@@ -121,6 +130,24 @@ def main():
121130
required=True,
122131
help="File containing list of projects that are non-billable within a specified duration",
123132
)
133+
parser.add_argument(
134+
"--prepay-credits",
135+
required=False,
136+
default="prepaid_credits.csv",
137+
help="CSV listing all prepay group credits. Defaults to 'prepaid_credits.csv'",
138+
)
139+
parser.add_argument(
140+
"--prepay-projects",
141+
required=False,
142+
default="prepaid_projects.csv",
143+
help="CSV listing all prepay group projects. Defaults to 'prepaid_projects.csv'",
144+
)
145+
parser.add_argument(
146+
"--prepay-contacts",
147+
required=False,
148+
default="prepaid_contacts.csv",
149+
help="CSV listing all prepay group contact information. Defaults to 'prepaid_contacts.csv'",
150+
)
124151

125152
parser.add_argument(
126153
"--nonbillable-file",
@@ -168,6 +195,11 @@ def main():
168195
required=False,
169196
help="Name of alias file listing PIs with aliases (and their aliases). If not provided, defaults to fetching from S3",
170197
)
198+
parser.add_argument(
199+
"--prepay-debits",
200+
required=False,
201+
help="Name of csv file listing all prepay group debits. If not provided, defaults to fetching from S3",
202+
)
171203
parser.add_argument(
172204
"--BU-subsidy-amount",
173205
required=True,
@@ -194,6 +226,15 @@ def main():
194226
alias_file = fetch_s3_alias_file()
195227
alias_dict = load_alias(alias_file)
196228

229+
if args.prepay_debits:
230+
prepay_debits_filepath = args.prepay_debits
231+
else:
232+
prepay_debits_filepath = fetch_s3_prepay_debits()
233+
234+
prepay_credits, prepay_projects, prepay_info = load_prepay_csv(
235+
args.prepay_credits, args.prepay_projects, args.prepay_contacts
236+
)
237+
197238
merged_dataframe = merge_csv(csv_files)
198239

199240
pi = []
@@ -255,7 +296,19 @@ def main():
255296
)
256297
bu_subsidy_proc.process()
257298

258-
processed_data = bu_subsidy_proc.data
299+
prepayment_proc = prepayment_processor.PrepaymentProcessor(
300+
"",
301+
invoice_month,
302+
bu_subsidy_proc.data,
303+
prepay_credits,
304+
prepay_projects,
305+
prepay_info,
306+
prepay_debits_filepath,
307+
args.upload_to_s3,
308+
)
309+
prepayment_proc.process()
310+
311+
processed_data = prepayment_proc.data
259312

260313
### Initialize invoices
261314

@@ -385,6 +438,13 @@ def fetch_s3_old_pi_file():
385438
return local_name
386439

387440

441+
def fetch_s3_prepay_debits():
442+
local_name = "prepay_debits.csv"
443+
invoice_bucket = util.get_invoice_bucket()
444+
invoice_bucket.download_file(PREPAY_DEBITS_S3_FILEPATH, local_name)
445+
return local_name
446+
447+
388448
def backup_to_s3_old_pi_file(old_pi_file):
389449
invoice_bucket = util.get_invoice_bucket()
390450
invoice_bucket.upload_file(old_pi_file, f"PIs/Archive/PI {get_iso8601_time()}.csv")

process_report/processors/add_institution_processor.py

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,6 @@
1414

1515
@dataclass
1616
class AddInstitutionProcessor(processor.Processor):
17-
@staticmethod
18-
def _get_institute_mapping(institute_list: list):
19-
institute_map = dict()
20-
for institute_info in institute_list:
21-
for domain in institute_info["domains"]:
22-
institute_map[domain] = institute_info["display_name"]
23-
24-
return institute_map
25-
26-
@staticmethod
27-
def _get_institution_from_pi(institute_map, pi_uname):
28-
institution_domain = pi_uname.split("@")[-1]
29-
for i in range(institution_domain.count(".") + 1):
30-
if institution_name := institute_map.get(institution_domain, ""):
31-
break
32-
institution_domain = institution_domain[institution_domain.find(".") + 1 :]
33-
34-
if institution_name == "":
35-
logger.warning(f"PI name {pi_uname} does not match any institution!")
36-
37-
return institution_name
38-
3917
def _add_institution(self):
4018
"""Determine every PI's institution name, logging any PI whose institution cannot be determined
4119
This is performed by `get_institution_from_pi()`, which tries to match the PI's username to
@@ -49,7 +27,7 @@ def _add_institution(self):
4927
The list of mappings are defined in `institute_map.json`.
5028
"""
5129
institute_list = util.load_institute_list()
52-
institute_map = self._get_institute_mapping(institute_list)
30+
institute_map = util.get_institute_mapping(institute_list)
5331
self.data = self.data.astype({invoice.INSTITUTION_FIELD: "str"})
5432
for i, row in self.data.iterrows():
5533
pi_name = row[invoice.PI_FIELD]
@@ -58,7 +36,7 @@ def _add_institution(self):
5836
else:
5937
self.data.at[
6038
i, invoice.INSTITUTION_FIELD
61-
] = self._get_institution_from_pi(institute_map, pi_name)
39+
] = util.get_institution_from_pi(institute_map, pi_name)
6240

6341
def _process(self):
6442
self._add_institution()

0 commit comments

Comments
 (0)