*qt side of cart should be pretty much complete now
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 6 Jan 2010 17:39:14 +0000 (17:39 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 6 Jan 2010 17:39:14 +0000 (17:39 +0000)
*php side of createOrder/Reservation started, but still lacks:
 - verification of vouchers
 - creation of objects in DB

git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@406 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

src/mwin/carttab.cpp
src/mwin/carttab.h
wob/basics.wolf
wob/cart.wolf
wob/order.wolf
www/inc/wext/autoload.php
www/inc/wext/cart.php [new file with mode: 0644]
www/inc/wext/order.php

index 89d29ee..5676552 100644 (file)
@@ -71,16 +71,19 @@ MCartTab::MCartTab(QString pk)
        vl2->addWidget(p=new QPushButton(tr("Customer:")),0);
        connect(p,SIGNAL(clicked()),this,SLOT(setCustomer()));
        vl2->addWidget(cartcustomer=new QLabel("..."));
+       cartcustomer->setAutoFillBackground(true);
        vl2->addWidget(frm=new QFrame,0);
        frm->setFrameShape(QFrame::HLine);
        vl2->addWidget(p=new QPushButton(tr("Invoice Address:")),0);
        connect(p,SIGNAL(clicked()),this,SLOT(setInvoiceAddr()));
        vl2->addWidget(invoiceaddr=new QLabel("..."));
+       invoiceaddr->setAutoFillBackground(true);
        vl2->addWidget(frm=new QFrame,0);
        frm->setFrameShape(QFrame::HLine);
        vl2->addWidget(p=new QPushButton(tr("Delivery Address:")),0);
        connect(p,SIGNAL(clicked()),this,SLOT(setDeliveryAddr()));
        vl2->addWidget(deliveryaddr=new QLabel("..."));
+       deliveryaddr->setAutoFillBackground(true);
        vl2->addWidget(frm=new QFrame,0);
        frm->setFrameShape(QFrame::HLine);
        vl2->addSpacing(10);
@@ -100,7 +103,7 @@ MCartTab::MCartTab(QString pk)
        connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
        hl->addWidget(p=new QPushButton(tr("Reserve")));
        p->setEnabled(req->hasRight(req->RCreateReservation));
-       connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
+       connect(p,SIGNAL(clicked()),this,SLOT(cartReserve()));
        hl->addWidget(p=new QPushButton(tr("Clear")));
        connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
        
@@ -118,7 +121,8 @@ QMenu*MCartTab::menu()
        QMenu*m=new QMenu(tr("C&art"));
        m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
        m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()));
-       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("Add &Shop-Item"),this,SLOT(cartAddItem()));
+       m->addAction(tr("&Remove Line"),this,SLOT(cartRemoveItem()));
        m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
        m->addSeparator();
        m->addAction(tr("&Update Shipping Options"),this,SLOT(updateShipping()));
@@ -137,13 +141,16 @@ void MCartTab::updateShipping()
        QList<MOShipping>ship=sh.getshipping();
        for(int i=0;i<ship.size();i++)
                cartship->addItem(ship[i].description(),(int)ship[i].shipid());
+       QPalette pal2=QComboBox().palette();
+       cartship->setPalette(pal2);
+       cartship->setToolTip(QString());
 }
 
 void MCartTab::initCart()
 {
        //clear cart
        cartmodel->clear();
-       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time"));
+       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time")<<tr("Price"));
        //clear customer
        customer=MOCustomer();
        cartcustomer->setText("");
@@ -155,6 +162,30 @@ void MCartTab::initCart()
        cartcomment->setPlainText("");
        //clear shipping
        cartship->setCurrentIndex(0);
+       //reset colors
+       resetColor();
+}
+
+void MCartTab::resetColor(bool addronly)
+{
+       QPalette pal=QLabel().palette();
+       cartcustomer->setPalette(pal);
+       cartcustomer->setToolTip(QString());
+       invoiceaddr->setPalette(pal);
+       invoiceaddr->setToolTip(QString());
+       deliveryaddr->setPalette(pal);
+       deliveryaddr->setToolTip(QString());
+       if(!addronly){
+               for(int i=0;i<cartmodel->rowCount();i++)
+                       for(int j=0;j<cartmodel->columnCount();j++){
+                               QModelIndex idx=cartmodel->index(i,j);
+                               cartmodel->setData(idx,QVariant(),Qt::ToolTipRole);
+                               cartmodel->setData(idx,QVariant(),Qt::BackgroundRole);
+                       }
+               QPalette pal2=QComboBox().palette();
+               cartship->setPalette(pal2);
+               cartship->setToolTip(QString());
+       }
 }
 
 void MCartTab::setCustomer()
@@ -167,6 +198,7 @@ void MCartTab::setCustomer()
        deliveryaddr->setText("");
        invoiceaddr->setText("");
        deliveryaddrid=invoiceaddrid=-1;
+       resetColor(true);
        //follow up with address dialog
        if(!customer.customerid().isNull())
                setInvoiceAddr();
