[storage] Added delete_transaction method
- Added storage.ledgercli implementation - Added storage.ledgercli update_transaction - Added storage.ledgercli get_transaction - Pushing pre-built docs
This commit is contained in:
		
							parent
							
								
									c80955f199
								
							
						
					
					
						commit
						02fc05aebd
					
				
					 8 changed files with 191 additions and 14 deletions
				
			
		|  | @ -4,8 +4,10 @@ | |||
| 
 | ||||
| from abc import ABCMeta, abstractmethod | ||||
| 
 | ||||
| from accounting.exceptions import AccountingException | ||||
| 
 | ||||
| class Storage(): | ||||
| 
 | ||||
| class Storage: | ||||
|     ''' | ||||
|     ABC for accounting storage | ||||
|     ''' | ||||
|  | @ -38,6 +40,14 @@ class Storage(): | |||
|     def update_transaction(self, transaction): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     @abstractmethod | ||||
|     def delete_transaction(self, transaction_id): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     @abstractmethod | ||||
|     def reverse_transaction(self, transaction_id): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| 
 | ||||
| class TransactionNotFound(AccountingException): | ||||
|     pass | ||||
|  |  | |||
|  | @ -6,13 +6,15 @@ import sys | |||
| import subprocess | ||||
| import logging | ||||
| import time | ||||
| import re | ||||
| 
 | ||||
| from datetime import datetime | ||||
| from xml.etree import ElementTree | ||||
| from contextlib import contextmanager | ||||
| 
 | ||||
| from accounting.exceptions import AccountingException | ||||
| from accounting.models import Account, Transaction, Posting, Amount | ||||
| from accounting.storage import Storage | ||||
| from accounting.storage import Storage, TransactionNotFound | ||||
| 
 | ||||
| _log = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -205,6 +207,8 @@ class Ledger(Storage): | |||
| 
 | ||||
|         _log.debug('written to file: %s', output) | ||||
| 
 | ||||
|         return transaction.id | ||||
| 
 | ||||
|     def bal(self): | ||||
|         output = self.send_command('xml') | ||||
| 
 | ||||
|  | @ -252,6 +256,16 @@ class Ledger(Storage): | |||
|     def get_transactions(self): | ||||
|         return self.reg() | ||||
| 
 | ||||
|     def get_transaction(self, transaction_id): | ||||
|         transactions = self.get_transactions() | ||||
| 
 | ||||
|         for transaction in transactions: | ||||
|             if transaction.id == transaction_id: | ||||
|                 return transaction | ||||
| 
 | ||||
|         raise TransactionNotFound('No transaction with id %s found', | ||||
|                                   transaction_id) | ||||
| 
 | ||||
|     def reg(self): | ||||
|         output = self.send_command('xml') | ||||
| 
 | ||||
|  | @ -314,8 +328,111 @@ class Ledger(Storage): | |||
| 
 | ||||
|         return entries | ||||
| 
 | ||||
|     def delete_transaction(self, transaction_id): | ||||
|         ''' | ||||
|         Delete a transaction from the ledger file. | ||||
| 
 | ||||
|         This method opens the ledger file, loads all lines into memory and | ||||
|         looks for the transaction_id, then looks for the bounds of that | ||||
|         transaction in the ledger file, removes all lines within the bounds of | ||||
|         the transaction and removes them, then writes the lines back to the | ||||
|         ledger file. | ||||
| 
 | ||||
|         Exceptions: | ||||
| 
 | ||||
|         -   RuntimeError: If all boundaries to the transaction are not found | ||||
|         -   TransactionNotFound: If no such transaction_id can be found in | ||||
|             :data:`self.ledger_file` | ||||
|         ''' | ||||
|         f = open(self.ledger_file, 'r') | ||||
| 
 | ||||
|         lines = [i for i in f] | ||||
| 
 | ||||
|         # A mapping of line meanings and their line numbers as found by the | ||||
|         # following logic | ||||
|         semantic_lines = dict( | ||||
|             id_location=None, | ||||
|             transaction_start=None, | ||||
|             next_transaction_or_eof=None | ||||
|         ) | ||||
| 
 | ||||
|         for i, line in enumerate(lines): | ||||
|             if transaction_id in line: | ||||
|                 semantic_lines['id_location'] = i | ||||
|                 break | ||||
| 
 | ||||
