Compare commits
4 commits
277d974ffe
...
94ed01c88a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94ed01c88a | ||
|
|
ec88bad538 | ||
|
|
ec3237ff22 | ||
|
|
a2d76db373 |
4 changed files with 87 additions and 42 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,3 +1,9 @@
|
|||
.venv/
|
||||
.env
|
||||
.idea/
|
||||
.vscode/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
instance/
|
||||
db.sqlite3
|
||||
|
||||
|
|
|
|||
17
To-Do.md
Normal file
17
To-Do.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Project To-Do and Feature Ideas
|
||||
|
||||
This file tracks potential new features and improvements for the Interbend banking system.
|
||||
|
||||
## Feature Suggestions
|
||||
|
||||
1. **Automated Payroll System:**
|
||||
* **Description:** Instead of requiring users to manually call the `/collect` endpoint, a scheduled script could run periodically (e.g., every 24 hours) to automatically distribute salaries to all eligible users.
|
||||
* **Benefits:** Improves user experience, ensures consistent pay, and reduces repeated API calls to the server.
|
||||
* **Important:** Due to the concept of this whole system it needs to be considered to only pay users who are attend. Bad Idea.
|
||||
* **Alternative:** Implement system to make sure you can only collect if the host is online. Make admin route to open server (set global bool)
|
||||
|
||||
2. **User Transaction History:**
|
||||
* **Description:** Create a new API endpoint (e.g., `GET /transactions`) that allows an authenticated user to retrieve a paginated list of their own transaction history.
|
||||
* **Benefits:** Provides users with transparency and a way to track their finances, which is a core feature of any banking application.
|
||||
|
||||
* FINISHED: PLEASE CHECK IF WORKING!
|
||||
|
|
@ -18,4 +18,4 @@ class Config:
|
|||
|
||||
# Admin
|
||||
ADMIN_KEY = os.getenv('ADMIN_KEY')
|
||||
COLLECT_COOLDOWN = os.getenv('COLLECT_COOLDOWN')
|
||||
COLLECT_COOLDOWN = int(os.getenv('COLLECT_COOLDOWN', 24))
|
||||
|
|
|
|||
|
|
@ -20,59 +20,81 @@ def get_balance():
|
|||
def collect():
|
||||
bid = request.bid
|
||||
cooldown = Config.COLLECT_COOLDOWN
|
||||
|
||||
try:
|
||||
with db.cursor(dictionary=True) as cur:
|
||||
# 1. Get user job
|
||||
cur.execute("SELECT * FROM user_jobs WHERE bid = %s", (bid,))
|
||||
user_jt = cur.fetchone()
|
||||
if not user_jt:
|
||||
return jsonify({"error": "You dont have any Jobs"}), 404
|
||||
active_cooldown = user_jt["collected"]
|
||||
except mysql.connector.Error as err:
|
||||
current_app.logger.error(f"Database error in collect, salary: {err}")
|
||||
return jsonify({"error": "A database error occurred, please try again later."}), 500
|
||||
if active_cooldown + timedelta(hours=cooldown) > datetime.now(timezone.utc):
|
||||
|
||||
# 2. Check cooldown
|
||||
active_cooldown = user_jt.get("collected")
|
||||
if active_cooldown and (active_cooldown + timedelta(hours=cooldown) > datetime.now(timezone.utc)):
|
||||
remaining_time = (active_cooldown + timedelta(hours=cooldown)) - datetime.now(timezone.utc)
|
||||
hours = int(remaining_time.total_seconds() // 3600)
|
||||
minutes = int(remaining_time.total_seconds() % 3600 // 60)
|
||||
return jsonify({"error": f"You can only collect your salary every {cooldown} hours. Please wait {hours}h {minutes}m."}), 429
|
||||
job = user_jt["job_id"]
|
||||
try:
|
||||
with db.cursor(dictionary=True) as cur:
|
||||
cur.execute("SELECT * FROM jobs WHERE job_id = %i", (job,))
|
||||
|
||||
# 3. Get job details
|
||||
job_id = user_jt["job_id"]
|
||||
cur.execute("SELECT * FROM jobs WHERE job_id = %s", (job_id,))
|
||||
job_data = cur.fetchone()
|
||||
except mysql.connector.Error as err:
|
||||
current_app.logger.error(f"Database error in collect, salary: {err}")
|
||||
return jsonify({"error": "A database error occurred, please try again later."}), 500
|
||||
if not job_data:
|
||||
return jsonify({"error": "Invalid Job","message":"If you believe this is an error, contact a "
|
||||
"Administrator"}), 404
|
||||
return jsonify({"error": "Invalid Job", "message": "If you believe this is an error, contact an Administrator"}), 404
|
||||
|
||||
# 4. Get salary details
|
||||
salary_class = job_data["salary_class"]
|
||||
try:
|
||||
with db.cursor(dictionary=True) as cur:
|
||||
cur.execute("SELECT * FROM salary WHERE class = %i", (salary_class,))
|
||||
cur.execute("SELECT * FROM salary WHERE class = %s", (salary_class,))
|
||||
salary_data = cur.fetchone()
|
||||
except mysql.connector.Error as err:
|
||||
current_app.logger.error(f"Database error in collect, salary: {err}")
|
||||
return jsonify({"error": "A database error occurred, please try again later."}), 500
|
||||
if not salary_data:
|
||||
return jsonify({"error": "Invalid Salary Class"}), 500
|
||||
|
||||
amount = salary_data["money"]
|
||||
try:
|
||||
with db.cursor(dictionary=True) as cur:
|
||||
cur.execute("UPDATE users SET balance = balance + %s WHERE bid = %s", (amount, bid,))
|
||||
cur.execute("UPDATE user_jobs SET collected = %s WHERE bid = %s", (datetime.now(timezone.utc), bid,))
|
||||
cur.execute("INSERT INTO transactions (source, target, amount, type, timestamp, status) VALUES (%s, %s, "
|
||||
"%s, %s, %s, %s)", "NULL", bid, amount, "salary", datetime.now(timezone.utc), "completed",)
|
||||
|
||||
# 5. Perform transaction
|
||||
db.start_transaction()
|
||||
cur.execute("UPDATE users SET balance = balance + %s WHERE bid = %s", (amount, bid))
|
||||
cur.execute("UPDATE user_jobs SET collected = %s WHERE bid = %s", (datetime.now(timezone.utc), bid))
|
||||
cur.execute(
|
||||
"INSERT INTO transactions (source, target, amount, type, timestamp, status) VALUES (%s, %s, %s, %s, %s, %s)",
|
||||
("SYSTEM", bid, amount, "salary", datetime.now(timezone.utc), "completed")
|
||||
)
|
||||
cur.execute("SELECT balance FROM users WHERE bid = %s", (bid,))
|
||||
new_bal2 = cur.fetchone()
|
||||
new_bal = new_bal2["balance"]
|
||||
new_balance = cur.fetchone()["balance"]
|
||||
db.commit()
|
||||
|
||||
return jsonify({"message": "Salary Collected", "New Balance": new_balance}), 200
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
db.rollback()
|
||||
current_app.logger.error(f"Database error in collect, salary: {err}")
|
||||
current_app.logger.error(f"Database error in /collect: {err}")
|
||||
return jsonify({"error": "A database error occurred, please try again later."}), 500
|
||||
return jsonify({"message":"Salary Collected","New Balance":new_bal}), 200
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
current_app.logger.error(f"An unexpected error occurred in /collect: {e}")
|
||||
return jsonify({"error": "An unexpected server error occurred."}), 500
|
||||
|
||||
@transactions_bp.route('/transactions', methods=['GET'])
|
||||
@jwt_required
|
||||
def get_transactions():
|
||||
user_bid = request.bid
|
||||
limit = request.args.get('limit', default=10, type=int)
|
||||
try:
|
||||
with db.cursor(dictionary=True) as cur:
|
||||
cur.execute("SELECT * FROM transactions WHERE source = %s OR target = %s ORDER BY timestamp DESC LIMIT %s", (user_bid, user_bid, limit))
|
||||
transactions = cur.fetchall()
|
||||
return jsonify({"transactions": transactions}), 200
|
||||
except mysql.connector.Error as err:
|
||||
current_app.logger.error(f"Database error in /transactions: {err}")
|
||||
return jsonify({"error": "A database error occurred, please try again later."}), 500
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"An unexpected error occurred in /transactions: {e}")
|
||||
return jsonify({"error": "An unexpected server error occurred."}), 500
|
||||
|
||||
|
||||
# this should be fine
|
||||
@transactions_bp.route('/transfer', methods=['POST'])
|
||||
@jwt_required
|
||||
def transfer():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue