minor: add payment

Admins can now add payments for their users.
This commit is contained in:
Lunaresk 2023-05-28 09:07:54 +02:00
parent 597725f46c
commit b21284f640
17 changed files with 121 additions and 15 deletions

1
.gitignore vendored
View File

@ -348,3 +348,4 @@ test.*
.flaskenv* .flaskenv*
!.env.project !.env.project
!.env.vault !.env.vault
*.ps1

View File

@ -0,0 +1,38 @@
"""Delete unnecessary columns
Revision ID: 4fec22c35530
Revises: 610854a6e2a0
Create Date: 2023-05-28 08:10:27.689070
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4fec22c35530'
down_revision = '610854a6e2a0'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('bought', schema=None) as batch_op:
batch_op.drop_column('registered')
with op.batch_alter_table('login_token', schema=None) as batch_op:
batch_op.drop_column('paid')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('login_token', schema=None) as batch_op:
batch_op.add_column(sa.Column('paid', sa.BIGINT(), server_default=sa.text("'0'::bigint"), autoincrement=False, nullable=False))
with op.batch_alter_table('bought', schema=None) as batch_op:
batch_op.add_column(sa.Column('registered', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -26,7 +26,7 @@ def upgrade():
sa.PrimaryKeyConstraint('user', 'establishment') sa.PrimaryKeyConstraint('user', 'establishment')
) )
op.create_table('payment', op.create_table('payment',
sa.Column('id', sa.BigInteger(), nullable=False), sa.Column('id', sa.BigInteger(), nullable=False, autoincrement=True),
sa.Column('token', sa.String(length=15), nullable=False), sa.Column('token', sa.String(length=15), nullable=False),
sa.Column('date', sa.Date(), server_default=sa.text('now()'), nullable=False), sa.Column('date', sa.Date(), server_default=sa.text('now()'), nullable=False),
sa.Column('amount', sa.BigInteger(), server_default='0', nullable=False), sa.Column('amount', sa.BigInteger(), server_default='0', nullable=False),

View File

@ -1,11 +1,13 @@
from flask import Blueprint from flask import Blueprint
bp = Blueprint('establishment', __name__, url_prefix='/establishment') bp = Blueprint('establishment', __name__, url_prefix='/establishment')
from src.establishment.new import bp as bp_new
bp.register_blueprint(bp_new)
from src.establishment.list import bp as bp_list
bp.register_blueprint(bp_list)
from src.establishment.overview import bp as bp_overview
bp.register_blueprint(bp_overview)
from src.establishment.candidates import bp as bp_candidates from src.establishment.candidates import bp as bp_candidates
bp.register_blueprint(bp_candidates) bp.register_blueprint(bp_candidates)
from src.establishment.list import bp as bp_list
bp.register_blueprint(bp_list)
from src.establishment.new import bp as bp_new
bp.register_blueprint(bp_new)
from src.establishment.overview import bp as bp_overview
bp.register_blueprint(bp_overview)
from src.establishment.payment import bp as bp_payment
bp.register_blueprint(bp_payment)

View File

@ -7,10 +7,10 @@ from src.models import Establishment
from src.utils import view_utils, database_utils from src.utils import view_utils, database_utils
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
@bp.route('/<establishment_id>', methods=['GET']) @bp.route('/<int:establishment_id>', methods=['GET'])
@login_required @login_required
def get_report_from_user(establishment_id): def get_report_from_user(establishment_id):
establishment = Establishment.query.filter_by(id=int(establishment_id)).first_or_404() Establishment.query.filter_by(id=int(establishment_id)).first_or_404()
if current_user.is_anonymous: if current_user.is_anonymous:
abort(403) abort(403)
if 'month' in request.args: if 'month' in request.args:

View File

@ -0,0 +1,5 @@
from flask import Blueprint
bp = Blueprint('payment', __name__, url_prefix='/payment')
from src.establishment.payment import routes

View File

@ -0,0 +1,17 @@
from src.models import LoginToken
from flask_wtf import FlaskForm
from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField
from wtforms.validators import DataRequired, Optional
class NewPaymentForm(FlaskForm):
token = SelectField("User", validators=[DataRequired()], render_kw={"class": "form-control"})
date = DateField("Date", validators=[DataRequired()], render_kw={"class": "form-control"})
amount = IntegerField("Amount (in ct)", validators=[DataRequired()], render_kw={"class": "form-control"})
submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"})
@classmethod
def new(cls, establishment_id):
form = cls()
tokens_for_establishment = LoginToken.query.filter_by(establishment=int(establishment_id)).order_by("user").all()
form.token.choices = [(t.token, t.User.email) for t in tokens_for_establishment]
return form

View File

@ -0,0 +1,24 @@
from flask import abort, redirect, url_for
from flask_login import current_user, login_required
from src import db, LOGGER
from src.establishment.payment import bp
from src.establishment.payment.forms import NewPaymentForm
from src.models import Establishment, Payment
from src.utils.routes_utils import render_custom_template as render_template
@bp.route('/<int:establishment_id>', methods=['GET', 'POST'])
@login_required
def insert_payment(establishment_id: int):
establishment = Establishment.query.get(int(establishment_id))
if current_user.is_anonymous or current_user.id != establishment.owner:
abort(403)
form = NewPaymentForm.new(establishment_id=establishment_id)
if form.validate_on_submit():
new_payment = Payment(token = form.token.data,
date = form.date.data,
amount = form.amount.data)
db.session.add(new_payment)
db.session.commit()
return redirect(url_for("main.index"))
return render_template('establishment/payment/new_payment.html', form=form)

View File

@ -1,5 +1,4 @@
from src.models.brand import Brand from src.models import Brand, Category
from src.models.category import Category
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField
from wtforms.validators import DataRequired, Optional from wtforms.validators import DataRequired, Optional

View File

@ -5,7 +5,6 @@ class Bought(db.Model):
item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue()) item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue())
date = db.Column(db.Date, primary_key=True) date = db.Column(db.Date, primary_key=True)
amount = db.Column(db.SmallInteger, nullable=False) amount = db.Column(db.SmallInteger, nullable=False)
registered = db.Column(db.Boolean, nullable=False, server_default=str(False))
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<Bought Object>" return f"<Bought Object>"

View File

@ -1,7 +1,7 @@
from src import db from src import db
class Payment(db.Model): class Payment(db.Model):
id = db.Column(db.BigInteger, primary_key=True) id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
token = db.Column(db.ForeignKey('login_token.token'), primary_key=True, server_onupdate=db.FetchedValue()) token = db.Column(db.ForeignKey('login_token.token'), primary_key=True, server_onupdate=db.FetchedValue())
date = db.Column(db.Date, nullable=False, server_default=db.func.now()) date = db.Column(db.Date, nullable=False, server_default=db.func.now())
amount = db.Column(db.BigInteger, nullable=False, server_default=str(0)) amount = db.Column(db.BigInteger, nullable=False, server_default=str(0))

View File

@ -4,8 +4,8 @@
{% if establishment %} {% if establishment %}
{% if current_user.id == establishment.owner %} {% if current_user.id == establishment.owner %}
<button type="button" class="btn btn-outline-dark px-2" data-bs-toggle="button" autocomplete="off" <button type="button" class="btn btn-outline-dark px-2" data-bs-toggle="button" autocomplete="off"
onclick="window.location.href='{{ url_for('establishment.overview.get_report_from_user', establishment_id=establishment.id) }}'"> onclick="window.location.href='{{ url_for('establishment.payment.insert_payment', establishment_id=establishment.id) }}'">
Abrechnung Zahlung hinzufügen
</button> </button>
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@ -0,0 +1,6 @@
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
{% include 'establishment/payment/new_payment_form.html' %}
{% endblock %}

View File

@ -0,0 +1,8 @@
{% from 'utils/form/_render_field.html' import render_field %}
<form action="" method="post">
{{ form.hidden_tag() }}
{{ render_field(form.token) }}
{{ render_field(form.date) }}
{{ render_field(form.amount) }}
{{ form.submit }}
</form>

View File

@ -1,6 +1,8 @@
#!/bin/bash #!/bin/bash
echo "Activating venv"
source venv/bin/activate source venv/bin/activate
cd backend cd backend
echo "Upgrading database"
for i in {0..5} for i in {0..5}
do do
flask db upgrade 2be4d1ae5493-1 flask db upgrade 2be4d1ae5493-1

View File

@ -8,6 +8,11 @@
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
</head> </head>
<body> <body>
<mat-sidenav-container>
<mat-sidenav>Start</mat-sidenav>
<mat-sidenav-content>
<app-root></app-root> <app-root></app-root>
</mat-sidenav-content>
</mat-sidenav-container>
</body> </body>
</html> </html>

Binary file not shown.