event editing possible again
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 3 Jan 2010 18:26:35 +0000 (18:26 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 3 Jan 2010 18:26:35 +0000 (18:26 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@396 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

16 files changed:
src/dialogs/dialogs.pri
src/dialogs/eventedit.cpp
src/dialogs/eventedit.h
src/dialogs/pricecatdlg.cpp [new file with mode: 0644]
src/dialogs/pricecatdlg.h [new file with mode: 0644]
wob/event.wolf
woc/phpout.cpp
woc/processor.h
woc/qtout.cpp
www/inc/classes/event.php
www/inc/db/dbupgrade.php
www/inc/wbase/table.php
www/inc/wext/artist.php [new file with mode: 0644]
www/inc/wext/autoload.php
www/inc/wext/event.php [new file with mode: 0644]
www/inc/wext/price.php [new file with mode: 0644]

index d8208c7..4e1a4e9 100644 (file)
@@ -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
index 0a8779c..a8d1b2d 100644 (file)
@@ -15,6 +15,7 @@
 #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){
@@ -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()<<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()
@@ -201,6 +351,57 @@ void MEventEditor::newRoom()
        }
 }
 
+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();
index 8fa2207..befb253 100644 (file)
@@ -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 (file)
index 0000000..211712c
--- /dev/null
@@ -0,0 +1,97 @@
+//
+// 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);
+}
diff --git a/src/dialogs/pricecatdlg.h b/src/dialogs/pricecatdlg.h
new file mode 100644 (file)
index 0000000..79af960
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// 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
index f98ef76..ecc405a 100644 (file)
                <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">
@@ -70,6 +76,7 @@
        </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>
        
index 74cfbc8..c062959 100644 (file)
@@ -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;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;
 }
 
@@ -713,6 +712,8 @@ QString WocPHPServerOut::classMappings(const WocClass&cls)
        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]);
@@ -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<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;
index a59d84b..845cbbe 100644 (file)
@@ -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*/
index 813b448..7f3482e 100644 (file)
@@ -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;
 }
index 293c7e0..0d810b9 100644 (file)
@@ -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*/
index 98ec1fd..3152958 100644 (file)
@@ -90,7 +90,7 @@ class DBUpgrade
        {
                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)
@@ -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"=>""));
                }
        }
        
index b706631..c95eed4 100644 (file)
@@ -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 (file)
index 0000000..593f3cf
--- /dev/null
@@ -0,0 +1,41 @@
+<?
+//
+// 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
index d51e01e..5eadba0 100644 (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
diff --git a/www/inc/wext/event.php b/www/inc/wext/event.php
new file mode 100644 (file)
index 0000000..6714c04
--- /dev/null
@@ -0,0 +1,182 @@
+<?
+//
+// 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
diff --git a/www/inc/wext/price.php b/www/inc/wext/price.php
new file mode 100644 (file)
index 0000000..d1a4bb7
--- /dev/null
@@ -0,0 +1,35 @@
+<?
+//
+// 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