From ba634e4e49ebbed1dc104139eb03b50a34967712 Mon Sep 17 00:00:00 2001 From: Lucas Mathews Date: Fri, 17 May 2024 19:48:23 +0200 Subject: [PATCH] add one to many relationships and various updates surrounding this --- api.yml | 21 +++++++++++++-------- bank.db | Bin 36864 -> 28672 bytes bank.ini | 1 - class_account.py | 10 +++++++--- class_client.py | 8 +++++--- class_transaction.py | 4 ++-- database.py | 22 ---------------------- manager.py | 16 ++++++++++------ 8 files changed, 37 insertions(+), 45 deletions(-) diff --git a/api.yml b/api.yml index 19b9cb2..45dbab7 100644 --- a/api.yml +++ b/api.yml @@ -5,7 +5,7 @@ info: Lucas Mathews - Fontys Student ID: 5023572 contact: email: 522499@student.fontys.nl - version: 2.0.0 + version: 3.0.0 servers: - url: http://127.0.0.1:81 tags: @@ -231,6 +231,12 @@ paths: description: Add a new account to the system operationId: manager.add_account parameters: + - name: client_id + in: query + description: ID of client to add account to + required: true + schema: + type: string - name: description in: query description: Account description @@ -254,8 +260,8 @@ paths: description: Successful operation '400': description: Invalid input - '422': - description: Validation exception + '404': + description: client_id not found put: tags: - account @@ -627,8 +633,6 @@ components: type: boolean administator: type: boolean - accounts: - type: array example: client_id: 1 name: "Lucas Mathews" @@ -641,13 +645,14 @@ components: notes: "This is a test client" enabled: true administator: false - accounts: [] Account: type: object properties: account_id: type: integer format: int32 + client_id: + type: string decription: type: string opening_timestamp: @@ -664,13 +669,13 @@ components: type: array example: account_id: 1 + client_id: 1 description: "Savings Account" opening_timestamp: "17-04-2022 16:21:12" account_type: "Rachelsmolen 1, 5612MA, Eindhoven" balance: 2314.23 enabled: true notes: "This is a savings account" - transactions: [] Transaction: type: object properties: @@ -686,7 +691,7 @@ components: type: string description: type: string - account_number: + account_id: type: string recipient_account_number: type: string diff --git a/bank.db b/bank.db index 9d458d41b97a93f61956a5b99b0b411609eed1b8..cc676775c96afc9350351058773652d1434d54e2 100644 GIT binary patch delta 922 zcmbtTO=}ZD7~ak1qnl)Rln|nZ#T8Tx+B!R5yPHyKl~klyHD2mTcV=gyP%5~BCi{5+k);}QV(cRh=1LCEJVR+wppLd?;eP;GPbPF74-G}1<1Cb}#CS*cUdf#vf{4sRI`6o)P1FNtZ*)CE}4!BI+P6h$B%F$Ut(0LnjmxBTfbCyDSVG z=q3ptK_Y@62$6%O4;?S?grFWpkhzY}nJ1`(BES@KABT_ARgzg$TT0Y?fr0^buu4#0SS8S=H1$+SqAWEt>Kp$zkWz}$PPFENsOmZG&&5{Akx=WlkN!>-cKN!d{qkiE34}(#H zfog)mHIRH1LK%^i@l-)8eM+;pV46Im6p^ymz~QlUaCjmLT}{PjRJAn7I2=zRYyJ!P CTki(| literal 36864 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 Bg_r;U diff --git a/bank.ini b/bank.ini index b006f23..04b9f6d 100644 --- a/bank.ini +++ b/bank.ini @@ -1,6 +1,5 @@ [database] name=bank.db -add_sample_data=True [api_file] name=api.yml diff --git a/class_account.py b/class_account.py index 0347dfc..173b2ed 100644 --- a/class_account.py +++ b/class_account.py @@ -2,6 +2,8 @@ # Banking System Account Class from sqlalchemy import ForeignKey, Column, String, Integer, Boolean +from sqlalchemy.orm import relationship + from class_base import Base @@ -9,23 +11,25 @@ from class_base import Base class Account(Base): __tablename__ = 'accounts' account_id = Column("account_id", String, primary_key=True) + client_id = Column(String, ForeignKey('clients.client_id')) description = Column("description", String) open_timestamp = Column("open_timestamp", String) account_type = Column("account_type", String) balance = Column("balance", Integer) enabled = Column("enabled", Boolean) notes = Column("notes", String) - transactions = ("transactions", String, ForeignKey("transactions.transaction_id")) + transactions = relationship("Transaction", backref="account") - def __init__(self, account_id, description, open_timestamp, account_type, balance, enabled, notes, transactions): + def __init__(self, account_id, client_id, description, open_timestamp, account_type, balance, enabled, notes, transactions): self.account_id = account_id + self.client_id = client_id self.description = description self.open_timestamp = open_timestamp self.account_type = account_type self.balance = balance self.enabled = enabled self.notes = notes - self.transactions = transactions + self.transactions = transactions if transactions is not None else [] def __repr__(self): return f"Account ID: {self.account_id}, Description: {self.description}, Open Timestamp: {self.open_timestamp}, Account Type: {self.account_type}, Balance: {self.balance}, Enabled: {self.enabled}, Notes: {self.notes}, Transactions: {self.transactions}" \ No newline at end of file diff --git a/class_client.py b/class_client.py index 691fe43..fea1a67 100644 --- a/class_client.py +++ b/class_client.py @@ -1,7 +1,9 @@ # Lucas Mathews - Fontys Student ID: 5023572 # Banking System Client Class -from sqlalchemy import Column, String, Boolean +from sqlalchemy import Column, String, Boolean, ForeignKey +from sqlalchemy.orm import relationship + from class_base import Base @@ -18,7 +20,7 @@ class Client(Base): notes = Column("notes", String) enabled = Column("enabled", Boolean) administrator = Column("administrator", Boolean) - accounts = Column("accounts", String) + accounts = relationship("Account", backref="client") def __init__(self, client_id, name, birthdate, opening_timestamp, address, phone_number, email, hash, notes, enabled, administrator, accounts): self.client_id = client_id @@ -32,7 +34,7 @@ class Client(Base): self.notes = notes self.enabled = enabled self.administrator = administrator - self.accounts = accounts + self.accounts = accounts if accounts is not None else [] def __repr__(self): return f"Client ID: {self.client_id}, Name: {self.name}, Birthdate: {self.birthdate}, Address: {self.address}, Phone Number: {self.phone_number}, Email: {self.email}, Enabled: {self.enabled}, Accounts: {self.accounts}" \ No newline at end of file diff --git a/class_transaction.py b/class_transaction.py index f548778..421d530 100644 --- a/class_transaction.py +++ b/class_transaction.py @@ -1,7 +1,7 @@ # Lucas Mathews - Fontys Student ID: 5023572 # Banking System Transaction Class -from sqlalchemy import Column, String, Integer +from sqlalchemy import Column, String, Integer, ForeignKey from class_base import Base @@ -12,7 +12,7 @@ class Transaction(Base): amount = Column("amount", Integer) timestamp = Column("timestamp", String) description = Column("description", String) - account_number = Column("account_number", Integer) + account_id = Column(String, ForeignKey('accounts.account_id')) recipient_account_number = Column("recipient_account_number", Integer) def __init__(self, transaction_id, transaction_type, amount, timestamp, description, account_number, recipient_account_number = None): diff --git a/database.py b/database.py index 2661569..ac3ba6a 100644 --- a/database.py +++ b/database.py @@ -34,25 +34,3 @@ Base.metadata.create_all(bind=engine) # Creates the tables in the database from # Creates a session to interact with the database Session = sessionmaker(bind=engine) # Creates a session to interact with the database session = Session() # Creates a session object - -# Add sample data if enabled in the configuration file if the database is empty -if CONFIG["database"]["add_sample_data"] == "True": # Checks if sample data addition is enabled - if session.query(Client).count() == 0: # Checks if the database is empty - print(f"Sample data addition is disabled because the database is not empty.") - print(f"Adding sample data to new database file {CONFIG["database"]["name"]}.") - session.add(Client("f9a16945-b570-4153-ba63-413f2cc2768a", "Lucas Mathews", "24/08/1998", "17/04/2024", "Rachelsmolen 1, 5612MA, Eindhoven", "0612345678", "522499@student.fontys.nl", "7835062ec36ed529fe22cc63baf3ec18d347dacb21c9801da8ba0848cc18efdf1e51717dd5b1240f7556aca3947aa0722452858be6002c1d46b1f1c311b0e9d8", "Notes", True, True, "1, 2")) - session.add(Client("5be2a74d-d55c-4de6-85a1-2ed6a355f2cd", "Rigby", "16/03/2018", "06/05/2024", "Rachelsmolen 1, 5612MA, Eindhoven", "0612345678", "522499@cat.fontys.nl", "d3e7df3c78682fbb51e8c6110b3926349bb426bc9834c640cd666519901aef3dfab7822d66fb2dd9e39eb5a8492f6801c2e17ba4c16b8fbcd159c036fe27d8bd", "Is a cat", True, False, "3")) - session.add(Account("4c227b02-348c-4611-99a2-8967680cdee6", "Savings Account", "17/04/2024", "Savings", 3000, True, "Savings account", "1")) - session.add(Account("b9d9b801-eaab-45be-a4d1-1f7b0bbf798f", "Spending Account", "17/04/2024", "Spending", 150, True, "Spending account", "1")) - session.add(Account("f182f186-0a88-4f98-8a02-3a568c65aba7", "Cat Account", "06/05/2024", "Cat Account", 497, True, "Food savings", "2")) - session.add(Transaction("9d989788-f983-4590-8de2-9aa0c8bec7d2", "Deposit", 5000, "17/04/2024", "Initial Deposit", 1, "23542335")) - session.add(Transaction("153cee93-51c7-4114-b9ef-e307fbf0bf87", "Deposit", 100, "17/04/2024", "Initial Deposit", 2, "23542335")) - session.add(Transaction("4bec761a-0f36-452f-a48a-127dcf526e47", "Deposit", 500, "06/05/2024", "Initial Deposit", 3, "23542335")) - session.add(Transaction("227a2a9e-a13b-484b-b037-78deeeb0258c", "Withdrawal", 2000, "06/05/2024", "Uni Fees", 3, "Fontys University")) - session.add(Transaction("7248a706-29a8-478b-a674-c12ebf9a904a", "Withdrawal", 50, "06/05/2024", "Groceries", 3, "Aldi")) - session.add(Transaction("ba367c28-41e6-4f8a-9bfa-3819f7b89a58", "Withdrawal", 3, "06/05/2024", "Treats", 3, "ZooPlus")) - session.commit() - else: - print(f"The database is not empty, skipping sample data addition.") -else: - print(f"Sample data addition is disabled.") \ No newline at end of file diff --git a/manager.py b/manager.py index 7ca7f79..37dcf77 100644 --- a/manager.py +++ b/manager.py @@ -110,15 +110,19 @@ def get_account(account_id:int): # Returns a specific account in the database return jsonify({"error": "Account not found"}), 404 if account is not None: for account in account: - return jsonify({"description": account.description, "account_type": account.account_type, "balance": account.balance, "enabled": account.enabled, "notes": account.notes}), 200 + return jsonify({"client_id": account.client.id, "description": account.description, "account_type": account.account_type, "balance": account.balance, "enabled": account.enabled, "notes": account.notes}), 200 -def add_account(description:str, account_type, **kwargs): # Adds a new account to the database +def add_account(client_id, description:str, account_type, **kwargs): # Adds a new account to the database account_id = generate_uuid_short() notes = kwargs.get("notes", None) - new_account = Account(account_id, description, timestamp(), account_type, 0, 1, notes, None) - session.add(new_account) - session.commit() - return f"New account has been added: description: {description}, uuid: {account_id} ", 200 + for client in session.query(Client).all(): + if client.client_id == client_id: + new_account = Account(account_id, client_id, description, timestamp(), account_type, 0, 1, notes, None) + session.add(new_account) + session.commit() + return f"New account has been added: description: {description}, uuid: {account_id} ", 200 + else: + return f"client_id: {client_id} is not found.", 422 def delete_account(account_id): # Deletes an account from the database for account in session.query(Account).all():