from flask import Flask, render_template, request, jsonify from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager, UserMixin, login_user, login_required, current_user, logout_user from flask_apscheduler import APScheduler from datetime import datetime, timedelta app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db' app.config['SECRET_KEY'] = 'your_secret_key' db = SQLAlchemy(app) login_manager = LoginManager(app) login_manager.login_view = 'login' scheduler = APScheduler() @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) @app.route('/dashboard') @login_required def dashboard(): if current_user.user_type == 'tenant': properties = current_user.properties return render_template('tenant_dashboard.html', properties=properties) elif current_user.user_type == 'landlord': properties = Property.query.filter_by(user_id=current_user.id).all() return render_template('landlord_dashboard.html', properties=properties) if __name__ == '__main__': db.create_all() scheduler.init_app(app) scheduler.start() app.run(debug=True) class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), unique=True, nullable=False) user_type = db.Column(db.String(10), nullable=False) properties = db.relationship('Property', backref='user', lazy=True) class Property(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) @app.route('/register', methods=['POST']) def register_user(): data = request.json username = data.get('username') user_type = data.get('user_type') if username and user_type: new_user = User(username=username, user_type=user_type) db.session.add(new_user) db.session.commit() return jsonify({'message': f'{username} registered successfully!'}) return jsonify({'error': 'Invalid data'}), 400 if __name__ == '__main__': db.create_all() app.run(debug=True) @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) if __name__ == '__main__': db.create_all() app.run(debug=True) class RentPayment(db.Model): id = db.Column(db.Integer, primary_key=True) amount = db.Column(db.Float, nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) date_paid = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) @app.route('/rent_tracking/') @login_required def rent_tracking(property_id): property = Property.query.get(property_id) return render_template('rent_tracking.html', property=property) @app.route('/pay_rent/', methods=['POST']) @login_required def pay_rent(property_id): property = Property.query.get(property_id) if not property: return jsonify({'error': 'Property not found'}), 404 amount_paid = float(request.form.get('amount_paid')) payment_method = request.form.get('payment_method') if amount_paid <= 0: return jsonify({'error': 'Invalid amount'}), 400 if payment_method == 'bank_transfer': # Integrate with a bank transfer API or handle the process # Example: Call a bank API to initiate the transfer transfer_status = initiate_bank_transfer(property, amount_paid) if transfer_status: record_payment(property, amount_paid) return redirect(url_for('dashboard')) else: return jsonify({'error': 'Bank transfer failed'}), 500 elif payment_method == 'mobile_money': # Integrate with a mobile money API or handle the process # Example: Call a mobile money API to initiate the transfer mm_status = initiate_mobile_money_transfer(property, amount_paid) if mm_status: record_payment(property, amount_paid) return redirect(url_for('dashboard')) else: return jsonify({'error': 'Mobile money transfer failed'}), 500 return jsonify({'error': 'Invalid payment method'}), 400 def initiate_bank_transfer(property, amount_paid): # Implement logic to initiate bank transfer # Example: Call a bank API return True # Placeholder for success, handle accordingly def initiate_mobile_money_transfer(property, amount_paid): # Implement logic to initiate mobile money transfer # Example: Call a mobile money API return True # Placeholder for success, handle accordingly def record_payment(property, amount_paid): # Record the payment in the database new_payment = RentPayment(amount=amount_paid, property=property) db.session.add(new_payment) db.session.commit() class MaintenanceRequest(db.Model): id = db.Column(db.Integer, primary_key=True) description = db.Column(db.String(255), nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) date_submitted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) is_resolved = db.Column(db.Boolean, default=False) @app.route('/submit_maintenance_request/', methods=['POST']) @login_required def submit_maintenance_request(property_id): property = Property.query.get(property_id) if not property: return jsonify({'error': 'Property not found'}), 404 description = request.form.get('description') if not description: return jsonify({'error': 'Description cannot be empty'}), 400 new_request = MaintenanceRequest(description=description, property=property) db.session.add(new_request) db.session.commit() return redirect(url_for('dashboard')) class Message(db.Model): id = db.Column(db.Integer, primary_key=True) content = db.Column(db.String(255), nullable=False) sender_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) date_sent = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) is_read = db.Column(db.Boolean, default=False) @app.route('/send_message/', methods=['POST']) @login_required def send_message(recipient_id): recipient = User.query.get(recipient_id) if not recipient: return jsonify({'error': 'Recipient not found'}), 404 content = request.form.get('content') if not content: return jsonify({'error': 'Content cannot be empty'}), 400 new_message = Message(content=content, sender=current_user, recipient=recipient) db.session.add(new_message) db.session.commit() return redirect(url_for('dashboard')) @app.route('/view_messages/') @login_required def view_messages(other_user_id): other_user = User.query.get(other_user_id) if not other_user: return jsonify({'error': 'User not found'}), 404 messages = Message.query.filter( ((Message.sender_id == current_user.id) & (Message.recipient_id == other_user_id)) | ((Message.sender_id == other_user_id) & (Message.recipient_id == current_user.id)) ).order_by(Message.date_sent).all() return render_template('view_messages.html', other_user=other_user, messages=messages) @app.route('/view_messages/') @login_required def view_messages(other_user_id): class Invoice(db.Model): id = db.Column(db.Integer, primary_key=True) amount = db.Column(db.Float, nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) date_issued = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) class ServiceCharge(db.Model): id = db.Column(db.Integer, primary_key=True) amount = db.Column(db.Float, nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) date_issued = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) class UtilityBill(db.Model): id = db.Column(db.Integer, primary_key=True) amount = db.Column(db.Float, nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) date_issued = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) @app.route('/generate_invoice/', methods=['POST']) @login_required def generate_invoice(property_id): property = Property.query.get(property_id) if not property: return jsonify({'error': 'Property not found'}), 404 amount = float(request.form.get('amount')) if amount <= 0: return jsonify({'error': 'Invalid amount'}), 400 new_invoice = Invoice(amount=amount, property=property) db.session.add(new_invoice) db.session.commit() return redirect(url_for('dashboard')) @app.route('/generate_service_charge/', methods=['POST']) @login_required def generate_service_charge(property_id): property = Property.query.get(property_id) if not property: return jsonify({'error': 'Property not found'}), 404 amount = float(request.form.get('amount')) if amount <= 0: return jsonify({'error': 'Invalid amount'}), 400 new_service_charge = ServiceCharge(amount=amount, property=property) db.session.add(new_service_charge) db.session.commit() return redirect(url_for('dashboard')) @app.route('/generate_utility_bill/', methods=['POST']) @login_required def generate_utility_bill(property_id): property = Property.query.get(property_id) if not property: return jsonify({'error': 'Property not found'}), 404 amount = float(request.form.get('amount')) if amount <= 0: return jsonify({'error': 'Invalid amount'}), 400 new_utility_bill = UtilityBill(amount=amount, property=property) db.session.add(new_utility_bill) db.session.commit() return redirect(url_for('dashboard')) class Notification(db.Model): id = db.Column(db.Integer, primary_key=True) content = db.Column(db.String(255), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) scheduler = APScheduler() def check_for_reminders(): # Logic to check for upcoming events and send notifications # For simplicity, we'll create reminders for upcoming rent payments and maintenance appointments upcoming_rent_payments = RentPayment.query.filter( (RentPayment.property.has(Property.user == current_user)) & (RentPayment.date_paid >= datetime.utcnow()) & (RentPayment.date_paid <= datetime.utcnow() + timedelta(days=7)) ).all() upcoming_maintenance_appointments = MaintenanceRequest.query.filter( (MaintenanceRequest.property.has(Property.user == current_user)) & (MaintenanceRequest.is_resolved.is_(False)) & (MaintenanceRequest.date_submitted <= datetime.utcnow() - timedelta(days=2)) ).all() # Create notifications for upcoming events for payment in upcoming_rent_payments: content = f"Upcoming rent payment of {payment.amount} for property {payment.property.name}." create_notification(content, current_user) for maintenance_request in upcoming_maintenance_appointments: content = f"Upcoming maintenance appointment for property {maintenance_request.property.name}." create_notification(content, current_user) def create_notification(content, user): new_notification = Notification(content=content, user=user) db.session.add(new_notification) db.session.commit() @app.route('/notifications') @login_required def view_notifications(): notifications = Notification.query.filter_by(user=current_user).order_by(Notification.date_created.desc()).all() return render_template('view_notifications.html', notifications=notifications) scheduler.add_job(id='check_for_reminders', func=check_for_reminders, trigger='interval', minutes=60) scheduler.start() class UserProperty(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) property_id = db.Column(db.Integer, db.ForeignKey('property.id'), nullable=False) is_landlord = db.Column(db.Boolean, default=False) # ... (previous routes) @app.route('/add_property', methods=['POST']) @login_required def add_property(): property_id = int(request.form.get('property_id')) if not property_id: return jsonify({'error': 'Invalid property id'}), 400 user_property = UserProperty.query.filter_by(user_id=current_user.id, property_id=property_id).first() if user_property: return jsonify({'error': 'Property already added'}), 400 new_user_property = UserProperty(user=current_user, property_id=property_id, is_landlord=False) db.session.add(new_user_property) db.session.commit() return redirect(url_for('dashboard')) login_manager = LoginManager(app) login_manager.login_view = 'login' @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form.get('username') password = request.form.get('password') user = User.query.filter_by(username=username).first() if user and user.check_password(password): login_user(user) return redirect(url_for('dashboard')) else: flash('Login failed. Check your username and password.') return render_template('login.html') @app.route('/logout') @login_required def logout(): logout_user() return redirect(url_for('login'))