Compare commits

..

No commits in common. "master" and "v0.13.1" have entirely different histories.

78 changed files with 988 additions and 1461 deletions

View file

@ -1,38 +1,27 @@
---
Language: Cpp Language: Cpp
# BasedOnStyle: LLVM # BasedOnStyle: LLVM
AccessModifierOffset: -4 AccessModifierOffset: -2
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignArrayOfStructures: None AlignConsecutiveAssignments: false
AlignConsecutiveMacros: None AlignConsecutiveDeclarations: false
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right AlignEscapedNewlines: Right
AlignOperands: Align AlignOperands: true
AlignTrailingComments: true AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true AllowShortBlocksOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All AllowShortIfStatementsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine AlwaysBreakTemplateDeclarations: false
AttributeMacros:
- __capability
BinPackArguments: true BinPackArguments: true
BinPackParameters: true BinPackParameters: true
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterClass: true
AfterClass: false AfterControlStatement: false
AfterControlStatement: Never
AfterEnum: false AfterEnum: false
AfterFunction: false AfterFunction: false
AfterNamespace: false AfterNamespace: false
@ -42,21 +31,13 @@ BraceWrapping:
AfterExternBlock: false AfterExternBlock: false
BeforeCatch: false BeforeCatch: false
BeforeElse: false BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false IndentBraces: false
SplitEmptyFunction: true SplitEmptyFunction: true
SplitEmptyRecord: true SplitEmptyRecord: true
SplitEmptyNamespace: true SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true BreakBeforeBraces: Linux
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterFunction: true
AfterNamespace: true
BreakBeforeInheritanceComma: false BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon BreakConstructorInitializers: BeforeColon
@ -69,56 +50,35 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4 ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true FixNamespaceComments: true
ForEachMacros: ForEachMacros:
- foreach - foreach
- Q_FOREACH - Q_FOREACH
- BOOST_FOREACH - BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve IncludeBlocks: Preserve
IncludeCategories: IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2 Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)' - Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3 Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*' - Regex: '.*'
Priority: 1 Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$' IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4 IndentWidth: 4
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave JavaScriptQuotes: Leave
JavaScriptWrapImports: true JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: '' MacroBlockBegin: ''
MacroBlockEnd: '' MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2 ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2 PenaltyBreakAssignment: 2
@ -126,57 +86,24 @@ PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300 PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120 PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000 PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000 PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60 PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0 PointerAlignment: Left
PointerAlignment: Right
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true ReflowComments: true
ShortNamespaceLines: 1 SortIncludes: true
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true SortUsingDeclarations: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
SpacesInAngles: Never SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false SpacesInParentheses: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false Standard: Auto
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8 TabWidth: 8
UseCRLF: false
UseTab: Never UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

5
.gitignore vendored
View file

@ -1,4 +1 @@
build build
.vscode/ipch/*
.kdev4
.cache

7
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "subprojects/nlohmann_json"] [submodule "3rdparty/nlohmann_json"]
path = subprojects/nlohmann_json path = 3rdparty/nlohmann_json
url = https://github.com/nlohmann/json.git url = https://github.com/nlohmann/json.git
[submodule "subprojects/singleapplication"]
path = subprojects/singleapplication/singleapplication.git
url = https://github.com/itay-grudev/SingleApplication.git

3
.vscode/launch.json vendored
View file

@ -21,8 +21,7 @@
"text": "-enable-pretty-printing", "text": "-enable-pretty-printing",
"ignoreFailures": true "ignoreFailures": true
} }
], ]
"visualizerFile": "/home/brodbemn/.config/Code - OSS/User/workspaceStorage/d64ec049841ecb3d43e402bb3c167cb5/tonka3000.qtvsctools/qt.natvis.xml"
} }
] ]
} }

42
.vscode/settings.json vendored
View file

@ -65,47 +65,9 @@
"condition_variable": "cpp", "condition_variable": "cpp",
"mutex": "cpp", "mutex": "cpp",
"hash_map": "cpp", "hash_map": "cpp",
"future": "cpp", "future": "cpp"
"bit": "cpp",
"compare": "cpp",
"concepts": "cpp",
"forward_list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_set": "cpp",
"iterator": "cpp",
"memory_resource": "cpp",
"random": "cpp",
"semaphore": "cpp",
"stop_token": "cpp",
"__bit_reference": "cpp",
"__bits": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__split_buffer": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"__verbose_abort": "cpp",
"format": "cpp",
"ios": "cpp",
"locale": "cpp"
}, },
"C_Cpp.clang_format_path": "/usr/bin/clang-format", "C_Cpp.clang_format_path": "/usr/bin/clang-format",
"cmake.configureOnOpen": true, "cmake.configureOnOpen": true,
"C_Cpp.configurationWarnings": "Disabled", "C_Cpp.configurationWarnings": "Disabled"
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true,
"**/.hg/store/**": true,
".flatpak/**": true,
"_build/**": true
}
} }

View file

@ -2,4 +2,3 @@ if(NOT KIMA2_USE_EXTERNAL_JSON)
set(JSON_BuildTests OFF CACHE INTERNAL "") set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json EXCLUDE_FROM_ALL) add_subdirectory(nlohmann_json EXCLUDE_FROM_ALL)
endif() endif()
#add_subdirectory(csv-parser)

1
3rdparty/nlohmann_json vendored Submodule

@ -0,0 +1 @@
Subproject commit f1768a540a7b7c5cc30cdcd6be9e9ef91083719b

View file

@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.8)
project(kima2 VERSION 1.8.3) project(kima2 VERSION 0.13.1)
set(CMAKE_MODULE_PATH "${CMAKE_HOME_DIRECTORY}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_HOME_DIRECTORY}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
#include(InstallRequiredSystemLibraries) #include(InstallRequiredSystemLibraries)
@ -12,12 +12,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(MSVC) if(MSVC)
add_compile_options(/W4 /WX) add_compile_options(/W4 /WX)
else() else()
#add_compile_options(-Wall -Wextra -pedantic -Woverloaded-virtual -Wredundant-decls -Wshadow) add_compile_options(-Wall -Wextra -pedantic -Woverloaded-virtual -Wredundant-decls -Wshadow)
add_compile_options(-Wall -Wextra)
endif() endif()
configure_file(config.h.in ${PROJECT_BINARY_DIR}/config.h) configure_file(config.h.in ${PROJECT_BINARY_DIR}/config.h)
configure_file(de.rustysoft.kima2.metainfo.xml.in ${PROJECT_BINARY_DIR}/de.rustysoft.kima2.metainfo.xml)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@ -29,14 +27,14 @@ if(KIMA2_USE_EXTERNAL_JSON)
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
endif() endif()
add_subdirectory(subprojects) add_subdirectory(3rdparty)
add_subdirectory(src) add_subdirectory(src)
#if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES Debug) if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES Debug)
# include(CTest) include(CTest)
# enable_testing() enable_testing()
# add_subdirectory(test) add_subdirectory(test)
#endif() endif()
# CPack # CPack
@ -80,8 +78,6 @@ else(WIN32 AND NOT UNIX)
DESTINATION share/${PROJECT_NAME}) DESTINATION share/${PROJECT_NAME})
install(FILES "${CMAKE_SOURCE_DIR}/misc/kima2.svg" install(FILES "${CMAKE_SOURCE_DIR}/misc/kima2.svg"
DESTINATION share/icons/hicolor/scalable/apps) DESTINATION share/icons/hicolor/scalable/apps)
install(FILES de.rustysoft.kima2.metainfo.xml
DESTINATION share/metainfo)
endif (WIN32 AND NOT UNIX) endif (WIN32 AND NOT UNIX)
if( MINGW ) if( MINGW )
@ -90,19 +86,18 @@ if( MINGW )
set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
${MINGW_PATH}/libstdc++-6.dll ${MINGW_PATH}/libstdc++-6.dll
${MINGW_PATH}/libgcc_s_seh-1.dll ${MINGW_PATH}/libgcc_s_seh-1.dll
${MINGW_PATH}/Qt6Core.dll ${MINGW_PATH}/Qt5Core.dll
${MINGW_PATH}/Qt6Gui.dll ${MINGW_PATH}/Qt5Gui.dll
${MINGW_PATH}/Qt6Widgets.dll ${MINGW_PATH}/Qt5Widgets.dll
${MINGW_PATH}/Qt6PrintSupport.dll ${MINGW_PATH}/Qt5PrintSupport.dll
${MINGW_PATH}/Qt6Network.dll
${MINGW_PATH}/libwinpthread-1.dll ${MINGW_PATH}/libwinpthread-1.dll
${MINGW_PATH}/libsqlite3-0.dll ${MINGW_PATH}/libsqlite3-0.dll
${MINGW_PATH}/libusb-1.0.dll ${MINGW_PATH}/libusb-1.0.dll
${MINGW_PATH}/libicuuc75.dll ${MINGW_PATH}/libxlnt.dll
${MINGW_PATH}/libicuin75.dll ${MINGW_PATH}/libicuuc62.dll
${MINGW_PATH}/libicudt75.dll ${MINGW_PATH}/libicuin62.dll
${MINGW_PATH}/libicudt62.dll
${MINGW_PATH}/libpcre2-16-0.dll ${MINGW_PATH}/libpcre2-16-0.dll
${MINGW_PATH}/libpcre2-8-0.dll
${MINGW_PATH}/zlib1.dll ${MINGW_PATH}/zlib1.dll
${MINGW_PATH}/libharfbuzz-0.dll ${MINGW_PATH}/libharfbuzz-0.dll
${MINGW_PATH}/libpng16-16.dll ${MINGW_PATH}/libpng16-16.dll
@ -112,26 +107,20 @@ if( MINGW )
${MINGW_PATH}/libbz2-1.dll ${MINGW_PATH}/libbz2-1.dll
${MINGW_PATH}/libintl-8.dll ${MINGW_PATH}/libintl-8.dll
${MINGW_PATH}/libpcre-1.dll ${MINGW_PATH}/libpcre-1.dll
${MINGW_PATH}/libdouble-conversion.dll
${MINGW_PATH}/libzstd.dll
${MINGW_PATH}/libmd4c.dll
${MINGW_PATH}/libbrotlicommon.dll
${MINGW_PATH}/libbrotlidec.dll
#${MINGW_PATH}/libfmt.dll
${MINGW_PATH}/libb2-1.dll
${MINGW_PATH}/libiconv-2.dll) ${MINGW_PATH}/libiconv-2.dll)
install(FILES ${MINGW_PATH}/../share/qt6/plugins/platforms/qwindows.dll install(FILES ${MINGW_PATH}/../share/qt5/plugins/platforms/qwindows.dll
${MINGW_PATH}/../share/qt6/plugins/platforms/qminimal.dll ${MINGW_PATH}/../share/qt5/plugins/platforms/qminimal.dll
DESTINATION bin/platforms) DESTINATION bin/platforms)
#install(FILES ${MINGW_PATH}/../share/qt6/plugins/printsupport/windowsprintersupport.dll install(FILES ${MINGW_PATH}/../share/qt5/plugins/printsupport/windowsprintersupport.dll
# DESTINATION bin/printsupport) DESTINATION bin/printsupport)
install(FILES ${MINGW_PATH}/../share/qt6/translations/qtbase_de.qm install(FILES ${MINGW_PATH}/../share/qt5/translations/qtbase_de.qm
${MINGW_PATH}/../share/qt6/translations/qt_de.qm ${MINGW_PATH}/../share/qt5/translations/qt_de.qm
${MINGW_PATH}/../share/qt6/translations/qt_help_de.qm ${MINGW_PATH}/../share/qt5/translations/qt_help_de.qm
${MINGW_PATH}/../share/qt6/translations/qtmultimedia_de.qm ${MINGW_PATH}/../share/qt5/translations/qtmultimedia_de.qm
DESTINATION bin/share/qt6/translations) ${MINGW_PATH}/../share/qt5/translations/qtquick1_de.qm
install(FILES ${MINGW_PATH}/../share/qt6/plugins/styles/qmodernwindowsstyle.dll ${MINGW_PATH}/../share/qt5/translations/qtscript_de.qm
DESTINATION bin/styles) ${MINGW_PATH}/../share/qt5/translations/qtxmlpatterns_de.qm
DESTINATION bin/translations)
endif( MINGW ) endif( MINGW )
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)

View file

@ -1,4 +1,4 @@
Copyright © 2018-2024 Martin Brodbeck Copyright © 2018 Martin Brodbeck
Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der
zugehörigen Dokumentationen (die "Software") erhält, die Erlaubnis erteilt, zugehörigen Dokumentationen (die "Software") erhält, die Erlaubnis erteilt,

View file

@ -13,16 +13,19 @@ Verkaufsdaten nach dem Verkaufsende auszutauschen.
Ebenso können über einen ESC/POS-Drucker Quittungen ausgestellt werden. Ebenso können über einen ESC/POS-Drucker Quittungen ausgestellt werden.
## Installation ## Installation
Auf [rustysoft.de](https://www.rustysoft.de/software/kima2/) werden die Installationsmöglichkeiten (Flatpak, Windows-Installer) erläutert. Bitte die Hinweise dort beachten. Auf [rustysoft.de](https://www.rustysoft.de/?01_kima2) werden verschiedene Installationspakete (Arch Linux,
Ubuntu, Windows) angeboten. Bitte die Hinweise dort beachten.
## Selbst compilieren ### Selbst compilieren
KIMA2 benötigt folgende Libraries: KIMA2 benötigt folgende Libraries:
* Qt 6 * Qt5
* boost >= 1.80 * boost >= 1.62
* libusb-1.0 * libusb-1.0
* xlnt >= 1.3.0
* nlohmann-json (als 3rdparty submodule vorhanden) * nlohmann-json (als 3rdparty submodule vorhanden)
Da Features aus C++20 sowie von neueren Compilern verwendet werden, sollte als Compiler mindestens GCC 14 verwendet werden. Da Features aus C++17 verwendet werden sowie std::filesystem, sollte als Compiler mindestens
GCC 8 verwendet werden.
Die Installationsschritte unter Linux sind wie folgt: Die Installationsschritte unter Linux sind wie folgt:
``` ```
@ -34,4 +37,4 @@ sudo make install
``` ```
Unter Windows muss vorab MinGW eingerichtet werden (z. B. MSYS2). Nach der Compilierung kann mit Unter Windows muss vorab MinGW eingerichtet werden (z. B. MSYS2). Nach der Compilierung kann mit
`cpack -G NSIS` ein Installationspaket erstellt werden. `cpack -G NSIS` ein Installationspaket erstellt werden.

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>de.rustysoft.kima2</id>
<name>KIMA2</name>
<summary>A small cash point program for childrens stuff markets</summary>
<metadata_license>MIT</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<releases>
<release version="@PROJECT_VERSION@" type="stable" date="2024-01-23" />
</releases>
<description>
<p>
A small cash point program for children's stuff markets. German language only.
</p>
</description>
<launchable type="desktop-id">de.rustysoft.kima2.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://rustysoft.de/images/software/kima2/screenshot.png</image>
</screenshot>
</screenshots>
</component>

View file

@ -1,4 +0,0 @@
[Project]
CreatedFrom=CMakeLists.txt
Manager=KDevCMakeManager
Name=kima2

Binary file not shown.

Binary file not shown.

View file

@ -1,33 +0,0 @@
project('kima2', 'cpp', default_options : ['cpp_std=c++20'], version : '1.8.0')
conf_data = configuration_data()
conf_data.set('PROJECT_VERSION', '"' + meson.project_version() + '"')
configure_file(output : 'config.h',
configuration : conf_data)
configuration_inc = include_directories('.')
#csv = cmake.subproject('csv-parser')
#csv_lib = csv.dependency('csv')
nlohmann_lib = dependency('nlohmann_json', version : '>=3.5.0', required : false)
if not nlohmann_lib.found()
nlohmann_inc = include_directories('subprojects/nlohmann_json/single_include')
nlohmann_lib = declare_dependency(include_directories : nlohmann_inc)
endif
csv_inc = include_directories('subprojects/csv-parser/single_include')
csv_dep = declare_dependency(include_directories : csv_inc)
singleapp_proj = subproject('singleapplication')
singleapp_lib = singleapp_proj.get_variable('singleapp_lib')
singleapp_dep = singleapp_proj.get_variable('singleapp_dep')
subdir('src')
if build_machine.system() == 'linux'
install_data('misc/kima2.svg', install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps')
install_data('misc/kima2.desktop', install_dir : get_option('datadir') / 'applications')
install_data('manual/Benutzerhandbuch.pdf', install_dir : get_option('datadir') / 'kima2')
endif

View file

@ -1,35 +1,29 @@
# Maintainer: Martin Brodbeck <martin at brodbeck-online dot de> # Maintainer: Martin Brodbeck <martin at brodbeck-online dot de>
pkgname=kima2 pkgname=kima2
pkgver=1.7.1 pkgver=0.13.0
pkgrel=1 pkgrel=1
pkgdesc="A small cash point program for children's things markets (German only)" pkgdesc="A small cash point program for children's things markets (German only)"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
url="http://www.rustysoft.de/software/kima2" url="http://www.rustysoft.de/?01_kima2"
license=('custom') license=('custom')
depends=('glibc' 'libusb' 'qt6-base' 'sqlite3') depends=('glibc' 'libusb' 'qt5-base' 'sqlite3' 'xlnt')
makedepends=('boost>=1.62') makedepends=('boost>=1.62')
source=(git+https://git.rustysoft.de/martin/kima2) source=($pkgname-$pkgver.tar.gz)
sha256sums=('SKIP') md5sums=('')
build() { build() {
cd $pkgname if [ ! -d $pkgname/build ]; then
mkdir $pkgname/build
git checkout v$pkgver
git submodule init
git submodule update
if [ -d build ]; then
rm -rf build
fi fi
mkdir build && cd build cd $pkgname/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DKIMA2_USE_EXTERNAL_JSON=OFF .. cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$pkgdir/usr -DKIMA2_USE_EXTERNAL_JSON=ON ..
make make
} }
package() { package() {
cd $pkgname/build cd $pkgname/build
make DESTDIR="$pkgdir" install make install
cd .. cd ..
install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
} }

View file

@ -3,8 +3,8 @@ Type=Application
Name=KIMA2 Name=KIMA2
GenericName=Cash Point Program GenericName=Cash Point Program
GenericName[de]=Kassenprogramm GenericName[de]=Kassenprogramm
Comment=A small cash point program for children's stuff markets Comment=A small cash point program
Comment[de]=Ein kleines Kassenprogramm für Kindersachenmärkte Comment[de]=Ein kleines Kassenprogramm
Exec=kima2 Exec=kima2
Icon=kima2 Icon=kima2
Categories=Office; Categories=Office;

View file

@ -1,43 +0,0 @@
Name: kima2
Version: 1.6.0
Release: 1%{?dist}
Summary: A small cash point program for children's things markets
License: custom
Source0: %{name}-%{version}.tar.gz
BuildRequires: meson
BuildRequires: gcc-c++
#BuildRequires: pkgconfig(nlohmann_json)
BuildRequires: boost-date-time
BuildRequires: sqlite-devel
BuildRequires: libusb-devel
BuildRequires: qt5-qtdeclarative-devel
#BuildRequires: pkgconfig(pthreads)
%description
%prep
%autosetup
%build
%meson
%meson_build
%install
%meson_install
%check
%meson_test
%files
%{_bindir}/kima2
%{_datadir}/applications/kima2.desktop
%{_datadir}/icons/hicolor/scalable/apps/kima2.svg
%{_datadir}/kima2/Benutzerhandbuch.pdf
%changelog
* Fri Oct 11 2019 Martin Brodbeck <infor@rustysoft.de> - dev builds
-

View file

@ -1,34 +1,34 @@
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
find_package(Boost 1.78 REQUIRED) find_package(Boost 1.62 COMPONENTS date_time REQUIRED)
find_package(SQLite3 REQUIRED) find_package(SQLite3 REQUIRED)
# Because csv-parser needs threads: if (MINGW)
find_package(XLNT REQUIRED STATIC)
find_package(fmt) else (MINGW)
find_package(PkgConfig REQUIRED)
pkg_check_modules(XLNT REQUIRED xlnt>=1.3)
endif (MINGW)
set(CORE_SOURCES set(CORE_SOURCES
database.cpp database.cpp
entity.cpp entity.cpp
entityint.cpp
entityuuid.cpp
seller.cpp seller.cpp
article.cpp article.cpp
sale.cpp sale.cpp
marketplace.cpp marketplace.cpp
csvreader.cpp excelreader.cpp
jsonutil.cpp jsonutil.cpp
utils.cpp utils.cpp
) )
add_library(core STATIC ${CORE_SOURCES}) add_library(core STATIC ${CORE_SOURCES})
#target_include_directories(core PRIVATE ${PROJECT_SOURCE_DIR}/subprojects/csv-parser/single_include)
if (WIN32) if (WIN32)
target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json) target_link_libraries(core PRIVATE printer Boost::boost Boost::date_time sqlite3 nlohmann_json::nlohmann_json ${XLNT_LIBRARY})
target_link_libraries(core PRIVATE bcrypt) target_link_libraries(core PRIVATE bcrypt)
else() else()
target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json) target_link_libraries(core PRIVATE printer Boost::boost Boost::date_time sqlite3 nlohmann_json::nlohmann_json ${XLNT_LIBRARIES})
endif() endif()
target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -1,38 +1,44 @@
#include "article.h" #include "article.h"
#include "seller.h"
#include "utils.h" #include "utils.h"
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
Article::Article(int price) : m_price(price) {} // Article::Article() : Entity() {}
void Article::setArticleNo(int articleNo) { m_articleNo = articleNo; } Article::Article(int price) : price_(price) {}
void Article::setPrice(int price) { m_price = price; } // Article::Article(std::shared_ptr<Seller> sellerPtr) : Entity() { sellerPtr_ = sellerPtr; }
void Article::setDescription(const std::string &description) { m_description = description; } void Article::setArticleNo(int articleNo) { articleNo_ = articleNo; }
void Article::setSale(Sale *salePtr) { m_salePtr = salePtr; } void Article::setPrice(int price) { price_ = price; }
void Article::setSeller(Seller *sellerPtr) { m_sellerPtr = sellerPtr; } void Article::setDescription(const std::string& description) { description_ = description; }
bool Article::isSold() { return m_salePtr ? true : false; } void Article::setSale(Sale* salePtr) { salePtr_ = salePtr; }
std::string Article::getDescription() { return m_description; } void Article::setSeller(Seller* sellerPtr) { sellerPtr_ = sellerPtr; }
Seller *Article::getSeller() { return m_sellerPtr; } bool Article::isSold() { return salePtr_ ? true : false; }
Sale *Article::getSale() { return m_salePtr; }
int Article::getPrice() const { return m_price; } std::string Article::getDescription() { return description_; }
std::string Article::getPriceAsString() const { return formatCentAsEuroString(m_price); } Seller* Article::getSeller() { return sellerPtr_; }
Sale* Article::getSale() { return salePtr_; }
int Article::getArticleNo() const { return m_articleNo; } int Article::getPrice() const { return price_; }
std::string Article::getPriceAsString() const
{
return formatCentAsEuroString(price_);
}
int Article::getArticleNo() const { return articleNo_; }
std::string Article::getCompleteArticleNo() const std::string Article::getCompleteArticleNo() const
{ {
std::stringstream artNoStream; std::stringstream artNoStream;
artNoStream << m_sourceNo << "K" << std::setfill('0') << std::setw(5) << m_articleNo; artNoStream << sourceNo_ << "K" << std::setfill('0') << std::setw(5) << articleNo_;
return artNoStream.str(); return artNoStream.str();
} }

View file

@ -1,7 +1,9 @@
#ifndef ARTICLE_H #ifndef ARTICLE_H
#define ARTICLE_H #define ARTICLE_H
#include "entityuuid.h" #include "entity.h"
//#include "sale.h"
//#include "seller.h"
#include <memory> #include <memory>
#include <string> #include <string>
@ -9,35 +11,34 @@
class Seller; class Seller;
class Sale; class Sale;
class Article : public EntityUuid class Article : public Entity
{ {
public: public:
Article() = default; Article() = default;
Article(int price); Article(int price);
Article(const Article &) = delete; //virtual ~Article() = default;
virtual ~Article() = default;
void setArticleNo(int articleNo); void setArticleNo(int articleNo);
void setPrice(int price); void setPrice(int price);
void setDescription(const std::string &description); void setDescription(const std::string& description);
bool isSold(); bool isSold();
void setSale(Sale *salePtr); void setSale(Sale* salePtr);
void setSeller(Seller *sellerPtr); void setSeller(Seller* sellerPtr);
int getArticleNo() const; int getArticleNo() const;
std::string getCompleteArticleNo() const; std::string getCompleteArticleNo() const;
std::string getDescription(); std::string getDescription();
Seller *getSeller(); Seller* getSeller();
Sale *getSale(); Sale* getSale();
int getPrice() const; int getPrice() const;
std::string getPriceAsString() const; std::string getPriceAsString() const;
private: private:
Seller *m_sellerPtr{}; Seller* sellerPtr_{};
Sale *m_salePtr{}; Sale* salePtr_{};
int m_articleNo{}; int articleNo_{};
int m_price{}; int price_{};
std::string m_description{}; std::string description_{};
}; };
#endif #endif

View file

@ -1,92 +0,0 @@
#include "csvreader.h"
#include "utils.h"
#include <fstream>
// #include <csv.hpp>
#include <boost/algorithm/string.hpp>
#ifdef DELETE
#undef DELETE
#endif
namespace fs = std::filesystem;
std::size_t CsvReader::readSellersFromFile(const fs::path &filePath, Marketplace *market)
{
#if defined(_WIN64) || defined(_WIN32)
// Windows: Somhow this is necessary in order to open file names with umlauts
auto wide = filePath.wstring();
std::string fileName(wide.begin(), wide.end());
std::ifstream infile(fileName);
#else
// csv::CSVReader csvReader(filePath.string(), format);
std::ifstream infile(filePath.string());
#endif
for (auto &seller : market->getSellers()) {
seller->setState(Seller::State::DELETE);
}
market->storeToDb(true);
std::string line;
while (getline(infile, line)) {
std::vector<std::string> strs;
boost::split(strs, line, boost::is_any_of(";"));
auto seller = std::make_unique<Seller>();
try {
int sellerNo = std::stoi(strs[0]);
seller->setSellerNo(sellerNo);
} catch (std::invalid_argument const &ex) {
continue;
}
if (isNumber(strs[1]))
seller->setNumArticlesOffered(std::stoi(strs[1]));
else
seller->setNumArticlesOffered(0);
// If both, first name and last name, are empty, use N. N.
// Else, use the real values.
if (strs[2].empty() && strs[2].empty()) {
seller->setFirstName("N.");
seller->setLastName("N.");
} else {
std::string firstName = strs[2];
seller->setFirstName(trim(firstName));
std::string lastName = strs[3];
seller->setLastName(trim(lastName));
}
market->getSellers().push_back(std::move(seller));
}
// Add one additional seller "RESERVE RESERVE"
auto seller = std::make_unique<Seller>();
seller->setSellerNo(market->getNextSellerNo());
seller->setFirstName("RESERVE");
seller->setLastName("RESERVE");
market->getSellers().push_back(std::move(seller));
// If there was no special seller "Sonderkonto" in import data, then create one
auto specialSeller = market->findSellerWithSellerNo(0);
if (!specialSeller) {
auto seller = std::make_unique<Seller>();
seller->setSellerNo(0);
seller->setLastName("Sonderkonto");
seller->setFirstName("Sonderkonto");
seller->setNumArticlesOffered(0);
market->getSellers().push_back(std::move(seller));
}
market->sortSellers();
market->storeToDb();
return market->getSellers().size() - 1; // minus 1 because we don't count the "special" seller
}

View file

@ -1,19 +0,0 @@
#ifndef CSV_READER_H
#define CSV_READER_H
#include "marketplace.h"
#include "seller.h"
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
class CsvReader
{
public:
static std::size_t readSellersFromFile(const std::filesystem::path &filePath,
Marketplace *market);
};
#endif

View file

@ -1,13 +1,13 @@
#include "database.h" #include "database.h"
#include <chrono>
#include <filesystem> #include <filesystem>
#include <format>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
Database::Database(const std::string &dbname) #include "boost/date_time/posix_time/posix_time.hpp"
Database::Database(const std::string& dbname)
{ {
dbname_ = dbname; dbname_ = dbname;
init(); init();
@ -28,7 +28,7 @@ Database::Database()
if (!fs::exists(dbpath)) { if (!fs::exists(dbpath)) {
try { try {
fs::create_directories(dbpath); fs::create_directories(dbpath);
} catch (fs::filesystem_error &err) { } catch (fs::filesystem_error& err) {
throw err; throw err;
} }
} }
@ -45,11 +45,8 @@ void Database::newDb()
fs::path sourcePath = dbname_; fs::path sourcePath = dbname_;
fs::path destPath = sourcePath.parent_path() / sourcePath.stem(); fs::path destPath = sourcePath.parent_path() / sourcePath.stem();
destPath += std::string("_") +=
auto chronoTime = std::chrono::system_clock::now(); boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) += ".db";
std::string timeString = std::format("{0:%FT%H-%M-%S}", chronoTime);
destPath += std::string("_") += timeString += ".db";
fs::copy_file(sourcePath, destPath, fs::copy_options::overwrite_existing); fs::copy_file(sourcePath, destPath, fs::copy_options::overwrite_existing);
@ -60,13 +57,13 @@ void Database::newDb()
Database::~Database() { sqlite3_close(db_); } Database::~Database() { sqlite3_close(db_); }
void Database::exec(const std::string &sql) void Database::exec(const std::string& sql)
{ {
char *errMsg; char* errMsg;
const int errCode = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &errMsg); const int errCode = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &errMsg);
if (errCode) { if (errCode) {
std::string errMsgString(errMsg); // Make a C++ string of the errMsg, so that we can call std::string errMsgString(errMsg); // Make a C++ string of the errMsg, so that we can call
// sqlite3_free() before throwing the exception // sqlite3_free() before throwing the exception
sqlite3_free(errMsg); sqlite3_free(errMsg);
throw std::runtime_error("Error in SQL execution: " + errMsgString); throw std::runtime_error("Error in SQL execution: " + errMsgString);
} }
@ -78,10 +75,11 @@ void Database::createNew()
std::string sqlCreateKima2{"CREATE TABLE IF NOT EXISTS kima2 (" std::string sqlCreateKima2{"CREATE TABLE IF NOT EXISTS kima2 ("
"version INTEGER NOT NULL);" "version INTEGER NOT NULL);"
"INSERT INTO kima2 (version) VALUES (3);"}; "INSERT INTO kima2 (version) VALUES (2);"};
sqlStrings.push_back(sqlCreateKima2); sqlStrings.push_back(sqlCreateKima2);
std::string sqlCreateSellers{"CREATE TABLE IF NOT EXISTS sellers (" std::string sqlCreateSellers{"CREATE TABLE IF NOT EXISTS sellers ("
"seller_no INTEGER PRIMARY KEY NOT NULL, " "id TEXT PRIMARY KEY NOT NULL, "
"seller_no INTEGER, "
"first_name TEXT, " "first_name TEXT, "
"last_name TEXT, " "last_name TEXT, "
"num_offered_articles INTEGER, " "num_offered_articles INTEGER, "
@ -91,13 +89,13 @@ void Database::createNew()
std::string sqlCreateArticles{ std::string sqlCreateArticles{
"CREATE TABLE IF NOT EXISTS articles (" "CREATE TABLE IF NOT EXISTS articles ("
"id TEXT PRIMARY KEY NOT NULL, " "id TEXT PRIMARY KEY NOT NULL, "
"seller_no TEXT NOT NULL, " "seller_id TEXT NOT NULL, "
"source_no INTEGER NOT NULL, " "source_no INTEGER NOT NULL, "
"article_no INTEGER NOT NULL, " "article_no INTEGER NOT NULL, "
"description TEXT, " "description TEXT, "
"price INTEGER NOT NULL, " "price INTEGER NOT NULL, "
"UNIQUE (source_no, article_no), " "UNIQUE (source_no, article_no), "
"FOREIGN KEY (seller_no) REFERENCES sellers(seller_no) ON DELETE CASCADE, " "FOREIGN KEY (seller_id) REFERENCES sellers(id) ON DELETE CASCADE, "
"CHECK (article_no BETWEEN 0 AND 99999)" "CHECK (article_no BETWEEN 0 AND 99999)"
");"}; ");"};
sqlStrings.push_back(sqlCreateArticles); sqlStrings.push_back(sqlCreateArticles);
@ -117,13 +115,13 @@ void Database::createNew()
sqlStrings.push_back(sqlCreateSalesItems); sqlStrings.push_back(sqlCreateSalesItems);
std::string sqlInitialEntries{ std::string sqlInitialEntries{
"INSERT OR IGNORE INTO sellers (seller_no, first_name, last_name, " "INSERT OR IGNORE INTO sellers (id, seller_no, first_name, last_name, "
"num_offered_articles) VALUES " "num_offered_articles) VALUES "
"(0, 'Sonderkonto', 'Sonderkonto', 0)"}; "('11111111-1111-1111-1111-111111111111', 0, 'Sonderkonto', 'Sonderkonto', 0)"};
sqlStrings.push_back(sqlInitialEntries); sqlStrings.push_back(sqlInitialEntries);
beginTransaction(); beginTransaction();
for (const auto &sql : sqlStrings) { for (const auto& sql : sqlStrings) {
exec(sql); exec(sql);
} }
endTransaction(); endTransaction();
@ -132,15 +130,13 @@ void Database::createNew()
void Database::updateDbToVer2() void Database::updateDbToVer2()
{ {
beginTransaction(); beginTransaction();
exec("INSERT OR IGNORE INTO sellers (seller_no, first_name, last_name, " exec("INSERT OR IGNORE INTO sellers (id, seller_no, first_name, last_name, "
"num_offered_articles) VALUES " "num_offered_articles) VALUES "
"(0, 'Sonderkonto', 'Sonderkonto', 0)"); "('11111111-1111-1111-1111-111111111111', 0, 'Sonderkonto', 'Sonderkonto', 0)");
exec("UPDATE kima2 SET version = 3"); exec("UPDATE kima2 SET version = 2");
endTransaction(); endTransaction();
} }
void Database::updateDbToVer3() { newDb(); }
void Database::init() void Database::init()
{ {
const int errCode = sqlite3_open(dbname_.c_str(), &db_); const int errCode = sqlite3_open(dbname_.c_str(), &db_);
@ -156,19 +152,12 @@ void Database::init()
switch (version) { switch (version) {
case 0: case 0:
createNew(); createNew();
initResult_ = InitResult::OK;
break; break;
case 1: case 1:
updateDbToVer3(); updateDbToVer2();
initResult_ = InitResult::OUTDATED_REPLACED;
break;
case 2:
updateDbToVer3();
initResult_ = InitResult::OUTDATED_REPLACED;
break; break;
default: default:
// Do nothing because we are up-to-date. // Do nothing because we are up-to-date.
initResult_ = InitResult::OK;
break; break;
} }
} }
@ -176,7 +165,7 @@ void Database::init()
int Database::getVersion() int Database::getVersion()
{ {
int retCode{}; int retCode{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
// Check if there's already a kima2 table available. // Check if there's already a kima2 table available.
// If not, return version == 0. // If not, return version == 0.
@ -223,26 +212,29 @@ void Database::beginTransaction() { exec("BEGIN TRANSACTION"); }
void Database::endTransaction() { exec("END TRANSACTION"); } void Database::endTransaction() { exec("END TRANSACTION"); }
unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &sellers, bool onlyDelete) unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>>& sellers, bool onlyDelete)
{ {
int retCode{}; int retCode{};
int count{}; int count{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
beginTransaction(); beginTransaction();
for (auto &seller : sellers) { for (auto& seller : sellers) {
if (seller->getState() == Seller::State::NEW && !onlyDelete) { if (seller->getState() == Seller::State::NEW && !onlyDelete) {
retCode = sqlite3_prepare_v2( retCode = sqlite3_prepare_v2(
db_, db_,
"INSERT INTO sellers" "INSERT INTO sellers"
" (seller_no, first_name, last_name, num_offered_articles)" " (id, seller_no, first_name, last_name, num_offered_articles)"
" VALUES (:seller_no, :first_name, :last_name, :num_offered_articles)", " VALUES (:uuid, :seller_no, :first_name, :last_name, :num_offered_articles)",
-1, &stmt, nullptr); -1, &stmt, nullptr);
if (retCode != SQLITE_OK) if (retCode != SQLITE_OK)
throw std::runtime_error(sqlite3_errmsg(db_)); throw std::runtime_error(sqlite3_errmsg(db_));
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"),
boost::uuids::to_string(seller->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_no"),
seller->getSellerNo()); seller->getSellerNo());
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":first_name"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":first_name"),
@ -268,13 +260,15 @@ unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &seller
"UPDATE sellers SET" "UPDATE sellers SET"
" seller_no = :seller_no, first_name = :first_name," " seller_no = :seller_no, first_name = :first_name,"
" last_name = :last_name, num_offered_articles = :num_offered_articles" " last_name = :last_name, num_offered_articles = :num_offered_articles"
" WHERE seller_no = :id", " WHERE id = :uuid",
-1, &stmt, nullptr); -1, &stmt, nullptr);
if (retCode != SQLITE_OK) if (retCode != SQLITE_OK)
throw std::runtime_error(sqlite3_errmsg(db_)); throw std::runtime_error(sqlite3_errmsg(db_));
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":id"), seller->getId()); sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"),
boost::uuids::to_string(seller->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_no"),
seller->getSellerNo()); seller->getSellerNo());
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":first_name"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":first_name"),
@ -297,13 +291,15 @@ unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &seller
} else if (seller->getState() == Seller::State::DELETE) { } else if (seller->getState() == Seller::State::DELETE) {
count += static_cast<int>(seller->getArticles(false).size()); count += static_cast<int>(seller->getArticles(false).size());
retCode = sqlite3_prepare_v2(db_, "DELETE FROM sellers WHERE seller_no = :id", -1, retCode =
&stmt, nullptr); sqlite3_prepare_v2(db_, "DELETE FROM sellers WHERE id = :uuid", -1, &stmt, nullptr);
if (retCode != SQLITE_OK) if (retCode != SQLITE_OK)
throw std::runtime_error(sqlite3_errmsg(db_)); throw std::runtime_error(sqlite3_errmsg(db_));
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":id"), seller->getId()); sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"),
boost::uuids::to_string(seller->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
retCode = sqlite3_step(stmt); retCode = sqlite3_step(stmt);
@ -326,12 +322,12 @@ unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &seller
// Everything went fine, so we can now update our objects // Everything went fine, so we can now update our objects
sellers.erase(std::remove_if(sellers.begin(), sellers.end(), sellers.erase(std::remove_if(sellers.begin(), sellers.end(),
[](const std::unique_ptr<Seller> &seller) { [](const std::unique_ptr<Seller>& seller) {
return (seller->getState() == Seller::State::DELETE); return (seller->getState() == Seller::State::DELETE);
}), }),
sellers.end()); sellers.end());
for (auto &seller : sellers) { for (auto& seller : sellers) {
seller->cleanupArticles(); seller->cleanupArticles();
seller->setState(Seller::State::OK); seller->setState(Seller::State::OK);
} }
@ -339,18 +335,18 @@ unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &seller
return count; return count;
} }
unsigned int Database::storeArticles(std::vector<Article *> articles) unsigned int Database::storeArticles(std::vector<Article*> articles)
{ {
int retCode{}; int retCode{};
int count{}; int count{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
for (auto &article : articles) { for (auto& article : articles) {
if (article->getState() == Article::State::NEW) { if (article->getState() == Article::State::NEW) {
retCode = sqlite3_prepare_v2( retCode = sqlite3_prepare_v2(
db_, db_,
"INSERT INTO articles" "INSERT INTO articles"
" (id, seller_no, source_no, article_no, description, price)" " (id, seller_id, source_no, article_no, description, price)"
" VALUES (:uuid, :seller_id, :source_no, :article_no, :desc, :price)", " VALUES (:uuid, :seller_id, :source_no, :article_no, :desc, :price)",
-1, &stmt, nullptr); -1, &stmt, nullptr);
@ -360,8 +356,9 @@ unsigned int Database::storeArticles(std::vector<Article *> articles)
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"),
boost::uuids::to_string(article->getUuid()).c_str(), -1, boost::uuids::to_string(article->getUuid()).c_str(), -1,
SQLITE_TRANSIENT); SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
article->getSeller()->getId()); boost::uuids::to_string(article->getSeller()->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"),
article->getSourceNo()); article->getSourceNo());
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":article_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":article_no"),
@ -385,7 +382,7 @@ unsigned int Database::storeArticles(std::vector<Article *> articles)
retCode = sqlite3_prepare_v2( retCode = sqlite3_prepare_v2(
db_, db_,
"UPDATE articles SET" "UPDATE articles SET"
" seller_no = :seller_id, source_no = :source_no, article_no = :article_no," " seller_id = seller_id, source_no = :source_no, article_no = :article_no,"
" description = :desc, price = :price" " description = :desc, price = :price"
" WHERE id = :uuid", " WHERE id = :uuid",
-1, &stmt, nullptr); -1, &stmt, nullptr);
@ -396,8 +393,9 @@ unsigned int Database::storeArticles(std::vector<Article *> articles)
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":uuid"),
boost::uuids::to_string(article->getUuid()).c_str(), -1, boost::uuids::to_string(article->getUuid()).c_str(), -1,
SQLITE_TRANSIENT); SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"), sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
article->getSeller()->getId()); boost::uuids::to_string(article->getSeller()->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"),
article->getSourceNo()); article->getSourceNo());
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":article_no"), sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":article_no"),
@ -444,18 +442,18 @@ unsigned int Database::storeArticles(std::vector<Article *> articles)
return count; return count;
} }
unsigned int Database::storeSales(std::vector<std::unique_ptr<Sale>> &sales) unsigned int Database::storeSales(std::vector<std::unique_ptr<Sale>>& sales)
{ {
int retCode{}; int retCode{};
int count{}; int count{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
if (sales.size() == 0) if (sales.size() == 0)
return 0; return 0;
beginTransaction(); beginTransaction();
for (auto &sale : sales) { for (auto& sale : sales) {
if (sale->getState() == Sale::State::NEW) { if (sale->getState() == Sale::State::NEW) {
retCode = sqlite3_prepare_v2(db_, retCode = sqlite3_prepare_v2(db_,
"INSERT INTO sales" "INSERT INTO sales"
@ -485,7 +483,7 @@ unsigned int Database::storeSales(std::vector<std::unique_ptr<Sale>> &sales)
++count; ++count;
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
for (const auto &article : sale->getArticles()) { for (const auto& article : sale->getArticles()) {
retCode = sqlite3_prepare_v2(db_, retCode = sqlite3_prepare_v2(db_,
"INSERT INTO sales_items" "INSERT INTO sales_items"
" (sale_id, article_id)" " (sale_id, article_id)"
@ -538,24 +536,24 @@ unsigned int Database::storeSales(std::vector<std::unique_ptr<Sale>> &sales)
// Everything went fine, so we can now update our objects // Everything went fine, so we can now update our objects
sales.erase( sales.erase(
std::remove_if(sales.begin(), sales.end(), std::remove_if(sales.begin(), sales.end(),
[](const auto &sale) { return (sale->getState() == Sale::State::DELETE); }), [](const auto& sale) { return (sale->getState() == Sale::State::DELETE); }),
sales.end()); sales.end());
for (auto &sale : sales) { for (auto& sale : sales) {
sale->setState(Sale::State::OK); sale->setState(Sale::State::OK);
} }
return count; return count;
} }
unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers) unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>>& sellers)
{ {
int retCode{}; int retCode{};
int count{}; int count{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
retCode = sqlite3_prepare_v2(db_, retCode = sqlite3_prepare_v2(db_,
"SELECT seller_no, first_name, last_name, " "SELECT id, seller_no, first_name, last_name, "
"num_offered_articles FROM sellers ORDER BY seller_no", "num_offered_articles FROM sellers ORDER BY seller_no",
-1, &stmt, nullptr); -1, &stmt, nullptr);
if (retCode != SQLITE_OK) if (retCode != SQLITE_OK)
@ -568,10 +566,11 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
while (retCode != SQLITE_DONE) { while (retCode != SQLITE_DONE) {
++count; ++count;
auto seller = std::make_unique<Seller>(); auto seller = std::make_unique<Seller>();
seller->setSellerNo(sqlite3_column_int(stmt, 0)); seller->setUuidFromString(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
seller->setFirstName(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1))); seller->setSellerNo(sqlite3_column_int(stmt, 1));
seller->setLastName(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2))); seller->setFirstName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
seller->setNumArticlesOffered(sqlite3_column_int(stmt, 3)); seller->setLastName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
seller->setNumArticlesOffered(sqlite3_column_int(stmt, 4));
seller->setState(Seller::State::OK); seller->setState(Seller::State::OK);
sellers.push_back(std::move(seller)); sellers.push_back(std::move(seller));
@ -580,29 +579,29 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
for (auto &seller : sellers) { for (auto& seller : sellers) {
retCode = sqlite3_prepare_v2(db_, retCode = sqlite3_prepare_v2(db_,
"SELECT id, source_no, article_no, description, price" "SELECT id, source_no, article_no, description, price"
" FROM articles" " FROM articles"
" WHERE seller_no = :seller_id" " WHERE seller_id = :seller_uuid"
" ORDER BY article_no", " ORDER BY article_no",
-1, &stmt, nullptr); -1, &stmt, nullptr);
if (retCode != SQLITE_OK) if (retCode != SQLITE_OK)
throw std::runtime_error(sqlite3_errmsg(db_)); throw std::runtime_error(sqlite3_errmsg(db_));
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"), seller->getId()); sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":seller_uuid"),
boost::uuids::to_string(seller->getUuid()).c_str(), -1, SQLITE_TRANSIENT);
retCode = sqlite3_step(stmt); retCode = sqlite3_step(stmt);
while (retCode != SQLITE_DONE) { while (retCode != SQLITE_DONE) {
++count; ++count;
auto article = std::make_unique<Article>(); auto article = std::make_unique<Article>();
article->setUuidFromString( article->setUuidFromString(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
article->setSeller(seller.get()); article->setSeller(seller.get());
article->setSourceNo(sqlite3_column_int(stmt, 1)); article->setSourceNo(sqlite3_column_int(stmt, 1));
article->setArticleNo(sqlite3_column_int(stmt, 2)); article->setArticleNo(sqlite3_column_int(stmt, 2));
article->setDescription(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3))); article->setDescription(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
article->setPrice(sqlite3_column_int(stmt, 4)); article->setPrice(sqlite3_column_int(stmt, 4));
article->setState(Article::State::OK); article->setState(Article::State::OK);
@ -617,12 +616,12 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
return count; return count;
} }
unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>> &sales, unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>>& sales,
std::vector<std::unique_ptr<Seller>> &sellers) std::vector<std::unique_ptr<Seller>>& sellers)
{ {
int retCode{}; int retCode{};
int count{}; int count{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
retCode = sqlite3_prepare_v2(db_, retCode = sqlite3_prepare_v2(db_,
"SELECT id, source_no, sold_at" "SELECT id, source_no, sold_at"
@ -635,13 +634,13 @@ unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>> &sales,
sales.clear(); sales.clear();
std::map<std::string, Sale *> saleMap; std::map<std::string, Sale*> saleMap;
while (retCode != SQLITE_DONE) { while (retCode != SQLITE_DONE) {
++count; ++count;
auto sale = std::make_unique<Sale>(); auto sale = std::make_unique<Sale>();
sale->setUuidFromString(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0))); sale->setUuidFromString(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
sale->setSourceNo(sqlite3_column_int(stmt, 1)); sale->setSourceNo(sqlite3_column_int(stmt, 1));
sale->setTimestamp(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2))); sale->setTimestamp(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
sale->setState(Sale::State::OK); sale->setState(Sale::State::OK);
saleMap.insert(std::make_pair(sale->getUuidAsString(), sale.get())); saleMap.insert(std::make_pair(sale->getUuidAsString(), sale.get()));
sales.push_back(std::move(sale)); sales.push_back(std::move(sale));
@ -651,8 +650,8 @@ unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>> &sales,
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
std::map<std::string, Article *> artMap; std::map<std::string, Article*> artMap;
for (const auto &seller : sellers) { for (const auto& seller : sellers) {
for (const auto article : seller->getArticles(false)) { for (const auto article : seller->getArticles(false)) {
artMap.insert(std::make_pair(article->getUuidAsString(), article)); artMap.insert(std::make_pair(article->getUuidAsString(), article));
} }
@ -668,8 +667,8 @@ unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>> &sales,
retCode = sqlite3_step(stmt); retCode = sqlite3_step(stmt);
while (retCode != SQLITE_DONE) { while (retCode != SQLITE_DONE) {
saleMap[reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0))]->addArticle( saleMap[reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))]->addArticle(
artMap[reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1))]); artMap[reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))]);
retCode = sqlite3_step(stmt); retCode = sqlite3_step(stmt);
} }
@ -682,7 +681,7 @@ unsigned int Database::loadSales(std::vector<std::unique_ptr<Sale>> &sales,
void Database::updateCashPointNo(int oldCashPointNo, int newCashPointNo) void Database::updateCashPointNo(int oldCashPointNo, int newCashPointNo)
{ {
int retCode{}; int retCode{};
sqlite3_stmt *stmt; sqlite3_stmt* stmt;
// Check if the new no ist already in use // Check if the new no ist already in use
retCode = sqlite3_prepare_v2(db_, "SELECT COUNT() FROM articles WHERE source_no = :source_no", retCode = sqlite3_prepare_v2(db_, "SELECT COUNT() FROM articles WHERE source_no = :source_no",
@ -747,4 +746,4 @@ void Database::updateCashPointNo(int oldCashPointNo, int newCashPointNo)
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
endTransaction(); endTransaction();
} }

View file

@ -10,36 +10,32 @@
class Database class Database
{ {
public: public:
enum class InitResult { OK, OUTDATED_REPLACED }; explicit Database(const std::string& dbname);
explicit Database(const std::string &dbname);
Database(); Database();
~Database(); ~Database();
Database(const Database &) = delete; Database(const Database&) = delete;
Database &operator=(const Database &) = delete; Database& operator=(const Database&) = delete;
void exec(const std::string &sql); void exec(const std::string& sql);
unsigned int storeSellers(std::vector<std::unique_ptr<Seller>> &sellers, unsigned int storeSellers(std::vector<std::unique_ptr<Seller>>& sellers,
bool onlyDelete = false); bool onlyDelete = false);
unsigned int loadSellers(std::vector<std::unique_ptr<Seller>> &sellers); unsigned int loadSellers(std::vector<std::unique_ptr<Seller>>& sellers);
unsigned int storeSales(std::vector<std::unique_ptr<Sale>> &sales); unsigned int storeSales(std::vector<std::unique_ptr<Sale>>& sales);
unsigned int loadSales(std::vector<std::unique_ptr<Sale>> &sales, unsigned int loadSales(std::vector<std::unique_ptr<Sale>>& sales,
std::vector<std::unique_ptr<Seller>> &sellers); std::vector<std::unique_ptr<Seller>>& sellers);
void updateCashPointNo(int oldCashPointNo, int newCashPointNo); void updateCashPointNo(int oldCashPointNo, int newCashPointNo);
void newDb(); void newDb();
InitResult getInitResult() { return initResult_; }
private: private:
sqlite3 *db_{nullptr}; sqlite3* db_{nullptr};
std::string dbname_; std::string dbname_;
void init(); void init();
void beginTransaction(); void beginTransaction();
void endTransaction(); void endTransaction();
void createNew(); void createNew();
int getVersion(); int getVersion();
unsigned int storeArticles(std::vector<Article *> articles); unsigned int storeArticles(std::vector<Article*> articles);
void updateDbToVer2(); void updateDbToVer2();
void updateDbToVer3();
InitResult initResult_{InitResult::OK};
}; };
#endif // DATABASE_H #endif // DATABASE_H

View file

@ -1,3 +1,33 @@
#include "entity.h" #include "entity.h"
Entity::State Entity::getState() const { return m_state; } #include <iostream>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
Entity::~Entity() = default;
void Entity::createUuid()
{
static boost::uuids::random_generator generator{};
uuid_ = generator();
}
void Entity::setUuidFromString(const std::string& uuidString)
{
boost::uuids::string_generator generator{};
uuid_ = generator(uuidString);
}
Entity::State Entity::getState() const
{
return state_;
}
void Entity::setSourceNo(int sourceNo) {
sourceNo_ = sourceNo;
}
int Entity::getSourceNo() const {
return sourceNo_;
}

View file

@ -1,16 +1,35 @@
#ifndef ENTITY_H #ifndef ENTITY_H
#define ENTITY_H #define ENTITY_H
#include <string>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
class Entity class Entity
{ {
public: public:
enum class State { NEW, UPDATE, DELETE, OK }; enum class State { NEW, UPDATE, DELETE, OK };
virtual ~Entity() = default;
void setState(State state) { m_state = state; }
virtual State getState() const;
private: // Entity() = default;
State m_state{State::NEW}; virtual ~Entity() = 0;
void createUuid();
void setUuidFromString(const std::string& uuidString);
void setState(State state) { state_ = state; }
void setSourceNo(int sourceNo);
const boost::uuids::uuid& getUuid() const { return uuid_; };
std::string getUuidAsString() const { return boost::uuids::to_string(uuid_); }
virtual State getState() const;
virtual int getSourceNo() const;
protected:
int sourceNo_{};
private:
boost::uuids::uuid uuid_{};
State state_{State::NEW};
}; };
#endif // ENTITY_H #endif // ENTITY_H

View file

@ -1,5 +0,0 @@
#include "entityint.h"
EntityInt::EntityInt(int id) { m_id = id; }
void EntityInt::setId(int id) { m_id = id; }

View file

@ -1,19 +0,0 @@
#ifndef ENTITY_INT_H
#define ENTITY_INT_H
#include "entity.h"
class EntityInt : public Entity
{
public:
EntityInt() = default;
virtual ~EntityInt() = default;
EntityInt(int id);
void setId(int id);
int getId() const { return m_id; };
protected:
int m_id{};
};
#endif // ENTITY_INT_H

View file

@ -1,22 +0,0 @@
#include "entityuuid.h"
#include <iostream>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
void EntityUuid::createUuid()
{
static boost::uuids::random_generator generator{};
m_uuid = generator();
}
void EntityUuid::setUuidFromString(const std::string &uuidString)
{
boost::uuids::string_generator generator{};
m_uuid = generator(uuidString);
}
void EntityUuid::setSourceNo(int sourceNo) { m_sourceNo = sourceNo; }
int EntityUuid::getSourceNo() const { return m_sourceNo; }

View file

@ -1,32 +0,0 @@
#ifndef ENTITY_UUID_H
#define ENTITY_UUID_H
#include "entity.h"
#include <string>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
class EntityUuid : public Entity
{
public:
EntityUuid() = default;
virtual ~EntityUuid() = default;
void createUuid();
void setUuidFromString(const std::string &uuidString);
void setSourceNo(int sourceNo);
const boost::uuids::uuid &getUuid() const { return m_uuid; };
std::string getUuidAsString() const { return boost::uuids::to_string(m_uuid); }
virtual int getSourceNo() const;
protected:
int m_sourceNo{};
private:
boost::uuids::uuid m_uuid{};
};
#endif // ENTITY_UUID_H

63
src/core/excelreader.cpp Normal file
View file

@ -0,0 +1,63 @@
#include "excelreader.h"
#include <xlnt/xlnt.hpp>
#include <fstream>
namespace fs = std::filesystem;
void ExcelReader::readSellersFromFile(const fs::path& filePath, Marketplace* market)
{
xlnt::workbook wb;
std::ifstream mystream(filePath, std::ios::binary);
if(!mystream.is_open()) {
throw std::runtime_error("Could not open ecxel file");
}
wb.load(mystream);
for (auto& seller : market->getSellers()) {
seller->setState(Seller::State::DELETE);
}
market->storeToDb(true);
auto ws = wb.sheet_by_index(0);
const int START_ROW = 5;
const int END_ROW = 350;
int rowCount{};
for (const auto& row : ws.rows(false)) {
if (rowCount < START_ROW) {
++rowCount;
continue;
} else if (rowCount > END_ROW) {
break;
}
if (row[2].value<std::string>().empty() && row[3].value<std::string>().empty()) {
++rowCount;
continue;
}
auto seller = std::make_unique<Seller>();
seller->createUuid();
seller->setSellerNo(row[0].value<int>());
seller->setNumArticlesOffered(row[1].value<int>());
seller->setFirstName(row[2].value<std::string>());
seller->setLastName(row[3].value<std::string>());
market->getSellers().push_back(std::move(seller));
rowCount++;
}
// If there was no special seller "Sonderkonto" in import data, then create one
auto specialSeller = market->findSellerWithUuid("11111111-1111-1111-1111-111111111111");
if (!specialSeller) {
auto seller = std::make_unique<Seller>();
seller->setUuidFromString("11111111-1111-1111-1111-111111111111");
seller->setSellerNo(0);
seller->setLastName("Sonderkonto");
seller->setFirstName("Sonderkonto");
seller->setNumArticlesOffered(0);
market->getSellers().push_back(std::move(seller));
}
market->sortSellers();
market->storeToDb();
}

18
src/core/excelreader.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef EXCEL_READER_H
#define EXCEL_READER_H
#include "marketplace.h"
#include "seller.h"
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
class ExcelReader
{
public:
static void readSellersFromFile(const std::filesystem::path& filePath, Marketplace* market);
};
#endif

View file

@ -5,15 +5,17 @@
#include <fstream> #include <fstream>
namespace fs = std::filesystem;
using json = nlohmann::json; using json = nlohmann::json;
void JsonUtil::exportSellers(const std::filesystem::path &filePath, Marketplace *market) void JsonUtil::exportSellers(const std::filesystem::path& filePath, Marketplace* market)
{ {
json root; json root;
std::ofstream file(filePath); std::ofstream file(filePath);
for (const auto &seller : market->getSellers()) { for (const auto& seller : market->getSellers()) {
json newEntry; json newEntry;
newEntry["uuid"] = seller->getUuidAsString();
newEntry["seller_no"] = seller->getSellerNo(); newEntry["seller_no"] = seller->getSellerNo();
newEntry["last_name"] = seller->getLastName(); newEntry["last_name"] = seller->getLastName();
newEntry["first_name"] = seller->getFirstName(); newEntry["first_name"] = seller->getFirstName();
@ -24,9 +26,9 @@ void JsonUtil::exportSellers(const std::filesystem::path &filePath, Marketplace
file << root.dump(4) << std::endl; file << root.dump(4) << std::endl;
} }
std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marketplace *market) void JsonUtil::importSellers(const std::filesystem::path& filePath, Marketplace* market)
{ {
for (auto &seller : market->getSellers()) { for (auto& seller : market->getSellers()) {
seller->setState(Seller::State::DELETE); seller->setState(Seller::State::DELETE);
} }
market->storeToDb(true); market->storeToDb(true);
@ -36,6 +38,7 @@ std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marke
for (auto val : jsonValues["sellers"]) { for (auto val : jsonValues["sellers"]) {
auto seller = std::make_unique<Seller>(); auto seller = std::make_unique<Seller>();
seller->setUuidFromString(val["uuid"]);
seller->setSellerNo(val["seller_no"]); seller->setSellerNo(val["seller_no"]);
seller->setLastName(val["last_name"]); seller->setLastName(val["last_name"]);
seller->setFirstName(val["first_name"]); seller->setFirstName(val["first_name"]);
@ -44,9 +47,10 @@ std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marke
} }
// If there was no special seller "Sonderkonto" in import data, then create one // If there was no special seller "Sonderkonto" in import data, then create one
auto specialSeller = market->findSellerWithSellerNo(0); auto specialSeller = market->findSellerWithUuid("11111111-1111-1111-1111-111111111111");
if (!specialSeller) { if (!specialSeller) {
auto seller = std::make_unique<Seller>(); auto seller = std::make_unique<Seller>();
seller->setUuidFromString("11111111-1111-1111-1111-111111111111");
seller->setSellerNo(0); seller->setSellerNo(0);
seller->setLastName("Sonderkonto"); seller->setLastName("Sonderkonto");
seller->setFirstName("Sonderkonto"); seller->setFirstName("Sonderkonto");
@ -55,20 +59,18 @@ std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marke
} }
market->sortSellers(); market->sortSellers();
market->storeToDb();
return market->getSellers().size() - 1; // minus 1 because we don't count the "special" seller market->storeToDb();
} }
void JsonUtil::exportSales(const std::filesystem::path &filePath, Marketplace *market, void JsonUtil::exportSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo)
int cashPointNo)
{ {
json root; json root;
std::ofstream file(filePath); std::ofstream file(filePath);
root["source_no"] = cashPointNo; root["source_no"] = cashPointNo;
for (const auto &sale : market->getSales()) { for (const auto& sale : market->getSales()) {
if (sale->getSourceNo() != cashPointNo) if (sale->getSourceNo() != cashPointNo)
continue; continue;
@ -76,10 +78,10 @@ void JsonUtil::exportSales(const std::filesystem::path &filePath, Marketplace *m
newSale["uuid"] = sale->getUuidAsString(); newSale["uuid"] = sale->getUuidAsString();
newSale["timestamp"] = sale->getTimestamp(); newSale["timestamp"] = sale->getTimestamp();
for (const auto &article : sale->getArticles()) { for (const auto& article : sale->getArticles()) {
json newArticle; json newArticle;
newArticle["uuid"] = article->getUuidAsString(); newArticle["uuid"] = article->getUuidAsString();
newArticle["seller_no"] = article->getSeller()->getSellerNo(); newArticle["seller_uuid"] = article->getSeller()->getUuidAsString();
newArticle["desc"] = article->getDescription(); newArticle["desc"] = article->getDescription();
newArticle["price"] = article->getPrice(); newArticle["price"] = article->getPrice();
// newArticle["source_no"] = article->getSourceNo(); // newArticle["source_no"] = article->getSourceNo();
@ -94,36 +96,33 @@ void JsonUtil::exportSales(const std::filesystem::path &filePath, Marketplace *m
file << root.dump(4) << std::endl; file << root.dump(4) << std::endl;
} }
void JsonUtil::importSales(const std::filesystem::path &filePath, Marketplace *market, void JsonUtil::importSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo)
int cashPointNo)
{ {
std::ifstream file(filePath); std::ifstream file(filePath);
json jsonValues = json::parse(file); json jsonValues = json::parse(file);
int source_no = jsonValues["source_no"]; int source_no = jsonValues["source_no"];
if (source_no == cashPointNo) { if (source_no == cashPointNo) {
std::string ret = "Die Kassen-Nr. "; throw std::runtime_error("Die Kassen-Nr. der zu imporierenden Daten wird von dieser Kasse "
ret += std::to_string(source_no); "hier bereits verwendet.");
ret += " der zu imporierenden Daten wird von dieser Kasse hier bereits verwendet.";
throw std::runtime_error(ret);
} }
market->setSalesToDelete(jsonValues["source_no"]); market->setSalesToDelete(jsonValues["source_no"]);
market->storeToDb(); market->storeToDb();
for (const auto &valSale : jsonValues["sales"]) { for (const auto& valSale : jsonValues["sales"]) {
auto sale = std::make_unique<Sale>(); auto sale = std::make_unique<Sale>();
sale->setUuidFromString(valSale["uuid"]); sale->setUuidFromString(valSale["uuid"]);
sale->setSourceNo(jsonValues["source_no"]); sale->setSourceNo(jsonValues["source_no"]);
sale->setTimestamp(valSale["timestamp"]); sale->setTimestamp(valSale["timestamp"]);
for (const auto &valArticle : valSale["articles"]) { for (const auto& valArticle : valSale["articles"]) {
auto article = std::make_unique<Article>(); auto article = std::make_unique<Article>();
article->setUuidFromString(valArticle["uuid"]); article->setUuidFromString(valArticle["uuid"]);
article->setSourceNo(jsonValues["source_no"]); article->setSourceNo(jsonValues["source_no"]);
article->setArticleNo(valArticle["article_no"]); article->setArticleNo(valArticle["article_no"]);
article->setDescription(valArticle["desc"]); article->setDescription(valArticle["desc"]);
article->setPrice(valArticle["price"]); article->setPrice(valArticle["price"]);
auto seller = market->findSellerWithSellerNo(valArticle["seller_no"]); auto seller = market->findSellerWithUuid(valArticle["seller_uuid"]);
if (seller == nullptr) { if (seller == nullptr) {
throw std::runtime_error( throw std::runtime_error(
"Die zu importierenden Daten verweisen auf einen nicht vorhandenen Verkäufer. " "Die zu importierenden Daten verweisen auf einen nicht vorhandenen Verkäufer. "
@ -137,4 +136,4 @@ void JsonUtil::importSales(const std::filesystem::path &filePath, Marketplace *m
} }
market->storeToDb(); market->storeToDb();
} }

View file

@ -3,18 +3,16 @@
#include "marketplace.h" #include "marketplace.h"
#include <filesystem>
#include <string> #include <string>
#include <filesystem>
class JsonUtil class JsonUtil
{ {
public: public:
static void exportSellers(const std::filesystem::path &filePath, Marketplace *market); static void exportSellers(const std::filesystem::path& filePath, Marketplace* market);
static std::size_t importSellers(const std::filesystem::path &filePath, Marketplace *market); static void importSellers(const std::filesystem::path& filePath, Marketplace* market);
static void exportSales(const std::filesystem::path &filePath, Marketplace *market, static void exportSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo);
int cashPointNo); static void importSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo);
static void importSales(const std::filesystem::path &filePath, Marketplace *market,
int cashPointNo);
}; };
#endif #endif

View file

@ -3,19 +3,19 @@
#include "utils.h" #include "utils.h"
#include <algorithm> #include <algorithm>
#include <filesystem>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
Marketplace::Marketplace() Marketplace::Marketplace()
{ {
/*auto seller = std::make_unique<Seller>("Max", "Mustermann"); auto seller = std::make_unique<Seller>("Max", "Mustermann");
seller->createUuid(); seller->createUuid();
sellers_.push_back(std::move(seller)); */ sellers_.push_back(std::move(seller));
} }
void Marketplace::storeToDb(bool onlyDelete) void Marketplace::storeToDb(bool onlyDelete)
@ -25,23 +25,22 @@ void Marketplace::storeToDb(bool onlyDelete)
db.storeSales(sales_); db.storeSales(sales_);
} }
Database::InitResult Marketplace::loadFromDb() void Marketplace::loadFromDb()
{ {
Database db; Database db;
db.loadSellers(sellers_); db.loadSellers(sellers_);
db.loadSales(sales_, sellers_); db.loadSales(sales_, sellers_);
return db.getInitResult();
} }
SellersVec &Marketplace::getSellers() { return sellers_; } SellersVec& Marketplace::getSellers() { return sellers_; }
SalesVec &Marketplace::getSales() { return sales_; } SalesVec& Marketplace::getSales() { return sales_; }
int Marketplace::getNextSellerNo() int Marketplace::getNextSellerNo()
{ {
auto iter = std::max_element( auto iter = std::max_element(
sellers_.begin(), sellers_.end(), sellers_.begin(), sellers_.end(),
[](const auto &a, const auto &b) -> bool { return a->getSellerNo() < b->getSellerNo(); }); [](const auto& a, const auto& b) -> bool { return a->getSellerNo() < b->getSellerNo(); });
if (iter == sellers_.end()) if (iter == sellers_.end())
return 1; return 1;
return (*iter)->getSellerNo() + 1; return (*iter)->getSellerNo() + 1;
@ -53,14 +52,14 @@ int Marketplace::getNextArticleNo()
int maxArtNoInBasket{0}; int maxArtNoInBasket{0};
auto iter = std::max_element(sellers_.begin(), sellers_.end(), auto iter = std::max_element(sellers_.begin(), sellers_.end(),
[](const auto &a, const auto &b) -> bool { [](const auto& a, const auto& b) -> bool {
return a->getMaxArticleNo() < b->getMaxArticleNo(); return a->getMaxArticleNo() < b->getMaxArticleNo();
}); });
if (iter != sellers_.end()) if (iter != sellers_.end())
maxArtNoInDb = (*iter)->getMaxArticleNo(); maxArtNoInDb = (*iter)->getMaxArticleNo();
auto iter2 = auto iter2 =
std::max_element(basket_.begin(), basket_.end(), [](const auto &a, const auto &b) -> bool { std::max_element(basket_.begin(), basket_.end(), [](const auto& a, const auto& b) -> bool {
return a->getArticleNo() < b->getArticleNo(); return a->getArticleNo() < b->getArticleNo();
}); });
@ -73,13 +72,13 @@ int Marketplace::getNextArticleNo()
int Marketplace::getNumSellersDelete() int Marketplace::getNumSellersDelete()
{ {
int count = std::count_if(sellers_.begin(), sellers_.end(), int count = std::count_if(sellers_.begin(), sellers_.end(),
[](const auto &a) { return a->getState() == Seller::State::DELETE; }); [](const auto& a) { return a->getState() == Seller::State::DELETE; });
return count; return count;
} }
int Marketplace::getNumArticlesSold() int Marketplace::getNumArticlesSold()
{ {
int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0, [](int a, const auto &seller) { int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0, [](int a, const auto& seller) {
return a + seller->numArticlesSold(); return a + seller->numArticlesSold();
}); });
return sum; return sum;
@ -87,7 +86,7 @@ int Marketplace::getNumArticlesSold()
int Marketplace::getNumArticlesOffered() int Marketplace::getNumArticlesOffered()
{ {
int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0, [](int a, const auto &seller) { int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0, [](int a, const auto& seller) {
return a + seller->numArticlesOffered(); return a + seller->numArticlesOffered();
}); });
return sum; return sum;
@ -95,10 +94,19 @@ int Marketplace::getNumArticlesOffered()
void Marketplace::sortSellers() { std::sort(sellers_.begin(), sellers_.end()); } void Marketplace::sortSellers() { std::sort(sellers_.begin(), sellers_.end()); }
Seller *Marketplace::findSellerWithSellerNo(int sellerNo) Seller* Marketplace::findSellerWithSellerNo(int sellerNo)
{ {
auto iter = std::find_if(sellers_.begin(), sellers_.end(), auto iter = std::find_if(sellers_.begin(), sellers_.end(),
[sellerNo](const auto &a) { return a->getSellerNo() == sellerNo; }); [sellerNo](const auto& a) { return a->getSellerNo() == sellerNo; });
if (iter == sellers_.end())
return nullptr;
return (*iter).get();
}
Seller* Marketplace::findSellerWithUuid(const std::string& uuid)
{
auto iter = std::find_if(sellers_.begin(), sellers_.end(),
[uuid](const auto& a) { return a->getUuidAsString() == uuid; });
if (iter == sellers_.end()) if (iter == sellers_.end())
return nullptr; return nullptr;
return (*iter).get(); return (*iter).get();
@ -106,8 +114,7 @@ Seller *Marketplace::findSellerWithSellerNo(int sellerNo)
void Marketplace::addArticleToBasket(std::unique_ptr<Article> article) void Marketplace::addArticleToBasket(std::unique_ptr<Article> article)
{ {
basket_.insert(basket_.begin(), basket_.insert(basket_.begin(), std::move(article)); // article to the beginning of the basket vector
std::move(article)); // article to the beginning of the basket vector
} }
size_t Marketplace::basketSize() { return basket_.size(); } size_t Marketplace::basketSize() { return basket_.size(); }
@ -129,12 +136,12 @@ void Marketplace::finishCurrentSale(std::unique_ptr<Sale> sale)
storeToDb(); storeToDb();
} }
BasketVec &Marketplace::getBasket() { return basket_; } BasketVec& Marketplace::getBasket() { return basket_; }
int Marketplace::getBasketSumInCent() int Marketplace::getBasketSumInCent()
{ {
int sum = std::accumulate(basket_.begin(), basket_.end(), 0, int sum = std::accumulate(basket_.begin(), basket_.end(), 0,
[](int a, const auto &b) { return a + b->getPrice(); }); [](int a, const auto& b) { return a + b->getPrice(); });
return sum; return sum;
} }
@ -148,40 +155,39 @@ std::string Marketplace::getBasketSumAsString()
void Marketplace::removeSale(boost::uuids::uuid uuid) void Marketplace::removeSale(boost::uuids::uuid uuid)
{ {
sales_.erase(std::remove_if(sales_.begin(), sales_.end(), sales_.erase(std::remove_if(sales_.begin(), sales_.end(),
[&uuid](const auto &a) { return a->getUuid() == uuid; }), [&uuid](const auto& a) { return a->getUuid() == uuid; }),
sales_.end()); sales_.end());
} }
void Marketplace::setSalesToDelete(int cashPointNo) void Marketplace::setSalesToDelete(int cashPointNo)
{ {
std::for_each(sales_.begin(), sales_.end(), [cashPointNo](auto &sale) { std::for_each(sales_.begin(), sales_.end(), [cashPointNo](auto& sale) {
if (sale->getSourceNo() == cashPointNo) { if (sale->getSourceNo() == cashPointNo) {
sale->setState(Sale::State::DELETE); sale->setState(Sale::State::DELETE);
for (auto &article : sale->getArticles()) { for (auto& article : sale->getArticles()) {
article->setState(Article::State::DELETE); article->setState(Article::State::DELETE);
} }
} }
}); });
} }
void Marketplace::exportReportToCSV(const fs::path &filePath, int feeInPercent, int maxFeeInEuro) void Marketplace::exportReportToCSV(const fs::path& filePath, int feeInPercent, int maxFeeInEuro)
{ {
const char delimiter = ';'; const char delimiter = ',';
std::ofstream file(filePath); std::ofstream file(filePath);
file << "Verk.Nr." << delimiter << "Nachname" << delimiter << "Vorname" << delimiter file << "Verk.Nr." << delimiter << "Nachname" << delimiter << "Vorname" << delimiter
<< "Anz. gemeldet" << delimiter << "Anz. verkauft" << delimiter << "Umsatz" << delimiter << "Anz. gemeldet" << delimiter << "Anz. verkauft" << delimiter << "Umsatz" << delimiter
<< "Auszahlung\n"; << "Auszahlung\n";
for (const auto &seller : sellers_) { for (const auto& seller : sellers_) {
file << seller->getSellerNo() << delimiter file << seller->getSellerNo() << delimiter
<< escapeCsvValue(seller->getLastName(), delimiter) << delimiter << escapeCsvValue(seller->getLastName(), delimiter) << delimiter
<< escapeCsvValue(seller->getFirstName(), delimiter) << delimiter << escapeCsvValue(seller->getFirstName(), delimiter) << delimiter
<< seller->numArticlesOffered() << delimiter << seller->numArticlesSold() << delimiter << seller->numArticlesOffered() << delimiter << seller->numArticlesSold() << delimiter
<< escapeCsvValue(seller->sumAsString(), delimiter) << delimiter << escapeCsvValue(seller->sumAsString(), delimiter) << delimiter
<< escapeCsvValue( << escapeCsvValue(paymentAsString(seller->sumInCents(), feeInPercent, maxFeeInEuro * 100),
paymentAsString(seller->sumInCents(), feeInPercent, maxFeeInEuro * 100), delimiter)
delimiter)
<< "\n"; << "\n";
} }
} }
@ -189,7 +195,7 @@ void Marketplace::exportReportToCSV(const fs::path &filePath, int feeInPercent,
int Marketplace::getOverallSumInCent() int Marketplace::getOverallSumInCent()
{ {
int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0, int sum = std::accumulate(sellers_.begin(), sellers_.end(), 0,
[](int a, const auto &b) { return a + b->sumInCents(); }); [](int a, const auto& b) { return a + b->sumInCents(); });
return sum; return sum;
} }
@ -202,7 +208,7 @@ std::string Marketplace::getOverallSumAsString()
int Marketplace::getOverallPaymentInCent(int percent, int maxFee) int Marketplace::getOverallPaymentInCent(int percent, int maxFee)
{ {
int sum = std::accumulate( int sum = std::accumulate(
sellers_.begin(), sellers_.end(), 0, [percent, maxFee](int a, const auto &b) { sellers_.begin(), sellers_.end(), 0, [percent, maxFee](int a, const auto& b) {
return a + b->sumInCents() - marketFee(b->sumInCents(), percent, maxFee); return a + b->sumInCents() - marketFee(b->sumInCents(), percent, maxFee);
}); });
return sum; return sum;
@ -240,7 +246,7 @@ std::string paymentAsString(int sumInCent, int percent, int maxFeeInCent)
return formatCentAsEuroString(sumInCent - marketFee(sumInCent, percent, maxFeeInCent)); return formatCentAsEuroString(sumInCent - marketFee(sumInCent, percent, maxFeeInCent));
} }
std::string escapeCsvValue(const std::string &value, const char delimiter) std::string escapeCsvValue(const std::string& value, const char delimiter)
{ {
std::stringstream output; std::stringstream output;
bool containsDelim{false}; bool containsDelim{false};
@ -250,7 +256,7 @@ std::string escapeCsvValue(const std::string &value, const char delimiter)
output << '"'; output << '"';
} }
for (auto &symbol : value) { for (auto& symbol : value) {
if (symbol == '"') { if (symbol == '"') {
output << '"' << symbol; output << '"' << symbol;
} else { } else {
@ -283,4 +289,4 @@ void Marketplace::clear()
Database db; Database db;
db.newDb(); db.newDb();
loadFromDb(); loadFromDb();
} }

View file

@ -2,7 +2,6 @@
#define MARKETPLACE_H #define MARKETPLACE_H
#include "article.h" #include "article.h"
#include "database.h"
#include "sale.h" #include "sale.h"
#include "seller.h" #include "seller.h"
@ -20,26 +19,26 @@ using BasketVec = std::vector<std::unique_ptr<Article>>;
class Marketplace class Marketplace
{ {
public: public:
Marketplace(); Marketplace();
void storeToDb(bool onlyDelete = false); void storeToDb(bool onlyDelete = false);
Database::InitResult loadFromDb(); void loadFromDb();
SellersVec &getSellers(); SellersVec& getSellers();
SalesVec &getSales(); SalesVec& getSales();
int getNextSellerNo(); int getNextSellerNo();
int getNextArticleNo(); int getNextArticleNo();
int getNumSellersDelete(); int getNumSellersDelete();
int getNumArticlesSold(); int getNumArticlesSold();
int getNumArticlesOffered(); int getNumArticlesOffered();
BasketVec &getBasket(); BasketVec& getBasket();
int getBasketSumInCent(); int getBasketSumInCent();
std::string getBasketSumAsString(); std::string getBasketSumAsString();
void sortSellers(); void sortSellers();
Seller *findSellerWithSellerNo(int sellerNo); Seller* findSellerWithSellerNo(int sellerNo);
Seller *findSellerWithUuid(const std::string &uuid); Seller* findSellerWithUuid(const std::string& uuid);
void addArticleToBasket(std::unique_ptr<Article> article); void addArticleToBasket(std::unique_ptr<Article> article);
size_t basketSize(); size_t basketSize();
void finishCurrentSale(std::unique_ptr<Sale> sale); void finishCurrentSale(std::unique_ptr<Sale> sale);
@ -54,12 +53,12 @@ public:
void clear(); void clear();
void exportReportToCSV(const std::filesystem::path &filePath, int feeInPercent, void exportReportToCSV(const std::filesystem::path& filePath, int feeInPercent,
int maxFeeInEuro); int maxFeeInEuro);
friend class ExcelReader; friend class ExcelReader;
private: private:
SellersVec sellers_; SellersVec sellers_;
SalesVec sales_; SalesVec sales_;
BasketVec basket_; BasketVec basket_;
@ -68,6 +67,6 @@ private:
double marketFee(int sumInCent, int percent, int maxFeeInCent); double marketFee(int sumInCent, int percent, int maxFeeInCent);
std::string marketFeeAsString(int sumInCent, int percent, int maxFeeInCent); std::string marketFeeAsString(int sumInCent, int percent, int maxFeeInCent);
std::string paymentAsString(int sumInCent, int percent, int maxFeeInCent); std::string paymentAsString(int sumInCent, int percent, int maxFeeInCent);
std::string escapeCsvValue(const std::string &value, const char delimiter); std::string escapeCsvValue(const std::string& value, const char delimiter);
#endif #endif

View file

@ -1,13 +0,0 @@
boost = dependency('boost', modules: ['date_time'], static: true)
xlnt = dependency('xlnt')
sqlite = dependency('sqlite3')
src = ['database.cpp', 'entity.cpp', 'entityint.cpp', 'entityuuid.cpp',
'seller.cpp', 'article.cpp', 'sale.cpp', 'marketplace.cpp',
'excelreader.cpp', 'csvreader.cpp', 'jsonutil.cpp', 'utils.cpp']
core_inc = include_directories('..')
core_lib = static_library('core', src, dependencies: [boost, xlnt, sqlite, nlohmann_lib, csv_dep])
core_dep = declare_dependency(link_with: core_lib, include_directories : core_inc)

View file

@ -3,41 +3,43 @@
#include <numeric> #include <numeric>
void Sale::addArticle(Article *articlePtr) void Sale::addArticle(Article* articlePtr)
{ {
articlePtr->setSale(this); articlePtr->setSale(this);
m_articles.push_back(articlePtr); articles_.push_back(articlePtr);
} }
ArticlesVec &Sale::getArticles() { return m_articles; } ArticlesVec& Sale::getArticles() { return articles_; }
void Sale::removeArticle(const Article *articlePtr) void Sale::removeArticle(const Article* articlePtr)
{ {
auto it = std::find(m_articles.begin(), m_articles.end(), articlePtr); /* auto it = std::find_if(articles_.begin(), articles_.end(),
[&articlePtr](auto art) { return art.get() == articlePtr; }); */
auto it = std::find(articles_.begin(), articles_.end(), articlePtr);
if (it != m_articles.end()) { if (it != articles_.end()) {
(*it)->setSale(nullptr); (*it)->setSale(nullptr);
(*it)->setState( (*it)->setState(
Article::State::DELETE); // since we only have ad-hoc articles, that have all been sold Article::State::DELETE); // since we only have ad-hoc articles, that have all been sold
m_articles.erase(it); articles_.erase(it);
} }
} }
int Sale::sumInCents() int Sale::sumInCents()
{ {
int sum = std::accumulate(m_articles.begin(), m_articles.end(), 0, int sum = std::accumulate(articles_.begin(), articles_.end(), 0,
[](int a, const Article *b) { return a + b->getPrice(); }); [](int a, const Article* b) { return a + b->getPrice(); });
return sum; return sum;
} }
std::string Sale::sumAsString() { return formatCentAsEuroString(sumInCents()); } std::string Sale::sumAsString() { return formatCentAsEuroString(sumInCents()); }
std::string Sale::getTimestamp() const { return m_timestamp; } std::string Sale::getTimestamp() const { return timestamp_; }
void Sale::setTimestamp(const std::string &timestamp) { m_timestamp = timestamp; } void Sale::setTimestamp(const std::string& timestamp) { timestamp_ = timestamp; }
std::string Sale::getTimestampFormatted() const std::string Sale::getTimestampFormatted() const
{ {
boost::posix_time::ptime time = boost::posix_time::from_iso_extended_string(m_timestamp); boost::posix_time::ptime time = boost::posix_time::from_iso_extended_string(timestamp_);
return boost::posix_time::to_simple_string(time); return boost::posix_time::to_simple_string(time);
} }

View file

@ -11,30 +11,27 @@
namespace namespace
{ {
using ArticlesVec = std::vector<Article *>; using ArticlesVec = std::vector<Article*>;
} }
class Sale : public EntityUuid class Sale : public Entity
{ {
public: public:
Sale() = default; void addArticle(Article* articlePtr);
Sale(const Sale &) = delete; void setTimestamp(const std::string& timestamp);
virtual ~Sale() = default;
void addArticle(Article *articlePtr);
void setTimestamp(const std::string &timestamp);
ArticlesVec &getArticles(); ArticlesVec& getArticles();
std::string getTimestamp() const; std::string getTimestamp() const;
std::string getTimestampFormatted() const; std::string getTimestampFormatted() const;
int sumInCents(); int sumInCents();
std::string sumAsString(); std::string sumAsString();
void removeArticle(const Article *articlePtr); void removeArticle(const Article* articlePtr);
private: private:
std::string m_timestamp{ std::string timestamp_{
boost::posix_time::to_iso_extended_string(boost::posix_time::second_clock::local_time())}; boost::posix_time::to_iso_extended_string(boost::posix_time::second_clock::local_time())};
mutable ArticlesVec m_articles{}; mutable ArticlesVec articles_{};
}; };
#endif #endif

View file

@ -5,49 +5,50 @@
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
Seller::Seller(const std::string &firstName, const std::string &lastName, int sellerNo, Seller::Seller(const std::string& firstName, const std::string& lastName, int sellerNo,
int numArticlesOffered) int numArticlesOffered)
: EntityInt(sellerNo) : Entity()
{ {
m_firstName = firstName; firstName_ = firstName;
m_lastName = lastName; lastName_ = lastName;
m_numArticlesOffered = numArticlesOffered; sellerNo_ = sellerNo;
numArticlesOffered_ = numArticlesOffered;
} }
void Seller::setSellerNo(int seller_no) { setId(seller_no); } void Seller::setSellerNo(int seller_no) { sellerNo_ = seller_no; }
void Seller::setFirstName(const std::string &firstName) { m_firstName = firstName; } void Seller::setFirstName(const std::string& firstName) { firstName_ = firstName; }
void Seller::setLastName(const std::string &lastName) { m_lastName = lastName; } void Seller::setLastName(const std::string& lastName) { lastName_ = lastName; }
void Seller::setNumArticlesOffered(int number) { m_numArticlesOffered = number; } void Seller::setNumArticlesOffered(int number) { numArticlesOffered_ = number; }
void Seller::addArticle(std::unique_ptr<Article> article) void Seller::addArticle(std::unique_ptr<Article> article)
{ {
article->setSeller(this); article->setSeller(this);
m_articles.push_back(std::move(article)); articles_.push_back(std::move(article));
} }
std::string Seller::getFirstName() const { return m_firstName; } std::string Seller::getFirstName() const { return firstName_; }
std::string Seller::getLastName() const { return m_lastName; } std::string Seller::getLastName() const { return lastName_; }
int Seller::getSellerNo() const { return getId(); } int Seller::getSellerNo() const { return sellerNo_; }
std::string Seller::getSellerNoAsString() const std::string Seller::getSellerNoAsString() const
{ {
std::stringstream selNoStr; std::stringstream selNoStr;
selNoStr << std::setfill('0') << std::setw(3) << m_id; selNoStr << std::setfill('0') << std::setw(3) << sellerNo_;
return selNoStr.str(); return selNoStr.str();
; ;
} }
std::vector<Article *> Seller::getArticles(bool onlySold) const std::vector<Article*> Seller::getArticles(bool onlySold) const
{ {
std::vector<Article *> articles; std::vector<Article*> articles;
for (const auto &article : m_articles) { for (const auto& article : articles_) {
if (onlySold && article->isSold()) { if (onlySold && article->isSold()) {
articles.push_back(article.get()); articles.push_back(article.get());
} else if (!onlySold) { } else if (!onlySold) {
@ -57,54 +58,54 @@ std::vector<Article *> Seller::getArticles(bool onlySold) const
return articles; return articles;
} }
Article *Seller::getArticleByUuid(const std::string &uuidString) Article* Seller::getArticleByUuid(const std::string& uuidString)
{ {
auto iter = std::find_if(m_articles.begin(), m_articles.end(), [&uuidString](const auto &art) { auto iter = std::find_if(articles_.begin(), articles_.end(), [&uuidString](const auto& art) {
return art->getUuidAsString() == uuidString; return art->getUuidAsString() == uuidString;
}); });
if (iter == m_articles.end()) if (iter == articles_.end())
return nullptr; return nullptr;
return (*iter).get(); return (*iter).get();
} }
int Seller::numArticlesSold() const { return static_cast<int>(getArticles(true).size()); } int Seller::numArticlesSold() const { return static_cast<int>(getArticles(true).size()); }
int Seller::numArticlesOffered() const { return m_numArticlesOffered; } int Seller::numArticlesOffered() const { return numArticlesOffered_; }
int Seller::getMaxArticleNo() const int Seller::getMaxArticleNo() const
{ {
auto iter = std::max_element( auto iter = std::max_element(
m_articles.begin(), m_articles.end(), articles_.begin(), articles_.end(),
[](const auto &a, const auto &b) -> bool { return a->getArticleNo() < b->getArticleNo(); }); [](const auto& a, const auto& b) -> bool { return a->getArticleNo() < b->getArticleNo(); });
if (iter == m_articles.end()) if (iter == articles_.end())
return 0; return 0;
return (*iter)->getArticleNo(); return (*iter)->getArticleNo();
} }
void Seller::cleanupArticles() void Seller::cleanupArticles()
{ {
m_articles.erase(std::remove_if(m_articles.begin(), m_articles.end(), articles_.erase(std::remove_if(articles_.begin(), articles_.end(),
[](const auto &article) { [](const auto& article) {
return article->getState() == Article::State::DELETE; return article->getState() == Article::State::DELETE;
}), }),
m_articles.end()); articles_.end());
for (auto &article : m_articles) { for (auto& article : articles_) {
article->setState(Article::State::OK); article->setState(Article::State::OK);
} }
} }
int Seller::sumInCents() int Seller::sumInCents()
{ {
int sum = std::accumulate(m_articles.begin(), m_articles.end(), 0, int sum = std::accumulate(articles_.begin(), articles_.end(), 0,
[](int a, const auto &b) { return a + b->getPrice(); }); [](int a, const auto& b) { return a + b->getPrice(); });
return sum; return sum;
} }
std::string Seller::sumAsString() { return formatCentAsEuroString(sumInCents()); } std::string Seller::sumAsString() { return formatCentAsEuroString(sumInCents()); }
bool operator<(const Seller &li, const Seller &re) { return li.m_id < re.m_id; } bool operator<(const Seller& li, const Seller& re) { return li.sellerNo_ < re.sellerNo_; }
bool operator<(const std::unique_ptr<Seller> &li, const std::unique_ptr<Seller> &re) bool operator<(const std::unique_ptr<Seller>& li, const std::unique_ptr<Seller>& re)
{ {
return li->m_id < re->m_id; return li->sellerNo_ < re->sellerNo_;
} }

View file

@ -2,7 +2,7 @@
#define SELLER_H #define SELLER_H
#include "article.h" #include "article.h"
#include "entityint.h" #include "entity.h"
#include <memory> #include <memory>
#include <string> #include <string>
@ -10,18 +10,17 @@
// class Article; // class Article;
class Seller : public EntityInt class Seller : public Entity
{ {
public: public:
Seller() = default; Seller() = default;
Seller(const Seller &) = delete; // virtual ~Seller() = default;
virtual ~Seller() = default; Seller(const std::string& firstName, const std::string& lastName, int sellerNo = 0,
Seller(const std::string &firstName, const std::string &lastName, int sellerNo = 0,
int numArticlesOffered = 0); int numArticlesOffered = 0);
void setSellerNo(int sellerNo); void setSellerNo(int sellerNo);
void setFirstName(const std::string &firstName); void setFirstName(const std::string& firstName);
void setLastName(const std::string &lastName); void setLastName(const std::string& lastName);
void setNumArticlesOffered(int number); void setNumArticlesOffered(int number);
void addArticle(std::unique_ptr<Article> article); void addArticle(std::unique_ptr<Article> article);
void cleanupArticles(); void cleanupArticles();
@ -32,20 +31,22 @@ public:
std::string getSellerNoAsString() const; std::string getSellerNoAsString() const;
int numArticlesOffered() const; int numArticlesOffered() const;
int numArticlesSold() const; int numArticlesSold() const;
std::vector<Article *> getArticles(bool onlySold = true) const; // int numArticlesTotal() const;
Article *getArticleByUuid(const std::string &uuidString); std::vector<Article*> getArticles(bool onlySold = true) const;
Article* getArticleByUuid(const std::string& uuidString);
int getMaxArticleNo() const; int getMaxArticleNo() const;
int sumInCents(); int sumInCents();
std::string sumAsString(); std::string sumAsString();
friend bool operator<(const Seller &li, const Seller &re); friend bool operator<(const Seller& li, const Seller& re);
friend bool operator<(const std::unique_ptr<Seller> &li, const std::unique_ptr<Seller> &re); friend bool operator<(const std::unique_ptr<Seller>& li, const std::unique_ptr<Seller>& re);
private: private:
int m_numArticlesOffered{}; int sellerNo_{-1};
std::string m_firstName{}; int numArticlesOffered_{};
std::string m_lastName{}; std::string firstName_{};
std::vector<std::unique_ptr<Article>> m_articles{}; std::string lastName_{};
std::vector<std::unique_ptr<Article>> articles_{};
}; };
#endif #endif

View file

@ -1,70 +1,46 @@
#include "utils.h" #include "utils.h"
#include <algorithm>
#include <clocale>
#include <format>
#include <iomanip> #include <iomanip>
#include <numeric> #include <numeric>
#include <iostream>
//using namespace fmt;
std::string formatCentAsEuroString(const int cent, int width) std::string formatCentAsEuroString(const int cent, int width)
{ {
/*std::stringstream currStream; std::stringstream currStream;
try { try {
std::locale myLocale("de_DE.utf8"); std::locale myLocale("de_DE.utf8");
currStream.imbue(myLocale); currStream.imbue(myLocale);
std::cout << ">>> " << fmt::format(myLocale, "{:6.2Lf}", 1.12345) << '\n';
currStream << std::right << std::setw(width) << std::showbase currStream << std::right << std::setw(width) << std::showbase
<< std::put_money(cent, false); << std::put_money(cent, false);
} catch (std::runtime_error &err) { } catch (std::runtime_error& err) {
currStream << std::fixed << std::setw(width >= 4 ? width - 4 : width) currStream << std::fixed << std::setw(width >= 4 ? width - 4 : width)
<< std::setprecision(2) << cent / 100.0L << ""; << std::setprecision(2) << cent / 100.0L << "";
} }
return currStream.str();*/ return currStream.str();
#if defined(_WIN64) || defined(_WIN32)
std::locale myLocale;
#else
std::locale myLocale{"de_DE.utf8"};
#endif
return std::format(myLocale, "{:{}.2Lf} €", cent / 100.0L, width);
} }
std::string &ltrim(std::string &str, const std::string &chars) std::optional<PrinterDevice> convertToPosPrinterDevice(const std::string& device,
const std::string& endpoint)
{ {
str.erase(0, str.find_first_not_of(chars)); if (device.empty()) {
return str; return std::nullopt;
} }
std::string &rtrim(std::string &str, const std::string &chars) PrinterDevice printerDevice;
{ std::string delimiter = ":";
str.erase(str.find_last_not_of(chars) + 1); try {
return str; printerDevice.idVendor = std::stoi(device.substr(0, device.find(delimiter)), 0, 16);
} printerDevice.idProduct = std::stoi(device.substr(device.find(delimiter) + 1), 0, 16);
if (endpoint.empty()) {
printerDevice.endpoint = 0x03;
} else {
printerDevice.endpoint = std::stoi(endpoint, 0, 16);
}
std::string &trim(std::string &str, const std::string &chars) } catch (std::exception& ex) {
{ throw ex;
return ltrim(rtrim(str, chars), chars); }
}
bool case_insensitive_match(std::string s1, std::string s2) return printerDevice;
{
// convert s1 and s2 into lower case strings
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
if (s1.compare(s2) == 0)
return true; // The strings are same
return false; // not matched
} }
bool isNumber(const std::string &str)
{
return !str.empty() && std::find_if(str.begin(), str.end(), [](unsigned char c) {
return !std::isdigit(c);
}) == str.end();
}

View file

@ -1,15 +1,14 @@
#ifndef CORE_UTILS_H #ifndef UTILS_H
#define CORE_UTILS_H #define UTILS_H
#include "posprinter.h"
#include <locale> #include <locale>
#include <optional> #include <optional>
#include <string> #include <string>
std::string formatCentAsEuroString(const int cent, int width = 6); std::string formatCentAsEuroString(const int cent, int width = 10);
std::string &ltrim(std::string &str, const std::string &chars = "\t\n\v\f\r "); std::optional<PrinterDevice> convertToPosPrinterDevice(const std::string& vendor,
std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r "); const std::string& endpoint);
std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r ");
bool case_insensitive_match(std::string s1, std::string s2);
bool isNumber(const std::string &str);
#endif #endif

View file

@ -8,14 +8,8 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
# Find the QtWidgets library # Find the QtWidgets library
find_package(Qt6 COMPONENTS Widgets Network PrintSupport CONFIG REQUIRED) find_package(Qt5Widgets CONFIG REQUIRED)
#find_package(Qt5Widgets CONFIG REQUIRED) find_package(Qt5PrintSupport CONFIG REQUIRED)
#find_package(Qt5PrintSupport CONFIG REQUIRED)
# For SingleApplication:
#find_package(Qt5Network CONFIG REQUIRED)
set(QAPPLICATION_CLASS QApplication)
add_compile_definitions(QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
set(GUI_SOURCES set(GUI_SOURCES
kima2.cpp kima2.cpp
@ -34,16 +28,11 @@ set(GUI_SOURCES
settingsdialog.cpp settingsdialog.cpp
settingsdialog.ui settingsdialog.ui
../../kima2.qrc ../../kima2.qrc
${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git/singleapplication.cpp
${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git/singleapplication_p.cpp
) )
add_executable(kima2 ${GUI_SOURCES} kima2.rc) add_executable(kima2 ${GUI_SOURCES} kima2.rc)
target_include_directories(kima2 PRIVATE ${PROJECT_BINARY_DIR}) target_include_directories(kima2 PRIVATE ${PROJECT_BINARY_DIR})
target_include_directories(kima2 PRIVATE ${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git) target_link_libraries(kima2 core printer Qt5::Widgets Qt5::PrintSupport stdc++fs)
# target_link_libraries(kima2 core printer Qt5::Widgets Qt5::PrintSupport Qt5::Network stdc++fs)
target_link_libraries(kima2 core printer Qt::Core Qt::PrintSupport Qt::Network)
if(WIN32) if(WIN32)
set_target_properties(kima2 PROPERTIES LINK_FLAGS "-mwindows") set_target_properties(kima2 PROPERTIES LINK_FLAGS "-mwindows")
endif(WIN32) endif(WIN32)

View file

@ -1,17 +1,17 @@
#include "basketmodel.h" #include "basketmodel.h"
#include <QFont> #include <QFont>
#include <QFontDatabase>
#include <QSettings> #include <QSettings>
#include <QFontDatabase>
BasketModel::BasketModel(Marketplace* market, QObject* parent) BasketModel::BasketModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_marketplace(market) : QAbstractTableModel(parent), marketplace_(market)
{ {
} }
int BasketModel::rowCount([[maybe_unused]] const QModelIndex& parent) const int BasketModel::rowCount([[maybe_unused]] const QModelIndex& parent) const
{ {
return static_cast<int>(m_marketplace->basketSize()); return static_cast<int>(marketplace_->basketSize());
} }
int BasketModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 4; } int BasketModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 4; }
@ -22,7 +22,7 @@ QVariant BasketModel::data(const QModelIndex& index, int role) const
QFont myFont; QFont myFont;
QFont myFixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); QFont myFixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
if (myFixedFont.fixedPitch() == false) { if (myFixedFont.fixedPitch() == false) {
myFixedFont.setFamily("monospace"); myFixedFont.setFamily("monospace");
} }
@ -46,10 +46,10 @@ QVariant BasketModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole) if (role != Qt::DisplayRole)
return QVariant(); return QVariant();
if (m_marketplace->basketSize() == 0) if (marketplace_->basketSize() == 0)
return QVariant(); return QVariant();
Article* article = m_marketplace->getBasket().at(index.row()).get(); Article* article = marketplace_->getBasket().at(index.row()).get();
switch (index.column()) { switch (index.column()) {
case 0: case 0:
@ -92,45 +92,45 @@ QVariant BasketModel::headerData(int section, Qt::Orientation orientation, int r
void BasketModel::addArticle(Seller* seller, int price, const std::string& desc) void BasketModel::addArticle(Seller* seller, int price, const std::string& desc)
{ {
emit beginInsertRows(QModelIndex(), m_marketplace->getBasket().size(), emit beginInsertRows(QModelIndex(), marketplace_->getBasket().size(),
m_marketplace->getBasket().size()); marketplace_->getBasket().size());
auto article = std::make_unique<Article>(price); auto article = std::make_unique<Article>(price);
article->createUuid(); article->createUuid();
article->setDescription(desc); article->setDescription(desc);
article->setArticleNo(m_marketplace->getNextArticleNo()); article->setArticleNo(marketplace_->getNextArticleNo());
article->setSourceNo(QSettings().value("global/cashPointNo").toInt()); article->setSourceNo(QSettings().value("global/cashPointNo").toInt());
article->setSeller(seller); article->setSeller(seller);
m_marketplace->addArticleToBasket(std::move(article)); marketplace_->addArticleToBasket(std::move(article));
emit endInsertRows(); emit endInsertRows();
} }
void BasketModel::finishSale() void BasketModel::finishSale()
{ {
emit beginRemoveRows(QModelIndex(), 0, m_marketplace->getBasket().size() - 1); emit beginRemoveRows(QModelIndex(), 0, marketplace_->getBasket().size() - 1);
auto sale = std::make_unique<Sale>(); auto sale = std::make_unique<Sale>();
sale->createUuid(); sale->createUuid();
sale->setSourceNo(QSettings().value("global/cashPointNo").toInt()); sale->setSourceNo(QSettings().value("global/cashPointNo").toInt());
m_marketplace->finishCurrentSale(std::move(sale)); marketplace_->finishCurrentSale(std::move(sale));
emit endRemoveRows(); emit endRemoveRows();
emit basketDataChanged(); emit basketDataChanged();
} }
void BasketModel::cancelSale() void BasketModel::cancelSale()
{ {
emit beginRemoveRows(QModelIndex(), 0, m_marketplace->getBasket().size() - 1); emit beginRemoveRows(QModelIndex(), 0, marketplace_->getBasket().size() - 1);
m_marketplace->getBasket().clear(); marketplace_->getBasket().clear();
emit endRemoveRows(); emit endRemoveRows();
} }
bool BasketModel::removeRows(int row, int count, const QModelIndex& parent) bool BasketModel::removeRows(int row, int count, const QModelIndex& parent)
{ {
auto article = m_marketplace->getBasket().at(row).get(); auto article = marketplace_->getBasket().at(row).get();
emit beginRemoveRows(parent, row, row + count - 1); emit beginRemoveRows(parent, row, row + count - 1);
m_marketplace->getBasket().erase( marketplace_->getBasket().erase(
std::remove_if(m_marketplace->getBasket().begin(), m_marketplace->getBasket().end(), std::remove_if(marketplace_->getBasket().begin(), marketplace_->getBasket().end(),
[&article](const auto& a) { return a->getUuid() == article->getUuid(); }), [&article](const auto& a) { return a->getUuid() == article->getUuid(); }),
m_marketplace->getBasket().end()); marketplace_->getBasket().end());
emit endRemoveRows(); emit endRemoveRows();
return true; return true;
} }

View file

@ -1,13 +1,13 @@
#ifndef BASKET_MODEL_H #ifndef BASKET_MODEL_H
#define BASKET_MODEL_H #define BASKET_MODEL_H
#include <core/marketplace.h> #include <marketplace.h>
#include <QAbstractTableModel> #include <QAbstractTableModel>
class BasketModel : public QAbstractTableModel class BasketModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit BasketModel(Marketplace* market, QObject* parent = nullptr); explicit BasketModel(Marketplace* market, QObject* parent = nullptr);
@ -15,16 +15,19 @@ class BasketModel : public QAbstractTableModel
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
//virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
//virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
//virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
void addArticle(Seller* seller, int price, const std::string& desc); void addArticle(Seller* seller, int price, const std::string& desc);
void finishSale(); void finishSale();
void cancelSale(); void cancelSale();
virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
signals: signals:
void basketDataChanged(); void basketDataChanged();
private: private:
Marketplace* m_marketplace; Marketplace* marketplace_;
}; };
#endif #endif

View file

@ -6,27 +6,26 @@
#include <QLibraryInfo> #include <QLibraryInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QSettings> #include <QSettings>
#include <QSharedMemory>
#include <QStyleFactory>
#include <QTranslator> #include <QTranslator>
#include <singleapplication.h> int main(int argc, char* argv[])
#include <stdexcept>
int main(int argc, char *argv[])
{ {
SingleApplication kimaApp(argc, argv, false, SingleApplication::Mode::User | SingleApplication::ExcludeAppPath | SingleApplication::ExcludeAppVersion); QApplication kimaApp{argc, argv};
// QCoreApplication::setOrganizationName("RustySoft"); // QCoreApplication::setOrganizationName("RustySoft");
QCoreApplication::setOrganizationDomain("rustysoft.de"); QCoreApplication::setOrganizationDomain("rustysoft.de");
QCoreApplication::setApplicationName("kima2"); QCoreApplication::setApplicationName("kima2");
QTranslator qtTranslator; QTranslator qTranslator;
QLocale german(QLocale::German);
if (qtTranslator.load(QLocale::system(), u"qtbase"_qs, u"_"_qs, #ifdef __linux__
QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { qTranslator.load("qt_" + german.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
kimaApp.installTranslator(&qtTranslator); #endif
} #ifdef _WIN32
qTranslator.load("qt_" + german.name(),
QApplication::applicationDirPath() + QDir::separator() + "translations");
#endif
kimaApp.installTranslator(&qTranslator);
QSettings settings{}; QSettings settings{};
while (!settings.contains("global/cashPointNo")) { while (!settings.contains("global/cashPointNo")) {

View file

@ -1,23 +1,22 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "basketmodel.h" #include "basketmodel.h"
#include "config.h"
#include "jsonutil.h"
#include "pricedialog.h" #include "pricedialog.h"
#include "reportdialog.h" #include "reportdialog.h"
#include "salemodel.h" #include "salemodel.h"
#include "sellerdialog.h" #include "sellerdialog.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include <config.h>
#include <core/csvreader.h> #include <utils.h>
#include <core/jsonutil.h>
#include <core/utils.h> #include <excelreader.h>
#include <printer/posprinter.h> #include <posprinter.h>
#include <printer/utils.h>
#include <exception> #include <exception>
#include <filesystem> #include <filesystem>
#include <regex> #include <regex>
#include <string>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
@ -31,31 +30,23 @@ constexpr int STATUSBAR_TIMEOUT = 5000;
MainWindow::MainWindow() MainWindow::MainWindow()
{ {
m_ui.setupUi(this); ui_.setupUi(this);
m_marketplace = std::make_unique<Marketplace>(); marketplace_ = std::make_unique<Marketplace>();
Database::InitResult res = m_marketplace->loadFromDb(); marketplace_->loadFromDb();
if (res == Database::InitResult::OUTDATED_REPLACED) {
QMessageBox(QMessageBox::Icon::Information, "Datenbankinformation",
"Es wurde eine <b>veraltete</b> Datenbankdatei erkannt.<br />Diese wurde "
"umbenannt und eine <b>neue</b> Datei wurde erstellt.")
.exec();
}
statusBar()->showMessage("Gespeicherte Daten wurden geladen.", STATUSBAR_TIMEOUT); statusBar()->showMessage("Gespeicherte Daten wurden geladen.", STATUSBAR_TIMEOUT);
BasketModel *model = new BasketModel(getMarketplace(), m_ui.basketView); BasketModel* model = new BasketModel(getMarketplace(), ui_.basketView);
m_ui.basketView->setModel(model); ui_.basketView->setModel(model);
m_ui.basketView->setColumnHidden(0, true); // hide the uuid ui_.basketView->setColumnHidden(0, true); // hide the uuid
setWindowTitle("KIMA2 - Kasse Nr. " + QSettings().value("global/cashPointNo").toString()); setWindowTitle("KIMA2 - Kasse Nr. " + QSettings().value("global/cashPointNo").toString());
m_ui.salesView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
setSaleModel(); setSaleModel();
connect(m_ui.actionQuit, &QAction::triggered, qApp, QApplication::closeAllWindows, connect(ui_.actionQuit, &QAction::triggered, qApp, QApplication::quit);
Qt::QueuedConnection); connect(ui_.newAction, &QAction::triggered, this, [=]() {
connect(m_ui.newAction, &QAction::triggered, this, [this]() { if (marketplace_->getSellers().size() == 0 && marketplace_->getSales().size() == 0) {
if (m_marketplace->getSellers().size() == 0 && m_marketplace->getSales().size() == 0) {
return; return;
} }
auto dlgResult = auto dlgResult =
@ -67,45 +58,46 @@ MainWindow::MainWindow()
if (dlgResult == QMessageBox::No) if (dlgResult == QMessageBox::No)
return; return;
delete m_ui.salesView->model(); delete ui_.salesView->model();
dynamic_cast<BasketModel *>(m_ui.basketView->model())->cancelSale(); dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
m_marketplace->clear(); marketplace_->clear();
setSaleModel(); setSaleModel();
updateStatLabel(); updateStatLabel();
}); });
m_ui.sellerNoEdit->installEventFilter(this); ui_.sellerNoEdit->installEventFilter(this);
m_ui.givenSpinBox->installEventFilter(this); ui_.givenSpinBox->installEventFilter(this);
connect(m_ui.actionEditSeller, &QAction::triggered, this, connect(ui_.actionEditSeller, &QAction::triggered, this,
&MainWindow::onActionEditSellerTriggered); &MainWindow::onActionEditSellerTriggered);
connect(m_ui.paidButton, &QPushButton::clicked, this, &MainWindow::onPaidButtonTriggered); connect(ui_.paidButton, &QPushButton::clicked, this, &MainWindow::onPaidButtonTriggered);
connect(m_ui.givenSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, connect(ui_.givenSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&MainWindow::onGivenSpinBoxValueChanged); &MainWindow::onGivenSpinBoxValueChanged);
connect(m_ui.basketView->selectionModel(), &QItemSelectionModel::selectionChanged, this, connect(ui_.basketView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onBasketViewSelectionChanged); &MainWindow::onBasketViewSelectionChanged);
connect(m_ui.cancelArticleButton, &QPushButton::clicked, this, connect(ui_.cancelArticleButton, &QPushButton::clicked, this,
&MainWindow::onCancelArticleButtonClicked); &MainWindow::onCancelArticleButtonClicked);
connect(m_ui.cancelSaleButton, &QPushButton::clicked, this, connect(ui_.cancelSaleButton, &QPushButton::clicked, this,
&MainWindow::onCancelSaleButtonClicked); &MainWindow::onCancelSaleButtonClicked);
connect(m_ui.printSaleReceiptButton, &QPushButton::clicked, this, connect(ui_.printSaleReceiptButton, &QPushButton::clicked, this,
&MainWindow::onPrintSaleReceiptButtonClicked); &MainWindow::onPrintSaleReceiptButtonClicked);
connect(m_ui.cancelAllArticlesButton, &QPushButton::clicked, this, connect(ui_.cancelAllArticlesButton, &QPushButton::clicked, this,
&MainWindow::onCancelAllArticlesButtonClicked); &MainWindow::onCancelAllArticlesButtonClicked);
connect(m_ui.aboutQtAction, &QAction::triggered, this, &MainWindow::onAboutQt); connect(ui_.aboutQtAction, &QAction::triggered, this, &MainWindow::onAboutQt);
connect(m_ui.aboutAction, &QAction::triggered, this, &MainWindow::onAbout); connect(ui_.aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
connect(m_ui.openManualAction, &QAction::triggered, this, []() { connect(ui_.openManualAction, &QAction::triggered, this, []() {
auto locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); auto locations = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
for (auto location : locations) { for (auto location : locations) {
if (QFile::exists(location + QString("/Benutzerhandbuch.pdf"))) { if (QFile::exists(location + QString("/Benutzerhandbuch.pdf"))) {
QDesktopServices::openUrl( QDesktopServices::openUrl(
QUrl::fromLocalFile(location + QString("/Benutzerhandbuch.pdf"))); QUrl(QString("file:///") + location + QString("/Benutzerhandbuch.pdf"),
QUrl::TolerantMode));
} }
} }
}); });
connect(m_ui.licenseAction, &QAction::triggered, this, [this]() { connect(ui_.licenseAction, &QAction::triggered, this, [=]() {
QString licenseText( QString licenseText(
"Copyright © 2018-2024 Martin Brodbeck\n\n" "Copyright © 2018 Martin Brodbeck\n\n"
"Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der " "Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der "
"zugehörigen Dokumentationen (die \"Software\") erhält, die Erlaubnis erteilt, " "zugehörigen Dokumentationen (die \"Software\") erhält, die Erlaubnis erteilt, "
"sie uneingeschränkt zu nutzen, inklusive und ohne Ausnahme mit dem Recht, " "sie uneingeschränkt zu nutzen, inklusive und ohne Ausnahme mit dem Recht, "
@ -124,30 +116,32 @@ MainWindow::MainWindow()
"SOFTWARE ODER SONSTIGER VERWENDUNG DER SOFTWARE ENTSTANDEN."); "SOFTWARE ODER SONSTIGER VERWENDUNG DER SOFTWARE ENTSTANDEN.");
QMessageBox::information(this, "Lizenzinformation", licenseText); QMessageBox::information(this, "Lizenzinformation", licenseText);
}); });
connect(m_ui.reportAction, &QAction::triggered, this, [this]() { ReportDialog(this).exec(); }); connect(ui_.reportAction, &QAction::triggered, this, [=]() { ReportDialog(this).exec(); });
connect(m_ui.configAction, &QAction::triggered, this, [this]() { connect(ui_.configAction, &QAction::triggered, this, [=]() {
int result = SettingsDialog(this).exec(); int result = SettingsDialog(this).exec();
if (result == QDialog::Accepted) { if (result == QDialog::Accepted) {
delete m_ui.salesView->model(); delete ui_.salesView->model();
m_marketplace->loadFromDb(); marketplace_->loadFromDb();
setSaleModel(); setSaleModel();
} }
this->setWindowTitle("KIMA2 - Kasse Nr. " + this->setWindowTitle("KIMA2 - Kasse Nr. " +
QSettings().value("global/cashPointNo").toString()); QSettings().value("global/cashPointNo").toString());
}); });
connect(m_ui.importSellerAction, &QAction::triggered, this, connect(ui_.importSellerExcelAction, &QAction::triggered, this,
&MainWindow::onImportSellerActionTriggered); &MainWindow::onImportSellerExcelActionTriggered);
connect(m_ui.exportSalesJsonAction, &QAction::triggered, this, connect(ui_.importSellerJsonAction, &QAction::triggered, this,
&MainWindow::onImportSellerJsonActionTriggered);
connect(ui_.exportSellerJsonAction, &QAction::triggered, this,
&MainWindow::onExportSellerJsonActionTriggered);
connect(ui_.exportSalesJsonAction, &QAction::triggered, this,
&MainWindow::onExportSalesJsonActionTriggered); &MainWindow::onExportSalesJsonActionTriggered);
connect(m_ui.importSalesJsonAction, &QAction::triggered, this, connect(ui_.importSalesJsonAction, &QAction::triggered, this,
&MainWindow::onImportSalesJsonActionTriggered); &MainWindow::onImportSalesJsonActionTriggered);
readGeometry(); readGeometry();
setWindowIcon(QIcon(":/misc/kima2.ico")); setWindowIcon(QIcon(":/misc/kima2.ico"));
updateStatLabel(); updateStatLabel();
m_ui.lastPriceLabel1->setText(formatCentAsEuroString(0).c_str());
m_ui.lastPriceLabel2->setText(formatCentAsEuroString(0).c_str());
} }
void MainWindow::onActionEditSellerTriggered() void MainWindow::onActionEditSellerTriggered()
@ -155,11 +149,11 @@ void MainWindow::onActionEditSellerTriggered()
auto dialog = std::make_unique<SellerDialog>(this); auto dialog = std::make_unique<SellerDialog>(this);
int retCode = dialog->exec(); int retCode = dialog->exec();
delete m_ui.salesView->model(); delete ui_.salesView->model();
if (retCode == QDialog::Accepted) { if (retCode == QDialog::Accepted) {
m_marketplace->sortSellers(); marketplace_->sortSellers();
m_marketplace->storeToDb(); marketplace_->storeToDb();
statusBar()->showMessage("Änderungen an den Verkäufer-Stammdaten gespeichert.", statusBar()->showMessage("Änderungen an den Verkäufer-Stammdaten gespeichert.",
STATUSBAR_TIMEOUT); STATUSBAR_TIMEOUT);
} else { } else {
@ -173,44 +167,43 @@ void MainWindow::onActionEditSellerTriggered()
void MainWindow::setSaleModel() void MainWindow::setSaleModel()
{ {
m_ui.salesView->setModel(new SaleModel(getMarketplace(), m_ui.salesView)); ui_.salesView->setModel(new SaleModel(getMarketplace(), ui_.salesView));
m_ui.salesView->setColumnHidden(2, true); ui_.salesView->setColumnHidden(2, true);
m_ui.salesView->resizeColumnToContents(0); ui_.salesView->resizeColumnToContents(0);
m_ui.salesView->resizeColumnToContents(1);
m_ui.printSaleReceiptButton->setEnabled(false); ui_.printSaleReceiptButton->setEnabled(false);
m_ui.cancelSaleButton->setEnabled(false); ui_.cancelSaleButton->setEnabled(false);
connect(static_cast<BasketModel *>(m_ui.basketView->model()), &BasketModel::basketDataChanged, connect(static_cast<BasketModel*>(ui_.basketView->model()), &BasketModel::basketDataChanged,
static_cast<SaleModel *>(m_ui.salesView->model()), &SaleModel::onBasketDataChanged); static_cast<SaleModel*>(ui_.salesView->model()), &SaleModel::onBasketDataChanged);
connect(m_ui.salesView->selectionModel(), &QItemSelectionModel::selectionChanged, this, connect(ui_.salesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onSalesViewSelectionChanged); &MainWindow::onSalesViewSelectionChanged);
} }
void MainWindow::onPaidButtonTriggered() void MainWindow::onPaidButtonTriggered()
{ {
if (m_marketplace->basketSize() > 0) { if (marketplace_->basketSize() > 0) {
QString lastPrice{m_marketplace->getBasketSumAsString().c_str()}; QString lastPrice{marketplace_->getBasketSumAsString().c_str()};
dynamic_cast<BasketModel *>(m_ui.basketView->model())->finishSale(); dynamic_cast<BasketModel*>(ui_.basketView->model())->finishSale();
m_ui.salesView->resizeColumnToContents(0); ui_.salesView->resizeColumnToContents(0);
m_ui.lastPriceLabel1->setText(lastPrice); ui_.lastPriceLabel1->setText(lastPrice);
m_ui.lastPriceLabel2->setText(lastPrice); ui_.lastPriceLabel2->setText(lastPrice);
m_ui.basketSumLabel->setText(formatCentAsEuroString(0).c_str()); ui_.basketSumLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackLabel->setText(formatCentAsEuroString(0).c_str()); ui_.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackContainerWidget->setEnabled(false); ui_.drawbackContainerWidget->setEnabled(false);
m_ui.sellerNoEdit->setFocus(); ui_.sellerNoEdit->setFocus();
statusBar()->showMessage("Verkaufsvorgang erfolgreich durchgeführt.", STATUSBAR_TIMEOUT); statusBar()->showMessage("Verkaufsvorgang erfolgreich durchgeführt.", STATUSBAR_TIMEOUT);
updateStatLabel(); updateStatLabel();
} }
} }
bool MainWindow::eventFilter(QObject *target, QEvent *event) bool MainWindow::eventFilter(QObject* target, QEvent* event)
{ {
if (target == m_ui.sellerNoEdit) { if (target == ui_.sellerNoEdit) {
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key::Key_Enter || keyEvent->key() == Qt::Key::Key_Return) { if (keyEvent->key() == Qt::Key::Key_Enter || keyEvent->key() == Qt::Key::Key_Return) {
if (keyEvent->modifiers() & Qt::ControlModifier) { if (keyEvent->modifiers() == Qt::ControlModifier) {
checkSellerNo(true); checkSellerNo(true);
} else { } else {
checkSellerNo(false); checkSellerNo(false);
@ -219,18 +212,18 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event)
return true; return true;
} }
} }
} else if (target == m_ui.givenSpinBox) { } else if (target == ui_.givenSpinBox) {
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key::Key_Enter || keyEvent->key() == Qt::Key::Key_Return) { if (keyEvent->key() == Qt::Key::Key_Enter || keyEvent->key() == Qt::Key::Key_Return) {
if (keyEvent->modifiers() & Qt::ControlModifier) { if (keyEvent->modifiers() == Qt::ControlModifier) {
onPaidButtonTriggered(); onPaidButtonTriggered();
return true; return true;
} }
} else if (keyEvent->key() == Qt::Key::Key_Escape) { } else if (keyEvent->key() == Qt::Key::Key_Escape) {
m_ui.drawbackLabel->setText(formatCentAsEuroString(0).c_str()); ui_.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackContainerWidget->setEnabled(false); ui_.drawbackContainerWidget->setEnabled(false);
m_ui.sellerNoEdit->setFocus(); ui_.sellerNoEdit->setFocus();
} }
} }
} }
@ -241,15 +234,15 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
{ {
using std::regex, std::regex_match, std::smatch; using std::regex, std::regex_match, std::smatch;
auto inputText = m_ui.sellerNoEdit->text().toStdString(); auto inputText = ui_.sellerNoEdit->text().toStdString();
if (inputText.empty()) { if (inputText.empty()) {
if (ctrlPressed == false) { if (ctrlPressed == false) {
onPaidButtonTriggered(); onPaidButtonTriggered();
} else if (m_marketplace->getBasket().size() > 0) { } else if (marketplace_->getBasket().size() > 0) {
m_ui.drawbackContainerWidget->setEnabled(true); ui_.drawbackContainerWidget->setEnabled(true);
m_ui.givenSpinBox->setFocus(); ui_.givenSpinBox->setFocus();
m_ui.givenSpinBox->selectAll(); ui_.givenSpinBox->selectAll();
} }
return; return;
} }
@ -258,13 +251,13 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
smatch result; smatch result;
if (!regex_match(inputText, result, pattern)) { if (!regex_match(inputText, result, pattern)) {
m_ui.sellerNoEdit->clear(); ui_.sellerNoEdit->clear();
return; return;
} }
int sellerNo = std::stoi(result[0]); int sellerNo = std::stoi(result[0]);
auto seller = m_marketplace->findSellerWithSellerNo(sellerNo); auto seller = marketplace_->findSellerWithSellerNo(sellerNo);
if (seller) { if (seller) {
PriceDialog priceDialog(this); PriceDialog priceDialog(this);
if (sellerNo == 0) { if (sellerNo == 0) {
@ -274,52 +267,52 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
if (dialogResult == QDialog::Accepted) { if (dialogResult == QDialog::Accepted) {
int price = priceDialog.getPrice(); int price = priceDialog.getPrice();
std::string desc = priceDialog.getDescription(); std::string desc = priceDialog.getDescription();
dynamic_cast<BasketModel *>(m_ui.basketView->model())->addArticle(seller, price, desc); dynamic_cast<BasketModel*>(ui_.basketView->model())->addArticle(seller, price, desc);
m_ui.basketView->resizeColumnToContents(1); ui_.basketView->resizeColumnToContents(1);
m_ui.basketSumLabel->setText(m_marketplace->getBasketSumAsString().c_str()); ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str());
} }
} }
m_ui.sellerNoEdit->clear(); ui_.sellerNoEdit->clear();
} }
void MainWindow::onGivenSpinBoxValueChanged(double value) void MainWindow::onGivenSpinBoxValueChanged(double value)
{ {
int givenInCent = std::round(value * 100); int givenInCent = std::round(value * 100);
int basketSumInCent = m_marketplace->getBasketSumInCent(); int basketSumInCent = marketplace_->getBasketSumInCent();
int drawback = givenInCent - basketSumInCent; int drawback = givenInCent - basketSumInCent;
m_ui.drawbackLabel->setText(formatCentAsEuroString(drawback).c_str()); ui_.drawbackLabel->setText(formatCentAsEuroString(drawback).c_str());
} }
void MainWindow::onBasketViewSelectionChanged(const QItemSelection &selected, void MainWindow::onBasketViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection &deselected) [[maybe_unused]] const QItemSelection& deselected)
{ {
if (selected.size() > 0) { if (selected.size() > 0) {
m_ui.cancelArticleButton->setEnabled(true); ui_.cancelArticleButton->setEnabled(true);
} else { } else {
m_ui.cancelArticleButton->setEnabled(false); ui_.cancelArticleButton->setEnabled(false);
} }
} }
void MainWindow::onSalesViewSelectionChanged(const QItemSelection &selected, void MainWindow::onSalesViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection &deselected) [[maybe_unused]] const QItemSelection& deselected)
{ {
if (selected.size() > 0) { if (selected.size() > 0) {
m_ui.cancelSaleButton->setEnabled(true); ui_.cancelSaleButton->setEnabled(true);
if (!selected.indexes()[0].parent().isValid()) if (!selected.indexes()[0].parent().isValid())
m_ui.printSaleReceiptButton->setEnabled(true); ui_.printSaleReceiptButton->setEnabled(true);
else else
m_ui.printSaleReceiptButton->setEnabled(false); ui_.printSaleReceiptButton->setEnabled(false);
} else { } else {
m_ui.cancelSaleButton->setEnabled(false); ui_.cancelSaleButton->setEnabled(false);
m_ui.printSaleReceiptButton->setEnabled(false); ui_.printSaleReceiptButton->setEnabled(false);
} }
} }
void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked) void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked)
{ {
auto selModel = m_ui.basketView->selectionModel(); auto selModel = ui_.basketView->selectionModel();
if (selModel->hasSelection() == false) if (selModel->hasSelection() == false)
return; return;
@ -336,23 +329,22 @@ void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked)
// Deleting the rows, beginning with the last one! // Deleting the rows, beginning with the last one!
for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) { for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) {
m_ui.basketView->model()->removeRow(iter->row()); ui_.basketView->model()->removeRow(iter->row());
} }
m_ui.basketSumLabel->setText( ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str()); // Update basket sum
m_marketplace->getBasketSumAsString().c_str()); // Update basket sum ui_.sellerNoEdit->setFocus();
m_ui.sellerNoEdit->setFocus();
} }
void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked) void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked)
{ {
auto selModel = m_ui.salesView->selectionModel(); auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false) if (selModel->hasSelection() == false)
return; return;
auto dlgResult = auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?", QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Möchten Sie wirklich aus abgeschlossenen Verkäufen stornieren?", "Möchten Sie wirklich stornieren?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this) QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec(); .exec();
if (dlgResult == QMessageBox::No) if (dlgResult == QMessageBox::No)
@ -363,25 +355,16 @@ void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked)
// Deleting the rows, beginning with the last one! // Deleting the rows, beginning with the last one!
for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) { for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) {
m_ui.salesView->model()->removeRow(iter->row(), iter->parent()); ui_.salesView->model()->removeRow(iter->row(), iter->parent());
} }
m_ui.salesView->collapseAll(); ui_.salesView->collapseAll();
QString lastPriceValue(formatCentAsEuroString(0).c_str());
if (m_ui.salesView->model()->rowCount() > 0) {
lastPriceValue =
m_ui.salesView->model()->data(m_ui.salesView->model()->index(0, 1)).toString();
}
m_ui.lastPriceLabel1->setText(lastPriceValue);
m_ui.lastPriceLabel2->setText(lastPriceValue);
updateStatLabel(); updateStatLabel();
} }
void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked) void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
{ {
auto selModel = m_ui.salesView->selectionModel(); auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false) if (selModel->hasSelection() == false)
return; return;
@ -390,7 +373,7 @@ void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString(); QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString();
auto indexes = selModel->selectedRows(); auto indexes = selModel->selectedRows();
auto &sale = m_marketplace->getSales().at(indexes[0].row()); auto& sale = marketplace_->getSales().at(indexes[0].row());
auto printerDevice = auto printerDevice =
convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString()); convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString());
@ -404,13 +387,12 @@ void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
} }
if (printer->isValid()) if (printer->isValid())
printer->printSaleReceipt( printer->printSaleReceipt(sale.get(), settings.value("global/commune", "Dettingen").toString().toStdString());
sale.get(), settings.value("global/commune", "Dettingen").toString().toStdString());
} }
void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked) void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked)
{ {
if (m_ui.basketView->model()->rowCount() == 0) if (ui_.basketView->model()->rowCount() == 0)
return; return;
auto dlgResult = auto dlgResult =
@ -421,11 +403,10 @@ void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked)
if (dlgResult == QMessageBox::No) if (dlgResult == QMessageBox::No)
return; return;
dynamic_cast<BasketModel *>(m_ui.basketView->model())->cancelSale(); dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
m_ui.basketSumLabel->setText( ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str()); // Update basket sum
m_marketplace->getBasketSumAsString().c_str()); // Update basket sum ui_.sellerNoEdit->setFocus();
m_ui.sellerNoEdit->setFocus();
} }
void MainWindow::onAboutQt() { QMessageBox::aboutQt(this); } void MainWindow::onAboutQt() { QMessageBox::aboutQt(this); }
@ -441,9 +422,9 @@ void MainWindow::onAbout()
">info@rustysoft.de</a>&gt;</p>"); ">info@rustysoft.de</a>&gt;</p>");
} }
void MainWindow::onImportSellerActionTriggered() void MainWindow::onImportSellerExcelActionTriggered()
{ {
if (!m_marketplace->getSales().empty()) { if (!marketplace_->getSales().empty()) {
QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich", QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich",
"Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.", "Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
QMessageBox::StandardButton::Ok, this) QMessageBox::StandardButton::Ok, this)
@ -451,31 +432,59 @@ void MainWindow::onImportSellerActionTriggered()
return; return;
} }
auto filename = QMessageBox(
QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(), QMessageBox::Icon::Information, "Bitte beachten",
"Alle unterstützte Dateien (*.csv);;CSV Dateien (*.csv)"); "<b>Achtung:</b> Importieren Sie die Verkäuferdaten nur auf <b>einer (!)</b> "
"KIMA2-Installation.<br /> "
"Verteilen Sie die Daten auf die anderen Installationen unbedingt über eine JSON-Datei!",
QMessageBox::StandardButton::Ok, this)
.exec();
auto filename = QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"Excel Dateien (*.xlsx *.xls)");
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
#if defined(_WIN64) || defined(_WIN32)
fs::path filePath(filename.toStdWString()); fs::path filePath(filename.toStdWString());
#else
fs::path filePath(filename.toStdString());
#endif
std::size_t numImported{};
numImported = CsvReader::readSellersFromFile(filePath, m_marketplace.get());
ExcelReader::readSellersFromFile(filePath, marketplace_.get());
updateStatLabel(); updateStatLabel();
}
using namespace std::string_literals; void MainWindow::onImportSellerJsonActionTriggered()
std::ostringstream msg; {
msg << "Aus der CSV-Datei wurden <b>"s << std::to_string(numImported) if (!marketplace_->getSales().empty()) {
<< "</b> Verkäufer importiert."; QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich",
QMessageBox(QMessageBox::Icon::Information, "Verkäufer erfolgreich importiert", "Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
msg.str().c_str(), QMessageBox::StandardButton::Ok, this) QMessageBox::StandardButton::Ok, this)
.exec(); .exec();
return;
}
auto filename = QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"JSON Dateien (*.json)");
if (filename.isEmpty())
return;
fs::path filePath(filename.toStdWString());
JsonUtil::importSellers(filePath, marketplace_.get());
updateStatLabel();
}
void MainWindow::onExportSellerJsonActionTriggered()
{
auto filename = QFileDialog::getSaveFileName(
this, "Verkäufer exportieren", QString("kima2_verkaeufer.json"), "JSON Dateien (*.json)");
if (filename.isEmpty())
return;
fs::path filePath(filename.toStdWString());
JsonUtil::exportSellers(filePath, marketplace_.get());
} }
void MainWindow::onExportSalesJsonActionTriggered() void MainWindow::onExportSalesJsonActionTriggered()
@ -490,13 +499,9 @@ void MainWindow::onExportSalesJsonActionTriggered()
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
#if defined(_WIN64) || defined(_WIN32)
fs::path filePath(filename.toStdWString()); fs::path filePath(filename.toStdWString());
#else
fs::path filePath(filename.toStdString());
#endif
JsonUtil::exportSales(filePath, m_marketplace.get(), JsonUtil::exportSales(filePath, marketplace_.get(),
settings.value("global/cashPointNo").toInt()); settings.value("global/cashPointNo").toInt());
} }
@ -504,30 +509,23 @@ void MainWindow::onImportSalesJsonActionTriggered()
{ {
QSettings settings; QSettings settings;
auto filenames = QFileDialog::getOpenFileNames(this, "Umsätze/Transaktionen importieren", auto filename = QFileDialog::getOpenFileName(this, "Umsätze/Transaktionen importieren",
QString(), "JSON Dateien (*.json)"); QString(), "JSON Dateien (*.json)");
if (filenames.isEmpty()) if (filename.isEmpty())
return; return;
for(auto filename: filenames) { fs::path filePath(filename.toStdWString());
#if defined(_WIN64) || defined(_WIN32)
fs::path filePath(filename.toStdWString());
#else
fs::path filePath(filename.toStdString());
#endif
delete m_ui.salesView->model(); delete ui_.salesView->model();
try { try {
JsonUtil::importSales(filePath, m_marketplace.get(), JsonUtil::importSales(filePath, marketplace_.get(),
settings.value("global/cashPointNo").toInt()); settings.value("global/cashPointNo").toInt());
} catch (std::runtime_error &err) { } catch (std::runtime_error& err) {
QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok, QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok,
this) this)
.exec(); .exec();
}
} }
setSaleModel(); setSaleModel();
updateStatLabel(); updateStatLabel();
} }
@ -552,7 +550,7 @@ void MainWindow::readGeometry()
settings.endGroup(); settings.endGroup();
} }
void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::closeEvent(QCloseEvent* event)
{ {
writeGeometry(); writeGeometry();
event->accept(); event->accept();
@ -562,9 +560,9 @@ void MainWindow::updateStatLabel()
{ {
std::string statistics("<b>KIMA2 - Version "); std::string statistics("<b>KIMA2 - Version ");
statistics += PROJECT_VERSION; statistics += PROJECT_VERSION;
statistics += "</b><br />Verkäufer: " + std::to_string(m_marketplace->getSellers().size() - 1); statistics += "</b><br />Verkäufer: " + std::to_string(marketplace_->getSellers().size() - 1);
statistics += "<br />Kunden: " + std::to_string(m_marketplace->getSales().size()); statistics += "<br />Kunden: " + std::to_string(marketplace_->getSales().size());
statistics += "<br />Umsatz: " + m_marketplace->getOverallSumAsString(); statistics += "<br />Umsatz: " + marketplace_->getOverallSumAsString();
m_ui.statLabel->setText(statistics.c_str()); ui_.statLabel->setText(statistics.c_str());
} }

View file

@ -3,7 +3,7 @@
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include <core/marketplace.h> #include <marketplace.h>
#include <QMainWindow> #include <QMainWindow>
#include <QtGui/QCloseEvent> #include <QtGui/QCloseEvent>
@ -16,7 +16,7 @@ class MainWindow : public QMainWindow
public: public:
MainWindow(); MainWindow();
Marketplace* getMarketplace() { return m_marketplace.get(); } Marketplace* getMarketplace() { return marketplace_.get(); }
private slots: private slots:
void onBasketViewSelectionChanged(const QItemSelection& selected, void onBasketViewSelectionChanged(const QItemSelection& selected,
@ -29,7 +29,7 @@ class MainWindow : public QMainWindow
void onCancelAllArticlesButtonClicked(bool checked); void onCancelAllArticlesButtonClicked(bool checked);
void onAboutQt(); void onAboutQt();
void onAbout(); void onAbout();
virtual bool eventFilter(QObject* target, QEvent* event) override; virtual bool eventFilter(QObject *target, QEvent *event) override;
protected: protected:
virtual void closeEvent(QCloseEvent* event) override; virtual void closeEvent(QCloseEvent* event) override;
@ -39,7 +39,9 @@ class MainWindow : public QMainWindow
void checkSellerNo(bool ctrlPressed = false); void checkSellerNo(bool ctrlPressed = false);
void onPaidButtonTriggered(); void onPaidButtonTriggered();
void onGivenSpinBoxValueChanged(double value); void onGivenSpinBoxValueChanged(double value);
void onImportSellerActionTriggered(); void onImportSellerExcelActionTriggered();
void onImportSellerJsonActionTriggered();
void onExportSellerJsonActionTriggered();
void onExportSalesJsonActionTriggered(); void onExportSalesJsonActionTriggered();
void onImportSalesJsonActionTriggered(); void onImportSalesJsonActionTriggered();
void setSaleModel(); void setSaleModel();
@ -47,8 +49,8 @@ class MainWindow : public QMainWindow
void readGeometry(); void readGeometry();
void updateStatLabel(); void updateStatLabel();
Ui::MainWindow m_ui; Ui::MainWindow ui_;
std::unique_ptr<Marketplace> m_marketplace; std::unique_ptr<Marketplace> marketplace_;
}; };
#endif #endif

View file

@ -112,11 +112,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QDoubleSpinBox" name="givenSpinBox"> <widget class="QDoubleSpinBox" name="givenSpinBox"/>
<property name="maximum">
<double>999.990000000000009</double>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
@ -440,8 +436,16 @@ drucken</string>
<property name="title"> <property name="title">
<string>&amp;Verkäufer</string> <string>&amp;Verkäufer</string>
</property> </property>
<widget class="QMenu" name="importSellerMenu">
<property name="title">
<string>Importieren</string>
</property>
<addaction name="importSellerExcelAction"/>
<addaction name="importSellerJsonAction"/>
</widget>
<addaction name="actionEditSeller"/> <addaction name="actionEditSeller"/>
<addaction name="importSellerAction"/> <addaction name="importSellerMenu"/>
<addaction name="exportSellerJsonAction"/>
</widget> </widget>
<widget class="QMenu" name="menuHilfe"> <widget class="QMenu" name="menuHilfe">
<property name="title"> <property name="title">
@ -505,9 +509,9 @@ drucken</string>
<string>Exportieren für andere Kasse (JSON)</string> <string>Exportieren für andere Kasse (JSON)</string>
</property> </property>
</action> </action>
<action name="importSellerActionX"> <action name="importSellerExcelAction">
<property name="text"> <property name="text">
<string>Aus CSV-Datei (initial)</string> <string>Aus Excel-Datei (initial)</string>
</property> </property>
</action> </action>
<action name="importSellerJsonAction"> <action name="importSellerJsonAction">
@ -540,11 +544,6 @@ drucken</string>
<string>Lizenz</string> <string>Lizenz</string>
</property> </property>
</action> </action>
<action name="importSellerAction">
<property name="text">
<string>Importieren (aus CSV-Datei)</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View file

@ -1,23 +0,0 @@
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui', 'PrintSupport', 'Network'])
thread_dep = dependency('threads')
src = ['kima2.cpp', 'mainwindow.cpp', 'sellerdialog.cpp', 'sellermodel.cpp',
'pricedialog.cpp', 'basketmodel.cpp', 'salemodel.cpp', 'reportdialog.cpp',
'reportmodel.cpp', 'settingsdialog.cpp']
ui = ['mainwindow.ui', 'sellerdialog.ui', 'pricedialog.ui', 'reportdialog.ui', 'settingsdialog.ui']
processed = qt5.preprocess(moc_headers : ['basketmodel.h', 'mainwindow.h', 'pricedialog.h',
'reportdialog.h', 'sellerdialog.h', 'settingsdialog.h',
'sellermodel.h', 'salemodel.h'],
ui_files : ui,
qresources : '../../kima2.qrc',
dependencies: qt5_dep)
kima2 = executable('kima2', sources : [src, processed],
dependencies : [qt5_dep, singleapp_dep, core_dep, printer_dep, thread_dep],
include_directories : [configuration_inc],
install : true)

View file

@ -6,31 +6,34 @@
PriceDialog::PriceDialog(QWidget* parent, bool forceDesc, Qt::WindowFlags f) : QDialog(parent, f) PriceDialog::PriceDialog(QWidget* parent, bool forceDesc, Qt::WindowFlags f) : QDialog(parent, f)
{ {
m_forceDesc = forceDesc; forceDesc_ = forceDesc;
m_ui.setupUi(this); ui_.setupUi(this);
m_ui.priceSpinBox->setFocus(); ui_.priceSpinBox->setFocus();
} }
int PriceDialog::getPrice() const { return static_cast<int>(m_ui.priceSpinBox->value() * 100); } int PriceDialog::getPrice() const { return static_cast<int>(ui_.priceSpinBox->value() * 100); }
std::string PriceDialog::getDescription() const { return m_ui.descEdit->text().toStdString(); } std::string PriceDialog::getDescription() const { return ui_.descEdit->text().toStdString(); }
void PriceDialog::accept() void PriceDialog::accept()
{ {
if (static_cast<int>(std::round(m_ui.priceSpinBox->value() * 100.0L)) % 50 != 0) { if (static_cast<int>(std::round(ui_.priceSpinBox->value() * 100.0L)) % 50 != 0) {
QMessageBox(QMessageBox::Icon::Warning, "Falsche Preiseingabe", QMessageBox(QMessageBox::Icon::Warning, "Falsche Preiseingabe",
"Es sind nur 0,50 Cent-Schritte erlaubt.", QMessageBox::StandardButton::Ok, "Es sind nur 0,50 Cent-Schritte erlaubt.", QMessageBox::StandardButton::Ok,
this) this)
.exec(); .exec();
} else if (m_forceDesc && m_ui.descEdit->text().trimmed().isEmpty()) { } else if (forceDesc_ && ui_.descEdit->text().trimmed().isEmpty()) {
QMessageBox(QMessageBox::Icon::Warning, "Artikelbeschreibung fehlt", QMessageBox(QMessageBox::Icon::Warning, "Artikelbeschreibung fehlt",
"Da Sie auf das Sonderkonto buchen ist eine Artikelbeschreibung erforderlich.", "Da Sie auf das Sonderkonto buchen ist eine Artikelbeschreibung erforderlich.",
QMessageBox::StandardButton::Ok, this) QMessageBox::StandardButton::Ok, this)
.exec(); .exec();
m_ui.descEdit->setFocus(); ui_.descEdit->setFocus();
} else { } else {
QDialog::accept(); QDialog::accept();
} }
} }
void PriceDialog::setForceDesc(bool force) { m_forceDesc = force; } void PriceDialog::setForceDesc(bool force)
{
forceDesc_ = force;
}

View file

@ -19,8 +19,8 @@ class PriceDialog : public QDialog
private: private:
void on_model_duplicateSellerNo(const QString& message); void on_model_duplicateSellerNo(const QString& message);
virtual void accept() override; virtual void accept() override;
Ui::PriceDialog m_ui; Ui::PriceDialog ui_;
bool m_forceDesc; bool forceDesc_;
}; };
#endif #endif

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>266</width> <width>201</width>
<height>128</height> <height>127</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -18,11 +18,6 @@
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text"> <property name="text">
<string>Preis</string> <string>Preis</string>
</property> </property>
@ -33,11 +28,6 @@
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QDoubleSpinBox" name="priceSpinBox"> <widget class="QDoubleSpinBox" name="priceSpinBox">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="minimum"> <property name="minimum">
<double>-999.990000000000009</double> <double>-999.990000000000009</double>
</property> </property>
@ -61,18 +51,6 @@
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="descEdit"> <widget class="QLineEdit" name="descEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="placeholderText"> <property name="placeholderText">
<string>(optional)</string> <string>(optional)</string>
</property> </property>

View file

@ -2,9 +2,8 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <core/utils.h> #include <posprinter.h>
#include <printer/posprinter.h> #include <utils.h>
#include <printer/utils.h>
#include <filesystem> #include <filesystem>
@ -17,22 +16,22 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
ReportDialog::ReportDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) ReportDialog::ReportDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f)
{ {
m_ui.setupUi(this); ui_.setupUi(this);
m_market = dynamic_cast<MainWindow *>(parent)->getMarketplace(); market_ = dynamic_cast<MainWindow*>(parent)->getMarketplace();
m_model = std::make_unique<ReportModel>(m_market, m_ui.reportView); model_ = std::make_unique<ReportModel>(market_, ui_.reportView);
m_ui.reportView->setModel(m_model.get()); ui_.reportView->setModel(model_.get());
m_ui.reportView->hideColumn(0); ui_.reportView->hideColumn(0);
m_ui.reportView->setRowHidden(0, true); // hide the special "Sonderkonto" user ui_.reportView->setRowHidden(0, true); // hide the special "Sonderkonto" user
connect(m_ui.exportCsvButton, &QPushButton::clicked, this, connect(ui_.exportCsvButton, &QPushButton::clicked, this,
&ReportDialog::onExportCsvButtonClicked); &ReportDialog::onExportCsvButtonClicked);
connect(m_ui.printReportButton, &QPushButton::clicked, this, connect(ui_.printReportButton, &QPushButton::clicked, this,
&ReportDialog::onPrintReportButtonClicked); &ReportDialog::onPrintReportButtonClicked);
connect(m_ui.printSellerReceiptButton, &QPushButton::clicked, this, connect(ui_.printSellerReceiptButton, &QPushButton::clicked, this,
&ReportDialog::onPrintSellerReceiptButtonClicked); &ReportDialog::onPrintSellerReceiptButtonClicked);
connect(m_ui.reportView->selectionModel(), &QItemSelectionModel::selectionChanged, this, connect(ui_.reportView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&ReportDialog::onReportViewSelectionChanged); &ReportDialog::onReportViewSelectionChanged);
} }
@ -48,13 +47,9 @@ void ReportDialog::onExportCsvButtonClicked()
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
#if defined(_WIN64) || defined(_WIN32)
fs::path filePath(filename.toStdWString()); fs::path filePath(filename.toStdWString());
#else
fs::path filePath(filename.toStdString());
#endif
m_market->exportReportToCSV(filePath, feeInPercent, maxFeeInEuro); market_->exportReportToCSV(filePath, feeInPercent, maxFeeInEuro);
} }
void ReportDialog::onPrintReportButtonClicked() void ReportDialog::onPrintReportButtonClicked()
@ -75,8 +70,8 @@ void ReportDialog::onPrintReportButtonClicked()
QPainter painter; QPainter painter;
int height = printer.height(); int height = printer.height();
int width = printer.width(); int width = printer.width();
const double ENTRIES_PER_PAGE = 45; const double ENTRIES_PER_PAGE = 51;
const auto &sellers = m_market->getSellers(); const auto& sellers = market_->getSellers();
unsigned int numPages = std::ceil(sellers.size() / ENTRIES_PER_PAGE); unsigned int numPages = std::ceil(sellers.size() / ENTRIES_PER_PAGE);
painter.begin(&printer); painter.begin(&printer);
@ -107,7 +102,7 @@ void ReportDialog::onPrintReportButtonClicked()
for (unsigned int j = 0; for (unsigned int j = 0;
j < ENTRIES_PER_PAGE && (i - 1) * ENTRIES_PER_PAGE + j < sellers.size(); ++j) { j < ENTRIES_PER_PAGE && (i - 1) * ENTRIES_PER_PAGE + j < sellers.size(); ++j) {
int idx = (i - 1) * ENTRIES_PER_PAGE + j; int idx = (i - 1) * ENTRIES_PER_PAGE + j;
if (sellers.at(idx)->getId() == 0) { if (sellers.at(idx)->getUuidAsString() == "11111111-1111-1111-1111-111111111111") {
continue; continue;
} }
content += QString("%1 %2 %3 %4 %5 %6 %7\n") content += QString("%1 %2 %3 %4 %5 %6 %7\n")
@ -126,7 +121,7 @@ void ReportDialog::onPrintReportButtonClicked()
} }
// pieces booked on the special account "Sonderkonto" // pieces booked on the special account "Sonderkonto"
const auto specialSeller = m_market->findSellerWithSellerNo(0); const auto specialSeller = market_->findSellerWithUuid("11111111-1111-1111-1111-111111111111");
if (specialSeller && specialSeller->numArticlesSold() > 0) { if (specialSeller && specialSeller->numArticlesSold() > 0) {
printer.newPage(); printer.newPage();
painter.setFont(QFont("Arial", 16, QFont::Bold)); painter.setFont(QFont("Arial", 16, QFont::Bold));
@ -136,7 +131,7 @@ void ReportDialog::onPrintReportButtonClicked()
QString content("Einzelteile ohne Nummer\n=======================\n\n"); QString content("Einzelteile ohne Nummer\n=======================\n\n");
unsigned int lines{0}; unsigned int lines{0};
unsigned int pages{1}; unsigned int pages{1};
for (const auto &article : specialSeller->getArticles(true)) { for (const auto& article : specialSeller->getArticles(true)) {
content += QString("- %1:").arg(article->getDescription().substr(0, 45).c_str(), -45); content += QString("- %1:").arg(article->getDescription().substr(0, 45).c_str(), -45);
content += QString("%1\n").arg(article->getPriceAsString().c_str(), 11); content += QString("%1\n").arg(article->getPriceAsString().c_str(), 11);
++lines; ++lines;
@ -163,8 +158,8 @@ void ReportDialog::onPrintReportButtonClicked()
"Auswertung Kindersachenmarkt"); "Auswertung Kindersachenmarkt");
painter.setFont(fixedFont); painter.setFont(fixedFont);
QString content("Gesamtstatistik\n===============\n\n"); QString content("Gesamtstatistik\n===============\n\n");
int numArticlesOffered = m_market->getNumArticlesOffered(); int numArticlesOffered = market_->getNumArticlesOffered();
int numArticlesSold = m_market->getNumArticlesSold(); int numArticlesSold = market_->getNumArticlesSold();
double percentArticlesSold = double percentArticlesSold =
(static_cast<double>(numArticlesSold) / static_cast<double>(numArticlesOffered)) * 100; (static_cast<double>(numArticlesSold) / static_cast<double>(numArticlesOffered)) * 100;
content += QString("Registrierte Verkäufer: %1\n").arg(sellers.size() - 1, 6); content += QString("Registrierte Verkäufer: %1\n").arg(sellers.size() - 1, 6);
@ -172,14 +167,14 @@ void ReportDialog::onPrintReportButtonClicked()
content += QString("Verkaufte Artikel: %1 (%L2 %)\n") content += QString("Verkaufte Artikel: %1 (%L2 %)\n")
.arg(numArticlesSold, 6) .arg(numArticlesSold, 6)
.arg(percentArticlesSold, 0, 'f', 2); .arg(percentArticlesSold, 0, 'f', 2);
content += QString("Anzahl Kunden: %1\n\n").arg(m_market->getSales().size(), 6); content += QString("Anzahl Kunden: %1\n\n").arg(market_->getSales().size(), 6);
content += QString("Gesamtumsatz: %1\n").arg(m_market->getOverallSumAsString().c_str(), 10); content += QString("Gesamtumsatz: %1\n").arg(market_->getOverallSumAsString().c_str(), 10);
content += content +=
QString("Ausgezahlt: %1\n") QString("Ausgezahlt: %1\n")
.arg(m_market->getOverallPaymentAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10); .arg(market_->getOverallPaymentAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10);
content += content +=
QString("Verbleibend: %1\n\n") QString("Verbleibend: %1\n\n")
.arg(m_market->getOverallRevenueAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10); .arg(market_->getOverallRevenueAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10);
content += QString("(Einbehaltener Prozentsatz: %1 %)\n").arg(feeInPercent, 3); content += QString("(Einbehaltener Prozentsatz: %1 %)\n").arg(feeInPercent, 3);
content += QString("(Maximal einbehaltener Betrag: %1 €)\n").arg(maxFeeInEuro, 3); content += QString("(Maximal einbehaltener Betrag: %1 €)\n").arg(maxFeeInEuro, 3);
@ -196,12 +191,12 @@ void ReportDialog::onPrintSellerReceiptButtonClicked()
QString posPrinterDevice = settings.value("global/posPrinterDevice", "").toString(); QString posPrinterDevice = settings.value("global/posPrinterDevice", "").toString();
QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString(); QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString();
auto selModel = m_ui.reportView->selectionModel(); auto selModel = ui_.reportView->selectionModel();
if (selModel->hasSelection() == false) if (selModel->hasSelection() == false)
return; return;
auto indexes = selModel->selectedRows(); auto indexes = selModel->selectedRows();
auto &seller = m_market->getSellers().at(indexes[0].row()); auto& seller = market_->getSellers().at(indexes[0].row());
auto printerDevice = auto printerDevice =
convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString()); convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString());
@ -220,12 +215,12 @@ void ReportDialog::onPrintSellerReceiptButtonClicked()
settings.value("global/commune", "Dettingen").toString().toStdString()); settings.value("global/commune", "Dettingen").toString().toStdString());
} }
void ReportDialog::onReportViewSelectionChanged(const QItemSelection &selected, void ReportDialog::onReportViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection &deselected) [[maybe_unused]] const QItemSelection& deselected)
{ {
if (selected.size() > 0) { if (selected.size() > 0) {
m_ui.printSellerReceiptButton->setEnabled(true); ui_.printSellerReceiptButton->setEnabled(true);
} else { } else {
m_ui.printSellerReceiptButton->setEnabled(false); ui_.printSellerReceiptButton->setEnabled(false);
} }
} }

