From 5dcd00e8c1a253ad7b42c2e83f0bcfedcab97770 Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 6 Dec 2008 17:15:40 +0000 Subject: [PATCH] more flexible reports about events git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@206 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- doc/prog_odttemplate.html | 104 +++++++++++++++++- doc/prog_protocol.html | 2 + src/eventsummary.cpp | 246 ++++++++++++++++++++++++++++++------------- src/eventsummary.h | 20 +++-- src/misc.cpp | 48 +++++++-- src/misc.h | 23 +++-- src/odtrender.cpp | 222 +++++++++++++++++++++++++++++++++++---- src/odtrender.h | 28 ++++- src/order.cpp | 6 + src/order.h | 3 + src/orderwin.cpp | 142 +++++++++++++++++++------ src/orderwin.h | 5 +- www/inc/classes/event.php | 6 +- www/inc/machine/version.inc | 4 +- 14 files changed, 695 insertions(+), 164 deletions(-) diff --git a/doc/prog_odttemplate.html b/doc/prog_odttemplate.html index b2069bb..b025cfb 100644 --- a/doc/prog_odttemplate.html +++ b/doc/prog_odttemplate.html @@ -7,12 +7,12 @@ This text describes how ODT templates are generated and which ones exist. ODT te

Creating a Template

-OpenDocumentText (ODT) files are basically zipped XML files. Magic Smoke ODT Templates are ODT files in which the "content.xml" file contains some special markup that is replaced by Magic Smoke before the file is used as a normal ODT file.

+Open Document Files (*.od?, usually *.odt) are basically zipped XML files. Magic Smoke ODF Templates are ODF files in which the "content.xml" file contains some special markup that is replaced by Magic Smoke before the file is used as a normal OD file.

This process needs some knowledge in XML.

    -
  1. Write an ODT file that meets your expectations for what you want to template. It is recommended that you already put all variables (@VAR@, see below) into the file to make it easier to find each location.
  2. +
  3. Write an OD file that meets your expectations for what you want to template. It is recommended that you already put all variables (@VAR@, see below) into the file to make it easier to find each location.
  4. Unzip it into a clean directory - make sure the directory structure of the ODT-ZIP-file is kept intact.
    Eg. under Linux to extract example.odt: mkdir example; cd example; unzip ../example.odt
  5. @@ -53,7 +53,7 @@ Loops cannot be nested.

    Calculations

    -Numeric variables allow some very simple calculations: +Numeric variables allow some very simple calculations in place:
     @VARONE+11@
    @@ -62,7 +62,60 @@ Numeric variables allow some very simple calculations:
     
     In the above example the first line will be replaced by the amount of VARONE plus 11 and the second line by the amount of VARTWO minus 77.

    -For integer variables this works on the plain integer value. For money values it adds/subtracts cents. +For integer variables this works on the plain integer value. For money values it adds/subtracts cents.

    + +More complex calculations can be done with the #CALC statement: + +

    +#CALC:TVAR/MONEY:@VAR1@ * @VAR2@ + 4
    +
    + +The above creates the temporary variable "@#TVAR@" that is the product of @VAR1@ and @VAR2@'s content plus 4. It is marked as a monetary value.

    + +Calculations are restricted to the operators below and are always done from left to right - more complex formulas require several lines. Tokens must be space separated. If no type or a non-existing type is requested INT is assumed. All calculations are done using 64bit signed integers. If the processor comes across an illegal token it sets the variable to "error".

    + + + + + + + + +
    OperatorDescription
    +adding
    -subtracting
    *multiplication
    /division
    %modulo
    + + + + + + + + +
    TypeDescription
    INTinteger number
    MONEYmonetary value (the number is interpreted as cents)
    DATEa unix timestamp to be shown as date
    TIMEa unix timestamp to be shown as its time component
    DATETIMEa unix timestamp to be shown as date plus time
    + +

    Newline Replacement

    + +The #SETNEWLINE statement can be used to create a macro that will replace newline in variables: + +
    +#SETNEWLINE:</text:p><text:p text:style-name="Text_20_body">
    +
    + +The default is a single space character, which can be restored by using "#SETNEWLINE:" without parameters. + +

    Generic Variables

    + +There are a few variables that always exist: + + + + + + +
    VariableDescription
    @TODAY@the current date
    @NOW@the current time
    @anyloop:ITERATION@for an active loop ("anyloop") the current iteration (0..n)
    + +

    Localization

    + +Per default all variables are localized before they get inserted into the document. To suppress localization prefix the variable with a "$"-sign (eg. @$TODAY@ instead of @TODAY@).

    Event Summary

    @@ -84,12 +137,31 @@ Variables: @UNUSED@tickets that are still unused @CANCELLED@tickets that were cancelled @TOTALMONEY@the total amount of income for this event -@TICKETS@the amount of ticket lines in the overview +@TICKETS@the amount of ticket lines in the overview @TICKETS:PRICE@the price of this category @TICKETS:BOUGHT@used+unused @TICKETS:USED@tickets from this category that have been used @TICKETS:UNUSED@tickets from this category that were not used + +@COMMENTS@the amount of (non-empty) comments attached to this event +@COMMENTS:ORDERID@the order-ID of this comment +@COMMENTS:CUSTOMERID@the ID of the customer this comment is attached to +@COMMENTS:CUSTOMER@the name of the customer this comment is attached to +@COMMENTS:TEXT@the text of the comment + +@ORDERS@the amount of orders connected to this event +@ORDERS:ORDERID@the order-ID of this comment +@ORDERS:CUSTOMERID@the ID of the customer this comment is attached to +@ORDERS:CUSTOMER@the name of the customer this comment is attached to +@ORDERS:NUMTICKETS@number of tickets in the order that are for this event +@ORDERS:TICKETPRICE@the accumulated price of all tickets in that order for this event +@ORDERS:FULLPRICE@the full price of this order +@ORDERS:SHIPPING@description of the shipping method of this order +@ORDERS:SHIPPINGCOST@the full shipping costs for this order +@ORDERS:SHIPPINGCOSTWEIGHTED@the weighted shipping costs of this order (costs * ticketsforthisevent / ticketsintotal) - Warning: this may not add up correctly! +@ORDERS:SHIPPINGCOSTIFFIRST@contains the shipping costs if this event is the earliest in the order, zero otherwise +@ORDERS:SHIPPINGCOSTIFLAST@contains the shipping costs if this event is the last in the order, zero otherwise

    Order Bills

    @@ -115,14 +187,17 @@ Variables: @FULLADDRESS@the name and address of the customer @NAME@the name of the customer @DELIVERYADDRESS@the address it is shipped to, if different from the customers address +@FINALADDRESS@equals DELIVERYADDRESS if it is non-empty, otherwise FULLADDRESS @TOTALPRICE@the total price of the order @AMOUNTPAID@the amount that has already been paid @SELLER@the login ID of the seller (it is not recommended to use this) @COMMENT@the comment in the order (it is not recommended to use this) @AMOUNTTOPAY@the amount that still needs to be paid @AMOUNTTOREFUND@the amount that has to be refunded -@TICKETS@the amount of tickets in the order +@SHIPPING@description of the shipping method used or empty string +@SHIPPINGPRICE@the costs for shipping +@TICKETS@the amount of tickets in the order @TICKETS:PRICE@the price of this ticket @TICKETS:ID@the ID of this ticket (barcode-string) @TICKETS:TITLE@the title of the event for this ticket @@ -131,8 +206,25 @@ Variables: @TICKETS:STARTTIME@the date and start time of the event for this ticket @TICKETS:ENDTIME@the end date and time of the event for this ticket @TICKETS:ROOM@the room/place of the event for this ticket + +@ACCTICKETS@the amount of distinct ticket types in the order +@ACCTICKETS:PRICE@the price of one ticket of this type +@ACCTICKETS:FULLPRICE@the accumulated price of all tickets of this type (PRICE*AMOUNT) +@ACCTICKETS:AMOUNT@the amount of tickets in this type +@ACCTICKETS:TITLE@the title of the event for this ticket type +@ACCTICKETS:ARTIST@the artist of the event for this ticket type +@ACCTICKETS:DATE@the date of the event for this ticket type +@ACCTICKETS:STARTTIME@the date and start time of the event for this ticket type +@ACCTICKETS:ENDTIME@the end date and time of the event for this ticket type +@ACCTICKETS:ROOM@the room/place of the event for this ticket type + @ADDRESSLINES@amount of lines that the address has @ADDRESSLINES:LINE@current line in the address loop + +@VOUCHERS@the amount of vouchers in the order +@VOUCHERS:PRICE@the price of this voucher +@VOUCHERS:VALUE@the (remaining) value of this voucher +@VOUCHERS:ID@the ID of this voucher diff --git a/doc/prog_protocol.html b/doc/prog_protocol.html index f6a949b..33e0663 100644 --- a/doc/prog_protocol.html +++ b/doc/prog_protocol.html @@ -219,6 +219,8 @@ The eventsummary transaction returns summary data for an event. The req totaltickets="numberOfUsableTickets" totalmoney="totalIncomeOfEventInCent" > <Tickets price="priceCategoryInCent" bought="numberOfUsableTicketsInThisCategory" used="numberOfUsedTickets" unused="numberOfUnusedTickets" /> + <Comment customerid="customerID" customer="customers Name" orderid="orderID">comment</Comment> + <Orders>space separated IDs of all orders for this event</Orders> </EventSummary>
    diff --git a/src/eventsummary.cpp b/src/eventsummary.cpp index bcc0086..9f524d9 100644 --- a/src/eventsummary.cpp +++ b/src/eventsummary.cpp @@ -28,16 +28,14 @@ #include MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) - :QDialog(par) + :QDialog(par),event(rq,eid) { req=rq; - eventid=eid; - starttime=capacity=nreserved=ncancelled=ntotaltickets=ntotalmoney=0; + nreserved=ncancelled=ntotaltickets=ntotalmoney=0; //get event data - getEventData(); getSummaryData(); //layout/tabs - setWindowTitle(tr("Summary for Event %1").arg(title)); + setWindowTitle(tr("Summary for Event %1").arg(event.title())); QVBoxLayout*vl; setLayout(vl=new QVBoxLayout); QTabWidget*tab; @@ -48,14 +46,13 @@ MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) w->setLayout(gl=new QGridLayout); int rc=0; gl->addWidget(new QLabel(tr("Title:")),rc,0); - gl->addWidget(new QLabel(title),rc,1); + gl->addWidget(new QLabel(event.title()),rc,1); gl->addWidget(new QLabel(tr("Artist:")),++rc,0); - gl->addWidget(new QLabel(artist),rc,1); + gl->addWidget(new QLabel(event.artist()),rc,1); gl->addWidget(new QLabel(tr("Start:")),++rc,0); - QString start=QDateTime::fromTime_t(starttime).toString(tr("yyyy-MM-dd hh:mm ap","Date+Time format for displaying event start time")); - gl->addWidget(new QLabel(start),rc,1); + gl->addWidget(new QLabel(event.startTimeString()),rc,1); gl->addWidget(new QLabel(tr("Capacity:")),++rc,0); - gl->addWidget(new QLabel(QString::number(capacity)),rc,1); + gl->addWidget(new QLabel(QString::number(event.capacity())),rc,1); gl->addWidget(new QLabel(tr("Tickets currently reserved:")),++rc,0); gl->addWidget(new QLabel(QString::number(nreserved)),rc,1); gl->addWidget(new QLabel(tr("Tickets currently cancelled:")),++rc,0); @@ -63,8 +60,7 @@ MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) gl->addWidget(new QLabel(tr("Tickets currently usable:")),++rc,0); gl->addWidget(new QLabel(QString::number(ntotaltickets)),rc,1); gl->addWidget(new QLabel(tr("Total Income:")),++rc,0); - QString tm=QString::number(ntotalmoney/100)+tr(".","decimal dot")+QString().sprintf("%02d",ntotalmoney%100); - gl->addWidget(new QLabel(tm),rc,1); + gl->addWidget(new QLabel(cent2str(ntotalmoney)),rc,1); QTableView*table; QStandardItemModel*model; @@ -76,8 +72,7 @@ MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) model->setHorizontalHeaderLabels(QStringList()<setData(model->index(i,0),tm); + model->setData(model->index(i,0),cent2str(tc.price)); model->setData(model->index(i,1),tc.bought); model->setData(model->index(i,2),tc.used); model->setData(model->index(i,3),tc.unused); @@ -114,29 +109,17 @@ MEventSummary::MEventSummary(QWidget*par,MWebRequest*rq,int eid) MEventSummary::~MEventSummary(){} -void MEventSummary::getEventData() +void MEventSummary::getOrderData() { - if(!req->request("geteventdata",QString::number(eventid).toAscii()))return; - if(req->responseStatus()!=MWebRequest::Ok)return; - QDomDocument doc; - if(!doc.setContent(req->responseBody()))return; - QDomNodeList nl=doc.elementsByTagName("Event"); - for(int i=0;i0)title=nl2.at(0).toElement().text(); - nl2=el.elementsByTagName("Artist"); - if(nl2.size()>0)artist=nl2.at(0).toElement().text(); + if(orderids.size()==orders.size())return; + for(int i=0;irequest("eventsummary",QString::number(eventid).toAscii()))return; + if(!req->request("eventsummary",QString::number(event.eventId()).toAscii()))return; if(req->responseStatus()!=MWebRequest::Ok)return; QDomDocument doc; if(!doc.setContent(req->responseBody()))return; @@ -167,6 +150,19 @@ void MEventSummary::getSummaryData() c.comment=el.text(); comments.append(c); } + nl=sum.elementsByTagName("Orders"); + for(int i=0;i=tickets.size())return; + if(loopname=="TICKETS"){ + if(iteration<0 || iteration>=tickets.size())return; + + if(varname=="PRICE"){ + value=tickets[iteration].price; + av=MOdtRenderer::MoneyVar; + }else + if(varname=="BOUGHT"){ + value=tickets[iteration].bought; + av=MOdtRenderer::IntVar; + }else + if(varname=="USED"){ + value=tickets[iteration].used; + av=MOdtRenderer::IntVar; + }else + if(varname=="UNUSED"){ + value=tickets[iteration].unused; + av=MOdtRenderer::IntVar; + } + }else + if(loopname=="COMMENTS"){ + if(iteration<0 || iteration>=comments.size())return; - if(varname=="PRICE"){ - int p=tickets[iteration].price+av; - value=QString::number(p/100) - +tr(".","decimal dot") - +QString().sprintf("%02d",p%100); + if(varname=="ORDERID")value=QString::number(comments[iteration].orderid);else + if(varname=="CUSTOMERID")value=QString::number(comments[iteration].custid);else + if(varname=="CUSTOMER")value=comments[iteration].custname;else + if(varname=="TEXT")value=comments[iteration].comment; }else - if(varname=="BOUGHT")value=QString::number(tickets[iteration].bought+av);else - if(varname=="USED")value=QString::number(tickets[iteration].used+av);else - if(varname=="UNUSED")value=QString::number(tickets[iteration].unused+av); + if(loopname=="ORDERS"){ + if(iteration<0 || iteration>=orderids.size())return; + //make sure data is here + getOrderData(); + //get order id + int oid=orderids[iteration]; + + if(varname=="ORDERID"){ + value=QString::number(oid); + return; + } + + //paranoia check + if(!orders.contains(oid))return; + + if(varname=="CUSTOMERID")value=QString::number(orders[oid].customerID());else + if(varname=="CUSTOMER")value=orders[oid].customer().name();else + if(varname=="FULLPRICE"){ + value=orders[oid].totalPrice(); + av=MOdtRenderer::MoneyVar; + }else + if(varname=="SHIPPING")value=orders[oid].shipping().description();else + if(varname=="SHIPPINGCOST"){ + value=orders[oid].shipping().price(); + av=MOdtRenderer::IntVar; + }else{ + QListticks=orders[oid].tickets(); + QListeticks; + int first,last; + first=last=event.startTime(); + int eid=event.eventId(); + for(int i=0;i +#include + +#include "order.h" +#include "odtrender.h" class MWebRequest; class QTableView; @@ -37,14 +41,14 @@ class MEventSummary:public QDialog void saveas(); //used for ODT rendering: - void getVariable(QString varname,int,QString&value); - void getLoopIterations(QString loopname,int&iterations); - void getLoopVariable(QString loopname,int iteration,QString varname,int,QString&value); + void getVariable(QString,MOdtRenderer::VarType&,QVariant&); + void getLoopIterations(QString,int&); + void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); private: MWebRequest*req; - int eventid,starttime,capacity; - QString title,artist; + int eventid; + MEvent event; int nreserved,ncancelled,ntotaltickets,ntotalmoney; struct Tickets{ int price,bought,used,unused; @@ -55,11 +59,13 @@ class MEventSummary:public QDialog QString custname,comment; }; QListcomments; + QListorderids; + QMaporders; - //get basic data about event - void getEventData(); //get summary void getSummaryData(); + //helper: get order details + void getOrderData(); }; #endif diff --git a/src/misc.cpp b/src/misc.cpp index c5c60ce..a055f29 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -13,6 +13,7 @@ #include "misc.h" #include +#include QString htmlize(QString str) { @@ -30,7 +31,7 @@ QString htmlize(QString str) return out; } -QString xmlize(QString str) +QString xmlize(QString str,QString newline) { QString out; for(int i=0;i')out+=">";else if(c=='&')out+="&";else + if(c=='\n')out+=newline;else if(c.isSpace()||(c.unicode()>=32&&c.unicode()<=0x7f))out+=c; else out+="&#"+QString::number(ci)+";"; } return out; } -QString cent2str(int c) +QString cent2str(int c,bool localize) { - QString ret=QCoreApplication::translate("misc","%1.%2","price with decimal dot"); + QString ret; + if(localize)ret=QCoreApplication::translate("misc","%1.%2","price with decimal dot"); + else ret="%1.%2"; return ret.arg(c/100).arg(c%100,2,10,QChar('0')); } -int str2cent(QString s) +int str2cent(QString s,bool localize) { - QString p=s.replace(QCoreApplication::translate("misc",".","decimal dot in price"),"."); - double c=s.toDouble()*100; + if(localize)s=s.replace(QCoreApplication::translate("misc",".","decimal dot in price"),"."); + double c=s.toDouble()*100.; return int(c); } -QRegExp priceRegExp() +QRegExp priceRegExp(bool localize) { - return QRegExp(QCoreApplication::translate("misc","[0-9]+\\.[0-9]{2}","regexp for price")); + if(localize) + return QRegExp(QCoreApplication::translate("misc","[0-9]+\\.[0-9]{2}","regexp for price")); + else + return QRegExp("[0-9]+\\.[0-9]{2}"); } + +QString unix2date(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd","localized date format"); + format="yyyy-MM-dd"; + return QDateTime::fromTime_t(tm).toString(format); +} + +QString unix2time(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","hh:mm","localized time format"); + format="hh:mm"; + return QDateTime::fromTime_t(tm).toString(format); +} + +QString unix2dateTime(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd hh:mm","localized date + time format"); + format="yyyy-MM-dd hh:mm"; + return QDateTime::fromTime_t(tm).toString(format); +} + diff --git a/src/misc.h b/src/misc.h index a816068..6d9766f 100644 --- a/src/misc.h +++ b/src/misc.h @@ -20,15 +20,24 @@ QString htmlize(QString str); /**converts special XML characters into harmless &-codes, so the text can be included*/ -QString xmlize(QString str); +QString xmlize(QString str,QString newline="\n"); -/**converts a cent value into a localized string*/ -QString cent2str(int c); +/**converts a cent value into a (localized) string*/ +QString cent2str(int cent,bool localize=true); -/**converts a localized string back into a cent value (must not contain spaces or extra dots)*/ -int str2cent(QString s); +/**converts a (localized) string back into a cent value (must not contain spaces or extra dots)*/ +int str2cent(QString s,bool fromlocal=true); -/**return a localized regular expression that validates prices*/ -QRegExp priceRegExp(); +/**converts a unix timestamp into a date*/ +QString unix2date(int,bool localize=true); + +/**converts a unix timestamp into a time (ommitting the date)*/ +QString unix2time(int,bool localize=true); + +/**converts a unix timestamp into a date-time-string*/ +QString unix2dateTime(int,bool localize=true); + +/**return a (localized) regular expression that validates prices*/ +QRegExp priceRegExp(bool localize=true); #endif diff --git a/src/odtrender.cpp b/src/odtrender.cpp index 3b09dfa..f10961d 100644 --- a/src/odtrender.cpp +++ b/src/odtrender.cpp @@ -49,10 +49,21 @@ class MOdtRendererPrivate QString getVariable(QString varname); QString getLoopVariable(QString loopname,int iteration,QString varname); + qint64 intToken(QString,QString,int); + void setLocalVar(QString,qint64); + void setLocalVarError(QString); + //data the parent does not access MOdtRenderer*parent; QUnZip temp; QFile tfile; + QString newline; + + struct LocalVar{ + MOdtRenderer::VarType type; + QVariant value; + }; + QMaplocalvars; }; MOdtRenderer::MOdtRenderer(MTemplate file) @@ -65,6 +76,7 @@ MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p) :tfile(file) { parent=p; + newline=" "; //open ZIP if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); //TODO: make sure this is a valid ZIP file, preferably with some ODT content @@ -204,7 +216,7 @@ QString MOdtRendererPrivate::render(QString s) if(fbuf[i].trimmed().startsWith("#LOOP:")){ lname=fbuf[i].trimmed().mid(6).trimmed(); isloop=true; - }else{//not a loop + }else{//not a loop or statement //convert line ret+=renderLine(fbuf[i],"",-1); ret+="\n"; @@ -219,15 +231,58 @@ QString MOdtRendererPrivate::renderLine(QString line,QString loop,int lpos) { QString ret,vname; bool isvar=false; - static QString vc="ABCDEFGHIJKLMNOPQRSTUVWXYZ:+-0123456789"; + static QString vc="ABCDEFGHIJKLMNOPQRSTUVWXYZ:+-0123456789$#"; + //check for statements + if(line.trimmed().startsWith("#SETNEWLINE:")){ + //set a new newline translation + newline=line.trimmed().mid(12).trimmed(); + if(newline=="")newline=" "; + return ""; + } + if(line.trimmed().startsWith("#CALC:")){ + //do a calculation + //get full statement + QString stmt=line.trimmed().mid(6).trimmed(); + qDebug("????????????????Calculation: %s",stmt.toAscii().data()); + //split out var name + int p=stmt.indexOf(':'); + if(p<1)return ""; + QString var=stmt.left(p).trimmed(); + //get list of statement tokens + QStringList stl=stmt.mid(p+1).trimmed().split(" "); + //go through + qint64 res=intToken(stl[0],loop,lpos); + qDebug("??????????CalcInit: %lli",res); + for(int i=1;i=stl.size()){ + setLocalVarError(var); + qDebug("??????????CalcError: missing operand"); + return ""; + } + qDebug("??????????Calc: operator '%s' operand '%s' -> '%lli'",stl[i].toAscii().data(),stl[i+1].toAscii().data(),intToken(stl[i+1],loop,lpos)); + if(stl[i]=="+")res+=intToken(stl[i+1],loop,lpos);else + if(stl[i]=="-")res-=intToken(stl[i+1],loop,lpos);else + if(stl[i]=="*")res*=intToken(stl[i+1],loop,lpos);else + if(stl[i]=="/")res/=intToken(stl[i+1],loop,lpos);else + if(stl[i]=="%")res%=intToken(stl[i+1],loop,lpos); + else { + setLocalVarError(var); + qDebug("??????????CalcError: unknown operator"); + return ""; + } + } + setLocalVar(var,res); + return ""; + } //scan characters for(int i=0;i2){ //this was a mistake, reset @@ -238,13 +293,13 @@ QString MOdtRendererPrivate::renderLine(QString line,QString loop,int lpos) //this is a loop variable, //check that it is the right loop //or any loop at all... - if(loop!="" && loop==vl[0]){ + if(loop!="" && (loop==vl[0] || ("$"+loop)==vl[0])){ //get value - ret+=xmlize(getLoopVariable(loop,lpos,vl[1])); + ret+=xmlize(getLoopVariable(vl[0],lpos,vl[1]).trimmed(),newline); } }else //this is a normal variable, get valie - ret+=xmlize(getVariable(vname)); + ret+=xmlize(getVariable(vname).trimmed(),newline); } //reset mode isvar=false; @@ -280,28 +335,151 @@ QString MOdtRendererPrivate::renderLine(QString line,QString loop,int lpos) return ret; } +static inline QString formatVar(QVariant r,MOdtRenderer::VarType tp,bool loc,int offset) +{ + switch(tp){ + case MOdtRenderer::StringVar: + return r.toString(); + case MOdtRenderer::IntVar: + return QString::number(r.toInt()+offset); + case MOdtRenderer::MoneyVar: + return cent2str(r.toInt()+offset,loc); + case MOdtRenderer::DateVar: + return unix2date(r.toInt()+offset,loc); + case MOdtRenderer::TimeVar: + return unix2time(r.toInt()+offset,loc); + case MOdtRenderer::DateTimeVar: + return unix2dateTime(r.toInt()+offset,loc); + } + return ""; +} + QString MOdtRendererPrivate::getVariable(QString varname) { + //split out calculation + int offset=0; int p=varname.indexOf('+'); - if(p>0) - return parent->getVariable(varname.left(p),varname.mid(p+1).toInt()); + if(p>0){ + offset=varname.mid(p+1).toInt(); + varname=varname.left(p); + } p=varname.indexOf('-'); - if(p>0) - return parent->getVariable(varname.left(p),varname.mid(p).toInt()); - return parent->getVariable(varname,0); + if(p>0){ + offset=varname.mid(p).toInt(); + varname=varname.left(p); + } + //split out $-sign + bool localize=true; + if(varname[0]=='$'){ + localize=false; + varname=varname.mid(1); + } + //get variable + MOdtRenderer::VarType tp=MOdtRenderer::StringVar; + QVariant r; + if(varname=="TODAY"){ + r=QDateTime::currentDateTime().toTime_t(); + tp=MOdtRenderer::DateVar; + }else if(varname=="NOW"){ + r=QDateTime::currentDateTime().toTime_t(); + tp=MOdtRenderer::TimeVar; + }else if(varname[0]=='#'){ + if(localvars.contains(varname.mid(1))){ + r=localvars[varname.mid(1)].value; + tp=localvars[varname.mid(1)].type; + } + }else{ + r=parent->getVariable(varname,tp); + } + return formatVar(r,tp,localize,offset); } QString MOdtRendererPrivate::getLoopVariable(QString loopname,int iteration,QString varname) { + //split out calculation + int offset=0; int p=varname.indexOf('+'); - if(p>0) - return parent->getLoopVariable(loopname,iteration,varname.left(p),varname.mid(p+1).toInt()); + if(p>0){ + offset=varname.mid(p+1).toInt(); + varname=varname.left(p); + } p=varname.indexOf('-'); - if(p>0) - return parent->getLoopVariable(loopname,iteration,varname.left(p),varname.mid(p).toInt()); - return parent->getLoopVariable(loopname,iteration,varname,0); + if(p>0){ + offset=varname.mid(p).toInt(); + varname=varname.left(p); + } + //split out $-sign + bool localize=true; + if(loopname[0]=='$'){ + localize=false; + loopname=loopname.mid(1); + } + qDebug("!!!!!!!!!!getting loop var '%s' : '%s' localized=%s offset=%i",loopname.toAscii().data(),varname.toAscii().data(),(localize?"yes":"no"),offset); + //get variable + MOdtRenderer::VarType tp=MOdtRenderer::StringVar; + QVariant r; + if(varname=="ITERATION"){ + r=iteration; + tp=MOdtRenderer::IntVar; + }else + r=parent->getLoopVariable(loopname,iteration,varname,tp); + return formatVar(r,tp,localize,offset); +} + +qint64 MOdtRendererPrivate::intToken(QString vname,QString loop,int lpos) +{ + //split the variable + QStringList vnl=vname.split(":"); + if(vnl.size()<2){ + //local var? + if(vnl[0][0]=='#'){ + if(localvars.contains(vnl[0].mid(1))) + return localvars[vnl[0].mid(1)].value.toLongLong(); + return 0; + } + //special var? + if(vname=="TODAY" || vname=="NOW") + return QDateTime::currentDateTime().toTime_t(); + //get from parent + MOdtRenderer::VarType tp; + return parent->getVariable(vnl[0],tp).toLongLong(); + }else{ + //correct loop? + if(vnl[0]!=loop)return 0; + //iteration? + if(vnl[1]=="ITERATION")return lpos; + //get from parent + MOdtRenderer::VarType tp; + return parent->getLoopVariable(loop,lpos,vnl[1],tp).toLongLong(); + } } +void MOdtRendererPrivate::setLocalVar(QString vn,qint64 va) +{ + //split vname/type + QStringList vnl=vn.split("/"); + MOdtRenderer::VarType tp=MOdtRenderer::IntVar; + if(vnl.size()>1){ + if(vnl[1]=="MONEY")tp=MOdtRenderer::MoneyVar;else + if(vnl[1]=="DATE")tp=MOdtRenderer::DateVar;else + if(vnl[1]=="TIME")tp=MOdtRenderer::TimeVar;else + if(vnl[1]=="DATETIME")tp=MOdtRenderer::DateTimeVar; + } + //store + LocalVar lv; + lv.type=tp; + lv.value=va; + localvars.insert(vnl[0],lv); +} + +void MOdtRendererPrivate::setLocalVarError(QString vn) +{ + QStringList vnl=vn.split("/"); + LocalVar lv; + lv.type=MOdtRenderer::StringVar; + lv.value="error"; + localvars.insert(vnl[0],lv); +} /********************************************************************/ @@ -312,9 +490,10 @@ MOdtSignalRenderer::MOdtSignalRenderer(MTemplate file) MOdtSignalRenderer::~MOdtSignalRenderer(){} -QString MOdtSignalRenderer::getVariable(QString varname,int av) +QVariant MOdtSignalRenderer::getVariable(QString varname,MOdtRenderer::VarType&av) { - QString ret; + QVariant ret; + av=MOdtRenderer::StringVar; emit getVariable(varname,av,ret); return ret; } @@ -326,9 +505,10 @@ int MOdtSignalRenderer::getLoopIterations(QString loopname) return ret; } -QString MOdtSignalRenderer::getLoopVariable(QString loopname,int iteration,QString varname,int av) +QVariant MOdtSignalRenderer::getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&av) { - QString ret; + QVariant ret="notfound"; + av=MOdtRenderer::StringVar; emit getLoopVariable(loopname,iteration,varname,av,ret); return ret; } diff --git a/src/odtrender.h b/src/odtrender.h index ce7313f..bae9fef 100644 --- a/src/odtrender.h +++ b/src/odtrender.h @@ -39,16 +39,32 @@ class MOdtRenderer /**starts the internal rendering routine and outputs to printer (calls OpenOffice to print)*/ virtual void renderToPrinter(); + /**variable type*/ + enum VarType{ + /**default: uninterpreted string*/ + StringVar, + /**simple integer value*/ + IntVar, + /**money value*/ + MoneyVar, + /**unix timestamp: format as date*/ + DateVar, + /**unix timestamp: format as time*/ + TimeVar, + /**unix timestamp: format as date+time*/ + DateTimeVar + }; + protected: friend class MOdtRendererPrivate; /**implement this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ - virtual QString getVariable(QString varname,int addval)=0; + virtual QVariant getVariable(QString varname,VarType&)=0; /**implement this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ virtual int getLoopIterations(QString loopname)=0; /**implement this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ - virtual QString getLoopVariable(QString loopname,int iteration,QString varname,int addval)=0; + virtual QVariant getLoopVariable(QString loopname,int iteration,QString varname,VarType&)=0; private: MOdtRendererPrivate*d; }; @@ -65,18 +81,18 @@ class MOdtSignalRenderer:public QObject,public MOdtRenderer signals: /**connect this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ - void getVariable(QString varname,int addval,QString&value); + void getVariable(QString varname,MOdtRenderer::VarType&,QVariant&value); /**connect this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ void getLoopIterations(QString loopname,int&iterations); /**connect this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ - void getLoopVariable(QString loopname,int iteration,QString varname,int addval,QString&value); + void getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&,QVariant&value); protected: - QString getVariable(QString varname,int addval); + QVariant getVariable(QString varname,MOdtRenderer::VarType&); int getLoopIterations(QString loopname); - QString getLoopVariable(QString loopname,int iteration,QString varname,int addval); + QVariant getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&); }; #endif diff --git a/src/order.cpp b/src/order.cpp index 852ac67..3713b93 100644 --- a/src/order.cpp +++ b/src/order.cpp @@ -826,6 +826,12 @@ int MTicket::amountToPay()const else return 0; } +bool MTicket::isToBePaid()const +{ + if(m_status==Bought || m_status==Used)return true; + else return false; +} + /****************************************************************************** * Voucher diff --git a/src/order.h b/src/order.h index cf02525..be58101 100644 --- a/src/order.h +++ b/src/order.h @@ -59,6 +59,9 @@ class MTicket /**returns the amount that is to be paid for this ticket; this is identical to the price if the ticket is bought or used, it is zero otherwise*/ int amountToPay()const; + /**returns whether the ticket is to be paid (ie. it is bought or already used)*/ + bool isToBePaid()const; + /**returns the ID of the event the ticket belongs to*/ qint32 eventID()const; diff --git a/src/orderwin.cpp b/src/orderwin.cpp index 0b8bc4e..fd27ac8 100644 --- a/src/orderwin.cpp +++ b/src/orderwin.cpp @@ -341,9 +341,9 @@ void MOrderWindow::printBill() //print bill initPrintBuffer(); MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,int,QString&)),this,SLOT(getVariable(QString,int,QString&))); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,int,QString&)),this,SLOT(getLoopVariable(QString,int,QString,int,QString&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); rend.renderToPrinter(); donePrintBuffer(); } @@ -379,37 +379,81 @@ void MOrderWindow::saveBill() //render bill initPrintBuffer(); MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,int,QString&)),this,SLOT(getVariable(QString,int,QString&))); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,int,QString&)),this,SLOT(getLoopVariable(QString,int,QString,int,QString&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); rend.renderToFile(fname); donePrintBuffer(); } -void MOrderWindow::getVariable(QString vn,int av,QString&value) +void MOrderWindow::getVariable(QString vn,MOdtRenderer::VarType& av,QVariant&value) { - if(vn=="ORDERDATE")value=m_order.orderDateStr();else - if(vn=="ORDERDATETIME")value=m_order.orderDateTimeStr();else - if(vn=="SENTDATE")value=m_order.sentDateStr();else - if(vn=="SENTDATETIME")value=m_order.sentDateTimeStr();else + if(vn=="ORDERDATE"){ + value=m_order.orderDateTime().toTime_t(); + av=MOdtRenderer::DateVar; + }else + if(vn=="ORDERDATETIME"){ + value=m_order.orderDateTime().toTime_t(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="SENTDATE"){ + value=m_order.sentDateTime().toTime_t(); + av=MOdtRenderer::DateVar; + }else + if(vn=="SENTDATETIME"){ + value=m_order.sentDateTime().toTime_t(); + av=MOdtRenderer::DateTimeVar; + }else if(vn=="CUSTOMERID")value=QString::number(m_order.customerID());else if(vn=="ORDERID")value=QString::number(m_order.orderID());else if(vn=="ADDRESS")value=m_order.customer().address();else if(vn=="FULLADDRESS")value=m_order.customer().getNameAddress();else if(vn=="NAME")value=m_order.customer().name();else if(vn=="DELIVERYADDRESS")value=m_order.deliveryAddress();else - if(vn=="TOTALPRICE")value=m_order.totalPriceString(av);else - if(vn=="AMOUNTPAID")value=m_order.amountPaidString(av);else + if(vn=="FINALADDRESS"){ + QString v=m_order.deliveryAddress(); + if(v.trimmed()=="")v=m_order.customer().getNameAddress(); + value=v; + }else + if(vn=="TOTALPRICE"){ + value=m_order.totalPrice(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="AMOUNTPAID"){ + value=m_order.amountPaid(); + av=MOdtRenderer::MoneyVar; + }else if(vn=="SELLER")value=m_order.seller();else if(vn=="COMMENT")value=m_order.comment();else - if(vn=="AMOUNTTOPAY")value=m_order.amountToPayStr(av);else - if(vn=="AMOUNTTOREFUND")value=m_order.amountToRefundStr(av);else - if(vn=="TICKETS")value=QString::number(printBuffer.tickets.size()+av);else - if(vn=="ACCTICKETS")value=QString::number(printBuffer.tickinfo.size()+av);else - if(vn=="VOUCHERS")value=QString::number(printBuffer.vouchers.size()+av);else - if(vn=="ADDRESSLINES")value=QString::number(m_order.customer().address().split("\n").size()+av);else + if(vn=="AMOUNTTOPAY"){ + value=m_order.amountToPay(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="AMOUNTTOREFUND"){ + value=m_order.amountToRefund(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="TICKETS"){ + value=printBuffer.tickets.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="ACCTICKETS"){ + value=printBuffer.tickinfo.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="VOUCHERS"){ + value=printBuffer.vouchers.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="ADDRESSLINES"){ + value=m_order.customer().address().split("\n").size(); + av=MOdtRenderer::IntVar; + }else if(vn=="SHIPPING")value=m_order.shipping().description();else - if(vn=="SHIPPINGPRICE")value=m_order.shipping().priceString(av); + if(vn=="SHIPPINGPRICE"){ + value=m_order.shipping().price(); + av=MOdtRenderer::MoneyVar; + } } void MOrderWindow::getLoopIterations(QString loopname,int&iterations) @@ -419,38 +463,74 @@ void MOrderWindow::getLoopIterations(QString loopname,int&iterations) if(loopname=="VOUCHERS")iterations=printBuffer.vouchers.size(); if(loopname=="ADDRESSLINES")iterations=m_order.customer().address().split("\n").size(); } -void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,int av,QString&value) +void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,MOdtRenderer::VarType& av,QVariant&value) { if(loopname=="TICKETS"){ QList &tickets=printBuffer.tickets; if(it<0 || it>=tickets.size())return; - if(vn=="PRICE")value=tickets[it].priceString(av);else + if(vn=="PRICE"){ + value=tickets[it].price(); + av=MOdtRenderer::MoneyVar; + }else if(vn=="ID")value=tickets[it].ticketID();else if(vn=="TITLE")value=tickets[it].event().title();else if(vn=="ARTIST")value=tickets[it].event().artist();else - if(vn=="DATE")value=tickets[it].event().startDateString();else - if(vn=="STARTTIME")value=tickets[it].event().startTimeString();else - if(vn=="ENDTIME")value=tickets[it].event().endTimeString();else + if(vn=="DATE"){ + value=tickets[it].event().startTime(); + av=MOdtRenderer::DateVar; + }else + if(vn=="STARTTIME"){ + value=tickets[it].event().startTime(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ENDTIME"){ + value=tickets[it].event().endTime(); + av=MOdtRenderer::DateTimeVar; + }else if(vn=="ROOM")value=tickets[it].event().room(); }else if(loopname=="ACCTICKETS"){ QList &tickets=printBuffer.tickinfo; if(it<0 || it>=tickets.size())return; - if(vn=="PRICE")value=tickets[it].proto.priceString(av);else - if(vn=="FULLPRICE")value=cent2str(tickets[it].proto.price()*tickets[it].amount+av);else + if(vn=="PRICE"){ + value=tickets[it].proto.price(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="FULLPRICE"){ + value=tickets[it].proto.price()*tickets[it].amount; + av=MOdtRenderer::MoneyVar; + }else if(vn=="TITLE")value=tickets[it].proto.event().title();else if(vn=="ARTIST")value=tickets[it].proto.event().artist();else - if(vn=="DATE")value=tickets[it].proto.event().startDateString();else - if(vn=="STARTTIME")value=tickets[it].proto.event().startTimeString();else - if(vn=="ENDTIME")value=tickets[it].proto.event().endTimeString();else + if(vn=="DATE"){ + value=tickets[it].proto.event().startTime(); + av=MOdtRenderer::DateVar; + }else + if(vn=="STARTTIME"){ + value=tickets[it].proto.event().startTime(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ENDTIME"){ + value=tickets[it].proto.event().endTime(); + av=MOdtRenderer::DateTimeVar; + }else if(vn=="ROOM")value=tickets[it].proto.event().room();else - if(vn=="AMOUNT")value=QString::number(tickets[it].amount+av); + if(vn=="AMOUNT"){ + value=tickets[it].amount; + av=MOdtRenderer::IntVar; + } }else if(loopname=="VOUCHERS"){ if(it<0 || it>=printBuffer.vouchers.size())return; - if(vn=="PRICE")value=printBuffer.vouchers[it].priceString(av);else - if(vn=="VALUE")value=printBuffer.vouchers[it].valueString(av);else + if(vn=="PRICE"){ + value=printBuffer.vouchers[it].price(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="VALUE"){ + value=printBuffer.vouchers[it].value(); + av=MOdtRenderer::MoneyVar; + }else if(vn=="ID")value=printBuffer.vouchers[it].voucherID(); }else if(loopname=="ADDRESSLINES"){ QStringList lst=m_order.customer().address().split("\n"); diff --git a/src/orderwin.h b/src/orderwin.h index 3a1467c..8574f98 100644 --- a/src/orderwin.h +++ b/src/orderwin.h @@ -15,6 +15,7 @@ #include #include "order.h" +#include "odtrender.h" class QLabel; class QTableView; @@ -61,11 +62,11 @@ class MOrderWindow:public QMainWindow /**save the bill as file*/ void saveBill(); /**callback for bill generator: variables; see MOdtSignalRenderer for details*/ - void getVariable(QString varname,int,QString&value); + void getVariable(QString,MOdtRenderer::VarType&,QVariant&); /**callback for bill generator: loops; see MOdtSignalRenderer for details*/ void getLoopIterations(QString loopname,int&iterations); /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/ - void getLoopVariable(QString loopname,int iteration,QString varname,int,QString&value); + void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); /**received payment*/ void payment(); diff --git a/www/inc/classes/event.php b/www/inc/classes/event.php index d441ed0..8f66e20 100644 --- a/www/inc/classes/event.php +++ b/www/inc/classes/event.php @@ -327,6 +327,7 @@ function getEventSummaryXml($evid) $tcused=array(); $tcall=array(); $oids=array(); + $soids=""; foreach($res as $tc){ switch($tc["status"]){ case TICKET_RESERVED:$tcreserve++;break; @@ -356,8 +357,10 @@ function getEventSummaryXml($evid) $total++; break; } - if($tc["orderid"]!==false && !in_array($tc["orderid"],$oids)) + if($tc["orderid"]!==false && !in_array($tc["orderid"],$oids)){ $oids[]=$tc["orderid"]; + $soids.=" ".$tc["orderid"]; + } } //get comments sort($oids); @@ -402,6 +405,7 @@ function getEventSummaryXml($evid) $p->appendChild($xml->createTextNode($comment["cm"])); $doc->appendChild($p); } + $doc->appendChild($xml->createElement("Orders",trim($soids))); $xml->appendChild($doc); header("X-MagicSmoke-Status: Ok"); print($xml->saveXml()); diff --git a/www/inc/machine/version.inc b/www/inc/machine/version.inc index 25dd38f..6589908 100644 --- a/www/inc/machine/version.inc +++ b/www/inc/machine/version.inc @@ -13,7 +13,7 @@ //minimum version that the server understands (4 hex digits) defversion(MINSERVER,0000) //current version of the server -defversion(CURSERVER,0003) +defversion(CURSERVER,0004) //current human readable version of the server defversion(HRSERVER,0.2 beta) @@ -21,7 +21,7 @@ defversion(HRSERVER,0.2 beta) //minimum version that the client requires defversion(MINCLIENT,0000) //current version of the client -defversion(CURCLIENT,0003) +defversion(CURCLIENT,0004) //current human readable version of the client defversion(HRCLIENT,0.2 beta) -- 1.7.2.5