261 lines
8.5 KiB
C++
261 lines
8.5 KiB
C++
|
|
#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) + " €");
|
||
|
|
}
|