mainwindow.cpp 37.3 KB
Newer Older
Hugo Hörnquist's avatar
Hugo Hörnquist committed
1
2
3
4
5
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtCore>
#include <QSqlQuery>
6
#include <QSqlRecord>
Hugo Hörnquist's avatar
Hugo Hörnquist committed
7
8
9
#include <QSqlTableModel>
#include <QTableView>

Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
10
11
#include <QModelIndexList>
#include <QSqlError>
12
#include <QSqlIndex>
Hugo Hörnquist's avatar
Hugo Hörnquist committed
13

14
#include <QSqlRelationalDelegate>
Hugo Hörnquist's avatar
Hugo Hörnquist committed
15
#include <QHeaderView>
16

17
18
#include <QMessageBox>

19
20
#include <QFileInfo>

21
22
23
24
25
26
#include <QPrinter>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <QPainter>
#include "tableprinter.h"

27
28
#include <cstring>

Hugo Hörnquist's avatar
Hugo Hörnquist committed
29
#include "comboboxitemdelegate.h"
30
#include "validatordelegate.h"
Hugo Hörnquist's avatar
Hugo Hörnquist committed
31
#include "moneydelegate.h"
Hugo Hörnquist's avatar
Hugo Hörnquist committed
32
#include "texteditdelegate.h"
33
34
35
#include "maybevalidatordelegate.h"

#include "qintornullvalidator.h"
Hugo Hörnquist's avatar
Hugo Hörnquist committed
36

37
38
#include "serial.h"

Hugo Hörnquist's avatar
Hugo Hörnquist committed
39
40
#define CASH_ACCOUNT "Cash Drawer"
#define VAULT_ACCOUNT "Vault"
Hugo Hörnquist's avatar
Hugo Hörnquist committed
41
#define CASH_NULL NULL
Hugo Hörnquist's avatar
Hugo Hörnquist committed
42

Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
43
// TODO maybe make it somehow possible to remove product
Hugo Hörnquist's avatar
Hugo Hörnquist committed
44
// or have a button to delete all "dead" products
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
45

Hugo Hörnquist's avatar
Hugo Hörnquist committed
46
47
48
49
// TODO magic numbers

// TODO delete buttons in tables should probably also work when only a field is selected

Hugo Hörnquist's avatar
Hugo Hörnquist committed
50
51
// TODO transaction

Hugo Hörnquist's avatar
Hugo Hörnquist committed
52
53
54
// TODO drainage view removal keep selection
//      (the loss is caused by the requery)

Hugo Hörnquist's avatar
Hugo Hörnquist committed
55
56
// acquisitions menu should allow power usage
// - search auto clear?
Hugo Hörnquist's avatar
Hugo Hörnquist committed
57
58
59
60
// - sugested buy from systemet (this is replaced by reading from done acquisitions)

// TODO money diff doesn't update when cash drawer changes elsewhere in program
//      it however still inserts the correct data into the db
61
62
// This binds into most strings not auto updating, and some more needing manual updates

63
64
65
66
67
// TODO stock diff need to exit field before submitting
//      This can lead to a missed field

// TODO stock diff should show null when actual field is null

Hugo Hörnquist's avatar
Hugo Hörnquist committed
68
69
70
71
72
// TODO possibly allow each money account in the database two have
// two nemes. One "true" name, which can alse be used as a key.
// And one "fancy" name, that should never be checked agains, and
// can be allowed to be translated.

73
74
75
76
/*
 * All internal prices should be in öre
 * Never trust a front end number unless you KNOW it's good
 */
Hugo Hörnquist's avatar
Hugo Hörnquist committed
77

Hugo Hörnquist's avatar
Hugo Hörnquist committed
78
79
80
81
82
83
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

84
    setbuf(stdout, NULL);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
85

86
87
    QString HOME = QString::fromLocal8Bit(getenv("HOME"));

Hugo Hörnquist's avatar
Hugo Hörnquist committed
88
    QString port = "/dev/ttyACM0";
89
90
91
    QString db_name = HOME + "/.stupan/stupan.db";

    QFile settingsFile(HOME + "/.stupan/config");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
92
93
94
95
    if (settingsFile.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream in(&settingsFile);
        //qDebug() << f.size() << in.readAll();
        foreach (QString str, in.readAll().split('\n', QString::SkipEmptyParts)) {
96
97
98
			if (str.size() == 0 || str.at(0) == '#')
				continue;

Hugo Hörnquist's avatar
Hugo Hörnquist committed
99
100
101
102
103
104
105
106
            QStringList keyvalue = str.split(' ');
            if (keyvalue.at(0) == "port")
                port = keyvalue.at(1);
            else if (keyvalue.at(0) == "database")
                db_name = keyvalue.at(1);
        }
    }

107
108
    port_name = new char[port.length() + 1];
    std::strcpy(port_name, port.toStdString().c_str());
109
110
    port_setup(port_name, 9600);

Hugo Hörnquist's avatar
Hugo Hörnquist committed
111
112
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");

113
114
115
116
117
118
119
120
121
122
123
124
    QFileInfo db_file_info(db_name);
    if (db_file_info.exists() && db_file_info.isFile()) {
        db.setDatabaseName(db_name);
        if(!db.open())
            qDebug() << __LINE__ << "Database connection failed";
    } else {
        QMessageBox::warning(this, "Error",
            "No database file available\n"
            "Please check that the config path is correct,\n"
            "Otherwise recreate the database");
        QApplication::exit(1);
    }
Hugo Hörnquist's avatar
Hugo Hörnquist committed
125
126
127

    QSqlQuery("PRAGMA FOREIGN_KEYS = ON");

Hugo Hörnquist's avatar
Hugo Hörnquist committed
128
129
    MoneyDelegate* monDel = new MoneyDelegate;

130
    // ============= Product List =======================
Hugo Hörnquist's avatar
Hugo Hörnquist committed
131

Hugo Hörnquist's avatar
Hugo Hörnquist committed
132
133
134
    model = new QSqlTableModel;
    model->setTable("products");

135
    model->setEditStrategy(QSqlTableModel::OnFieldChange);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
136

Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
137
138
    // TODO fix column order in database

Hugo Hörnquist's avatar
Hugo Hörnquist committed
139
140
    model->select();
    model->setHeaderData(0, Qt::Horizontal, "id");
