entrance scan/control works
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 29 Mar 2008 10:15:22 +0000 (10:15 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 29 Mar 2008 10:15:22 +0000 (10:15 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@146 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

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

index 6469b99..ce6177d 100644 (file)
@@ -545,6 +545,33 @@ The <tt>getorderlist</tt> transaction can be used to get a list of all currently
 <!-- ************************************************************************************
      ************************************************************************************
      ************************************************************************************ -->
+<h2>Tickets</h2>
+
+<h3>Getting Tickets</h3>
+
+The <tt>getticket</tt> transaction can be used to get information about a ticket. The request contains only the ticketID, the response looks like:<p>
+
+<pre>
+&lt;Ticket id="ticketid" status="ticketstate" order="orderid" event="eventid" price="priceincent" orderpaystate="status of the order" />
+</pre>
+
+The attribute orderid may be &lt;0 if the ticket is not attached to an order.<p>
+
+<table frame="1" border="1">
+<tr><td><b>Attribute</b></td><td><b>Description</b></td></tr>
+<tr><td>status</td><td>can be any of reserved, bought, used, refund, error (see getorder above for details)</td></tr>
+<tr><td>orderpaystate</td><td>the payment status of the order, it can be "none" if the order is invalid or the ticket is not attached to one, "ok" if the order has been paid correctly, "cancelled" if the order was cancelled, "needpayment" if the order is not fully paid yet, or "needrefund" if too much has been paid</td></tr>
+</table>
+
+<h3>Using Tickets</h3>
+
+The <tt>useticket</tt> transaction marks a ticket as used. The request contains only the ticket ID, the response has status ok and no body if the action succeeded, it has status error and an explanatory text if it failed.<p>
+
+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.
+
+<!-- ************************************************************************************
+     ************************************************************************************
+     ************************************************************************************ -->
 <h2>Templates</h2>
 
 Templates are used for printouts and documents. There are several types of templates:<p>
index fbdebf2..f27fcc0 100644 (file)
@@ -352,11 +352,32 @@ MTicket::MTicket()
        m_eventid=m_orderid=-1;
        m_price=0;
        m_status=Invalid;
+       m_paystate=PSUnknown;
+}
+
+MTicket::MTicket(MWebRequest*r,QString t)
+{
+       req=r;
+       m_eventid=m_orderid=-1;
+       m_price=0;
+       m_status=Invalid;
+       m_paystate=PSUnknown;
+       if(!req->request("getticket",t.toAscii()))return;
+       if(req->responseStatus()!=MWebRequest::Ok)return;
+       QDomDocument doc;
+       if(!doc.setContent(req->responseBody()))return;
+       scanXml(doc.documentElement());
 }
 
 MTicket::MTicket(MWebRequest*r,const QDomElement&e)
 {
        req=r;
+       m_paystate=PSUnknown;
+       scanXml(e);
+}
+
+void MTicket::scanXml(const QDomElement&e)
+{
        m_eventid=e.attribute("event","-1").toInt();
        m_orderid=e.attribute("order","-1").toInt();
        m_id=e.attribute("id");
@@ -374,6 +395,13 @@ MTicket::MTicket(MWebRequest*r,const QDomElement&e)
        if(st=="cancelled")m_status=CheckFailCancelled;else
        if(st=="invalid")m_status=CheckFailEventInvalid;
        else m_status=Invalid;
+       st=e.attribute("orderpaystate");
+       if(st=="none")m_paystate=PSNone;else
+       if(st=="cancelled")m_paystate=PSCancelled;else
+       if(st=="ok")m_paystate=PSOk;else
+       if(st=="needpayment")m_paystate=PSNeedPayment;else
+       if(st=="needrefund")m_paystate=PSNeedRefund;
+       else m_paystate=PSUnknown;
 }
 
 MTicket::MTicket(const MTicket&t)
@@ -389,6 +417,7 @@ MTicket& MTicket::operator=(const MTicket&t)
        m_price=t.m_price;
        m_status=t.m_status;
        m_id=t.m_id;
+       m_paystate=t.m_paystate;
        return *this;
 }
 
@@ -454,6 +483,26 @@ QString MTicket::statusString()const
        }
 }
 
