significantly more on order window
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 30 Dec 2009 17:38:48 +0000 (17:38 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 30 Dec 2009 17:38:48 +0000 (17:38 +0000)
got rid of old event.*

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

30 files changed:
src/dialogs/eventedit.h
src/dialogs/orderwin.cpp
src/dialogs/orderwin.h
src/iface/iface.pri
src/iface/msinterface.cpp
src/iface/msinterface.h
src/templates/templates.h
src/wbase/WObject.h
src/wext/MOAddress.cpp [new file with mode: 0644]
src/wext/MOAddress.h [new file with mode: 0644]
src/wext/MOCustomerInfo.cpp [new file with mode: 0644]
src/wext/MOCustomerInfo.h
src/wext/MOEvent.cpp [moved from src/iface/event.cpp with 53% similarity]
src/wext/MOEvent.h [moved from src/iface/event.h with 54% similarity]
src/wext/MOOrder.cpp
src/wext/MOOrder.h
src/wext/MOTicket.h
src/wext/MOVoucher.h [new file with mode: 0644]
src/wext/wext.pri
wob/customer.wolf
wob/event.wolf
wob/order.wolf
woc/phpout.cpp
woc/phpout.h
woc/processor.cpp
woc/processor.h
woc/qtout.cpp
www/inc/classes/event.php
www/inc/wbase/table.php
www/inc/wext/order.php

index bd183a7..96f5046 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <QDialog>
 
-#include "event.h"
+#include "MOEvent.h"
 
 class QCheckBox;
 class QDateTime;
@@ -38,7 +38,7 @@ class MEventEditor:public QDialog
                void startTimeChanged(const QDateTime&);
                void endTimeChanged(const QDateTime&);
        private:
-               MEvent event;
+               MOEvent event;
                QDateTimeEdit*starttime,*endtime;
                QLineEdit*title,*artist,*room,*price,*cancelreason;
                QTextEdit*description;
index 8b60a08..4a6f118 100644 (file)
@@ -11,7 +11,6 @@
 //
 
 #include "centbox.h"
-#include "event.h"
 #include "labeldlg.h"
 #include "misc.h"
 #include "moneylog.h"
@@ -19,6 +18,9 @@
 #include "orderwin.h"
 #include "ticketrender.h"
 #include "msinterface.h"
+#include "templates.h"
+
+#include "MOEvent.h"
 
 #include <QApplication>
 #include <QBoxLayout>
@@ -67,7 +69,7 @@ MOrderWindow::MOrderWindow(QWidget*par,const MOOrder&o)
        m->addAction(tr("Change Commen&t..."),this,SLOT(changeComment()))
         ->setEnabled(req->hasRole("setordercomment"));
        m->addAction(tr("Change Sh&ipping Method..."),this,SLOT(changeShipping()))
-        ->setEnabled(req->hasRole("changeordershipping"));
+        ->setEnabled(req->hasRight(req->ROrderChangeShipping));
        m->addSeparator();
        m->addAction(tr("MoneyLog for Order..."),this,SLOT(moneyLogOrder()))
         ->setEnabled(req->hasRole("moneylog"));
@@ -110,9 +112,14 @@ MOrderWindow::MOrderWindow(QWidget*par,const MOOrder&o)
        gl->addWidget(m_sentdate=new QLabel(m_order.sentDateTimeStr()),rw,1);
        gl->addWidget(new QLabel(tr("Customer:")),++rw,0);
        gl->addWidget(new QLabel(m_order.customer().value().fullName()),rw,1);
-       gl->addWidget(new QLabel(tr("Delivery Address:")),++rw,0);
-       //FIXME:gl->addWidget(lab=new QLabel(m_order.deliveryAddress()),rw,1);
-       //lab->setWordWrap(true);
+       gl->addWidget(lab=new QLabel(tr("Delivery Address:")),++rw,0);
+       lab->setAlignment(Qt::AlignTop);
+       gl->addWidget(lab=new QLabel(m_order.fullDeliveryAddress(false)),rw,1);
+       lab->setWordWrap(true);lab->setFrameShape(lab->Box);lab->setFrameShadow(lab->Raised);
+       gl->addWidget(lab=new QLabel(tr("Invoice Address:")),++rw,0);
+       lab->setAlignment(Qt::AlignTop);
+       gl->addWidget(lab=new QLabel(m_order.fullInvoiceAddress(false)),rw,1);
+       lab->setWordWrap(true);lab->setFrameShape(lab->Box);lab->setFrameShadow(lab->Raised);
        gl->addWidget(new QLabel(tr("Sold by:")),++rw,0);
        gl->addWidget(new QLabel(m_order.soldby()),rw,1);
        gl->addWidget(new QLabel(tr("Total Price:")),++rw,0);
@@ -122,14 +129,13 @@ MOrderWindow::MOrderWindow(QWidget*par,const MOOrder&o)
        gl->addWidget(new QLabel(tr("Order State:")),++rw,0);
        gl->addWidget(m_state=new QLabel(m_order.orderStatusString()),rw,1);
        gl->addWidget(new QLabel(tr("Shipping Method:")),++rw,0);
-       //FIXME:
-       gl->addWidget(m_shipmeth=new QLabel(/*m_order.shipping().description()*/"ship?"),rw,1);
+       gl->addWidget(m_shipmeth=new QLabel(m_order.shippingtype().value().description()),rw,1);
        gl->addWidget(new QLabel(tr("Shipping Costs:")),++rw,0);
-       gl->addWidget(m_shipprice=new QLabel(/*m_order.shipping().priceString()*/),rw,1);
-       gl->addWidget(new QLabel(tr("Order Comment:")),++rw,0);
-       //FIXME:
-       gl->addWidget(m_comment=lab=new QLabel(/*m_order.comment()*/"comment?"),rw,1);
-       lab->setWordWrap(true);
+       gl->addWidget(m_shipprice=new QLabel(cent2str(m_order.shippingcosts())),rw,1);
+       gl->addWidget(lab=new QLabel(tr("Order Comment:")),++rw,0);
+       lab->setAlignment(Qt::AlignTop);
+       gl->addWidget(m_comment=lab=new QLabel(m_order.comments()),rw,1);
+       lab->setWordWrap(true);lab->setFrameShape(lab->Box);lab->setFrameShadow(lab->Raised);
        gl->setColumnStretch(0,0);
        gl->setColumnStretch(1,10);
        
@@ -147,46 +153,66 @@ MOrderWindow::MOrderWindow(QWidget*par,const MOOrder&o)
        sz.setHeight(sz.height()+vsz.height()+40);
        //TODO: limit this to the screen size; find a better measure than viewport
        resize(sz);
-       
-       req->dataDir();
 }
 
 static const int ITEM_TICKET=1;
 static const int ITEM_VOUCHER=2;