141
    model->setHeaderData(1, Qt::Horizontal, "Sorterings-ID");
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
142
    model->setHeaderData(2, Qt::Horizontal, "Systembolaget ID");
143
    model->setHeaderData(3, Qt::Horizontal, "Streckkod");
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
144
145
146
    model->setHeaderData(4, Qt::Horizontal, "Namn");
    model->setHeaderData(5, Qt::Horizontal, "Pris");
    model->setHeaderData(6, Qt::Horizontal, "Till Salu?");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
147

Hugo Hörnquist's avatar
Hugo Hörnquist committed
148
149
150
151
152
    QObject::connect(
                model, &QSqlTableModel::dataChanged,
                this, &MainWindow::on_productModel_dataChanged
                );

Hugo Hörnquist's avatar
Hugo Hörnquist committed
153
154
155
156
157
    QTableView* view = ui->tableView;
    view->setModel(model);
    view->hideColumn(0); // don't show ID
    view->setEditTriggers(QAbstractItemView::AllEditTriggers);

Hugo Hörnquist's avatar
Hugo Hörnquist committed
158
159
    QIntValidator* anyIntVal = new QIntValidator(INT_MIN, INT_MAX);
    ValidatorDelegate* valDel = new ValidatorDelegate(anyIntVal);
160
    ComboBoxItemDelegate* cbiDel = new ComboBoxItemDelegate(/*view*/);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
161
162
163

    view->setItemDelegateForColumn(1, valDel);
    view->setItemDelegateForColumn(2, valDel);
164
165
166
167
    // TODO this can result in prices with öre, but hidden
    // update sell log to fix in post
    view->setItemDelegateForColumn(5, new MoneyDelegate(0));
    view->setItemDelegateForColumn(6, cbiDel);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
168
169
    view->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    view->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
170

171
172
    setProductFilter();

173
    // ============= Stock ==============================
Hugo Hörnquist's avatar
Hugo Hörnquist committed
174
175
176
177

    QSqlRelationalTableModel* stockModel = new QSqlRelationalTableModel();
    stockModel->setTable("stock");
    stockModel->setHeaderData(0, Qt::Horizontal, "Namn"); // foreign
178
179
    stockModel->setHeaderData(1, Qt::Horizontal, "Lager");
    stockModel->setHeaderData(2, Qt::Horizontal, "Annat lager"); // hidden
Hugo Hörnquist's avatar
Hugo Hörnquist committed
180
181
182
183
184
185
186
187
188
    stockModel->setRelation(0, QSqlRelation("products", "id", "name"));
    stockModel->setSort(0, Qt::AscendingOrder);
    stockModel->select();
    ui->stockView->setModel(stockModel);
    ui->stockView->hideColumn(2);
    ui->stockView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->stockView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
    ui->stockView->setEditTriggers(QAbstractItemView::NoEditTriggers);

189
    // ============= Acquisitions =======================
190

Hugo Hörnquist's avatar
Hugo Hörnquist committed
191
192
193
194
    QSqlQuery("UPDATE my_db_settings SET value = 0 WHERE name = 'acquisitions_temp_transfer'");
    QSqlQuery("DELETE FROM acquisitions_temp");
    QSqlQuery("UPDATE my_db_settings SET value = 1 WHERE name = 'acquisitions_temp_transfer'");

Hugo Hörnquist's avatar
Hugo Hörnquist committed
195
196
197
198
199
    QSqlTableModel* listModel = new QSqlTableModel;
    listModel->setTable("products");
    listModel->setFilter("sale_status IN (0, 1)");
    listModel->setSort(5, Qt::AscendingOrder);
    listModel->setHeaderData(4, Qt::Horizontal, "Namn");
200
    listModel->setHeaderData(5, Qt::Horizontal, "Försäljningspris");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
201
202
    listModel->setHeaderData(6, Qt::Horizontal, "Försäljningsstatus");
    listModel->select();
203

Hugo Hörnquist's avatar
Hugo Hörnquist committed
204
205
    ui->productSearch->setModel(listModel);
    ui->productSearch->hideColumn(0);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
206
207
208
209
210
211
212
213
    ui->productSearch->hideColumn(1);
    ui->productSearch->hideColumn(2);
    ui->productSearch->hideColumn(3);
    ui->productSearch->setItemDelegateForColumn(5, monDel);
    ui->productSearch->setItemDelegateForColumn(6, cbiDel);
    ui->productSearch->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->productSearch->header()->setSectionResizeMode(4, QHeaderView::Stretch);
    ui->productSearch->setEditTriggers(QAbstractItemView::NoEditTriggers);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
214

215
216
    // TODO decide on how to best do input for the price field
    // TODO clear this table on startup, or update the sum below
Hugo Hörnquist's avatar
Hugo Hörnquist committed
217

218
219
    QList<int> disabledColumns;
    disabledColumns << 0 << 1 << 4;
Hugo Hörnquist's avatar
Hugo Hörnquist committed
220
    tempAcquisitionsModel = new DisablingModel(disabledColumns);
221
222
    tempAcquisitionsModel->setTable("acquisitions_temp");
    tempAcquisitionsModel->setHeaderData(0, Qt::Horizontal, "id");
223
    tempAcquisitionsModel->setHeaderData(1, Qt::Horizontal, "Namn"); // foreign
Hugo Hörnquist's avatar
Hugo Hörnquist committed
224
    tempAcquisitionsModel->setHeaderData(2, Qt::Horizontal, "Antal");
225
226
    tempAcquisitionsModel->setHeaderData(3, Qt::Horizontal, "Pris");
    tempAcquisitionsModel->setHeaderData(4, Qt::Horizontal, "Totalt Pris");
227

Hugo Hörnquist's avatar
Hugo Hörnquist committed
228
229
    tempAcquisitionsModel->setEditStrategy(QSqlTableModel::OnFieldChange);

230
    QObject::connect(
Hugo Hörnquist's avatar
Hugo Hörnquist committed
231
                tempAcquisitionsModel, &DisablingModel::dataChanged,
Hugo Hörnquist's avatar
Hugo Hörnquist committed
232
                this, &MainWindow::on_acquisitionModel_dataChanged
233
234
235
236
237
238
239
240
241
                );

    int product_column = tempAcquisitionsModel->fieldIndex("product_id");
    tempAcquisitionsModel->setRelation(product_column, QSqlRelation("products", "id", "name"));

    tempAcquisitionsModel->select();

    QTableView* acView = ui->purchaseView;
    acView->setModel(tempAcquisitionsModel);
