dialogs/shipping.h \
dialogs/customerdlg.h \
dialogs/checkdlg.h \
- dialogs/passwdchg.h
+ dialogs/passwdchg.h \
+ dialogs/pricecatdlg.h
SOURCES += \
dialogs/configdialog.cpp \
dialogs/shipping.cpp \
dialogs/customerdlg.cpp \
dialogs/checkdlg.cpp \
- dialogs/passwdchg.cpp
+ dialogs/passwdchg.cpp \
+ dialogs/pricecatdlg.cpp
INCLUDEPATH += ./dialogs
\ No newline at end of file
#include <QBoxLayout>
#include <QCheckBox>
#include <QDateTimeEdit>
+#include <QFormLayout>
#include <QGridLayout>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QTableView>
#include <QTextEdit>
#include <QTimer>
-#include <msinterface.h>
-#include <MTGetEvent.h>
+#include "msinterface.h"
+#include "MTGetEvent.h"
+#include "centbox.h"
+#include "pricecatdlg.h"
-MEventEditor::MEventEditor(QWidget*w,qint64 id)
- :QDialog(w)
+MEventEditor::MEventEditor(QWidget*pw,qint64 id)
+ :QDialog(pw)
{
MTGetEvent ge=MTGetEvent::query(id);
if(ge.stage()!=ge.Success){
setWindowTitle(tr("Event Editor"));
QGridLayout*gl;
- QVBoxLayout*vl;
+ QVBoxLayout*vl,*vl2;
QHBoxLayout*hl;
QPushButton*p;
int lctr=0;
QLabel*lab;
+ QTabWidget*tab;
+ QWidget*w;
setLayout(vl=new QVBoxLayout);
- vl->addLayout(gl=new QGridLayout);
+ vl->addWidget(tab=new QTabWidget,10);
+
+ tab->addTab(w=new QWidget,tr("Event"));
+ w->setLayout(gl=new QGridLayout);
gl->addWidget(lab=new QLabel(tr("ID:")),lctr,0);
lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
gl->addWidget(eventid=new QLabel,lctr,1);
- eventid->setText(QString::number(event.id()));
+ eventid->setText(event.id().isNull()?"new":QString::number(event.id()));
gl->addWidget(lab=new QLabel(tr("Title:")),++lctr,0);
lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
gl->addWidget(lab=new QLabel(tr("Artist:")),++lctr,0);
lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
- gl->addWidget(artist=new QLineEdit,lctr,1);
+ gl->addLayout(hl=new QHBoxLayout,lctr,1);
+ hl->addWidget(artist=new QLineEdit,10);
+ artist->setReadOnly(true);
artist->setText(event.artist().value().name());
-
- gl->addWidget(lab=new QLabel(tr("Description:")),++lctr,0);
- lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
- gl->addWidget(description=new QTextEdit,lctr,1);
- description->setPlainText(event.description());
-
- gl->addWidget(lab=new QLabel(tr("Comment:")),++lctr,0);
- lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
- gl->addWidget(comment=new QTextEdit,lctr,1);
- comment->setPlainText(event.comment());
+ hl->addWidget(p=new QPushButton("..."),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(selectArtist()));
gl->addWidget(lab=new QLabel(tr("Start Time:")),++lctr,0);
lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
gl->addWidget(starttime=new QDateTimeEdit,lctr,1);
starttime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format"));
starttime->setCalendarPopup(true);
- starttime->setDateTime(QDateTime::fromTime_t(event.start()));
connect(starttime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(startTimeChanged(const QDateTime&)));
gl->addWidget(lab=new QLabel(tr("End Time:")),++lctr,0);
gl->addWidget(endtime=new QDateTimeEdit,lctr,1);
endtime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format"));
endtime->setCalendarPopup(true);
- endtime->setDateTime(QDateTime::fromTime_t(event.end()));
connect(endtime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(endTimeChanged(const QDateTime&)));
+ if(event.id().isNull()){
+ QDateTime tt(QDate::currentDate().addDays(1),QTime(20,0));//default: tomorrow 8pm
+ starttime->setDateTime(tt);
+ endtime->setDateTime(tt.addSecs(3600));
+ }else{//valid event: use the date and time from event
+ starttime->setDateTime(QDateTime::fromTime_t(event.start()));
+ endtime->setDateTime(QDateTime::fromTime_t(event.end()));
+ }
gl->addWidget(lab=new QLabel(tr("Room/Place:")),++lctr,0);
lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
capacity->setRange(0,1000000000);//it is unlikely that any show will attract more people!
capacity->setValue(event.capacity());
- gl->addWidget(lab=new QLabel(tr("Default Price:")),++lctr,0);
- lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
- gl->addWidget(price=new QLineEdit,lctr,1);
- price->setValidator(new QRegExpValidator(event.priceRegExp(),this));
- price->setText(event.priceString());
-
gl->addWidget(cancelcheck=new QCheckBox(tr("Event Cancelled:")),++lctr,0);
cancelcheck->setChecked(event.iscancelled());
- cancelcheck->setEnabled(false);
+ cancelcheck->setEnabled(!event.id().isNull() && req->hasRight(req->PChangeEvent_CancelEvent));
gl->addWidget(cancelreason=new QLineEdit,lctr,1);
cancelreason->setEnabled(event.iscancelled());
cancelreason->setText(event.cancelreason());
connect(cancelcheck,SIGNAL(toggled(bool)),cancelreason,SLOT(setEnabled(bool)));
- vl->addStretch();
+ tab->addTab(w=new QWidget,tr("Description"));
+ w->setLayout(vl2=new QVBoxLayout);
+ vl2->addWidget(new QLabel(tr("The description will be displayed on the web site, please use HTML syntax.")),0);
+ vl2->addWidget(description=new QTextEdit,10);
+ description->setPlainText(event.description());
+
+ tab->addTab(w=new QWidget,tr("Comment"));
+ w->setLayout(vl2=new QVBoxLayout);
+ vl2->addWidget(new QLabel(tr("The comment is for internal use only, please add any hints relevant for your collegues.")),0);
+ vl2->addWidget(comment=new QTextEdit,10);
+ comment->setPlainText(event.comment());
+
+ tab->addTab(w=new QWidget,tr("Prices"));
+ w->setLayout(vl2=new QVBoxLayout);
+ vl2->addWidget(pricetable=new QTableView,10);
+ vl2->addLayout(hl=new QHBoxLayout,0);
+ hl->addStretch(10);
+ hl->addWidget(p=new QPushButton(tr("Change Price")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(changePrice()));
+ hl->addWidget(p=new QPushButton(tr("Add Price")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(addPrice()));
+ hl->addWidget(p=new QPushButton(tr("Remove Price")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(removePrice()));
+ pricetable->setModel(pricemodel=new QStandardItemModel(this));
+ pricetable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ updatePrice();
vl->addLayout(hl=new QHBoxLayout,0);
hl->addStretch();
hl->addWidget(p=new QPushButton(tr("Save")));
- connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+// connect(p,SIGNAL(clicked()),this,SLOT(accept()));
connect(p,SIGNAL(clicked()),this,SLOT(writeBack()));
- hl->addWidget(p=new QPushButton(tr("Cancel")));
+ hl->addWidget(p=new QPushButton(tr("Close")));
connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+
+ setSizeGripEnabled(true);
}
void MEventEditor::writeBack()
event.settitle(title->text());
event.setstart(starttime->dateTime().toTime_t());
event.setend(endtime->dateTime().toTime_t());
-// event.setartist(artist->text());
- event.setroom(room->text());
- event.setdefaultprice(price->text());
event.setiscancelled(cancelcheck->isChecked());
event.setcancelreason(cancelreason->text());
event.setdescription(description->toPlainText());
+ event.setcomment(comment->toPlainText());
event.setcapacity(capacity->value());
+ event.setroom(room->text());
+ //artist is set in other methods already
+ //prices are changed by the methods reacting to the table
//send to server
- /*TODO
- event.makeValid();
- QString r=event.save();
- if(r!=""){
- QMessageBox::warning(this,tr("Warning"),tr("Problem while uploading event: %s").arg(r));
- }else
- accept();*/
+ if(event.id().isNull()){
+ MTCreateEvent ce=req->queryCreateEvent(event);
+ if(ce.hasError())
+ QMessageBox::warning(this,tr("Warning"),tr("Error while creating event: %1").arg(ce.errorString()));
+ }else{
+ MTChangeEvent ce=req->queryChangeEvent(event);
+ if(ce.hasError())
+ QMessageBox::warning(this,tr("Warning"),tr("Error while changing event: %1").arg(ce.errorString()));
+ }
+}
+
+void MEventEditor::updatePrice()
+{
+ pricemodel->clear();
+ pricemodel->insertColumns(0,5);
+ pricemodel->setHorizontalHeaderLabels(QStringList()<<tr("Price Category")<<tr("Price")<<tr("Ticket Capacity")<<tr("Tickets")<<tr("Seats Blocked"));
+ QList<MOEventPrice> prc=event.price();
+ pricemodel->insertRows(0,prc.size());
+ for(int i=0;i<prc.size();i++){
+ pricemodel->setData(pricemodel->index(i,0),prc[i].pricecategory().value().name().value());
+ pricemodel->setData(pricemodel->index(i,0),prc[i].pricecategoryid().value(),Qt::UserRole);
+ pricemodel->setData(pricemodel->index(i,1),cent2str(prc[i].price().value()));
+ pricemodel->setData(pricemodel->index(i,2),prc[i].maxavailable().value());
+ pricemodel->setData(pricemodel->index(i,3),prc[i].amounttickets().value());
+ pricemodel->setData(pricemodel->index(i,4),prc[i].amountticketsblock().value());
+ }
+ pricetable->resizeColumnsToContents();
+}
+
+MEEPriceEdit::MEEPriceEdit(QWidget*pw,MOEventPrice prc,int maxseats)
+ :QDialog(pw)
+{
+ QFormLayout*gl;
+ QVBoxLayout*vl;
+ QHBoxLayout*hl;
+ QPushButton*p;
+ QDialog d(this);
+ setWindowTitle(tr("Change Price"));
+ setLayout(vl=new QVBoxLayout);
+ vl->addLayout(gl=new QFormLayout,10);
+ gl->addRow(tr("Price category:"),new QLabel(prc.pricecategory().value().name()));
+ gl->addRow(tr("Price:"),price=new MCentSpinBox(&d,prc.price()));
+ gl->addRow(tr("Maximum Seats:"),cap=new QSpinBox);
+ cap->setRange(prc.amountticketsblock(),maxseats);
+ cap->setValue(prc.maxavailable());
+ vl->addSpacing(10);
+ vl->addStretch(1);
+ vl->addLayout(hl=new QHBoxLayout,0);
+ hl->addStretch(10);
+ hl->addWidget(p=new QPushButton(tr("Ok")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+ hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+void MEventEditor::changePrice()
+{
+ //get selection
+ QModelIndex idx=pricetable->currentIndex();
+ if(!idx.isValid())return;
+ int pid=pricemodel->data(pricemodel->index(idx.row(),0),Qt::UserRole).toInt();
+ int lid=-1;
+ QList<MOEventPrice> prc=event.price();
+ for(int i=0;i<prc.size();i++)
+ if(prc[i].pricecategoryid().value()==pid){
+ lid=i;
+ break;
+ }
+ if(lid<0)return;
+ //display dialog
+ MEEPriceEdit d(this,prc[lid],capacity->value());
+ if(d.exec()!=QDialog::Accepted)return;
+ //use data
+ prc[lid].setprice(d.price->value());
+ prc[lid].setmaxavailable(d.cap->value());
+ event.setprice(prc);
+ updatePrice();
+}
+
+void MEventEditor::addPrice()
+{
+ //get category
+ MPriceCategoryDialog pcd(this);
+ if(pcd.exec()!=QDialog::Accepted)return;
+ MOPriceCategory cat=pcd.selection();
+ //convert category into price
+ if(cat.pricecategoryid().isNull())return;
+ MOEventPrice ep;
+ ep.setpricecategory(cat);
+ ep.setpricecategoryid(cat.pricecategoryid());
+ ep.setflags(cat.flags());
+ //TODO: execute formula
+ //get local properties
+ MEEPriceEdit d(this,ep,capacity->value());
+ if(d.exec()!=QDialog::Accepted)return;
+ //use data
+ ep.setprice(d.price->value());
+ ep.setmaxavailable(d.cap->value());
+ event.setprice(event.price()<<ep);
+ updatePrice();
+}
+
+void MEventEditor::removePrice()
+{
+ //get selection
+ QModelIndex idx=pricetable->currentIndex();
+ if(!idx.isValid())return;
+ int pid=pricemodel->data(pricemodel->index(idx.row(),0),Qt::UserRole).toInt();
+ int lid=-1;
+ QList<MOEventPrice> prc=event.price();
+ for(int i=0;i<prc.size();i++)
+ if(prc[i].pricecategoryid().value()==pid){
+ lid=i;
+ break;
+ }
+ if(lid<0)return;
+ //check
+ if(prc[lid].amounttickets().value()>0){
+ QMessageBox::warning(this,tr("Warning"),tr("Cannot remove price '%1' - it has tickets in the database.").arg(prc[lid].pricecategory().value().name().value()));
+ return;
+ }
+ //remove
+ prc.removeAt(lid);
+ event.setprice(prc);
+ updatePrice();
}
void MEventEditor::selectRoom()
}
}
+void MEventEditor::selectArtist()
+{
+ QList<MOArtist>rlst=req->queryGetAllArtists().getartists();
+ QDialog d;
+ d.setWindowTitle(tr("Select an Artist"));
+ QVBoxLayout*vl;
+ d.setLayout(vl=new QVBoxLayout);
+ QListWidget*rlstw;
+ vl->addWidget(rlstw=new QListWidget,10);
+ for(int i=0;i<rlst.size();i++){
+ QListWidgetItem*it=new QListWidgetItem(rlst[i].name());
+ it->setData(Qt::UserRole,i);
+ rlstw->addItem(it);
+ }
+ QHBoxLayout*hl;
+ vl->addLayout(hl=new QHBoxLayout,0);
+ hl->addStretch(10);
+ QPushButton*p;
+ hl->addWidget(p=new QPushButton(tr("New...","new artist")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(newArtist()));
+ connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+ p->setEnabled(req->hasRight(req->RCreateArtist));
+ hl->addWidget(p=new QPushButton(tr("Select","select artist")),0);
+ connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+ hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+ connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+ if(d.exec()==QDialog::Rejected)return;
+ //get selection
+ QList<QListWidgetItem*>wlst=rlstw->selectedItems();
+ if(wlst.size()<1)return;
+ artist->setText(wlst[0]->text());
+ event.setartist(rlst[wlst[0]->data(Qt::UserRole).toInt()]);
+ event.setartistid(rlst[wlst[0]->data(Qt::UserRole).toInt()].id());
+}
+
+void MEventEditor::newArtist()
+{
+ //TODO: do more intelligent input for new artist
+ QString rid=QInputDialog::getText(this,tr("New Artist"),tr("Name of new artist:"));
+ if(rid!=""){
+ MTCreateArtist cr=req->queryCreateArtist(rid,"","");
+ if(cr.hasError()){
+ QMessageBox::warning(this,tr("Warning"),tr("Error while creating new artist: %1").arg(cr.errorString()));
+ return;
+ }
+ artist->setText(rid);
+ event.setartist(cr.getartist());
+ event.setartistid(cr.getartist().value().id());
+ }
+}
+
void MEventEditor::startTimeChanged(const QDateTime&st)
{
QDateTime et=endtime->dateTime();
class QLabel;
class QLineEdit;
class QSpinBox;
+class QStandardItemModel;
+class QTableView;
class QTextEdit;
+/**create and edit events*/
class MEventEditor:public QDialog
{
Q_OBJECT
public:
+ /**opens the editor, retrieves the event automatically if given*/
MEventEditor(QWidget*,qint64 id=-1);
private slots:
+ /**sends the event back to the database*/
void writeBack();
+
+ /**room button has been clicked: open a list of rooms, select one*/
void selectRoom();
+ /**create a new room*/
void newRoom();
+ /**artist button has been clicked: open a list of artists, select one*/
+ void selectArtist();
+ /**create a new artist*/
+ void newArtist();
+
+ /**called when the start time of the event changes: validates the end time*/
void startTimeChanged(const QDateTime&);
+ /**called when the end time of the event changes: validates the start time*/
void endTimeChanged(const QDateTime&);
+
+ /**updates the price table*/
+ void updatePrice();
+ /**changes a price*/
+ void changePrice();
+ /**adds a price*/
+ void addPrice();
+ /**removes a price*/
+ void removePrice();
private:
MOEvent event;
QDateTimeEdit*starttime,*endtime;
- QLineEdit*title,*artist,*room,*price,*cancelreason;
+ QLineEdit*title,*artist,*room,*cancelreason;
QTextEdit*description,*comment;
QCheckBox*cancelcheck;
QSpinBox*capacity;
QLabel*eventid;
+ QTableView*pricetable;
+ QStandardItemModel*pricemodel;
+};
+
+class MCentSpinBox;
+class QSpinBox;
+
+/**helper class for event editor: edits a price */
+class MEEPriceEdit:public QDialog
+{
+ Q_OBJECT
+ protected:
+ friend class MEventEditor;
+ MCentSpinBox*price;
+ QSpinBox*cap;
+ MEEPriceEdit(QWidget*,MOEventPrice,int);
};
+
#endif
--- /dev/null
+//
+// C++ Implementation: pricecatdlg
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "pricecatdlg.h"
+#include "msinterface.h"
+
+#include <QBoxLayout>
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QListWidget>
+#include <QMessageBox>
+#include <QPushButton>
+
+MPriceCategoryDialog::MPriceCategoryDialog(QWidget*pw)
+ :QDialog(pw)
+{
+ m_cat=req->queryGetAllPriceCategories().getpricecategories();
+ setWindowTitle(tr("Select a Price Category"));
+ QVBoxLayout*vl;
+ setLayout(vl=new QVBoxLayout);
+ vl->addWidget(m_list=new QListWidget,10);
+ for(int i=0;i<m_cat.size();i++){
+ QListWidgetItem*it=new QListWidgetItem(m_cat[i].name());
+ it->setData(Qt::UserRole,i);
+ m_list->addItem(it);
+ }
+ QHBoxLayout*hl;
+ vl->addLayout(hl=new QHBoxLayout,0);
+ hl->addStretch(10);
+ QPushButton*p;
+ hl->addWidget(p=new QPushButton(tr("New...","new price category")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(newCat()));
+ p->setEnabled(req->hasRight(req->RCreateArtist));
+ hl->addWidget(p=new QPushButton(tr("Select","select price category")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+ hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+ connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+MOPriceCategory MPriceCategoryDialog::selection()const
+{
+ //get selection
+ QList<QListWidgetItem*>wlst=m_list->selectedItems();
+ if(wlst.size()<1)return MOPriceCategory();
+ return m_cat[wlst[0]->data(Qt::UserRole).toInt()];
+}
+
+void MPriceCategoryDialog::newCat()
+{
+ //TODO: remaining properties
+ //dialog
+ QDialog d;
+ d.setWindowTitle(tr("New Price Category"));
+ QVBoxLayout*vl;
+ d.setLayout(vl=new QVBoxLayout);
+ QFormLayout*fl;
+ vl->addLayout(fl=new QFormLayout,1);
+ QLineEdit*name,*abbr;
+ fl->addRow(tr("Category Name:"),name=new QLineEdit);
+ fl->addRow(tr("Category Abbreviation:"),abbr=new QLineEdit);
+ vl->addSpacing(10);
+ QHBoxLayout*hl;
+ vl->addLayout(hl=new QHBoxLayout,0);
+ hl->addStretch(10);
+ QPushButton*p;
+ hl->addWidget(p=new QPushButton(tr("Create")),0);
+ connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+ hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+ connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+ //ask
+ if(d.exec()!=QDialog::Accepted)return;
+ //get props, create cat
+ MOPriceCategory cat;
+ cat.setname(name->text());
+ cat.setabbreviation(abbr->text());
+ MTCreatePriceCategory cpc=req->queryCreatePriceCategory(cat);
+ if(cpc.hasError()){
+ QMessageBox::warning(this,tr("Warning"),tr("Error while creating new price category: %1").arg(cpc.errorString()));
+ return;
+ }
+ //add and select
+ cat=cpc.getpricecategory();
+ m_cat<<cat;
+ QListWidgetItem*it=new QListWidgetItem(cat.name());
+ it->setData(Qt::UserRole,m_cat.size()-1);
+ m_list->addItem(it);
+ m_list->setCurrentItem(it);
+}
--- /dev/null
+//
+// C++ Interface: pricecatdlg
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_PRICECATDLG_H
+#define MAGICSMOKE_PRICECATDLG_H
+
+#include <QDialog>
+
+#include "MOPriceCategory.h"
+
+class QListWidget;
+
+/**shows a list of price categories, allows to edit them, returns the one selected*/
+class MPriceCategoryDialog:public QDialog
+{
+ Q_OBJECT
+ public:
+ MPriceCategoryDialog(QWidget*p=0);
+
+ /**returns the current selection*/
+ MOPriceCategory selection()const;
+ private:
+ QListWidget*m_list;
+ QList<MOPriceCategory>m_cat;
+ private slots:
+ /**internal: called to create a new category*/
+ void newCat();
+};
+
+#endif
<Column name="formula" type="string"/>
<Column name="flags" type="string"/>
- <Preset><V col="name" val="normal"/><V col="abbreviation" val="norm"/></Preset>
+ <Preset>
+ <V col="pricecategoryid" val="1"/>
+ <V col="name" val="normal"/>
+ <V col="abbreviation" val="norm"/>
+ <V col="formula" val=""/>
+ <V col="flags" val=""/>
+ </Preset>
</Table>
<Table name="artist" backup="yes">
</Table>
<Class name="Artist">
+ <Abstract lang="php"/>
<Property name="id" type="int" id="yes"/>
<Property name="name" type="string"/>
<Property name="description" type="string"/>
</Mapping>
</Class>
- <Class name="Price">
+ <Transaction name="GetAllArtists">
+ <Call lang="php" method="$this->setartists(WOArtist::fromTableArrayartist(WTartist::selectFromDB('','ORDER BY artistname')));"/>
+ <Output>
+ <Var name="artists" type="List:Artist"/>
+ </Output>
+ </Transaction>
+ <Transaction name="CreateArtist">
+ <Input>
+ <Var name="name" type="string"/>
+ <Var name="description" type="string"/>
+ <Var name="comment" type="string"/>
+ </Input>
+ <Call lang="php" method="WOArtist::createArtist($this);"/>
+ <Output>
+ <Var name="artist" type="Artist"/>
+ </Output>
+ </Transaction>
+
+ <Class name="PriceCategory">
+ <Abstract lang="php"/>
+ <Property name="pricecategoryid" type="int"/>
+ <Property name="name" type="string"/>
+ <Property name="abbreviation" type="astring"/>
+ <Property name="formula" type="string"/>
+ <Property name="flags" type="string"/>
+ <Mapping table="pricecategory">
+ <Map column="pricecategoryid"/>
+ <Map column="name"/>
+ <Map column="abbreviation"/>
+ <Map column="formula"/>
+ <Map column="flags"/>
+ </Mapping>
+ </Class>
+
+ <Transaction name="GetAllPriceCategories">
+ <Call lang="php" method="$this->setpricecategories(WOPriceCategory::fromTableArraypricecategory(WTpricecategory::selectFromDB()));"/>
+ <Output>
+ <Var name="pricecategories" type="List:PriceCategory"/>
+ </Output>
+ </Transaction>
+
+ <Transaction name="CreatePriceCategory">
+ <Input>
+ <Var name="pricecategory" type="PriceCategory">properties as requested by user</Var>
+ </Input>
+ <Call lang="php" method="WOPriceCategory::createCategory($this);"/>
+ <Output>
+ <Var name="pricecategory" type="PriceCategory">properties as actually stored</Var>
+ </Output>
+ </Transaction>
+
+ <Class name="EventPrice">
+ <Abstract lang="php"/>
<Property name="eventid" type="int"/>
<Property name="pricecategoryid" type="int"/>
+ <Property name="pricecategory" type="PriceCategory"/>
<Property name="maxavailable" type="int32"/>
<Property name="price" type="int32"/>
<Property name="flags" type="string"/>
+
+ <Property name="amounttickets" type="int">calculated property: contains the amount of tickets currently contained in this price, ignored if sent from client</Property>
+ <Property name="amountticketsblock" type="int">calculated property: contains the amount of tickets currently contained in this price that are actually usable or reserved, ignored if sent from client</Property>
+
+ <Mapping table="eventprice">
+ <Map column="eventid"/>
+ <Map column="pricecategoryid"/>
+ <Map column="maxavailable"/>
+ <Map column="price"/>
+ <Map column="flags"/>
+ <Map property="pricecategory">
+ <Call lang="php" method="WOPriceCategory::fromTablepricecategory(WTpricecategory::getFromDB($table->pricecategoryid))"/>
+ </Map>
+ <Map property="amounttickets">
+ <Call lang="php" method="$data->getAmountTicketsFromDB()"/>
+ </Map>
+ <Map property="amountticketsblock">
+ <Call lang="php" method="$data->getAmountTicketsBlockFromDB()"/>
+ </Map>
+ </Mapping>
</Class>
<Class name="Event">
<Abstract lang="qt"/>
+ <Abstract lang="php"/>
<Property name="id" type="int" id="yes"/>
<Property name="start" type="int64"/>
<Property name="end" type="int64"/>
<Property name="capacity" type="int"/>
- <Property name="price" type="List:Price"/>
+ <Property name="price" type="List:EventPrice"/>
<Property name="title" type="string"/>
+ <Property name="artistid" type="int"/>
<Property name="artist" type="Artist"/>
<Property name="room" type="string"/>
<Property name="seatplanid" type="int"/>
<Mapping table="event">
<Map column="eventid" property="id"/>
<Map column="title"/>
+ <Map column="artistid"/>
<Map property="artist">
<Call lang="php" method="WOArtist::fromTableartist(WTartist::getFromDB($table->artistid))"/>
</Map>
<Map column="flags"/>
<Map column="tax"/>
<Map column="cancelreason"/>
+ <Map property="price">
+ <Call lang="php" method="WOEventPrice::fromTableArrayeventprice(WTeventprice::selectFromDB('eventid='.$GLOBALS['db']->escapeInt($table->eventid)))"/>
+ </Map>
</Mapping>
</Class>
<Transaction name="GetAllEvents">
<Input/>
- <Call lang="php" method="Event::getAllEvents($this);"/>
+ <Call lang="php" method="WOEvent::getAllEvents($this);"/>
<Output>
<Var name="events" type="List:Event"/>
</Output>
<Input>
<Var name="eventids" type="List:int"/>
</Input>
- <Call lang="php" method="Event::getEventList($this);"/>
+ <Call lang="php" method="WOEvent::getEventList($this);"/>
<Output>
<Var name="events" type="List:Event"/>
</Output>
</Transaction>
- <Transaction name="CreateEvent"/>
- <Transaction name="ChangeEvent"/>
+ <Transaction name="CreateEvent">
+ <Input>
+ <Var name="event" type="Event"/>
+ </Input>
+ <Call lang="php" method="WOEvent::createEvent($this);"/>
+ <Output>
+ <Var name="event" type="Event"/>
+ </Output>
+ </Transaction>
+ <Transaction name="ChangeEvent">
+ <Privilege name="CancelEvent">users with this privilege are allowed to set the iscancelled property and hence cancel or uncancel events</Privilege>
+ <Input>
+ <Var name="event" type="Event"/>
+ </Input>
+ <Call lang="php" method="WOEvent::changeEvent($this);"/>
+ <Output>
+ <Var name="event" type="Event"/>
+ </Output>
+ </Transaction>
<Transaction name="CancelEvent">
<Input>
<Var name="eventid" type="int"/>
<Var name="reason" type="string"/>
</Input>
+ <Call lang="php" method="WOEvent::cancelEvent($this);"/>
<Output/>
</Transaction>
code+="\tif(!$xml->loadXml(trim($txt)))";
code+="\n\t\tthrow WobXmlException(translate(\""+abstractClassName(cls)+"\",\"Unable to deserialize object of type "+className(cls)+": invalid XML.\"));";
code+="\n\treturn self::fromXml($xml,$xml->documentElement);\n}\n";
- code+="static public function fromXml($xml,$elem){\n\t$data=array();\n";
+ code+="static public function fromXml($xml,$elem){\n\t$data=new "+className(cls)+"();\n";
k=cls.propertyNames();
for(int i=0;i<k.size();i++){
//scan properties
if(cls.propertyIsList(k[i])){
- code+="\t$data[\""+k[i]+"\"]=array();\n";
- code+="\tforeach($elem->elementsByTagName(\""+k[i]+"\") as $el){\n";
+ code+="\t$data->clear_"+k[i]+"();\n";
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
if(cls.propertyIsObject(k[i])){
- code+="\t\t$data[\""+k[i]+"\"][]=WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el);\n";
+ code+="\t\t$data->add_"+k[i]+"(WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el));\n";
}else if(cls.propertyIsBlob(k[i])){
- code+="\t\t$data[\""+k[i]+"\"][]=base64_decode($el->textContent);\n";
+ code+="\t\t$data->add_"+k[i]+"(base64_decode($el->textContent));\n";
}else{
- code+="\t\t$data[\""+k[i]+"\"][]=$el->textContent;\n";
+ code+="\t\t$data->add_"+k[i]+"($el->textContent);\n";
}
code+="\t}\n";
}else{
if(cls.propertyIsObject(k[i])){
- code+="\tforeach($elem->elementsByTagName(\""+k[i]+"\") as $el){\n";
- code+="\t\t$data[\""+k[i]+"\"]=WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el);\n";
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
+ code+="\t\t$data->set_"+k[i]+"(WO"+cls.propertyPlainType(k[i])+"::fromXml($xml,$el));\n";
code+="\t}\n";
}else
if(cls.propertyIsAttribute(k[i])){
code+="\tif($elem->hasAttribute(\""+k[i]+"\"))\n";
- code+="\t\t$data[\""+k[i]+"\"]=$elem->getAttribute(\""+k[i]+"\");\n";
+ code+="\t\t$data->set_"+k[i]+"($elem->getAttribute(\""+k[i]+"\"));\n";
}else{
- code+="\tforeach($elem->elementsByTagName(\""+k[i]+"\") as $el){\n";
+ code+="\tforeach(WObject::elementsByTagName($elem,\""+k[i]+"\") as $el){\n";
if(cls.propertyIsBlob(k[i]))
- code+="\t\t$data[\""+k[i]+"\"]=base64_decode($elem->textContent);\n";
+ code+="\t\t$data->set_"+k[i]+"(base64_decode($el->textContent));\n";
else
- code+="\t\t$data[\""+k[i]+"\"]=$elem->textContent;\n";
+ code+="\t\t$data->set_"+k[i]+"($el->textContent);\n";
code+="\t}\n";
}
}
}
- //TODO: use setters (be careful with blob)
- code+="\treturn new "+className(cls)+"($data);\n}\n";
+ code+="\treturn $data;\n}\n";
return code;
}
QString code;
QStringList k=cls.mappingTables();
for(int i=0;i<k.size();i++){
+ WocTable tab=WocProcessor::instance()->table(k[i]);
+ //single object mapping
code+="\nstatic public function fromTable"+k[i]+"($table){\n";
code+="\t$data=new WO"+cls.name()+"();\n";
QMap<QString,QString>map=cls.mapping(k[i]);
else code+="\t$data->prop_"+mapk[j]+"=$table->"+map[mapk[j]]+";\n";
}
code+="\treturn $data;\n}\n";
+ //wrapper for multi-object mapping
code+="static public function fromTableArray"+k[i]+"(array $table){\n\t$ret=array();\n";
code+="\tfor($i=0;$i<count($table);$i++)$ret[]=self::fromTable"+k[i]+"($table[$i]);\n";
code+="\treturn $ret;\n}\n";
+ //reverse mapping
+ code+="public function toTable"+k[i]+"(&$table){\n";
+ for(int j=0;j<mapk.size();j++){
+ //do not reverse translate method conversions
+ QString meth=cls.mapMethod(k[i],mapk[j],"php").trimmed();
+ if(meth!="")continue;
+ //check that column exists
+ if(tab.hasColumn(map[mapk[j]])){
+ code+="\tif($this->prop_"+mapk[j]+"!==null && $table->"+map[mapk[j]]+"!=$this->prop_"+mapk[j]+")\n";
+ code+="\t\t$table->"+map[mapk[j]]+"=$this->prop_"+mapk[j]+";\n";
+ }
+ }
+ code+="\treturn $table;\n}\n";
}
return code;
/**returns the type without list or xml qualifiers*/
QString plainType(QString t)const{
if(t.startsWith("List:"))t=t.mid(5);
- t=t.split("/",QString::SkipEmptyParts)[0];
+ QStringList l=t.split("/",QString::SkipEmptyParts);
+ if(l.size()>0)t=l[0];else t="unknown";
return t;
}
/**returns the XML serializer for Object types*/
if(tp=="astring" || tp=="string")r+="QString";else
if(tp=="int"||tp=="int32"||tp=="int64")r+="qint64";else
if(tp=="blob")r+="QByteArray";else
- if(tp=="bool")r+="bool";
- else r+=m_prefix+"O"+tp.split("/",QString::SkipEmptyParts).at(0);
+ if(tp=="bool")r+="bool";else
+ if(tp==""){
+ qDebug("Warning: the final type of property %s is empty!",v.toAscii().data());
+ r+="void";
+ }else r+=m_prefix+"O"+tp.split("/",QString::SkipEmptyParts).at(0);
r+=e;r+=" ";
return r;
}
}
return $this->capacity - $amt;
}
-
- /**XML iface: get all events*/
- public static function getAllEvents($trans)
- {
- $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("","ORDER BY starttime"));
- $trans->setevents($evlst);
- }
-
- /**XML iface: get list of events*/
- public static function getEventList($trans)
- {
- global $db;
- $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("eventid in ".$db->escapeIntList($trans->geteventids())));
- $trans->setevents($evlst);
- }
};
/**machine-function: get the requested events as XML data*/
{
global $db,$dbScheme;
self::fprint("<br>Deleting Target DB...\n");
- foreach($dbScheme->tableNames() as $t)
+ foreach(array_reverse($dbScheme->tableNames()) as $t)
$db->deleteRows($t,"1=1");
self::fprint("<br>Resetting presets...\n");
foreach($dbScheme->tableNames() as $t)
//create artist
$evt["artistid"]=self::mkartist($evt["artist"]);
unset($evt["artist"]);
- //create price
- $db->insert("eventprice",array("eventid"=>$evt["eventid"],"pricecategoryid"=>$prc,
- "maxavailable"=>$evt["capacity"],"price"=>$evt["defaultprice"],
- "flags"=>""));
+ //remember price
+ $dfprc=$evt["defaultprice"];
unset($evt["defaultprice"]);
//convert and copy data
$evt["comment"]=$evt["description"];
$evt["flags"]="";$evt["tax"]=0;
$evt["iscancelled"]=($evt["cancelreason"]!="");
self::insert("event",$evt);
+ //create price
+ $db->insert("eventprice",array("eventid"=>$evt["eventid"],"pricecategoryid"=>$prc,
+ "maxavailable"=>$evt["capacity"],"price"=>$dfprc,
+ "flags"=>""));
}
}
return $r;
}
- /**returns the property*/
+ /**returns the property/column*/
public function __get($name)
{
//verify name
else return null;
}
+ /**checks whether a column exists*/
public function __isset($name)
{
global $db;
else return false;
}
+ /**unsets column-properties to NULL*/
public function __unset($name)
{
global $dbScheme;
if($this->hasProperty($name))$this->cdata[$name]=null;
}
+ /**returns whether any property has changed since the last DB sync*/
+ public function isChanged()
+ {
+ return count($this->cdata)>0;
+ }
+
+ /**returns whether a specific column has changed since the last DB sync*/
+ public function isColumnChanged($c)
+ {
+ return array_key_exists($c,$this->cdata);
+ }
+
/**insert the object under a new primary key value into the DB (implicitly calls newKey); returns true on success*/
public function insert()
{
--- /dev/null
+<?
+//
+// PHP Implementation: artist
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class WOArtist extends WOArtistAbstract
+{
+ /**called from the CreateArtist transaction*/
+ static public function createArtist($trans)
+ {
+ $nm=trim($trans->getname());
+ if($nm===false || $nm==""){
+ $trans->abortWithError(tr("Artist name must not be empty!"));
+ return;
+ }
+ //check for doublettes
+ global $db;
+ $at=WTartist::selectFromDB('artistname='.$db->escapeString($nm));
+ if(count($at)>0){
+ $trans->abortWithError(tr("An artist with this name already exists."));
+ return;
+ }
+ //create
+ $at=WTartist::newRow();
+ $at->artistname=$nm;
+ $at->description=$trans->getdescription();
+ $at->comment=$trans->getcomment();
+ $at->insert();
+ //return
+ $trans->setartist(WOArtist::fromTableartist($at));
+ }
+};
+?>
\ No newline at end of file
//
//
-$AUTOCLASS["WORole"]="inc/wext/role.php";
-$AUTOCLASS["WOOrderInfo"]="inc/wext/order.php";
+$AUTOCLASS["WOArtist"]="inc/wext/artist.php";
+$AUTOCLASS["WOEventPrice"]="inc/wext/event.php";
+$AUTOCLASS["WOEvent"]="inc/wext/event.php";
$AUTOCLASS["WOOrder"]="inc/wext/order.php";
-$AUTOCLASS["WOTicket"]="inc/wext/ticket.php";
-$AUTOCLASS["WOTemplate"]="inc/wext/template.php";
+$AUTOCLASS["WOOrderInfo"]="inc/wext/order.php";
+$AUTOCLASS["WOPriceCategory"]="inc/wext/price.php";
+$AUTOCLASS["WORole"]="inc/wext/role.php";
$AUTOCLASS["WORoom"]="inc/wext/room.php";
+$AUTOCLASS["WOTemplate"]="inc/wext/template.php";
+$AUTOCLASS["WOTicket"]="inc/wext/ticket.php";
?>
\ No newline at end of file
--- /dev/null
+<?
+//
+// PHP Implementation: event
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class WOEventPrice extends WOEventPriceAbstract
+{
+ /**used by table mapping to count tickets*/
+ public function getAmountTicketsFromDB()
+ {
+ global $db;
+ $res=$db->select("ticket","count(*)as count", "eventid=".$db->escapeInt($this->prop_eventid)." AND pricecategoryid=".$db->escapeInt($this->prop_pricecategoryid));
+ return $res[0]["count"];
+ }
+ /**used by table mapping to count tickets*/
+ public function getAmountTicketsBlockFromDB()
+ {
+ global $db;
+ $res=$db->select("ticket","status", "eventid=".$db->escapeInt($this->prop_eventid)." AND pricecategoryid=".$db->escapeInt($this->prop_pricecategoryid));
+ $cnt=0;
+ foreach($res as $r)
+ if($r["status"] & WTticket::MaskBlock)
+ $cnt++;
+ return $cnt;
+ }
+};
+
+class WOEvent extends WOEventAbstract
+{
+ /**XML iface: get all events*/
+ public static function getAllEvents($trans)
+ {
+ $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("","ORDER BY starttime"));
+ $trans->setevents($evlst);
+ }
+
+ /**XML iface: get list of events*/
+ public static function getEventList($trans)
+ {
+ global $db;
+ $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("eventid in ".$db->escapeIntList($trans->geteventids())));
+ $trans->setevents($evlst);
+ }
+
+ /**called by CreateEvent transaction*/
+ public static function createEvent($trans)
+ {
+ //get input
+ $evt=$trans->getevent();
+ if(!is_a($evt,"WOEvent")){
+ $trans->abortWithError(tr("The event to be created must be a valid event object!"));
+ return;
+ }
+ //convert for DB
+ $tab=WTevent::newRow();
+ $evt->toTableevent($tab);
+ //make sure it fits and is not cancelled
+ $tab->revert("eventid");
+ $tab->iscancelled=false;
+ $tab->revert("cancelreason");
+ //create
+ $tab->insert();
+ //remaining conversions
+ $evt->prop_id=$tab->eventid;
+ $evt->syncPricesToDB();
+ //return
+ $trans->setevent(WOEvent::fromTableevent($tab));
+ }
+
+ /**called by ChangeEvent transaction*/
+ public static function changeEvent($trans)
+ {
+ //get input
+ $evt=$trans->getevent();
+ if(!is_a($evt,"WOEvent")){
+ $trans->abortWithError(tr("The event to be changed must be a valid event object!"));
+ return;
+ }
+ $tab=WTevent::getFromDB($evt->get_id());
+ if($tab === false){
+ $trans->abortWithError(tr("The event is not valid."));
+ return;
+ }
+ //copy stuff
+ $evt->toTableevent($tab);
+ //check for cancel
+ if($tab->isColumnChanged("iscancelled") && $tab->iscancelled){
+ if($trans->havePrivilege(WtrChangeEvent::Priv_CancelEvent)){
+ //cancel tickets
+ $evt->cancelAllTickets();
+ }else{
+ //alarm
+ $trans->abortWithError(tr("You do not have the privilege to cancel events."));
+ return;
+ }
+ }
+ //now sync
+ $tab->update();
+ $evt->syncPricesToDB();
+ //return
+ $trans->setevent(WOEvent::fromTableevent($tab));
+ }
+
+ /**helper function for create/changeEvent - pushes the current list of prices to the database*/
+ public function syncPricesToDB()
+ {
+ global $db;
+ $dbprc=WTeventprice::selectFromDB("eventid=".$db->escapeInt($this->prop_id));
+ //sort
+ $dbids=array();$dbp=array();
+ foreach($dbprc as $p){
+ $dbp[$p->pricecategoryid]=$p;
+ $dbids[]=$p->pricecategoryid;
+ }
+ $evids=array();
+ foreach($this->prop_price as $p)$evids[]=$p->get_pricecategoryid();
+ //delete unneeded ones
+ foreach($dbprc as $p){
+ if(!in_array($p->pricecategoryid,$evids)){
+ $p->deleteFromDB();
+ }
+ }
+ //create new ones, change existing ones
+ foreach($this->prop_price as $p){
+ $pcid=$p->get_pricecategoryid();
+ if(in_array($pcid,$dbids)){
+ //exists in DB, compare
+ $pp=$dbp[$pcid];
+ $p->toTableeventprice($pp);
+ $pp->revert("eventid");
+ if($pp->eventid != $this->prop_id)
+ $pp->eventid = $this->prop_id;
+ if($pp->isChanged())
+ $pp->update();
+ }else{
+ //does not exist yet
+ $tab=WTeventprice::newRow();
+ $p->toTableeventprice($tab);
+ $tab->eventid=$this->prop_id;//we are paranoid!
+ $tab->insert();
+ }
+ }
+ }
+
+ /**called by CancelEvent transaction*/
+ static public function cancelEvent($trans)
+ {
+ $tab=WTevent::getFromDB($trans->geteventid());
+ if(!is_a($tab,"WTevent")){
+ $trans->abortWithError(tr("This is not a valid event."));
+ return;
+ }
+ //cancel
+ $tab->iscancelled=true;
+ $tab->cancelreason=$trans->getreason();
+ $tab->update();
+ WOEvent::fromTableevent($tab)->cancelAllTickets();
+ }
+
+ /**helper function: cancels all usable tickets of this event*/
+ public function cancelAllTickets()
+ {
+ global $db;
+ $ticks=WTticket::selectFromDB("eventid=".$db->escapeint($this->prop_eventid));
+ foreach($ticks as $t){
+ if($t->status & WTticket::MaskReturnable){
+ $t->status=WTticket::Refund;
+ $t->update();
+ }
+ }
+ }
+};
+
+?>
\ No newline at end of file
--- /dev/null
+<?
+//
+// PHP Implementation: price
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class WOPriceCategory extends WOPriceCategoryAbstract
+{
+ /**called from CreatePriceCategory transaction*/
+ static public function createCategory($trans)
+ {
+ $cat=$trans->getpricecategory();
+ if(!is_a($cat,"WOPriceCategory")){
+ $trans->abortWithError(tr("New Category must be a valid object."));
+ return;
+ }
+ //TODO: verify that name and abbrev. are unique
+ //convert
+ $tab=WTpricecategory::newRow();
+ $cat->toTablepricecategory($tab);
+ $tab->revert("pricecategoryid");
+ $tab->insert();
+ //return
+ $trans->setpricecategory(WOPriceCategory::fromTablepricecategory($tab));
+ }
+};
+
+?>
\ No newline at end of file