+static const int ITEM_ITEM=3;
 
 void MOrderWindow::updateTable()
-{/*TODO:
+{
+       //get detail data
        QList<MOTicket> tickets=m_order.tickets();
-       QList<MEvent> events;
-       if(tickets.size()>0)
-               events=req->getAllEvents();
-       QList<MVoucher> vouchers=m_order.vouchers();
+       QList<MOEvent> events;
+       if(tickets.size()>0){
+               QList<qint64>evid;
+               for(int i=0;i<tickets.size();i++)
+                       if(!evid.contains(tickets[i].eventid()))
+                               evid.append(tickets[i].eventid());
+               MTGetEventList gel=req->queryGetEventList(evid);
+               events=gel.getevents();
+       }
+       QList<MOVoucher> vouchers=m_order.vouchers();
+       QList<MOItemInfo> items=m_order.items();
+       //set up model
        m_model->clear();
        m_model->setHorizontalHeaderLabels(QStringList()<<tr("Item ID")<<tr("Description")<<tr("Start Time")<<tr("Status")<<tr("Price"));
-       m_model->insertRows(0,tickets.size()+vouchers.size());
+       m_model->insertRows(0,tickets.size()+vouchers.size()+items.size());
+       //insert tickets
        for(int i=0;i<tickets.size();i++){
-               m_model->setData(m_model->index(i,0),tickets[i].ticketID());
+               m_model->setData(m_model->index(i,0),tickets[i].ticketid().value());
                m_model->setData(m_model->index(i,0),ITEM_TICKET,Qt::UserRole);
                m_model->setData(m_model->index(i,3),tickets[i].statusString());
                m_model->setData(m_model->index(i,4),tickets[i].priceString());
                //find event
-               MEvent ev;int eid=tickets[i].eventID();
+               MOEvent ev;int eid=tickets[i].eventid();
                for(int j=0;j<events.size();j++)
-                       if(events[j].eventId()==eid)
+                       if(events[j].eventid().value()==eid)
                                ev=events[j];
                //render remainder
-               m_model->setData(m_model->index(i,1),ev.title());
+               m_model->setData(m_model->index(i,1),ev.title().value());
                m_model->setData(m_model->index(i,2),ev.startTimeString());
        }
+       //insert vouchers
        int off=tickets.size();
        for(int i=0;i<vouchers.size();i++){
                m_model->setData(m_model->index(i+off,0),ITEM_VOUCHER,Qt::UserRole);
-               m_model->setData(m_model->index(i+off,0),vouchers[i].voucherID());
+               m_model->setData(m_model->index(i+off,0),vouchers[i].voucherid().value());
                m_model->setData(m_model->index(i+off,1),tr("Voucher (current value: %1)").arg(vouchers[i].valueString()));
                m_model->setData(m_model->index(i+off,3),vouchers[i].statusString());
                m_model->setData(m_model->index(i+off,4),vouchers[i].priceString());
        }
-       m_table->resizeColumnsToContents();*/
+       //TODO: insert items
+       off+=vouchers.size();
+       for(int i=0;i<items.size();i++){
+               m_model->setData(m_model->index(i+off,0),ITEM_ITEM,Qt::UserRole);
+               m_model->setData(m_model->index(i+off,0),items[i].itemid().value());
+               m_model->setData(m_model->index(i+off,1),tr("%1x %2").arg(items[i].amount().value()).arg(items[i].productname().value()));
+               m_model->setData(m_model->index(i+off,3),"");
+               m_model->setData(m_model->index(i+off,4),cent2str(items[i].totalprice()));
+       }
+       //refresh
+       m_table->resizeColumnsToContents();
 }
 
 void MOrderWindow::setChanged()
@@ -239,22 +265,20 @@ void MOrderWindow::printCurrentItem()
 
 void MOrderWindow::printTickets()
 {
-       //FIXME:
-       //printTickets(m_order.tickets());
+       printTickets(m_order.tickets());
 }
 
 void MOrderWindow::printVouchers()
 {
-       //FIXME
-       //printVouchers(m_order.vouchers());
+       printVouchers(m_order.vouchers());
 }
 
 void MOrderWindow::printTickets(QList<MOTicket> ticketsin)
-{/*TODO
+{
        //reduce ticket list to usable ones
-       QList<MTicket> tickets;
+       QList<MOTicket> tickets;
        for(int i=0;i<ticketsin.size();i++){
-               if(ticketsin[i].status()==MTicket::Bought)
+               if(ticketsin[i].status()&MOTicket::MaskUsable)
                        tickets.append(ticketsin[i]);
        }
        //sanity check
@@ -263,7 +287,7 @@ void MOrderWindow::printTickets(QList<MOTicket> ticketsin)
                return;
        }
        //get template
-       MTemplate tf=req->getTemplate("ticket");
+       MTemplate tf=req->templateStore()->getTemplate("ticket");
        if(!tf.isValid()){
                QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (ticket.xtt). Giving up."));
                return;
@@ -287,15 +311,15 @@ void MOrderWindow::printTickets(QList<MOTicket> ticketsin)
                        printer.newPage();
                }
                render.render(tickets[i],printer,&painter,p);
-       }*/
+       }
 }
 
 void MOrderWindow::printVouchers(QList<MOVoucher> vouchersin)