@@ -183,6 +215,8 @@ void MCartTab::setDeliveryAddr()
        customer=d.customer();
        deliveryaddr->setText(d.address().fullAddress(customer.fullName()));
        deliveryaddrid=d.addressId();
+       deliveryaddr->setPalette(QLabel().palette());
+       deliveryaddr->setToolTip(QString());
 }
 
 void MCartTab::setInvoiceAddr()
@@ -198,6 +232,8 @@ void MCartTab::setInvoiceAddr()
        customer=d.customer();
        invoiceaddr->setText(d.address().fullAddress(customer.fullName()));
        invoiceaddrid=d.addressId();
+       invoiceaddr->setPalette(QLabel().palette());
+       invoiceaddr->setToolTip(QString());
 }
 
 static const int CART_TICKET=1;
@@ -205,6 +241,7 @@ static const int CART_VOUCHER=2;
 
 static const int CART_IDROLE=Qt::UserRole;//ticket id
 static const int CART_PRICEROLE=Qt::UserRole;//voucher price
+static const int CART_PRICEIDROLE=CART_PRICEROLE;//for tickets: price category id
 static const int CART_VALUEROLE=Qt::UserRole+1;//voucher value
 static const int CART_TYPEROLE=Qt::UserRole+2;//which is it? ticket or voucher?
 
@@ -233,22 +270,67 @@ void MCartTab::cartAddTicket()
        hl->addWidget(p=new QPushButton(tr("Cancel")),0);
        connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
        //wait for it
-       if(dlg.exec()==QDialog::Accepted){
-               //get selection
-               QModelIndex idx=tv->currentIndex();
-               if(!idx.isValid())return;
-               int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
-               if(id<0)return;
-               //copy to cart
-               int cr=cartmodel->rowCount();
-               cartmodel->insertRows(cr,1);
-               cartmodel->setData(cartmodel->index(cr,0),1);
-               cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
-               cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
-               cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(idx.row(),1)));
-               cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(idx.row(),0)));
-               carttable->resizeColumnsToContents();
+       if(dlg.exec()!=QDialog::Accepted)return;
+       //get selection
+       QModelIndex idx=tv->currentIndex();
+       if(!idx.isValid())return;
+       int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
+       if(id<0)return;
+       addTicketForEvent(id);
+}
+
+void MCartTab::addTicketForEvent(qint64 id)
+{
+       //get event
+       MTGetEvent ge=MTGetEvent::query(id);
+       if(ge.hasError()){
+               QMessageBox::warning(this,tr("Warning"),tr("Error getting event, please try again."));
+               return;
        }
+       MOEvent ev=ge.getevent();
+       //get Price Category
+       QList<MOEventPrice> ep=ev.price();
+       if(ep.size()==0){
+               QMessageBox::warning(this,tr("Warning"),tr("This event has no prices associated. Cannot sell tickets."));
+               return;
+       }
+       int pcidx=0;
+       if(ep.size()>1){
+               QDialog d(this);
+               d.setWindowTitle(tr("Select Price Category"));
+               QVBoxLayout*vl;
+               QHBoxLayout*hl;
+               QComboBox*box;
+               QPushButton*p;
+               d.setLayout(vl=new QVBoxLayout);
+               vl->addWidget(new QLabel(tr("Please chose a price category:")));
+               vl->addWidget(box=new QComboBox);
+               for(int i=0;i<ep.size();i++)
+                       box->addItem(ep[i].pricecategory().value().name().value()+": "+cent2str(ep[i].price()));
+               box->setEditable(false);
+               vl->addSpacing(10);
+               vl->addStretch(10);
+               vl->addLayout(hl=new QHBoxLayout);
+               hl->addStretch(10);
+               hl->addWidget(p=new QPushButton(tr("Ok")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+               hl->addWidget(p=new QPushButton(tr("Cancel")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+               if(d.exec()!=QDialog::Accepted)return;
+               pcidx=box->currentIndex();
+       }
+       //copy to cart
+       int cr=cartmodel->rowCount();
+       cartmodel->insertRows(cr,1);
+       cartmodel->setData(cartmodel->index(cr,0),1);
+       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+       cartmodel->setData(cartmodel->index(cr,0),ep[pcidx].pricecategoryid().value(),CART_PRICEIDROLE);
+       cartmodel->setData(cartmodel->index(cr,1),ev.title().value());
+       cartmodel->setData(cartmodel->index(cr,2),ev.startTimeString());
+       QString pcn=cent2str(ep[pcidx].price())+" ("+ep[pcidx].pricecategory().value().name().value()+")";
+       cartmodel->setData(cartmodel->index(cr,3),pcn);
+       carttable->resizeColumnsToContents();
 }
 
 void MCartTab::eventOrderTicket()
@@ -258,14 +340,7 @@ void MCartTab::eventOrderTicket()
        //activate order tab
        emit requestFocus();
        //insert event into table
-       int cr=cartmodel->rowCount();
-       cartmodel->insertRows(cr,1);
-       cartmodel->setData(cartmodel->index(cr,0),1);
-       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
-       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
-       cartmodel->setData(cartmodel->index(cr,1),emit currentEventTitle());
-       cartmodel->setData(cartmodel->index(cr,2),emit currentEventStart());
-       carttable->resizeColumnsToContents();
+       addTicketForEvent(id);
 }
 
 void MCartTab::cartAddVoucher()
@@ -323,7 +398,8 @@ void MCartTab::cartAddVoucher()
                cartmodel->setData(cartmodel->index(cr,0),price,CART_PRICEROLE);
                cartmodel->setData(cartmodel->index(cr,0),value,CART_VALUEROLE);
                cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE);
-               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value)));
+               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (value %1)").arg(cent2str(value)));
+               cartmodel->setData(cartmodel->index(cr,3),cent2str(price));
                carttable->resizeColumnsToContents();
        }
 }