242
    acView->hideColumn(0);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
243
    acView->setItemDelegateForColumn(2, valDel);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
244
245
    acView->setItemDelegateForColumn(3, monDel);
    acView->setItemDelegateForColumn(4, monDel);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
246
247
    acView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    acView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
248

249
250
251
252
253
254
255
256
257
258
259
260
    // TODO this combo box isn't updated when new accounts are added.
    ui->submitBuyAccountCombo->clear();
    QSqlQuery accQuery("SELECT id, name FROM money WHERE amount IS NOT NULL");
    while (accQuery.next()) {
        QString name = accQuery.value(1).toString();
        QVariant value = accQuery.value(0);
        ui->submitBuyAccountCombo->addItem(name, value);
    }

    // We usually want the "Vault" account. So we select it by default.
    ui->submitBuyAccountCombo->setCurrentIndex(1);

261
    // ============== Stock Check =======================
262

263
    clear_stockDiffTemp();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
264

Hugo Hörnquist's avatar
Hugo Hörnquist committed
265
    QList<int> inventoryCheckDisabled;
266
    inventoryCheckDisabled << 0 << 1 << 2 << 3 << 4 << 6;
Hugo Hörnquist's avatar
Hugo Hörnquist committed
267
    DisablingModel* inventoryModel = new DisablingModel(inventoryCheckDisabled);
268
    inventoryModel->setTable("diff_view");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
269
    inventoryModel->setHeaderData(0, Qt::Horizontal, "id");
270
271
272
273
274
275
276
    inventoryModel->setHeaderData(1, Qt::Horizontal, "product id");
    inventoryModel->setHeaderData(2, Qt::Horizontal, "sale status");
    inventoryModel->setHeaderData(3, Qt::Horizontal, "Namn");
    inventoryModel->setHeaderData(4, Qt::Horizontal, "Förväntat");
    inventoryModel->setHeaderData(5, Qt::Horizontal, "Faktiskt");
    inventoryModel->setHeaderData(6, Qt::Horizontal, "Diff");

Hugo Hörnquist's avatar
Hugo Hörnquist committed
277
278
    inventoryModel->setEditStrategy(QSqlTableModel::OnFieldChange);

279
280
    QObject::connect(inventoryModel, &QAbstractItemModel::dataChanged,
                     this, &MainWindow::on_inventoryModel_dataChanged);
281

Hugo Hörnquist's avatar
Hugo Hörnquist committed
282
283
284
285
    inventoryModel->select();
    ui->inventoryCheckView->setModel(inventoryModel);
    ui->inventoryCheckView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->inventoryCheckView->setEditTriggers(QAbstractItemView::AllEditTriggers);
286
287
    QIntOrNullValidator* intOrNullVal = new QIntOrNullValidator(INT_MIN, INT_MAX);
    MaybeValidatorDelegate* maybeValDel = new MaybeValidatorDelegate(intOrNullVal);
288
    ui->inventoryCheckView->setItemDelegateForColumn(5, maybeValDel);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
289
    ui->inventoryCheckView->hideColumn(0);
290
291
292
    ui->inventoryCheckView->hideColumn(1);
    ui->inventoryCheckView->hideColumn(2);

293
294
    ui->quickInventoryCheckBox->setChecked(true);

295
    // -------------- Money Check -----------------------
Hugo Hörnquist's avatar
Hugo Hörnquist committed
296
297
298
299

    setMoneyDiffLabels();

    ui->diffDrawer->setValidator(anyIntVal);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
300

301
    // ============== Drainage ==========================
Hugo Hörnquist's avatar
Hugo Hörnquist committed
302

Hugo Hörnquist's avatar
Hugo Hörnquist committed
303
304
    // TODO some of these things possibly should requery under usage
    // Autoupdate, as it's called
305
306


307
    // TODO set column names in frontend instead of in query
308
309
310
311
    QSqlQueryModel* drainageModel = new QSqlQueryModel();
    drainageModel->setQuery("SELECT id, "
                            "    datetime(start_time, 'localtime') AS Starttid, "
                            "    datetime(end_time, 'localtime') AS Sluttid, "
312
313
314
                            "    decrease AS [Kr/Tid],"
                            "    how_often_minutes AS [Hur ofta], "
                            "    min_price AS [Minimipris] "
315
316
317
318
                            "FROM drainage "
                            "WHERE strftime('%s', start_time) > strftime('%s', 'now') "
                            "ORDER BY start_time");
    ui->drainageView->setModel(drainageModel);
319
    ui->drainageView->hideColumn(0);
320
321
    ui->drainageView->setItemDelegateForColumn(3, monDel);
    ui->drainageView->setItemDelegateForColumn(5, monDel);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
322
    ui->drainageView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
323

324
325
    // TODO making the end smaller can make the start smaller

Hugo Hörnquist's avatar
Hugo Hörnquist committed
326
327
328
329
330
331
332
333
    QDateTime now = QDateTime::currentDateTime();
    //ui->startTimeDateTimeEdit->setMinimumDateTime(now);
    ui->endTimeDateTimeEdit->setMinimumDateTime(now);
    ui->startTimeDateTimeEdit->setDateTime(now);
    ui->endTimeDateTimeEdit->setDateTime(now);

    updateCurrentDrainageStatus();

334
335
    // TODO past drainages

336
    // ============= Money ==============================
337

338
339
340
341
342
343
    QSqlTableModel* accModel = new QSqlTableModel();
    ui->accTreeView->setModel(accModel);
    accModel->setTable("money_simple");
    accModel->select();
    accModel->setHeaderData(0, Qt::Horizontal, "Namn");
    accModel->setHeaderData(1, Qt::Horizontal, "Kronor");
344
    // Don't actualy try to submit on this table
345
    accModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
346
    ui->accTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
347

348
    setMoneyAccountValues();
349

350
    setAccTransferCombo();
