Professional Documents
Culture Documents
INTRODUCTION
THRIFT (“the quality of using money and other resources carefully and not wastefully.”) is an expense
tracking and management system designed to help individuals and businesses track,
manage, and analyse their expenses conveniently and efficiently. It provides a user-friendly
interface and a range of features to simplify the process of expense tracking on
smartphones, tablets & computers.
This system allows users to record their expenses on-the-go. It ensures that expenses are
captured in real-time and hence minimizing the chance of forgetting or missing any
transactions.
OBJECTIVE
The main objective of Expense tracking and management system is to provide an effective
method of keeping track of an individual or business’s expenditure in order to take a firm
and stable decision in the upcoming days or years and to manage their budget as peer there
need by analysing them using data visualisation charts and graphs.
SYSTEM REQUIREMENT
The general hardware and software requirements to consider for an expense tracking
system are as follow:
Hardware Requirements:
• MySQL Workbench
3.Web-Technology: expense tracking system is developed using a
framework and markup language.
• Python version- 3.9.2 (64 bit (AMD64)
• HTML (Hypertext markup language)
• CSS (Cascading style sheet)
• FLASK(Python)
4
ADVANTAGES
An expense tracking and management system offers numerous advantages for individuals
and businesses. Here are some key benefits:
1. Financial Awareness:
An expense tracking system provides users with a clear understanding of their
spending habits. By recording and categorizing expenses, users gain insight into where
their money is being spent, helping them make informed financial decisions. This
awareness enables better control over personal or business finances and promotes
responsible spending.
2. Budget Management:
Effective budget management is crucial for financial stability. An expense tracking
system allows users to set budgets for different expense categories and monitor their
spending against those budgets. Users receive alerts when they exceed their budgeted
amounts, helping them stay on track and avoid overspending.
3. Expense Analysis:
An expense tracking system generates reports, charts, and graphs that analyse spending
patterns over time. Users can identify trends, compare expenses across categories, and
gain a comprehensive overview of their financial situation. This analysis helps users
make informed decisions on where to cut costs, optimize spending, and allocate
resources more effectively.
4. Efficiency and Time Savings:
Manual expense tracking can be time-consuming and prone to errors. An automated
expense tracking system streamlines the process by allowing users to quickly enter
expenses, capture receipts, and categorize transactions. This automation saves time,
reduces human error, and eliminates the need for manual data entry.
5. Financial Transparency:
An expense tracking system promotes transparency within organizations. It allows
business owners, managers, or financial advisors to access real-time expense data,
monitor spending across departments or projects, and ensure compliance with financial
policies. This transparency enhances financial control, accountability, and decision-
making.
5
1. Time-consuming:
Manual expense tracking requires significant time and effort. Users need to
manually record each expense, gather receipts, and organize them accordingly. This
process can be tedious and time-consuming, especially when dealing with a large
volume of expenses.
2. Prone to Errors:
Manual data entry is susceptible to human errors. From incorrect calculations to
data entry mistakes, the chances of errors are higher in manual expense tracking
systems. These errors can lead to inaccurate financial records and reporting,
potentially impacting budgeting, tax filings, and decision-making.
3. Lack of Real-time Visibility:
Manual expense tracking systems often lack real-time visibility into financial data.
Users need to wait until they have compiled and organized all the expenses before
they can assess their spending patterns and financial situation. This delay can hinder
proactive financial management and timely decision-making.
4. Limited Reporting and Analysis:
Traditional expense tracking methods may not offer sophisticated reporting and
analysis capabilities. Users might have to manually aggregate data from multiple
sources to generate reports or analyze spending patterns. This limitation can hinder
the ability to gain meaningful insights and make informed financial decisions.
5. Difficulties in Retrieval and Storage:
Storing and retrieving expense records in manual systems can be challenging. Paper
receipts and documents can be misplaced, damaged, or lost over time. Locating
specific records when needed can become time-consuming and cumbersome,
leading to inefficiencies and potential compliance issues.
6. Reduced Mobility and Accessibility:
6
SCREENSHORTS
11
12
13
14
15
16
17
18
19
1. Layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>THRIFT</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="/static/icons/dashboard-icon.png" rel="icon">
<link href="/static/assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.gstatic.com" rel="preconnect">
<!-- Template Main CSS File -->
<link href="/static/assets/css/style.css" rel="stylesheet">
</head>
<body>
{% block content %}
{% endblock %}
<li class="nav-item">
<a class="nav-link collapsed" href="/add_income">
<i class="bi bi-bank2"></i>
<span>Add income</span>
</a>
</li><!-- End add income -->
<li class="nav-item">
<a class="nav-link collapsed" href="/add_expense">
<i class="bi bi-layout-text-window-reverse"></i>
<span>Add expense</span>
</a>
</li>
<!-- End add income -->
<li class="nav-item">
<a class="nav-link collapsed" href="/lpg_cylinder">
<i class="bi bi-fire"></i>
<span>LGP Cylinder</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="##">
<i class="bi bi-house"></i>
<span>Rent Details</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#tables-nav" data-bs-
toggle="collapse" href="#">
<i class="bi bi-cash-coin"></i><span>Transactions</span><i class="bi bi-
chevron-down ms-auto"></i>
</a>
<ul id="tables-nav" class="nav-content collapse " data-bs-parent="#sidebar-
nav">
23
<li>
<a href="/expense_transaction">
<i class="bi bi-circle"></i><span>All Expenses</span>
</a>
</li>
<li>
<a href="/income_transaction">
<i class="bi bi-circle"></i><span>All Income</span>
</a> </li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="/add_budget">
<i class="bi bi-command"></i>
<span>Set Budget</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="/user_profile">
<i class="bi bi-person"></i>
<span>Profile</span>
</a>
</li><!-- End Profile Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="/user_logout">
<i class="bi bi-dash-circle"></i>
<span>Log Out</span>
</a>
</li>
{%endif%}
{% if (session['user_email'] == undefined ) %}
<li class="nav-item">
<a class="nav-link collapsed" href="/user_registration">
24
</body>
25
2. Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>THRIFT</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="/static/icons/dashboard-icon.png" rel="icon">
<link href="/static/icons/dashboard-icon.png" rel="apple-touch-icon">
<!--Vendor CSS Files-->
<link href="/static/assets/vendor/bootstrap/css/bootstrap.min.css"
rel="stylesheet">
<link href="/static/assets/vendor/bootstrap-icons/bootstrap-icons.css"
rel="stylesheet"><!--features and insight design-->
<!-- Template Main CSS File -->
<link href="/static/assets/css/index_style.css" rel="stylesheet">
</head>
<body>
<!-- ======= Header ======= -->
<header id="header" class="fixed-top d-flex align-items-center">
<div class="container d-flex justify-content-between align-items-center">
<div class="logo">
<a href="/" class="logo">
<h1><a href="/">THRIFT</a></h1>
</div>
26
{% if "user_email" in session %}
<li><a href="/user_dashboard">Dashboard</a></li>
</ul>
<ul><h6>
<li class="dropdown"><a href="##">{{session['first_name']}}</a>
<ul>
<li><a href="/user_profile">Profile</a></li>
<li><a href="/user_logout">Log out</a></li>
</ul> </li>
</h6> </ul>
{% endif %}
</nav><!-- end navbar -->
</div>
</header><!-- End Header -->
<!-- ======= top shelf Section ======= -->
<section class="hero-section" id="hero">
<div class="wave">
</div>
<div class="container">
<div class="row align-items-center">
<div class="col-12 hero-text-image">
<div class="row">
<div class="col-lg-8 text-center text-lg-start">
<h1>Your personal expense tracker</h1>
<p class="mb-5" >The active management of your finances.</p>
{% if "user_email" in session %}
<p><a
href="/user_dashboard" class="btn btn-outline-white">Dashboard</a></p>
{% else %}
28
{%endif%}
</div>
<div class="col-lg-4 iphone-wrap">
<img src="/static/assets/img/phone_1.jpg" alt="Image" class="phone-1" >
<img src="/static/assets/img/phone_2.jpg" alt="Image" class="phone-2" >
</div> </div>
</div> </div>
</div>
</div>
29
<div class="container">
<div class="row">
<div class="col-md-4 mb-4 mb-md-0">
<h3>About THRIFT</h3>
<p>A tool designed to help individuals or businesses track and manage their
expenses efficiently. It allows users to record, categorize, and analyze their spending,
providing valuable insights into their financial habits. </p>
<p class="social">
<a href="#"><span class="bi bi-twitter"></span></a>
<a href="#"><span class="bi bi-facebook"></span></a>
<a href="#"><span class="bi bi-instagram"></span></a>
<a href="{{session['linkdin']}}"><span class="bi bi-linkedin"></span></a>
</p>
</div>
<div class="row justify-content-center text-center">
<div class="col-md-7">
Designed by <a href="##">Viraj II</a>
</div> </div>
</div> </div>
</footer>
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
class="bi bi-arrow-up-short"></i></a>
<!-- Vendor JS Files -->
<script src="/static/assets/vendor/aos/aos.js"></script>
<script src="/static/assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="/static/assets/vendor/swiper/swiper-bundle.min.js"></script>
<script src="/static/assets/vendor/php-email-form/validate.js"></script>
3. user_dashboard.html
{% extends "layout.html" %}
<body>
{% block content %}
<div class="pagetitle">
<h1>Dashboard</h1>
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item active"><a
href="/user_dashboard">Dashboard</a></li>
</ol>
</nav>
</div><!-- End Page Title -->
<section class="section dashboard">
<div class="row">
<!-- Left side columns -->
<div class="col-lg-8">
<div class="row">
<div class="card-body">
<h5 class="card-title">Total income <span>| Today</span></h5>
dots"></i></a>
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<li class="dropdown-header text-start">
<h6>Filter</h6>
</li>
<li><a class="dropdown-item" href="#">Today</a></li>
<li><a class="dropdown-item" href="#">This Month</a></li>
<li><a class="dropdown-item" href="#">This Year</a></li>
</ul>
</div>
<div class="card-body">
<h5 class="card-title">Total spent </h5>
</thead>
<tbody>
{% for m in most %}
<tr>
<th scope="row">{{m[0]}}</th>
<td><a href="#" class="text-primary fw-bold">{{m[1]}}</a></td>
<td>{{m[2]}}</td>
<td class="fw-bold">{{m[3]}}</td>
<td>{{m[4]}}</td>
</tr>
{%endfor%}
</tbody>
</table> </div>
</div> </div><!-- End most expenses -->
</div>
</div><!-- End Left side columns -->
<!-- Right side columns -->
<div class="col-lg-4">
<!-- Recent Activity -->
<div class="card">
<div class="card-body">
<h5 class="card-title">Recent Expenditure<span>|(last 5 expense)</span></h5>
<div class="activity">
{% for a in recent %}
<div class="activity-item d-flex">
<div class="activite-label">{{a[0]}} </div>
<i class='bi bi-circle-fill activity-badge text-danger align-self-start'></i>
<div class="activity-content">
( {{a[1]}} ) <a href="#" class="fw-bold text-dark">{{a[2]}}</a> 
({{a[3]}} )
</div> </div><!-- End activity item-->
{%endfor%}
38
</div>
</div>
</div><!-- End Recent Activity -->
<!-- Budget Report -->
<div class="card">
<div class="filter">
<a class="icon" href="#" data-bs-toggle="dropdown"><i class="bi bi-
three-dots"></i></a>
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<li class="dropdown-header text-start">
<h6>Filter</h6>
</li>
<li><a class="dropdown-item" href="#">Today</a></li>
<li><a class="dropdown-item" href="#">This Month</a></li>
<li><a class="dropdown-item" href="#">This Year</a></li>
</ul>
</div>
</div><!-- End Right side columns -->
</div>
</section>
</main><!-- End #main -->
</html>
39
4. user_registration.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<body>
<main>
<div class="container">
<div class="card-body">
<div class="pt-4 pb-2">
<h5 class="card-title text-center pb-0 fs-4">Create an Account</h5>
<p class="text-center small">Enter your personal details to create account</p>
</div>
<div class="col-12">
<label for="Email" class="form-label">Your Email</label>
42
<div class="col-12">
<label for="contact" class="form-label">Mobile</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend">+91</span>
<input type="text" name="mobile" class="form-control"
id="mobile" required>
<div class="invalid-feedback">Please enter mobile number</div>
</div>
</div>
<div class="col-12">
<label for="Password" class="form-label">Password</label>
<input type="password" name="password" class="form-control"
id="Password" required>
<div class="invalid-feedback">Please enter your password!</div>
</div>
<div class="col-5 row g-3">
<imgsrc="../static/captcha/user_captcha.png" width="170px"
height="60px"><br>
</div>
<div class="col-6">
<label for="captcha" class="form-label">Enter the text(case sensitive)</label>
<input type="captcha" name="captcha" class="form-control" id="captcha"
required>
</div>
<div class="col-12">
43
<div class="form-check">
<input class="form-check-input" name="terms" type="checkbox"
value="" id="acceptTerms" required>
<label class="form-check-label" for="acceptTerms">I agree and accept
the
<a href="#">terms and conditions</a></label>
<div class="invalid-feedback">You must agree before submitting.</div>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary w-100" type="submit">Create Account</button>
</div>
<div class="col-12">
<p class="small mb-0">Already have an account? <a href="/user_login">Log in
</a></p>
</div>
</form>
</div>
</div>
<div class="credits">
Designed by <a href="######">VIRAJ II</a>
</div>
</div>
</div>
</div>
</section>
</div>
</form>
</main><!-- End #main -->
44
</html>
45
5. user_login.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>user_Login-THRIFT</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="/static/icons/dashboard-icon.png" rel="icon">
<link href="/static/icons/dashboard-icon.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.gstatic.com" rel="preconnect">
<link
href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,7
00,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i
,600,600i,700,700i" rel="stylesheet">
<div class="card-body">
</html>
49
6. user_profile.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Users_Profile</title>
<meta content="" name="description">
<meta content="" name="keywords">
</head>
<body>
{% block content %}
<div class="pagetitle">
<h1>Profile</h1>
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
<li class="breadcrumb-item">Users</li>
<li class="breadcrumb-item active">Profile</li>
</ol>
</nav>
</div><!-- End Page Title -->
<div class="card">
<div class="card-body profile-card pt-4 d-flex flex-column align-items-center">
{% for r in record %}
51
</div>
<div class="col-xl-8">
{% with messages = get_flashed_messages() %} <!--jinja codes to get
message from flash and store it-->
{% if messages %} <!--check wether if there any message in flash-->
{% for message in messages %} <!--store messages in message-->
<div class="alert alert-success" role="success">
{{message}}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="card">
<div class="card-body pt-3">
52
<li class="nav-item">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#profile-
overview">Overview</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-
edit">Edit Profile</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-change-
password">Change Password</button>
</li>
</ul>
<div class="tab-content pt-2">
<div class="row">
<div class="col-lg-3 col-md-4 label ">Full Name</div>
<div class="col-lg-9 col-md-
8">{{session['first_name']}} {{session['last_name']}}</div>
</div>
<div class="row">
53
<div class="row">
<div class="col-lg-3 col-md-4 label">Email</div>
<div class="col-lg-9 col-md-8">{{session['user_email']}}</div>
</div>
</div>
<div class="col">
<div class="col-md-4">
<input type="file" name="photo" class="form-control" placeholder="choose
" style="width:300px"><br>
<button type="submit" class="btn btn-primary">upload</button>
</div>
<div class="text-center">
</div>
</form>
54
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</form><!-- End Profile Edit Form -->
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Change Password</button>
</div>
</form><!-- End Change Password Form -->
</div>
<div class="credits">
Designed by <a href="###########">VIRAJ II</a>
</div>
58
</html>
59
7. add_income.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<body>
{% block content %}
<main id="main" class="main">
<div class="pagetitle">
<h1>INCOME</h1>
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/add_income">Add
income</a></li>
</ol>
</nav>
</div><!-- End Page Title -->
<section class="section">
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">ADD INCOME</h5>
{% with messages = get_flashed_messages() %} <!--jinja codes to get
message from flash and store it-->
{% if messages %} <!--check wether if there any message in flash-->
{% for message in messages %} <!--store messages in message-->
<div class="alert alert-success" role="success">
{{message}}
60
</div>
{% endfor %}
{% endif %}
{% endwith %}
<!-- Floating Labels Form -->
<form action="/add_income_insert" method="POST" class="row g-3">
<div class="col-md-12">
<label for="floatingName">DATE</label>
<div class="form-floating">
<input type="date" name="date" class="form-control" id="date"
onfocus="this.max=new Date().toISOString().split('T')[0]"
required>
</div>
</div>
<div class="col-md-6">
<label for="floatingSelect">source OF INCOME</label>
<div class="form-floating mb-3">
<input type="text" name="source" class="form-control"
id="source"required>
</div>
</div>
<div class="col-12">
<label for="floatingTextarea">Remarks</label>
<div class="form-floating">
<textarea class="form-control" name="remarks" id="remarks"
style="height: 100px;"></textarea>
</div>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form><!-- End floating Labels Form -->
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Recent income<span>|(last 5 income)</span></h5>
<div class="activity">
{% for i in income %}
<div class="activity-item d-flex">
<div class="activite-label">{{ i[0]}}   </div>
<i class='bi bi-circle-fill activity-badge text-success align-self-start'></i> 
<div class="activity-content">
62
</html>
63
8. add expense.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<body>
{% block content %}
<main id="main" class="main">
<div class="pagetitle">
<h1>ADD EXPENSE</h1>
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/add_expense"></a>add_expense</li>
</ol>
</nav>
</div><!-- End Page Title -->
<section class="section">
<div class="row">
<div class="col-lg-6">
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-body">
{% with messages = get_flashed_messages() %} <!--jinja codes to get message
from flash and store it-->
{% if messages %} <!--check wether if there any message in flash-->
64
<div class="col-12">
<label for="item" class="form-label">item</label>
<input type="text" class="form-control" id="item" name="item">
</div>
<div class="col-12">
<label for="inputAddress" class="form-label">amount</label>
<input type="int" class="form-control" id="amount" name="amount">
</div>
<div class="col-12">
<label for="floatingTextarea">Remarks</label>
<div class="form-floating">
<textarea class="form-control" name="remarks" id="remarks" style="height:
100px;" name="remarks"></textarea>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Submit</button>
<button type="reset" class="btn btn-secondary">Reset</button>
</div>
</form><!-- Vertical Form -->
</div>
</div>
</div>
</div>
</section>
{% endblock %}
</body>
</html>
66
9. expense_transaction.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<body>
{% block content %}
<main id="main" class="main">
<div class="pagetitle">
<h1>ADD EXPENSE</h1>
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/add_expense"></a>add_expense</li>
</ol>
</nav>
</div><!-- End Page Title -->
<section class="section">
<div class="row">
<div class="col-lg-6">
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-body">
{% with messages = get_flashed_messages() %} <!--jinja codes to get message
from flash and store it-->
{% if messages %} <!--check wether if there any message in flash-->
67
<div class="col-12">
<label for="item" class="form-label">item</label>
<input type="text" class="form-control" id="item" name="item">
</div>
<div class="col-12">
<label for="inputAddress" class="form-label">amount</label>
<input type="int" class="form-control" id="amount" name="amount">
</div>
<div class="col-12">
<label for="floatingTextarea">Remarks</label>
<div class="form-floating">
<textarea class="form-control" name="remarks" id="remarks" style="height:
100px;" name="remarks"></textarea>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Submit</button>
<button type="reset" class="btn btn-secondary">Reset</button>
</div>
</form><!-- Vertical Form -->
</div>
</div>
</div>
</div>
</section>
{% endblock %}
</body>
</html>
69
10. income_transaction.html
{% extends "layout.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>THRIFT-Dashboard</title>
<meta content="" name="description">
<meta content="" name="keywords">
<th scope="col">Remarks</th>
</tr>
</thead>
<tbody>
{% for i in income %}
<tr>
<th scope="row">{{i[4]}}</th>
<td>{{i[0]}}</td>
<td>{{i[1]}}</td>
<td>{{i[2]}}</td>
<td>{{i[3]}}</td>
</tr>
{%endfor%}
</tbody>
</table>
<!-- End Table with stripped rows -->
</div>
</div>
</div>
</div>
</section>
</main><!-- End #main -->
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
class="bi bi-arrow-up-short"></i></a>
<script src="/static/assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
11.user_email_verify.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>user_verify-THRIFT</title>
<meta content="" name="description">
<meta content="" name="keywords">
</head>
<body>
<main>
<div class="container">
</body>
</html>
75
12. app.py
from flask import Flask, render_template, request, redirect, url_for, flash, session
from user import user_operation # importing from user.py
import hashlib # importing password encription module
from captcha.image import ImageCaptcha
# import flash from redirect,url_for
from flask_mail import *
import random
# ...............mail configuration...............
app.config["MAIL_SERVER"] = 'smtp.office365.com'
app.config["MAIL_PORT"] = '587'
app.config["MAIL_USERNAME"] = 'pythonproject2023@outlook.com'
app.config["MAIL_PASSWORD"] = 'Viraj@123'
app.config["MAIL_USE_TLS"] = True
app.config["MAIL_USE_SSL"] = False
mail = Mail(app) # mail object
def user_dashboard():
if "user_email" in session: # creating index function
# linking index.html to local server / rendering it from templet folder in
"project_python" folder
op=user_operation()
r = op.total_income()
op=user_operation()
e= op.total_expense()
if(r[0][0]==None and e[0][0]==None):#when both income and expene
rest = 0
elif(r[0][0]==None):
rest = 0 - int(e[0][0])
elif(e[0][0]==None):
rest = int(r[0][0]) - 0
else:
rest=int(r[0][0])- int(e[0][0])
op=user_operation()
a= op.recent_expense() # a is variable reciving data from user.py
op=user_operation()
m= op.most_expense()
return
render_template("user_dashboard.html",income=r,expense=e,rest=rest,rec
ent=a,most=m) #recent will be used in html page as data holder from
database
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
@app.route("/user_registration")
77
def user_registration():
num = random.randrange(1000, 9999)
# create an image instance of given size range
img = ImageCaptcha(width=280, height=90)
# image captcha text
global captcha_text
captcha_text = str(num) # convert int into string
img.write(captcha_text, "static/captcha/user_captcha.png")
return render_template("user_registration.html")
# getting post from form to server
@app.route("/user_registration_insert", methods=['GET', 'POST'])
def user_registration_insert():
if request.method == "POST": # button is clicked
if (captcha_text != request.form['captcha']): # varifying captcha
flash("invalid captcha")
return redirect(url_for("user_registration"))
first_name = request.form['first_name']
last_name = request.form['last_name']
email = request.form['email']
mobile = request.form['mobile']
password = request.form['password']
# ..............password encription........
pas = hashlib.md5(password.encode())
password = pas.hexdigest()
#flash("sucessfully registered!!")
# return render_template("user_signup.html")
78
# .............email verification..............
global otp
otp = random.randint(1000, 99999)
msg = Message('viraj''s'' project email
verification',sender='pythonproject2023@outlook.com', recipients =
[email])
msg.body = "hello " + first_name + "\n welcome to my project in
python \n your otp for email verification is :" + str(otp)
mail.send(msg)
# return "data submitted"
return render_template("user_email_verify.html", email=email)
email=request.form['email']
op = user_operation() # object create
op.user_delete(email)
flash("Your Email verification is failed... Register with Valid
Email!!!")
return redirect(url_for('user_registration'))
@app.route("/user_login")
def user_login():
return render_template("user_login.html")
79
@app.route("/user_login_verify",methods=["GET","POST"])
def user_login_verify():
if request.method=="POST":
email=request.form['email']
password=request.form['password']
#--- password encryption----------------
pas = hashlib.md5(password.encode())
password = pas.hexdigest()
@app.route("/user_profile")
def user_profile():
if "user_email" in session:
op = user_operation() # object create
r=op.user_profile()
# op=user_operation() ################################
# p = op.profile_update_insert()
return render_template("user_profile.html",record=r)
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
#user password form
@app.route("/user_password_form")
def user_password_form():
80
if "user_email" in session:
return render_template("user_password_form.html")
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
@app.route("/user_password_change",methods=['POST','GET'])
def user_password_change():
if 'user_email' in session: #check wether user is login or not
if request.method=='POST':
oldpassword=request.form['oldpassword']
newpassword=request.form['newpassword']
pas = hashlib.md5(newpassword.encode())
newpassword = pas.hexdigest()
ob = user_operation() #object
ob.profile_update_insert(first_name,last_name,mobile,twitter,faceb
ook,instagram,linkdin)#photo_name
flash("Your Profile updated successfully!!!")
return redirect(url_for('user_profile'))
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
@app.route("/user_photo_update",methods=["GET","POST"])
def user_photo_update():
if "user_email" in session:
if request.method=="POST":
photo=request.files["photo"]
82
photo_name = photo.filename
photo.save("static/profile_image/" + photo_name)
ob = user_operation() #object
ob.profile_photo_insert(photo_name)
@app.route("/user_logout")
def user_logout():
session.clear()
flash("Logged out successfully.... :)")
return render_template("index.html")
@app.route("/add_income")
def add_income():
if "user_email" in session:
op=user_operation()
i= op.recent_income()
return render_template("add_income.html",income=i)
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
#return redirect(url_for('add_income'))
@app.route("/add_income_insert",methods=["GET","POST"])
def add_income_insert():
if request.method == "POST": # button is clicked
date = request.form['date']
source = request.form['source']
amount = request.form['amount']
83
remarks = request.form['remarks']
@app.route("/add_expense")
def add_expense():
if "user_email" in session:
return render_template("add_expense.html")
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
@app.route("/add_expense_insert",methods=["GET","POST"])
def add_expense_insert():
if request.method == "POST": # button is clicked
date = request.form['date']
category = request.form['category']
item = request.form['item']
amount = request.form['amount']
remarks = request.form['remarks']
@app.route("/lpg_cylinder")
def lpg_cylinder():
if "user_email" in session:
op=user_operation()
l= op.recent_lpg_cylinder()
return render_template("update_lpg.html",lpg=l)
else:
flash("You are not authorised.... login now!!")
return redirect(url_for('user_login'))
@app.route("/lpg_cylinder_insert",methods=["GET","POST"])
def lpg_cylinder_insert():
if request.method == "POST": # button is clicked
end_date = request.form['end_date']
remarks = request.form['remarks']
@app.route("/expense_transaction")
def expense_transaction():
op=user_operation()
all= op.all_expense()
return render_template("expense_transaction.html",recent=all)
85
@app.route("/income_transaction")
def income_transaction():
op=user_operation()
i= op.all_income()
return render_template("income_transaction.html",income=i)
@app.route("/add_budget")
def add_budget():
return render_template("add_budget.html")#record=r
@app.route("/add_budget_insert")
def add_budget_insert():
if "user_email" in session:
if request.method == "POST": # button is clicked
budget = request.form['budget']
if __name__ == "__main__":
# to activate server // debug=true to always keep server active
app.run(debug=True)
86
13.user.py
import mysql.connector
from flask import session
class user_operation:
def connection(self):
db=mysql.connector.connect(host="localhost",port="3306",user="root",
password="root",db="thrift")
return db
def user_registration_insert(self,first_name,last_name,email,mobile,password):
db = self.connection() #con
mycursor=db.cursor()
sq="insert into user (first_name,last_name,email,mobile,password)
values(%s,%s,%s,%s,%s)"
record=[first_name,last_name,email,mobile,password]
mycursor.execute(sq,record) # essential for every data connection
db.commit()
mycursor.close()
db.close()
return
def user_delete(self,email):
db = self.connection()
mycursor = db.cursor()
sq="delete from user where email=%s"
record=[email]
mycursor.execute(sq,record)
db.commit()
87
mycursor.close()
db.close()
return
def user_login_verify(self,email,password):
db = self.connection()
mycursor=db.cursor()
sq="select
first_name,email,last_name,mobile,twitter,facebook,instagram,linkdin,photo,budg
et from user where email=%s and password=%s"
record=[email,password]
mycursor.execute(sq,record)
row = mycursor.fetchall()
r=mycursor.rowcount
mycursor.close()
db.close()
if(r==0):
return 0
else:
for rec in row:
session['first_name']=rec[0] #retriving records from sql as per above array
sequence
session['user_email']=rec[1]
session['last_name']=rec[2]
session['mobile']=rec[3]
session['twitter']=rec[4]
session['facebook']=rec[5]
session['instagram']=rec[6]
session['linkdin']=rec[7]
session['photo']=rec[8]
session['budget']=rec[9]
88
return 1
def user_profile(self):
db = self.connection()
mycursor = db.cursor()
sq ="select first_name,last_name,email,mobile,photo from user where
email=%s"
record=[session['user_email']]
mycursor.execute(sq,record)
r = mycursor.fetchall()
mycursor.close()
db.close()
return r
def user_password_change(self,oldpassword,newpassword):
db = self.connection()
mycursor = db.cursor()
sq="select password from user where password=%s and email=%s"
record=[oldpassword,session['user_email']]
mycursor.execute(sq,record)
row = mycursor.fetchall()
rc = mycursor.rowcount
if(rc==0):
return 0
else:
sq="update user set password=%s where email=%s"
record=[newpassword,session['user_email']]
mycursor.execute(sq,record)
db.commit()
mycursor.close()
db.close()
89
return 1
def lpg_cylinder_insert(self,end_date,remarks):
db = self.connection() #con
mycursor=db.cursor()
sq="insert into lpg_cylinder(email,end_date,remarks)values(%s,%s,%s)"
record=[session['user_email'],end_date,remarks]
mycursor.execute(sq,record) # essential for every data connection
db.commit()
sq ="select lpg_id from lpg_cylinder order by lpg_id desc limit 1"
mycursor.execute(sq)
row = mycursor.fetchall()
mycursor.close()
db.close()
return row
def recent_lpg_cylinder(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT start_date,end_date,remarks,DATEDIFF(end_date, start_date)
AS life_span FROM lpg_cylinder where email=%s order by lpg_id desc limit 5"
record=[session['user_email']]
mycursor.execute(sq,record)
l = mycursor.fetchall() # "i" will store array value fetched by above query
mycursor.close()
db.close()
return l
def
profile_update_insert(self,first_name,last_name,mobile,twitter,facebook,instagra
m,linkdin):
db = self.connection()
mycursor = db.cursor()
91
def profile_photo_insert(self,photo_name):
db = self.connection()
mycursor = db.cursor()
sq ="update user set photo=%s where email=%s"
record=[photo_name,session['user_email']]
mycursor.execute(sq,record)
db.commit()
mycursor.close()
db.close()
session['photo']=photo_name
return
def user_password_change(self,oldpassword,newpassword):
db = self.connection()
92
mycursor = db.cursor()
sq="select password from user where password=%s and email=%s"
record=[oldpassword,session['user_email']]
mycursor.execute(sq,record)
row = mycursor.fetchall()
rc = mycursor.rowcount
if(rc==0):
return 0
else:
sq="update user set password=%s where email=%s"
record=[newpassword,session['user_email']]
mycursor.execute(sq,record)
db.commit()
mycursor.close()
db.close()
return 1
def total_income(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT sum(amount) FROM income where email=%s"
record=[session['user_email']]
mycursor.execute(sq,record)
r = mycursor.fetchall()
mycursor.close()
db.close()
return r
def total_expense(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT sum(amount) FROM expense where email=%s"
record=[session['user_email']]
93
mycursor.execute(sq,record)
e = mycursor.fetchall()
mycursor.close()
db.close()
return e
def recent_expense(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT date,category,item,amount FROM expense where email=%s
order by expenditure_id desc limit 5"
record=[session['user_email']]
mycursor.execute(sq,record)
a = mycursor.fetchall() # "a" will store array value fetched by above query
mycursor.close()
db.close()
return a
def recent_income(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT date,source,amount,remarks FROM income where email=%s
order by income_id desc limit 5"
record=[session['user_email']]
mycursor.execute(sq,record)
i = mycursor.fetchall() # "i" will store array value fetched by above query
mycursor.close()
db.close()
return i
def all_income(self):
db = self.connection()
94
mycursor = db.cursor()
sq = "SELECT date,source,amount,remarks,income_id FROM income where
email=%s order by income_id desc"
record=[session['user_email']]
mycursor.execute(sq,record)
i = mycursor.fetchall() # "i" will store array value fetched by above query
mycursor.close()
db.close()
return i
def all_expense(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT date,category,item,amount FROM expense where email=%s
order by expenditure_id desc"
record=[session['user_email']]
mycursor.execute(sq,record)
all = mycursor.fetchall() # "a" will store array value fetched by above query
mycursor.close()
db.close()
return all
def most_expense(self):
db = self.connection()
mycursor = db.cursor()
sq = "SELECT category,count(*),sum(amount) FROM expense where
email=%s GROUP BY category ORDER BY sum(amount) DESC"
record=[session['user_email']]
mycursor.execute(sq,record)
m = mycursor.fetchall() # "a" will store array value fetched by above query
mycursor.close()
95
db.close()
return m
def add_budget_insert(self,budget):
db = self.connection()
mycursor=db.cursor()
sq ="update user set budget=%s where email=%s"
record=[budget ,session['user_email']]
mycursor.execute(sq,record)
db.commit()
mycursor.close()
db.close()
session['budget']=budget
return
96
14.INDEX.CSS
html {
overflow-x: hidden;
}
body {
font-family: "Roboto", sans-serif;
color: #9fa1a4;
line-height: 1.5;
}
a{
color: #777;
text-decoration: none;
transition: 0.3s all ease;
}
a:hover {
color: #000;
}
h1,h2,h3,h4,h5,h6,.font-heading
{
font-family: "Poppins", sans-serif;
color: #000;
}
.container
{
z-index: 2;
97
position: relative;
}
.text-black {
color: #000 !important;
}
.text-primary {
color: #2d71a1 !important;
}
.border-top {
border-top: 1px solid #f2f2f2 !important;
}
.border-bottom {
border-bottom: 1px solid #f2f2f2 !important;
}
figure figcaption {
margin-top: 0.5rem;
font-style: italic;
font-size: 0.8rem;
}
section {
overflow: hidden;
}
.section {
padding: 7rem 0;
}
98
.section-heading {
font-size: 3rem;
font-weight: 700;
background: linear-gradient(-45deg, #3db3c5, #274685);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
# Back to top button
.back-to-top {
position: fixed;
visibility: hidden;
opacity: 0;
right: 15px;
bottom: 15px;
z-index: 996;
background: #2d71a1;
width: 40px;
height: 40px;
border-radius: 50px;
transition: all 0.4s;
}
.back-to-top i {
font-size: 28px;
color: #fff;
line-height: 0;
}
.back-to-top:hover {
background: #3687c1;
color: #fff;
}
99
.back-to-top.active {
visibility: visible;
opacity: 1;
}
/* Default btn sre-tyling */
.btn {
border: none;
padding: 15px 30px !important;
}
.btn.btn-outline-white {
border: 2px solid #fff;
background: none;
color: #fff;
}
.btn.btn-outline-white:hover {
background: #fff;
color: #2d71a1;
}
.btn.btn-primary {
background: #2d71a1;
background: linear-gradient(-45deg, #1391a5, #274685);
color: #fff;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.15);
}
/* Feature 1 */
.feature-1 .wrap-icon {
margin: 0 auto;
height: 100px;
width: 100px;
border-radius: 50%;
position: relative;
margin-bottom: 30px;
100
text-align: center;
left: 0;
}
.pricing .price-cta .price {
display: block;
margin-bottom: 20px;
font-size: 2rem;
font-weight: 300;
}
.pricing .popularity {
text-transform: uppercase;
font-size: 12px;
letter-spacing: 0.2rem;
display: block;
margin-bottom: 20px;
}
.pricing ul {
margin-bottom: 50px;
}.pricing ul li {
margin-bottom: 10px;
}
.pricing .btn-white {
background: #fff;
border: 2px solid rgb(241, 241, 241);
border-radius: 4px;
box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.1);
}
.pricing .btn-white:hover {
color: #2d71a1;
}
.pricing.popular {
background: #fff;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.2);
103
color: #000000;
background: linear-gradient(-45deg, #1391a5, #274685);
color: #fff;
box-shadow: none;
}
.pricing.popular .popularity {
color: #b3b3b3;
}.pricing.popular h3 {
color: #fff;
background: none;
}
.pricing.popular .btn-white {
border: 2px solid #2d71a1;
}
/* CTA Section */
.cta-section {
background: linear-gradient(to right, rgb(39, 70, 133) 0%, rgb(61, 179, 197)
100%);
color: #fff;
}
.cta-section h2 {
color: #fff;
font-size: 3rem;
font-weight: 700;
}
@media screen and (max-width: 768px) {
.cta-section h2 {
font-size: 2rem;
}
}
.cta-section .btn {
background: #000000;
color: #fff;
104
}
.cta-section .btn i
{
margin-right: 5px;
font-size: 24px;
line-height: 0;
}
/* Contact Form */
.form-control {
height: 48px;
border-radius: 0;
border: 1px solid #dae0e5;
}
.form-control:active,
.form-control:focus {
outline: none;
box-shadow: none;
border: 1px solid #2d71a1;
}
.php-email-form .validate {
display: none;
color: red;
margin: 0 0 15px 0;
font-weight: 400;
font-size: 13px;
}
.php-email-form .error-message {
display: none;
color: #fff;
105
background: #ed3c0d;
text-align: left;
padding: 15px;
font-weight: 600;
}
.php-email-form .sent-message {
display: none;
color: #fff;
background: #18d26e;
text-align: center;
padding: 15px;
font-weight: 600;
}
.php-email-form .loading {
display: none;
background: #fff;
text-align: center;
padding: 15px;
}
.php-email-form .loading:before {
content: "";
display: inline-block;
border-radius: 50%;
width: 24px;
height: 24px;
margin: 0 10px -6px 0;
106
.php-email-form textarea {
min-height: 160px;
}
@keyframes animate-loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Blog */
.post-entry {
margin-bottom: 60px;
}
.post-entry .post-text h3 {
107
font-size: 20px;
color: #000000;
}
.post-entry .post-text h3 a {
text-decoration: none;
color: #000000;
}
.sidebar-box {
margin-bottom: 30px;
padding: 25px;
font-size: 15px;
width: 100%;
float: left;
background: #fff;
}
.sidebar-box *:last-child {
margin-bottom: 0;
}
.sidebar-box h3 {
font-size: 18px;
108
margin-bottom: 15px;
}
.categories li,
.sidelink li {
position: relative;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px dotted gray("300");
list-style: none;
}
.categories li:last-child,
.sidelink li:last-child {
margin-bottom: 0;
border-bottom: none;
padding-bottom: 0;
}
.categories li a,
.sidelink li a {
text-decoration: none;
display: block;
}
.categories li a span,
.sidelink li a span {
position: absolute;
right: 0;
top: 0;
color: #ccc;
}
109
.categories li.active a,
.sidelink li.active a {
text-decoration: none;
color: #000000;
font-style: italic;
}
.comment-form-wrap {
clear: both;
}
.comment-list {
padding: 0;
margin: 0;
}
.comment-list .children {
padding: 50px 0 0 40px;
margin: 0;
float: left;
width: 100%;
}
.comment-list li {
padding: 0;
margin: 0 0 30px 0;
float: left;
width: 100%;
clear: both;
list-style: none;
}
.comment-list li .vcard {
110
width: 80px;
float: left;
}
.comment-list li .comment-body {
float: right;
width: calc(100% - 80px);
}
.comment-list li .comment-body h3 {
font-size: 20px;
}
.search-form {
background: #f7f7f7;
padding: 10px;
}
.search-form .form-group {
position: relative;
}
.search-form .icon {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
……………..# Header…………….
#header {
height: 80px;
transition: all 0.5s;
z-index: 997;
transition: all 0.5s;
}
112
#header.header-scrolled {
background: rgba(39, 70, 133, 0.8);
height: 60px;
}
#header .logo h1 {
font-size: 28px;
margin: 0;
padding: 4px 0;
line-height: 1;
font-weight: 500;
}
#header .logo h1 a,
#header .logo h1 a:hover {
color: #fff;
text-decoration: none;
}
.navbar ul {
margin: 0;
113
padding: 0;
display: flex;
list-style: none;
align-items: center;
}
.navbar a,
.navbar a:focus {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 0 10px 30px;
font-size: 16px;
font-weight: 400;
color: rgba(255, 255, 255, 0.65);
white-space: nowrap;
transition: 0.3s;
}
.navbar a i,
.navbar a:focus i {
font-size: 12px;
line-height: 0;
margin-left: 5px;
}
.navbar a:hover,
.navbar .active,
.navbar .active:focus,
.navbar li:hover>a {
color: #fcfafa;
}
114
.navbar .dropdown ul {
display: block;
position: absolute;
left: 14px;
top: calc(100% + 30px);
margin: 0;
padding: 10px 0;
z-index: 99;
opacity: 0;
visibility: hidden;
background: #fff;
box-shadow: 0px 0px 30px rgba(127, 137, 161, 0.25);
transition: 0.3s;
border-radius: 4px;
}
.navbar .dropdown ul li {
min-width: 200px;
}
.navbar .dropdown ul a {
padding: 10px 20px;
font-size: 15px;
color: #101c36;
}
.navbar .dropdown ul a i {
font-size: 12px;
}
color: #10acdb;
}
.navbar .dropdown:hover>ul {
opacity: 1;
top: 100%;
visibility: visible;
}
/**
116
* Mobile Navigation
*/
.mobile-nav-toggle {
color: #fff;
font-size: 28px;
cursor: pointer;
display: none;
line-height: 0;
transition: 0.5s;
}
.navbar ul {
display: none;
}
}
.navbar-mobile {
position: fixed;
overflow: hidden;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(27, 49, 94, 0.9);
transition: 0.3s;
z-index: 999;
}
117
.navbar-mobile .mobile-nav-toggle {
position: absolute;
top: 15px;
right: 15px;
}
.navbar-mobile ul {
display: block;
position: absolute;
top: 55px;
right: 15px;
bottom: 15px;
left: 15px;
padding: 10px 0;
border-radius: 10px;
background-color: #fff;
overflow-y: auto;
transition: 0.3s;
}
.navbar-mobile a,
.navbar-mobile a:focus {
padding: 10px 20px;
font-size: 15px;
color: #101c36;
}
.navbar-mobile a:hover,
.navbar-mobile .active,
.navbar-mobile li:hover>a {
color: #2d71a1;
}
118
.navbar-mobile .dropdown ul {
position: static;
display: none;
margin: 10px 20px;
padding: 10px 0;
z-index: 99;
opacity: 1;
visibility: visible;
background: #fff;
box-shadow: 0px 0px 30px rgba(127, 137, 161, 0.25);
}
.navbar-mobile .dropdown ul li {
min-width: 200px;
}
.navbar-mobile .dropdown ul a {
padding: 10px 20px;
}
.navbar-mobile .dropdown ul a i {
font-size: 12px;
}
.navbar-mobile .dropdown ul a:hover,
.navbar-mobile .dropdown ul .active:hover,
.navbar-mobile .dropdown ul li:hover>a {
color: #2d71a1;
}
.navbar-mobile .dropdown>.dropdown-active {
display: block;
}
.hero-section {
background: linear-gradient(to right, rgba(39, 70, 133, 0.8) 0%, rgba(61,
179, 197, 0.8) 100%), url(../img/hero-bg.jpg);
119
position: relative;
}
.hero-section .wave {
width: 100%;
overflow: hidden;
position: absolute;
z-index: 1;
bottom: -150px;
}
.hero-section.inner-page .hero-text {
transform: translateY(-150px);
margin-top: -120px;
}
120
.hero-section p {
font-size: 18px;
color: #fff;
}
.hero-section .iphone-wrap {
position: relative;
}
@media screen and (max-width: 992px) {
.hero-section .iphone-wrap {
121
text-align: center;
}
}
.hero-section .iphone-wrap .phone-2,
.hero-section .iphone-wrap .phone-1 {
position: absolute;
top: -50%;
overflow: hidden;
left: 0;
box-shadow: 0 15px 50px 0 rgba(0, 0, 0, 0.3);
border-radius: 30px;
}
@media screen and (max-width: 992px) {
margin-left: 100px;
width: 250px;
}
@media screen and (max-width: 992px) {
.hero-section .iphone-wrap .phone-2 {
width: 250px;
position: absolute;
margin-top: 0px;
margin-left: 100px;
}
}
# Footer
.footer {
padding: 5rem 0 2.5rem 0;
}
.footer h3 {
font-size: 18px;
margin-bottom: 30px;
}
.footer ul li {
margin-bottom: 10px;
}
.footer a {
color: #000;
}
.footer .copyright {
margin-bottom: 0px;
}
.footer .copyright,
.footer .credits {
font-size: 14px;
}
.social a {
123
display: inline-block;
width: 50px;
height: 50px;
border-radius: 50%;
background: #f8f9fa;
position: relative;
text-align: center;
transition: 0.3s background ease;
color: #0d1e2d;
line-height: 0;
}
.social a span {
display: inline-block;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
.social a:hover {
color: #fff;
background: #2d71a1;
}
.social a i {
line-height: 0;
}
124
15.STYLE.CSS
# General
--------------------------------------------------------------*/
:root {
scroll-behavior: smooth;
}
body {
font-family: "Open Sans", sans-serif;
background: #f6f9ff;
color: #444444;
}
a{
color: #4154f1;
text-decoration: none;
}
a:hover {
color: #717ff5;
text-decoration: none;
}
h1,h2,h3,h4,h5,h6 {
font-family: "Nunito", sans-serif;
}
# Main
---------------------------------------------------
#main {
125
margin-top: 60px;
padding: 20px 30px;
transition: all 0.3s;
}
/*--------------------------------------------------------------
# Page Title
--------------------------------------------------------------*/
.pagetitle {
margin-bottom: 10px;
}
.pagetitle h1 {
font-size: 24px;
margin-bottom: 0;
font-weight: 600;
color: #012970;
}
/*--------------------------------------------------------------
# Override some default Bootstrap stylings
--------------------------------------------------------------*/
/* Dropdown menus */
.dropdown-menu {
border-radius: 4px;
padding: 10px 0;
animation-name: dropdown-animate;
animation-duration: 0.2s;
126
animation-fill-mode: both;
border: 0;
box-shadow: 0 5px 30px 0 rgba(82, 63, 105, 0.2);
}
.dropdown-menu .dropdown-header,
.dropdown-menu .dropdown-footer {
text-align: center;
font-size: 15px;
padding: 10px 25px;
}
.dropdown-menu .dropdown-footer a {
color: #444444;
text-decoration: underline;
}
.dropdown-menu .dropdown-divider {
color: #a5c5fe;
margin: 0;
}
.dropdown-menu .dropdown-item {
font-size: 14px;
padding: 10px 15px;
transition: 0.3s;
}
.dropdown-menu .dropdown-item i {
127
margin-right: 10px;
font-size: 18px;
line-height: 0;
}
.dropdown-menu .dropdown-item:hover {
background-color: #f6f9ff;
}
@keyframes dropdown-animate {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
128
0% {
opacity: 0;
}
}
/* Light Backgrounds */
.bg-primary-light {
background-color: #cfe2ff;
border-color: #cfe2ff;
}
.bg-secondary-light {
background-color: #e2e3e5;
border-color: #e2e3e5;
}
.bg-success-light {
background-color: #d1e7dd;
border-color: #d1e7dd;
}
.bg-danger-light {
background-color: #f8d7da;
border-color: #f8d7da;
}
.bg-warning-light {
background-color: #fff3cd;
border-color: #fff3cd;
}
.bg-info-light {
background-color: #cff4fc;
129
border-color: #cff4fc;
}
.bg-dark-light {
background-color: #d3d3d4;
border-color: #d3d3d4;
}
/* Card */
.card {
margin-bottom: 30px;
border: none;
border-radius: 5px;
box-shadow: 0px 0 30px rgba(1, 41, 112, 0.1);
}
.card-header,
.card-footer {
border-color: #ebeef4;
background-color: #fff;
color: #798eb3;
padding: 15px;
}
.card-title {
padding: 20px 0 15px 0;
font-size: 18px;
font-weight: 500;
color: #012970;
font-family: "Poppins", sans-serif;
}
.card-title span {
130
color: #899bbd;
font-size: 14px;
font-weight: 400;
}
.card-body {
padding: 0 20px 20px 20px;
}
.card-img-overlay {
background-color: rgba(255, 255, 255, 0.6);
}
/* Alerts */
.alert-heading {
font-weight: 500;
font-family: "Poppins", sans-serif;
font-size: 20px;
}
/* Close Button */
.btn-close {
background-size: 25%;
}
.btn-close:focus {
outline: 0;
box-shadow: none;
}
/* Accordion */
.accordion-item {
border: 1px solid #ebeef4;
131
.accordion-button:focus {
outline: 0;
box-shadow: none;
}
.accordion-button:not(.collapsed) {
color: #012970;
background-color: #f6f9ff;
}
.accordion-flush .accordion-button {
padding: 15px 0;
background: none;
border: 0;
}
.accordion-flush .accordion-button:not(.collapsed) {
box-shadow: none;
color: #4154f1;
}
.accordion-flush .accordion-body {
padding: 0 0 15px 0;
color: #3e4f6f;
font-size: 15px;
}
/* Breadcrumbs */
.breadcrumb {
font-size: 14px;
font-family: "Nunito", sans-serif;
132
color: #899bbd;
font-weight: 600;
}
.breadcrumb a {
color: #899bbd;
transition: 0.3s;
}
.breadcrumb a:hover {
color: #51678f;
}
.breadcrumb .breadcrumb-item::before {
color: #899bbd;
}
.breadcrumb .active {
color: #51678f;
font-weight: 600;
}
/* Bordered Tabs */
.nav-tabs-bordered {
border-bottom: 2px solid #ebeef4;
}
.nav-tabs-bordered .nav-link {
margin-bottom: -2px;
border: none;
color: #2c384e;
}
133
.nav-tabs-bordered .nav-link:hover,
.nav-tabs-bordered .nav-link:focus {
color: #4154f1;
}
.nav-tabs-bordered .nav-link.active {
background-color: #fff;
color: #4154f1;
border-bottom: 2px solid #4154f1;
}
/*--------------------------------------------------------------
# Header
--------------------------------------------------------------*/
.logo {
line-height: 1;
}
.logo img {
max-height: 26px;
margin-right: 6px;
}
.logo span {
font-size: 26px;
font-weight: 700;
color: #012970;
134
.header {
transition: all 0.5s;
z-index: 997;
height: 60px;
box-shadow: 0px 2px 20px rgba(1, 41, 112, 0.1);
background-color: #fff;
padding-left: 20px;
/* Toggle Sidebar Button */
/* Search Bar */
}
.header .toggle-sidebar-btn {
font-size: 32px;
padding-left: 10px;
cursor: pointer;
color: #012970;
}
.header .search-bar {
min-width: 360px;
padding: 0 20px;
}
.header .search-bar-show {
top: 60px;
visibility: visible;
opacity: 1;
}
}
.header .search-form {
width: 100%;
}
/*--------------------------------------------------------------
# Header Nav
--------------------------------------------------------------*/
.header-nav ul {
list-style: none;
}
.header-nav>ul {
margin: 0;
padding: 0;
}
.header-nav .nav-icon {
font-size: 22px;
color: #012970;
margin-right: 25px;
position: relative;
}
137
.header-nav .nav-profile {
color: #012970;
}
.header-nav .badge-number {
position: absolute;
inset: -2px -5px auto auto;
font-weight: normal;
font-size: 12px;
padding: 3px 6px;
}
.header-nav .notifications {
inset: 8px -15px auto auto !important;
}
.header-nav .messages {
inset: 8px -15px auto auto !important;
}
.header-nav .profile {
min-width: 240px;
padding-bottom: 0;
top: 8px !important;
}
color: #444444;
}
/*--------------------------------------------------------------
# Sidebar
--------------------------------------------------------------*/
.sidebar {
position: fixed;
top: 60px;
left: 0;
bottom: 0;
width: 300px;
z-index: 996;
141
.sidebar::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #fff;
}
.sidebar::-webkit-scrollbar-thumb {
background-color: #aab7cf;
}
#main,
#footer {
margin-left: 300px;
}
}
142
.toggle-sidebar #main,
.toggle-sidebar #footer {
margin-left: 0;
}
.toggle-sidebar .sidebar {
left: -300px;
}
}
.sidebar-nav {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav li {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-item {
margin-bottom: 5px;
}
143
.sidebar-nav .nav-heading {
font-size: 11px;
text-transform: uppercase;
color: #899bbd;
font-weight: 600;
margin: 10px 0 5px 15px;
}
.sidebar-nav .nav-link {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 600;
color: #4154f1;
transition: 0.3;
background: #f6f9ff;
padding: 10px 15px;
border-radius: 4px;
}
.sidebar-nav .nav-link i {
font-size: 16px;
margin-right: 10px;
color: #4154f1;
}
.sidebar-nav .nav-link.collapsed {
color: #012970;
background: #fff;
}
.sidebar-nav .nav-link.collapsed i {
144
color: #899bbd;
}
.sidebar-nav .nav-link:hover {
color: #4154f1;
background: #f6f9ff;
}
.sidebar-nav .nav-link:hover i {
color: #4154f1;
}
.sidebar-nav .nav-content {
padding: 5px 0 0 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-content a {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 600;
color: #012970;
145
transition: 0.3;
padding: 10px 0 10px 40px;
transition: 0.3s;
}
.sidebar-nav .nav-content a i {
font-size: 6px;
margin-right: 8px;
line-height: 0;
border-radius: 50%;
}
/*--------------------------------------------------------------
# Dashboard
--------------------------------------------------------------*/
/* Filter dropdown */
.dashboard .filter {
position: absolute;
right: 0px;
top: 15px;
}
padding-right: 20px;
padding-bottom: 5px;
transition: 0.3s;
font-size: 16px;
}
/* Info Cards */
.dashboard .info-card {
padding-bottom: 10px;
}
147
.dashboard .info-card h6 {
font-size: 28px;
color: #012970;
font-weight: 700;
margin: 0;
padding: 0;
}
.dashboard .card-icon {
font-size: 32px;
line-height: 0;
width: 64px;
height: 64px;
flex-shrink: 0;
flex-grow: 0;
}
/* Activity */
.dashboard .activity {
font-size: 14px;
}
.dashboard .news h4 {
font-size: 15px;
margin-left: 95px;
font-weight: bold;
margin-bottom: 5px;
}
.dashboard .news h4 a {
150
color: #012970;
transition: 0.3s;
}
.dashboard .news h4 a:hover {
color: #4154f1;
}
.dashboard .news p {
font-size: 14px;
color: #777777;
margin-left: 95px;
}
/* Recent Sales */
.dashboard .recent-sales {
font-size: 14px;
}
.dashboard .recent-sales .table thead {
background: #f6f6fe;
}
.dashboard .recent-sales .table thead th {
border: 0;
}
.dashboard .recent-sales .dataTable-top {
padding: 0 0 10px 0;
}
.dashboard .recent-sales .dataTable-bottom {
padding: 10px 0 0 0;
}
/* Top Selling */
.dashboard .top-selling {
font-size: 14px;
}
151
FUTURE SCOPE
The future scope of expense tracking and management systems is promising, driven by
ongoing advancements in technology and the increasing need for efficient financial
management. Some potential developments and future applications for expense tracking
systems are :
3. Blockchain Integration:
Blockchain technology offers enhanced security, transparency, and immutability of data.
By integrating blockchain, expense tracking systems can provide a tamper-proof audit
trail of financial transactions, increasing trust and reliability for both individuals and
businesses.
CONCLUSION
Expense analysis and reporting features provide valuable insights into spending patterns,
enabling users to make data-driven decisions, optimize their financial resources, and
allocate funds efficiently. By setting financial goals and monitoring progress, users stay
motivated and focused on achieving their objectives, whether it's saving for a vacation,
paying off debt, or investing in a business venture.
For businesses, expense tracking systems streamline the reimbursement process, simplify
financial reporting, and enhance financial transparency and control within the organization.
Integrations with other financial tools and platforms reduce manual data entry, enhance
data accuracy, and facilitate collaboration among different stakeholders.
Despite the advantages, manual expense tracking systems or traditional methods also come
with significant disadvantages. They are time-consuming, prone to human errors, lack real-
time visibility, offer limited reporting capabilities, and can be challenging to retrieve and
store expense records efficiently. Additionally, manual systems may struggle to scale with
increased volumes of expenses and pose security risks to sensitive financial data.
155
Overall, expense tracking systems play a crucial role in personal and business financial
management. They serve as powerful tools that empower users with financial awareness,
budget management, goal setting, and financial optimization. By adopting automated
expense tracking systems, individuals and businesses can harness the advantages of
technology to streamline their financial processes, achieve better financial control, and
work towards long-term financial stability and success.
156
BIBLIOGRAPHY
Website: -
• https://stackoverflow.com/
• https://flask.palletsprojects.com/en/2.3.x/
• https://www.w3schools.com/python/default.asp
• https://bootstrapmade.com/
• https://www.youtube.com/
Books: -
• Programming with Python for Dummies - by John Paul Mueller
• Fundamentals of Database Systems "Ramez Elmasri", Pearson
Education
• Alex Martelli- PYTHON IN A NUTSHELL,2ND Edition, O’REILLY