Local changes.
parent
bb78ab70b3
commit
6ef0abbe70
|
@ -76,7 +76,7 @@ class User(object):
|
|||
if not self.is_authenticated():
|
||||
return False
|
||||
if self._admin is None:
|
||||
r = requests.get('https://capacifier.hackerspace.pl/staff/'+
|
||||
r = requests.get('https://capacifier.hackerspace.pl/kasownik_access/'+
|
||||
self.username)
|
||||
self._admin = r.status_code == 200
|
||||
return self._admin
|
||||
|
|
|
@ -151,7 +151,7 @@ def api_member():
|
|||
transfer["from"] = mt.transfer.name_from
|
||||
t["transfer"] = transfer
|
||||
response["paid"].append(t)
|
||||
response["months_due"] = member.months_due()
|
||||
response["months_due"] = member.get_months_due()
|
||||
response["membership"] = member.type
|
||||
|
||||
return response
|
||||
|
@ -202,7 +202,7 @@ def api_months_due(membername):
|
|||
raise APIError("Stoned.",420)
|
||||
if year and member.active == False:
|
||||
raise APIError("No longer a member.", 410)
|
||||
due = member.months_due()
|
||||
due = member.get_months_due()
|
||||
#now = datetime.datetime.now()
|
||||
#then_timestamp = year * 12 + (month-1)
|
||||
#now_timestamp = now.year * 12 + (now.month-1)
|
||||
|
@ -222,7 +222,7 @@ def api_cashflow(year, month):
|
|||
month = 1
|
||||
year += 1
|
||||
end = datetime.date(year=year, month=month, day=1)
|
||||
transfers = models.Transfer.query.filter(and_(models.Transfer.date >= start, models.Transfer.date < end)).all()
|
||||
transfers = models.Transfer.query.filter(and_(models.Transfer.date >= start, models.Transfer.date < end, models.Transfer.ignore == False)).all()
|
||||
amount_in = sum(t.amount for t in transfers)
|
||||
mc.set(cache_key, amount_in)
|
||||
return {"in": amount_in/100, "out": -1}
|
||||
|
|
|
@ -67,6 +67,15 @@ class PaymentStatus(enum.Enum):
|
|||
unpaid = 2 # more than 3 fees unapid
|
||||
okay = 3 # fees paid
|
||||
|
||||
class PaymentPolicy(enum.Enum):
|
||||
normal = "Normal"
|
||||
extended = "Extended Grace Period"
|
||||
potato = "Potato"
|
||||
disabled = "Disabled"
|
||||
|
||||
class MembershipType(enum.Enum):
|
||||
fatty = "Fatty"
|
||||
starving = "Starving"
|
||||
|
||||
class Member(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
@ -83,10 +92,7 @@ class Member(db.Model):
|
|||
# Extended Grace Period - do not shut off account after grace period
|
||||
# Potato - do not ever shut off account, report falsified payment status
|
||||
# Disabled - manual disable override, regardless of payment extra
|
||||
payment_policy = db.Column(db.Enum('Normal',
|
||||
'Extended Grace Period',
|
||||
'Potato',
|
||||
'Disabled',
|
||||
payment_policy = db.Column(db.Enum(*[p.value for p in PaymentPolicy.__members__.values()],
|
||||
name='payment_policy_types'))
|
||||
preferred_email = db.Column(db.String(64))
|
||||
|
||||
|
@ -147,7 +153,7 @@ class Member(db.Model):
|
|||
status['payment_policy'] = self.payment_policy
|
||||
# First check - did we actually get any transfers?
|
||||
if not self.transfers or self.transfers[0].transfer.uid == app.config['DUMMY_TRANSFER_UID']:
|
||||
status['payment_status'] = PaymentStatus.never_paid
|
||||
status['payment_status'] = PaymentStatus.never_paid.value
|
||||
status['months_due'] = None
|
||||
status['last_paid'] = (None, None)
|
||||
if self.join_year is not None and self.join_month is not None:
|
||||
|
@ -214,7 +220,7 @@ class Member(db.Model):
|
|||
unpaid_months += (now - previous_scalar)
|
||||
|
||||
status['months_due'] = unpaid_months
|
||||
status['payment_status'] = PaymentStatus.okay if unpaid_months < 4 else PaymentStatus.unpaid
|
||||
status['payment_status'] = PaymentStatus.okay.value if unpaid_months < 4 else PaymentStatus.unpaid.value
|
||||
status['last_paid'] = most_recent_transfer
|
||||
status['left'] = not active_payment
|
||||
|
||||
|
@ -262,7 +268,7 @@ class Member(db.Model):
|
|||
return
|
||||
policy = status['payment_policy']
|
||||
if policy == 'Normal':
|
||||
if status['payment_status'] == PaymentStatus.okay and status['last_paid'][0] is not None:
|
||||
if status['payment_status'] == PaymentStatus.okay.value and status['last_paid'][0] is not None:
|
||||
status['judgement'] = True
|
||||
else:
|
||||
status['judgement'] = False
|
||||
|
@ -295,6 +301,8 @@ class Member(db.Model):
|
|||
now_date = datetime.datetime.now()
|
||||
self.join_year = now_date.year
|
||||
self.join_month = now_date.month
|
||||
self.ldap_username = _username
|
||||
self.payment_policy = PaymentPolicy.normal.value
|
||||
|
||||
|
||||
class Transfer(db.Model):
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
<h4>Active operations:</h4>
|
||||
<h4>Available operations:</h4>
|
||||
<p>
|
||||
<form action="/fetch" method="post">
|
||||
<!--<form action="/fetch" method="post">
|
||||
<button type="button" class="btn btn-primary">Fetch transfer data</button>
|
||||
</form>
|
||||
<form action="/spam" method="post">
|
||||
<button type="button" class="btn btn-primary">Send reminders</button>
|
||||
</form>
|
||||
</form>-->
|
||||
<a href="/admin/fetch"><b>Fetch transfer data</b></a>
|
||||
</p>
|
||||
</div>
|
||||
{% for group in active_members|groupby("type") %}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
{% extends "root.html" %}
|
||||
{% block title %}brefetch{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Fetch banking data from BRE</h2>
|
||||
<form method="post" action="/fetch">
|
||||
|
||||
<div class="container">
|
||||
<h2>Fetch banking data from BRE</h2>
|
||||
<form method="post" action="/admin/fetch">
|
||||
{{ form.identifier()|safe }}
|
||||
{{ form.token()|safe }}
|
||||
<input type="submit" value="Fetch" />
|
||||
</form>
|
||||
<h2>Matching operations</h2>
|
||||
<a href="/match-easy">Match all easily matchable transfers</a><br />
|
||||
<a href="/match-manual">Match manually all unmatched transfers</a><br />
|
||||
<a href="/match-auto">Auto: first match easy transfers, then manualy match the rest</a>
|
||||
<a href="/admin/match/auto">Match all easily matchable transfers</a><br />
|
||||
<a href="/admin/match/manual">Match manually all unmatched transfers</a><br />
|
||||
<h2>Unmatched transfers - troublesome</h2>
|
||||
<ul>
|
||||
{% for t in transfers_unmatched %}
|
||||
|
@ -27,4 +28,5 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% extends "root.html" %}
|
||||
{% block title %}manual match{% endblock %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<script>
|
||||
function payment(months, uid, username)
|
||||
{
|
||||
|
@ -8,7 +9,7 @@
|
|||
div.style.display = "none";
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/match/" + username + "/" + uid + "/" + months, true);
|
||||
xhr.open("GET", "/admin/match/" + username + "/" + uid + "/" + months, true);
|
||||
xhr.send();
|
||||
}
|
||||
</script>
|
||||
|
@ -39,9 +40,9 @@
|
|||
|
||||
{% elif matchability == 2 %}
|
||||
<b>Unknown member...</b><br />
|
||||
<a href="add/starving/{{extra}}">Add member {{extra}} - starving</a><br />
|
||||
<a href="add/fatty/{{extra}}">Add member {{extra}} - fatty</a>
|
||||
<form method="POST" action="/match/">
|
||||
<a href="/admin/member/add/starving/{{extra}}">Add member {{extra}} - starving</a><br />
|
||||
<a href="/admin/member/add/fatty/{{extra}}">Add member {{extra}} - fatty</a>
|
||||
<form method="POST" action="/admin/match/">
|
||||
username: <input name="username" />
|
||||
<input type="hidden" name="uid" value="{{t.uid}}" />
|
||||
<input type="submit" value="match other username" />
|
||||
|
@ -49,7 +50,7 @@
|
|||
|
||||
{% elif matchability == 3 %}
|
||||
<b>Unparseable...</b>
|
||||
<form method="POST" action="/match/">
|
||||
<form method="POST" action="/admin/match/">
|
||||
username: <input name="username" />
|
||||
<input type="hidden" name="uid" value="{{t.uid}}" />
|
||||
<input type="submit" value="match" />
|
||||
|
@ -59,4 +60,5 @@
|
|||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
{% extends "root.html" %}
|
||||
{% block title %}member {{member.username}}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<script>
|
||||
function payment(months, uid, username)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/match/" + username + "/" + uid + "/" + months, true);
|
||||
xhr.open("GET", "/admin/match/" + username + "/" + uid + "/" + months, true);
|
||||
xhr.send();
|
||||
}
|
||||
</script>
|
||||
|
@ -13,7 +14,7 @@
|
|||
<h3>Info</h3>
|
||||
Active: {{member.active}}<br />
|
||||
Type: {{member.type}}<br />
|
||||
Months due: {{member.months_due()}}<br />
|
||||
Months due: {{member.get_months_due()}}<br />
|
||||
Amount due: {{amount_due}}
|
||||
<h3>Transfers...</h3>
|
||||
<ul>
|
||||
|
@ -27,4 +28,5 @@
|
|||
<a href="javascript:payment({{fattycount|int}}, '{{transfer.uid}}', '{{ member.username }}')">This is a {{fattycount|int}}-time payment. (fatty)</a><br />
|
||||
<a href="javascript:payment({{starvingcount|int}}, '{{transfer.uid}}', '{{ member.username }}')">This is a {{starvingcount|int}}-time payment. (starving)</a><br />
|
||||
<a href="javascript:payment(prompt('months?', '0'), '{{transfer.uid}}', '{{ member.username }}')">This is a N-time payment. (superfatty?)</a><br />
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "root.html" %}
|
||||
{% block title %}member {{member.username}}{% endblock %}
|
||||
{% block content %}
|
||||
<h2>{{member.username}}</h2>
|
||||
<h3>Info</h3>
|
||||
Active: {{member.active}}<br />
|
||||
Type: {{member.type}}<br />
|
||||
Months due: {{member.months_due()}}<br />
|
||||
Amount due: {{amount_due}}
|
||||
<h3>Transfers...</h3>
|
||||
<ul>
|
||||
{% for member_transfer in member.transfers %}
|
||||
<li>{{member_transfer.year}}/{{member_transfer.month}} - <b>{{ member_transfer.transfer.amount/100 }}PLN</b> (transfer „ {{member_transfer.transfer.title}}” at {{member_transfer.transfer.date}} from {{member_transfer.transfer.name_from}})</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
139
webapp/views.py
139
webapp/views.py
|
@ -92,6 +92,145 @@ def admin_index():
|
|||
active_members=active_members,
|
||||
inactive_members=inactive_members)
|
||||
|
||||
@app.route('/admin/member/<membername>')
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_member(membername):
|
||||
member = models.Member.get_members(True).filter_by(ldap_username=membername).first()
|
||||
if not member:
|
||||
abort(404)
|
||||
status = member.get_status()
|
||||
cn = directory.get_member_fields(g.ldap, member.ldap_username, 'cn')['cn']
|
||||
return render_template("admin_member.html", member=member, status=status,
|
||||
cn=cn, admin=True)
|
||||
|
||||
@app.route("/admin/member/<membername>/policy:<policy>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_member_set_policy(membername,policy):
|
||||
member = models.Member.query.filter_by(ldap_username=membername).first()
|
||||
member.payment_policy = models.PaymentPolicy[policy].value
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
return redirect(request.referrer)
|
||||
|
||||
@app.route("/admin/member/<membername>/membership:<membershiptype>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_member_set_membership(membername,membershiptype):
|
||||
member = models.Member.query.filter_by(ldap_username=membername).first()
|
||||
member.type = models.MembershipType[membershiptype].name
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
return redirect(request.referrer)
|
||||
|
||||
|
||||
@app.route("/admin/member/add/<membershiptype>/<username>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_member(type, username):
|
||||
member = models.Member(None, username, models.MembershipType[membershiptype].name, True)
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
||||
@app.route("/admin/fetch", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_fetch():
|
||||
form = forms.BREFetchForm(request.form)
|
||||
if request.method == "POST" and form.validate():
|
||||
identifier = form.identifier.data
|
||||
token = form.token.data
|
||||
try:
|
||||
f = banking.BREFetcher()
|
||||
f.login(identifier, token)
|
||||
data = f.create_report().read()
|
||||
flash("Fetched data from BRE ({} rows)".format(data.count("\n")))
|
||||
f = open(app.config["BRE_SNAPSHOT_PATH"], "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
return redirect(url_for("admin_fetch"))
|
||||
except Exception as e:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
|
||||
flash("Error when fetching data. %s" % traceback.format_exception(exc_type, exc_value,exc_traceback))
|
||||
return redirect(url_for("admin_fetch"))
|
||||
|
||||
logic.update_transfer_rows()
|
||||
transfers_unmatched = logic.get_unmatched_transfers()
|
||||
|
||||
return render_template("fetch.html", form=form, transfers_unmatched=transfers_unmatched)
|
||||
|
||||
|
||||
@app.route("/admin/match/auto", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_match_auto():
|
||||
matched = 0
|
||||
left = 0
|
||||
transfers_unmatched = logic.get_unmatched_transfers()
|
||||
for transfer in transfers_unmatched:
|
||||
matchability, extra = transfer.get_matchability()
|
||||
if matchability == models.Transfer.MATCH_OK:
|
||||
member = extra
|
||||
if len(member.transfers) > 0:
|
||||
year, month = member.get_next_unpaid()
|
||||
else:
|
||||
year, month = transfer.date.year, transfer.date.month
|
||||
mt = models.MemberTransfer(None, year, month, transfer)
|
||||
member.transfers.append(mt)
|
||||
db.session.add(mt)
|
||||
matched += 1
|
||||
else:
|
||||
left += 1
|
||||
db.session.commit()
|
||||
flash("Matched %i, %i left" % (matched, left))
|
||||
return redirect(url_for("admin_fetch"))
|
||||
|
||||
@app.route("/admin/match/manual", methods=["GET"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def match_manual():
|
||||
transfers_unmatched = logic.get_unmatched_transfers()
|
||||
return render_template("match_manual.html", transfers_unmatched=transfers_unmatched)
|
||||
|
||||
@app.route("/admin/match/<username>/<uid>/<int:months>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def match(username, uid, months):
|
||||
member = models.Member.query.filter_by(username=username).first()
|
||||
if not member:
|
||||
return "no member"
|
||||
transfer = models.Transfer.query.filter_by(uid=uid).first()
|
||||
if not transfer:
|
||||
return "no transfer"
|
||||
|
||||
for _ in range(months):
|
||||
year, month = member.get_next_unpaid()
|
||||
mt = models.MemberTransfer(None, year, month, transfer)
|
||||
member.transfers.append(mt)
|
||||
db.session.add(mt)
|
||||
|
||||
db.session.commit()
|
||||
return "ok, %i PLN get!" % transfer.amount
|
||||
|
||||
|
||||
@app.route("/admin/match/", methods=["POST"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def match_user_transfer():
|
||||
username = request.form["username"]
|
||||
uid = request.form["uid"]
|
||||
member = models.Member.query.filter_by(username=username).first()
|
||||
if not member:
|
||||
return "no such member! :("
|
||||
transfer = models.Transfer.query.filter_by(uid=uid).first()
|
||||
if not transfer:
|
||||
return "no transfer"
|
||||
|
||||
return render_template("match_user_transfer.html", member=member, transfer=transfer)
|
||||
|
||||
@app.route("/login", methods=["POST", "GET"])
|
||||
def login():
|
||||
form = forms.LoginForm(request.form)
|
||||
|
|
Loading…
Reference in New Issue