Merge pull request 'Improved CSV export' (#26) from stranck-dev into drew-dev
Reviewed-on: #26
This commit is contained in:
commit
ab2c8d4b85
86
admin.py
86
admin.py
|
@ -4,7 +4,10 @@ from room import unconfirm_room_by_order
|
||||||
from config import *
|
from config import *
|
||||||
from utils import *
|
from utils import *
|
||||||
from ext import *
|
from ext import *
|
||||||
|
from io import StringIO
|
||||||
from sanic.log import logger
|
from sanic.log import logger
|
||||||
|
import csv
|
||||||
|
import time
|
||||||
|
|
||||||
bp = Blueprint("admin", url_prefix="/manage/admin")
|
bp = Blueprint("admin", url_prefix="/manage/admin")
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ async def login_as(request, code, order:Order):
|
||||||
|
|
||||||
@bp.get('/room/verify')
|
@bp.get('/room/verify')
|
||||||
async def verify_rooms(request, order:Order):
|
async def verify_rooms(request, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
already_checked, success = await request.app.ctx.om.update_cache()
|
already_checked, success = await request.app.ctx.om.update_cache()
|
||||||
if not already_checked and success:
|
if not already_checked and success:
|
||||||
orders = filter(lambda x: x.status not in ['c', 'e'] and x.room_id == x.code, request.app.ctx.om.cache.values())
|
orders = filter(lambda x: x.status not in ['c', 'e'] and x.room_id == x.code, request.app.ctx.om.cache.values())
|
||||||
|
@ -56,6 +60,7 @@ async def unconfirm_room(request, code, order:Order):
|
||||||
|
|
||||||
@bp.get('/room/autoconfirm')
|
@bp.get('/room/autoconfirm')
|
||||||
async def autoconfirm_room(request, code, order:Order):
|
async def autoconfirm_room(request, code, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
orders = request.app.ctx.om.cache.values()
|
orders = request.app.ctx.om.cache.values()
|
||||||
for order in orders:
|
for order in orders:
|
||||||
if(order.code == order.room_id and not order.room_confirmed and len(order.room_members) == order.room_person_no):
|
if(order.code == order.room_id and not order.room_confirmed and len(order.room_members) == order.room_person_no):
|
||||||
|
@ -65,6 +70,7 @@ async def autoconfirm_room(request, code, order:Order):
|
||||||
|
|
||||||
@bp.get('/room/delete/<code>')
|
@bp.get('/room/delete/<code>')
|
||||||
async def delete_room(request, code, order:Order):
|
async def delete_room(request, code, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
dOrder = await get_order_by_code(request, code, throwException=True)
|
dOrder = await get_order_by_code(request, code, throwException=True)
|
||||||
|
|
||||||
ppl = await get_people_in_room_by_code(request, code)
|
ppl = await get_people_in_room_by_code(request, code)
|
||||||
|
@ -84,6 +90,7 @@ async def delete_room(request, code, order:Order):
|
||||||
|
|
||||||
@bp.post('/room/rename/<code>')
|
@bp.post('/room/rename/<code>')
|
||||||
async def rename_room(request, code, order:Order):
|
async def rename_room(request, code, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
dOrder = await get_order_by_code(request, code, throwException=True)
|
dOrder = await get_order_by_code(request, code, throwException=True)
|
||||||
|
|
||||||
name = request.form.get('name')
|
name = request.form.get('name')
|
||||||
|
@ -107,4 +114,81 @@ async def propic_remind_missing(request, order:Order):
|
||||||
# print(f"{order.code}: prp={missingPropic} fpr={missingFursuitPropic} - {order.name}")
|
# print(f"{order.code}: prp={missingPropic} fpr={missingFursuitPropic} - {order.name}")
|
||||||
await send_missing_propic_message(order, missingPropic, missingFursuitPropic)
|
await send_missing_propic_message(order, missingPropic, missingFursuitPropic)
|
||||||
|
|
||||||
return redirect(f'/manage/admin')
|
return redirect(f'/manage/admin')
|
||||||
|
|
||||||
|
@bp.get('/export/export')
|
||||||
|
async def export_export(request, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
|
|
||||||
|
data = StringIO()
|
||||||
|
w = csv.writer(data)
|
||||||
|
|
||||||
|
w.writerow(['Status', 'Code', 'First name', 'Last name', 'Nick', 'State', 'Card', 'Artist', 'Fursuiter', 'Sponsorhip', 'Early', 'Late', 'Daily', 'Daily days', 'Shirt', 'Room type', 'Room count', 'Room members', 'Payment', 'Price', 'Refunds', 'Staff'])
|
||||||
|
|
||||||
|
orders = request.app.ctx.om.cache.values()
|
||||||
|
order: Order
|
||||||
|
for order in orders:
|
||||||
|
w.writerow([
|
||||||
|
order.status,
|
||||||
|
order.code,
|
||||||
|
order.first_name,
|
||||||
|
order.last_name,
|
||||||
|
order.name,
|
||||||
|
order.country,
|
||||||
|
order.has_card,
|
||||||
|
order.is_artist,
|
||||||
|
order.is_fursuiter,
|
||||||
|
order.sponsorship,
|
||||||
|
order.has_early,
|
||||||
|
order.has_late,
|
||||||
|
order.daily,
|
||||||
|
','.join(order.dailyDays),
|
||||||
|
order.shirt_size,
|
||||||
|
ROOM_TYPE_NAMES[order.bed_in_room] if order.bed_in_room in ROOM_TYPE_NAMES else "-",
|
||||||
|
len(order.room_members),
|
||||||
|
','.join(order.room_members),
|
||||||
|
order.payment_provider,
|
||||||
|
order.total - order.fees,
|
||||||
|
order.refunds,
|
||||||
|
order.ans('staff_role') or 'attendee',
|
||||||
|
])
|
||||||
|
|
||||||
|
data.seek(0)
|
||||||
|
str = data.read() #data.read().decode("UTF-8")
|
||||||
|
data.flush()
|
||||||
|
data.close()
|
||||||
|
|
||||||
|
return raw(str, status=200, headers={'Content-Disposition': f'attachment; filename="export_{int(time.time())}.csv"', "Content-Type": "text/csv; charset=UTF-8"})
|
||||||
|
|
||||||
|
@bp.get('/export/hotel')
|
||||||
|
async def export_hotel(request, order:Order):
|
||||||
|
await clear_cache(request, order)
|
||||||
|
|
||||||
|
data = StringIO()
|
||||||
|
w = csv.writer(data)
|
||||||
|
|
||||||
|
w.writerow(['Room type', 'Room name', 'Room code', 'First name', 'Last name', 'Birthday', 'Address', 'Email', 'Phone number', 'Status'])
|
||||||
|
|
||||||
|
orders = sorted(request.app.ctx.om.cache.values(), key=lambda d: (d.room_id if d.room_id != None else "~"))
|
||||||
|
order: Order
|
||||||
|
for order in orders:
|
||||||
|
w.writerow([
|
||||||
|
ROOM_TYPE_NAMES[order.bed_in_room] if order.bed_in_room in ROOM_TYPE_NAMES else "-",
|
||||||
|
order.room_name,
|
||||||
|
order.room_id,
|
||||||
|
order.first_name,
|
||||||
|
order.last_name,
|
||||||
|
order.birth_date,
|
||||||
|
order.address,
|
||||||
|
order.email,
|
||||||
|
order.phone,
|
||||||
|
order.status,
|
||||||
|
order.code
|
||||||
|
])
|
||||||
|
|
||||||
|
data.seek(0)
|
||||||
|
str = data.read() #data.read().decode("UTF-8")
|
||||||
|
data.flush()
|
||||||
|
data.close()
|
||||||
|
|
||||||
|
return raw(str, status=200, headers={'Content-Disposition': f'attachment; filename="hotel_{int(time.time())}.csv"', "Content-Type": "text/csv; charset=UTF-8"})
|
3
app.py
3
app.py
|
@ -29,14 +29,13 @@ app.ext.add_dependency(Quotas, get_quotas)
|
||||||
from room import bp as room_bp
|
from room import bp as room_bp
|
||||||
from propic import bp as propic_bp
|
from propic import bp as propic_bp
|
||||||
from karaoke import bp as karaoke_bp
|
from karaoke import bp as karaoke_bp
|
||||||
from export import bp as export_bp
|
|
||||||
from stats import bp as stats_bp
|
from stats import bp as stats_bp
|
||||||
from api import bp as api_bp
|
from api import bp as api_bp
|
||||||
from carpooling import bp as carpooling_bp
|
from carpooling import bp as carpooling_bp
|
||||||
from checkin import bp as checkin_bp
|
from checkin import bp as checkin_bp
|
||||||
from admin import bp as admin_bp
|
from admin import bp as admin_bp
|
||||||
|
|
||||||
app.blueprint([room_bp, karaoke_bp, propic_bp, export_bp, stats_bp, api_bp, carpooling_bp, checkin_bp, admin_bp])
|
app.blueprint([room_bp, karaoke_bp, propic_bp, stats_bp, api_bp, carpooling_bp, checkin_bp, admin_bp])
|
||||||
|
|
||||||
|
|
||||||
async def clear_session(response):
|
async def clear_session(response):
|
||||||
|
|
87
export.py
87
export.py
|
@ -1,87 +0,0 @@
|
||||||
from sanic.response import text
|
|
||||||
from sanic import Blueprint, exceptions
|
|
||||||
from ext import *
|
|
||||||
from config import headers, ADMINS, ORGANIZER, EVENT_NAME
|
|
||||||
|
|
||||||
bp = Blueprint("export", url_prefix="/manage/export")
|
|
||||||
|
|
||||||
@bp.route("/export.csv")
|
|
||||||
async def export_csv(request, order: Order):
|
|
||||||
if not order: raise exceptions.Forbidden("You have been logged out. Please access the link in your E-Mail to login again!")
|
|
||||||
if not order.isAdmin(): raise exceptions.Forbidden("Birichino :)")
|
|
||||||
|
|
||||||
page = 0
|
|
||||||
orders = {}
|
|
||||||
|
|
||||||
ret = 'status;code;nome;cognome;nick;nazione;tessera;artista;fursuiter;sponsorship;early;late;shirt;roomsize;roommembers;payment;price;refunds;staff\n'
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
page += 1
|
|
||||||
|
|
||||||
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/orders/?page={page}', headers=headers)
|
|
||||||
if r.status_code == 404: break
|
|
||||||
|
|
||||||
for r in r.json()['results']:
|
|
||||||
|
|
||||||
o = Order(r)
|
|
||||||
orders[o.code] = o
|
|
||||||
|
|
||||||
ret += (';'.join(map(lambda x: str(x),
|
|
||||||
[
|
|
||||||
o.status,
|
|
||||||
o.code,
|
|
||||||
o.first_name,
|
|
||||||
o.last_name,
|
|
||||||
o.name,
|
|
||||||
o.country,
|
|
||||||
o.has_card or '',
|
|
||||||
o.is_artist or '',
|
|
||||||
o.is_fursuiter or '',
|
|
||||||
o.sponsorship or '',
|
|
||||||
o.has_early or '',
|
|
||||||
o.has_late or '',
|
|
||||||
o.shirt_size,
|
|
||||||
len(o.room_members),
|
|
||||||
','.join(o.room_members),
|
|
||||||
o.payment_provider,
|
|
||||||
o.total-o.fees,
|
|
||||||
o.refunds,
|
|
||||||
o.ans('staff_role') or 'attendee',
|
|
||||||
]))) + "\n"
|
|
||||||
|
|
||||||
return text(ret)
|
|
||||||
|
|
||||||
@bp.route("/hotel_export.csv")
|
|
||||||
async def export_hotel_csv(request, order: Order):
|
|
||||||
if not order: raise exceptions.Forbidden("You have been logged out. Please access the link in your E-Mail to login again!")
|
|
||||||
if order.code not in ['HWUC9','9YKGJ']: raise exceptions.Forbidden("Birichino :)")
|
|
||||||
|
|
||||||
page = 0
|
|
||||||
orders = {}
|
|
||||||
|
|
||||||
ret = 'code;nome;cognome;datanascita;posnascita;indirizzo;mail;status\n'
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
page += 1
|
|
||||||
|
|
||||||
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/orders/?page={page}', headers=headers)
|
|
||||||
if r.status_code == 404: break
|
|
||||||
|
|
||||||
for r in r.json()['results']:
|
|
||||||
|
|
||||||
o = Order(r)
|
|
||||||
orders[o.code] = o
|
|
||||||
|
|
||||||
ret += (';'.join(map(lambda x: str(x),
|
|
||||||
[
|
|
||||||
o.code,
|
|
||||||
o.first_name,
|
|
||||||
o.last_name,
|
|
||||||
o.birth_date,
|
|
||||||
o.birth_location,
|
|
||||||
o.address,
|
|
||||||
o.email,
|
|
||||||
o.status
|
|
||||||
]))) + "\n"
|
|
||||||
|
|
||||||
return text(ret)
|
|
2
ext.py
2
ext.py
|
@ -57,7 +57,7 @@ class Order:
|
||||||
|
|
||||||
idata = data['invoice_address']
|
idata = data['invoice_address']
|
||||||
if idata:
|
if idata:
|
||||||
self.address = f"{idata['street']} - {idata['zipcode']} {idata['city']} - {idata['country']}"
|
self.address = f"{idata['street'].strip()} - {idata['zipcode'].strip()} {idata['city'].strip()} - {idata['country'].strip()}".replace("\n", "").replace("\r", "")
|
||||||
self.country = idata['country']
|
self.country = idata['country']
|
||||||
|
|
||||||
for p in self.data['positions']:
|
for p in self.data['positions']:
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
<a href="/manage/admin/room/verify" role="button" title="Will unconfirm rooms that fail the default check. Useful when editing answers from Pretix">Verify Rooms</a>
|
<a href="/manage/admin/room/verify" role="button" title="Will unconfirm rooms that fail the default check. Useful when editing answers from Pretix">Verify Rooms</a>
|
||||||
<a href="#" onclick="confirmAction('propicReminder', this)" role="button" title="Will remind via mail all people who event uploaded a badge to do it" action="/manage/admin/propic/remind">Remind badge upload</a>
|
<a href="#" onclick="confirmAction('propicReminder', this)" role="button" title="Will remind via mail all people who event uploaded a badge to do it" action="/manage/admin/propic/remind">Remind badge upload</a>
|
||||||
<a href="/manage/admin/room/autoconfirm" role="button" title="Will confirm all the full rooms that are still unconfirmed">Auto-confirm Rooms</a>
|
<a href="/manage/admin/room/autoconfirm" role="button" title="Will confirm all the full rooms that are still unconfirmed">Auto-confirm Rooms</a>
|
||||||
|
<a download href="/manage/admin/export/export" role="button" title="Will export most of informations about the orders">Export CSV</a>
|
||||||
|
<a download href="/manage/admin/export/hotel" role="button" title="Will export a CSV for the hotel accomodation">Export hotel CSV</a>
|
||||||
<hr>
|
<hr>
|
||||||
{% include 'components/confirm_action_modal.html' %}
|
{% include 'components/confirm_action_modal.html' %}
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in New Issue