*.kdev*
*.tag
doxygen*.db
+*.kate-swp
#Build files, libs, executables
libQtZip*.*
object_script*
*.prl
.qmake.stash
+/dists/
#generated sources, translations, docu
doc/wob
#User files
*.mshk
+*.mshh
www/config.php
+*.od?t
+*.xtt
#Distribution files for various platforms
dist-*
MProgressWrapperGui(QString label,QString button)
{
pd=new QProgressDialog(label,button,0,0);
- pd->setMinimumDuration(0);
- pd->show();
+ pd->setMinimumDuration(500);
+ //pd->show();
}
~MProgressWrapperGui()
{
{
pd->cancel();
}
+ virtual void hide()
+ {
+ pd->hide();
+ }
virtual void setRange(int mi,int ma)
{
pd->setRange(mi,ma);
return ELAM::Exception(ELAM::Exception::ArgumentListError,"expecting 1 string argument");
return xmlize(args[0].value<QString>());
});
- engine.setFunction("xml",[](const QList<QVariant>&args,ELAM::Engine&)->QVariant{
+ engine.setFunction("raw",[](const QList<QVariant>&args,ELAM::Engine&)->QVariant{
if(args.size()!=1||!args[0].canConvert<QString>())
return ELAM::Exception(ELAM::Exception::ArgumentListError,"expecting 1 string argument");
return args[0];
});
+ //MIME
+ engine.setFunction("base64",[](const QList<QVariant>&args,ELAM::Engine&)->QVariant{
+ if(args.size()!=1||!args[0].canConvert<QByteArray>())
+ return ELAM::Exception(ELAM::Exception::ArgumentListError,"expecting 1 blob/byteArray argument");
+ const auto base=args[0].toByteArray().toBase64();
+ QString r;
+ for(int i=0;i<base.size();i+=76)
+ r+=QString::fromLatin1(base.mid(i,76))+"\r\n";
+ return r;
+ });
+ engine.setFunction("implode",[](const QList<QVariant>&args,ELAM::Engine&)->QVariant{
+ if(args.size()!=2||!args[0].canConvert<QStringList>()||!args[1].canConvert<QString>())
+ return ELAM::Exception(ELAM::Exception::ArgumentListError,"expecting 2 arguments: (stringlist elements, string separator)");
+ return args[0].toStringList().join(args[1].toString());
+ });
//Access Rights
engine.setFunction("checkflags",[](const QList<QVariant>&args,ELAM::Engine&)->QVariant{
if(args.size()!=1)
class MStickToken;
namespace ELAM {class Engine;}
-///A Twig-like renderer for HTML pages.
+///A Twig-like renderer for HTML pages or other text based documents.
class MAGICSMOKE_COMMON_EXPORT MStickRenderer
{
public:
+ ///instantiate the renderer
MStickRenderer();
+ ///clean up
virtual ~MStickRenderer();
+ ///sets the template text file
virtual void setTemplateFile(QString filename);
+ ///sets the template as plain text
virtual void setTemplate(QString text);
+ ///makes a property available as a variable in the renderer
virtual void setProperty(QString name,QVariant value);
+ ///makes several properties available as variables in the renderer
virtual void setProperties(QMap<QString,QVariant>properties);
+ ///deletes a property/variable
virtual void removeProperty(QString name);
+ ///returns a specific property or a NULL variant if not found
virtual QVariant property(QString name)const;
+ ///returns the names of all known properties
virtual QStringList propertyNames()const;
+ ///executes one rendering run on the template and returns the result as string
virtual QString render();
private:
QMap<QString,QVariant>mproperties;
MStickToken*mtemplate=nullptr;
+
+ ///initializes the internal ELAM engine
void initEngine(ELAM::Engine&);
};
--- /dev/null
+//
+// C++ Implementation: bill odtrender
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2016
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#include "billrender.h"
+#include <QVariant>
+#include <QDebug>
+
+static inline bool compare(const MOTicket&a,const MOTicket&b)
+{
+ if(a.eventid()!=b.eventid())return false;
+ if(a.price()!=b.price())return false;
+ return true;
+}
+
+MBillRenderer::MBillRenderer ( const MOOrder&o, const MTemplate& tmp)
+ :MOdtRenderer(tmp),m_order(o)
+{
+ //get tickets (only valid ones, only those that are to be paid)
+ QList<MOTicket>tlst=m_order.tickets();
+ for(int i=0;i<tlst.size();i++)
+ if(!tlst[i].ticketid().isNull() && (tlst[i].status()&MOTicket::MaskPay)!=0){
+ printBuffer.tickets.append(tlst[i]);
+ }
+ //accumulated view on tickets
+ for(int i=0;i<printBuffer.tickets.size();i++){
+ MOTicket t=printBuffer.tickets[i];
+ bool found=false;
+ for(int j=0;j<printBuffer.tickinfo.size();j++){
+ if(compare(printBuffer.tickinfo[j].proto,t)){
+ found=true;
+ printBuffer.tickinfo[j].amount++;
+ break;
+ }
+ }
+ if(!found)printBuffer.tickinfo.append(t);
+ }
+ //get valid vouchers
+ QList<MOVoucher>vlst=m_order.vouchers();
+ for(int i=0;i<vlst.size();i++)
+ if(vlst[i].price()>0||vlst[i].value()>0)
+ printBuffer.vouchers.append(vlst[i]);
+}
+
+QVariant MBillRenderer::getVariable(QString vn)
+{
+ if(vn=="ORDERDATE"){
+ return m_order.ordertime().value();
+ }else
+ if(vn=="ORDERDATETIME"){
+ return m_order.ordertime().value();
+ }else
+ if(vn=="SENTDATE"){
+ return m_order.senttime().value();
+ }else
+ if(vn=="SENTDATETIME"){
+ return m_order.senttime().value();
+ }else
+ if(vn=="CUSTOMERID")return QString::number(m_order.customerid());else
+ if(vn=="ORDERID")return QString::number(m_order.orderid());else
+ if(vn=="ADDRESS")return m_order.fullInvoiceAddress();else
+ if(vn=="FULLADDRESS")return m_order.fullInvoiceAddress();else
+ if(vn=="NAME")return m_order.customer().value().fullName();else
+ if(vn=="DELIVERYADDRESS")return m_order.fullDeliveryAddress();else
+ if(vn=="FINALADDRESS")return m_order.fullDeliveryAddress();else
+ if(vn=="TOTALPRICE"){
+ return m_order.totalprice().value();
+ }else
+ if(vn=="AMOUNTPAID"){
+ return m_order.amountpaid().value();
+ }else
+ if(vn=="SELLER")return m_order.soldby().value();else
+ if(vn=="COMMENT")return m_order.comments().value();else
+ if(vn=="AMOUNTTOPAY"){
+ return m_order.amountToPay();
+ }else
+ if(vn=="AMOUNTTOREFUND"){
+ return m_order.amountToRefund();
+ }else
+ if(vn=="TICKETS"){
+ return printBuffer.tickets.size();
+ }else
+ if(vn=="ACCTICKETS"){
+ return printBuffer.tickinfo.size();
+ }else
+ if(vn=="VOUCHERS"){
+ return printBuffer.vouchers.size();
+ }else
+ if(vn=="ADDRESSLINES"){
+ return m_order.fullInvoiceAddress().split("\n").size();
+ }else
+ if(vn=="SHIPPING")return m_order.shippingtype().value().description().value();else
+ if(vn=="SHIPPINGPRICE"){
+ return m_order.shippingtype().value().cost().value();
+ }else{
+ if(vn.contains(':')){
+ QStringList sl=vn.split(':');
+ int it=-1;
+ if(m_loopiter.contains(sl[0]))it=m_loopiter[sl[0]];
+ return getLoopVariable(sl[0],it,sl[1]);
+ }
+ }
+// qDebug()<<"got variable"<<vn<<"value"<<value;
+ qDebug()<<"Warning: requested unknown variable"<<vn;
+ return QVariant();
+}
+
+int MBillRenderer::getLoopIterations(QString loopname)
+{
+ if(loopname=="TICKETS")return printBuffer.tickets.size();
+ if(loopname=="ACCTICKETS")return printBuffer.tickinfo.size();
+ if(loopname=="VOUCHERS")return printBuffer.vouchers.size();
+ if(loopname=="ADDRESSLINES")return m_order.fullInvoiceAddress().split("\n").size();
+// qDebug()<<"loop"<<loopname<<"has"<<iterations<<"iterations";
+ //fall back
+ qDebug()<<"Warning: requested unknown loop"<<loopname;
+ return -1;
+}
+
+void MBillRenderer::setLoopIteration(QString loopname, int iteration)
+{
+// qDebug()<<"setting loop iter"<<loopname<<iteration;
+ if(iteration<0)return;
+ int max=getLoopIterations(loopname);
+ if(iteration>=max)return;
+ m_loopiter.insert(loopname,iteration);
+}
+
+
+QVariant MBillRenderer::getLoopVariable(QString loopname,int it,QString vn)
+{
+ if(loopname=="TICKETS"){
+ QList<MOTicket> &tickets=printBuffer.tickets;
+ if(it<0 || it>=tickets.size())return QVariant();
+
+ if(vn=="PRICE"){
+ return tickets[it].price().value();
+ }else
+ if(vn=="ID")return tickets[it].ticketid().value();else
+ if(vn=="TITLE")return tickets[it].event().title().value();else
+ if(vn=="ARTIST")return tickets[it].event().artist().value().name().value();else
+ if(vn=="DATE"){
+ return tickets[it].event().start().value();
+ }else
+ if(vn=="STARTTIME"){
+ return tickets[it].event().start().value();
+ }else
+ if(vn=="ENDTIME"){
+ return tickets[it].event().end().value();
+ }else
+ if(vn=="ROOM")return tickets[it].event().room().value();
+ }else if(loopname=="ACCTICKETS"){
+ QList<TickInfo> &tickets=printBuffer.tickinfo;
+ if(it<0 || it>=tickets.size())return QVariant();
+
+ if(vn=="PRICE"){
+ return tickets[it].proto.price().value();
+ }else
+ if(vn=="FULLPRICE"){
+ return tickets[it].proto.price().value()*tickets[it].amount;
+ }else
+ if(vn=="TITLE")return tickets[it].proto.event().title().value();else
+ if(vn=="ARTIST")return tickets[it].proto.event().artist().value().name().value();else
+ if(vn=="DATE"){
+ return tickets[it].proto.event().start().value();
+ }else
+ if(vn=="STARTTIME"){
+ return tickets[it].proto.event().start().value();
+ }else
+ if(vn=="ENDTIME"){
+ return tickets[it].proto.event().end().value();
+ }else
+ if(vn=="ROOM")return tickets[it].proto.event().room().value();else
+ if(vn=="AMOUNT"){
+ return tickets[it].amount;
+ }
+ }else if(loopname=="VOUCHERS"){
+ if(it<0 || it>=printBuffer.vouchers.size())return QVariant();
+
+ if(vn=="PRICE"){
+ return printBuffer.vouchers[it].price().value();
+ }else
+ if(vn=="VALUE"){
+ return printBuffer.vouchers[it].value().value();
+ }else
+ if(vn=="ID")return printBuffer.vouchers[it].voucherid().value();
+ }else if(loopname=="ADDRESSLINES"){
+ QStringList lst=m_order.fullInvoiceAddress().split("\n");
+ if(it<0 || it>=lst.size())return QVariant();
+ return lst[it];
+ }else{
+ qDebug()<<"Warning: requested variable"<<vn<<"from unknown loop"<<loopname;
+ return QVariant();
+ }
+ qDebug()<<"Warning: requested unknown variable"<<vn<<"from loop"<<loopname;
+ return QVariant();
+}
+
--- /dev/null
+//
+// C++ Interface: order bill renderer
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2016
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_BILLRENDER_H
+#define MAGICSMOKE_BILLRENDER_H
+
+#include <QMap>
+
+#include "odtrender.h"
+
+#include "MOOrder"
+#include "MOShipping"
+
+/**displays an order and allows the user to execute several commands on it*/
+class MAGICSMOKE_COMMON_EXPORT MBillRenderer:public MOdtRenderer
+{
+ public:
+ /**creates the order renderer*/
+ MBillRenderer(const MOOrder&,const MTemplate&);
+
+ protected:
+ /**callback for bill generator: variables; see MOdtSignalRenderer for details*/
+ QVariant getVariable(QString)override;
+ /**callback for bill generator: loops; see MOdtSignalRenderer for details*/
+ int getLoopIterations(QString loopname)override;
+ /**callback to set values of a specific loop iteration*/
+ void setLoopIteration(QString loopname,int iteration)override;
+ /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/
+ QVariant getLoopVariable(QString,int,QString);
+
+ private:
+ MOOrder m_order;
+ QMap<QString,int>m_loopiter;
+
+ //printing buffer
+ struct TickInfo{
+ TickInfo(const MOTicket&t):proto(t){amount=1;}
+ TickInfo(const TickInfo&t):proto(t.proto){amount=t.amount;}
+ TickInfo(){amount=0;}
+ MOTicket proto;
+ int amount;
+ };
+ struct PrintBuffer{
+ QList<MOTicket> tickets;
+ QList<MOVoucher> vouchers;
+ QList<TickInfo> tickinfo;
+ }printBuffer;
+};
+
+#endif
}
}
-void MOdtRenderer::renderToFile(QFile &file)
+void MOdtRenderer::renderToFile(QFile &file,bool preventopen)
{
if(d->renderToFile(file))
- if(QSettings().value("doOpenODFs",false).toBool())
+ if(!preventopen && QSettings().value("doOpenODFs",false).toBool())
openOfficeFile(file.fileName());
}
bool MOdtRendererPrivate::renderToFile(QFile &file)
QFile(tname).remove();
}
+QString MOdtRenderer::renderToPdf()
+{
+ //generate temporary file
+ QTemporaryFile tfile;
+ tfile.setAutoRemove(false);//we don't want it to be auto-deleted on close()
+ tfile.setFileTemplate(QDir::tempPath()+"/msmoke_XXXXXX."+d->extension);
+ tfile.open();
+ QString tname=tfile.fileName();
+ //render
+ d->renderToFile(tfile);
+ tfile.close();
+ //call ooffice and print
+ QString pdf=convertOfficeFilePdf(tname);
+ //remove temporary file
+ QFile(tname).remove();
+
+ return pdf;
+}
+
void MOdtRendererPrivate::render(QIODevice*out)
{
//sanity check
virtual void renderToFile(QString file);
/**starts the internal rendering routine and outputs to file*/
- virtual void renderToFile(QFile& file);
+ virtual void renderToFile(QFile& file,bool preventOpen=false);
/**starts the internal rendering routine and outputs to printer (calls OpenOffice to print)*/
virtual void renderToPrinter();
+
+ ///like renderToPrinter, but renders to PDF, returns the PDF file name
+ virtual QString renderToPdf();
///helper routine: converts a V1 template to V2
///you have to make sure to not do a double conversion on an already converted document
#include <QComboBox>
#include <QCoreApplication>
#include <QDebug>
+#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QGroupBox>
}
}
+QString convertOfficeFilePdf(QString fname)
+{
+ QFileInfo finf(fname);
+ //calculate parameters
+ QStringList r;
+ r<<"--headless"<<"--convert-to"<<"pdf"<<"--outdir"<<finf.dir().absolutePath();
+ r<<fname;
+ //print and wait for finish
+ QProcess proc;
+ proc.start(getofficepath(),r);
+ proc.waitForFinished();
+ //calculate new name
+ QString pname=finf.dir().absoluteFilePath(finf.completeBaseName()+".pdf");
+ if(QFile::exists(pname))return pname;
+ else return QString();
+}
+
MOfficeConfig::MOfficeConfig(QWidget*par)
:QDialog(par)
{
/**calls OpenOffice.org to print an ODF file*/
void printOfficeFile(QString fname);
+///calls OpenOffice.org to convert an ODF file to PDF;
+///returns the PDF file name on success, empty string on failure
+QString convertOfficeFilePdf(QString fname);
+
#include <QDialog>
#include "commonexport.h"
$$PWD/odtrender.h \
$$PWD/ticketrender.h \
$$PWD/office.h \
- $$PWD/labeldlg.h
+ $$PWD/labeldlg.h \
+ $$PWD/billrender.h
SOURCES += \
$$PWD/odtrender.cpp \
$$PWD/ticketrender.cpp \
$$PWD/office.cpp \
- $$PWD/labeldlg.cpp
+ $$PWD/labeldlg.cpp \
+ $$PWD/billrender.cpp
INCLUDEPATH += $$PWD
//called by MLabelRenderer
QSizeF labelSize(const QPaintDevice&);
+ QSizeF labelSizeMM();
private:
MLabelRenderer*parent;
return tonatural(dev,tsize);
}
+QSizeF MLabelRenderer::labelSizeMM()
+{
+ return d->labelSizeMM();
+}
+
+QSizeF MLabelRendererPrivate::labelSizeMM()
+{
+ qreal fac;
+ if(unit=="mm")fac=1.0;else fac=25.4;
+ return QSizeF(tsize.width()*fac, tsize.height()*fac);
+}
+
+
MLabel::MLabel(){}
MLabel::~MLabel(){}
/**returns the size of the ticket in the coordinates of the specified paint device (used for preview)*/
virtual QSizeF labelSize(const QPaintDevice&);
+
+ ///returns the size of the label in Millimeters
+ virtual QSizeF labelSizeMM();
protected:
friend class MLabelRendererPrivate;
--- /dev/null
+../icons/logo/logo.png
\ No newline at end of file
--- /dev/null
+The Oxygen Icon Theme
+ Copyright (C) 2007 Nuno Pinheiro <nuno@oxygen-icons.org>
+ Copyright (C) 2007 David Vignoni <david@icon-king.com>
+ Copyright (C) 2007 David Miller <miller@oxygen-icons.org>
+ Copyright (C) 2007 Johann Ollivier Lapeyre <johann@oxygen-icons.org>
+ Copyright (C) 2007 Kenneth Wimer <kwwii@bootsplash.org>
+ Copyright (C) 2007 Riccardo Iaconelli <riccardo@oxygen-icons.org>
+
+
+and others
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+Clarification:
+
+ The GNU Lesser General Public License or LGPL is written for
+ software libraries in the first place. We expressly want the LGPL to
+ be valid for this artwork library too.
+
+ KDE Oxygen theme icons is a special kind of software library, it is an
+ artwork library, it's elements can be used in a Graphical User Interface, or
+ GUI.
+
+ Source code, for this library means:
+ - where they exist, SVG;
+ - otherwise, if applicable, the multi-layered formats xcf or psd, or
+ otherwise png.
+
+ The LGPL in some sections obliges you to make the files carry
+ notices. With images this is in some cases impossible or hardly useful.
+
+ With this library a notice is placed at a prominent place in the directory
+ containing the elements. You may follow this practice.
+
+ The exception in section 5 of the GNU Lesser General Public License covers
+ the use of elements of this art library in a GUI.
+
+ kde-artists [at] kde.org
+
+-----
+see doc/copying-lgpl.html for license details
--- /dev/null
+Images in this folder were pulled from WikiPedia and are under Public Domain.
virtual void setLabelText(QString l){label=l;}
virtual void setCancelButtonText(QString){}
virtual void cancel(){}
+ virtual void hide(){}
virtual void setRange(int mi,int ma){
min=mi;max=ma;
if(min>max)min=max;
virtual void cancel()=0;
virtual void setRange(int,int)=0;
virtual void setValue(int)=0;
+ virtual void hide()=0;
};
#endif
set.setValue(s.filename()+"/description",s.description().value());
set.setValue(s.filename()+"/flags",s.flags().value());
}
+
+ progress->hide();
}
bool MTemplateStore::retrieveFile(QString dname,QString fn)
if(x=="zip")return ZipTemplate;
//HTML?
if(x=="html")return HtmlTemplate;
+ //MIME?
+ if(x=="mime")return MimeTemplate;
//hmm, unknown one
return UnknownTemplate;
}
QStringList MTemplate::legalBaseNames()
{
if(tempBaseNames.size()==0){
- tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary"<<"scripts"<<"eventview";
+ tempBaseNames <<"ticket" <<"voucher" <<"bill" <<"eventsummary" <<"scripts" <<"eventview" <<"printathome";
}
return tempBaseNames;
}
return ZipTemplate;
if(bn=="eventview")
return HtmlTemplate;
+ if(bn=="printathome")
+ return MimeTemplate;
return UnknownTemplate;
}
return QStringList()<<"zip";
case HtmlTemplate:
return QStringList()<<"html";
+ case MimeTemplate:
+ return QStringList()<<"mime";
default:
return QStringList();
}
/**Script-Zip template*/
ZipTemplate=0x200,
///HTML patterns
- HtmlTemplate=0x400
+ HtmlTemplate=0x400,
+ ///MIME patterns
+ MimeTemplate=0x800
};
Q_DECLARE_FLAGS(Types,Type)
\param useFirst if true: use the first match regardless of whether there are more candidates
*/
MTemplate getTemplate(QString base,bool useFirst=false);
- /**returns a specific template by its full name, opens a template choice dialog if necessary
- \param full the base name of the template to retrieve (eg. "ticket.xtt,1")*/
+ /**returns a specific template by its full name, returns an invalid template if it does not exist
+ \param full the full name of the template to retrieve (eg. "ticket.xtt,1")*/
MTemplate getTemplateByFile(QString full);
/**returns all templates (for MTemplateEditor)*/
QList<MTemplate> allTemplates();
-
+
private:
QString profileid;
};
-Subproject commit c3ce03861e7e94ee5a87b8cb506b120af4d74348
+Subproject commit 2802df28960dcde2a86a78a154cdcb6590152856
--- /dev/null
+README for Print@Home Icons
+=============================
+
+The basic MagicSmoke Icon is part of the MagicSmoke project.
+
+The Icon Overlays have been copied from the KDE Oxygen Icon Theme.
+
+You can download them from: ftp://ftp.kde.org
+
+These Icons are licensed under GNU LGPL version 3 or any newer.
//
#include "clientcfg.h"
+#include "pah.h"
#include "scli.h"
#include <QLineEdit>
#include <QSettings>
-#define GROUP "PrintAtHome/Client"
+#define GROUP PRINTATHOME_SETTINGSGROUP "/Client"
#define TIMER GROUP "/timermin"
+#define ORDERAGE GROUP "/orderage"
#define SETPROFILE GROUP "/setprofile"
#define PROFILE GROUP "/profile"
#define SETUSER GROUP "/setuser"
fl->addRow(tr("Check Interval in Minutes:"),mtimer=new QSpinBox);
mtimer->setRange(1,10080);
mtimer->setValue(timerInMinutes());
+ //age of orders
+ fl->addRow(tr("Maximum Age of Orders in Days:"),morderage=new QSpinBox);
+ morderage->setRange(0,999);
+ morderage->setValue(maximumAgeOfOrders());
//profile
fl->addRow("",msetprofile=new QCheckBox(tr("Preselect Profile")));
fl->addRow(tr("Profile:"),mprofile=new QComboBox);
QSettings set;
set.setValue(SETPROFILE,msetprofile->isChecked());
set.setValue(TIMER,mtimer->value());
+ set.setValue(ORDERAGE,morderage->value());
set.setValue(PROFILE,mprofile->currentData());
set.setValue(SETUSER,msetuser->isChecked());
set.setValue(USERNAME,musername->text());
return QSettings().value(TIMER,60).toInt();
}
+int MPClientConfig::maximumAgeOfOrders()
+{
+ return QSettings().value(ORDERAGE,7).toInt();
+}
+
+
QString MPClientConfig::preselectedProfileId()
{
return QSettings().value(PROFILE).toString();
MPClientConfig(QWidget*parent=nullptr);
static int timerInMinutes();
+ static int maximumAgeOfOrders();
static bool preselectProfile();
static QString preselectedProfileId();
static bool preselectUser();
void save();
private:
- QSpinBox*mtimer;
+ QSpinBox*mtimer,*morderage;
QCheckBox*msetprofile,*msetuser,*mautologin;
QLineEdit*musername,*mpassword;
QComboBox*mprofile;
--- /dev/null
+{#
+This template contains the mail sent to a customer
+when an order for this customer is executed by print@home.
+
+The first non-empty line contains the subject,
+subsequent lines contain the headers, then an empty line
+and after that the body of the mail.
+#}
+Order {{order.orderid}} - Your Print@Home Tickets are Ready
+From: no-reply@localhost
+Cc: {{cc|implode(", ")}}
+Bcc: info@localhost
+Content-Type: multipart/mixed; boundary="------boundary-aYAmoTT04MIpvxx"
+MIME-Version: 1.0
+
+ This is a multi-part message in MIME format.
+
+--------boundary-aYAmoTT04MIpvxx
+Content-Type: multipart/alternative; boundary="------boundary-aYAmoTT04MIpviI"
+Content-Transfer-Encoding: 8bit
+
+ This is a multi-part message in MIME format.
+
+--------boundary-aYAmoTT04MIpviI
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+Hello {{customer.title}} {{customer.name}}!
+
+Your order number {{order.orderid}} has been generated.
+
+total price : {{order.totalprice|asMoney}}
+
+
+Your documents are:
+{% for doc in docs %}
+{{doc.fileid}} {{doc.filename}}
+{% endfor %}
+
+
+ with best regards,
+ your MagicSmoke team
+
+--------boundary-aYAmoTT04MIpviI
+Content-Type: multipart/related; boundary="iKETDhtPafV07ewA9JlUOMitE"
+Content-Transfer-Encoding: 8bit
+
+--iKETDhtPafV07ewA9JlUOMitE
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+
+<h2>Hello {{customer.title}} {{customer.name}}!</h2>
+
+<p>Your order number {{order.orderid}} has been generated.</p>
+
+<p>Your documents are:
+<ul>
+{% for doc in docs %}
+<li>{{doc.fileid}} {{doc.filename}}</li>
+{% endfor %}
+</ul></p>
+
+<p></p>
+<p></p>
+<p></p>
+
+<img src="cid:logo_png" align="right"/>
+ with best regards,<br/>
+ your MagicSmoke team
+
+--iKETDhtPafV07ewA9JlUOMitE
+Content-ID: <logo_png>
+Content-Transfer-Encoding: base64
+Content-Type: image/png; name="logo.png"
+
+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
+
+--iKETDhtPafV07ewA9JlUOMitE--
+
+--------boundary-aYAmoTT04MIpviI--
+
+{% for doc in docs %}
+--------boundary-aYAmoTT04MIpvxx
+Content-Transfer-Encoding: base64
+Content-Type: application/pdf; name="{{doc.filename}}"
+
+{{doc.content|base64}}
+
+{% endfor %}
+--------boundary-aYAmoTT04MIpvxx--
<file>icon-print.png</file>
<file>icon-block.png</file>
<file>icon-active.png</file>
+ <file>icon-problem.png</file>
</qresource>
</RCC>
#include "mapplication.h"
#include "msinterface.h"
#include "scli.h"
-#include <WTransaction>
+#include "WTransaction"
+#include "MTGetOrderList"
#include "pah.h"
#include "clientcfg.h"
#include "servercfg.h"
+#include "printrun.h"
+#include <QAction>
+#include <QDateTime>
#include <QIcon>
#include <QMenu>
-#include <QAction>
+#include <QMessageBox>
+#include <QSettings>
+#include <QTimer>
+
+static PrintIcon*piInstance=nullptr;
+
+#define PRINTACTIVESETTING PRINTATHOME_SETTINGSGROUP "/isActive"
PrintIcon::PrintIcon()
{
setPrintMode(PrintMode::Blocked);
QMenu*ctx=new QMenu;
- ctx->addAction(tr("Start &Printing now"));
+ ctx->addAction(tr("Start &Printing now"),this,SIGNAL(startPrinting()));
+ QAction *a=ctx->addAction(tr("Printing &Active"));
+ a->setCheckable(true);
+ a->setChecked(misactive=QSettings().value(PRINTACTIVESETTING,true).toBool());
+ connect(a,SIGNAL(toggled(bool)),this,SLOT(activatePrint(bool)));
ctx->addSeparator();
ctx->addAction(tr("&Client Configuration..."),this,SLOT(clientConfig()));
ctx->addAction(tr("&Server Configuration..."),this,SLOT(serverConfig()));
setContextMenu(ctx);
show();
+
+ piInstance=this;
+}
+
+PrintIcon* PrintIcon::instance()
+{
+ return piInstance;
}
+
void PrintIcon::setPrintMode(PrintMode m)
{
- QString mode;
switch(m){
case PrintMode::Normal:
setIcon(QIcon(":/icon-print.png"));
- mode=tr("Ready");
+ mmode=tr("Ready");
break;
case PrintMode::Blocked:
setIcon(QIcon(":/icon-block.png"));
- mode=tr("Blocked");
+ mmode=tr("Blocked");
break;
case PrintMode::Printing:
setIcon(QIcon(":/icon-active.png"));
- mode=tr("Printing...");
+ mmode=tr("Printing...");
+ break;
+ case PrintMode::Problem:
+ setIcon(QIcon(":/icon-problem.png"));
+ mmode=tr("Configuration Problems!");
break;
}
+ toolTipUpdate();
+}
+
+void PrintIcon::toolTipUpdate()
+{
QString user=tr("(not logged in)"),host;
if(req){
user=req->currentUser();
host=req->profileName();
}
- setToolTip(tr("MagicSmoke Print@Home: %1 - logged in as %2 at %3").arg(mode).arg(user).arg(host));
+ setToolTip(tr("MagicSmoke Print@Home: %1\nlogged in as %2 at %3\nNext print: %4")
+ .arg(mmode)
+ .arg(user).arg(host)
+ .arg(mnexttime)
+ );
+}
+
+void PrintIcon::setNextTime(QString s)
+{
+ mnexttime=s;
+ toolTipUpdate();
+}
+
+void PrintIcon::activatePrint(bool a)
+{
+ misactive=a;
+ emit printActivated(a);
}
void PrintIcon::clientConfig()
{
MPClientConfig cc;
- cc.exec();
+ if(cc.exec()==QDialog::Accepted)
+ emit settingsChanged();
}
void PrintIcon::serverConfig()
{
MPServerConfig sc;
- sc.exec();
+ if(sc.exec()==QDialog::Accepted)
+ emit settingsChanged();
+}
+
+
+PrintScheduler::PrintScheduler()
+{
+ //set icon to active mode
+ PrintIcon *pi=PrintIcon::instance();
+ pi->setPrintMode(pi->printIsActive()?PrintIcon::PrintMode::Normal:PrintIcon::PrintMode::Blocked);
+
+ //create timer
+ mtimer=new QTimer;
+ mtimer->setSingleShot(false);
+ connect(mtimer,SIGNAL(timeout()),this,SLOT(startPrinting()));
+
+ //connect signals
+ connect(pi,SIGNAL(printActivate(bool)),this,SLOT(activatePrint(bool)));
+ connect(pi,SIGNAL(settingsChanged()),this,SLOT(reinit()));
+ connect(pi,SIGNAL(startPrinting()),this,SLOT(startPrinting()));
+
+ //init
+ reinit();
+}
+
+void PrintScheduler::activatePrint(bool a)
+{
+ if(a!=mtimer->isActive())
+ reinit();
+}
+
+void PrintScheduler::reinit()
+{
+ PrintIcon*pi=PrintIcon::instance();
+ //check and change timer interval
+ const int interval=MPClientConfig::timerInMinutes()*60000;
+ if(interval!=mtimer->interval())
+ mtimer->setInterval(interval);
+
+ //validate server config
+ if(!MPServerConfig::validateConfig()){
+ pi->setNextTime(tr("not running"));
+ pi->setPrintMode(PrintIcon::PrintMode::Problem);
+ mtimer->stop();
+ return;
+ }
+
+ //check whether the user blocked it
+ if(!PrintIcon::instance()->printIsActive()){
+ pi->setNextTime(tr("not running"));
+ PrintIcon::instance()->setPrintMode(PrintIcon::PrintMode::Blocked);
+ mtimer->stop();
+ return;
+ }
+
+ //make sure timer is running
+ if(!mtimer->isActive())mtimer->start();
+ pi->setNextTime(QDateTime::currentDateTime().addMSecs(mtimer->remainingTime()).time().toString());
+ PrintIcon::instance()->setPrintMode(PrintIcon::PrintMode::Normal);
+}
+
+void PrintScheduler::startPrinting()
+{
+ //sanity check
+ if(!MPServerConfig::validateConfig()){
+ QMessageBox::warning(nullptr,tr("Warning"),tr("Cannot execute Print@Home: the server configuration is not consistent!"));
+ return;
+ }
+
+ //take care of logistics
+ static bool isprinting=false;
+ if(isprinting){
+ qDebug()<<"Printing is already active. Ignoring.";
+ return;
+ }
+ qDebug()<<"Starting to print now...";
+ isprinting=true;
+ PrintIcon*pi=PrintIcon::instance();
+ pi->setPrintMode(PrintIcon::PrintMode::Printing);
+
+ // print
+ PrintingRun().exec();
+
+ // done
+ pi->setPrintMode(pi->printIsActive()?PrintIcon::PrintMode::Normal:PrintIcon::PrintMode::Blocked);
+ isprinting=false;
}
ms->loginSession(sc.currentUsername(), sc.currentSessionId());
ms->initialize();
QObject::connect(&sc,SIGNAL(sessionIdChanged(QString)),ms,SLOT(setSessionId(QString)));
- pi.setPrintMode(PrintIcon::PrintMode::Normal);
}else{
qDebug()<<"Unable to get session. Giving up.";
return 1;
}
+ //activate scheduler
+ PrintScheduler ps;
+
//event loop
return app.exec();
}
#include <QSystemTrayIcon>
+#include "MOOrderInfo"
+#include "MOCustomerInfo"
+
+#define PRINTATHOME_SETTINGSGROUP "PrintAtHome"
+
+class QTimer;
+
+///This represents the icon in the system tray and the main UI of the Print at Home client
class PrintIcon:public QSystemTrayIcon
{
Q_OBJECT
public:
PrintIcon();
+
+ ///returns the Icon instance
+ static PrintIcon* instance();
enum class PrintMode{
///Normal operation, waiting for events
Normal,
///Actively printing
Printing,
- ///operation blocked, no connection
- Blocked
+ ///operation blocked, no connection or printing deactivated
+ Blocked,
+ ///operation not possible, problem with settings
+ Problem
};
+
+ ///returns true if the "Activate Printing" menu item is ticked
+ bool printIsActive(){return misactive;}
+
public slots:
+ ///sets the icon variant
void setPrintMode(PrintMode);
+ ///tells the tool tio when we will print next time
+ void setNextTime(QString s);
+
+private slots:
+ ///opens the client configuration dialog
void clientConfig();
+ ///opens the server configuration dialog
void serverConfig();
+
+ ///callback for the menu
+ void activatePrint(bool);
+ ///updates the tool tip text with current settings
+ void toolTipUpdate();
+
+signals:
+ ///emitted when the "Activate Printing" menu item is changed
+ void printActivated(bool);
+ ///emitted whenever settings have changed
+ void settingsChanged();
+ ///emitted when the user wants to start printing immediately
+ void startPrinting();
+
+private:
+ bool misactive=false;
+ QString mmode,mnexttime;
+};
+
+///Central scheduler class for the Print at Home client.
+class PrintScheduler:public QObject
+{
+ Q_OBJECT
+public:
+ PrintScheduler();
+public slots:
+ ///initiates and controls the print job.
+ void startPrinting();
+ ///call back for the menu item - affects the timer
+ void activatePrint(bool);
+ ///re-initializes the scheduler with current settings
+ void reinit();
+private:
+ QTimer*mtimer;
};
#endif
include(../commonlib/commonlib.pri)
#sources
-SOURCES += pah.cpp clientcfg.cpp servercfg.cpp
-HEADERS += pah.h clientcfg.h servercfg.h
+SOURCES += pah.cpp clientcfg.cpp servercfg.cpp printrun.cpp
+HEADERS += pah.h clientcfg.h servercfg.h printrun.h
RESOURCES += files.qrc
DEPENDPATH += $$INCLUDEPATH
#make sure the correct Qt DLLs are used
-QT += network gui widgets
+QT += network gui widgets printsupport
--- /dev/null
+//
+// C++ Implementation: print @ home run
+//
+// Description: Print runner
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2016
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#include "mapplication.h"
+#include "msinterface.h"
+#include "MOOrder"
+#include "MOOrderDocument"
+#include "MTGetCustomer"
+#include "MTGetOrder"
+#include "MTGetOrderList"
+#include "MTSetOrderDocument"
+#include "WTransaction"
+#include "MTSendCustomerMail"
+#include "MTChangeCustomerMail"
+
+#include "ticketrender.h"
+#include "odtrender.h"
+#include "billrender.h"
+#include "stick.h"
+
+#include "pah.h"
+#include "printrun.h"
+#include "servercfg.h"
+#include "clientcfg.h"
+
+#include <QDateTime>
+#include <QDebug>
+#include <QDir>
+#include <QPainter>
+#include <QPrinter>
+#include <QStringList>
+#include <QTemporaryFile>
+#include <QVariant>
+
+PrintingRun::PrintingRun()
+{
+ // get templates
+ MTemplateStore *ts=req->templateStore();
+ ticket=ts->getTemplateByFile(MPServerConfig::ticketTemplateName());
+ voucher=ts->getTemplateByFile(MPServerConfig::voucherTemplateName());
+ invoice=ts->getTemplateByFile(MPServerConfig::billTemplateName());
+ mail=ts->getTemplateByFile(MPServerConfig::mailTemplateName());
+
+ mticketname=MPServerConfig::ticketFileName()+".pdf";
+ mvouchername=MPServerConfig::voucherFileName()+".pdf";
+ minvoicename=MPServerConfig::billFileName()+".pdf";
+
+ // get orders
+ const int age=MPClientConfig::maximumAgeOfOrders();
+ const qint64 oldest=age<=0?0:QDateTime::currentDateTime().addDays(-age).toTime_t();
+ MTGetOrderList olt=req->queryGetOrderList(oldest);
+ QList<MOOrderInfo> olist=olt.getorders();
+ mcustomers=olt.getcustomers();
+
+ // filter orders
+ const QList<int>shipids=MPServerConfig::shippingIds();
+ for(const MOOrderInfo&ord:olist)
+ if(ord.isPlaced() && shipids.contains(ord.shippingtypeid()))
+ morders.append(ord);
+ qDebug()<<"Processing"<<morders.size()<<"orders of"<<olist.size()<<"since"<<age<<"days";
+}
+
+void PrintingRun::exec()
+{
+ for(const MOOrderInfo&ord:morders)
+ printOneOrder(ord);
+ qDebug()<<"Finished Print Run.";
+}
+
+void PrintingRun::printOneOrder(const MOOrderInfo&orderinfo)
+{
+ qDebug()<<"Printing order"<<orderinfo.orderid();
+ //get order details
+ //TODO: mark as shipped instead
+ MOOrder order=req->queryGetOrder(orderinfo.orderid()).getorder();
+
+ QList<MOOrderDocument> doclist;
+
+ //generate tickets
+ if(order.tickets().size()>0){
+ QTemporaryFile tmp(QDir::tempPath()+"/mspah-XXXXXX.pdf");
+ tmp.open();tmp.close();
+ QPrinter prn(QPrinter::HighResolution);
+ prn.setOutputFileName(tmp.fileName());
+ MTicketRenderer render(ticket);
+ prn.setPageSizeMM(render.labelSizeMM());
+ QPainter*paint=new QPainter(&prn);
+ bool np=false;
+ for(MOTicket tick:order.tickets()){
+ //do we know the event?
+ if(mevents.contains(tick.eventid()))
+ tick.setEvent(mevents[tick.eventid()]);
+ else
+ //this automatically retrieves the event
+ if(tick.event().isValid())
+ mevents.insert(tick.eventid(),tick.event());
+ //print the ticket
+ if(np)prn.newPage();
+ else np=true;
+ render.render(tick,prn,paint);
+ }
+ delete paint;
+ uploadFile(order.orderid(),tmp.fileName(),mticketname,doclist);
+ }
+
+ //generate vouchers
+ if(order.vouchers().size()>0){
+ QTemporaryFile tmp(QDir::tempPath()+"/mspah-XXXXXX.pdf");
+ tmp.open();tmp.close();
+ QPrinter prn(QPrinter::HighResolution);
+ prn.setOutputFileName(tmp.fileName());
+ MVoucherRenderer render(voucher);
+ prn.setPageSizeMM(render.labelSizeMM());
+ QPainter*paint=new QPainter(&prn);
+ bool np=false;
+ for(MOVoucher vouc:order.vouchers()){
+ //print the voucher
+ if(np)prn.newPage();
+ else np=true;
+ render.render(vouc,prn,paint);
+ }
+ delete paint;
+ uploadFile(order.orderid(),tmp.fileName(),mvouchername,doclist);
+ }
+
+ //generate bill
+ MBillRenderer orender(order,invoice);
+ QString pname=orender.renderToPdf();
+ qDebug()<<"rendered bill to"<<pname;
+ uploadFile(order.orderid(),pname,minvoicename,doclist);
+
+ //send mail
+ sendMail(order,doclist);
+}
+
+void PrintingRun::uploadFile(int orderid,QString localfile,QString remotefile,QList<MOOrderDocument>&doclist)
+{
+ MOOrderDocument doc;
+ doc.setorderid(orderid);
+ doc.setfilename(remotefile);
+ QFile fd(localfile);
+ fd.open(QIODevice::ReadOnly);
+ doc.setcontent(fd.readAll());
+ fd.close();
+ doc.setvisible(true);
+ MTSetOrderDocument trans=MTSetOrderDocument::query(doc);
+ doclist.append(doc);
+}
+
+void PrintingRun::sendMail(const MOOrder&order,const QList<MOOrderDocument>&doclist)
+{
+ //get customer details
+ MOCustomer cust;
+ if(mcustomerdetails.contains(order.customerid()))
+ cust=mcustomerdetails[order.customerid()];
+ else
+ cust=MTGetCustomer::query(order.customerid()).getcustomer();
+ QStringList cc;
+ const QList<int>contacttypes=MPServerConfig::mailContactTypeIds();
+ for(auto co:cust.contacts())
+ if(contacttypes.contains(co.contactid()))
+ cc<<co.contact();
+ //feed renderer
+ MStickRenderer render;
+ render.setProperty("order",QVariant::fromValue(order));
+ render.setProperty("docs",QVariant::fromValue(doclist));
+ render.setProperty("customer",QVariant::fromValue(cust));
+ render.setProperty("cc",cc);
+ render.setTemplateFile(mail.cacheFileName());
+ //execute
+ QString mymail=render.render();
+ //make sure customer has a mail address configured
+ if(cust.email().isNull() || cust.email().value().isEmpty()){
+ if(cc.size()>0)
+ MTChangeCustomerMail::query(cust.customerid(),cc[0]);
+ }
+ //send mail
+ MTSendCustomerMail::query(order.customerid(),mymail);
+}
--- /dev/null
+//
+// C++ Interface: print @ home run
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2016
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#ifndef PAH_RUN_H
+#define PAH_RUN_H
+
+#include <QObject>
+#include <QMap>
+
+#include "MOOrderInfo"
+#include "MOCustomerInfo"
+#include "MOCustomer"
+#include "MOEvent"
+
+#include "templates/templates.h"
+
+class MOOrderDocument;
+class MOOrder;
+
+///Represents a single printing run with multiple orders to be printed.
+class PrintingRun:public QObject
+{
+ Q_OBJECT
+public:
+ ///retrieves all basic information for open orders
+ PrintingRun();
+
+public slots:
+ ///executes the actual print run
+ void exec();
+private:
+ QList<MOOrderInfo>morders;
+ QList<MOCustomerInfo>mcustomers;
+ QMap<int,MOCustomer>mcustomerdetails;
+ MTemplate ticket,voucher,invoice,mail;
+ QString mticketname,mvouchername,minvoicename;
+ QMap<int,MOEvent>mevents;
+
+ void printOneOrder(const MOOrderInfo&);
+ void uploadFile(int orderid,QString localfile,QString remotefile,QList<MOOrderDocument>&doclist);
+ void sendMail(const MOOrder&,const QList<MOOrderDocument>&);
+};
+
+#endif
#include "templates.h"
#include "MTGetAllContactTypes"
+#include "MTGetAllShipping"
#include "MTGetPrintAtHomeSettings"
#include "MTSetPrintAtHomeSettings"
-#include <QFormLayout>
#include <QBoxLayout>
#include <QCheckBox>
-#include <QPushButton>
#include <QComboBox>
-#include <QSpinBox>
-#include <QLineEdit>
-#include <QSettings>
+#include <QCoreApplication>
#include <QDebug>
+#include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
#define TICKETCS "TicketChecksum"
#define VOUCHERCS "VoucherChecksum"
#define INVOICECS "InvoiceChecksum"
+#define MAILCS "MailChecksum"
#define MAILCONTACTS "MailContactTypes"
+#define SHIPPING "ShippingTypes"
+#define TICKETNM "TicketName"
+#define VOUCHERNM "VoucherName"
+#define INVOICENM "InvoiceName"
//seconds between forced re-inits
#define INIT_TIMER 5*60
QList<MOContactType> MPServerConfig::mcontacttypes;
QDateTime MPServerConfig::mlastinit;
QMap<QString,QString> MPServerConfig::msettings;
+QList<MOShipping> MPServerConfig::mshiptypes;
+
+//helpers to store sets of checksum:name pairs
+static inline QString strpair2str(const QPair<QString,QString>&pair)
+{
+ QByteArray a;
+ QDataStream stream(&a,QIODevice::WriteOnly);
+ stream<<pair;
+ return QString::fromLatin1(a.toBase64());
+}
+
+static inline QString strpair2str(const QString&checksum,const QString&filename)
+{
+ return strpair2str(QPair<QString,QString>(checksum,filename));
+}
+
+static inline QPair<QString,QString> str2strpair(const QString& str)
+{
+ QByteArray a(QByteArray::fromBase64(str.toLatin1()));
+ QDataStream stream(a);
+ QPair<QString,QString>pair;
+ stream>>pair;
+ return pair;
+}
+
MPServerConfig::MPServerConfig(QWidget* parent)
:QDialog(parent)
{
setWindowTitle(tr("Print@Home Server Configuration"));
- QVBoxLayout*vl,*vl2;
+ QVBoxLayout*vl,*vl2,*vl3;
+ QHBoxLayout*hl;
setLayout(vl=new QVBoxLayout);
QFormLayout*fl;
vl->addLayout(fl=new QFormLayout);
//template for tickets
fl->addRow(tr("Ticket Template:"),mticket=new QComboBox);
+ fl->addRow(tr("Ticket File Name:"),hl=new QHBoxLayout);
+ hl->addWidget(mticketn=new QLineEdit(ticketFileName()),1);
+ hl->addWidget(new QLabel(".pdf"),0);
//template for vouchers
fl->addRow(tr("Voucher Template:"),mvoucher=new QComboBox);
+ fl->addRow(tr("Voucher File Name:"),hl=new QHBoxLayout);
+ hl->addWidget(mvouchern=new QLineEdit(voucherFileName()),1);
+ hl->addWidget(new QLabel(".pdf"),0);
//template for invoice
fl->addRow(tr("Invoice Template:"),minvoice=new QComboBox);
+ fl->addRow(tr("Invoice File Name:"),hl=new QHBoxLayout);
+ hl->addWidget(minvoicen=new QLineEdit(billFileName()),1);
+ hl->addWidget(new QLabel(".pdf"),0);
+ //template for mail
+ fl->addRow(tr("Mail Template:"),mmail=new QComboBox);
//contacts
- fl->addRow(tr("eMail Contacts:"),vl2=new QVBoxLayout);
+ QFrame*frm;
+ fl->addRow(tr("eMail Contacts:"),frm=new QFrame);
+ frm->setFrameStyle(QFrame::StyledPanel|QFrame::Plain);
+ frm->setLayout(vl2=new QVBoxLayout);
+ //shipping types
+ fl->addRow(tr("Shipping Types:"),frm=new QFrame);
+ frm->setFrameStyle(QFrame::StyledPanel|QFrame::Plain);
+ frm->setLayout(vl3=new QVBoxLayout);
//get settings
init();
//update templates
QList<MTemplate>tpl=req->templateStore()->allTemplates();
- int tp=-1,vp=-1,ip=-1;
- const QString tc=ticketTemplateCS(),vc=voucherTemplateCS(),ic=invoiceTemplateCS();
+ int tp=-1,vp=-1,ip=-1,mp=-1;
+ const QPair<QString,QString> tc=ticketTemplateCS(), vc=voucherTemplateCS(), ic=invoiceTemplateCS(), mc=mailTemplateCS();
qDebug()<<"DEFAULTS tick"<<tc<<", vouch"<<vc<<", inv"<<ic;
for(MTemplate tmp:tpl){
qDebug()<<"JFF"<<tmp.baseName()<<tmp.description()<<tmp.checksum()<<tmp.completeFileName();
if(tmp.baseName()=="ticket"){
- mticket->addItem(tmp.description(),tmp.checksum());
- if(tc==tmp.checksum())tp=mticket->count()-1;
+ mticket->addItem(tmp.description(), strpair2str(tmp.checksum(),tmp.completeFileName()));
+ if(tc.first==tmp.checksum()&&tc.second==tmp.completeFileName())
+ tp=mticket->count()-1;
}
- if(tmp.baseName()=="voucher"){
- mvoucher->addItem(tmp.description(),tmp.checksum());
- if(vc==tmp.checksum())vp=mvoucher->count()-1;
+ else if(tmp.baseName()=="voucher"){
+ mvoucher->addItem(tmp.description(), strpair2str(tmp.checksum(),tmp.completeFileName()));
+ if(vc.first==tmp.checksum()&&vc.second==tmp.completeFileName())
+ vp=mvoucher->count()-1;
}
- if(tmp.baseName()=="bill"){
- minvoice->addItem(tmp.description(),tmp.checksum());
- if(ic==tmp.checksum())ip=minvoice->count()-1;
+ else if(tmp.baseName()=="bill"){
+ minvoice->addItem(tmp.description(), strpair2str(tmp.checksum(),tmp.completeFileName()));
+ if(ic.first==tmp.checksum(),ic.second==tmp.completeFileName())
+ ip=minvoice->count()-1;
+ }
+ else if(tmp.baseName()=="printathome"){
+ mmail->addItem(tmp.description(), strpair2str(tmp.checksum(),tmp.completeFileName()));
+ if(mc.first==tmp.checksum(),mc.second==tmp.completeFileName())
+ mp=mmail->count()-1;
}
}
+ qDebug()<<"tp"<<tp<<"vp"<<vp<<"ip"<<ip<<"mp"<<mp;
mticket->setCurrentIndex(tp);
mvoucher->setCurrentIndex(vp);
minvoice->setCurrentIndex(ip);
+ mmail->setCurrentIndex(mp);
//update contacts
QList<int> mcont=mailContactTypeIds();
- qDebug()<<"DEFAULT contacts"<<mcont;
+ qDebug()<<"DEFAULT contacts"<<mcont<<mailContactTypes();
for(auto ctc:mcontacttypes){
const QString cn=ctc.contacttype();
QCheckBox*cb=new QCheckBox(cn);
vl2->addWidget(cb);
mcontacts.insert(ctc.contacttypeid(),cb);
}
-
+ //update shipping types
+ QList<int> mship=shippingIds();
+ qDebug()<<"DEFAULT shipping types"<<mship;
+ for(auto ctc:mshiptypes){
+ const QString cn=ctc.description();
+ QCheckBox*cb=new QCheckBox(cn);
+ cb->setChecked(mship.contains(ctc.shipid()));
+ vl3->addWidget(cb);
+ mshipping.insert(ctc.shipid(),cb);
+ }
+
vl->addSpacing(15);
- QHBoxLayout*hl;
vl->addLayout(hl=new QHBoxLayout);
hl->addStretch(1);
QPushButton*p;
qDebug()<<"NEW-SETTINGS"<<msettings;
mcontacttypes=req->queryGetAllContactTypes().gettypes();
+ mshiptypes=req->queryGetAllShipping().getshipping();
mlastinit=QDateTime::currentDateTime();
}
settings.append(MOKeyValuePair(TICKETCS,mticket->currentData().toString()));
settings.append(MOKeyValuePair(VOUCHERCS,mvoucher->currentData().toString()));
settings.append(MOKeyValuePair(INVOICECS,minvoice->currentData().toString()));
+ settings.append(MOKeyValuePair(MAILCS,mmail->currentData().toString()));
+ settings.append(MOKeyValuePair(TICKETNM,mticketn->text()));
+ settings.append(MOKeyValuePair(VOUCHERNM,mvouchern->text()));
+ settings.append(MOKeyValuePair(INVOICENM,minvoicen->text()));
QString mct;
for(int cid:mcontacts.keys())
if(mcontacts[cid]->isChecked())
mct+=QString("%1 ").arg(cid);
- settings.append(MOKeyValuePair(MAILCONTACTS,mct));
+ settings.append(MOKeyValuePair(MAILCONTACTS,mct.trimmed()));
+ mct.clear();
+ for(int sid:mshipping.keys())
+ if(mshipping[sid]->isChecked())
+ mct+=QString("%1 ").arg(sid);
+ settings.append(MOKeyValuePair(SHIPPING,mct.trimmed()));
qDebug()<<"SAVING"<<toMap(settings);
//save
init(true);
}
-// TODO: THIS SHOULD REALLY BE STORED ON THE SERVER AS CONFIG VALUE!!!!!!
-QString MPServerConfig::ticketTemplateCS()
+QPair<QString,QString> MPServerConfig::ticketTemplateCS()
{
init();
- return msettings.value(TICKETCS);
+ return str2strpair(msettings.value(TICKETCS));
}
-QString MPServerConfig::voucherTemplateCS()
+QPair<QString,QString> MPServerConfig::voucherTemplateCS()
{
init();
- return msettings.value(VOUCHERCS);
+ return str2strpair(msettings.value(VOUCHERCS));
}
-QString MPServerConfig::invoiceTemplateCS()
+QPair<QString,QString> MPServerConfig::invoiceTemplateCS()
{
init();
- return msettings.value(INVOICECS);
+ return str2strpair(msettings.value(INVOICECS));
+}
+
+QPair<QString,QString> MPServerConfig::mailTemplateCS()
+{
+ init();
+ return str2strpair(msettings.value(MAILCS));
}
QStringList MPServerConfig::mailContactTypes()
ret.append(s.toInt());
return ret;
}
+
+QList<int> MPServerConfig::shippingIds()
+{
+ init();
+ QList<int>ret;
+ for(auto s:msettings.value(SHIPPING).split(' ',QString::SkipEmptyParts))
+ ret.append(s.toInt());
+ return ret;
+}
+
+QString MPServerConfig::ticketFileName()
+{
+ return msettings.value(TICKETNM,QCoreApplication::translate("MPServerConfig","tickets","file name"));
+}
+
+QString MPServerConfig::voucherFileName()
+{
+ return msettings.value(VOUCHERNM,QCoreApplication::translate("MPServerConfig","vouchers","file name"));
+}
+
+QString MPServerConfig::billFileName()
+{
+ return msettings.value(INVOICENM,QCoreApplication::translate("MPServerConfig","invoice","file name"));
+}
+
+bool MPServerConfig::validateConfig()
+{
+ init();
+ //check we even have a config
+ QPair<QString,QString>
+ tc=ticketTemplateCS(),
+ vc=voucherTemplateCS(),
+ ic=invoiceTemplateCS(),
+ mc=mailTemplateCS();
+ if(tc.first.isEmpty()||vc.first.isEmpty()||ic.first.isEmpty())
+ return false;
+ //validate templates exist
+ MTemplateStore*ts=req->templateStore();
+ MTemplate tmp=ts->getTemplateByFile(tc.second);
+ if(!tmp.isValid()||tmp.checksum()!=tc.first)return false;
+ tmp=ts->getTemplateByFile(vc.second);
+ if(!tmp.isValid()||tmp.checksum()!=vc.first)return false;
+ tmp=ts->getTemplateByFile(ic.second);
+ if(!tmp.isValid()||tmp.checksum()!=ic.first)return false;
+ tmp=ts->getTemplateByFile(mc.second);
+ if(!tmp.isValid()||tmp.checksum()!=mc.first)return false;
+ //validate contacts exist
+ for(int id:mailContactTypeIds()){
+ bool found=false;
+ for(const MOContactType &ct:mcontacttypes)
+ if(ct.contacttypeid()==id){
+ found=true;
+ break;
+ }
+ if(!found)return false;
+ }
+ //validate shipping types
+ for(int id:shippingIds()){
+ bool found=false;
+ for(const MOShipping&st:mshiptypes)
+ if(st.shipid()==id){
+ found=true;
+ break;
+ }
+ if(!found)return false;
+ }
+ //done
+ return true;
+}
#include <QMap>
#include <QList>
#include <QDateTime>
+#include <QPair>
#include "MOContactType"
+#include "MOShipping"
class QCheckBox;
class QLineEdit;
public:
MPServerConfig(QWidget*parent=nullptr);
+ ///returns all contact types that are mail addresses
static QStringList mailContactTypes();
+ ///returns the IDs of all contact types that are mail addresses
static QList<int> mailContactTypeIds();
+
+ ///returns the IDs of shipping types used for PrintAtHome
+ static QList<int> shippingIds();
+
+ ///returns true if the server configuration is consistent
+ static bool validateConfig();
+
+ ///returns the template name for tickets
+ static QString ticketTemplateName(){return ticketTemplateCS().second;}
+ ///returns the template name for vouchers
+ static QString voucherTemplateName(){return voucherTemplateCS().second;}
+ ///returns the template name for bills
+ static QString billTemplateName(){return invoiceTemplateCS().second;}
+ ///returns the template name for mails
+ static QString mailTemplateName(){return mailTemplateCS().second;}
+
+ ///returns the name under which the ticket PDF should be stored on the server
+ static QString ticketFileName();
+ ///returns the name under which the voucher PDF should be stored on the server
+ static QString voucherFileName();
+ ///returns the name under which the bill/invoice PDF should be stored on the server
+ static QString billFileName();
public slots:
void save();
private:
- QComboBox*mticket,*mvoucher,*minvoice;
- QMap<int,QCheckBox*>mcontacts;
+ QComboBox*mticket,*mvoucher,*minvoice,*mmail;
+ QLineEdit*mticketn,*mvouchern,*minvoicen;
+ QMap<int,QCheckBox*>mcontacts,mshipping;
static QMap<QString,QString>msettings;
static QList<MOContactType>mcontacttypes;
+ static QList<MOShipping>mshiptypes;
static QDateTime mlastinit;
- static QString ticketTemplateCS();
- static QString voucherTemplateCS();
- static QString invoiceTemplateCS();
+ static QPair<QString,QString> ticketTemplateCS();
+ static QPair<QString,QString> voucherTemplateCS();
+ static QPair<QString,QString> invoiceTemplateCS();
+ static QPair<QString,QString> mailTemplateCS();
static void init(bool force=false);
};
#include "payedit.h"
#include "templates.h"
#include "ticketrender.h"
+#include "billrender.h"
#include "MOEvent"
#include "MTCancelOrder"
updateData();
}
//print bill
- initPrintBuffer();
- MOdtSignalRenderer rend(tf);
- connect(&rend,SIGNAL(getVariable(QString,QVariant&)), this,SLOT(getVariable(QString,QVariant&)));
- connect(&rend,SIGNAL(getLoopIterations(QString,int&)), this,SLOT(getLoopIterations(QString,int&)));
- connect(&rend,SIGNAL(setLoopIteration(QString,int)), this,SLOT(setLoopIteration(QString,int)));
+ MBillRenderer rend(m_order, tf);
rend.renderToPrinter();
- donePrintBuffer();
}
void MOrderWindow::saveBill()
updateData();
}
//render bill
- initPrintBuffer();
- MOdtSignalRenderer rend(tf);
- connect(&rend,SIGNAL(getVariable(QString,QVariant&)), this,SLOT(getVariable(QString,QVariant&)));
- connect(&rend,SIGNAL(getLoopIterations(QString,int&)), this,SLOT(getLoopIterations(QString,int&)));
- connect(&rend,SIGNAL(setLoopIteration(QString,int)), this,SLOT(setLoopIteration(QString,int)));
+ MBillRenderer rend(m_order, tf);
rend.renderToFile(fname);
- donePrintBuffer();
-}
-
-void MOrderWindow::getVariable(QString vn,QVariant&value)
-{
- if(vn=="ORDERDATE"){
- value=m_order.ordertime().value();
- }else
- if(vn=="ORDERDATETIME"){
- value=m_order.ordertime().value();
- }else
- if(vn=="SENTDATE"){
- value=m_order.senttime().value();
- }else
- if(vn=="SENTDATETIME"){
- value=m_order.senttime().value();
- }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.fullInvoiceAddress();else
- if(vn=="FULLADDRESS")value=m_order.fullInvoiceAddress();else
- if(vn=="NAME")value=m_order.customer().value().fullName();else
- if(vn=="DELIVERYADDRESS")value=m_order.fullDeliveryAddress();else
- if(vn=="FINALADDRESS")value=m_order.fullDeliveryAddress();else
- if(vn=="TOTALPRICE"){
- value=m_order.totalprice().value();
- }else
- if(vn=="AMOUNTPAID"){
- value=m_order.amountpaid().value();
- }else
- if(vn=="SELLER")value=m_order.soldby().value();else
- if(vn=="COMMENT")value=m_order.comments().value();else
- if(vn=="AMOUNTTOPAY"){
- value=m_order.amountToPay();
- }else
- if(vn=="AMOUNTTOREFUND"){
- value=m_order.amountToRefund();
- }else
- if(vn=="TICKETS"){
- value=printBuffer.tickets.size();
- }else
- if(vn=="ACCTICKETS"){
- value=printBuffer.tickinfo.size();
- }else
- if(vn=="VOUCHERS"){
- value=printBuffer.vouchers.size();
- }else
- if(vn=="ADDRESSLINES"){
- value=m_order.fullInvoiceAddress().split("\n").size();
- }else
- if(vn=="SHIPPING")value=m_order.shippingtype().value().description().value();else
- if(vn=="SHIPPINGPRICE"){
- value=m_order.shippingtype().value().cost().value();
- }else{
- if(vn.contains(':')){
- QStringList sl=vn.split(':');
- int it=-1;
- if(m_loopiter.contains(sl[0]))it=m_loopiter[sl[0]];
- getLoopVariable(sl[0],it,sl[1],value);
- }
- }
-// qDebug()<<"got variable"<<vn<<"value"<<value;
-}
-
-void MOrderWindow::getLoopIterations(QString loopname,int&iterations)
-{
- if(loopname=="TICKETS")iterations=printBuffer.tickets.size();
- if(loopname=="ACCTICKETS")iterations=printBuffer.tickinfo.size();
- if(loopname=="VOUCHERS")iterations=printBuffer.vouchers.size();
- if(loopname=="ADDRESSLINES")iterations=m_order.fullInvoiceAddress().split("\n").size();
-// qDebug()<<"loop"<<loopname<<"has"<<iterations<<"iterations";
-}
-
-void MOrderWindow::setLoopIteration(QString loopname, int iteration)
-{
-// qDebug()<<"setting loop iter"<<loopname<<iteration;
- int max=-1;
- if(iteration<0)return;
- getLoopIterations(loopname,max);
- if(iteration>=max)return;
- m_loopiter.insert(loopname,iteration);
-}
-
-
-void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,QVariant&value)
-{
- if(loopname=="TICKETS"){
- QList<MOTicket> &tickets=printBuffer.tickets;
- if(it<0 || it>=tickets.size())return;
-
- if(vn=="PRICE"){
- value=tickets[it].price().value();
- }else
- if(vn=="ID")value=tickets[it].ticketid().value();else
- if(vn=="TITLE")value=tickets[it].event().title().value();else
- if(vn=="ARTIST")value=tickets[it].event().artist().value().name().value();else
- if(vn=="DATE"){
- value=tickets[it].event().start().value();
- }else
- if(vn=="STARTTIME"){
- value=tickets[it].event().start().value();
- }else
- if(vn=="ENDTIME"){
- value=tickets[it].event().end().value();
- }else
- if(vn=="ROOM")value=tickets[it].event().room().value();
- }else if(loopname=="ACCTICKETS"){
- QList<TickInfo> &tickets=printBuffer.tickinfo;
- if(it<0 || it>=tickets.size())return;
-
- if(vn=="PRICE"){
- value=tickets[it].proto.price().value();
- }else
- if(vn=="FULLPRICE"){
- value=tickets[it].proto.price().value()*tickets[it].amount;
- }else
- if(vn=="TITLE")value=tickets[it].proto.event().title().value();else
- if(vn=="ARTIST")value=tickets[it].proto.event().artist().value().name().value();else
- if(vn=="DATE"){
- value=tickets[it].proto.event().start().value();
- }else
- if(vn=="STARTTIME"){
- value=tickets[it].proto.event().start().value();
- }else
- if(vn=="ENDTIME"){
- value=tickets[it].proto.event().end().value();
- }else
- if(vn=="ROOM")value=tickets[it].proto.event().room().value();else
- if(vn=="AMOUNT"){
- value=tickets[it].amount;
- }
- }else if(loopname=="VOUCHERS"){
- if(it<0 || it>=printBuffer.vouchers.size())return;
-
- if(vn=="PRICE"){
- value=printBuffer.vouchers[it].price().value();
- }else
- if(vn=="VALUE"){
- value=printBuffer.vouchers[it].value().value();
- }else
- if(vn=="ID")value=printBuffer.vouchers[it].voucherid().value();
- }else if(loopname=="ADDRESSLINES"){
- QStringList lst=m_order.fullInvoiceAddress().split("\n");
- if(it<0 || it>=lst.size())return;
- value=lst[it];
- }else
- return /*empty handed*/;
-}
-
-void MOrderWindow::donePrintBuffer()
-{
- printBuffer.tickets.clear();
- printBuffer.vouchers.clear();
- printBuffer.tickinfo.clear();
-}
-
-static inline bool compare(const MOTicket&a,const MOTicket&b)
-{
- if(a.eventid()!=b.eventid())return false;
- if(a.price()!=b.price())return false;
- return true;
-}
-
-void MOrderWindow::initPrintBuffer()
-{
- //clear
- donePrintBuffer();
- //get tickets (only valid ones, only those that are to be paid)
- QList<MOTicket>tlst=m_order.tickets();
- for(int i=0;i<tlst.size();i++)
- if(!tlst[i].ticketid().isNull() && (tlst[i].status()&MOTicket::MaskPay)!=0){
- printBuffer.tickets.append(tlst[i]);
- }
- //accumulated view on tickets
- for(int i=0;i<printBuffer.tickets.size();i++){
- MOTicket t=printBuffer.tickets[i];
- bool found=false;
- for(int j=0;j<printBuffer.tickinfo.size();j++){
- if(compare(printBuffer.tickinfo[j].proto,t)){
- found=true;
- printBuffer.tickinfo[j].amount++;
- break;
- }
- }
- if(!found)printBuffer.tickinfo.append(t);
- }
- //get valid vouchers
- QList<MOVoucher>vlst=m_order.vouchers();
- for(int i=0;i<vlst.size();i++)
- if(vlst[i].price()>0||vlst[i].value()>0)
- printBuffer.vouchers.append(vlst[i]);
}
void MOrderWindow::payment()
void printBill();
/**save the bill as file*/
void saveBill();
- /**callback for bill generator: variables; see MOdtSignalRenderer for details*/
- void getVariable(QString,QVariant&);
- /**callback for bill generator: loops; see MOdtSignalRenderer for details*/
- void getLoopIterations(QString loopname,int&iterations);
- /**callback to set values of a specific loop iteration*/
- void setLoopIteration(QString loopname,int iteration);
- /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/
- void getLoopVariable(QString,int,QString,QVariant&);
/**received payment*/
void payment();
QAction*m_res2order,*m_cancel,*m_ship,*m_pay,*m_payv,*m_refund;
QMap<QString,int>m_loopiter;
QString m_testTemplate;
-
- //printing buffer
- struct TickInfo{
- TickInfo(const MOTicket&t):proto(t){amount=1;}
- TickInfo(const TickInfo&t):proto(t.proto){amount=t.amount;}
- TickInfo(){amount=0;}
- MOTicket proto;
- int amount;
- };
- struct PrintBuffer{
- QList<MOTicket> tickets;
- QList<MOVoucher> vouchers;
- QList<TickInfo> tickinfo;
- }printBuffer;
- void initPrintBuffer();
- void donePrintBuffer();
};
class MTicketRenderer;
--- /dev/null
+../../icons/arrows/arrowdiag.png
\ No newline at end of file
--- /dev/null
+../../icons/arrows/arrowdown.png
\ No newline at end of file
--- /dev/null
+../../icons/arrows/arrowleft.png
\ No newline at end of file
--- /dev/null
+../../icons/arrows/arrowright.png
\ No newline at end of file
--- /dev/null
+../../icons/arrows/arrowup.png
\ No newline at end of file
--- /dev/null
+../../icons/misc/cancel.png
\ No newline at end of file
--- /dev/null
+../../icons/misc/done.png
\ No newline at end of file
--- /dev/null
+../../icons/logo/icon.png
\ No newline at end of file
--- /dev/null
+../../icons/misc/next.png
\ No newline at end of file
--- /dev/null
+../../icons/misc/prev.png
\ No newline at end of file
--- /dev/null
+../../icons/misc/separator.png
\ No newline at end of file
<Property name="amountdue" type="int">amount that needs to be paid, negative if too much has been paid</Property>
<Property name="totalprice" type="int">total price for this order (including shipping and all items)</Property>
<Property name="shippingcosts" type="int">costs for shipping</Property>
-
+ <Property name="shippingtypeid" type="int"/>
+
<Property name="ordertime" type="int64"/>
<Property name="senttime" type="int64"/>
<!-- etc.pp. -->
<Map column="senttime"/>
<Map column="amountpaid"/>
<Map column="shippingcosts"/>
-
+ <Map column="shippingtype" property="shippingtypeid"/>
+
<Map property="totalprice">
<Call lang="php" method="$data->getTotalPriceFromDB()"/>
</Map>
<Map column="flags"/>
</Mapping>
</Class>
+
+ <Class name="OrderDocument">
+ <Doc>This class represents a document stored for a specific order.</Doc>
+ <Property name="fileid" type="int64">Informational: internal file ID</Property>
+ <Property name="orderid" type="int64">The order it belongs to.</Property>
+ <Property name="filename" type="string">The file name of the document.</Property>
+ <Property name="mtime" type="int64">Modification Time</Property>
+ <Property name="rtime" type="int64">Web Retrieval Time</Property>
+ <Property name="content" type="blob">File Content</Property>
+ <Property name="visible" type="bool">True if the file is visible for the customer</Property>
+ <Mapping table="orderdocuments">
+ <Map column="fileid"/>
+ <Map column="orderid"/>
+ <Map column="filename"/>
+ <Map column="mtime"/>
+ <Map column="rtime"/>
+ <Map column="content"/>
+ <Map column="visible"/>
+ </Mapping>
+ </Class>
+ <Class name="OrderDocumentInfo">
+ <Doc>
+ This class represents a document stored for a specific order without the
+ actual content blob.
+ </Doc>
+ <Property name="fileid" type="int64">Informational: internal file ID</Property>
+ <Property name="orderid" type="int64">The order it belongs to.</Property>
+ <Property name="filename" type="string">The file name of the document.</Property>
+ <Property name="mtime" type="int64">Modification Time</Property>
+ <Property name="rtime" type="int64">Web Retrieval Time</Property>
+ <Property name="visible" type="bool">True if the file is visible for the customer</Property>
+ <Mapping table="orderdocuments">
+ <Map column="fileid"/>
+ <Map column="orderid"/>
+ <Map column="filename"/>
+ <Map column="mtime"/>
+ <Map column="rtime"/>
+ <Map column="visible"/>
+ </Mapping>
+ </Class>
</Wolf>
<Input>
<Var name="orderid" type="int"/>
</Input>
- <Call lang="php" method="WOOrder::getOrderDocuments($this);"/>
+ <Call lang="php" method="WOOrder::getOrderDocumentNames($this);"/>
<Output>
- <Var name="filename" type="List:string"/>
+ <Var name="documentinfo" type="List:OrderDocumentInfo"/>
</Output>
</Transaction>
<Transaction name="GetOrderDocument" update="no">
</Input>
<Call lang="php" method="WOOrder::getOrderDocument($this);"/>
<Output>
- <Var name="content" type="blob"/>
- <Var name="visible" type="bool"/>
- <Var name="mtime" type="int64"/>
- <Var name="rtime" type="int64"/>
+ <Var name="document" type="OrderDocument"/>
</Output>
</Transaction>
<Transaction name="SetOrderDocument" update="yes">
<Doc>Stores a document associated with an order. Overwrites the document if it already exists, creates it otherwise.</Doc>
<Input>
- <Var name="orderid" type="int"/>
- <Var name="filename" type="string"/>
- <Var name="content" type="blob"/>
- <Var name="visible" type="bool"/>
+ <Var name="document" type="OrderDocument">
+ The document to be set.
+ Hint: the fileid is ignored, matching happens through orderid and filename.
+ </Var>
</Input>
- <Call lang="php" method="WOOrder::getOrderDocument($this);"/>
+ <Call lang="php" method="WOOrder::setOrderDocument($this);"/>
<Output/>
</Transaction>
<Transaction name="DeleteOrderDocument" update="yes">
<Var name="orderid" type="int"/>
<Var name="filename" type="string"/>
</Input>
- <Call lang="php" method="WOOrder::getOrderDocument($this);"/>
+ <Call lang="php" method="WOOrder::deleteOrderDocument($this);"/><!-- TODO -->
<Output/>
</Transaction>
<Doc>Sends an eMail to a customer. Usually to update the customer about Order data.</Doc>
<Input>
<Var name="customerid" type="int">ID of the customer. Must be given! The mail address associated with the account is used.</Var>
- <Var name="cc" type="List:string">Additional Cc addresses - usually extracted from the customer contact information.</Var>
- <Var name="content" type="blob">Content of the eMail.</Var>
+ <Var name="content" type="string">Content of the eMail.</Var>
</Input>
- <Call lang="php" method=";"/><!-- TODO -->
+ <Call lang="php" method="WOCustomer::sendMail($this);"/>
<Output/>
</Transaction>
<Transaction name="GetPrintAtHomeSettings" update="no">
<Doc>Gets all settings pertaining to Print@Home</Doc>
<Input/>
- <Call lang="php" method="WOOrder::getPrintAtHomeSettings($this);"/><!-- TODO -->
+ <Call lang="php" method="WOOrder::getPrintAtHomeSettings($this);"/>
<Output>
<Var name="settings" type="List:KeyValuePair"/>
</Output>
<Input>
<Var name="settings" type="List:KeyValuePair"/>
</Input>
- <Call lang="php" method="WOOrder::setPrintAtHomeSettings($this);"/><!-- TODO -->
+ <Call lang="php" method="WOOrder::setPrintAtHomeSettings($this);"/>
<Output/>
</Transaction>
</Wolf>
//create engine: server-host, user, password
-$db = new MysqlEngine("localhost","smoke","");
+$db = new MysqlEngine("192.168.1.5","smoke","");
//set database name
//$db->setDbName("smoke2");
$db->setDbName("DB396352");
were listed as being in the public domain.
The Logo (logo.png) is under the same license as the rest of the documentation,
-see the global README file for details.
\ No newline at end of file
+see the global README file for details.
+
+The maintenance.png Icon was copied from the KDE Oxygen Icon Theme and is
+distributed under the GNU LGPL v3 or any newer. Its original file name was
+preferences-system.png.
--- /dev/null
+../../icons/arrows/arrowdown.png
\ No newline at end of file
--- /dev/null
+../../icons/wikipedia/de.png
\ No newline at end of file
--- /dev/null
+../../icons/wikipedia/en.png
\ No newline at end of file
--- /dev/null
+../../icons/oxygen/preferences-system.png
\ No newline at end of file
redirectHome(array("mode"=>"checkout"));
}
+ ///callback for the GetCreateCustomerHints transaction
static public function createHints($trans)
{
$trans->setcontacttypes( WOContactType::fromTableArraycontacttype( WTcontacttype::selectFromDB()));
$trans->setstates($rs);
}
}
+
+ ///callback for the SendCustomerMail transaction
+ static public function sendMail($trans)
+ {
+ //get customer basics
+ $ct=WTcustomer::getFromDB($trans->getcustomerid());
+ if(!is_a($ct,"WTcustomer")){
+ return;
+ }
+ if(!isEmail($ct->email)){
+ return;
+ }
+ //parse mail
+ $page=explode("\n",trim($trans->getcontent()));
+ if(count($page)<2)return;
+ $subject=array_shift($page);
+ $mode=0;
+ $mailtext="";$mailheader="";
+ foreach($page as $line){
+ if($mode==0){
+ if(trim($line)=="")$mode=1;
+ else $mailheader.=$line."\n";
+ }else{
+ $mailtext.=$line."\n";
+ }
+ }
+ //send mail
+ mail($ct->email,$subject,$mailtext,$mailheader);
+
+ }
};
//eof
$res=array();
$cfg=WTconfig::selectFromDB();
foreach($cfg as $c) {
- if(strncmp($c->ckey,"printathome:",12)==0)
- $r=new WOKeyValuePair();
+ if(strncmp($c->ckey,"printathome:",12)==0){
+ $r=new WOKeyValuePair;
$r->setkey(substr($c->ckey,12));
$r->setvalue($c->cval);
$res[]=$r;
+ }
}
$trans->setsettings($res);
}
}
+
+ static public function getOrderDocumentNames($trans)
+ {
+ global $db;
+ $q="orderid=".$db->escapeInt($trans->getorderid());
+ $trans->setdocumentinfo(WOOrderDocumentInfo::fromTableArrayorderdocuments(
+ WTorderdocuments::selectFromDB($q)));
+ }
+
+ static public function getOrderDocument($trans)
+ {
+ global $db;
+ $q="orderid=".$db->escapeInt($trans->getorderid())." AND filename=".
+ $db->escapeString($trans->getfilename());
+ $tab=WTorderdocuments::selectFromDB($q);
+ if(count($tab)>0)
+ $trans->setdocument(WOOrderDocument::fromTableorderdocuments($tab[0]));
+ }
+
+ static public function setOrderDocument($trans)
+ {
+ global $db;
+ $doc=$trans->getdocument();
+ $q="orderid=".$db->escapeInt($doc->getorderid())." AND filename=".
+ $db->escapeString($doc->getfilename());
+ $tab=WTorderdocuments::selectFromDB($q);
+ if(count($tab)>0)
+ $nrow=$tab[0];
+ else
+ $nrow=WTorderdocuments::newRow(array(
+ "orderid"=>$doc->getorderid(),
+ "filename"=>$doc->getfilename()
+ ));
+ $nrow->content=$doc->getcontent();
+ $nrow->mtime=time();
+ $nrow->visible=$doc->getvisible();
+ $nrow->insertOrUpdate();
+ }
};
// protected under the GNU AGPL version 3 or at your option any newer
// see COPYING.AGPL
+//bail out during maintenance
+if(file_exists("maintenance.php")){
+ include("maintenance.php");
+ die("<!-- Maintenance! -->");
+}
+
//basics
include('inc/loader.php');
include('inc/loader_nonadmin.php');
// protected under the GNU AGPL version 3 or at your option any newer
// see COPYING.AGPL
+//check for maintenance mode
+if(file_exists("maintenance.php"))
+ die("<!-- Sorry, Down For Maintenance! -->");
+
//fix content-type to something that is not manipulated by proxies
header("Content-Type: application/x-MagicSmoke");
--- /dev/null
+<?php
+ /* RENAME THIS FILE TO maintenance.php IF YOU WANT MAGICSMOKE TO STOP ANSWERING.
+ * THIS WILL DISABLE BOTH THE USER/CUSTOMER FACING WEB SITE AS WELL AS THE MACHINE INTERFACE.
+ * THE ADMINISTRATIVE PAGE admin.php IS UNAFFECTED.
+ * THE HTML CODE BELOW IS SHOWN ON THE USER/CUSTOMER FACING WEB SITE INSTEAD OF THE USUAL
+ * RENDERING OF MAGICSMOKE DATA.
+ */
+?>
+<html>
+<title>Maintenance</title>
+<body>
+<img src="images/maintenance.png" align="left"/>
+<img src="images/maintenance.png" align="right"/>
+<h1>Sorry, down for Maintenance</h1>
+
+<p>We are currently executing important maintenance tasks to make your experience as good as possible.
+We are trying our best to make this maintenance window as short as possible.</p>
+
+<p><b>Please return in one or two hours.</b></p>
+
+<h1>Wir führen gerade Wartungsarbeiten durch</h1>
+
+<p>...damit unsere Webseite so gut wie möglich für Sie funktioniert. Wir versuchen unser
+bestes den Ausfall so kurz wie möglich zu gestalten.</p>
+
+<p><b>Bitte kommen Sie in ein bis zwei Stunden wieder.</b></p>
+
+</body>
+</html>
subsequent lines contain the headers, then an empty line
and after that the body of the mail.
#}
-Order {{order.orderid}} Details at MagicSmoke.silmor.de
-From: no-reply@localdomain.com
+Order {{order.orderid}} Details at MagicSmoke.silmor.de
+From: no-reply@localhost
+Bcc: info@localhost
Content-Type: multipart/alternative; boundary="------boundary-aYAmoTT04MIpviI"
MIME-Version: 1.0