|         if not semantic_lines['id_location']: | ||||
|             raise TransactionNotFound('No transaction with ID "%s" found') | ||||
| 
 | ||||
|         transaction_start_pattern = re.compile(r'^\S') | ||||
| 
 | ||||
|         cursor = semantic_lines['id_location'] - 1 | ||||
| 
 | ||||
|         # Find the first line of the transaction | ||||
|         while True: | ||||
|             if transaction_start_pattern.match(lines[cursor]): | ||||
|                 semantic_lines['transaction_start'] = cursor | ||||
|                 break | ||||
| 
 | ||||
|             cursor -= 1 | ||||
| 
 | ||||
|         cursor = semantic_lines['id_location'] + 1 | ||||
| 
 | ||||
|         # Find the last line of the transaction | ||||
|         while True: | ||||
|             try: | ||||
|                 if transaction_start_pattern.match(lines[cursor]): | ||||
|                     semantic_lines['next_transaction_or_eof'] = cursor | ||||
|                     break | ||||
|             except IndexError: | ||||
|                 # Set next_line_without_starting_space_or_end_of_file to | ||||
|                 # the cursor. The cursor will be an index not included in the | ||||
|                 # list of lines | ||||
|                 semantic_lines['next_transaction_or_eof'] = cursor | ||||
|                 break | ||||
| 
 | ||||
|             cursor += 1 | ||||
| 
 | ||||
|         if not all(map(lambda v: v is not None, semantic_lines.values())): | ||||
|             raise RuntimeError('Could not find all the values necessary for' | ||||
|                                ' safe deletion of a transaction.') | ||||
| 
 | ||||
|         del_start = semantic_lines['transaction_start'] | ||||
| 
 | ||||
|         if len(lines) == semantic_lines['next_transaction_or_eof']: | ||||
|             _log.debug('There are no transactions below the transaction being' | ||||
|                        ' deleted. The line before the first line of the' | ||||
|                        ' transaction will be deleted.') | ||||
|             # Delete the preceding line to make the file | ||||
|             del_start -= 1 | ||||
| 
 | ||||
|         del lines[del_start:semantic_lines['next_transaction_or_eof']] | ||||
| 
 | ||||
|         with open(self.ledger_file, 'w') as f: | ||||
|             for line in lines: | ||||
|                 f.write(line) | ||||
| 
 | ||||
|     def update_transaction(self, transaction): | ||||
|         _log.debug('DUMMY: Updated transaction: %s', transaction) | ||||
|         ''' | ||||
|         Update a transaction in the ledger file. | ||||
| 
 | ||||
|         Takes a :class:`~accounting.models.Transaction` object and removes | ||||
|         the old transaction using :data:`transaction.id` from the passed | ||||
|         :class:`~accounting.models.Transaction` instance and adds | ||||
|         :data:`transaction` to the database. | ||||
|         ''' | ||||
|         if not transaction.id: | ||||
|             return AccountingException('The transaction %s has no' | ||||
|                                        ' id attribute', transaction) | ||||
| 
 | ||||
|         old_transaction = self.get_transaction(transaction.id) | ||||
| 
 | ||||
|         self.delete_transaction(transaction.id) | ||||
| 
 | ||||
|         self.add_transaction(transaction) | ||||
| 
 | ||||
|         _log.debug('Updated transaction from: %s to: %s', old_transaction, | ||||
|                    transaction) | ||||
| 
 | ||||
| 
 | ||||
| def main(argv=None): | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ import logging | |||
| import argparse | ||||
| 
 | ||||
| from flask import Flask, jsonify, request | ||||
| from flask.ext.sqlalchemy import SQLAlchemy | ||||
| from flask.ext.script import Manager | ||||
| from flask.ext.migrate import Migrate, MigrateCommand | ||||
| 
 | ||||