351
352
353
354
355
356
357
358
359
360
361
362
363
364

    QSqlTableModel* transHistoryModel = new QSqlTableModel();
    ui->moneyTransferHistory->setModel(transHistoryModel);
    transHistoryModel->setTable("money_transfers_simple");
    transHistoryModel->select();
    transHistoryModel->setHeaderData(0, Qt::Horizontal, "Tid");
    transHistoryModel->setHeaderData(1, Qt::Horizontal, "Från");
    transHistoryModel->setHeaderData(2, Qt::Horizontal, "Till");
    transHistoryModel->setHeaderData(3, Qt::Horizontal, "Summa");
    transHistoryModel->setHeaderData(4, Qt::Horizontal, "Notering");
    // Don't actualy try to submit on this table
    transHistoryModel->setEditStrategy(QSqlTableModel::OnManualSubmit);

    ui->moneyTransferHistory->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
365

366
    // ============= SQL ================================
367
368
369
370
371
372
373
374
375
376
377
378
379

    QSqlQueryModel* sqlQueryModel = new QSqlQueryModel;
    ui->sqlOutput->setModel(sqlQueryModel);

    QSqlTableModel* sqlQueryListModel = new QSqlTableModel;
    sqlQueryListModel->setTable("sql_queries");
    sqlQueryListModel->select();
    sqlQueryListModel->setHeaderData(0, Qt::Horizontal, "id");
    sqlQueryListModel->setHeaderData(1, Qt::Horizontal, "Namn");
    sqlQueryListModel->setHeaderData(2, Qt::Horizontal, "Query");
    ui->sqlBufferList->setModel(sqlQueryListModel);
    ui->sqlBufferList->hideColumn(0);
    ui->sqlBufferList->hideColumn(2);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
380
    ui->sqlBufferList->sortByColumn(1);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
381
382
383
384
385
386
387
}

MainWindow::~MainWindow()
{
    delete ui;
}

388
389
void MainWindow::updateMoneyString()
{
390
391
    setMoneyDiffLabels();
    setMoneyAccountValues();
392
    ((QSqlTableModel*) ui->moneyTransferHistory->model())->select();
393
394
}

395
396
397
398
399
400
401
void MainWindow::setAccTransferCombo() {

    ui->accTransferFrom->clear();
    ui->accTransferTo->clear();

    QSqlQuery accQuery("SELECT id, name FROM money");
    while (accQuery.next()) {
402
403
404
405
        QString name = accQuery.value(1).toString();
        QVariant value = accQuery.value(0);
        ui->accTransferFrom->addItem(name, value);
        ui->accTransferTo->addItem(name, value);
406
407
408
    }
}

409
410
411
412
413
414
415
void MainWindow::setMoneyAccountValues() {
    QSqlTableModel* accModel = (QSqlTableModel*) ui->accTreeView->model();

    accModel->select();

    QSqlRecord rec = accModel->record();

Hugo Hörnquist's avatar
Hugo Hörnquist committed
416
    QVariant projected_price = get_projected_stock_value();
417
    rec.setValue("name", QVariant("Lager (projicerat)"));
Hugo Hörnquist's avatar
Hugo Hörnquist committed
418
    rec.setValue("amount", QVariant(formatMoney(projected_price.toDouble() / 100.0)));
419
420
    accModel->insertRecord(-1, rec);

Hugo Hörnquist's avatar
Hugo Hörnquist committed
421
    QVariant buy_price = get_acquistion_stock_value();
422
    rec.setValue("name", QVariant("Lager (inköp)"));
Hugo Hörnquist's avatar
Hugo Hörnquist committed
423
    rec.setValue("amount", QVariant(formatMoney(buy_price.toDouble() / 100.0)));
424
    accModel->insertRecord(-1, rec);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
425
426
427
428
429
430
431
432
433
434
435
436
437

    QSqlQuery query("SELECT sum(amount) FROM money");
    if (query.next()) {
        qlonglong sum = query.value(0).toLongLong()
                        + projected_price.toLongLong();
        rec.setValue("name", QVariant("Totalt (projicerat)"));
        rec.setValue("amount", QVariant(formatMoney((double) sum / 100.0)));
        accModel->insertRecord(-1, rec);
    }
}

QString MainWindow::formatMoney(double in){
    return QString("%1").arg(in, 0, 'f', 2);
438
439
}

440
441
442
443
444
445
446
447
448
/*
 * This updates the QSqlTableModel to contain the same data as the database.
 * This is needed since it looks at a view, and can therefore not find the
 * primary key. Requiring all the fields in the front-end and back-end database
 * to have the exact same fields.
 *
 * So, the calculations here are also done in the database, and those are what
 * should be used when doing further stuff with the data.
 */
449
void MainWindow::on_inventoryModel_dataChanged(const QModelIndex &topLeft, const QModelIndex& /*bottomRight*/, const QVector<int>& /*roles*/)
Hugo Hörnquist's avatar
Hugo Hörnquist committed
450
{
451
452
453
454
455
456
457
458
459
460
    QSqlTableModel* model = (QSqlTableModel*) ui->inventoryCheckView->model();

    if (model->isDirty()) {
        int row = topLeft.row();

        bool number;
        int expected = model->data(model->index(row, 4)).toInt();
        int actual = model->data(model->index(row, 5)).toInt(&number);

        model->setData(model->index(row, 6),
461
                       number ? actual - expected
462
463
                              : QVariant());
    }
Hugo Hörnquist's avatar
Hugo Hörnquist committed
464
465
}

Hugo Hörnquist's avatar
Hugo Hörnquist committed
466
/*
467
468
469
 * This updates acquisitions with the new names when products are edited.
 * TODO inventeringssystemet uppdateras inte här, bör det göra det?
 * TODO inte heller lager-status, dock har den en refresh knapp.
Hugo Hörnquist's avatar
Hugo Hörnquist committed
470
 */
471
void MainWindow::on_productModel_dataChanged(const QModelIndex& /*topLeft*/, const QModelIndex& /*bottmRight*/, const QVector<int>& /*roles*/)
Hugo Hörnquist's avatar
Hugo Hörnquist committed
472
{
473
474
475
    // TODO this is possibly quite slow, test on slow system.
    ((QSqlTableModel*) ui->productSearch->model())->select();
    ((QSqlTableModel*) ui->purchaseView->model())->select();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
476
477
478
479
480
481
}

/*
 * Calculates the total price in the acquisitions menu
 */
