Compare commits
5 Commits
d3ae41e94d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a2d3eda4e9 | |||
| 5475fc301d | |||
| d900ecb313 | |||
| ed1ac4266c | |||
| 7d607f5139 |
@@ -0,0 +1 @@
|
|||||||
|
*.o
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
|
|||||||
+22
-22
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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};
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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) + " €");
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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."));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user