View file

@ -5,7 +5,7 @@
#include "reportmodel.h" #include "reportmodel.h"
#include <core/marketplace.h> #include <marketplace.h>
#include <QDialog> #include <QDialog>
@ -24,10 +24,9 @@ class ReportDialog : public QDialog
void onReportViewSelectionChanged(const QItemSelection& selected, void onReportViewSelectionChanged(const QItemSelection& selected,
const QItemSelection& deselected); const QItemSelection& deselected);
private: private : Ui::ReportDialog ui_;
Ui::ReportDialog m_ui; Marketplace* market_;
Marketplace* m_market; std::unique_ptr<ReportModel> model_;
std::unique_ptr<ReportModel> m_model;
}; };
#endif #endif

View file

@ -5,16 +5,16 @@
#include <QSettings> #include <QSettings>
ReportModel::ReportModel(Marketplace* market, QObject* parent) ReportModel::ReportModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_market(market) : QAbstractTableModel(parent), market_(market)
{ {
QSettings settings; QSettings settings;
m_feeInPercent = settings.value("global/feeInPercent").toInt(); feeInPercent_ = settings.value("global/feeInPercent").toInt();
m_maxFeeInCent = settings.value("global/maxFeeInEuro").toInt() * 100; maxFeeInCent_ = settings.value("global/maxFeeInEuro").toInt() * 100;
} }
int ReportModel::rowCount([[maybe_unused]] const QModelIndex& parent) const int ReportModel::rowCount([[maybe_unused]] const QModelIndex& parent) const
{ {
return static_cast<int>(m_market->getSellers().size()); return static_cast<int>(market_->getSellers().size());
} }
int ReportModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 7; } int ReportModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 7; }
@ -52,14 +52,14 @@ QVariant ReportModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole) if (role != Qt::DisplayRole)
return QVariant(); return QVariant();
if (m_market->getSellers().size() == 0) if (market_->getSellers().size() == 0)
return QVariant(); return QVariant();
Seller* seller = m_market->getSellers().at(index.row()).get(); Seller* seller = market_->getSellers().at(index.row()).get();
switch (index.column()) { switch (index.column()) {
case 0: case 0:
return seller->getId(); return seller->getUuidAsString().c_str();
case 1: case 1:
return seller->getSellerNo(); return seller->getSellerNo();
case 2: case 2:
@ -71,7 +71,7 @@ QVariant ReportModel::data(const QModelIndex& index, int role) const
case 5: case 5:
return seller->sumAsString().c_str(); return seller->sumAsString().c_str();
case 6: case 6:
return paymentAsString(seller->sumInCents(), m_feeInPercent, m_maxFeeInCent).c_str(); return paymentAsString(seller->sumInCents(), feeInPercent_, maxFeeInCent_).c_str();
default: default:
return "???"; return "???";
} }
@ -104,4 +104,4 @@ QVariant ReportModel::headerData(int section, Qt::Orientation orientation, int r
// return QStringLiteral("%1").arg(section); // return QStringLiteral("%1").arg(section);
} else } else
return ""; return "";
} }

View file

@ -1,7 +1,7 @@
#ifndef REPORT_MODEL_H #ifndef REPORT_MODEL_H
#define REPORT_MODEL_H #define REPORT_MODEL_H
#include <core/marketplace.h> #include <marketplace.h>
#include <QAbstractTableModel> #include <QAbstractTableModel>
@ -15,9 +15,9 @@ class ReportModel : public QAbstractTableModel
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
private: private:
Marketplace* m_market; Marketplace* market_;
int m_feeInPercent{}; int feeInPercent_{};
int m_maxFeeInCent{}; int maxFeeInCent_{};
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
#include "salemodel.h" #include "salemodel.h"
#include <core/article.h> #include <article.h>
#include <algorithm> #include <algorithm>
@ -9,7 +9,7 @@
SaleModel::SaleModel(Marketplace* market, QObject* parent) : QAbstractItemModel(parent) SaleModel::SaleModel(Marketplace* market, QObject* parent) : QAbstractItemModel(parent)
{ {
m_marketplace = market; marketplace_ = market;
} }
QModelIndex SaleModel::index(int row, int column, const QModelIndex& parent) const QModelIndex SaleModel::index(int row, int column, const QModelIndex& parent) const
@ -18,7 +18,7 @@ QModelIndex SaleModel::index(int row, int column, const QModelIndex& parent) con
return QModelIndex(); return QModelIndex();
if (!parent.isValid()) { if (!parent.isValid()) {
Sale* sale = m_marketplace->getSales().at(row).get(); Sale* sale = marketplace_->getSales().at(row).get();
return createIndex(row, column, sale); return createIndex(row, column, sale);
} else if (!parent.parent().isValid()) { } else if (!parent.parent().isValid()) {
Sale* sale = static_cast<Sale*>(parent.internalPointer()); Sale* sale = static_cast<Sale*>(parent.internalPointer());
@ -44,15 +44,15 @@ QModelIndex SaleModel::parent(const QModelIndex& index) const
Sale* sale{}; Sale* sale{};
Article* article{}; Article* article{};
EntityUuid* ent = static_cast<EntityUuid*>(index.internalPointer()); Entity* ent = static_cast<Entity*>(index.internalPointer());
sale = dynamic_cast<Sale*>(ent); sale = dynamic_cast<Sale*>(ent);
if (sale) { if (sale) {
if (sale == m_rootItem.get()) if (sale == rootItem.get())
return QModelIndex(); return QModelIndex();
else { else {
return createIndex(-1, 0, m_rootItem.get()); return createIndex(-1, 0, rootItem.get());
} }
} else { } else {
article = dynamic_cast<Article*>(ent); article = dynamic_cast<Article*>(ent);
@ -80,7 +80,7 @@ QVariant SaleModel::data(const QModelIndex& index, int role) const
if (role == Qt::FontRole) { if (role == Qt::FontRole) {
QFont myFont; QFont myFont;
QFont myFixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); QFont myFixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
if (myFixedFont.fixedPitch() == false) { if (myFixedFont.fixedPitch() == false) {
myFixedFont.setFamily("monospace"); myFixedFont.setFamily("monospace");
} }
@ -113,9 +113,7 @@ QVariant SaleModel::data(const QModelIndex& index, int role) const
Article* article = static_cast<Article*>(index.internalPointer()); Article* article = static_cast<Article*>(index.internalPointer());
switch (index.column()) { switch (index.column()) {
case 0: case 0:
return (std::string("Verk. ") + article->getSeller()->getSellerNoAsString() + " (" + return (std::string("Verk. ") + article->getSeller()->getSellerNoAsString() + " (" + article->getCompleteArticleNo() + ")").c_str();
article->getCompleteArticleNo() + ")")
.c_str();
case 1: case 1:
return article->getPriceAsString().c_str(); return article->getPriceAsString().c_str();
case 2: case 2:
@ -132,7 +130,7 @@ int SaleModel::rowCount(const QModelIndex& parent) const
return 0; return 0;
if (!parent.isValid()) { if (!parent.isValid()) {
return m_marketplace->getSales().size(); return marketplace_->getSales().size();
} else if (!parent.parent().isValid()) { } else if (!parent.parent().isValid()) {
Sale* sale = static_cast<Sale*>(parent.internalPointer()); Sale* sale = static_cast<Sale*>(parent.internalPointer());
return sale->getArticles().size(); return sale->getArticles().size();
@ -167,7 +165,7 @@ QVariant SaleModel::headerData(int section, Qt::Orientation orientation, int rol
void SaleModel::onBasketDataChanged() void SaleModel::onBasketDataChanged()
{ {
emit beginResetModel(); emit beginResetModel();
auto& sales = m_marketplace->getSales(); auto& sales = marketplace_->getSales();
std::sort(sales.begin(), sales.end(), [](const auto& lhs, const auto& rhs) { std::sort(sales.begin(), sales.end(), [](const auto& lhs, const auto& rhs) {
return lhs->getTimestamp() > rhs->getTimestamp(); return lhs->getTimestamp() > rhs->getTimestamp();
}); });
@ -179,11 +177,11 @@ bool SaleModel::removeRows(int row, int count, const QModelIndex& parent)
if (!parent.isValid()) { if (!parent.isValid()) {
// remove complete sale // remove complete sale
emit beginRemoveRows(parent, row, row + count - 1); emit beginRemoveRows(parent, row, row + count - 1);
auto& sale = m_marketplace->getSales().at(row); auto& sale = marketplace_->getSales().at(row);
sale->setState(Sale::State::DELETE); sale->setState(Sale::State::DELETE);
std::for_each(sale->getArticles().begin(), sale->getArticles().end(), std::for_each(sale->getArticles().begin(), sale->getArticles().end(),
[](auto& a) { a->setState(Article::State::DELETE); }); [](auto& a) { a->setState(Article::State::DELETE); });
m_marketplace->storeToDb(); marketplace_->storeToDb();
emit endRemoveRows(); emit endRemoveRows();
} else if (!parent.parent().isValid()) { } else if (!parent.parent().isValid()) {
@ -199,7 +197,7 @@ bool SaleModel::removeRows(int row, int count, const QModelIndex& parent)
sale->setState(Sale::State::DELETE); sale->setState(Sale::State::DELETE);
} }
emit beginRemoveRows(parent.parent(), 0, 0); emit beginRemoveRows(parent.parent(), 0, 0);
m_marketplace->storeToDb(); marketplace_->storeToDb();
emit endRemoveRows(); emit endRemoveRows();
} }

View file

@ -1,7 +1,7 @@
#ifndef SALEMODEL_H #ifndef SALEMODEL_H
#define SALEMODEL_H #define SALEMODEL_H
#include <core/marketplace.h> #include <marketplace.h>
#include <QAbstractItemModel> #include <QAbstractItemModel>
@ -12,7 +12,7 @@ class SaleModel : public QAbstractItemModel
public: public:
explicit SaleModel(Marketplace* market, QObject* parent = nullptr); explicit SaleModel(Marketplace* market, QObject* parent = nullptr);
virtual QModelIndex index(int row, int column, virtual QModelIndex index(int row, int column,
const QModelIndex& parent = QModelIndex()) const override; const QModelIndex& parent = QModelIndex()) const override;
virtual QModelIndex parent(const QModelIndex& index) const override; virtual QModelIndex parent(const QModelIndex& index) const override;
virtual QVariant data(const QModelIndex& index, int role) const override; virtual QVariant data(const QModelIndex& index, int role) const override;
virtual int rowCount(const QModelIndex& parent) const override; virtual int rowCount(const QModelIndex& parent) const override;
@ -24,8 +24,8 @@ class SaleModel : public QAbstractItemModel
void onBasketDataChanged(); void onBasketDataChanged();
private: private:
Marketplace* m_marketplace; Marketplace* marketplace_;
std::unique_ptr<Sale> m_rootItem{new Sale()}; std::unique_ptr<Sale> rootItem{new Sale()};
}; };
#endif #endif

View file

@ -7,25 +7,25 @@
SellerDialog::SellerDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) SellerDialog::SellerDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f)
{ {
m_ui.setupUi(this); ui_.setupUi(this);
m_ui.editButton->setVisible(false); ui_.editButton->setVisible(false);
m_market = dynamic_cast<MainWindow*>(parent)->getMarketplace(); market_ = dynamic_cast<MainWindow*>(parent)->getMarketplace();
m_model = std::make_unique<SellerModel>(m_market, m_ui.tableView); model_ = std::make_unique<SellerModel>(market_, ui_.tableView);
m_ui.tableView->setModel(m_model.get()); ui_.tableView->setModel(model_.get());
m_ui.tableView->setColumnHidden(0, true); // hide the uuid ui_.tableView->setColumnHidden(0, true); // hide the uuid
m_ui.tableView->setRowHidden(0, true); // hide the special "Sonderkonto" user ui_.tableView->setRowHidden(0, true); // hide the special "Sonderkonto" user
connect(m_ui.newButton, &QPushButton::clicked, this, &SellerDialog::on_newButton_clicked); connect(ui_.newButton, &QPushButton::clicked, this, &SellerDialog::on_newButton_clicked);
connect(m_ui.deleteButton, &QPushButton::clicked, this, &SellerDialog::on_deleteButton_clicked); connect(ui_.deleteButton, &QPushButton::clicked, this, &SellerDialog::on_deleteButton_clicked);
connect(m_model.get(), &SellerModel::duplicateSellerNo, this, connect(model_.get(), &SellerModel::duplicateSellerNo, this,
&SellerDialog::on_model_duplicateSellerNo); &SellerDialog::on_model_duplicateSellerNo);
connect(m_ui.tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, connect(ui_.tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&SellerDialog::onSellerViewSelectionChanged); &SellerDialog::onSellerViewSelectionChanged);
} }
void SellerDialog::on_newButton_clicked() void SellerDialog::on_newButton_clicked()
{ {
// Don't allow new seller if market has already started // Don't allow new seller if market has already started
if (m_market->getSales().size() > 0) { if (market_->getSales().size() > 0) {
QMessageBox(QMessageBox::Icon::Warning, "Hinweis", QMessageBox(QMessageBox::Icon::Warning, "Hinweis",
"Da die Verkaufsphase schon begonnen hat (Artikel wurden bereits verkauft) " "Da die Verkaufsphase schon begonnen hat (Artikel wurden bereits verkauft) "
"können Sie keine Verkäufer mehr hinzufügen.", "können Sie keine Verkäufer mehr hinzufügen.",
@ -34,22 +34,22 @@ void SellerDialog::on_newButton_clicked()
return; return;
} }
m_ui.tableView->reset(); ui_.tableView->reset();
m_ui.tableView->model()->insertRows(m_ui.tableView->model()->rowCount(), 1); ui_.tableView->model()->insertRows(ui_.tableView->model()->rowCount(), 1);
m_ui.tableView->scrollToBottom(); ui_.tableView->scrollToBottom();
m_ui.tableView->selectRow(m_ui.tableView->model()->rowCount() - 1); ui_.tableView->selectRow(ui_.tableView->model()->rowCount() - 1);
QModelIndex idx = m_ui.tableView->model()->index(m_ui.tableView->model()->rowCount() - 1, 2); QModelIndex idx = ui_.tableView->model()->index(ui_.tableView->model()->rowCount() - 1, 2);
m_ui.tableView->setCurrentIndex(idx); ui_.tableView->setCurrentIndex(idx);
m_ui.tableView->edit(idx); ui_.tableView->edit(idx);
} }
void SellerDialog::on_deleteButton_clicked() void SellerDialog::on_deleteButton_clicked()
{ {
auto selModel = m_ui.tableView->selectionModel(); auto selModel = ui_.tableView->selectionModel();
if (selModel->hasSelection() == false) if (selModel->hasSelection() == false)
return; return;
if (m_market->getSales().size() > 0) { if (market_->getSales().size() > 0) {
QMessageBox(QMessageBox::Icon::Warning, "Hinweis", QMessageBox(QMessageBox::Icon::Warning, "Hinweis",
"Da die Verkaufsphase schon begonnen hat (Artikel wurden bereits verkauft) " "Da die Verkaufsphase schon begonnen hat (Artikel wurden bereits verkauft) "
"können Sie keine Verkäufer mehr löschen.", "können Sie keine Verkäufer mehr löschen.",
@ -60,8 +60,7 @@ void SellerDialog::on_deleteButton_clicked()
auto dlgResult = auto dlgResult =
QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?", QMessageBox(QMessageBox::Icon::Warning, "Sind Sie sicher?",
"Löschen wirkt sich <b>sofort</b> auf die Datenbank aus. Sie können den " "Löschen wirkt sich direkt auf die Datenbank aus. Möchten Sie fortfahren?",
"Vorgang nicht rückgängig machen. Möchten Sie fortfahren?",
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this) QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, this)
.exec(); .exec();
if (dlgResult == QMessageBox::No) if (dlgResult == QMessageBox::No)
@ -72,7 +71,7 @@ void SellerDialog::on_deleteButton_clicked()
// Deleting the rows, beginning with the last one! // Deleting the rows, beginning with the last one!
for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) { for (auto iter = indexes.constEnd() - 1; iter >= indexes.constBegin(); --iter) {
m_ui.tableView->model()->removeRow(iter->row()); ui_.tableView->model()->removeRow(iter->row());
} }
} }
@ -102,8 +101,8 @@ void SellerDialog::onSellerViewSelectionChanged(const QItemSelection& selected,
[[maybe_unused]] const QItemSelection& deselected) [[maybe_unused]] const QItemSelection& deselected)
{ {
if (selected.size() > 0) { if (selected.size() > 0) {
m_ui.deleteButton->setEnabled(true); ui_.deleteButton->setEnabled(true);
} else { } else {
m_ui.deleteButton->setEnabled(false); ui_.deleteButton->setEnabled(false);
} }
} }

View file

@ -26,9 +26,9 @@ class SellerDialog : public QDialog
void on_deleteButton_clicked(); void on_deleteButton_clicked();
void on_model_duplicateSellerNo(const QString& message); void on_model_duplicateSellerNo(const QString& message);
virtual void accept() override; virtual void accept() override;
Ui::SellerDialog m_ui; Ui::SellerDialog ui_;
Marketplace* m_market; Marketplace* market_;
std::unique_ptr<SellerModel> m_model; std::unique_ptr<SellerModel> model_;
}; };
#endif #endif

View file

@ -5,13 +5,13 @@
#include <QMessageBox> #include <QMessageBox>
SellerModel::SellerModel(Marketplace* market, QObject* parent) SellerModel::SellerModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_marketplace(market) : QAbstractTableModel(parent), marketplace_(market)
{ {
} }
int SellerModel::rowCount([[maybe_unused]] const QModelIndex& parent) const int SellerModel::rowCount([[maybe_unused]] const QModelIndex& parent) const
{ {
return m_marketplace->getSellers().size(); return marketplace_->getSellers().size();
} }
int SellerModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 5; } int SellerModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 5; }
@ -21,14 +21,17 @@ QVariant SellerModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole) if (role != Qt::DisplayRole)
return QVariant(); return QVariant();
if (m_marketplace->getSellers().size() == 0) if (marketplace_->getSellers().size() == 0)
return QVariant(); return QVariant();
Seller* seller = m_marketplace->getSellers().at(index.row()).get(); Seller* seller = marketplace_->getSellers().at(index.row()).get();
/* if (seller->getState() == Seller::State::DELETE)
return QVariant();
*/
switch (index.column()) { switch (index.column()) {
case 0: case 0:
return seller->getId(); return seller->getUuidAsString().c_str();
case 1: case 1:
return seller->getSellerNo(); return seller->getSellerNo();
case 2: case 2:
@ -78,21 +81,21 @@ bool SellerModel::setData(const QModelIndex& index, const QVariant& value, int r
if (role != Qt::EditRole) if (role != Qt::EditRole)
return false; return false;
Seller* seller = m_marketplace->getSellers().at(index.row()).get(); Seller* seller = marketplace_->getSellers().at(index.row()).get();
switch (index.column()) { switch (index.column()) {
case 0: case 0:
seller->setId(value.toInt()); seller->setUuidFromString(value.toString().toStdString());
break; break;
case 1: { case 1: {
if (value.toInt() < 0) if (value.toInt() < 0)
return false; return false;
auto iter = auto iter =
std::find_if(m_marketplace->getSellers().begin(), m_marketplace->getSellers().end(), std::find_if(marketplace_->getSellers().begin(), marketplace_->getSellers().end(),
[&value](const std::unique_ptr<Seller>& s) { [&value](const std::unique_ptr<Seller>& s) {
return value.toInt() == s->getSellerNo(); return value.toInt() == s->getSellerNo();
}); });
if (iter != m_marketplace->getSellers().end()) { if (iter != marketplace_->getSellers().end()) {
emit duplicateSellerNo( emit duplicateSellerNo(
"Die Verkäufernummer muss eindeutig sein.\n(Möglicherweise wird die Nummer von " "Die Verkäufernummer muss eindeutig sein.\n(Möglicherweise wird die Nummer von "
"einem (ausgeblendeten) Eintrag, der zum Löschen vorgemerkt ist, verwendet.)"); "einem (ausgeblendeten) Eintrag, der zum Löschen vorgemerkt ist, verwendet.)");
@ -123,8 +126,9 @@ bool SellerModel::insertRows(int row, int count, const QModelIndex& parent)
{ {
emit beginInsertRows(parent, row, row + count - 1); emit beginInsertRows(parent, row, row + count - 1);
auto seller = std::make_unique<Seller>(); auto seller = std::make_unique<Seller>();
seller->setSellerNo(m_marketplace->getNextSellerNo()); seller->createUuid();
m_marketplace->getSellers().push_back(std::move(seller)); seller->setSellerNo(marketplace_->getNextSellerNo());
marketplace_->getSellers().push_back(std::move(seller));
emit endInsertRows(); emit endInsertRows();
return true; return true;
@ -132,24 +136,24 @@ bool SellerModel::insertRows(int row, int count, const QModelIndex& parent)
bool SellerModel::removeRows(int row, int count, const QModelIndex& parent) bool SellerModel::removeRows(int row, int count, const QModelIndex& parent)
{ {
auto seller = m_marketplace->getSellers().at(row).get(); auto seller = marketplace_->getSellers().at(row).get();
if (seller->getState() == Seller::State::NEW) { if (seller->getState() == Seller::State::NEW) {
emit beginRemoveRows(parent, row, row + count - 1); emit beginRemoveRows(parent, row, row + count - 1);
m_marketplace->getSellers().erase( marketplace_->getSellers().erase(
std::remove_if(m_marketplace->getSellers().begin(), m_marketplace->getSellers().end(), std::remove_if(marketplace_->getSellers().begin(), marketplace_->getSellers().end(),
[&seller](const std::unique_ptr<Seller>& a) { [&seller](const std::unique_ptr<Seller>& a) {
return a->getId() == seller->getId(); return a->getUuid() == seller->getUuid();
}), }),
m_marketplace->getSellers().end()); marketplace_->getSellers().end());
emit endRemoveRows(); emit endRemoveRows();
return true; return true;
} else { } else {
emit beginRemoveRows(parent, row, row + count - 1); emit beginRemoveRows(parent, row, row + count - 1);
seller->setState(Seller::State::DELETE); seller->setState(Seller::State::DELETE);
m_marketplace->storeToDb(true); marketplace_->storeToDb(true);
emit endRemoveRows(); emit endRemoveRows();
return true; return true;
} }
return false; return false;
} }

View file

@ -1,31 +1,30 @@
#ifndef SELLER_MODEL_H #ifndef SELLER_MODEL_H
#define SELLER_MODEL_H #define SELLER_MODEL_H
#include <core/marketplace.h> #include <marketplace.h>
#include <QAbstractTableModel> #include <QAbstractTableModel>
class SellerModel : public QAbstractTableModel class SellerModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SellerModel(Marketplace *market, QObject *parent = nullptr); explicit SellerModel(Marketplace* market, QObject* parent = nullptr);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override; virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
int role = Qt::EditRole) override; virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
signals: signals:
void duplicateSellerNo(const QString &message); void duplicateSellerNo(const QString& message);
private: private:
Marketplace *m_marketplace; Marketplace* marketplace_;
}; };
#endif #endif

View file

@ -2,10 +2,9 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <core/database.h> #include <database.h>
#include <core/utils.h> #include <posprinter.h>
#include <printer/posprinter.h> #include <utils.h>
#include <printer/utils.h>
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
@ -13,9 +12,9 @@
#include <QMessageBox> #include <QMessageBox>
#include <QSettings> #include <QSettings>
SettingsDialog::SettingsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) SettingsDialog::SettingsDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f)
{ {
m_ui.setupUi(this); ui_.setupUi(this);
QSettings settings{}; QSettings settings{};
int cashPointNo = settings.value("global/cashPointNo").toInt(); int cashPointNo = settings.value("global/cashPointNo").toInt();
@ -26,25 +25,25 @@ SettingsDialog::SettingsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(par
int maxFeeInEuro = settings.value("global/maxFeeInEuro").toInt(); int maxFeeInEuro = settings.value("global/maxFeeInEuro").toInt();
if (parent) if (parent)
m_market = dynamic_cast<MainWindow *>(parent)->getMarketplace(); market_ = dynamic_cast<MainWindow*>(parent)->getMarketplace();
m_ui.cashPointNoSpinBox->setValue(cashPointNo); ui_.cashPointNoSpinBox->setValue(cashPointNo);
m_ui.communeEdit->setText(commune); ui_.communeEdit->setText(commune);
m_ui.posPrinterDeviceEdit->setText(posPrinterDevice); ui_.posPrinterDeviceEdit->setText(posPrinterDevice);
m_ui.posPrinterEndpointEdit->setText(posPrinterEndpoint); ui_.posPrinterEndpointEdit->setText(posPrinterEndpoint);
m_ui.feePercentSpinBox->setValue(feeInPercent); ui_.feePercentSpinBox->setValue(feeInPercent);
m_ui.maxFeeSpinBox->setValue(maxFeeInEuro); ui_.maxFeeSpinBox->setValue(maxFeeInEuro);
connect(m_ui.testPosPrinterButton, &QPushButton::clicked, this, [this]() { connect(ui_.testPosPrinterButton, &QPushButton::clicked, this, [=]() {
using namespace std::string_literals; using namespace std::string_literals;
try { try {
if (m_ui.posPrinterDeviceEdit->text().isEmpty()) { if (ui_.posPrinterDeviceEdit->text().isEmpty()) {
PosPrinter printer; PosPrinter printer;
printer.printTest(); printer.printTest();
} else { } else {
std::string posPrinterDeviceString = m_ui.posPrinterDeviceEdit->text().toStdString(); std::string posPrinterDeviceString = ui_.posPrinterDeviceEdit->text().toStdString();
std::string posPrinterEndpointString = std::string posPrinterEndpointString =
m_ui.posPrinterEndpointEdit->text().toStdString(); ui_.posPrinterEndpointEdit->text().toStdString();
try { try {
auto printerDevice = auto printerDevice =
@ -55,7 +54,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(par
printer.printTest(); printer.printTest();
} }
} catch (std::exception &) { } catch (std::exception&) {
QMessageBox(QMessageBox::Icon::Warning, "Falsche Eingabe", QMessageBox(QMessageBox::Icon::Warning, "Falsche Eingabe",
QString("Eingabeformat für Device (hexadezimale IDs): " QString("Eingabeformat für Device (hexadezimale IDs): "
"<VendorID>:<ProductID>\nBeispiel: 0416:5011\n " "<VendorID>:<ProductID>\nBeispiel: 0416:5011\n "
@ -65,7 +64,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(par
return; return;
} }
} }
} catch (std::runtime_error &err) { } catch (std::runtime_error& err) {
QMessageBox(QMessageBox::Icon::Warning, "Bondrucker Fehler", QMessageBox(QMessageBox::Icon::Warning, "Bondrucker Fehler",
QString("Test schlug fehl: ") + err.what(), QMessageBox::StandardButton::Ok, QString("Test schlug fehl: ") + err.what(), QMessageBox::StandardButton::Ok,
this) this)
@ -80,17 +79,17 @@ void SettingsDialog::accept()
QSettings settings; QSettings settings;
int oldCashPointNo = settings.value("global/cashPointNo").toInt(); int oldCashPointNo = settings.value("global/cashPointNo").toInt();
int newCashPointNo = m_ui.cashPointNoSpinBox->value(); int newCashPointNo = ui_.cashPointNoSpinBox->value();
settings.setValue("global/commune", m_ui.communeEdit->text().trimmed()); settings.setValue("global/commune", ui_.communeEdit->text().trimmed());
settings.setValue("global/posPrinterDevice", m_ui.posPrinterDeviceEdit->text().trimmed()); settings.setValue("global/posPrinterDevice", ui_.posPrinterDeviceEdit->text().trimmed());
settings.setValue("global/posPrinterEndpoint", m_ui.posPrinterEndpointEdit->text().trimmed()); settings.setValue("global/posPrinterEndpoint", ui_.posPrinterEndpointEdit->text().trimmed());
settings.setValue("global/feeInPercent", m_ui.feePercentSpinBox->value()); settings.setValue("global/feeInPercent", ui_.feePercentSpinBox->value());
settings.setValue("global/maxFeeInEuro", m_ui.maxFeeSpinBox->value()); settings.setValue("global/maxFeeInEuro", ui_.maxFeeSpinBox->value());
if (oldCashPointNo != newCashPointNo) { if (oldCashPointNo != newCashPointNo) {
int result{0}; int result{0};
if (m_market && m_market->getSales().size() > 0) { if (market_ && market_->getSales().size() > 0) {
result = QMessageBox(QMessageBox::Icon::Question, "Sind Sie sicher?", result = QMessageBox(QMessageBox::Icon::Question, "Sind Sie sicher?",
"Möchten Sie die Kassen-Nr wirklich ändern? Diese muss über alle " "Möchten Sie die Kassen-Nr wirklich ändern? Diese muss über alle "
"Installationen hinweg eindeutig sein.", "Installationen hinweg eindeutig sein.",
@ -103,7 +102,7 @@ void SettingsDialog::accept()
if (result == QMessageBox::Yes) { if (result == QMessageBox::Yes) {
try { try {
Database().updateCashPointNo(oldCashPointNo, newCashPointNo); Database().updateCashPointNo(oldCashPointNo, newCashPointNo);
} catch (std::exception &ex) { } catch (std::exception& ex) {
std::string errMsg("Das Ändern der Kassen-Nr. ist fehlgeschlagen: "); std::string errMsg("Das Ändern der Kassen-Nr. ist fehlgeschlagen: ");
errMsg.append(ex.what()); errMsg.append(ex.what());
QMessageBox(QMessageBox::Icon::Critical, "Fehler", errMsg.c_str(), QMessageBox(QMessageBox::Icon::Critical, "Fehler", errMsg.c_str(),
@ -112,9 +111,9 @@ void SettingsDialog::accept()
QDialog::accept(); QDialog::accept();
return; return;
} }
settings.setValue("global/cashPointNo", m_ui.cashPointNoSpinBox->value()); settings.setValue("global/cashPointNo", ui_.cashPointNoSpinBox->value());
} }
} }
QDialog::accept(); QDialog::accept();
} }

View file

@ -3,14 +3,12 @@
#include "ui_settingsdialog.h" #include "ui_settingsdialog.h"
#include <core/marketplace.h> #include <marketplace.h>
#include <QDialog> #include <QDialog>
class SettingsDialog : public QDialog class SettingsDialog : public QDialog
{ {
Q_OBJECT
public: public:
SettingsDialog(QWidget* parent = nullptr, SettingsDialog(QWidget* parent = nullptr,
Qt::WindowFlags f = Qt::WindowTitleHint | Qt::WindowSystemMenuHint); Qt::WindowFlags f = Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@ -19,8 +17,8 @@ class SettingsDialog : public QDialog
void accept() override; void accept() override;
private: private:
Ui::SettingsDialog m_ui; Ui::SettingsDialog ui_;
Marketplace* m_market{}; Marketplace* market_{};
}; };
#endif #endif

View file

@ -1,3 +0,0 @@
subdir('core')
subdir('printer')
subdir('gui')

View file

@ -1,6 +1,6 @@
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
find_package(Boost 1.78 REQUIRED) find_package(Boost 1.62 REQUIRED)
if(WIN32) if(WIN32)
find_package(LIBUSB REQUIRED) find_package(LIBUSB REQUIRED)
@ -11,7 +11,6 @@ endif()
set(PRINTER_SOURCES set(PRINTER_SOURCES
posprinter.cpp posprinter.cpp
utils.cpp
) )
add_library(printer STATIC ${PRINTER_SOURCES}) add_library(printer STATIC ${PRINTER_SOURCES})
@ -20,4 +19,4 @@ if(WIN32)
else() else()
target_link_libraries(printer core ${LibUSB_LIBRARIES}) target_link_libraries(printer core ${LibUSB_LIBRARIES})
endif() endif()
target_include_directories(printer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. ${Boost_INCLUDE_DIRS}) target_include_directories(printer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -1,9 +0,0 @@
libusb = dependency('libusb-1.0')
src = ['posprinter.cpp', 'utils.cpp']
printer_inc = include_directories('..')
printer_lib = static_library('printer', src, dependencies: [libusb, core_dep])
printer_dep = declare_dependency(link_with : printer_lib, include_directories : printer_inc)

View file

@ -1,6 +1,6 @@
#include "posprinter.h" #include "posprinter.h"
#include <core/marketplace.h> #include <marketplace.h>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
@ -213,4 +213,4 @@ bool PosPrinter::isValid()
return true; return true;
else else
return false; return false;
} }

View file

@ -1,8 +1,8 @@
#ifndef POS_PRINTER_H #ifndef POS_PRINTER_H
#define POS_PRINTER_H #define POS_PRINTER_H
#include <core/sale.h> #include <sale.h>
#include <core/seller.h> #include <seller.h>
#include <memory> #include <memory>
@ -36,8 +36,7 @@ class PosPrinter
void printHeader(const std::string& commune = "Musterhausen"); void printHeader(const std::string& commune = "Musterhausen");
void printTest(); void printTest();
void printSaleReceipt(Sale* sale, const std::string& commune = "Dettingen"); void printSaleReceipt(Sale* sale, const std::string& commune = "Dettingen");
void printSellerReceipt(Seller* seller, const int percent, const int maxFeeInCent, void printSellerReceipt(Seller* seller, const int percent, const int maxFeeInCent, const std::string& commune = "Dettingen");
const std::string& commune = "Dettingen");
bool isValid(); bool isValid();
struct Command { struct Command {

View file

@ -1,26 +0,0 @@
#include "utils.h"
std::optional<PrinterDevice> convertToPosPrinterDevice(const std::string& device,
const std::string& endpoint)
{
if (device.empty()) {
return std::nullopt;
}
PrinterDevice printerDevice;
std::string delimiter = ":";
try {
printerDevice.idVendor = std::stoi(device.substr(0, device.find(delimiter)), 0, 16);
printerDevice.idProduct = std::stoi(device.substr(device.find(delimiter) + 1), 0, 16);
if (endpoint.empty()) {
printerDevice.endpoint = 0x03;
} else {
printerDevice.endpoint = std::stoi(endpoint, 0, 16);
}
} catch (std::exception& ex) {
throw ex;
}
return printerDevice;
}

View file

@ -1,12 +0,0 @@
#ifndef PRINTER_UTILS_H
#define PRINTER_UTILS_H
#include "posprinter.h"
#include <optional>
#include <string>
std::optional<PrinterDevice> convertToPosPrinterDevice(const std::string& vendor,
const std::string& endpoint);
#endif

@ -1 +0,0 @@
Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03

View file

@ -1,27 +0,0 @@
project('singleapplication')
qt5 = import('qt5')
dep_qt5 = dependency('qt5', modules: ['Core', 'Widgets', 'Network'])
singleapp_inc = include_directories('singleapplication.git')
singleapp_moc = qt5.preprocess(
moc_headers: ['singleapplication.git/singleapplication.h', 'singleapplication.git/singleapplication_p.h'],
moc_extra_arguments: ['-DQAPPLICATION_CLASS=QApplication'],
dependencies: dep_qt5
)
singleapp_lib = static_library('SingleApplication',
['singleapplication.git/singleapplication.cpp', 'singleapplication.git/singleapplication_p.cpp', singleapp_moc],
include_directories: singleapp_inc,
cpp_args : '-DQAPPLICATION_CLASS=QApplication',
dependencies: dep_qt5
)
singleapp_dep = declare_dependency(
include_directories: singleapp_inc,
link_with: singleapp_lib
)
# On windows, SingleApplication needs to be linked against advapi32. This is
# done by adding 'advapi32' to cpp_winlibs, where it should be by default.

@ -1 +0,0 @@
Subproject commit 8c48163c4d3fbba603cfe8a5b94046c9dad71825

View file

@ -9,14 +9,14 @@
BOOST_AUTO_TEST_CASE(create_uuid_nil) BOOST_AUTO_TEST_CASE(create_uuid_nil)
{ {
Seller seller{}; Seller seller{};
BOOST_TEST(seller.getId().is_nil() == true); BOOST_TEST(seller.getUuid().is_nil() == true);
} }
BOOST_AUTO_TEST_CASE(create_uuid) BOOST_AUTO_TEST_CASE(create_uuid)
{ {
Seller seller{}; Seller seller{};
seller.createUuid(); seller.createUuid();
BOOST_TEST(seller.getId().is_nil() == false); BOOST_TEST(seller.getUuid().is_nil() == false);
} }
BOOST_AUTO_TEST_CASE(create_many) BOOST_AUTO_TEST_CASE(create_many)
@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(create_many)
std::array<Seller, QUANTITY> sellers; std::array<Seller, QUANTITY> sellers;
for (unsigned i = 0; i < sellers.size(); i++) { for (unsigned i = 0; i < sellers.size(); i++) {
sellers[i] = Seller(); sellers[i] = Seller();
//sellers[i].createUuid(); sellers[i].createUuid();
} }
} }
@ -37,4 +37,4 @@ BOOST_AUTO_TEST_CASE(with_article) {
BOOST_TEST((article == nullptr)); BOOST_TEST((article == nullptr));
BOOST_TEST(seller.getArticles(false).at(0)->getDescription() == "Test article"); BOOST_TEST(seller.getArticles(false).at(0)->getDescription() == "Test article");
BOOST_TEST(seller.numArticlesSold() == 0); BOOST_TEST(seller.numArticlesSold() == 0);
} }