@@ -342,20 +418,11 @@ void MCartTab::cartRemoveItem()
        cartmodel->removeRow(idx.row());
 }
 
-void MCartTab::cartOrder()
+void MCartTab::cartOrder(bool isreserve)
 {
        //sanity checks
-       if(cartmodel->rowCount()<1){
-               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
-               return;
-       }
-       if(!customer.isValid()){
-               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
-               return;
-       }
-       if(cartship->currentIndex()>0 && deliveryaddrid<0 && invoiceaddrid<0){
-               if(QMessageBox::question(this,tr("Shipping"),tr("You have chosen a shipping method, but no address. Are you sure you want to continue?"),QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes)return;
-       }
+       if(!canorder(isreserve))return;
+       resetColor(false);
        ///////////////
        //create order
        MOCartOrder cord;
@@ -367,6 +434,67 @@ void MCartTab::cartOrder()
        QString s=cartcomment->toPlainText().trimmed();
        if(s!="")cord.setcomment(s);
        //scan tickets & scan vouchers
+       cartTableToOrder(cord);
+       //set shipping info
+       if(cartship->currentIndex()>0)
+               cord.setshippingtypeid(cartship->itemData(cartship->currentIndex()).toInt());
+       /////
+       //send
+       MOOrder ord;
+       if(!orderExecute(cord,ord,isreserve))return;
+       /////
+       //everything ok, move on
+       if(!ord.orderid().isNull()){
+               initCart();
+               MOrderWindow *ow=new MOrderWindow(window(),ord);
+               ow->show();
+               return;
+       }
+       /////
+       //something went wrong: verify cart
+       QMessageBox::warning(this,tr("Warning"),tr("There are problems with the contents of the cart, please check and then try again."));
+       //verify customer
+       verifyOrderCustomer(cord);
+       //verify tickets
+       verifyOrderTickets(cord.tickets());
+       verifyOrderVouchers(cord.vouchers());
+       verifyOrderItems(cord.items());
+}
+
+void MCartTab::cartReserve()
+{
+       cartOrder(true);
+}
+
+bool MCartTab::canorder(bool isreserve)
+{
+       //basics
+       if(cartmodel->rowCount()<1){
+               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
+               return false;
+       }
+       if(!customer.isValid()){
+               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
+               return false;
+       }
+       if(cartship->currentIndex()>0 && deliveryaddrid<0 && invoiceaddrid<0){
+               if(QMessageBox::question(this,tr("Shipping"),tr("You have chosen a shipping method, but no address. Are you sure you want to continue?"),QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes)return false;
+       }
+       //if for a reservation: tickets only please
+       if(isreserve)
+       for(int i=0;i<cartmodel->rowCount();i++){
+               int tp=cartmodel->data(cartmodel->index(i,0),CART_TYPEROLE).toInt();
+               if(tp!=CART_TICKET){
+                       QMessageBox::warning(this,tr("Warning"),tr("Reservations can only contain tickets."));
+                       return false;
+               }
+       }
+       //all clear
+       return true;
+}
+
+void MCartTab::cartTableToOrder(MOCartOrder&cord)
+{
        for(int i=0;i<cartmodel->rowCount();i++){
                QModelIndex idx=cartmodel->index(i,0);
                int tp=cartmodel->data(idx,CART_TYPEROLE).toInt();
@@ -374,6 +502,8 @@ void MCartTab::cartOrder()
                        MOCartTicket ct;
                        ct.setamount(cartmodel->data(idx).toInt());
                        ct.seteventid(cartmodel->data(idx,CART_IDROLE).toInt());
+                       ct.setpricecategoryid(cartmodel->data(idx,CART_PRICEIDROLE).toInt());
+                       ct.setcartlineid(i);
                        cord.addtickets(ct);
                }else
                if(tp==CART_VOUCHER){
@@ -381,21 +511,122 @@ void MCartTab::cartOrder()
                        cv.setamount(cartmodel->data(idx).toInt());
                        cv.setprice(cartmodel->data(idx,CART_PRICEROLE).toInt());
                        cv.setvalue(cartmodel->data(idx,CART_VALUEROLE).toInt());
+                       cv.setcartlineid(i);
                        cord.addvouchers(cv);
                }
                //TODO: product/items
        }
-       //set shipping info
-       cord.setshippingtypeid(cartship->itemData(cartship->currentIndex()).toInt());
-       //send
-       MTCreateOrder co=req->queryCreateOrder(cord);
-       if(co.hasError()){
-               QMessageBox::warning(this,tr("Warning"),tr("Error while creating order: %1").arg(co.errorString()));
-               return;
+}
+
+bool MCartTab::orderExecute(MOCartOrder&cord,MOOrder&ord,bool isreserve)
+{
+       if(isreserve){
+               MTCreateReservation co=req->queryCreateReservation(cord);
+               if(co.hasError()){
+                       QMessageBox::warning(this,tr("Warning"),tr("Error while creating reservation: %1").arg(co.errorString()));
+                       return false;
+               }
+               ord=co.getorder();
+               cord=co.getcart();
+       }else{
+               MTCreateOrder co=req->queryCreateOrder(cord);
+               if(co.hasError()){
+                       QMessageBox::warning(this,tr("Warning"),tr("Error while creating order: %1").arg(co.errorString()));
+                       return false;
+               }
+               ord=co.getorder();
+               cord=co.getcart();
+       }
+       return true;
+}
+
+void MCartTab::verifyOrderCustomer(MOCartOrder&cord)
+{
+       QPalette red=QLabel().palette();red.setColor(QPalette::Window,Qt::red);
+       if(cord.customerid() != customer.customerid()){
+               customer=MOCustomer();
+               cartcustomer->setPalette(red);
+               cartcustomer->setToolTip(tr("The customer is not valid, please chose another one."));
+       }
+       if(deliveryaddrid>=0 && cord.deliveryaddressid() != deliveryaddrid){
+               deliveryaddrid=-1;
+               deliveryaddr->setPalette(red);
+               deliveryaddr->setToolTip(tr("The delivery address is not valid, please chose another one."));
+       }
+       if(invoiceaddrid>=0 && cord.invoiceaddressid() != invoiceaddrid){
+               invoiceaddrid=-1;
+               invoiceaddr->setPalette(red);
+               invoiceaddr->setToolTip(tr("The invoice address is not valid, please chose another one."));
+       }
+       if(cartship->currentIndex()>0 && cord.shippingtypeid().isNull()){
+               QPalette red2=QComboBox().palette();red2.setColor(QPalette::Window,Qt::red);
+               cartship->setPalette(red2);
+               cartship->setToolTip(tr("Shipping Type does not exist or you do not have permission to use it."));
+       }
+}
+
+void MCartTab::verifyOrderTickets(const QList<MOCartTicket>&ticks)
+{
+       for(int i=0;i<ticks.size();i++){
+               if(ticks[i].status()!=MOCartTicket::Ok){
+                       //find it
+                       int j=ticks[i].cartlineid();
+                       if(j<0 || j>=cartmodel->rowCount())continue;
+                       QModelIndex idx0=cartmodel->index(j,0);
+                       if(cartmodel->data(idx0,CART_TYPEROLE).toInt() != CART_TICKET)continue;
+                       QModelIndex idx1=cartmodel->index(j,1);
+                       cartmodel->setData(idx1,Qt::red,Qt::BackgroundRole);
+                       //check state, color it
+                       switch(ticks[i].status().value()){
+                               case MOCartTicket::EventOver:
+                                       cartmodel->setData(idx1,tr("The event is already over, please remove this entry."),Qt::ToolTipRole);
+                                       break;
+                               case MOCartTicket::TooLate:
+                                       cartmodel->setData(idx1,tr("You cannot order tickets for this event anymore, ask a more privileged user."),Qt::ToolTipRole);
+                                       break;
+                               case MOCartTicket::Exhausted:{
+                                       cartmodel->setData(idx0,Qt::red,Qt::BackgroundRole);
+                                       QString tt=tr("The event is (almost) sold out, there are %1 tickets left.").arg(ticks[i].maxamount());
+                                       cartmodel->setData(idx0,tt,Qt::ToolTipRole);
+                                       cartmodel->setData(idx1,tt,Qt::ToolTipRole);
+                                       break;}
+                               case MOCartTicket::Invalid:
+                                       cartmodel->setData(idx1,tr("The event does not exist or there is another serious problem, please remove this entry."),Qt::ToolTipRole);
+                                       break;
+                               default:break;//ignore all others
+                       }
+               }
+       }
+}
+
+void MCartTab::verifyOrderVouchers(const QList<MOCartVoucher>&voucs)
+{
+       for(int i=0;i<voucs.size();i++){
+               if(voucs[i].status()!=MOCartVoucher::Ok){
+                       //find it
+                       int j=voucs[i].cartlineid();
+                       if(j<0 || j>=cartmodel->rowCount())continue;
+                       QModelIndex idx0=cartmodel->index(j,0);
+                       if(cartmodel->data(idx0,CART_TYPEROLE).toInt() != CART_VOUCHER)continue;
+                       QModelIndex idx1=cartmodel->index(j,1);
+                       cartmodel->setData(idx1,Qt::red,Qt::BackgroundRole);
+                       //check state, color it
+                       switch(voucs[i].status().value()){
+                               case MOCartVoucher::InvalidValue:
+                                       cartmodel->setData(idx1,tr("You do not have permission to create vouchers with this value, please remove it."),Qt::ToolTipRole);
+                                       break;
+                               case MOCartVoucher::InvalidPrice:
+                                       cartmodel->setData(idx1,tr("The price tag of this voucher is not valid, please remove and recreate it."),Qt::ToolTipRole);
+                                       break;
+                               default:break;//ignore all others
+                       }
+               }
        }
-       initCart();
-       MOrderWindow *ow=new MOrderWindow(window(),co.getorder());
-       ow->show();
+}
+
+void MCartTab::verifyOrderItems(const QList<MOCartItem>&)
+{
+       //TODO: implement items
 }
 
 /********************************************************************************/
index 99a2365..0435247 100644 (file)
@@ -35,6 +35,12 @@ class QTextEdit;
 
 class MSInterface;
 
+class MOCartOrder;
+class MOCartItem;
+class MOCartTicket;
+class MOCartVoucher;
+class MOOrder;
+
 /**Main Overview Window: cart tab*/
 class MCartTab:public QWidget
 {
@@ -87,8 +93,12 @@ class MCartTab:public QWidget
                void cartAddItem();
                /**remove item from the cart*/
                void cartRemoveItem();
-               /**check the order on the server*/
-               void cartOrder();
+               /**create the order on the server*/
+               void cartOrder(bool isreserve=false);
+               /**create a reservation on the server*/
+               void cartReserve();
+               /**reset the colors of the tab*/
+               void resetColor(bool addronly=false);
                
        private:
                //the profile associated with this session
@@ -102,6 +112,24 @@ class MCartTab:public QWidget
                //cart
                MOCustomer customer;
                qint64 deliveryaddrid,invoiceaddrid;
+               
+               /**helper for order: returns true if an order can be sent*/
+               bool canorder(bool isreserve);
+               /**helper for order: turns the cart table into order items*/
+               void cartTableToOrder(MOCartOrder&);
+               /**helper for order: makes the actual order or reserve; returns the result in the first two parameters; returns false if the transaction was aborted and processing should stop here*/
+               bool orderExecute(MOCartOrder&cart,MOOrder&order,bool isreserve);
+               /**helper for order: verifies customer properties*/
+               void verifyOrderCustomer(MOCartOrder&);
+               /**helper for order: verifies tickets*/
+               void verifyOrderTickets(const QList<MOCartTicket>&);
+               /**helper for order: verifies vouchers*/
+               void verifyOrderVouchers(const QList<MOCartVoucher>&);
+               /**helper for order: verifies product items*/
+               void verifyOrderItems(const QList<MOCartItem>&);
+               
+               /**helper for cartAddTicket and eventOrderTicket: choses a price category and then adds the ticket*/
+               void addTicketForEvent(qint64);
 };
 
 /**Helper class for shopping cart: allow editing amount, but nothing else*/
index 30a7715..d686019 100644 (file)
@@ -14,7 +14,7 @@
                <Preset><V col="ckey" val="MagicSmokeVersion"/><V col="cval" code="$this->version()"/></Preset>
                <Preset><V col="ckey" val="ValidVouchers"/><V col="cval" val="1000 2000 2500 5000"/></Preset>
                <Preset><V col="ckey" val="OrderStop"/><V col="cval" val="24"/></Preset>
-               <Preset><V col="ckey" val="SaleStop"/><V col="cval" val="0"/></Preset>
+               <Preset><V col="ckey" val="ReserveStop"/><V col="cval" val="48"/></Preset>
                <Preset><V col="ckey" val="TicketIDChars"/><V col="cval" val="10"/></Preset>
                <Preset><V col="ckey" val="VoucherIDChars"/><V col="cval" val="10"/></Preset>
                <Preset><V col="ckey" val="Flag admin"/><V col="cval" val="User is Admin"/></Preset>
index 426c967..0fd5a81 100644 (file)
        
        <Class name="CartTicket">
                <Enum name="TicketValidationState">
-                       <Value name="Ok"/>
-                       <Value name="TooLate"/>
-                       <Value name="Exhausted"/>
-                       <Value name="SaleOnly"/>
-                       <Value name="OrderOnly"/>
+                       <Value name="Ok">The tickets can be sold</Value>
+                       <Value name="EventOver">The event is already over</Value>
+                       <Value name="TooLate">The event is not yet over, but normal sale is no longer possible, you need the CreateOrder:LateSale privilege</Value>
+                       <Value name="Exhausted">There are not enough tickets for this event</Value>
+                       <Value name="Invalid">There is an inherent mismatch in the ticket (eg. non-existent event or price category), it can't possibly be sold.</Value>
                </Enum>
+               <Property name="cartlineid" type="int">optional property that can be used by the calling process to distinguish lines in the cart, the server must preserve it unchanged</Property>
                <Property name="eventid" type="int"/>
                <Property name="amount" type="int"/>
+               <Property name="pricecategoryid" type="int"/>
                <Property name="price" type="int" optional="1"/>
                <Property name="status" type="TicketValidationState" optional="1"/>
                <Property name="maxamount" type="int" optional="1"/>
        
        <Class name="CartVoucher">
                <Enum name="ValidationState">
-                       <Value name="Ok"/>
-                       <Value name="InvalidValue"/>
-                       <Value name="InvalidPrice"/>
+                       <Value name="Ok">The voucher can be sold</Value>
+                       <Value name="InvalidValue">The value is not one of the allowed ones and you do not have the privilege to set an arbitrary one, or the value is negative.</Value>
+                       <Value name="InvalidPrice">The price is negative, the price property is ignored if you do not have the privilege to chose a price that differs from the value</Value>
                </Enum>
+               <Property name="cartlineid" type="int" optional="1">optional property that can be used by the calling process to distinguish lines in the cart, the server must preserve it unchanged</Property>
                <Property name="amount" type="int"/>
                <Property name="value" type="int"/>
                <Property name="price" type="int" optional="1"/>
                <Property name="status" type="ValidationState" optional="1"/>
        </Class>
        
+       <Class name="CartItem"/>
+       
        <Class name="CartOrder">
+               <Abstract lang="php"/>
                <Enum name="ValidationState">
-                       <Value name="Ok"/>
-                       <Value name="SaleOnly"/>
-                       <Value name="OrderOnly"/>
-                       <Value name="Invalid"/>
+                       <Value name="Ok">The cart has been processed successfully</Value>
+                       <Value name="Invalid">There are problems with the cart, it cannot be processed</Value>
                </Enum>
-               <Property name="status" type="ValidationState" optional="1"/>
+               <Property name="cartid" type="int" optional="1">optional ID for the cart itself, the calling process can use this to distinguish different carts, the server must preserve it between input and output</Property>
+               <Property name="status" type="ValidationState" optional="1">set by the server to reflect the processing state of the cart</Property>
                <Property name="customerid" type="int"/>
                <Property name="invoiceaddressid" type="int"/>
                <Property name="deliveryaddressid" type="int"/>
@@ -89,5 +94,6 @@
                <Property name="shippingtypeid" type="int"/>
                <Property name="tickets" type="List:CartTicket"/>
                <Property name="vouchers" type="List:CartVoucher"/>
+               <Property name="items" type="List:CartItem"/>
        </Class>
 </Wolf>
\ No newline at end of file
index d82b43a..c10c8ed 100644 (file)
                <Doc>CreateOrder creates orders that are queued to be executed immediately, they may contain tickets, vouchers, or shopping items</Doc>
                <Privilege name="AnyVoucherValue">users with this privilege can create vouchers with arbitrary value</Privilege>
                <Privilege name="DiffVoucherValuePrice">users with this privilege can create vouchers with a price (what the customer pays) different from its value (what the customer can buy with it)</Privilege>
+               <Privilege name="LateSale">users with this privilege can sell tickets until the event is over, otherwise a configurable limit applies</Privilege>
+               <Privilege name="AfterTheFactSale">users with this privilege can sell tickets for past events - be careful to give this privilege only to very few special users, it is an invitation to mistakes!</Privilege>
                <Input>
-                       <Var name="cart" type="CartOrder"/>
+                       <Var name="cart" type="CartOrder">The cart contents</Var>
                </Input>
+               <Call lang="php" method="WOCartOrder::createOrder($this);"/>
                <Output>
-                       <Var name="order" type="Order"/>
+                       <Var name="order" type="Order">If successful: the created order</Var>
+                       <Var name="cart" type="CartOrder">If unsuccessful: the cart with annotations</Var>
                </Output>
        </Transaction>
        
        <Transaction name="CreateReservation">
                <Doc>Reservations are orders that are not executed right away. They may only contain tickets that block some seats for a limited time. They cannot contain any shopping items or vouchers.</Doc>
+               <Privilege name="LateReserve">users with this right can make reservations right up to the start of the event, otherwise a configured limit applies</Privilege>
                <Input>
-                       <Var name="cart" type="CartOrder"/>
+                       <Var name="cart" type="CartOrder">The cart contents</Var>
                </Input>
+               <!-- this call automatically realizes that it is executing a reservation-->
+               <Call lang="php" method="WOCartOrder::createOrder($this);"/>
                <Output>
-                       <Var name="order" type="Order"/>
+                       <Var name="order" type="Order">If successful: the created order</Var>
+                       <Var name="cart" type="CartOrder">If unsuccessful: the cart with annotations</Var>
                </Output>
        </Transaction>
        <Transaction name="ReservationToOrder">
index 82096e7..1dbec32 100644 (file)
@@ -12,6 +12,7 @@
 //
 
 $AUTOCLASS["WOArtist"]="inc/wext/artist.php";
+$AUTOCLASS["WOCartOrder"]="inc/wext/cart.php";
 $AUTOCLASS["WOCustomer"]="inc/wext/customer.php";
 $AUTOCLASS["WOEventPrice"]="inc/wext/event.php";
 $AUTOCLASS["WOEvent"]="inc/wext/event.php";
diff --git a/www/inc/wext/cart.php b/www/inc/wext/cart.php
new file mode 100644 (file)
index 0000000..d0b4040
--- /dev/null
@@ -0,0 +1,243 @@
+<?
+//
+// PHP Implementation: cart
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2010
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class WOCartOrder extends WOCartOrderAbstract
+{
+       const LateSale=-1;
+       const AfterSale=-2;
+       
+       /**called by the CreateOrder and CreateReservation transactions*/
+       public static function createOrder($trans)
+       {
+               //get cart object
+               $cart=$trans->getcart();
+               if(!is_a($cart,"WOCartOrder")){
+                       $trans->abortWithError(tr("Not a valid cart object."));
+                       return;
+               }
+               //get permissions
+               global $db;
+               $isreserve=false;
+               $vanyval=false;
+               $vdiffprice=false;
+               $tsalestop=0;
+               if(is_a($trans,"WTrCreateOrder")){
+                       $vanyval=$trans->havePrivilege(WTrCreateOrder::Priv_AnyVoucherValue);
+                       $vdiffprice=$trans->havePrivilege(WTrCreateOrder::Priv_DiffVoucherValuePrice);
+                       $tsalestop=$db->getConfig("OrderStop")+0;
+                       if($tsalestop<0)$tsalestop=0;
+                       if($trans->havePrivilege(WTrCreateOrder::Priv_LateSale))
+                               $tsalestop=self::LateSale;
+                       if($trans->havePrivilege(WTrCreateOrder::Priv_AfterTheFactSale))
+                               $tsalestop=self::AfterSale;
+               }else
+               if(is_a($trans,"WTrCreateReservation")){
+                       $isreserve=true;
+                       $tsalestop=$db->getConfig("ReserveStop")+0;
+                       if($tsalestop<0)$tsalestop=0;
+                       if($trans->havePrivilege(WTrCreateReservation::Priv_LateReserve))
+                               $tsalestop=0;
+               }else{
+                       $trans->abortWithError(tr("CreateSale called from an unknown transaction."));
+                       return;
+               }
+               //verify necessary elements and content
+               $very=true;
+               $very&=$cart->verifyCustomer($trans);
+               $very&=$cart->verifyShipping($trans);
+               
+               $very&=$cart->verifyTickets($trans,$tsalestop);
+               if($isreserve){
+                       if(count($cart->get_vouchers())>0 || count($cart->get_items())>0){
+                               $trans->abortWithError(tr("Reservations must not contain anything but tickets."));
+                               return;
+                       }
+               }else{
+                       $very&=$cart->verifyVouchers($trans,$vanyval,$vdiffprice);
+                       $very&=$cart->verifyItems($trans);
+               }
+               //verification successful?
+               if(!$very){
+                       //no: set verified cart and return to caller
+                       $cart->set_status(WOCartOrder::Invalid);
+                       $trans->setcart($cart);
+                       return;
+               }
+               $cart->set_status(WOCartOrder::Ok);
+               //create order
+               $ord=$cart->createOrderOnDB($isreserve);
+               
+               //return verified cart and order
+               $trans->setorder($ord);
+               $trans->setcart($cart);
+       }
+       
+       /**helper function for createOrder: verifies customer settings*/
+       private function verifyCustomer($trans)
+       {
+               //check customer exists
+               $cust=WTcustomer::getFromDB($this->prop_customerid);
+               if(!is_a($cust,"WTcustomer")){
+                       $this->prop_customerid=null;
+                       $this->prop_deliveryaddressid=null;
+                       $this->prop_invoiceaddressid=null;
+                       return false;
+               }
+               //check addresses belong to customer
+               $ret=true;
+               if($this->prop_invoiceaddressid!==null){
+                       $addr=WTaddress::getFromDB($this->prop_invoiceaddressid);
+                       if(!is_a($addr,"WTaddress")){
+                               $this->prop_invoiceaddressid=null;
+                               $ret=false;
+                       }else{
+                               if($addr->customerid != $this->prop_customerid){
+                                       $this->prop_invoiceaddressid=null;
+                                       $ret=false;
+                               }
+                       }
+               }
+               if($this->prop_deliveryaddressid!==null){
+                       $addr=WTaddress::getFromDB($this->prop_deliveryaddressid);
+                       if(!is_a($addr,"WTaddress")){
+                               $this->prop_deliveryaddressid=null;
+                               $ret=false;
+                       }else{
+                               if($addr->customerid != $this->prop_customerid){
+                                       $this->prop_deliveryaddressid=null;
+                                       $ret=false;
+                               }
+                       }
+               }
+               return $ret;
+       }
+       
+       /**helper function for createOrder: verifies customer settings*/
+       private function verifyShipping($trans)
+       {
+               if($this->prop_shippingtypeid !== null){
+                       $ship=WTshipping::getFromDB($this->prop_shippingtypeid);
+                       if(!is_a($ship,"WTshipping")){
+                               $this->prop_shippingtypeid=null;
+                               return false;
+                       }
+               }
+               return true;
+       }
+       
+       /**helper for helper verifyTickets: gets statistics about sold tickets*/
+       private function eventTicketStatistics($evid,$cap)
+       {
+               global $db;
+               $ret=array("all"=>$cap);
+               $epcs=WTeventprice::selectFromDB("eventid=".$db->escapeInt($evid));
+               foreach($epcs as $pc){
+                       $ret[$pc->pricecategoryid]=$pc->maxavailable;
+               }
+               $ticks=WTticket::selectFromDB("eventid=".$db->escapeInt($evid));
+               foreach($ticks as $t){
+                       if(($t & WTticket::MaskBlock)==0)continue;
+                       $ret["all"]--;
+                       if($t->pricecategoryid !== null)
+                               $ret[$t->pricecategoryid]--;
+               }
+               return $ret;
+       }
+       
+       /**helper function for createOrder: verifies customer settings*/
+       private function verifyTickets($trans,$salestop)
+       {
+               $ret=true;
+               $evseats=array();
+               $now=time();
+               if($salestop>0)$now+=$salestop*3600;
+               foreach($this->prop_tickets as &$tick){
+                       //assume ok
+                       $tick->set_status(WOCartTicket::Ok);
+                       //check event exists
+                       $evid=$tick->get_eventid();
+                       $ev=WTevent::getFromDB($evid);
+                       if(!is_a($ev,"WTevent")){
+                               $tick->set_status(WOCartTicket::Invalid);
+                               $ret=false;
+                               continue;
+                       }
+                       if(!array_key_exists($evid,$evseats))
+                               $evseats[$evid]=$this->eventTicketStatistics($evid,$ev->capacity);
+                       //verify price category
+                       $pcid=$tick->get_pricecategoryid();
+                       if(!array_key_exists($pcid,$evseats[$evid])){
+                               $tick->set_status(WOCartTicket::Invalid);
+                               $ret=false;
+                               continue;
+                       }
+                       //check enough seats for event
+                       if($tick->get_amount() > $evseats[$evid]["all"]){
+                               $tick->set_status(WOCartTicket::Exhausted);
+                               $tick->set_amount($evseats[$evid]["all"]);
+                               $ret=false;
+                       }
+                       $evseats[$evid]["all"]-=$tick->get_amount();
+                       //check enough seats for category
+                       if($tick->get_amount() > $evseats[$evid][$pcid]){
+                               $tick->set_status(WOCartTicket::Exhausted);
+                               $tick->set_amount($evseats[$evid][$pcid]);
+                               $ret=false;
+                       }
+                       $evseats[$evid][$pcid]-=$tick->get_amount();
+                       //check sale time
+                       if($salestop==self::AfterSale)continue;
+                       if($salestop==self::LateSale){
+                               if($now>$ev->endtime){
+                                       $tick->set_status(WOCartTicket::TooLate);
+                                       $ret=false;
+                               }
+                       }else{
+                               if($now>$ev->starttime){
+                                       $tick->set_status(WOCartTicket::TooLate);
+                                       $ret=false;
+                               }
+                       }
+               }
+               return $ret;
+       }
+       
+       /**helper function for createOrder: verifies customer settings*/
+       private function verifyVouchers($trans,$vanyval,$vdiffprice)
+       {
+               //TODO: implement
+               return true;
+       }
+       
+       /**helper function for createOrder: verifies customer settings*/
+       private function verifyItems($trans)
+       {
+               //TODO: implement items
+               return true;
+       }
+       
+       /**helper function for createOrder: creates the order on the database*/
+       private function createOrderOnDB($trans)
+       {
+               //create order
+               $ord=WTorder::newRow();
+               //create tickets
+               //create vouchers
+               //create items
+               //update address use
+               //return created order
+               return WOOrder::fromTableorder($ord);
+       }
+};
+
+?>
\ No newline at end of file
index 123fb37..3c77a78 100644 (file)
@@ -118,6 +118,9 @@ class WOOrderInfo extends WOOrderInfoAbstract
        }
 };
 
+
+
+/**full order class*/
 class WOOrder extends WOOrderAbstract
 {
        /**analyses itself and returns price*/