ctdo-trac/TracBooking/tracbooking/admin.py

587 lines
28 KiB
Python

# -*- coding: utf-8 -*-
import os
from os.path import join
from re import match
from trac.admin import IAdminPanelProvider
from trac.core import *
from trac.web.chrome import add_stylesheet, add_warning, add_ctxtnav, add_script, add_notice
from trac.web import RequestDone
from trac.util.translation import _, N_, gettext
from trac.util.datefmt import utc
from trac.util.text import to_unicode
from datetime import datetime
from tracbooking.model import *
from tracbooking.report import create_report
from tracbooking.utils import validate_id, time_parse, date_parse, get_tz, get_option_count, validate_email
from tracbooking.web_ui import UserUploadComponent
def get_actions(myactions):
actions = []
for action in myactions:
if isinstance(action, tuple):
actions.append(action[0])
else:
actions.append(action)
return actions
class BookingAdminPanel(Component):
implements(IAdminPanelProvider)
# IAdminPanelProvider methods
def get_admin_panels(self, req):
if 'BOOKING_ADMIN' in req.perm:
yield ('booking', _('Booking System'), 'reminder',
'Erinnerungen verwalten')
yield ('booking', _('Booking System'), 'events',
'Events verwalten')
yield ('booking', _('Booking System'), 'options',
'Optionen verwalten')
yield ('booking', _('Booking System'), 'attendees',
'Teilnehmer')
yield ('booking', _('Booking System'), 'options2events',
u'Optionen mit Events verknüpfen')
yield ('booking', _('Booking System'), 'einkauf',
u'Bestellungen einsehen')
def render_admin_panel(self, req, cat, page, path_info):
req.perm.require('BOOKING_ADMIN')
print "render", req, cat, page, path_info
if page == "events":
return self._render_events(req, cat, page, path_info)
if page == "attendees":
return self._render_attendees(req, cat, page, path_info)
if page == "options":
return self._render_options(req, cat, page, path_info)
if page == "options2events":
return self._render_options2events(req, cat, page, path_info)
if page == "reminder":
return self._render_reminder(req, cat, page, path_info)
if page == "einkauf":
return self._render_einkauf(req, cat, page, path_info)
#return self._render_admin_panel(req, cat, page, path_info)
def _render_reminder(self, req, cat, page, bookingtype):
print "BookingReminderManager._render_admin_panel()"
add_stylesheet (req, 'hw/css/booking.css')
key = req.path_info
m = match(r'/admin/booking/reminder/(\d+)$', key)
if not m:
if key == "/admin/booking/reminder":
return "admin_reminder.html", {"events" : Event.fetch_all(self.env), "reminders" : None}
e_id = int(m.group(1))
event = Event.fetch_one(self.env, e_id)
if req.method == "POST":
if req.args.get("add") and \
req.args.has_key("text") and \
req.args.has_key("notify_on"):
text = req.args.get("text")
notify_on = req.args.get("notify_on")
notify_on = time_parse(notify_on)
reminder = BookingReminder(self.env, 0, e_id, text, notify_on)
reminder.commit()
elif req.args.has_key("save") and req.args.has_key("sel"):
sel = req.args.get('sel')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
BookingReminder.delete(self.env, int(key))
return "admin_reminder.html", {"reminders" : BookingReminder.fetch_by_event(self.env, e_id), "eventname" : event.name}
def _render_events(self, req, cat, page, bookingtype):
add_stylesheet (req, 'hw/css/booking.css')
add_stylesheet (req, 'hw/css/ui.all.css')
add_script (req, 'hw/script/jquery-ui-1.6.custom.min.js')
key = req.path_info
data = {}
e_id = None
m = match(r'/admin/booking/events/(\d+)$', key)
if m:
e_id = int(m.group(1))
event = Event.fetch_one(self.env, e_id)
account = EventAccount.fetch_by_event(self.env, e_id)
else:
event = Event(self.env, 0, "", "", datetime.now(utc), datetime.now(utc))
account = EventAccount(self.env, 0, 0, "", "", "", "", "", "")
if req.method == "POST":
if req.args.get("add") and \
req.args.has_key("name") and \
req.args.has_key("date_begin") and \
req.args.has_key("date_end") and \
req.args.has_key("time_begin") and \
req.args.has_key("time_end"):
name = req.args.get("name")
date_begin = date_parse(req.args.get("date_begin"))
time_begin = time_parse(req.args.get("time_begin"))
dt_begin = datetime.combine(date_begin, time_begin)
dt_begin = dt_begin.replace(tzinfo=utc)
date_end = date_parse(req.args.get("date_end"))
time_end = time_parse(req.args.get("time_end"))
dt_end = datetime.combine(date_end, time_end)
dt_end = dt_end.replace(tzinfo=utc)
date_begin = date_parse(req.args.get("edit_deadline_date"))
time_begin = time_parse(req.args.get("edit_deadline_time"))
edit_deadline = datetime.combine(date_begin, time_begin)
edit_deadline = edit_deadline.replace(tzinfo=utc)
payment_deadline_date = date_parse(req.args.get("payment_deadline_date"))
payment_deadline_time = time_parse(req.args.get("payment_deadline_time"))
payment_deadline = datetime.combine(payment_deadline_date, payment_deadline_time)
payment_deadline = payment_deadline.replace(tzinfo=utc)
account_owner = req.args.get("account_owner")
account_no = req.args.get("account_no")
bank_name = req.args.get("bank_name")
bank_no = req.args.get("bank_no")
first_reason = req.args.get("first_reason")
#second_reason = req.args.get("second_reason")
description = req.args.get("description", "")
event.name = name
event.description = description
event.time_begin = dt_begin
event.time_end = dt_end
event.edit_deadline = edit_deadline
event.payment_deadline = payment_deadline
account.account_owner = account_owner
account.account_no = account_no
account.bank_name = bank_name
account.bank_no = bank_no
account.first_reason = first_reason
#account.second_reason = second_reason
if not e_id:
event.commit()
account.commit()
else:
event.update()
account.update()
elif req.args.has_key("save") and req.args.has_key("rsel"):
sel = req.args.get('rsel')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
e_id = int(key)
Event.delete(self.env, e_id)
elif req.args.has_key("save") and req.args.has_key("copy"):
e_id = int(req.args.get('copy'))
event = Event.copy(self.env, e_id)
elif req.args.has_key("save") and req.args.has_key("finish"):
e_id = int(req.args.get('finish'))
attendees = Attendee.fetch_all(self.env, e_id)
for attendee in attendees:
attendee.finished = True
attendee.update()
event = Event.fetch_one(self.env, e_id)
event.name += " (Abgeschlossen)"
event.update()
req.redirect(req.href("/admin/booking/events", e_id))
data["event"] = event
data["event_account"] = account
data["events"] = Event.fetch_all(self.env)
return "admin_events.html", data
def _render_options(self, req, cat, page, bookingtype):
print "AvailableOptionsManager._render_admin_panel()"
add_stylesheet (req, 'hw/css/booking.css')
data = {}
key = req.path_info
m = match(r'/admin/booking/options/(\d+)$', key)
option_id = None
option = AvailableOption(self.env, 0, "", "", 0.0, 0.0, 0, 0, 0, 0, 0)
if m:
option_id = int(m.group(1))
option = AvailableOption.fetch_one(self.env, option_id)
if req.method == "POST":
if req.args.get("add") and \
req.args.has_key("name") and \
req.args.has_key("price"):
name = req.args.get("name")
desc = req.args.get("desc")
price = float(req.args.get("price"))
minc = int(req.args.get("min_count", 0))
maxc = int(req.args.get("max_count", 0))
supplier_id = int(req.args.get("supplier_id", 0))
ext_id = req.args.get("ext_id", None)
stock_count = int(req.args.get("stock_count", 0))
option.name = name
option.price = price
option.description = desc
option.min_count = minc
option.max_count = maxc
option.supplier_id = supplier_id
option.ext_id = ext_id
option.stock_count = stock_count
if option_id:
option.update()
else:
option.commit()
req.redirect(req.href.admin("booking", "options"))
elif req.args.has_key("save"):
if req.args.has_key("rsel"):
sel = req.args.get('rsel')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
try:
ao_id = int(key)
except ValueError:
raise TracError("wrong value")
AvailableOption.delete(self.env, ao_id)
a_ids = set()
if req.args.has_key("actives"):
sel = req.args.get('actives')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
try:
a_ids.add(int(key))
except ValueError:
continue
options = AvailableOption.fetch_all(self.env)
for option in options:
if option.active:
if not option.ao_id in a_ids:
option.active = 0
option.update()
elif option.ao_id in a_ids:
option.active = 1
option.update()
data["options"] = AvailableOption.fetch_all(self.env)
data["suppliers"] = Supplier.fetch_all(self.env)
data["option"] = option
return "admin_options.html", data
def _render_attendees(self, req, cat, page, bookingtype):
print "RegistrationOverview._render_admin_panel()"
add_stylesheet (req, 'hw/css/booking.css')
key = req.path_info
m1 = match(r'/admin/booking/attendees/(\d+)/(\d+)$', key)
m2 = match(r'/admin/booking/attendees/(\d+)$', key)
print "data", req.args, cat, page, bookingtype
print "matches", m1, m2
if m1:
notice = "Bestellung erfolgreich gespeichert."
if req.session.has_key("notice"):
add_notice(req, req.session["notice"])
del req.session["notice"]
req.session.save()
event_id = int(m1.group(1))
a_id = m1.group(2)
attendee = Attendee.fetch_one(self.env, a_id, e_id=event_id, fetch_options=True)
add_ctxtnav(req, 'Back to Overview', req.href.admin("booking", "attendees", event_id))
data = {"attendee" : attendee,
"bank_name" : self.config.get("booking", "bank_name"),
"bank_no" : self.config.get("booking", "bank_no"),
"account_owner" : self.config.get("booking", "account_owner"),
"account" : self.config.get("booking", "account"),
"first_reason" : self.config.get("booking", "first_reason")}
print 1
if req.method == "POST":
print "post", attendee.finished
if not attendee.finished:
print "not finished"
failure = False
if req.args.has_key("email"):
email = req.args["email"]
if not validate_email(email):
add_warning(req, u"email nicht gültig")
attendee.email = email
attendee.update()
req.session["notice"] = "Daten erfolgreich aktualisiert."
elif req.args.has_key("unregister"):
UserUploadComponent(self.env).clean_userdir(attendee)
Attendee.delete(self.env, attendee.a_id)
print "redirect to", req.href.admin("booking", "attendees", event_id)
req.redirect(req.href.admin("booking", "attendees", event_id))
elif req.args.has_key("finish"):
attendee.finished = True
attendee.update()
print "redirect to", req.href.admin("booking", "attendees", event_id, a_id)
req.redirect(req.href.admin("booking", "attendees", event_id, a_id))
elif req.args.has_key("unfinish"):
attendee.finished = False
attendee.update()
print "redirect to", req.href.admin("booking", "attendees", event_id, a_id)
req.redirect(req.href.admin("booking", "attendees", event_id, a_id))
else:
args = req.args
for arg in args:
if arg.startswith("count"):
try:
prefix, ao_id = arg.split("_", 1)
ao_id = int(ao_id)
count = int(args[arg])
validate_id(count)
validate_id(ao_id)
except ValueError:
add_warning(req, u"Bitte für Anzahlfelder nur positive Zahen eingeben.")
failure = True
continue
aoption = AvailableOption.fetch_one(self.env, ao_id, fetch_variations=False)
if not aoption:
add_warning(req, u"Artikel %r nicht gefunden" % ao_id)
failure = True
continue
elif not aoption.active:
add_warning(req, u"Artikel %r nicht aktiviert" % ao_id)
failure = True
continue
if count < aoption.min_count:
add_warning(req, u"Artikel '%s' kann minimal '%d' Mal bestellt werden;-)" % (aoption.name, aoption.min_count))
failure = True
continue
elif aoption.max_count and count > aoption.max_count:
add_warning(req, u"Artikel '%s' kann maximal '%d' Mal bestellt werden;-)" % (aoption.name, aoption.max_count))
failure = True
continue
if not count:
BookingOption.delete(self.env, attendee.a_id, ao_id)
else:
opt = BookingOption.fetch_one(self.env, attendee.a_id, ao_id)
if not opt:
opt = BookingOption(self.env, 0, attendee.a_id, ao_id, count)
opt.commit()
else:
opt.count = count
opt.update()
#elif arg.startswith("var"):
#prefix, variation_id = arg.split("_", 1)
#try:
#variation_id = int(variation_id)
#validate_id(variation_id)
#value = int(args[arg])
#validate_id(value)
#except (ValueError,):
#add_warning(req, u"Bitte eine Zahl eingeben;-)")
#failure = True
#continue
#variation = BookingOptionVariation.fetch_one(self.env, attendee.a_id, variation_id)
#if not variation:
#b = BookingOptionVariation(self.env, attendee.a_id, variation_id, value)
#b.commit()
#else:
#BookingOptionVariation.update(self.env, attendee.a_id, variation_id, value)
if not failure:
req.session["notice"] = notice
print "before redirect", req.href.admin("booking", "attendees", event_id, a_id)
req.redirect(req.href.admin("booking", "attendees", event_id, a_id))
elif req.args.has_key("download_invoice"):
e_id = req.args["event_id"]
event = Event.fetch_one(self.env, e_id)
session_tzname, selected_tz = get_tz(req.session.get('tz', self.env.config.get("trac", "default_timezone") or None))
data = create_attendee_report(self.env, event, attendee, selected_tz)
data_len = len(data)
req.send_response(200)
req.send_header("Content-Type", "text/pdf;charset=utf-8")
req.send_header("Content-Length", data_len)
req.send_header("Content-Disposition", 'filename=%s.pdf' % event.name.replace("/", "_").replace(u" ", u"_"))
req.end_headers()
req.write(data)
raise RequestDone
elif req.args.has_key("unfinish"):
attendee.finished = False
attendee.update()
print "redirect to", req.href.admin("booking", "attendees", event_id, a_id)
req.redirect(req.href.admin("booking", "attendees", event_id, a_id))
else:
attendee = Attendee.fetch_one(self.env, a_id, e_id=event_id, fetch_options=True)
event = Event.fetch_one(self.env, e_id=event_id, fetch_options=True, attendee_id=attendee.a_id)
for i in event.options:
get_option_count(attendee, i)
data.update({"event" : event, "attendee" : attendee})
return 'admin_attendee_status_edit.html', data
if not m2:
#if key == "/admin/booking/attendees":
return "admin_attendees.html", {"events" : Event.fetch_all(self.env), "attendees" : None, "event" : None}
else:
add_ctxtnav(req, 'Back to Overview', req.href.admin("booking", "attendees"))
e_id = int(m2.group(1))
event = Event.fetch_one(self.env, e_id)
if req.method == "POST":
if req.args.has_key("remove_empty"):
attendees = Attendee.fetch_all(self.env, e_id=e_id, fetch_options=True)
for attendee in attendees:
if not attendee.options:
attendee.delete(self.env, attendee.a_id)
req.redirect(req.href.admin("booking", "attendees", e_id))
elif req.args.has_key("download_report"):
session_tzname, selected_tz = get_tz(req.session.get('tz', self.env.config.get("trac", "default_timezone") or None))
data = create_report(self.env, e_id, selected_tz)
data_len = len(data)
req.send_response(200)
req.send_header("Content-Type", "text/pdf;charset=utf-8")
req.send_header("Content-Length", data_len)
req.send_header("Content-Disposition", 'filename=%s.pdf' % event.name.replace("/", "_").replace(" ", "_"))
req.end_headers()
req.write(data)
raise RequestDone
if req.args.has_key("sel"):
sel = req.args.get('sel')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
try:
a_id = int(key)
except ValueError:
continue
else:
UserUploadComponent(self.env).clean_userdir(Attendee.fetch_one(self.env, a_id))
Attendee.delete(self.env, a_id)
attendees = Attendee.fetch_all(self.env, e_id, True)
a_ids = set()
if req.args.has_key("has_paid"):
sel = req.args.get('has_paid')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
try:
a_ids.add(int(key))
except ValueError:
continue
for attendee in attendees:
if attendee.has_paid:
if not attendee.a_id in a_ids:
attendee.has_paid = 0
attendee.update()
elif attendee.a_id in a_ids:
attendee.has_paid = 1
attendee.update()
actual_amount = req.args.get('actual_amount_%d' % attendee.a_id)
if actual_amount:
try:
attendee.actual_amount = float(actual_amount)
attendee.update()
except TypeError:
add_warning(req, u"Das Attribut 'Eingezahlter Betrag' muss ein float Wert sein")
else:
attendee.actual_amount = None
attendee.update()
return "admin_attendees.html", {"attendees" : Attendee.fetch_all(self.env, e_id, True), "event" : event, "events" : Event.fetch_all(self.env)}
def _render_options2events(self, req, cat, page, bookingtype):
print "ComponentOptions2EventsManager._render_admin_panel()"
add_stylesheet (req, 'hw/css/booking.css')
data = {}
if req.method == "POST":
if req.args.get("add"):
option = req.args.get("option")
event = req.args.get("event")
option = AvailableOption.fetch_one(self.env, name=option)
event = Event.fetch_one(self.env, name=event)
if not option or not event:
raise TracError(_(u'Nicht genügend Informationen'))
o2e = Option2Event.fetch_one(self.env, option.ao_id, event.e_id)
if o2e:
add_warning(req, _(u'Option bereits zum Event hinzugefügt'))
data.update({"options" : AvailableOption.fetch_all(self.env),
"events" : Event.fetch_all(self.env, fetch_options=True)})
return "admin_options_to_events.html", data
o2e = Option2Event(self.env, option.ao_id, event.e_id)
o2e.commit()
elif req.args.has_key("save") and req.args.has_key("sel"):
sel = req.args.get('sel')
if isinstance(sel, basestring):
sel = [sel,]
for key in sel:
ao_id, e_id = key.split(":", 1)
Option2Event.delete(self.env, int(ao_id), int(e_id))
data.update({"options" : AvailableOption.fetch_all(self.env),
"events" : Event.fetch_all(self.env, fetch_options=True)})
return "admin_options_to_events.html", data
def _render_einkauf(self, req, cat, page, bookingtype):
print "ComonentEinkauf._render_admin_panel()"
add_stylesheet (req, 'hw/css/booking.css')
key = req.path_info
m = match(r'/admin/booking/einkauf/(\d+)$', key)
if not m:
if key == "/admin/booking/einkauf":
return "admin_einkauf.html", {"events" : Event.fetch_all(self.env), "items" : None}
e_id = int(m.group(1))
e = Event.fetch_one(self.env, e_id)
if req.method == "POST":
if req.args.has_key("remove_empty"):
attendees = Attendee.fetch_all(self.env, e_id=e_id, fetch_options=True)
attendees = sorted(attendees, key=lambda x: x.nick)
for attendee in attendees:
if not attendee.options:
attendee.delete(self.env, attendee.a_id)
req.redirect(req.href.admin("booking", "einkauf", e_id))
elif req.args.has_key("download_report"):
session_tzname, selected_tz = get_tz(req.session.get('tz', self.env.config.get("trac", "default_timezone") or None))
data = create_report(self.env, e_id, selected_tz)
data_len = len(data)
req.send_response(200)
req.send_header('Content-Type', "text/pdf;charset=utf-8")
req.send_header('Content-Length', data_len)
req.send_header('Content-Disposition', 'filename=%s_bestellung.pdf' % e.name.replace("/", "_").replace(" ", "_"))
req.end_headers()
req.write(data)
raise RequestDone
data = {}
query_old = "SELECT booking_option.ao_id,booking_available_option.name,booking_available_option.price," \
"SUM(booking_option.count),booking_available_option.price * SUM(booking_option.count)" \
"FROM booking_available_option,booking_option,option_to_event " \
"WHERE booking_available_option.ao_id = booking_option.ao_id AND " \
"booking_available_option.ao_id = option_to_event.ao_id AND " \
"option_to_event.e_id=%s GROUP BY booking_option.ao_id;"
query = "select " \
"booking_option.ao_id, " \
"booking_available_option.name, " \
"booking_available_option.price, " \
"SUM(booking_option.count), " \
"SUM(booking_option.count) * booking_available_option.price " \
"from " \
"booking_option,booking_available_option " \
"where " \
"booking_option.a_id IN (select a_id from attendee where e_id=%s) AND " \
"booking_option.ao_id = booking_available_option.ao_id " \
"group by " \
"booking_option.ao_id;"
db = self.env.get_db_cnx()
cursor = db.cursor()
cursor.execute(query, (e_id,))
items = cursor.fetchall()
return "admin_einkauf.html", {"events" : Event.fetch_all(self.env), "items" : items, "eventname": e.name}