From 642b75592d536676d33c81361d94facc959e4c78 Mon Sep 17 00:00:00 2001 From: konrad Date: Sun, 3 Jan 2010 18:26:35 +0000 Subject: [PATCH] event editing possible again git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@396 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- src/dialogs/dialogs.pri | 6 +- src/dialogs/eventedit.cpp | 281 +++++++++++++++++++++++++++++++++++++------ src/dialogs/eventedit.h | 43 +++++++- src/dialogs/pricecatdlg.cpp | 97 +++++++++++++++ src/dialogs/pricecatdlg.h | 39 ++++++ wob/event.wolf | 118 +++++++++++++++++- woc/phpout.cpp | 43 +++++-- woc/processor.h | 3 +- woc/qtout.cpp | 7 +- www/inc/classes/event.php | 15 --- www/inc/db/dbupgrade.php | 12 +- www/inc/wbase/table.php | 16 +++- www/inc/wext/artist.php | 41 +++++++ www/inc/wext/autoload.php | 12 ++- www/inc/wext/event.php | 182 ++++++++++++++++++++++++++++ www/inc/wext/price.php | 35 ++++++ 16 files changed, 858 insertions(+), 92 deletions(-) create mode 100644 src/dialogs/pricecatdlg.cpp create mode 100644 src/dialogs/pricecatdlg.h create mode 100644 www/inc/wext/artist.php create mode 100644 www/inc/wext/event.php create mode 100644 www/inc/wext/price.php diff --git a/src/dialogs/dialogs.pri b/src/dialogs/dialogs.pri index d8208c7..4e1a4e9 100644 --- a/src/dialogs/dialogs.pri +++ b/src/dialogs/dialogs.pri @@ -7,7 +7,8 @@ HEADERS += \ dialogs/shipping.h \ dialogs/customerdlg.h \ dialogs/checkdlg.h \ - dialogs/passwdchg.h + dialogs/passwdchg.h \ + dialogs/pricecatdlg.h SOURCES += \ dialogs/configdialog.cpp \ @@ -18,6 +19,7 @@ SOURCES += \ 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 diff --git a/src/dialogs/eventedit.cpp b/src/dialogs/eventedit.cpp index 0a8779c..a8d1b2d 100644 --- a/src/dialogs/eventedit.cpp +++ b/src/dialogs/eventedit.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,14 +24,18 @@ #include #include #include +#include +#include #include #include -#include -#include +#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){ @@ -44,19 +49,24 @@ MEventEditor::MEventEditor(QWidget*w,qint64 id) 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); @@ -65,25 +75,18 @@ MEventEditor::MEventEditor(QWidget*w,qint64 id) 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); @@ -91,8 +94,15 @@ MEventEditor::MEventEditor(QWidget*w,qint64 id) 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); @@ -109,29 +119,50 @@ MEventEditor::MEventEditor(QWidget*w,qint64 id) 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() @@ -140,21 +171,140 @@ 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()< prc=event.price(); + pricemodel->insertRows(0,prc.size()); + for(int i=0;isetData(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 prc=event.price(); + for(int i=0;ivalue()); + 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()<currentIndex(); + if(!idx.isValid())return; + int pid=pricemodel->data(pricemodel->index(idx.row(),0),Qt::UserRole).toInt(); + int lid=-1; + QList prc=event.price(); + for(int i=0;i0){ + 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() @@ -201,6 +351,57 @@ void MEventEditor::newRoom() } } +void MEventEditor::selectArtist() +{ + QListrlst=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;isetData(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 + QListwlst=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(); diff --git a/src/dialogs/eventedit.h b/src/dialogs/eventedit.h index 8fa2207..befb253 100644 --- a/src/dialogs/eventedit.h +++ b/src/dialogs/eventedit.h @@ -23,29 +23,70 @@ class QDateTimeEdit; 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 diff --git a/src/dialogs/pricecatdlg.cpp b/src/dialogs/pricecatdlg.cpp new file mode 100644 index 0000000..211712c --- /dev/null +++ b/src/dialogs/pricecatdlg.cpp @@ -0,0 +1,97 @@ +// +// C++ Implementation: pricecatdlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2010 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "pricecatdlg.h" +#include "msinterface.h" + +#include +#include +#include +#include +#include +#include + +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;isetData(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 + QListwlst=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<setData(Qt::UserRole,m_cat.size()-1); + m_list->addItem(it); + m_list->setCurrentItem(it); +} diff --git a/src/dialogs/pricecatdlg.h b/src/dialogs/pricecatdlg.h new file mode 100644 index 0000000..79af960 --- /dev/null +++ b/src/dialogs/pricecatdlg.h @@ -0,0 +1,39 @@ +// +// C++ Interface: pricecatdlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2010 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_PRICECATDLG_H +#define MAGICSMOKE_PRICECATDLG_H + +#include + +#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; + QListm_cat; + private slots: + /**internal: called to create a new category*/ + void newCat(); +}; + +#endif diff --git a/wob/event.wolf b/wob/event.wolf index f98ef76..ecc405a 100644 --- a/wob/event.wolf +++ b/wob/event.wolf @@ -29,7 +29,13 @@ - + + + + + + + @@ -70,6 +76,7 @@
+ @@ -83,22 +90,97 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + properties as requested by user + + + + properties as actually stored + + + + + + + + calculated property: contains the amount of tickets currently contained in this price, ignored if sent from client + calculated property: contains the amount of tickets currently contained in this price that are actually usable or reserved, ignored if sent from client + + + + + + + + + + + + + + + + + + - + + @@ -113,6 +195,7 @@ + @@ -127,6 +210,9 @@ + + + @@ -155,7 +241,7 @@ - + @@ -165,20 +251,38 @@ - + - - + + + + + + + + + + + users with this privilege are allowed to set the iscancelled property and hence cancel or uncancel events + + + + + + + + + diff --git a/woc/phpout.cpp b/woc/phpout.cpp index 74cfbc8..c062959 100644 --- a/woc/phpout.cpp +++ b/woc/phpout.cpp @@ -668,42 +668,41 @@ QString WocPHPServerOut::classDeserializers(const WocClass&cls) 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;itextContent);\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; } @@ -713,6 +712,8 @@ QString WocPHPServerOut::classMappings(const WocClass&cls) QString code; QStringList k=cls.mappingTables(); for(int i=0;itable(k[i]); + //single object mapping code+="\nstatic public function fromTable"+k[i]+"($table){\n"; code+="\t$data=new WO"+cls.name()+"();\n"; QMapmap=cls.mapping(k[i]); @@ -723,9 +724,23 @@ QString WocPHPServerOut::classMappings(const WocClass&cls) 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"+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; diff --git a/woc/processor.h b/woc/processor.h index a59d84b..845cbbe 100644 --- a/woc/processor.h +++ b/woc/processor.h @@ -300,7 +300,8 @@ class WocTransaction /**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*/ diff --git a/woc/qtout.cpp b/woc/qtout.cpp index 813b448..7f3482e 100644 --- a/woc/qtout.cpp +++ b/woc/qtout.cpp @@ -785,8 +785,11 @@ QString WocQtClientOut::qttype(const WocTransaction&trn,QString v,InOut io) 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; } diff --git a/www/inc/classes/event.php b/www/inc/classes/event.php index 293c7e0..0d810b9 100644 --- a/www/inc/classes/event.php +++ b/www/inc/classes/event.php @@ -140,21 +140,6 @@ class Event } 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*/ diff --git a/www/inc/db/dbupgrade.php b/www/inc/db/dbupgrade.php index 98ec1fd..3152958 100644 --- a/www/inc/db/dbupgrade.php +++ b/www/inc/db/dbupgrade.php @@ -90,7 +90,7 @@ class DBUpgrade { global $db,$dbScheme; self::fprint("
Deleting Target DB...\n"); - foreach($dbScheme->tableNames() as $t) + foreach(array_reverse($dbScheme->tableNames()) as $t) $db->deleteRows($t,"1=1"); self::fprint("
Resetting presets...\n"); foreach($dbScheme->tableNames() as $t) @@ -241,16 +241,18 @@ class DBUpgrade //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"=>"")); } } diff --git a/www/inc/wbase/table.php b/www/inc/wbase/table.php index b706631..c95eed4 100644 --- a/www/inc/wbase/table.php +++ b/www/inc/wbase/table.php @@ -115,7 +115,7 @@ abstract class WobTable return $r; } - /**returns the property*/ + /**returns the property/column*/ public function __get($name) { //verify name @@ -129,6 +129,7 @@ abstract class WobTable else return null; } + /**checks whether a column exists*/ public function __isset($name) { global $db; @@ -138,6 +139,7 @@ abstract class WobTable else return false; } + /**unsets column-properties to NULL*/ public function __unset($name) { global $dbScheme; @@ -145,6 +147,18 @@ abstract class WobTable 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() { diff --git a/www/inc/wext/artist.php b/www/inc/wext/artist.php new file mode 100644 index 0000000..593f3cf --- /dev/null +++ b/www/inc/wext/artist.php @@ -0,0 +1,41 @@ +, (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 diff --git a/www/inc/wext/autoload.php b/www/inc/wext/autoload.php index d51e01e..5eadba0 100644 --- a/www/inc/wext/autoload.php +++ b/www/inc/wext/autoload.php @@ -11,10 +11,14 @@ // // -$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 diff --git a/www/inc/wext/event.php b/www/inc/wext/event.php new file mode 100644 index 0000000..6714c04 --- /dev/null +++ b/www/inc/wext/event.php @@ -0,0 +1,182 @@ +, (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 diff --git a/www/inc/wext/price.php b/www/inc/wext/price.php new file mode 100644 index 0000000..d1a4bb7 --- /dev/null +++ b/www/inc/wext/price.php @@ -0,0 +1,35 @@ +, (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 -- 1.7.2.5