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