void MainWindow::on_acquisitionModel_dataChanged(QModelIndex topLeft, QModelIndex /* bottomRight */) {
482
483
484
    int row = topLeft.row();
    int col = topLeft.column();

485
    // only the amount and price should be editable anyways
486
    if (col == 2 || col == 3) {
487
488
        int amount = tempAcquisitionsModel->data(tempAcquisitionsModel->index(row, 2)).toInt();
        int price = tempAcquisitionsModel->data(tempAcquisitionsModel->index(row, 3)).toInt();
489
        tempAcquisitionsModel->setData(tempAcquisitionsModel->index(row, 4), amount * price);
490
    }
491
492
493
494
495

    QSqlQuery query("SELECT sum(total_price) FROM acquisitions_temp");
    query.next();
    double total = query.value(0).toDouble() / 100.0;
    ui->totalPriceLabel->setText(QString("%L1").arg(total));
496
497
}

498
void MainWindow::on_checkBox_toggled(bool /*checked*/)
Hugo Hörnquist's avatar
Hugo Hörnquist committed
499
{
500
    setProductFilter();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
501
502
}

Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
503
504
505
// Add new row for new product
void MainWindow::on_newItemButton_clicked()
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
506
    // trigger creates stock entry
Hugo Hörnquist's avatar
Hugo Hörnquist committed
507
    QSqlQuery("INSERT INTO products DEFAULT VALUES");
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
508
    model->select();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
509
510

    ui->buySearch->setText("");
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
511
512
}

Hugo Hörnquist's avatar
Hugo Hörnquist committed
513
514
// TODO can't remove item which is used elsewhere,
//      currently fails silently.
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
515
516
517
518
519
520
void MainWindow::on_deleteButton_clicked()
{
    QItemSelectionModel* selection = ui->tableView->selectionModel();
    if (!selection->hasSelection()) return;
    QModelIndexList lst = selection->selectedRows();
    foreach ( QModelIndex index, lst ) {
521
        model->removeRow(index.row());
Hugo Hörnquist's avatar
work    
Hugo Hörnquist committed
522
523
    }
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
524
525
526
527
528
529

void MainWindow::on_buyAddBtn_clicked()
{
    // Only a single line should really be able to be selected at a time
    QItemSelectionModel* model = ui->productSearch->selectionModel();
    foreach (QModelIndex index, model->selectedRows(0)) {
Hugo Hörnquist's avatar
Hugo Hörnquist committed
530
        QVariant id = index.data();
531
532
533
534
        QSqlQuery query;
        query.prepare("INSERT INTO acquisitions_temp (product_id) VALUES (:id)");
        query.bindValue(":id", id);
        query.exec();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
535
536
537
538
539

        tempAcquisitionsModel->select();

        QSqlQuery price_query;
        price_query.prepare("SELECT item_price FROM acquisitions "
540
541
542
                            "WHERE product_id = :id "
                            "ORDER BY time DESC "
                            "LIMIT 1");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
543
544
545
546
547
548
549
        price_query.bindValue(":id", id);
        price_query.exec();
        if (price_query.next())
            tempAcquisitionsModel->setData(
                tempAcquisitionsModel->index(
                    tempAcquisitionsModel->rowCount() - 1, 3),
                price_query.value(0));
Hugo Hörnquist's avatar
Hugo Hörnquist committed
550
551
    }

Hugo Hörnquist's avatar
Hugo Hörnquist committed
552

553
554
}

Hugo Hörnquist's avatar
Hugo Hörnquist committed
555
556
// TODO possibly updated sale status from hidden to not_for_sale
// when search is numeric (barcode)
557
void MainWindow::on_buySearch_textChanged(const QString &arg1)
558
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
559
560
561
562
563
564
565
566
567
568
569
    bool isNumber;
    arg1.toInt(&isNumber, 10);
    QString filter = QString(
                isNumber
                ? "bar_code = '%1'"
                : "name LIKE '\%%1\%' AND sale_status IN (0, 1)"
                ).arg(arg1);

    QSqlTableModel* model = ((QSqlTableModel*) ui->productSearch->model());
    model->setFilter(filter);
    model->select();
570
571
}

Hugo Hörnquist's avatar
Hugo Hörnquist committed
572
573
/*
 * data is transfered from acquisitions_temp to acquisitions on delete via trigger
574
 *
Hugo Hörnquist's avatar
Hugo Hörnquist committed
575
 */
576
577
void MainWindow::on_submitBuyButton_clicked()
{
578
579
580
581
582
583
584
585
586
587
588
    QVariant activeAccount = ui->submitBuyAccountCombo->currentData();

    // TODO is this safe?
    // Or could some other process modify active_money_account while
    // the acquisitions_temp triggers fire?
    QSqlDatabase::database().transaction();
    QSqlQuery query;
    query.prepare("UPDATE my_db_settings SET value = :account WHERE "
                  "name = 'active_money_account'");
    query.bindValue(":account", activeAccount);
    query.exec();
589
    QSqlQuery("DELETE FROM acquisitions_temp");
590
591
592
593
    if (! QSqlDatabase::database().commit()) {
        qDebug() << QSqlDatabase::database().lastError();
        //QMessageBox::warning( this, "SQL Querry error", "Error while executing query\n\n " + model->lastError().text());
    }
Hugo Hörnquist's avatar
Hugo Hörnquist committed
594

595
    tempAcquisitionsModel->select();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
596
    updateMoneyString();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
597
    ((QSqlRelationalTableModel*) ui->stockView->model())->select();
598
599

    open_till();
600
601
602
603
604
605
606
607
}

