# -*- 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 from ctdotools.utils import datetime_parse 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/scripts/jquery-ui-1.6.custom.min.js') key = req.path_info data = {} e_id = None session_tzname, selected_tz = get_tz(req.session.get('tz', self.config.get("trac", "default_timezone") or 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, "", "", "", "", "", "") assert account assert event 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") dt_begin = datetime_parse("%s %s" % (req.args["date_begin"], req.args["time_begin"]), selected_tz) dt_end = datetime_parse("%s %s" % (req.args["date_end"], req.args["time_end"]), selected_tz) edit_deadline = datetime_parse("%s %s" % (req.args["edit_deadline_date"], req.args["edit_deadline_time"]), selected_tz) payment_deadline = datetime_parse("%s %s" % (req.args["payment_deadline_date"], req.args["payment_deadline_time"]), selected_tz) print req.args["date_begin"], req.args["time_begin"], dt_begin, dt_end 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) data["selected_tz"] = selected_tz 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}