+
+MTicket::PaymentStatus MTicket::paymentStatus()
+{
+       if(m_paystate!=PSUnknown)return m_paystate;
+       if(!isValid())return PSUnknown;
+       if(!req->request("getticket",m_id.toAscii()))return PSUnknown;
+       if(req->responseStatus()!=MWebRequest::Ok)return PSUnknown;
+       QDomDocument doc;
+       if(!doc.setContent(req->responseBody()))return PSUnknown;
+       scanXml(doc.documentElement());
+       return m_paystate;
+}
+
+QString MTicket::markUsed()
+{
+       if(!req->request("useticket",m_id.toAscii()))return QCoreApplication::translate("MTicket","Cannot execute request.");
+       if(req->responseStatus()==MWebRequest::Ok)return "";
+       return QCoreApplication::translate("MTicket",req->responseBody().data());
+}
+
 void MTicket::setOrderID(qint32 o)
 {
        m_orderid=o;
index 186fd9a..750b4ba 100644 (file)
@@ -30,6 +30,8 @@ class MTicket
        public:
                /**creates an invalid ticket*/
                MTicket();
+               /**gets the ticket from the database*/
+               MTicket(MWebRequest*,QString);
                /**creates a ticket from XML*/
                MTicket(MWebRequest*,const QDomElement&);
                /**copies a ticket*/
@@ -99,6 +101,28 @@ class MTicket
                /**returns the ticket status as string*/
                QString statusString()const;
                
+               /**payment state of the order*/
+               enum PaymentStatus{
+                       /**yet unknown, need to retrieve it*/
+                       PSUnknown,
+                       /**no order state (no order)*/
+                       PSNone,
+                       /**order has been paid ok*/
+                       PSOk,
+                       /**order is cancelled*/
+                       PSCancelled,
+                       /**order needs payment*/
+                       PSNeedPayment,
+                       /**order needs refund*/
+                       PSNeedRefund
+               };
+               
+               /**returns the payment state of the order (may check database)*/
+               PaymentStatus paymentStatus();
+               
+               /**marks the ticket as used in the database; returns empty string on success, error on failure*/
+               QString markUsed();
+               
        protected:
                friend class MOrder;
                /**sets the order-ID of the ticket, used by MOrder*/
@@ -108,8 +132,12 @@ class MTicket
                MWebRequest*req;
                qint32 m_eventid,m_orderid,m_price;
                TicketStatus m_status;
+               PaymentStatus m_paystate;
                QString m_id;
                mutable MEvent m_event;
+               
+               /**helper: scan XML data*/
+               void scanXml(const QDomElement&);
 };
 
 class MOrder
