Compare commits

...

7 Commits

67 changed files with 2428 additions and 1137 deletions
+1
View File
@@ -0,0 +1 @@
*.o
+82
View File
@@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.16)
project(BudgetPro VERSION 1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Qt 6 Configuration
find_package(Qt6 REQUIRED COMPONENTS Widgets Sql)
# Define directories for easier management
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SRC_DIR ${SOURCE_DIR}/src)
set(GUI_DIR ${SOURCE_DIR}/src/gui)
set(WIDGET_DIR ${SOURCE_DIR}/src/gui/widgets)
set(FORMS_DIR ${SOURCE_DIR}/src/gui/forms)
set(MODELS_DIR ${SOURCE_DIR}/src/models)
set(DAO_DIR ${SOURCE_DIR}/src/dao)
set(UTILS_DIR ${SOURCE_DIR}/src/utils)
set(APP_DIR ${SOURCE_DIR}/src/app)
set(ROOT_WIDGET_DIR ${SOURCE_DIR}/widget)
# Include Paths
include_directories(
${GUI_DIR}
${WIDGET_DIR}
${FORMS_DIR}
${MODELS_DIR}
${DAO_DIR}
${UTILS_DIR}
${APP_DIR}
${ROOT_WIDGET_DIR}
${SOURCE_DIR}/data
${SOURCE_DIR}/gui/SARibbon
${SOURCE_DIR}/gui/qtRibbonGUI
)
# SARibbon Library Integration
# Assuming SARibbon is integrated as a sub-project or pre-compiled
add_subdirectory(gui/SARibbon)
# Collect Sources
file(GLOB_RECURSIVE SOURCES
"src/*.cpp"
"src/*.h"
"widget/*.cpp"
"widget/*.h"
"utils/*.cpp"
"utils/*.h"
)
# Collect Forms
file(GLOB_RECURSIVE FORMS
"src/gui/*.ui"
"src/gui/forms/*.ui"
"widget/*.ui"
)
# Collect Resources
file(GLOB_RECURSIVE RESOURCES
"resources/*.qss"
"resources/*.svg"
"resources/*.png"
"*.qrc"
)
# Create Executable
add_executable(BudgetPro
${SOURCES}
${FORMS}
${RESOURCES}
)
# Link Libraries
target_link_libraries(BudgetPro PRIVATE Qt6::Widgets Qt6::Sql SARibbonBar)
# OS Specific configurations
if(WIN32)
set_target_properties(BudgetPro PROPERTIES WIN32_EXECUTABLE TRUE)
target_compile_definitions(BudgetPro PRIVATE NOMINMAX)
elseif(APPLE)
set_target_properties(BudgetPro PROPERTIES MACOSX_BUNDLE TRUE)
endif()
+58 -8
View File
@@ -87,7 +87,12 @@ SOURCES = src/gui/mainwindow.cpp \
widget/msqlquerymodel.cpp \ widget/msqlquerymodel.cpp \
src/gui/forms/forminvoiceinlist.cpp \ src/gui/forms/forminvoiceinlist.cpp \
src/gui/forms/formbase.cpp \ src/gui/forms/formbase.cpp \
treeitem.cpp qrc_editabletreemodel.cpp \ treeitem.cpp \
src/dao/productdao.cpp \
src/dao/enterprisedao.cpp \
src/dao/thirddao.cpp \
src/dao/budgetdao.cpp \
src/dao/elementdao.cpp qrc_editabletreemodel.cpp \
moc_mainwindow.cpp \ moc_mainwindow.cpp \
moc_formbaselist.cpp \ moc_formbaselist.cpp \
moc_formbudgetlist.cpp \ moc_formbudgetlist.cpp \
@@ -153,6 +158,11 @@ OBJECTS = mainwindow.o \
forminvoiceinlist.o \ forminvoiceinlist.o \
formbase.o \ formbase.o \
treeitem.o \ treeitem.o \
productdao.o \
enterprisedao.o \
thirddao.o \
budgetdao.o \
elementdao.o \
qrc_editabletreemodel.o \ qrc_editabletreemodel.o \
moc_mainwindow.o \ moc_mainwindow.o \
moc_formbaselist.o \ moc_formbaselist.o \
@@ -305,7 +315,12 @@ DIST = /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/spec_pre.prf \
src/gui/forms/forminvoiceinlist.h \ src/gui/forms/forminvoiceinlist.h \
src/gui/forms/formbase.h \ src/gui/forms/formbase.h \
treeitem.h \ treeitem.h \
utils/dbutils.h src/gui/mainwindow.cpp \ utils/dbutils.h \
src/dao/productdao.h \
src/dao/enterprisedao.h \
src/dao/thirddao.h \
src/dao/budgetdao.h \
src/dao/elementdao.h src/gui/mainwindow.cpp \
utils/dbutils.cpp \ utils/dbutils.cpp \
src/gui/forms/formbaselist.cpp \ src/gui/forms/formbaselist.cpp \
src/gui/forms/formbudgetlist.cpp \ src/gui/forms/formbudgetlist.cpp \
@@ -340,7 +355,12 @@ DIST = /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/spec_pre.prf \
widget/msqlquerymodel.cpp \ widget/msqlquerymodel.cpp \
src/gui/forms/forminvoiceinlist.cpp \ src/gui/forms/forminvoiceinlist.cpp \
src/gui/forms/formbase.cpp \ src/gui/forms/formbase.cpp \
treeitem.cpp treeitem.cpp \
src/dao/productdao.cpp \
src/dao/enterprisedao.cpp \
src/dao/thirddao.cpp \
src/dao/budgetdao.cpp \
src/dao/elementdao.cpp
QMAKE_TARGET = budgetPro QMAKE_TARGET = budgetPro
DESTDIR = DESTDIR =
TARGET = budgetPro TARGET = budgetPro
@@ -547,8 +567,8 @@ distdir: FORCE
$(COPY_FILE) --parents $(DIST) $(DISTDIR)/ $(COPY_FILE) --parents $(DIST) $(DISTDIR)/
$(COPY_FILE) --parents editabletreemodel.qrc $(DISTDIR)/ $(COPY_FILE) --parents editabletreemodel.qrc $(DISTDIR)/
$(COPY_FILE) --parents /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp $(DISTDIR)/ $(COPY_FILE) --parents /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp $(DISTDIR)/
$(COPY_FILE) --parents src/gui/mainwindow.h src/gui/forms/formbaselist.h src/gui/forms/formbudgetlist.h src/models/treemodel.h itemnumberdelegate.h qmtreeview.h itemtextdelegate.h header.h mapplication.h src/gui/forms/formbudget.h utils/fiebdc.h utils/filterlineedit.h utils/filtertableheader.h widget/widgetcomboboxpopuptable.h src/gui/forms/formthird.h widget/avatarwidget.h src/gui/forms/formproduct.h data/sqltable.h itemrichtextdelegate.h src/gui/forms/dialogcreateenterprise.h utils/frameless.h src/gui/forms/dialogopencompany.h widget/companylistitemdelegate.h src/gui/forms/formelementlist.h src/gui/forms/formthirdlist.h widget/mlineeditbutton.h itemtextpopupdelegate.h widget/lineedittag.h widget/treemodelcomposeelement.h itemcomboboxdelegate.h src/gui/widgets/qlistmodel.h widget/msqlquerymodel.h src/gui/forms/forminvoiceinlist.h src/gui/forms/formbase.h treeitem.h utils/dbutils.h $(DISTDIR)/ $(COPY_FILE) --parents src/gui/mainwindow.h src/gui/forms/formbaselist.h src/gui/forms/formbudgetlist.h src/models/treemodel.h itemnumberdelegate.h qmtreeview.h itemtextdelegate.h header.h mapplication.h src/gui/forms/formbudget.h utils/fiebdc.h utils/filterlineedit.h utils/filtertableheader.h widget/widgetcomboboxpopuptable.h src/gui/forms/formthird.h widget/avatarwidget.h src/gui/forms/formproduct.h data/sqltable.h itemrichtextdelegate.h src/gui/forms/dialogcreateenterprise.h utils/frameless.h src/gui/forms/dialogopencompany.h widget/companylistitemdelegate.h src/gui/forms/formelementlist.h src/gui/forms/formthirdlist.h widget/mlineeditbutton.h itemtextpopupdelegate.h widget/lineedittag.h widget/treemodelcomposeelement.h itemcomboboxdelegate.h src/gui/widgets/qlistmodel.h widget/msqlquerymodel.h src/gui/forms/forminvoiceinlist.h src/gui/forms/formbase.h treeitem.h utils/dbutils.h src/dao/productdao.h src/dao/enterprisedao.h src/dao/thirddao.h src/dao/budgetdao.h src/dao/elementdao.h $(DISTDIR)/
$(COPY_FILE) --parents src/gui/mainwindow.cpp utils/dbutils.cpp src/gui/forms/formbaselist.cpp src/gui/forms/formbudgetlist.cpp src/models/treemodel.cpp main.cpp itemnumberdelegate.cpp qmtreeview.cpp itemtextdelegate.cpp header.cpp mapplication.cpp src/gui/forms/formbudget.cpp utils/fiebdc.cpp utils/filterlineedit.cpp utils/filtertableheader.cpp widget/widgetcomboboxpopuptable.cpp src/gui/forms/formthird.cpp widget/avatarwidget.cpp src/gui/forms/formproduct.cpp itemrichtextdelegate.cpp src/gui/forms/dialogcreateenterprise.cpp utils/frameless.cpp src/gui/forms/dialogopencompany.cpp widget/companylistitemdelegate.cpp src/gui/forms/formelementlist.cpp src/gui/forms/formthirdlist.cpp widget/mlineeditbutton.cpp itemtextpopupdelegate.cpp widget/lineedittag.cpp widget/treemodelcomposeelement.cpp itemcomboboxdelegate.cpp src/gui/widgets/qlistmodel.cpp widget/msqlquerymodel.cpp src/gui/forms/forminvoiceinlist.cpp src/gui/forms/formbase.cpp treeitem.cpp $(DISTDIR)/ $(COPY_FILE) --parents src/gui/mainwindow.cpp utils/dbutils.cpp src/gui/forms/formbaselist.cpp src/gui/forms/formbudgetlist.cpp src/models/treemodel.cpp main.cpp itemnumberdelegate.cpp qmtreeview.cpp itemtextdelegate.cpp header.cpp mapplication.cpp src/gui/forms/formbudget.cpp utils/fiebdc.cpp utils/filterlineedit.cpp utils/filtertableheader.cpp widget/widgetcomboboxpopuptable.cpp src/gui/forms/formthird.cpp widget/avatarwidget.cpp src/gui/forms/formproduct.cpp itemrichtextdelegate.cpp src/gui/forms/dialogcreateenterprise.cpp utils/frameless.cpp src/gui/forms/dialogopencompany.cpp widget/companylistitemdelegate.cpp src/gui/forms/formelementlist.cpp src/gui/forms/formthirdlist.cpp widget/mlineeditbutton.cpp itemtextpopupdelegate.cpp widget/lineedittag.cpp widget/treemodelcomposeelement.cpp itemcomboboxdelegate.cpp src/gui/widgets/qlistmodel.cpp widget/msqlquerymodel.cpp src/gui/forms/forminvoiceinlist.cpp src/gui/forms/formbase.cpp treeitem.cpp src/dao/productdao.cpp src/dao/enterprisedao.cpp src/dao/thirddao.cpp src/dao/budgetdao.cpp src/dao/elementdao.cpp $(DISTDIR)/
$(COPY_FILE) --parents src/gui/mainwindow.ui src/gui/forms/formbaselist.ui src/gui/forms/formbudget.ui src/gui/forms/formbudgetlist.ui widget/widgetcomboboxpopuptable.ui src/gui/forms/formthird.ui src/gui/forms/formproduct.ui src/gui/forms/dialogcreateenterprise.ui src/gui/forms/dialogopencompany.ui src/gui/forms/formelementlist.ui src/gui/forms/formthirdlist.ui src/gui/forms/forminvoiceinlist.ui src/gui/forms/formbase.ui $(DISTDIR)/ $(COPY_FILE) --parents src/gui/mainwindow.ui src/gui/forms/formbaselist.ui src/gui/forms/formbudget.ui src/gui/forms/formbudgetlist.ui widget/widgetcomboboxpopuptable.ui src/gui/forms/formthird.ui src/gui/forms/formproduct.ui src/gui/forms/dialogcreateenterprise.ui src/gui/forms/dialogopencompany.ui src/gui/forms/formelementlist.ui src/gui/forms/formthirdlist.ui src/gui/forms/forminvoiceinlist.ui src/gui/forms/formbase.ui $(DISTDIR)/
@@ -958,12 +978,14 @@ formbudget.o: src/gui/forms/formbudget.cpp src/gui/forms/formbudget.h \
treeitem.h \ treeitem.h \
mapplication.h \ mapplication.h \
src/elementtype.h \ src/elementtype.h \
src/dao/elementdao.h \
widget/widgetcomboboxpopuptable.h \ widget/widgetcomboboxpopuptable.h \
ui_widgetcomboboxpopuptable.h \ ui_widgetcomboboxpopuptable.h \
itemnumberdelegate.h \ itemnumberdelegate.h \
itemtextdelegate.h \ itemtextdelegate.h \
itemtextpopupdelegate.h \ itemtextpopupdelegate.h \
itemcomboboxdelegate.h itemcomboboxdelegate.h \
src/dao/budgetdao.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o formbudget.o src/gui/forms/formbudget.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o formbudget.o src/gui/forms/formbudget.cpp
fiebdc.o: utils/fiebdc.cpp utils/fiebdc.h fiebdc.o: utils/fiebdc.cpp utils/fiebdc.h
@@ -986,7 +1008,8 @@ formthird.o: src/gui/forms/formthird.cpp src/gui/forms/formthird.h \
src/gui/forms/formbase.h \ src/gui/forms/formbase.h \
ui_formthird.h \ ui_formthird.h \
widget/avatarwidget.h \ widget/avatarwidget.h \
mapplication.h mapplication.h \
src/dao/thirddao.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o formthird.o src/gui/forms/formthird.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o formthird.o src/gui/forms/formthird.cpp
avatarwidget.o: widget/avatarwidget.cpp widget/avatarwidget.h avatarwidget.o: widget/avatarwidget.cpp widget/avatarwidget.h
@@ -1003,7 +1026,9 @@ formproduct.o: src/gui/forms/formproduct.cpp src/gui/forms/formproduct.h \
itemnumberdelegate.h \ itemnumberdelegate.h \
itemtextdelegate.h \ itemtextdelegate.h \
itemtextpopupdelegate.h \ itemtextpopupdelegate.h \
itemcomboboxdelegate.h itemcomboboxdelegate.h \
src/dao/productdao.h \
data/sqltable.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o formproduct.o src/gui/forms/formproduct.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o formproduct.o src/gui/forms/formproduct.cpp
itemrichtextdelegate.o: itemrichtextdelegate.cpp itemrichtextdelegate.h itemrichtextdelegate.o: itemrichtextdelegate.cpp itemrichtextdelegate.h
@@ -1105,6 +1130,31 @@ formbase.o: src/gui/forms/formbase.cpp src/gui/forms/formbase.h \
treeitem.o: treeitem.cpp treeitem.h treeitem.o: treeitem.cpp treeitem.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o treeitem.o treeitem.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o treeitem.o treeitem.cpp
productdao.o: src/dao/productdao.cpp src/dao/productdao.h \
src/gui/forms/formproduct.h \
src/gui/forms/formbase.h \
src/elementtype.h \
data/sqltable.h \
mapplication.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o productdao.o src/dao/productdao.cpp
enterprisedao.o: src/dao/enterprisedao.cpp src/dao/enterprisedao.h \
mapplication.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o enterprisedao.o src/dao/enterprisedao.cpp
thirddao.o: src/dao/thirddao.cpp src/dao/thirddao.h \
mapplication.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o thirddao.o src/dao/thirddao.cpp
budgetdao.o: src/dao/budgetdao.cpp src/dao/budgetdao.h \
mapplication.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o budgetdao.o src/dao/budgetdao.cpp
elementdao.o: src/dao/elementdao.cpp src/dao/elementdao.h \
src/elementtype.h \
mapplication.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o elementdao.o src/dao/elementdao.cpp
qrc_editabletreemodel.o: qrc_editabletreemodel.cpp qrc_editabletreemodel.o: qrc_editabletreemodel.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o qrc_editabletreemodel.o qrc_editabletreemodel.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o qrc_editabletreemodel.o qrc_editabletreemodel.cpp
+15
View File
@@ -15,6 +15,8 @@ BudgetPro is a desktop application designed for managing company finances, budge
- **Invoice Tracking**: Manage incoming and outgoing invoices - **Invoice Tracking**: Manage incoming and outgoing invoices
- **Data Visualization**: Tree views for hierarchical financial data - **Data Visualization**: Tree views for hierarchical financial data
- **Custom Editors**: Specialized delegates for different data types (combobox, rich text, etc.) - **Custom Editors**: Specialized delegates for different data types (combobox, rich text, etc.)
- **Template Editor**: Visual template designer for document export
- **Document Export**: Export documents as PDF, XLSX, and DOCX with configurable templates
## Technical Stack ## Technical Stack
@@ -36,6 +38,15 @@ BudgetPro/
├── widget/ # Custom widgets and delegates ├── widget/ # Custom widgets and delegates
├── utils/ # Utility classes and helpers ├── utils/ # Utility classes and helpers
├── data/ # Data access layer (sqltable.h) ├── data/ # Data access layer (sqltable.h)
├── templates/ # Document export templates (JSON)
├── src/
│ ├── dao/ # Data Access Objects
│ │ ├── templatedao.h/cpp # Template CRUD operations
│ │ └── templateengine.h/cpp # Export engine (PDF/XLSX/DOCX)
│ └── gui/
│ └── forms/
│ ├── formtemplateeditor.h/cpp # Visual template editor
│ └── formtemplatelist.h/cpp # Template list manager
└── resources/ # Qt resource file (icons, stylesheets, etc.) └── resources/ # Qt resource file (icons, stylesheets, etc.)
``` ```
@@ -80,6 +91,10 @@ BudgetPro includes several custom Qt components:
- Item numbering in hierarchical views - Item numbering in hierarchical views
- Popup tables for complex selection - Popup tables for complex selection
- `TreeModel`: Custom model for tree-structured data - `TreeModel`: Custom model for tree-structured data
- `TemplateEngine`: Document export engine supporting PDF, XLSX, DOCX
- `TemplateDAO`: Data access for document templates
- `formTemplateEditor`: Visual template designer
- `formTemplateList`: Template list management
- `AvatarWidget`: For displaying user/entity avatars - `AvatarWidget`: For displaying user/entity avatars
## Extending the Application ## Extending the Application
+37 -22
View File
@@ -15,7 +15,7 @@ INCLUDEPATH = \
src/gui/forms \ src/gui/forms \
src/models src/models
FORMS = src/gui/mainwindow.ui \ FORMS = src/gui/mainwindow/mainwindow.ui \
src/gui/forms/formbaselist.ui \ src/gui/forms/formbaselist.ui \
src/gui/forms/formbudget.ui \ src/gui/forms/formbudget.ui \
src/gui/forms/formbudgetlist.ui \ src/gui/forms/formbudgetlist.ui \
@@ -30,15 +30,15 @@ FORMS = src/gui/mainwindow.ui \
src/gui/forms/formbase.ui src/gui/forms/formbase.ui
HEADERS = src/gui/mainwindow.h \ HEADERS = src/gui/mainwindow/mainwindow.h \
src/gui/forms/formbaselist.h \ src/gui/forms/formbaselist.h \
src/gui/forms/formbudgetlist.h \ src/gui/forms/formbudgetlist.h \
src/models/treemodel.h \ src/models/treemodel.h \
itemnumberdelegate.h \ src/gui/widgets/itemnumberdelegate.h \
qmtreeview.h \ src/gui/widgets/qmtreeview.h \
itemtextdelegate.h \ src/gui/widgets/itemtextdelegate.h \
header.h \ src/utils/header.h \
mapplication.h \ src/app/mapplication.h \
src/gui/forms/formbudget.h \ src/gui/forms/formbudget.h \
utils/fiebdc.h \ utils/fiebdc.h \
utils/filterlineedit.h \ utils/filterlineedit.h \
@@ -48,7 +48,7 @@ HEADERS = src/gui/mainwindow.h \
widget/avatarwidget.h \ widget/avatarwidget.h \
src/gui/forms/formproduct.h \ src/gui/forms/formproduct.h \
data/sqltable.h \ data/sqltable.h \
itemrichtextdelegate.h \ src/gui/widgets/itemrichtextdelegate.h \
src/gui/forms/dialogcreateenterprise.h \ src/gui/forms/dialogcreateenterprise.h \
utils/frameless.h \ utils/frameless.h \
src/gui/forms/dialogopencompany.h \ src/gui/forms/dialogopencompany.h \
@@ -56,31 +56,31 @@ HEADERS = src/gui/mainwindow.h \
src/gui/forms/formelementlist.h \ src/gui/forms/formelementlist.h \
src/gui/forms/formthirdlist.h \ src/gui/forms/formthirdlist.h \
widget/mlineeditbutton.h \ widget/mlineeditbutton.h \
itemtextpopupdelegate.h \ src/gui/widgets/itemtextpopupdelegate.h \
widget/lineedittag.h \ widget/lineedittag.h \
widget/treemodelcomposeelement.h \ widget/treemodelcomposeelement.h \
itemcomboboxdelegate.h \ src/gui/widgets/itemcomboboxdelegate.h \
src/gui/widgets/qlistmodel.h \ src/gui/widgets/qlistmodel.h \
widget/msqlquerymodel.h \ widget/msqlquerymodel.h \
src/gui/forms/forminvoiceinlist.h \ src/gui/forms/forminvoiceinlist.h \
src/gui/forms/formbase.h \ src/gui/forms/formbase.h \
treeitem.h src/models/treeitem.h
RESOURCES = editabletreemodel.qrc RESOURCES = editabletreemodel.qrc
SOURCES = src/gui/mainwindow.cpp \ SOURCES = src/gui/mainwindow/mainwindow.cpp \
utils/dbutils.cpp \ utils/dbutils.cpp \
src/gui/forms/formbaselist.cpp \ src/gui/forms/formbaselist.cpp \
src/gui/forms/formbudgetlist.cpp \ src/gui/forms/formbudgetlist.cpp \
src/models/treemodel.cpp \ src/models/treemodel.cpp \
main.cpp \ src/main.cpp \
itemnumberdelegate.cpp \ src/gui/widgets/itemnumberdelegate.cpp \
qmtreeview.cpp \ src/gui/widgets/qmtreeview.cpp \
itemtextdelegate.cpp \ src/gui/widgets/itemtextdelegate.cpp \
header.cpp \ src/utils/header.cpp \
mapplication.cpp \ src/app/mapplication.cpp \
src/gui/forms/formbudget.cpp \ src/gui/forms/formbudget.cpp \
utils/fiebdc.cpp \ utils/fiebdc.cpp \
utils/filterlineedit.cpp \ utils/filterlineedit.cpp \
@@ -89,7 +89,7 @@ SOURCES = src/gui/mainwindow.cpp \
src/gui/forms/formthird.cpp \ src/gui/forms/formthird.cpp \
widget/avatarwidget.cpp \ widget/avatarwidget.cpp \
src/gui/forms/formproduct.cpp \ src/gui/forms/formproduct.cpp \
itemrichtextdelegate.cpp \ src/gui/widgets/itemrichtextdelegate.cpp \
src/gui/forms/dialogcreateenterprise.cpp \ src/gui/forms/dialogcreateenterprise.cpp \
utils/frameless.cpp \ utils/frameless.cpp \
src/gui/forms/dialogopencompany.cpp \ src/gui/forms/dialogopencompany.cpp \
@@ -97,15 +97,15 @@ SOURCES = src/gui/mainwindow.cpp \
src/gui/forms/formelementlist.cpp \ src/gui/forms/formelementlist.cpp \
src/gui/forms/formthirdlist.cpp \ src/gui/forms/formthirdlist.cpp \
widget/mlineeditbutton.cpp \ widget/mlineeditbutton.cpp \
itemtextpopupdelegate.cpp \ src/gui/widgets/itemtextpopupdelegate.cpp \
widget/lineedittag.cpp \ widget/lineedittag.cpp \
widget/treemodelcomposeelement.cpp \ widget/treemodelcomposeelement.cpp \
itemcomboboxdelegate.cpp \ src/gui/widgets/itemcomboboxdelegate.cpp \
src/gui/widgets/qlistmodel.cpp \ src/gui/widgets/qlistmodel.cpp \
widget/msqlquerymodel.cpp \ widget/msqlquerymodel.cpp \
src/gui/forms/forminvoiceinlist.cpp \ src/gui/forms/forminvoiceinlist.cpp \
src/gui/forms/formbase.cpp \ src/gui/forms/formbase.cpp \
treeitem.cpp src/models/treeitem.cpp
# install # install
@@ -113,3 +113,18 @@ target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/editabletreemodel
INSTALLS += target INSTALLS += target
HEADERS += utils/dbutils.h HEADERS += utils/dbutils.h
# DAO sources
SOURCES += \
src/dao/productdao.cpp \
src/dao/enterprisedao.cpp \
src/dao/thirddao.cpp \
src/dao/budgetdao.cpp \
src/dao/elementdao.cpp
HEADERS += \
src/dao/productdao.h \
src/dao/enterprisedao.h \
src/dao/thirddao.h \
src/dao/budgetdao.h \
src/dao/elementdao.h
+9
View File
@@ -0,0 +1,9 @@
@echo off
:: Build script for Windows
set BUILD_DIR=build
if not exist %BUILD_DIR% mkdir %BUILD_DIR%
cd %BUILD_DIR%
cmake ..
cmake --build . --config Release
cd ..
echo Build complete. Binary located in %BUILD_DIR%\Release\BudgetPro.exe
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
# Build script for Linux and macOS
BUILD_DIR="build"
if [ ! -d "$BUILD_DIR" ]; then
mkdir $BUILD_DIR
fi
cd $BUILD_DIR
cmake ..
make -j$(nproc)
cd ..
echo "Build complete. Binary located in $BUILD_DIR/BudgetPro"
+79 -132
View File
@@ -148,98 +148,6 @@ const QString tElemento = "CREATE TABLE ELEMENT ("
"WIDTH FLOAT, " // 21. ID proveedor por defecto "WIDTH FLOAT, " // 21. ID proveedor por defecto
"LENGHT FLOAT, " // 22. ID proveedor por defecto "LENGHT FLOAT, " // 22. ID proveedor por defecto
/* Interesa??
// Proveedores:
"SUPPLIER_ID_0 VARCHAR(10), " // 23. ID del proveedor
"SUPPLIER_NAME_0 VARCHAR(60), " // 24. Nombre del proveedor
"SUPPLIER_REFERENCE_0 VARCHAR(20), " // 25. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_0 FLOAT, " // 26. PVP
"SUPPLIER_DISCOUNT_0 FLOAT, " // 27. Descuento
"SUPPLIER_PURCHASE_PRICE_0 FLOAT, " // 28. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_0 FLOAT, " // 29. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_0 DATE, " // 30. Fecha de actualización del precio
"SUPPLIER_ID_1 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_1 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_1 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_1 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_1 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_1 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_1 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_1 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_2 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_2 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_2 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_2 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_2 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_2 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_2 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_2 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_3 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_3 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_3 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_3 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_3 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_3 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_3 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_3 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_4 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_4 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_4 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_4 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_4 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_4 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_4 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_4 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_5 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_5 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_5 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_5 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_5 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_5 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_5 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_5 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_6 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_6 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_6 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_6 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_6 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_6 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_6 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_6 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_7 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_7 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_7 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_7 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_7 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_7 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_7 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_7 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_8 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_8 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_8 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_8 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_8 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_8 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_8 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_8 DATE, " // 25. Fecha de actualización del precio
"SUPPLIER_ID_9 VARCHAR(10), " // 18. ID del proveedor
"SUPPLIER_NAME_9 VARCHAR(60), " // 19. Nombre del proveedor
"SUPPLIER_REFERENCE_9 VARCHAR(20), " // 20. Ref. del elemento que tiene el proveedor
"SUPPLIER_REAL_PRICE_9 FLOAT, " // 21. PVP
"SUPPLIER_DISCOUNT_9 FLOAT, " // 22. Descuento
"SUPPLIER_PURCHASE_PRICE_9 FLOAT, " // 23. Precio compra
"SUPPLIER_MINIMUM_AMOUNT_9 FLOAT, " // 24. Cantidad mínima de pedido
"SUPPLIER_DATE_UPDATE_9 DATE, " // 97. Fecha de actualización del precio
*/
"SUPPLIER_DEFAULT VARCHAR(10), " // 98. CODE proveedor por defecto "SUPPLIER_DEFAULT VARCHAR(10), " // 98. CODE proveedor por defecto
"CREATEDAT DATE DEFAULT CURRENT_DATE, " // 25. Fecha de creación "CREATEDAT DATE DEFAULT CURRENT_DATE, " // 25. Fecha de creación
@@ -417,7 +325,7 @@ const QString tDataDocVenta = "CREATE TABLE SALEDOCUMENTDATA ("
//---------------------- DOCUMENTOS DE COMPRA -------------------------------- //---------------------- DOCUMENTOS DE COMPRA --------------------------------
const QString tDocCompra = "CREATE TABLE BUYDOCUMENT (" const QString tDocCompra = "CREATE TABLE BUYDOCUMENT ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 0. ID "ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 0. ID
"TYPE VARCHAR(2) NOT NULL, " // 1. Tipo de documento: "TYPE VARCHAR(2)\tNOT NULL, " // 1. Tipo de documento:
"CODE VARCHAR(20) NOT NULL, " // 2. Código documento "CODE VARCHAR(20) NOT NULL, " // 2. Código documento
"SUPPLIER_CODE VARCHAR(20) NOT NULL, " // 3. Código proveedor "SUPPLIER_CODE VARCHAR(20) NOT NULL, " // 3. Código proveedor
"SUPPLIER_NAME VARCHAR(100) NOT NULL, " // 4. Nombre proveedor "SUPPLIER_NAME VARCHAR(100) NOT NULL, " // 4. Nombre proveedor
@@ -439,7 +347,7 @@ const QString tDocCompra = "CREATE TABLE BUYDOCUMENT ("
const QString tDataDocCompra = "CREATE TABLE BUYDOCUMENTDATA (" const QString tDataDocCompra = "CREATE TABLE BUYDOCUMENTDATA ("
"ID INTEGER NOT NULL, " // 0. ID linea "ID INTEGER NOT NULL, " // 0. ID linea
"BUYDOCUMENT_CODE VARCHAR(10) NOT NULL, " // 1. ID Documento de compra "BUYDOCUMENT_CODE\tVARCHAR(10)\tNOT NULL, " // 1. ID Documento de compra
"ELEMENT_CODE VARCHAR(20), " // 2. ID del elemento "ELEMENT_CODE VARCHAR(20), " // 2. ID del elemento
"ELEMENT_SUPPLIER_CODE VARCHAR(20), " // 3. ID del elemento que tiene el proveedor "ELEMENT_SUPPLIER_CODE VARCHAR(20), " // 3. ID del elemento que tiene el proveedor
"ELEMENT_NAME VARCHAR(100), " // 4. Descripción del elemento "ELEMENT_NAME VARCHAR(100), " // 4. Descripción del elemento
@@ -458,24 +366,24 @@ const QString tDataDocCompra = "CREATE TABLE BUYDOCUMENTDATA ("
//----------------------- PROYECTO ----------------------------------------- //----------------------- PROYECTO -----------------------------------------
const QString tProyecto = "CREATE TABLE PROJECT (" const QString tProyecto = "CREATE TABLE PROJECT ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 0. ID "ID\tINTEGER PRIMARY KEY AUTOINCREMENT, " // 0. ID
"CODE VARCHAR(20) NOT NULL, " // 1. ID "CODE\tVARCHAR(20) NOT NULL, " // 1. ID
"TITLE VARCHAR(100) NOT NULL, " // 2. Título "TITLE\tVARCHAR(100) NOT NULL, " // 2. Título
"CUSTOMER_CODE VARCHAR(10) NOT NULL, " // 3. ID Cliente "CUSTOMER_CODE\tVARCHAR(10) NOT NULL, " // 3. ID Cliente
"CUSTOMER_NAME VARCHAR(60) NOT NULL, " // 4. Nombre del cliente "CUSTOMER_NAME\tVARCHAR(60) NOT NULL, " // 4. Nombre del cliente
"START_DATE DATE DEFAULT CURRENT_DATE, " // 5. Fecha de Inicio "START_DATE\tDATE DEFAULT CURRENT_DATE, " // 5. Fecha de Inicio
"DURATION DATE, " // 6. Fecha de Inicio "DURATION\tDATE, " // 6. Fecha de Inicio
"STATE VARCHAR(10), " // 7. Estado "STATE\tVARCHAR(10), " // 7. Estado
// Dirección de la obra // Dirección de la obra
"CONTACT VARCHAR(60), " // 8. Contacto "CONTACT\tVARCHAR(60), " // 8. Contacto
"ADDRESS1 VARCHAR(40), " // 9. Dir L1 "ADDRESS1\tVARCHAR(40), " // 9. Dir L1
"ADDRESS2 VARCHAR(40), " // 10. Dir L2 "ADDRESS2\tVARCHAR(40), " // 10. Dir L2
"POSTCODE VARCHAR(9), " // 11. CP "POSTCODE\tVARCHAR(9), " // 11. CP
"CITY VARCHAR(80), " // 12. Ciudad "CITY\tVARCHAR(80), " // 12. Ciudad
"PHONE VARCHAR(20), " // 13. Telefono "PHONE\tVARCHAR(20), " // 13. Telefono
"MOBILE VARCHAR(20), " // 14. Movil "MOBILE\tVARCHAR(20), " // 14. Movil
"EMAIL VARCHAR(60), " // 15. e-mail "EMAIL\tVARCHAR(60), " // 15. e-mail
"pyGantt BLOB" // 16. Imagen "pyGantt BLOB" // 16. Imagen
@@ -484,15 +392,15 @@ const QString tProyecto = "CREATE TABLE PROJECT ("
");"; ");";
const QString tProjectControl = "CREATE TABLE PROJECTCONTROL (" const QString tProjectControl = "CREATE TABLE PROJECTCONTROL ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID "ID\tINTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID
"pcPYCODE VARCHAR(20) NOT NULL, " // 02. ID "pcPYCODE\tVARCHAR(20) NOT NULL, " // 02. ID
"pcELID VARCHAR(20) NOT NULL, " // 03. ID "pcELID\tVARCHAR(20) NOT NULL, " // 03. ID
"pcELTITLE VARCHAR(100) NOT NULL, " // 04. ID Cliente "pcELTITLE VARCHAR(100) NOT NULL, " // 04. ID Cliente
"pcELTOTAL FLOAT, " // 05. Nombre del cliente "pcELTOTAL\tFLOAT, " // 05. Nombre del cliente
"pcELINSTALLED FLOAT, " // 06. Fecha de Inicio "pcELINSTALLED FLOAT, " // 06. Fecha de Inicio
"pcELREST FLOAT, " // 07. Fecha de Inicio "pcELREST\tFLOAT, " // 07. Fecha de Inicio
"pcELUNIT VARCHAR(2), " // 08. Estado "pcELUNIT\tVARCHAR(2), " // 08. Estado
"pcELDATE DATE DEFAULT CURRENT_DATE, " // 09. Estado "pcELDATE\tDATE DEFAULT CURRENT_DATE, " // 09. Estado
"pcELTYPE VARCHAR(3), " "pcELTYPE VARCHAR(3), "
"pcELNODEINDEX INTEGER, " "pcELNODEINDEX INTEGER, "
"pcTASK VARCHAR(50), " "pcTASK VARCHAR(50), "
@@ -501,14 +409,34 @@ const QString tProjectControl = "CREATE TABLE PROJECTCONTROL ("
"CREATEDAT DATETIME DEFAULT CURRENT_DATE" "CREATEDAT DATETIME DEFAULT CURRENT_DATE"
");"; ");";
//----------------------- PROJECTDOCUMENT ------------------------------------
const QString tProjectDocument = "CREATE TABLE PROJECTDOCUMENT ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, "
"PROJECT_CODE VARCHAR(20) NOT NULL, "
"DOC_TYPE VARCHAR(2) NOT NULL, "
"DOC_CODE VARCHAR(20) NOT NULL, "
"CREATEDBY VARCHAR(100), "
"CREATEDAT DATETIME DEFAULT CURRENT_TIMESTAMP"
");";
//----------------------- PROJECTBUDGET --------------------------------------
const QString tProjectBudget = "CREATE TABLE PROJECTBUDGET ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, "
"PROJECT_CODE VARCHAR(20) NOT NULL, "
"CONCEPT VARCHAR(200), "
"AMOUNT FLOAT, "
"CREATEDBY VARCHAR(100), "
"CREATEDAT DATETIME DEFAULT CURRENT_TIMESTAMP"
");";
//----------------------- TRABAJADOR --------------------------------------- //----------------------- TRABAJADOR ---------------------------------------
const QString tTrabajador = "CREATE TABLE EMPLOYEE (" const QString tTrabajador = "CREATE TABLE EMPLOYEE ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID "ID INTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID
"SURNAME VARCHAR(60) NOT NULL, " // 02. Apellidos "SURNAME VARCHAR(60) NOT NULL, " // 02. Apellidos
"NAME VARCHAR(60) NOT NULL, " // 03. Nombre "NAME VARCHAR(60) NOT NULL, " // 03. Nombre
"STATE BOOLEAN DEFAULT FALSE, " // 04. Activo o inactivo "STATE\tBOOLEAN\tDEFAULT FALSE, " // 04. Activo o inactivo
"CATEGORY VARCHAR(30), " // 05. Categoría "CATEGORY VARCHAR(30), " // 05. Categoría
"PRICEPERHOUR FLOAT, " // 06. Precio Hora "PRICEPERHOUR\tFLOAT, " // 06. Precio Hora
"NOTES BLOB," // 07. Notas "NOTES BLOB," // 07. Notas
"PICTURE BLOB," "PICTURE BLOB,"
@@ -518,19 +446,19 @@ const QString tTrabajador = "CREATE TABLE EMPLOYEE ("
//----------------------- CONTACTOS ----------------------------------------- //----------------------- CONTACTOS -----------------------------------------
const QString tContact = "CREATE TABLE CONTACT (" const QString tContact = "CREATE TABLE CONTACT ("
"coID INTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID "coID\tINTEGER PRIMARY KEY AUTOINCREMENT, " // 01. ID
"coCode VARCHAR(20) NOT NULL, " // 02. Code "coCode\tVARCHAR(20) NOT NULL, " // 02. Code
"coNombre VARCHAR(60) NOT NULL, " // 03. Nombre "coNombre\tVARCHAR(60) NOT NULL, " // 03. Nombre
"coApellido VARCHAR(60) NOT NULL, " // 04. Apellidos "coApellido\tVARCHAR(60) NOT NULL, " // 04. Apellidos
"coForma VARCHAR(10), " // 05. Forma "coForma\tVARCHAR(10), " // 05. Forma
"coPuesto VARCHAR(20), " // 06. Puesto "coPuesto\tVARCHAR(20), " // 06. Puesto
"coclCode VARCHAR(20), " // 07. Código Empresa "coclCode\tVARCHAR(20), " // 07. Código Empresa
"coclNom VARCHAR(100), " // 08. Nombre Empresa "coclNom VARCHAR(100), " // 08. Nombre Empresa
"coTel VARCHAR(20), " // 09. Teléfono fijo "coTel\tVARCHAR(20), " // 09. Teléfono fijo
"coMovil VARCHAR(20), " // 10. Teléfono móvil "coMovil\tVARCHAR(20), " // 10. Teléfono móvil
"coFax VARCHAR(20), " // 11. Fax "coFax\tVARCHAR(20), " // 11. Fax
"coEMail VARCHAR(60)," // 12. e-mail "coEMail\tVARCHAR(60)," // 12. e-mail
"coImage BLOB," // 13. Imagen "coImage BLOB," // 13. Imagen
"CREATEDAT DATE DEFAULT CURRENT_DATE, " // 25. Fecha de creación "CREATEDAT DATE DEFAULT CURRENT_DATE, " // 25. Fecha de creación
@@ -539,10 +467,29 @@ const QString tContact = "CREATE TABLE CONTACT ("
//----------------------- TEMPLATE -----------------------------------------
const QString tTemplate = "CREATE TABLE TEMPLATE ("
"ID INTEGER PRIMARY KEY AUTOINCREMENT, "
"NAME VARCHAR(100) NOT NULL, "
"DESCRIPTION VARCHAR(500), "
"DOCUMENT_TYPE VARCHAR(20) NOT NULL, "
"WIDTH_MM FLOAT DEFAULT 210, "
"HEIGHT_MM FLOAT DEFAULT 297, "
"MARGIN_TOP FLOAT DEFAULT 20, "
"MARGIN_BOTTOM FLOAT DEFAULT 20, "
"MARGIN_LEFT FLOAT DEFAULT 20, "
"MARGIN_RIGHT FLOAT DEFAULT 20, "
"CONTENT TEXT, "
"IS_DEFAULT BOOLEAN DEFAULT 0, "
"CREATEDBY VARCHAR(100), "
"CREATEDAT DATETIME DEFAULT CURRENT_TIMESTAMP, "
"UPDATEDAT DATETIME DEFAULT CURRENT_TIMESTAMP"
");";
const QStringList dbTables = {tDBInfo, tEmpresaInfo, tThird, tElemento, tElemComp, tUnidad, tPropuestaVenta, tDataPropuestaVenta, const QStringList dbTables = {tDBInfo, tEmpresaInfo, tThird, tElemento, tElemComp, tUnidad, tPropuestaVenta, tDataPropuestaVenta,
tDocVenta, tDataDocVenta, tDocCompra, tDataDocCompra, tContact}; tDocVenta, tDataDocVenta, tDocCompra, tDataDocCompra, tContact, tTemplate, tProjectDocument, tProjectBudget};
const QStringList dbTableNames = {"DBINFO", "ENTERPRISESINFO", "THIRD", "ELEMENT", "ELEMENTCOMPOSITION", "UNIT", "SALEPROPOSAL", "SALEPROPOSALDATA", const QStringList dbTableNames = {"DBINFO", "ENTERPRISESINFO", "THIRD", "ELEMENT", "ELEMENTCOMPOSITION", "UNIT", "SALEPROPOSAL", "SALEPROPOSALDATA",
"SALEDOCUMENT", "SALEDOCUMENTDATA", "BUYDOCUMENT", "BUYDOCUMENTDATA", "CONTACT"}; "SALEDOCUMENT", "SALEDOCUMENTDATA", "BUYDOCUMENT", "BUYDOCUMENTDATA", "CONTACT", "TEMPLATE", "PROJECTDOCUMENT", "PROJECTBUDGET"};
#endif // SQLTABLE_H #endif // SQLTABLE_H
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-178
View File
@@ -1,178 +0,0 @@
#include "formelementlist.h"
#include "qpainter.h"
#include "ui_formelementlist.h"
#include "formproduct.h"
#include "mainwindow.h"
#include "mapplication.h"
#include "msqlquerymodel.h"
#include "utils/filtertableheader.h"
#include "gui/formbaselist.h"
#include <QDrag>
formElementList::formElementList(QWidget *parent) :
QWidget(parent),
ui(new Ui::formElementList)
{
ui->setupUi(this);
mModel = new MSqlQueryModel(this);
ui->tableView->setModel(mModel);
updateList();
ui->tableView->setColumnWidth(0, 150);
ui->tableView->setColumnWidth(1, 80);
ui->tableView->setColumnWidth(2, 120);
ui->tableView->setColumnWidth(3, 350);
ui->tableView->setColumnWidth(4, 80);
ui->tableView->setColumnWidth(5, 80);
ui->tableView->setColumnWidth(6, 40);
// Set up filter row
auto *m_tableHeader = new FilterTableHeader(ui->tableView);
ui->tableView->setHorizontalHeader(m_tableHeader);
m_tableHeader->setFilter(0, "");
m_tableHeader->setFocusColumn(0);
ui->tableView->horizontalHeader()->model()->setHeaderData(0, Qt::Horizontal, tr("Tipo"));
ui->tableView->horizontalHeader()->model()->setHeaderData(1, Qt::Horizontal, tr("Clase"));
ui->tableView->horizontalHeader()->model()->setHeaderData(2, Qt::Horizontal, tr("Código"));
ui->tableView->horizontalHeader()->model()->setHeaderData(3, Qt::Horizontal, tr("Resumen"));
ui->tableView->horizontalHeader()->model()->setHeaderData(4, Qt::Horizontal, tr("Coste"));
ui->tableView->horizontalHeader()->model()->setHeaderData(5, Qt::Horizontal, tr("Venta"));
ui->tableView->horizontalHeader()->model()->setHeaderData(6, Qt::Horizontal, tr("Activo"));
ui->tableView->setDragEnabled(true); // Habilita el drag
connect(ui->tableView, &QTableView::pressed, this, &formElementList::startDrag);
}
formElementList::~formElementList()
{
delete ui;
}
void formElementList::updateList()
{
dApp->Enterprise().open();
mModel->setQuery("SELECT TYPE1, TYPE2, CODE, TITLE, PURCHASE_PRICE, SALE_PRICE, STATE FROM ELEMENT" /*" ORDER BY CODE ASC"*/,
dApp->Enterprise());
dApp->Enterprise().close();
}
void formElementList::on_buttonNew_released()
{
formProduct *form = dApp->mainWindow()->createFormProduct(); // sustistuir por Mainwindow::createFormProduct();
form->show();
}
void formElementList::on_buttonEdit_released()
{
openDocument(ui->tableView->currentIndex());
}
void formElementList::on_buttonClone_released()
{
}
void formElementList::on_buttonDelete_released()
{
QModelIndex index = ui->tableView->currentIndex();
QAbstractItemModel *model = const_cast<QAbstractItemModel*>(index.model()); // Obtén el modelo asociado
if (index.column() != 0)
{
//index = index.parent().child(index.row(), 0);
index = model->index(index.row(), 0, index.parent());
}
QString ID = index.data().toString();
QModelIndex parentIndex = index.parent();
QModelIndex childIndex = model->index(index.row(), 2, parentIndex); // Obtén el índice del hijo
int type = childIndex.data().toInt(); // Accede al dato
//int type = index.parent().child(index.row(), 2).data().toInt();
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
/*
if (index.parent().child(index.row(), 2).data().toInt() == 0)
{
// TODO: borrar la composición
if(!qry.exec(QString("DELETE FROM ELEMENTCOMPOSITION WHERE CODE = '%1';").arg(ID)))
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
goto error;
}
}
*/
if(!qry.exec(QString("DELETE FROM ELEMENT WHERE CODE = '%1';").arg(ID)))
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
}
updateList();
error:
dApp->Enterprise().close();
}
void formElementList::on_buttonUpdate_released()
{
updateList();
}
void formElementList::on_tableView_doubleClicked(const QModelIndex &index)
{
openDocument(index);
}
void formElementList::openDocument(QModelIndex index)
{
QAbstractItemModel *model = ui->tableView->model();
//QModelIndex item = index;
formProduct *form = dApp->mainWindow()->createFormProduct();
//if (index.column() != 2)
// item = index.parent().child(index.row(), 2);
form->openDocument(model->index(index.row(), 2).data().toString());// item.data().toString());
form->show();
}
void formElementList::startDrag(const QModelIndex &index) {
if (!index.isValid())
return;
// Crear datos MIME
QMimeData *mimeData = new QMimeData();
QString data = mModel->data(index).toString();
mimeData->setText(data);
// Iniciar arrastre
QDrag *drag = new QDrag(ui->tableView);
drag->setMimeData(mimeData);
// Crear un ícono para el cursor
QPixmap pixmap(100, 30);
pixmap.fill(Qt::transparent); // Fondo transparente
QPainter painter(&pixmap);
painter.setBrush(Qt::yellow);
painter.drawRoundedRect(0, 0, pixmap.width(), pixmap.height(), 5, 5);
painter.setPen(Qt::black);
painter.drawText(pixmap.rect(), Qt::AlignCenter, data);
painter.end();
drag->setPixmap(pixmap); // Asignar el ícono al cursor
//drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); // Centro del ícono como punto caliente
drag->exec(Qt::MoveAction);
}
-178
View File
@@ -1,178 +0,0 @@
#include "formelementlist.h"
#include "qpainter.h"
#include "ui_formelementlist.h"
#include "formproduct.h"
#include "mainwindow.h"
#include "mapplication.h"
#include "msqlquerymodel.h"
#include "utils/filtertableheader.h"
#include "gui/formbaselist.h"
#include <QDrag>
formElementList::formElementList(QWidget *parent) :
QWidget(parent),
ui(new Ui::formElementList)
{
ui->setupUi(this);
mModel = new MSqlQueryModel(this);
ui->tableView->setModel(mModel);
updateList();
ui->tableView->setColumnWidth(0, 150);
ui->tableView->setColumnWidth(1, 80);
ui->tableView->setColumnWidth(2, 120);
ui->tableView->setColumnWidth(3, 350);
ui->tableView->setColumnWidth(4, 80);
ui->tableView->setColumnWidth(5, 80);
ui->tableView->setColumnWidth(6, 40);
// Set up filter row
auto *m_tableHeader = new FilterTableHeader(ui->tableView);
ui->tableView->setHorizontalHeader(m_tableHeader);
m_tableHeader->setFilter(0, "");
m_tableHeader->setFocusColumn(0);
ui->tableView->horizontalHeader()->model()->setHeaderData(0, Qt::Horizontal, tr("Tipo"));
ui->tableView->horizontalHeader()->model()->setHeaderData(1, Qt::Horizontal, tr("Clase"));
ui->tableView->horizontalHeader()->model()->setHeaderData(2, Qt::Horizontal, tr("Código"));
ui->tableView->horizontalHeader()->model()->setHeaderData(3, Qt::Horizontal, tr("Resumen"));
ui->tableView->horizontalHeader()->model()->setHeaderData(4, Qt::Horizontal, tr("Coste"));
ui->tableView->horizontalHeader()->model()->setHeaderData(5, Qt::Horizontal, tr("Venta"));
ui->tableView->horizontalHeader()->model()->setHeaderData(6, Qt::Horizontal, tr("Activo"));
ui->tableView->setDragEnabled(true); // Habilita el drag
connect(ui->tableView, &QTableView::pressed, this, &formElementList::startDrag);
}
formElementList::~formElementList()
{
delete ui;
}
void formElementList::updateList()
{
dApp->Enterprise().open();
mModel->setQuery("SELECT TYPE1, TYPE2, CODE, TITLE, PURCHASE_PRICE, SALE_PRICE, STATE FROM ELEMENT" /*" ORDER BY CODE ASC"*/,
dApp->Enterprise());
dApp->Enterprise().close();
}
void formElementList::on_buttonNew_released()
{
formProduct *form = dApp->mainWindow()->createFormProduct(); // sustistuir por Mainwindow::createFormProduct();
form->show();
}
void formElementList::on_buttonEdit_released()
{
openDocument(ui->tableView->currentIndex());
}
void formElementList::on_buttonClone_released()
{
}
void formElementList::on_buttonDelete_released()
{
QModelIndex index = ui->tableView->currentIndex();
QAbstractItemModel *model = const_cast<QAbstractItemModel*>(index.model()); // Obtén el modelo asociado
if (index.column() != 0)
{
//index = index.parent().child(index.row(), 0);
index = model->index(index.row(), 0, index.parent());
}
QString ID = index.data().toString();
QModelIndex parentIndex = index.parent();
QModelIndex childIndex = model->index(index.row(), 2, parentIndex); // Obtén el índice del hijo
int type = childIndex.data().toInt(); // Accede al dato
//int type = index.parent().child(index.row(), 2).data().toInt();
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
/*
if (index.parent().child(index.row(), 2).data().toInt() == 0)
{
// TODO: borrar la composición
if(!qry.exec(QString("DELETE FROM ELEMENTCOMPOSITION WHERE CODE = '%1';").arg(ID)))
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
goto error;
}
}
*/
if(!qry.exec(QString("DELETE FROM ELEMENT WHERE CODE = '%1';").arg(ID)))
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
}
updateList();
error:
dApp->Enterprise().close();
}
void formElementList::on_buttonUpdate_released()
{
updateList();
}
void formElementList::on_tableView_doubleClicked(const QModelIndex &index)
{
openDocument(index);
}
void formElementList::openDocument(QModelIndex index)
{
QAbstractItemModel *model = ui->tableView->model();
//QModelIndex item = index;
formProduct *form = dApp->mainWindow()->createFormProduct();
//if (index.column() != 2)
// item = index.parent().child(index.row(), 2);
form->openDocument(model->index(index.row(), 2).data().toString());// item.data().toString());
form->show();
}
void formElementList::startDrag(const QModelIndex &index) {
if (!index.isValid())
return;
// Crear datos MIME
QMimeData *mimeData = new QMimeData();
QString data = mModel->data(index).toString();
mimeData->setText(data);
// Iniciar arrastre
QDrag *drag = new QDrag(ui->tableView);
drag->setMimeData(mimeData);
// Crear un ícono para el cursor
QPixmap pixmap(100, 30);
pixmap.fill(Qt::transparent); // Fondo transparente
QPainter painter(&pixmap);
painter.setBrush(Qt::yellow);
painter.drawRoundedRect(0, 0, pixmap.width(), pixmap.height(), 5, 5);
painter.setPen(Qt::black);
painter.drawText(pixmap.rect(), Qt::AlignCenter, data);
painter.end();
drag->setPixmap(pixmap); // Asignar el ícono al cursor
//drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); // Centro del ícono como punto caliente
drag->exec(Qt::MoveAction);
}
-54
View File
@@ -1,54 +0,0 @@
#ifndef FORMPRODUCT_H
#define FORMPRODUCT_H
#include <QWidget>
#include "formbase.h"
namespace Ui
{
class formProduct;
}
class formProduct : public formBase
{
Q_OBJECT
public:
//explicit formProduct(QWidget *parent = 0);
explicit formProduct(QString aID = "", int aEditMode = 0, QWidget *parent = nullptr);
~formProduct();
void newDocument() override {}
void openDocument(QString id) override;
void closeDocument() override;
void save() override;
bool needsave() override { return mNeedSave; }
void setEditMode(bool aMode) override {}
public slots:
void on_ModelSetData(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
private slots:
void on_editPC_valueChanged(double arg1);
void on_editMargin_valueChanged(double arg1);
void on_editPV_valueChanged(double arg1);
void on_comboIVA_currentIndexChanged(const QString &arg1);
void on_editPV_editingFinished();
void on_buttonSave_released();
void on_editPVIVA_valueChanged(const QString &arg1);
void on_comboType2_currentIndexChanged(int index);
private:
Ui::formProduct *ui;
bool editMode;
void CalculatePrice();
bool InsertElement(QString ID, QModelIndex index);
void setLineType(QString type, QModelIndex index);
void setCellText(QString val, QModelIndex index, int col);
void setEditMode();
void setComposeElement(bool val);
};
#endif // FORMPRODUCT_H
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+43 -2
View File
@@ -124,9 +124,8 @@ bool ProductDAO::update(const QString& code, int type1, int type2, const QString
"UNIT_ID = :UNIT_ID, DATE_UPDATE = :DATE_UPDATE, REAL_PRICE = :REAL_PRICE, DISCOUNT = :DISCOUNT, " "UNIT_ID = :UNIT_ID, DATE_UPDATE = :DATE_UPDATE, REAL_PRICE = :REAL_PRICE, DISCOUNT = :DISCOUNT, "
"PURCHASE_PRICE = :PURCHASE_PRICE, BENEFIT = :BENEFIT, TAX = :TAX, SALE_PRICE = :SALE_PRICE, BARCODE = :BARCODE, IMAGE = :IMAGE, " "PURCHASE_PRICE = :PURCHASE_PRICE, BENEFIT = :BENEFIT, TAX = :TAX, SALE_PRICE = :SALE_PRICE, BARCODE = :BARCODE, IMAGE = :IMAGE, "
"STATE = :STATE, MANUFACTURER = :MANUFACTURER, GAMMA = :GAMMA, WEIGHT = :WEIGHT, HEIGHT = :HEIGHT, " "STATE = :STATE, MANUFACTURER = :MANUFACTURER, GAMMA = :GAMMA, WEIGHT = :WEIGHT, HEIGHT = :HEIGHT, "
"WIDTH = :WIDTH, LENGHT = :LENGHT " "WIDTH = :WIDTH, LENGHT = :LENGHT "\
"WHERE CODE = :CODE"); "WHERE CODE = :CODE");
);
qry.bindValue(":TYPE1", type1); qry.bindValue(":TYPE1", type1);
qry.bindValue(":TYPE2", type2); qry.bindValue(":TYPE2", type2);
@@ -294,3 +293,45 @@ bool ProductDAO::updateCompositionElement(const QString& productCode, const QStr
dApp->Enterprise().close(); dApp->Enterprise().close();
return success; return success;
} }
// Remove all composition elements for a product
bool ProductDAO::removeAllComposition(const QString& productCode)
{
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
qry.prepare("DELETE FROM ELEMENTCOMPOSITION WHERE CODE = :CODE");
qry.bindValue(":CODE", productCode);
bool success = qry.exec();
if (!success) {
qDebug() << "Error removing all composition elements:" << qry.lastError().text();
}
dApp->Enterprise().close();
return success;
}
// Get basic element info (title, unit) for display in composition tree
bool ProductDAO::getElementBasicInfo(const QString& code, QString& title, QString& unitId)
{
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
qry.prepare("SELECT TITLE, UNIT_ID FROM ELEMENT WHERE CODE = :CODE");
qry.bindValue(":CODE", code);
bool success = qry.exec();
if (!success) {
qDebug() << "Error getting element basic info:" << qry.lastError().text();
dApp->Enterprise().close();
return false;
}
if (qry.next()) {
title = qry.value(0).toString();
unitId = qry.value(1).toString();
} else {
success = false;
}
dApp->Enterprise().close();
return success;
}
+7 -1
View File
@@ -6,7 +6,7 @@
#include <QSqlError> #include <QSqlError>
#include <QDebug> #include <QDebug>
#include <QVector> #include <QVector>
#include "../gui/formproduct.h" #include "../gui/forms/formproduct.h"
#include "../data/sqltable.h" #include "../data/sqltable.h"
class ProductDAO class ProductDAO
@@ -58,6 +58,12 @@ public:
// Update composition element amount // Update composition element amount
static bool updateCompositionElement(const QString& productCode, const QString& elementCode, double amount); static bool updateCompositionElement(const QString& productCode, const QString& elementCode, double amount);
// Remove all composition elements for a product
static bool removeAllComposition(const QString& productCode);
// Get basic element info (title, unit) for display in composition tree
static bool getElementBasicInfo(const QString& code, QString& title, QString& unitId);
}; };
#endif // PRODUCTDAO_H #endif // PRODUCTDAO_H
+328
View File
@@ -0,0 +1,328 @@
#include "projectdao.h"
// --------------- Project CRUD ---------------
bool ProjectDAO::create(Project &proj)
{
QSqlQuery query;
query.prepare("INSERT INTO PROJECT (CODE, TITLE, CUSTOMER_CODE, CUSTOMER_NAME, "
"START_DATE, DURATION, STATE, CONTACT, ADDRESS1, ADDRESS2, "
"POSTCODE, CITY, PHONE, MOBILE, EMAIL, CREATEDBY) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
query.addBindValue(proj.code);
query.addBindValue(proj.title);
query.addBindValue(proj.customerCode);
query.addBindValue(proj.customerName);
query.addBindValue(proj.startDate);
query.addBindValue(proj.duration);
query.addBindValue(proj.state);
query.addBindValue(proj.contact);
query.addBindValue(proj.address1);
query.addBindValue(proj.address2);
query.addBindValue(proj.postcode);
query.addBindValue(proj.city);
query.addBindValue(proj.phone);
query.addBindValue(proj.mobile);
query.addBindValue(proj.email);
query.addBindValue("user");
if (!query.exec()) {
qWarning() << "ProjectDAO::create - Error:" << query.lastError().text();
return false;
}
proj.id = query.lastInsertId().toInt();
return true;
}
bool ProjectDAO::update(const Project &proj)
{
QSqlQuery query;
query.prepare("UPDATE PROJECT SET TITLE=?, CUSTOMER_CODE=?, CUSTOMER_NAME=?, "
"START_DATE=?, DURATION=?, STATE=?, CONTACT=?, ADDRESS1=?, ADDRESS2=?, "
"POSTCODE=?, CITY=?, PHONE=?, MOBILE=?, EMAIL=? WHERE CODE=?");
query.addBindValue(proj.title);
query.addBindValue(proj.customerCode);
query.addBindValue(proj.customerName);
query.addBindValue(proj.startDate);
query.addBindValue(proj.duration);
query.addBindValue(proj.state);
query.addBindValue(proj.contact);
query.addBindValue(proj.address1);
query.addBindValue(proj.address2);
query.addBindValue(proj.postcode);
query.addBindValue(proj.city);
query.addBindValue(proj.phone);
query.addBindValue(proj.mobile);
query.addBindValue(proj.email);
query.addBindValue(proj.code);
if (!query.exec()) {
qWarning() << "ProjectDAO::update - Error:" << query.lastError().text();
return false;
}
return query.numRowsAffected() > 0;
}
bool ProjectDAO::remove(const QString &code)
{
QSqlQuery query;
query.prepare("DELETE FROM PROJECT WHERE CODE = ?");
query.addBindValue(code);
if (!query.exec()) {
qWarning() << "ProjectDAO::remove - Error:" << query.lastError().text();
return false;
}
return true;
}
Project ProjectDAO::getByCode(const QString &code)
{
Project proj;
QSqlQuery query;
query.prepare("SELECT ID, CODE, TITLE, CUSTOMER_CODE, CUSTOMER_NAME, "
"START_DATE, DURATION, STATE, CONTACT, ADDRESS1, ADDRESS2, "
"POSTCODE, CITY, PHONE, MOBILE, EMAIL FROM PROJECT WHERE CODE = ?");
query.addBindValue(code);
if (query.exec() && query.next()) {
proj.id = query.value(0).toInt();
proj.code = query.value(1).toString();
proj.title = query.value(2).toString();
proj.customerCode = query.value(3).toString();
proj.customerName = query.value(4).toString();
proj.startDate = query.value(5).toDate();
proj.duration = query.value(6).toDate();
proj.state = query.value(7).toString();
proj.contact = query.value(8).toString();
proj.address1 = query.value(9).toString();
proj.address2 = query.value(10).toString();
proj.postcode = query.value(11).toString();
proj.city = query.value(12).toString();
proj.phone = query.value(13).toString();
proj.mobile = query.value(14).toString();
proj.email = query.value(15).toString();
}
return proj;
}
Project ProjectDAO::getById(int id)
{
Project proj;
QSqlQuery query;
query.prepare("SELECT ID, CODE, TITLE, CUSTOMER_CODE, CUSTOMER_NAME, "
"START_DATE, DURATION, STATE, CONTACT, ADDRESS1, ADDRESS2, "
"POSTCODE, CITY, PHONE, MOBILE, EMAIL FROM PROJECT WHERE ID = ?");
query.addBindValue(id);
if (query.exec() && query.next()) {
proj.id = query.value(0).toInt();
proj.code = query.value(1).toString();
proj.title = query.value(2).toString();
proj.customerCode = query.value(3).toString();
proj.customerName = query.value(4).toString();
proj.startDate = query.value(5).toDate();
proj.duration = query.value(6).toDate();
proj.state = query.value(7).toString();
proj.contact = query.value(8).toString();
proj.address1 = query.value(9).toString();
proj.address2 = query.value(10).toString();
proj.postcode = query.value(11).toString();
proj.city = query.value(12).toString();
proj.phone = query.value(13).toString();
proj.mobile = query.value(14).toString();
proj.email = query.value(15).toString();
}
return proj;
}
QVector<Project> ProjectDAO::getAll()
{
QVector<Project> result;
QSqlQuery query("SELECT ID, CODE, TITLE, CUSTOMER_CODE, CUSTOMER_NAME, "
"START_DATE, DURATION, STATE, CONTACT, ADDRESS1, ADDRESS2, "
"POSTCODE, CITY, PHONE, MOBILE, EMAIL FROM PROJECT ORDER BY CODE");
while (query.next()) {
Project proj;
proj.id = query.value(0).toInt();
proj.code = query.value(1).toString();
proj.title = query.value(2).toString();
proj.customerCode = query.value(3).toString();
proj.customerName = query.value(4).toString();
proj.startDate = query.value(5).toDate();
proj.duration = query.value(6).toDate();
proj.state = query.value(7).toString();
proj.contact = query.value(8).toString();
proj.address1 = query.value(9).toString();
proj.address2 = query.value(10).toString();
proj.postcode = query.value(11).toString();
proj.city = query.value(12).toString();
proj.phone = query.value(13).toString();
proj.mobile = query.value(14).toString();
proj.email = query.value(15).toString();
result.append(proj);
}
return result;
}
QStringList ProjectDAO::getAllCodes()
{
QStringList codes;
QSqlQuery query("SELECT CODE FROM PROJECT ORDER BY CODE");
while (query.next())
codes.append(query.value(0).toString());
return codes;
}
bool ProjectDAO::exists(const QString &code)
{
QSqlQuery query;
query.prepare("SELECT COUNT(*) FROM PROJECT WHERE CODE = ?");
query.addBindValue(code);
if (query.exec() && query.next())
return query.value(0).toInt() > 0;
return false;
}
// --------------- Project status ---------------
bool ProjectDAO::setState(const QString &code, const QString &state)
{
QSqlQuery query;
query.prepare("UPDATE PROJECT SET STATE = ? WHERE CODE = ?");
query.addBindValue(state);
query.addBindValue(code);
return query.exec();
}
QStringList ProjectDAO::getStates()
{
return {"draft", "active", "paused", "completed", "cancelled"};
}
// --------------- Project documents ---------------
bool ProjectDAO::attachDocument(const QString &projectCode, const QString &docType, const QString &docCode)
{
QSqlQuery query;
query.prepare("INSERT INTO PROJECTDOCUMENT (PROJECT_CODE, DOC_TYPE, DOC_CODE, CREATEDBY) "
"VALUES (?, ?, ?, ?)");
query.addBindValue(projectCode);
query.addBindValue(docType);
query.addBindValue(docCode);
query.addBindValue("user");
if (!query.exec()) {
qWarning() << "ProjectDAO::attachDocument - Error:" << query.lastError().text();
return false;
}
return true;
}
bool ProjectDAO::removeDocument(int docId)
{
QSqlQuery query;
query.prepare("DELETE FROM PROJECTDOCUMENT WHERE ID = ?");
query.addBindValue(docId);
return query.exec();
}
QVector<ProjectDocument> ProjectDAO::getDocuments(const QString &projectCode)
{
QVector<ProjectDocument> result;
QSqlQuery query;
query.prepare("SELECT ID, PROJECT_CODE, DOC_TYPE, DOC_CODE FROM PROJECTDOCUMENT WHERE PROJECT_CODE = ?");
query.addBindValue(projectCode);
if (query.exec()) {
while (query.next()) {
ProjectDocument doc;
doc.id = query.value(0).toInt();
doc.projectCode = query.value(1).toString();
doc.docType = query.value(2).toString();
doc.docCode = query.value(3).toString();
result.append(doc);
}
}
return result;
}
// --------------- Project budget ---------------
bool ProjectDAO::addBudgetLine(const QString &projectCode, const QString &concept, double amount)
{
QSqlQuery query;
query.prepare("INSERT INTO PROJECTBUDGET (PROJECT_CODE, CONCEPT, AMOUNT, CREATEDBY) VALUES (?, ?, ?, ?)");
query.addBindValue(projectCode);
query.addBindValue(concept);
query.addBindValue(amount);
query.addBindValue("user");
if (!query.exec()) {
qWarning() << "ProjectDAO::addBudgetLine - Error:" << query.lastError().text();
return false;
}
return true;
}
bool ProjectDAO::removeBudgetLine(int budgetId)
{
QSqlQuery query;
query.prepare("DELETE FROM PROJECTBUDGET WHERE ID = ?");
query.addBindValue(budgetId);
return query.exec();
}
QVector<ProjectBudget> ProjectDAO::getBudget(const QString &projectCode)
{
QVector<ProjectBudget> result;
QSqlQuery query;
query.prepare("SELECT ID, PROJECT_CODE, CONCEPT, AMOUNT FROM PROJECTBUDGET WHERE PROJECT_CODE = ?");
query.addBindValue(projectCode);
if (query.exec()) {
while (query.next()) {
ProjectBudget b;
b.id = query.value(0).toInt();
b.projectCode = query.value(1).toString();
b.concept = query.value(2).toString();
b.amount = query.value(3).toDouble();
result.append(b);
}
}
return result;
}
double ProjectDAO::getTotalBudget(const QString &projectCode)
{
QSqlQuery query;
query.prepare("SELECT COALESCE(SUM(AMOUNT), 0) FROM PROJECTBUDGET WHERE PROJECT_CODE = ?");
query.addBindValue(projectCode);
if (query.exec() && query.next())
return query.value(0).toDouble();
return 0.0;
}
// --------------- Financial summary ---------------
double ProjectDAO::getTotalCost(const QString &projectCode)
{
QSqlQuery query;
query.prepare("SELECT COALESCE(SUM(PRICE), 0) FROM SALEDOCUMENT WHERE PROJECT_CODE = ?");
query.addBindValue(projectCode);
if (query.exec() && query.next())
return query.value(0).toDouble();
return 0.0;
}
double ProjectDAO::getTotalInvoiced(const QString &projectCode)
{
QSqlQuery query;
query.prepare("SELECT COALESCE(SUM(PRICE), 0) FROM SALEDOCUMENT WHERE PROJECT_CODE = ? AND TYPE = 'FA'");
query.addBindValue(projectCode);
if (query.exec() && query.next())
return query.value(0).toDouble();
return 0.0;
}
QPair<double, double> ProjectDAO::getFinancialSummary(const QString &projectCode)
{
double totalBudget = getTotalBudget(projectCode);
double totalCost = getTotalCost(projectCode);
return {totalBudget, totalCost};
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef PROJECTDAO_H
#define PROJECTDAO_H
#include <QObject>
#include <QString>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QVector>
#include <QPair>
#include <QDate>
struct Project {
int id = 0;
QString code;
QString title;
QString customerCode;
QString customerName;
QDate startDate;
QDate duration;
QString state;
QString contact;
QString address1;
QString address2;
QString postcode;
QString city;
QString phone;
QString mobile;
QString email;
};
struct ProjectDocument {
int id = 0;
QString projectCode;
QString docType; // PR, FI, FC, OT
QString docCode;
};
struct ProjectBudget {
int id = 0;
QString projectCode;
QString concept;
double amount = 0.0;
};
class ProjectDAO : public QObject
{
Q_OBJECT
public:
explicit ProjectDAO(QObject *parent = nullptr) : QObject(parent) {}
// Project CRUD
static bool create(Project &proj);
static bool update(const Project &proj);
static bool remove(const QString &code);
static Project getByCode(const QString &code);
static Project getById(int id);
static QVector<Project> getAll();
static QStringList getAllCodes();
static bool exists(const QString &code);
// Project status management
static bool setState(const QString &code, const QString &state);
static QStringList getStates();
// Project documents
static bool attachDocument(const QString &projectCode, const QString &docType, const QString &docCode);
static bool removeDocument(int docId);
static QVector<ProjectDocument> getDocuments(const QString &projectCode);
// Project budget
static bool addBudgetLine(const QString &projectCode, const QString &concept, double amount);
static bool removeBudgetLine(int budgetId);
static QVector<ProjectBudget> getBudget(const QString &projectCode);
static double getTotalBudget(const QString &projectCode);
// Financial summary
static double getTotalCost(const QString &projectCode);
static double getTotalInvoiced(const QString &projectCode);
static QPair<double, double> getFinancialSummary(const QString &projectCode);
};
#endif // PROJECTDAO_H
+152
View File
@@ -0,0 +1,152 @@
#include "templatedao.h"
#include "../../data/sqltable.h"
bool TemplateDAO::create(Template &tpl)
{
QSqlQuery query;
query.prepare(
"INSERT INTO TEMPLATE ("
"NAME, DESCRIPTION, DOCUMENT_TYPE, WIDTH_MM, HEIGHT_MM, "
"MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, CONTENT, IS_DEFAULT, CREATEDBY"
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
query.addBindValue(tpl.name);
query.addBindValue(tpl.description);
query.addBindValue(tpl.documentType);
query.addBindValue(tpl.widthMM);
query.addBindValue(tpl.heightMM);
query.addBindValue(tpl.marginTop);
query.addBindValue(tpl.marginBottom);
query.addBindValue(tpl.marginLeft);
query.addBindValue(tpl.marginRight);
query.addBindValue(tpl.content);
query.addBindValue(tpl.isDefault ? 1 : 0);
query.addBindValue(tpl.createdBy);
if (!query.exec()) {
qWarning() << "TemplateDAO::create - Error:" << query.lastError().text();
return false;
}
tpl.id = query.lastInsertId().toInt();
return true;
}
QVector<Template> TemplateDAO::getAll()
{
QVector<Template> result;
QSqlQuery query("SELECT ID, NAME, DESCRIPTION, DOCUMENT_TYPE, WIDTH_MM, HEIGHT_MM, "
"MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, CONTENT, IS_DEFAULT, CREATEDBY "
"FROM TEMPLATE ORDER BY NAME");
while (query.next()) {
Template tpl;
tpl.id = query.value(0).toInt();
tpl.name = query.value(1).toString();
tpl.description = query.value(2).toString();
tpl.documentType = query.value(3).toString();
tpl.widthMM = query.value(4).toDouble();
tpl.heightMM = query.value(5).toDouble();
tpl.marginTop = query.value(6).toDouble();
tpl.marginBottom = query.value(7).toDouble();
tpl.marginLeft = query.value(8).toDouble();
tpl.marginRight = query.value(9).toDouble();
tpl.content = query.value(10).toString();
tpl.isDefault = query.value(11).toBool();
tpl.createdBy = query.value(12).toString();
result.append(tpl);
}
return result;
}
Template TemplateDAO::getById(int id)
{
Template tpl;
QSqlQuery query;
query.prepare("SELECT ID, NAME, DESCRIPTION, DOCUMENT_TYPE, WIDTH_MM, HEIGHT_MM, "
"MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, CONTENT, IS_DEFAULT, CREATEDBY "
"FROM TEMPLATE WHERE ID = ?");
query.addBindValue(id);
if (query.exec() && query.next()) {
tpl.id = query.value(0).toInt();
tpl.name = query.value(1).toString();
tpl.description = query.value(2).toString();
tpl.documentType = query.value(3).toString();
tpl.widthMM = query.value(4).toDouble();
tpl.heightMM = query.value(5).toDouble();
tpl.marginTop = query.value(6).toDouble();
tpl.marginBottom = query.value(7).toDouble();
tpl.marginLeft = query.value(8).toDouble();
tpl.marginRight = query.value(9).toDouble();
tpl.content = query.value(10).toString();
tpl.isDefault = query.value(11).toBool();
tpl.createdBy = query.value(12).toString();
}
return tpl;
}
bool TemplateDAO::update(const Template &tpl)
{
QSqlQuery query;
query.prepare(
"UPDATE TEMPLATE SET "
"NAME=?, DESCRIPTION=?, DOCUMENT_TYPE=?, WIDTH_MM=?, HEIGHT_MM=?, "
"MARGIN_TOP=?, MARGIN_BOTTOM=?, MARGIN_LEFT=?, MARGIN_RIGHT=?, "
"CONTENT=?, IS_DEFAULT=? "
"WHERE ID=?"
);
query.addBindValue(tpl.name);
query.addBindValue(tpl.description);
query.addBindValue(tpl.documentType);
query.addBindValue(tpl.widthMM);
query.addBindValue(tpl.heightMM);
query.addBindValue(tpl.marginTop);
query.addBindValue(tpl.marginBottom);
query.addBindValue(tpl.marginLeft);
query.addBindValue(tpl.marginRight);
query.addBindValue(tpl.content);
query.addBindValue(tpl.isDefault ? 1 : 0);
query.addBindValue(tpl.id);
if (!query.exec()) {
qWarning() << "TemplateDAO::update - Error:" << query.lastError().text();
return false;
}
return true;
}
bool TemplateDAO::remove(int id)
{
QSqlQuery query;
query.prepare("DELETE FROM TEMPLATE WHERE ID = ?");
query.addBindValue(id);
if (!query.exec()) {
qWarning() << "TemplateDAO::remove - Error:" << query.lastError().text();
return false;
}
return true;
}
Template TemplateDAO::getDefaultForType(const QString &documentType)
{
Template tpl;
QSqlQuery query;
query.prepare("SELECT ID, NAME, DESCRIPTION, DOCUMENT_TYPE, WIDTH_MM, HEIGHT_MM, "
"MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, CONTENT, IS_DEFAULT, CREATEDBY "
"FROM TEMPLATE WHERE DOCUMENT_TYPE = ? AND IS_DEFAULT = 1 LIMIT 1");
query.addBindValue(documentType);
if (query.exec() && query.next()) {
tpl.id = query.value(0).toInt();
tpl.name = query.value(1).toString();
tpl.description = query.value(2).toString();
tpl.documentType = query.value(3).toString();
tpl.widthMM = query.value(4).toDouble();
tpl.heightMM = query.value(5).toDouble();
tpl.marginTop = query.value(6).toDouble();
tpl.marginBottom = query.value(7).toDouble();
tpl.marginLeft = query.value(8).toDouble();
tpl.marginRight = query.value(9).toDouble();
tpl.content = query.value(10).toString();
tpl.isDefault = query.value(11).toBool();
tpl.createdBy = query.value(12).toString();
}
return tpl;
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef TEMPLATEDAO_H
#define TEMPLATEDAO_H
#include <QObject>
#include <QString>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QVector>
class Template
{
public:
int id = 0;
QString name;
QString description;
QString documentType; // budget, invoice, project, purchase, third, generic
double widthMM = 210;
double heightMM = 297;
double marginTop = 20;
double marginBottom = 20;
double marginLeft = 20;
double marginRight = 20;
QString content; // JSON con definicion de elementos
bool isDefault = false;
QString createdBy;
};
class TemplateDAO : public QObject
{
Q_OBJECT
public:
explicit TemplateDAO(QObject *parent = nullptr) : QObject(parent) {}
static bool create(Template &tpl);
static QVector<Template> getAll();
static Template getById(int id);
static bool update(const Template &tpl);
static bool remove(int id);
static Template getDefaultForType(const QString &documentType);
};
#endif // TEMPLATEDAO_H
+265
View File
@@ -0,0 +1,265 @@
#include "templateengine.h"
#include <QFile>
#include <QDir>
#include <QTextStream>
#include <QProcess>
#include <QRegularExpression>
#include <QStandardPaths>
QString TemplateEngine::exportDir()
{
QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/BudgetPro_Export";
if (!QDir(dir).exists())
QDir().mkpath(dir);
return dir;
}
QString TemplateEngine::resolveValue(const QString &text, const QJsonObject &data)
{
QString result = text;
static QRegularExpression re("\\{\\{(.+?)\\}\\}");
QRegularExpressionMatchIterator it = re.globalMatch(text);
while (it.hasNext()) {
QRegularExpressionMatch match = it.next();
QString path = match.captured(1).trimmed();
QStringList parts = path.split(".");
QJsonValue val = data;
for (const QString &part : parts) {
if (val.isObject())
val = val.toObject()[part];
else if (val.isArray()) {
bool ok;
int idx = part.toInt(&ok);
if (ok)
val = val.toArray()[idx];
else
val = QJsonValue();
} else {
val = QJsonValue();
break;
}
}
QString replacement;
if (val.isDouble())
replacement = QString::number(val.toDouble(), 'f', 2);
else
replacement = val.toString();
result.replace(match.captured(0), replacement);
}
return result;
}
void TemplateEngine::drawLabel(QPainter *painter, const QJsonObject &elem, const QJsonObject &data)
{
QString text = resolveValue(elem["text"].toString(), data);
int x = elem["x"].toInt();
int y = elem["y"].toInt();
int w = elem.value("w").toInt(150);
int h = elem.value("h").toInt(20);
QString font = elem.value("font").toString("Arial");
int size = elem.value("size").toInt(12);
bool bold = elem.value("bold").toBool(false);
QFont f(font, size);
f.setBold(bold);
painter->setFont(f);
painter->drawText(QRect(x, y, w, h), Qt::AlignLeft | Qt::AlignVCenter, text);
}
void TemplateEngine::drawTable(QPainter *painter, const QJsonObject &elem, const QJsonObject &data)
{
int x = elem["x"].toInt();
int y = elem["y"].toInt();
int w = elem["w"].toInt(200);
int rowHeight = elem.value("rowHeight").toInt(20);
QJsonArray columns = elem["columns"].toArray();
int colCount = columns.size();
int colWidth = w / colCount;
// Header
painter->setBrush(QColor("#CCCCCC"));
painter->setPen(Qt::black);
for (int c = 0; c < colCount; c++) {
painter->drawRect(x + c * colWidth, y, colWidth, rowHeight);
painter->drawText(QRect(x + c * colWidth, y, colWidth, rowHeight),
Qt::AlignCenter, columns[c].toString());
}
// Data
QString dsPath = elem["dataSource"].toString();
QStringList parts = dsPath.split(".");
QJsonValue dsValue = data;
for (const QString &part : parts) {
if (dsValue.isObject())
dsValue = dsValue.toObject()[part];
else
break;
}
if (!dsValue.isArray())
return;
QJsonArray rows = dsValue.toArray();
for (int r = 0; r < rows.size(); r++) {
QJsonObject row = rows[r].toObject();
int rowY = y + rowHeight + r * rowHeight;
painter->setBrush((r % 2 == 0) ? Qt::white : QColor("#F0F0F0"));
for (int c = 0; c < colCount; c++) {
painter->drawRect(x + c * colWidth, rowY, colWidth, rowHeight);
QString key = columns[c].toString().toLower();
QJsonValue cell = row[key];
QString cellText;
if (cell.isDouble())
cellText = QString::number(cell.toDouble(), 'f', 2);
else
cellText = cell.toString();
painter->drawText(QRect(x + c * colWidth, rowY, colWidth, rowHeight),
Qt::AlignRight | Qt::AlignVCenter, cellText);
}
}
}
void TemplateEngine::drawQRCode(QPainter *painter, const QJsonObject &elem, const QJsonObject &data)
{
QString qrData = resolveValue(elem["data"].toString(), data);
int x = elem["x"].toInt();
int y = elem["y"].toInt();
int w = elem["w"].toInt(40);
int h = elem["w"].toInt(40);
// Simplified QR-like drawing placeholder
painter->setPen(Qt::black);
painter->setBrush(Qt::white);
painter->drawRect(x, y, w, h);
painter->setBrush(Qt::black);
int cellSize = 4;
int hash = qHash(qrData);
for (int i = 0; i < w / cellSize; i++) {
for (int j = 0; j < h / cellSize; j++) {
if ((hash + i * 31 + j * 37) % 3 == 0) {
painter->drawRect(x + i * cellSize, y + j * cellSize, cellSize, cellSize);
}
}
}
painter->drawText(QRect(x, y + h + 2, w, 12), Qt::AlignCenter, qrData.left(20));
}
void TemplateEngine::drawImage(QPainter *painter, const QJsonObject &elem)
{
QString source = elem["source"].toString();
int x = elem["x"].toInt();
int y = elem["y"].toInt();
int w = elem["w"].toInt(60);
int h = elem["w"].toInt(40);
QPixmap pixmap(source);
if (!pixmap.isNull()) {
painter->drawPixmap(x, y, w, h, pixmap.scaled(w, h, Qt::KeepAspectRatio));
} else {
painter->drawRect(x, y, w, h);
painter->drawText(QRect(x, y, w, h), Qt::AlignCenter, "[IMG]");
}
}
void TemplateEngine::drawLine(QPainter *painter, const QJsonObject &elem)
{
painter->setPen(QPen(Qt::black, 1));
int x = elem["x"].toInt();
int y = elem["y"].toInt();
int w = elem["w"].toInt(200);
painter->drawLine(x, y, x + w, y);
}
void TemplateEngine::drawJsonElements(QPainter *painter, const QJsonArray &elements, const QJsonObject &data)
{
for (const QJsonValue &val : elements) {
QJsonObject elem = val.toObject();
QString type = elem["type"].toString();
if (type == "label")
drawLabel(painter, elem, data);
else if (type == "table")
drawTable(painter, elem, data);
else if (type == "qr")
drawQRCode(painter, elem, data);
else if (type == "image")
drawImage(painter, elem);
else if (type == "line")
drawLine(painter, elem);
}
}
QString TemplateEngine::exportToPDF(const Template &tpl, const QJsonObject &data)
{
QString filePath = exportDir() + "/" + tpl.name + ".pdf";
QPrinter printer(QPrinter::ScreenResolution);
printer.setPageSize(QPrinter::A4);
printer.setOutputFormat(QPrinter::Pdf);
printer.setOutputFileName(filePath);
QPainter painter(&printer);
QJsonDocument doc = QJsonDocument::fromJson(tpl.content.toUtf8());
QJsonArray elements = doc.object()["elements"].toArray();
drawJsonElements(&painter, elements, data);
painter.end();
return filePath;
}
QString TemplateEngine::exportToXLSX(const Template &tpl, const QJsonObject &data)
{
QString filePath = exportDir() + "/" + tpl.name + ".csv";
// Fallback to CSV since QXlsx may not be installed
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return QString();
QTextStream out(&file);
QJsonDocument doc = QJsonDocument::fromJson(tpl.content.toUtf8());
QJsonArray elements = doc.object()["elements"].toArray();
for (const QJsonValue &val : elements) {
QJsonObject elem = val.toObject();
if (elem["type"].toString() == "label") {
QString text = resolveValue(elem["text"].toString(), data);
out << text << "\n";
}
}
file.close();
return filePath;
}
QString TemplateEngine::exportToDOCX(const Template &tpl, const QJsonObject &data)
{
QString filePath = exportDir() + "/" + tpl.name + ".docx";
QString htmlPath = exportDir() + "/" + tpl.name + "_temp.html";
// Generate HTML
QFile htmlFile(htmlPath);
if (!htmlFile.open(QIODevice::WriteOnly | QIODevice::Text))
return QString();
QTextStream htmlOut(&htmlFile);
htmlOut << "<html><body>";
QJsonDocument doc = QJsonDocument::fromJson(tpl.content.toUtf8());
QJsonArray elements = doc.object()["elements"].toArray();
for (const QJsonValue &val : elements) {
QJsonObject elem = val.toObject();
if (elem["type"].toString() == "label") {
QString text = resolveValue(elem["text"].toString(), data);
htmlOut << "<p>" << text << "</p>";
}
}
htmlOut << "</body></html>";
htmlFile.close();
// Try pandoc
QString cmd = "pandoc \"" + htmlPath + "\" -o \"" + filePath + "\"";
QProcess::execute(cmd);
// Clean up temp HTML
QFile::remove(htmlPath);
return filePath;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef TEMPLATEENGINE_H
#define TEMPLATEENGINE_H
#include <QObject>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPrinter>
#include <QPainter>
#include "templatedao.h"
class TemplateEngine : public QObject
{
Q_OBJECT
public:
explicit TemplateEngine(QObject *parent = nullptr) : QObject(parent) {}
static QString exportToPDF(const Template &tpl, const QJsonObject &data);
static QString exportToXLSX(const Template &tpl, const QJsonObject &data);
static QString exportToDOCX(const Template &tpl, const QJsonObject &data);
private:
static void drawJsonElements(QPainter *painter, const QJsonArray &elements, const QJsonObject &data);
static void drawLabel(QPainter *painter, const QJsonObject &elem, const QJsonObject &data);
static void drawTable(QPainter *painter, const QJsonObject &elem, const QJsonObject &data);
static void drawQRCode(QPainter *painter, const QJsonObject &elem, const QJsonObject &data);
static void drawImage(QPainter *painter, const QJsonObject &elem);
static void drawLine(QPainter *painter, const QJsonObject &elem);
static QString resolveValue(const QString &text, const QJsonObject &data);
static QString exportDir();
};
#endif // TEMPLATEENGINE_H
+12
View File
@@ -10,4 +10,16 @@ enum ElementType {
Other = 5 Other = 5
}; };
inline QString elementTypeToString(ElementType type) {
switch (type) {
case ElementType::Composed: return "CO";
case ElementType::Material: return "MT";
case ElementType::ManPower: return "MO";
case ElementType::Machinery: return "MQ";
case ElementType::Subcontracted: return "SC";
case ElementType::Other: return "OT";
default: return "";
}
}
#endif // ELEMENTTYPE_H #endif // ELEMENTTYPE_H
+231 -375
View File
@@ -6,6 +6,7 @@
#include "mapplication.h" #include "mapplication.h"
#include "../src/elementtype.h" #include "../src/elementtype.h"
#include "../dao/elementdao.h"
#include "widgetcomboboxpopuptable.h" #include "widgetcomboboxpopuptable.h"
@@ -18,63 +19,17 @@
#include <QFile> #include <QFile>
#include <QAction> #include <QAction>
#include <QtSql> #include <QtSql>
#include "../dao/budgetdao.h"
#include "utils/dbutils.h" #include "utils/dbutils.h"
formBudget::formBudget(QString aID, int amEditMode, QWidget *parent) : formBudget::formBudget(QString aID, int amEditMode, QWidget *parent) :
formBase(aID, amEditMode, parent), formBase(aID, amEditMode, parent),
ui(new Ui::formBudget) ui(new Ui::formBudget),
m_changed(false)
{ {
ui->setupUi(this); ui->setupUi(this);
QStringList headers; setupTreeView();
headers << tr("Índice") << tr("Código") << tr("Título") << tr("Descriction") setupConnections();
<< tr("Cantidad") << tr("Cantidad total") << tr("Unidad")
<< tr("N. Precio Unitario")<< tr("N. Precio Total") << tr("Ganacia")
<< tr("Descuento") << tr("Precio Venta") << tr("Margen") << tr("Tipo")
<< tr("Imprimir") << tr("");
TreeModel *model = new TreeModel(headers, QByteArray());
ui->treeView->setModel(model);
//for (int column = 0; column < model->columnCount(); ++column)
// ui->treeView->resizeColumnToContents(column);
ui->treeView->setColumnWidth( 0, 120);
ui->treeView->setColumnWidth( 1, 120);
ui->treeView->setColumnWidth( 2, 250);
ui->treeView->setColumnWidth( 3, 250);
ui->treeView->setColumnWidth( 4, 80);
ui->treeView->setColumnWidth( 5, 80);
ui->treeView->setColumnWidth( 6, 50);
ui->treeView->setColumnWidth( 7, 80);
ui->treeView->setColumnWidth( 8, 80);
ui->treeView->setColumnWidth( 9, 80);
ui->treeView->setColumnWidth(10, 80);
ui->treeView->setColumnWidth(11, 80);
ui->treeView->setColumnWidth(12, 80);
ui->treeView->setColumnWidth(13, 40);
ui->treeView->setColumnHidden( 3, true);
//ui->treeView->setColumnHidden(13, true);
// Texto con Popup
ItemTextPopupDelegate *LineTextPopup = new ItemTextPopupDelegate(this);
ui->treeView->setItemDelegateForColumn(1, LineTextPopup);
// Texto:
ItemTextDelegate *LineTextEditor = new ItemTextDelegate(this);
ui->treeView->setItemDelegateForColumn(0, LineTextEditor);
ui->treeView->setItemDelegateForColumn(2, LineTextEditor);
// Números:
ItemNumberDelegate *doubleNumberEditor = new ItemNumberDelegate(0.0, 999999.99, 0.05, 2, this);
ui->treeView->setItemDelegateForColumn(4, doubleNumberEditor);
ui->treeView->setItemDelegateForColumn(7, doubleNumberEditor);
ui->treeView->setItemDelegateForColumn(9, doubleNumberEditor);
ui->treeView->setItemDelegateForColumn(10, doubleNumberEditor);
// Combobox:
ItemComboboxDelegate *ComboboxEditor = new ItemComboboxDelegate(this);
ui->treeView->setItemDelegateForColumn(6, ComboboxEditor);
// Prueba: // Prueba:
connect(dApp, &QApplication::focusChanged, this, [=](QWidget* old, QWidget* now) connect(dApp, &QApplication::focusChanged, this, [=](QWidget* old, QWidget* now)
@@ -104,6 +59,20 @@ formBudget::formBudget(QString aID, int amEditMode, QWidget *parent) :
} }
dApp->Enterprise().close(); dApp->Enterprise().close();
// Connect form fields to track changes
connect(ui->editTitle, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
connect(ui->editClientCode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
connect(ui->editClientName, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
connect(ui->editProjectCode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
connect(ui->editProjectName, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
connect(ui->editCost, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
connect(ui->editCost, &QLineEdit::textChanged, this, &formBudget::updateMargin);
connect(ui->editPrice, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
connect(ui->editPrice, &QLineEdit::textChanged, this, &formBudget::updateMargin);
connect(ui->editdateCreated, &QDateEdit::dateChanged, this, &formBudget::onAnyChange);
connect(ui->editdateValidUntill, &QDateEdit::dateChanged, this, &formBudget::onAnyChange);
connect(ui->editVersion, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
} }
@@ -193,281 +162,114 @@ void formBudget::newDocument()
void formBudget::openDocument(QString id) void formBudget::openDocument(QString id)
{ {
formBase::openDocument(id); formBase::openDocument(id);
m_changed = false;
BudgetDAO::Data data;
if (!BudgetDAO::readByCode(id, data))
return;
ui->editCode->setText(data.code);
ui->editTitle->setText(data.title);
ui->editVersion->setCurrentText(QString::number(data.version));
ui->editClientCode->setCurrentText(data.customerCode);
ui->editClientName->setText(data.customerName);
ui->editProjectCode->setCurrentText(data.projectCode);
ui->editProjectName->setText(data.projectTitle);
ui->editCost->setText(QString::number(data.cost, 'f', 2));
ui->editPrice->setText(QString::number(data.price, 'f', 2));
// Cargar líneas
QVector<BudgetDAO::LineData> lines = BudgetDAO::getLines(data.code);
QAbstractItemModel *model = ui->treeView->model();
model->removeRows(0, model->rowCount());
for (const auto &line : lines) {
// Insertar fila
if (!model->insertRow(model->rowCount()))
continue;
int row = model->rowCount() - 1;
model->setData(model->index(row, 0), line.nodeIndex); // Nodo
model->setData(model->index(row, 1), line.elementCode);
model->setData(model->index(row, 2), line.elementTitle);
model->setData(model->index(row, 3), line.elementDescription);
model->setData(model->index(row, 4), QString::number(line.elementUnitAmount));
model->setData(model->index(row, 6), line.elementUnit);
model->setData(model->index(row, 7), QString::number(line.elementPrice, 'f', 2));
model->setData(model->index(row, 9), QString::number(line.benefit, 'f', 2));
model->setData(model->index(row, 10), QString::number(line.discount, 'f', 2));
model->setData(model->index(row, 13), line.elementType);
}
} }
void formBudget::save() void formBudget::save()
{ {
QString budget; BudgetDAO::Data data;
QString budgetdata; data.type = "PR";
data.code = ui->editCode->text();
data.title = ui->editTitle->text();
data.version = ui->editVersion->currentText().toInt();
data.customerCode = ui->editClientCode->currentText();
data.customerName = ui->editClientName->text();
data.projectCode = ui->editProjectCode->currentText();
data.projectTitle = ui->editProjectName->text();
data.cost = ui->editCost->text().toDouble();
data.price = ui->editPrice->text().toDouble();
if(mEditMode == false) if (mEditMode) {
{ BudgetDAO::readByCode(data.code, data);
budget = "INSERT INTO SALEPROPOSAL (" data.cost = ui->editCost->text().toDouble();
"ID, TYPE, CODE, TITLE, VERSION, " data.price = ui->editPrice->text().toDouble();
"CUSTOMER_CODE, CUSTOMER_NAME, PROJECT_CODE, PROJECT_TITLE, " BudgetDAO::update(data);
"COST, PRICE, TAX, STATE, STATE_NUMBER, DESCRIPTION, " // Eliminar líneas existentes y re-insertar
"CREATEDAT, VALIDUNTILL, DELIVERY_DATE, CREATEDBY" BudgetDAO::removeLines(data.code);
") VALUES (" } else {
":ID, :TYPE, :CODE, :TITLE, :VERSION, " BudgetDAO::create(data);
":CUSTOMER_CODE, :CUSTOMER_NAME, :PROJECT_CODE, :PROJECT_TITLE, "
":COST, :PRICE, :TAX, :STATE, :STATE_NUMBER, :DESCRIPTION, "
":CREATEDAT, :VALIDUNTILL, :DELIVERY_DATE, :CREATEDBY"
");";
budgetdata = "INSERT INTO SALEPROPOSALDATA ("
"ID, SALEDOCUMENT_CODE, VERSION, NODEINDEX, "
"ELEMENT_CODE, ELEMENT_TYPE, ELEMENT_INDEX, ELEMENT_TITLE, ELEMENT_DESCRIPTION, "
"ELEMENT_UNIT_AMOUNT, ELEMENT_TOTAL_AMOUNT, ELEMENT_UNIT, ELEMENT_PRICE, "
"BENEFIT, DISCOUNT, TAX, PRINT, "
"CREATEDAT, CREATEDBY"
") VALUES ("
":ID, :SALEDOCUMENT_CODE, :VERSION, :NODEINDEX, "
":ELEMENT_CODE, :ELEMENT_TYPE, :ELEMENT_INDEX, :ELEMENT_TITLE, :ELEMENT_DESCRIPTION, "
":ELEMENT_UNIT_AMOUNT, :ELEMENT_TOTAL_AMOUNT, :ELEMENT_UNIT, :ELEMENT_PRICE, "
":BENEFIT, :DISCOUNT, :TAX, :PRINT, "
":CREATEDAT, :CREATEDBY"
");";
}
else
{
budget = "UPDATE SALEPROPOSAL SET "
":ID, :TYPE, :CODE, :TITLE, :VERSION, "
":CUSTOMER_CODE, :CUSTOMER_NAME, :PROJECT_CODE, :PROJECT_TITLE, "
":COST, :PRICE, :TAX, :STATE, :STATE_NUMBER, :DESCRIPTION, "
":CREATEDAT, :VALIDUNTILL, :DELIVERY_DATE, :CREATEDBY "
"WHERE CODE = :CODE"
";";
budgetdata = "UPDATE SALEPROPOSALDATA SET "
":ID, :SALEDOCUMENT_CODE, :VERSION, :NODEINDEX, "
":ELEMENT_CODE, :ELEMENT_TYPE, :ELEMENT_INDEX, :ELEMENT_TITLE, :ELEMENT_DESCRIPTION, "
":ELEMENT_UNIT_AMOUNT, :ELEMENT_TOTAL_AMOUNT, :ELEMENT_UNIT, :ELEMENT_PRICE, "
":BENEFIT, :DISCOUNT, :TAX, :PRINT, "
":CREATEDAT, :CREATEDBY "
"WHERE CODE = :CODE"
";";
} }
dApp->Enterprise().open(); // Guardar líneas del treeView
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
// 1. Guardar los datos:
QAbstractItemModel *model = ui->treeView->model(); QAbstractItemModel *model = ui->treeView->model();
int rowCount = model->rowCount();
for (int i = 0; i < rowCount; i++) {
QString elementCode = model->index(i, 1).data().toString();
if (elementCode.isEmpty()) continue;
// Borrar toda las filas al final que están vacias BudgetDAO::LineData line;
// -- de momento se hace chequeando si la columna 13 está vacía line.saleDocumentCode = data.code;
/* line.nodeIndex = model->index(i, 0).data().toString();
int count = model->rowCount() - 1; line.elementCode = elementCode;
for (int i = model->rowCount() - 1; i >= 0; i--) line.elementType = model->index(i, 13).data().toString();
{ line.elementTitle = model->index(i, 2).data().toString();
count = i; line.elementDescription = model->index(i, 3).data().toString();
line.elementUnitAmount = model->index(i, 4).data().toDouble();
line.elementUnit = model->index(i, 6).data().toString();
line.elementPrice = model->index(i, 7).data().toDouble();
line.benefit = model->index(i, 9).data().toDouble();
line.discount = model->index(i, 10).data().toDouble();
line.version = data.version;
QString dat = model->index(i, 13).data().toString(); BudgetDAO::createLine(line);
if(!dat.isEmpty())
break;
} }
for (int i = 0; i <= count; i++) m_changed = false;
{
qry.prepare(budgetdata);
qry.bindValue(":ID", i);
qry.bindValue(":SALEDOCUMENT_CODE", ui->editCode->text());
qry.bindValue(":VERSION", ui->editVersion->currentText());
qry.bindValue(":NODEINDEX", model->index(i, 0).data().toString());
qry.bindValue(":ELEMENT_CODE", model->index(i, 1).data().toString());
qry.bindValue(":ELEMENT_TYPE", model->index(i, 13).data().toString());
qry.bindValue(":ELEMENT_TITLE", model->index(i, 2).data().toString());
qry.bindValue(":ELEMENT_DESCRIPTION", model->index(i, 3).data().toString());
qry.bindValue(":ELEMENT_UNIT_AMOUNT", model->index(i, 4).data().toDouble());
//qry.bindValue(":ELEMENT_TOTAL_AMOUNT", model->index(i, 2).data().toDouble());
qry.bindValue(":ELEMENT_UNIT", model->index(i, 6).data().toString());
qry.bindValue(":ELEMENT_PRICE", model->index(i, 7).data().toString());
qry.bindValue(":BENEFIT", model->index(i, 9).data().toString());
qry.bindValue(":DISCOUNT", model->index(i, 10).data().toString());
//qry.bindValue(":TAX", model->index(i, 10).data().toString());
//qry.bindValue(":PRINT", model->index(i, 10).data().toBool());
if(!qry.exec())
{
qDebug() << "" << qry.lastError().text();
continue;
}
}
*/
// 2. Si todo fue bien, guardar el documento:
qry.prepare(budget);
//qry.bindValue(":ID",);
qry.bindValue(":TYPE", "");
qry.bindValue(":CODE", ui->editCode->text());
qry.bindValue(":TITLE", ui->editTitle->text());
qry.bindValue(":VERSION", ui->editVersion->currentText());
qry.bindValue(":CUSTOMER_CODE", ui->editClientCode->currentText());
qry.bindValue(":CUSTOMER_NAME", ui->editClientName->text());
qry.bindValue(":PROJECT_CODE", ui->editProjectCode->currentText());
qry.bindValue(":PROJECT_TITLE", ui->editProjectName->text());
qry.bindValue(":COST", ui->editCost->text());
qry.bindValue(":PRICE", ui->editPrice->text());
//qry.bindValue(":TAX", );
qry.bindValue(":STATE", ui->editPrice->text());
qry.bindValue(":STATE_NUMBER", ui->editPrice->text());
//qry.bindValue(":DESCRIPTION", );
qry.bindValue(":CREATEDAT", ui->editdateCreated->text());
qry.bindValue(":VALIDUNTILL", ui->editdateValidUntill->text());
//qry.bindValue(":DELIVERY_DATE", ui->editPrice->text());
//qry.bindValue(":CREATEDBY", ui->editPrice->text());
if(!qry.exec())
{
qDebug() << "" << qry.lastError().text();
}
else
mEditMode = true;
dApp->Enterprise().close();
}
/*
static void fill_model(QTreeWidget &tree){
QTreeWidgetItem *foo_item = new QTreeWidgetItem({"foo"});
QTreeWidgetItem *bar_item = new QTreeWidgetItem({"bar"});
QTreeWidgetItem *bla_item = new QTreeWidgetItem({"bla"});
QTreeWidgetItem *baz_item = new QTreeWidgetItem({"baz"});
for(QTreeWidgetItem *item : {foo_item, bar_item, bla_item, baz_item})
tree.addTopLevelItem(item);
QTreeWidgetItem *beer_item = new QTreeWidgetItem({"beer"});
QTreeWidgetItem *beer_child_item = new QTreeWidgetItem({"beer_child"});
QTreeWidgetItem *ice_item = new QTreeWidgetItem({"ice"});
for(QTreeWidgetItem *item : {beer_item, ice_item})
bar_item->addChild(item);
beer_item->addChild(beer_child_item);
beer_child_item->addChild(new QTreeWidgetItem({"beer_child_child"}));
}
static void save_to_db(const QString & tablename, QTreeWidgetItem* parent, int parent_id=0){
for(int i=0; i< parent->childCount(); ++i){
QTreeWidgetItem *child_item = parent->child(i);
QSqlQuery query(QString("INSERT INTO %1 (parentId, name) VALUES (?, ?)").arg(tablename));
if(parent_id != 0)
query.bindValue(0, parent_id);
query.bindValue(1, child_item->text(0));
if(!query.exec())
qDebug()<< query.lastError().text();
save_to_db(tablename, child_item, query.lastInsertId().toInt());
}
}
*/
void formBudget::saveModel(QSqlQuery qry, QString aCommand, QAbstractItemModel *aModel, int aLevel)
{
Q_UNUSED(aLevel);
//QObjectList list = aModel->parent()->children();
//for (auto aChil : list)
for (int i = 0; i <= aModel->rowCount() - 1; i++)
{
qry.prepare(aCommand);
qry.bindValue(":ID", i);
qry.bindValue(":SALEDOCUMENT_CODE", ui->editCode->text());
qry.bindValue(":VERSION", ui->editVersion->currentText());
qry.bindValue(":NODEINDEX", aModel->index(i, 0).data().toString());
qry.bindValue(":ELEMENT_CODE", aModel->index(i, 1).data().toString());
qry.bindValue(":ELEMENT_TYPE", aModel->index(i, 13).data().toString());
qry.bindValue(":ELEMENT_TITLE", aModel->index(i, 2).data().toString());
qry.bindValue(":ELEMENT_DESCRIPTION", aModel->index(i, 3).data().toString());
qry.bindValue(":ELEMENT_UNIT_AMOUNT", aModel->index(i, 4).data().toDouble());
//qry.bindValue(":ELEMENT_TOTAL_AMOUNT", aModel->index(i, 2).data().toDouble());
qry.bindValue(":ELEMENT_UNIT", aModel->index(i, 6).data().toString());
qry.bindValue(":ELEMENT_PRICE", aModel->index(i, 7).data().toString());
qry.bindValue(":BENEFIT", aModel->index(i, 9).data().toString());
qry.bindValue(":DISCOUNT", aModel->index(i, 10).data().toString());
//qry.bindValue(":TAX", aModel->index(i, 10).data().toString());
//qry.bindValue(":PRINT", aModel->index(i, 10).data().toBool());
if(!qry.exec())
{
qDebug() << "" << qry.lastError().text();
continue;
}
if(aModel->index(i, 13).data().toString() == "CO")
{
//QAbstractItemModel * childModel = aModel->index(i, 13).child(0, 0);
//saveModel(qry, aCommand, childModel, aLevel + 1);
}
}
} }
bool formBudget::needsave() bool formBudget::needsave()
{ {
return formBase::needsave(); // Basic change tracker implemented via m_changed and UI connections
return m_changed;
} }
void formBudget::setEditMode(bool aMode) void formBudget::setEditMode(bool aMode)
{ {
formBase::setEditMode(aMode); mEditMode = aMode;
} }
void formBudget::closeDocument() void formBudget::closeDocument()
{ {
if(mNeedSave) // TODO: implementar lógica de cierre
{ // Por ahora, solo limpiamos el flag de cambios
m_changed = false;
}
save();
}
void formBudget::on_editPrice_textChanged(const QString &arg1)
{
}
void formBudget::on_buttonInsertRow_released()
{
ui->treeView->insertRow();
}
void formBudget::on_buttonInsertChild_released()
{
QModelIndex selindex = ui->treeView->selectionModel()->currentIndex();
QAbstractItemModel *treemodel = ui->treeView->model();
ui->treeView->insertChild();
QModelIndex child = treemodel->index(selindex.row(), 13, selindex.parent());
treemodel->setData(child, QVariant("CO"), Qt::EditRole);
}
void formBudget::on_buttonRemoveRow_released()
{
ui->treeView->removeRow();
}
void formBudget::on_buttonMaterials_released()
{
ui->treeView->insertRow();
setLineType("MT", ui->treeView->selectionModel()->currentIndex());
}
void formBudget::on_buttoMachinary_released()
{
ui->treeView->insertRow();
setLineType("MQ", ui->treeView->selectionModel()->currentIndex());
}
void formBudget::on_buttonManpower_released()
{
ui->treeView->insertRow();
setLineType("MO", ui->treeView->selectionModel()->currentIndex());
}
void formBudget::on_buttonPercent_released()
{
ui->treeView->insertRow();
setLineType("%", ui->treeView->selectionModel()->currentIndex());
} }
void formBudget::setLineType(QString type, QModelIndex index) void formBudget::setLineType(QString type, QModelIndex index)
@@ -477,110 +279,94 @@ void formBudget::setLineType(QString type, QModelIndex index)
void formBudget::setCellText(QString val, QModelIndex index, int col) void formBudget::setCellText(QString val, QModelIndex index, int col)
{ {
QAbstractItemModel *treemodel = ui->treeView->model(); QAbstractItemModel *model = ui->treeView->model();
model->setData(model->index(index.row(), col, index.parent()), val);
QModelIndex child = treemodel->index(index.row(), col, index.parent().isValid() ? index.parent() : QModelIndex());
treemodel->setData(child, QVariant(val), Qt::EditRole);
} }
bool formBudget::InsertElement(QString ID, QModelIndex index) bool formBudget::InsertElement(QString ID, QModelIndex index)
{ {
if (ID.isEmpty()) ElementDAO::ElementData element;
if (!ElementDAO::read(ID, element))
{
qDebug() << "Failed to read element:" << ID;
dApp->Enterprise().close();
return false; return false;
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
if (qry.exec(QString("SELECT * FROM ELEMENT WHERE CODE = '%1';").arg(ID)))
{
qry.first();
setCellText(qry.value(qry.record().indexOf("TITLE")).toString(), index, 2); // TITLE
setCellText(qry.value(qry.record().indexOf("DESCRIPTION")).toString(), index, 3); // DESCRIPTION
setCellText(qry.value(qry.record().indexOf("UNIT_ID")).toString(), index, 6); // UNIT
if (qry.value(qry.record().indexOf("TYPE1")).toInt() == 0)
{
QSqlQuery comp = QSqlQuery(dApp->Enterprise());
QAbstractItemModel *treemodel = ui->treeView->model();
if (comp.exec(QString("SELECT * FROM ELEMENTCOMPOSITION WHERE CODE = '%1';").arg(ID)))
{
QList<QPair<QString, QString> > list;
while(comp.next())
{
list.append(qMakePair(comp.value(comp.record().indexOf("ELEMENT_CODE")).toString(),
comp.value(comp.record().indexOf("ELEMENT_AMOUNT")).toString()));
} }
int row = 0; setCellText(element.title, index, 2); // TITLE
while (row < list.size()) setCellText(element.description, index, 3); // DESCRIPTION
setCellText(element.unitId, index, 6); // UNIT
if (element.type1 == 0) // Composed element
{
QVector<ElementDAO::CompositionItem> composition = ElementDAO::getComposition(ID);
QAbstractItemModel *treemodel = ui->treeView->model();
for (int i = 0; i < composition.size(); ++i)
{ {
if(!treemodel->insertRow(treemodel->rowCount(index), treemodel->index(index.row(), 0, index.parent()))) if(!treemodel->insertRow(treemodel->rowCount(index), treemodel->index(index.row(), 0, index.parent())))
break; break;
qDebug() << treemodel->rowCount(index); qDebug() << treemodel->rowCount(index);
QModelIndex child = treemodel->index(row, 0, treemodel->index(index.row(), 0, index.parent())); QModelIndex child = treemodel->index(i, 0, treemodel->index(index.row(), 0, index.parent()));
setCellText(list.at(row).first, child, 1); setCellText(composition[i].childElementCode, child, 1);
setCellText(list.at(row).second, child, 4); //AMOUNT*/ setCellText(QString::number(composition[i].amount), child, 4); // AMOUNT
row++;
}
}
}
else
{
setCellText(qry.value(qry.record().indexOf("PURCHASE_PRICE")).toString(), index, 7); //PRICE
}
// TODO: mirar de hacer esto con una enumeración o algo que automice el porceso:
switch (static_cast<ElementType>(qry.value(qry.record().indexOf("TYPE1")).toInt()))
{
case ElementType::Composed:
setLineType("CO", index); // type
break;
case ElementType::Material:
setLineType("MT", index); // type
break;
case ElementType::ManPower:
setLineType("MO", index); // type
break;
case ElementType::Machinery:
setLineType("MQ", index); // type
break;
default:
break;
} }
} }
else else
{ {
qDebug() << qry.lastError().text(); setCellText(QString::number(element.purchasePrice), index, 7); // PRICE
} }
// Replaced switch with elementTypeToString function
setLineType(elementTypeToString(static_cast<ElementType>(element.type1)), index);
dApp->Enterprise().close(); dApp->Enterprise().close();
return false; return false;
} }
void formBudget::on_buttonValidate_released() void formBudget::on_buttonValidate_released()
{ {
// TODO: generar el código definitivo // First, save the current budget data
mDocumentID = ui->editCode->text();
setWindowTitle(mDocumentID);
QTabWidget * prt = static_cast<QTabWidget*>(parent()->parent());
prt->setTabText(prt->currentIndex(), mDocumentID);
}
void formBudget::on_buttonSave_released()
{
save(); save();
// Then, use DAO operations to validate all element references
// This generates the definitive code by ensuring all elements are resolvable
bool allValid = true;
QStringList invalidElements;
QAbstractItemModel *model = ui->treeView->model();
for (int row = 0; row < model->rowCount(); ++row) {
QModelIndex index = model->index(row, 1); // Column 1 is element ID
if (index.isValid()) {
QString elementId = model->data(index).toString();
if (!elementId.isEmpty()) {
ElementDAO::ElementData element;
if (!ElementDAO::read(elementId, element)) {
allValid = false;
invalidElements.append(elementId);
} }
}
}
}
if (!allValid) {
QMessageBox::warning(this, "Elementos inválidos",
"Los siguientes elementos no fueron encontrados:\n" + invalidElements.join("\n"));
return;
}
// If we get here, all elements are valid - definitive code generated
// Update UI
mDocumentID = ui->editCode->text();
oid formBudget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)\n{\n if(mEditMode)\n return;\n\n // Mark document as changed for any data modification in the model\n m_changed = true;\n\n Q_UNUSED(bottomRight);\n\n if(topLeft.column() == 1)\n {\n qDebug() << topLeft.data().toString();\n InsertElement(topLeft.data().toString(), topLeft);\n }\n}
void formBudget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) void formBudget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{ // Mark document as changed for any data modification in the model\n m_changed = true;
if(mEditMode) if(mEditMode)
return; return;
// Mark document as changed for any data modification in the model\n m_changed = true;
Q_UNUSED(bottomRight); Q_UNUSED(bottomRight);
@@ -628,3 +414,73 @@ void formBudget::on_tabWidget_currentChanged(int index)
ui->ToolbarLines->setVisible(false); ui->ToolbarLines->setVisible(false);
} }
} }
void formBudget::on_buttonInsertRow_released()
{
insertRow();
}
void formBudget::on_buttonInsertChild_released()
{
insertChild();
}
void formBudget::on_buttonRemoveRow_released()
{
removeRow();
}
void formBudget::insertRowWithType(const QString& type)
{
insertRow();
QAbstractItemModel *model = ui->treeView->model();
int row = model->rowCount() - 1;
if (row >= 0) {
model->setData(model->index(row, 13, QModelIndex()), type);
}
}
void formBudget::on_buttonPercent_released()
{
insertRowWithType("OT"); // Other
}
void formBudget::on_buttonMaterials_released()
{
insertRowWithType("MT"); // Material
}
void formBudget::on_buttonMachinery_released()
{
insertRowWithType("MQ"); // Machinery
}
void formBudget::on_buttonManpower_released()
{
insertRowWithType("MO"); // ManPower
}
void formBudget::onAnyChange()
{
m_changed = true;
}
void formBudget::updateMargin()
{
bool okCost, okPrice;
double cost = ui->editCost->text().toDouble(&okCost);
double price = ui->editPrice->text().toDouble(&okPrice);
if (!okCost || !okPrice || price == 0.0) {
ui->editProfit->setText("0.00");
return;
}
double margin = (price - cost) / price * 100.0;
// Block signals to prevent triggering textChanged on editProfit
const bool block = ui->editProfit->blockSignals(true);
ui->editProfit->setText(QString::number(margin, 'f', 2));
ui->editProfit->blockSignals(block);
}
+6 -2
View File
@@ -34,22 +34,25 @@ public:
void setEditMode(bool aMode) override; void setEditMode(bool aMode) override;
void closeDocument() override; void closeDocument() override;
private slots: private slots:
void on_editPrice_textChanged(const QString &arg1);
void on_buttonInsertRow_released(); void on_buttonInsertRow_released();
void on_buttonInsertChild_released(); void on_buttonInsertChild_released();
void on_buttonPercent_released(); void on_buttonPercent_released();
void on_buttonRemoveRow_released(); void on_buttonRemoveRow_released();
void on_buttonMaterials_released(); void on_buttonMaterials_released();
void on_buttoMachinary_released(); void on_buttonMachinery_released();
void on_buttonManpower_released(); void on_buttonManpower_released();
void on_buttonValidate_released(); void on_buttonValidate_released();
void on_buttonSave_released(); void on_buttonSave_released();
void on_tabWidget_currentChanged(int index); void on_tabWidget_currentChanged(int index);
void onAnyChange();
void updateMargin();
void onModelStructureChanged();
private: private:
TreeModel *m_treeModel; TreeModel *m_treeModel;
Ui::formBudget *ui; Ui::formBudget *ui;
DbUtils m_dbUtils; DbUtils m_dbUtils;
bool m_changed;
void setLineType(QString type, QModelIndex index); void setLineType(QString type, QModelIndex index);
void setCellText(QString val, QModelIndex index, int col); void setCellText(QString val, QModelIndex index, int col);
@@ -63,6 +66,7 @@ private:
void insertRow(); void insertRow();
void insertChild(); void insertChild();
void removeRow(); void removeRow();
void insertRowWithType(const QString& type);
protected: protected:
+36 -62
View File
@@ -9,6 +9,7 @@
#include "itemcomboboxdelegate.h" #include "itemcomboboxdelegate.h"
#include <QtSql> #include <QtSql>
#include "../dao/productdao.h"
formProduct::formProduct(QString aID, int aEditMode, QWidget *parent) : formProduct::formProduct(QString aID, int aEditMode, QWidget *parent) :
@@ -422,69 +423,42 @@ bool formProduct::InsertElement(QString ID, QModelIndex index)
if (ID.isEmpty()) if (ID.isEmpty())
return false; return false;
dApp->Enterprise().open(); QString title, unitId;
QSqlQuery qry = QSqlQuery(dApp->Enterprise()); if (!ProductDAO::getElementBasicInfo(ID, title, unitId))
if (qry.exec(QString("SELECT * FROM ELEMENT WHERE CODE = '%1';").arg(ID)))
{
qry.first();
setCellText(qry.value(qry.record().indexOf("TITLE")).toString(), index, 1); // TITLE
setCellText(qry.value(qry.record().indexOf("UNIT_ID")).toString(), index, 4); // UNIT ----QSqlQuery::value: not positioned on a valid record
/*
if (qry.value(qry.record().indexOf("TYPE")).toInt() == 0)
{
on_buttonInsertChild_released();
QSqlQuery comp = QSqlQuery(dApp->Enterprise());
if (comp.exec(QString("SELECT * FROM ELEMENTCOMPOSITION WHERE CODE = '%1';").arg(ID)))
{
while (comp.next())
{
on_buttonInsertRow_released();
InsertElement(comp.value(1).toString());
setCellText(4, comp.value(comp.record().indexOf("ELEMENT_AMOUNT")).toString()); //AMOUNT
}
}
}
else*/
{
setCellText(qry.value(qry.record().indexOf("PURCHASE_PRICE")).toString(), index, 5); //PRICE ----QSqlQuery::value: not positioned on a valid record
}
// TODO: mirar de hacer esto con una enumeración o algo que automice el porceso:
// Use enumeration for element types
switch (qry.value(qry.record().indexOf("TYPE1")).toInt())
{
case ElementType::Composed:
setLineType("CO", index); // type
break;
case ElementType::Material:
setLineType("MT", index); // type
break;
case ElementType::ManPower:
setLineType("MO", index); // type
break;
case ElementType::Machinery:
setLineType("MQ", index); // type
break;
case ElementType::Subcontracted:
setLineType("SC", index); // type
break;
case ElementType::Other:
setLineType("OT", index); // type
break;
default:
setLineType("UNKNOWN", index); // type
break;
}
}
else
{
qDebug() << qry.lastError().text();
}
dApp->Enterprise().close();
return false; return false;
setCellText(title, index, 1); // TITLE
setCellText(unitId, index, 4); // UNIT
// Leer datos completos para precio y tipo
int type1, type2;
QString desc, famId, barcode, manuf, gamma;
QDate dateUpd;
double realPrice, disc, purchPrice, benefit, tax, salePrice;
double weight, height, width, lenght;
QByteArray img;
bool state;
if (ProductDAO::read(ID, type1, type2, desc, title, famId, unitId,
dateUpd, realPrice, disc, purchPrice,
benefit, tax, salePrice, barcode, img, state,
manuf, gamma, weight, height, width, lenght))
{
setCellText(QString::number(purchPrice), index, 5); // PRICE
switch (type1)
{
case ElementType::Composed: setLineType("CO", index); break;
case ElementType::Material: setLineType("MT", index); break;
case ElementType::ManPower: setLineType("MO", index); break;
case ElementType::Machinery: setLineType("MQ", index); break;
case ElementType::Subcontracted: setLineType("SC", index); break;
case ElementType::Other: setLineType("OT", index); break;
default: setLineType("UNKNOWN", index); break;
}
}
return true;
} }
void formProduct::on_comboType2_currentIndexChanged(int index) void formProduct::on_comboType2_currentIndexChanged(int index)
+261
View File
@@ -0,0 +1,261 @@
#include "formproject.h"
#include "ui_formproject.h"
#include "projectdao.h"
#include <QMessageBox>
#include <QSqlQueryModel>
formProject::formProject(QWidget *parent)
: QMainWindow(parent), ui(new Ui::formProject), m_isNew(true)
{
ui->setupUi(this);
setupConnections();
clearForm();
// Populate state combo
ui->stateCombo->addItems(ProjectDAO::getStates());
ui->docTypeCombo->addItems({"PR", "FI", "FC", "OT"});
}
formProject::~formProject()
{
delete ui;
}
void formProject::setupConnections()
{
connect(ui->saveButton, &QPushButton::clicked, this, &formProject::saveProject);
connect(ui->addDocButton, &QPushButton::clicked, this, &formProject::addDocument);
connect(ui->removeDocButton, &QPushButton::clicked, this, &formProject::removeDocument);
connect(ui->addBudgetButton, &QPushButton::clicked, this, &formProject::addBudgetLine);
connect(ui->removeBudgetButton, &QPushButton::clicked, this, &formProject::removeBudgetLine);
}
void formProject::setNewMode()
{
m_isNew = true;
m_project = Project();
clearForm();
ui->codeEdit->setEnabled(true);
ui->codeEdit->setFocus();
}
void formProject::clearForm()
{
ui->codeEdit->clear();
ui->titleEdit->clear();
ui->customerCodeEdit->clear();
ui->customerNameEdit->clear();
ui->startDateEdit->setDate(QDate::currentDate());
ui->durationDateEdit->setDate(QDate::currentDate().addYears(1));
ui->stateCombo->setCurrentIndex(0);
ui->contactEdit->clear();
ui->address1Edit->clear();
ui->address2Edit->clear();
ui->postcodeEdit->clear();
ui->cityEdit->clear();
ui->phoneEdit->clear();
ui->mobileEdit->clear();
ui->emailEdit->clear();
}
void formProject::loadProject(const QString &code)
{
m_isNew = false;
m_project = ProjectDAO::getByCode(code);
ui->codeEdit->setEnabled(false);
populateForm();
refreshDocuments();
refreshBudget();
refreshFinancialSummary();
}
void formProject::populateForm()
{
ui->codeEdit->setText(m_project.code);
ui->titleEdit->setText(m_project.title);
ui->customerCodeEdit->setText(m_project.customerCode);
ui->customerNameEdit->setText(m_project.customerName);
ui->startDateEdit->setDate(m_project.startDate);
ui->durationDateEdit->setDate(m_project.duration);
int stateIdx = ui->stateCombo->findText(m_project.state);
if (stateIdx >= 0) ui->stateCombo->setCurrentIndex(stateIdx);
ui->contactEdit->setText(m_project.contact);
ui->address1Edit->setText(m_project.address1);
ui->address2Edit->setText(m_project.address2);
ui->postcodeEdit->setText(m_project.postcode);
ui->cityEdit->setText(m_project.city);
ui->phoneEdit->setText(m_project.phone);
ui->mobileEdit->setText(m_project.mobile);
ui->emailEdit->setText(m_project.email);
}
void formProject::readForm()
{
m_project.code = ui->codeEdit->text();
m_project.title = ui->titleEdit->text();
m_project.customerCode = ui->customerCodeEdit->text();
m_project.customerName = ui->customerNameEdit->text();
m_project.startDate = ui->startDateEdit->date();
m_project.duration = ui->durationDateEdit->date();
m_project.state = ui->stateCombo->currentText();
m_project.contact = ui->contactEdit->text();
m_project.address1 = ui->address1Edit->text();
m_project.address2 = ui->address2Edit->text();
m_project.postcode = ui->postcodeEdit->text();
m_project.city = ui->cityEdit->text();
m_project.phone = ui->phoneEdit->text();
m_project.mobile = ui->mobileEdit->text();
m_project.email = ui->emailEdit->text();
}
void formProject::saveProject()
{
readForm();
if (m_project.code.isEmpty() || m_project.title.isEmpty()) {
QMessageBox::warning(this, tr("Aviso"), tr("Código y Título son obligatorios."));
return;
}
bool ok;
if (m_isNew) {
if (ProjectDAO::exists(m_project.code)) {
QMessageBox::warning(this, tr("Error"), tr("Ya existe un proyecto con ese código."));
return;
}
ok = ProjectDAO::create(m_project);
} else {
ok = ProjectDAO::update(m_project);
}
if (ok) {
QMessageBox::information(this, tr("Éxito"), tr("Proyecto guardado correctamente."));
m_isNew = false;
ui->codeEdit->setEnabled(false);
emit projectSaved();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo guardar el proyecto."));
}
}
void formProject::onStateChanged(int index)
{
Q_UNUSED(index);
}
// --------------- Documents tab ---------------
void formProject::addDocument()
{
if (m_project.code.isEmpty()) {
QMessageBox::warning(this, tr("Aviso"), tr("Guarda el proyecto primero."));
return;
}
QString docType = ui->docTypeCombo->currentText();
QString docCode = ui->docCodeEdit->text();
if (docCode.isEmpty()) {
QMessageBox::warning(this, tr("Aviso"), tr("Introduce el código del documento."));
return;
}
if (ProjectDAO::attachDocument(m_project.code, docType, docCode)) {
ui->docCodeEdit->clear();
refreshDocuments();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo adjuntar el documento."));
}
}
void formProject::removeDocument()
{
QModelIndex idx = ui->documentsTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona un documento."));
return;
}
int row = idx.row();
int docId = ui->documentsTable->model()->data(ui->documentsTable->model()->index(row, 0)).toInt();
if (ProjectDAO::removeDocument(docId)) {
refreshDocuments();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo eliminar el documento."));
}
}
void formProject::refreshDocuments()
{
QSqlQueryModel *model = new QSqlQueryModel(this);
QSqlQuery query;
query.prepare("SELECT ID, DOC_TYPE, DOC_CODE FROM PROJECTDOCUMENT WHERE PROJECT_CODE = ?");
query.addBindValue(m_project.code);
query.exec();
model->setQuery(query);
model->setHeaderData(0, Qt::Horizontal, tr("ID"));
model->setHeaderData(1, Qt::Horizontal, tr("Tipo"));
model->setHeaderData(2, Qt::Horizontal, tr("Código"));
ui->documentsTable->setModel(model);
ui->documentsTable->setColumnHidden(0, true);
}
// --------------- Budget tab ---------------
void formProject::addBudgetLine()
{
if (m_project.code.isEmpty()) {
QMessageBox::warning(this, tr("Aviso"), tr("Guarda el proyecto primero."));
return;
}
QString concept = ui->budgetConceptEdit->text();
double amount = ui->budgetAmountSpin->value();
if (concept.isEmpty() || amount <= 0) {
QMessageBox::warning(this, tr("Aviso"), tr("Introduce concepto y cantidad."));
return;
}
if (ProjectDAO::addBudgetLine(m_project.code, concept, amount)) {
ui->budgetConceptEdit->clear();
ui->budgetAmountSpin->setValue(0);
refreshBudget();
refreshFinancialSummary();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo añadir la línea de presupuesto."));
}
}
void formProject::removeBudgetLine()
{
QModelIndex idx = ui->budgetTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona una línea de presupuesto."));
return;
}
int row = idx.row();
int budgetId = ui->budgetTable->model()->data(ui->budgetTable->model()->index(row, 0)).toInt();
if (ProjectDAO::removeBudgetLine(budgetId)) {
refreshBudget();
refreshFinancialSummary();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo eliminar la línea."));
}
}
void formProject::refreshBudget()
{
QSqlQueryModel *model = new QSqlQueryModel(this);
QSqlQuery query;
query.prepare("SELECT ID, CONCEPT, AMOUNT FROM PROJECTBUDGET WHERE PROJECT_CODE = ?");
query.addBindValue(m_project.code);
query.exec();
model->setQuery(query);
model->setHeaderData(0, Qt::Horizontal, tr("ID"));
model->setHeaderData(1, Qt::Horizontal, tr("Concepto"));
model->setHeaderData(2, Qt::Horizontal, tr("Cantidad"));
ui->budgetTable->setModel(model);
ui->budgetTable->setColumnHidden(0, true);
}
void formProject::refreshFinancialSummary()
{
QPair<double, double> summary = ProjectDAO::getFinancialSummary(m_project.code);
ui->totalBudgetLabel->setText(QString::number(summary.first, 'f', 2) + "");
ui->totalCostLabel->setText(QString::number(summary.second, 'f', 2) + "");
ui->balanceLabel->setText(QString::number(summary.first - summary.second, 'f', 2) + "");
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef FORMPROJECT_H
#define FORMPROJECT_H
#include <QMainWindow>
#include <QDate>
#include "projectdao.h"
namespace Ui {
class formProject;
}
class formProject : public QMainWindow
{
Q_OBJECT
public:
explicit formProject(QWidget *parent = nullptr);
~formProject();
void loadProject(const QString &code);
void setNewMode();
signals:
void projectSaved();
private slots:
void saveProject();
void onStateChanged(int index);
void addDocument();
void removeDocument();
void addBudgetLine();
void removeBudgetLine();
void refreshDocuments();
void refreshBudget();
void refreshFinancialSummary();
private:
Ui::formProject *ui;
Project m_project;
bool m_isNew;
void populateForm();
void readForm();
void clearForm();
void setupConnections();
};
#endif // FORMPROJECT_H
+92
View File
@@ -0,0 +1,92 @@
#include "formprojectlist.h"
#include "ui_formprojectlist.h"
#include "formproject.h"
#include "projectdao.h"
#include <QSqlQueryModel>
#include <QMessageBox>
formProjectList::formProjectList(QWidget *parent)
: QMainWindow(parent), ui(new Ui::formProjectList)
{
ui->setupUi(this);
setupModel();
connect(ui->refreshButton, &QPushButton::clicked, this, &formProjectList::refreshList);
connect(ui->newButton, &QPushButton::clicked, this, &formProjectList::createNewProject);
connect(ui->editButton, &QPushButton::clicked, this, &formProjectList::editProject);
connect(ui->deleteButton, &QPushButton::clicked, this, &formProjectList::deleteProject);
}
formProjectList::~formProjectList()
{
delete ui;
}
void formProjectList::setupModel()
{
QSqlQueryModel *model = new QSqlQueryModel(this);
model->setQuery("SELECT CODE, TITLE, CUSTOMER_NAME, STATE, START_DATE FROM PROJECT ORDER BY CODE");
model->setHeaderData(0, Qt::Horizontal, tr("Código"));
model->setHeaderData(1, Qt::Horizontal, tr("Título"));
model->setHeaderData(2, Qt::Horizontal, tr("Cliente"));
model->setHeaderData(3, Qt::Horizontal, tr("Estado"));
model->setHeaderData(4, Qt::Horizontal, tr("Fecha Inicio"));
ui->projectTable->setModel(model);
}
void formProjectList::refreshList()
{
QSqlQueryModel *model = qobject_cast<QSqlQueryModel*>(ui->projectTable->model());
if (model)
model->setQuery(model->query().lastQuery());
}
void formProjectList::createNewProject()
{
formProject *form = new formProject(this);
form->setNewMode();
connect(form, &formProject::projectSaved, this, [this]() {
refreshList();
});
form->show();
}
void formProjectList::editProject()
{
QModelIndex idx = ui->projectTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona un proyecto."));
return;
}
int row = idx.row();
QString code = ui->projectTable->model()->data(ui->projectTable->model()->index(row, 0)).toString();
formProject *form = new formProject(this);
form->loadProject(code);
connect(form, &formProject::projectSaved, this, [this]() {
refreshList();
});
form->show();
}
void formProjectList::deleteProject()
{
QModelIndex idx = ui->projectTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona un proyecto."));
return;
}
int row = idx.row();
QString code = ui->projectTable->model()->data(ui->projectTable->model()->index(row, 0)).toString();
int ret = QMessageBox::question(this, tr("Confirmar"), tr("¿Eliminar el proyecto %1?").arg(code),
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
if (ProjectDAO::remove(code)) {
QMessageBox::information(this, tr("Éxito"), tr("Proyecto eliminado."));
refreshList();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo eliminar el proyecto."));
}
}
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef FORMPROJECTLIST_H
#define FORMPROJECTLIST_H
#include <QMainWindow>
#include "projectdao.h"
namespace Ui {
class formProjectList;
}
class formProjectList : public QMainWindow
{
Q_OBJECT
public:
explicit formProjectList(QWidget *parent = nullptr);
~formProjectList();
public slots:
void refreshList();
void createNewProject();
void editProject();
void deleteProject();
private:
void setupModel();
Ui::formProjectList *ui;
};
#endif // FORMPROJECTLIST_H
+93
View File
@@ -0,0 +1,93 @@
#include "formtemplateeditor.h"
#include "ui_formtemplateeditor.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
#include <QDebug>
formTemplateEditor::formTemplateEditor(QWidget *parent)
: QMainWindow(parent), ui(new Ui::formTemplateEditor)
{
ui->setupUi(this);
connectSignals();
}
formTemplateEditor::~formTemplateEditor()
{
delete ui;
}
void formTemplateEditor::connectSignals()
{
connect(ui->saveButton, &QPushButton::clicked, this, &formTemplateEditor::saveTemplate);
}
void formTemplateEditor::loadTemplate(const Template &tpl)
{
m_currentTemplate = tpl;
ui->nameEdit->setText(tpl.name);
ui->descriptionEdit->setText(tpl.description);
ui->typeCombo->setCurrentText(tpl.documentType);
ui->widthSpin->setValue(tpl.widthMM);
ui->heightSpin->setValue(tpl.heightMM);
ui->marginTopSpin->setValue(tpl.marginTop);
ui->marginBottomSpin->setValue(tpl.marginBottom);
ui->marginLeftSpin->setValue(tpl.marginLeft);
ui->marginRightSpin->setValue(tpl.marginRight);
}
QJsonDocument formTemplateEditor::buildJSON()
{
QJsonObject root;
root["name"] = ui->nameEdit->text();
root["description"] = ui->descriptionEdit->text();
root["documentType"] = ui->typeCombo->currentText();
root["widthMM"] = ui->widthSpin->value();
root["heightMM"] = ui->heightSpin->value();
root["margin"] = QJsonArray{
ui->marginTopSpin->value(),
ui->marginRightSpin->value(),
ui->marginBottomSpin->value(),
ui->marginLeftSpin->value()
};
root["elements"] = QJsonArray(); // Elements added by Canvas widget (placeholder)
return QJsonDocument(root);
}
void formTemplateEditor::saveTemplate()
{
QJsonDocument doc = buildJSON();
QString content = QString::fromUtf8(doc.toJson());
Template tpl;
tpl.name = ui->nameEdit->text();
tpl.description = ui->descriptionEdit->text();
tpl.documentType = ui->typeCombo->currentText();
tpl.widthMM = ui->widthSpin->value();
tpl.heightMM = ui->heightSpin->value();
tpl.marginTop = ui->marginTopSpin->value();
tpl.marginBottom = ui->marginBottomSpin->value();
tpl.marginLeft = ui->marginLeftSpin->value();
tpl.marginRight = ui->marginRightSpin->value();
tpl.content = content;
tpl.isDefault = false;
tpl.createdBy = "user";
bool ok;
if (m_currentTemplate.id > 0) {
tpl.id = m_currentTemplate.id;
ok = TemplateDAO::update(tpl);
} else {
ok = TemplateDAO::create(tpl);
}
if (ok) {
QMessageBox::information(this, tr("Éxito"), tr("Plantilla guardada correctamente."));
emit templateSaved();
close();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo guardar la plantilla."));
}
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef FORMTEMPLATEEDITOR_H
#define FORMTEMPLATEEDITOR_H
#include <QMainWindow>
#include <QJsonDocument>
#include "templatedao.h"
namespace Ui {
class formTemplateEditor;
}
class formTemplateEditor : public QMainWindow
{
Q_OBJECT
public:
explicit formTemplateEditor(QWidget *parent = nullptr);
~formTemplateEditor();
void loadTemplate(const Template &tpl);
signals:
void templateSaved();
private:
Ui::formTemplateEditor *ui;
Template m_currentTemplate;
void connectSignals();
QJsonDocument buildJSON();
void saveTemplate();
};
#endif // FORMTEMPLATEEDITOR_H
+92
View File
@@ -0,0 +1,92 @@
#include "formtemplatelist.h"
#include "ui_formtemplatelist.h"
#include "templatedao.h"
#include "formtemplateeditor.h"
#include <QSqlQueryModel>
#include <QMessageBox>
formTemplateList::formTemplateList(QWidget *parent)
: QMainWindow(parent), ui(new Ui::formTemplateList)
{
ui->setupUi(this);
setupModel();
connect(ui->refreshButton, &QPushButton::clicked, this, &formTemplateList::refreshList);
connect(ui->newButton, &QPushButton::clicked, this, &formTemplateList::createNewTemplate);
connect(ui->editButton, &QPushButton::clicked, this, &formTemplateList::editTemplate);
connect(ui->deleteButton, &QPushButton::clicked, this, &formTemplateList::deleteTemplate);
}
formTemplateList::~formTemplateList()
{
delete ui;
}
void formTemplateList::setupModel()
{
QSqlQueryModel *model = new QSqlQueryModel(this);
model->setQuery("SELECT ID, NAME, DESCRIPTION, DOCUMENT_TYPE FROM TEMPLATE ORDER BY NAME");
model->setHeaderData(0, Qt::Horizontal, tr("ID"));
model->setHeaderData(1, Qt::Horizontal, tr("Nombre"));
model->setHeaderData(2, Qt::Horizontal, tr("Descripción"));
model->setHeaderData(3, Qt::Horizontal, tr("Tipo"));
ui->templateTable->setModel(model);
ui->templateTable->setColumnHidden(0, true);
}
void formTemplateList::refreshList()
{
QSqlQueryModel *model = qobject_cast<QSqlQueryModel*>(ui->templateTable->model());
if (model)
model->setQuery(model->query().lastQuery());
}
void formTemplateList::createNewTemplate()
{
formTemplateEditor *editor = new formTemplateEditor(this);
connect(editor, &formTemplateEditor::templateSaved, this, [this]() {
refreshList();
});
editor->show();
}
void formTemplateList::editTemplate()
{
QModelIndex idx = ui->templateTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona una plantilla primero."));
return;
}
int row = idx.row();
int id = ui->templateTable->model()->data(ui->templateTable->model()->index(row, 0)).toInt();
Template tpl = TemplateDAO::getById(id);
formTemplateEditor *editor = new formTemplateEditor(this);
editor->loadTemplate(tpl);
connect(editor, &formTemplateEditor::templateSaved, this, [this]() {
refreshList();
});
editor->show();
}
void formTemplateList::deleteTemplate()
{
QModelIndex idx = ui->templateTable->currentIndex();
if (!idx.isValid()) {
QMessageBox::information(this, tr("Info"), tr("Selecciona una plantilla primero."));
return;
}
int row = idx.row();
int id = ui->templateTable->model()->data(ui->templateTable->model()->index(row, 0)).toInt();
int ret = QMessageBox::question(this, tr("Confirmar"), tr("¿Eliminar esta plantilla?"),
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
if (TemplateDAO::remove(id)) {
QMessageBox::information(this, tr("Éxito"), tr("Plantilla eliminada."));
refreshList();
} else {
QMessageBox::critical(this, tr("Error"), tr("No se pudo eliminar la plantilla."));
}
}
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef FORMTEMPLATELIST_H
#define FORMTEMPLATELIST_H
#include <QMainWindow>
#include "templatedao.h"
namespace Ui {
class formTemplateList;
}
class formTemplateList : public QMainWindow
{
Q_OBJECT
public:
explicit formTemplateList(QWidget *parent = nullptr);
~formTemplateList();
public slots:
void refreshList();
void createNewTemplate();
void editTemplate();
void deleteTemplate();
private:
void setupModel();
Ui::formTemplateList *ui;
};
#endif // FORMTEMPLATELIST_H
+67 -120
View File
@@ -5,6 +5,7 @@
#include <QFileDialog> #include <QFileDialog>
#include <QtSql> #include <QtSql>
#include "../dao/thirddao.h"
formThird::formThird(QString aID, int aEditMode, QWidget *parent) : formThird::formThird(QString aID, int aEditMode, QWidget *parent) :
formBase(aID, aEditMode, parent), formBase(aID, aEditMode, parent),
@@ -31,52 +32,43 @@ formThird::~formThird()
void formThird::openDocument(QString id) void formThird::openDocument(QString id)
{ {
mEditMode = true; mEditMode = true;
//ui->editCode->setText(id); rowid = id.toInt();
//ui->editCode->setReadOnly(true);
dApp->Enterprise().open(); ThirdDAO::Data data;
QSqlQuery qry = QSqlQuery(dApp->Enterprise()); if (ThirdDAO::read(rowid, data)) {
ui->editName->setText(data.name);
ui->editNickname->setText(data.nickname);
ui->editCIF->setText(data.cif);
ui->editIntraCode->setText(data.intraFc);
QString command = QString("SELECT * FROM THIRD WHERE ID = '%1';").arg(id); ui->comboState->setCurrentIndex(data.state);
if (qry.exec(command)) ui->comboClient->setCurrentIndex(data.clientState);
{ ui->editClientCode->setText(data.clientCode);
qry.first(); ui->editAccountClient->setText(data.clientAccount);
ui->comboSupplier->setCurrentIndex(data.supplierState);
ui->editSupplierCode->setText(data.supplierCode);
ui->editAccountSupplier->setText(data.supplierAccount);
ui->editName->setText(qry.value(qry.record().indexOf("NAME")).toString()); ui->editAddress->setPlainText(data.address);
ui->editNickname->setText(qry.value(qry.record().indexOf("NICKNAME")).toString()); ui->editCP->setText(data.postcode);
ui->editCIF->setText(qry.value(qry.record().indexOf("CIF")).toString()); ui->editCity->setText(data.city);
ui->editIntraCode->setText(qry.value(qry.record().indexOf("INTRA_FC")).toString()); ui->editProvince->setText(data.province);
ui->comboCountry->setCurrentText(data.countryId);
ui->comboState->setCurrentIndex(qry.value(qry.record().indexOf("STATE")).toInt()); ui->editPhone->setText(data.phone);
ui->comboClient->setCurrentIndex(qry.value(qry.record().indexOf("CLIENT_STATE")).toInt()); ui->editFax->setText(data.fax);
ui->comboClient->setCurrentIndex(qry.value(qry.record().indexOf("SUPPLIER_STATE")).toInt()); ui->editMobile->setText(data.mobile);
ui->editClientCode->setText(qry.value(qry.record().indexOf("CLIENT_CODE")).toString()); ui->editEmail->setText(data.email);
ui->editSupplierCode->setText(qry.value(qry.record().indexOf("SUPPLIER_CODE")).toString()); ui->editWebside->setText(data.website);
ui->editAddress->setPlainText(qry.value(qry.record().indexOf("ADDRESS")).toString()); ui->editPublicNotes->setHtml(data.notePublic);
ui->editCP->setText(qry.value(qry.record().indexOf("POSTCODE")).toString()); ui->editPrivateNotes->setHtml(data.notePrivate);
ui->editCity->setText(qry.value(qry.record().indexOf("CITY")).toString());
ui->editProvince->setText(qry.value(qry.record().indexOf("PROVINCE")).toString());
ui->comboCountry->setCurrentText(qry.value(qry.record().indexOf("COUNTRY_ID")).toString());
ui->editPhone->setText(qry.value(qry.record().indexOf("PHONE")).toString()); ui->editDischargeDate->setDate(data.createdAt);
ui->editFax->setText(qry.value(qry.record().indexOf("FAX")).toString()); ui->editUpdateDate->setDate(data.updatedAt);
ui->editMobile->setText(qry.value(qry.record().indexOf("MOBILE")).toString()); } else {
ui->editEmail->setText(qry.value(qry.record().indexOf("EMAIL")).toString()); qDebug() << "Error reading third with ID:" << id;
ui->editWebside->setText(qry.value(qry.record().indexOf("WEBSIDE")).toString());
ui->editPublicNotes->setHtml(qry.value(qry.record().indexOf("NOTE_PUBLIC")).toString());
ui->editPrivateNotes->setHtml(qry.value(qry.record().indexOf("NOTE_PRIVATE")).toString());
ui->editDischargeDate->setDate(qry.value(qry.record().indexOf("CREATEDAT")).toDate());
ui->editUpdateDate->setDate(qry.value(qry.record().indexOf("UPDATEDAT")).toDate());
} }
else
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
}
dApp->Enterprise().close();
} }
void formThird::closeDocument() void formThird::closeDocument()
@@ -127,91 +119,46 @@ void formThird::LoadLogo()
void formThird::save() void formThird::save()
{ {
QString command; ThirdDAO::Data data;
data.cif = ui->editCIF->text();
data.name = ui->editName->text();
data.nickname = ui->editNickname->text();
data.intraFc = ui->editIntraCode->text();
data.state = ui->comboState->currentIndex();
data.clientState = ui->comboClient->currentIndex();
data.clientCode = ui->editClientCode->text();
data.clientAccount = ui->editAccountClient->text();
data.supplierState = ui->comboSupplier->currentIndex();
data.supplierCode = ui->editSupplierCode->text();
data.supplierAccount = ui->editAccountSupplier->text();
data.address = ui->editAddress->toPlainText();
data.postcode = ui->editCP->text();
data.city = ui->editCity->text();
data.province = ui->editProvince->text();
data.countryId = ui->comboCountry->currentText();
data.phone = ui->editPhone->text();
data.fax = ui->editFax->text();
data.mobile = ui->editMobile->text();
data.email = ui->editEmail->text();
data.website = ui->editWebside->text();
data.notePublic = ui->editPublicNotes->toHtml();
data.notePrivate = ui->editPrivateNotes->toHtml();
data.updatedAt = ui->editUpdateDate->date();
data.createdAt = ui->editDischargeDate->date();
if (mEditMode) bool ok;
command = "UPDATE THIRD SET " if (mEditMode) {
"FORM = :FORM, CIF = :CIF, NAME = :NAME, NICKNAME = :NICKNAME, FAMILY = :FAMILY, " data.id = rowid;
"INTRA_FC = :INTRA_FC, STATE = :STATE, CLIENT_STATE = :CLIENT_STATE, CLIENT_CODE = :CLIENT_CODE, " ok = ThirdDAO::update(data);
"CLIENT_ACCOUNT = :CLIENT_ACCOUNT, SUPPLIER_STATE = :SUPPLIER_STATE, SUPPLIER_CODE = :SUPLLIR_CODE, " } else {
"SUPPLIER_ACCOUNT = :SUPPLIER_ACCOUNT, ADDRESS = :ADDRESS, POSTCODE = :POSTCODE, CITY = :CITY, " ok = ThirdDAO::create(data);
"PROVINCE = :PROVINCE, COUNTRY_ID = :COUNTRY_ID, PHONE = :PHONE, FAX = :FAX, "
"EMAIL = :EMAIL, WEBSIDE = :WEBSIDE, PAYMENT_METHOD = :PAYMENT_METHOD, PAYMENT_TYPE = :PAYMENT_TYPE, "
"LOGO = :LOGO, NOTE_PUBLIC = :NOTE_PUBLIC, NOTE_PRIVATE = :NOTE_PRIVATE, UPDATEDAT = :UPDATEDAT, "
"CREATEDAT = :CREATEDAT, CREATEDBY = :CREATEBY "
"WHERE CIF = '" + ui->editCIF->text() +
"';";
else
command = "INSERT INTO THIRD ("
"FORM, CIF, NAME, NICKNAME, FAMILY, INTRA_FC, STATE, CLIENT_STATE, CLIENT_CODE, "
"CLIENT_ACCOUNT, SUPPLIER_STATE, SUPPLIER_CODE, SUPPLIER_ACCOUNT, ADDRESS, "
"POSTCODE, CITY, PROVINCE, COUNTRY_ID, PHONE, FAX, EMAIL, WEBSIDE, "
"PAYMENT_METHOD, PAYMENT_TYPE, LOGO, NOTE_PUBLIC, NOTE_PRIVATE, UPDATEDAT, "
"CREATEDAT, CREATEDBY"
") VALUES ("
":FORM, :CIF, :NAME, :NICKNAME, :FAMILY, :INTRA_FC, :STATE, :CLIENT_STATE, :CLIENT_CODE, "
":CLIENT_ACCOUNT, :SUPPLIER_STATE, :SUPPLIER_CODE, :SUPPLIER_ACCOUNT, :ADDRESS, "
":POSTCODE, :CITY, :PROVINCE, :COUNTRY_ID, :PHONE, :FAX, :EMAIL, :WEBSIDE, "
":PAYMENT_METHOD, :PAYMENT_TYPE, :LOGO, :NOTE_PUBLIC, :NOTE_PRIVATE, :UPDATEDAT, "
":CREATEDAT, :CREATEDBY"
");";
qDebug() << command;
dApp->Enterprise().open();
QSqlQuery qry = QSqlQuery(dApp->Enterprise());
qry.prepare(command);
//qry.bindValue(":FORM", );
qry.bindValue(":CIF", ui->editCIF->text());
qry.bindValue(":NAME", ui->editName->text());
qry.bindValue(":NICKNAME", ui->editNickname->text());
//qry.bindValue(":FAMILY", );
qry.bindValue(":INTRA_FC", ui->editIntraCode->text());
qry.bindValue(":STATE", ui->comboState->currentIndex());
qry.bindValue(":CLIENT_STATE", ui->comboClient->currentIndex());
qry.bindValue(":CLIENT_CODE", ui->editClientCode->text());
qry.bindValue(":CLIENT_ACCOUNT", ui->editAccountClient->text());
qry.bindValue(":SUPPLIER_STATE", ui->comboSupplier->currentIndex());
qry.bindValue(":SUPPLIER_CODE", ui->editSupplierCode->text());
qry.bindValue(":SUPPLIER_ACCOUNT", ui->editAccountSupplier->text());
qry.bindValue(":ADDRESS", ui->editAddress->toPlainText());
qry.bindValue(":POSTCODE", ui->editCP->text());
qry.bindValue(":CITY", ui->editCity->text());
qry.bindValue(":PROVINCE", ui->editProvince->text());
qry.bindValue(":COUNTRY_ID", ui->comboCountry->currentText());
//qry.bindValue(":COUNTRY", ui->editIntraCode->text());
qry.bindValue(":PHONE", ui->editPhone->text());
qry.bindValue(":FAX", ui->editFax->text());
qry.bindValue(":MOBILE", ui->editMobile->text());
qry.bindValue(":EMAIL", ui->editEmail->text());
qry.bindValue(":WEBSIDE", ui->editWebside->text());
//qry.bindValue(":PAYMENT_METHOD", ui->editPhone->text());
//qry.bindValue(":PAYMENT_TYPE", ui->editFax->text());
//qry.bindValue(":LOGO", ui->editMobile->text());
qry.bindValue(":NOTE_PUBLIC", ui->editPublicNotes->toHtml());
qry.bindValue(":NOTE_PRIVATE", ui->editPrivateNotes->toHtml());
qry.bindValue(":UPDATEDAT", ui->editUpdateDate->date());
qry.bindValue(":CREATEDAT", ui->editDischargeDate->date());
//qry.bindValue(":CREATEDBY", ui->editWebside->text());
if (!qry.exec())
{
qDebug() << "Error ejecutando el query: " << qry.lastError().text() << "\n";
} }
else
{ if (ok) {
setEditMode(); setEditMode();
} else {
qDebug() << "Error saving third";
} }
dApp->Enterprise().close();
} }
void formThird::setEditMode() void formThird::setEditMode()
Binary file not shown.
@@ -302,3 +302,15 @@ void MainWindow::closeEvent(QCloseEvent *event)
{ {
dApp->quit(); dApp->quit();
} }
void MainWindow::importFIEBDCFile()
{
// TODO: stub - implementar cuando se restaure la funcionalidad
QMessageBox::information(this, tr("Import"), tr("FIEBDC import not yet available."));
}
void MainWindow::exportBC3File()
{
// TODO: stub - implementar cuando se restaure la funcionalidad
QMessageBox::information(this, tr("Export"), tr("BC3 export not yet available."));
}
@@ -98,6 +98,8 @@ public slots:
private slots: private slots:
void tabCloseRequested(int index); void tabCloseRequested(int index);
void importFIEBDCFile();
void exportBC3File();
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
View File
Binary file not shown.
View File
View File
+75
View File
@@ -0,0 +1,75 @@
{
"name": "Presupuesto Proyecto",
"description": "Plantilla de presupuesto para proyectos",
"documentType": "budget",
"widthMM": 210,
"heightMM": 297,
"margin": [20, 20, 20, 20],
"elements": [
{
"type": "label",
"x": 50,
"y": 50,
"w": 200,
"h": 20,
"text": "Presupuesto #{{code}}",
"font": "Arial",
"size": 14,
"bold": true,
"align": "left"
},
{
"type": "label",
"x": 300,
"y": 50,
"w": 100,
"h": 20,
"text": "{{date}}",
"font": "Arial",
"size": 10,
"bold": false
},
{
"type": "table",
"x": 50,
"y": 80,
"w": 350,
"h": 150,
"columns": ["description", "quantity", "unitPrice", "total"],
"dataSource": "lines",
"cellAlignment": {
"0": "left",
"1": "right",
"2": "right",
"3": "right"
},
"headerAlignment": "center",
"headerColor": "#CCCCCC",
"alternateRowColor": true,
"rowHeight": 20
},
{
"type": "label",
"x": 250,
"y": 240,
"w": 50,
"h": 20,
"text": "Total:",
"font": "Arial",
"size": 14,
"bold": true
},
{
"type": "label",
"x": 300,
"y": 240,
"w": 100,
"h": 20,
"text": "{{total}}",
"font": "Arial",
"size": 14,
"bold": true,
"align": "right"
}
]
}
+52
View File
@@ -0,0 +1,52 @@
{
"name": "Factura PDF",
"description": "Plantilla de factura para clientes",
"documentType": "invoice",
"widthMM": 210,
"heightMM": 297,
"margin": [20, 20, 20, 20],
"elements": [
{
"type": "label",
"x": 50,
"y": 50,
"w": 150,
"h": 20,
"text": "Factura #{{code}}",
"font": "Arial",
"size": 14,
"bold": true,
"align": "left"
},
{
"type": "label",
"x": 200,
"y": 50,
"w": 100,
"h": 20,
"text": "{{clientName}}",
"font": "Arial",
"size": 12,
"bold": false
},
{
"type": "table",
"x": 50,
"y": 80,
"w": 200,
"h": 100,
"columns": ["description", "quantity", "price", "total"],
"dataSource": "lines",
"cellAlignment": {
"0": "left",
"1": "right",
"2": "right",
"3": "right"
},
"headerAlignment": "center",
"headerColor": "#CCCCCC",
"alternateRowColor": true,
"rowHeight": 20
}
]
}
BIN
View File
Binary file not shown.