order works on GUI now
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 15 Mar 2008 21:16:04 +0000 (21:16 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 15 Mar 2008 21:16:04 +0000 (21:16 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@117 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

doc/prog_protocol.html
src/overview.cpp
src/overview.h
www/config.php.template
www/inc/classes/cart.php
www/inc/classes/event.php
www/inc/classes/order.php
www/inc/classes/random.php
www/inc/classes/ticket.php
www/inc/machine/session.php
www/machine.php

index 1f520b0..7663575 100644 (file)
@@ -388,10 +388,111 @@ The "mail" attribute is optional - it is only reported for customers that have a
 
 <h2>Orders and Sales</h2>
 
-<h3>Creating Orders/Sales</h2>
+The order XML representation looks as follows:
+
+<pre>
+&lt;Order id="orderid" customer="customerid" seller="sellerid" ordertime="timestamp" senttime="timestamp"
+    totalprice="amountInCent" paid="amountInCent" status="orderstate">
+  &lt;Ticket event="eventid" id="ticketid" price="priceInCent" status="ticketstate" />
+  &lt;Voucher id="voucherid" price="priceInCent" value="remainingValueInCent" />
+  &lt;DeliveryAddress>deliver address&lt;/DeliveryAddress>
+  &lt;Comment>comment...&lt;/Comment>
+&lt;/Order>
+</pre>
+
+<table frame="1" border="1">
+<tr><td><b>Item</b></td><td><b>Description</b></td><td><b>Occurrence</b></td></tr>
+
+<tr/>
+<tr><td>Order</td><td>Container for one single order or sale</td><td>1</td></tr>
+<tr><td>&nbsp; id</td><td>ID of the order, if already known.</td><td>0-1</td></tr>
+<tr><td>&nbsp; customer</td><td>ID of the customer. Mandatory.</td><td>1</td></tr>
+<tr><td>&nbsp; seller</td><td>Login of the seller. Automatically filled in.</td><td>0-1</td></tr>
+<tr><td>&nbsp; ordertime</td><td>Time of the order. Automatically filled in.</td><td>0-1</td></tr>
+<tr><td>&nbsp; senttime</td><td>Time at which the order was shipped. Automatically filled in.</td><td>0-1</td></tr>
+<tr><td>&nbsp; totalprice</td><td>Total accumulated price of the order. Automatically filled in.</td><td>0-1</td></tr>
+<tr><td>&nbsp; paid</td><td>Amount that has already been paid. Automatically filled in.</td><td>0-1</td></tr>
+<tr><td>&nbsp; status</td><td>Current status of the order. Automatically filled in. See table below.</td><td>0-1</td></tr>
+
+<tr/>
+<tr><td>Ticket(*)</td><td>data about a single ticket bought in this order</td><td>0-unlimited</td></tr>
+</table>
+(*)At least one of Ticket or Voucher must be used.<p>
+
+If items that are not expected are filled in in a message, they will be ignored.<p>
+
+Order status:<br/>
+<table frame="1" border="1">
+<tr><td><b>Status</b></td><td><b>Description</b></td></tr>
+<tr><td>placed</td><td>The order has been placed, nothing has been sent or paid yet.</td></tr>
+<tr><td>sent</td><td>The order has been shipped.</td></tr>
+<tr><td>cancelled</td><td>The user cancelled an unshipped and unpaid order.</td></tr>
+<tr><td>closed</td><td>The order is final and cannot be altered. (State maybe not needed.)</td></tr>
+</table><p/>
+
+Ticket status:<br/>
+<table frame="1" border="1">
+<tr><td><b>Status</b></td><td><b>Description</b></td></tr>
+<tr><td>bought(1)</td><td>The ticket is valid; whether it is paid for depends on the order status.</td></tr>
+<tr><td>refund(2)</td><td>The ticket has been or needs to be refunded; eg. after the event or order was cancelled.</td></tr>
+<tr><td>used(1)</td><td>The ticket has been used.</td></tr>
+<tr><td>reserved</td><td>The ticket is reserved. This state is currently not used.</td></tr>
+</table>
+(1)bought and used tickets add to the total price of an order; only bought tickets can be used<br/>
+(2)refunded tickets add nothing to the total price of an order, this may make the paid amount higher than the amount due.<p/>
+
+<h3>Checking or Creating Orders/Sales</h3>
+
+The <tt>createorder</tt> transaction creates an open order. The initial state of the order is "placed".<br/>
+The <tt>createsale</tt> transaction creates an order that is marked as delivered and paid. The initial state of the created order is "sent" and the amount paid is equal to the total price.<br/>
+The <tt>checkorder</tt> transaction performs all checks and lookups of an order, but does not commit it to the database.<p>
+
+The <tt>create*</tt> transactions fail with an error if a ticket cannot be reserved or if a voucher value is invalid. The <tt>checkorder</tt> transaction uses special state values to signify failure. It sets the price of a voucher to the nearest legal voucher value if the value is not allowed.<p>
+
+The request is an order object without most fields filled in, the response is a copy of that object with all relevant fields filled in:
+
+<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>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/>
+(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>
+
+Order status for checks:
+<table frame="1" border="1">
+<tr><td><b>State</b></td><td><b>Description</b></td></tr>
+<tr><td>ok(1)</td><td>the order can be executed as is</td></tr>
+<tr><td>saleonly(2)</td><td>the order can only be continued as a sale, not as an open order</td></tr>
+<tr><td>orderonly(2)</td><td>the order can only be continued as an open order, not as a sale; this state also shows that there is a problem with the configuration</td></tr>
+<tr><td>fail</td><td>the order contains failed items</td></tr>
+</table>
+(1)Attention: the return code "ok" means the order would have succeeded at the time of the check, it may still fail when it is actually placed<br/>
+(2)these states are equivalent to ok if the intended transaction matches and to fail if it does not match<p/>
+
+Ticket status for checks:
+<table frame="1" border="1">
+<tr><td><b>State</b></td><td><b>Description</b></td></tr>
+<tr><td>ok(1)</td><td>the order can be executed as is</td></tr>
+<tr><td>saleonly(2)</td><td>the order can only be continued as a sale, not as an open order</td></tr>
+<tr><td>orderonly(2)</td><td>the order can only be continued as an open order, not as a sale; this state also shows that there is a problem with the configuration</td></tr>
+<tr><td>toolate</td><td>the order is not possible any more</td></tr>
+<tr><td>exhausted</td><td>there are no more tickets for this event</td></tr>
+<tr><td>cancelled</td><td>the event has been cancelled, no order is possible</td>
+<tr><td>invalid</td><td>the event does not exist in the database</td></tr>
+</table>
+(1)Attention: the return code "ok" means the order would have succeeded at the time of the check, it may still fail when it is actually placed<br/>
+(2)if two or more tickets contradict on this state the order is returned as failed<p/>
 
-The <tt>createorder</tt> transaction creates an open order. The <tt>createsale</tt> transactions creates an order that is marked as delivered and paid. The request is an order object, the response is a copy of that object with prices filled in. (???)
 
+<!-- ***************************************** -->
 <h2>Templates</h2>
 
 Templates are used for printouts and documents. There are several types of templates:<p>
index b2364ae..4283f53 100644 (file)
@@ -34,6 +34,8 @@
 #include <QFile>
 #include <QCryptographicHash>
 #include <QSpinBox>
+#include <QDomDocument>
+#include <QDomElement>
 
 MOverview::MOverview(MWebRequest*mw,QString pk)
 {
@@ -59,10 +61,10 @@ MOverview::MOverview(MWebRequest*mw,QString pk)
        m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
        
        m=mb->addMenu(tr("C&art"));
-       m->addAction(tr("Add &Ticket"));
-       m->addAction(tr("Add &Voucher"));
-       m->addAction(tr("&Remove Item"));
-       m->addAction(tr("&Abort Shopping"));
+       m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
+       m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()))->setEnabled(false);
+       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
        m->addSeparator();
        m->addAction(tr("&Show all orders"));
        
@@ -674,14 +676,66 @@ void MOverview::cartRemoveItem()
        cartmodel->removeRow(idx.row());
 }
 
-void MOverview::cartOrder()
+void MOverview::cartOrder(QString otype)
 {
-       //TODO: implement
+       //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;
+       }
+       ///////////////
+       //create order
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",customer.customerID());
+       //is there a delivery address
+       QString s=cartaddr->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(s));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       s=cartcomment->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(s));
+               root.appendChild(cc);
+       }
+       //scan tickets
+       //  TODO: scan vouchers
+       for(int i=0;i<cartmodel->rowCount();i++){
+               int amt=cartmodel->data(cartmodel->index(i,0)).toInt();
+               int evid=cartmodel->data(cartmodel->index(i,0),Qt::UserRole).toInt();
+               for(int j=0;j<amt;j++){
+                       QDomElement tc=doc.createElement("Ticket");
+                       tc.setAttribute("event",evid);
+                       root.appendChild(tc);
+               }
+       }
+       doc.appendChild(root);
+       //send
+       if(req->request(otype,doc.toByteArray())==false){
+               QMessageBox::warning(this,tr("Error"),tr("The request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MWebRequest::Ok){
+               QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(tr(req->responseBody())));
+               return;
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       //TODO: do something with it
 }
 
 void MOverview::cartSell()
 {
-       //TODO: implement
+       cartOrder("createsale");
 }
 
 void MOverview::customerMgmt()
@@ -754,7 +808,7 @@ QWidget *MCartTableDelegate::createEditor(QWidget *parent,
        if(index.column()!=0)return 0;
        
        QSpinBox *editor = new QSpinBox(parent);
-       editor->setRange(0,1000);
+       editor->setRange(1,1000);
        editor->installEventFilter(const_cast<MCartTableDelegate*>(this));
        return editor;
 }
index c92c5fc..c407fd7 100644 (file)
@@ -95,7 +95,7 @@ class MOverview:public QMainWindow
                /**remove item from the cart*/
                void cartRemoveItem();
                /**send the order to the server*/
-               void cartOrder();
+               void cartOrder(QString otype="createorder");
                /**send the order to the server as sold*/
                void cartSell();
                
index b9f7e43..4142f64 100644 (file)
@@ -22,6 +22,8 @@ $db->setDbName("smoke");
 $db->setPrefix("smoke_");
 //set this to one of the supported MySQL storage engines for DB creation
 $db->setStorageEngine("InnoDB");
+//set default character set
+$db->setCharacterSet("utf8");
 
 
 ////////////
index cec8e8d..df217e4 100644 (file)
@@ -68,6 +68,8 @@ define("CE_EVENTNOTICKETS",11);
 define("CE_EVENTUNKNOWN",12);
 /**this error is returned if the event is already over or tickets cannot be purchased anymore*/
 define("CE_EVENTOVER",13);
+/**this error is returned if an invalid voucher value is ordered*/
+define("CE_INVALIDVOUCHER",20);
 
 /**instantiated by Cart::orderCheck to report errors*/
 class CartError
@@ -212,22 +214,39 @@ class Cart
        public function orderCheck()
        {
                global $db;
-               //TODO: extend to differentiate online, shop and direct sale
+               //NOTE: only covers online order
                $ret=array();
                //go through events
                global $db;
                $res=$db->select("cart_ticket","*","cartid=".$db->escapeString($this->cartid));
+               $orderstop=($db->getConfig("OrderStop")+0)*3600;
                if(count($res)>0)
                foreach($res as $k=>$tc){
                        $evt=new Event($tc["eventid"]);
-                       //TODO: add more checks (event over, cancelled, etc.pp.)
+                       //check that tickets can be sold
+                       if(!$evt->exists())
+                               $ret[]=new CartError(CE_EVENTUNKNOWN,$tc["eventid"]);
+                       else
                        if($evt->availableTicketAmount()<$tc["amount"])
                                $ret[]=new CartError(CE_EVENTNOTICKETS,$tc["eventid"]);
+                       else
+                       if(($evt->getStartTime()-$orderstop)<=time())
+                               $ret[]=new CartError(CE_EVENTOVER,$tc["eventid"]);
+                       else
+                       if($evt->isCancelled())
+                               $ret[]=new CartError(CE_EVENTCANCELLED,$tc["eventid"]);
+                       else
+                               $itemcnt++;
+               }
+               //check voucher values
+               $validvouchers=explode(" ",$db->getConfig("ValidVouchers"));
+               $res=$db->select("cart_voucher", "cvid,value", "cartid=".$db->escapeString($this->cartid));
+               foreach($res as $k=>$vc){
+                       if(in_array("".$vc["value"],$validvouchers))
+                               $itmcnt++;
+                       else
+                               $ret[]=new CartError(CE_INVALIDVOUCHER);
                }
-               //vouchers are ok by default, just check amount
-               $itmcnt=count($res);
-               $res=$db->select("cart_voucher", "cvid", "cartid=".$db->escapeString($this->cartid));
-               $itmcnt+=count($res);
                //check that we have something to order
                if($itmcnt<=0)
                        $ret[]=new CartError(CE_NOITEMS);
index a694347..482202a 100644 (file)
@@ -141,7 +141,7 @@ class Event
                reset($res);
                if(count($res)>0)
                foreach($res as $tk){
-                       if(!($tk["status"]&TICKET_CANCELLED))$amt++;
+                       if(!($tk["status"]&TICKET_MBLOCK))$amt++;
                }
                return $this->capacity - $amt;
        }
index be8c896..6fed4e0 100644 (file)
 //
 
 /**an order has been placed, this flag is set when the order is filled and finalized*/
-define("ORDER_PLACED",1);
+define("ORDER_PLACED",0);
 /**the order has been sent out (it must be placed first; direct sales are automatically sent)*/
-define("ORDER_SENT",2);
+define("ORDER_SENT",1);
 /**the order has been cancelled by the user (this is only possible as long as no money has been paid and nothing has been sent yet)*/
-define("ORDER_CANCELLED",4);
-/**the order is closed (optional: this flag means no further payment/cancellation/etc. is possible)*/
-define("ORDER_CLOSED",8);
+define("ORDER_CANCELLED",2);
+/**the order has been finalized; no more changes possible*/
+define("ORDER_CLOSED",10);
 
 
 /**this class represents an order in the database*/
 class Order
 {
-       private $orderid;
+       //cache
+       private $orderid=false;
        private $status=false;
        private $customerid=false;
+       private $deliveryaddress="";
+       private $comment="";
+       private $seller=false;
+       private $amountpaid=0;
+       private $ordertime=false;
+       private $senttime=false;
+       //to be submitted
+       private $newtickets;
+       private $newvouchers;
        
        /**instantiates an existing order with the given orderid or creates a new one if orderid===false*/
        public function __construct($orderid=false)
        {
                global $db;
-               if($orderid===false){
-                       //create a new one
-                       $odr=array(
-                               //set to default
-                               "soldby"=>"_online",
-                               "status" => 0,
-                               "ordertime" => time()
-                       );
-                       $this->orderid=$db->insert("order",$odr);
-               }else{
+               if($orderid!==false){
                        //get it from DB
                        $res=$db->select("order","*","orderid=".$db->escapeInt($orderid));
                        if(count($res)==0){
-                               $this->orderid=false;
                                return;
                        }
                        $this->orderid=$res[0]["orderid"];
                        $this->status=$res[0]["status"];
                        $this->customerid=$res[0]["customerid"];
+                       $this->deliveryaddress=$res[0]["deliveryaddress"];
+                       $this->comment=$res[0]["comments"];
+                       $this->seller=$res[0]["soldby"];
+                       $this->amountpaid=$res[0]["amountpaid"];
+                       $this->ordertime=$res[0]["ordertime"];
+                       $this->senttime=$res[0]["senttime"];
                }
+               $this->newtickets=array();
+               $this->newvouchers=array();
        }
        
-       /**returns whether the order can still be changed*/
+       /**returns whether the order can still be changed; this does not affect the modify routines*/
        public function canChange()
        {
-               return $this->isValid() && $this->status == 0;
+               return $this->status == false;
        }
        
        /**returns whether the order is a valid DB object*/
@@ -74,71 +82,314 @@ class Order
                //check myself
                if(!$this->canChange())return false;
                //get tickets
-               $db->beginTransaction();
                $tick=$cart->getTickets();
                if(count($tick)>0)
                foreach($tick as $k=>$tc){
-                       $this->addTickets($tc->getEventId(),$tc->getAmount());
+                       $eid=$tc->getEventId();
+                       $amt=$tc->getAmount();
                        $tc->changeAmount(0);
+                       if(isset($this->newtickets[$eid]))
+                               $this->newtickets[$eid]+=$amt;
+                       else
+                               $this->newtickets[$eid]=$amt;
                }
                //TODO: get vouchers
-               //done
-               $db->commitTransaction();
                return true;
        }
        
-       /**adds some tickets to the order, returns ticketid or false if change is not possible*/
-       public function addTickets($eventid,$amount)
+       /**used by XML functions: add a single ticket for an event*/
+       public function addTicket($eid)
        {
-               if(!$this->canChange() || $amount <= 0)return false;
-               global $db;
-               //get event
-               $event=new Event($eventid);
-               //check that there are tickets available
-               if($event->availableTicketAmount()<$amount)return false;
-               //create ticket
-               $tc=array("eventid" => $eventid,
-                       "price" => $event->getDefaultPrice(),
-                       "status" => 0,
-                       "orderid" => $this->orderid
-               );
-               $ret=array();
-               for($i=0;$i<$amount;$i++)$ret[]=$db->insert("ticket",$tc);
-               return $ret;
+               if(isset($this->newtickets[$eid]))
+                       $this->newtickets[$eid]+=1;
+               else
+                       $this->newtickets[$eid]=1;
        }
        
-       /**sets the customer of this order; returns 1 on success, false or 0 on failure*/
+       /**sets the customer of this order; returns true on success, false on failure*/
        public function setCustomer($cust)
        {
                global $db;
                if(!$this->canChange() || !$cust->isValid())return false;
-               return $db->update("order",array("customerid"=>$cust->getID()),"orderid=".$db->escapeInt($this->orderid));
+               $this->customerid=$cust->getID();
+               return true;
+       }
+       
+       /**sets the customer of this order; returns true on success, false on failure*/
+       public function setCustomerid($cust)
+       {
+               return $this->setCustomer(new Customer($cust));
        }
        
        /**places/finalizes the order; returns false on failure, true on success or if the order already was finalized()*/
-       public function placeOrder()
+       public function placeOrder($isSale=false)
        {
-               if(!$this->canChange())return;
-               global $db;
+               //sanity check
+               if(!$this->canChange())return false;
+               if((count($this->newtickets)+count($this->newvouchers))==0)return false;
+               global $db,$session;
                $db->beginTransaction();
-               //get orderstatus and correct it
-               $res=$db->select("order","status","orderid=".$db->escapeInt($this->orderid));
-               if(count($res)==0){
-                       $this->orderid=false;
+               if(!$this->validateOrder()){
                        $db->rollbackTransaction();
                        return false;
                }
-               $db->update("order",array("status"=>ORDER_PLACED),"orderid=".$db->escapeInt($this->orderid));
+               //create order
                $this->status=ORDER_PLACED;
+               if(isset($session))$usr=$session->getUser();
+               else $usr=false;
+               $this->seller=$usr;
+               $this->ordertime=time();
+               $this->amountpaid=0;
+               $this->orderid=$db->insert("order",array("customerid"=>$this->customerid,"soldby"=>$usr,"deliveryaddress"=>$this->deliveryaddress,"status"=>$this->status,"ordertime"=>$this->ordertime,"comments"=>$this->comment,"amountpaid"=>0));
+               //orderid ok?
+               if($this->orderid===false){
+                       $db->rollbackTransaction();
+                       return false;
+               }
+               //insert tickets
+               $totalprice=0;
+               foreach($this->newtickets as $evid=>$amount){
+                       for($i=0;$i<$amount;$i++){
+                               $tick=new Ticket;
+                               $tick->setEventId($evid);
+                               $tick->addToOrder($this->orderid);
+                               $totalprice+=$tick->getPrice();
+                               //TODO: check return code of addToOrder
+                       }
+               }
+               //TODO: insert vouchers
+               //update amountpaid for sales
+               if($isSale){
+                       $db->update("order",array("amountpaid"=>$totalprice,"status"=>ORDER_SENT),"orderid=".$db->escapeInt($this->orderid));
+                       $this->status=ORDER_SENT;
+                       $this->amountpaid=$totalprice;
+               }
                //end
                $db->commitTransaction();
                return true;
        }
+       
+       /**validates the order against the database; returns whether it can be opened as an order; prints an order object fit for checkorder if $dumpxml is true*/
+       public function validateOrder($dumpxml=false)
+       {
+               global $db;
+               $ret=true;
+               $price=0;
+               $ostat="ok";
+               $xml=new DomDocument;
+               $ord=$xml->createElement("Order");
+               //check customer
+               $res=$db->select("customer","customerid","customerid=".$db->escapeInt($this->customerid));
+               if(count($res)<1){
+                       if($dumpxml===false)return false;
+                       $ostat="fail";
+                       $ret=false;
+                       $ord->setAttribute("customer","-1");
+               }else
+                       $ord->setAttribute("customer",$this->customerid);
+               //check tickets
+               $orderstop=($db->getConfig("OrderStop")+0)*3600;
+               $salestop=($db->getConfig("SaleStop")+0)*3600;
+               $curtime=time();
+               foreach($this->newtickets as $evid => $amount){
+                       
+                       $evt=new Event($evid);
+                       if(!$evt->exists()){
+                               if($dumpxml===false)return false;
+                               //create only one ticket and make it sound negative
+                               $ev=$xml->createElement("Ticket");
+                               $ev->setAttribute("event",$evid);
+                               $ev->setAttribute("status","invalid");
+                               $ord->appendChild($ev);
+                               $ret=false;
+                               $ostat="fail";
+                               continue;
+                       }
+                       $stime=$evt->getStartTime();
+                       $estat="ok";
+                       if(($stime-$orderstop)<=$curtime){
+                               if($dumpxml===false)return false;
+                               $estat="saleonly";
+                               $ret=false;
+                       }
+                       if(($stime-$salestop)<=$curtime)
+                               if($estat=="ok")$estat="orderonly";
+                               else $estat="toolate";
+                       if($estat!="ok"){
+                               //create only one ticket and make it sound negative
+                               $ev=$xml->createElement("Ticket");
+                               $ev->setAttribute("event",$evid);
+                               $ev->setAttribute("status",$estat);
+                               $ord->appendChild($ev);
+                               if($ostat=="ok")$ostat=$estat;
+                               else if($ostat!=$estat)$ostat="fail";
+                               $ret=false;
+                               continue;
+                       }
+                       if($evt->isCancelled()){
+                               if($dumpxml===false)return false;
+                               //create only one ticket and make it sound negative
+                               $ev=$xml->createElement("Ticket");
+                               $ev->setAttribute("event",$evid);
+                               $ev->setAttribute("status","cancelled");
+                               $ord->appendChild($ev);
+                               $ret=false;
+                               continue;
+                       }
+                       $avail=$evt->availableTicketAmount();
+                       if($avail<$amount){
+                               if($dumpxml===false)return false;
+                               //create a few good ones
+                               for($i=0;$i<$avail;$i++){
+                                       $ev=$xml->createElement("Ticket");
+                                       $ev->setAttribute("event",$evid);
+                                       $ev->setAttribute("status","ok");
+                                       $ev->setAttribute("price",$evt->getDefaultPrice());
+                                       $ord->appendChild($ev);
+                               }
+                               //create only one bad ticket
+                               $ev=$xml->createElement("Ticket");
+                               $ev->setAttribute("event",$evid);
+                               $ev->setAttribute("status","exhausted");
+                               $ord->appendChild($ev);
+                               $ret=false;
+                               continue;
+                       }
+                       //finally create good ones
+                       for($i=0;$i<$amount;$i++){
+                               $ev=$xml->createElement("Ticket");
+                               $ev->setAttribute("event",$evid);
+                               $ev->setAttribute("status","ok");
+                               $ev->setAttribute("price",$evt->getDefaultPrice());
+                               $ord->appendChild($ev);
+                       }
+               }
+               
+               //TODO: check vouchers
+               
+               //add other data
+               if($dumpxml){
+                       $ord->appendChild($xml->createElement("DeliveryAddress",$this->deliveryaddress));
+                       $ord->appendChild($xml->createElement("Comment",$this->comment));
+                       $ord->setAttribute("status",$ostat);
+                       $xml->appendChild($ord);
+                       print($xml->saveXml());
+               }
+               return $ret;
+       }
+       
+       /**returns the ID of this order or false if it is not in the database yet*/
+       public function getOrderId()
+       {
+               return $this->orderid;
+       }
+       
+       /**dumps the whole order as XML*/
+       public function dumpXml()
+       {
+               $xml=new DomDocument;
+               $doc=$xml->createElement("Order");
+               $doc->setAttribute("id",$this->orderid);
+               $doc->setAttribute("customer",$this->customerid);
+               $doc->setAttribute("seller",$this->seller);
+               $doc->setAttribute("ordertime",$this->ordertime);
+               $doc->setAttribute("paid",$this->amountpaid);
+               switch($this->status){
+                       case ORDER_PLACED:
+                               $doc->setAttribute("status","placed");
+                               break;
+                       case ORDER_SENT:
+                               $doc->setAttribute("status","sent");
+                               break;
+                       case ORDER_CANCELLED:
+                               $doc->setAttribute("status","cancelled");
+                               break;
+                       case ORDER_CLOSED:
+                               $doc->setAttribute("status","closed");
+                               break;
+                       default:
+                               $doc->setAttribute("status","error");
+                               break;
+               }
+               $doc->setAttribute("senttime",$this->senttime);
+               //add Tickets
+               $totalprice=0;
+               global $db;
+               $res=$db->select("ticket","ticketid","orderid=".$db->escapeInt($this->orderid));
+               if(count($res)>0)
+               foreach($res as $tc){
+                       $tick=new Ticket($tc["ticketid"]);
+                       $tx=$xml->createElement("Ticket");
+                       $tx->setAttribute("event",$tick->getEventId());
+                       $tx->setAttribute("id",$tick->getTicketID());
+                       $tx->setAttribute("price",$tick->getPrice());
+                       $tx->setAttribute("status",$tick->xmlStatus());
+                       if($tick->mustBePaid())$totalprice+=$tick->getPrice();
+                       $doc->appendChild($tx);
+               }
+               //TODO: add vouchers
+               
+               //add sum
+               $doc->setAttribute("totalprice",$totalprice);
+               
+               //add static fields
+               $doc->appendChild($xml->createElement("DeliveryAddress",$this->deliveryaddress));
+               $doc->appendChild($xml->createElement("Comment",$this->comment));
+               
+               //dump
+               $xml->appendChild($doc);
+               print($xml->saveXml());
+       }
 };
 
-function createOrderXml($xmldata,$ispaid)
+function createOrderXml($xmldata,$action)
 {
-       //parse XML data
+       //parse XML data and fill order object
+       $order=new Order;
+       $xml=new DomDocument;
+       $xml->loadXml($xmldata);
+       $doc=$xml->documentElement;
+       $cust=$doc->getAttribute("customer")+0;
+       $order->setCustomerId($cust);
+       //get tickets
+       foreach($doc->getElementsByTagName("Ticket") as $tc){
+               $order->addTicket($tc->getAttribute("event")+0);
+       }
+       //TODO: get vouchers
+       
+       //check action
+       switch($action){
+               case "check":
+                       // check order
+                       $order->validateOrder(true);
+                       header("X-MagicSmoke-Status: Ok");
+                       break;
+               case "order":
+                       // create order
+//                     $order->validateOrder(true);
+                       if($order->placeOrder()){
+                               header("X-MagicSmoke-Status: Ok");
+                               $order->dumpXml();
+                       }else{
+                               header("X-MagicSmoke-Status: Error");
+                               die(tr("Cannot place order, sorry."));
+                       }
+                       break;
+               case "sell":
+                       //create order
+                       if($order->placeOrder(true)){
+                               header("X-MagicSmoke-Status: Ok");
+                               //finalize sale
+                               $order->dumpXml();
+                       }else{
+                               header("X-MagicSmoke-Status: Error");
+                               die(tr("Cannot place order, sorry."));
+                       }
+                       break;
+               default:
+                       header("X-MagicSmoke-Status: Error");
+                       die(tr("Internal Error: unknown action."));
+       }
 }
 
 ?>
\ No newline at end of file
index 9b19645..ff154af 100644 (file)
@@ -50,4 +50,20 @@ function getSalt()
        return getRandom(16*4);
 }
 
+/**return a new Code-39 capable ID; length is the amount of characters*/
+function getCode39ID($length)
+{
+       $c39="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       $rnd=getRandom($length*8);
+       $ret="";
+       for($i=0;$i<$length;$i++){
+               //cut random
+               $r="0x".substr($rnd,$i*2,2);
+               $r=($r+0)&31;
+               //append char
+               $ret.=substr($c39,$r,1);
+       }
+       return $ret;
+}
+
 ?>
\ No newline at end of file
index ff3a28c..322943a 100644 (file)
 //
 //
 
+//masks
+/**mask: ticket is blocked (can be used or is used)*/
+define("TICKET_MBLOCK",0x100);
+
 
 /**ticket has been reserved by a seller*/
-define("TICKET_RESERVED",1);
+define("TICKET_RESERVED",0x101);
 /**ticket is part of an order or has been sold independently*/
-define("TICKET_SOLD",2);
+define("TICKET_BOUGHT",0x102);
 /**ticket has been used*/
-define("TICKET_USED",4);
-/**the ticket has been paid*/
-define("TICKET_PAID",8);
+define("TICKET_USED",0x103);
 /**ticket has been cancelled by some entity*/
-define("TICKET_CANCELLED",16);
+define("TICKET_CANCELLED",0x4);
+/**ticket has been refunded*/
+define("TICKET_REFUND",0x4);
+
+class Ticket
+{
+       private $ticketid=false;
+       private $eventid=false;
+       private $price=false;
+       private $status=false;
+       private $reservedby=false;
+       private $reservetimeout=false;
+       private $orderid=false;
+       
+       private static $NumTicketChars=false;
+       
+       /**generates a ticket, if $ticketid is false it creates an empty ticket, if it is a string it attempts to find it in the database*/
+       public function __construct($ticketid=false)
+       {
+               global $db;
+               if(self::$NumTicketChars===false){
+                       self::$NumTicketChars=$db->getConfig("TicketIDChars")+0;
+                       if(self::$NumTicketChars<=5)self::$NumTicketChars=10;
+               }
+               if($ticketid!==false){
+                       $res=$db->select("ticket","*","ticketid=".$db->escapeString(strtoupper($ticketid)));
+                       if(count($res)<1)return;
+                       $this->ticketid=strtoupper($ticketid);
+                       $this->eventid=$res[0]["eventid"];
+                       $this->price=$res[0]["price"];
+                       $this->status=$res[0]["status"];
+                       $this->reservedby=$res[0]["reservedby"];
+                       $this->reservetimeout=$res[0]["reservetimeout"];
+                       $this->orderid=$res[0]["orderid"];
+               }
+       }
+       
+       /**returns whether this is a valid DB object*/
+       public function isValid()
+       {
+               return $this->ticketid!==false;
+       }
+       
+       /**returns the ID of the ticket*/
+       public function getTicketId()
+       {
+               return $this->ticketid;
+       }
+       
+       /**returns the ID of the event*/
+       public function getEventId()
+       {
+               return $this->eventid;
+       }
+       
+       /**returns the price of the ticket*/
+       public function getPrice()
+       {
+               return $this->price;
+       }
+       
+       /**returns the ticket status*/
+       public function getStatus()
+       {
+               return $this->status;
+       }
+       
+       /**returns the ticket status for XML output*/
+       public function xmlStatus()
+       {
+               switch($this->status){
+                       case TICKET_RESERVED:
+                               return "reserved";
+                       case TICKET_BOUGHT:
+                               return "bought";
+                       case TICKET_USED:
+                               return "used";
+                       case TICKET_CANCELLED:
+                               return "refund";
+                       default:
+                               return "error";
+               }
+       }
+       
+       /**returns whether the ticket must be paid*/
+       public function mustBePaid()
+       {
+               return ($this->status & TICKET_MBLOCK) != 0;
+       }
+       
+       /**sets the event and copies the price from it; returns true on success*/
+       public function setEventId($e)
+       {
+               global $db;
+               //find event
+               $res=$db->select("event","defaultprice","eventid=".$db->escapeInt($e));
+               if(count($res)<1)return false;
+               $this->eventid=$e+0;
+               $this->price=$res[0]["defaultprice"];
+       }
+       
+       /**sets the event and copies the price from it; returns true on success*/
+       public function setEvent($e)
+       {
+               return $this->setEventID($e->getEventId());
+       }
+       
+       /**creates the ticket in the database and adds it to the order; expects orderid as argument; returns false if it fails; it may fail if the event has not been set*/
+       public function addToOrder($o)
+       {
+               global $db;
+               //sanity checks
+               if($this->ticketid!==false)return false;
+               if($this->eventid===false)return false;
+               //generate ticket ID
+               $db->beginTransaction();
+               do{
+                       $tid=getCode39ID(self::$NumTicketChars);
+                       $res=$db->select("ticket","ticketid","ticketid=".$db->escapeString($tid));
+                       if(count($res)==0)break;
+               }while(true);
+               //create entry
+               $res=$db->insert("ticket",array("ticketid"=>$tid,"eventid"=>$this->eventid, "price"=>$this->price,"status"=>TICKET_BOUGHT,"orderid"=>$o));
+               if($res===false){
+                       $db->rollbackTransaction();
+                       return false;
+               }
+               $db->commitTransaction();
+               $this->ticketid=$tid;
+               $this->status=TICKET_BOUGHT;
+               $this->orderid=$o;
+               return true;
+       }
+       
+       
+};
 
 ?>
\ No newline at end of file
index f509ba8..d9ebd82 100644 (file)
@@ -71,6 +71,12 @@ class Session
                return $this->sessid!="";
        }
        