index d5a307c..df5d240 100644 (file)
@@ -825,23 +825,53 @@ void MOverview::tabChanged()
 
 void MOverview::entranceValidate()
 {
-       //TODO: actually ask the server
+       //check content
+       QString tid=entrancescan->text().trimmed();
+       //avoid spurious events
+       if(tid=="")return;
+       //avoid double scans
+       QDateTime now=QDateTime::currentDateTime();
+       if(tid==lastbarcode && lastbcscan.addSecs(20)>=now){
+               entrancescan->setText("");
+               return;
+       }
+       lastbarcode=tid;
+       lastbcscan=now;
+       //ask the server
+       MTicket tick(req,tid);
+       //decide what to do
        QPalette pal=entrancelabel->palette();
        QPalette::ColorRole rl=QPalette::Window;
-       switch(rand()%3){
-               case 0:
-                       entrancelabel->setText(tr("Ticket Ok"));
-                       pal.setColor(rl,Qt::green);
-                       break;
-               case 1:
-                       entrancelabel->setText(tr("Ticket Already Used"));
-                       pal.setColor(rl,Qt::magenta);
-                       break;
-               case 2:
-                       entrancelabel->setText(tr("Ticket Not Paid"));
-                       pal.setColor(rl,Qt::red);
-                       break;
+       if(!tick.isValid()){
+               entrancelabel->setText(tr("Ticket \"%1\" Not Valid").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.status()==MTicket::Used){
+               entrancelabel->setText(tr("Ticket \"%1\" has already been used").arg(tid));
+               pal.setColor(rl,Qt::magenta);
+       }else
+       if(tick.status()!=MTicket::Bought){
+               entrancelabel->setText(tr("Ticket \"%1\" has not been bought.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.paymentStatus()==MTicket::PSOk){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedRefund){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok; the Order has a refund").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedPayment){
+               entrancelabel->setText(tr("Ticket \"%1\" is not paid for!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else{
+               entrancelabel->setText(tr("Ticket \"%1\" cannot be accepted, please check the order!").arg(tid));
+               pal.setColor(rl,Qt::red);
        }
+       
        entrancelabel->setPalette(pal);
        entrancescan->setFocus(Qt::OtherFocusReason);
        entrancescan->setText("");
@@ -930,7 +960,7 @@ MPasswordChange::MPasswordChange(QWidget*par,QString user)
        if(user=="")
                setWindowTitle(tr("Change my password"));
        else
-               setWindowTitle(tr("Reset password of user %1").arg(user));
+               setWindowTitle(tr("Reset password of user \"%1\"").arg(user));
        QGridLayout*gl;
        setLayout(gl=new QGridLayout);
        if(user==""){
index d82abe3..a0f4c66 100644 (file)
 #ifndef MAGICSMOKE_OVERVIEW_H
 #define MAGICSMOKE_OVERVIEW_H
 
-#include <QMainWindow>
-#include <QPointer>
+#include <QDateTime>
 #include <QDialog>
 #include <QItemDelegate>
+#include <QMainWindow>
+#include <QPointer>
 
 #include "customer.h"
 
@@ -136,6 +137,9 @@ class MOverview:public QMainWindow
                QLineEdit*entrancescan;
                //cart
                MCustomer customer;
+               //barcode cache
+               QString lastbarcode;
+               QDateTime lastbcscan;
 };
 
 /**Helper dialog for changing passwords*/
index d2a352a..91265e8 100644 (file)
@@ -349,6 +349,31 @@ class Order
                $xml->appendChild($doc);
                print($xml->saveXml());
        }
+       
+       /**returns the current status of the order*/
+       public function getStatus()
+       {
+               return $this->status;
+       }
+       
+       /**helper function: returns whether the order has outstanding payments/refunds*/
+       public function getPaymentStatus()
+       {
+               global $db;
+               //calculate amount due
+               $totalprice=0;
+               $res=$db->select("ticket","ticketid","orderid=".$db->escapeInt($this->orderid));
+               if(count($res)>0)
+               foreach($res as $tc){
+                       $tick=new Ticket($tc["ticketid"]);
+                       if($tick->mustBePaid())$totalprice+=$tick->getPrice();
+               }
+               //TODO: add vouchers
+               //compare with what has been paid
+               if($totalprice==$this->amountpaid)return "ok";
+               if($totalprice<$this->amountpaid)return "needrefund";
+               else return "needpayment";
+       }
 };
 
 function createOrderXml($xmldata,$action)
index 77c719d..f355b6e 100644 (file)
@@ -109,7 +109,7 @@ class Ticket
                }
        }
        
-       /**returns whether the ticket must be paid*/
+       /**returns whether the ticket must be paid (or is already paid)*/
        public function mustBePaid()
        {
                return ($this->status & TICKET_MBLOCK) != 0;
@@ -159,7 +159,83 @@ class Ticket
                return true;
        }
        
+       /**dumps the ticket as XML*/
+       public function dumpXml()
+       {
+               $xml=new DomDocument;
+               $doc=$xml->createElement("Ticket");
+               $doc->setAttribute("id",$this->ticketid);
+               $doc->setAttribute("status",$this->xmlStatus());
+               $doc->setAttribute("order",$this->orderid);
+               $doc->setAttribute("event",$this->eventid);
+               $doc->setAttribute("price",$this->price);
+               $doc->setAttribute("orderpaystate",$this->orderPayStateXml());
+               $xml->appendChild($doc);
+               print($xml->saveXml());
+       }
+       
+       /**helper: gets the status of the order for dumpXml*/
+       protected function orderPayStateXml()
+       {
+               if($this->orderid<0)return "none";
+               $ord=new Order($this->orderid);
+               if(!$ord->isValid())return "none";
+               if($ord->getStatus()==ORDER_CLOSED)return "ok";
+               if($ord->getStatus()==ORDER_CANCELLED)return "cancelled";
+               return $ord->getPaymentStatus();
+       }
        
+       /**tries to mark the ticket as used*/
+       public function markUsedXml()
+       {
+               if(!$this->isValid()){
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("The ticket is not valid."));
+               }
+               if($this->status==TICKET_USED){
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("The ticket has already been used."));
+               }
+               if($this->status!=TICKET_BOUGHT){
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("The ticket has not been bought or is cancelled."));
+               }
+               $ps=$this->orderPayStateXml();
+               if($ps=="needpayment"){
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("The ticket has not been paid."));
+               }
+               if($ps!="ok" && $ps!="needrefund"){
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("The tickets order is in an invalid state or does not exist."));
+               }
+               $this->status=TICKET_USED;
+               global $db;
+               $db->update("ticket",array("status"=>TICKET_USED),"ticketid=".$db->escapeInt($this->ticketid));
+       }
 };
 
+function getTicketXml($tid)
+{
+       $tick=new Ticket($tid);
+       if($tick->isValid()){
+               header("X-MagicSmoke-Status: Ok");
+               $tick->dumpXml();
+       }else{
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Unable to find this ticket."));
+       }
+}
+
+function useTicketXml($tid)
+{
+       $tick=new Ticket($tid);
+       if($tick->isValid())
+               $tick->markUsedXml();
+       else{
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Unable to find this ticket."));
+       }
+}
+
 ?>
\ No newline at end of file
index 1614254..381da55 100644 (file)
@@ -24,6 +24,7 @@ $ALLOWEDREQUESTS=array(
        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("gettemplatelist"),tr("gettemplate"),tr("settemplate") //templates
 );
 /**contains the low-level request name from the client*/
@@ -286,6 +287,16 @@ if($SMOKEREQUEST=="getorder"){
        exit();
 }
 
+//get a ticket
+if($SMOKEREQUEST=="getticket"){
+       getTicketXml(trim($REQUESTDATA));
+       exit();
+}
+//mark a ticket as used
+if($SMOKEREQUEST=="useticket"){
+       useTicketXml(trim($REQUESTDATA));
+       exit();
+}
 
 //EOF
 header("X-MagicSmoke-Status: Error");