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

3
.gitignore vendored
View file

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

7
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "subprojects/nlohmann_json"]
path = subprojects/nlohmann_json
[submodule "3rdparty/nlohmann_json"]
path = 3rdparty/nlohmann_json
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",
"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",
"mutex": "cpp",
"hash_map": "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"
"future": "cpp"
},
"C_Cpp.clang_format_path": "/usr/bin/clang-format",
"cmake.configureOnOpen": true,
"C_Cpp.configurationWarnings": "Disabled",
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true,
"**/.hg/store/**": true,
".flatpak/**": true,
"_build/**": true
}
"C_Cpp.configurationWarnings": "Disabled"
}

View file

@ -2,4 +2,3 @@ if(NOT KIMA2_USE_EXTERNAL_JSON)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json EXCLUDE_FROM_ALL)
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)
#include(InstallRequiredSystemLibraries)
@ -12,12 +12,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(MSVC)
add_compile_options(/W4 /WX)
else()
#add_compile_options(-Wall -Wextra -pedantic -Woverloaded-virtual -Wredundant-decls -Wshadow)
add_compile_options(-Wall -Wextra)
add_compile_options(-Wall -Wextra -pedantic -Woverloaded-virtual -Wredundant-decls -Wshadow)
endif()
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_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@ -29,14 +27,14 @@ if(KIMA2_USE_EXTERNAL_JSON)
find_package(nlohmann_json REQUIRED)
endif()
add_subdirectory(subprojects)
add_subdirectory(3rdparty)
add_subdirectory(src)
#if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES Debug)
# include(CTest)
# enable_testing()
# add_subdirectory(test)
#endif()
if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES Debug)
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
# CPack
@ -80,8 +78,6 @@ else(WIN32 AND NOT UNIX)
DESTINATION share/${PROJECT_NAME})
install(FILES "${CMAKE_SOURCE_DIR}/misc/kima2.svg"
DESTINATION share/icons/hicolor/scalable/apps)
install(FILES de.rustysoft.kima2.metainfo.xml
DESTINATION share/metainfo)
endif (WIN32 AND NOT UNIX)
if( MINGW )
@ -90,19 +86,18 @@ if( MINGW )
set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
${MINGW_PATH}/libstdc++-6.dll
${MINGW_PATH}/libgcc_s_seh-1.dll
${MINGW_PATH}/Qt6Core.dll
${MINGW_PATH}/Qt6Gui.dll
${MINGW_PATH}/Qt6Widgets.dll
${MINGW_PATH}/Qt6PrintSupport.dll
${MINGW_PATH}/Qt6Network.dll
${MINGW_PATH}/Qt5Core.dll
${MINGW_PATH}/Qt5Gui.dll
${MINGW_PATH}/Qt5Widgets.dll
${MINGW_PATH}/Qt5PrintSupport.dll
${MINGW_PATH}/libwinpthread-1.dll
${MINGW_PATH}/libsqlite3-0.dll
${MINGW_PATH}/libusb-1.0.dll
${MINGW_PATH}/libicuuc75.dll
${MINGW_PATH}/libicuin75.dll
${MINGW_PATH}/libicudt75.dll
${MINGW_PATH}/libxlnt.dll
${MINGW_PATH}/libicuuc62.dll
${MINGW_PATH}/libicuin62.dll
${MINGW_PATH}/libicudt62.dll
${MINGW_PATH}/libpcre2-16-0.dll
${MINGW_PATH}/libpcre2-8-0.dll
${MINGW_PATH}/zlib1.dll
${MINGW_PATH}/libharfbuzz-0.dll
${MINGW_PATH}/libpng16-16.dll
@ -112,26 +107,20 @@ if( MINGW )
${MINGW_PATH}/libbz2-1.dll
${MINGW_PATH}/libintl-8.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)
install(FILES ${MINGW_PATH}/../share/qt6/plugins/platforms/qwindows.dll
${MINGW_PATH}/../share/qt6/plugins/platforms/qminimal.dll
install(FILES ${MINGW_PATH}/../share/qt5/plugins/platforms/qwindows.dll
${MINGW_PATH}/../share/qt5/plugins/platforms/qminimal.dll
DESTINATION bin/platforms)
#install(FILES ${MINGW_PATH}/../share/qt6/plugins/printsupport/windowsprintersupport.dll
# DESTINATION bin/printsupport)
install(FILES ${MINGW_PATH}/../share/qt6/translations/qtbase_de.qm
${MINGW_PATH}/../share/qt6/translations/qt_de.qm
${MINGW_PATH}/../share/qt6/translations/qt_help_de.qm
${MINGW_PATH}/../share/qt6/translations/qtmultimedia_de.qm
DESTINATION bin/share/qt6/translations)
install(FILES ${MINGW_PATH}/../share/qt6/plugins/styles/qmodernwindowsstyle.dll
DESTINATION bin/styles)
install(FILES ${MINGW_PATH}/../share/qt5/plugins/printsupport/windowsprintersupport.dll
DESTINATION bin/printsupport)
install(FILES ${MINGW_PATH}/../share/qt5/translations/qtbase_de.qm
${MINGW_PATH}/../share/qt5/translations/qt_de.qm
${MINGW_PATH}/../share/qt5/translations/qt_help_de.qm
${MINGW_PATH}/../share/qt5/translations/qtmultimedia_de.qm
${MINGW_PATH}/../share/qt5/translations/qtquick1_de.qm
${MINGW_PATH}/../share/qt5/translations/qtscript_de.qm
${MINGW_PATH}/../share/qt5/translations/qtxmlpatterns_de.qm
DESTINATION bin/translations)
endif( MINGW )
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
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.
## 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:
* Qt 6
* boost >= 1.80
* Qt5
* boost >= 1.62
* libusb-1.0
* xlnt >= 1.3.0
* 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:
```

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>
pkgname=kima2
pkgver=1.7.1
pkgver=0.13.0
pkgrel=1
pkgdesc="A small cash point program for children's things markets (German only)"
arch=('i686' 'x86_64')
url="http://www.rustysoft.de/software/kima2"
url="http://www.rustysoft.de/?01_kima2"
license=('custom')
depends=('glibc' 'libusb' 'qt6-base' 'sqlite3')
depends=('glibc' 'libusb' 'qt5-base' 'sqlite3' 'xlnt')
makedepends=('boost>=1.62')
source=(git+https://git.rustysoft.de/martin/kima2)
sha256sums=('SKIP')
source=($pkgname-$pkgver.tar.gz)
md5sums=('')
build() {
cd $pkgname
git checkout v$pkgver
git submodule init
git submodule update
if [ -d build ]; then
rm -rf build
if [ ! -d $pkgname/build ]; then
mkdir $pkgname/build
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
}
package() {
cd $pkgname/build
make DESTDIR="$pkgdir" install
make install
cd ..
install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}

View file

@ -3,8 +3,8 @@ Type=Application
Name=KIMA2
GenericName=Cash Point Program
GenericName[de]=Kassenprogramm
Comment=A small cash point program for children's stuff markets
Comment[de]=Ein kleines Kassenprogramm für Kindersachenmärkte
Comment=A small cash point program
Comment[de]=Ein kleines Kassenprogramm
Exec=kima2
Icon=kima2
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)
find_package(Boost 1.78 REQUIRED)
find_package(Boost 1.62 COMPONENTS date_time REQUIRED)
find_package(SQLite3 REQUIRED)
# Because csv-parser needs threads:
find_package(fmt)
if (MINGW)
find_package(XLNT REQUIRED STATIC)
else (MINGW)
find_package(PkgConfig REQUIRED)
pkg_check_modules(XLNT REQUIRED xlnt>=1.3)
endif (MINGW)
set(CORE_SOURCES
database.cpp
entity.cpp
entityint.cpp
entityuuid.cpp
seller.cpp
article.cpp
sale.cpp
marketplace.cpp
csvreader.cpp
excelreader.cpp
jsonutil.cpp
utils.cpp
)
add_library(core STATIC ${CORE_SOURCES})
#target_include_directories(core PRIVATE ${PROJECT_SOURCE_DIR}/subprojects/csv-parser/single_include)
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)
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()
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 "seller.h"
#include "utils.h"
#include <iomanip>
#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; }
Sale *Article::getSale() { return m_salePtr; }
bool Article::isSold() { return salePtr_ ? true : false; }
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::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();
}

View file

@ -1,7 +1,9 @@
#ifndef ARTICLE_H
#define ARTICLE_H
#include "entityuuid.h"
#include "entity.h"
//#include "sale.h"
//#include "seller.h"
#include <memory>
#include <string>
@ -9,13 +11,12 @@
class Seller;
class Sale;
class Article : public EntityUuid
class Article : public Entity
{
public:
Article() = default;
Article(int price);
Article(const Article &) = delete;
virtual ~Article() = default;
//virtual ~Article() = default;
void setArticleNo(int articleNo);
void setPrice(int price);
@ -33,11 +34,11 @@ public:
std::string getPriceAsString() const;
private:
Seller *m_sellerPtr{};
Sale *m_salePtr{};
int m_articleNo{};
int m_price{};
std::string m_description{};
Seller* sellerPtr_{};
Sale* salePtr_{};
int articleNo_{};
int price_{};
std::string description_{};
};
#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,12 +1,12 @@
#include "database.h"
#include <chrono>
#include <filesystem>
#include <format>
#include <iostream>
#include <stdexcept>
#include <vector>
#include "boost/date_time/posix_time/posix_time.hpp"
Database::Database(const std::string& dbname)
{
dbname_ = dbname;
@ -45,11 +45,8 @@ void Database::newDb()
fs::path sourcePath = dbname_;
fs::path destPath = sourcePath.parent_path() / sourcePath.stem();
auto chronoTime = std::chrono::system_clock::now();
std::string timeString = std::format("{0:%FT%H-%M-%S}", chronoTime);
destPath += std::string("_") += timeString += ".db";
destPath += std::string("_") +=
boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) += ".db";
fs::copy_file(sourcePath, destPath, fs::copy_options::overwrite_existing);
@ -78,10 +75,11 @@ void Database::createNew()
std::string sqlCreateKima2{"CREATE TABLE IF NOT EXISTS kima2 ("
"version INTEGER NOT NULL);"
"INSERT INTO kima2 (version) VALUES (3);"};
"INSERT INTO kima2 (version) VALUES (2);"};
sqlStrings.push_back(sqlCreateKima2);
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, "
"last_name TEXT, "
"num_offered_articles INTEGER, "
@ -91,13 +89,13 @@ void Database::createNew()
std::string sqlCreateArticles{
"CREATE TABLE IF NOT EXISTS articles ("
"id TEXT PRIMARY KEY NOT NULL, "
"seller_no TEXT NOT NULL, "
"seller_id TEXT NOT NULL, "
"source_no INTEGER NOT NULL, "
"article_no INTEGER NOT NULL, "
"description TEXT, "
"price INTEGER NOT NULL, "
"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)"
");"};
sqlStrings.push_back(sqlCreateArticles);
@ -117,9 +115,9 @@ void Database::createNew()
sqlStrings.push_back(sqlCreateSalesItems);
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 "
"(0, 'Sonderkonto', 'Sonderkonto', 0)"};
"('11111111-1111-1111-1111-111111111111', 0, 'Sonderkonto', 'Sonderkonto', 0)"};
sqlStrings.push_back(sqlInitialEntries);
beginTransaction();
@ -132,15 +130,13 @@ void Database::createNew()
void Database::updateDbToVer2()
{
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 "
"(0, 'Sonderkonto', 'Sonderkonto', 0)");
exec("UPDATE kima2 SET version = 3");
"('11111111-1111-1111-1111-111111111111', 0, 'Sonderkonto', 'Sonderkonto', 0)");
exec("UPDATE kima2 SET version = 2");
endTransaction();
}
void Database::updateDbToVer3() { newDb(); }
void Database::init()
{
const int errCode = sqlite3_open(dbname_.c_str(), &db_);
@ -156,19 +152,12 @@ void Database::init()
switch (version) {
case 0:
createNew();
initResult_ = InitResult::OK;
break;
case 1:
updateDbToVer3();
initResult_ = InitResult::OUTDATED_REPLACED;
break;
case 2:
updateDbToVer3();
initResult_ = InitResult::OUTDATED_REPLACED;
updateDbToVer2();
break;
default:
// Do nothing because we are up-to-date.
initResult_ = InitResult::OK;
break;
}
}
@ -236,13 +225,16 @@ unsigned int Database::storeSellers(std::vector<std::unique_ptr<Seller>> &seller
retCode = sqlite3_prepare_v2(
db_,
"INSERT INTO sellers"
" (seller_no, first_name, last_name, num_offered_articles)"
" VALUES (:seller_no, :first_name, :last_name, :num_offered_articles)",
" (id, seller_no, first_name, last_name, num_offered_articles)"
" VALUES (:uuid, :seller_no, :first_name, :last_name, :num_offered_articles)",
-1, &stmt, nullptr);
if (retCode != SQLITE_OK)
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"),
seller->getSellerNo());
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"
" seller_no = :seller_no, first_name = :first_name,"
" last_name = :last_name, num_offered_articles = :num_offered_articles"
" WHERE seller_no = :id",
" WHERE id = :uuid",
-1, &stmt, nullptr);
if (retCode != SQLITE_OK)
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"),
seller->getSellerNo());
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) {
count += static_cast<int>(seller->getArticles(false).size());
retCode = sqlite3_prepare_v2(db_, "DELETE FROM sellers WHERE seller_no = :id", -1,
&stmt, nullptr);
retCode =
sqlite3_prepare_v2(db_, "DELETE FROM sellers WHERE id = :uuid", -1, &stmt, nullptr);
if (retCode != SQLITE_OK)
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);
@ -350,7 +346,7 @@ unsigned int Database::storeArticles(std::vector<Article *> articles)
retCode = sqlite3_prepare_v2(
db_,
"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)",
-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"),
boost::uuids::to_string(article->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
article->getSeller()->getId());
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
boost::uuids::to_string(article->getSeller()->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"),
article->getSourceNo());
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(
db_,
"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"
" WHERE id = :uuid",
-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"),
boost::uuids::to_string(article->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
article->getSeller()->getId());
sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":seller_id"),
boost::uuids::to_string(article->getSeller()->getUuid()).c_str(), -1,
SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":source_no"),
article->getSourceNo());
sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, ":article_no"),
@ -555,7 +553,7 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
sqlite3_stmt* stmt;
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",
-1, &stmt, nullptr);
if (retCode != SQLITE_OK)
@ -568,10 +566,11 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
while (retCode != SQLITE_DONE) {
++count;
auto seller = std::make_unique<Seller>();
seller->setSellerNo(sqlite3_column_int(stmt, 0));
seller->setFirstName(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)));
seller->setLastName(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)));
seller->setNumArticlesOffered(sqlite3_column_int(stmt, 3));
seller->setUuidFromString(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
seller->setSellerNo(sqlite3_column_int(stmt, 1));
seller->setFirstName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
seller->setLastName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
seller->setNumArticlesOffered(sqlite3_column_int(stmt, 4));
seller->setState(Seller::State::OK);
sellers.push_back(std::move(seller));
@ -584,21 +583,21 @@ unsigned int Database::loadSellers(std::vector<std::unique_ptr<Seller>> &sellers
retCode = sqlite3_prepare_v2(db_,
"SELECT id, source_no, article_no, description, price"
" FROM articles"
" WHERE seller_no = :seller_id"
" WHERE seller_id = :seller_uuid"
" ORDER BY article_no",
-1, &stmt, nullptr);
if (retCode != SQLITE_OK)
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);
while (retCode != SQLITE_DONE) {
++count;
auto article = std::make_unique<Article>();
article->setUuidFromString(
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
article->setUuidFromString(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
article->setSeller(seller.get());
article->setSourceNo(sqlite3_column_int(stmt, 1));
article->setArticleNo(sqlite3_column_int(stmt, 2));

View file

@ -11,7 +11,6 @@
class Database
{
public:
enum class InitResult { OK, OUTDATED_REPLACED };
explicit Database(const std::string& dbname);
Database();
~Database();
@ -26,7 +25,6 @@ public:
std::vector<std::unique_ptr<Seller>>& sellers);
void updateCashPointNo(int oldCashPointNo, int newCashPointNo);
void newDb();
InitResult getInitResult() { return initResult_; }
private:
sqlite3* db_{nullptr};
@ -38,8 +36,6 @@ private:
int getVersion();
unsigned int storeArticles(std::vector<Article*> articles);
void updateDbToVer2();
void updateDbToVer3();
InitResult initResult_{InitResult::OK};
};
#endif // DATABASE_H

View file

@ -1,3 +1,33 @@
#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
#define ENTITY_H
#include <string>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
class Entity
{
public:
enum class State { NEW, UPDATE, DELETE, OK };
virtual ~Entity() = default;
void setState(State state) { m_state = state; }
// Entity() = default;
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:
State m_state{State::NEW};
boost::uuids::uuid uuid_{};
State state_{State::NEW};
};
#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,6 +5,7 @@
#include <fstream>
namespace fs = std::filesystem;
using json = nlohmann::json;
void JsonUtil::exportSellers(const std::filesystem::path& filePath, Marketplace* market)
@ -14,6 +15,7 @@ void JsonUtil::exportSellers(const std::filesystem::path &filePath, Marketplace
for (const auto& seller : market->getSellers()) {
json newEntry;
newEntry["uuid"] = seller->getUuidAsString();
newEntry["seller_no"] = seller->getSellerNo();
newEntry["last_name"] = seller->getLastName();
newEntry["first_name"] = seller->getFirstName();
@ -24,7 +26,7 @@ void JsonUtil::exportSellers(const std::filesystem::path &filePath, Marketplace
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()) {
seller->setState(Seller::State::DELETE);
@ -36,6 +38,7 @@ std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marke
for (auto val : jsonValues["sellers"]) {
auto seller = std::make_unique<Seller>();
seller->setUuidFromString(val["uuid"]);
seller->setSellerNo(val["seller_no"]);
seller->setLastName(val["last_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
auto specialSeller = market->findSellerWithSellerNo(0);
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");
@ -55,13 +59,11 @@ std::size_t JsonUtil::importSellers(const std::filesystem::path &filePath, Marke
}
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,
int cashPointNo)
void JsonUtil::exportSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo)
{
json root;
std::ofstream file(filePath);
@ -79,7 +81,7 @@ void JsonUtil::exportSales(const std::filesystem::path &filePath, Marketplace *m
for (const auto& article : sale->getArticles()) {
json newArticle;
newArticle["uuid"] = article->getUuidAsString();
newArticle["seller_no"] = article->getSeller()->getSellerNo();
newArticle["seller_uuid"] = article->getSeller()->getUuidAsString();
newArticle["desc"] = article->getDescription();
newArticle["price"] = article->getPrice();
// newArticle["source_no"] = article->getSourceNo();
@ -94,18 +96,15 @@ void JsonUtil::exportSales(const std::filesystem::path &filePath, Marketplace *m
file << root.dump(4) << std::endl;
}
void JsonUtil::importSales(const std::filesystem::path &filePath, Marketplace *market,
int cashPointNo)
void JsonUtil::importSales(const std::filesystem::path& filePath, Marketplace* market, int cashPointNo)
{
std::ifstream file(filePath);
json jsonValues = json::parse(file);
int source_no = jsonValues["source_no"];
if (source_no == cashPointNo) {
std::string ret = "Die Kassen-Nr. ";
ret += std::to_string(source_no);
ret += " der zu imporierenden Daten wird von dieser Kasse hier bereits verwendet.";
throw std::runtime_error(ret);
throw std::runtime_error("Die Kassen-Nr. der zu imporierenden Daten wird von dieser Kasse "
"hier bereits verwendet.");
}
market->setSalesToDelete(jsonValues["source_no"]);
@ -123,7 +122,7 @@ void JsonUtil::importSales(const std::filesystem::path &filePath, Marketplace *m
article->setArticleNo(valArticle["article_no"]);
article->setDescription(valArticle["desc"]);
article->setPrice(valArticle["price"]);
auto seller = market->findSellerWithSellerNo(valArticle["seller_no"]);
auto seller = market->findSellerWithUuid(valArticle["seller_uuid"]);
if (seller == nullptr) {
throw std::runtime_error(
"Die zu importierenden Daten verweisen auf einen nicht vorhandenen Verkäufer. "

View file

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

View file

@ -3,19 +3,19 @@
#include "utils.h"
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <filesystem>
namespace fs = std::filesystem;
Marketplace::Marketplace()
{
/*auto seller = std::make_unique<Seller>("Max", "Mustermann");
auto seller = std::make_unique<Seller>("Max", "Mustermann");
seller->createUuid();
sellers_.push_back(std::move(seller)); */
sellers_.push_back(std::move(seller));
}
void Marketplace::storeToDb(bool onlyDelete)
@ -25,12 +25,11 @@ void Marketplace::storeToDb(bool onlyDelete)
db.storeSales(sales_);
}
Database::InitResult Marketplace::loadFromDb()
void Marketplace::loadFromDb()
{
Database db;
db.loadSellers(sellers_);
db.loadSales(sales_, sellers_);
return db.getInitResult();
}
SellersVec& Marketplace::getSellers() { return sellers_; }
@ -104,10 +103,18 @@ Seller *Marketplace::findSellerWithSellerNo(int sellerNo)
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())
return nullptr;
return (*iter).get();
}
void Marketplace::addArticleToBasket(std::unique_ptr<Article> article)
{
basket_.insert(basket_.begin(),
std::move(article)); // article to the beginning of the basket vector
basket_.insert(basket_.begin(), std::move(article)); // article to the beginning of the basket vector
}
size_t Marketplace::basketSize() { return basket_.size(); }
@ -166,7 +173,7 @@ void Marketplace::setSalesToDelete(int cashPointNo)
void Marketplace::exportReportToCSV(const fs::path& filePath, int feeInPercent, int maxFeeInEuro)
{
const char delimiter = ';';
const char delimiter = ',';
std::ofstream file(filePath);
file << "Verk.Nr." << delimiter << "Nachname" << delimiter << "Vorname" << delimiter
@ -179,8 +186,7 @@ void Marketplace::exportReportToCSV(const fs::path &filePath, int feeInPercent,
<< escapeCsvValue(seller->getFirstName(), delimiter) << delimiter
<< seller->numArticlesOffered() << delimiter << seller->numArticlesSold() << delimiter
<< escapeCsvValue(seller->sumAsString(), delimiter) << delimiter
<< escapeCsvValue(
paymentAsString(seller->sumInCents(), feeInPercent, maxFeeInEuro * 100),
<< escapeCsvValue(paymentAsString(seller->sumInCents(), feeInPercent, maxFeeInEuro * 100),
delimiter)
<< "\n";
}

View file

@ -2,7 +2,6 @@
#define MARKETPLACE_H
#include "article.h"
#include "database.h"
#include "sale.h"
#include "seller.h"
@ -24,7 +23,7 @@ public:
Marketplace();
void storeToDb(bool onlyDelete = false);
Database::InitResult loadFromDb();
void loadFromDb();
SellersVec& getSellers();
SalesVec& getSales();

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

@ -6,38 +6,40 @@
void Sale::addArticle(Article* articlePtr)
{
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)
{
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)->setState(
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 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(); });
return sum;
}
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
{
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);
}

View file

@ -14,12 +14,9 @@ namespace
using ArticlesVec = std::vector<Article*>;
}
class Sale : public EntityUuid
class Sale : public Entity
{
public:
Sale() = default;
Sale(const Sale &) = delete;
virtual ~Sale() = default;
void addArticle(Article* articlePtr);
void setTimestamp(const std::string& timestamp);
@ -32,9 +29,9 @@ public:
void removeArticle(const Article* articlePtr);
private:
std::string m_timestamp{
std::string timestamp_{
boost::posix_time::to_iso_extended_string(boost::posix_time::second_clock::local_time())};
mutable ArticlesVec m_articles{};
mutable ArticlesVec articles_{};
};
#endif

View file

@ -7,38 +7,39 @@
Seller::Seller(const std::string& firstName, const std::string& lastName, int sellerNo,
int numArticlesOffered)
: EntityInt(sellerNo)
: Entity()
{
m_firstName = firstName;
m_lastName = lastName;
m_numArticlesOffered = numArticlesOffered;
firstName_ = firstName;
lastName_ = lastName;
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)
{
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::stringstream selNoStr;
selNoStr << std::setfill('0') << std::setw(3) << m_id;
selNoStr << std::setfill('0') << std::setw(3) << sellerNo_;
return selNoStr.str();
;
@ -47,7 +48,7 @@ std::string Seller::getSellerNoAsString() const
std::vector<Article*> Seller::getArticles(bool onlySold) const
{
std::vector<Article*> articles;
for (const auto &article : m_articles) {
for (const auto& article : articles_) {
if (onlySold && article->isSold()) {
articles.push_back(article.get());
} else if (!onlySold) {
@ -59,52 +60,52 @@ std::vector<Article *> Seller::getArticles(bool onlySold) const
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;
});
if (iter == m_articles.end())
if (iter == articles_.end())
return nullptr;
return (*iter).get();
}
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
{
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(); });
if (iter == m_articles.end())
if (iter == articles_.end())
return 0;
return (*iter)->getArticleNo();
}
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) {
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);
}
}
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(); });
return sum;
}
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)
{
return li->m_id < re->m_id;
return li->sellerNo_ < re->sellerNo_;
}

View file

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

View file

@ -1,23 +1,15 @@
#include "utils.h"
#include <algorithm>
#include <clocale>
#include <format>
#include <iomanip>
#include <numeric>
#include <iostream>
//using namespace fmt;
std::string formatCentAsEuroString(const int cent, int width)
{
/*std::stringstream currStream;
std::stringstream currStream;
try {
std::locale myLocale("de_DE.utf8");
currStream.imbue(myLocale);
std::cout << ">>> " << fmt::format(myLocale, "{:6.2Lf}", 1.12345) << '\n';
currStream << std::right << std::setw(width) << std::showbase
<< std::put_money(cent, false);
} catch (std::runtime_error& err) {
@ -25,46 +17,30 @@ std::string formatCentAsEuroString(const int cent, int width)
<< std::setprecision(2) << cent / 100.0L << "";
}
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);
return currStream.str();
}
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));
return str;
if (device.empty()) {
return std::nullopt;
}
std::string &rtrim(std::string &str, const std::string &chars)
{
str.erase(str.find_last_not_of(chars) + 1);
return str;
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);
}
std::string &trim(std::string &str, const std::string &chars)
{
return ltrim(rtrim(str, chars), chars);
} catch (std::exception& ex) {
throw ex;
}
bool case_insensitive_match(std::string s1, std::string s2)
{
// 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();
return printerDevice;
}

View file

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

View file

@ -8,14 +8,8 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
# Find the QtWidgets library
find_package(Qt6 COMPONENTS Widgets Network PrintSupport CONFIG REQUIRED)
#find_package(Qt5Widgets 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})
find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5PrintSupport CONFIG REQUIRED)
set(GUI_SOURCES
kima2.cpp
@ -34,16 +28,11 @@ set(GUI_SOURCES
settingsdialog.cpp
settingsdialog.ui
../../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)
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 Qt5::Network stdc++fs)
target_link_libraries(kima2 core printer Qt::Core Qt::PrintSupport Qt::Network)
target_link_libraries(kima2 core printer Qt5::Widgets Qt5::PrintSupport stdc++fs)
if(WIN32)
set_target_properties(kima2 PROPERTIES LINK_FLAGS "-mwindows")
endif(WIN32)

View file

@ -1,17 +1,17 @@
#include "basketmodel.h"
#include <QFont>
#include <QFontDatabase>
#include <QSettings>
#include <QFontDatabase>
BasketModel::BasketModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_marketplace(market)
: QAbstractTableModel(parent), marketplace_(market)
{
}
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; }
@ -46,10 +46,10 @@ QVariant BasketModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole)
return QVariant();
if (m_marketplace->basketSize() == 0)
if (marketplace_->basketSize() == 0)
return QVariant();
Article* article = m_marketplace->getBasket().at(index.row()).get();
Article* article = marketplace_->getBasket().at(index.row()).get();
switch (index.column()) {
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)
{
emit beginInsertRows(QModelIndex(), m_marketplace->getBasket().size(),
m_marketplace->getBasket().size());
emit beginInsertRows(QModelIndex(), marketplace_->getBasket().size(),
marketplace_->getBasket().size());
auto article = std::make_unique<Article>(price);
article->createUuid();
article->setDescription(desc);
article->setArticleNo(m_marketplace->getNextArticleNo());
article->setArticleNo(marketplace_->getNextArticleNo());
article->setSourceNo(QSettings().value("global/cashPointNo").toInt());
article->setSeller(seller);
m_marketplace->addArticleToBasket(std::move(article));
marketplace_->addArticleToBasket(std::move(article));
emit endInsertRows();
}
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>();
sale->createUuid();
sale->setSourceNo(QSettings().value("global/cashPointNo").toInt());
m_marketplace->finishCurrentSale(std::move(sale));
marketplace_->finishCurrentSale(std::move(sale));
emit endRemoveRows();
emit basketDataChanged();
}
void BasketModel::cancelSale()
{
emit beginRemoveRows(QModelIndex(), 0, m_marketplace->getBasket().size() - 1);
m_marketplace->getBasket().clear();
emit beginRemoveRows(QModelIndex(), 0, marketplace_->getBasket().size() - 1);
marketplace_->getBasket().clear();
emit endRemoveRows();
}
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);
m_marketplace->getBasket().erase(
std::remove_if(m_marketplace->getBasket().begin(), m_marketplace->getBasket().end(),
marketplace_->getBasket().erase(
std::remove_if(marketplace_->getBasket().begin(), marketplace_->getBasket().end(),
[&article](const auto& a) { return a->getUuid() == article->getUuid(); }),
m_marketplace->getBasket().end());
marketplace_->getBasket().end());
emit endRemoveRows();
return true;
}

View file

@ -1,7 +1,7 @@
#ifndef BASKET_MODEL_H
#define BASKET_MODEL_H
#include <core/marketplace.h>
#include <marketplace.h>
#include <QAbstractTableModel>
@ -15,6 +15,9 @@ class BasketModel : public QAbstractTableModel
virtual int columnCount(const QModelIndex& parent = QModelIndex()) 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 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 finishSale();
void cancelSale();
@ -24,7 +27,7 @@ class BasketModel : public QAbstractTableModel
void basketDataChanged();
private:
Marketplace* m_marketplace;
Marketplace* marketplace_;
};
#endif

View file

@ -6,27 +6,26 @@
#include <QLibraryInfo>
#include <QMessageBox>
#include <QSettings>
#include <QSharedMemory>
#include <QStyleFactory>
#include <QTranslator>
#include <singleapplication.h>
#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::setOrganizationDomain("rustysoft.de");
QCoreApplication::setApplicationName("kima2");
QTranslator qtTranslator;
if (qtTranslator.load(QLocale::system(), u"qtbase"_qs, u"_"_qs,
QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
kimaApp.installTranslator(&qtTranslator);
}
QTranslator qTranslator;
QLocale german(QLocale::German);
#ifdef __linux__
qTranslator.load("qt_" + german.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
#endif
#ifdef _WIN32
qTranslator.load("qt_" + german.name(),
QApplication::applicationDirPath() + QDir::separator() + "translations");
#endif
kimaApp.installTranslator(&qTranslator);
QSettings settings{};
while (!settings.contains("global/cashPointNo")) {

View file

@ -1,23 +1,22 @@
#include "mainwindow.h"
#include "basketmodel.h"
#include "config.h"
#include "jsonutil.h"
#include "pricedialog.h"
#include "reportdialog.h"
#include "salemodel.h"
#include "sellerdialog.h"
#include "settingsdialog.h"
#include <config.h>
#include <core/csvreader.h>
#include <core/jsonutil.h>
#include <core/utils.h>
#include <printer/posprinter.h>
#include <printer/utils.h>
#include <utils.h>
#include <excelreader.h>
#include <posprinter.h>
#include <exception>
#include <filesystem>
#include <regex>
#include <string>
#include <QFileDialog>
#include <QMessageBox>
@ -31,31 +30,23 @@ constexpr int STATUSBAR_TIMEOUT = 5000;
MainWindow::MainWindow()
{
m_ui.setupUi(this);
ui_.setupUi(this);
m_marketplace = std::make_unique<Marketplace>();
Database::InitResult res = m_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();
}
marketplace_ = std::make_unique<Marketplace>();
marketplace_->loadFromDb();
statusBar()->showMessage("Gespeicherte Daten wurden geladen.", STATUSBAR_TIMEOUT);
BasketModel *model = new BasketModel(getMarketplace(), m_ui.basketView);
m_ui.basketView->setModel(model);
m_ui.basketView->setColumnHidden(0, true); // hide the uuid
BasketModel* model = new BasketModel(getMarketplace(), ui_.basketView);
ui_.basketView->setModel(model);
ui_.basketView->setColumnHidden(0, true); // hide the uuid
setWindowTitle("KIMA2 - Kasse Nr. " + QSettings().value("global/cashPointNo").toString());
m_ui.salesView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
setSaleModel();
connect(m_ui.actionQuit, &QAction::triggered, qApp, QApplication::closeAllWindows,
Qt::QueuedConnection);
connect(m_ui.newAction, &QAction::triggered, this, [this]() {
if (m_marketplace->getSellers().size() == 0 && m_marketplace->getSales().size() == 0) {
connect(ui_.actionQuit, &QAction::triggered, qApp, QApplication::quit);
connect(ui_.newAction, &QAction::triggered, this, [=]() {
if (marketplace_->getSellers().size() == 0 && marketplace_->getSales().size() == 0) {
return;
}
auto dlgResult =
@ -67,45 +58,46 @@ MainWindow::MainWindow()
if (dlgResult == QMessageBox::No)
return;
delete m_ui.salesView->model();
dynamic_cast<BasketModel *>(m_ui.basketView->model())->cancelSale();
m_marketplace->clear();
delete ui_.salesView->model();
dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
marketplace_->clear();
setSaleModel();
updateStatLabel();
});
m_ui.sellerNoEdit->installEventFilter(this);
m_ui.givenSpinBox->installEventFilter(this);
ui_.sellerNoEdit->installEventFilter(this);
ui_.givenSpinBox->installEventFilter(this);
connect(m_ui.actionEditSeller, &QAction::triggered, this,
connect(ui_.actionEditSeller, &QAction::triggered, this,
&MainWindow::onActionEditSellerTriggered);
connect(m_ui.paidButton, &QPushButton::clicked, this, &MainWindow::onPaidButtonTriggered);
connect(m_ui.givenSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
connect(ui_.paidButton, &QPushButton::clicked, this, &MainWindow::onPaidButtonTriggered);
connect(ui_.givenSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&MainWindow::onGivenSpinBoxValueChanged);
connect(m_ui.basketView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
connect(ui_.basketView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onBasketViewSelectionChanged);
connect(m_ui.cancelArticleButton, &QPushButton::clicked, this,
connect(ui_.cancelArticleButton, &QPushButton::clicked, this,
&MainWindow::onCancelArticleButtonClicked);
connect(m_ui.cancelSaleButton, &QPushButton::clicked, this,
connect(ui_.cancelSaleButton, &QPushButton::clicked, this,
&MainWindow::onCancelSaleButtonClicked);
connect(m_ui.printSaleReceiptButton, &QPushButton::clicked, this,
connect(ui_.printSaleReceiptButton, &QPushButton::clicked, this,
&MainWindow::onPrintSaleReceiptButtonClicked);
connect(m_ui.cancelAllArticlesButton, &QPushButton::clicked, this,
connect(ui_.cancelAllArticlesButton, &QPushButton::clicked, this,
&MainWindow::onCancelAllArticlesButtonClicked);
connect(m_ui.aboutQtAction, &QAction::triggered, this, &MainWindow::onAboutQt);
connect(m_ui.aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
connect(m_ui.openManualAction, &QAction::triggered, this, []() {
auto locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
connect(ui_.aboutQtAction, &QAction::triggered, this, &MainWindow::onAboutQt);
connect(ui_.aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
connect(ui_.openManualAction, &QAction::triggered, this, []() {
auto locations = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
for (auto location : locations) {
if (QFile::exists(location + QString("/Benutzerhandbuch.pdf"))) {
QDesktopServices::openUrl(
QUrl::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(
"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 "
"zugehörigen Dokumentationen (die \"Software\") erhält, die Erlaubnis erteilt, "
"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.");
QMessageBox::information(this, "Lizenzinformation", licenseText);
});
connect(m_ui.reportAction, &QAction::triggered, this, [this]() { ReportDialog(this).exec(); });
connect(m_ui.configAction, &QAction::triggered, this, [this]() {
connect(ui_.reportAction, &QAction::triggered, this, [=]() { ReportDialog(this).exec(); });
connect(ui_.configAction, &QAction::triggered, this, [=]() {
int result = SettingsDialog(this).exec();
if (result == QDialog::Accepted) {
delete m_ui.salesView->model();
m_marketplace->loadFromDb();
delete ui_.salesView->model();
marketplace_->loadFromDb();
setSaleModel();
}
this->setWindowTitle("KIMA2 - Kasse Nr. " +
QSettings().value("global/cashPointNo").toString());
});
connect(m_ui.importSellerAction, &QAction::triggered, this,
&MainWindow::onImportSellerActionTriggered);
connect(m_ui.exportSalesJsonAction, &QAction::triggered, this,
connect(ui_.importSellerExcelAction, &QAction::triggered, this,
&MainWindow::onImportSellerExcelActionTriggered);
connect(ui_.importSellerJsonAction, &QAction::triggered, this,
&MainWindow::onImportSellerJsonActionTriggered);
connect(ui_.exportSellerJsonAction, &QAction::triggered, this,
&MainWindow::onExportSellerJsonActionTriggered);
connect(ui_.exportSalesJsonAction, &QAction::triggered, this,
&MainWindow::onExportSalesJsonActionTriggered);
connect(m_ui.importSalesJsonAction, &QAction::triggered, this,
connect(ui_.importSalesJsonAction, &QAction::triggered, this,
&MainWindow::onImportSalesJsonActionTriggered);
readGeometry();
setWindowIcon(QIcon(":/misc/kima2.ico"));
updateStatLabel();
m_ui.lastPriceLabel1->setText(formatCentAsEuroString(0).c_str());
m_ui.lastPriceLabel2->setText(formatCentAsEuroString(0).c_str());
}
void MainWindow::onActionEditSellerTriggered()
@ -155,11 +149,11 @@ void MainWindow::onActionEditSellerTriggered()
auto dialog = std::make_unique<SellerDialog>(this);
int retCode = dialog->exec();
delete m_ui.salesView->model();
delete ui_.salesView->model();
if (retCode == QDialog::Accepted) {
m_marketplace->sortSellers();
m_marketplace->storeToDb();
marketplace_->sortSellers();
marketplace_->storeToDb();
statusBar()->showMessage("Änderungen an den Verkäufer-Stammdaten gespeichert.",
STATUSBAR_TIMEOUT);
} else {
@ -173,32 +167,31 @@ void MainWindow::onActionEditSellerTriggered()
void MainWindow::setSaleModel()
{
m_ui.salesView->setModel(new SaleModel(getMarketplace(), m_ui.salesView));
m_ui.salesView->setColumnHidden(2, true);
m_ui.salesView->resizeColumnToContents(0);
m_ui.salesView->resizeColumnToContents(1);
ui_.salesView->setModel(new SaleModel(getMarketplace(), ui_.salesView));
ui_.salesView->setColumnHidden(2, true);
ui_.salesView->resizeColumnToContents(0);
m_ui.printSaleReceiptButton->setEnabled(false);
m_ui.cancelSaleButton->setEnabled(false);
ui_.printSaleReceiptButton->setEnabled(false);
ui_.cancelSaleButton->setEnabled(false);
connect(static_cast<BasketModel *>(m_ui.basketView->model()), &BasketModel::basketDataChanged,
static_cast<SaleModel *>(m_ui.salesView->model()), &SaleModel::onBasketDataChanged);
connect(m_ui.salesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
connect(static_cast<BasketModel*>(ui_.basketView->model()), &BasketModel::basketDataChanged,
static_cast<SaleModel*>(ui_.salesView->model()), &SaleModel::onBasketDataChanged);
connect(ui_.salesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&MainWindow::onSalesViewSelectionChanged);
}
void MainWindow::onPaidButtonTriggered()
{
if (m_marketplace->basketSize() > 0) {
QString lastPrice{m_marketplace->getBasketSumAsString().c_str()};
dynamic_cast<BasketModel *>(m_ui.basketView->model())->finishSale();
m_ui.salesView->resizeColumnToContents(0);
m_ui.lastPriceLabel1->setText(lastPrice);
m_ui.lastPriceLabel2->setText(lastPrice);
m_ui.basketSumLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackContainerWidget->setEnabled(false);
m_ui.sellerNoEdit->setFocus();
if (marketplace_->basketSize() > 0) {
QString lastPrice{marketplace_->getBasketSumAsString().c_str()};
dynamic_cast<BasketModel*>(ui_.basketView->model())->finishSale();
ui_.salesView->resizeColumnToContents(0);
ui_.lastPriceLabel1->setText(lastPrice);
ui_.lastPriceLabel2->setText(lastPrice);
ui_.basketSumLabel->setText(formatCentAsEuroString(0).c_str());
ui_.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
ui_.drawbackContainerWidget->setEnabled(false);
ui_.sellerNoEdit->setFocus();
statusBar()->showMessage("Verkaufsvorgang erfolgreich durchgeführt.", STATUSBAR_TIMEOUT);
updateStatLabel();
}
@ -206,11 +199,11 @@ void MainWindow::onPaidButtonTriggered()
bool MainWindow::eventFilter(QObject* target, QEvent* event)
{
if (target == m_ui.sellerNoEdit) {
if (target == ui_.sellerNoEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
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);
} else {
checkSellerNo(false);
@ -219,18 +212,18 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event)
return true;
}
}
} else if (target == m_ui.givenSpinBox) {
} else if (target == ui_.givenSpinBox) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key::Key_Enter || keyEvent->key() == Qt::Key::Key_Return) {
if (keyEvent->modifiers() & Qt::ControlModifier) {
if (keyEvent->modifiers() == Qt::ControlModifier) {
onPaidButtonTriggered();
return true;
}
} else if (keyEvent->key() == Qt::Key::Key_Escape) {
m_ui.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
m_ui.drawbackContainerWidget->setEnabled(false);
m_ui.sellerNoEdit->setFocus();
ui_.drawbackLabel->setText(formatCentAsEuroString(0).c_str());
ui_.drawbackContainerWidget->setEnabled(false);
ui_.sellerNoEdit->setFocus();
}
}
}
@ -241,15 +234,15 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
{
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 (ctrlPressed == false) {
onPaidButtonTriggered();
} else if (m_marketplace->getBasket().size() > 0) {
m_ui.drawbackContainerWidget->setEnabled(true);
m_ui.givenSpinBox->setFocus();
m_ui.givenSpinBox->selectAll();
} else if (marketplace_->getBasket().size() > 0) {
ui_.drawbackContainerWidget->setEnabled(true);
ui_.givenSpinBox->setFocus();
ui_.givenSpinBox->selectAll();
}
return;
}
@ -258,13 +251,13 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
smatch result;
if (!regex_match(inputText, result, pattern)) {
m_ui.sellerNoEdit->clear();
ui_.sellerNoEdit->clear();
return;
}
int sellerNo = std::stoi(result[0]);
auto seller = m_marketplace->findSellerWithSellerNo(sellerNo);
auto seller = marketplace_->findSellerWithSellerNo(sellerNo);
if (seller) {
PriceDialog priceDialog(this);
if (sellerNo == 0) {
@ -274,30 +267,30 @@ void MainWindow::checkSellerNo(bool ctrlPressed)
if (dialogResult == QDialog::Accepted) {
int price = priceDialog.getPrice();
std::string desc = priceDialog.getDescription();
dynamic_cast<BasketModel *>(m_ui.basketView->model())->addArticle(seller, price, desc);
m_ui.basketView->resizeColumnToContents(1);
m_ui.basketSumLabel->setText(m_marketplace->getBasketSumAsString().c_str());
dynamic_cast<BasketModel*>(ui_.basketView->model())->addArticle(seller, price, desc);
ui_.basketView->resizeColumnToContents(1);
ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str());
}
}
m_ui.sellerNoEdit->clear();
ui_.sellerNoEdit->clear();
}
void MainWindow::onGivenSpinBoxValueChanged(double value)
{
int givenInCent = std::round(value * 100);
int basketSumInCent = m_marketplace->getBasketSumInCent();
int basketSumInCent = marketplace_->getBasketSumInCent();
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,
[[maybe_unused]] const QItemSelection& deselected)
{
if (selected.size() > 0) {
m_ui.cancelArticleButton->setEnabled(true);
ui_.cancelArticleButton->setEnabled(true);
} else {
m_ui.cancelArticleButton->setEnabled(false);
ui_.cancelArticleButton->setEnabled(false);
}
}
@ -305,21 +298,21 @@ void MainWindow::onSalesViewSelectionChanged(const QItemSelection &selected,
[[maybe_unused]] const QItemSelection& deselected)
{
if (selected.size() > 0) {
m_ui.cancelSaleButton->setEnabled(true);
ui_.cancelSaleButton->setEnabled(true);
if (!selected.indexes()[0].parent().isValid())
m_ui.printSaleReceiptButton->setEnabled(true);
ui_.printSaleReceiptButton->setEnabled(true);
else
m_ui.printSaleReceiptButton->setEnabled(false);
ui_.printSaleReceiptButton->setEnabled(false);
} else {
m_ui.cancelSaleButton->setEnabled(false);
m_ui.printSaleReceiptButton->setEnabled(false);
ui_.cancelSaleButton->setEnabled(false);
ui_.printSaleReceiptButton->setEnabled(false);
}
}
void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = m_ui.basketView->selectionModel();
auto selModel = ui_.basketView->selectionModel();
if (selModel->hasSelection() == false)
return;
@ -336,23 +329,22 @@ void MainWindow::onCancelArticleButtonClicked([[maybe_unused]] bool checked)
// Deleting the rows, beginning with the last one!
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(
m_marketplace->getBasketSumAsString().c_str()); // Update basket sum
m_ui.sellerNoEdit->setFocus();
ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str()); // Update basket sum
ui_.sellerNoEdit->setFocus();
}
void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = m_ui.salesView->selectionModel();
auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false)
return;
auto dlgResult =
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)
.exec();
if (dlgResult == QMessageBox::No)
@ -363,25 +355,16 @@ void MainWindow::onCancelSaleButtonClicked([[maybe_unused]] bool checked)
// Deleting the rows, beginning with the last one!
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();
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);
ui_.salesView->collapseAll();
updateStatLabel();
}
void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
{
auto selModel = m_ui.salesView->selectionModel();
auto selModel = ui_.salesView->selectionModel();
if (selModel->hasSelection() == false)
return;
@ -390,7 +373,7 @@ void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString();
auto indexes = selModel->selectedRows();
auto &sale = m_marketplace->getSales().at(indexes[0].row());
auto& sale = marketplace_->getSales().at(indexes[0].row());
auto printerDevice =
convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString());
@ -404,13 +387,12 @@ void MainWindow::onPrintSaleReceiptButtonClicked([[maybe_unused]] bool checked)
}
if (printer->isValid())
printer->printSaleReceipt(
sale.get(), settings.value("global/commune", "Dettingen").toString().toStdString());
printer->printSaleReceipt(sale.get(), settings.value("global/commune", "Dettingen").toString().toStdString());
}
void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked)
{
if (m_ui.basketView->model()->rowCount() == 0)
if (ui_.basketView->model()->rowCount() == 0)
return;
auto dlgResult =
@ -421,11 +403,10 @@ void MainWindow::onCancelAllArticlesButtonClicked([[maybe_unused]] bool checked)
if (dlgResult == QMessageBox::No)
return;
dynamic_cast<BasketModel *>(m_ui.basketView->model())->cancelSale();
dynamic_cast<BasketModel*>(ui_.basketView->model())->cancelSale();
m_ui.basketSumLabel->setText(
m_marketplace->getBasketSumAsString().c_str()); // Update basket sum
m_ui.sellerNoEdit->setFocus();
ui_.basketSumLabel->setText(marketplace_->getBasketSumAsString().c_str()); // Update basket sum
ui_.sellerNoEdit->setFocus();
}
void MainWindow::onAboutQt() { QMessageBox::aboutQt(this); }
@ -441,9 +422,9 @@ void MainWindow::onAbout()
">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",
"Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
QMessageBox::StandardButton::Ok, this)
@ -451,31 +432,59 @@ void MainWindow::onImportSellerActionTriggered()
return;
}
auto filename =
QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"Alle unterstützte Dateien (*.csv);;CSV Dateien (*.csv)");
QMessageBox(
QMessageBox::Icon::Information, "Bitte beachten",
"<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())
return;
#if defined(_WIN64) || defined(_WIN32)
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();
}
using namespace std::string_literals;
std::ostringstream msg;
msg << "Aus der CSV-Datei wurden <b>"s << std::to_string(numImported)
<< "</b> Verkäufer importiert.";
QMessageBox(QMessageBox::Icon::Information, "Verkäufer erfolgreich importiert",
msg.str().c_str(), QMessageBox::StandardButton::Ok, this)
void MainWindow::onImportSellerJsonActionTriggered()
{
if (!marketplace_->getSales().empty()) {
QMessageBox(QMessageBox::Icon::Information, "Import nicht möglich",
"Der Import ist nicht möglich, da schon Verkäufe getätigt wurden.",
QMessageBox::StandardButton::Ok, this)
.exec();
return;
}
auto filename = QFileDialog::getOpenFileName(this, "Verkäufer importieren", QString(),
"JSON Dateien (*.json)");
if (filename.isEmpty())
return;
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()
@ -490,13 +499,9 @@ void MainWindow::onExportSalesJsonActionTriggered()
if (filename.isEmpty())
return;
#if defined(_WIN64) || defined(_WIN32)
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());
}
@ -504,30 +509,23 @@ void MainWindow::onImportSalesJsonActionTriggered()
{
QSettings settings;
auto filenames = QFileDialog::getOpenFileNames(this, "Umsätze/Transaktionen importieren",
auto filename = QFileDialog::getOpenFileName(this, "Umsätze/Transaktionen importieren",
QString(), "JSON Dateien (*.json)");
if (filenames.isEmpty())
if (filename.isEmpty())
return;
for(auto filename: filenames) {
#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 {
JsonUtil::importSales(filePath, m_marketplace.get(),
JsonUtil::importSales(filePath, marketplace_.get(),
settings.value("global/cashPointNo").toInt());
} catch (std::runtime_error& err) {
QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok,
this)
.exec();
}
}
setSaleModel();
updateStatLabel();
}
@ -562,9 +560,9 @@ void MainWindow::updateStatLabel()
{
std::string statistics("<b>KIMA2 - Version ");
statistics += PROJECT_VERSION;
statistics += "</b><br />Verkäufer: " + std::to_string(m_marketplace->getSellers().size() - 1);
statistics += "<br />Kunden: " + std::to_string(m_marketplace->getSales().size());
statistics += "<br />Umsatz: " + m_marketplace->getOverallSumAsString();
statistics += "</b><br />Verkäufer: " + std::to_string(marketplace_->getSellers().size() - 1);
statistics += "<br />Kunden: " + std::to_string(marketplace_->getSales().size());
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 <core/marketplace.h>
#include <marketplace.h>
#include <QMainWindow>
#include <QtGui/QCloseEvent>
@ -16,7 +16,7 @@ class MainWindow : public QMainWindow
public:
MainWindow();
Marketplace* getMarketplace() { return m_marketplace.get(); }
Marketplace* getMarketplace() { return marketplace_.get(); }
private slots:
void onBasketViewSelectionChanged(const QItemSelection& selected,
@ -39,7 +39,9 @@ class MainWindow : public QMainWindow
void checkSellerNo(bool ctrlPressed = false);
void onPaidButtonTriggered();
void onGivenSpinBoxValueChanged(double value);
void onImportSellerActionTriggered();
void onImportSellerExcelActionTriggered();
void onImportSellerJsonActionTriggered();
void onExportSellerJsonActionTriggered();
void onExportSalesJsonActionTriggered();
void onImportSalesJsonActionTriggered();
void setSaleModel();
@ -47,8 +49,8 @@ class MainWindow : public QMainWindow
void readGeometry();
void updateStatLabel();
Ui::MainWindow m_ui;
std::unique_ptr<Marketplace> m_marketplace;
Ui::MainWindow ui_;
std::unique_ptr<Marketplace> marketplace_;
};
#endif

View file

@ -112,11 +112,7 @@
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="givenSpinBox">
<property name="maximum">
<double>999.990000000000009</double>
</property>
</widget>
<widget class="QDoubleSpinBox" name="givenSpinBox"/>
</item>
<item>
<widget class="QLabel" name="label_4">
@ -440,8 +436,16 @@ drucken</string>
<property name="title">
<string>&amp;Verkäufer</string>
</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="importSellerAction"/>
<addaction name="importSellerMenu"/>
<addaction name="exportSellerJsonAction"/>
</widget>
<widget class="QMenu" name="menuHilfe">
<property name="title">
@ -505,9 +509,9 @@ drucken</string>
<string>Exportieren für andere Kasse (JSON)</string>
</property>
</action>
<action name="importSellerActionX">
<action name="importSellerExcelAction">
<property name="text">
<string>Aus CSV-Datei (initial)</string>
<string>Aus Excel-Datei (initial)</string>
</property>
</action>
<action name="importSellerJsonAction">
@ -540,11 +544,6 @@ drucken</string>
<string>Lizenz</string>
</property>
</action>
<action name="importSellerAction">
<property name="text">
<string>Importieren (aus CSV-Datei)</string>
</property>
</action>
</widget>
<resources/>
<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)
{
m_forceDesc = forceDesc;
m_ui.setupUi(this);
m_ui.priceSpinBox->setFocus();
forceDesc_ = forceDesc;
ui_.setupUi(this);
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()
{
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",
"Es sind nur 0,50 Cent-Schritte erlaubt.", QMessageBox::StandardButton::Ok,
this)
.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",
"Da Sie auf das Sonderkonto buchen ist eine Artikelbeschreibung erforderlich.",
QMessageBox::StandardButton::Ok, this)
.exec();
m_ui.descEdit->setFocus();
ui_.descEdit->setFocus();
} else {
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:
void on_model_duplicateSellerNo(const QString& message);
virtual void accept() override;
Ui::PriceDialog m_ui;
bool m_forceDesc;
Ui::PriceDialog ui_;
bool forceDesc_;
};
#endif

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>266</width>
<height>128</height>
<width>201</width>
<height>127</height>
</rect>
</property>
<property name="windowTitle">
@ -18,11 +18,6 @@
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Preis</string>
</property>
@ -33,11 +28,6 @@
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="priceSpinBox">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="minimum">
<double>-999.990000000000009</double>
</property>
@ -61,18 +51,6 @@
</item>
<item row="1" column="1">
<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">
<string>(optional)</string>
</property>

View file

@ -2,9 +2,8 @@
#include "mainwindow.h"
#include <core/utils.h>
#include <printer/posprinter.h>
#include <printer/utils.h>
#include <posprinter.h>
#include <utils.h>
#include <filesystem>
@ -19,20 +18,20 @@ namespace fs = std::filesystem;
ReportDialog::ReportDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f)
{
m_ui.setupUi(this);
m_market = dynamic_cast<MainWindow *>(parent)->getMarketplace();
m_model = std::make_unique<ReportModel>(m_market, m_ui.reportView);
m_ui.reportView->setModel(m_model.get());
m_ui.reportView->hideColumn(0);
m_ui.reportView->setRowHidden(0, true); // hide the special "Sonderkonto" user
ui_.setupUi(this);
market_ = dynamic_cast<MainWindow*>(parent)->getMarketplace();
model_ = std::make_unique<ReportModel>(market_, ui_.reportView);
ui_.reportView->setModel(model_.get());
ui_.reportView->hideColumn(0);
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);
connect(m_ui.printReportButton, &QPushButton::clicked, this,
connect(ui_.printReportButton, &QPushButton::clicked, this,
&ReportDialog::onPrintReportButtonClicked);
connect(m_ui.printSellerReceiptButton, &QPushButton::clicked, this,
connect(ui_.printSellerReceiptButton, &QPushButton::clicked, this,
&ReportDialog::onPrintSellerReceiptButtonClicked);
connect(m_ui.reportView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
connect(ui_.reportView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&ReportDialog::onReportViewSelectionChanged);
}
@ -48,13 +47,9 @@ void ReportDialog::onExportCsvButtonClicked()
if (filename.isEmpty())
return;
#if defined(_WIN64) || defined(_WIN32)
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()
@ -75,8 +70,8 @@ void ReportDialog::onPrintReportButtonClicked()
QPainter painter;
int height = printer.height();
int width = printer.width();
const double ENTRIES_PER_PAGE = 45;
const auto &sellers = m_market->getSellers();
const double ENTRIES_PER_PAGE = 51;
const auto& sellers = market_->getSellers();
unsigned int numPages = std::ceil(sellers.size() / ENTRIES_PER_PAGE);
painter.begin(&printer);
@ -107,7 +102,7 @@ void ReportDialog::onPrintReportButtonClicked()
for (unsigned int j = 0;
j < ENTRIES_PER_PAGE && (i - 1) * ENTRIES_PER_PAGE + j < sellers.size(); ++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;
}
content += QString("%1 %2 %3 %4 %5 %6 %7\n")
@ -126,7 +121,7 @@ void ReportDialog::onPrintReportButtonClicked()
}
// 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) {
printer.newPage();
painter.setFont(QFont("Arial", 16, QFont::Bold));
@ -163,8 +158,8 @@ void ReportDialog::onPrintReportButtonClicked()
"Auswertung Kindersachenmarkt");
painter.setFont(fixedFont);
QString content("Gesamtstatistik\n===============\n\n");
int numArticlesOffered = m_market->getNumArticlesOffered();
int numArticlesSold = m_market->getNumArticlesSold();
int numArticlesOffered = market_->getNumArticlesOffered();
int numArticlesSold = market_->getNumArticlesSold();
double percentArticlesSold =
(static_cast<double>(numArticlesSold) / static_cast<double>(numArticlesOffered)) * 100;
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")
.arg(numArticlesSold, 6)
.arg(percentArticlesSold, 0, 'f', 2);
content += QString("Anzahl Kunden: %1\n\n").arg(m_market->getSales().size(), 6);
content += QString("Gesamtumsatz: %1\n").arg(m_market->getOverallSumAsString().c_str(), 10);
content += QString("Anzahl Kunden: %1\n\n").arg(market_->getSales().size(), 6);
content += QString("Gesamtumsatz: %1\n").arg(market_->getOverallSumAsString().c_str(), 10);
content +=
QString("Ausgezahlt: %1\n")
.arg(m_market->getOverallPaymentAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10);
.arg(market_->getOverallPaymentAsString(feeInPercent, maxFeeInEuro * 100).c_str(), 10);
content +=
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("(Maximal einbehaltener Betrag: %1 €)\n").arg(maxFeeInEuro, 3);
@ -196,12 +191,12 @@ void ReportDialog::onPrintSellerReceiptButtonClicked()
QString posPrinterDevice = settings.value("global/posPrinterDevice", "").toString();
QString posPrinterEndpoint = settings.value("global/posPrinterEndpoint", "").toString();
auto selModel = m_ui.reportView->selectionModel();
auto selModel = ui_.reportView->selectionModel();
if (selModel->hasSelection() == false)
return;
auto indexes = selModel->selectedRows();
auto &seller = m_market->getSellers().at(indexes[0].row());
auto& seller = market_->getSellers().at(indexes[0].row());
auto printerDevice =
convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString());
@ -224,8 +219,8 @@ void ReportDialog::onReportViewSelectionChanged(const QItemSelection &selected,
[[maybe_unused]] const QItemSelection& deselected)
{
if (selected.size() > 0) {
m_ui.printSellerReceiptButton->setEnabled(true);
ui_.printSellerReceiptButton->setEnabled(true);
} else {
m_ui.printSellerReceiptButton->setEnabled(false);
ui_.printSellerReceiptButton->setEnabled(false);
}
}

View file

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

View file

@ -5,16 +5,16 @@
#include <QSettings>
ReportModel::ReportModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_market(market)
: QAbstractTableModel(parent), market_(market)
{
QSettings settings;
m_feeInPercent = settings.value("global/feeInPercent").toInt();
m_maxFeeInCent = settings.value("global/maxFeeInEuro").toInt() * 100;
feeInPercent_ = settings.value("global/feeInPercent").toInt();
maxFeeInCent_ = settings.value("global/maxFeeInEuro").toInt() * 100;
}
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; }
@ -52,14 +52,14 @@ QVariant ReportModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole)
return QVariant();
if (m_market->getSellers().size() == 0)
if (market_->getSellers().size() == 0)
return QVariant();
Seller* seller = m_market->getSellers().at(index.row()).get();
Seller* seller = market_->getSellers().at(index.row()).get();
switch (index.column()) {
case 0:
return seller->getId();
return seller->getUuidAsString().c_str();
case 1:
return seller->getSellerNo();
case 2:
@ -71,7 +71,7 @@ QVariant ReportModel::data(const QModelIndex& index, int role) const
case 5:
return seller->sumAsString().c_str();
case 6:
return paymentAsString(seller->sumInCents(), m_feeInPercent, m_maxFeeInCent).c_str();
return paymentAsString(seller->sumInCents(), feeInPercent_, maxFeeInCent_).c_str();
default:
return "???";
}

View file

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

View file

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

View file

@ -1,7 +1,7 @@
#ifndef SALEMODEL_H
#define SALEMODEL_H
#include <core/marketplace.h>
#include <marketplace.h>
#include <QAbstractItemModel>
@ -24,8 +24,8 @@ class SaleModel : public QAbstractItemModel
void onBasketDataChanged();
private:
Marketplace* m_marketplace;
std::unique_ptr<Sale> m_rootItem{new Sale()};
Marketplace* marketplace_;
std::unique_ptr<Sale> rootItem{new Sale()};
};
#endif

View file

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

View file

@ -5,13 +5,13 @@
#include <QMessageBox>
SellerModel::SellerModel(Marketplace* market, QObject* parent)
: QAbstractTableModel(parent), m_marketplace(market)
: QAbstractTableModel(parent), marketplace_(market)
{
}
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; }
@ -21,14 +21,17 @@ QVariant SellerModel::data(const QModelIndex& index, int role) const
if (role != Qt::DisplayRole)
return QVariant();
if (m_marketplace->getSellers().size() == 0)
if (marketplace_->getSellers().size() == 0)
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()) {
case 0:
return seller->getId();
return seller->getUuidAsString().c_str();
case 1:
return seller->getSellerNo();
case 2:
@ -78,21 +81,21 @@ bool SellerModel::setData(const QModelIndex& index, const QVariant& value, int r
if (role != Qt::EditRole)
return false;
Seller* seller = m_marketplace->getSellers().at(index.row()).get();
Seller* seller = marketplace_->getSellers().at(index.row()).get();
switch (index.column()) {
case 0:
seller->setId(value.toInt());
seller->setUuidFromString(value.toString().toStdString());
break;
case 1: {
if (value.toInt() < 0)
return false;
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) {
return value.toInt() == s->getSellerNo();
});
if (iter != m_marketplace->getSellers().end()) {
if (iter != marketplace_->getSellers().end()) {
emit duplicateSellerNo(
"Die Verkäufernummer muss eindeutig sein.\n(Möglicherweise wird die Nummer von "
"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);
auto seller = std::make_unique<Seller>();
seller->setSellerNo(m_marketplace->getNextSellerNo());
m_marketplace->getSellers().push_back(std::move(seller));
seller->createUuid();
seller->setSellerNo(marketplace_->getNextSellerNo());
marketplace_->getSellers().push_back(std::move(seller));
emit endInsertRows();
return true;
@ -132,21 +136,21 @@ bool SellerModel::insertRows(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) {
emit beginRemoveRows(parent, row, row + count - 1);
m_marketplace->getSellers().erase(
std::remove_if(m_marketplace->getSellers().begin(), m_marketplace->getSellers().end(),
marketplace_->getSellers().erase(
std::remove_if(marketplace_->getSellers().begin(), marketplace_->getSellers().end(),
[&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();
return true;
} else {
emit beginRemoveRows(parent, row, row + count - 1);
seller->setState(Seller::State::DELETE);
m_marketplace->storeToDb(true);
marketplace_->storeToDb(true);
emit endRemoveRows();
return true;
}

View file

@ -1,7 +1,7 @@
#ifndef SELLER_MODEL_H
#define SELLER_MODEL_H
#include <core/marketplace.h>
#include <marketplace.h>
#include <QAbstractTableModel>
@ -16,8 +16,7 @@ public:
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 Qt::ItemFlags flags(const QModelIndex& index) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) 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;
virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
@ -25,7 +24,7 @@ signals:
void duplicateSellerNo(const QString& message);
private:
Marketplace *m_marketplace;
Marketplace* marketplace_;
};
#endif

View file

@ -2,10 +2,9 @@
#include "mainwindow.h"
#include <core/database.h>
#include <core/utils.h>
#include <printer/posprinter.h>
#include <printer/utils.h>
#include <database.h>
#include <posprinter.h>
#include <utils.h>
#include <exception>
#include <stdexcept>
@ -15,7 +14,7 @@
SettingsDialog::SettingsDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f)
{
m_ui.setupUi(this);
ui_.setupUi(this);
QSettings settings{};
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();
if (parent)
m_market = dynamic_cast<MainWindow *>(parent)->getMarketplace();
market_ = dynamic_cast<MainWindow*>(parent)->getMarketplace();
m_ui.cashPointNoSpinBox->setValue(cashPointNo);
m_ui.communeEdit->setText(commune);
m_ui.posPrinterDeviceEdit->setText(posPrinterDevice);
m_ui.posPrinterEndpointEdit->setText(posPrinterEndpoint);
m_ui.feePercentSpinBox->setValue(feeInPercent);
m_ui.maxFeeSpinBox->setValue(maxFeeInEuro);
ui_.cashPointNoSpinBox->setValue(cashPointNo);
ui_.communeEdit->setText(commune);
ui_.posPrinterDeviceEdit->setText(posPrinterDevice);
ui_.posPrinterEndpointEdit->setText(posPrinterEndpoint);
ui_.feePercentSpinBox->setValue(feeInPercent);
ui_.maxFeeSpinBox->setValue(maxFeeInEuro);
connect(m_ui.testPosPrinterButton, &QPushButton::clicked, this, [this]() {
connect(ui_.testPosPrinterButton, &QPushButton::clicked, this, [=]() {
using namespace std::string_literals;
try {
if (m_ui.posPrinterDeviceEdit->text().isEmpty()) {
if (ui_.posPrinterDeviceEdit->text().isEmpty()) {
PosPrinter printer;
printer.printTest();
} else {
std::string posPrinterDeviceString = m_ui.posPrinterDeviceEdit->text().toStdString();
std::string posPrinterDeviceString = ui_.posPrinterDeviceEdit->text().toStdString();
std::string posPrinterEndpointString =
m_ui.posPrinterEndpointEdit->text().toStdString();
ui_.posPrinterEndpointEdit->text().toStdString();
try {
auto printerDevice =
@ -80,17 +79,17 @@ void SettingsDialog::accept()
QSettings settings;
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/posPrinterDevice", m_ui.posPrinterDeviceEdit->text().trimmed());
settings.setValue("global/posPrinterEndpoint", m_ui.posPrinterEndpointEdit->text().trimmed());
settings.setValue("global/feeInPercent", m_ui.feePercentSpinBox->value());
settings.setValue("global/maxFeeInEuro", m_ui.maxFeeSpinBox->value());
settings.setValue("global/commune", ui_.communeEdit->text().trimmed());
settings.setValue("global/posPrinterDevice", ui_.posPrinterDeviceEdit->text().trimmed());
settings.setValue("global/posPrinterEndpoint", ui_.posPrinterEndpointEdit->text().trimmed());
settings.setValue("global/feeInPercent", ui_.feePercentSpinBox->value());
settings.setValue("global/maxFeeInEuro", ui_.maxFeeSpinBox->value());
if (oldCashPointNo != newCashPointNo) {
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?",
"Möchten Sie die Kassen-Nr wirklich ändern? Diese muss über alle "
"Installationen hinweg eindeutig sein.",
@ -112,7 +111,7 @@ void SettingsDialog::accept()
QDialog::accept();
return;
}
settings.setValue("global/cashPointNo", m_ui.cashPointNoSpinBox->value());
settings.setValue("global/cashPointNo", ui_.cashPointNoSpinBox->value());
}
}

View file

@ -3,14 +3,12 @@
#include "ui_settingsdialog.h"
#include <core/marketplace.h>
#include <marketplace.h>
#include <QDialog>
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
SettingsDialog(QWidget* parent = nullptr,
Qt::WindowFlags f = Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@ -19,8 +17,8 @@ class SettingsDialog : public QDialog
void accept() override;
private:
Ui::SettingsDialog m_ui;
Marketplace* m_market{};
Ui::SettingsDialog ui_;
Marketplace* market_{};
};
#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)
find_package(Boost 1.78 REQUIRED)
find_package(Boost 1.62 REQUIRED)
if(WIN32)
find_package(LIBUSB REQUIRED)
@ -11,7 +11,6 @@ endif()
set(PRINTER_SOURCES
posprinter.cpp
utils.cpp
)
add_library(printer STATIC ${PRINTER_SOURCES})
@ -20,4 +19,4 @@ if(WIN32)
else()
target_link_libraries(printer core ${LibUSB_LIBRARIES})
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 <core/marketplace.h>
#include <marketplace.h>
#include <boost/date_time/posix_time/posix_time.hpp>

View file

@ -1,8 +1,8 @@
#ifndef POS_PRINTER_H
#define POS_PRINTER_H
#include <core/sale.h>
#include <core/seller.h>
#include <sale.h>
#include <seller.h>
#include <memory>
@ -36,8 +36,7 @@ class PosPrinter
void printHeader(const std::string& commune = "Musterhausen");
void printTest();
void printSaleReceipt(Sale* sale, const std::string& commune = "Dettingen");
void printSellerReceipt(Seller* seller, const int percent, const int maxFeeInCent,
const std::string& commune = "Dettingen");
void printSellerReceipt(Seller* seller, const int percent, const int maxFeeInCent, const std::string& commune = "Dettingen");
bool isValid();
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)
{
Seller seller{};
BOOST_TEST(seller.getId().is_nil() == true);
BOOST_TEST(seller.getUuid().is_nil() == true);
}
BOOST_AUTO_TEST_CASE(create_uuid)
{
Seller seller{};
seller.createUuid();
BOOST_TEST(seller.getId().is_nil() == false);
BOOST_TEST(seller.getUuid().is_nil() == false);
}
BOOST_AUTO_TEST_CASE(create_many)
@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(create_many)
std::array<Seller, QUANTITY> sellers;
for (unsigned i = 0; i < sellers.size(); i++) {
sellers[i] = Seller();
//sellers[i].createUuid();
sellers[i].createUuid();
}
}