first re-commit.

This commit is contained in:
2025-08-05 22:37:51 +02:00
commit 5295a82aa3
109 changed files with 9928 additions and 0 deletions

11
libMiniCash/README.md Normal file
View File

@@ -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

185
libMiniCash/libMiniCash.h Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,12 @@
#ifndef LIBMINICASH_GLOBAL_H
#define LIBMINICASH_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(LIBMINICASH_LIBRARY)
#define LIBMINICASH_EXPORT Q_DECL_EXPORT
#else
#define LIBMINICASH_EXPORT Q_DECL_IMPORT
#endif
#endif // LIBMINICASH_GLOBAL_H

View File

@@ -0,0 +1,2 @@
#include "libminicash.h"

View File

@@ -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 <QMessageBox>
#include <QPainter>
#include <QtCore>
#include <QtGui>
#include <QStatusBar>
#include <QProgressBar>
#include <QRegularExpressionValidator>
#include <mcprinter.h>
#include <mcbillingview.h>
#include <mcloaddialog.h>
#include <mcmainwindowbase.h>
#include <ui_mcbillingview.h>
/**
* @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:
* <b><n>_<monat-tag-jahr>.klm</b>, also etwa: <b>1_03-13-2022.klm</b>
*
*/
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(
"<tr>"
"<td width='25%' align='left'>%0</td>"
"<td width='25%' align='center'>%1</td>"
"<td width='25%' align='right'>%2 </td>"
"<td width='25%' align='right'>%3 </td>"
"</tr>"
);
/// 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();
///<FIX>
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 &#8364; <-- 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", "<br>" );
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(
"<tr>"
"<td>%0</td>"
"<td align='center'>%1 </td>"
"<td align='center'>%2 </td>"
"<td>&nbsp;</td>"
"<td>&nbsp;</td>"
"</tr>"
"<tr><td colspan='5'>-------------------------------------------------------------------------------------------------------------------------------------------------------</td></tr>"
);
/// 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 &#8364; <-- 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.") );
}

View File

@@ -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 <QFrame>
#include <libMiniCash.h>
#include <mcsalesmodel.h>
#include <mcsalessummary.h>
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

View File

@@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCBillingView</class>
<widget class="QFrame" name="MCBillingView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>793</width>
<height>726</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="19" column="2">
<widget class="QCheckBox" name="_trSaveReceipts">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Druck in Datei</string>
</property>
</widget>
</item>
<item row="19" column="3">
<widget class="QPushButton" name="_trButtonPrintReceipts">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Quittungsliste drucken</string>
</property>
<property name="text">
<string>Quittungsliste drucken</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/myresource/images/printer2.png</normaloff>:/myresource/images/printer2.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item row="18" column="2">
<widget class="QCheckBox" name="_trSaveBills">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Druck in Datei</string>
</property>
</widget>
</item>
<item row="18" column="3">
<widget class="QPushButton" name="_trButtonPrintBills">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Alle Abrechungen Drucken</string>
</property>
<property name="text">
<string>Abrechnungen drucken</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/myresource/images/printer2.png</normaloff>:/myresource/images/printer2.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item row="15" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" rowspan="4" colspan="4">
<widget class="MCTreeView" name="_trList">
<property name="minimumSize">
<size>
<width>0</width>
<height>240</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
</widget>
</item>
<item row="9" column="0" colspan="4">
<widget class="QTextEdit" name="_trFooterText">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-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';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0">
<widget class="QLabel" name="_label2">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Fußzeilentext (optional)</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="_trButtonRead">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Einlesen der Kassendateien vom Memorystick starten&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Kassendateien einlesen</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/myresource/images/fileexport.png</normaloff>:/myresource/images/fileexport.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item row="10" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="SWDriveSelector" name="_srcDrive">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="_label1">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Quelllaufwerk (z.B. 'E:\')</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLineEdit" name="_trProfit">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="_label5">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Abrechnung Kundennumer von ... bis</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Anteil Kindergarten (%)</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="_trFrom">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>1100</string>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QLineEdit" name="_trTo">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>1399</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MCTreeView</class>
<extends>QTreeView</extends>
<header location="global">mctreeview.h</header>
</customwidget>
<customwidget>
<class>SWDriveSelector</class>
<extends>QComboBox</extends>
<header location="global">swdriveselector.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -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;
}

