statement_reconciler: Add initial support for Citizens Bank
This commit is contained in:
		
							parent
							
								
									e2f90d86bb
								
							
						
					
					
						commit
						e21142f0ba
					
				
					 3 changed files with 52 additions and 1 deletions
				
			
		|  | @ -305,6 +305,39 @@ def read_chase_csv(f: TextIO) -> list: | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def validate_citizens_csv(sample: str) -> None: | ||||
|     required_cols = {'Effective Date', 'Amount', 'Account Number', 'Transaction Description'} | ||||
|     reader = csv.DictReader(io.StringIO(sample)) | ||||
|     if reader.fieldnames and not required_cols.issubset(reader.fieldnames): | ||||
|         sys.exit( | ||||
|             f"This Citizens CSV doesn't seem to have the columns we're expecting, including: {', '.join(required_cols)}. Please use an unmodified statement direct from the institution." | ||||
|         ) | ||||
| 
 | ||||
| def standardize_citizens_record(row: Dict, line: int) -> Dict: | ||||
|     """Turn an Chase CSV row into a standard dict format representing a transaction.""" | ||||
|     return { | ||||
|         'date': datetime.datetime.strptime(row['Effective Date'], '%m/%d/%Y').date(), | ||||
|         'amount': parse_amount(row['Amount']), | ||||
|         'payee': ('{originator} {beneficiary}'.format( | ||||
|             originator=row['Originator Name'].strip(), | ||||
|             beneficiary=row['Beneficiary Name'].strip(), | ||||
|         ) or '')[:50], | ||||
|         'check_id': '', | ||||
|         'line': line, | ||||
|     } | ||||
| 
 | ||||
| def read_citizens_csv(f: TextIO) -> list: | ||||
|     reader = csv.reader(f) | ||||
|     headers = next(reader) | ||||
|     # CSV duplicates the "Effective Date" field, so we can't use DictReader. | ||||
|     headers[21] = 'Effective Date 2' | ||||
|     reader = (dict(zip(headers, row)) for row in csv.reader(f)) | ||||
|     # The reader.line_num is the source line number, not the spreadsheet row | ||||
|     # number due to multi-line records. | ||||
|     return sort_records( | ||||
|         [standardize_citizens_record(row, i) for i, row in enumerate(reader, 2)] | ||||
|     ) | ||||
| 
 | ||||
| def standardize_beancount_record(row) -> Dict:  # type: ignore[no-untyped-def] | ||||
|     """Turn a Beancount query result row into a standard dict representing a transaction.""" | ||||
|     return { | ||||
|  | @ -826,6 +859,9 @@ def main( | |||
|     elif 'Chase' in args.account: | ||||
|         validate_csv = validate_chase_csv | ||||
|         read_csv = read_chase_csv | ||||
|     elif 'Citizens' in args.account: | ||||
|         validate_csv = validate_citizens_csv | ||||
|         read_csv = read_citizens_csv | ||||
|     else: | ||||
|         sys.exit("This account provided doesn't match one of AMEX, FR or Chase.") | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| [metadata] | ||||
| name = conservancy_beancount | ||||
| version = 1.21.0 | ||||
| version = 1.22.0 | ||||
| author = Software Freedom Conservancy | ||||
| author_email = info@sfconservancy.org | ||||
| description = Plugin, library, and reports for reading Conservancy’s books | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ from conservancy_beancount.reconcile.statement_reconciler import ( | |||
|     payee_match, | ||||
|     read_amex_csv, | ||||
|     read_fr_csv, | ||||
|     read_citizens_csv, | ||||
|     remove_duplicate_words, | ||||
|     remove_payee_junk, | ||||
|     round_to_month, | ||||
|  | @ -421,6 +422,20 @@ def test_handles_fr_csv(): | |||
|     assert read_fr_csv(io.StringIO(CSV)) == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_handles_citizens_csv(): | ||||
|     CSV = """Effective Date,Bank ID,Account Number,Account Name,Transaction Description,Status,Debit/Credit,Amount,Bank Reference,Customer Reference,Transaction Detail,BAI Code,Type,Additional Information,Currency,Image,Advice Reference,Transaction Number,Originator Id,Originator Name,Company Entry Description,Effective Date,Related Reference,Value Date of Payment,Transaction Reference,SEC Type,Settlement Reference,Payer Account Name,Payer Account,Payer Address 1,Payer Address 2,Payer Address 3,Payer Address 4,Payer Bank Code,Payer Bank Name,Payer Bank Address 1,Payer Bank Address 2,Payer Bank Address 3,Sender Bank Id,Sender Bank,Sender Address 1,Sender Address 2,Sender Address 3,Sender Address 4,Beneficiary Name,Beneficiary Account,Beneficiary Address 1,Beneficiary Address 2,Beneficiary Address 3,Beneficiary Address 4,Beneficiary Bank Code,Beneficiary Bank Name,Beneficiary Bank Address 1,Beneficiary Bank Address 2,Beneficiary Bank Address 3,Reference For Beneficiary,Foreign Amount,Foreign Currency,Exchange Rate,Payment Details 1,Payment Details 2,Payment Details 3,Payment Details 4,Payment Details 5,Payment Details 6,Bank Reference,Bank Reference 2,Bank Reference 3,Bank Reference 4,Bank Reference 5,Bank Reference 6,Receiving Bank Id,Receiving Bank,Receiving Bank Address 1,Receiving Bank Address 2,Receiving Bank Address 3,Receiving Bank Address 4,Intermediary Bank Id,Intermediary Bank Name,Intermediary Bank Address 1,Intermediary Bank Address 2,Intermediary Bank Address 3,Intermediary Bank Address 4,Ordering Bank,Ordering Bank Address 1,Ordering Bank Address 2,Ordering Bank Address 3,Ordering Bank Address 4,Instructing Bank,Terminal Location,Terminal City,Terminal State,TIME\n05/30/2025,021313103,4030961273,SOFTWARE FREEDOM CONSERVANCY INC,PREAUTHORIZED ACH DEBIT,Cleared,Debit,-275.64,,,SEC : CCD                                                        ORIG NAME :  PAYCHEX EIB                                                      CO. ENTRY DESC:  INVOICE                                                      RECIP NAME:  SOFTWARE FREEDOM CONSE                                           INDIVIDUAL ID: X12201000015079                                                EFFECTIVE DATE: 250530                                                        CO DESCRIPTION DATE: 250530                                                   PAR#: 025149005728064                                                         ADVICEREF: 025149005728064                                                   ,455,ACH,View Details,USD,, 025149005728064, 025149005728064,,  PAYCHEX EIB                                   ,  INVOICE                                       , 250530                                         ,,,, CCD ,,,,,,,,,,,,,,,,,,,  SOFTWARE FREEDOM CONSE                                          ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\n""" | ||||
|     expected = [ | ||||
|         { | ||||
|             'date': datetime.date(2025, 5, 30), | ||||
|             'amount': decimal.Decimal('-275.64'), | ||||
|             'payee': 'PAYCHEX EIB SOFTWARE FREEDOM CONSE', | ||||
|             'check_id': '', | ||||
|             'line': 2, | ||||
|         }, | ||||
|     ] | ||||
|     assert read_citizens_csv(io.StringIO(CSV)) == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_format_output(): | ||||
|     statement = [S1] | ||||
|     books = [B1] | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue