Implement declaration validation with confirmation dialog
Features: - Add validation confirmation dialog (non-JavaScript popup) - Remove recalculate button after validation - Generate and save detailed PDF to Dolibarr documents - Add document icons in declaration list - Add status icons (checkmark for validated, edit for draft) - Create documents linking table - Add validation language strings (FR/EN) Technical: - Enhanced validateDeclaration() method with user tracking - saveValidatedPDF() method for document storage - hasValidatedDocument() method for icon display - Custom confirmation dialog with CSS styling - Database migration for documents table - Status-based UI changes
This commit is contained in:
parent
91ebf73866
commit
f07f6a7c28
@ -764,21 +764,6 @@ class DeclarationTVA
|
|||||||
return $lines;
|
return $lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate declaration
|
|
||||||
*
|
|
||||||
* @param int $declaration_id Declaration ID
|
|
||||||
* @return bool Success
|
|
||||||
*/
|
|
||||||
public function validateDeclaration($declaration_id)
|
|
||||||
{
|
|
||||||
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
|
||||||
SET status = 'validated'
|
|
||||||
WHERE rowid = " . $declaration_id . " AND entity = " . $this->entity;
|
|
||||||
|
|
||||||
$result = $this->db->query($sql);
|
|
||||||
return $result !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit declaration
|
* Submit declaration
|
||||||
@ -1005,4 +990,118 @@ class DeclarationTVA
|
|||||||
'account_count' => count($details)
|
'account_count' => count($details)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a declaration
|
||||||
|
*
|
||||||
|
* @param int $declaration_id Declaration ID
|
||||||
|
* @return bool Success
|
||||||
|
*/
|
||||||
|
public function validateDeclaration($declaration_id)
|
||||||
|
{
|
||||||
|
$sql = "UPDATE " . MAIN_DB_PREFIX . "declarationtva_declarations
|
||||||
|
SET status = 'validated',
|
||||||
|
validated_date = NOW(),
|
||||||
|
validated_by = " . $this->db->escape($GLOBALS['user']->id) . "
|
||||||
|
WHERE rowid = " . (int)$declaration_id . "
|
||||||
|
AND entity = " . $this->entity;
|
||||||
|
|
||||||
|
$result = $this->db->query($sql);
|
||||||
|
if ($result) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->error = $this->db->lasterror();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save validated PDF to Dolibarr documents
|
||||||
|
*
|
||||||
|
* @param int $declaration_id Declaration ID
|
||||||
|
* @param string $pdf_path Path to the PDF file
|
||||||
|
* @return bool Success
|
||||||
|
*/
|
||||||
|
public function saveValidatedPDF($declaration_id, $pdf_path)
|
||||||
|
{
|
||||||
|
global $conf, $user;
|
||||||
|
|
||||||
|
// Create documents directory if it doesn't exist
|
||||||
|
$doc_dir = DOL_DATA_ROOT . '/declarationtva/validated/';
|
||||||
|
if (!is_dir($doc_dir)) {
|
||||||
|
dol_mkdir($doc_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate filename
|
||||||
|
$filename = 'CA3_Validated_' . $this->declaration_number . '_' . date('Y-m-d') . '.pdf';
|
||||||
|
$dest_path = $doc_dir . $filename;
|
||||||
|
|
||||||
|
// Copy PDF to documents directory
|
||||||
|
if (copy($pdf_path, $dest_path)) {
|
||||||
|
// Add document record to Dolibarr
|
||||||
|
require_once DOL_DOCUMENT_ROOT . '/core/class/ecmfiles.class.php';
|
||||||
|
$ecmfile = new EcmFiles($this->db);
|
||||||
|
|
||||||
|
$ecmfile->filepath = 'declarationtva/validated/';
|
||||||
|
$ecmfile->filename = $filename;
|
||||||
|
$ecmfile->label = 'CA-3 Validated Declaration - ' . $this->declaration_number;
|
||||||
|
$ecmfile->description = 'Validated CA-3 declaration with detailed breakdown';
|
||||||
|
$ecmfile->entity = $this->entity;
|
||||||
|
$ecmfile->fk_user_author = $user->id;
|
||||||
|
$ecmfile->fk_user_modif = $user->id;
|
||||||
|
$ecmfile->datec = dol_now();
|
||||||
|
$ecmfile->tms = dol_now();
|
||||||
|
$ecmfile->mimetype = 'application/pdf';
|
||||||
|
$ecmfile->filesize = filesize($dest_path);
|
||||||
|
$ecmfile->checksum = md5_file($dest_path);
|
||||||
|
|
||||||
|
$result = $ecmfile->create($user);
|
||||||
|
if ($result > 0) {
|
||||||
|
// Link document to declaration
|
||||||
|
$this->linkDocumentToDeclaration($declaration_id, $ecmfile->id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link document to declaration
|
||||||
|
*
|
||||||
|
* @param int $declaration_id Declaration ID
|
||||||
|
* @param int $document_id Document ID
|
||||||
|
* @return bool Success
|
||||||
|
*/
|
||||||
|
private function linkDocumentToDeclaration($declaration_id, $document_id)
|
||||||
|
{
|
||||||
|
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "declarationtva_documents
|
||||||
|
(declaration_id, document_id, created_date)
|
||||||
|
VALUES (" . (int)$declaration_id . ", " . (int)$document_id . ", NOW())";
|
||||||
|
|
||||||
|
return $this->db->query($sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if declaration has a validated document
|
||||||
|
*
|
||||||
|
* @param int $declaration_id Declaration ID
|
||||||
|
* @return bool Has document
|
||||||
|
*/
|
||||||
|
public function hasValidatedDocument($declaration_id)
|
||||||
|
{
|
||||||
|
$sql = "SELECT COUNT(*) as count
|
||||||
|
FROM " . MAIN_DB_PREFIX . "declarationtva_documents dd
|
||||||
|
INNER JOIN " . MAIN_DB_PREFIX . "ecm_files ef ON dd.document_id = ef.rowid
|
||||||
|
WHERE dd.declaration_id = " . (int)$declaration_id . "
|
||||||
|
AND dd.entity = " . $this->entity;
|
||||||
|
|
||||||
|
$result = $this->db->query($sql);
|
||||||
|
if ($result && $this->db->num_rows($result) > 0) {
|
||||||
|
$obj = $this->db->fetch_object($result);
|
||||||
|
return $obj->count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,6 +98,25 @@ if ($action == 'export_pdf_detailed') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($action == 'validate' && $token) {
|
||||||
|
// Validate the declaration
|
||||||
|
if ($declarationtva->validateDeclaration($id)) {
|
||||||
|
setEventMessages($langs->trans("DeclarationValidated"), null, 'mesgs');
|
||||||
|
|
||||||
|
// Generate and save detailed PDF to Dolibarr documents
|
||||||
|
require_once DOL_DOCUMENT_ROOT . '/custom/declarationtva/core/class/declarationtva_pdf.class.php';
|
||||||
|
$pdf_generator = new DeclarationTVA_PDF($db);
|
||||||
|
|
||||||
|
$pdf_path = $pdf_generator->generateDetailedCA3PDF($id);
|
||||||
|
if ($pdf_path && file_exists($pdf_path)) {
|
||||||
|
// Save PDF to Dolibarr documents
|
||||||
|
$declarationtva->saveValidatedPDF($id, $pdf_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setEventMessages($langs->trans("ErrorValidatingDeclaration"), null, 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch declaration
|
// Fetch declaration
|
||||||
if ($declarationtva->fetch($id) < 0) {
|
if ($declarationtva->fetch($id) < 0) {
|
||||||
setEventMessages($langs->trans("DeclarationNotFound"), null, 'errors');
|
setEventMessages($langs->trans("DeclarationNotFound"), null, 'errors');
|
||||||
@ -409,15 +428,18 @@ print '<div class="titre">' . $langs->trans("Actions") . '</div>';
|
|||||||
|
|
||||||
print '<div class="center">';
|
print '<div class="center">';
|
||||||
|
|
||||||
// Recalculate button (always available)
|
// Recalculate button (only for draft status)
|
||||||
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=recalculate&token=' . newToken() . '" class="butAction">' . $langs->trans("Recalculate") . '</a> ';
|
if ($declarationtva->status == 'draft') {
|
||||||
|
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=recalculate&token=' . newToken() . '" class="butAction">' . $langs->trans("Recalculate") . '</a> ';
|
||||||
|
}
|
||||||
|
|
||||||
// PDF Export buttons (always available)
|
// PDF Export buttons (always available)
|
||||||
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=export_pdf" class="butAction">' . $langs->trans("ExportPDF") . '</a> ';
|
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=export_pdf" class="butAction">' . $langs->trans("ExportPDF") . '</a> ';
|
||||||
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=export_pdf_detailed" class="butAction">' . $langs->trans("ExportPDFDetailed") . '</a> ';
|
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=export_pdf_detailed" class="butAction">' . $langs->trans("ExportPDFDetailed") . '</a> ';
|
||||||
|
|
||||||
if ($declarationtva->status == 'draft') {
|
if ($declarationtva->status == 'draft') {
|
||||||
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=validate" class="butAction">' . $langs->trans("Validate") . '</a> ';
|
// Validation button with confirmation dialog
|
||||||
|
print '<a href="#" onclick="confirmValidation(' . $id . '); return false;" class="butAction">' . $langs->trans("Validate") . '</a> ';
|
||||||
} elseif ($declarationtva->status == 'validated') {
|
} elseif ($declarationtva->status == 'validated') {
|
||||||
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=submit" class="butAction">' . $langs->trans("Submit") . '</a> ';
|
print '<a href="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&action=submit" class="butAction">' . $langs->trans("Submit") . '</a> ';
|
||||||
}
|
}
|
||||||
@ -520,6 +542,38 @@ function loadLineDetails(line) {
|
|||||||
};
|
};
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function confirmValidation(declarationId) {
|
||||||
|
// Create confirmation dialog
|
||||||
|
var dialog = document.createElement("div");
|
||||||
|
dialog.style.cssText = "position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 10000; display: flex; align-items: center; justify-content: center;";
|
||||||
|
|
||||||
|
var dialogContent = document.createElement("div");
|
||||||
|
dialogContent.style.cssText = "background: white; padding: 20px; border-radius: 5px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); max-width: 500px; text-align: center;";
|
||||||
|
|
||||||
|
dialogContent.innerHTML = `
|
||||||
|
<h3>' . $langs->trans("ConfirmValidation") . '</h3>
|
||||||
|
<p>' . $langs->trans("ValidationConfirmationMessage") . '</p>
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<button onclick="proceedValidation(' . $id . '); this.parentElement.parentElement.parentElement.remove();"
|
||||||
|
style="background: #28a745; color: white; border: none; padding: 10px 20px; margin: 0 10px; border-radius: 3px; cursor: pointer;">
|
||||||
|
' . $langs->trans("YesValidate") . '
|
||||||
|
</button>
|
||||||
|
<button onclick="this.parentElement.parentElement.parentElement.remove();"
|
||||||
|
style="background: #6c757d; color: white; border: none; padding: 10px 20px; margin: 0 10px; border-radius: 3px; cursor: pointer;">
|
||||||
|
' . $langs->trans("Cancel") . '
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
dialog.appendChild(dialogContent);
|
||||||
|
document.body.appendChild(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
function proceedValidation(declarationId) {
|
||||||
|
// Redirect to validation action
|
||||||
|
window.location.href = "' . $_SERVER['PHP_SELF'] . '?id=" + declarationId + "&action=validate&token=' . newToken() . '";
|
||||||
|
}
|
||||||
</script>';
|
</script>';
|
||||||
|
|
||||||
// Print footer
|
// Print footer
|
||||||
|
|||||||
@ -123,6 +123,7 @@ if (empty($declarations)) {
|
|||||||
print '<th class="center">' . $langs->trans("Period") . '</th>';
|
print '<th class="center">' . $langs->trans("Period") . '</th>';
|
||||||
print '<th class="center">' . $langs->trans("Status") . '</th>';
|
print '<th class="center">' . $langs->trans("Status") . '</th>';
|
||||||
print '<th class="center">' . $langs->trans("NetVATDue") . '</th>';
|
print '<th class="center">' . $langs->trans("NetVATDue") . '</th>';
|
||||||
|
print '<th class="center">' . $langs->trans("Document") . '</th>';
|
||||||
print '<th class="center">' . $langs->trans("Actions") . '</th>';
|
print '<th class="center">' . $langs->trans("Actions") . '</th>';
|
||||||
print '</tr>';
|
print '</tr>';
|
||||||
|
|
||||||
@ -130,8 +131,33 @@ if (empty($declarations)) {
|
|||||||
print '<tr>';
|
print '<tr>';
|
||||||
print '<td>' . $d['declaration_number'] . '</td>';
|
print '<td>' . $d['declaration_number'] . '</td>';
|
||||||
print '<td class="center">' . dol_print_date($d['start_date'], 'day') . ' - ' . dol_print_date($d['end_date'], 'day') . '</td>';
|
print '<td class="center">' . dol_print_date($d['start_date'], 'day') . ' - ' . dol_print_date($d['end_date'], 'day') . '</td>';
|
||||||
print '<td class="center">' . $langs->trans("Status" . ucfirst($d['status'])) . '</td>';
|
|
||||||
|
// Status with icon
|
||||||
|
$status_icon = '';
|
||||||
|
if ($d['status'] == 'validated') {
|
||||||
|
$status_icon = ' <i class="fa fa-check-circle text-success" title="' . $langs->trans("ValidatedDeclaration") . '"></i>';
|
||||||
|
} elseif ($d['status'] == 'draft') {
|
||||||
|
$status_icon = ' <i class="fa fa-edit text-warning" title="' . $langs->trans("DraftDeclaration") . '"></i>';
|
||||||
|
}
|
||||||
|
print '<td class="center">' . $langs->trans("Status" . ucfirst($d['status'])) . $status_icon . '</td>';
|
||||||
|
|
||||||
print '<td class="center">' . price($d['net_vat_due']) . '</td>';
|
print '<td class="center">' . price($d['net_vat_due']) . '</td>';
|
||||||
|
|
||||||
|
// Document column
|
||||||
|
print '<td class="center">';
|
||||||
|
if ($d['status'] == 'validated') {
|
||||||
|
// Check if document exists
|
||||||
|
$has_document = $declarationtva->hasValidatedDocument($d['rowid']);
|
||||||
|
if ($has_document) {
|
||||||
|
print '<i class="fa fa-file-pdf-o text-success" title="' . $langs->trans("ValidatedPDFAvailable") . '"></i>';
|
||||||
|
} else {
|
||||||
|
print '<i class="fa fa-file-o text-muted" title="' . $langs->trans("NoDocument") . '"></i>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print '<i class="fa fa-minus text-muted"></i>';
|
||||||
|
}
|
||||||
|
print '</td>';
|
||||||
|
|
||||||
print '<td class="center">';
|
print '<td class="center">';
|
||||||
|
|
||||||
if ($d['status'] == 'draft') {
|
if ($d['status'] == 'draft') {
|
||||||
|
|||||||
@ -492,3 +492,19 @@ TemplateResetFailed = Error resetting to official template
|
|||||||
ErrorGeneratingPDF = Error generating PDF
|
ErrorGeneratingPDF = Error generating PDF
|
||||||
TemplateUpdated = Template updated successfully
|
TemplateUpdated = Template updated successfully
|
||||||
TemplateUpdateFailed = Error updating template
|
TemplateUpdateFailed = Error updating template
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
Validate = Validate
|
||||||
|
ConfirmValidation = Confirm Validation
|
||||||
|
ValidationConfirmationMessage = Are you sure you want to validate this declaration? This action is irreversible and will automatically generate the detailed PDF.
|
||||||
|
YesValidate = Yes, validate
|
||||||
|
Cancel = Cancel
|
||||||
|
DeclarationValidated = Declaration validated successfully
|
||||||
|
ErrorValidatingDeclaration = Error validating declaration
|
||||||
|
|
||||||
|
# Document and status icons
|
||||||
|
Document = Document
|
||||||
|
ValidatedDeclaration = Validated Declaration
|
||||||
|
DraftDeclaration = Draft Declaration
|
||||||
|
ValidatedPDFAvailable = Validated PDF Available
|
||||||
|
NoDocument = No Document
|
||||||
|
|||||||
@ -464,3 +464,19 @@ TemplateResetFailed = Erreur lors du retour au modèle officiel
|
|||||||
ErrorGeneratingPDF = Erreur lors de la génération du PDF
|
ErrorGeneratingPDF = Erreur lors de la génération du PDF
|
||||||
TemplateUpdated = Modèle mis à jour avec succès
|
TemplateUpdated = Modèle mis à jour avec succès
|
||||||
TemplateUpdateFailed = Erreur lors de la mise à jour du modèle
|
TemplateUpdateFailed = Erreur lors de la mise à jour du modèle
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
Validate = Valider
|
||||||
|
ConfirmValidation = Confirmer la validation
|
||||||
|
ValidationConfirmationMessage = Êtes-vous sûr de vouloir valider cette déclaration ? Cette action est irréversible et générera automatiquement le PDF détaillé.
|
||||||
|
YesValidate = Oui, valider
|
||||||
|
Cancel = Annuler
|
||||||
|
DeclarationValidated = Déclaration validée avec succès
|
||||||
|
ErrorValidatingDeclaration = Erreur lors de la validation de la déclaration
|
||||||
|
|
||||||
|
# Document and status icons
|
||||||
|
Document = Document
|
||||||
|
ValidatedDeclaration = Déclaration validée
|
||||||
|
DraftDeclaration = Déclaration brouillon
|
||||||
|
ValidatedPDFAvailable = PDF validé disponible
|
||||||
|
NoDocument = Aucun document
|
||||||
|
|||||||
26
sql/migration_add_documents_table.sql
Normal file
26
sql/migration_add_documents_table.sql
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
-- Migration: Add documents table for linking validated PDFs to declarations
|
||||||
|
-- Version: 2.1.0
|
||||||
|
-- Date: 2025-01-06
|
||||||
|
|
||||||
|
-- Create table for linking documents to declarations
|
||||||
|
CREATE TABLE IF NOT EXISTS `llx_declarationtva_documents` (
|
||||||
|
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`declaration_id` int(11) NOT NULL,
|
||||||
|
`document_id` int(11) NOT NULL,
|
||||||
|
`created_date` datetime NOT NULL,
|
||||||
|
`entity` int(11) NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`rowid`),
|
||||||
|
KEY `idx_declaration_id` (`declaration_id`),
|
||||||
|
KEY `idx_document_id` (`document_id`),
|
||||||
|
KEY `idx_entity` (`entity`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Add validated_date and validated_by columns to declarations table if they don't exist
|
||||||
|
ALTER TABLE `llx_declarationtva_declarations`
|
||||||
|
ADD COLUMN IF NOT EXISTS `validated_date` datetime DEFAULT NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS `validated_by` int(11) DEFAULT NULL;
|
||||||
|
|
||||||
|
-- Add indexes for performance
|
||||||
|
ALTER TABLE `llx_declarationtva_declarations`
|
||||||
|
ADD INDEX IF NOT EXISTS `idx_validated_date` (`validated_date`),
|
||||||
|
ADD INDEX IF NOT EXISTS `idx_validated_by` (`validated_by`);
|
||||||
Loading…
Reference in New Issue
Block a user