Logo Search packages:      
Sourcecode: lemonpos-kde4 version File versions  Download package

lemonview.cpp

/***************************************************************************
 *   Copyright (C) 2007 by Miguel Chavez Gamboa                            *
 *   miguel.chavez.gamboa@gmail.com                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *

 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include "lemonview.h"
#include "settings.h"
#include "inputdialog.h"
#include "productdelegate.h"

//StarMicronics printers
// #include "printers/sp500.h"

#include <QWidget>
#include <QStringList>
#include <QTimer>
#include <QColor>
#include <QPixmap>
#include <QHeaderView>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QInputDialog>
#include <QTextCodec>
#include <QRegExp>
#include <QRegExpValidator>
#include <QValidator>
#include <QGridLayout>
#include <QDesktopWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QTextDocument>
#include <QTextEdit>
#include <QPushButton>

#include <klocale.h>
#include <kpassworddialog.h>
#include <kiconloader.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>


/* Widgets zone                                                                                                         */
/*======================================================================================================================*/


class TicketPopup : public QFrame
{
  private:
    QGridLayout *gridLayout;
    QLabel *imagelabel;
    QTextEdit *editText;
    QTimer *timer;

  public:
    TicketPopup(QWidget *parent=0, QString text="", QPixmap pixmap=0, int timeToClose=1000)
    {
      setFrameStyle(QFrame::StyledPanel|QFrame::Raised);
      setMidLineWidth(2);
      setWindowFlags(Qt::Popup);
      setObjectName("main");

      gridLayout = new QGridLayout(this);
      imagelabel = new QLabel(this);
      imagelabel->setPixmap(pixmap);
      imagelabel->setAlignment(Qt::AlignCenter);
      gridLayout->addWidget(imagelabel, 0, 0);
      editText = new QTextEdit(this);
      editText->setHtml(text);
      editText->setReadOnly(true);
      gridLayout->addWidget(editText, 1, 0);
      gridLayout->setMargin(17);

      timer = new QTimer(this);
      timer->setInterval(timeToClose);
      connect(timer, SIGNAL(timeout()), this, SLOT(close()));

      //Working on non rectangular dialogs...
      //With this, and compiz.. no shadow is drawn... But, who wants compiz on a production box?
      QString path = KStandardDirs::locate("appdata", "images/");
      QString filen = path + "/imgPrint.png";
      QPixmap pix(filen);
      setMask(pix.mask());
      QString st;
      st = QString("QFrame#main { background-image: url(%1);}").arg(filen);
      setStyleSheet(st);
    }
    void setPixmap(QPixmap pixmap) { imagelabel->setPixmap(pixmap); }
    void popup()
    {
      //NOTE: Why before show() the frameGeometry is bigger, and after showing it, it resizes itself?
      move(2000,2000);
      show();
      int x = (QApplication::desktop()->width()/2 )-(frameGeometry().width()/2);
      int y = (QApplication::desktop()->height()/2)-(frameGeometry().height()/2);
      setGeometry(x,y,335,340);
      timer->start();
    }
};

class BalanceDialog : public QDialog
{
  private:
    QGridLayout *gridLayout;
    QTextEdit *editText;
    QPushButton *buttonClose;

  public:
    BalanceDialog(QWidget *parent=0, QString str="")
    {
      setWindowFlags(Qt::Dialog|Qt::FramelessWindowHint);
      setWindowModality(Qt::ApplicationModal);

      gridLayout = new QGridLayout(this);
      editText = new QTextEdit(str);
      editText->setReadOnly(true);
      editText->setMinimumSize(QSize(320,450));
      gridLayout->addWidget(editText, 0, 0);
      buttonClose = new QPushButton(this);
      buttonClose->setText(i18n("Continue"));
      buttonClose->setDefault(true);
      buttonClose->setShortcut(Qt::Key_Enter);
      gridLayout->addWidget(buttonClose, 1,0);

      connect(buttonClose, SIGNAL(clicked()), this, SLOT(close()));
      //connect(buttonClose, SIGNAL(clicked()), parent, SLOT(slotDoStartOperation()));
    }
    virtual void paint(QPainter *) {}
  protected:
    void paintEvent(QPaintEvent *e)
    {
      QPainter painter;
      painter.begin(this);
      painter.setClipRect(e->rect());
      painter.setRenderHint(QPainter::Antialiasing);

      paint(&painter);
      painter.restore();
      painter.save();
      int level = 180;
      painter.setPen(QPen(QColor(level, level, level), 6));
      painter.setBrush(Qt::NoBrush);
      painter.drawRect(rect());
    }

};


void lemonView::cancelByExit()
{
  clearUsedWidgets();
  refreshTotalLabel();
  preCancelCurrentTransaction();
  db.close();
}

lemonView::lemonView(QWidget *parent) //: QWidget(parent)
{
  ui_mainview.setupUi(this);
  dlgLogin = new LoginWindow(this,
                             i18n("Welcome to Lemon"),
                             i18n("Enter username and password to start using the system."),
                             LoginWindow::FullScreen);
  dlgPassword = new LoginWindow(this,
                             i18n("Authorisation Required"),
                             i18n("Enter administrator password please."),
                             LoginWindow::PasswordOnly);
  settingsChanged();
  QTimer::singleShot(1000, this, SLOT(setupDB()));
  setAutoFillBackground(true);
  QTimer::singleShot(1100, this, SLOT(login()));
  QTimer *timerClock = new QTimer(this);


  //Signals
  connect(timerClock, SIGNAL(timeout()), SLOT(timerTimeout()) );
  connect(ui_mainview.editItemDescSearch, SIGNAL(returnPressed()), this, SLOT(doSearchItemDesc()));
  //TODO: Next line needs to be adapted for future. How are we going to receive barcode reader string?
  connect(ui_mainview.editItemCode, SIGNAL(returnPressed()), this, SLOT(doEmitSignalQueryDb()));
  connect(this, SIGNAL(signalQueryDb(QString)), this, SLOT(insertItem(QString)) );
  connect(ui_mainview.tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), SLOT(itemDoubleClicked(QTableWidgetItem*)) );
  connect(ui_mainview.tableSearch, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), SLOT(itemSearchDoubleClicked(QTableWidgetItem*)) );
  connect(ui_mainview.tableWidget, SIGNAL(itemClicked(QTableWidgetItem*)), SLOT(displayItemInfo(QTableWidgetItem*)));
  //connect(ui_mainview.listView, SIGNAL(activated(const QModelIndex &)), SLOT(listViewOnClick(const QModelIndex &)));
  connect(ui_mainview.listView, SIGNAL(clicked(const QModelIndex &)), SLOT(listViewOnClick(const QModelIndex &)));
  connect(ui_mainview.listView, SIGNAL(entered(const QModelIndex &)), SLOT(listViewOnMouseMove(const QModelIndex &)));
  connect(ui_mainview.buttonSearchDone, SIGNAL(clicked()), SLOT(buttonDone()) );
  connect(ui_mainview.checkCard, SIGNAL(toggled(bool)), SLOT(checksChanged())  );
  connect(ui_mainview.checkCash, SIGNAL(toggled(bool)), SLOT(checksChanged())  );
  connect(ui_mainview.editAmount,SIGNAL(returnPressed()), SLOT(finishCurrentTransaction()) );
  connect(ui_mainview.editAmount, SIGNAL(textChanged(const QString &)), SLOT(refreshTotalLabel()));
  connect(ui_mainview.editCardNumber, SIGNAL(returnPressed()), SLOT(goSelectCardAuthNumber()) );
  connect(ui_mainview.editCardAuthNumber, SIGNAL(returnPressed()), SLOT(finishCurrentTransaction()) );
  connect(ui_mainview.splitter, SIGNAL(splitterMoved(int, int)), SLOT(setUpTable()));
  connect(ui_mainview.comboClients, SIGNAL(currentIndexChanged(int)), SLOT(comboClientsOnChange()));

  timerClock->start(1000);
  drawer = new Gaveta();
  operationStarted = false;
  productsHash.clear();
  clientsHash.clear();
  ui_mainview.lblClientPhoto->hide();

  clearUsedWidgets();
  loadIcons();
  setUpInputs();
  QTimer::singleShot(500, this, SLOT(setUpTable()));
  ui_mainview.groupWidgets->setCurrentIndex(pageMain);
  //FIXME::
  if (Settings::showGrid()) showProductsGrid(true); else showProductsGrid(false);
}

void lemonView::loadIcons()
{
  ui_mainview.labelImageSearch->setPixmap(DesktopIcon("edit-find", 64));
  QString logoBottomFile = KStandardDirs::locate("appdata", "images/logo_bottom.png");
  ui_mainview.labelStoreImage->setPixmap(QPixmap(Settings::editLogoFileName()));
  ui_mainview.labelBanner->setPixmap(QPixmap(logoBottomFile));
  ui_mainview.labelStoreImage->setAlignment(Qt::AlignCenter);
  ui_mainview.labelBanner->setAlignment(Qt::AlignCenter);
}

void lemonView::setUpTable()
{
  QSize tableSize = ui_mainview.tableWidget->size();
  int portion = tableSize.width()/10;
  ui_mainview.tableWidget->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colCode, portion); //BAR CODE
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colDesc, (portion*4)+9); //DESCRIPTION
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colPrice, portion); //PRICE
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colQty, portion-20);  //QTY
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colUnits, portion-15);//UNITS
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colDisc, portion); //Discount
  ui_mainview.tableWidget->horizontalHeader()->resizeSection(colDue, portion+10); //DUE
  //search table
  tableSize = ui_mainview.tableSearch->size();
  ui_mainview.tableSearch->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
  ui_mainview.tableSearch->horizontalHeader()->resizeSection(0, tableSize.width()-5);
  ui_mainview.tableSearch->horizontalHeader()->resizeSection(1, 50);
  ui_mainview.tableSearch->horizontalHeader()->resizeSection(2,50);
}

void lemonView::setUpInputs()
{
  //TODO: Tratar de poner un filtro con lugares llenos de ceros, e ir insertando los numeros.
  //For amount received.
  QRegExp regexpA("[0-9]*[//.]*[0-9][0-9]*"); //Cualquier numero flotante (0.1, 100, 0, .10, 100.0, 12.23)
  QRegExpValidator * validatorFloat = new QRegExpValidator(regexpA,this);
  ui_mainview.editAmount->setValidator(validatorFloat);
  //Item code (to insert)
  QRegExp regexpC("[0-9]{1,13}"); //(EAN-13 y EAN-8) .. y productos sin codigo de barras?
  QRegExpValidator * validatorEAN13 = new QRegExpValidator(regexpC, this);
  ui_mainview.editItemCode->setValidator(validatorEAN13);
  QRegExp regexpAN("[A-Za-z_0-9\\\\/\\-]+");//any letter, number, both slashes, dash and lower dash.
  QRegExpValidator *regexpAlpha = new QRegExpValidator(regexpAN, this);
  ui_mainview.editCardAuthNumber->setValidator(regexpAlpha);
}

void lemonView::timerTimeout()
{
  emit signalUpdateClock();
}

void lemonView::clearLabelPayMsg()
{
  ui_mainview.labelPayMsg->clear();
}

void lemonView::clearLabelInsertCodeMsg()
{
  ui_mainview.labelInsertCodeMsg->clear();
}

void::lemonView::clearLabelSearchMsg()
{
  ui_mainview.labelSearchMsg->clear();
}

void lemonView::setTheSplitterSizes(QList<int> s)
{
  ui_mainview.splitter->setSizes(s);
}

QList<int> lemonView::getTheSplitterSizes()
{
  return ui_mainview.splitter->sizes();
}

void lemonView::settingsChanged()
{
  //Store Logo
  ui_mainview.labelStoreImage->setPixmap(QPixmap(Settings::editLogoFileName()));
  //Total label (and currency label)
  refreshTotalLabel();
}

00311 void lemonView::showEnterCodeWidget()
{
  ui_mainview.groupWidgets->setCurrentIndex(pageMain);
  ui_mainview.editItemCode->setFocus();
  setUpTable();
}

00318 void lemonView::showSearchItemWidget()
{
  ui_mainview.groupWidgets->setCurrentIndex(pageSearch); // searchItem
  ui_mainview.editItemDescSearch->setFocus();
}

void lemonView::buttonDone()
{
  ui_mainview.tableSearch->setRowCount(0);
  ui_mainview.labelSearchMsg->setText("");
  ui_mainview.editItemDescSearch->setText("");
  ui_mainview.editItemCode->setCursorPosition(0);
  ui_mainview.groupWidgets->setCurrentIndex(0); // back to welcome widget
}

void lemonView::checksChanged()
{
  if (ui_mainview.checkCash->isChecked())
  {
    ui_mainview.stackedWidget->setCurrentIndex(0);
    ui_mainview.editAmount->setFocus();
    ui_mainview.editAmount->setSelection(0,ui_mainview.editAmount->text().length());
  }//cash
  else  //Card, need editCardkNumber...
  {
    ui_mainview.stackedWidget->setCurrentIndex(1);
    ui_mainview.editAmount->setText(QString::number(totalSum));
    ui_mainview.editCardNumber->setFocus();
    ui_mainview.editCardNumber->setSelection(0,ui_mainview.editCardNumber->text().length());
  }
  refreshTotalLabel();
}

00351 void lemonView::clearUsedWidgets()
{
  ui_mainview.editAmount->setText("0.0");
  ui_mainview.editCardNumber->setText("");
  ui_mainview.editCardAuthNumber->setText("");
  ui_mainview.tableWidget->clearContents();
  ui_mainview.tableWidget->setRowCount(0);
  totalSum = 0.0;
  ui_mainview.labelDetailTax1->setText("");
  ui_mainview.labelDetailTax2->setText("");
  ui_mainview.labelDetailUnits->setText("");
  ui_mainview.labelDetailDesc->setText(i18n("No product selected"));
  ui_mainview.labelDetailPrice->setText("");
  ui_mainview.labelDetailDiscount->setText("");
  ui_mainview.labelDetailTotalTaxes->setText("");
  ui_mainview.labelDetailPhoto->clear();
}


void lemonView::askForIdToCancel()
{
  dlgPassword->show();
  dlgPassword->hide();
  dlgPassword->clearLines();
  if (dlgPassword->exec()) {
    bool ok=false;
    int id = 0;
    InputDialog *dlg = new InputDialog(this, true, dialogTicket, i18n("Enter the ticket number to cancel"));
    if (dlg->exec())
    {
      id = dlg->iValue;
      ok = true;
    }
    //TODO:DB Stuff
    if (ok) {                 // FIXME OR NOTE:
      cancelTransaction(id); //Mark as cancelled in database.. but what about balance? is this transaction
                            //done in the current operation, or a day ago, a month ago, 10 hours ago?
                           //Allow cancelation of same day of sell, or older ones too?
    }
  }
}

void lemonView::focusPayInput()
{
  ui_mainview.groupWidgets->setCurrentIndex(pageMain);
  ui_mainview.editAmount->setFocus();
  ui_mainview.editAmount->setSelection(0, ui_mainview.editAmount->text().length());
}

void lemonView::goSelectCardAuthNumber()
{
  ui_mainview.editCardAuthNumber->setFocus();
}

lemonView::~lemonView()
{
  delete drawer;
}


/* Users zone                                                                                                          */
/*=====================================================================================================================*/

QString lemonView::getLoggedUser()
{
  return loggedUser;
}

//TODO: DB Stuff
QString lemonView::getLoggedUserName(QString id)
{
  QString uname = "";
  if (!db.isOpen()) db.open();
  if (db.isOpen()) {
    QSqlQuery queryUname(db);
    QString qry = QString("SELECT name FROM users WHERE username='%1'").arg(id);
    if (!queryUname.exec(qry)) { qDebug()<<"ERROR:"<<queryUname.lastError(); }
    else {
      if (queryUname.isActive() && queryUname.isSelect()) { //qDebug()<<"queryUname select && active.";
        if (queryUname.first()) { //qDebug()<<"queryUname.first()=true";
          uname = queryUname.value(0).toString();
          //qDebug()<<"USERNAME: "<<uname;
        }
      }
    }
  } else { qDebug()<<"ERROR:"<< db.lastError(); }
  return uname;
}

unsigned int lemonView::getLoggedUserId(QString uname)
{
  unsigned int iD = 0; //FIXME: How to report that not found? assuming id 0 is a valid id number...
  if (!db.isOpen()) db.open();
  if (db.isOpen()) {
    QSqlQuery queryId(db);
    QString qry = QString("SELECT id FROM users WHERE username='%1'").arg(uname);
    if (!queryId.exec(qry)) { qDebug()<<"ERROR:"<<queryId.lastError(); }
    else {
      if (queryId.isActive() && queryId.isSelect()) { //qDebug()<<"queryId select && active.";
        if (queryId.first()) { //qDebug()<<"queryId.first()=true";
          iD = queryId.value(0).toUInt();
        }
      }
    }
  } else { qDebug()<<"ERROR:"<< db.lastError(); }
  return iD;
}

void lemonView::login()
{
  qDebug()<<"Login()";
  //Make a corteDeCaja
  if (!loggedUser.isEmpty() && operationStarted) {
    corteDeCaja();
    loggedUser = "";
    loggedUserName ="";
    emit signalNoLoggedUser();
  }

  dlgLogin->clearLines();
  if ( dlgLogin->exec() ) {
    loggedUser = dlgLogin->username();
    loggedUserName = getLoggedUserName(loggedUser);
    loggedUserId = getLoggedUserId(loggedUser);
    emit signalLoggedUser();
    if (loggedUser == "admin") {
      emit signalAdminLoggedOn();
      //if (!canStartSelling()) startOperation();
    } else {
      emit signalAdminLoggedOff();
      slotDoStartOperation();
    }
  } else {
    loggedUser ="";
    loggedUserName = "";
    loggedUserId = 0;
    emit signalNoLoggedUser();
  }
}

bool lemonView::validAdminUser()
{
  bool result = false;
  dlgPassword->show();
  dlgPassword->hide();
  dlgPassword->clearLines();
  if (dlgPassword->exec())  result = true;
  return result;
}

/* Item things: shopping list, search, insert, delete, calculate total */
/*--------------------------------------------------------------------*/

00504 void lemonView::doSearchItemDesc()
{
  //clear last search
  ui_mainview.tableSearch->clearContents();
  ui_mainview.tableSearch->setRowCount(0);
  //Search
  int rows = 0;
  QString desc = ui_mainview.editItemDescSearch->text();
  if (!db.isOpen()) db.open();
  bool ok = db.isOpen();
  if (ok) {
    QSqlQuery query(db);
    QString qry;
    QRegExp regexp = QRegExp(ui_mainview.editItemDescSearch->text());
    if (!regexp.isValid() || ui_mainview.editItemDescSearch->text().isEmpty())  ui_mainview.editItemDescSearch->setText("*");
    if (ui_mainview.editItemDescSearch->text()=="*") qry = QString("SELECT * from products");
    else qry = QString("SELECT code,name,price,stockqty FROM products WHERE `name` REGEXP '%1'").arg(desc);
    if (!query.exec(qry))
    {
      int errNum = query.lastError().number();
      QSqlError::ErrorType errType = query.lastError().type();
      QString errStr = query.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when searching the database, click details to see the error details."), details, i18n("Error"));
    }
    rows = query.size();
    while (query.next()) {
      int fieldCode = query.record().indexOf("code");
      int fieldDesc = query.record().indexOf("name");
      int fieldPrice= query.record().indexOf("price");
      int fieldStockQty = query.record().indexOf("stockqty");
      QString idesc = query.value(fieldDesc).toString();
      QString icode = query.value(fieldCode).toString();
      QString iprice= query.value(fieldPrice).toString();
      double    istockq= query.value(fieldStockQty).toDouble(); //FIXED: STOCKQTY is DOUBLE no integer...
      //ADD to tableSearch
      int rowCount = ui_mainview.tableSearch->rowCount();
      ui_mainview.tableSearch->insertRow(rowCount);
      QTableWidgetItem *tid = new QTableWidgetItem(idesc);
      if (istockq == 0) {
        QBrush b = QBrush(QColor::fromRgb(255,100,0), Qt::SolidPattern);
        tid->setBackground(b);
      }
      else if (istockq > 0 && istockq < 5) { //TODO:Add an option to configure the minimum stockqty alert.
        QBrush b = QBrush(QColor::fromRgb(255,176,73), Qt::SolidPattern);
        tid->setBackground(b);
      }
      ui_mainview.tableSearch->setItem(rowCount, 0, tid);
      ui_mainview.tableSearch->setItem(rowCount, 1, new QTableWidgetItem(iprice));
      ui_mainview.tableSearch->setItem(rowCount, 2, new QTableWidgetItem(icode));
      ui_mainview.tableSearch->resizeRowsToContents();
    }
    if (rows>0) ui_mainview.labelSearchMsg->setText(i18np("%1 item found","%1 items found.", rows));
    else ui_mainview.labelSearchMsg->setText(i18n("No items found."));
  }//if database open
  else {
      //There is an error openning data base..
    int errNum = db.lastError().number();
    QSqlError::ErrorType errType = db.lastError().type();
    QString errStr = db.lastError().text();
    QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
    KMessageBox::detailedError(this, i18n("Lemon has encountered an error when openning database, click 'details' to see the error details."), details, i18n("Error"));
    ui_mainview.labelSearchMsg->setText(i18n("<html><font color=red weight=bold>Not connected to database</font>.</html>"));
  }
  //end Search
}

00571 int lemonView::getItemRow(QString c)
{
  int result = 0;
  for (int row=0; row<ui_mainview.tableWidget->rowCount(); ++row)
  {
    QTableWidgetItem * item = ui_mainview.tableWidget->item(row, colCode);
    QString icode = item->data(Qt::DisplayRole).toString();
    if (icode == c) {
      result = row;
      break;
    }
  }
  return result; //0 if not found
}

00586 void lemonView::refreshTotalLabel()
{
  double sum=0.0;
  qulonglong points=0;
  QString fullCurrency = Settings::editCurrencyFull();
  QString shortCurrency = QString("");
  if (Settings::showCurrencyOnTotal())  shortCurrency = Settings::editCurrencyShort();
  if (ui_mainview.tableWidget->rowCount()>0) {
    for (int row=0; row<ui_mainview.tableWidget->rowCount(); ++row)
    {
      QTableWidgetItem *item = ui_mainview.tableWidget->item(row, colDue);
      bool isNumber = false;
      if (item->data(Qt::DisplayRole).canConvert(QVariant::String)) {
        QString text = item->data(Qt::DisplayRole).toString();
        double number = text.toDouble(&isNumber);
        if (isNumber) sum += number;
      }
    }
    ProductInfo info;
    QHashIterator<qulonglong, ProductInfo> i(productsHash);
    while (i.hasNext()) {
      i.next();
      info = i.value();
      points += (info.points*info.qtyOnList);
      qDebug()<<info.desc<<" qtyOnList:"<<info.qtyOnList;
    }
  }
  buyPoints = points;
  discMoney = (clientInfo.discount/100)*sum;
  totalSum = sum - discMoney;
  ui_mainview.totaltitle2->setText(i18n("Currency: %1",fullCurrency));
  ui_mainview.labelTotal->setText(i18n("%1 %2",shortCurrency, KGlobal::locale()->formatMoney(totalSum)));
  ui_mainview.labelClientDiscounted->setText(i18n("Amount Discounted:%1 %2",shortCurrency, KGlobal::locale()->formatMoney(discMoney)));
  ui_mainview.labelClientTotalWODiscount->setText(i18n("Before discount:%1 %2",shortCurrency, KGlobal::locale()->formatMoney(sum)));
  ui_mainview.labelClientPointsSale->setText(i18n("Buy Points:%1", points) );
  long double paid, change;
  bool isNum;
  paid = ui_mainview.editAmount->text().toDouble(&isNum);
  if (isNum) change = paid - totalSum; else change = 0.0;
  if (paid <= 0) change = 0.0;
  ui_mainview.labelChange->setText(i18n("%1 %2", shortCurrency, KGlobal::locale()->formatMoney(change)));
}

void lemonView::doEmitSignalQueryDb()
{
  emit signalQueryDb(ui_mainview.editItemCode->text());
}

00634 bool lemonView::incrementTableItemQty(QString code, double q)
{
  double qty  = 1;
  double price=0.0;
  double discount_old=0.0;
  double qty_old=0.0;
  double stockqty=0;
  int    rows=0;
  bool done=false;
  ProductInfo info;

  //Este es el fix para el TODO de abajo..
//   if (productsHash.contains(code.toULongLong())) {
// 
//   }

  //This for cycle whas done before implementation of the productsHash...
  //TODO: Really FIX this, replace this for cycle code with a if.. with the productsHash... is more efficient.
  // Also the code to get stockqty from database could be replaced by this productsHash... all info is in there!
  for (int row=0; row<ui_mainview.tableWidget->rowCount(); ++row)
  {
    QTableWidgetItem *item = ui_mainview.tableWidget->item(row, colCode);//item code
    if (item->data(Qt::DisplayRole).canConvert(QVariant::String)) {
      QString text = item->data(Qt::DisplayRole).toString();
      if (text == code ) {
        //CONSULT DB, we need to know if there is stockqty availability
        if (!db.isOpen()) db.open();
        bool ok = db.isOpen();
        if (ok) {
          QSqlQuery query(db);
          QString qry = QString("SELECT stockqty FROM products WHERE code=%1").arg(code);
          if (!query.exec(qry)) {
            int errNum = query.lastError().number();
            QSqlError::ErrorType errType = query.lastError().type();
            QString errStr = query.lastError().text();
            QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
            KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Error"));
          }
          rows = query.size();
          while (query.next()) { //its supposed to have only one record...
            int fieldStockQty = query.record().indexOf("stockqty");
            stockqty = query.value(fieldStockQty).toDouble();//FIXED, it was int
          }
        }//if database open
        else {
        //There is an error openning data base..
          int errNum = db.lastError().number();
          QSqlError::ErrorType errType = db.lastError().type();
          QString errStr = db.lastError().text();
          QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
          KMessageBox::detailedError(this, i18n("Lemon has encountered an error when openning database, click details to see the error details."), details, i18n("Error"));
        }
        //get item price
        QTableWidgetItem *itemP = ui_mainview.tableWidget->item(row, colPrice);//item price
        if (itemP->data(Qt::DisplayRole).canConvert(QVariant::Double))
          price = itemP->data(Qt::DisplayRole).toDouble();
        //get item qty to increment it by one...
        QTableWidgetItem *itemQ = ui_mainview.tableWidget->item(row, colQty);//item qty
        if ( itemQ->data(Qt::DisplayRole).canConvert(QVariant::Double) ) {
          qty = itemQ->data(Qt::DisplayRole).toDouble();
          qty_old = qty;
          if (stockqty>=q+qty) qty+=q; else {
            QString msg = i18n("<html><font color=red weight=bold>Product not available in stock.</font>");
            if (ui_mainview.groupWidgets->currentIndex() == pageMain) {
              ui_mainview.labelInsertCodeMsg->setText(msg);
              QTimer::singleShot(3000, this, SLOT(clearLabelInsertCodeMsg()));
            }
            if (ui_mainview.groupWidgets->currentIndex() == pageSearch) {
              ui_mainview.labelSearchMsg->setText(msg);
              QTimer::singleShot(3000, this, SLOT(clearLabelSearchMsg()) );
            }
          }
          itemQ->setData(Qt::EditRole, QVariant(qty));
          done = true;
        }//inc qty

        //get item discount
        QTableWidgetItem *itemD = ui_mainview.tableWidget->item(row, colDisc);//item discount
        if (itemD->data(Qt::DisplayRole).canConvert(QVariant::Double))
          discount_old = itemD->data(Qt::DisplayRole).toDouble();
        //calculate new discount
        double discountperitem = (discount_old/qty_old);
        double newdiscount = discountperitem*qty;
        itemD->setData(Qt::EditRole, QVariant(newdiscount));

        qulonglong c = code.toULongLong();
        if (productsHash.contains(c)) {
          info = productsHash.take(c);
          info.qtyOnList = qty; //qty is already added q+qty..
          productsHash.insert(c, info);
        }

        //get item Due to update it.
        QTableWidgetItem *itemDue = ui_mainview.tableWidget->item(row, colDue); //4 item Due
        itemDue->setData(Qt::EditRole, QVariant((price*qty)-newdiscount));
        refreshTotalLabel();
        displayItemInfo(item);
        ui_mainview.editItemCode->clear();
        break;
      }
    }
  }
  return done;
}

00739 void lemonView::insertItem(QString code)
{
  QString desc="";
  double qty  = 1; //by default 1, TODO: falta hacer que pueda modificarse esto manualmente.
  double price=0.0;
  double discount=0.0;
  QByteArray photo;
  int units;
  double cost;
  double tax1;
  double tax2;
  int    category;
  int    validuntilday=0;
  int    validuntilmonth=0;
  int    validuntilyear=0;
  double stockqty=0;
  int    rows = 0;
  qulonglong thecode;
  qulonglong points=0;
  QString uLabel;
  ProductInfo info;


  if (!incrementTableItemQty(code, qty) ) {
    if (!db.isOpen()) db.open();
    bool ok = db.isOpen();
    if (ok) {
      QSqlQuery query(db); QSqlQuery query2(db); //using 1 query variable, sometimes crashes the app. (i think due to time to complete the query1, and executing query2 while not finished query1)
      QString qry = QString("SELECT * FROM products WHERE code=%1").arg(code);
      if (!query.exec(qry)) {
        int errNum = query.lastError().number();
        QSqlError::ErrorType errType = query.lastError().type();
        QString errStr = query.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Error"));
      } //FIXME: Could be necesary to add an else satement here?.. in case the query does not execute, does not continue the rest of the code...
      rows = query.size();
      while (query.next()) {
        int fieldPrice    = query.record().indexOf("price");
        int fieldDesc     = query.record().indexOf("name");
        int fieldStockQty = query.record().indexOf("stockqty");
        int fieldCost     = query.record().indexOf("cost");
        int fieldUnits    = query.record().indexOf("units");
        int fieldTaxp     = query.record().indexOf("taxpercentage");
        int fieldEtraTax  = query.record().indexOf("extrataxes");
        int fieldCategory = query.record().indexOf("category");
        int fieldPhoto    = query.record().indexOf("photo");
        int fieldCode     = query.record().indexOf("code");
        int fieldPoints   = query.record().indexOf("points");
        thecode       = query.value(fieldCode).toULongLong();
        desc     = query.value(fieldDesc).toString();
        price    = query.value(fieldPrice).toDouble();
        stockqty = query.value(fieldStockQty).toDouble();
        cost     = query.value(fieldCost).toDouble();
        units    = query.value(fieldUnits).toInt();
        tax1     = query.value(fieldTaxp).toDouble();
        tax2     = query.value(fieldEtraTax).toDouble();
        category = query.value(fieldCategory).toInt();
        photo    = query.value(fieldPhoto).toByteArray();
        points   = query.value(fieldPoints).toULongLong();
        //Add to productsHash
        info.code = thecode;
        info.desc = desc;
        info.price = price;
        info.cost = cost;
        info.tax  = tax1;
        info.extratax = tax2;
        double pWOtax = price/(1+((tax1+tax2)/100));
        info.totaltax = pWOtax*((tax1+tax2)/100); // in money...
        info.photo = photo;
        info.stockqty = stockqty;
        info.units = units;
        info.category = category;
        info.utility = cost - price;
        info.points = points;
        info.qtyOnList = qty;
      }
      qry = QString("SELECT * from offers WHERE product_id=%1").arg(code);
      if (!query2.exec(qry)) {
        int errNum = query.lastError().number();
        QSqlError::ErrorType errType = query2.lastError().type();
        QString errStr = query2.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Error"));
      }
      //int drows = query2.size();
      //FIXME:Here, could be more than one row for the result (2 discounts for a product, in diferent dates)
      while (query2.next()) {
        int fieldDiscount = query2.record().indexOf("discount");
        int fieldValidUntilday = query2.record().indexOf("validuntilday");
        int fieldValidUntilmonth = query2.record().indexOf("validuntilmonth");
        int fieldValidUntilyear = query2.record().indexOf("validuntilyear");
        discount = query2.value(fieldDiscount).toDouble();
        info.discpercentage = discount; //Discount in percentage...
        validuntilday = query2.value(fieldValidUntilday).toInt();
        validuntilmonth = query2.value(fieldValidUntilmonth).toInt();
        validuntilyear  = query2.value(fieldValidUntilyear).toInt();
      }
      //get units descriptions
      qry = QString("SELECT * from measures WHERE id=%1").arg(info.units);
      QSqlQuery query3(db);
      if (!query3.exec(qry)) {
        int errNum = query.lastError().number();
        QSqlError::ErrorType errType = query3.lastError().type();
        QString errStr = query3.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Error"));
      }
      while (query3.next()) {
        int fieldUD = query3.record().indexOf("text");
        uLabel = query3.value(fieldUD).toString();
        info.unitStr=uLabel; //Added: Dec 15 2007
      }//query3 - get descritptions
    }//if database open
    else {
      //There is an error openning data base..
      int errNum = db.lastError().number();
      QSqlError::ErrorType errType = db.lastError().type();
      QString errStr = db.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when openning database, click details to see the error details."), details, i18n("Error"));
    }
    //CHeck for a valid discount.
    QDate  date = QDate::currentDate();
    QDate  discountdate = QDate(validuntilyear, validuntilmonth, validuntilday);
    if (discountdate < date) {
      discount = 0.0;
      info.validDiscount=false;
      info.disc = 0.0;
    } else {
      discount = ((discount/100)*price); //discount is finally in money, not in percentage.
      info.validDiscount=true;
      info.disc = discount;
    }
    //now we have the discount to incorporate it to the hash...
    productsHash.insert(thecode, info);
    QString msg;
    if ( rows == 0 )  msg = i18n("<html><font color=red weight=bold>Product not found in database.</font></html>");
    else if ( rows > 0 && stockqty >=  qty ) doInsertItem(code, desc, qty, price, discount, uLabel); else
            msg = i18n("<html><font color=red weight=bold>Product not available in stock.</font></html>");
            if (!msg.isEmpty()) {
              if (ui_mainview.groupWidgets->currentIndex() == pageMain) {
                ui_mainview.labelInsertCodeMsg->setText(msg);
                QTimer::singleShot(3000, this, SLOT(clearLabelInsertCodeMsg()));
              }
              if (ui_mainview.groupWidgets->currentIndex() == pageSearch) {
                ui_mainview.labelSearchMsg->setText(msg);
                QTimer::singleShot(3000, this, SLOT(clearLabelSearchMsg()) );
              }
              ui_mainview.editItemCode->clear();
            }
  }
}


00894 void lemonView::doInsertItem(QString itemCode, QString itemDesc, double itemQty, double itemPrice, double itemDiscount, QString itemUnits)
{
  int rowCount = ui_mainview.tableWidget->rowCount();
  ui_mainview.tableWidget->insertRow(rowCount);
  //TODO: View doc to see if insertRow returns the row where it was inserted...
  ui_mainview.tableWidget->setItem(rowCount, colCode, new QTableWidgetItem(itemCode));
  ui_mainview.tableWidget->setItem(rowCount, colDesc, new QTableWidgetItem(itemDesc));
  ui_mainview.tableWidget->setItem(rowCount, colPrice, new QTableWidgetItem(""));//must be empty for HACK
  ui_mainview.tableWidget->setItem(rowCount, colQty, new QTableWidgetItem(QString::number(itemQty)));
  ui_mainview.tableWidget->setItem(rowCount, colUnits, new QTableWidgetItem(itemUnits));
  ui_mainview.tableWidget->setItem(rowCount, colDisc, new QTableWidgetItem(""));//must be empty for HACK
  ui_mainview.tableWidget->setItem(rowCount, colDue, new QTableWidgetItem(""));//must be empty for HACK

  QTableWidgetItem *item = ui_mainview.tableWidget->item(rowCount, colDisc);
  if (itemDiscount>0) {
    QBrush b = QBrush(QColor::fromRgb(255,0,0), Qt::SolidPattern);
    item->setForeground(b);
  }
  //HACK:The next 4 lines are for setting numbers with comas (1,234.00) instead of 1234.00.
  //      seems to be an effect of QVariant(double d)
  item->setData(Qt::EditRole, QVariant(itemDiscount));
  item = ui_mainview.tableWidget->item(rowCount, colDue);
  item->setData(Qt::EditRole, QVariant(itemQty*(itemPrice-itemDiscount)));
  item = ui_mainview.tableWidget->item(rowCount, colPrice);
  item->setData(Qt::EditRole, QVariant(itemPrice));

  //This resizes the heigh... looks beter...
  ui_mainview.tableWidget->resizeRowsToContents();

  if (productsHash.contains(itemCode.toULongLong())) { //Codigo mudado de int a Unsigned long long: qulonlong
    ProductInfo  info = productsHash.value(itemCode.toULongLong());
    if (info.units != uPiece) itemDoubleClicked(item);//NOTE: Pieces must be id=1 at database!!!! its a workaround.
    //STqDebug()<<"itemDoubleClicked at doInsertItem...";
  }

  refreshTotalLabel();
  ui_mainview.editItemCode->setFocus();
  displayItemInfo(item);

  ui_mainview.editItemCode->setText("");
  ui_mainview.editItemCode->setCursorPosition(0);
  ui_mainview.groupWidgets->setCurrentIndex(pageMain);
  //return 0; //FIXME: fix this!.. doing this, causes a crash... i haven't checked the code...
}

00939 void lemonView::deleteSelectedItem()
{
  bool continueIt=false;
  bool reinsert = false;
  double qty=0;
  if (ui_mainview.tableWidget->currentRow()!=-1 && ui_mainview.tableWidget->selectedItems().count()>4) {
    if (Settings::requiereDelAuth()) {
      dlgPassword->show();
      dlgPassword->hide();
      dlgPassword->clearLines();
      if ( dlgPassword->exec() ) continueIt=true;
    }//if requiereDelAuth
    else continueIt=true; //if no authreq, so continue deleting..

    if (continueIt) {
      int row = ui_mainview.tableWidget->currentRow();
      QTableWidgetItem *item = ui_mainview.tableWidget->item(row, colCode);
      qulonglong code = item->data(Qt::DisplayRole).toULongLong();
      ProductInfo info = productsHash.take(code); //insert it later...
      qty = info.qtyOnList; //this must be the same as obtaining from the table... this arrived on Dec 18 2007
     //if the itemQty is more than 1, decrement it, if its 1, delete it
     //item = ui_mainview.tableWidget->item(row, colDisc);
     //double discount_old = item->data(Qt::DisplayRole).toDouble();
      item = ui_mainview.tableWidget->item(row, colUnits);//get item Units in strings...
      QString iUnitString = item->data(Qt::DisplayRole).toString();
      item = ui_mainview.tableWidget->item(row, colQty); //get Qty
      if ((item->data(Qt::DisplayRole).canConvert(QVariant::Double))) {
        qty = item->data(Qt::DisplayRole).toDouble();
       //NOTE and FIXME:
       //  Here, we are going to delete only items that are bigger than 1. and remove them one by one..
       //  or are we goint to decrement items only sold by pieces?
       // How to identify a unit?.. item_Units is a string...but units in enum is integer.
        if (qty>1 && info.units==uPiece) {
          qty--;
          item->setData(Qt::EditRole, QVariant(qty));
          double price    = info.price;
          double discountperitem = info.disc;
          double newdiscount = discountperitem*qty;
          item = ui_mainview.tableWidget->item(row, colDue);
          item->setData(Qt::EditRole, QVariant((qty*price)-newdiscount));
          item = ui_mainview.tableWidget->item(row, colDisc);
          item->setData(Qt::EditRole, QVariant(newdiscount));
          info.qtyOnList = qty;
          reinsert = true;
        }//if qty>1
        else { //Remove from the productsHash and tableWidget...
         //get item code
          //int removed = productsHash.remove(code);
          productsHash.remove(code);
          ui_mainview.tableWidget->removeRow(row);
          reinsert = false;
        }//qty = 1...
      }//if canConvert
      if (reinsert) productsHash.insert(code, info); //we remove it with .take...
    }//continueIt
  }//there is something to delete..
  refreshTotalLabel();
}

00998 void lemonView::itemDoubleClicked(QTableWidgetItem* item)
{
  int row = item->row();
  QTableWidgetItem *i2Modify = ui_mainview.tableWidget->item(row, colCode);
  qulonglong code = i2Modify->data(Qt::DisplayRole).toULongLong();
  ProductInfo info = productsHash.take(code);
  double dmaxItems = info.stockqty;
  int    imaxItems = info.stockqty;
  QString msg = i18n("Enter the number of %1", info.unitStr); //Added on Dec 15, 2007

  //Launch a dialog to as the new qty
  double dqty = 0.0;
  bool   ok   = false;
  int    iqty = 0;
  if (info.units == uPiece) {
    InputDialog *dlg = new InputDialog(this, true, dialogMeasures, msg, 0.0, imaxItems);
    if (dlg->exec() ) {
      iqty = dlg->iValue;
      ok=true;
    }
  }
  else {
    InputDialog *dlg = new InputDialog(this, false, dialogMeasures, msg, 0.001, dmaxItems);
    if (dlg->exec() ) {
      dqty = dlg->dValue;
      ok=true;
    }
  }
  if (ok) {
    double newqty = dqty+iqty; //one must be cero
    //modify Qty and discount...
    i2Modify = ui_mainview.tableWidget->item(row, colQty);
    i2Modify->setData(Qt::EditRole, QVariant(newqty));
    double price    = info.price;
    double discountperitem = info.disc;
    double newdiscount = discountperitem*newqty;
    i2Modify = ui_mainview.tableWidget->item(row, colDue);
    i2Modify->setData(Qt::EditRole, QVariant((newqty*price)-newdiscount));
    i2Modify = ui_mainview.tableWidget->item(row, colDisc);
    i2Modify->setData(Qt::EditRole, QVariant(newdiscount));
    info.qtyOnList = newqty;

    ui_mainview.editItemCode->setFocus();
  }
  productsHash.insert(code, info);
  refreshTotalLabel();
}

01046 void lemonView::itemSearchDoubleClicked(QTableWidgetItem *item)
{
  int row = item->row();
  QTableWidgetItem *cItem = ui_mainview.tableSearch->item(row,2); //get item code
  qulonglong code = cItem->data(Qt::DisplayRole).toULongLong();
  if (productsHash.contains(code)) {
    int pos = getItemRow(QString::number(code));
    if (pos>=0) {
      QTableWidgetItem *thisItem = ui_mainview.tableWidget->item(pos, colCode);
      ProductInfo info = productsHash.value(code);
      if (info.units == uPiece) incrementTableItemQty(QString::number(code), 1);
      else itemDoubleClicked(thisItem);
    }
  }
  else {
    insertItem(QString::number(code));
  }
}

01065 void lemonView::displayItemInfo(QTableWidgetItem* item)
{
  int row = item->row();
  qulonglong code  = (ui_mainview.tableWidget->item(row, colCode))->data(Qt::DisplayRole).toULongLong();
  QString desc  = (ui_mainview.tableWidget->item(row, colDesc))->data(Qt::DisplayRole).toString();
  double price = (ui_mainview.tableWidget->item(row, colPrice))->data(Qt::DisplayRole).toDouble();
  if (productsHash.contains(code)) {
    ProductInfo info = productsHash.value(code);
    QString uLabel=info.unitStr; // Dec 15  2007

    double discP=0.0;
    if (info.validDiscount) discP = info.discpercentage;
    QString str;
    QString tTotalTax= i18n("Taxes:");
    QString tTax    = i18n("Tax:");
    QString tOTax   = i18n("Other taxes:");
    QString tUnits  = i18n("Sold by:");
    QString tPrice  = i18n("Price:");
    QString tDisc   = i18n("Discount:");
    QString tPoints = i18n("Points:");
    double pWOtax = info.price/(1+((info.tax+info.extratax)/100));
    double tax1m = (info.tax/100)*pWOtax;
    double tax2m = (info.extratax/100)*pWOtax;
    QPixmap pix;
    pix.loadFromData(info.photo);

    ui_mainview.labelDetailPhoto->setPixmap(pix);
    str = QString("%1 (%2 %)")
        .arg(KGlobal::locale()->formatMoney(info.totaltax)).arg(info.tax+info.extratax);
    ui_mainview.labelDetailTotalTaxes->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tTotalTax).arg(str));
    str = QString("%1 (%2 %)")
        .arg(KGlobal::locale()->formatMoney(tax1m)).arg(info.tax);
    ui_mainview.labelDetailTax1->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tTax).arg(str));
    str = QString("%1 (%2 %)")
        .arg(KGlobal::locale()->formatMoney(tax2m)).arg(info.extratax);
    ui_mainview.labelDetailTax2->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tOTax).arg(str));
    ui_mainview.labelDetailUnits->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tUnits).arg(uLabel));
    ui_mainview.labelDetailDesc->setText(QString("<html><b>%1</b></html>").arg(desc));
    ui_mainview.labelDetailPrice->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tPrice).arg(KGlobal::locale()->formatMoney(price)));
    ui_mainview.labelDetailDiscount->setText(QString("<html>%1 <b>%2 (%3 %)</b></html>")
        .arg(tDisc).arg(KGlobal::locale()->formatMoney(info.disc)).arg(discP));
    if (info.points>0) {
      ui_mainview.labelDetailPoints->setText(QString("<html>%1 <b>%2</b></html>")
        .arg(tPoints).arg(info.points));
      ui_mainview.labelDetailPoints->show();
    } else ui_mainview.labelDetailPoints->hide();
  }
}

/* TRANSACTIONS ZONE */
/*------------------*/

QString lemonView::getCurrentTransactionString()
{
  return QString::number(currentTransaction);
}

int  lemonView::getCurrentTransaction()
{
  return currentTransaction;
}

01132 void lemonView::createNewTransaction(TransactionType type)
{
  //If there is an operation started, doit...
  if ( operationStarted ) {
    if (!db.isOpen()) db.open();
    bool ok = db.isOpen();
    if (ok) {
      QDateTime datetime = QDateTime::currentDateTime();
      QString day, month, year, hour, minute;
      day    = datetime.toString("d");
      month  = datetime.toString("M");
      year   = datetime.toString("yyyy");
      hour   = datetime.toString("h");
      minute = datetime.toString("m");
      QSqlQuery query(db);
      //TODO:Add client id to the transaction!
      query.prepare("INSERT INTO transactions (type, amount, day, month, year, hour, minute, paidwith, changegiven, paymethod, state, userid, cardnumber, itemcount, itemslist, cardauthnumber, utility, terminalnum) VALUES (:type, :amount, :day, :month, :year, :hour, :minute, :paidwith, :changegiven, :paymethod, :state, :userid, :cardnumber, :itemcount, :itemslist, :cardauthnumber, :utility, :terminalnum)");
      query.bindValue(":type", type);
      query.bindValue(":amount", 0.0);
      query.bindValue(":day", day);
      query.bindValue(":month", month);
      query.bindValue(":year", year);
      query.bindValue(":hour", hour);
      query.bindValue(":minute", minute);
      query.bindValue(":paidwith",0.0 );
      query.bindValue(":changegiven", 0.0);
      query.bindValue(":paymethod", pCash);
      query.bindValue(":state", tNotCompleted);
      query.bindValue(":userid", loggedUserId);
      query.bindValue(":cardnumber", "---");
      query.bindValue(":itemcount", 0);
      query.bindValue(":itemslist", "");
      query.bindValue(":cardauthnumber","---");
      query.bindValue(":utility", 0);
      query.bindValue(":terminalnum", Settings::editTerminalNumber());
      if (!query.exec() ) {
        int errNum = query.lastError().number();
        QSqlError::ErrorType errType = query.lastError().type();
        QString errStr = query.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Error"));
      }
      //TODO:Could be necesary to move from int to qulonglong the transaction number??
      currentTransaction = query.lastInsertId().toInt();
      transactionInProgress = true;
      emit signalUpdateTransactionInfo();
    }
    else { //error openning database
      int errNum = db.lastError().number();
      QSqlError::ErrorType errType = db.lastError().type();
      QString errStr = db.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when openning database, click details to see the error details."), details, i18n("Create New Transaction: Error"));
    }
  }
  productsHash.clear();
}

01190 void lemonView::finishCurrentTransaction()
{
  bool canfinish = true;
  refreshTotalLabel();
  QString msg;
  ui_mainview.groupWidgets->setCurrentIndex(pageMain);
  if (ui_mainview.editAmount->text().isEmpty()) ui_mainview.editAmount->setText("0.0");
  if (ui_mainview.checkCash->isChecked()) {
    if (ui_mainview.editAmount->text().toDouble()<totalSum) {
      canfinish = false;
      ui_mainview.editAmount->setFocus();
      ui_mainview.editAmount->setStyleSheet("background-color: rgb(255,100,0); color:white; selection-color: white; font-weight:bold;");
      ui_mainview.editCardNumber->setStyleSheet("");
      ui_mainview.editAmount->setSelection(0, ui_mainview.editAmount->text().length());
      msg = i18n("<html><font color=red weight=bold>Please fill the correct pay amount before finishing a transaction.</font></html>");
      ui_mainview.labelPayMsg->setText(msg);
      QTimer::singleShot(3000, this, SLOT(clearLabelPayMsg()));
    }
  }
  else {
    if (!ui_mainview.editCardNumber->hasAcceptableInput()) {
      canfinish = false;
      ui_mainview.editCardNumber->setFocus();
      ui_mainview.editCardNumber->setStyleSheet("background-color: rgb(255,100,0); color:white; font-weight:bold; selection-color: white;");
      ui_mainview.editAmount->setStyleSheet("");
      ui_mainview.editCardNumber->setSelection(0, ui_mainview.editCardNumber->text().length());
      msg = i18n("<html><font color=red weight=bold>Please enter the card number.</font></html>");
    }
    else if (!ui_mainview.editCardAuthNumber->hasAcceptableInput()) {
      canfinish = false;
      ui_mainview.editCardAuthNumber->setFocus();
      ui_mainview.editCardAuthNumber->setStyleSheet("background-color: rgb(255,100,0); color:white; font-weight:bold; selection-color: white;");
      ui_mainview.editAmount->setStyleSheet("");
      ui_mainview.editCardAuthNumber->setSelection(0, ui_mainview.editCardAuthNumber->text().length());
      msg = i18n("<html><font color=red weight=bold>Please enter the Authorisation number from the bank voucher.</font></html>");
    }
    ui_mainview.labelPayMsg->setText(msg);
    QTimer::singleShot(3000, this, SLOT(clearLabelPayMsg()));
  }
  if (ui_mainview.tableWidget->rowCount() == 0) canfinish = false;
  if (!canStartSelling()) {
    canfinish=false;
    KMessageBox::sorry(this, i18n("Before selling, you must start operations."));
  }

  if (canfinish)
  {
    ui_mainview.editAmount->setStyleSheet("");
    ui_mainview.editCardNumber->setStyleSheet("");
    PaymentType      pType;
    TransactionState tState = tCompleted;
    double           payWith = 0.0;
    double           payTotal = 0.0;
    double           changeGiven = 0.0;
    QString          authnumber = "'[Not Used]'";
    QString          cardNum = "'[Not Used]'";
    QString          paidStr = "'[Not Available]'";
    int              termnum = Settings::editTerminalNumber();
    QString qry;
    QStringList ilist;
    payTotal = totalSum;
    if (ui_mainview.checkCash->isChecked()) {
      pType = pCash;
      if (!ui_mainview.editAmount->text().isEmpty()) payWith = ui_mainview.editAmount->text().toDouble();
      changeGiven = payWith- totalSum;
    } else {
      pType = pCard;
      if (ui_mainview.editCardNumber->hasAcceptableInput()) cardNum = ui_mainview.editCardNumber->text();
      if (ui_mainview.editCardAuthNumber->hasAcceptableInput()) authnumber = ui_mainview.editCardAuthNumber->text();
      cardNum = "'"+cardNum+"'";
      authnumber = "'"+authnumber+"'";
      payWith = payTotal; //NOTE: Is this right? well, yes, paid is exact the total amount.
    }
    if (!db.isOpen()) db.open();
    bool ok = db.isOpen();
    if (ok) {
      int icount=0; //items sold (5 items sold: 4 sodas and 0.500 kg of sugar)...
      QDate date = QDate::currentDate();
      QString datestr = date.toString("d/MM/yyyy");
      //Update Products StockQTY for each sold product
      if (ui_mainview.tableWidget->rowCount()>0) {
        for (int row=0; row<ui_mainview.tableWidget->rowCount(); ++row)
        {
          QSqlQuery query(db);
          //we need to know how many items...
          QTableWidgetItem *itemq = ui_mainview.tableWidget->item(row, colQty);//item qty
          double iq = 0;
          QTableWidgetItem *itemcodei = ui_mainview.tableWidget->item(row, colCode);
          qulonglong icode = itemcodei->data(Qt::DisplayRole).toULongLong();
          ProductInfo info = productsHash.value(icode);
          if (itemq->data(Qt::DisplayRole).canConvert(QVariant::Double)) iq = itemq->data(Qt::DisplayRole).toDouble();
          QTableWidgetItem *item = ui_mainview.tableWidget->item(row, colCode);
          if (item->data(Qt::DisplayRole).canConvert(QVariant::String)) {
            QString pcode = item->data(Qt::DisplayRole).toString();
            if (info.units == uPiece) icount += iq; else icount += 1; // :)
            ilist.append(pcode+"/"+QString::number(iq));
            qry = QString("UPDATE products SET stockqty=stockqty-%1 , soldunits=soldunits+%2 , datelastsold=%3 WHERE code=%4")
                .arg(iq)
                .arg(iq)
                .arg("'"+datestr+"'")
                .arg(pcode);
            if (!query.exec(qry)) {
              int errNum = query.lastError().number();
              QSqlError::ErrorType errType = query.lastError().type();
              QString errStr = query.lastError().text();
              QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
              KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Finish Transaction: Error"));
            }//qry error
          }
        }//for
      }//if row>0
      // Update transactions
      QString ilistStr = "'" + ilist.join(",") + "'";
      QSqlQuery query2(db);
      qry = QString("UPDATE transactions SET clientid=%15, amount=%1 , paidwith=%2 , paymethod=%3 , state=%4 , cardnumber=%5 , changegiven=%6 , itemcount=%7 , itemslist=%8 , cardauthnumber=%9 , terminalnum=%10, points=%12, disc=%13, discmoney=%14 WHERE id=%11")
          .arg(payTotal)
          .arg(payWith)
          .arg(pType)
          .arg(tState)
          .arg(cardNum)
          .arg(changeGiven)
          .arg(icount)
          .arg(ilistStr)
          .arg(authnumber)
          .arg(termnum)
          .arg(currentTransaction)
          .arg(buyPoints)
          .arg(clientInfo.discount)
          .arg(discMoney)
          .arg(clientInfo.id);
      if (!query2.exec(qry)) {
        int errNum = query2.lastError().number();
        QSqlError::ErrorType errType = query2.lastError().type();
        QString errStr = query2.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Update Transaction: Error"));
      }
      // Update client points
      QSqlQuery query3(db);
      qry = QString("UPDATE clients SET  points=points+%1 WHERE id=%2")
        .arg(buyPoints)
        .arg(clientInfo.id);
      if (!query2.exec(qry)) {
        int errNum = query2.lastError().number();
        QSqlError::ErrorType errType = query2.lastError().type();
        QString errStr = query2.lastError().text();
        QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
        KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Update Transaction: Error"));
      }
      if (drawer) {
        //FIXME: What to di first?... add or substract?... when there is No money or there is less money than the needed for the change.. what to do?
        if (ui_mainview.checkCash->isChecked()) {
          drawer->addCash(payWith);
          drawer->substractCash(changeGiven);
          drawer->incCashTransactions();
          drawer->open();
        } else {
          drawer->incCardTransactions();
          drawer->addCard(payWith);
        }
        drawer->insertTransactionId(getCurrentTransaction());
      }
      else {
        KMessageBox::error(this, i18n("The Drawer is not initialized, please start operation first."), i18n("Error") );
      }
      //update client info in the hash....
      clientInfo.points += buyPoints;
      clientsHash.remove(QString::number(clientInfo.id));
      clientsHash.insert(QString::number(clientInfo.id), clientInfo);
      updateClientInfo();
      TicketInfo ticket;
      ticket.number = currentTransaction;
      ticket.total  = payTotal;
      ticket.change = changeGiven;
      ticket.paidwith = payWith;
      ticket.itemcount = icount;
      ticket.cardnum = cardNum;
      ticket.cardAuthNum = authnumber;
      ticket.paidWithCard = ui_mainview.checkCard->isChecked();
      ticket.clientDisc = clientInfo.discount;
      ticket.clientDiscMoney = discMoney;
      ticket.buyPoints = buyPoints;
      ticket.clientPoints = clientInfo.points;
      printTicket(ticket);
      transactionInProgress = false;
      updateModelView();
    }
    else {
      int errNum = db.lastError().number();
      QSqlError::ErrorType errType = db.lastError().type();
      QString errStr = db.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when saving transaction, click details to see the error details."), details, i18n("Error"));
    }
    ui_mainview.editItemCode->setFocus();
  }
}

01388 void lemonView::printTicket(TicketInfo ticket)
{
  //TRanslateable strings:
  QString salesperson    = i18n("Salesperson: %1", loggedUserName);
  QString hQty           = i18n("Qty");
  QString hProduct       = i18n("Product");
  QString hPrice         = i18n("Price");
  QString hDisc          = i18n("Special");
  QString hTotal         = i18n("Total");
  QString hClientDisc    = i18n("Your discount: %1", discMoney);
  QString hClientBuyPoints  = i18n("Your points this buy: %1", buyPoints);
  QString hClientPoints  = i18n("Your total points: %1", clientInfo.points);
  QString hTicket  = i18n("Ticket # %1", ticket.number);
  QString terminal = i18n("Terminal #%1", Settings::editTerminalNumber());
  //HTML Ticket
  QStringList ticketHtml;
  double tDisc = 0.0;
  //Ticket header
  ticketHtml.append(QString("<html><body><b>%1 - %2</b> [%3]<br>Ticket #%4 %5 %6<br>")
      .arg(Settings::editStoreName())
      .arg(Settings::editBranchName())
      .arg(Settings::editBranchNumber())
      .arg(ticket.number)
      .arg(salesperson)
      .arg(terminal));
  //Ticket Table header
  ticketHtml.append(QString("<table border=0><tr><th>%1</th><th>%2</th><th>%3</th><th>%4</th><th>%5</th></tr>")
      .arg(hQty).arg(hProduct).arg(hPrice).arg(hDisc).arg(hTotal));

  //TEXT Ticket
  QStringList itemsForPrint;
  QString line;
  line = QString("%1,  [#%2]").arg(Settings::editStoreName()).arg(Settings::editBranchNumber());
  itemsForPrint.append(line);
  line = QString("%2  %1")
     .arg(terminal)
     .arg(Settings::editBranchName());
  itemsForPrint.append(line);
  line = QString("%1  %2").arg(hTicket).arg(salesperson);
  itemsForPrint.append(line);
  line = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(), KLocale::LongDate);
  itemsForPrint.append(line);
  itemsForPrint.append("          ");
  hQty.truncate(6);
  hProduct.truncate(14);
  hPrice.truncate(7);
  hTotal.truncate(6);
  //qDebug()<< "Strings:"<< hQty;qDebug()<< ", "<< hProduct<<", "<<hPrice<<", "<<hTotal;
  itemsForPrint.append(hQty +"  "+ hProduct +"      "+ hPrice+ " "+ hTotal);
  itemsForPrint.append("------  --------------  -------  -------");
  for (int row=0; row<ui_mainview.tableWidget->rowCount(); ++row)
  {
    QTableWidgetItem *item;
    item = ui_mainview.tableWidget->item(row, colCode);
    qulonglong code = item->data(Qt::DisplayRole).toULongLong();
    ProductInfo info = productsHash.value(code);
    item = ui_mainview.tableWidget->item(row, colDesc);//desc
    QString  idesc =  item->data(Qt::DisplayRole).toString();
    item = ui_mainview.tableWidget->item(row, colPrice);//price
    QString iprice =  item->data(Qt::DisplayRole).toString();
    item = ui_mainview.tableWidget->item(row, colQty);//qty
    QString iqty =  item->data(Qt::DisplayRole).toString();
    iqty = iqty+" "+info.unitStr;
    item = ui_mainview.tableWidget->item(row, colDisc);//discount
    QString idiscount =  item->data(Qt::DisplayRole).toString();
    bool hasDiscount = false;
    //qDebug()<<"Total discount:"<<tDisc;
    if (item->data(Qt::DisplayRole).toDouble() > 0) {
      hasDiscount = true;
      tDisc = tDisc + item->data(Qt::DisplayRole).toDouble();
//       qDebug()<<"Has discount, new tDisc:"<<tDisc;
    }
    item = ui_mainview.tableWidget->item(row, colDue);//due
    QString idue =  item->data(Qt::DisplayRole).toString();

    //HTML Ticket
    ticketHtml.append(QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
        .arg(iqty).arg(idesc).arg(iprice).arg(idiscount).arg(idue));
    //TEXT TICKET
    //adjusting length
    if (idesc.length()>14) idesc.truncate(14); //idesc = idesc.insert(19, '\n');
    else {
      while (idesc.length()<14) idesc = idesc.insert(idesc.length(), ' ');
    }
    //FIXME: Falta ajustar iqty, iprice, idiscount
    while (iqty.length()<6) iqty = iqty.insert(iqty.length(), ' ');
    while (iprice.length()<7) iprice = iprice.insert(iprice.length(), ' ');
//     while (idiscount.length()<4) idiscount = idiscount.insert(idiscount.length(), ' ');

    line = QString("%1  %2  %3  %4").
        arg(iqty).
        arg(idesc).
        arg(iprice).
        arg(idue);
    itemsForPrint.append(line);
    if (hasDiscount) itemsForPrint.append(i18n("        * %1 *     -%2", hDisc, idiscount));
  }//for each item
  //HTML Ticket
  QString harticles = i18np("%1 article.", "%1 articles.", ticket.itemcount);
  QString htotal    = i18n("A total of");
  ticketHtml.append(QString("</table><br><br><b>%1</b> %2 <b>%3</b>")
      .arg(harticles).arg(htotal).arg(KGlobal::locale()->formatMoney(ticket.total)));
  ticketHtml.append(i18n("<br>Paid with %1, your change is <b>%2</b><br>",
                    KGlobal::locale()->formatMoney(ticket.paidwith),
                                    KGlobal::locale()->formatMoney(ticket.change)));
  ticketHtml.append(Settings::editTicketMessage());
  //Text Ticket
  itemsForPrint.append("  ");
  line = QString("%1  %2 %3").arg(harticles).arg(htotal).arg(ticket.total);
  itemsForPrint.append(line);
  if (tDisc > 0) {
    line = i18n("You saved $%1", tDisc);
    itemsForPrint.append(line);
  }
  if (clientInfo.discount>0) itemsForPrint.append(hClientDisc);
  if (buyPoints>0) itemsForPrint.append(hClientBuyPoints);
  if (clientInfo.points>0) itemsForPrint.append(hClientPoints);
  itemsForPrint.append(" ");
  line = i18n("Paid with %1, your change is %2",
              ticket.paidwith, KGlobal::locale()->formatMoney(ticket.change));
  itemsForPrint.append(line);
  itemsForPrint.append(" ");
  if (ticket.paidWithCard) {
    ticketHtml.append(i18n("<br>Card # %1<br>Authorisation # %2",ticket.cardnum, ticket.cardAuthNum));
    line = QString("Card Number:%1 \nAuthorisation #:%2").arg(ticket.cardnum).arg(ticket.cardAuthNum);
    itemsForPrint.append(line);
    itemsForPrint.append(" ");
  }
  line = QString(Settings::editTicketMessage());
  itemsForPrint.append(line);
  ticketHtml.append("</body></html>");

  //Printing...
  qDebug()<< itemsForPrint.join("\n");

  //This is a test... fix it later.
  if (Settings::printTicket()) {
    QFile file("/dev/lp0");
    if (file.open(QIODevice::ReadWrite)) {
      qDebug()<<"Printing ticket...";
      QTextStream out(&file);
      out << "\x1b\x4b\x30";              // Feed back x30 dot lines
      out << "\x1b\x4b\x20";              // Feed back x20 dot lines
      out << itemsForPrint.join("\n");    // Print data

      out << "\x1b\x64\x06";              // Feed 6 lines
      file.close();
    } else qDebug()<<"ERROR: Could not open printer...";
  }

  //Using SP500 for now...
//   StarPrinter *printer = new StarPrinter();
//   printer->openPrinterPort();
//   printer->setCharacterSet_toLatinamerican();
//   if (printer->isPortOpen()) {
//     qDebug()<<"Printer port opened, printing ticket...";
//     printer->writeToPort(itemsForPrint.join("\n"));
//     printer->closePrinterPort();
//   } else { qDebug()<<"Could not open port, lastError:"<<printer->lastError(); }
//   delete printer;

  if (Settings::showDialogOnPrinting())
  {
    TicketPopup *popup = new TicketPopup(this, ticketHtml.join(" "), DesktopIcon("printer", 48), 3000);
    QApplication::beep();
    popup->popup();
  }
  //Start Again a new transaction and clear all used widgets..
  QTimer::singleShot(1000, this, SLOT(startAgain()));

}

void lemonView::quitaAcentos(QString &text)
{
  //NOTE: Es para reemplazar acentos por caracteres no acentuados... la impresora no los imprime.
  //TODO: Rewrite this...
  char chars[5];
//   chars[0] = 'á';
//   chars[1] = 'é';
//   chars[2] = 'í';
//   chars[3] = 'ó';
//   chars[4] = 'ú';
  for (int x=0; x<5; x++) {
    while ( text.contains(chars[x]) ) text = text.replace(x,1, char(x+97));
    qDebug()<<"Letra #"<<x<<" Letra con acento:"<<chars[x]<<" Letra sin acento"<<char(x+97);
  }
  // Ahora las mayusculas...
  // Ahora los signos raros... como !¡ ¿ ? ...
}

void lemonView::startAgain()
{
  qDebug()<<"startAgain(): New Transaction";
  productsHash.clear();
  setupClients(); //clear the clientInfo (sets the default client info)
  clearUsedWidgets();
  buyPoints =0;
  discMoney=0;
  refreshTotalLabel();
  createNewTransaction(tSell);
}

01590 void lemonView::cancelCurrentTransaction()
{
  cancelTransaction(getCurrentTransaction());
}


void lemonView::preCancelCurrentTransaction()
{
  if (ui_mainview.tableWidget->rowCount()==0 ) { //empty transaction
    if (Settings::deleteEmptyCancelledTransactions()) deleteCurrentTransaction();
    else cancelCurrentTransaction();
  }
  else cancelCurrentTransaction();
}

void lemonView::deleteCurrentTransaction()
{
  if (!db.isOpen()) db.open();
  if (db.isOpen()) {
    QSqlQuery query(db);
    QString qry = QString("DELETE FROM transactions WHERE id=%1").arg(getCurrentTransaction());
    if (!query.exec(qry)) {
      int errNum = query.lastError().number();
      QSqlError::ErrorType errType = query.lastError().type();
      QString errStr = query.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Delete Transaction: Error"));
    } else {
      qDebug()<<"Transaction deleted:"<<getCurrentTransaction();
      transactionInProgress = false;
      //finally create a new transaction.
      createNewTransaction(tSell);
    }
  }
  else qDebug()<<"ERROR:"<<db.lastError();
}

01627 void lemonView::cancelTransaction(int transactionNumber)
{
  //This action has many implied problems: What about balances, points, etc.. in the database
  clearUsedWidgets();
  refreshTotalLabel();
  //Mark as cancelled
  if (!db.isOpen()) db.open();
  bool ok = db.isOpen();
  if (ok) {
    QSqlQuery query(db);
    QString qry = QString("UPDATE transactions SET  state=%1 WHERE id=%2")
        .arg(tCancelled)
        .arg(transactionNumber);
    if (!query.exec(qry)) {
      int errNum = query.lastError().number();
      QSqlError::ErrorType errType = query.lastError().type();
      QString errStr = query.lastError().text();
      QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
      KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Cancel Transaction: Error"));
    } else { //Cancelled...
      transactionInProgress = false;
      //finally create a new transaction.
      createNewTransaction(tSell);
    }
  }
  else {
    int errNum = db.lastError().number();
    QSqlError::ErrorType errType = db.lastError().type();
    QString errStr = db.lastError().text();
    QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
    KMessageBox::detailedError(this, i18n("Lemon has encountered an error when openning database, click details to see the error details."), details, i18n("Cancel Transaction: Error"));
  }
}


01662 void lemonView::startOperation()
{
  qDebug()<<"Starting operations...";
  bool ok=false;
  double qty=0.0;
  InputDialog *dlg = new InputDialog(this, false, dialogMoney, i18n("Enter the amount of money to deposit in the drawer"));
  dlg->setEnabled(true);
  if (dlg->exec() ) {
    qty = dlg->dValue;
    ok = true;
  }
  if (ok) {
    if (drawer == 0) drawer = new Gaveta();//FIXME!
    drawer->open();
   // Set drawer amount.
    drawer->setStartDateTime(QDateTime::currentDateTime());
    drawer->setAvailableInCash(qty);
    drawer->setInitialAmount(qty);
    operationStarted = true;
    createNewTransaction(tSell);
  }
  else operationStarted = false;
  emit signalStartedOperation();
}

void lemonView::slotDoStartOperation()
{
  qDebug()<<"doStartOperations..";
  if (!operationStarted) {
    bool doit = false;
    do  {
      dlgPassword->show();
      dlgPassword->clearLines();
      dlgPassword->hide();
      doit = dlgPassword->exec();
    } while (!doit);
    if (doit) startOperation();
  }
}

/* REPORTS ZONE */
/*--------------*/

01705 void lemonView::corteDeCaja()
{
  qDebug()<<"Doing Balance..";
  preCancelCurrentTransaction();
  QDateTime datetime = QDateTime::currentDateTime();
  QStringList lines;
  QStringList linesHTML;
  QString line;
  QString day    = "'"+datetime.toString("d")+"'";
  QString month  = "'"+datetime.toString("M")+"'";
  QString year   = "'"+datetime.toString("yyyy")+"'";

  QString dId;
  QString dAmount;
  QString dHour;
  QString dMinute;
  QString dPaidWith;
  QString dPayMethod;

  int termnum=Settings::editTerminalNumber();

  QStringList transactionList;
  QList<int> intList = drawer->getTransactionIds();
  if (intList.isEmpty()) transactionList.append("EMPTY");
  else {
    for (int i = 0; i < intList.size(); ++i) {
      transactionList.append( QString::number(intList.at(i)) );
    }
  }

  //Save balance on Database
  if (!db.isOpen()) db.open();
  QSqlQuery queryBalance(db);
  queryBalance.prepare("INSERT INTO balances (balances.datetime_start, balances.datetime_end, balances.userid, balances.usern, balances.initamount, balances.in, balances.out, balances.cash, balances.card, balances.transactions) VALUES (:date_start, :date_end, :userid, :user, :initA, :in, :out, :cash, :card, :transactions)");
  queryBalance.bindValue(":date_start", KGlobal::locale()->formatDateTime(drawer->getStartDateTime()));
  queryBalance.bindValue(":date_end", KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()));
  queryBalance.bindValue(":userid", loggedUserId);
  queryBalance.bindValue(":user", loggedUserName);
  queryBalance.bindValue(":initA", drawer->getInitialAmount());
  queryBalance.bindValue(":in", drawer->getInAmount());
  queryBalance.bindValue(":out", drawer->getOutAmount());
  queryBalance.bindValue(":cash", drawer->getAvailableInCash());
  queryBalance.bindValue(":card", drawer->getAvailableInCard());
  queryBalance.bindValue(":transactions", transactionList.join(","));

  if (!queryBalance.exec() ) {
    int errNum = queryBalance.lastError().number();
    QSqlError::ErrorType errType = queryBalance.lastError().type();
    QString errStr = queryBalance.lastError().text();
    QString details = i18n("Error #%1, Type:%2\n'%3'",QString::number(errNum), QString::number(errType),errStr);
    KMessageBox::detailedError(this, i18n("Lemon has encountered an error when querying the database, click details to see the error details."), details, i18n("Balance (Corte de caja): Error"));
  }


  // Create lines to print and/or show on dialog...

  //----------Translated strings--------------------
  QString strTitle      = i18n("Balance for user %1", loggedUserName);
  QString strInitAmount = i18n("Initial Amount deposited:");
  QString strInitAmountH= i18n("Deposit");
  QString strInH         = i18n("In");
  QString strOutH        = i18n("Out");
  QString strInDrawerH   = i18n("In Drawer");
  QString strTitlePre    = i18n("Drawer Balance");
  QString strTitleTrans  = i18n("Transactions Details");
  QString strTitleTransH = i18n("Transactions");
  QString strId          = i18n("Id");
  QString strTimeH       = i18n("Time");
  QString strAmount      = i18n("Amount");
  QString strPaidWith    = i18n("Paid with");
  QString strPayMethodH =  i18n("Pay Method");

  //HTML
  line = QString("<html><body><h3>%1</h3>").arg(strTitle);
  linesHTML.append(line);
  line = QString("<center><table border=1 cellpadding=5><tr><th colspan=4>%9</th></tr><tr><th>%1</th><th>%2</th><th>%3</th><th>%4</th></tr><tr><td>%5</td><td>%6</td><td>%7</td><td>%8</td></tr></table></ceter><br>")
      .arg(strInitAmountH)
      .arg(strInH)
      .arg(strOutH)
      .arg(strInDrawerH)
      .arg(KGlobal::locale()->formatMoney(drawer->getInitialAmount()))
      .arg(KGlobal::locale()->formatMoney(drawer->getInAmount()))
      .arg(KGlobal::locale()->formatMoney(drawer->getOutAmount()))
      .arg(KGlobal::locale()->formatMoney(drawer->getAvailableInCash()))
      .arg(strTitlePre);
  linesHTML.append(line);
  line = QString("<table border=1 cellpadding=5><tr><th colspan=5>%1</th></tr><tr><th>%2</th><th>%3</th><th>%4</th><th>%5</th><th>%6</th></tr>")
      .arg(strTitleTransH)
      .arg(strId)
      .arg(strTimeH)
      .arg(strAmount)
      .arg(strPaidWith)
      .arg(strPayMethodH);
  linesHTML.append(line);

  //TXT
  lines.append(strTitle);
  line = QString(KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(), KLocale::LongDate));
  lines.append(line);
  lines.append("----------------------------------------");
  line = QString("%1 %2").arg(strInitAmount).arg(KGlobal::locale()->formatMoney(drawer->getInitialAmount()));
  lines.append(line);
  line = QString("%1 :%2, %3 :%4")
      .arg(strInH)
      .arg(KGlobal::locale()->formatMoney(drawer->getInAmount()))
      .arg(strOutH)
      .arg(KGlobal::locale()->formatMoney(drawer->getOutAmount()));
  lines.append(line);
  line = QString(" %1 %2").arg(KGlobal::locale()->formatMoney(drawer->getAvailableInCash())).arg(strInDrawerH);
  lines.append(line);
  //Now, add a transactions report per user and for today.
  //At this point, drawer must be initialized and valid.
  line = i18n("----------%1----------",strTitleTrans);
  lines.append(line);
  line = i18n("%1           %2      %3",strId, strAmount, strPaidWith);
  lines.append(line);
  lines.append("----------  ----------  ----------");
  QList<int> transactionsByUser = drawer->getTransactionIds();
  //This gets all transactions ids done since last corteDeCaja.
  for (int i = 0; i < transactionsByUser.size(); ++i) {
    int idNum = transactionsByUser.at(i);
    QString qry = QString("SELECT * FROM transactions WHERE id=%1 and terminalnum=%2").arg(idNum).arg(termnum);
    QSqlQuery query;
    if (!query.exec(qry)) { qDebug()<<query.lastError(); }
    else {
      while (query.next()) {
        int fieldId = query.record().indexOf("id");
        int fieldAmount = query.record().indexOf("amount");
        int fieldHour = query.record().indexOf("hour");
        int fieldMinute = query.record().indexOf("minute");
        int fieldPaidWith = query.record().indexOf("paidwith");
        int fieldPayMethod = query.record().indexOf("paymethod");
        dId       = query.value(fieldId).toString();
        dAmount   = query.value(fieldAmount).toString();
        dHour     = query.value(fieldHour).toString();
        dMinute   = query.value(fieldMinute).toString();
        dPaidWith = query.value(fieldPaidWith).toString();

        while (dId.length()<10) dId = dId.insert(dId.length(), ' ');
        while (dAmount.length()<14) dAmount = dAmount.insert(dAmount.length(), ' ');
        while ((dHour+dMinute).length()<6) dMinute = dMinute.insert(dMinute.length(), ' ');
        while (dPaidWith.length()<10) dPaidWith = dPaidWith.insert(dPaidWith.length(), ' ');

        if (query.value(fieldPayMethod).toInt() == pCash)
          dPayMethod = i18n("Cash");/*dPaidWith;*/ else if (query.value(fieldPayMethod).toInt() == pCard)
              dPayMethod = i18n("Card");  else dPayMethod = i18n("Unknown");
              line = QString("%1 %2 %3")
                  .arg(dId)
                  //.arg(dHour)
                  //.arg(dMinute)
                  .arg(dAmount)
                  //.arg(dPaidWith);
                  .arg(dPayMethod);
              lines.append(line);
              line = QString("<tr><td>%1</td><td>%2:%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
                  .arg(dId)
                  .arg(dHour)
                  .arg(dMinute)
                  .arg(dAmount)
                  .arg(dPaidWith)
                  .arg(dPayMethod);
              linesHTML.append(line);
      }
    }
  }
  line = QString("</table></body></html>");
  linesHTML.append(line);
  operationStarted = false;
  showBalance(linesHTML);
  printBalance(lines);
  slotDoStartOperation();
}

void lemonView::showBalance(QStringList lines)
{
  if (Settings::showDialogOnPrinting())
  {
    BalanceDialog *popup = new BalanceDialog(this, lines.join("\n"));
    popup->show();
    popup->hide();
    int result = popup->exec();
    if (result) { 
      //qDebug()<<"exec=true";
    }
  }
}

01892 void lemonView::printBalance(QStringList lines)
{
  if (Settings::printTicket()) {
    QFile file("/dev/lp0");
    if (file.open(QIODevice::ReadWrite)) {
      qDebug()<<"Printing balance...";
      QTextStream out(&file);
      out << "\x1b\x4b\x30";              // Feed back x30 dot lines
      out << "\x1b\x4b\x20";              // Feed back x20 dot lines
      out << lines.join("\n");    // Print data
      out << "\x1b\x64\x06";              // Feed 6 lines
      file.close();
    } else qDebug()<<"ERROR: Could not open printer...";
  }
}


/* MODEL Zone */

void lemonView::setupModel()
{
  qDebug()<<"Setting up products model...";
  if (db.isOpen()) {
    productsModel->setTable("products");
    productsModel->setEditStrategy(QSqlTableModel::OnRowChange);
    ui_mainview.listView->setModel(productsModel);
    ui_mainview.listView->setResizeMode(QListView::Adjust);

    ui_mainview.listView->setModelColumn(productsModel->fieldIndex("photo"));
    ui_mainview.listView->setViewMode(QListView::IconMode);
    ui_mainview.listView->setGridSize(QSize(170,170));
    ui_mainview.listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui_mainview.listView->setMouseTracking(true); //for the tooltip

    ProductDelegate *delegate = new ProductDelegate(ui_mainview.listView);
    ui_mainview.listView->setItemDelegate(delegate);

    productsModel->select();

    //Categories popuplist
    populateCategoriesHash();
    QHashIterator<QString, int> item(categoriesHash);
    while (item.hasNext()) {
      item.next();
      ui_mainview.comboFilterByCategory->addItem(item.key());
      //qDebug()<<"iterando por el hash en el item:"<<item.key()<<"/"<<item.value();
    }

    ui_mainview.comboFilterByCategory->setCurrentIndex(0);
    connect(ui_mainview.comboFilterByCategory,SIGNAL(currentIndexChanged(int)), this, SLOT( setFilter()) );
    connect(ui_mainview.editFilterByDesc,SIGNAL(returnPressed()), this, SLOT( setFilter()) );
    connect(ui_mainview.rbFilterByDesc, SIGNAL(toggled(bool)), this, SLOT( setFilter()) );
    connect(ui_mainview.rbFilterByCategory, SIGNAL(toggled(bool)), this, SLOT( setFilter()) );

    ui_mainview.rbFilterByCategory->setChecked(true);
    setFilter();
  }
  else {
      //At this point, what to do?
     // inform to the user about the error and finish app  or retry again some time later?
    QString details = db.lastError().text();
    KMessageBox::detailedError(this, i18n("Lemon has encountered an error, click details to see the error details."), details, i18n("Error"));
    QTimer::singleShot(10000, this, SLOT(setupModel()));
  }
 }

void lemonView::populateCategoriesHash()
{
  if (!db.isOpen()) db.open();
  QSqlQuery myQuery(db);
  if (myQuery.exec("select * from categories;")) {
    while (myQuery.next()) {
      int fieldId   = myQuery.record().indexOf("catid");
      int fieldText = myQuery.record().indexOf("text");
      int id = myQuery.value(fieldId).toInt();
      QString text = myQuery.value(fieldText).toString();
      categoriesHash.insert(text, id);
      qDebug()<<text<<":"<<id;
    }
//     qDebug()<<categoriesHash.count()<<" Items";
  }
  else {
    qDebug()<<"ERROR: "<<myQuery.lastError();
  }
}

void lemonView::listViewOnMouseMove(const QModelIndex & index)
{
  //NOTE: Problem: here the data on the view does not change. This is because we do not
  //      update this view's data, we modify directly the data at database until we sell a product.
  //      and until that moment we can update this view.
  QString tprice = i18n("Price: ");
  QString tstock = i18n("Available: ");
  QString tdisc  = i18n("Discount:"); //TODO: Only include if valid until now...
  QString tcategory = i18n("Category:");

  //getting data from model...
  const QAbstractItemModel *model = index.model();
  int row = index.row();
  QModelIndex indx = model->index(row, 1);
  QString desc = model->data(indx, Qt::DisplayRole).toString();
  indx = model->index(row, 2);
  double price = model->data(indx, Qt::DisplayRole).toDouble();
  indx = model->index(row, 3);
  double stockqty = model->data(indx, Qt::DisplayRole).toDouble();

  QString line1 = QString("<p><b><i>%1</i></b><br>").arg(desc);
  QString line2 = QString("<b>%1</b> %2<br>").arg(tprice).arg(price);
  QString line3 = QString("<b>%1</b> %2<br></p>").arg(tstock).arg(stockqty);
  QString text = line1+line2+line3;

  ui_mainview.listView->setToolTip(text);
}

void lemonView::listViewOnClick(const QModelIndex & index)
{
  //getting data from model...
  const QAbstractItemModel *model = index.model();
  int row = index.row();
  QModelIndex indx = model->index(row, 0);
  QString code = model->data(indx, Qt::DisplayRole).toString();
  insertItem(code);
}

//This is done at the end of each transaction...
void lemonView::updateModelView()
{
  //Submit and select causes a flick and costs some milliseconds
  productsModel->submitAll();
  productsModel->select();
}

void lemonView::showProductsGrid(bool show)
{
  if (show) ui_mainview.frameGridView->show();
  else ui_mainview.frameGridView->hide();
}

void lemonView::hideProductsGrid()
{
  ui_mainview.frameGridView->hide();
}

void lemonView::setFilter()
{
//NOTE: This is a QT BUG.
//   If filter by description is selected and the text is empty, and later is re-filtered
//   then NO pictures are shown; even if is refiltered again.
  QRegExp regexp = QRegExp(ui_mainview.editFilterByDesc->text());

  if (ui_mainview.rbFilterByDesc->isChecked()) {
    if (!regexp.isValid() || ui_mainview.editFilterByDesc->text().isEmpty())  ui_mainview.editFilterByDesc->setText("*");
    if (ui_mainview.editFilterByDesc->text()=="*") productsModel->setFilter("");
    else  productsModel->setFilter(QString("products.name REGEXP '%1'").arg(ui_mainview.editFilterByDesc->text()));
  }
  else {
    //Find catId for the text on the combobox.
    int catId=-1;
    QString catText = ui_mainview.comboFilterByCategory->currentText();
    if (categoriesHash.contains(catText)) {
      catId = categoriesHash.value(catText);
    }
    productsModel->setFilter(QString("products.category=%1").arg(catId));
  }
  productsModel->select();
}


void lemonView::setupDB()
{
  qDebug()<<"Setting up database...";
  QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
  db = QSqlDatabase::addDatabase("QMYSQL");
  db.setHostName(Settings::editDBServer());
  db.setDatabaseName(Settings::editDBName());
  db.setUserName(Settings::editDBUsername());
  db.setPassword(Settings::editDBPassword());
  //The Connectiion will be openned later...
  dlgLogin->setDb(db);
  dlgPassword->setDb(db);

  //Create model...
  productsModel = new QSqlTableModel();
  setupModel();
  setupClients();
}

void lemonView::setupClients()
{
  qDebug()<<"Setting up clients...";
  ClientInfo info;
  QString mainClient;
  clientsHash.clear();
  ui_mainview.comboClients->clear();
  if (!db.isOpen()) db.open();
  QSqlQuery qC(db);
  if (qC.exec("select * from clients;")) {
    while (qC.next()) {
      int fieldId     = qC.record().indexOf("id");
      int fieldName   = qC.record().indexOf("name");
      int fieldPoints = qC.record().indexOf("points");
      int fieldPhoto  = qC.record().indexOf("photo");
      int fieldDisc   = qC.record().indexOf("discount");
      info.id = qC.value(fieldId).toUInt();
      info.name       = qC.value(fieldName).toString();
      info.points     = qC.value(fieldPoints).toULongLong();
      info.discount   = qC.value(fieldDisc).toDouble();
      info.photo      = qC.value(fieldPhoto).toByteArray();
      clientsHash.insert(info.name, info);
      ui_mainview.comboClients->addItem(info.name);
      if (info.id == 1) mainClient=info.name;
    }
  }
  else {
    qDebug()<<"ERROR: "<<qC.lastError();
  }
  //Set by default the 'general' client.
  int idx = ui_mainview.comboClients->findText(mainClient,Qt::MatchCaseSensitive);
  if (idx>-1) ui_mainview.comboClients->setCurrentIndex(idx);
  clientInfo = clientsHash.value(mainClient);
  updateClientInfo();
}

void lemonView::comboClientsOnChange()
{
  QString newClientName    = ui_mainview.comboClients->currentText();
  if (clientsHash.contains(newClientName)) {
    clientInfo = clientsHash.value(newClientName);
    updateClientInfo();
    refreshTotalLabel();
    ui_mainview.editItemCode->setFocus();
  }
}

void lemonView::updateClientInfo()
{
  QString pStr = i18n("Points: %1", clientInfo.points);
  QString dStr = i18n("Discount: %1%",clientInfo.discount);
  ui_mainview.lblClientDiscount->setText(dStr);
  ui_mainview.lblClientPoints->setText(pStr);
  QPixmap pix;
  pix.loadFromData(clientInfo.photo);
  ui_mainview.lblClientPhoto->setPixmap(pix);
}

#include "lemonview.moc"



Generated by  Doxygen 1.6.0   Back to index