|  | @ -65,6 +64,7 @@ def transaction_get(): | |||
|     ''' | ||||
|     return jsonify(transactions=storage.get_transactions()) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/transaction/<string:transaction_id>', methods=['POST']) | ||||
| @jsonify_exceptions | ||||
| def transaction_update(transaction_id=None): | ||||
|  | @ -74,8 +74,8 @@ def transaction_update(transaction_id=None): | |||
|     transaction = request.json['transaction'] | ||||
| 
 | ||||
|     if transaction.id is not None and not transaction.id == transaction_id: | ||||
|         raise AccountingException('The transaction data has an ID attribute and' | ||||
|                                   ' it is not the same ID as in the path') | ||||
|         raise AccountingException('The transaction data has an ID attribute' | ||||
|                                   ' and it is not the same ID as in the path') | ||||
|     elif transaction.id is None: | ||||
|         transaction.id = transaction_id | ||||
| 
 | ||||
|  | @ -84,6 +84,17 @@ def transaction_update(transaction_id=None): | |||
|     return jsonify(status='OK') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/transaction/<string:transaction_id>', methods=['DELETE']) | ||||
| @jsonify_exceptions | ||||
| def transaction_delete(transaction_id=None): | ||||
|     if transaction_id is None: | ||||
|         raise AccountingException('Transaction ID cannot be None') | ||||
| 
 | ||||
|     storage.delete_transaction(transaction_id) | ||||
| 
 | ||||
|     return jsonify(status='OK') | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/transaction', methods=['POST']) | ||||
| @jsonify_exceptions | ||||
| def transaction_post(): | ||||
|  | @ -139,10 +150,12 @@ def transaction_post(): | |||
|     if not transactions: | ||||
|         raise AccountingException('No transaction data provided') | ||||
| 
 | ||||
|     for transaction in transactions: | ||||
|         storage.add_transaction(transaction) | ||||
|     transaction_ids = [] | ||||
| 
 | ||||
|     return jsonify(status='OK') | ||||
|     for transaction in transactions: | ||||
|         transaction_ids.append(storage.add_transaction(transaction)) | ||||
| 
 | ||||
|     return jsonify(status='OK', transaction_ids=transaction_ids) | ||||
| 
 | ||||
| 
 | ||||
| def main(argv=None): | ||||
|  |  | |||
							
								
								
									
										5
									
								
								doc/build/html/api/accounting.html
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								doc/build/html/api/accounting.html
									
										
									
									
										vendored
									
									
								
							|  | @ -285,6 +285,11 @@ and the Flask endpoints.</p> | |||
| <tt class="descclassname">accounting.web.</tt><tt class="descname">main</tt><big>(</big><em>argv=None</em><big>)</big><a class="reference internal" href="../_modules/accounting/web.html#main"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#accounting.web.main" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| 
 | ||||
| <dl class="function"> | ||||
| <dt id="accounting.web.transaction_delete"> | ||||
| <tt class="descclassname">accounting.web.</tt><tt class="descname">transaction_delete</tt><big>(</big><em>transaction_id=None</em><big>)</big><a class="headerlink" href="#accounting.web.transaction_delete" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| 
 | ||||
| <dl class="function"> | ||||
| <dt id="accounting.web.transaction_get"> | ||||
| <tt class="descclassname">accounting.web.</tt><tt class="descname">transaction_get</tt><big>(</big><big>)</big><a class="reference internal" href="../_modules/accounting/web.html#transaction_get"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#accounting.web.transaction_get" title="Permalink to this definition">¶</a></dt> | ||||
|  |  | |||
							
								
								
									
										26
									
								
								doc/build/html/api/accounting.storage.html
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								doc/build/html/api/accounting.storage.html
									
										
									
									
										vendored
									
									
								
							|  | @ -102,7 +102,19 @@ based on <tt class="xref py py-attr docutils literal"><span class="pre">self.led | |||
| <dl class="method"> | ||||
| <dt id="accounting.storage.ledgercli.Ledger.delete_transaction"> | ||||
| <tt class="descname">delete_transaction</tt><big>(</big><em>transaction_id</em><big>)</big><a class="headerlink" href="#accounting.storage.ledgercli.Ledger.delete_transaction" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| <dd><p>Delete a transaction from the ledger file.</p> | ||||
| <p>This method opens the ledger file, loads all lines into memory and | ||||
| looks for the transaction_id, then looks for the bounds of that | ||||
| transaction in the ledger file, removes all lines within the bounds of | ||||
| the transaction and removes them, then writes the lines back to the | ||||
| ledger file.</p> | ||||
| <p>Exceptions:</p> | ||||
| <ul class="simple"> | ||||
| <li>RuntimeError: If all boundaries to the transaction are not found</li> | ||||
| <li>TransactionNotFound: If no such transaction_id can be found in | ||||
| <tt class="xref py py-data docutils literal"><span class="pre">self.ledger_file</span></tt></li> | ||||
| </ul> | ||||
| </dd></dl> | ||||
| 
 | ||||
| <dl class="method"> | ||||
| <dt id="accounting.storage.ledgercli.Ledger.get_process"> | ||||
|  | @ -168,7 +180,12 @@ without the prompt.</p> | |||
| <dl class="method"> | ||||
| <dt id="accounting.storage.ledgercli.Ledger.update_transaction"> | ||||
| <tt class="descname">update_transaction</tt><big>(</big><em>transaction</em><big>)</big><a class="reference internal" href="../_modules/accounting/storage/ledgercli.html#Ledger.update_transaction"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#accounting.storage.ledgercli.Ledger.update_transaction" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| <dd><p>Update a transaction in the ledger file.</p> | ||||
| <p>Takes a <a class="reference internal" href="accounting.html#accounting.models.Transaction" title="accounting.models.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> object and removes | ||||
| the old transaction using <tt class="xref py py-data docutils literal"><span class="pre">transaction.id</span></tt> from the passed | ||||
| <a class="reference internal" href="accounting.html#accounting.models.Transaction" title="accounting.models.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> instance and adds | ||||
| <tt class="xref py py-data docutils literal"><span class="pre">transaction</span></tt> to the database.</p> | ||||
| </dd></dl> | ||||
| 
 | ||||
| </dd></dl> | ||||
| 
 | ||||
|  | @ -190,6 +207,11 @@ without the prompt.</p> | |||
| <tt class="descname">add_transaction</tt><big>(</big><em>transaction</em><big>)</big><a class="headerlink" href="#accounting.storage.Storage.add_transaction" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| 
 | ||||
| <dl class="method"> | ||||
| <dt id="accounting.storage.Storage.delete_transaction"> | ||||
| <tt class="descname">delete_transaction</tt><big>(</big><em>transaction_id</em><big>)</big><a class="headerlink" href="#accounting.storage.Storage.delete_transaction" title="Permalink to this definition">¶</a></dt> | ||||
| <dd></dd></dl> | ||||
| 
 | ||||
| <dl class="method"> | ||||
| <dt id="accounting.storage.Storage.get_account"> | ||||
| <tt class="descname">get_account</tt><big>(</big><em>*args</em>, <em>**kw</em><big>)</big><a class="reference internal" href="../_modules/accounting/storage.html#Storage.get_account"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#accounting.storage.Storage.get_account" title="Permalink to this definition">¶</a></dt> | ||||
|  |  | |||
							
								
								
									
										14
									
								
								doc/build/html/genindex.html
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								doc/build/html/genindex.html
									
										
									
									
										vendored
									
									
								
							|  | @ -243,6 +243,12 @@ | |||
|   <dt><a href="api/accounting.storage.html#accounting.storage.ledgercli.Ledger.delete_transaction">delete_transaction() (accounting.storage.ledgercli.Ledger method)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|       <dd><dl> | ||||
|          | ||||
|   <dt><a href="api/accounting.storage.html#accounting.storage.Storage.delete_transaction">(accounting.storage.Storage method)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|       </dl></dd> | ||||
|        | ||||
|   <dt><a href="api/accounting.html#accounting.transport.AccountingDecoder.dict_to_object">dict_to_object() (accounting.transport.AccountingDecoder method)</a> | ||||
|   </dt> | ||||
|  | @ -546,16 +552,20 @@ | |||
| 
 | ||||
|       </dl></dd> | ||||
|        | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_get">transaction_get() (in module accounting.web)</a> | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_delete">transaction_delete() (in module accounting.web)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|        | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_post">transaction_post() (in module accounting.web)</a> | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_get">transaction_get() (in module accounting.web)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|   </dl></td> | ||||
|   <td style="width: 33%" valign="top"><dl> | ||||
|        | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_post">transaction_post() (in module accounting.web)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|        | ||||
|   <dt><a href="api/accounting.html#accounting.web.transaction_update">transaction_update() (in module accounting.web)</a> | ||||
|   </dt> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								doc/build/html/objects.inv
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/build/html/objects.inv
									
										
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								doc/build/html/searchindex.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								doc/build/html/searchindex.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Joar Wandborg
						Joar Wandborg