void MainWindow::on_buyRemoveButton_clicked()
{
    foreach (QModelIndex row, ui->purchaseView->selectionModel()->selectedRows()) {
        tempAcquisitionsModel->removeRow(row.row());
    }
    tempAcquisitionsModel->select();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
608
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
609

Hugo Hörnquist's avatar
Hugo Hörnquist committed
610
611
void MainWindow::on_addDrainageButton_clicked()
{
612
613
614
    // Products to go from crown to öre
    QVariant per_hour = ui->amountPerHourSpinBox->value() * 100;
    QVariant min_price = ui->minPriceSpinBox->value() * 100;
Hugo Hörnquist's avatar
Hugo Hörnquist committed
615
    QVariant how_often = ui->howOftenSpinBox->value();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
616

617
618
619
    QDateTime start_time = ui->startTimeDateTimeEdit->dateTime().toUTC();
    QDateTime end_time = ui->endTimeDateTimeEdit->dateTime().toUTC();

620
	/*
621
    if (end_time < QDateTime::currentDateTime().toUTC()) {
Hugo Hörnquist's avatar
Hugo Hörnquist committed
622
        QMessageBox::warning(this, "Error", "Kan inte skapa tömmning helt i det förflutna");
623
624
625
626
627
        return;
    }

    // This shouldn't be able to happen due to the end_time min being set to start_time
    if (start_time > end_time) {
Hugo Hörnquist's avatar
Hugo Hörnquist committed
628
        QMessageBox::warning(this, "Error", "Jag går inte med på krökningar i rumtiden!");
629
630
        return;
    }
631
	*/
632

633
634
    // drainages always start and end on a whole minute
    QString timeStr = "yyyy-MM-dd hh:mm:00";
635
636
    QVariant start_str = start_time.toString(timeStr);
    QVariant end_str = end_time.toString(timeStr);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
637
638
639
640

    QSqlQuery query;
    query.prepare ("INSERT INTO drainage (start_time, end_time, decrease, how_often_minutes, min_price) "
                   "VALUES (:start, :end, :dec, :often, :min)");
641
642
    query.bindValue(":start", start_str);
    query.bindValue(":end", end_str);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
643
644
645
646
    query.bindValue(":min", min_price);
    query.bindValue(":dec", per_hour);
    query.bindValue(":often", how_often);

Hugo Hörnquist's avatar
Hugo Hörnquist committed
647
    if (!query.exec()) {
Hugo Hörnquist's avatar
Hugo Hörnquist committed
648
        qDebug() << query.lastError();
649
		// Drainages in the past, overlapping, or with negative time spans
Hugo Hörnquist's avatar
Hugo Hörnquist committed
650
651
        QMessageBox::warning(this, "Error", query.lastError().databaseText());
    }
Hugo Hörnquist's avatar
Hugo Hörnquist committed
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700

    updateDrainageView();
    updateCurrentDrainageStatus();

}

void MainWindow::updateDrainageView()
{
    QSqlQueryModel* model = (QSqlQueryModel*) ui->drainageView->model();
    QString queryStr = model->query().executedQuery();
    model->clear();
    model->setQuery(queryStr);
}

void MainWindow::on_timeZoneComboBox_currentIndexChanged(int index)
{
    // TODO magic number
    Qt::TimeSpec spec = index == 0 ? Qt::LocalTime : Qt::UTC;
    QDateTimeEdit* startEdit = ui->startTimeDateTimeEdit;
    QDateTimeEdit* endEdit   = ui->endTimeDateTimeEdit;

    startEdit->setTimeSpec(spec);
    endEdit->setTimeSpec(spec);

    // This is to update the ui
    startEdit->setDateTime(startEdit->dateTime());
    endEdit->setDateTime(endEdit->dateTime());
}

void MainWindow::on_startTimeDateTimeEdit_dateTimeChanged(const QDateTime &dateTime)
{
    ui->endTimeDateTimeEdit->setMinimumDateTime(dateTime);
}

void MainWindow::on_removeDrainageButton_clicked()
{
    // TODO batch, even though only a single value can be selected at a time currently
    foreach ( QModelIndex i, ui->drainageView->selectionModel()->selectedRows(0) ) {
        QSqlQuery query;
        query.prepare("DELETE FROM drainage WHERE id = :id");
        query.bindValue(":id", i.data());
        if (!query.exec())
            qDebug() << query.lastError();
    }
    updateDrainageView();
}

void MainWindow::on_cancelDrainageButton_clicked()
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
701
    QSqlQuery("UPDATE drainage SET end_time = CURRENT_TIMESTAMP "
Hugo Hörnquist's avatar
Hugo Hörnquist committed
702
              "WHERE CURRENT_TIMESTAMP BETWEEN start_time AND end_time");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
703
704

    // TODO this should be done 1 secound later
Hugo Hörnquist's avatar
Hugo Hörnquist committed
705
706
707
708
709
710
711
712
713
714
715
716
717
    updateCurrentDrainageStatus();
}

void MainWindow::on_updateCurrentDrainageButton_clicked()
{
    updateCurrentDrainageStatus();
}

// TODO this should preferably also be called when a drainage starts
// due to the passage of time

void MainWindow::updateCurrentDrainageStatus()
{
718
    // division to get crowns
Hugo Hörnquist's avatar
Hugo Hörnquist committed
719
720
    QSqlQuery currentDrainageQuery("SELECT datetime(start_time, 'localtime'), "
                                   "       datetime(end_time, 'localtime'), "
721
                                   "       decrease / 100.0, "
Hugo Hörnquist's avatar
Hugo Hörnquist committed
722
                                   "       how_often_minutes, "
723
                                   "       min_price / 100.0 "
Hugo Hörnquist's avatar
Hugo Hörnquist committed
724
725
726
727
728
729
730
                                   "FROM drainage "
                                   "WHERE CURRENT_TIMESTAMP BETWEEN start_time AND end_time "
                                   "LIMIT 1");

    if (currentDrainageQuery.next()) {
        QString startStr    = currentDrainageQuery.value(0).toString();
        QString endStr      = currentDrainageQuery.value(1).toString();
731
        double decreaseStr = currentDrainageQuery.value(2).toDouble();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
732
        QString minutesStr  = currentDrainageQuery.value(3).toString();
733
        double minStr      = currentDrainageQuery.value(4).toDouble();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
734
        ui->drainageLabel->setText(QString("%1 kr/%2 min, ner till %3 kr\nMellan %4 och %5 lokal tid")
735
                                   .arg(decreaseStr, 0, 'f', 2)
Hugo Hörnquist's avatar
Hugo Hörnquist committed
736
                                   .arg(minutesStr)
737
                                   .arg(minStr, 0, 'f', 2)
Hugo Hörnquist's avatar
Hugo Hörnquist committed
738
739
740
741
                                   .arg(startStr)
                                   .arg(endStr));
        ui->cancelDrainageButton->setVisible(true);
    } else {
742
        ui->drainageLabel->setText("Ingen pågående tömning");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
743
744
745
        ui->cancelDrainageButton->setVisible(false);
    }
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
746

Hugo Hörnquist's avatar
Hugo Hörnquist committed
747
748
749
750
void MainWindow::on_stockRefreshButton_clicked()
{
    ((QSqlRelationalTableModel*) ui->stockView->model())->select();
}
751

Hugo Hörnquist's avatar
Hugo Hörnquist committed
752
753
void MainWindow::on_diffSubmit_clicked()
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
754
755
756
    QString str = ui->diffDrawer->text();
    if (str == "") return;
    int total = str.toInt() * 100;
Hugo Hörnquist's avatar
Hugo Hörnquist committed
757
    QSqlQuery query;
758
759
    query.prepare("INSERT INTO money_diffs (actual, expected, account) "
                  "SELECT :total, amount, id "
Hugo Hörnquist's avatar
Hugo Hörnquist committed
760
761
762
763
764
                  " FROM money WHERE name = 'Cash Drawer'");
    query.bindValue(":total", total);
    if (!query.exec())
        qDebug() << query.lastError();

765

Hugo Hörnquist's avatar
Hugo Hörnquist committed
766
767
    ui->diffDrawer->setText("");
    setMoneyDiffLabels();
Hugo Hörnquist's avatar
Hugo Hörnquist committed
768
769
770
771
}

void MainWindow::on_diffDrawer_textChanged(const QString &arg1)
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
772
773
    int new_total = arg1.toInt() * 100;
    setMoneyDiffLabels(new_total);
Hugo Hörnquist's avatar
Hugo Hörnquist committed
774
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
775
776
777

void MainWindow::on_submitStockDiff_clicked()
{
Hugo Hörnquist's avatar
Hugo Hörnquist committed
778
    QSqlQuery("DELETE FROM diff_view");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
779
780
    ((QSqlRelationalTableModel*) ui->inventoryCheckView->model())->select();
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
781
782
783
784
785
786
787

int MainWindow::setMoneyDiffLabels()
{
    QSqlQuery query("SELECT amount FROM money WHERE name = 'Cash Drawer'");
    query.next();
    int expected = query.value(0).toInt();
    QString diff_text = QString("%1 kr").arg(expected / 100.0, 0, 'f', 2);
788
789
790
791
792

    // This might seem like a mistake at first sight, though it isn't.
    // This just sets a default value for diffTotal. The new value is
    // calculated and set in setMoneyDiffLabels(int new_total)

Hugo Hörnquist's avatar
Hugo Hörnquist committed
793
794
795
796
797
798
799
800
801
802
803
    ui->diffExpected->setText(diff_text);
    ui->diffTotal->setText(diff_text);

    return expected;
}

void MainWindow::setMoneyDiffLabels(int new_total)
{
    double diff = new_total - setMoneyDiffLabels();
    ui->diffTotal->setText(QString("%1 kr").arg(diff / 100.0, 0, 'f', 2));
}
804
805
806
807
808
809
810
811

void MainWindow::on_openTillButton_clicked()
{
    open_till();
}

void MainWindow::open_till()
{
812
    port_write(port_name, '1');
813
}
814
815
816
817
818

void MainWindow::on_stockDiffReset_clicked()
{
    clear_stockDiffTemp();

Hugo Hörnquist's avatar
Hugo Hörnquist committed
819
    ((QSqlTableModel*) ui->inventoryCheckView->model())->select();
820
821
}

Hugo Hörnquist's avatar
Hugo Hörnquist committed
822
// this also inserts the new needed data into diff_help
823
824
825
826
void MainWindow::clear_stockDiffTemp()
{
    // TODO transaction
    QSqlQuery("UPDATE my_db_settings SET value = 0 WHERE name = 'stock_diff_temp_transfer'");
Hugo Hörnquist's avatar
Hugo Hörnquist committed
827
    QSqlQuery("DELETE FROM diff_help");
828
829
    QSqlQuery("UPDATE my_db_settings SET value = 1 WHERE name = 'stock_diff_temp_transfer'");
}
830
831
832

QVariant MainWindow::get_acquistion_stock_value()
{
833
    qlonglong total_price = 0;
834
835
836
837
    QSqlQuery tQuery("SELECT s.product_id as id, s.active as active, p.name "
                     "FROM stock s INNER JOIN products p "
                     "ON s.product_id = p.id");
    while (tQuery.next()) {
838
        // qDebug() << __LINE__;
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
        long target = tQuery.value("active").toLongLong();

        if (target < 0) continue;

        QSqlQuery query;
        query.prepare("SELECT id, time, product_id, item_price, amount "
                      "FROM acquisitions WHERE product_id = :id "
                      "ORDER BY time DESC");
        query.bindValue(":id", tQuery.value("id"));
        query.exec();

        long amount = 0;
        long total_product_price = 0;
        while (query.next()) {
            long sub_amount = query.value("amount").toLongLong();
            long item_price = query.value("item_price").toLongLong();
855
            // qDebug() << __LINE__ << amount << sub_amount;
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
            if (amount + sub_amount > target) {
                total_product_price += (target - amount) * item_price;
                amount = target;
                break;
            } else {
                amount += sub_amount;
                total_product_price += sub_amount * item_price;
            }

        }
        total_price += total_product_price;
    }

    return QVariant(total_price);
}

QVariant MainWindow::get_projected_stock_value() {
    QSqlQuery query("SELECT SUM(p.price * s.active) "
                    "FROM products p "
                    "INNER JOIN stock s ON "
                    "p.id = s.product_id");
    if (query.next())
        return query.value(0);
    return QVariant::Int;

}

883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
void MainWindow::setProductFilter()
{
    QString searchStr = ui->productListSearch->text();

    bool isNumber;
    searchStr.toInt(&isNumber, 10);

    QString filter = QString(
                isNumber
                ? "bar_code = '%1'"
                : "name LIKE '\%%1\%' "
                ).arg(searchStr);

    if (ui->checkBox->isChecked()) {
        filter.append ("AND sale_status >= 0");
    } else {
        filter.append ("AND sale_status IN (0, 1)");
    }

    QSqlTableModel* model = ((QSqlTableModel*) ui->tableView->model());
    model->setFilter(filter);
    model->select();
}

void MainWindow::on_productListSearch_textChanged(const QString &arg1)
{
    setProductFilter();
}
911

912
913
914
915
916
/*
 * Note that the hidden rows can still contain data that WILL be
 * submitted.
 * TODO Possibly have some form of warning when it comes to that.
 */
917
918
void MainWindow::on_quickInventoryCheckBox_toggled(bool checked)
{
919
920
921
922
    ((QSqlRelationalTableModel*) ui->inventoryCheckView->model())
            ->setFilter( checked
                         ? "sale_status = 0 or expected != 0"
                         : "sale_status in (0, 1)");
923
}
Hugo Hörnquist's avatar
Hugo Hörnquist committed
924
925
926
927
928
929

void MainWindow::on_moneyDiffReload_clicked()
{
    ui->diffDrawer->setText("");
    setMoneyDiffLabels();
}
930
931
932
933
934
935

void MainWindow::on_accTransferSubmit_clicked()
{
    qlonglong amount = ui->accTransferAmonut->value() * 100;
    qlonglong from   = ui->accTransferFrom->currentData().toLongLong();
    qlonglong to     = ui->accTransferTo->currentData().toLongLong();
936
    QString text     =  ui->accTransferText->toPlainText();
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

    if (amount == 0 || from == to) return;

    qDebug() << amount << from << to << text;

    QSqlQuery query;
    query.prepare("INSERT INTO money_transfers (change, from_acc, to_acc, note) "
                  "VALUES (:amount, :from, :to, :note)");
    query.bindValue(":amount", amount);
    query.bindValue(":from", from);
    query.bindValue(":to", to);
    query.bindValue(":note", text.isEmpty() ? QVariant::String : QVariant(text));
    if (!query.exec())
        qDebug() << query.lastError();

    ui->accTransferAmonut->setValue(0);
    ui->accTransferFrom->setCurrentIndex(0);
    ui->accTransferTo->setCurrentIndex(0);
955
    ui->accTransferText->setPlainText("");
956
957

    // TODO update money values
958
959

    updateMoneyString();
960
}
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989

void MainWindow::on_accUpdateBtn_clicked()
{
    setMoneyAccountValues();
}

void MainWindow::on_accNewAccBtn_clicked()
{
    QString name = ui->accNewAccText->text();
    if (name.isEmpty()) return;

    QSqlQuery query;
    query.prepare("INSERT INTO money (name) VALUES (:name)");
    query.bindValue(":name", name);
    if (!query.exec()) {
        qDebug() << query.lastError();
        if (query.lastError().text().contains("UNIQUE")) {
            QMessageBox::warning(this, "Add failed",
                                 "Account with that name probably already exitst. "
                                 "It's either that, or that SQLite have bad error messages");
            return;
        }
    }

    ui->accNewAccText->setText("");

    setMoneyAccountValues();
    setAccTransferCombo();
}
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049

void MainWindow::setSqlQuery(qlonglong id)
{
    QSqlQuery query;
    query.prepare("SELECT name, query FROM sql_queries "
                  "WHERE id = :id");
    query.bindValue(":id", id);
    query.exec();

    if (query.next()) {
        ui->sqlBufferName->setText(query.value(0).toString());
        ui->sqlEdit->setPlainText(query.value(1).toString());
    }
}

void MainWindow::setSqlQuery(QString name)
{
    QSqlQuery query;
    query.prepare("SELECT name, query FROM sql_queries "
                  "WHERE name = :name");
    query.bindValue(":name", name);
    query.exec();

    if (query.next()) {
        ui->sqlBufferName->setText(query.value(0).toString());
        ui->sqlEdit->setPlainText(query.value(1).toString());
    }
}

void MainWindow::on_sqlBufferList_activated(const QModelIndex &index)
{
    QAbstractItemModel* model = ui->sqlBufferList->model();
    qlonglong id = model->data(model->index(index.row(), 0)).toLongLong();
    setSqlQuery(id);
}

void MainWindow::on_sqlLoad_clicked()
{
    setSqlQuery(ui->sqlBufferName->text());
}

void MainWindow::on_sqlSave_clicked()
{
    // QSqlTableModel* model = (QSqlTableModel*) ui->sqlBufferList->model();

    QSqlQuery query;
    query.prepare("INSERT OR REPLACE "
                  "INTO sql_queries (name, query) "
                  "VALUES (:name, :query)");
    query.bindValue(":name", ui->sqlBufferName->text());
    query.bindValue(":query", ui->sqlEdit->toPlainText());
    query.exec();

    ((QSqlTableModel*) ui->sqlBufferList->model())->select();
}

void MainWindow::on_sqlOutReload_clicked()
{
    QSqlQueryModel* model = (QSqlQueryModel*) ui->sqlOutput->model();
    model->setQuery(ui->sqlEdit->toPlainText());
1050
1051
1052
1053
1054
1055
1056
1057

    if (model->lastError().isValid()) {
        QMessageBox::warning(
                    this, "SQL Querry error",
                    "Error while executing query\n\n " + model->lastError().text());
        return;
    }

1058
1059
    ui->tabWidget_2->setCurrentIndex(0);
}
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096

void MainWindow::printTable(QPrinter* printer)
{
    QPainter painter;
    if (!painter.begin(printer)) {
        qWarning() << "can't start printer";
        return;
    }

    QSqlQueryModel* model = (QSqlQueryModel*) ui->sqlOutput->model();

    TablePrinter tablePrinter(&painter, printer);

    QVector<int> columnStretch = QVector<int>();
    QVector<QString> headers = QVector<QString>();
    for (int i = 0; i <  model->columnCount(); i++) {
        columnStretch << 1;
        headers << model->headerData(i, Qt::Horizontal).toString();
    }

    QFont headerFont;
    headerFont.setBold(true);
    tablePrinter.setHeadersFont(headerFont);

    if (!tablePrinter.printTable(ui->sqlOutput->model(), columnStretch, headers)) {
        qDebug() << tablePrinter.lastError();
    }

    painter.end();
}

void MainWindow::on_sqlPrint_clicked()
{
    QPrintPreviewDialog dialog;
    connect(&dialog, SIGNAL(paintRequested(QPrinter*)), this, SLOT(printTable(QPrinter*)));
    dialog.exec();
}
1097
1098
1099
1100
1101
1102

void MainWindow::on_sqlBufferDeleteButton_clicked()
{
    QSqlTableModel* model = (QSqlTableModel*) ui->sqlBufferList->model();

    QSqlQuery query;
Hugo Hörnquist's avatar
Hugo Hörnquist committed
1103
    query.prepare("DELETE FROM sql_queries WHERE id = ?");
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116

    QVariantList ids;
    foreach (QModelIndex index,  ui->sqlBufferList->selectionModel()->selectedRows())
    {
        ids << model->data(model->index(index.row(), 0));
    }
    query.addBindValue(ids);

    if (!query.execBatch())
        qDebug() << query.lastError();

    model->select();
}