Last active
December 15, 2022 21:02
-
-
Save wenboown/df1f1d707bf11b7ff5b5fb1c87dea93e to your computer and use it in GitHub Desktop.
A simple script to parse Tmobile's monthly bill and extract billing of individual number line into an xlsx file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ''' | |
| Bo Wen | |
| v1: Dec 25, 2019 | |
| v2: Nov 21, 2020 | |
| v3: Jun, 2021 - updated for tmobile's new summary pdf layout | |
| v4: Dec 2022 - check phone number exists in the summary before processing to avoid error | |
| require: | |
| Python3 | |
| pipenv install pdfplumber | |
| pipenv install xlsxwriter | |
| ''' | |
| import xlsxwriter | |
| import pdfplumber | |
| import re | |
| import argparse | |
| # the final xlsx report will follow the number order and list bill from left to right | |
| phone_list=['(123)\xa0456-7890', | |
| '(123)\xa0456-7891', | |
| '(123)\xa0456-7892', | |
| ] | |
| # helper functions: | |
| def search_next(lis, word): | |
| return next((i for i,v in enumerate(lis) if v.startswith(word)), None) | |
| def parse_dollar(word): | |
| if word == '-': | |
| return 0 | |
| else: | |
| v=word.split('$')[-1] | |
| if ')' in v: | |
| return -float(v.split(')')[0]) | |
| else: | |
| return float(v) | |
| # main function: | |
| def Parse_file(filename, phone_list): | |
| alltext='' | |
| parsed_dict={} | |
| ind_dict={} | |
| if '.pdf' in filename: | |
| filename = filename.split('.pdf')[0] | |
| with pdfplumber.open(filename+'.pdf') as pdf: | |
| for p in pdf.pages: | |
| temp = p.extract_text(x_tolerance=3, y_tolerance=3) | |
| if temp is not None: | |
| alltext=alltext+temp | |
| lines=re.split(r'\s{2,}|\n', alltext) | |
| workbook = xlsxwriter.Workbook(filename+'.xlsx') | |
| worksheet = workbook.add_worksheet() | |
| parsed_dict['Bill period']=lines[1].split(' XXXXXXXXX',1)[0] # replace "XXXXXXXXX" with your actual tmobile account number, near top right of the pdf | |
| parsed_dict['Tmobile billed amount']=parse_dollar(lines[search_next(lines, "Here's your bill")-1].split()[0]) | |
| parsed_dict['plan charge']=parse_dollar(lines[search_next(lines, "Account")].split("$")[-1]) | |
| worksheet.write('A1', 'Bill period = '+parsed_dict['Bill period']) | |
| worksheet.write('B1', parsed_dict['Tmobile billed amount']) | |
| worksheet.write('A2', 'account + tax (sevice for next month)') | |
| worksheet.write('C2', parsed_dict['plan charge']) | |
| row=3 | |
| col=0 | |
| pos_ = search_next(lines, "THIS BILL SUMMARY") | |
| pos_end = search_next(lines, "DETAILED CHARGES") | |
| for phone in phone_list: | |
| if any(phone in s for s in lines[pos_:pos_end]): | |
| print(f"processing {phone}") | |
| phone_line = lines[pos_ + search_next(lines[pos_: pos_ + 20], phone)] | |
| phone_items = phone_line.split('$', 1)[1].split() | |
| plans_charge = parse_dollar(phone_items[0]) | |
| eq_charge = parse_dollar(phone_items[1]) | |
| service_charge = parse_dollar(phone_items[2]) | |
| one_time_charge = parse_dollar(phone_items[3]) | |
| if plans_charge > 10: | |
| plans_charge = plans_charge - 10 | |
| worksheet.write(row, col, plans_charge) | |
| worksheet.write(row + 1, col, eq_charge) | |
| worksheet.write(row + 2, col, service_charge) | |
| worksheet.write(row + 3, col, one_time_charge) | |
| col = col + 1 | |
| else: | |
| print(f"{phone} doesn't exist, skip") | |
| workbook.close() | |
| if __name__ == '__main__': | |
| parser = argparse.ArgumentParser(description='tmobile bill parser') | |
| parser.add_argument('-f', '--file', required=True, help='bill pdf file') | |
| # parser.add_argument('-p', '--phone_list', required=False, help='phone number list json') | |
| args = parser.parse_args() | |
| Parse_file(args.file, phone_list) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment