*implement payment and refunds
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 30 Mar 2008 14:09:31 +0000 (14:09 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 30 Mar 2008 14:09:31 +0000 (14:09 +0000)
*implement ticket price change
*move order/sale to orderwindow
*make orders/sales with changed ticket prices possible

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

doc/prog_protocol.html
src/order.cpp
src/order.h
src/orderwin.cpp
src/orderwin.h
src/overview.cpp
src/overview.h
www/inc/classes/order.php
www/inc/classes/ticket.php
www/machine.php

index ce6177d..5c8705c 100644 (file)
@@ -492,17 +492,18 @@ The request is an order object without most fields filled in, the response is a
 <table frame="1" border="1">
 <tr><td><b>Element</b></td><td><b>Attributes in Request</b></td><td><b>Attributes in Response</b></td></tr>
 <tr><td>Order</td><td>customer</td><td>id(1), customer, seller(3), ordertime(1,4), totalprice(5), paid(1), status(6), senttime(2,4)</td></tr>
-<tr><td>Ticket</td><td>event</td><td>event, id(1), price, status(6)</td></tr>
-<tr><td>Voucher</td><td>value</td><td>value, price, id(1)</td></tr>
+<tr><td>Ticket</td><td>event, price(7)</td><td>event, id(1), price, status(6)</td></tr>
+<tr><td>Voucher</td><td>value, price(7)</td><td>value, price, id(1)</td></tr>
 <tr><td>DeliveryAddress</td><td>-</td><td>-</td></tr>
 <tr><td>Comment</td><td>-</td><td>-</td></tr>
 </table>
-(1)field is optional for checks and has no meaning there.<br/>
+(1)field is optional for checks and has no meaning there, it is recommended the server returns a dummy ID for checks<br/>
 (2)the field only exists for sales<br/>
 (3)the seller is automatically taken to be the session user<br/>
 (4)time stamps are automatically filled in with the current server time<br/>
 (5)the total price is the accumulated price of all tickets and vouchers in the order<br/>
-(6)the status fields have special meanings for checks, see below<p>
+(6)the status fields have special meanings for checks, see below<br/>
+(7)the price field will only be honoured in the request, if the user also has the privilege to use the changeticketprice transaction<p>
 
 Order status for checks:
 <table frame="1" border="1">
@@ -542,6 +543,10 @@ The <tt>getorderlist</tt> transaction can be used to get a list of all currently
 </pre>
 (this is a small subset of the full order object)
 
+<h3>Paying/Refunding Orders</h3>
+
+The <tt>orderpay</tt> transaction is used to add to the amount paid in an order. The <tt>orderrefund</tt> transaction is used to subtract from the amount paid of an order. In both cases the request consists of two positive numbers separated by a space: the order-ID and the amount in cent. The response contains the new amount paid after the transaction in the case of success and status error plus an explanation in case of any problem.
+
 <!-- ************************************************************************************
      ************************************************************************************
      ************************************************************************************ -->
@@ -569,6 +574,10 @@ The <tt>useticket</tt> transaction marks a ticket as used. The request contains
 
 Only tickets that have status "bought" and whose order have payment status "ok" or "needrefund" can be used. The transaction fails for all other tickets.
 
+<h3>Changing Ticket Prices</h3>
+
+The <tt>changeticketprice</tt> transaction can be used to change the price of a ticket. The request contains the ticket-ID and the new price in cent separated by a newline. The response is empty.
+
 <!-- ************************************************************************************
      ************************************************************************************
      ************************************************************************************ -->
index f27fcc0..940a140 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <QCoreApplication>
 #include <QDomElement>
+#include <QMessageBox>
 
 MOrder::MOrder()
 {
@@ -85,6 +86,26 @@ MOrder::OrderStatus MOrder::orderStatus()const
        return m_status;
 }
 
+bool MOrder::isStored()const
+{
+       return (m_status&Mask)==MaskIsStored;
+}
+
+bool MOrder::isCheck()const
+{
+       return (m_status&Mask)==MaskIsChecked;
+}
+
+bool MOrder::canOrder()const
+{
+       return m_status==CheckOk || m_status==CheckOrderOnly;
+}
+
+bool MOrder::canSell()const
+{
+       return m_status==CheckOk || m_status==CheckSaleOnly;
+}
+
 QString MOrder::orderStatusString()const
 {
        switch(m_status){
@@ -224,8 +245,7 @@ void MOrder::parseXml(const QDomElement&e)
        if(st=="fail")m_status=CheckFail;
        else m_status=Invalid;
        //complete stuff
-       if(!e.hasAttribute("seller"))return;
-       m_complete=true;
+       if(e.hasAttribute("seller"))m_complete=true;
        m_otime=e.attribute("ordertime","0").toInt();
        m_stime=e.attribute("senttime","0").toInt();
        m_seller=e.attribute("seller");
@@ -279,6 +299,7 @@ QDateTime MOrder::orderDateTime()
 QString MOrder::orderDateTimeStr()
 {
        makeComplete();
+       if(m_otime==0)return "";
        return QDateTime::fromTime_t(m_otime).toString(QCoreApplication::translate("MOrder","yyyy-MM-dd hh:mm ap","date/time format"));
 }
 
@@ -291,6 +312,7 @@ QDate MOrder::orderDate()
 QString MOrder::orderDateStr()
 {
        makeComplete();
+       if(m_otime==0)return "";
        return QDateTime::fromTime_t(m_otime).toString(QCoreApplication::translate("MOrder","yyyy-MM-dd","date format"));
 }
 
@@ -303,6 +325,7 @@ QDateTime MOrder::sentDateTime()
 QString MOrder::sentDateTimeStr()
 {
        makeComplete();
+       if(m_stime==0)return "";
        return QDateTime::fromTime_t(m_stime).toString(QCoreApplication::translate("MOrder","yyyy-MM-dd hh:mm ap","date/time format"));
 }
 
@@ -315,6 +338,7 @@ QDate MOrder::sentDate()
 QString MOrder::sentDateStr()
 {
        makeComplete();
+       if(m_stime==0)return "";
        return QDateTime::fromTime_t(m_stime).toString(QCoreApplication::translate("MOrder","yyyy-MM-dd","date format"));
 }
 
@@ -342,6 +366,68 @@ QList<MTicket> MOrder::tickets()
        return m_tickets;
 }
 
+void MOrder::setAmountPaid(int p)
+{
+       m_paid=p;
+}
+
+void MOrder::updateTicketPrice(QString tid,int price)
+{
+       for(int i=0;i<m_tickets.size();i++){
+               if(m_tickets[i].ticketID()==tid){
+                       int op=m_tickets[i].price();
+                       m_tickets[i].updatePrice(price);
+                       int np=m_tickets[i].price();
+                       m_price+=np-op;
+               }
+       }
+}
+
+MOrder MOrder::createOrder(QString type)
+{
+       ///////////////
+       //create order xml
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",m_customer);
+       //is there a delivery address
+       if(m_deladdress!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(m_deladdress));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       if(m_comment!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(m_comment));
+               root.appendChild(cc);
+       }
+       //scan tickets
+       //  TODO: scan vouchers
+       for(int i=0;i<m_tickets.size();i++){
+               m_tickets[i].xmlForOrder(doc,root);
+       }
+       doc.appendChild(root);
+       //send
+       if(req->request(type,doc.toByteArray())==false){
+               QMessageBox::warning(0,QCoreApplication::translate("MOrder","Error"),QCoreApplication::translate("MOrder","The request failed."));
+               return MOrder();
+       }
+       if(req->responseStatus()!=MWebRequest::Ok){
+               QMessageBox::warning(0,QCoreApplication::translate("MOrder","Error"),QCoreApplication::translate("MOrder","A problem occurred during the order: %1").arg(QCoreApplication::translate("MOrder",req->responseBody())));
+               return MOrder();
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       return MOrder(req,rdoc.documentElement());
+}
+
+MOrder MOrder::createSale()
+{
+       return createOrder("createsale");
+}
+
 /******************************************************************************
  * Ticket
  ******************************************************************************/
@@ -404,6 +490,14 @@ void MTicket::scanXml(const QDomElement&e)
        else m_paystate=PSUnknown;
 }
 
+void MTicket::xmlForOrder(QDomDocument&doc,QDomElement&root)
+{
+       QDomElement tc=doc.createElement("Ticket");
+       tc.setAttribute("event",m_eventid);
+       tc.setAttribute("price",m_price);
+       root.appendChild(tc);
+}
+
 MTicket::MTicket(const MTicket&t)
 {
        operator=(t);
@@ -465,6 +559,16 @@ MTicket::TicketStatus MTicket::status()const
        return m_status;
 }
 
+bool MTicket::isStored()const
+{
+       return (m_status&Mask)==MaskIsStored;
+}
+
+bool MTicket::isCheck()const
+{
+       return (m_status&Mask)==MaskIsChecked;
+}
+
 QString MTicket::statusString()const
 {
        switch(m_status){
@@ -507,3 +611,18 @@ void MTicket::setOrderID(qint32 o)
 {
        m_orderid=o;
 }
+
+void MTicket::updatePrice(int p)
+{
+       if(p<0 || p==m_price)return;
+       //it only makes sense to contact the DB if it can be found there
+       if(isStored()){
+               if(req==0)return;
+               //send request
+               QByteArray rq=m_id.toAscii()+"\n"+QByteArray::number(p);
+               if(!req->request("changeticketprice",rq))return;
+               if(req->responseStatus()!=MWebRequest::Ok)return;
+       }
+       //update locally
+       m_price=p;
+}
index 750b4ba..16902ce 100644 (file)
@@ -22,6 +22,7 @@
 #include "event.h"
 
 class MWebRequest;
+class QDomDocument;
 class QDomElement;
 
 /**this class represents a single ticket*/
@@ -98,6 +99,12 @@ class MTicket
                /**returns the status of the ticket*/
                TicketStatus status()const;
                
+               /**returns whether this order is stored in the DB*/
+               bool isStored()const;
+               
+               /**returns whether this order object is the result of a check operation*/
+               bool isCheck()const;
+               
                /**returns the ticket status as string*/
                QString statusString()const;
                
@@ -123,10 +130,15 @@ class MTicket
                /**marks the ticket as used in the database; returns empty string on success, error on failure*/
                QString markUsed();
                
+               /**updates the price of this ticket, calls DB*/
+               void updatePrice(int);
+               
        protected:
                friend class MOrder;
                /**sets the order-ID of the ticket, used by MOrder*/
                void setOrderID(qint32);
+               /**used by createOrder to generate XML elements for each ticket*/
+               void xmlForOrder(QDomDocument&,QDomElement&);
                
        private:
                MWebRequest*req;
@@ -198,6 +210,18 @@ class MOrder
                /**returns the status of the order*/
                OrderStatus orderStatus()const;
                
+               /**returns whether this order is stored in the DB*/
+               bool isStored()const;
+               
+               /**returns whether this order object is the result of a check operation*/
+               bool isCheck()const;
+               
+               /**returns whether this order object can be used to generate an order (to be delivered later)*/
+               bool canOrder()const;
+               
+               /**returns whether this order object can be used to generate a sale (delivered and paid immediately)*/
+               bool canSell()const;
+               
                /**returns the status of the order as localized string*/
                QString orderStatusString()const;
                
@@ -270,6 +294,18 @@ class MOrder
                /**returns the list of tickets of this order*/
                QList<MTicket> tickets();
                
+               /**used by payment and refund routines: updates the amount paid for this instance*/
+               void setAmountPaid(int);
+               
+               /**used to update the price of a ticket, calls DB*/
+               void updateTicketPrice(QString,int);
+               
+               /**create a new order in the DB; returns it*/
+               MOrder createOrder(QString type="createorder");
+               
+               /**create a sale in the DB; returns it*/
+               MOrder createSale();
+       
        private:
                MWebRequest*req;
                int m_orderid,m_customer,m_price,m_paid,m_otime,m_stime;
index c93c804..828f53e 100644 (file)
@@ -21,6 +21,7 @@
 #include <QComboBox>
 #include <QFileDialog>
 #include <QGridLayout>
+#include <QInputDialog>
 #include <QLabel>
 #include <QMenu>
 #include <QMenuBar>
 #include <QStandardItemModel>
 #include <QTableView>
 
+#include <math.h>
+
 MOrderWindow::MOrderWindow(QWidget*par,MWebRequest*r,const MOrder&o)
        :QMainWindow(par),req(r),m_order(o)
 {
        setWindowTitle(tr("Order Details"));
+       setAttribute(Qt::WA_DeleteOnClose);
        m_changed=false;
        
        QMenuBar*mb=menuBar();
        QMenu *m=mb->addMenu(tr("&Order"));
-       m->addAction(tr("&Order..."));
-       m->addAction(tr("&Sell..."));
+       m->addAction(tr("&Order..."),this,SLOT(createOrder()))
+        ->setEnabled(req->hasRole("createorder")&&o.canOrder());
+       m->addAction(tr("&Sell..."),this,SLOT(createSale()))
+        ->setEnabled(req->hasRole("createsale")&&o.canSell());
+       m->addSeparator();
+       m->addAction(tr("C&ancel Order..."))
+        ->setEnabled(req->hasRole("cancelorder")&&o.isStored());
        m->addSeparator();
-       m->addAction(tr("C&ancel Order..."));
+       m->addAction(tr("Ch&ange Ticket-Price..."),this,SLOT(changeTicket()))
+        ->setEnabled(req->hasRole("changeticketprice"));
        m->addSeparator();
        m->addAction(tr("&Close"),this,SLOT(close()));
        m=mb->addMenu(tr("&Payment"));
-       m->addAction(tr("Receive &Payment..."));
-       m->addAction(tr("&Refund..."));
+       m->setEnabled(o.isStored());
+       m->addAction(tr("Receive &Payment..."),this,SLOT(payment()))
+        ->setEnabled(req->hasRole("orderpay"));
+       m->addAction(tr("&Refund..."),this,SLOT(refund()))
+        ->setEnabled(req->hasRole("orderrefund"));
        m=mb->addMenu(tr("P&rinting"));
+       m->setEnabled(o.isStored());
        m->addAction(tr("Print &Bill..."),this,SLOT(printBill()));
        m->addAction(tr("Save Bill &as file..."),this,SLOT(saveBill()));
        m->addSeparator();
@@ -77,9 +91,9 @@ MOrderWindow::MOrderWindow(QWidget*par,MWebRequest*r,const MOrder&o)
        gl->addWidget(new QLabel(tr("Sold by:")),++rw,0);
        gl->addWidget(new QLabel(m_order.seller()),rw,1);
        gl->addWidget(new QLabel(tr("Total Price:")),++rw,0);
-       gl->addWidget(new QLabel(m_order.totalPriceString()),rw,1);
+       gl->addWidget(m_total=new QLabel(m_order.totalPriceString()),rw,1);
        gl->addWidget(new QLabel(tr("Already Paid:")),++rw,0);
-       gl->addWidget(new QLabel(m_order.amountPaidString()),rw,1);
+       gl->addWidget(m_paid=new QLabel(m_order.amountPaidString()),rw,1);
        gl->addWidget(new QLabel(tr("Order State:")),++rw,0);
        gl->addWidget(m_state=new QLabel(m_order.orderStatusString()),rw,1);
        gl->setColumnStretch(0,0);
@@ -100,6 +114,7 @@ void MOrderWindow::updateTable()
        QList<MEvent> events;
        if(tickets.size()>0)
                events=req->getAllEvents();
+       m_ticketmodel->clear();
        m_ticketmodel->setHorizontalHeaderLabels(QStringList()<<tr("Ticket ID")<<tr("Event")<<tr("Start Time")<<tr("Status")<<tr("Price"));
        m_ticketmodel->insertRows(0,tickets.size());
        for(int i=0;i<tickets.size();i++){
@@ -265,6 +280,101 @@ void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,QString&va
        if(vn=="ROOM")value=tickets[it].event().room();
 }
 
+void MOrderWindow::payment()
+{
+       if(!m_order.isValid())return;
+       //get value
+       bool ok;
+       double rt=QInputDialog::getDouble(this,tr("Enter Payment"),tr("Please enter the amount that has been paid:"),m_order.amountToPay()/100.0,0,m_order.amountToPay()/100.0,2,&ok);
+       if(!ok)return;
+       int pay=rt*100.0;
+       if(pay<=0)return;
+       //submit
+       QByteArray rq=QByteArray::number(m_order.orderID())+" "+QByteArray::number(pay);
+       if(!req->request("orderpay",rq)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to submit payment request."));
+               return;
+       }
+       if(req->responseStatus()!=MWebRequest::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Error whily trying to pay: %1").arg(tr(req->responseBody())));
+               return;
+       }
+       m_order.setAmountPaid(req->responseBody().trimmed().toInt());
+       m_paid->setText(m_order.amountPaidString());
+}
+
+void MOrderWindow::refund()
+{
+       if(!m_order.isValid())return;
+       //get value
+       bool ok;
+       double rt=QInputDialog::getDouble(this,tr("Enter Refund"),tr("Please enter the amount that will be refunded:"),m_order.amountToRefund()/100.0,0,m_order.amountToRefund()/100.0,2,&ok);
+       if(!ok)return;
+       int pay=rt*100.0;
+       if(pay<=0)return;
+       //submit
+       QByteArray rq=QByteArray::number(m_order.orderID())+" "+QByteArray::number(pay);
+       if(!req->request("orderrefund",rq)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to submit refund request."));
+               return;
+       }
+       if(req->responseStatus()!=MWebRequest::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Error whily trying to refund: %1").arg(tr(req->responseBody())));
+               return;
+       }
+       m_order.setAmountPaid(req->responseBody().trimmed().toInt());
+       m_paid->setText(m_order.amountPaidString());
+}
+
+void MOrderWindow::changeTicket()
+{
+       if(!m_order.isValid())return;
+       //get ticket selection
+       QModelIndexList lst=m_tickettable->selectionModel()->selectedIndexes();
+       if(lst.size()<1)return;
+       QModelIndex idx=m_ticketmodel->index(lst[0].row(),0);
+       QString id=m_ticketmodel->data(idx).toString();
+       if(id=="")return;
+       //find ticket
+       QList<MTicket>tickets=m_order.tickets();
+       MTicket tick;
+       for(int i=0;i<tickets.size();i++)
+               if(tickets[i].ticketID()==id)
+                       tick=tickets[i];
+       if(!tick.isValid())return;
+       //get value
+       bool ok;
+       double rt=QInputDialog::getDouble(this,tr("Enter Refund"),tr("Please enter the amount that will be refunded:"),tick.price()/100.0,0,1000000,2,&ok);
+       if(!ok)return;
+       int pay=rt*100.0;
+       if(pay<0)return;
+       //submit
+       m_order.updateTicketPrice(tick.ticketID(),pay);
+       m_total->setText(m_order.totalPriceString());
+       updateTable();
+}
+
+void MOrderWindow::cancelOrder()
+{}
+
+void MOrderWindow::createOrder(bool issale)
+{
+       MOrder ord;
+       if(issale)ord=m_order.createSale();
+       else ord=m_order.createOrder();
+       if(!ord.isValid())return;
+       //display final order
+       MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord);
+       ow->show();
+       //undisplay self
+       close();
+}
+
+
+void MOrderWindow::createSale()
+{
+       createOrder(true);
+}
 
 /*************************************************************************************/
 
index 6711807..549ad7f 100644 (file)
@@ -59,12 +59,28 @@ class MOrderWindow:public QMainWindow
                /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/
                void getLoopVariable(QString loopname,int iteration,QString varname,QString&value);
 
+               /**received payment*/
+               void payment();
+               /**generate a refund*/
+               void refund();
+               
+               /**change a ticket price*/
+               void changeTicket();
+               
+               /**cancel the order*/
+               void cancelOrder();
+               
+               /**create a new order*/
+               void createOrder(bool issale=false);
+               
+               /**create a sale*/
+               void createSale();
        
        private:
                MWebRequest*req;
                MOrder m_order;
                bool m_changed;
-               QLabel *m_orderid,*m_orderdate,*m_sentdate,*m_state;
+               QLabel *m_orderid,*m_orderdate,*m_sentdate,*m_state,*m_paid,*m_total;
                QTableView *m_tickettable;
                QStandardItemModel *m_ticketmodel;
 };
index df5d240..9d31860 100644 (file)
@@ -153,11 +153,8 @@ MOverview::MOverview(MWebRequest*mw,QString pk)
        vl->addLayout(hl=new QHBoxLayout,0);
        hl->addStretch(10);
        hl->addWidget(p=new QPushButton(tr("Order Items")));
-       p->setEnabled(req->hasRole("createorder"));
+       p->setEnabled(req->hasRole("checkorder"));
        connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
-       hl->addWidget(p=new QPushButton(tr("Sell Items")));
-       p->setEnabled(req->hasRole("createsale"));
-       connect(p,SIGNAL(clicked()),this,SLOT(cartSell()));
        hl->addWidget(p=new QPushButton(tr("Clear")));
        connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
        
@@ -746,7 +743,7 @@ void MOverview::cartRemoveItem()
        cartmodel->removeRow(idx.row());
 }
 
-void MOverview::cartOrder(QString otype)
+void MOverview::cartOrder()
 {
        //sanity checks
        if(cartmodel->rowCount()<1){
@@ -789,7 +786,7 @@ void MOverview::cartOrder(QString otype)
        }
        doc.appendChild(root);
        //send
-       if(req->request(otype,doc.toByteArray())==false){
+       if(req->request("checkorder",doc.toByteArray())==false){
                QMessageBox::warning(this,tr("Error"),tr("The request failed."));
                return;
        }
@@ -800,12 +797,9 @@ void MOverview::cartOrder(QString otype)
        //parse result
        QDomDocument rdoc;
        rdoc.setContent(req->responseBody());
-       //TODO: do something with it
-}
-
-void MOverview::cartSell()
-{
-       cartOrder("createsale");
+       //display order and give user chance to actually order it
+       MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement()));
+       ow->show();
 }
 
 void MOverview::customerMgmt()
index a0f4c66..372c6d9 100644 (file)
@@ -103,10 +103,8 @@ class MOverview:public QMainWindow
                //void cartAddVoucher();
                /**remove item from the cart*/
                void cartRemoveItem();
-               /**send the order to the server*/
-               void cartOrder(QString otype="createorder");
-               /**send the order to the server as sold*/
-               void cartSell();
+               /**check the order on the server*/
+               void cartOrder();
                
                /**manage customers*/
                void customerMgmt();
index 91265e8..12357be 100644 (file)
@@ -36,6 +36,7 @@ class Order
        private $senttime=false;
        //to be submitted
        private $newtickets;
+       private $newticketamounts;
        private $newvouchers;
        
        /**instantiates an existing order with the given orderid or creates a new one if orderid===false*/
@@ -59,6 +60,7 @@ class Order
                        $this->senttime=$res[0]["senttime"];
                }
                $this->newtickets=array();
+               $this->newticketamounts=array();
                $this->newvouchers=array();
        }
        
@@ -88,10 +90,8 @@ class Order
                        $eid=$tc->getEventId();
                        $amt=$tc->getAmount();
                        $tc->changeAmount(0);
-                       if(isset($this->newtickets[$eid]))
-                               $this->newtickets[$eid]+=$amt;
-                       else
-                               $this->newtickets[$eid]=$amt;
+                       for($i=0;$i<$amt;$i++)
+                               $this->newtickets[$eid][]=-1;
                }
                //TODO: get vouchers
                
@@ -102,12 +102,9 @@ class Order
        }
        
        /**used by XML functions: add a single ticket for an event*/
-       public function addTicket($eid)
+       public function addTicket($eid,$price=-1)
        {
-               if(isset($this->newtickets[$eid]))
-                       $this->newtickets[$eid]+=1;
-               else
-                       $this->newtickets[$eid]=1;
+               $this->newtickets[$eid][]=$price;
        }
        
        /**sets the customer of this order; returns true on success, false on failure*/
@@ -156,10 +153,12 @@ class Order
                }
                //insert tickets
                $totalprice=0;
-               foreach($this->newtickets as $evid=>$amount){
+               foreach($this->newtickets as $evid=>$tcs){
+                       $amount=count($tcs);
                        for($i=0;$i<$amount;$i++){
                                $tick=new Ticket;
                                $tick->setEventId($evid);
+                               if($tcs[$i]>=0)$tick->setPrice($tcs[$i]);
                                $tick->addToOrder($this->orderid);
                                $totalprice+=$tick->getPrice();
                                //TODO: check return code of addToOrder
@@ -200,8 +199,10 @@ class Order
                $orderstop=($db->getConfig("OrderStop")+0)*3600;
                $salestop=($db->getConfig("SaleStop")+0)*3600;
                $curtime=time();
-               foreach($this->newtickets as $evid => $amount){
-                       
+               $totalprice=0;
+               $ftid=0;
+               foreach($this->newtickets as $evid => $tcs){
+                       $amount=count($tcs);
                        $evt=new Event($evid);
                        if(!$evt->exists()){
                                if($dumpxml===false)return false;
@@ -209,6 +210,7 @@ class Order
                                $ev=$xml->createElement("Ticket");
                                $ev->setAttribute("event",$evid);
                                $ev->setAttribute("status","invalid");
+                               $ev->setAttribute("id",$ftid++);
                                $ord->appendChild($ev);
                                $ret=false;
                                $ostat="fail";
@@ -229,6 +231,7 @@ class Order
                                $ev=$xml->createElement("Ticket");
                                $ev->setAttribute("event",$evid);
                                $ev->setAttribute("status",$estat);
+                               $ev->setAttribute("id",$ftid++);
                                $ord->appendChild($ev);
                                if($ostat=="ok")$ostat=$estat;
                                else if($ostat!=$estat)$ostat="fail";
@@ -241,6 +244,7 @@ class Order
                                $ev=$xml->createElement("Ticket");
                                $ev->setAttribute("event",$evid);
                                $ev->setAttribute("status","cancelled");
+                               $ev->setAttribute("id",$ftid++);
                                $ord->appendChild($ev);
                                $ret=false;
                                continue;
@@ -254,12 +258,15 @@ class Order
                                        $ev->setAttribute("event",$evid);
                                        $ev->setAttribute("status","ok");
                                        $ev->setAttribute("price",$evt->getDefaultPrice());
+                                       $ev->setAttribute("id",$ftid++);
                                        $ord->appendChild($ev);
+                                       $totalprice+=$evt->getDefaultPrice();
                                }
                                //create only one bad ticket
                                $ev=$xml->createElement("Ticket");
                                $ev->setAttribute("event",$evid);
                                $ev->setAttribute("status","exhausted");
+                               $ev->setAttribute("id",$ftid++);
                                $ord->appendChild($ev);
                                $ret=false;
                                continue;
@@ -270,7 +277,9 @@ class Order
                                $ev->setAttribute("event",$evid);
                                $ev->setAttribute("status","ok");
                                $ev->setAttribute("price",$evt->getDefaultPrice());
+                               $ev->setAttribute("id",$ftid++);
                                $ord->appendChild($ev);
+                               $totalprice+=$evt->getDefaultPrice();
                        }
                }
                
@@ -281,6 +290,7 @@ class Order
                        $ord->appendChild($xml->createElement("DeliveryAddress",$this->deliveryaddress));
                        $ord->appendChild($xml->createElement("Comment",$this->comment));
                        $ord->setAttribute("status",$ostat);
+                       $ord->setAttribute("totalprice",$totalprice);
                        $xml->appendChild($ord);
                        print($xml->saveXml());
                }
@@ -385,9 +395,16 @@ function createOrderXml($xmldata,$action)
        $doc=$xml->documentElement;
        $cust=$doc->getAttribute("customer")+0;
        $order->setCustomerId($cust);
+       global $session;
+       $canprice=$session->canExecute("changeticketprice");
        //get tickets
        foreach($doc->getElementsByTagName("Ticket") as $tc){
-               $order->addTicket($tc->getAttribute("event")+0);
+               if($canprice){
+                       $price=trim($tc->getAttribute("price"));
+                       if($price=="" || !is_numeric($price))$price=-1;
+                       else $price=$price+0;
+               }else $price=-1;
+               $order->addTicket($tc->getAttribute("event")+0,$price);
        }
        //TODO: get vouchers
        
@@ -395,8 +412,8 @@ function createOrderXml($xmldata,$action)
        switch($action){
                case "check":
                        // check order
-                       $order->validateOrder(true);
                        header("X-MagicSmoke-Status: Ok");
+                       $order->validateOrder(true);
                        break;
                case "order":
                        // create order
@@ -484,4 +501,49 @@ function getOrderXml($oid)
        }
 }
 
+//pay or refund
+function orderPayXml($data,$factor)
+{
+       //split data
+       $dlst=explode(" ",trim($data));
+       if(count($dlst)!=2){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Expected 2 arguments."));
+       }
+       //check that order id is int
+       $oid=$dlst[0]+0;
+       if(!is_numeric($dlst[0])||$oid<0){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Invalid Order ID")." $oid $dlst[0]");
+       }
+       //check amount
+       $amt=round($dlst[1]+0);
+       if($amt<=0){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Expected positive amount."));
+       }
+       //check that order exists
+       global $db;
+       $db->beginTransaction();
+       $res=$db->select("order","amountpaid,status","orderid=".$db->escapeInt($oid));
+       if(count($res)<1){
+               $db->rollbackTransaction();
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Order does not exist."));
+       }
+       //check status
+       if($res[0]["status"]==ORDER_CLOSED){
+               $db->rollbackTransaction();
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Order cannot be changed, it is closed."));
+       }
+       //correct DB
+       $amt2=$res[0]["amountpaid"]+($amt*$factor);
+       $db->update("order",array("amountpaid"=>$amt2),"orderid=".$db->escapeInt($oid));
+       $db->commitTransaction();
+       //output
+       header("X-MagicSmoke-Status: Ok");
+       echo $amt2;
+}
+
 ?>
\ No newline at end of file
index f355b6e..1d5dc45 100644 (file)
@@ -86,6 +86,12 @@ class Ticket
                return $this->price;
        }
        
+       /**overwrites the price stored in this object (used by order before the ticket is stored to the DB)*/
+       public function setPrice($p)
+       {
+               $this->price=$p;
+       }
+       
        /**returns the ticket status*/
        public function getStatus()
        {
@@ -238,4 +244,36 @@ function useTicketXml($tid)
        }
 }
 
+function changeTicketPriceXml($data)
+{
+       //split
+       $lst=explode("\n",$data);
+       if(count($lst)!=2){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Malformed request."));
+       }
+       //check price
+       if(!is_numeric(trim($lst[1]))){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Price must be a number."));
+       }
+       $prc=trim($lst[1])+0;
+       if($prc<0){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Price must be positive."));
+       }
+       //get ticket
+       global $db;
+       $db->beginTransaction();
+       $res=$db->select("ticket","ticketid","ticketid=".$db->escapeString(trim($lst[0])));
+       if(count($res)<1){
+               $db->rollbackTransaction();
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Unable to find this ticket."));
+       }
+       $db->update("ticket",array("price"=>$prc),"ticketid=".$db->escapeString(trim($lst[0])));
+       $db->commitTransaction();
+       header("X-MagicSmoke-Status: Ok");
+}
+
 ?>
\ No newline at end of file
index 381da55..a210415 100644 (file)
@@ -23,8 +23,8 @@ $ALLOWEDREQUESTS=array(
        tr("geteventlist"),tr("geteventdata"),tr("seteventdata"),tr("eventsummary"), //event infos
        tr("getroomdata"),tr("setroomdata"),//room infos
        tr("getcustomerlist"),tr("getcustomer"),tr("setcustomer"), //customer info
-       tr("checkorder"),tr("createorder"),tr("createsale"),tr("getorderlist"),tr("getorder"), //sell/order stuff
-       tr("getticket"),tr("useticket"),//ticket management
+       tr("checkorder"),tr("createorder"),tr("createsale"),tr("getorderlist"),tr("getorder"),tr("orderpay"),tr("orderrefund"), //sell/order stuff
+       tr("getticket"),tr("useticket"),tr("changeticketprice"),//ticket management
        tr("gettemplatelist"),tr("gettemplate"),tr("settemplate") //templates
 );
 /**contains the low-level request name from the client*/
@@ -286,6 +286,16 @@ if($SMOKEREQUEST=="getorder"){
        getOrderXml(trim($REQUESTDATA)+0);
        exit();
 }
+//pay for an order
+if($SMOKEREQUEST=="orderpay"){
+       orderPayXml($REQUESTDATA,1);
+       exit();
+}
+//refund an order
+if($SMOKEREQUEST=="orderrefund"){
+       orderPayXml($REQUESTDATA,-1);
+       exit();
+}
 
 //get a ticket
 if($SMOKEREQUEST=="getticket"){
@@ -297,6 +307,11 @@ if($SMOKEREQUEST=="useticket"){
        useTicketXml(trim($REQUESTDATA));
        exit();
 }
+//change the price of a ticket
+if($SMOKEREQUEST=="changeticketprice"){
+       changeTicketPriceXml(trim($REQUESTDATA));
+       exit();
+}
 
 //EOF
 header("X-MagicSmoke-Status: Error");