Initial project

This commit is contained in:
2025-05-08 16:12:33 +12:00
commit 5340430298
11 changed files with 942 additions and 0 deletions

161
accounting/api.py Normal file
View File

@@ -0,0 +1,161 @@
import cherrypy
from sqlalchemy.orm import sessionmaker
from datetime import datetime
from accounting.models import Account, BankAccount, BankTransaction, JournalEntry, JournalEntryLine, ReconciliationReport, \
ReconciliationMatch
import simplejson as json
class AccountingAPI:
def __init__(self, db_engine):
self.db_engine = db_engine
Session = sessionmaker(bind=db_engine)
self.session = Session()
@cherrypy.expose
@cherrypy.tools.json_out()
def index(self):
return {"status": "success", "message": "Accounting API is running"}
# Bank Accounts Endpoints
@cherrypy.expose
@cherrypy.tools.json_out()
def bank_accounts(self):
if cherrypy.request.method != 'GET':
raise cherrypy.HTTPError(405)
accounts = self.session.query(BankAccount).all()
return [{
'id': a.id,
'name': a.name,
'bank_name': a.bank_name,
'account_number': a.account_number,
'currency': a.currency
} for a in accounts]
@cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out()
def add_bank_account(self):
if cherrypy.request.method != 'POST':
raise cherrypy.HTTPError(405)
data = cherrypy.request.json
account = BankAccount(
name=data['name'],
bank_name=data['bank_name'],
account_number=data['account_number'],
currency=data.get('currency', 'USD')
)
self.session.add(account)
self.session.commit()
return {'status': 'success', 'id': account.id}
# Add OPTIONS method handler for CORS preflight
@cherrypy.expose
def add_bank_account_options(self):
cherrypy.response.headers['Allow'] = 'POST, OPTIONS'
cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
return ''
# Accounts Endpoints
@cherrypy.expose
@cherrypy.tools.json_out()
def accounts(self):
if cherrypy.request.method != 'GET':
raise cherrypy.HTTPError(405)
accounts = self.session.query(Account).all()
return [{
'id': a.id,
'name': a.name,
'code': a.code,
'type': a.account_type,
'balance': float(a.balance) if a.balance else 0
} for a in accounts]
@cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out()
def add_account(self):
if cherrypy.request.method != 'POST':
raise cherrypy.HTTPError(405)
data = cherrypy.request.json
account = Account(
name=data['name'],
account_type=data['type'],
code=data['code'],
parent_id=data.get('parent_id')
)
self.session.add(account)
self.session.commit()
return {'status': 'success', 'id': account.id}
# Journal Entries Endpoints
@cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out()
def add_journal_entry(self):
if cherrypy.request.method != 'POST':
raise cherrypy.HTTPError(405)
data = cherrypy.request.json
total_debit = sum(line['amount'] for line in data['lines'] if line['is_debit'])
total_credit = sum(line['amount'] for line in data['lines'] if not line['is_debit'])
if abs(total_debit - total_credit) > 0.01:
return {'status': 'error', 'message': 'Debits and credits must balance'}
entry = JournalEntry(
date=datetime.strptime(data['date'], '%Y-%m-%d').date(),
reference=data.get('reference', ''),
description=data.get('description', '')
)
self.session.add(entry)
for line_data in data['lines']:
line = JournalEntryLine(
journal_entry=entry,
account_id=line_data['account_id'],
amount=line_data['amount'],
is_debit=line_data['is_debit']
)
self.session.add(line)
account = self.session.query(Account).get(line_data['account_id'])
if line_data['is_debit']:
account.balance += line_data['amount']
else:
account.balance -= line_data['amount']
self.session.commit()
return {'status': 'success', 'id': entry.id}
@cherrypy.expose
@cherrypy.tools.json_out()
def journal_entries(self):
if cherrypy.request.method != 'GET':
raise cherrypy.HTTPError(405)
entries = self.session.query(JournalEntry).all()
return [{
'id': e.id,
'date': e.date.isoformat(),
'description': e.description,
'reference': e.reference,
'lines': [{
'account_id': l.account_id,
'amount': float(l.amount),
'is_debit': l.is_debit
} for l in e.lines]
} for e in entries]
# Add default OPTIONS handler for all endpoints
@cherrypy.expose
def default(self, *args, **kwargs):
if cherrypy.request.method == 'OPTIONS':
cherrypy.response.headers['Allow'] = 'GET, POST, OPTIONS'
cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
return ''
raise cherrypy.HTTPError(404)