diff --git a/loans/forms.py b/loans/forms.py
index 87359a7..ba4648d 100644
--- a/loans/forms.py
+++ b/loans/forms.py
@@ -19,24 +19,17 @@ class AddForm(Form):
outstanding_balance = FloatField('outstanding_balance')
class EditForm(Form):
- first_name = StringField(
- 'first_name',
- validators=[DataRequired(), Length(min=3, max=25)]
- )
- last_name = StringField(
- 'last_name',
- validators=[DataRequired(), Length(min=3, max=25)]
- )
- number_shares = IntegerField('number_shares')
- email = StringField(
- 'email',
- validators=[DataRequired(), Email(message=None), Length(min=6, max=40)]
- )
- address = StringField(
- 'address',
- validators=[DataRequired(), Length(min=3, max=25)]
- )
- mobile_phone = StringField(
- 'mobile_phone',
- validators=[DataRequired(), Length(min=3, max=25)]
- )
\ No newline at end of file
+ customer_name = SelectField(u'Customers', coerce=int)
+
+ date_release = StringField(
+ 'date_release')
+ date_due = StringField(
+ 'date_release')
+ fully_paid_on = StringField(
+ 'fully_paid_on')
+ amount = FloatField('amount')
+ interest = SelectField(u'Interest', coerce=int)
+ total_payable = FloatField('total_payable')
+ payment = FloatField('payment')
+ total_payment = FloatField('total_payment')
+ outstanding_balance = FloatField('outstanding_balance')
\ No newline at end of file
diff --git a/loans/models.py b/loans/models.py
index 62c4af5..e765499 100644
--- a/loans/models.py
+++ b/loans/models.py
@@ -4,7 +4,6 @@ class Loan(db.Model):
__tablename__ = "loans"
id = db.Column(db.Integer, primary_key=True)
- customer_id = db.Column(db.Integer, db.ForeignKey("customers.id"))
amount = db.Column(db.Float, unique=False)
interest = db.Column(db.Float, unique=False)
payment = db.Column(db.Float, unique=False)
@@ -14,21 +13,19 @@ class Loan(db.Model):
fully_paid_on = db.Column(db.String(80))
date_release = db.Column(db.String(80))
date_due = db.Column(db.String(80))
- is_dormant = db.Column(db.Boolean)
- customer = db.relationship('Customer', backref='customers')
+ customer_id = db.Column(db.Integer, db.ForeignKey("customers.id"))
- def __init__(self, customer_id=0, amount=0, interest=0, payment=0, total_payable=0, total_payment=0, outstanding_balance=0, fully_paid_on=None, date_release=None, date_due=None, is_dormant=0):
- self.customer_id = customer_id
- self.amount = amount
- self.interest = interest
- self.payment = payment
- self.total_payable = total_payable
- self.total_payment = total_payment
- self.outstanding_balance = outstanding_balance
- self.fully_paid_on = fully_paid_on
- self.date_release = date_release
- self.date_due = date_due
- self.is_dormant = is_dormant
+ # def __init__(self, customer_id=0, amount=0, interest=0, payment=0, total_payable=0, total_payment=0, outstanding_balance=0, fully_paid_on=None, date_release=None, date_due=None):
+ # self.customer_id = customer_id
+ # self.amount = amount
+ # self.interest = interest
+ # self.payment = payment
+ # self.total_payable = total_payable
+ # self.total_payment = total_payment
+ # self.outstanding_balance = outstanding_balance
+ # self.fully_paid_on = fully_paid_on
+ # self.date_release = date_release
+ # self.date_due = date_due
class Interest(db.Model):
__tablename__ = "interest"
diff --git a/loans/templates/addloan.html b/loans/templates/addloan.html
index 24644e1..eed6635 100644
--- a/loans/templates/addloan.html
+++ b/loans/templates/addloan.html
@@ -28,7 +28,7 @@
- {{ form.customer_name(type="text", autofocus="True", class="form-control") }}
+ {{ render_field(form.customer_name, type="text", autofocus="True", class="form-control") }}
@@ -58,7 +58,7 @@
- {{ form.interest(type="text", class="form-control", style="width:75%;") }}
+ {{ render_field(form.interest, type="text", class="form-control", style="width:75%;") }}
diff --git a/loans/templates/editloan.html b/loans/templates/editloan.html
index 025e99c..b8d97e2 100644
--- a/loans/templates/editloan.html
+++ b/loans/templates/editloan.html
@@ -14,11 +14,11 @@
-
- List
+ List
{% if current_user.can_create: %}
-
- Create
+ Create
{% endif %}
{% if current_user.can_update: %}
@@ -27,13 +27,82 @@
{% endif %}
-
{% endblock %}
diff --git a/loans/templates/loans.html b/loans/templates/loans.html
index da68d64..8982166 100644
--- a/loans/templates/loans.html
+++ b/loans/templates/loans.html
@@ -13,7 +13,7 @@
{% block membercontent %}
-
- List ({{ query_loans.count() }})
+ List ({{ query_loans|length }})
{% if current_user.can_create: %}
-
@@ -36,23 +36,23 @@
- {% for loan, customer in query_loans: %}
+ {% for loan in query_loans: %}
{% if current_user.can_update or current_user.can_delete : %}
{% if current_user.can_update: %}
-
+
{% endif %}
{% if current_user.can_delete : %}
-
+
{% endif %}
|
{% endif %}
- {{ customer.name }} |
+ {{ loan.customer.name }} |
{{ loan.amount }} |
{{ loan.interest }} |
{{ loan.total_payable }} |
diff --git a/loans/views.py b/loans/views.py
index 9871902..5b8778f 100644
--- a/loans/views.py
+++ b/loans/views.py
@@ -1,6 +1,6 @@
from flask import Blueprint, render_template, abort, request, redirect, url_for, flash
from jinja2 import TemplateNotFound
-from flask_login import login_required
+from flask_login import login_required, current_user
from .forms import AddForm, EditForm
@@ -47,9 +47,7 @@ def get_list_order_by(field, sort_by):
def get_list(order_by):
from models import Loan
from coinage import db
- from customers.models import Customer
- return db.session.query(Loan, Customer).join(Customer).filter(Loan.customer_id == Customer.id).filter(
- Loan.is_dormant == 0).order_by(order_by)
+ return db.session.query(Loan).join(Loan.customer).order_by(order_by).all()
@loans_blueprint.route("/loans/new/", methods=['POST','GET'])
@login_required
@@ -58,10 +56,12 @@ def newloans():
from customers.models import Customer
from models import Interest, Loan
try:
+ if not current_user.can_create:
+ return redirect(url_for('loans.loans'))
form = AddForm(request.form)
- customer = Customer.query.with_entities(Customer.id, Customer.name).order_by(Customer.name)
+ _customer = Customer.query.with_entities(Customer.id, Customer.name).order_by(Customer.name)
interest = Interest.query.order_by(Interest.value)
- form.customer_name.choices = [(g.id, g.name) for g in customer]
+ form.customer_name.choices = [(g.id, g.name) for g in _customer]
form.interest.choices = [(g.value, g.name) for g in interest]
if request.method == 'GET':
form.payment.data = 0
@@ -78,7 +78,6 @@ def newloans():
loan.total_payment = form.total_payment.data
loan.outstanding_balance = form.outstanding_balance.data
loan.fully_paid_on = form.fully_paid_on.data
- loan.is_dormant = 0;
db.session.add(loan)
db.session.commit()
flash(u'Record was successfully created.', 'success')
@@ -89,12 +88,66 @@ def newloans():
abort(404)
-@loans_blueprint.route("/loans/edit//")
+@loans_blueprint.route("/loans/edit//", methods=['GET', 'POST'])
@login_required
def editloans(id):
- try:
- return render_template("editloan.html")
- except TemplateNotFound:
- abort(404)
+ from coinage import db
+ from models import Loan, Interest
+ from customers.models import Customer
+ if not current_user.can_update:
+ return redirect(url_for('loans.loans'))
+ form = EditForm(request.form)
+ loan = Loan.query.filter_by(id=id).first()
+ if loan is None:
+ flash(u'Cannot find loan.', 'danger')
+ return redirect(url_for('loans.loans'))
+ _customer = Customer.query.with_entities(Customer.id, Customer.name).order_by(Customer.name)
+ interest = Interest.query.order_by(Interest.value)
+ form.customer_name.choices = [(g.id, g.name) for g in _customer]
+ form.interest.choices = [(g.value, g.name) for g in interest]
+ if request.method == 'POST':
+ if form.validate_on_submit():
+ loan.customer_id = form.customer_name.data
+ loan.date_release = form.date_release.data
+ loan.amount = form.amount.data
+ loan.date_due = form.date_due.data
+ loan.interest = form.interest.data
+ loan.total_payable = form.total_payable.data
+ loan.payment = form.payment.data
+ loan.total_payment = form.total_payment.data
+ loan.outstanding_balance = form.outstanding_balance.data
+ loan.fully_paid_on = form.fully_paid_on.data
+ db.session.commit()
+ flash(u'Record successfully saved.', 'success')
+ return redirect(url_for('loans.loans'))
+ else:
+ form.customer_name.data = loan.customer_id
+ form.date_release.data = loan.date_release
+ form.amount.data = loan.amount
+ form.date_due.data = loan.date_due
+ form.interest.data = loan.interest
+ form.total_payable.data = loan.total_payable
+ form.payment.data = loan.payment
+ form.total_payment.data = loan.total_payment
+ form.outstanding_balance.data = loan.outstanding_balance
+ form.fully_paid_on.data = loan.fully_paid_on
+ return render_template("editloan.html", form=form)
+@loans_blueprint.route("/loans/delete/", methods=['POST']) # pragma: no cover)
+@login_required
+def deleteloan():
+ from coinage import db
+ from models import Loan
+ if not current_user.can_delete:
+ return redirect(url_for('loans.loans'))
+ id = request.form['id']
+ loan = Loan.query.filter_by(id=id).first()
+ if loan is None:
+ flash(u'Cannot find loan.', 'danger')
+ return redirect(url_for('loans.loans'))
+ else:
+ db.session.delete(loan)
+ db.session.commit()
+ flash(u'Record was successfully deleted.', 'success')
+ return redirect(url_for('loans.loans'))
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000..c6d5d19
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,11 @@
+from flask_script import Manager
+from flask_migrate import Migrate, MigrateCommand
+from coinage import app, db
+
+migrate = Migrate(app, db)
+
+manager = Manager(app)
+manager.add_command('db', MigrateCommand)
+
+if __name__ == '__main__':
+ manager.run()
diff --git a/alembic.ini b/migrations/alembic.ini
similarity index 52%
rename from alembic.ini
rename to migrations/alembic.ini
index 9d8d772..f8ed480 100644
--- a/alembic.ini
+++ b/migrations/alembic.ini
@@ -1,36 +1,13 @@
# A generic, single database configuration.
[alembic]
-# path to migration scripts
-script_location = migrations
-
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
-# max length of characters to apply to the
-# "slug" field
-#truncate_slug_length = 40
-
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
-# set to 'true' to allow .pyc and .pyo files without
-# a source .py file to be detected as revisions in the
-# versions/ directory
-# sourceless = false
-
-# version location specification; this defaults
-# to migrations/versions. When using multiple version
-# directories, initial revisions must be specified with --version-path
-# version_locations = %(here)s/bar %(here)s/bat migrations/versions
-
-# the output encoding used when revision files
-# are written from script.py.mako
-# output_encoding = utf-8
-
-#sqlalchemy.url = driver://user:pass@localhost/dbname
-
# Logging configuration
[loggers]
diff --git a/migrations/env.py b/migrations/env.py
index 31aeb34..70961ce 100644
--- a/migrations/env.py
+++ b/migrations/env.py
@@ -24,7 +24,6 @@
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
-
def run_migrations_offline():
"""Run migrations in 'offline' mode.
@@ -38,13 +37,11 @@ def run_migrations_offline():
"""
url = config.get_main_option("sqlalchemy.url")
- context.configure(
- url=url, target_metadata=target_metadata, literal_binds=True)
+ context.configure(url=url)
with context.begin_transaction():
context.run_migrations()
-
def run_migrations_online():
"""Run migrations in 'online' mode.
@@ -52,21 +49,25 @@ def run_migrations_online():
and associate a connection with the context.
"""
- connectable = engine_from_config(
- config.get_section(config.config_ini_section),
- prefix='sqlalchemy.',
- poolclass=pool.NullPool)
+ engine = engine_from_config(
+ config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool)
- with connectable.connect() as connection:
- context.configure(
- connection=connection,
- target_metadata=target_metadata
- )
+ connection = engine.connect()
+ context.configure(
+ connection=connection,
+ target_metadata=target_metadata
+ )
+ try:
with context.begin_transaction():
context.run_migrations()
+ finally:
+ connection.close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
+
diff --git a/migrations/script.py.mako b/migrations/script.py.mako
index 43c0940..9570201 100644
--- a/migrations/script.py.mako
+++ b/migrations/script.py.mako
@@ -1,7 +1,7 @@
"""${message}
Revision ID: ${up_revision}
-Revises: ${down_revision | comma,n}
+Revises: ${down_revision}
Create Date: ${create_date}
"""
@@ -9,8 +9,6 @@ Create Date: ${create_date}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
-branch_labels = ${repr(branch_labels)}
-depends_on = ${repr(depends_on)}
from alembic import op
import sqlalchemy as sa
diff --git a/migrations/versions/e1d572336c0_.py b/migrations/versions/e1d572336c0_.py
new file mode 100644
index 0000000..94d43c9
--- /dev/null
+++ b/migrations/versions/e1d572336c0_.py
@@ -0,0 +1,80 @@
+"""empty message
+
+Revision ID: e1d572336c0
+Revises: None
+Create Date: 2017-02-20 14:43:25.880000
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'e1d572336c0'
+down_revision = None
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+def upgrade():
+ ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('interest')
+ op.drop_table('loans')
+ op.drop_table('customers')
+ op.drop_table('users')
+ ### end Alembic commands ###
+
+
+def downgrade():
+ ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('users',
+ sa.Column('id', mysql.INTEGER(display_width=11), nullable=False),
+ sa.Column('name', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('email', mysql.VARCHAR(length=150), nullable=True),
+ sa.Column('password', mysql.VARCHAR(length=150), nullable=True),
+ sa.Column('can_create', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.Column('can_update', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.Column('can_delete', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.PrimaryKeyConstraint('id'),
+ mysql_default_charset=u'utf8',
+ mysql_engine=u'InnoDB'
+ )
+ op.create_table('customers',
+ sa.Column('id', mysql.INTEGER(display_width=11), nullable=False),
+ sa.Column('first_name', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('last_name', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('name', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('number_shares', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.Column('email', mysql.VARCHAR(length=150), nullable=True),
+ sa.Column('address', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('mobile_phone', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('is_dormant', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True),
+ sa.PrimaryKeyConstraint('id'),
+ mysql_default_charset=u'utf8',
+ mysql_engine=u'InnoDB'
+ )
+ op.create_table('loans',
+ sa.Column('id', mysql.INTEGER(display_width=11), nullable=False),
+ sa.Column('customer_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.Column('amount', mysql.FLOAT(), nullable=True),
+ sa.Column('interest', mysql.FLOAT(), nullable=True),
+ sa.Column('payment', mysql.FLOAT(), nullable=True),
+ sa.Column('total_payable', mysql.FLOAT(), nullable=True),
+ sa.Column('total_payment', mysql.FLOAT(), nullable=True),
+ sa.Column('outstanding_balance', mysql.FLOAT(), nullable=True),
+ sa.Column('fully_paid_on', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('date_release', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('date_due', mysql.VARCHAR(length=80), nullable=True),
+ sa.Column('is_dormant', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True),
+ sa.ForeignKeyConstraint(['customer_id'], [u'customers.id'], name=u'loans_ibfk_1'),
+ sa.PrimaryKeyConstraint('id'),
+ mysql_default_charset=u'utf8',
+ mysql_engine=u'InnoDB'
+ )
+ op.create_table('interest',
+ sa.Column('id', mysql.INTEGER(display_width=11), nullable=False),
+ sa.Column('value', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
+ sa.Column('name', mysql.VARCHAR(length=50), nullable=True),
+ sa.PrimaryKeyConstraint('id'),
+ mysql_default_charset=u'utf8',
+ mysql_engine=u'InnoDB'
+ )
+ ### end Alembic commands ###
diff --git a/static/js/formvalidator.js b/static/js/formvalidator.js
index 696fb8e..0e1fa34 100644
--- a/static/js/formvalidator.js
+++ b/static/js/formvalidator.js
@@ -180,6 +180,12 @@ $(document).ready(function(){
var id = $(this).data('id');
var name = $(this).data('name');
var url = $(this).data('url');
+ if(url === "/customers/delete/"){
+ $(".modal-body #instructions").text("Please be aware that deleting this customer would also delete all loans/contributions connected to it.");
+ }
+ else if(url === "/loans/delete/"){
+ name = name + " with loan amount of " + $(this).data('amount');
+ }
$(".modal-body #id").val(id);
$(".modal-body #name").text(" '" + name + "' ");
$(".modal-body #url").val(url);
diff --git a/users/models.py b/users/models.py
index 46fa420..0d558e4 100644
--- a/users/models.py
+++ b/users/models.py
@@ -11,19 +11,17 @@ class User(db.Model):
can_create = db.Column(db.Integer)
can_update = db.Column(db.Integer)
can_delete = db.Column(db.Integer)
- is_dormant = db.Column(db.Boolean)
- def __init__(self, can_create=0, can_update=0, can_delete=0, name=None, email=None, password=None, is_dormant=0):
- self.set_property(can_create, can_update, can_delete, name, email, password, is_dormant)
+ def __init__(self, can_create=0, can_update=0, can_delete=0, name=None, email=None, password=None):
+ self.set_property(can_create, can_update, can_delete, name, email, password)
- def set_property(self, can_create=0, can_update=0, can_delete=0, name=None, email=None, password=None, is_dormant=0):
+ def set_property(self, can_create=0, can_update=0, can_delete=0, name=None, email=None, password=None):
self.name = name
self.email = email
self.password = bcrypt.generate_password_hash(password)
self.can_create = can_create
self.can_update = can_update
self.can_delete = can_delete
- self.is_dormant = is_dormant
def is_authenticated(self):
return True
diff --git a/users/views.py b/users/views.py
index a6ed377..ac5d02e 100644
--- a/users/views.py
+++ b/users/views.py
@@ -12,7 +12,7 @@
def users():
from models import User
try:
- query_users = User.query.filter(User.name != current_user.name).filter(User.is_dormant == 0).order_by(User.name)
+ query_users = User.query.filter(User.name != current_user.name).order_by(User.name)
return render_template('users.html', query_users=query_users)
except TemplateNotFound:
abort(404)
@@ -24,7 +24,7 @@ def edituser(id):
from models import User
if not current_user.can_update:
return redirect(url_for('users.users'))
- user = User.query.filter(User.id==id).filter(User.is_dormant==0).first()
+ user = User.query.filter_by(id=id).first()
if user is None:
flash(u'Cannot find user.', 'danger')
return redirect(url_for('users.users'))
@@ -54,9 +54,9 @@ def deleteuser():
if not current_user.can_delete:
return redirect(url_for('users.users'))
id = request.form['id']
- user = User.query.filter(User.id==id).filter(User.is_dormant==0).first()
+ user = User.query.filter_by(id=id).first()
if not user is None:
- user.is_dormant = 1
+ db.session.delete(user)
db.session.commit()
flash(u'Record was successfully deleted.', 'success')
return redirect(url_for('users.users'))
@@ -74,7 +74,7 @@ def add():
form.can_update.data = 0
error = None
if form.validate_on_submit():
- user = User.query.filter(User.name==form.username.data.strip()).filter(User.is_dormant==0).first()
+ user = User.query.filter_by(name=form.username.data.strip()).first()
if user is None:
user = User(
name=form.username.data.strip(),