Local changes.

master
Kasownik 2016-09-27 00:39:53 +02:00 committed by Remigiusz Marcinkiewicz
parent bb78ab70b3
commit 6ef0abbe70
9 changed files with 196 additions and 26 deletions

View File

@ -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

View File

@ -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}

View File

@ -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):

View File

@ -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") %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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)