kima2/src/gui/mainwindow.cpp

418 lines
14 KiB
C++

#include "mainwindow.h"
#include "basketmodel.h"
#include "config.h"
#include "jsonutil.h"
#include "pricedialog.h"
#include "reportdialog.h"
#include "salemodel.h"
#include "sellerdialog.h"
#include "settingsdialog.h"
#include <excelreader.h>
#include <posprinter.h>
#include <exception>
#include <regex>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QStandardPaths>
#include <QtGui/QDesktopServices>
constexpr int STATUSBAR_TIMEOUT = 5000;
MainWindow::MainWindow()
{
ui_.setupUi(this);
marketplace_ = std::make_unique<Marketplace>();
marketplace_->loadFromDb();
statusBar()->showMessage("Gespeicherte Daten wurden geladen.", STATUSBAR_TIMEOUT);
BasketModel* model = new BasketModel(getMarketplace(), ui_.basketView);
ui_.basketView->setModel(model);
ui_.basketView->setColumnHidden(0, true); // hide the uuid
setWindowTitle("KIMA2 - Kasse Nr. " + QSettings().value("global/cashPointNo").toString());
setSaleModel();
connect(ui_.actionQuit, &QAction::triggered, qApp, QApplication::quit);
connect(ui_.newAction, &QAction::triggered, this, [=]() {
if (marketplace_->getSellers().size() == 0 && marketplace_->getSales().size() == 0) {
return;
}
auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Möchten Sie wirklich alle gespeicherten Daten verwerfen?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec();
if (dlgResult == QMessageBox::No)
return;
delete ui_.salesView->model();
dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
marketplace_->clear();
setSaleModel();
});
connect(ui_.actionEditSeller, &QAction::triggered, this,
&MainWindow::onActionEditSellerTriggered);
connect(ui_.sellerNoEdit, &QLineEdit::returnPressed, this,
&MainWindow::onSellerNoEditCheckSellerNo);
connect(ui_.paidButton, &QPushButton::clicked, this, &MainWindow::onPaidButtonTriggered);
connect(ui_.basketView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onBasketViewSelectionChanged);
connect(ui_.cancelArticleButton, &QPushButton::clicked, this,
&MainWindow::onCancelArticleButtonClicked);
connect(ui_.cancelSaleButton, &QPushButton::clicked, this,
&MainWindow::onCancelSaleButtonClicked);
connect(ui_.printSaleReceiptButton, &QPushButton::clicked, this,
&MainWindow::onPrintSaleReceiptButtonClicked);
connect(ui_.cancelAllArticlesButton, &QPushButton::clicked, this,
&MainWindow::onCancelAllArticlesButtonClicked);
connect(ui_.aboutQtAction, &QAction::triggered, this, &MainWindow::onAboutQt);
connect(ui_.aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
connect(ui_.openManualAction, &QAction::triggered, this, []() {
auto locations = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
for (auto location : locations) {
if (QFile::exists(location + QString("/Benutzerhandbuch.pdf"))) {
QDesktopServices::openUrl(
QUrl(QString("file:///") + location + QString("/Benutzerhandbuch.pdf"),
QUrl::TolerantMode));
}
}
});
connect(ui_.reportAction, &QAction::triggered, this, [=]() { ReportDialog(this).exec(); });
connect(ui_.configAction, &QAction::triggered, this, [=]() {
int result = SettingsDialog(this).exec();
if (result == QDialog::Accepted) {
delete ui_.salesView->model();
marketplace_->loadFromDb();
setSaleModel();
}
this->setWindowTitle("KIMA2 - Kasse Nr. " +
QSettings().value("global/cashPointNo").toString());
});
connect(ui_.importSellerExcelAction, &QAction::triggered, this,
&MainWindow::onImportSellerExcelActionTriggered);
connect(ui_.importSellerJsonAction, &QAction::triggered, this,
&MainWindow::onImportSellerJsonActionTriggered);
connect(ui_.exportSellerJsonAction, &QAction::triggered, this,
&MainWindow::onExportSellerJsonActionTriggered);
connect(ui_.exportSalesJsonAction, &QAction::triggered, this,
&MainWindow::onExportSalesJsonActionTriggered);
connect(ui_.importSalesJsonAction, &QAction::triggered, this,
&MainWindow::onImportSalesJsonActionTriggered);
readGeometry();
setWindowIcon(QIcon(":/misc/kima2.ico"));
}
void MainWindow::onActionEditSellerTriggered()
{
auto dialog = std::make_unique<SellerDialog>(this);
int retCode = dialog->exec();
delete ui_.salesView->model();
if (retCode == QDialog::Accepted) {
marketplace_->sortSellers();
marketplace_->storeToDb();
statusBar()->showMessage("Änderungen an den Verkäufer-Stammdaten gespeichert.",
STATUSBAR_TIMEOUT);
} else {
marketplace_->loadFromDb();
statusBar()->showMessage("Änderungen an den Verkäufer-Stammdaten verworfen!",
STATUSBAR_TIMEOUT);
}
setSaleModel();
}
void MainWindow::setSaleModel()
{
ui_.salesView->setModel(new SaleModel(getMarketplace(), ui_.salesView));
ui_.salesView->setColumnHidden(2, true);
ui_.salesView->resizeColumnToContents(0);
connect(static_cast<BasketModel*>(ui_.basketView->model()), &BasketModel::basketDataChanged,
static_cast<SaleModel*>(ui_.salesView->model()), &SaleModel::onBasketDataChanged);
connect(ui_.salesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onSalesViewSelectionChanged);
}
void MainWindow::onPaidButtonTriggered()
{
if (marketplace_->basketSize() > 0) {
QString lastPrice{marketplace_->getBasketSumAsString().c_str()};
dynamic_cast<BasketModel*>(ui_.basketView->model())->finishSale();
ui_.lastPriceLabel1->setText(lastPrice);
ui_.lastPriceLabel2->setText(lastPrice);
ui_.basketSumLabel->setText(" 0,00 €");
statusBar()->showMessage("Verkaufsvorgang erfolgreich durchgeführt.", STATUSBAR_TIMEOUT);
}
}
void MainWindow::onSellerNoEditCheckSellerNo()
{
using std::regex, std::regex_match, std::smatch;
auto inputText = ui_.sellerNoEdit->text().toStdString();
if (inputText.empty()) {
onPaidButtonTriggered();
return;
}
regex pattern{R"(\d{1,5})"};
smatch result;
if (!regex_match(inputText, result, pattern)) {
ui_.sellerNoEdit->clear();
return;
}
int sellerNo = std::stoi(result[0]);
auto seller = marketplace_->findSellerWithSellerNo(sellerNo);
if (seller) {
PriceDialog priceDialog(this);
auto dialogResult = priceDialog.exec();
if (dialogResult == QDialog::Accepted) {
int price = priceDialog.getPrice();
std::string desc = priceDialog.getDescription();
dynamic_cast<BasketModel*>(ui_.basketView->model())->addArticle(seller, price, desc);
ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str());
}
}
ui_.sellerNoEdit->clear();
}
void MainWindow::onBasketViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection& deselected)
{
if (selected.size() > 0) {
ui_.cancelArticleButton->setEnabled(true);
} else {
ui_.cancelArticleButton->setEnabled(false);
}
}
void MainWindow::onSalesViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection& deselected)
{
if (selected.size() > 0) {
ui_.cancelSaleButton->setEnabled(true);
if (!selected.indexes()[0].parent().isValid())
ui_.printSaleReceiptButton->setEnabled(true);
else
ui_.printSaleReceiptButton->setEnabled(false);
} else {
ui_.cancelSaleButton->setEnabled(false);
ui_.printSaleReceiptButton->setEnabled(false);
}
}
void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = ui_.basketView->selectionModel();
if (selModel->hasSelection() == false)
return;
auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Möchten Sie wirklich den Artikel stornieren?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec();
if (dlgResult == QMessageBox::No)
return;
auto indexes = selModel->selectedRows();
std::sort(indexes.begin(), indexes.end());
// Deleting the rows, beginning with the last one!
for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) {
ui_.basketView->model()->removeRow(iter->row());
}
}
void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false)
return;
auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Möchten Sie wirklich stornieren?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec();
if (dlgResult == QMessageBox::No)
return;
auto indexes = selModel->selectedRows();
std::sort(indexes.begin(), indexes.end());
// Deleting the rows, beginning with the last one!
for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) {
ui_.salesView->model()->removeRow(iter->row(), iter->parent());
}
}
void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false)
return;
auto indexes = selModel->selectedRows();
auto& sale = marketplace_->getSales().at(indexes[0].row());
PosPrinter printer;
if (printer.isValid())
printer.printSaleReceipt(sale.get());
}
void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked)
{
if (ui_.basketView->model()->rowCount() == 0)
return;
auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Möchten Sie wirklich *alle* Artikel des aktuellen Einkaufs stornieren?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec();
if (dlgResult == QMessageBox::No)
return;
dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
}
void MainWindow::onAboutQt() { QMessageBox::aboutQt(this); }
void MainWindow::onAbout()
{
QMessageBox::about(
this, "Über",
QString("<p style='text-align:center;'><b>KIMA2</b> - Version ") + PROJECT_VERSION +
"</p>"
"<p>KIMA2 ist ein kleines Kassenprogramm für Kindersachenmärkte.<p />"
"<p>Copyright © Martin Brodbeck &lt;<a href=mailto:martin@brodbeck-online.de"
">info@rustysoft.de</a>&gt;</p>");
}
void MainWindow::onImportSellerExcelActionTriggered()
{
if (!marketplace_->getSales().empty()) {
QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich",
"Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
QMessageBox::StandardButton::Ok, this)
.exec();
return;
}
auto filename = QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"Excel Dateien (*.xlsx *.xls)");
if (filename.isEmpty())
return;
ExcelReader::readSellersFromFile(filename.toStdString(), marketplace_.get());
}
void MainWindow::onImportSellerJsonActionTriggered()
{
if (!marketplace_->getSales().empty()) {
QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich",
"Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
QMessageBox::StandardButton::Ok, this)
.exec();
return;
}
auto filename = QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"JSON Dateien (*.json)");
if (filename.isEmpty())
return;
JsonUtil::importSellers(filename.toStdString(), marketplace_.get());
}
void MainWindow::onExportSellerJsonActionTriggered()
{
auto filename = QFileDialog::getSaveFileName(this, "Verkäufer exportieren", QString(),
"JSON Dateien (*.json)");
if (filename.isEmpty())
return;
JsonUtil::exportSellers(filename.toStdString(), marketplace_.get());
}
void MainWindow::onExportSalesJsonActionTriggered()
{
QSettings settings;
auto filename = QFileDialog::getSaveFileName(this, "Umsätze/Transaktionen exportieren",
QString(), "JSON Dateien (*.json)");
if (filename.isEmpty())
return;
JsonUtil::exportSales(filename.toStdString(), marketplace_.get(),
settings.value("global/cashPointNo").toInt());
}
void MainWindow::onImportSalesJsonActionTriggered()
{
QSettings settings;
auto filename = QFileDialog::getOpenFileName(this, "Umsätze/Transaktionen importieren",
QString(), "JSON Dateien (*.json)");
if (filename.isEmpty())
return;
delete ui_.salesView->model();
try {
JsonUtil::importSales(filename.toStdString(), marketplace_.get(),
settings.value("global/cashPointNo").toInt());
} catch (std::runtime_error& err) {
QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok,
this)
.exec();
}
setSaleModel();
}
void MainWindow::writeGeometry()
{
QSettings settings;
settings.beginGroup("mainwindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readGeometry()
{
QSettings settings;
settings.beginGroup("mainwindow");
resize(settings.value("size", QSize(800, 600)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
void MainWindow::closeEvent(QCloseEvent* event)
{
writeGeometry();
event->accept();
}