From 5295a82aa377ce4e972513ead563053527f0ebe9 Mon Sep 17 00:00:00 2001 From: "PANIK\\chris" Date: Tue, 5 Aug 2025 22:37:51 +0200 Subject: [PATCH] first re-commit. --- .gitignore | 2 + libMiniCash/README.md | 11 + libMiniCash/libMiniCash.h | 185 ++++++ libMiniCash/libMiniCash.pro | 75 +++ libMiniCash/libMiniCash_global.h | 12 + libMiniCash/libminicash.cpp | 2 + libMiniCash/mcbillingview.cpp | 634 +++++++++++++++++++ libMiniCash/mcbillingview.h | 72 +++ libMiniCash/mcbillingview.ui | 369 +++++++++++ libMiniCash/mcformwidget.cpp | 14 + libMiniCash/mcformwidget.h | 27 + libMiniCash/mcformwidget.ui | 31 + libMiniCash/mcinputview.cpp | 274 +++++++++ libMiniCash/mcinputview.h | 73 +++ libMiniCash/mcinputview.ui | 380 ++++++++++++ libMiniCash/mcloaddialog.cpp | 94 +++ libMiniCash/mcloaddialog.h | 58 ++ libMiniCash/mcloaddialog.ui | 89 +++ libMiniCash/mcmainwindowbase.cpp | 468 ++++++++++++++ libMiniCash/mcmainwindowbase.h | 120 ++++ libMiniCash/mcnetworkdialog.cpp | 206 +++++++ libMiniCash/mcnetworkdialog.h | 62 ++ libMiniCash/mcnetworkdialog.ui | 261 ++++++++ libMiniCash/mcnetworkwidget.cpp | 112 ++++ libMiniCash/mcnetworkwidget.h | 74 +++ libMiniCash/mcnetworkwidget.ui | 69 +++ libMiniCash/mcprinter.cpp | 28 + libMiniCash/mcprinter.h | 37 ++ libMiniCash/mcreceiver.cpp | 173 ++++++ libMiniCash/mcreceiver.h | 66 ++ libMiniCash/mcsalesitem.h | 67 ++ libMiniCash/mcsalesitemmap.cpp | 77 +++ libMiniCash/mcsalesitemmap.h | 55 ++ libMiniCash/mcsalesmodel.cpp | 181 ++++++ libMiniCash/mcsalesmodel.h | 55 ++ libMiniCash/mcsalessummary.cpp | 116 ++++ libMiniCash/mcsalessummary.h | 54 ++ libMiniCash/mcsender.cpp | 126 ++++ libMiniCash/mcsender.h | 58 ++ libMiniCash/mcsetupdialog.cpp | 185 ++++++ libMiniCash/mcsetupdialog.h | 69 +++ libMiniCash/mcsetupdialog.ui | 364 +++++++++++ libMiniCash/mctransactionview.cpp | 33 + libMiniCash/mctransactionview.h | 46 ++ libMiniCash/mctransactionview.ui | 46 ++ libMiniCash/mctreeview.cpp | 37 ++ libMiniCash/mctreeview.h | 45 ++ libMiniCash/mcvendorsdialog.cpp | 81 +++ libMiniCash/mcvendorsdialog.h | 47 ++ libMiniCash/mcvendorsdialog.ui | 95 +++ libMiniCash/swdriveselector.cpp | 44 ++ libMiniCash/swdriveselector.h | 47 ++ libMiniCash/swsidebar.cpp | 197 ++++++ libMiniCash/swsidebar.h | 69 +++ miniCash/main.cpp | 22 + miniCash/mcaboutme.cpp | 32 + miniCash/mcaboutme.h | 37 ++ miniCash/mcaboutme.ui | 126 ++++ miniCash/mceditdialog.cpp | 107 ++++ miniCash/mceditdialog.h | 56 ++ miniCash/mceditdialog.ui | 150 +++++ miniCash/mcmainwindowlocal.cpp | 126 ++++ miniCash/mcmainwindowlocal.h | 42 ++ miniCash/mcmainwindowlocal.ui | 266 ++++++++ miniCash/miniCash.h | 112 ++++ miniCash/miniCash.pro | 49 ++ miniCash/miniCash.qrc | 32 + miniCashAll.pro | 9 + miniCashConnect/.gitignore | 8 + miniCashConnect/.gitmodules | 3 + miniCashConnect/LICENSE | 674 +++++++++++++++++++++ miniCashConnect/README.md | 2 + miniCashConnect/images/_billing2.png | Bin 0 -> 6245 bytes miniCashConnect/images/_edit2.png | Bin 0 -> 6341 bytes miniCashConnect/images/_input2.png | Bin 0 -> 6605 bytes miniCashConnect/images/_network2.png | Bin 0 -> 7478 bytes miniCashConnect/images/_server.png | Bin 0 -> 5965 bytes miniCashConnect/images/_setup2.png | Bin 0 -> 8441 bytes miniCashConnect/images/_transactions2.png | Bin 0 -> 6095 bytes miniCashConnect/images/button_ok.png | Bin 0 -> 3695 bytes miniCashConnect/images/connect.png | Bin 0 -> 6071 bytes miniCashConnect/images/contexthelp.png | Bin 0 -> 2162 bytes miniCashConnect/images/disconnect.png | Bin 0 -> 6663 bytes miniCashConnect/images/exit.png | Bin 0 -> 2360 bytes miniCashConnect/images/filesave.png | Bin 0 -> 1440 bytes miniCashConnect/images/filesaveas.png | Bin 0 -> 1942 bytes miniCashConnect/images/findf.png | Bin 0 -> 1897 bytes miniCashConnect/images/folder_new.png | Bin 0 -> 1713 bytes miniCashConnect/images/help.png | Bin 0 -> 2461 bytes miniCashConnect/images/miniCashConnect.png | Bin 0 -> 33300 bytes miniCashConnect/images/nfs_mount.png | Bin 0 -> 7476 bytes miniCashConnect/images/stick.png | Bin 0 -> 1416 bytes miniCashConnect/main.cpp | 59 ++ miniCashConnect/mccaboutme.cpp | 31 + miniCashConnect/mccaboutme.h | 38 ++ miniCashConnect/mccaboutme.ui | 126 ++++ miniCashConnect/mcceditview.cpp | 151 +++++ miniCashConnect/mcceditview.h | 67 ++ miniCashConnect/mcceditview.ui | 147 +++++ miniCashConnect/mcconnectmainwindow.cpp | 384 ++++++++++++ miniCashConnect/mcconnectmainwindow.h | 89 +++ miniCashConnect/mcconnectmainwindow.ui | 425 +++++++++++++ miniCashConnect/miniCashConnect.h | 67 ++ miniCashConnect/miniCashConnect.pro | 60 ++ miniCashConnect/miniCashConnect.qrc | 26 + miniCashConnect/miniCashConnect_en_DE.ts | 3 + miniCashConnect/templates/tplFinal.html | 52 ++ miniCashConnect/templates/tplPayoff.html | 39 ++ miniCashConnect/templates/tplReceipt.html | 39 ++ 109 files changed, 9928 insertions(+) create mode 100644 .gitignore create mode 100644 libMiniCash/README.md create mode 100644 libMiniCash/libMiniCash.h create mode 100644 libMiniCash/libMiniCash.pro create mode 100644 libMiniCash/libMiniCash_global.h create mode 100644 libMiniCash/libminicash.cpp create mode 100644 libMiniCash/mcbillingview.cpp create mode 100644 libMiniCash/mcbillingview.h create mode 100644 libMiniCash/mcbillingview.ui create mode 100644 libMiniCash/mcformwidget.cpp create mode 100644 libMiniCash/mcformwidget.h create mode 100644 libMiniCash/mcformwidget.ui create mode 100644 libMiniCash/mcinputview.cpp create mode 100644 libMiniCash/mcinputview.h create mode 100644 libMiniCash/mcinputview.ui create mode 100644 libMiniCash/mcloaddialog.cpp create mode 100644 libMiniCash/mcloaddialog.h create mode 100644 libMiniCash/mcloaddialog.ui create mode 100644 libMiniCash/mcmainwindowbase.cpp create mode 100644 libMiniCash/mcmainwindowbase.h create mode 100644 libMiniCash/mcnetworkdialog.cpp create mode 100644 libMiniCash/mcnetworkdialog.h create mode 100644 libMiniCash/mcnetworkdialog.ui create mode 100644 libMiniCash/mcnetworkwidget.cpp create mode 100644 libMiniCash/mcnetworkwidget.h create mode 100644 libMiniCash/mcnetworkwidget.ui create mode 100644 libMiniCash/mcprinter.cpp create mode 100644 libMiniCash/mcprinter.h create mode 100644 libMiniCash/mcreceiver.cpp create mode 100644 libMiniCash/mcreceiver.h create mode 100644 libMiniCash/mcsalesitem.h create mode 100644 libMiniCash/mcsalesitemmap.cpp create mode 100644 libMiniCash/mcsalesitemmap.h create mode 100644 libMiniCash/mcsalesmodel.cpp create mode 100644 libMiniCash/mcsalesmodel.h create mode 100644 libMiniCash/mcsalessummary.cpp create mode 100644 libMiniCash/mcsalessummary.h create mode 100644 libMiniCash/mcsender.cpp create mode 100644 libMiniCash/mcsender.h create mode 100644 libMiniCash/mcsetupdialog.cpp create mode 100644 libMiniCash/mcsetupdialog.h create mode 100644 libMiniCash/mcsetupdialog.ui create mode 100644 libMiniCash/mctransactionview.cpp create mode 100644 libMiniCash/mctransactionview.h create mode 100644 libMiniCash/mctransactionview.ui create mode 100644 libMiniCash/mctreeview.cpp create mode 100644 libMiniCash/mctreeview.h create mode 100644 libMiniCash/mcvendorsdialog.cpp create mode 100644 libMiniCash/mcvendorsdialog.h create mode 100644 libMiniCash/mcvendorsdialog.ui create mode 100644 libMiniCash/swdriveselector.cpp create mode 100644 libMiniCash/swdriveselector.h create mode 100644 libMiniCash/swsidebar.cpp create mode 100644 libMiniCash/swsidebar.h create mode 100644 miniCash/main.cpp create mode 100644 miniCash/mcaboutme.cpp create mode 100644 miniCash/mcaboutme.h create mode 100644 miniCash/mcaboutme.ui create mode 100644 miniCash/mceditdialog.cpp create mode 100644 miniCash/mceditdialog.h create mode 100644 miniCash/mceditdialog.ui create mode 100644 miniCash/mcmainwindowlocal.cpp create mode 100644 miniCash/mcmainwindowlocal.h create mode 100644 miniCash/mcmainwindowlocal.ui create mode 100644 miniCash/miniCash.h create mode 100644 miniCash/miniCash.pro create mode 100644 miniCash/miniCash.qrc create mode 100644 miniCashAll.pro create mode 100644 miniCashConnect/.gitignore create mode 100644 miniCashConnect/.gitmodules create mode 100644 miniCashConnect/LICENSE create mode 100644 miniCashConnect/README.md create mode 100644 miniCashConnect/images/_billing2.png create mode 100644 miniCashConnect/images/_edit2.png create mode 100644 miniCashConnect/images/_input2.png create mode 100644 miniCashConnect/images/_network2.png create mode 100644 miniCashConnect/images/_server.png create mode 100644 miniCashConnect/images/_setup2.png create mode 100644 miniCashConnect/images/_transactions2.png create mode 100644 miniCashConnect/images/button_ok.png create mode 100644 miniCashConnect/images/connect.png create mode 100644 miniCashConnect/images/contexthelp.png create mode 100644 miniCashConnect/images/disconnect.png create mode 100644 miniCashConnect/images/exit.png create mode 100644 miniCashConnect/images/filesave.png create mode 100644 miniCashConnect/images/filesaveas.png create mode 100644 miniCashConnect/images/findf.png create mode 100644 miniCashConnect/images/folder_new.png create mode 100644 miniCashConnect/images/help.png create mode 100644 miniCashConnect/images/miniCashConnect.png create mode 100644 miniCashConnect/images/nfs_mount.png create mode 100644 miniCashConnect/images/stick.png create mode 100644 miniCashConnect/main.cpp create mode 100644 miniCashConnect/mccaboutme.cpp create mode 100644 miniCashConnect/mccaboutme.h create mode 100644 miniCashConnect/mccaboutme.ui create mode 100644 miniCashConnect/mcceditview.cpp create mode 100644 miniCashConnect/mcceditview.h create mode 100644 miniCashConnect/mcceditview.ui create mode 100644 miniCashConnect/mcconnectmainwindow.cpp create mode 100644 miniCashConnect/mcconnectmainwindow.h create mode 100644 miniCashConnect/mcconnectmainwindow.ui create mode 100644 miniCashConnect/miniCashConnect.h create mode 100644 miniCashConnect/miniCashConnect.pro create mode 100644 miniCashConnect/miniCashConnect.qrc create mode 100644 miniCashConnect/miniCashConnect_en_DE.ts create mode 100644 miniCashConnect/templates/tplFinal.html create mode 100644 miniCashConnect/templates/tplPayoff.html create mode 100644 miniCashConnect/templates/tplReceipt.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da1d64b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.user +build/ diff --git a/libMiniCash/README.md b/libMiniCash/README.md new file mode 100644 index 0000000..bbd771f --- /dev/null +++ b/libMiniCash/README.md @@ -0,0 +1,11 @@ +# libMiniCash README.md + +## about +`libMiniCash` enthält die von den Kassensystemen 'miniCash' und 'miniCash.connect' gemeinsam verwendete Funktionalität als Dll. + +## Funktionsbereiche +- Datenmodelle und Datentypen +- Eingabe der Verkäufe +- Setup-Dialoge +- Erzeugung der Abrechnungen +- Druckersteuerung diff --git a/libMiniCash/libMiniCash.h b/libMiniCash/libMiniCash.h new file mode 100644 index 0000000..b4d8c0f --- /dev/null +++ b/libMiniCash/libMiniCash.h @@ -0,0 +1,185 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef LIBMINICASH_H +#define LIBMINICASH_H + +#include "libMiniCash_global.h" + + +/** + +@mainpage libMiniCash + +@section xxx Die libMiniCash Dll + +libMiniCash enthält die von den Kassensystemen 'miniCash' und 'miniCash.connect' +gemeinsam verwendete Funktionalität als Dll. + +@subsection xxz Funktionsbereiche + - Datenmodelle und Datentypen + - Eingabe der Verkäufe + - Setup-Dialoge + - Erzeugung der Abrechnungen + - Druckersteuerung + +@section sec3 Ideen & TODO: + +@subsection sec3_1 Ideen: + + - oberfläche erneuern? + - beim server hochfahren: daten abholen, puffern, wahlweise via usb + - adressverwaltung einbeziehen, für personalisierte Abrechnungen + +@subsection sec3_2 TODO für 1.0: + + - wlan first, disk backup + - netzprotocol, erfinden oder json/xml + - splash screen? + - fehler dulden wg. kassenschlange, hinterher kennzeichnen + - server security: only allowed hosts + - auto feeder zum testen + - data: kasse|count|cust|pos|price|timestamp + - protocol: [...]: transaction, -: storno; + - kasse: semi blocking (soll genau was heissen, chris?) + - Beim einlesen mitzählen, Ergebnis in den statusbar. + - suche bei Storno mit mehreren Feldern zulassen + - setup.exe bauen + + +@subsection sec3_3 TODO für 0.9: + + - backup über WLAN -> Adhoc Netzwerk einrichten + - layouts verwenden + - handbuch schreiben + - vernünftiger setup-dialog mit abbruch möglichkeit + + +@subsection sec3_4 TODO für 0.8: + + - Auswertung: laden und speichern : + - Printbuttons ab/an schalten : + - Kurzanleitung : + - programm muss immer starten, fehlerloop verwirrt nur + QUARK: Programm _kann_ ohne Laufwerk nicht starten! + - help about : mit hinweis auf sourceworx & logo + - fonts vereinheitlichen + - statusbar einbinden ?!? + - Caps lock abschalten, wie ? + +*/ + +/** + * @brief der namespace miniCash enthält Definitionen und Konstanten. + * + * Hier stehen die Konstanten für + * - die HTML-Templates zur Erzeugung der Print-Files + * - Die Dateipfade + * - die RegEx zur Eingabekontrolle + * - Copyright-Hinweise + * Der Namespace gilt Anwendungsübergreifend sowohl für die Library als + * auch die damit implementierten Anwendungen. + */ + + +namespace miniCash +{ +/// networkstate +typedef enum +{ + Disabled = 0, + UnConnected, + Error, + Connected, + IsServer, + ServerReady, + CStateSize +} CState; + +[[maybe_unused]] constexpr static const char* cstDisabled = " "; +[[maybe_unused]] constexpr static const char* cstUnConnected = "--Ready"; +[[maybe_unused]] constexpr static const char* cstError = "Error"; +[[maybe_unused]] constexpr static const char* cstConnected = "Connected"; +[[maybe_unused]] constexpr static const char* cstIsServer = "Ready"; +[[maybe_unused]] constexpr static const char* cstServerReady = "Connected"; + +[[maybe_unused]] static const char* const icnConnected = ":images/connect.png"; +[[maybe_unused]] static const char* const icnUnConnected = ":images/disconnect.png"; +[[maybe_unused]] static const char* const icnServer = ":images/_server.png"; + +/// basics +[[maybe_unused]] static const char* const orgName = "source::worx"; +[[maybe_unused]] static const char* const domainName = "sourceworx.org"; + +/// eigene KassenID +[[maybe_unused]] static const char* const keySelfID = "selfID"; +[[maybe_unused]] static const char* const selfID = "1"; + +/// transaktionszähler, vormals die hässliche Zähldatei +[[maybe_unused]] static const char* const keyTransCount = "TransCount"; +[[maybe_unused]] static const char* const transCount = "1"; + +/// file handling +[[maybe_unused]] static const char* const keyMobileDrive = "MobileDrive"; +[[maybe_unused]] static const char* const mobileDrive = "E:/"; +[[maybe_unused]] static const char* const dataDir = "/miniCash.data/"; +[[maybe_unused]] static const char* const filetype = ".mcd"; + +/// address handling +[[maybe_unused]] static const char* const keyAddressFile = "AddressFile"; + +/// defaults +[[maybe_unused]] static const char* const keyProfit = "Profit"; +[[maybe_unused]] static const char* const profit = "15"; + +[[maybe_unused]] static const char* const keyFooterText = "FooterText"; + +/// networking +[[maybe_unused]] static const char* const keyIsTcpReceiver = "isTcpReceiver"; +[[maybe_unused]] static const bool isTcpReceiver = false; + +[[maybe_unused]] static const char* const keyIsTcpSender = "isTcpSender"; +[[maybe_unused]] static const bool isTcpSender = true; +[[maybe_unused]] static const int senderTimeout = 60000; + +[[maybe_unused]] static const char* const keyReceiverPort = "receiverPort"; +[[maybe_unused]] static const int receiverPort = 7077; + +[[maybe_unused]] static const char* const keyReceiverHost = "receiverHost"; + + +/// resource handling +[[maybe_unused]] static const char* const tplFinal = ":templates/tplFinal.html"; +[[maybe_unused]] static const char* const tplPayoff = ":templates/tplPayoff.html"; +[[maybe_unused]] static const char* const tplReceipt = ":templates/tplReceipt.html"; + +/// input filter +[[maybe_unused]] static const char* const fCustID = "^[0-9]{4}$"; +[[maybe_unused]] static const char* const fItemNo = "^[0-9]{1,3}$"; +[[maybe_unused]] static const char* const fPrice = "^[0-9]{1,3}(,[0-9]{1,2})?$"; + +[[maybe_unused]] static const char* const fSrcDrive = "^[e-zE-Z]$"; +[[maybe_unused]] static const char* const fProfit = "^[0-9]{2}$"; +[[maybe_unused]] static const char* const fFromID = "^1[1-3][0-9]{2}$"; +[[maybe_unused]] static const char* const fToID = "^1[1-3][0-9]{2}$"; + +/// misc +[[maybe_unused]] static const char* const versionLib = "Version 0.8.42, 14.07.2022"; +[[maybe_unused]] static const char* const copyright = "miniCash, © 2013-2022 Christoph Holzheuer c.holzheuer@sourceworx.org "; +[[maybe_unused]] static const char* const copyShort = "miniCash, © 2013-2022\nc.holzheuer@sourceworx.org "; + +} + + +#endif // LIBMINICASH_H diff --git a/libMiniCash/libMiniCash.pro b/libMiniCash/libMiniCash.pro new file mode 100644 index 0000000..b264eba --- /dev/null +++ b/libMiniCash/libMiniCash.pro @@ -0,0 +1,75 @@ +QT += printsupport core gui network widgets + +TEMPLATE = lib +TARGET = libMiniCash +DEFINES += LIBMINICASH_LIBRARY + +DESTDIR = $$OUT_PWD/../common + +CONFIG += c++17 + +SOURCES += \ + libminicash.cpp \ + mcbillingview.cpp \ + mcformwidget.cpp \ + mcinputview.cpp \ + mcloaddialog.cpp \ + mcmainwindowbase.cpp \ + mcnetworkdialog.cpp \ + mcnetworkwidget.cpp \ + mcprinter.cpp \ + mcreceiver.cpp \ + mcsalesitemmap.cpp \ + mcsalesmodel.cpp \ + mcsalessummary.cpp \ + mcsender.cpp \ + mcsetupdialog.cpp \ + mctransactionview.cpp \ + mctreeview.cpp \ + mcvendorsdialog.cpp \ + swdriveselector.cpp \ + swsidebar.cpp + +HEADERS += \ + libMiniCash_global.h \ + libminicash.h \ + mcbillingview.h \ + mcformwidget.h \ + mcinputview.h \ + mcloaddialog.h \ + mcmainwindowbase.h \ + mcnetworkdialog.h \ + mcnetworkwidget.h \ + mcprinter.h \ + mcreceiver.h \ + mcsalesitem.h \ + mcsalesitemmap.h \ + mcsalesmodel.h \ + mcsalessummary.h \ + mcsender.h \ + mcsetupdialog.h \ + mctransactionview.h \ + mctreeview.h \ + mcvendorsdialog.h \ + swdriveselector.h \ + swsidebar.h + +# Default rules for deployment. +unix { + target.path = /usr/lib +} +!isEmpty(target.path): INSTALLS += target + +FORMS += \ + mcbillingview.ui \ + mcformwidget.ui \ + mcinputview.ui \ + mcloaddialog.ui \ + mcnetworkdialog.ui \ + mcnetworkwidget.ui \ + mcsetupdialog.ui \ + mctransactionview.ui \ + mcvendorsdialog.ui + +DISTFILES += \ + README.md diff --git a/libMiniCash/libMiniCash_global.h b/libMiniCash/libMiniCash_global.h new file mode 100644 index 0000000..ea202dc --- /dev/null +++ b/libMiniCash/libMiniCash_global.h @@ -0,0 +1,12 @@ +#ifndef LIBMINICASH_GLOBAL_H +#define LIBMINICASH_GLOBAL_H + +#include + +#if defined(LIBMINICASH_LIBRARY) +#define LIBMINICASH_EXPORT Q_DECL_EXPORT +#else +#define LIBMINICASH_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBMINICASH_GLOBAL_H diff --git a/libMiniCash/libminicash.cpp b/libMiniCash/libminicash.cpp new file mode 100644 index 0000000..138181f --- /dev/null +++ b/libMiniCash/libminicash.cpp @@ -0,0 +1,2 @@ +#include "libminicash.h" + diff --git a/libMiniCash/mcbillingview.cpp b/libMiniCash/mcbillingview.cpp new file mode 100644 index 0000000..8a3ce3a --- /dev/null +++ b/libMiniCash/mcbillingview.cpp @@ -0,0 +1,634 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/** + * @brief Konstruktor des Abrechnungsdialogs + * + * @param parent Das Elternfenster + * @param datafilename Der Filename der Kassendatei + * @param settings die globalen Systemeinstellungen + * + */ + +MCBillingView::MCBillingView( QWidget *parent ) + : QFrame( parent ), _ui{new Ui::MCBillingView}, _allCustomers( 0 ) +{ + + _ui->setupUi( this ); + + /// model setzen + _salesModel.setParent( this ); + _ui->_trList->setModel( &_salesModel ); + + QRegularExpressionValidator* srcDrive = new QRegularExpressionValidator( QRegularExpression( miniCash::fSrcDrive ) ); + QRegularExpressionValidator* profit = new QRegularExpressionValidator( QRegularExpression( miniCash::fProfit ) ); + QRegularExpressionValidator* fromID = new QRegularExpressionValidator( QRegularExpression( miniCash::fFromID ) ); + QRegularExpressionValidator* toID = new QRegularExpressionValidator( QRegularExpression( miniCash::fToID ) ); + + _ui->_srcDrive->setValidator( srcDrive ); + _ui->_trProfit->setValidator( profit ); + _ui->_trFrom->setValidator( fromID ); + _ui->_trTo->setValidator( toID ); + +} + + +/** + * @brief Destruktor + * + * Destruktor + * + */ + +MCBillingView::~MCBillingView() +{ + +} + + +/** + * @brief MCBillingView::setupDefaults: Werte von ausserhalb, weil durch die + * Qt-setpUi()-Autotmatik nichts mehr über den Konstruktor übergeben werden + * kann. + * + * @param datafilename + * @param settings + */ + +void MCBillingView::setupDefaults( const QString& datafilename, QSettings* settings ) +{ + + /// dateifilter für die Kassenfiles + _fileFilter = "*_" + datafilename; + _settings = settings; + /// Wertvorgaben laden + _ui->_srcDrive->addItem( _settings->value( miniCash::keyMobileDrive ).toString() ); + _ui->_trFooterText->setText( _settings->value( miniCash::keyFooterText ).toString() ); + + connect( _ui->_trButtonRead, SIGNAL(clicked()), this, SLOT( onReadTransactions()) ); + connect( _ui->_trButtonPrintBills, SIGNAL(clicked()), this, SLOT( onPrintBills()) ); + connect( _ui->_trButtonPrintReceipts,SIGNAL(clicked()), this, SLOT( onPrintReceipts()) ); + + /// erst lesen dann drucken + _ui->_trButtonPrintBills->setEnabled( false ); + _ui->_trButtonPrintReceipts->setEnabled( false ); + _ui->_trProfit->setText( _settings->value( miniCash::keyProfit ).toString() ); + +} + + +/** + * @brief testet die Formulareingaben! + * + * Testet die Eingaben des Abrechnungsformulars auf Gültigkeit: + * + * - Anteil des Kindergartens + * - Kundennummer 'von' + * - Kundennummer 'bis' + * + */ + +bool MCBillingView::testFormData() +{ + const QString& profit = _ui->_trProfit->text(); + const QString& trFrom = _ui->_trFrom->text(); + const QString& trTo = _ui->_trTo->text(); + + if( profit.isEmpty() || trFrom.isEmpty() || trTo.isEmpty() ) + { + QMessageBox::warning + ( + this, + "Eingabefehler", + QString( + "Die Felder 'Anteil Kindergarten' und\n " + "'Abrechung Kundenummer von...bis'\nmüssen belegt sein." + ) + ); + return false; + } + + // alles ok, also Felder sichern + _settings->setValue( miniCash::keyMobileDrive, _ui->_srcDrive->currentText() ); + _settings->setValue( miniCash::keyProfit, profit ); + _settings->setValue( miniCash::keyFooterText, _ui->_trFooterText->document()->toPlainText() ); + + return true; +} + + +/** + * @brief Kassendateien einlesen + * + * Liest die (nunmehr zusammenkopierten) Kassendateien zur weiteren Bearbeitung ein. + * Die Dateinamen sind aus der jeweiligen Kassennummer (1..x) und dem Basisnahmen + * zusammengesetzt: + * _.klm, also etwa: 1_03-13-2022.klm + * + */ + +void MCBillingView::onReadTransactions() +{ + + /// erst lesen dann drucken + _ui->_trButtonPrintBills->setEnabled( false ); + _ui->_trButtonPrintReceipts->setEnabled( false ); + + + /// + /// erstmal die Felder prüfen und erst bei korrekten Daten weitermachen. + /// + + if( !testFormData() ) + return; + + /// saubermachen + _salesSummary.clear(); + + QDir datadir( _ui->_srcDrive->currentText() ); + + datadir.setFilter( QDir::Files | QDir::NoSymLinks ); + datadir.setSorting( QDir::Name ); + + + /// Dateien holen und zeigen + QStringList filter( _fileFilter ); + QStringList list = datadir.entryList( filter ); + + /// was gefunden? + if( list.isEmpty() ) + { + QString msg( "Im Pfad '%0' \nkonnten keine Kassendateien gefunden werden." ); + QMessageBox::warning(this, "Keine Kassendateien gefunden", msg.arg( datadir.absolutePath() + _fileFilter ) ); + return; + } + + /// listview befüllen + MCLoadDialog dlg( this ); + for( const QString& entry : list ) + dlg.appendEntry( entry ); + + if( dlg.exec() != QDialog::Accepted ) + return; + + /// alle Kassenfiles einlesen + _salesSummary.clear(); + ///_salesModel.clear(); <-- löscht den Header mit + _salesModel.removeRows( 0, _salesModel.rowCount() ); + + dlg.show(); + + _allCustomers = 0; + int salescount=0, customercount=0; + QString dlgitem( ": Kunden: %0 Artikel: %1" ); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + for( int i = 0; i < list.size(); ++i ) + { + QString filename = _ui->_srcDrive->currentText() + list.at( i ); + salescount = _salesSummary.appendFromFile( filename, customercount, _salesModel ); + _allCustomers += customercount; + dlg.updateEntry( i, dlgitem.arg( customercount ).arg( salescount ) ); + } + QApplication::restoreOverrideCursor(); + + if( dlg.exec() != QDialog::Accepted ) + return; + + /// es kann gedruckt werden + _ui->_trButtonPrintBills->setEnabled( true ); + _ui->_trButtonPrintReceipts->setEnabled( true ); + +} + + +/** + * @brief Abrechungen drucken + * + * Erzeugt aus den eingelesenen Kassendaten mit Hilfe + * der vorgegebenen HTML-Templates die Druckdateien der + * Abrechung als .pdf-Files. + * + * Auf den Abrechnungen sind pro Kunden(=Verkäufer)-Nummer die Laufnummern der + * jeweils verkauften Artikel, der Umsatz und der Auszahlungsbetrag nach Abzug der + * Provision für den Kindergarten aufgelistet. + * + * @bug die untere ('1100') und obere ('1399') Grenze des Kundennummernintervalls + * sind nicht mehr unbedingt gültig und sollten hier nicht hardkodiert sein. + * @bug der progressbar wir nicht benutzt. + */ + +void MCBillingView::onPrintBills() +{ + + + /// + /// nochmal die Felder prüfen und erst bei korrekten Daten weitermachen. + /// + + if( !testFormData() ) + return; + + /// + /// Step 1: HTML-Template laden und Wiederholungsblock + /// (= Zeile auf der Abrechnung) erzeugen + /// + + + QFile file( miniCash::tplPayoff ); + if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QMessageBox::critical( + this, + tr( "Dateifehler" ), + QString( tr( "Datei nicht gefunden: %1" ) ).arg( file.errorString() ), + QMessageBox::Ok ); + return; + } + + /// HTML-template für die Abrechnung + QString invoice( file.readAll() ); + /// speichert alles Abrechnungen + /// Zeilentemplate der Abrechung + QString block( + "" + "%0" + "%1" + "%2 " + "%3 " + "" + ); + + /// Die Abrechnung + QTextDocument document; + /// der Anteil für den Kindergarten in % + double fee = _settings->value( miniCash::keyProfit ).toDouble(); + /// in Datei Drucken ? + bool printToFile = _ui->_trSaveBills->isChecked(); + + QString drive = _ui->_srcDrive->currentText(); + QPrinter printer; + if( printToFile ) + printer.setOutputFormat( QPrinter::PdfFormat ); + + + /// + /// Step 2: Iterieren über alle Verkäufer ... + /// + + const QString& strFrom = _ui->_trFrom->text(); + const QString& strTo = _ui->_trTo->text(); + + /// wenn ein intervall angegeben ist, muss zuerst der exakte Schlüssel + /// gesucht werden, denn upperbound liefert die position _nach_ dem + /// angegebenen Schlüssel. + + MCSalesSummary::const_iterator posSeller = _salesSummary.cbegin(); + + if( strFrom != "1100" ) + { + posSeller = _salesSummary.constFind( strFrom ); + if( posSeller == _salesSummary.cend() ) + posSeller = _salesSummary.lowerBound( strFrom ); + } + + /// dito das 'obere' Ende des Intervalls + + MCSalesSummary::const_iterator posEnd = _salesSummary.cend(); + /// + if( strTo != "1399" ) + { + posEnd = _salesSummary.constFind( strTo ); + if( posEnd == _salesSummary.cend() ) + posEnd = _salesSummary.upperBound( strTo ); + } + + /// Progressbar vorbereiten + + /* + int sellerCount = 0; + QStatusBar* statusBar = ( (MCMainWindow*) parent() )->statusBar(); + QProgressBar* progress = new QProgressBar( bar ); + progress->setRange( 0, _salesSummary.size() ); + bar->addWidget( progress ); + */ + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + /// Über alle Verkäufernummern ... + for( ; posSeller != posEnd; ++posSeller ) + { + + /// + /// Step 2B: Iterieren über alle verkauften Artikel des Verkäufers ... + /// + + //// FIX! + //// progress->setValue( sellerCount++ ); + /// Der Zeilenblock, also die Einzelauflistung der verkauften Artikel + QString result; + /// Der Umsatz der Verkäufers + double revenueOverall = 0; + /// Der Auszahlungsbetrag (Umsatz abzgl. Kindergartenanteil) + double gainOverall = 0; + + int soldItems = 0; + MCSalesItemMap::const_iterator posSales = posSeller.value().begin(); + for( ; posSales != posSeller.value().end(); ++posSales ) + { + + qDebug() << "Kunde: " << posSeller.key(); + /// Ein Eintrag + const MCSalesItem& itm = posSales.value(); + revenueOverall += itm.trPrice; + double gain = itm.trPrice / 100.0 * (100.0 - fee ); + gainOverall += gain; + ++soldItems; + + QString entry = block.arg + ( + itm.trSellerID, + itm.trItemNo, + MCSalesModel::toCurrency( itm.trPrice ), + MCSalesModel::toCurrency( gain ) + ); + result += entry + '\n'; + + + } /// Über alle Artikel € <-- Euro + + /// Seite fertig: Header Parameter in die Abrechnung schreiben + QDate date = QDate::currentDate(); + /// header + QString soldStr = QString("%1").arg( soldItems ); + QString tmpInvoice = invoice.arg + ( + date.toString( "dd.MM.yyyy" ), + posSeller.key(), + soldStr, + MCSalesModel::toCurrency( revenueOverall ), + MCSalesModel::toCurrency( gainOverall ) + ); + + /// body & footer + + QString footer = _settings->value( miniCash::keyFooterText ).toString(); + if( !footer.isEmpty() ) + { + footer.replace( "\n", "
" ); + footer = "-------------------------------------------------------------------------------------------------------------------------------------------------------\n" + footer; + } + + tmpInvoice = tmpInvoice.arg( result, footer ); + if( printToFile ) + printer.setOutputFileName( drive + QString("abrechung_%1.pdf").arg( posSeller.key() ) ); + document.setHtml( tmpInvoice ); + document.print( &printer ); + + } /// über alle Verkäufer + + ///statusBar->removeWidget( progress ); + QApplication::restoreOverrideCursor(); + QMessageBox::information( this, "Abrechungen drucken", "Alle Druckaufträge wurden erfolgreich erzeugt." ); + + +} + + +/** + * @brief Quittierlisten drucken + * + * Erzeugt aus den eingelesenen Kassendaten mit Hilfe + * der vorgegebenen HTML-Templates die Druckdateien der + * Quittierlisten als .pdf-Files. + * + * Auf den Quittierlisten steht die Kunden(=Verkäufer)-Nummer, der + * Auszahlungsbetrag und das Unterschriftsfeld zur Bestätigung der Auszahlung. + * + * @bug die untere ('1100') und obere ('1399') Grenze des Kundennummernintervalls + * sind nicht mehr unbedingt gültig und sollten hier nicht hardkodiert sein. + * @bug der progressbar wir nicht benutzt. + */ + +void MCBillingView::onPrintReceipts() +{ + + static const int MAXLINES = 23; + + + /// + /// nochmal die Felder prüfen und erst bei korrekten Daten weitermachen. + /// + + if( !testFormData() ) + return; + + /// + /// Step 1: HTML-Template laden und Wiederholungsblock + /// (= Zeile auf der Abrechnung) erzeugen + /// + + QString fileKey = miniCash::tplReceipt; + QFile file( fileKey ); + if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QMessageBox::critical( this, "Dateifehler", QString( "Datei nicht gefunden: %1" ).arg( file.errorString() ), QMessageBox::Ok ); + return; + } + + /// HTML-template für die Quittungsliste + QString receipt( file.readAll() ); + + + /// Zeilentemplate der Abrechung + QString block( + "" + "%0" + "%1 " + "%2 " + " " + " " + "" + "-------------------------------------------------------------------------------------------------------------------------------------------------------" + ); + + + /// Die Abrechnung + QTextDocument document; + /// der Anteil für den Kindergarten in % + double fee = _settings->value( miniCash::keyProfit ).toDouble(); + + MCPrinter printer; + + QString drive = _ui->_srcDrive->currentText(); + bool printToFile = _ui->_trSaveReceipts->isChecked(); + + if( printToFile ) + printer.setOutputFormat( QPrinter::PdfFormat ); + + /// Der Zeilenblock, also die Einzelauflistung der verkauften Artikel + QString result, fromKey, toKey; + bool setKey = true; + int pageCount=1; + int lineCount=0; + + double revenueFinal = 0; + double gainFinal = 0; + int piecesFinal = 0; + + /* + QStatusBar* statusBar = ( (MCMainWindow*) parent() )->statusBar(); + QProgressBar* progress = new QProgressBar( statusBar ); + progress->setRange( 0, _salesSummary.size() ); + statusBar->addWidget( progress ); + */ + + /// + /// Step 2: Iterieren über alle Verkäufer ... + /// + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + MCSalesSummary::const_iterator posSeller = _salesSummary.cbegin(); + for( ; posSeller != _salesSummary.cend(); ++posSeller ) + { + /// Schlüssel merken für die Anzeige "Verkäufer von .. bis" + if( setKey ) + { + fromKey = posSeller.key(); + setKey = false; + } + toKey = posSeller.key(); + + /// + /// Step 2B: Iterieren über alle verkauften Artikel des Verkäufers ... + /// + + /// Der Umsatz der Verkäufers + double revenueOverall = 0; + /// Der Auszahlungsbetrag (Umsatz abzgl. Kindergartenanteil) + double gainOverall = 0; + + ////progress->setValue( pageCount ); + + MCSalesItemMap::const_iterator posSales = posSeller.value().cbegin(); + piecesFinal += posSeller.value().size(); + for( ; posSales != posSeller.value().cend(); ++posSales ) + { + + /// Ein Eintrag + const MCSalesItem& itm = posSales.value(); + + revenueOverall += itm.trPrice; + double gain = itm.trPrice / 100.0 * (100.0 - fee ); + gainOverall += gain; + + + } /// über alle Artikel € <-- Euro + + revenueFinal += revenueOverall; + gainFinal += gainOverall; + QString entry = block.arg + ( + posSeller.key(), + MCSalesModel::toCurrency( revenueOverall ), + MCSalesModel::toCurrency( gainOverall ) + ); + result += entry + '\n'; + + /// Seite fertig: drucken, zurücksetzen & neu starten + if( ++lineCount >= MAXLINES ) + { + lineCount = 0; + if( printToFile ) + printer.setOutputFileName( drive + QString("quittungen_%1.pdf").arg( pageCount ) ); + pageCount++; + /// Seite fertig: Header Parameter in die Abrechnung schreiben + setKey = true; + QDate date = QDate::currentDate(); + /// header + QString tmpReceipt = receipt.arg( date.toString( "dd.MM.yyyy" ), fromKey, toKey, result ); + + document.setHtml( tmpReceipt ); + document.print( &printer ); + document.clear(); + result = ""; + } + + ///if(pageCount >= 3 ) + /// break; + + } /// über alle Verkäufer + + /// Reste Drucken: + QDate date = QDate::currentDate(); + if( lineCount && lineCount < MAXLINES ) + { + + /// header + QString tmpReceipt = receipt.arg( date.toString( "dd.MM.yyyy" ), fromKey, toKey, result ); + if( printToFile ) + printer.setOutputFileName( drive + QString( "receipts_%1.pdf" ).arg( pageCount ) ); + document.setHtml( tmpReceipt ); + document.print( &printer ); + } + + /// und das Finale Abschlussdokument: die Endabrechnung + QFile lastpage( miniCash::tplFinal ); + if( !lastpage.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QMessageBox::critical( this, tr("Dateifehler"), QString( tr("Datei nicht gefunden: %1") ).arg( lastpage.errorString() ), QMessageBox::Ok ); + return; + } + + QString final( lastpage.readAll() ); + final = final.arg( date.toString( "dd.MM.yyyy" ), MCSalesModel::toCurrency( revenueFinal ), MCSalesModel::toCurrency( gainFinal ) ); + final = final.arg( MCSalesModel::toCurrency( revenueFinal - gainFinal ) ); + final = final.arg( fee ); + final = final.arg( piecesFinal ); + final = final.arg( _allCustomers ); + final = final.arg( _salesSummary.size() ); + + if( printToFile ) + printer.setOutputFileName( drive + "FinalInvoice.pdf" ); + document.setHtml( final ); + document.print( &printer ); + + QApplication::restoreOverrideCursor(); + ///statusBar->removeWidget( progress ); + QMessageBox::information( this, tr("Quittungen drucken"), tr("Alle Druckaufträge wurden erfolgreich erzeugt.") ); + +} + + + + + + + + diff --git a/libMiniCash/mcbillingview.h b/libMiniCash/mcbillingview.h new file mode 100644 index 0000000..a928e59 --- /dev/null +++ b/libMiniCash/mcbillingview.h @@ -0,0 +1,72 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCBILLINGVIEW_H +#define MCBILLINGVIEW_H + +#include + +#include +#include +#include + + + +class MCMainWindow; + +namespace Ui +{ + class MCBillingView; +} + +/** + * @brief Das Hauptfenster der Anwendung im Abrechnungsmodus. + * + * Beim Umschalten in den Abrechnungsmodus wir ein neues Hauptfenster + * angezeigt. Hier lassen sich die zur Abrechnung notwendigen Daten noch + * einmal überprüfen und gegebenenfalls ändern. + */ + +class LIBMINICASH_EXPORT MCBillingView : public QFrame +{ + Q_OBJECT + +public: + + explicit MCBillingView( QWidget *parent = nullptr ); + virtual ~MCBillingView(); + + void setupDefaults( const QString& datafilename, QSettings* settings ); + +protected slots: + + void onReadTransactions(); // Kassendateien einlesen + void onPrintBills(); // Abrechnungen drucken + void onPrintReceipts(); // Quittungen drucken + +protected: + + bool testFormData(); + + Ui::MCBillingView* _ui{}; + int _allCustomers; + QSettings* _settings = nullptr; + MCSalesModel _salesModel; // StandardItemModel, speichert Verkaufsdaten und zeigt sie an. + MCSalesSummary _salesSummary; // _alle_ transaktionen, für die Auswertung + QString _fileFilter; + +}; + + +#endif // MCBILLINGVIEW_H diff --git a/libMiniCash/mcbillingview.ui b/libMiniCash/mcbillingview.ui new file mode 100644 index 0000000..518ecbe --- /dev/null +++ b/libMiniCash/mcbillingview.ui @@ -0,0 +1,369 @@ + + + MCBillingView + + + + 0 + 0 + 793 + 726 + + + + Frame + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 9 + true + + + + Druck in Datei + + + + + + + + 0 + 0 + + + + + 9 + true + + + + Quittungsliste drucken + + + Quittungsliste drucken + + + + :/myresource/images/printer2.png:/myresource/images/printer2.png + + + + 16 + 16 + + + + + + + + + 9 + true + + + + Druck in Datei + + + + + + + + 0 + 0 + + + + + 9 + true + + + + Alle Abrechungen Drucken + + + Abrechnungen drucken + + + + :/myresource/images/printer2.png:/myresource/images/printer2.png + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 240 + + + + + 9 + true + + + + Qt::NoFocus + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + false + + + + + + + + 9 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 9 + true + + + + Fußzeilentext (optional) + + + Qt::AutoText + + + + + + + + 0 + 0 + + + + + 9 + true + + + + <html><head/><body><p>Einlesen der Kassendateien vom Memorystick starten</p></body></html> + + + Kassendateien einlesen + + + + :/myresource/images/fileexport.png:/myresource/images/fileexport.png + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 9 + true + + + + + + + + + 9 + true + + + + Quelllaufwerk (z.B. 'E:\') + + + Qt::AutoText + + + + + + + + 9 + true + + + + + + + + + 9 + true + + + + Abrechnung Kundennumer von ... bis + + + Qt::AutoText + + + + + + + + 9 + true + + + + Anteil Kindergarten (%) + + + + + + + + 9 + true + + + + 1100 + + + + + + + + 9 + true + + + + 1399 + + + + + + + + MCTreeView + QTreeView +
mctreeview.h
+
+ + SWDriveSelector + QComboBox +
swdriveselector.h
+
+
+ + +
diff --git a/libMiniCash/mcformwidget.cpp b/libMiniCash/mcformwidget.cpp new file mode 100644 index 0000000..32056ea --- /dev/null +++ b/libMiniCash/mcformwidget.cpp @@ -0,0 +1,14 @@ +#include "mcformwidget.h" +#include "ui_mcformwidget.h" + +MCFormWidget::MCFormWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::MCFormWidget) +{ + ui->setupUi(this); +} + +MCFormWidget::~MCFormWidget() +{ + delete ui; +} diff --git a/libMiniCash/mcformwidget.h b/libMiniCash/mcformwidget.h new file mode 100644 index 0000000..5c8218c --- /dev/null +++ b/libMiniCash/mcformwidget.h @@ -0,0 +1,27 @@ +#ifndef MCFORMWIDGET_H +#define MCFORMWIDGET_H + +#include + +#include "libMiniCash_global.h" + +namespace Ui +{ + class MCFormWidget; +} + +class LIBMINICASH_EXPORT MCFormWidget : public QWidget +{ + Q_OBJECT + +public: + + explicit MCFormWidget(QWidget *parent = nullptr); + ~MCFormWidget(); + +private: + + Ui::MCFormWidget *ui; +}; + +#endif // MCFORMWIDGET_H diff --git a/libMiniCash/mcformwidget.ui b/libMiniCash/mcformwidget.ui new file mode 100644 index 0000000..6fe8740 --- /dev/null +++ b/libMiniCash/mcformwidget.ui @@ -0,0 +1,31 @@ + + + MCFormWidget + + + + 0 + 0 + 540 + 300 + + + + Form + + + + + + FITZ! + + + + + + + + + + + diff --git a/libMiniCash/mcinputview.cpp b/libMiniCash/mcinputview.cpp new file mode 100644 index 0000000..5dd1f8f --- /dev/null +++ b/libMiniCash/mcinputview.cpp @@ -0,0 +1,274 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include + +#include +#include +#include + +#include +/** + * Standardkonstruktor. + * @param parent + */ + +MCInputView::MCInputView( QWidget* parent ) + : QWidget( parent ), _ui{new Ui::MCInputView} +{ + _ui->setupUi( this ); + _ui->_trSellerID->setFocus(); +} + + +/** + * @brief Destruktor + */ + +MCInputView::~MCInputView() +{ + delete _ui; +} + + +/** + * @brief Vorgabewerete der Eingabemaske setzen + * @param parent + * @param salesModel + */ + +void MCInputView::setupDefaults( MCMainWindowBase* parent, MCSalesModel* salesModel ) +{ + + _parent = parent; + Q_ASSERT( _parent != nullptr ); + + // model setzen + _salesModel = salesModel; + _ui->_trList->setModel( _salesModel ); + + _valCustId.setRegularExpression( QRegularExpression( miniCash::fCustID ) ); // Validator für die Kundennnummer + _valItemNo.setRegularExpression( QRegularExpression( miniCash::fItemNo ) ); // Validator für die Kundennnummer; // Validator für die laufende Nummer des Artikels + _valPrice.setRegularExpression( QRegularExpression( miniCash::fPrice ) ); // Validator für die Kundennnummer; // Validator für die Preisangabe + + _ui->_trSellerID->setValidator( &_valCustId ); + _ui->_trItemNo->setValidator( &_valItemNo ); + _ui->_trPrice->setValidator( &_valPrice ); + + // Doppelklick auf einen Eintrag in der View soll diesen löschen + connect( _ui->_trList, SIGNAL( doubleClicked(QModelIndex) ), this, SLOT( onRemoveEntry(QModelIndex)) ); + + // hosianna : key event handling ist gar nicht nötig + QShortcut* shortcutPayback = new QShortcut( QKeySequence( Qt::Key_F1 ), this ); + QShortcut* shortcutSave = new QShortcut( QKeySequence( Qt::Key_F12 ), this ); + + connect( shortcutPayback, SIGNAL(activated()), this, SLOT( onCalculatePayback()) ); + connect( shortcutSave, SIGNAL(activated()), _parent, SLOT( onSaveTransaction()) ); + + // Alle Transaktionen sichern + connect( _ui->_trOK, SIGNAL(clicked()), _parent, SLOT( onSaveTransaction()) ); + + // Felder auch mit Enter weiterschalten + connect( _ui->_trSellerID, SIGNAL(returnPressed()), this, SLOT( onMoveInputFocus()) ); + connect( _ui->_trItemNo, SIGNAL(returnPressed()), this, SLOT( onMoveInputFocus()) ); + + // Transaktion fertig eingegeben? Dann prüfen + connect( _ui->_trPrice, SIGNAL(editingFinished()),this, SLOT( onAddSalesItem()) ); + + _ui->_trPos->setText( "1" ); + _ui->_trCount->setText( _parent->transCount() ); + +} + + + /** + * @brief Eingabefelder per Enter weiterschalten + * + * Die Eingabefelder (Kundennummer, laufende Nummer etc. ) sollen nicht nur per TAB + * sondern auch per ENTER weitergeschaltet werden, also wird das Signal "returnPressed" + * eingefangen und der Focus an das jeweils nächste Eingabeelement weitergereicht. + */ + + void MCInputView::onMoveInputFocus() + { + QWidget* sigsender = dynamic_cast( sender() ); + if( sigsender ) + sigsender->nextInFocusChain()->setFocus(); + } + + + /** + * @brief einen verkauften Artikel speichern + * + * Wird aufgerufen wenn ein verkaufter Artikel fertig eingegeben ist + * (sprich: wenn das Preisfeld den Fokus verliert oder Enter gedrückt wird). + * Nach erfolgreicher Überprüfung der Eingaben wird ein neuer Eintrag in die + * Transaktionliste geschrieben. + */ + + void MCInputView::onAddSalesItem() + { + + /// murx, präventiv + _ui->_trList->clearSelection(); + + QString custID = _ui->_trSellerID->text(); + QString itemNo = _ui->_trItemNo->text(); + QString price = _ui->_trPrice->text(); + + /// TODO: + /// Bei Fehlern: + /// - message im statusbar + /// - feld dg rot, focus + /// - tönchen + /// _kein_ popup + + int pos = 0; + if + ( + custID.isEmpty() || + itemNo.isEmpty() || + price.isEmpty() || + _valCustId.validate( custID, pos ) != QValidator::Acceptable || + _valItemNo.validate( itemNo, pos ) != QValidator::Acceptable || + _valPrice.validate( price, pos ) != QValidator::Acceptable + ) + { + QApplication::beep(); + return; + } + + /// den neuen Eintrag in der schicken liste speichern & anzeigen ... + _salesModel->appendEntry( _parent->transCount(), custID, itemNo, price ); + + /// Die Liste Runterscrollen damit der Beitrag auch sichtbar wird + _ui->_trList->scrollToBottom(); + + /// ... und die Lineedits wieder löschen ... + _ui->_trSellerID->clear(); + _ui->_trItemNo->clear(); + _ui->_trPrice->clear(); + + /// positionscount hochzählen + _ui->_trPos->setText( QString( "%0" ).arg( ++_poscount ) ); + /// und die gesamtsumme sichern + _overallSum += MCSalesModel::fromCurrency( price ); + _ui->_trOverall->setText( MCSalesModel::toCurrency( _overallSum ) ); + + _ui->_trSellerID->setFocus(); + + } + + + /** + * @brief Das Rückgeld berechnen + * + * Zeigt einen einfachen Dialog, um das Rückgeld zu berechnen. + */ + + void MCInputView::onCalculatePayback() + { + bool ok; + double amount = QInputDialog::getDouble + ( + this, + "Rückgeld berechnen", + "Welchen Betrag haben Sie erhalten?", + 0, 0, 1000, 2, &ok + ); + if( ok ) + { + QString ret( "Das Rückgeld beträgt: %0"); + QMessageBox::information( this, "Rückgeld", ret.arg( MCSalesModel::toCurrency( amount - _overallSum ) ) ); + } + + } + + + /** + * @brief einen Artikel per Doppelklick aus der + * Verkaufsliste entfernen + * @param idx + * + * Einen Verkaufseintrag per Doppelklick auf die entsprechende Zeile + * in der View löschen. Die Gesamtsumme und die Positionszähler müssen + * entsprechend angepasst werden. + * + */ + + void MCInputView::onRemoveEntry( QModelIndex idx ) + { + + // murx, translate + QMessageBox msg; + msg.setWindowTitle( "Eintrag löschen" ); + msg.setText( "Soll dieser Eintrag wirklich gelöscht werden?" ); + msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msg.addButton( "Ja", QMessageBox::YesRole); + msg.addButton("Nein", QMessageBox::NoRole ); + msg.setDefaultButton(QMessageBox::Yes); + msg.setIcon ( QMessageBox::Question ); + + _ui->_trList->clearSelection(); + + if( msg.exec() == QMessageBox::No ) + return; + + // die gesamtsumme anpassen + QVariant var = _salesModel->item( idx.row(), 3 )->data( Qt::DisplayRole ); + + double price = MCSalesModel::fromCurrency( var.toString() ); + double newprice = _overallSum - price; + + // oops we did it again ... + _salesModel->removeRow( idx.row() ); + + // recalc maxpos + _ui->_trPos->setText( QString( "%0" ).arg( --_poscount ) ); + + // neue summe + _ui->_trOverall->setText( MCSalesModel::toCurrency( newprice ) ); + _overallSum = newprice; + _ui->_trList->clearSelection(); + + } + + + /** + * @brief Die Eingabemaske zurücksetzen + * + * Setzt die Eingabemaske nach einer Kundentransaktion zurück, + * erhöht die internen Zähler und zeigt diese an. + */ + + void MCInputView::onResetView() + { + _ui->_trSellerID->clear(); + _ui->_trItemNo->clear(); + _ui->_trPrice->clear(); + + // Gesamtsumme nicht vergessen + _ui->_trOverall->setText( MCSalesModel::toCurrency( 0 ) ); + + // Zähler anzeigen + _ui->_trCount->setText( _parent->transCount() ); + _ui->_trPos->setText( "1" ); + + _overallSum = 0.0; + _salesModel->removeRows( 0, _salesModel->rowCount() ); + + + } diff --git a/libMiniCash/mcinputview.h b/libMiniCash/mcinputview.h new file mode 100644 index 0000000..f1b73d1 --- /dev/null +++ b/libMiniCash/mcinputview.h @@ -0,0 +1,73 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCINPUTVIEW_H +#define MCCINPUTVIEW_H + +#include +#include +#include + +#include + + + +class MCMainWindowBase; +class MCSalesModel; + +namespace Ui +{ + class MCInputView; +} + +/** + * @brief The MCInputView class + */ + +class LIBMINICASH_EXPORT MCInputView : public QWidget +{ + Q_OBJECT + +public: + + explicit MCInputView( QWidget* parent = nullptr ); + virtual ~MCInputView(); + + void setupDefaults( MCMainWindowBase* parent, MCSalesModel* salesModel ); + +public slots: + + void onCalculatePayback(); + void onResetView(); + void onRemoveEntry( QModelIndex idx ); + void onMoveInputFocus(); /// Eingabefelder sollen auch per Enter weitergeschaltet werden + void onAddSalesItem(); + +private: + + Ui::MCInputView* _ui{}; + + QRegularExpressionValidator _valCustId; /// Validator für die Kundennnummer + QRegularExpressionValidator _valItemNo; /// Validator für die laufende Nummer des Artikels + QRegularExpressionValidator _valPrice; /// Validator für die Preisangabe + + int _poscount = 1; /// Verkaufsposition innerhalb des aktuellen Vorgangs + double _overallSum = 0.0; /// Gesamtpreis der aktuellen Verkaufstransaktion + + MCSalesModel* _salesModel = nullptr; + MCMainWindowBase* _parent = nullptr; + +}; + +#endif /// MCCINPUTVIEW_H diff --git a/libMiniCash/mcinputview.ui b/libMiniCash/mcinputview.ui new file mode 100644 index 0000000..3f33731 --- /dev/null +++ b/libMiniCash/mcinputview.ui @@ -0,0 +1,380 @@ + + + MCInputView + + + + 0 + 0 + 950 + 770 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Lucida Sans Typewriter + 9 + true + + + + Qt::NoFocus + + + false + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + false + + + + + + + + + + 0 + 0 + + + + + 240 + 10 + + + + + 14 + true + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt; font-weight:400;">Hier klicken (oder F12 drücken) um einen neuen Verkaufsvorgang zu starten.</span></p></body></html> + + + QWidget{ background: rgb(210, 210, 200) } + + + Neuer Kunde (F12) + + + F12 + + + false + + + + + + + true + + + + 20 + 0 + + + + + 40 + 16777215 + + + + + 14 + + + + Qt::NoFocus + + + QWidget{ background: rgb(232, 232, 232) } + + + 99 + + + + + + + + 14 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Geben sie hier die zweistellige laufende Nummer des Artikels ein.</span></p></body></html> + + + + + + + + + + + 14 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Geben sie hier den Preis des Artikels ein.</span></p></body></html> + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 9 + true + + + + Preis + + + + + + + true + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + 14 + + + + Qt::NoFocus + + + + + + + + + + + + QWidget{ background: rgb(232, 232, 232) } + + + Qt::ImhDigitsOnly + + + 9999 + + + + + + + + 9 + true + + + + Pos. + + + + + + + + 9 + true + + + + Verkäufernummer + + + + + + + + 9 + true + + + + laufende Nummer + + + + + + + + 14 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Geben sie hier die Kundennummer (1100 bis 1999) ein.</span></p></body></html> + + + + + + + + + + + 9 + true + + + + Kunde + + + + + + + + 40 + false + + + + Gesamtpreis + + + QLabel { background-color: white } + + + QFrame::StyledPanel + + + QFrame::Sunken + + + 0,00 € + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 9 + false + + + + Hinweise: + - <tab> wechselt die Eingabefelder + - <enter> bzw. <tab> schließt die Eingabe ab + - Doppelklick in der Übersicht löscht den Eintrag + - F1 zur Rückgeldberechnung drücken + + + + + + + + + + MCTreeView + QTreeView +
mctreeview.h
+
+
+ + _trSellerID + _trItemNo + _trPrice + + + +
diff --git a/libMiniCash/mcloaddialog.cpp b/libMiniCash/mcloaddialog.cpp new file mode 100644 index 0000000..4d2c2ed --- /dev/null +++ b/libMiniCash/mcloaddialog.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + +#include +#include + +/** + * @brief Dialogfenster das das Laden der Kassendateien anzeigt. + * + * @param parent Elternfenster + * Die Namen der Kassendateien werden aufgelistet und nach erfolgreichem + * Ladevorgang abgehakt. + */ + +MCLoadDialog::MCLoadDialog( QWidget* parent ) + : QDialog(parent), _ui{new Ui::MCLoadDialog}, _firstTime( true ) +{ + _ui->setupUi( this ); + + connect( _ui->_OkButton, SIGNAL(clicked()), this, SLOT( accept() ) ); + +} + +MCLoadDialog::~MCLoadDialog() +{ + delete _ui; +} + + +/** + * @brief Einen Dateinamen in die Liste schreiben + * @param entry der Dateiname + */ + +void MCLoadDialog::appendEntry( const QString& entry ) +{ + _ui->_listWidget->addItem( entry ); +} + + +/** + * @brief Statusmeldung an einen Dateinamen der Liste anhängen. + * + * @param idx der Index des Dateinnamens + * @param text der Zusatztext: 'OK' oder 'Fehler'. + */ + +void MCLoadDialog::updateEntry( int idx, const QString& text ) +{ + const QString& txt = _ui->_listWidget->item( idx )->text(); + QIcon icon( ":/images/button_ok.png" ); + // text ändern + QListWidgetItem& itm = *_ui->_listWidget->item( idx ); + itm.setIcon( icon ); + itm.setText( txt + text ); +} + + +/** + * @brief Startet das einlesen der Kassendateien. + * + * Beim ersten Klick auf 'OK' (Anzeige 'Einlesen') werden die Ergebnisse + * angezeigt und der Text geändert. Beim zweiten 'OK' (Anzeige: 'Weiter' ) + * werden die Texte zurückgesetzt und es geht tatsächlich weiter. + */ + +void MCLoadDialog::accept() +{ + + if( _firstTime ) + { + _firstTime = false; + // Murx, FIX! das sollte über den Translator gehen + //buttonBox->button( QDialogButtonBox::Ok )->setText( "Weiter" ); + _ui->_label1->setText( "verkaufte Artikel:" ); + + } + + return QDialog::accept(); +} diff --git a/libMiniCash/mcloaddialog.h b/libMiniCash/mcloaddialog.h new file mode 100644 index 0000000..a9e9fd4 --- /dev/null +++ b/libMiniCash/mcloaddialog.h @@ -0,0 +1,58 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCLOADDIALOG_H +#define MCLOADDIALOG_H + +#include + +#include +#include + +namespace Ui +{ + class MCLoadDialog; +} + +/** + * @brief Infodialog, der bei der Abrechnung die vorhandenen Kassendateien anzeigt. + */ + +class LIBMINICASH_EXPORT MCLoadDialog : public QDialog +{ + Q_OBJECT + +public: + + explicit MCLoadDialog( QWidget* parent ); + ~MCLoadDialog(); + + void appendEntry( const QString& entry ); + void updateEntry( int idx, const QString& text ); + +protected: + + void accept(); + +private: + + Ui::MCLoadDialog* _ui{}; + bool _firstTime; + +}; + +#endif // MCLOADDIALOG_H + + + diff --git a/libMiniCash/mcloaddialog.ui b/libMiniCash/mcloaddialog.ui new file mode 100644 index 0000000..0472b19 --- /dev/null +++ b/libMiniCash/mcloaddialog.ui @@ -0,0 +1,89 @@ + + + MCLoadDialog + + + + 0 + 0 + 450 + 250 + + + + Dialog + + + + + + + 10 + true + + + + + + + Folgende Kassendateien werden jetzt eingelesen: + + + + + + + false + + + + 10 + + + + QWidget{ background: rgb(232, 232, 232) } + + + + 22 + 22 + + + + + + + + Qt::Horizontal + + + + 325 + 20 + + + + + + + + + 0 + 0 + + + + + true + + + + OK + + + + + + + + diff --git a/libMiniCash/mcmainwindowbase.cpp b/libMiniCash/mcmainwindowbase.cpp new file mode 100644 index 0000000..8395e09 --- /dev/null +++ b/libMiniCash/mcmainwindowbase.cpp @@ -0,0 +1,468 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2018 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +/// Für den Test auf CapsLock +///#include "Windows.h" +/* + * bool QMyClass::checkCapsLock() +{ +// platform dependent method of determining if CAPS LOCK is on +#ifdef Q_OS_WIN32 // MS Windows version +return GetKeyState(VK_CAPITAL) == 1; +#else // X11 version (Linux/Unix/Mac OS X/etc...) +Display * d = XOpenDisplay((char*)0); +bool caps_state = false; +if (d) +{ +unsigned n; +XkbGetIndicatorState(d, XkbUseCoreKbd, &n); +caps_state = (n & 0x01) == 1; +} +return caps_state; +#endif +} +*/ + + +/** + * @brief Der Konstruktor, die Initialisierungen des GUI + * und der Netzverbindung werden in den Unterklassen vorgenommen. + */ + +MCMainWindowBase::MCMainWindowBase( QWidget* parent ) + : QMainWindow( parent ) +{ + + /// model setzen + _salesModel.setParent( this ); + +} + + +/** + * @brief MCMainWindowBase::~MCMainWindowBase ! + */ + +MCMainWindowBase::~MCMainWindowBase() +{ + +} + + +/** + * @brief MCMainWindowBase::transCount ! + * @return + */ + +QString MCMainWindowBase::transCount() +{ + return MCSalesModel::formatInt( _transCount ); +} + + +/** + * @brief Dateipfad anhand der Vorgaben aus dem Setup-Dialog erzeugen. + * @param key settingskey + * + * Dateipfad anhand der Vorgaben aus den settings zusammenbasteln, Hilfsfunktion + * + * @return pfad + */ + +QString MCMainWindowBase::fetchSetting( const QString& key ) +{ + return _mainSettings.value( key ).toString(); +} + + +/** + * @brief Datei-Fehlermeldung anzeigen: Meistens sind einfach die Pfadeinstellungen falsch. + * @param filename + * @param errormsg + * + * Conveniencefunction zur vereinfachten Handhabung von Dateifehlern, + * errortxt holen, Messagebox erzeugen etc. + * @return immer false + */ + +bool MCMainWindowBase::showFileError( const QString& filename, const QString& errormsg ) +{ + + QString msg( "Datei '%0' konnte nicht geöffnet werden.\nFehlercode: %1" ); + /// je schlimmer je geiler + QMessageBox::critical( this, "Fehler", msg.arg( filename, errormsg ) ); + return false; +} + + +/** + * @brief Dateien & Settings initialisieren + * + * Wird direkt beim Programmstart aufgerufen, setzt die Vorgabewerte + * und erzeugt die Arbeitsdateien. + * + * @see setupDataFile + * + */ + +void MCMainWindowBase::setupDefaults() +{ + + /// leer? dann defaults reinschreiben + if( !_mainSettings.contains( miniCash::keyMobileDrive) ) + { + _mainSettings.setValue( miniCash::keyMobileDrive, miniCash::mobileDrive ); + _mainSettings.setValue( miniCash::keyProfit, miniCash::profit ); + _mainSettings.setValue( miniCash::keySelfID, miniCash::selfID ); + _mainSettings.setValue( miniCash::keyFooterText, "" ); + } + + /// solange Setup-Dialog zeigen bis die Arbeitsfiles + /// nutzbar sind + + bool allfine = false; + while( !allfine ) + { + allfine = setupDataFile(); + if( !allfine ) + { + QString msg( "Die lokale Arbeitsdatei konnte nicht angelegt werden.\nBitte die Programmeinstellungen überprüfen." ); + QMessageBox::critical( this, "Dateifehler", msg ); + setupDataFile(); + } + } + +} + + +/** + * @brief Kassendateien öffnen oder erzeugen + * + * Hier werden die beiden Arbeitsdateien geöffnet bzw. erzeugt: es + * wird entschieden, ob ein zum heutigen Datum (also Freitag oder Samstag) + * ein passender Kleidermarkt vorhanden ist. + * Falls nicht, wird eine Kassendatei fürs heutige Datum angelegt. + */ + +bool MCMainWindowBase::setupDataFile() +{ + + /// step 1: Filenamen aus Datum bauen, hack: wir nehmen immer den Freitag + QDate date = QDate::currentDate(); + /// Hack: Am Samstag schalten wir auf Freitag + if( date.dayOfWeek() == 6 ) + date = date.addDays( -1 ); + + /// Filenames aus Datum + _dataFileName = date.toString( "MM-dd-yyyy" ) + miniCash::filetype; + QString dirName = QDir::homePath() + miniCash::dataDir; + QDir dir( dirName ); + if( !dir.exists() ) + dir.mkpath( dirName ); + + _dataFilePath = dirName + _dataFileName; + + /// erstmal alles auf Anfang + _transCount = 1; + + /// Ist das File schon vorhanden ? Sonst anlegen + QFile datafile( _dataFilePath ); + + if( !datafile.exists() ) + { + /// hats auch wirklich geklappt? + if( !datafile.open( QIODevice::WriteOnly ) ) + /// wenn schon der start misslingt, hat + /// nichts mehr einen sinn + return showFileError( _dataFilePath, datafile.errorString() ); + _mainSettings.setValue( miniCash::keyTransCount, "1" ); + } + + /// Zählerstand lesen. + _transCount = _mainSettings.value( miniCash::keyTransCount ).toInt(); + + return true; + +} + + + +/** + * @brief Speichert die Transaktionsdaten in eine Datei, hier Stick und Festplatte + * @param filename Zieldatei + * @param result die Verkaufstransaktion + * + * Verkaufte Artikel auf Platte oder Stick sichern. Ds ist eine Hilfsfunktion für + * @see onSaveTransaction, wir zweimal aufgerufen: einmal auf Stick und einmal + * als Geheim-Backup auf Platte. + * + */ + +bool MCMainWindowBase::saveTransactionToFile( const QString& filename, const QString& transaction ) +{ + QFile datafile( filename ); + if (!datafile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append )) + return showFileError( filename, datafile.errorString() ); + + /// file nicht direkt beschreiben + QTextStream output( &datafile ); + /// Stream füllen + output << transaction; + + return true; + +} + + +/** + * @brief Schreibt die Einkäufe eines Kunden (==Transaktion) + * via QTextStream formatiert in einen String. + * + * Alle bisherigen Verkäufe, also der Inhalt des @see MCSalesModel, werden + * mit Hilfe eines QTextStreams als Tab-Separated-Values in einen QString + * geschrieben + * + * @return Die Verkaufstransaktion als String + * + */ + +QString MCMainWindowBase::saveTransactionToString() +{ + + QString result; + QTextStream output( &result ); + + /// Stream füllen + for( int row = 0; row < _salesModel.rowCount(); ++row ) + { + + /// TransactionNo + QModelIndex idx = _salesModel.index( row, MCSalesItemMap::Count ); + QString content = _salesModel.data( idx ).toString(); + output << content << " "; + + /// SellerID + idx = _salesModel.index( row, MCSalesItemMap::SellerID ); + content = _salesModel.data( idx ).toString(); + output << content << " "; + + /// Laufende ArtikelNo + idx = _salesModel.index( row, MCSalesItemMap::ItemNo ); + + /// passiert jetzt schon im model + ///output << formatInt( _salesModel.data( idx ).toInt(), 3 ); + output << _salesModel.data( idx ).toString(); + + idx = _salesModel.index( row, MCSalesItemMap::Price ); + content = _salesModel.data( idx ).toString(); + + /// Eurozeichen absäbeln, komma statt punkt wg. kompatibilität + /// mit PCK + + if( content.isEmpty() || content.isNull() ) + { + /// FIX, murx: log error + content = "0,0"; + } + else + { + content = content.split( ' ' ).at(0); + } + + /// so sollte man es eigentlich machen + output << Qt::right << qSetFieldWidth(15) << content << Qt::reset; + /// datum/zeit dranhängen & zeile fertig + QString dtstr = QDateTime::currentDateTime().toString( "MM-dd-yyyy hh:mm:ss" ); + output << ' ' << dtstr << Qt::endl; + + } + + return result; + +} + + +/** + * @brief Vom aktuellen Kunden gekaufte Artikel auf Platte sichern. + * + * Speichert die vom aktuellen Kunden gekauften Artikel auf Platte. + * @see saveTransactionToString() + * + */ + +bool MCMainWindowBase::onSaveTransaction() +{ + + // View auslesen + /// an datei anhängen + /// zähler zurücksetzen + /// die Lineedits wieder löschen + + /// + /// Step 0: gibbet überhaupt View-Daten? + /// + + if( _salesModel.rowCount() == 0 ) + { + QApplication::beep(); + return false; + } + + /// + /// Step 1: View-Daten via Textstream in einen String schreiben + /// + + QString transaction = saveTransactionToString(); + + /// + /// Step 2a: Die (nunmehr formatierte) Transaktion speichern und sichern + /// + + /// Offizieller Speicherort auf dem Stick bzw. nunmehr auf SSD + if( !saveTransactionToFile( _dataFilePath, transaction ) ) + return false; + + /// Dummy für Speichern im Netz + emit transactionCreated( transaction ); + + /// + /// Step 4: das Zählerfeld neu setzen + /// + _newTransCount++; + _transCount++; + _mainSettings.setValue( miniCash::keyTransCount, _transCount ); + + /// + /// Step 4: Die Lineedits & view wieder löschen + /// + + _inputViewProxy->onResetView(); + + return true; + +} + + +/** + * @brief Verkaufstransaktionen kopieren + * + * Alle Verkaufstransaktionen zur Auswertung auf einen Memorystick + * kopieren + * + */ + +void MCMainWindowBase::onCopyTransactions() +{ + + /// FIX murx + QMessageBox msg; + msg.setWindowTitle( "Auswertungsdatei erzeugen" ); + QString txt( "Wenn der Memorystick in Laufwerk '%0' \neingesteckt ist bitte auf 'Speichern' klicken" ); + msg.setText( txt.arg( fetchSetting( miniCash::keyMobileDrive ) ) ); + msg.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel ); + msg.addButton("Speichern",QMessageBox::AcceptRole); + msg.addButton("Abbrechen",QMessageBox::RejectRole); + msg.setDefaultButton(QMessageBox::Save); + msg.setIcon ( QMessageBox::Information ); + + if( msg.exec() == QMessageBox::Cancel ) + return; + + QString target = fetchSetting( miniCash::keyMobileDrive ) + fetchSetting( miniCash::keySelfID ); + target += "_" + _dataFileName; + + /// falls vorhanden löschen weil copy nicht überschreibt + QFileInfo fitarget( target ); + + if( fitarget.exists() ) + QFile::remove( target ); + + if( !QFile::copy( _dataFilePath, target ) ) + { + QString msg( "Dateifehler: Kopieren von %0\nnach %1 fehlgeschlagen."); + QMessageBox::warning(this, "Dateifehler", msg.arg( _dataFilePath, target ) ); + + return onSetup(); + } + + QMessageBox::information( this, "Auswertungsdatei erzeugen", "Auswertungsdatei wurde erfolgreich erzeugt." ); + +} + + + + +/** + * @brief Handbuch anzeigen + * + * @bug Handbuch ist noch nicht fertig. + */ + +void MCMainWindowBase::onHelpManual() +{ + //QMessageBox::StandardButton reply = QMessageBox::information(this, "onHelpContents()", "onHelpContents()" ); + //_helpViewer->show(); + onHelpAbout(); +} + + + +/** + * @brief Speichern und Beenden, die Toolbarversion: Es wird nachgefragt. + */ + +void MCMainWindowBase::onExitConfirmed() +{ + /// murx + QMessageBox msg; + msg.setWindowTitle("Programm beenden"); + msg.setText("Programm wirklich beenden?"); + msg.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel ); + msg.addButton("OK", QMessageBox::AcceptRole ); + msg.addButton("Abbrechen",QMessageBox::RejectRole); + msg.setDefaultButton(QMessageBox::Save); + msg.setIcon ( QMessageBox::Information ); + + if( msg.exec() == QMessageBox::Cancel ) + return; + + onExit(); + +} + + +/** + * @brief Speichern und Beenden, die Menuversion: Es wird nicht nachgefragt. + */ + +void MCMainWindowBase::onExit() +{ + + /// Falls noch Transaktion vorhanden, + /// diese sichern + if( _salesModel.rowCount() != 0 ) + onSaveTransaction(); + qApp->exit(); +} diff --git a/libMiniCash/mcmainwindowbase.h b/libMiniCash/mcmainwindowbase.h new file mode 100644 index 0000000..50d0ae0 --- /dev/null +++ b/libMiniCash/mcmainwindowbase.h @@ -0,0 +1,120 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCMAINWINDOWBASE_H +#define MCMAINWINDOWBASE_H + +#include +#include + +#include +#include +#include + + +/** + * @brief Dient als abstrakte MainWindow-Basisklasse für Projekte, + * die auf libMiniCash aufbauen. + * + * Die MCMainWindowBase-Klasse ist die Hauptklasse der libMiniCash-Library und dient als + * abstrakte Basisklasse der jeweiligen MainWindows in den Projekten, die auf libMiniCash aufbauen. + * + * Die Benutzeroberlfläche wird hier _nicht_ implementiert, sondern nur die Infrastruktur zum + * + * - Eingeben + * - Bearbeiten + * - sowie Speichern + * + * von Verkaufsdaten. Funktionen, die direkt mit der Nutzeroberfläche interagieren, werden + * daher in den Subklassen implemntiert. + +* Die dazu verwendeten Klassen werden auch in dieser Bibliothek definiert: +* + * - @see mcsalesitem + * - @see mcsalesitemmap + * - @see mcsalesmodel + * - @see mcsalessummary + * + * Weiterhing enthält MCMainWindowBase die Implementierung der SLOTS für Servicefunktionalität der + * Benutzeroberfläche. + * + */ + +class LIBMINICASH_EXPORT MCMainWindowBase : public QMainWindow +{ + Q_OBJECT + +public: + + explicit MCMainWindowBase( QWidget* parent = nullptr ); + virtual ~MCMainWindowBase(); + + QString transCount(); + +signals: + + void fileError(); + void transactionCreated( const QString& transaction ); /// Einkaufstransaktion beenden, senden + +protected: + + QString fetchSetting( const QString& key ); /// Hilfsfunktion: Dateipfad erzeugen + bool showFileError( const QString& filename, const QString& errormsg ); /// Hilfsfunktion: Fehlermeldung anzeigen + + void setupDefaults(); /// Init-Funktion, wird beim Programmstart aufgerufen + bool setupDataFile(); /// Arbeitsdateien erzeugen bzw. öffnen + + QString saveTransactionToString(); + bool saveTransactionToFile( const QString& filename, const QString& transaction ); /// Einkaufstransaktion beenden, auf platte oder ins netz schreiben schreiben + +protected slots: + + virtual void onSetup() = 0; + virtual void onEditTransactions() = 0; /// Kassendatei durchsuchen und editieren + virtual bool onSaveTransaction(); /// Kundentransaktion beenden, auf platte schreiben + virtual void onCopyTransactions(); /// Alle Transaktionen zur Auswertung von Disk auf Stick kopieren + virtual void onStartBilling() = 0; /// Kassieren beenden und Abrechnungsmodus starten + virtual void onExit(); /// Programm beenden + virtual void onExitConfirmed(); /// Programm beenden, mit Bestätigung + virtual void onHelpAbout() = 0; /// rumbalotte + virtual void onHelpManual(); /// Hilfe anzeigen + +protected: + + int _transCount = -10; /// Anzahl der Transaktionen (== Verkäufe) ingesamt bisher + int _newTransCount = 0; /// Anzahl der Transaktionen (== Verkäufe) seit dem Programmstart + + MCSalesModel _salesModel; /// StandardItemModel, speichert Verkaufsdaten und zeigt sie an. + QString _dataFileName; /// Name der Transaktionsdatei _ohne_ Laufwerk: 02-15-2013.klm + QString _dataFilePath; /// Pfad der Transaktionsdatei _ohne_ Laufwerk: 02-15-2013.klm + MCInputView* _inputViewProxy = nullptr; /// Platzhalter für die InputView, die in den subclasses implementiert wird. + QSettings _mainSettings; /// Persistente Einstellungen + +}; + +#endif // MCMAINWINDOWBASE_H + + + + + + + + + + + + + + diff --git a/libMiniCash/mcnetworkdialog.cpp b/libMiniCash/mcnetworkdialog.cpp new file mode 100644 index 0000000..a4f7806 --- /dev/null +++ b/libMiniCash/mcnetworkdialog.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** + + miniCash + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + +#include +#include + +#include + + +MCNetworkDialog::MCNetworkDialog( QWidget* parent, QSettings* settings ) + : QDialog( parent ), _ui{new Ui::MCNetworkDialog}, _settings( settings ) +{ + + Q_ASSERT( nullptr != _settings ); + + _ui->setupUi( this ); + + // Murx, FIX! das sollte über den Translator gehen + _ui->_buttonBox->button( QDialogButtonBox::Ok )->setText( "Speichern" ); + _ui->_buttonBox->button( QDialogButtonBox::Cancel )->setText( "Abbrechen" ); + + /// Vorgabewerte setzen + _ui->_receiverHost->setText( _settings->value( miniCash::keyReceiverHost ).toString() ); + _ui->_receiverPort->setText( _settings->value( miniCash::keyReceiverPort, miniCash::receiverPort ).toString() ); + _ui->_senderHost->setText( QHostInfo::localHostName() ); + + bool isReceiver = _settings->value( miniCash::keyIsTcpReceiver, miniCash::isTcpReceiver ).toBool(); + bool isSender = _settings->value( miniCash::keyIsTcpSender, miniCash::isTcpSender ).toBool(); + _ui->_isSender->setChecked ( isSender ); + _ui->_isReceiver->setChecked( isReceiver ); + + onSetNetworkEnabled( true ); + onTestHostEntry(); + + connect( _ui->_buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); + connect( _ui->_buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); + + connect( _ui->_receiverHost, SIGNAL( textChanged(QString) ), this, SLOT( onTestHostEntry(QString) ) ); + connect( _ui->_receiverPort, SIGNAL( textChanged(QString) ), this, SLOT( onTestHostEntry(QString) ) ); + connect( _ui->_isSender, SIGNAL( toggled(bool) ), this, SLOT( onSetNetworkEnabled(bool) ) ); + connect( _ui->_isReceiver, SIGNAL( toggled(bool) ), this, SLOT( onSetNetworkEnabled(bool) ) ); + + /// @see https://www.kdab.com/nailing-13-signal-slot-mistakes-clazy-1-3/: + /// warning pass a context object as 3rd connect parameter + connect( _ui->_buttonUseNetwork, &QAbstractButton::toggled, _ui->_receiverHost, + [=]( bool isOn ) + { + _ui->_groupBox->setEnabled( isOn ); + _useNetwork = isOn; + if( !isOn ) + { + _ui->_isSender->setChecked( false ); + _ui->_isReceiver->setChecked( false ); + } + } ); + + connect( _ui->_buttonTest, &QPushButton::clicked, _ui->_receiverHost, + [=]() + { + QHostInfo::lookupHost( _ui->_receiverHost->text(), this, SLOT( onLookupHost(QHostInfo) ) ); + } ); + +} + +/** + * @brief Destruktor + */ + +MCNetworkDialog::~MCNetworkDialog() +{ + delete _ui; +} + + +void MCNetworkDialog::onTestHostEntry( const QString& ) +{ + bool enable = !_ui->_receiverHost->text().isEmpty() && !_ui->_receiverPort->text().isEmpty(); + _ui->_buttonTest->setEnabled( enable ); +} + + +void MCNetworkDialog::onSetNetworkEnabled( bool ) +{ + + bool isSender = _ui->_isSender->isChecked(); + bool isReceiver = _ui->_isReceiver->isChecked(); + + _ui->_buttonTest->setEnabled( isSender ); + _ui->_receiverHost->setEnabled( isSender ); + _ui->_receiverPort->setEnabled( isSender ); + + _useNetwork = isSender || isReceiver; + /// klappt nicht! Bedenke die Logik! + ///_buttonUseNetwork->setChecked( _useNetwork ); + _ui->_buttonUseUSB->setChecked( !_useNetwork ); + _ui->_buttonUseNetwork->setChecked( _useNetwork ); + _ui->_groupBox->setEnabled( _useNetwork ); + +} + + +bool MCNetworkDialog::onLookupHost( const QHostInfo& hostInfo ) +{ + + if( hostInfo.error() != QHostInfo::NoError ) + { + _ui->_labelTest->setStyleSheet( "font-weight: bold; color: red" ); + _ui->_labelTest->setText( "Host nicht gefunden" ); + return false; + } + + _ui->_labelTest->setStyleSheet( "font-weight: normal; color: green" ); + _ui->_labelTest->setText( "Verbindung möglich" ); + + return true; + +} + + +/** + * @brief ok gedrückt: geänderte Daten prüfen und übernehmen + */ + +void MCNetworkDialog::accept() +{ + + qDebug() << "MCNetworkDialog::accept()"; + + const QString& host = _ui->_receiverHost->text(); + const QString& port = _ui->_receiverPort->text(); + QHostInfo hostInfo; + + /// wollen wir ins netz? + onSetNetworkEnabled( true ); + + /// wir wollen gar kein netz? + if( !_useNetwork || _ui->_buttonUseUSB->isChecked() ) + //return QDialog::reject(); + goto xx; + + /// wollen wir server sein? + if( !_ui->_isSender->isChecked() ) + goto xx; + + /// wir wollen senden, also Receiver prüfen + if( host.isEmpty() || port.isEmpty() ) + { + QMessageBox::warning + ( + this, + "Eingabefehler", + "Die Felder 'Servername' und 'Port'\n " + "müssen belegt sein." + ); + return; + } + + /* + Nein, das haut so nicht hin + // alles da, klappts dann auch mit dem Nachbarn? + int res = QHostInfo::lookupHost( host, this, SLOT( onLookupHost(QHostInfo) ) ); + /// hier warten, bis 'onLookupHost' zurückkommt und '_hostValid' gesetzt ist + _lookupLock.lock(); + */ + + hostInfo = QHostInfo::fromName( host ); + if( onLookupHost( hostInfo ) ) + goto xx; + + QMessageBox::warning + ( + this, + "Netzwerkfehler", + "Der Server '" + host + "' ist \n" + "nicht erreichbar." + ); + return; + + +xx: _settings->setValue( miniCash::keyIsTcpSender, _ui->_isSender->isChecked() ); + _settings->setValue( miniCash::keyIsTcpReceiver, _ui->_isReceiver->isChecked() ); + _settings->setValue( miniCash::keyReceiverHost, host ); + _settings->setValue( miniCash::keyReceiverPort, port ); + + qDebug() << "-- isSender: " << _ui->_isSender->isChecked(); + qDebug() << "-- isReceiver: " << _ui->_isReceiver->isChecked(); + qDebug() << "-- host: " << host; + qDebug() << "-- port: " << port; + + return QDialog::accept(); + +} diff --git a/libMiniCash/mcnetworkdialog.h b/libMiniCash/mcnetworkdialog.h new file mode 100644 index 0000000..7575ce9 --- /dev/null +++ b/libMiniCash/mcnetworkdialog.h @@ -0,0 +1,62 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCNETWORKDIALOG_H +#define MCCNETWORKDIALOG_H + +#include +#include +#include +#include + +#include + +namespace Ui +{ + class MCNetworkDialog; +} + +/** + * @brief Hilfsdialog, setzt und überprüft die Netzwerkeinstellungen, + * zusätzlich zum normalen 'Setup'-Dialog. + */ + +class LIBMINICASH_EXPORT MCNetworkDialog : public QDialog +{ + + Q_OBJECT + +public: + + explicit MCNetworkDialog( QWidget* parent, QSettings* settings ); + virtual ~MCNetworkDialog(); + +public slots: + + void accept() override; + void onSetNetworkEnabled(bool); + void onTestHostEntry( const QString& entry = "" ); + bool onLookupHost( const QHostInfo& hostInfo ); + +protected: + + Ui::MCNetworkDialog* _ui{}; + + QSettings* _settings = nullptr; + bool _useNetwork = false; + +}; + + +#endif // MCCNETWORKDIALOG_H diff --git a/libMiniCash/mcnetworkdialog.ui b/libMiniCash/mcnetworkdialog.ui new file mode 100644 index 0000000..bb2bdce --- /dev/null +++ b/libMiniCash/mcnetworkdialog.ui @@ -0,0 +1,261 @@ + + + MCNetworkDialog + + + + 0 + 0 + 592 + 405 + + + + Netzwerkeinstellungen + + + + + + + + 11 + 11 + 471 + 36 + + + + + 16 + true + + + + Netzwerkeinstellungen + + + Qt::AutoText + + + + + + 10 + 50 + 632 + 3 + + + + Qt::Horizontal + + + + + + 10 + 345 + 571 + 16 + + + + Qt::Horizontal + + + + + + 20 + 70 + 401 + 24 + + + + Daten nur auf USB-Stick speichern + + + + + + 20 + 100 + 411 + 24 + + + + Daten über Netzwerk senden + + + + + + 10 + 130 + 571 + 211 + + + + Setup + + + + + 30 + 102 + 141 + 20 + + + + Servername, Port: + + + + + + 180 + 100 + 113 + 26 + + + + + + + 300 + 100 + 16 + 18 + + + + + 12 + true + + + + : + + + + + + 310 + 100 + 81 + 26 + + + + + + + 10 + 150 + 521 + 24 + + + + Dieser PC ist die Abrechnungskasse ('Server') + + + + + + 10 + 70 + 221 + 24 + + + + diese Kasse ist Sender + + + + + + 30 + 32 + 141 + 20 + + + + Eigener Name: + + + + + false + + + + 180 + 30 + 113 + 26 + + + + + + + + + + 402 + 100 + 151 + 28 + + + + Verbindung Testen + + + + + + 402 + 69 + 151 + 25 + + + + + + + + + + + 130 + 365 + 449 + 29 + + + + + 9 + true + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + diff --git a/libMiniCash/mcnetworkwidget.cpp b/libMiniCash/mcnetworkwidget.cpp new file mode 100644 index 0000000..818df8b --- /dev/null +++ b/libMiniCash/mcnetworkwidget.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + + miniCash + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + +#include +#include + +#include + +MCNetworkWidget::MCNetworkWidget( QWidget* parent ) + : QLabel{ parent }, _ui{ new Ui::MCNetworkWidget} +{ + + _ui->setupUi( this ); + _ui->_labelState->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + /// wir haben vier mögliche Zustände + /// - das Netz wird gar nicht verwendet + /// - noch nicht verbunden + /// - Verbindungsfehler + /// - Wir haben die gewünschte Verbindung + + QIcon iconOff ( miniCash::icnUnConnected ); + QIcon iconOn ( miniCash::icnConnected ); + QIcon iconServer( miniCash::icnServer ); + + _networkStates[miniCash::Disabled] = MCNetworkState( miniCash::cstDisabled, QIcon( iconOff.pixmap( QSize(64,64), QIcon::Disabled, QIcon::On ) ) ); + _networkStates[miniCash::UnConnected] = MCNetworkState( miniCash::cstUnConnected, QIcon( iconOff.pixmap( QSize(64,64), QIcon::Disabled, QIcon::On ) ) ); + _networkStates[miniCash::Error] = MCNetworkState( miniCash::cstError, iconOff ); + _networkStates[miniCash::Connected] = MCNetworkState( miniCash::cstConnected, iconOn ); + _networkStates[miniCash::IsServer] = MCNetworkState( miniCash::cstIsServer, QIcon( iconServer.pixmap( QSize(64,64), QIcon::Disabled, QIcon::On ) ) ); + _networkStates[miniCash::ServerReady] = MCNetworkState( miniCash::cstServerReady, iconServer ); + + /// erstmal sind wir neutral + setConnectionState( miniCash::Disabled ); + + /// hack: Netzwerksachen sollen erst ausgeführt werden, + /// wenn das Mainwindow zu sehen ist + ///QTimer::singleShot( 500, this, &MCConnectMainWindow::onStartNetworking ); + + /// Button nach aussen weiterleiten + connect( _ui->_buttonState, &QPushButton::clicked, this, + [=]() + { + emit showNetworkDialog(); + } ); + +} + + + +MCNetworkWidget::~MCNetworkWidget() +{ + delete _ui; +} + + +miniCash::CState MCNetworkWidget::connectionState() +{ + return _senderState; +} + + +void MCNetworkWidget::setConnectionState( miniCash::CState state ) +{ + qDebug() << "SET STATE:" << state; + _senderState = state; + _ui->_labelState->setText( _networkStates[_senderState].label ); + _ui->_buttonState->setIcon( _networkStates[_senderState].icon ); +} + +/* + QPixmap pixmap = icon.pixmap(QSize(22, 22), + isEnabled() ? QIcon::Normal + : QIcon::Disabled, + isChecked() ? QIcon::On + : QIcon::Off); + + +myPushButton = new QPushButton(); +myMovie = new QMovie("someAnimation.gif"); + +connect(myMovie,SIGNAL(frameChanged(int)),this,SLOT(setButtonIcon(int))); + +// if movie doesn't loop forever, force it to. +if (myMovie->loopCount() != -1) + connect(myMovie,SIGNAL(finished()),myMovie,SLOT(start())); + +myMovie->start(); +*/ + + + + + + + + + diff --git a/libMiniCash/mcnetworkwidget.h b/libMiniCash/mcnetworkwidget.h new file mode 100644 index 0000000..2185e26 --- /dev/null +++ b/libMiniCash/mcnetworkwidget.h @@ -0,0 +1,74 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCNETWORKWIDGET_H +#define MCCNETWORKWIDGET_H + +#include +#include +#include +#include + +#include + +namespace Ui +{ + class MCNetworkWidget; +} + +class LIBMINICASH_EXPORT MCNetworkWidget : public QLabel +{ + Q_OBJECT + +public: + + explicit MCNetworkWidget( QWidget* parent = nullptr ); + virtual ~MCNetworkWidget(); + + miniCash::CState connectionState(); + void setConnectionState( miniCash::CState state ); + +signals: + + void showNetworkDialog(); + +protected: + + struct MCNetworkState + { + MCNetworkState() + { + } + + MCNetworkState( const QString alabel, QIcon aicon ) + : label{ alabel }, icon{ aicon } + { + } + + QString label; + QIcon icon; + + }; + + Ui::MCNetworkWidget* _ui{}; + + miniCash::CState _senderState = miniCash::Disabled; + MCNetworkState _networkStates[miniCash::CStateSize]; + +}; + +#endif /// MCCNETWORKWIDGET_H + + + diff --git a/libMiniCash/mcnetworkwidget.ui b/libMiniCash/mcnetworkwidget.ui new file mode 100644 index 0000000..49bb5d8 --- /dev/null +++ b/libMiniCash/mcnetworkwidget.ui @@ -0,0 +1,69 @@ + + + MCNetworkWidget + + + + 0 + 0 + 140 + 90 + + + + ConnectionState + + + background: groove gray; + + + + true + + + + 40 + 2 + 64 + 64 + + + + + + + + + + + 64 + 64 + + + + false + + + true + + + + + + 5 + 62 + 130 + 20 + + + + color:white; + + + + + + + + + diff --git a/libMiniCash/mcprinter.cpp b/libMiniCash/mcprinter.cpp new file mode 100644 index 0000000..6c109eb --- /dev/null +++ b/libMiniCash/mcprinter.cpp @@ -0,0 +1,28 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include + +/** + * @brief Erzeugt einen QPrinter mit den gewünschten Voreinstellungen. + */ + +MCPrinter::MCPrinter() +{ + // Seite einrichten + setPageOrientation( QPageLayout::Portrait ); + setPageSize( QPageSize( QPageSize::A4 ) ); + setFullPage( false ); + setPrintRange( QPrinter::AllPages ); +} diff --git a/libMiniCash/mcprinter.h b/libMiniCash/mcprinter.h new file mode 100644 index 0000000..12a9521 --- /dev/null +++ b/libMiniCash/mcprinter.h @@ -0,0 +1,37 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCPRINTER_H +#define MCPRINTER_H + +#include + +#include + + +/** + * @brief Convenience-Klasse um einen vorkonfigurierten + * Printer zu erzeugen. + */ + +class LIBMINICASH_EXPORT MCPrinter : public QPrinter +{ + +public: + + MCPrinter(); + +}; + +#endif // MCPRINTER_H diff --git a/libMiniCash/mcreceiver.cpp b/libMiniCash/mcreceiver.cpp new file mode 100644 index 0000000..55bc6a8 --- /dev/null +++ b/libMiniCash/mcreceiver.cpp @@ -0,0 +1,173 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/** + * @brief Destructor, alles schließen + */ + +MCReceiver::~MCReceiver() +{ + onDiscardConnection(); + deleteLater(); +} + + +/** + * @brief Empfangsbereit machen: hier passiert weiter nichts, + * erst wir nur der parameter 'port' neu gesetzt, die + * entsprechende Aktion wird über ein SIGNAL getriggert. + */ + +void MCReceiver::setupConnection( int port ) +{ + qDebug() << "MCReceiver::setupConnection: " << port; + _port = port; +} + + +/** + * @brief Slot, + */ + +void MCReceiver::onCreateConnection() +{ + if( isListening() ) + onDiscardConnection(); + + //qDebug( "MCReceiver::onCreateConnection() 1: listen...." ); + + if( listen( QHostAddress::Any, _port ) ) + { + //qDebug( "MCReceiver::onCreateConnection() 2: Server is listening..."); + connect( this, &QTcpServer::newConnection, this, &MCReceiver::onNewConnection ); + //qDebug( "MCReceiver::onCreateConnection() 3: Server is listening..."); + + emit connectionChanged( miniCash::IsServer ); + + return; + } + + emit connectionChanged( miniCash::Error ); + + //QMessageBox::critical(this,"QTCPServer",QString("Unable to start the server: %1.").arg(errorString())); + //exit(EXIT_FAILURE); + +} + + +void MCReceiver::onDiscardConnection() +{ + + //qDebug( "MCReceiver::onDiscardConnection()"); + + foreach( QTcpSocket* socket, _connections ) + { + socket->close(); + socket->deleteLater(); + } + close(); + + emit connectionChanged( miniCash::UnConnected ); + +} + + + +/** + * @brief Nimmt neue Connections an und schreibt sie + * in die Connectionliste. + */ + +void MCReceiver::onNewConnection() +{ + + while( hasPendingConnections() ) + appendToSocketList( nextPendingConnection() ); + + emit connectionChanged( miniCash::ServerReady ); +} + + +void MCReceiver::appendToSocketList( QTcpSocket* socket ) +{ + _connections.insert(socket); + connect( socket, &QTcpSocket::readyRead, this, &MCReceiver::onReadReady ); + connect( socket, &QTcpSocket::disconnected, this, &MCReceiver::onSocketDisconnected ); + + //qDebug() << QString("INFO :: Client with sockd:%1 has just entered the room").arg(socket->socketDescriptor() ); + +} + + +void MCReceiver::onReadReady() +{ + + QTcpSocket* socket = reinterpret_cast( sender() ); + QByteArray buffer; + + QDataStream socketStream( socket ); + socketStream.setVersion( QDataStream::Qt_5_15 ); + + socketStream.startTransaction(); + socketStream >> buffer; + + if( !socketStream.commitTransaction() ) + return; + /* + { + QString message = QString("%1 :: Waiting for more data to come..").arg(socket->socketDescriptor()); + emit newData(message); + return; + } + */ + + // warum?? + //QString message = QString::fromStdString( buffer.toStdString() ); + + emit newTransaction( QString( buffer ) ); + +} + + + +void MCReceiver::onSocketDisconnected() +{ + QTcpSocket* socket = reinterpret_cast(sender()); + + QSet::iterator it = _connections.find(socket); + if (it != _connections.end()) + { + //displayMessage( QString("INFO :: A client has just left the room").arg(socket->socketDescriptor()) ); + _connections.remove( *it ); + } + + socket->deleteLater(); +} + + + + diff --git a/libMiniCash/mcreceiver.h b/libMiniCash/mcreceiver.h new file mode 100644 index 0000000..52a101e --- /dev/null +++ b/libMiniCash/mcreceiver.h @@ -0,0 +1,66 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCRECEIVER_H +#define MCRECEIVER_H + +#include +#include + +#include + + +/** + * @brief Ein angespasster QTcpServer + */ + +class LIBMINICASH_EXPORT MCReceiver : public QTcpServer +{ + + Q_OBJECT + +public: + + explicit MCReceiver() = default; + virtual ~MCReceiver(); + + void setupConnection( int port ); + +public slots: + + void onCreateConnection(); + void onDiscardConnection(); + +signals: + + void connectionChanged( miniCash::CState newState ); + void newTransaction( QString data ); + +protected slots: + + void onNewConnection(); + void onReadReady(); + void onSocketDisconnected(); + +protected: + + void appendToSocketList(QTcpSocket* socket); + + int _port = -1; + QSet _connections; + +}; + + +#endif // MCRECEIVER_H diff --git a/libMiniCash/mcsalesitem.h b/libMiniCash/mcsalesitem.h new file mode 100644 index 0000000..44cf1c6 --- /dev/null +++ b/libMiniCash/mcsalesitem.h @@ -0,0 +1,67 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCSALESITEM_H +#define MCSALESITEM_H + + +#include + +#include + + +//class MCSalesModel; + + +/** + * @brief Ein verkaufter Artikel + * + * Ein verkaufter Artikel : Verkäufenummrer, Listennummer und Preis + */ + + +struct LIBMINICASH_EXPORT MCSalesItem +{ + + QString trSellerID; + QString trItemNo; + double trPrice; + + MCSalesItem() + { + + } + + MCSalesItem( const QString& id, const QString& no, double price ) + : trSellerID( id ) , trItemNo( no ), trPrice( price ) + { + + } + + QString toString() const + { + QString result( "id: %1 itemno: %2 price: %3" ); + result = result.arg( trSellerID, trItemNo ).arg( trPrice ); + return result; + } + + bool operator==(const MCSalesItem& other) const + { + return (trSellerID == other.trSellerID && trItemNo == other.trItemNo && trPrice == other.trPrice); + } + +}; + + +#endif // MCSALESITEM_H diff --git a/libMiniCash/mcsalesitemmap.cpp b/libMiniCash/mcsalesitemmap.cpp new file mode 100644 index 0000000..f15f182 --- /dev/null +++ b/libMiniCash/mcsalesitemmap.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + +#include +#include +#include + + +/** + * @brief speichert verkaufte Artikel. + * + * Speichert verkaufte Artikel pro Kunde nach der laufenden Nummer des Artikels + */ + +MCSalesItemMap::MCSalesItemMap() +: QMap() + +{ + +} + + +/** + * @brief einen neuen Eintrag erzeugen + * + * @param id Die Kunden- bzw. Verkäufernummer + * @param num Die laufende Nummer des verkauften Artikels + * @param strprice der Preis des Artikels + */ + +void MCSalesItemMap::appendItem( const QString& id, const QString& num, const QString& strprice ) +{ + + // doppelt vergebene laufende nummern werden + // gekennzeichnet: '025' -> '#025' + QString key = num; + if( contains( num ) ) + { + key = '#' + num; + } + + // Wir wollen beim Dateiformat kompatibel bleiben: + // 0003 1211 012 2,00 02-13-2013 10:39:55 + // also: float mit komma, ohne Euro-Zeichen + + insert( key, MCSalesItem( id, key, MCSalesModel::toDoubleLocale( strprice ) ) ); + +} + + +/** + * @brief Dump nach cout zu debugging-zwecken + */ + +void MCSalesItemMap::dump() const +{ + MCSalesItemMap::const_iterator pos = begin(); + for( ; pos != end(); ++pos ) + { + qDebug() << "key:" << pos.key() << " value: " << pos.value().toString(); + } + qDebug() << Qt::endl; +} + + + + diff --git a/libMiniCash/mcsalesitemmap.h b/libMiniCash/mcsalesitemmap.h new file mode 100644 index 0000000..a450d94 --- /dev/null +++ b/libMiniCash/mcsalesitemmap.h @@ -0,0 +1,55 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCSALESITEMMAP_H +#define MCSALESITEMMAP_H + +#include +#include + +#include +#include + + + +/** + * @brief Speichert verkaufte Artikel. + * + * Speichert verkaufte Artikel pro Kunde nach der laufenden Nummer des Artikels. + */ + +class MCSalesItemMap : public QMap +{ + +public: + + enum Index + { + Count = 0, + SellerID, + ItemNo, + Price, + MaxSize + }; + + MCSalesItemMap(); + + void appendItem( const QString& id, const QString& no, const QString& price ); + + void dump() const; + + +}; + +#endif // MCSALESITEMMAP_H diff --git a/libMiniCash/mcsalesmodel.cpp b/libMiniCash/mcsalesmodel.cpp new file mode 100644 index 0000000..8908964 --- /dev/null +++ b/libMiniCash/mcsalesmodel.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + +#include +#include + +using namespace std; + + +/** + * @brief Macht aus int x den String 000x zum schönaussehen. + * @param count der Wert + * @param len die voranzustellenden Nullen + * + * Macht aus int x den String 000x zum schönaussehen. + * + */ + +QString MCSalesModel::formatInt(int count, int len ) +{ + QString result( "%0" ); + result = result.arg( count, len, 10, QChar( '0' ) ); + return result; +} + + +/** + * @brief Formatiert einen double als String im Währungsformat: 2.3 -> 2,30 € + * + * Formatiert einen double als String im Währungsformat: 2.3 -> 2,30 € + * + */ + +QString MCSalesModel::toCurrency( double amount ) +{ + QLocale loc; + return loc.toCurrencyString( amount ); +} + + +/** + * @brief Konvertiert einen String-Zahlenwert in + * deutscher Schreibweise zum double. + * + * Macht aus einem Zahlen-String in deutscher Schreibweise: + * 1,50 (statt 1.5) einen double. + * + */ + +double MCSalesModel::toDoubleLocale( QString amount ) +{ + QLocale converter( QLocale::German ); + bool ok; + return converter.toDouble( amount, &ok ) ; +} + + +/** + * @brief Konvertiert einen Währungs-String zurück ins Gleitkommaformat. + * @param Eingabewert als String + * @return 0.0 im Fehlerfall, sonst: Der Zahlenwert des String + * + * Das €-Zeichen wird abgeschitten: "23,20 €" wird zu 23.2 + * + */ + +double MCSalesModel::fromCurrency( QString amount ) +{ + + if( amount.isEmpty() || amount.isNull() ) + return 0.0; + + QString raw = amount.split( ' ' ).at(0); + return toDoubleLocale( raw ); +} + + +/** + * @brief Defaultkonstruktor. + */ + +MCSalesModel::MCSalesModel( QObject *parent ) : + QStandardItemModel( parent ) +{ + + QStringList header; + header << "Kunde" << "Verkäufernummer" << "lfd. Nummer" << "Verkaufspreis"; + setHorizontalHeaderLabels( header ); + +} + + +/** + * @brief Speichert einen Verkaufseintrag. + * + * @param trCount laufende Transaktionsnummer + * @param trSellerID die Kundennummer + * @param trItemNo die Artikelnummer + * @param trPrice der Preis + * + */ + +void MCSalesModel::appendEntry( const QString& trCount, const QString& trSellerID, const QString& trItemNo, const QString& trPrice ) +{ + + QStandardItem* item1 = new QStandardItem( trCount ); + QStandardItem* item2 = new QStandardItem( trSellerID ); + // wir formatieren gleich auf 3 Stellen: 12 -> 012 + QStandardItem* item3 = new QStandardItem( formatInt( trItemNo.toInt(), 3 ) ); + // wild: price ist ein string mit komma: "2,6" + QStandardItem* item4 = new QStandardItem( toCurrency( toDoubleLocale( trPrice ) ) ); + //QStandardItem* item4 = new QStandardItem( "77,77 €" ); + item1->setTextAlignment ( Qt::AlignCenter ); + item2->setTextAlignment ( Qt::AlignCenter ); + item3->setTextAlignment ( Qt::AlignCenter ); + item4->setTextAlignment ( Qt::AlignRight ); + + QList items; + items.append( item1 ); + items.append( item2 ); + items.append( item3 ); + items.append( item4 ); + + appendRow( items ); + +} + + +/** + * @brief Transaktionen aus einem TextStream einlesen + * @param input TextStream zeigt auf eine Datei mit Transaktionen (==Verkäufen) + */ + +void MCSalesModel::appendTransactions( QTextStream& input ) +{ + + + while( !input.atEnd() ) + { + + QString line = input.readLine(); + QStringList entries = line.simplified().split( QRegularExpression("\\s+") ); + + if( entries.size() < MCSalesItemMap::MaxSize ) + continue; + + const QString& tcount = entries[ MCSalesItemMap::Count ]; + const QString& sellerID = entries[ MCSalesItemMap::SellerID ]; + const QString& itemNo = entries[ MCSalesItemMap::ItemNo ]; + const QString& price = entries[ MCSalesItemMap::Price ]; + + /// die Transaktionsnummer entspricht der Anzahl der Kunden + /// und auch anzeigen + appendEntry + ( + tcount, + sellerID, + itemNo, + price + ); + + + } /// while + + +} + diff --git a/libMiniCash/mcsalesmodel.h b/libMiniCash/mcsalesmodel.h new file mode 100644 index 0000000..1bb6423 --- /dev/null +++ b/libMiniCash/mcsalesmodel.h @@ -0,0 +1,55 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCSALESMODEL_H +#define MCSALESMODEL_H + +#include +#include + +#include + + +/** + * @brief Das Itemmodel zur Anzeige der verkauften Artikel + * + * @see QStandardItemModel + * @see QTreeView + * + * MCSalesModel ist ein QStandardItemModel zur Anzeige der verkauften Artikel an einer Kasse. + * Mit @see appendEntry wurde eine neue Methode hinzugefügt: Hier werden die Werte der + * Eingabefelder formatiert und per ("flacher") TreeView angezeigt. + * + */ + +class LIBMINICASH_EXPORT MCSalesModel : public QStandardItemModel +{ + Q_OBJECT + +public: + + static QString formatInt( int count, int len=4 ); /// Macht aus int x den String 000x zum schönaussehen. + static QString toCurrency( double amount ); /// Formatiert einen double als String im Währungsformat: 2.3 -> 2,30 EUR + static double toDoubleLocale( QString amount ); /// Macht aus einem Zahlen-String in deutscher Schreibweise: 1,50 (statt 1.5) einen double. + static double fromCurrency( QString amount ); /// Versucht, das EUR-Zeichen abzusäbeln: "23,20 EUR" wird zu 23.2 + + explicit MCSalesModel( QObject* parent = nullptr ); + + void appendEntry( const QString& trCount, const QString &trSellerID, const QString &trItemNo, const QString &trPrice ); + void appendTransactions( QTextStream& input ); + +}; + + +#endif // MCSALESMODEL_H diff --git a/libMiniCash/mcsalessummary.cpp b/libMiniCash/mcsalessummary.cpp new file mode 100644 index 0000000..6bcf246 --- /dev/null +++ b/libMiniCash/mcsalessummary.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include + +#include +#include +#include + +/** + * @brief MCSalesSummary::MCSalesSummary: speichert die Verkaufsliste einzelner Kunden nach Kundennummer. + */ + +MCSalesSummary::MCSalesSummary() +: QMap() +{ + +} + + +/** + * @brief Liest jeweils eine Transaktionsdatei ein. + * + * @param filename der Dateiname + * @param salescount die Gesamtanzahl der Verkäufe, wird hier hochgezählt + * @param model das Datenmodel + * @return die Anzahl der Verkäufe in dieser Datei + */ + +int MCSalesSummary::appendFromFile( const QString& filename, int& customercount, MCSalesModel& model ) +{ + QFile file( filename ); + if ( !file.open(QIODevice::ReadOnly | QIODevice::Text ) ) + return -1; // throw... + + int salescount = 0; + + QSet customerSet; + QTextStream input(&file); + while( !input.atEnd() ) + { + + QString line = input.readLine(); + QStringList entries = line.simplified().split( QRegularExpression("\\s+") ); + + if( entries.size() < MCSalesItemMap::MaxSize ) + continue; + + const QString& tcount = entries[ MCSalesItemMap::Count ]; + const QString& sellerID = entries[ MCSalesItemMap::SellerID ]; + const QString& itemNo = entries[ MCSalesItemMap::ItemNo ]; + const QString& price = entries[ MCSalesItemMap::Price ]; + + /// Transaktionen des Kunden holen, eventuell erzeugen + MCSalesItemMap& result = operator[]( sellerID ); + customerSet.insert( tcount ); + + /// speichern ... + result.appendItem + ( + sellerID, + itemNo, + price + ); + + /// die Transaktionsnummer entspricht der Anzahl der Kunden + /// und auch anzeigen + model.appendEntry + ( + tcount, + sellerID, + itemNo, + price + ); + + salescount++; + + } + customercount = customerSet.count(); + return salescount; + +} + + +/** + * @brief Dump nach cout zu debugging-zwecken + */ + +void MCSalesSummary::dump() +{ + // for( const QString& key : *this->keys() ) haut so nicht hin, lernen + foreach (const QString &str, keys()) + { + qDebug() << str << ':' << ": "; + value( str ).dump(); + } + +} + + + + + diff --git a/libMiniCash/mcsalessummary.h b/libMiniCash/mcsalessummary.h new file mode 100644 index 0000000..1e5aa4a --- /dev/null +++ b/libMiniCash/mcsalessummary.h @@ -0,0 +1,54 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + +#ifndef MCSALESSUMMARY_H +#define MCSALESSUMMARY_H + +#include +#include + +#include +#include + +class MCSalesModel; + +/** + * @brief Speichert die Verkaufsliste einzelner Kunden nach Kundennummer. + * + * Verwaltet _alle_ Verkaufstransaktionen, wird benötigt für die Endabrechnung. + * Die einzelen Verkäufe an der Kasse werden von @see MCSalesItemMap abgedeckt. + * + * Die einzelen Kassendateien werden nacheinander eingelesen und dann für die + * Endabrechnung ausgewertet. Für jede Kundennummer wird eine Map mit verkauften Artikeln + * angelegt, der Schlüssel ist die laufende Nummer des Artikels, die Verwendung einer Map + * sichert die automatische Sortierung der Einträge. Die Artikelmaps landen wiederum in der + * "Hauptmap", mit der CustomerId als Schlüssel. Ergebnis ist eine sortierte Struktur mit allen + * Kunden und den jeweils verkauften Artikeln. QMultiMap taugt hierfür leider nicht, + * es wird also eine "Map of Maps" implementiert. + * + */ + +class LIBMINICASH_EXPORT MCSalesSummary : public QMap +{ + +public: + + explicit MCSalesSummary(); + + int appendFromFile( const QString& filename, int& customercount, MCSalesModel& model ); + + void dump(); + +}; + +#endif // MCSALESSUMMARY_H diff --git a/libMiniCash/mcsender.cpp b/libMiniCash/mcsender.cpp new file mode 100644 index 0000000..3b49c1f --- /dev/null +++ b/libMiniCash/mcsender.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +/** + * @brief MCSender::MCSender + */ + +MCSender::MCSender() +{ + +} + + +/** + * @brief MCSender::~MCSender + */ + +MCSender::~MCSender() +{ + if( isOpen() ) + close(); +} + + +void MCSender::setupConnection( const QString& host, int port ) +{ + //qDebug() << "\n\nMCSender::setupConnection(): " << host << " : " << port; + _port = port; + _host = host; +} + + +/** + * @brief MCSender::initConnection + * @param parent + * @param host + * @param port + * @return + */ + +void MCSender::onCreateConnection() +{ + if( isOpen() ) + onDiscardConnection(); + + //qDebug() << "MCSender::onCreateConnection()"; + + connectToHost( _host, _port, QIODevice::WriteOnly ); + if( waitForConnected( miniCash::senderTimeout ) ) + { + emit connectionChanged( miniCash::Connected ); + return; // allet jut + } + + emit errorOccurred( error() ); + +} + + +/** + * @brief MCSender::onDiscardConnection + */ + +void MCSender::onDiscardConnection() +{ + // qDebug() << "MCSender::onDiscardConnection()"; + flush(); + if( isOpen() ) + close(); + + emit connectionChanged( miniCash::UnConnected ); + +} + + +/** + * @brief MCSender::writeTransaction + * @param transaction + */ + +void MCSender::onSendTransaction( const QString& transaction ) +{ + + if( !isOpen() ) + { + emit connectionChanged( miniCash::UnConnected ); + //qDebug( "---QTCPClient: Not connected"); + return; + } + + QDataStream socketStream( this ); + socketStream.setVersion(QDataStream::Qt_5_15); + QByteArray byteArray = transaction.toUtf8(); + + socketStream << byteArray; + +} + + + diff --git a/libMiniCash/mcsender.h b/libMiniCash/mcsender.h new file mode 100644 index 0000000..bd02495 --- /dev/null +++ b/libMiniCash/mcsender.h @@ -0,0 +1,58 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCSENDER_H +#define MCSENDER_H + +#include +#include + +#include + + + +/** + * @brief Ein angepasstes QTcpSocket zur Datenübertragung + */ + +class LIBMINICASH_EXPORT MCSender : public QTcpSocket +{ + Q_OBJECT + +public: + + MCSender(); + virtual ~MCSender(); + + void setupConnection( const QString& host, int port ); + +signals: + + void connectionChanged( miniCash::CState newState ); + +public slots: + + void onCreateConnection(); + void onDiscardConnection(); + + void onSendTransaction( const QString& transaction ); + +protected: + + int _port = -1; + QString _host; + +}; + +#endif // MCSENDER_H diff --git a/libMiniCash/mcsetupdialog.cpp b/libMiniCash/mcsetupdialog.cpp new file mode 100644 index 0000000..f24153b --- /dev/null +++ b/libMiniCash/mcsetupdialog.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/** + * @brief Der Setup-Dialog: Hier werden die Vorgabewerte gesetzt. + */ + +MCSetupDialog::MCSetupDialog( QWidget* parent, QSettings* settings ) + : QDialog{ parent }, _ui{new Ui::MCSetupDialog}, _settings{ settings } + +{ + + _ui->setupUi( this ); + setupDefaults(); + + // Murx, FIX! das sollte über den Translator gehen + _ui->_buttonBox->button( QDialogButtonBox::Ok )->setText( "Speichern" ); + _ui->_buttonBox->button( QDialogButtonBox::Cancel )->setText( "Abbrechen" ); + + connect( _ui->_buttonReset, SIGNAL( clicked() ), this, SLOT( onReset() ) ); + connect( _ui->_buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); + connect( _ui->_buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); + connect( _ui->_buttonFile, SIGNAL( clicked() ), this, SLOT( onChooseVendorsFile() ) ); + connect( _ui->_buttonViewFile, SIGNAL( clicked() ), this, SLOT( onViewVendorsFile() ) ); + + _ui->_tabWidget->setCurrentIndex( 0 ); + +} + + +/** + * @brief Destruktor. + */ + +MCSetupDialog::~MCSetupDialog() +{ + delete _ui; +} + + +/** + * @brief Vorgabewerte ins Form laden + */ + +void MCSetupDialog::setupDefaults() +{ + // Vorgabewerte setzen + QString driveLetter = _settings->value( miniCash::keyMobileDrive, miniCash::mobileDrive ).toString(); + _ui->_driveMobile->addItem( driveLetter ); + _ui->_driveMobile->setCurrentText( driveLetter ); + _ui->_trProfit->setValue( _settings->value( miniCash::keyProfit, miniCash::profit ).toInt() ); + _ui->_selfID->setValue( _settings->value( miniCash::keySelfID, miniCash::selfID ).toInt() ); + _ui->_trFooterText->setText( _settings->value( miniCash::keyFooterText ).toString() ); + + _ui->_buttonViewFile->setEnabled( false ); + QString filePath = _settings->value( miniCash::keyAddressFile ).toString(); + if( !filePath.isEmpty() ) + { + QFileInfo addressFile( filePath ); + if( addressFile.exists() ) + { + _ui->_addressFile->setText( addressFile.fileName() ); + _ui->_buttonViewFile->setEnabled( true ); + } + } + + +} + + +/** + * @brief Setzt alle voreinstellungen zurück auf den jeweiligen Default-Wert. + */ + +void MCSetupDialog::onReset() +{ + int ret = QMessageBox::warning(this, "miniCash Setup", + tr("Sollen die Voreinstellugen\n" + "neu geladen werden?"), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Cancel); + + if( ret == QMessageBox::Cancel ) + return; + + _settings->clear(); + setupDefaults(); + + /// neu: wir setzen hier auch schon die network-defaults, weil der dialog + /// jetzt auch von minicash.connect verwendet wird. + + _settings->setValue( miniCash::keyIsTcpSender, miniCash::isTcpSender ); + _settings->setValue( miniCash::keyReceiverHost, "" ); + _settings->setValue( miniCash::keyReceiverPort, miniCash::receiverPort ); + _settings->setValue( miniCash::keyIsTcpReceiver, miniCash::isTcpReceiver ); + _settings->setValue( miniCash::keyAddressFile, "" ); + /// gefährlich + _settings->setValue( miniCash::keyTransCount, "1" ); + +} + + +void MCSetupDialog::onChooseVendorsFile() +{ + + _ui->_buttonViewFile->setEnabled( false ); + QString docDir = QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation ); + QString filePath = QFileDialog::getOpenFileName( this, tr("Adressdatei"), docDir, tr("CSV Datei (*.csv *.txt)") ); + + if( !filePath.isEmpty() ) + { + _ui->_buttonViewFile->setEnabled( true ); + QFileInfo addressFile( filePath ); + _settings->setValue( miniCash::keyAddressFile, addressFile.absoluteFilePath() ); + _ui->_addressFile->setText( addressFile.fileName() ); + } +} + + +void MCSetupDialog::onViewVendorsFile() +{ + QString filePath = _settings->value( miniCash::keyAddressFile ).toString(); + if( filePath.isEmpty() || !QFileInfo::exists( filePath ) ) + return; + + MCVendorsDialog( this, filePath ).exec(); + +} + + +/** + * @brief ok gedrückt: geänderte Daten übernehmen + */ + +void MCSetupDialog::accept() +{ + + const QString& mDrive = _ui->_driveMobile->currentText(); + const QString& profit = _ui->_trProfit->cleanText(); + const QString& prefix = _ui->_selfID->cleanText(); + + // Murx, FIX! das sollte über den Translator gehen + if( profit.isEmpty() || prefix.isEmpty() ) + { + QMessageBox::warning + ( + this, + "Eingabefehler", + "Die Felder\n - lokales Laufwerk', 'KassenNr.'\n " + "sowie 'Anteil Kindergarten' müssen belegt sein." + ); + return; + } + + _settings->setValue( miniCash::keyMobileDrive, mDrive ); + _settings->setValue( miniCash::keyProfit, profit ); + _settings->setValue( miniCash::keySelfID, prefix ); + _settings->setValue( miniCash::keyFooterText, _ui->_trFooterText->document()->toPlainText() ); + + return QDialog::accept(); + +} diff --git a/libMiniCash/mcsetupdialog.h b/libMiniCash/mcsetupdialog.h new file mode 100644 index 0000000..bf31b51 --- /dev/null +++ b/libMiniCash/mcsetupdialog.h @@ -0,0 +1,69 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCSETUPDIALOG_H +#define MCSETUPDIALOG_H + +#include +#include + +#include + +namespace Ui +{ + class MCSetupDialog; +} + +/** + * @brief Der Setup-Dialog: Hier werden die Grundeinstellungen vorgenommen. + * + * Im Setup-Dialog werden folgende Grundeinstellungen vorgenommen: + * für den Kassenmodus: + * - die Kassennummer + * - das lokale Datenlaufwerk, Vorgabe: E:\ + * - das "Transport"-Laufwerk, auf das die Kassendaten zur Abrechnung kopiert werden + * für den Abrechnungsmodus: + * - Das Laufwerk, vom dem die zusammengeführten Kassendaten geladen werden, Vorgabe: E:\ + * - Der Gewinnanteil des Kindergartens in Prozent, Vorgabe: 15% + * - Ein optionaler Fußzeilentext, wird mit auf die Abrechnungen gedruckt. + */ + +class LIBMINICASH_EXPORT MCSetupDialog : public QDialog +{ + Q_OBJECT + +public: + + explicit MCSetupDialog( QWidget* parent, QSettings* settings ); + virtual ~MCSetupDialog(); + + void accept(); + void setupDefaults(); + +public slots: + + void onReset(); + void onChooseVendorsFile(); + void onViewVendorsFile(); + +protected: + + Ui::MCSetupDialog* _ui{}; + + QSettings* _settings = nullptr; + +}; + + +#endif // MCSETUPDIALOG_H diff --git a/libMiniCash/mcsetupdialog.ui b/libMiniCash/mcsetupdialog.ui new file mode 100644 index 0000000..bb849e7 --- /dev/null +++ b/libMiniCash/mcsetupdialog.ui @@ -0,0 +1,364 @@ + + + MCSetupDialog + + + + 0 + 0 + 650 + 400 + + + + miniCash Setup + + + + + + + 9 + true + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + + + + + 16 + true + + + + Einstellungen + + + Qt::AutoText + + + + + + + Qt::Horizontal + + + + + + + + 9 + true + + + + 0 + + + + diese Kasse + + + + + 340 + 20 + 51 + 24 + + + + + + + 11 + 21 + 77 + 18 + + + + + 9 + true + + + + KassenNr. + + + + + + 340 + 60 + 51 + 24 + + + + + 0 + 0 + + + + + + + 10 + 60 + 321 + 18 + + + + + 9 + true + + + + Laufwerk zum Datentransport (z.B. 'F:\') + + + + + + 340 + 145 + 93 + 29 + + + + Reset + + + + + + 10 + 150 + 321 + 18 + + + + + 9 + true + + + + Alle Programm-Einstellungen zurücksetzen + + + + + + 10 + 105 + 321 + 18 + + + + + 9 + true + + + + Adressdatei im CSV-Format (optional) + + + + + + 372 + 100 + 141 + 29 + + + + + + + 340 + 100 + 29 + 29 + + + + + + + + :/images/open.png:/images/open.png + + + + + + 520 + 100 + 81 + 29 + + + + Anzeigen + + + + + + Abrechnung + + + + + 10 + 90 + 601 + 151 + + + + + 9 + true + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:700; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:400;"><br /></p></body></html> + + + + + + 10 + 70 + 182 + 18 + + + + + 9 + true + + + + Fußzeilentext (optional) + + + Qt::AutoText + + + + + + 210 + 21 + 46 + 24 + + + + + 0 + 0 + + + + + + + 12 + 21 + 186 + 18 + + + + + 9 + true + + + + Anteil Kindergarten in % + + + + + + + + + + SWDriveSelector + QComboBox +
swdriveselector.h
+
+
+ + + + + + _buttonBox + accepted() + MCSetupDialog + accept() + + + 257 + 451 + + + 295 + 241 + + + + + _buttonBox + rejected() + MCSetupDialog + reject() + + + 257 + 451 + + + 295 + 241 + + + + +
diff --git a/libMiniCash/mctransactionview.cpp b/libMiniCash/mctransactionview.cpp new file mode 100644 index 0000000..5068381 --- /dev/null +++ b/libMiniCash/mctransactionview.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + + miniCash + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + + +MCTransactionView::MCTransactionView( QWidget* parent ) + : QFrame( parent ), _ui{new Ui::MCTransactionView} +{ + _ui->setupUi( this ); +} + +MCTransactionView::~MCTransactionView() +{ + +} + +void MCTransactionView::onTransactionReceived( const QString& transaction ) +{ + _ui->_textView->appendPlainText( transaction ); +} diff --git a/libMiniCash/mctransactionview.h b/libMiniCash/mctransactionview.h new file mode 100644 index 0000000..1a9dacf --- /dev/null +++ b/libMiniCash/mctransactionview.h @@ -0,0 +1,46 @@ +/*************************************************************************** + + miniCash + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCTRANSACTIONVIEW_H +#define MCCTRANSACTIONVIEW_H + +#include + +#include + +namespace Ui +{ + class MCTransactionView; +} + +class LIBMINICASH_EXPORT MCTransactionView : public QFrame +{ + Q_OBJECT + +public: + + explicit MCTransactionView( QWidget* parent = nullptr ); + virtual ~MCTransactionView(); + +public slots: + + void onTransactionReceived( const QString& transaction ); + +protected: + + Ui::MCTransactionView* _ui{}; + +}; + +#endif // MCCTRANSACTIONVIEW_H diff --git a/libMiniCash/mctransactionview.ui b/libMiniCash/mctransactionview.ui new file mode 100644 index 0000000..f649286 --- /dev/null +++ b/libMiniCash/mctransactionview.ui @@ -0,0 +1,46 @@ + + + MCTransactionView + + + + 0 + 0 + 793 + 624 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Roboto Mono + 9 + + + + true + + + + + + + + diff --git a/libMiniCash/mctreeview.cpp b/libMiniCash/mctreeview.cpp new file mode 100644 index 0000000..abfd9c4 --- /dev/null +++ b/libMiniCash/mctreeview.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + + +/** + * @brief Konstruktor, setzt die Default-Styles. + * @param parent + */ + +MCTreeView::MCTreeView( QWidget* parent ) + : QTreeView( parent ) +{ + header()->setDefaultAlignment ( Qt::AlignHCenter ); + header()->setMinimumSectionSize( 150 ); + header()->setDefaultSectionSize( 185 ); + setStyleSheet("QHeaderView::section { background-color:#eeeeee }"); +} + + +MCTreeView::~MCTreeView() +{ + +} diff --git a/libMiniCash/mctreeview.h b/libMiniCash/mctreeview.h new file mode 100644 index 0000000..ff2294c --- /dev/null +++ b/libMiniCash/mctreeview.h @@ -0,0 +1,45 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCTREEVIEW_H +#define MCTREEVIEW_H + +#include +#include +#include + +#include + + +/** + * @brief The MCTreeView class: Eine angepasste QTreeView + * + * Convenience-Klasse: Konfiguriert dei QTreeView als Listenansicht + * mit verschiebbaren Header-Spalten + */ + +class LIBMINICASH_EXPORT MCTreeView : public QTreeView +{ + + Q_OBJECT + +public: + + MCTreeView( QWidget* parent = nullptr ); + virtual ~MCTreeView(); + +}; + + +#endif // MCTREEVIEW_H diff --git a/libMiniCash/mcvendorsdialog.cpp b/libMiniCash/mcvendorsdialog.cpp new file mode 100644 index 0000000..9c66cfe --- /dev/null +++ b/libMiniCash/mcvendorsdialog.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + +#include +#include + +MCVendorsDialog::MCVendorsDialog( QWidget* parent, const QString& filePath ) + : QDialog( parent ), _ui{new Ui::MCVendorsDialog} + +{ + _ui->setupUi( this ); + loadVendorsFile( filePath ); + + connect( _ui->_buttonOk, &QPushButton::clicked, this, + [=] + { + accept(); + } ); +} + + +MCVendorsDialog::~MCVendorsDialog() +{ + delete _ui; +} + + +void MCVendorsDialog::loadVendorsFile( const QString& filePath ) +{ + + QFile file( filePath ); + + if( !file.open(QFile::ReadOnly | QFile::Text) ) + return; + + /// Create a data model for the mapping table from a CSV file + int cols[]{ 0, 3, 4, 5 }; + _csvModel.setColumnCount( 4 ); + _csvModel.setHorizontalHeaderLabels( QStringList( {"Nummer", "Name", "Anschrift", "Telephon"} ) ); + _ui->_vendorsView->setModel( &_csvModel ); + _ui->_vendorsView->setStyleSheet("QHeaderView::section { background-color:#eeeeee }"); + _ui->_vendorsView->setCornerButtonEnabled( false ); + // Open the file from the resources. Instead of the file + // Need to specify the path to your desired file + + // Create a thread to retrieve data from a file + QTextStream in( &file ); + in.readLine(); + //Reads the data up to the end of file + while( !in.atEnd() ) + { + QStringList entries = in.readLine().split( "\t" ); + // Adding to the model in line with the elements + QList standardItemsList; + + for( int idx : cols ) + { + if( entries.size() > idx ) + standardItemsList.append( new QStandardItem( entries[idx] ) ); + } + + _csvModel.insertRow( _csvModel.rowCount(), standardItemsList ); + } + + file.close(); + +} diff --git a/libMiniCash/mcvendorsdialog.h b/libMiniCash/mcvendorsdialog.h new file mode 100644 index 0000000..c1b0755 --- /dev/null +++ b/libMiniCash/mcvendorsdialog.h @@ -0,0 +1,47 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCVENDORSDIALOG_H +#define MCVENDORSDIALOG_H + +#include +#include + +#include +#include + +namespace Ui +{ + class MCVendorsDialog; +} + +class LIBMINICASH_EXPORT MCVendorsDialog : public QDialog +{ + + Q_OBJECT + +public: + + explicit MCVendorsDialog( QWidget* parent, const QString& filePath ); + virtual ~MCVendorsDialog(); + +protected: + + void loadVendorsFile( const QString& filePath ); + + Ui::MCVendorsDialog* _ui{}; + QStandardItemModel _csvModel; +}; + +#endif // MCVENDORSDIALOG_H diff --git a/libMiniCash/mcvendorsdialog.ui b/libMiniCash/mcvendorsdialog.ui new file mode 100644 index 0000000..da20efb --- /dev/null +++ b/libMiniCash/mcvendorsdialog.ui @@ -0,0 +1,95 @@ + + + MCVendorsDialog + + + + 0 + 0 + 727 + 572 + + + + Verkäuferliste + + + + + + + 16777215 + 36 + + + + + 16 + true + + + + Verkäuferliste + + + Qt::AutoText + + + + + + + Qt::Horizontal + + + + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 90 + 16777215 + + + + + true + + + + Schliessen + + + + + + + + + + diff --git a/libMiniCash/swdriveselector.cpp b/libMiniCash/swdriveselector.cpp new file mode 100644 index 0000000..b92e717 --- /dev/null +++ b/libMiniCash/swdriveselector.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include + + +SWDriveSelector::SWDriveSelector( QWidget* parent ) + : QComboBox( parent ) +{ + +} + +SWDriveSelector::~SWDriveSelector() +{ + +} + +bool SWDriveSelector::event( QEvent* event ) +{ + if( event->type() == QEvent::MouseButtonPress ) + { + clear(); + for( auto& storage : QStorageInfo::mountedVolumes() ) + { + if( storage.isValid() && storage.isReady() ) + addItem( storage.rootPath() ); + } + } + return QComboBox::event( event ); +} + + diff --git a/libMiniCash/swdriveselector.h b/libMiniCash/swdriveselector.h new file mode 100644 index 0000000..f8b812e --- /dev/null +++ b/libMiniCash/swdriveselector.h @@ -0,0 +1,47 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef QDRIVESELECTOR_H +#define QDRIVESELECTOR_H + +#include +#include +#include +#include + +#include + +/** + * @brief Eine QComboBox zur Auswahl von Laufwerken. + * + * Mit dem QDriveSelektor wird ein Laufwerk(sbuchstabe) + * ausgewählt. Besonderheit: Beim Aktivieren werden ad hoc alle + * verfügbaren Laufwerke in die ComboBox geladen, um Fehleingaben + * zu reduzieren. + */ + +class LIBMINICASH_EXPORT SWDriveSelector : public QComboBox +{ + Q_OBJECT + +public: + + explicit SWDriveSelector( QWidget* parent = nullptr ); + virtual ~SWDriveSelector(); + + virtual bool event(QEvent* ev); + +}; + +#endif // QDRIVESELECTOR_H diff --git a/libMiniCash/swsidebar.cpp b/libMiniCash/swsidebar.cpp new file mode 100644 index 0000000..aa77db9 --- /dev/null +++ b/libMiniCash/swsidebar.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + + source::worx libWidgets + Copyright © 2021-2022 c.holzheuer + c.holzheuer@sourceworx.org + + 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. + +***************************************************************************/ + + + + +#include +#include +#include +#include +#include + +#include + + + + + +SWSideBar::SWSideBar( QWidget *parent ) + : QFrame( parent ) +{ + setMouseTracking( true ); +} + + +SWSideBar::~SWSideBar() +{ + +} + + +void SWSideBar::appendAction( QAction* action ) +{ + Q_ASSERT( action != nullptr ); + action->setCheckable( true ); + //action->setEnabled( false ); + QFrame::addAction( action ); + +} + + +void SWSideBar::appendAction( const QIcon& icon, const QString& text ) +{ + return appendAction( new QAction( icon, text ) ); +} + +void SWSideBar::setCheckedAction( QAction* action ) +{ + /// PFUSCH! Prüfen! + _checkedAction = action; + update(); +} + +void SWSideBar::paintEvent( QPaintEvent* event ) +{ + + + QPainter painter( this ); + + int actionY = 0; + for( auto& action : actions() ) + { + + QRect actionRect( 0, actionY, event->rect().width(), SWACTIONHEIGHT ); + if( action->isEnabled() ) + { + if( action == _hoveredAction ) + painter.fillRect( actionRect, _hoveredColor ); + + if( action == _pressedAction ) + painter.fillRect( actionRect, Qt::lightGray ); + + if( action == _checkedAction ) + painter.fillRect( actionRect, _checkedColor ); + + } + + QSize size = painter.fontMetrics().size( Qt::TextSingleLine, action->text() ); + QRect textRect( QPoint( actionRect.width()/2 - size.width()/2, actionRect.bottom()-size.height() - 10 ), size ); + painter.setPen( action->isEnabled() ? Qt::white : Qt::gray ); + painter.drawText( textRect, Qt::AlignCenter, action->text() ); + + QRect pixmapRect( actionRect.width()/2 - 32, actionY+15 , 64, 64 ); + QPixmap pixmap = action->icon().pixmap( QSize( 64, 64 ), action->isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On ); + painter.drawPixmap( pixmapRect, pixmap ); + + actionY += actionRect.height(); + + } + +} + + + +void SWSideBar::mousePressEvent( QMouseEvent* event ) +{ + + QAction* tempAction = actionAt( event->pos() ); + if( tempAction == nullptr ) + return; + + if( _hoveredAction == tempAction ) + _hoveredAction = nullptr; + + _pressedAction = tempAction; + + update(); + QFrame::mousePressEvent (event ); + +} + + +void SWSideBar::mouseReleaseEvent( QMouseEvent *event ) +{ + + QAction* tempAction = actionAt( event->pos() ); + if( tempAction == nullptr ) + return; + + if( tempAction == _pressedAction ) + { + _hoveredAction = _pressedAction; + _checkedAction = _pressedAction; + _pressedAction = nullptr; + update(); + if( _checkedAction->isEnabled() ) + _checkedAction->trigger(); + + } + + + //update();QGuiApplication::palette()) an QPalette::Highlight + QFrame::mouseReleaseEvent( event ); + +} + + +void SWSideBar::mouseMoveEvent(QMouseEvent *event) +{ + QAction* tempAction = actionAt( event->pos() ); + /// nix gefunden + if( tempAction == nullptr) + { + /// dann ist auch nix gehovered + _hoveredAction = nullptr; + update(); + return; + } + /// ist schon gehovered? auch weg + if( _hoveredAction == tempAction ) + return; + + _hoveredAction = tempAction; + update(); + QFrame::mouseMoveEvent(event); +} + + +void SWSideBar::leaveEvent(QEvent * event) +{ + _hoveredAction = _pressedAction = nullptr; + update(); + QFrame::leaveEvent(event); +} + + +QSize SWSideBar::minimumSizeHint() const +{ + return SWACTIONHEIGHT * QSize( 1, actions().size() ); +} + + +QAction* SWSideBar::actionAt(const QPoint &at) +{ + int actionY = 0; + + for( QAction* action : actions() ) + { + QRect actionRect( 0, actionY, rect().width(), SWACTIONHEIGHT ); + if(actionRect.contains(at)) + return action; + actionY += actionRect.height(); + } + return nullptr; +} + + diff --git a/libMiniCash/swsidebar.h b/libMiniCash/swsidebar.h new file mode 100644 index 0000000..6801d37 --- /dev/null +++ b/libMiniCash/swsidebar.h @@ -0,0 +1,69 @@ +/*************************************************************************** + + source::worx libWidgets + Copyright © 2021-2022 c.holzheuer + c.holzheuer@sourceworx.org + + 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. + +***************************************************************************/ + + +#ifndef SWSIDEBAR_H +#define SWSIDEBAR_H + +#include +#include +#include + +#include + + +class LIBMINICASH_EXPORT SWSideBar : public QFrame +{ + Q_OBJECT + +public: + + explicit SWSideBar( QWidget *parent = nullptr ); + virtual ~SWSideBar(); + + void appendAction( QAction* action ); + void appendAction( const QIcon &icon, const QString &text = "" ); + void setCheckedAction( QAction* action ); + + QSize minimumSizeHint() const; + +signals: + +public slots: + + //void koo(); + +protected: + + void paintEvent( QPaintEvent *event ); + void mousePressEvent( QMouseEvent *event ); + void mouseReleaseEvent( QMouseEvent *event ); + void mouseMoveEvent( QMouseEvent *event ); + void leaveEvent( QEvent * event ); + + QAction* actionAt( const QPoint &at ); + + + static const int SWACTIONHEIGHT = 108; + + const QColor _hoveredColor = QColor( 150, 150, 150 ); + const QColor _checkedColor = QColor( 55, 55, 55 ); + + QAction* _hoveredAction = nullptr; + QAction* _pressedAction = nullptr; + QAction* _checkedAction = nullptr; + + +}; + +#endif // SWSIDEBAR_H diff --git a/miniCash/main.cpp b/miniCash/main.cpp new file mode 100644 index 0000000..123c36f --- /dev/null +++ b/miniCash/main.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include + + +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication::setOrganizationName ( miniCash::orgName ); + QCoreApplication::setOrganizationDomain( miniCash::domainName ); + QCoreApplication::setApplicationName ( miniCash::appName ); + + QApplication application(argc, argv); + + MCMainWindowLocal window; + window.show(); + + return application.exec(); +} diff --git a/miniCash/mcaboutme.cpp b/miniCash/mcaboutme.cpp new file mode 100644 index 0000000..731aabb --- /dev/null +++ b/miniCash/mcaboutme.cpp @@ -0,0 +1,32 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include + +MCAboutMe::MCAboutMe(QWidget *parent) : + QDialog( parent ) +{ + + setupUi( this ); + label2->setText( QString( miniCash::copyShort ) + '\n' + miniCash::version ); +} + + +MCAboutMe::~MCAboutMe() +{ + +} diff --git a/miniCash/mcaboutme.h b/miniCash/mcaboutme.h new file mode 100644 index 0000000..5d7ef33 --- /dev/null +++ b/miniCash/mcaboutme.h @@ -0,0 +1,37 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCABOUTME_H +#define MCABOUTME_H + +#include +#include + +/** + * @brief + */ + +class MCAboutMe : public QDialog, private Ui_MCAboutMe +{ + Q_OBJECT + +public: + + explicit MCAboutMe( QWidget* parent = nullptr ); + virtual ~MCAboutMe(); + +}; + + +#endif // MCABOUTME_H diff --git a/miniCash/mcaboutme.ui b/miniCash/mcaboutme.ui new file mode 100644 index 0000000..80e4b91 --- /dev/null +++ b/miniCash/mcaboutme.ui @@ -0,0 +1,126 @@ + + + MCAboutMe + + + + 0 + 0 + 612 + 393 + + + + über minCash + + + + + 230 + 320 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + 40 + 30 + 351 + 81 + + + + + + + :/miniCash/images/miniCash.png + + + + + + 60 + 200 + 441 + 101 + + + + Based on Qt 5.15.2(64 bit) + +The program is provided AS IS with NO WARRANTY OF ANY KIND, +INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + 60 + 120 + 461 + 71 + + + + + 10 + true + + + + <html><head/><body><p>...</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + buttonBox + rejected() + MCAboutMe + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + MCAboutMe + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/miniCash/mceditdialog.cpp b/miniCash/mceditdialog.cpp new file mode 100644 index 0000000..4aa7f66 --- /dev/null +++ b/miniCash/mceditdialog.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include + + +/** + * @brief Erzeugt das Dialogfenster, im dem die Kassendatei editiert + * werden kann. + * @param parent das Elternfenster + * @param filename der Name der Kassendatei + */ + +MCEditDialog::MCEditDialog( QWidget* parent, const QString& filename ) : + QDialog( parent ), + _filename( filename ) +{ + + setupUi(this); + + // Murx, FIX! das sollte über den Translator gehen + buttonBox->button( QDialogButtonBox::Ok )->setText( "Kassendatei Speichern" ); + buttonBox->button( QDialogButtonBox::Cancel )->setText( "Abbrechen" ); + + connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + connect( _startSearch, SIGNAL(clicked()), this, SLOT( onSearch() ) ); + + onLoadFile(); + +} + + +MCEditDialog::~MCEditDialog() +{ + +} + + +/** + * @brief lädt die Kassendatei + */ + +void MCEditDialog::onLoadFile() +{ + QFile file( _filename ); + if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QString msg( "Datei '%0' konnte nicht geöffnet werden.\nFehlercode: %1" ); + QMessageBox::warning( this, "Dateifehler", msg.arg( _filename, file.errorString() ) ); + return; + } + + _trSalesText->setPlainText( file.readAll() ); + +} + + +/** + * @brief Durchsucht die Kassendatei nach einen Schlüsselbegriff + */ + +void MCEditDialog::onSearch() +{ + QString src =_searchString->text(); + _trSalesText->find( src ); +} + + +/** + * @brief sichert die ggf. geänderte Kassendatei + */ + +void MCEditDialog::accept() +{ + // sichern + + QFile file( _filename ); + if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + { + QString msg( "Datei '%0' konnte nicht geschrieben werden.\nFehlercode: %1" ); + QMessageBox::warning( this, "Dateifehler", msg.arg( _filename, file.errorString() ) ); + return; + } + + file.write(_trSalesText->toPlainText().toLatin1() ); + + return QDialog::accept(); + +} diff --git a/miniCash/mceditdialog.h b/miniCash/mceditdialog.h new file mode 100644 index 0000000..1afa3f9 --- /dev/null +++ b/miniCash/mceditdialog.h @@ -0,0 +1,56 @@ +/*************************************************************************** + + libMiniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCEDITDIALOG_H +#define MCEDITDIALOG_H + +#include +#include +#include + +/** + * @brief Editiert eine Kassendatei + * + * Hier kann die Verkaufsdatei einer Kassen direkt editiert + * werden, um Zahlendrehen oder Tippfehler zu korrigieren oder + * Einträge zu löschen (Storno des kleinen Mannes) + * + */ + +class MCEditDialog : public QDialog, private Ui_MCEditDialog +{ + Q_OBJECT + +public: + + explicit MCEditDialog(QWidget *parent = nullptr, const QString& filename="" ); + ~MCEditDialog(); + +public slots: + + void onSearch(); + +protected: + + void onLoadFile(); + void accept(); + +protected: + + QString _filename; + +}; + + +#endif // MCEditDialog_H diff --git a/miniCash/mceditdialog.ui b/miniCash/mceditdialog.ui new file mode 100644 index 0000000..d3095c3 --- /dev/null +++ b/miniCash/mceditdialog.ui @@ -0,0 +1,150 @@ + + + MCEditDialog + + + + 0 + 0 + 694 + 588 + + + + Dialog + + + + + + + 9 + true + + + + <html><head/><body><p>Suchbegriff:</p></body></html> + + + Qt::AutoText + + + + + + + + 9 + true + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + + + + + 16 + true + + + + Kassendatei editieren + + + Qt::AutoText + + + + + + + + 9 + + + + + + + + + 9 + true + + + + Verkaufte Artikel + + + + + + + + Lucida Sans Typewriter + 10 + + + + false + + + + + + + + 0 + 0 + + + + + 9 + true + + + + Kassendatei durchsuchen + + + Suchen + + + + :/myresource/images/package_editors.png:/myresource/images/package_editors.png + + + + 16 + 16 + + + + + + + + Qt::Horizontal + + + + + + + + diff --git a/miniCash/mcmainwindowlocal.cpp b/miniCash/mcmainwindowlocal.cpp new file mode 100644 index 0000000..513a976 --- /dev/null +++ b/miniCash/mcmainwindowlocal.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "ui_mcmainwindowlocal.h" + + +MCMainWindowLocal::MCMainWindowLocal( QWidget* parent ) : + MCMainWindowBase( parent ), _ui{new Ui::MCMainWindowLocal} + +{ + + _ui->setupUi( this ); + setupDefaults(); + + _inputViewProxy = _ui->_inputView; + _ui->_inputView->setupDefaults( this, &_salesModel ); + _ui->_billingView->setupDefaults( _dataFileName, &_mainSettings ); + _ui->_contentWidget->setCurrentWidget( _ui->_inputView ); + + statusBar()->setFont( QFont( "Arial", 8 ) ); + statusBar()->showMessage( QString( miniCash::copyright ) + miniCash::version ); + + //_helpViewer = new MCHelpViewer(); + //_helpViewer->load( "file:///C:/HandbuchMiniCash.html" ); + + // Menü Leiste + connect( _ui->_actionHelpAbout, SIGNAL(triggered()), this, SLOT( onHelpAbout() ) ); + connect( _ui->_actionHelpContents, SIGNAL(triggered()), this, SLOT( onHelpManual() ) ); + connect( _ui->_actionStartBilling, SIGNAL(triggered()), this, SLOT( onStartBilling() ) ); + connect( _ui->_actionEditSalesFile, SIGNAL(triggered()), this, SLOT( onEditTransactions() ) ); + connect( _ui->_actionCopySaleData, SIGNAL(triggered()), this, SLOT( onCopyTransactions() ) ); + connect( _ui->_actionSetup, SIGNAL(triggered()), this, SLOT( onSetup() ) ); + connect( _ui->_actionExit, SIGNAL(triggered()), this, SLOT( onExit()) ); + connect( _ui->_actionExitConfirmed, SIGNAL(triggered()), this, SLOT( onExitConfirmed()) ); + +} + + +/** + * @brief Tod und Verderben + */ + +MCMainWindowLocal::~MCMainWindowLocal() +{ + +} + + + + +/** + * @brief In den Abrechungsmodus schalten + * + * Abrechnung starten: Dazu wird das Hauptfenster auf die Abrechungsmaske + * umgeschaltet (irreversibel) + */ + +void MCMainWindowLocal::onStartBilling() +{ + _ui->_contentWidget->setCurrentWidget( _ui->_billingView ); +} + + +/** + * @brief Die Kassendatei editieren + */ + +void MCMainWindowLocal::onEditTransactions() +{ + MCEditDialog dlg( this, _dataFilePath ); + dlg.exec(); + +} + + +/** + * @brief setup dialog anzeigen + * + * Maske mit den Programmeinstellungen anzeigen: Ziellaufwerk etc. + * + */ + +void MCMainWindowLocal::onSetup() +{ + MCSetupDialog dlg( this, &_mainSettings ); + dlg.exec(); +} + + +/** + * @brief Kurzinfo anzeigen + * + */ + +void MCMainWindowLocal::onHelpAbout() +{ + MCAboutMe aboutMe; + aboutMe.exec(); + +} diff --git a/miniCash/mcmainwindowlocal.h b/miniCash/mcmainwindowlocal.h new file mode 100644 index 0000000..5ee9b21 --- /dev/null +++ b/miniCash/mcmainwindowlocal.h @@ -0,0 +1,42 @@ +#ifndef MCMAINWINDOWLOCAL_H +#define MCMAINWINDOWLOCAL_H + +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui +{ + class MCMainWindowLocal; +} +QT_END_NAMESPACE + +/** + * @brief MainWindow der miniCash-Anwendung. + * + * Erbt von MCMainWindowBase und stellt die Implementierung der Nutzeroberfläche + * zur Verfügung. + */ + +class MCMainWindowLocal : public MCMainWindowBase +{ + Q_OBJECT + +public: + + explicit MCMainWindowLocal( QWidget* parent = 0 ); + virtual ~MCMainWindowLocal(); + +protected slots: + + void onSetup() override; // Programmeinstellungen vornehmen + void onEditTransactions() override; // Kassendatei durchsuchen und editieren + void onStartBilling() override; // Kassieren beenden, Abrechnungsmodus starten + void onHelpAbout() override; // Kurzinfo anzeigen + +private: + + Ui::MCMainWindowLocal* _ui{}; +}; + +#endif // MCMAINWINDOWLOCAL diff --git a/miniCash/mcmainwindowlocal.ui b/miniCash/mcmainwindowlocal.ui new file mode 100644 index 0000000..597ad25 --- /dev/null +++ b/miniCash/mcmainwindowlocal.ui @@ -0,0 +1,266 @@ + + + MCMainWindowLocal + + + + 0 + 0 + 1000 + 700 + + + + miniCash.local + + + + + + + + + + + + + + + 0 + 0 + 1000 + 26 + + + + + 9 + true + + + + + + 9 + false + + + + &Datei + + + + + + + + + + 9 + false + + + + &Abrechnung + + + + + + + + 9 + false + + + + &Hilfe + + + + + + + + + + + + 9 + true + + + + TopToolBarArea + + + false + + + + + + + + + + 10 + + + + + + + :/images/exit.png:/images/exit.png + + + &Speichern und Beenden + + + Speichern und Programm beenden + + + + 9 + true + + + + + + + :/images/contexthelp.png:/images/contexthelp.png + + + Handbuch anzeigen + + + + 9 + true + + + + + + + :/images/help.png:/images/help.png + + + Über miniCash + + + + 9 + true + + + + + + + :/images/buisness.png:/images/buisness.png + + + &Abrechung starten + + + Abrechnung starten + + + Eingabe verlassen und Abrechnung starten + + + + 9 + true + + + + + + + :/images/agt_Utilities.png:/images/agt_Utilities.png + + + Kassendatei editieren + + + Verkauften Artikel suchen und ggf. stornieren + + + + 9 + true + + + + + + + :/images/stick.png:/images/stick.png + + + Daten &kopieren + + + Kopiert die Verkaufsdaten auf den Memorystick + + + Kopiert die Verkaufsdaten auf den Memorystick + + + + 9 + true + + + + + + + :/images/exit.png:/images/exit.png + + + ExitConfirmed + + + Speichern und Programm beenden + + + + + + :/images/agt_utilities_copy.png:/images/agt_utilities_copy.png + + + Programmeinstellungen + + + + 9 + true + + + + + + + + MCInputView + QWidget +
mcinputview.h
+ 1 +
+ + MCBillingView + QWidget +
mcbillingview.h
+ 1 +
+
+ + + + +
diff --git a/miniCash/miniCash.h b/miniCash/miniCash.h new file mode 100644 index 0000000..a37c37d --- /dev/null +++ b/miniCash/miniCash.h @@ -0,0 +1,112 @@ +/*************************************************************************** + + miniCash + Copyright © 2013-2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MINICASH_H +#define MINICASH_H + +#include + +/** + +@mainpage miniCash + +@section xxx das Kassensystem 'miniCash' + +'miniCash' ist ein semi-verteiltes Kassen- und Abrechnungssystem für den KinderKleiderMarkt +in Kist. Beim Kister Kleidermarkt können Kindersachen günstig verkauft und erworben, sozusagen +weitergereicht werden. +so + +... + +@warning ein zwei warning + +@note ein zwei note + +@bug ein zwei bug + +@deprecated ein zwei deprecated + +@todo eins zwei todo + +@remark eins zwei remark + +@subsection xxz Funktionsbereiche + - Datenmodelle und Datentypen + - Eingabe der Verkäufe + - Setup-Dialoge + - Erzeugung der Abrechnungen + - Druckersteuerung + +@section sec3 Ideen & TODO: + +@warning das handling von 'enter' und 'tab' überprüfen +@bug die filterung von falschen kundennummern geht nicht. + +@subsection sec3_1 Ideen: + + - oberfläche erneuern? + - beim server hochfahren: daten abholen, puffern, wahlweise via usb + - adressverwaltung einbeziehen, für personalisierte Abrechnungen + +@subsection sec3_2 TODO für 1.0: + + - wlan first, disk backup + - netzprotocol, erfinden oder json/xml + - splash screen? + - fehler dulden wg. Kassenschlange, hinterher kennzeichnen + - server security: only allowed hosts + - auto feeder zum testen + - data: kasse|count|cust|pos|price|timestamp + - protocol: [...]: transaction, -: storno; + - kasse: semi blocking (soll genau was heissen, chris?) + - Beim einlesen mitzählen, Ergebnis in den statusbar. + - suche bei Storno mit mehreren Feldern zulassen + - setup.exe bauen + + +@subsection sec3_3 TODO für 0.9: + + - backup über WLAN -> Adhoc Netzwerk einrichten + - DONE: layouts verwenden + - Handbuch schreiben + - DONE: vernünftiger Setup-dialog mit Abbruchmöglichkeit + - Auswertung: laden und speichern ? + - Printbuttons ab/an schalten ? + - Kurzanleitung ? + - QUARK: programm muss immer starten, fehlerloop verwirrt nur + QUARK: Programm _kann_ ohne Laufwerk nicht starten! + - help about : mit hinweis auf sourceworx & logo + - Fonts vereinheitlichen + - Statusbar einbinden ?!? + - Caps lock abschalten, wie ? + +*/ + + +/** + * @brief der namespace miniCash enthält Definitionen und Konstanten. + */ + +namespace miniCash +{ +/// basics +[[maybe_unused]] static const char* const appName = "miniCash.local"; + +/// misc +[[maybe_unused]] static const char* const version = "Version 0.8.21. 14.07.2022"; + +} + +#endif // MINICASH_H diff --git a/miniCash/miniCash.pro b/miniCash/miniCash.pro new file mode 100644 index 0000000..67eb561 --- /dev/null +++ b/miniCash/miniCash.pro @@ -0,0 +1,49 @@ +QT += core gui widgets + +CONFIG += c++17 + +TEMPLATE = app +TARGET = miniCash + + +DESTDIR = $$OUT_PWD/../common + + +INCLUDEPATH += $$PWD/../libMiniCash + +SOURCES += \ + main.cpp \ + mcaboutme.cpp \ + mceditdialog.cpp \ + mcmainwindowlocal.cpp + +HEADERS += \ + mcaboutme.h \ + mceditdialog.h \ + mcmainwindowlocal.h \ + miniCash.h + +FORMS += \ + mcaboutme.ui \ + mceditdialog.ui \ + mcmainwindowlocal.ui + +DEPENDPATH += $$PWD/../libMiniCash + +LIBS += -L$$OUT_PWD/../common -llibMiniCash + + +#PRE_TARGETDEPS += $$OUT_PWD/../build/lib/$$qtLibraryTarget(libMiniCash) + +#SRC_DIR = $$OUT_PWD/../libMiniCash/debug +#DEST_DIR = $$OUT_PWD/debug + +#QMAKE_PRE_LINK += $$QMAKE_COPY_FILE $$shell_path($$SRC_DIR/libMiniCash.dll) $$shell_path($$DEST_DIR) +#QMAKE_POST_LINK += $$QMAKE_COPY_FILE $$shell_path($$SRC_DIR/libMiniCash.dll) $$shell_path($$DEST_DIR) + + +message("OUT_PWD = $$OUT_PWD") +message("shellpath = $$shell_path($$SRC_DIR/libMiniCash.dll)") +message("dest = $$shell_path($$DEST_DIR)") +message("copy file = $$QMAKE_COPY_FILE") + diff --git a/miniCash/miniCash.qrc b/miniCash/miniCash.qrc new file mode 100644 index 0000000..9554690 --- /dev/null +++ b/miniCash/miniCash.qrc @@ -0,0 +1,32 @@ + + + + images/agt_utilities_copy.png + images/agt_Utilities.png + images/buisness.png + images/help.png + images/contexthelp.png + images/copy.png + images/cut.png + images/exit.png + images/filenew.png + images/fileopen.png + images/filesave.png + images/filesaveas.png + images/findf.png + images/folder_new.png + images/new.png + images/open.png + images/paste.png + images/save.png + images/stick.png + images/printer2.png + images/fileexport.png + images/button_ok.png + images/search.png + templates/tplFinal.html + templates/tplPayoff.html + templates/tplReceipt.html + + + diff --git a/miniCashAll.pro b/miniCashAll.pro new file mode 100644 index 0000000..7c35617 --- /dev/null +++ b/miniCashAll.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + libMiniCash \ + miniCashConnect \ + miniCash + +miniCash.depends = libMiniCash +miniCashConnect.depends = libMiniCash diff --git a/miniCashConnect/.gitignore b/miniCashConnect/.gitignore new file mode 100644 index 0000000..5e57128 --- /dev/null +++ b/miniCashConnect/.gitignore @@ -0,0 +1,8 @@ +*.o +build +*.autosave +*.pro.user +*.pro.user.* +miniCashConnect.pro.user + + diff --git a/miniCashConnect/.gitmodules b/miniCashConnect/.gitmodules new file mode 100644 index 0000000..9fb4212 --- /dev/null +++ b/miniCashConnect/.gitmodules @@ -0,0 +1,3 @@ +[submodule "doc/doxygen-awesome-css"] + path = doc/doxygen-awesome-css + url = https://github.com/jothepro/doxygen-awesome-css.git diff --git a/miniCashConnect/LICENSE b/miniCashConnect/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/miniCashConnect/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/miniCashConnect/README.md b/miniCashConnect/README.md new file mode 100644 index 0000000..dcf3151 --- /dev/null +++ b/miniCashConnect/README.md @@ -0,0 +1,2 @@ +# README.md miniCashConnect +## miniCashConnect zweite diff --git a/miniCashConnect/images/_billing2.png b/miniCashConnect/images/_billing2.png new file mode 100644 index 0000000000000000000000000000000000000000..e6b4ebc7dc50caa677d027350c7fe795fd37928e GIT binary patch literal 6245 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 P00000NkvXXu0mjfAl3+{ literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/_edit2.png b/miniCashConnect/images/_edit2.png new file mode 100644 index 0000000000000000000000000000000000000000..fab5d329696f5498636cd79854a0825ae23f8738 GIT binary patch literal 6341 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 Hu0mjf{b@&p literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/_input2.png b/miniCashConnect/images/_input2.png new file mode 100644 index 0000000000000000000000000000000000000000..e8138ffe7930c3af740049b1c80946623653ef4e GIT binary patch literal 6605 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 AvH$=8 literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/_server.png b/miniCashConnect/images/_server.png new file mode 100644 index 0000000000000000000000000000000000000000..a45e5184d1d274d5c8adbb1b3fb7645fa476f045 GIT binary patch literal 5965 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 literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/_setup2.png b/miniCashConnect/images/_setup2.png new file mode 100644 index 0000000000000000000000000000000000000000..769baf271ffe4c0a63372290deda865454bf604b GIT binary patch literal 8441 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 bDhB@_f~cAL>m9Hh00000NkvXXu0mjfKqf`< literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/_transactions2.png b/miniCashConnect/images/_transactions2.png new file mode 100644 index 0000000000000000000000000000000000000000..1ee082455108c9bd31c8b8a86e30bd1067c87a89 GIT binary patch literal 6095 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
    eF;aO*rD{qKXQdQ}4)^l@o`dY& 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 literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/contexthelp.png b/miniCashConnect/images/contexthelp.png new file mode 100644 index 0000000000000000000000000000000000000000..197708e3629eb00baa911fd073763f2e1105ce59 GIT binary patch literal 2162 zcmV-&2#xoNP) zc6V^Kt=5hs+udrl;0ktK5ws|DL`OgfDnc||!aX4*klQ)$erRE-3R1`Y&%7VbdwHJU zJkRr94n+vT&y_LhMFq5}I+0W&OPD>sv-XbFB9$=Y+mBykf37WRA^^)n721rnX$w+Q zld_d6mChFO+!U2gYxns5JfTXH{GXzdzm$Ai`M2OXYh35|E$M$|0B=T2PI_y_+})W* z{bEL|k$}%bSKkmkvT$f;<^TX#HUNjy#Z{dA^3s`87mwaBHx%7$Yj92!fIrs2{_JU+ zK7IeSKQn5%1g>VF$_%g^ST_%n8M!0#Xqt~nN(FC8h9)=H7n<`a<2?Z2y@>)mHUfuC zsk=A7nz9Rn?Lcb>;0b`EMId}JTK!UB?kdO^uYrJLA(2YJb31`QECLt;geKtFg{IHe zesgK#Q$^sTblv(LtM$8Jw*VF^h}#Pngy`oucswq&dZp;Ew}6CRhf*qnN*w`p-35f) zsRa}YfFoEtH(|q{a%bAMl~(PUa0C`?`Yb_MeI{d@A?QG6aJ!sueE@clMHeSSubYCU zb0BcN!_{Pw$MyDgTkk?OS*D(vn2?q;XR5KLK%jBngM#k^B@zI!(QpW~fsKbQAoP3DX7}K`=DybAZuVd9sI-=V?fwPU z-t&O!?h&;#n8O>+7MdJt>6=TYg(X5EfYR#%+S;Lr3+AuRN!|%y!4o5pV|rVh6d_&r z>m6G^j8BM{vmC+I(yQqH@&Fp^?%K~e=#!K*s3OpM`~1~jTjyv4=@b>@1F}{|$@jgU z5|$Fqcp-rghzf^Y8qL0Qs7(Kjt?T+&06YNj+&IH6dgB+r42uYt0|3pV5EdVWrmUsh z*>2x4e@{!^P+fWc!_EQV1|b7N;9^mWbD!BZ;C68$fDoYH38lzOr^l+tjQ|e-NW=_P zTa%@oVWa?nA&(c`J$-1cy3*)=V9u|!cbc!UfiVw^8-xS~IC9~d&2@FiN5E1v;PC=J zH{vxRFFX-|4%G=Img{!jKsNvaA1DkE3Y|?&4HRG<&%m%~pw~L!yFTa%fc5zSryX$i zKqY75(?hheW3A%@0NZWxN8am_8mk$I-L*!<_-EXu3a7_fDh7ht?t8Kgg#s^SG zsURHc0sIc|D{m7%-z*&$z+;TZs|E#M8-L)pWFvez!<0BRxt06;53f)O(f z^b2W#fCd0`I8F_+fucYLUqD|A_#e5fcmPo2wAtIcdh5U!0TKoRu?S+h3^5AnbOOjH z3NR@qI-}%l0UTW&00537@Ug61C=Zc8&iM!c0GO@a<=|*QEQE*(fDuzjoh+T9776A( z$?;4PL(dM6TcFj?nHMCH;7maQEX~dEvn&V`tPb>dJ+ga-HF6Z!wA#yC?QD01Od3k{ zyPy>K5g97M@+igbESkPo!LpSPFP=5sBw#WYq$pC1$;+7jUCOEghJEENEPZtuK0k68 zDpi=b_~^0U1x+^z#sV0LK-u6>OOd(vYlx(PjDd{uU~&+UsSA$ToETcLBszLS8jlw= zJU>k!qIisKwygAU#_RSg8(tE(YSTOo;5=>w$z)i!Zapl`jXZP1Ew?Ijk!UP{pWKEy zj5O|x)ib_}QF_(r>H!(@q0a+!sMAotXba3$RpypkHRYb3F00(>)+N)x#tVQWXKZ zdN7G*A=$JOvash6AFWMty}UGubvc30KSHdd8w?|djPgQA`OqsAfJgsO{e%$EJR0x5 zy%xF%^%j%KG}-6%tt-D$?j92W01h|X@_#!$TC;ogtUofLgW%%ykWSYl3P41N0)CD| zV8D(Cu@Q(I@&XhOpeR5h2Ir+fsFAFK5CV##FmK*V2o9F7+`D&gxY1}_dHM3?_D5=9 zwD#Y!?Av~#`u#RVGU4T{0s+9WEO}0^SRgSI?DN^+(oI0-LfAv5`h9+u z8*OVi#d^ISJ9qA!rBo`dv%xP;IA5r`I@P*-kweu{4Q|z zR;!PYehL_>`_WsfMia(@qJ|w0%j@-`u&|)Bv9WPgb#-;ePn-}!CfqWl3i`$8O`@^J zXQZcx9Xxo*O$Z^SrDdeJxR@h9s-&cZ7z~D;53iZfkI6)pq1USy&Yy1)iA28Br%!M5 z`~A@;PoCVCkdOeDWwB$&4rgg;siCT>%KTIjcv8#G&ej->#zT6&K8g?mxm+&avSrI% zzu!*?A*8Opj+o|}z8<~inF0_(px5iE(ch7gkt_0#=MQIs9654?7z~Ex|2KfgHG{$M ziN#_egb;H6{CQ$D<{Td$8+R8xttg73$f)9SyWM;8^73AZiHVUH78dT|I5ux&?z1ey o@syR7W#S0w{=TxZc69%L0mSOga#R{JZ~y=R07*qoM6N<$f;3+j3;+NC literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/disconnect.png b/miniCashConnect/images/disconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..6a7e03533420869feef3f905323e266d9e7d00df GIT binary patch literal 6663 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 CZ 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 literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/findf.png b/miniCashConnect/images/findf.png new file mode 100644 index 0000000000000000000000000000000000000000..3946c5fae97c5573c79aca8f8a4b266fe82bf9b6 GIT binary patch literal 1897 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 Hu0mjfM9NfX literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/help.png b/miniCashConnect/images/help.png new file mode 100644 index 0000000000000000000000000000000000000000..6bd02815da850b432fad2922161b2d3db3770067 GIT binary patch literal 2461 zcmV;O31aq%P)Z zdvH|s70187``o>|n|)c$wY4+q z*r`QjYEi_#w6sMT0p$^#@JKK~APF&Vl594c>~8jX_jT|6^$#=}j3{HzUw7`@bH1N@ z&iVa*=SL`|_%>Ekd6y&FjL>QPa-hH`P#~2;Dv?HyU&VDRR{;jc^!FO22q!hPJh%DCUw1XV+CJny*dBCGepP(# za^lb3P`2rnU#@#WpKE6k9R&4t14$J`1r&vWj)4CalFMeEhedq5&L3z%a~3=eE6| zZ*K<4D~7^2@%p}wKfS!C`SH_K`;yqK8Q67i?e_J{%Nh_H1w3OQz948?L5lE*F%l9G z5Y$BY(@unX2EYgcBvC|0Mh2`lJ9O{A1`LjZDioY6hDVl{{aD9yCIA~Q)nYz-xch-$ z69Cv!QSi|Hi{~^T;RVLVfQbM!MMH?{;Z{s=2Pxd6LG+D8(AzhPqsLC*N%$d%)#U=CVS6qL)=cFme za}EwkgOMaa83xG70?Eq5CqBb?<4e1%o1!t#j1mY8tr~sj`Lk;uxaXE-4Qs6Djvd3` zPy!3$9t1fHJW&FVH;g^~ftC}&^lGte(MHYhK9Y*drwPEs<8jI79e4E{KUy8m)UUg* z#9pIvCb$F&NlO9~eo#?FiNlb+>c;Y)19)NvfEpZ6oZahb*Z^8R3`cN!plXxroux4!y8c22gDPzn$huKXMnuKGTX zNZIJwx7Rz882iMirD}q$dtW>ekA^R;Whmw!|>?8`r z;vjMqS&~&>J~!tM0KL;qXvr&_?{sB3jFKK81OO0@L=c~v0BZowwj6vT(fQGD4s{)W zdp7Y)K!O5r;($A{-Q$nZsKP=83!*51EJK8hsySJ=POpL+s_(Il2UTy>>*>`=`sqM1 zSw=`sps%fMMD|Y}W`M8U%`UYzO2huNda%=<=t-qCq`(27Ks*7c3CwY3T(^MXBmiK< z(!~;qP05zfs7PYL=^zP)N1QMi?>>JXz+fw-$~OhTMLG9qB-yRXaj3}zAcuiS5J*Ik zp%+~G{CV>MfD1RhnRE!6SkSahNBaK`XcAO=5uncnAJUK<9&{7nYfrUHjRjCfM56oJ6hR5Gom7?$H00BH4H==1ufIsq2o zc@P5V7!AD0qQoqg=?E#hQUD#t6%So}^%qI22iUQ@Pc!www^@n~GNpMtfe}t&ciNtE>*E0|x0+S4t6y#GrD# zn3@EGMXf2IrR^u-0FQou7Az`HMR{i9+okm_=;VW$ClCxR!NhoVh{;Q^xr zFbvEj4s(Wpe7nf6pKE)uK;+g}5W>$Uo@>qe!PVE@+-&VW{J~ne?anG~2rB}IQ1RA} z(6r@AOnmSUU}6wQ_wH?JefM9RO=We4oQ7vzGX|2?F8lJ=*Ol)za8b};7$g!wlJXc= z3^n+5E!p)&wuiGE2ElG*k;z0s zr~+Baz-dDnQnq4jefz*q-GSI)+p1rfAz4~x09;E5dHj}ZUu&$hJxrA-5D0?A6G&?e ze2fJn4bNjjZ^fj?gUR7xZ#W!w>juv&wxRx_>yv|4o5jFMMgbO`1`CxzKtc5)V6%Z3 zocP`G_v$J_CB;V%Y?m20%ddI%pO%U~r;&jJvS=Q1h?a z(&^4GYJRDyTGHu}WoF}sXV%=bb75)0RcdA!B&~s|Z-AKrGUgN_l}aO(PJwa)f`K7u z1x^%*#)|<61tlz~PK0JOfi>9C+#MKt=AZi?O({zErFye=_5M)w*b=>X-_IVp_l=cH z=2v6h0w^{Yh^m5N7>J?(Q4|0Gip7RR(LBHiXkbA(7MdV}k&K{J!0rRBr=Q=k=doxa z*?Q*Uk^S`m0Ps;fd9Ko6eXw;nx@Fzw#q}jX1_+=k3Mc>qfaQ54SP^Pr88oX1jpe}# zI)>m{A({JRnB<}oo1op_B)rZxZ}YM%L0{?>gJcrxHO&VNsqhqS=Lklb`s#6P~`lfzH7Z&&e32eF6|Zbs6C+0sw$o zPGHljqH&qICD7aQQbAuBET@C)_b92@IDj+BjL~joO;)oS^7&ij;1$mb bU$p-L(h)?sbJ0m{00000NkvXXu0mjfTsooG literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/miniCashConnect.png b/miniCashConnect/images/miniCashConnect.png new file mode 100644 index 0000000000000000000000000000000000000000..b74d156dd69b1f1db593644cad68d663335378c1 GIT binary patch literal 33300 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�?z$To}0jwJl4~>}`FQ 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 F_&;IZAQu1t literal 0 HcmV?d00001 diff --git a/miniCashConnect/images/nfs_mount.png b/miniCashConnect/images/nfs_mount.png new file mode 100644 index 0000000000000000000000000000000000000000..40ae998b8389662184b727611cb3f6c971b4e44b GIT binary patch literal 7476 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 W@Xgrl6+S2c0000 +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + + QCoreApplication::setOrganizationName ( miniCash::orgName ); + QCoreApplication::setOrganizationDomain( miniCash::domainName ); + QCoreApplication::setApplicationName ( miniCash::appName ); + + QApplication application(argc, argv); + + /* + qDebug() << " -- first"; + myMutex.lock(); + qDebug() << " -- second"; + myfunc(); + myMutex.lock(); + qDebug() << " -- third"; + */ + + QTranslator translator; + QLocale locale; + + QStringList list = locale.uiLanguages(); + for( const QString& lang : list ) + qDebug() << "lang: " << lang; + qDebug() << "name:" << locale.name(); + + //translator.load( QLocale(), QLatin1String("miniCash"), QLatin1String("_"), QLatin1String(":/i18n")); + //translator.load( "miniCash_en" ); + //application.installTranslator( &translator ); + + MCConnectMainWindow window; + window.show(); + + return application.exec(); +} diff --git a/miniCashConnect/mccaboutme.cpp b/miniCashConnect/mccaboutme.cpp new file mode 100644 index 0000000..0789d94 --- /dev/null +++ b/miniCashConnect/mccaboutme.cpp @@ -0,0 +1,31 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include + +MCCAboutMe::MCCAboutMe(QWidget *parent) : + QDialog( parent ) + +{ + setupUi( this ); + label2->setText( QString( miniCash::copyConnect ) + '\n' + miniCash::versionConnect ); +} + + +MCCAboutMe::~MCCAboutMe() +{ + +} diff --git a/miniCashConnect/mccaboutme.h b/miniCashConnect/mccaboutme.h new file mode 100644 index 0000000..78ba5c2 --- /dev/null +++ b/miniCashConnect/mccaboutme.h @@ -0,0 +1,38 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCABOUTME_H +#define MCCABOUTME_H + +#include +#include + + +/** + * @brief The MCCAboutMe class ! + */ + +class MCCAboutMe : public QDialog, private Ui_MCCAboutMe +{ + Q_OBJECT + +public: + + explicit MCCAboutMe( QWidget* parent = nullptr ); + virtual ~MCCAboutMe(); + +}; + + +#endif // MCCABOUTME_H diff --git a/miniCashConnect/mccaboutme.ui b/miniCashConnect/mccaboutme.ui new file mode 100644 index 0000000..22cad89 --- /dev/null +++ b/miniCashConnect/mccaboutme.ui @@ -0,0 +1,126 @@ + + + MCCAboutMe + + + + 0 + 0 + 580 + 434 + + + + über minCash + + + + + 190 + 370 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + 40 + 50 + 351 + 111 + + + + + + + :/images/miniCashConnect.png + + + + + + 60 + 240 + 441 + 101 + + + + Based on Qt 5.15.2(64 bit) + +The program is provided AS IS with NO WARRANTY OF ANY KIND, +INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + 60 + 160 + 461 + 71 + + + + + 10 + true + + + + <html><head/><body><p>...</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + buttonBox + rejected() + MCCAboutMe + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + MCCAboutMe + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/miniCashConnect/mcceditview.cpp b/miniCashConnect/mcceditview.cpp new file mode 100644 index 0000000..1032679 --- /dev/null +++ b/miniCashConnect/mcceditview.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include + +#include +#include +#include +#include + + +/** + * @brief Default Konstruktor + * @param parent + */ + +MCCEditView::MCCEditView( QWidget* parent ) + : QWidget( parent ) + +{ + setupUi( this ); +} + + +/** + * @brief Default Destruktor + */ + +MCCEditView::~MCCEditView() +{ + +} + + +void MCCEditView::setupDefaults( MCMainWindowBase* parent ) +{ + _parent = parent; + Q_ASSERT( _parent != nullptr ); + + /// model setzen: + _trList->setModel( &_salesModel ); + + _valCustId.setRegularExpression( QRegularExpression( miniCash::fCustID ) ); // Validator für die Kundennnummer + _valItemNo.setRegularExpression( QRegularExpression( miniCash::fItemNo ) ); // Validator für die Kundennnummer; // Validator für die laufende Nummer des Artikels + _valPrice.setRegularExpression( QRegularExpression( miniCash::fPrice ) ); // Validator für die Kundennnummer; // Validator für die Preisangabe + + /* + _trSellerID->setValidator( &_valCustId ); + _trItemNo->setValidator( &_valItemNo ); + _trPrice->setValidator( &_valPrice ); + */ + + /* + // Doppelklick auf einen Eintrag in der View soll diesen löschen + connect( _trList, SIGNAL( doubleClicked(QModelIndex) ), this, SLOT( onRemoveEntry(QModelIndex)) ); + + // hosianna : key event handling ist gar nicht nötig + QShortcut* shortcutPayback = new QShortcut( QKeySequence( Qt::Key_F1 ), this ); + QShortcut* shortcutSave = new QShortcut( QKeySequence( Qt::Key_F12 ), this ); + + connect( shortcutPayback, SIGNAL(activated()), this, SLOT( onCalculatePayback()) ); + connect( shortcutSave, SIGNAL(activated()), _parent, SLOT( onSaveTransaction()) ); + + // Alle Transaktionen sichern + connect( _trOK, SIGNAL(clicked()), _parent, SLOT( onSaveTransaction()) ); + + // Felder auch mit Enter weiterschalten + connect( _trSellerID, SIGNAL(returnPressed()), this, SLOT( onMoveInputFocus()) ); + connect( _trItemNo, SIGNAL(returnPressed()), this, SLOT( onMoveInputFocus()) ); + + // Transaktion fertig eingegeben? Dann prüfen + connect( _trPrice, SIGNAL(editingFinished()),this, SLOT( onAddSalesItem()) ); + + _trPos->setText( "1" ); + _trCount->setText( _parent->transCount() ); + */ +} + + +/** + * @brief lädt die Kassendatei + */ + +void MCCEditView::loadTransactions( const QString& fileName ) +{ + + QFile file( fileName ); + if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QString msg( "Datei '%0' konnte nicht geöffnet werden.\nFehlercode: %1" ); + QMessageBox::warning( this, "Dateifehler", msg.arg( fileName, file.errorString() ) ); + return; + } + + QTextStream inputStream(&file); + /// nicht aggregieren + + ///_salesModel.clear(); <-- löscht den Header mit + ///_salesModel.removeRows( 0, _salesModel.rowCount() ); + /// anhängen + _salesModel.appendTransactions( inputStream ); + +} + + + +/** + * @brief Durchsucht die Kassendatei nach einen Schlüsselbegriff + */ + +void MCCEditView::onSearch() +{ + /* + QString src =_searchString->text(); + _trSalesText->find( src ); + */ +} + + +/** + * @brief sichert die ggf. geänderte Kassendatei + */ + +void MCCEditView::accept() +{ + // sichern +/* + QFile file( _filename ); + if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + { + QString msg( "Datei '%0' konnte nicht geschrieben werden.\nFehlercode: %1" ); + QMessageBox::warning( this, "Dateifehler", msg.arg( _filename, file.errorString() ) ); + return; + } + + file.write(_trSalesText->toPlainText().toLatin1() ); + + return QDialog::accept(); +*/ +} diff --git a/miniCashConnect/mcceditview.h b/miniCashConnect/mcceditview.h new file mode 100644 index 0000000..2f14f8f --- /dev/null +++ b/miniCashConnect/mcceditview.h @@ -0,0 +1,67 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCEDITVIEW_H +#define MCCEDITVIEW_H + +#include +#include + +#include +#include +#include + + +class MCMainWindowBase; + + +/** + * @brief Dieses Widget zeigt die aktuelle Transaktionsdatei an und ermöglicht Änderungen + * und Stornos. + */ + +class MCCEditView : public QWidget, private Ui_MCCEditView +{ + + Q_OBJECT + +public: + + explicit MCCEditView( QWidget* parent = nullptr ); + virtual ~MCCEditView(); + + void setupDefaults( MCMainWindowBase* parent ); + void loadTransactions( const QString& fileName ); + +public slots: + + void onSearch(); + +protected: + + + void accept(); + + MCMainWindowBase* _parent = nullptr; + MCSalesModel _salesModel; + int _poscount = 1; /// Verkaufsposition innerhanlb des aktuellen Vorgangs + double _overallSum = 0.0; /// Gesamtpreis der aktuellen Verkaufstransaktion + + QRegularExpressionValidator _valCustId; /// Validator für die Kundennnummer + QRegularExpressionValidator _valItemNo; /// Validator für die laufende Nummer des Artikels + QRegularExpressionValidator _valPrice; /// Validator für die Preisangabe + +}; + +#endif // MCCEDITVIEW_H diff --git a/miniCashConnect/mcceditview.ui b/miniCashConnect/mcceditview.ui new file mode 100644 index 0000000..64b433a --- /dev/null +++ b/miniCashConnect/mcceditview.ui @@ -0,0 +1,147 @@ + + + MCCEditView + + + + 0 + 0 + 1054 + 605 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Lucida Sans Typewriter + true + + + + + + + + + 0 + 32 + + + + + 16777215 + 32 + + + + background: lightGray + + + + + 625 + 2 + 86 + 29 + + + + + 9 + true + + + + <html><head/><body><p>Suchbegriff:</p></body></html> + + + Qt::AutoText + + + + + + 920 + 2 + 93 + 29 + + + + + 0 + 0 + + + + + 9 + true + + + + Kassendatei durchsuchen + + + Suchen + + + + :/myresource/images/package_editors.png:/myresource/images/package_editors.png + + + + 16 + 16 + + + + + + + 718 + 4 + 195 + 26 + + + + + 9 + + + + background: white + + + + + + + + + MCTreeView + QTreeView +
    mctreeview.h
    +
    +
    + + +
    diff --git a/miniCashConnect/mcconnectmainwindow.cpp b/miniCashConnect/mcconnectmainwindow.cpp new file mode 100644 index 0000000..5b09e59 --- /dev/null +++ b/miniCashConnect/mcconnectmainwindow.cpp @@ -0,0 +1,384 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * @brief MCConnectMainWindow::MCConnectMainWindow + * @param parent + */ + +MCConnectMainWindow::MCConnectMainWindow( QWidget* parent ) + : MCMainWindowBase{ parent } + +{ + + setupUi( this ); + + /// kommt aus der miniCash library + setupDefaults(); + + _billingView->setupDefaults( _dataFileName, &_mainSettings ); + /// das ist ein hack, der der Oberklasse 'MCMainwindowbase' den Zugriff ermöglicht. + _inputViewProxy = _inputView; + _inputView->setupDefaults( this, &_salesModel ); + _editView->setupDefaults( this ); + + statusBar()->setFont( QFont( "Arial", 8 ) ); + statusBar()->showMessage( QString( miniCash::copyConnect ) + miniCash::versionConnect ); + + //_helpViewer = new MCHelpViewer(); + //_helpViewer->load( "file:///C:/HandbuchMiniCash.html" ); + + /// actions + connect( _actionSetup, SIGNAL( triggered() ), this, SLOT( onSetup() ) ); + connect( _actionSetupNetwork, SIGNAL( triggered() ), this, SLOT( onShowNetworkDialog() ) ); + connect( _actionInputTransactions, SIGNAL( triggered() ), this, SLOT( onInputTransactions() ) ); + connect( _actionViewTransactions, SIGNAL( triggered() ), this, SLOT( onViewTransactions() ) ); + connect( _actionEditTransactions, SIGNAL( triggered() ), this, SLOT( onEditTransactions() ) ); + connect( _actionCopySaleData, SIGNAL( triggered() ), this, SLOT( onCopyTransactions() ) ); + connect( _actionStartBilling, SIGNAL( triggered() ), this, SLOT( onStartBilling() ) ); + connect( _actionExit, SIGNAL( triggered() ), this, SLOT( onExit() ) ); + connect( _actionExitConfirmed, SIGNAL( triggered() ), this, SLOT( onExitConfirmed() ) ); + connect( _actionHelpAbout, SIGNAL( triggered() ), this, SLOT( onHelpAbout() ) ); + connect( _actionHelpContents, SIGNAL( triggered() ), this, SLOT( onHelpManual() ) ); + + + /// senden & empfangen sind asynchron, also schieben wir die in + /// eigenen Threads + _tcpSender.moveToThread( &_senderThread ); + _tcpReceiver.moveToThread( &_receiverThread ); + + //connect( this, SIGNAL( stopNetwork() ), &_tcpSender, SLOT( onDiscardConnection() ) ); + //connect( this, SIGNAL( stopNetwork() ), &_tcpReceiver, SLOT( onDiscardConnection() ) ); + + connect( this, SIGNAL( startNetwork() ), &_tcpSender, SLOT( onCreateConnection() ) ); + connect( this, SIGNAL( startNetwork() ), &_tcpReceiver, SLOT( onCreateConnection() ) ); + + qRegisterMetaType("miniCash::CState"); + qRegisterMetaType("QAbstractSocket::SocketError"); + + connect( &_tcpSender, SIGNAL( connectionChanged(miniCash::CState) ), this, SLOT( onStateChanged(miniCash::CState) ) ); + connect( &_tcpReceiver, SIGNAL( connectionChanged(miniCash::CState) ), this, SLOT( onStateChanged(miniCash::CState) ) ); + + /// das SIG transactionCreated() stammt aus der Basisklass MCMainWindowBase, nette Möglichkleit, eine + /// abstrakte Methode 'sendTransaction() = 0' zu ersetzen. + connect( this, SIGNAL( transactionCreated(QString) ), &_tcpSender, SLOT( onSendTransaction(QString) ) ); + connect( &_tcpReceiver, SIGNAL( newTransaction(QString) ), this, SLOT( onTransactionReceived(QString) ) ); + + + /// catch network errors + connect( &_tcpSender, SIGNAL( errorOccurred(QAbstractSocket::SocketError) ), this, SLOT( onConnectionError(QAbstractSocket::SocketError) ) ); + connect( &_tcpReceiver, SIGNAL( acceptError(QAbstractSocket::SocketError) ), this, SLOT( onConnectionError(QAbstractSocket::SocketError) ) ); + + /// erstmal die Basis ... + /// wenn wir das erste mal hier sind, defaults laden. + if( !_mainSettings.contains( miniCash::keyReceiverHost ) ) + { + _mainSettings.setValue( miniCash::keyIsTcpReceiver, miniCash::isTcpReceiver ); + _mainSettings.setValue( miniCash::keyIsTcpSender, miniCash::isTcpSender ); + _mainSettings.setValue( miniCash::keyReceiverHost, "" ); + _mainSettings.setValue( miniCash::keyReceiverPort, miniCash::receiverPort ); + } + + connect( _netWidget, SIGNAL( showNetworkDialog() ), this, SLOT( onShowNetworkDialog() ) ); + + /// gleich beim Start NetDlg zeigen? + //_isSender = _mainSettings.value( miniCash::keyIsTcpSender ).toBool(); + //_host = _mainSettings.value( miniCash::keyReceiverHost ).toString(); + //if( _isSender && _host.isEmpty() ) + + /// Ist schon Ok, den DLG immer anzuzeigen + _showDlg = true; + + _isReceiver = _mainSettings.value( miniCash::keyIsTcpReceiver ).toBool(); + + _sideBar->appendAction( _actionInputTransactions ); + if( _isReceiver ) + _sideBar->appendAction( _actionViewTransactions ); + _sideBar->appendAction( _actionEditTransactions ); + _sideBar->appendAction( _actionStartBilling ); + _sideBar->setCheckedAction( _actionInputTransactions ); + +} + + +/** + * @brief Destruktor + */ + +MCConnectMainWindow::~MCConnectMainWindow() +{ + _senderThread.exit(); + _receiverThread.exit(); + + if( !_senderThread.wait( 3000 ) ) //Wait until it actually has terminated (max. 3 sec) + { + _senderThread.terminate(); //Thread didn't exit in time, probably deadlocked, terminate it! + _senderThread.wait(); //We have to wait again here! + } + if( !_receiverThread.wait( 3000 ) ) //Wait until it actually has terminated (max. 3 sec) + { + _receiverThread.terminate(); //Thread didn't exit in time, probably deadlocked, terminate it! + _receiverThread.wait(); //We have to wait again here! + } + + +} + + +/** + * @brief Überschreibt 'QMainWindow::showEvent', um ggf. einen NetworkSetup Dialog + * einzuschmuggleln. + * @param event + */ + +void MCConnectMainWindow::showEvent( QShowEvent* event ) +{ + + /// 'onShowNetworkDialog' gehört eigentlich in den Konstruktor (falls der Hostname nicht gesetzt ist, + /// wenn aber dort der NetworkSetup-Dialog aufgerufen wird, dann erscheint dieser _vor_ dem + /// Hauptfenster. Um das zu vermeiden, schmuggeln wir das per 'showEvent' ein. + + QMainWindow::showEvent( event ); + + /// guard: der DLG soll nur einmal beim Start erscheinen + if( !_showDlg ) + return; + + /// Call slot via queued connection so it's called from the UI thread after this method has returned and the window has been shown + QMetaObject::invokeMethod( this, &MCConnectMainWindow::onShowNetworkDialog, Qt::ConnectionType::QueuedConnection ); + _showDlg = false; + +} + + + + +void MCConnectMainWindow::onStateChanged( miniCash::CState state ) +{ + /// Serverstate schlägt Clientstate, ist deswege numerisch höher, + /// Errorstates werden woanders gesetzt + if( state > _netWidget->connectionState() ) + _netWidget->setConnectionState( state ); +} + + +/** + * @brief setup dialog anzeigen + * + * Maske mit den Programmeinstellungen anzeigen: Ziellaufwerk etc. + * + */ + +void MCConnectMainWindow::onSetup() +{ + MCSetupDialog( this, &_mainSettings ).exec(); + /// alles kann geändert worden sein -> also nochmal los + setupDefaults(); +} + + +void MCConnectMainWindow::onShowNetworkDialog() +{ + + int result = MCNetworkDialog( this, &_mainSettings ).exec(); + if( QDialog::Rejected == result ) + return; + + setupNetwork(); + +} + + +/** + * @brief Netzwerksettings initialisieren + * + * Wird direkt beim Programmstart aufgerufen, setzt die Vorgabewerte + * fürs Networking. Das ist eine Ergänzung zu @see setupDefaults in der Basisklasse. + */ + +void MCConnectMainWindow::setupNetwork() +{ + + //emit stopNetwork(); + + _isSender = _mainSettings.value( miniCash::keyIsTcpSender ).toBool(); + _isReceiver = _mainSettings.value( miniCash::keyIsTcpReceiver ).toBool(); + _host = _mainSettings.value( miniCash::keyReceiverHost ).toString(); + _port = _mainSettings.value( miniCash::keyReceiverPort ).toInt(); + + bool useNetwork = _isSender || _isReceiver; + + /// gar kein Netz? + if( !useNetwork ) + return _netWidget->setConnectionState( miniCash::Disabled ); + + /* + /// ... und nochmal Prüfen: Host, default ist ja leer + if( _host.isEmpty() ) + { + int result = MCNetworkDialog( this, &_mainSettings ).exec(); + if( QDialog::Rejected == result ) + return; + } + */ + + /// Netz wird verwendet, verrbinden ... + _netWidget->setConnectionState( miniCash::UnConnected ); + + /// bin ich Server, also Empfänger + if( _isReceiver ) + { + /// (Re-)init server + _tcpReceiver.setupConnection( _port ); + if( !_receiverThread.isRunning() ) + _receiverThread.start(); + } + + /// bin ich Client, also Sender? + if( _isSender ) + { + _tcpSender.setupConnection( _host, _port ); + if( !_senderThread.isRunning() ) + _senderThread.start(); + } + + emit startNetwork(); + +} + + + +void MCConnectMainWindow::onConnectionError( QAbstractSocket::SocketError socketError ) +{ + + qDebug() << "socketError:" << socketError; + + switch( socketError ) + { + case QAbstractSocket::RemoteHostClosedError: + QMessageBox::information(this, "QTCPServer", "RemoteHostClosedError:"); + break; + + case QAbstractSocket::HostNotFoundError: + QMessageBox::information(this, "QTCPServer", "The host was not found. Please check the host name and port settings."); + + break; + + case QAbstractSocket::ConnectionRefusedError: + QMessageBox::information(this, "QTCPServer", "The connection was refused by the peer. Make sure QTCPServer is running, and check that the host name and port settings are correct."); + break; + + default: + QTcpSocket* socket = qobject_cast(sender()); + QMessageBox::information(this, "QTCPServer", QString("The following error occurred: %1.").arg(socket->errorString())); + break; + } + + +} + + + +/** + * @brief Eingabemaske (wieder) einblenden, in den + * Eingabemodus schalten + */ + +void MCConnectMainWindow::onInputTransactions() +{ + _contentWidget->setCurrentWidget( _inputView ); +} + + +/** + * @brief TransactionView einblenden: Eingehende Transaktionen werden angezeigt + */ + +void MCConnectMainWindow::onViewTransactions() +{ + // Anim?? + _contentWidget->setCurrentWidget( _transactionView ); +} + + +/** + * @brief Transaktionsdaten korrigieren, z.B. Zahlendreher beheben oder Stornos + * einbuchen. + */ + +void MCConnectMainWindow::onEditTransactions() +{ + + qDebug() << " -- Edit Transactions: " << _dataFilePath; + + _editView->loadTransactions( _dataFilePath ); + _contentWidget->setCurrentWidget( _editView ); + +} + + + +/** + * @brief MCConnectMainWindow::onTransactionReceived + * @param transaction: Transaktionen als String + */ + +void MCConnectMainWindow::onTransactionReceived( const QString& transaction ) +{ + _transactionView->onTransactionReceived( transaction ); +} + + +/** + * @brief In den Abrechungsmodus schalten + * + * Abrechnung starten: Dazu wird das Hauptfenster auf die Abrechungsmaske + * umgeschaltet + */ + +void MCConnectMainWindow::onStartBilling() +{ + _contentWidget->setCurrentWidget( _billingView ); +} + + +/** + * @brief Kurzinfo anzeigen + * + */ + +void MCConnectMainWindow::onHelpAbout() +{ + MCCAboutMe().exec(); +} diff --git a/miniCashConnect/mcconnectmainwindow.h b/miniCashConnect/mcconnectmainwindow.h new file mode 100644 index 0000000..e0ec6c6 --- /dev/null +++ b/miniCashConnect/mcconnectmainwindow.h @@ -0,0 +1,89 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MCCONNECTMAINWINDOW_H +#define MCCONNECTMAINWINDOW_H + + +#include +#include +#include +#include + +#include + + +/** + * @brief MainWindow der miniCashConnect-Anwendung. + * + * Erbt von MCMainWindowBase und stellt die Implementierung der Nutzeroberfläche + * zur Verfügung. + */ + +class MCConnectMainWindow : public MCMainWindowBase, private Ui_MCConnectMainWindow +{ + + Q_OBJECT + +public: + + explicit MCConnectMainWindow( QWidget* parent = nullptr ); + virtual ~MCConnectMainWindow(); + +signals: + + //void stopNetwork(); + void startNetwork(); + +public slots: + + void onShowNetworkDialog(); + void onStateChanged( miniCash::CState state ); + void onConnectionError( QAbstractSocket::SocketError socketError ); + /// ref?? + void onTransactionReceived( const QString& transaction ); + +protected slots: + + void onSetup() override; /// Programmeinstellungen vornehmen + + void onInputTransactions(); /// Eingabemaske, hier als StackedWidget + void onViewTransactions(); /// im Server(==Receiver) Modus: ankommende Transaktionen anzeigen + void onEditTransactions() override; /// Alle Transaktionen durchsuchen und editieren + void onStartBilling() override; /// Kassieren beenden, Abrechnungsmodus starten + void onHelpAbout() override; /// Kurzinfo anzeigen + +protected: + + void showEvent( QShowEvent* event ) override; + void setupNetwork(); + + int _sentTransCount = 0; /// Anzahl der Transaktionen (== Verkäufe) die übers Netz gesendet wurden + + QString _host; + int _port; + + bool _isSender = false; + bool _isReceiver = false; + bool _showDlg = false; + + MCSender _tcpSender; + MCReceiver _tcpReceiver; + + QThread _senderThread; + QThread _receiverThread; + +}; + +#endif /// MCLOCALMAINWINDOW_H diff --git a/miniCashConnect/mcconnectmainwindow.ui b/miniCashConnect/mcconnectmainwindow.ui new file mode 100644 index 0000000..e558586 --- /dev/null +++ b/miniCashConnect/mcconnectmainwindow.ui @@ -0,0 +1,425 @@ + + + MCConnectMainWindow + + + + 0 + 0 + 1186 + 916 + + + + miniCash.connect + + + + + + + + + + 140 + 0 + + + + + 140 + 16777215 + + + + background: groove gray; + + + QFrame::WinPanel + + + QFrame::Sunken + + + + + + + + 140 + 90 + + + + + 140 + 90 + + + + background: groove gray; + + + + + + + + + + + + + + + + 7 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + 0 + 0 + 1186 + 26 + + + + + 9 + true + + + + + + 9 + false + + + + &Datei + + + + + + + + + + 9 + false + + + + &Abrechnung + + + + + + + + 9 + false + + + + &Hilfe + + + + + + + + + + + + 9 + true + + + + TopToolBarArea + + + false + + + + + + + + + + 10 + + + + + + + :/images/exit.png:/images/exit.png + + + &Speichern und Beenden + + + Speichern und Programm beenden + + + + 9 + true + + + + + + + :/images/contexthelp.png:/images/contexthelp.png + + + Handbuch anzeigen + + + + 9 + true + + + + + + + :/images/help.png:/images/help.png + + + Über miniCash + + + + 9 + true + + + + + + + :/images/_billing2.png:/images/_billing2.png + + + Abrechung + + + Abrechnung starten + + + Eingabe verlassen und Abrechnung starten + + + + 9 + true + + + + + + + :/images/_edit2.png:/images/_edit2.png + + + Kassendatei editieren + + + Verkauften Artikel suchen und ggf. stornieren + + + + 9 + true + + + + + + + :/images/stick.png:/images/stick.png + + + Daten &kopieren + + + Kopiert die Verkaufsdaten auf den Memorystick + + + Kopiert die Verkaufsdaten auf den Memorystick + + + + 9 + true + + + + + + + :/images/exit.png:/images/exit.png + + + ExitConfirmed + + + Speichern und Programm beenden + + + + + + :/images/_setup2.png:/images/_setup2.png + + + Programmeinstellungen + + + + 9 + true + + + + + + + :/images/_transactions2.png:/images/_transactions2.png + + + Verkäufe + + + Transaktionen anzeigen + + + + + + :/images/_input2.png:/images/_input2.png + + + Kasse + + + Eingabemaske der Kasse öffnen + + + + 9 + true + + + + + + + :/images/_edit2.png:/images/_edit2.png + + + Storno + + + Verkauften Artikel suchen und ggf. stornieren + + + + 9 + true + + + + + + + :/images/connect.png:/images/connect.png + + + Netzwerkeinstellungen + + + + true + + + + + + + + SWSideBar + QFrame +
    swsidebar.h
    + 1 +
    + + MCInputView + QWidget +
    mcinputview.h
    + 1 +
    + + MCBillingView + QWidget +
    mcbillingview.h
    + 1 +
    + + MCCEditView + QWidget +
    mcceditview.h
    + 1 +
    + + MCTransactionView + QWidget +
    mctransactionview.h
    + 1 +
    + + MCNetworkWidget + QFrame +
    mcnetworkwidget.h
    + 1 +
    +
    + + + + +
    diff --git a/miniCashConnect/miniCashConnect.h b/miniCashConnect/miniCashConnect.h new file mode 100644 index 0000000..da4544f --- /dev/null +++ b/miniCashConnect/miniCashConnect.h @@ -0,0 +1,67 @@ +/*************************************************************************** + + miniCashConnect + Copyright © 2022 christoph holzheuer + c.holzheuer@sourceworx.org + + 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 3 of the License, or + (at your option) any later version. + +***************************************************************************/ + + +#ifndef MINICASHCONNECT_H +#define MINICASHCONNECT_H + + +#include + +/** + +@mainpage miniCashConnect + +@section xxx das Kassensystem 'miniCashConnect' + +'miniCashConnect' ist ein semi-verteiltes Kassen- und Abrechnungssystem für den KinderKleiderMarkt +in Kist. Beim Kister Kleidermarkt können Kindersachen günstig verkauft und erworben, sozusagen +weitergereicht werden. +so + +... + +@warning ein zwei warning + +@note ein zwei note + +@bug ein zwei bug + +@deprecated ein zwei deprecated + +@todo eins zwei todo + +@remark eins zwei remark + +*/ + + + +/** + * @brief der namespace miniCash enthält Definitionen und Konstanten. + */ + +namespace miniCash +{ + + /// basics + [[maybe_unused]] constexpr static const char* appName = "miniCash.connect"; + + + /// misc + [[maybe_unused]] constexpr static const char* versionConnect = "Version 0.0.40, 14.07.2022"; + [[maybe_unused]] constexpr static const char* copyConnect = "miniCashConnect, © 2022\nc.holzheuer@sourceworx.org "; + +} + +#endif // MINICASHCONNECT_H diff --git a/miniCashConnect/miniCashConnect.pro b/miniCashConnect/miniCashConnect.pro new file mode 100644 index 0000000..626cec3 --- /dev/null +++ b/miniCashConnect/miniCashConnect.pro @@ -0,0 +1,60 @@ +QT += printsupport core gui network widgets + +CONFIG += c++17 + +TEMPLATE = app +TARGET = miniCashConnect + +DESTDIR = $$OUT_PWD/../common + +INCLUDEPATH += $$PWD/../libMiniCash + +DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + main.cpp \ + mccaboutme.cpp \ + mcceditview.cpp \ + mcconnectmainwindow.cpp \ + + +HEADERS += \ + miniCashConnect.h \ + mccaboutme.h \ + mcceditview.h \ + mcconnectmainwindow.h \ + +FORMS += \ + mccaboutme.ui \ + mcceditview.ui \ + mcconnectmainwindow.ui + +RESOURCES += \ + miniCashConnect.qrc + + +DEPENDPATH += $$PWD/../libMiniCash + +LIBS += -L$$OUT_PWD/../common -llibMiniCash + +#SRC_DIR = $$OUT_PWD/../libMiniCash/debug +#DEST_DIR = $$OUT_PWD/debug + +#QMAKE_PRE_LINK += $$QMAKE_COPY_FILE $$shell_path($$SRC_DIR/libMiniCash.dll) $$shell_path($$DEST_DIR) +#QMAKE_POST_LINK += $$QMAKE_COPY_FILE $$shell_path($$SRC_DIR/libMiniCash.dll) $$shell_path($$DEST_DIR) + + +#DEPENDPATH += . ../libMiniCash + +#linux { +# TARGET = miniCash +# INCLUDEPATH += ../libMiniCash +# LIBS += -L../libMiniCash /usr/lib -lMiniCash +# TARGET = miniCashConnect +#} + +#windows { +# INCLUDEPATH += ../libMiniCash +# LIBS += -L../../../libMiniCash/build/Desktop_Qt_6_9_0_MinGW_64_bit-Debug/debug -lMiniCash +#} + diff --git a/miniCashConnect/miniCashConnect.qrc b/miniCashConnect/miniCashConnect.qrc new file mode 100644 index 0000000..d47ebff --- /dev/null +++ b/miniCashConnect/miniCashConnect.qrc @@ -0,0 +1,26 @@ + + + images/help.png + images/contexthelp.png + images/exit.png + images/filesave.png + images/filesaveas.png + images/findf.png + images/folder_new.png + images/stick.png + images/button_ok.png + templates/tplFinal.html + templates/tplPayoff.html + templates/tplReceipt.html + images/miniCashConnect.png + images/_billing2.png + images/_edit2.png + images/_input2.png + images/_transactions2.png + images/_setup2.png + images/_network2.png + images/connect.png + images/disconnect.png + images/_server.png + + diff --git a/miniCashConnect/miniCashConnect_en_DE.ts b/miniCashConnect/miniCashConnect_en_DE.ts new file mode 100644 index 0000000..1e97bc2 --- /dev/null +++ b/miniCashConnect/miniCashConnect_en_DE.ts @@ -0,0 +1,3 @@ + + + diff --git a/miniCashConnect/templates/tplFinal.html b/miniCashConnect/templates/tplFinal.html new file mode 100644 index 0000000..b9ae970 --- /dev/null +++ b/miniCashConnect/templates/tplFinal.html @@ -0,0 +1,52 @@ + + + + + Quittungsdruck + + + +
    +
    +

    Kleidermarkt Kindergarten Kist

    +

    Datum: %0

    +
    +

    Endabrechnung

    + +------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Gesamtumsatz:%1
    Gesamtauszahlungssumme:%2
    Gewinn:%3
    Anteil Kindergarten:%4 %
    verkaufte Teile:%5
    Anzahl Kunden:%6
    Anzahl Verkäufer:%7
    +------------------------------------------------------------------------------------------------------------------------------------------------------- +
    +
    + diff --git a/miniCashConnect/templates/tplPayoff.html b/miniCashConnect/templates/tplPayoff.html new file mode 100644 index 0000000..7788ee3 --- /dev/null +++ b/miniCashConnect/templates/tplPayoff.html @@ -0,0 +1,39 @@ + + +template.html + + + +
    +
    +

    Kleidermarkt Kindergarten Kist

    +

    Datum: %0

    +

    Abrechung für Verkäufernummer: %1

    +

    Verkaufte Teile: %2   Gesamtbetrag: %3    Auszahlungsbetrag: %4

    +
    +
    + + + + + + + + + + + + + +
    Verkäufernummerlaufende NummerUmsatzAuszahlungssumme
    -------------------------------------------------------------------------------------------------------------------------------------------------------
    + + +%5 + +
    +
    +%6 +
    +
    +
    + diff --git a/miniCashConnect/templates/tplReceipt.html b/miniCashConnect/templates/tplReceipt.html new file mode 100644 index 0000000..7e8c11f --- /dev/null +++ b/miniCashConnect/templates/tplReceipt.html @@ -0,0 +1,39 @@ + + +Quittungsdruck + + + +
    + +
    +

    Kleidermarkt Kindergarten Kist

    +

    Datum: %0

    +
    +

    Quittungsliste für Kennziffer %1 bis %2:

    +
    +
    + + + + + + + + + + + + + + +%3 + +
    Verk.Nr.VerkaufspreisAuszahlungspreisDatumUnterschrift
    + ------------------------------------------------------------------------------------------------------------------------------------------------------- +
    + +
    +
    + +