View File

@@ -0,0 +1,27 @@
#ifndef MCFORMWIDGET_H
#define MCFORMWIDGET_H
#include <QWidget>
#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

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCFormWidget</class>
<widget class="QWidget" name="MCFormWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>540</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCommandLinkButton" name="commandLinkButton">
<property name="text">
<string>FITZ!</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QListWidget" name="listWidget"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

274
libMiniCash/mcinputview.cpp Normal file
View File

@@ -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 <QInputDialog>
#include <QMessageBox>
#include <QShortcut>
#include <mcinputview.h>
#include <mcmainwindowbase.h>
#include <mcsalesmodel.h>
#include <ui_mcinputview.h>
/**
* 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<QWidget*>( 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() );
}

73
libMiniCash/mcinputview.h Normal file
View File

@@ -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 <QWidget>
#include <QRegularExpressionValidator>
#include <QModelIndex>
#include <libMiniCash.h>
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

380
libMiniCash/mcinputview.ui Normal file
View File

@@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCInputView</class>
<widget class="QWidget" name="MCInputView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>950</width>
<height>770</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="MCTreeView" name="_trList">
<property name="font">
<font>
<family>Lucida Sans Typewriter</family>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="6" rowspan="2">
<widget class="QPushButton" name="_trOK">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>240</width>
<height>10</height>
</size>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:600; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:9pt; font-weight:400;&quot;&gt;Hier klicken (oder F12 drücken) um einen neuen Verkaufsvorgang zu starten.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget{ background: rgb(210, 210, 200) }</string>
</property>
<property name="text">
<string>Neuer Kunde (F12)</string>
</property>
<property name="shortcut">
<string>F12</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="_trPos">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">QWidget{ background: rgb(232, 232, 232) }</string>
</property>
<property name="inputMask">
<string>99</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLineEdit" name="_trItemNo">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;Geben sie hier die zweistellige laufende Nummer des Artikels ein.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string/>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QLineEdit" name="_trPrice">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;Geben sie hier den Preis des Artikels ein.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string/>
</property>
</widget>
</item>
<item row="3" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="5">
<widget class="QLabel" name="_labelPrice">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Preis</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLineEdit" name="_trCount">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string comment="" extracomment="maa"/>
</property>
<property name="statusTip">
<string comment="klklkl" extracomment="lkllkllk"/>
</property>
<property name="whatsThis">
<string comment="jhjhj" extracomment="jhjhjhj"/>
</property>
<property name="styleSheet">
<string notr="true">QWidget{ background: rgb(232, 232, 232) }</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhDigitsOnly</set>
</property>
<property name="inputMask">
<string>9999</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="_labelPos">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Pos.</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="_labelCustomer">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Verkäufernummer</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLabel" name="_labelItemNo">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>laufende Nummer</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="_trSellerID">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;Geben sie hier die Kundennummer (1100 bis 1999) ein.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="_labelCount">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Kunde</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="6">
<widget class="QLabel" name="_trOverall">
<property name="font">
<font>
<pointsize>40</pointsize>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Gesamtpreis</string>
</property>
<property name="styleSheet">
<string notr="true"> QLabel { background-color: white }</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>0,00 €</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="_labelHint">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Hinweise:
- &lt;tab&gt; wechselt die Eingabefelder
- &lt;enter&gt; bzw. &lt;tab&gt; schließt die Eingabe ab
- Doppelklick in der Übersicht löscht den Eintrag
- F1 zur Rückgeldberechnung drücken</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MCTreeView</class>
<extends>QTreeView</extends>
<header location="global">mctreeview.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>_trSellerID</tabstop>
<tabstop>_trItemNo</tabstop>
<tabstop>_trPrice</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -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 <QMessageBox>
#include <QPushButton>
#include <mcloaddialog.h>
#include <ui_mcloaddialog.h>
/**
* @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();
}

View File

@@ -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 <QDialog>
#include <libMiniCash.h>
#include <ui_mcloaddialog.h>
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

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCLoadDialog</class>
<widget class="QDialog" name="MCLoadDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>250</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="_label1">
<property name="font">
<font>
<pointsize>10</pointsize>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>Folgende Kassendateien werden jetzt eingelesen:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="_listWidget">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QWidget{ background: rgb(232, 232, 232) }</string>
</property>
<property name="iconSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>325</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="_OkButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -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 <QtGui>
#include <QWidget>
#include <QMessageBox>
#include <QShortcut>
#include <QInputDialog>
#include <QDir>
#include <QPalette>
#include <QApplication>
#include <mcmainwindowbase.h>
#include <mcbillingview.h>
/// 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();
}

View File

@@ -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 <QMainWindow>
#include <QSettings>
#include <libMiniCash.h>
#include <mcsalesmodel.h>
#include <mcinputview.h>
/**
* @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

View File

@@ -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 <QMessageBox>
#include <QDialogButtonBox>
#include <libMiniCash.h>
#include <mcnetworkdialog.h>
#include <ui_mcnetworkdialog.h>
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();
}

View File

@@ -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 <QDialog>
#include <QtGui>
#include <QHostInfo>
#include <QMutex>
#include <libMiniCash.h>
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

View File

@@ -0,0 +1,261 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCNetworkDialog</class>
<widget class="QDialog" name="MCNetworkDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>592</width>
<height>405</height>
</rect>
</property>
<property name="windowTitle">
<string>Netzwerkeinstellungen</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QLabel" name="_label1">
<property name="geometry">
<rect>
<x>11</x>
<y>11</y>
<width>471</width>
<height>36</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Netzwerkeinstellungen</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
<widget class="Line" name="_line1">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>632</width>
<height>3</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="Line" name="_line2">
<property name="geometry">
<rect>
<x>10</x>
<y>345</y>
<width>571</width>
<height>16</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QRadioButton" name="_buttonUseUSB">
<property name="geometry">
<rect>
<x>20</x>
<y>70</y>
<width>401</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Daten nur auf USB-Stick speichern</string>
</property>
</widget>
<widget class="QRadioButton" name="_buttonUseNetwork">
<property name="geometry">
<rect>
<x>20</x>
<y>100</y>
<width>411</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Daten über Netzwerk senden</string>
</property>
</widget>
<widget class="QGroupBox" name="_groupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>571</width>
<height>211</height>
</rect>
</property>
<property name="title">
<string>Setup</string>
</property>
<widget class="QLabel" name="_label">
<property name="geometry">
<rect>
<x>30</x>
<y>102</y>
<width>141</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Servername, Port:</string>
</property>
</widget>
<widget class="QLineEdit" name="_receiverHost">
<property name="geometry">
<rect>
<x>180</x>
<y>100</y>
<width>113</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="_label4_2">
<property name="geometry">
<rect>
<x>300</x>
<y>100</y>
<width>16</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>:</string>
</property>
</widget>
<widget class="QLineEdit" name="_receiverPort">
<property name="geometry">
<rect>
<x>310</x>
<y>100</y>
<width>81</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QCheckBox" name="_isReceiver">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>521</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Dieser PC ist die Abrechnungskasse ('Server')</string>
</property>
</widget>
<widget class="QCheckBox" name="_isSender">
<property name="geometry">
<rect>
<x>10</x>
<y>70</y>
<width>221</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>diese Kasse ist Sender</string>
</property>
</widget>
<widget class="QLabel" name="_label_2">
<property name="geometry">
<rect>
<x>30</x>
<y>32</y>
<width>141</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Eigener Name:</string>
</property>
</widget>
<widget class="QLineEdit" name="_senderHost">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>180</x>
<y>30</y>
<width>113</width>
<height>26</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="_buttonTest">
<property name="geometry">
<rect>
<x>402</x>
<y>100</y>
<width>151</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Verbindung Testen</string>
</property>
</widget>
<widget class="QLabel" name="_labelTest">
<property name="geometry">
<rect>
<x>402</x>
<y>69</y>
<width>151</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<widget class="QDialogButtonBox" name="_buttonBox">
<property name="geometry">
<rect>
<x>130</x>
<y>365</y>
<width>449</width>
<height>29</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -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 <QMessageBox>
#include <QDialog>
#include <mcnetworkwidget.h>
#include <mcnetworkdialog.h>
#include <ui_mcnetworkwidget.h>
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();
*/

View File

@@ -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 <QLabel>
#include <QAction>
#include <QSettings>
#include <QIcon>
#include <libMiniCash.h>
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

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCNetworkWidget</class>
<widget class="QLabel" name="MCNetworkWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>140</width>
<height>90</height>
</rect>
</property>
<property name="windowTitle">
<string>ConnectionState</string>
</property>
<property name="styleSheet">
<string notr="true">background: groove gray;</string>
</property>
<widget class="QPushButton" name="_buttonState">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>40</x>
<y>2</y>
<width>64</width>
<height>64</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="_labelState">
<property name="geometry">
<rect>
<x>5</x>
<y>62</y>
<width>130</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color:white;</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

28
libMiniCash/mcprinter.cpp Normal file
View File

@@ -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 <mcprinter.h>
/**
* @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 );
}

37
libMiniCash/mcprinter.h Normal file
View File

@@ -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 <QPrinter>
#include <libMiniCash.h>
/**
* @brief Convenience-Klasse um einen vorkonfigurierten
* Printer zu erzeugen.
*/
class LIBMINICASH_EXPORT MCPrinter : public QPrinter
{
public:
MCPrinter();
};
#endif // MCPRINTER_H

173
libMiniCash/mcreceiver.cpp Normal file
View File

@@ -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 <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QMetaType>
#include <QSet>
#include <QTcpSocket>
#include <QDebug>
#include <libMiniCash.h>
#include <mcreceiver.h>
/**
* @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<QTcpSocket*>( 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<QTcpSocket*>(sender());
QSet<QTcpSocket*>::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();
}

66
libMiniCash/mcreceiver.h Normal file
View File

@@ -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 <QTcpServer>
#include <QWidget>
#include <libMiniCash.h>
/**
* @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<QTcpSocket*> _connections;
};
#endif // MCRECEIVER_H

67
libMiniCash/mcsalesitem.h Normal file
View File

@@ -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 <QString>
#include <libMiniCash.h>
//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

View File

@@ -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 <mcsalesitemmap.h>
#include <mcsalesmodel.h>
#include <mcsalesitemmap.h>
/**
* @brief speichert verkaufte Artikel.
*
* Speichert verkaufte Artikel pro Kunde nach der laufenden Nummer des Artikels
*/
MCSalesItemMap::MCSalesItemMap()
: QMap<QString, MCSalesItem>()
{
}
/**
* @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;
}

View File

@@ -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 <QMap>
#include <QString>
#include <libMiniCash.h>
#include <mcsalesitem.h>
/**
* @brief Speichert verkaufte Artikel.
*
* Speichert verkaufte Artikel pro Kunde nach der laufenden Nummer des Artikels.
*/
class MCSalesItemMap : public QMap<QString, MCSalesItem>
{
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

View File

@@ -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 <QtGui>
#include <QtCore>
#include <mcsalesmodel.h>
#include <mcsalesitemmap.h>
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<QStandardItem*> 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
}