-{/*TODO
+{
        //reduce voucher list to usable ones
-       QList<MVoucher>vouchers;
+       QList<MOVoucher>vouchers;
        for(int i=0;i<vouchersin.size();i++){
-               if(vouchersin[i].isValid() && vouchersin[i].value()>0 && vouchersin[i].xmlState()=="")
+               if(vouchersin[i].isValid() && vouchersin[i].value()>0)
                        vouchers.append(vouchersin[i]);
        }
        //sanity check
@@ -304,7 +328,7 @@ void MOrderWindow::printVouchers(QList<MOVoucher> vouchersin)
                return;
        }
        //get template
-       MTemplate tf=req->getTemplate("voucher");
+       MTemplate tf=req->templateStore()->getTemplate("voucher");
        if(!tf.isValid()){
                QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (voucher.xtt). Giving up."));
                return;
@@ -328,7 +352,7 @@ void MOrderWindow::printVouchers(QList<MOVoucher> vouchersin)
                        printer.newPage();
                }
                render.render(vouchers[i],printer,&painter,p);
-       }*/
+       }
 }
 
 void MOrderWindow::restorePrinter(QPrinter&prn,QString key)
@@ -841,31 +865,6 @@ void MOrderWindow::createOrder(Create mode)
        close();*/
 }
 
-void MOrderWindow::createSale()
-{
-       createOrder(CreateSale);
-}
-
-void MOrderWindow::createReservation()
-{
-       createOrder(CreateReservation);
-}
-
-void MOrderWindow::recheckOrder()
-{/*TODO
-       //prune
-       m_order.pruneInvalid();
-       //now check
-       MOrder ord;
-       ord=m_order.createOrder("checkorder");
-       if(!ord.isValid())return;
-       //display final order
-       MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord);
-       ow->show();
-       //undisplay self
-       close();*/
-}
-
 void MOrderWindow::shipOrder()
 {/*TODO
        if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){
@@ -926,17 +925,24 @@ void MOrderWindow::changeComment()
 }
 
 void MOrderWindow::changeShipping()
-{/*TODO
+{
        //create editor dialog
-       MShippingChange d(this,req,m_order.shipping());
+       MShippingChange d(this,m_order.shippingtype(),m_order.shippingcosts());
        //get status
        if(d.exec()!=QDialog::Accepted)return;
        //send to server
-       m_order.sendShipping(d.selection());
+       int shipid=-1;
+       if(!d.selection().shipid().isNull())shipid=d.selection().shipid();
+       MTOrderChangeShipping ocs=req->queryOrderChangeShipping(m_order.orderid(),shipid,d.price());
+       if(ocs.hasError()){
+               QMessageBox::warning(this,tr("Warning"),tr("Error while changing shipping: %1").arg(ocs.errorString()));
+               return;
+       }
+       m_order=ocs.getorder();
        //reset display
-       m_shipmeth->setText(m_order.shipping().description());
-       m_shipprice->setText(m_order.shipping().priceString());
-       m_total->setText(m_order.totalPriceString());*/
+       m_shipmeth->setText(m_order.shippingtype().value().description());
+       m_shipprice->setText(cent2str(m_order.shippingcosts()));
+       m_total->setText(m_order.totalPriceString());
 }
 
 void MOrderWindow::moneyLogOrder()
@@ -984,23 +990,20 @@ MOrderItemView::MOrderItemView(QWidget*w,QList<MOTicket>t,QList<MOVoucher>v)
                cb->addItem(tr("Voucher: ")+vouchers[i].voucherid());
        vl->addWidget(disp=new QLabel,10);
        //get the templates
-       /*TODO
-       trender=new MTicketRenderer(req->getTemplate("ticket"));
-       vrender=new MVoucherRenderer(req->getTemplate("voucher"));
-       */
+       trender=new MTicketRenderer(req->templateStore()->getTemplate("ticket"));
+       vrender=new MVoucherRenderer(req->templateStore()->getTemplate("voucher"));
        changeItem(0);
        connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int)));
 }
 
 MOrderItemView::~MOrderItemView()
 {
-       //FIXME
-       //delete trender;
-       //delete vrender;
+       delete trender;
+       delete vrender;
 }
 
 void MOrderItemView::changeItem(int idx)
-{/*TODO
+{
        //ticket or voucher?
        if(idx<tickets.size()){
                QSizeF sz=trender->labelSize(*disp);
@@ -1016,21 +1019,20 @@ void MOrderItemView::changeItem(int idx)
                if(!vrender->render(vouchers[idx-tickets.size()],tick))
                        qDebug("unable to render");
                disp->setPixmap(tick);
-       }*/
+       }
 }
 
 
 /*************************************************************************************/
 
-MShippingChange::MShippingChange(QWidget*pa,MOShipping s)
+MShippingChange::MShippingChange(QWidget*pa,MOShipping s,int costs)
        :QDialog(pa)
 {
        all=req->queryGetAllShipping().getshipping();
        setWindowTitle(tr("Change Shipping Method"));
        
        int cid=-1;
-       //FIXME:
-       //if(s.isValid())cid=s.id();
+       if(!s.shipid().isNull())cid=s.shipid();
        
        QGridLayout*gl;
        setLayout(gl=new QGridLayout);
@@ -1050,8 +1052,8 @@ MShippingChange::MShippingChange(QWidget*pa,MOShipping s)
        connect(p,SIGNAL(clicked()),this,SLOT(reject()));
        
        prc->setRange(0,1000000000);//hmm, even in Yen this should be big enough
-       prc->setValue(s.cost());
-       prc->setEnabled(req->hasRole("orderchangeshipping"));
+       prc->setValue(costs);
+       prc->setEnabled(req->hasRight(req->POrderChangeShipping_ChangePrice));
        
        opt->addItem(tr("(None)","shipping method"));
        int scid=0;
index b4175ac..d08819c 100644 (file)
@@ -96,15 +96,6 @@ class MOrderWindow:public QMainWindow
                /**create a new order*/
                void createOrder(Create mode=CreateOrder);
                
-               /**create a sale*/
-               void createSale();
-               
-               /**create a new reservation*/
-               void createReservation();
-               
-               /**prune and recheck the order*/
-               void recheckOrder();
-               
                /**money log for the order*/
                void moneyLogOrder();
                /**money log for a voucher*/
@@ -170,7 +161,7 @@ class MShippingChange:public QDialog
        Q_OBJECT
        public:
                /**creates the dialog*/
-               MShippingChange(QWidget*,MOShipping);
+               MShippingChange(QWidget*,MOShipping,int);
                
                /**returns the selected shipping option, including corrected price*/
                MOShipping selection()const;
index 2836044..c9dc8e7 100644 (file)
@@ -1,13 +1,11 @@
 HEADERS += \
        iface/msinterface.h \
-       iface/event.h \
        iface/sslexception.h \
        iface/customer.h
        
 
 SOURCES += \
        iface/msinterface.cpp \
-       iface/event.cpp \
        iface/sslexception.cpp \
        iface/customer.cpp
 
index 74f4ba0..374efee 100644 (file)
@@ -13,6 +13,7 @@
 #include "msinterface.h"
 #include "main.h"
 #include "sslexception.h"
+#include "templates.h"
 
 #include <QDebug>
 #include <QDir>
@@ -41,6 +42,7 @@ MSInterface::MSInterface(QString pid)
        setLogLevel((LogLevel)set.value("webloglevel",LogOnError).toInt());
        setWebTimeout(set.value("webtimeout",30).toInt()*1000);
        sslexcept=new MSslExceptions(dataDir()+"/sslexceptions.xml");
+       temp=new MTemplateStore(pid);
 }
 
 MSInterface::~MSInterface()
@@ -48,6 +50,8 @@ MSInterface::~MSInterface()
        logout();
        if(sslexcept)delete sslexcept;
        sslexcept=0;
+       if(temp)delete temp;
+       temp=0;
 }
 
 bool MSInterface::login(QString username,QString passwd)
index 937d8c7..bc4b07f 100644 (file)
@@ -19,6 +19,7 @@
 
 
 class MSslExceptions;
+class MTemplateStore;
 
 /**the MagicSmoke specific interface class - enhances the basic interface by some functionality needed in the MagicSmoke context*/
 class MSInterface:public MInterface
@@ -64,6 +65,9 @@ class MSInterface:public MInterface
                
                /**initializes the interface, ie. retrieves language and scripts*/
                void initialize();
+               
+               /**returns a pointer to the template storage engine*/
+               MTemplateStore* templateStore(){return temp;}
        
        public slots:
                /**logs into the server, returns true on success*/
@@ -84,6 +88,7 @@ class MSInterface:public MInterface
                QByteArray servertranslation;
                MSslExceptions*sslexcept;
                bool didsslerror;
+               MTemplateStore *temp;
 };
 
 
index 08e5aa4..6fe0d96 100644 (file)
@@ -105,7 +105,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTemplate::Types)
 class MTemplateStore
 {
        protected:
-               //FIXME friend class MWebRequest;
+               friend class MSInterface;
                friend class MTemplateEditor;
                /**instantiates the template subsystem*/
                MTemplateStore(QString);
index d10cbc6..afce3bd 100644 (file)
 class QDomElement;
 class QDomDocument;
 
+/**base class of all web based objects*/
 class WObject:public QObject
 {
        protected:
                WObject(){}
 };
 
+/**this exception is thrown if the deserialization of an object fails on the XML parser level*/
 class WDeserializerException:public WException
 {
        public:
                WDeserializerException(QString e):WException(e,"Deserializer"){}
 };
 
+/**the WOBJECT macro defines the necessary constructors if you just want to extend an abstract class without overwriting the constructors yourself*/
+#define WOBJECT(wob) public: \
+ wob():wob ## Abstract(){} \
+ wob(const wob&w):wob ## Abstract(w){} \
+ wob(const wob ## Abstract&w):wob ## Abstract(w){} \
+ wob(const QDomElement&w):wob ## Abstract(w){} \
+ wob& operator=(const wob&w){wob ## Abstract::operator=(w);return *this;} \
+ wob& operator=(const wob ## Abstract&w){wob ## Abstract::operator=(w);return *this;} \
+ private:
+
 #endif
diff --git a/src/wext/MOAddress.cpp b/src/wext/MOAddress.cpp
new file mode 100644 (file)
index 0000000..2f18aea
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// C++ Implementation: MOAddress
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "MOAddress.h"
+
+#include <QStringList>
+
+QString MOAddress::fullAddress(QString nm)const
+{
+       //if not valid: return nothing
+       if(!isValid())return "";
+       //collect lines
+       QStringList rl;
+       if(name().isNull()){
+               if(nm!="")rl<<nm;
+       }else rl<<name();
+       if(!addr1().isNull())rl<<addr1();
+       if(!addr2().isNull())rl<<addr2();
+       if(!city().isNull())rl<<city();
+       if(!state().isNull())rl<<state();
+       if(!zipcode().isNull())rl<<zipcode();
+       if(!country().isNull())rl<<country().value().name();
+       //assemble
+       QString r;
+       for(int i=0;i<rl.size();i++){
+               if(i)r+="\n";
+               r+=rl[i];
+       }
+       
+       return r;
+}
diff --git a/src/wext/MOAddress.h b/src/wext/MOAddress.h
new file mode 100644 (file)
index 0000000..1aea6d9
--- /dev/null
@@ -0,0 +1,30 @@
+//
+// C++ Interface: MOAddress
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_MADDRESS_H
+#define MAGICSMOKE_MADDRESS_H
+
+#include "MOAddressAbstract.h"
+
+class MOAddress:public MOAddressAbstract
+{
+       WOBJECT(MOAddress);
+       public:
+               /**returns the full address, if name is given and the address does not have its own name, it is included as top line*/
+               QString fullAddress(QString name=QString())const;
+               
+               /**returns true if this is a valid address (ie. it has an address ID)*/
+               bool isValid()const{return !addressid().isNull() && addressid().value()>=0;}
+};
+
+
+#endif
diff --git a/src/wext/MOCustomerInfo.cpp b/src/wext/MOCustomerInfo.cpp
new file mode 100644 (file)
index 0000000..52bf13c
--- /dev/null
@@ -0,0 +1,14 @@
+//
+// C++ Implementation: MOCustomerInfo
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "MOCustomerInfo.h"
+
index 998befe..34c1bcc 100644 (file)
 #include "MOCustomerInfoAbstract.h"
 class MOCustomerInfo:public MOCustomerInfoAbstract
 {
+       WOBJECT(MOCustomerInfo);
        public:
-               MOCustomerInfo():MOCustomerInfoAbstract(){}
-               MOCustomerInfo(const MOCustomerInfo&o):MOCustomerInfoAbstract(o){}
-               MOCustomerInfo(const QDomElement&e):MOCustomerInfoAbstract(e){}
-
                QString fullName()const{return title()+" "+name()+", "+firstname();}
 };
 
similarity index 53%
rename from src/iface/event.cpp
rename to src/wext/MOEvent.cpp
index e81f4a6..d8413eb 100644 (file)
@@ -10,7 +10,7 @@
 //
 //
 
-#include "event.h"
+#include "MOEvent.h"
 
 #include <QCoreApplication>
 #include <QDateTime>
 
 #include "msinterface.h"
 
-MEvent::MEvent(qint64 i)
+MOEvent::MOEvent(qint64 i)
 {
        MTGetEvent ge=MSInterface::instance()->queryGetEvent(i);
        if(ge.stage()==ge.Success)
                operator=(ge.getevent().value());
 }
 
-QRegExp MEvent::priceRegExp()const
+QRegExp MOEvent::priceRegExp()const
 {
-       return QRegExp(QCoreApplication::translate("MEvent","[0-9]+\\.[0-9]{2}","price validator regexp"));
+       return QRegExp(QCoreApplication::translate("MOEvent","[0-9]+\\.[0-9]{2}","price validator regexp"));
 }
 
-QString MEvent::priceString()const
+QString MOEvent::priceString()const
 {
        qint64 dp=/*defaultprice()*/0;
        QString ret=QString::number(dp/100);
-       ret+=QCoreApplication::translate("MEvent",".","price decimal dot");
+       ret+=QCoreApplication::translate("MOEvent",".","price decimal dot");
        ret+=QString::number((dp/10)%10);
        ret+=QString::number(dp%10);
        return ret;
 }
 
-QString MEvent::startTimeString()const
+QString MOEvent::startTimeString()const
 {
-        return QDateTime::fromTime_t(start()).toString(QCoreApplication::translate("MEvent","yyyy-MM-dd hh:mm ap","date/time format"));
+        return QDateTime::fromTime_t(start()).toString(QCoreApplication::translate("MOEvent","yyyy-MM-dd hh:mm ap","date/time format"));
 }
 
-QString MEvent::startDateString()const
+QString MOEvent::startDateString()const
 {
-        return QDateTime::fromTime_t(start()).toString(QCoreApplication::translate("MEvent","yyyy-MM-dd","date format"));
+        return QDateTime::fromTime_t(start()).toString(QCoreApplication::translate("MOEvent","yyyy-MM-dd","date format"));
 }
 
-QString MEvent::endTimeString()const
+QString MOEvent::endTimeString()const
 {
-        return QDateTime::fromTime_t(end()).toString(QCoreApplication::translate("MEvent","yyyy-MM-dd hh:mm ap","date/time format"));
+        return QDateTime::fromTime_t(end()).toString(QCoreApplication::translate("MOEvent","yyyy-MM-dd hh:mm ap","date/time format"));
 }
 
-void MEvent::setdefaultprice(QString str)
+void MOEvent::setdefaultprice(QString str)
 {
-       QStringList ps=str.split(QCoreApplication::translate("MEvent",".","price decimal dot"));
+       /*TODO: we have multiple prices now!
+       QStringList ps=str.split(QCoreApplication::translate("MOEvent",".","price decimal dot"));
        qint64 prc=0;
        if(ps.size()>=1)prc=ps[0].toInt()*100;
        if(ps.size()>=2)prc+=ps[1].toInt();
-       setdefaultprice(prc);
+       setdefaultprice(prc);*/
 }
similarity index 54%
rename from src/iface/event.h
rename to src/wext/MOEvent.h
index e5b9f7b..7f981a8 100644 (file)
 #define EVENT_H
 
 #include <QString>
-#include <MOEvent.h>
+#include <MOEventAbstract.h>
 
 /**encapsulation of an event, this class wraps the auto-generated event class to provide some convenience methods*/
-class MEvent:public MOEvent
+class MOEvent:public MOEventAbstract
 {
+       WOBJECT(MOEvent);
        public:
-               /**creates an invalid event*/
-               MEvent():MOEvent(){}
-               /**copies an event*/
-               MEvent(const MEvent&e):MOEvent(e){}
-               /**copies an event*/
-               MEvent(const MOEvent&e):MOEvent(e){}
                /**get event directly from server*/
-               MEvent(qint64);
-               /**destructs an event*/
-               ~MEvent(){}
+               MOEvent(qint64);
                
-               /**copies the event*/
-               MEvent& operator=(const MEvent&e){MOEvent::operator=(e);return *this;}
-               
-               /**updates data from the database, can be used to upgrade an incomplete event to a complete one*/
-               //void refresh();
-               
-               /**saves all data back to the database, it returns an empty string on success, it does not do anything if the event is invalid or incomplete*/
-               //QString save();
+               /**alias for id()*/
+               inline Nullable<qint64> eventid()const{return id();}
                
                /**returns the start time of the event as localized string*/
                QString startTimeString()const;
@@ -56,14 +43,8 @@ class MEvent:public MOEvent
                /**set the price as string*/
                void setdefaultprice(QString);
                
-               //inherit alternative definition
-               inline void setdefaultprice(qint64 p){/*MOEvent::setdefaultprice(p);*/}
-               
                /**returns whether the event is valid. an event can be invalid if it is uninitialized (negative ID) or the server request failed*/
-               //bool isValid()const{return m_valid;}
-               
-               /**requests to cancel the event from the DB; expects reason as argument; returns true on success*/
-               //bool cancelEvent(QString);
+               bool isValid()const{return !eventid().isNull() && eventid().value()>0;}
 };
 
 #endif
index 27387b9..9f103a8 100644 (file)
@@ -100,3 +100,26 @@ QString MOOrder::sentDateStr()
        return QDateTime::fromTime_t(senttime()).toString(QCoreApplication::translate("MOOrder","yyyy-MM-dd","date format"));
 }
 
+QString MOOrder::fullInvoiceAddress(bool allowfallback)const
+{
+       if(!invoiceaddress().isNull() && invoiceaddress().value().isValid())
+               return invoiceaddress().value().fullAddress(customer().value().fullName());
+       //fall back
+       if(!allowfallback)return "";
+       if(!deliveryaddress().isNull() && deliveryaddress().value().isValid())
+               return deliveryaddress().value().fullAddress(customer().value().fullName());
+       //give up
+       return "";
+}
+
+QString MOOrder::fullDeliveryAddress(bool allowfallback)const
+{
+       if(!deliveryaddress().isNull() && deliveryaddress().value().isValid())
+               return deliveryaddress().value().fullAddress(customer().value().fullName());
+       //fall back
+       if(!allowfallback)return "";
+       if(!invoiceaddress().isNull() && invoiceaddress().value().isValid())
+               return invoiceaddress().value().fullAddress(customer().value().fullName());
+       //give up
+       return "";
+}
index 465c5a9..f7d1b07 100644 (file)
@@ -89,6 +89,10 @@ class MOOrder:public MOOrderAbstract
                /**returns the shipping date only as string*/
                QString sentDateStr();
                
+               /**returns the full invoice address, or delivery address if no explicit invoice address was given and allowfallback==true*/
+               QString fullInvoiceAddress(bool allowfallback=true)const;
+               /**returns the full delivery address, or invoice address if no explicit delivery address was given and allowfallback==true*/
+               QString fullDeliveryAddress(bool allowfallback=true)const;
 };
 
 #endif
index 5b38f97..175ad2d 100644 (file)
 #define MAGICSMOKE_MOTICKET_H
 
 #include "MOTicketAbstract.h"
+#include "misc.h"
+
 class MOTicket:public MOTicketAbstract
 {
+       WOBJECT(MOTicket);
        public:
-               MOTicket():MOTicketAbstract(){}
-               MOTicket(const MOTicket&m):MOTicketAbstract(m){}
-               MOTicket(const QDomElement&e):MOTicketAbstract(e){}
-               
+               /**returns the amount to be paid for this ticket; this may be 0 even if there is a price attached*/
                int amountToPay()const{if(status()&MaskPay)return price();else return 0;}
+               
+               /**returns the price as string*/
+               QString priceString()const{return cent2str(price());}
+               
+               /**returns the ticket status as localized string*/
+               QString statusString()const{return TicketState2locstr(status());}
 };
 
 #endif
diff --git a/src/wext/MOVoucher.h b/src/wext/MOVoucher.h
new file mode 100644 (file)
index 0000000..4971f1f
--- /dev/null
@@ -0,0 +1,33 @@
+//
+// C++ Interface: MOVoucher
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_MOVOUCHER_H
+#define MAGICSMOKE_MOVOUCHER_H
+
+#include "MOVoucherAbstract.h"
+#include "misc.h"
+
+class MOVoucher:public MOVoucherAbstract
+{
+       WOBJECT(MOVoucher);
+       public:
+               /**returns whether this is a valid voucher object (ie. it has a voucher ID)*/
+               bool isValid()const{return !voucherid().isNull();}
+               /**returns the current value as string*/
+               QString valueString()const{return cent2str(value());}
+               /**returns the status of the voucher as string*/
+               QString statusString()const{return VoucherState2locstr(status());}
+               /**returns the price as string*/
+               QString priceString()const{return cent2str(price());}
+};
+
+#endif
index 15cc4a3..6ab44cb 100644 (file)
@@ -5,7 +5,12 @@ HEADERS += \
        wext/MOOrder.h \
        wext/MOOrderInfo.h \
        wext/MORole.h \
-       wext/MOTicket.h
+       wext/MOTicket.h \
+       wext/MOAddress.h \
+       wext/MOEvent.h
 
 SOURCES += \
-       wext/MOOrder.cpp
\ No newline at end of file
+       wext/MOCustomerInfo.cpp \
+       wext/MOOrder.cpp \
+       wext/MOAddress.cpp \
+       wext/MOEvent.cpp
\ No newline at end of file
index 6b8e23f..c8aad6c 100644 (file)
@@ -61,6 +61,7 @@
                </Mapping>
        </Class>
        <Class name="Address">
+               <Abstract lang="qt"/><!-- eg. fullAddress() method -->
                <Property name="addressid" type="int64"/>
                <Property name="customerid" type="int32"/>
                <Property name="lastused" type="int64"/>
index b7db45c..26d513e 100644 (file)
@@ -92,6 +92,7 @@
        </Class>
        
        <Class name="Event">
+               <Abstract lang="qt"/>
                <Property name="id" type="int" id="yes"/>
                <Property name="start" type="int64"/>
                <Property name="end" type="int64"/>
                </Output>
        </Transaction>
        
+       <Transaction name="GetEventList">
+               <Input>
+                       <Var name="eventids" type="List:int"/>
+               </Input>
+               <Call lang="php" method="Event::getEventList($this);"/>
+               <Output>
+                       <Var name="events" type="List:Event"/>
+               </Output>
+       </Transaction>
+       
        <Transaction name="CancelEvent">
                <Input>
                        <Var name="eventid" type="int"/>
index 16d8a2e..e706bae 100644 (file)
        </Transaction>
        
        <Class name="Voucher">
+               <Abstract lang="qt"/>
                <Enum name="VoucherState">
                        <Value name="Ok"/>
                        <Value name="InvalidValue"/>
        <Transaction name="OrderRefund"/>
        <Transaction name="UseVoucher"/>
        
+       <Transaction name="OrderChangeShipping">
+               <Doc>Changes the shipping option and/or price of an order</Doc>
+               <Privilege name="ChangePrice"/>
+               <Input>
+                       <Var name="orderid" type="int">The order to be changed</Var>
+                       <Var name="shippingid" type="int">the new shipping option or -1 if shipping is to be deleted</Var>
+                       <Var name="shippingcosts" type="int">if the user has the privilege ChangePrice this field overrides the shipping costs, otherwise the default from the shipping table is used</Var>
+               </Input>
+               <Call lang="php" method="WOOrder::changeShipping($this);"/>
+               <Output>
+                       <Var name="order" type="Order">a fresh copy of the changed order</Var>
+               </Output>
+       </Transaction>
+       
        <Transaction name="GetAllShipping">
                <Input/>
+               <Call lang="php" method="$this->setshipping(WOShipping::fromTableArrayshipping(WTshipping::selectFromDB()));"/>
                <Output>
                        <Var name="shipping" type="List:Shipping"/>
                </Output>
index 83679f4..d265edf 100644 (file)
@@ -99,6 +99,7 @@ void WocPHPServerOut::transInfo()
 void WocPHPServerOut::transInfo2()
 {
        WocProcessor*woc=WocProcessor::instance();
+       //transaction names
        QString code="  static public function transactionNames(){\n\treturn array(";
        QStringList tns=woc->transactionNames();
        for(int i=0;i<tns.size();i++){
@@ -106,6 +107,15 @@ void WocPHPServerOut::transInfo2()
                code+="\n\t\ttranslate(\"_TransactionNames\",\""+tns[i]+"\")";
        }
        code+=");\n  }\n";
+       //privilege names
+       code+="static public function privilegeNames(){\n\treturn array(";
+       QStringList priv=woc->privilegeNames();
+       for(int i=0;i<priv.size();i++){
+               if(i)code+=",\n\t\t";else code+="\n\t\t";
+               code+="translate(\"_PrivilegeNames\",\""+priv[i]+"\")";
+       }
+       code+="\n\t);\n}\n";
+       
        m_transact.write(code.toAscii());
 }
 
@@ -147,7 +157,7 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
        code+="protected function __construct(array $data,$isfromdb){parent::__construct($data,$isfromdb,\""+tbl.name()+"\");}\n\n";
        
        //static new instance for insert only
-       code+="public static function newRow(){return new WT"+tbl.name()+"(array(),false);}\n\n";
+       code+="public static function newRow(array $data=array()){return new WT"+tbl.name()+"($data,false);}\n\n";
        
        //static get instance
        QStringList cols=tbl.columns();
@@ -178,7 +188,7 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
                }
                //implement enum check for set method of enum columns
                if(tbl.columnType(cols[i]).startsWith("enum")){
-                       code+="private function verifyValue"+cols[i]+"($v){if(false";
+                       code+="protected function verifyValue"+cols[i]+"($v){if(false";
                        QList<WocEnum>ens=tbl.columnEnums(cols[i]);
                        QList<int>envs;
                        for(int j=0;j<ens.size();j++){
@@ -229,7 +239,7 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
        //create audit stuff
        if(tbl.isAuditable()){
                code+="public function isAuditable(){return true;}\n";
-               code+="protected function createAudit(){$ad=new WT"+tbl.name()+"_audit($this->data,false,\""+tbl.name()+"_audit\");\n";
+               code+="protected function createAudit(){$ad=WT"+tbl.name()+"_audit::newRow($this->data);\n";
                code+="\treturn $ad->insert();\n}\n";
        }
        
@@ -826,6 +836,9 @@ void WocPHPServerOut::newTransaction(const WocTransaction&trn)
        //direct execution
        tf.write(trnExecute(trn).toAscii());
        
+       //privileges
+       tf.write(trnPrivileges(trn).toAscii());
+       
        //end
        code="\n//end of class\n}\n";
        tf.write(code.toAscii());
@@ -1043,3 +1056,26 @@ QString WocPHPServerOut::trnExecute(const WocTransaction&trn)
        code+="private function do_execute(){"+trn.callFunction("php")+"}\n";
        return code;
 }
+
+QString WocPHPServerOut::trnPrivileges(const WocTransaction&trn)
+{
+       //privilege inventory
+       QString code;
+       code+="static public function privileges(){\n\treturn array(";
+       QString cn=trnClassName(trn);
+       QStringList priv=trn.privileges();
+       for(int i=0;i<priv.size();i++){
+               if(i)code+=",\n\t\t";else code+="\n\t\t";
+               code+="\""+priv[i]+"\"";
+       }
+       code+="\n\t);\n}\n";
+       //constants for use by custom code
+       for(int i=0;i<priv.size();i++)
+               code+="const Priv_"+priv[i]+"=\""+priv[i]+"\";\n";
+       //check method
+       code+="public function havePrivilege($priv){\n";
+       code+="\tif(!in_array($priv,self::privileges()))return false;\n";
+       code+="\treturn "+QString(m_hasrole).replace("%","(\""+trn.name()+":\".$priv)")+";\n}\n";
+       
+       return code;
+}
index 28bddeb..186039e 100644 (file)
@@ -82,6 +82,8 @@ class WocPHPServerOut:public WocOutput
                QString trnGetSet(const WocTransaction&);
                /**helper: create direct execution code for web interface*/
                QString trnExecute(const WocTransaction&);
+               /**helper: create privilege check code for web interface*/
+               QString trnPrivileges(const WocTransaction&);
                
                /**helper: return the PHP-class-name of a WocClass*/
                QString className(const WocClass&c){return "WO"+c.name();}
index 4c64a0a..768e3d9 100644 (file)
@@ -302,6 +302,18 @@ QStringList WocProcessor::tableNames()const
        return l;
 }
 
+QStringList WocProcessor::privilegeNames()const
+{
+       QStringList l;
+       for(int i=0;i<m_transactions.size();i++){
+               QString cn=m_transactions[i].name();
+               QStringList priv=m_transactions[i].privileges();
+               for(int j=0;j<priv.size();j++)
+                       l<<(cn+":"+priv[j]);
+       }
+       return l;
+}
+
 /******************************************************************************
  * WocOutput
  ******************************************************************************/
@@ -1140,6 +1152,12 @@ WocTransaction::WocTransaction(const QDomElement&root)
                QString s=nl.at(i).toElement().text().trimmed();
                if(s!="")m_docstrings<<s;
        }
+       //privileges
+       nl=root.elementsByTagName("Privilege");
+       for(int i=0;i<nl.size();i++){
+               QString s=nl.at(i).toElement().attribute("name").trimmed();
+               if(s!="")m_privileges<<s;
+       }
 }
 
 bool WocTransaction::hasInput(QString v)const
index 9e19246..5435bab 100644 (file)
@@ -330,12 +330,16 @@ class WocTransaction
                /**return docu of output element*/
                QString outputDoc(QString v)const
                {if(m_outdoc.contains(v))return m_outdoc[v];else return "";}
+               
+               /**return privileges that exist inside this transaction*/
+               QStringList privileges()const{return m_privileges;}
        private:
                QString m_name;
                bool m_valid;
                AuthMode m_mode;
                QMap<QString,QString> m_call;
                QList<QPair<QString,QString> >m_input,m_output;
+               QStringList m_privileges;
                //docu
                QStringList m_docstrings;
                QMap<QString,QString>m_indoc,m_outdoc;
@@ -419,7 +423,11 @@ class WocProcessor:public QObject
                /**returns a list of table names*/
                QStringList tableNames()const;
                
+               /**returns global docu*/
                QStringList docStrings()const{return m_docstrings;}
+               
+               /**returns the qualified names of all privileges*/
+               QStringList privilegeNames()const;
        signals:
                void sfinalize();
                void newClass(const WocClass&);
index 396c629..53a336b 100644 (file)
@@ -725,8 +725,12 @@ void WocQtClientOut::trnList()
        //header
        code+="  enum Right {\n    NoRight";
        QStringList r=WocProcessor::instance()->transactionNames();
+       QStringList p=WocProcessor::instance()->privilegeNames();
+       QStringList pp=p;
        for(int i=0;i<r.size();i++)
                code+=",\n    R"+r[i];
+       for(int i=0;i<p.size();i++)
+               code+=",\n    P"+pp[i].replace(':',"_");
        code+="\n  };\n";
        code+="  static QString rightToString(Right);\n";
        code+="  static Right stringToRight(QString);\n";
@@ -737,20 +741,28 @@ void WocQtClientOut::trnList()
        code="QString "+m_prefix+"Interface::rightToString(Right r)\n{\n\tswitch(r){\n";
        for(int i=0;i<r.size();i++)
                code+="\t\tcase R"+r[i]+":return \""+r[i]+"\";\n";
+       for(int i=0;i<p.size();i++)
+               code+="\t\tcase P"+pp[i]+":return \""+p[i]+"\";\n";
        code+="\t\tdefault:return \"\";\n\t}\n}\n";
        code+=m_prefix+"Interface::Right "+m_prefix+"Interface::stringToRight(QString s)\n{\n";
        for(int i=0;i<r.size();i++)
                code+="\tif(s==\""+r[i]+"\")return R"+r[i]+";else\n";
+       for(int i=0;i<p.size();i++)
+               code+="\tif(s==\""+p[i]+"\")return P"+pp[i]+";else\n";
        code+="\treturn NoRight;\n}\n";
        code+="QList<"+m_prefix+"Interface::Right> "+m_prefix+"Interface::allKnownRights()\n{\n";
        code+="\tQList<Right> ret;ret";
        for(int i=0;i<r.size();i++)
                code+="<<R"+r[i];
+       for(int i=0;i<p.size();i++)
+               code+="<<P"+pp[i];
        code+=";\n\treturn ret;\n}\n";
        code+="QStringList "+m_prefix+"Interface::allKnownRightsString()\n{\n";
        code+="\tQStringList ret;ret";
        for(int i=0;i<r.size();i++)
                code+="<<\""+r[i]+"\"";
+       for(int i=0;i<p.size();i++)
+               code+="<<\""+p[i]+"\"";
        code+=";\n\treturn ret;\n}\n";
        m_ifacecpp.write(code.toAscii());
 }
index 2573876..293c7e0 100644 (file)
@@ -147,6 +147,14 @@ class Event
                $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("","ORDER BY starttime"));
                $trans->setevents($evlst);
        }
+       
+       /**XML iface: get list of events*/
+       public static function getEventList($trans)
+       {
+               global $db;
+               $evlst=WOEvent::fromTableArrayevent(WTevent::selectFromDB("eventid in ".$db->escapeIntList($trans->geteventids())));
+               $trans->setevents($evlst);
+       }
 };
 
 /**machine-function: get the requested events as XML data*/
index a7e575a..b706631 100644 (file)
@@ -23,15 +23,28 @@ class ValueOutOfRange extends Exception
 /**parent class of all tables*/
 abstract class WobTable
 {
-       private $data;
-       private $cdata;
+       protected $data;
+       protected $cdata;
        private $isfromdb;
        private $table;
        
        /**constructs a basic table*/
        protected function __construct(array $data,$isfromdb,$table)
        {
-               $this->data=$data;
+               $this->data=array();
+               if($isfromdb)$this->data=$data;
+               else
+               foreach($data as $k=>$d){
+                       //silently ignore garbage
+                       if(!$this->hasProperty($k))continue;
+                       //verify non-garbage
+                       $vm="verifyValue".$k;
+                       if(method_exists($this,$vm))
+                       if(!$this->$vm($d))
+                               throw ValueOutOfRange($this->table,$k,$d);
+                       //set
+                       $this->data[$k]=$d;
+               }
                $this->isfromdb=$isfromdb;
                $this->table=$table;
                $this->cdata=array();
index 69e88f7..8e03f00 100644 (file)
@@ -135,10 +135,10 @@ class WOOrder extends WOOrderAbstract
                        $prc+=$it->amountToPay();
                //add vouchers
                foreach($this->prop_vouchers as $it)
-                       $prc+=$it->getprice();
+                       $prc+=$it->get_price();
                //add items
                foreach($this->prop_items as $it)
-                       $prc+=$it->gettotalprice();
+                       $prc+=$it->get_totalprice();
                //return
                return $prc;
        }
@@ -156,6 +156,40 @@ class WOOrder extends WOOrderAbstract
                if(count($res)>=0)
                        $trans->setorder(WOOrder::fromTableorder(WTorder::getFromDB($res[0]["orderid"])));
        }
+       
+       /**called by OrderChangeShipping transaction*/
+       static public function changeShipping($trans)
+       {
+               //get shipping
+               $shipid=$trans->getshippingid();
+//             print_r($shipid);
+               if($shipid===false)$shipid=-1;else $shipid=$shipid+0;
+               if($shipid>=0){
+                       $ship=WTshipping::getFromDB($shipid);
+                       if($ship===false){
+                               $trans->abortWithError(tr("Invalid shipping ID."));
+                               return;
+                       }
+               }
+               //get order
+               $ord=WTorder::getFromDB($trans->getorderid());
+               //get shipping costs
+               $cost=0;
+               if($shipid>=0)$cost=$ship->cost;
+               if($trans->havePrivilege(WtrOrderChangeShipping::Priv_ChangePrice)){
+                       if($trans->getshippingcosts()!==false)
+                               $cost=$trans->getshippingcosts();
+               }
+               //set order
+               $ord->shippingcosts=$cost;
+               if($shipid>=0)
+                       $ord->shippingtype=$shipid;
+               else
+                       $ord->shippingtype=null;
+               $ord->update();
+               //return order
+               $trans->setorder(WOOrder::fromTableorder($ord));
+       }
 };
 
 ?>
\ No newline at end of file