+       /**returns the user name of the session*/
+       public function getUser()
+       {
+               return $this->user;
+       }
+       
        /**returns true if the session is actually authenticated*/
        public function isAuthenticated()
        {
index 89f672d..e759177 100644 (file)
@@ -23,7 +23,7 @@ $ALLOWEDREQUESTS=array(
        tr("geteventlist"),tr("geteventdata"),tr("seteventdata"), //event infos
        tr("getroomdata"),tr("setroomdata"),//room infos
        tr("getcustomerlist"),tr("getcustomer"),tr("setcustomer"), //customer info
-       tr("createorder"),tr("createsale"), //sell/order stuff
+       tr("checkorder"),tr("createorder"),tr("createsale"), //sell/order stuff
        tr("gettemplatelist"),tr("gettemplate"),tr("settemplate") //templates
 );
 /**contains the low-level request name from the client*/
@@ -255,12 +255,16 @@ if($SMOKEREQUEST=="setcustomer"){
 }
 
 
+if($SMOKEREQUEST=="checkorder"){
+       createOrderXml($REQUESTDATA,"check");
+       exit();
+}
 if($SMOKEREQUEST=="createorder"){
-       createOrderXml($REQUESTDATA,false);
+       createOrderXml($REQUESTDATA,"order");
        exit();
 }
 if($SMOKEREQUEST=="createsale"){
-       createOrderXml($REQUESTDATA,true);
+       createOrderXml($REQUESTDATA,"sell");
        exit();
 }