View File

@@ -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 <QStandardItemModel>
#include <QTextStream>
#include <libMiniCash.h>
/**
* @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

View File

@@ -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 <QMessageBox>
#include <QDebug>
#include <QSet>
#include <mcsalessummary.h>
#include <mcsalesmodel.h>
#include <mcsalessummary.h>
/**
* @brief MCSalesSummary::MCSalesSummary: speichert die Verkaufsliste einzelner Kunden nach Kundennummer.
*/
MCSalesSummary::MCSalesSummary()
: QMap<QString, MCSalesItemMap>()
{
}
/**
* @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<QString> 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();
}
}

View File

@@ -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 <QtGui>
#include <QtCore>
#include <libMiniCash.h>
#include <mcsalesitemmap.h>
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<QString, MCSalesItemMap>
{
public:
explicit MCSalesSummary();
int appendFromFile( const QString& filename, int& customercount, MCSalesModel& model );
void dump();
};
#endif // MCSALESSUMMARY_H

126
libMiniCash/mcsender.cpp Normal file
View File

@@ -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 <QAbstractSocket>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QHostAddress>
#include <QMessageBox>
#include <QMetaType>
#include <QString>
#include <QStandardPaths>
#include <QTcpSocket>
#include <mcsender.h>
/**
* @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;
}

58
libMiniCash/mcsender.h Normal file
View File

@@ -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 <QTcpSocket>
#include <QObject>
#include <libMiniCash.h>
/**
* @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

View File

@@ -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 <QMessageBox>
#include <QPushButton>
#include <QFileDialog>
#include <QFileInfo>
#include <QStandardPaths>
#include <libMiniCash.h>
#include <mcsetupdialog.h>
#include <mcvendorsdialog.h>
#include <ui_mcsetupdialog.h>
/**
* @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();
}

View File

@@ -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 <QDialog>
#include <QSettings>
#include <libMiniCash.h>
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

View File

@@ -0,0 +1,364 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCSetupDialog</class>
<widget class="QDialog" name="MCSetupDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>650</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>miniCash Setup</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="2">
<widget class="QDialogButtonBox" name="_buttonBox">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2" colspan="3">
<widget class="Line" name="_line1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="_label1">
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Einstellungen</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="Line" name="_line2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QTabWidget" name="_tabWidget">
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab1">
<attribute name="title">
<string>diese Kasse</string>
</attribute>
<widget class="QSpinBox" name="_selfID">
<property name="geometry">
<rect>
<x>340</x>
<y>20</y>
<width>51</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="_label1B">
<property name="geometry">
<rect>
<x>11</x>
<y>21</y>
<width>77</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>KassenNr.</string>
</property>
</widget>
<widget class="SWDriveSelector" name="_driveMobile">
<property name="geometry">
<rect>
<x>340</x>
<y>60</y>
<width>51</width>
<height>24</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QLabel" name="_label2">
<property name="geometry">
<rect>
<x>10</x>
<y>60</y>
<width>321</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Laufwerk zum Datentransport (z.B. 'F:\')</string>
</property>
</widget>
<widget class="QPushButton" name="_buttonReset">
<property name="geometry">
<rect>
<x>340</x>
<y>145</y>
<width>93</width>
<height>29</height>
</rect>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
<widget class="QLabel" name="_label4">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>321</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Alle Programm-Einstellungen zurücksetzen</string>
</property>
</widget>
<widget class="QLabel" name="_label3">
<property name="geometry">
<rect>
<x>10</x>
<y>105</y>
<width>321</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Adressdatei im CSV-Format (optional)</string>
</property>
</widget>
<widget class="QLineEdit" name="_addressFile">
<property name="geometry">
<rect>
<x>372</x>
<y>100</y>
<width>141</width>
<height>29</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="_buttonFile">
<property name="geometry">
<rect>
<x>340</x>
<y>100</y>
<width>29</width>
<height>29</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="libMiniCash.qrc">
<normaloff>:/images/open.png</normaloff>:/images/open.png</iconset>
</property>
</widget>
<widget class="QPushButton" name="_buttonViewFile">
<property name="geometry">
<rect>
<x>520</x>
<y>100</y>
<width>81</width>
<height>29</height>
</rect>
</property>
<property name="text">
<string>Anzeigen</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab2">
<attribute name="title">
<string>Abrechnung</string>
</attribute>
<widget class="QTextEdit" name="_trFooterText">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>601</width>
<height>151</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:700; font-style:normal;&quot;&gt;
&lt;p style=&quot;-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;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QLabel" name="_label5">
<property name="geometry">
<rect>
<x>10</x>
<y>70</y>
<width>182</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Fußzeilentext (optional)</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
<widget class="QSpinBox" name="_trProfit">
<property name="geometry">
<rect>
<x>210</x>
<y>21</y>
<width>46</width>
<height>24</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QLabel" name="_label7">
<property name="geometry">
<rect>
<x>12</x>
<y>21</y>
<width>186</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Anteil Kindergarten in %</string>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SWDriveSelector</class>
<extends>QComboBox</extends>
<header location="global">swdriveselector.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="libMiniCash.qrc"/>
</resources>
<connections>
<connection>
<sender>_buttonBox</sender>
<signal>accepted()</signal>
<receiver>MCSetupDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>451</y>
</hint>
<hint type="destinationlabel">
<x>295</x>
<y>241</y>
</hint>
</hints>
</connection>
<connection>
<sender>_buttonBox</sender>
<signal>rejected()</signal>
<receiver>MCSetupDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>451</y>
</hint>
<hint type="destinationlabel">
<x>295</x>
<y>241</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -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 <mctransactionview.h>
#include <ui_mctransactionview.h>
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 );
}

View File

@@ -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 <QFrame>
#include <libMiniCash.h>
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

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCTransactionView</class>
<widget class="QWidget" name="MCTransactionView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>793</width>
<height>624</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPlainTextEdit" name="_textView">
<property name="font">
<font>
<family>Roboto Mono</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -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 <QHeaderView>
#include <mctreeview.h>
/**
* @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()
{
}

45
libMiniCash/mctreeview.h Normal file
View File

@@ -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 <QTreeView>
#include <QtGui>
#include <QtCore>
#include <libMiniCash.h>
/**
* @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

View File

@@ -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 <QFile>
#include <QDebug>
#include <mcvendorsdialog.h>
#include <ui_mcvendorsdialog.h>
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<QStandardItem *> standardItemsList;
for( int idx : cols )
{
if( entries.size() > idx )
standardItemsList.append( new QStandardItem( entries[idx] ) );
}
_csvModel.insertRow( _csvModel.rowCount(), standardItemsList );
}
file.close();
}

View File

@@ -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 <QDialog>
#include <QStandardItemModel>
#include <libMiniCash.h>
#include <ui_mcvendorsdialog.h>
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

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MCVendorsDialog</class>
<widget class="QDialog" name="MCVendorsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>727</width>
<height>572</height>
</rect>
</property>
<property name="windowTitle">
<string>Verkäuferliste</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="_label1">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Verkäuferliste</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
</widget>
</item>
<item>
<widget class="Line" name="_line1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="_vendorsView"/>
</item>
<item>
<widget class="Line" name="_line2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="_buttonOk">
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Schliessen</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -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 <swdriveselector.h>
#include <QStorageInfo>
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 );
}

View File

@@ -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 <QComboBox>
#include <QEvent>
#include <QtGui>
#include <QtCore>
#include <libMiniCash.h>
/**
* @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

197
libMiniCash/swsidebar.cpp Normal file
View File

@@ -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 <QPaintEvent>
#include <QPainter>
#include <QDebug>
#include <QEvent>
#include <QStyleOption>
#include <swsidebar.h>
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;
}

69
libMiniCash/swsidebar.h Normal file
View File

@@ -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 <QWidget>
#include <QAction>
#include <QFrame>
#include <libMiniCash.h>
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