Initial commit
This commit is contained in:
		
						commit
						4d8ab562c2
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | data/ | ||||||
|  | src/rules.yaml | ||||||
|  | venv/ | ||||||
							
								
								
									
										53
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | # CSV to Beancount Converter | ||||||
|  | 
 | ||||||
|  | This project provides a simple utility to convert CSV files into Beancount format. It is designed to facilitate the management of financial data by transforming structured CSV data into a format compatible with Beancount accounting software. | ||||||
|  | 
 | ||||||
|  | ## Project Structure | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | csv-to-beancount | ||||||
|  | ├── src | ||||||
|  | │   ├── main.py          # Entry point for the application | ||||||
|  | │   ├── converter.py     # Logic for converting CSV to Beancount | ||||||
|  | │   ├── config.py        # Configuration settings loader | ||||||
|  | │   └── utils | ||||||
|  | │       └── file_utils.py # Utility functions for file operations | ||||||
|  | ├── config | ||||||
|  | │   └── settings.yaml    # Configuration file with fixed values | ||||||
|  | ├── data | ||||||
|  | │   └── example.csv      # Sample CSV file for conversion | ||||||
|  | ├── requirements.txt      # Project dependencies | ||||||
|  | └── README.md            # Project documentation | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Installation | ||||||
|  | 
 | ||||||
|  | To set up the project, clone the repository and install the required dependencies: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git clone <repository-url> | ||||||
|  | cd csv-to-beancount | ||||||
|  | pip install -r requirements.txt | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | 
 | ||||||
|  | To convert a CSV file to Beancount format, run the following command: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | python src/main.py data/example.csv | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This command will read the specified CSV file, convert its contents into Beancount format using the defined mappings in the configuration file, and save the output to a Beancount file. | ||||||
|  | 
 | ||||||
|  | ## Configuration | ||||||
|  | 
 | ||||||
|  | The configuration settings are stored in `config/settings.yaml`. You can modify this file to adjust account mappings and other constants used during the conversion process. | ||||||
|  | 
 | ||||||
|  | ## Contributing | ||||||
|  | 
 | ||||||
|  | Contributions are welcome! Please feel free to submit a pull request or open an issue for any enhancements or bug fixes. | ||||||
|  | 
 | ||||||
|  | ## License | ||||||
|  | 
 | ||||||
|  | This project is licensed under the MIT License. See the LICENSE file for more details. | ||||||
							
								
								
									
										9
									
								
								config/settings.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config/settings.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | account_mappings: | ||||||
|  |   giro_account: "Assets:Bank:Giro" | ||||||
|  | 
 | ||||||
|  | fixed_values: | ||||||
|  |   currency: "EUR" | ||||||
|  |   default_transaction_type: "expense" | ||||||
|  | 
 | ||||||
|  | file_mappings: | ||||||
|  |   example.csv: "Assets:Bank:Giro" | ||||||
							
								
								
									
										2
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | PyYAML | ||||||
|  | pandas | ||||||
							
								
								
									
										8
									
								
								src/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/config.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | from pathlib import Path | ||||||
|  | import yaml | ||||||
|  | 
 | ||||||
|  | def load_config(): | ||||||
|  |     config_path = Path(__file__).parent.parent / 'config' / 'settings.yaml' | ||||||
|  |     with open(config_path, 'r') as file: | ||||||
|  |         config = yaml.safe_load(file) | ||||||
|  |     return config | ||||||
							
								
								
									
										15
									
								
								src/converter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/converter.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | def convert_csv_to_beancount(csv_data, config): | ||||||
|  |     beancount_entries = [] | ||||||
|  |      | ||||||
|  |     for row in csv_data: | ||||||
|  |         date = row['date'] | ||||||
|  |         amount = row['amount'] | ||||||
|  |         description = row['description'] | ||||||
|  |          | ||||||
|  |         # Map the account based on the configuration | ||||||
|  |         account = config['account_mappings'].get(row['filename'], 'Assets:Bank:Giro') | ||||||
|  |          | ||||||
|  |         entry = f"{date} * \"{description}\"\n    {account}  {amount}\n" | ||||||
|  |         beancount_entries.append(entry) | ||||||
|  |      | ||||||
|  |     return ''.join(beancount_entries) | ||||||
							
								
								
									
										43
									
								
								src/converter_new.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/converter_new.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | import yaml | ||||||
|  | 
 | ||||||
|  | class BeancountConverter: | ||||||
|  |     def __init__(self, rules_file): | ||||||
|  |         with open(rules_file, 'r') as f: | ||||||
|  |             self.rule_definitions = yaml.safe_load(f) | ||||||
|  |          | ||||||
|  |         # Compile rules | ||||||
|  |         self.rules = self._compile_rules(self.rule_definitions) | ||||||
|  |      | ||||||
|  |     def _compile_rules(self, rule_defs): | ||||||
|  |         compiled_rules = [] | ||||||
|  |          | ||||||
|  |         for rule in rule_defs: | ||||||
|  |             conditions = [] | ||||||
|  |              | ||||||
|  |             # Build conditions from rule definition | ||||||
|  |             if 'description_contains' in rule: | ||||||
|  |                 terms = rule['description_contains'] | ||||||
|  |                 conditions.append( | ||||||
|  |                     lambda t, terms=terms: any(term.upper() in t.get('description', '').upper() for term in terms) | ||||||
|  |                 ) | ||||||
|  |              | ||||||
|  |             if 'amount_range' in rule: | ||||||
|  |                 min_val = rule['amount_range'].get('min', float('-inf')) | ||||||
|  |                 max_val = rule['amount_range'].get('max', float('inf')) | ||||||
|  |                 conditions.append( | ||||||
|  |                     lambda t, min_val=min_val, max_val=max_val:  | ||||||
|  |                         min_val <= float(t.get('amount', 0)) <= max_val | ||||||
|  |                 ) | ||||||
|  |              | ||||||
|  |             # Combine all conditions | ||||||
|  |             compiled_rule = ( | ||||||
|  |                 lambda t, conditions=conditions: all(cond(t) for cond in conditions), | ||||||
|  |                 rule['target_account'] | ||||||
|  |             ) | ||||||
|  |              | ||||||
|  |             compiled_rules.append(compiled_rule) | ||||||
|  |              | ||||||
|  |         # Add default rule | ||||||
|  |         compiled_rules.append((lambda t: True, 'Expenses:Uncategorized')) | ||||||
|  |          | ||||||
|  |         return compiled_rules | ||||||
							
								
								
									
										22
									
								
								src/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/main.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | import pandas as pd | ||||||
|  | from src.config import load_config | ||||||
|  | from src.converter import convert_csv_to_beancount | ||||||
|  | from src.utils.file_utils import write_beancount | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     # Load configuration settings | ||||||
|  |     config = load_config() | ||||||
|  | 
 | ||||||
|  |     # Read the CSV file | ||||||
|  |     csv_file_path = 'data/example.csv' | ||||||
|  |     csv_data = pd.read_csv(csv_file_path) | ||||||
|  | 
 | ||||||
|  |     # Convert CSV data to Beancount format | ||||||
|  |     beancount_entries = convert_csv_to_beancount(csv_data, config) | ||||||
|  | 
 | ||||||
|  |     # Write the Beancount entries to a file | ||||||
|  |     output_file_path = 'data/output.beancount' | ||||||
|  |     write_beancount(output_file_path, beancount_entries) | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										8
									
								
								src/utils/file_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/utils/file_utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | def read_csv(filepath): | ||||||
|  |     import pandas as pd | ||||||
|  |     return pd.read_csv(filepath) | ||||||
|  | 
 | ||||||
|  | def write_beancount(filepath, beancount_entries): | ||||||
|  |     with open(filepath, 'w') as f: | ||||||
|  |         for entry in beancount_entries: | ||||||
|  |             f.write(entry + '\n') | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user