Supplementary documents for an operation, an operation can

have several attached documents
This commit is contained in:
sparkyx 2025-11-08 15:41:15 +01:00
parent b5f55a129a
commit 5b337881e5
8 changed files with 586 additions and 5 deletions

View file

@ -2050,3 +2050,171 @@ var operation_exercice = {
}
}
}
var Supplement_Document={
};
/**
* see ledger_detail_sup_files.php
* $rowid=sprintf("row_js_%s_%s",$div,$item->js_id);
* @param {int} nDossier
* @param {string} sDiv
* @param {int} nJS_ID
* @returns {void}
*/
Supplement_Document.delete_document=function (nDossier,sDiv,nJS_ID,nJR_ID)
{
confirm_box(null
,content[47]
,function (){
try
{
var queryString = {
gDossier:nDossier,
div:sDiv,
jr_id:nJR_ID,
js_id:nJS_ID,
op:"ledger",
act:"rmsup"
};
var action = new Ajax.Request(
"ajax_misc.php",
{
method: 'POST',
parameters: queryString,
onSuccess: function (req) {
remove_waiting_box();
if (req.responseText == 'NOCONX') {
reconnect();
return;
}
id$("row_js_"+sDiv+"_"+nJS_ID).remove();
}
}
);
} catch (e)
{
alert_box(e.message);
}
}
);
}
Supplement_Document.input_file=function(nDossier,sDiv,nJR_ID)
{
try
{
var dgbox = "sup_doc_input_file"+sDiv;
waiting_box();
removeDiv(dgbox);
var queryString = {
gDossier:nDossier,
div:sDiv,
jr_id:nJR_ID,
op:"ledger",
act:"input_file",
dgbox:dgbox
};
var action = new Ajax.Request(
"ajax_misc.php",
{
method: 'GET',
parameters: queryString,
onFailure: ajax_misc_failure,
onSuccess: function (req) {
remove_waiting_box();
if (req.responseText == 'NOCONX') {
reconnect();
return;
}
var y = calcy(15);
var div_style = "position:absolute;" + ";top:" + y + "px"+";z-index:"+get_next_layer();
add_div({id: dgbox, cssclass: 'inner_box2', html: loading(), style: div_style, drag: true});
$(dgbox).innerHTML = req.responseText;
}
}
);
} catch (e)
{
alert_box(e.message);
}
}
/**
*
* @param {string} FORM ID
* @returns {Boolean}
*/
Supplement_Document.save_file=function(form_dom_id)
{
try
{
waiting_box();
var form_data=$(form_dom_id).serialize();
var xhr = new XMLHttpRequest();
var div=id$(form_dom_id).elements["div"].value;
// check size
var total_size=0;
var file_to_upload=id$("doc_sup");
var max_size=id$(form_dom_id).elements["MAX_FILE_SIZE"].value;
var post_max_size=id$(form_dom_id).elements["post_max_size"].value;
var feedback_div=id$('feedback'+div);
for (var e=0;e<file_to_upload.files.length;e++) {
// check the size
if (file_to_upload.files[e].size > max_size) {
// if size > accepted size , push filename with error in an array feedback,
feedback_div.innerHTML += '<p class="notice">' + file_to_upload.files[e].name
+content[78]+ "</p>";
remove_waiting_box();
return false;
} else if ( total_size+file_to_upload.files[e].size >= post_max_size )
{
feedback_div.innerHTML += '<p > limite '+content[78]+" </p>";
remove_waiting_box();
return false;
}
else {
total_size+=file_to_upload.files[e].size;
}
}
feedback_div.innerHTML="loading....";
document.getElementById("progress_upload1b").setAttribute("value", 0);
xhr.upload.onprogress = function (e) {
document.getElementById("progress_upload1b").setAttribute("max", e.total) + "<br/>";
document.getElementById("progress_upload1b").setAttribute("value", e.loaded) + "<br/>";
}
xhr.onreadystatechange = function (event) {
if (this.readyState == XMLHttpRequest.DONE)
{
remove_waiting_box();
if (this.status === 200) {
document.getElementById("supplement_div_list"+div).innerHTML += this.responseText ;
let dgbox=id$(form_dom_id).elements["dgbox"].value;
removeDiv(dgbox);
} else {
document.getElementById("supplement_div_list"+div).innerHTML += "status" + this.statusText + "<br/>";
}
}
}
xhr.open("POST", "ajax_misc.php?"+form_data, true);
// works xhr.send(new FormData(input.parentElement));
var formData = new FormData(document.getElementById(form_dom_id));
xhr.send(formData);
}catch(e)
{
console.error("Supplement_Document.save_file "+e.message)
}
remove_waiting_box();
return false;
}

View file

@ -29,7 +29,7 @@ namespace Noalyss\XMLDocument;
*/
/**
* @file
* @class
* @brief Get information from an XML
* Exception code :
* - 55 : XML Invalid
@ -139,7 +139,7 @@ class XMLInvoice_Reader
/**
* @brief returns the embedded document in an array (keys : filecontent (BYTES),mimecode , filename)
* or false if there is no document
* @return bool|array of array : filecontent (BYTES),mimecode , filename)
* @return bool|array of Document_Reference
* @throws \Exception if there are several documents
*
*/

View file

@ -566,6 +566,93 @@ switch ($action) {
$acc_operation_note= Acc_Operation_Note::build_jrn_id($jr_id);
echo substr($acc_operation_note->getNote()??"",0,120);
return;
case "rmsup":
//------------------------------------------------
// Remove a document from JRN_SUP_DOCUMENT
//------------------------------------------------
$js_id=$http->post("js_id","number");
$jrn_sup= new Jrn_Sup_Document_SQL($cn,$js_id);
$jrn_sup->delete();
// no answer, we stop here
return;
case 'input_file':
//------------------------------------------------
// Display form for adding file , directly HTML
//
//------------------------------------------------
require_once NOALYSS_TEMPLATE."/ajax_ledger+input_file.php";
return;
case 'save_file':
//------------------------------------------------
// Add a document to the operation
//------------------------------------------------
if (sizeof($_FILES)==0) {
return;
}
$nb=count($_FILES['document_supplemental']["name"]);
$cn->start();
for ($i=0;$i<$nb;$i++)
{
$file= tempnam($_ENV["TMP"], "sup_file");
if ( move_uploaded_file($_FILES['document_supplemental']['tmp_name'][$i],$file))
{
if ( ($oid=$cn->lo_import($file)) != false )
{
$jrn_sup=new Jrn_Sup_Document_SQL($cn);
$jrn_sup->jr_id=$jr_id;
$jrn_sup->js_lob=$oid;
$jrn_sup->js_mimetype=$_FILES['document_supplemental']['type'][$i];
$jrn_sup->js_filename=$_FILES['document_supplemental']['name'][$i];
$jrn_sup->insert();
$rowid=sprintf("row_js_%s_%s",$div,$jrn_sup->js_id);
// @var $download (url) to send file
$download="export.php?". http_build_query(
[
"act"=>"RAW:suppl-document"
,"js_id"=>$jrn_sup->js_id
,"gDossier"=>$gDossier
]);
$script_remove="Supplement_Document.delete_document('$gDossier','$div','{$jrn_sup->js_id}','$jr_id')";
$icon_remove=\Icon_Action::trash(uniqid("sdd"),$script_remove);
echo <<<EOF
<div class="row" id="{$rowid}">
<div class="col">
<a href="{$download}" download>
{$jrn_sup->js_filename}
</a>
</div>
<div class="col">
{$jrn_sup->js_description}
</div>
<div class="col">
{$icon_remove}
</div>
</div>
EOF;
}
else
{
// failed
print '<div class="row">';
echo_warning(_("1 Echec ").$_FILES["name"]);
print '</div>';
}
}
else
{
//failed
// failed
print '<div class="row">';
echo_warning(_("2 Echec ").$_FILES["name"]);
print '</div>';
}
}
$cn->commit();
return;
}
$html = escape_xml($html);

View file

@ -0,0 +1,151 @@
<?php
/*
* This file is part of NOALYSS.
*
* NOALYSS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* NOALYSS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOALYSS; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
/**
* @file
* @brief download document
*/
if ( ! defined ('ALLOWED')) die (_('Non autorisé'));
include_once NOALYSS_INCLUDE.'/lib/ac_common.php';
$http=new HttpInput();
try
{
$js_id=$http->get('js_id',"number");
$operation_id=$http->get("operation_id",'number',0);
}
catch (Exception $exc)
{
record_log($exc);
return;
}
$cn=Dossier::connect();
//------------------------------------------------
// Download only one document
//------------------------------------------------
if ( $js_id > 0)
{
$jrn_def_id=$cn->get_value("select jr_def_id from jrn_sup_document join jrn using (jr_id) where js_id=$1",array($js_id));
global $g_user;
if ($jrn_def_id =="" || $g_user->check_jrn($jrn_def_id) == 'X' )
{
/* Cannot Access */
NoAccess();
exit -1;
}
$jrn=new Jrn_Sup_Document_SQL($cn,$js_id);
$cn->start();
ini_set('zlib.output_compression','Off');
header("Pragma: public");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: must-revalidate");
header('Content-type: '.$jrn->js_mimetype);
header('Content-Disposition: attachment;filename="'.$jrn->js_filename.'"',FALSE);
header("Accept-Ranges: bytes");
echo $cn->lo_read($jrn->js_lob);
$cn->commit();
return;
}
//------------------------------------------------
// Download all documents
//------------------------------------------------
if ( $operation_id > 0)
{
$jrn_def_id=$cn->get_value("select jr_def_id from jrn where jr_id=$1",array($operation_id));
global $g_user;
if ($jrn_def_id =="" || $g_user->check_jrn($jrn_def_id) == 'X' )
{
/* Cannot Access */
NoAccess();
exit -1;
}
$jr_internal=$cn->get_value("select jr_internal from jrn where jr_id=$1",array($operation_id));
try {
$cn->start();
// find all the documents for this operation
$a_file=$cn->get_array("select js_lob,js_filename from jrn_sup_document where jr_id=$1",
[$operation_id]);
// save them into a temp folder
if ( count ($a_file) == 0 ) {
// @TODO send an empty file
return;
}
$a_file_dwn=array();
$store = tempnam($_ENV['TMP'], 'pdf_');
unlink($store);
mkdir($store);
$nb_file=count($a_file);
for($i=0;$i < $nb_file;$i++)
{
$filename=sprintf("%s".DIRECTORY_SEPARATOR."%s",
$store,
$a_file[$i]['js_filename']);
// avoid to overwrite a previous file with same name
if (file_exists($filename)) {
$dup=1;
do {
$filename=sprintf("%s".DIRECTORY_SEPARATOR."%s-%s",
$store,
$dup,
$a_file[$i]['js_filename']);
$dup++;
}while ( file_exists($filename));
}
$cn->lo_export($a_file[$i]['js_lob'], $filename);
$a_file_dwn[]=$filename;
}
$cn->commit();
// zip the folder
$zip = new Zip_Extended();
$zip_file=sprintf("%s".DIRECTORY_SEPARATOR."%s.zip"
,$store
,$jr_internal);
chdir($store);
$res=$zip->open($zip_file, ZipArchive::CREATE);
foreach ($a_file_dwn as $item)
{
$zip->addFile(basename($item));
}
$zip->close();
// send the folder to browser
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="document-'.$jr_internal.'.zip"');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
echo file_get_contents($zip_file);
} catch (Exception $exc) {
record_log($exc);
}
}

View file

@ -0,0 +1,68 @@
<?php
/*
* This file is part of NOALYSS.
*
* NOALYSS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* NOALYSS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOALYSS; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
/**
* @file
* @brief display form to add supplemental files to an operation
* var $gDossier (int) dossier
* var $jr_id (int) jrn.jr_id operation
* var $cn (Database) database cnx
* var $dgbox name of the dgbox
* var $div is the DIV
* supplement_div_list<?=$div?> list of files to update after uploading
*/
$dgbox=$http->request("dgbox");
$form_id="save_file{$div}";
$progress="progress{$div}";
$max_post_size=convert_ini_unit(ini_get("post_max_size"));
echo \HtmlInput::title_box(_("Ajout de fichier"), $dgbox);
?>
<div class="p-1">
<p>
<?=_("Ajouter des fichiers à cette opération")?>
</p>
<FORM method="POST" enctype="multipart/form-data" onsubmit="return false" id="<?=$form_id?>">
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="<?= MAX_FILE_SIZE ?>">
<input type="hidden" id="post_max_size" name="post_max_size" value="<?= $max_post_size ?>">
<?=\HtmlInput::hidden("jr_id",$jr_id)?>
<?=\HtmlInput::hidden("gDossier",$gDossier)?>
<?=\HtmlInput::hidden("op","ledger")?>
<?=\HtmlInput::hidden("act","save_file")?>
<?=\HtmlInput::hidden("div",$div)?>
<?=\HtmlInput::hidden("dgbox",$dgbox)?>
<input type="FILE" name="document_supplemental[]" id="doc_sup" multiple>
<div id="feedback<?=$div?>"></div>
<ul class="aligned-block">
<li>
<input type='SUBMIT' class="smallbutton" name="upload" value="<?=_("Sauve")?>" onclick="return Supplement_Document.save_file('<?=$form_id?>');">
</li>
<li>
<?=\HtmlInput::button_close($dgbox)?>
</li>
</ul>
</FORM>
<progress style="height:auto;width: 100%;appearance: none;" id="progress_upload1b" max="100" value="0"></progress>
</div>

View file

@ -44,6 +44,7 @@ $a_tab['linked_operation_div']=array('id'=>'linked_operation_div'.$div,'label'=>
$a_tab['document_operation_div']=array('id'=>'document_operation_div'.$div,'label'=>_('Document').'('.$nb_document.')','display'=>'block');
$a_tab['linked_action_div']=array('id'=>'linked_action_div'.$div,'label'=>_('Actions Gestion').'('.count($a_followup).')','display'=>'none');
$a_tab['analytic_div']=array('id'=>'analytic_div'.$div,'label'=>_('Comptabilité Analytique'),'display'=>'none');
$a_tab['supplemental_doc_div']=array('id'=>'supplemental_doc_div'.$div,'label'=>_('Documents supplémentaires'),'display'=>'none');
//var $g_parameter \Noalyss_Parameter_Folder
global $g_parameter;
@ -293,9 +294,17 @@ echo '</div>';
?>
<?php
//------------------------------------------------
// Receipt
//------------------------------------------------
require_once NOALYSS_TEMPLATE.'/ledger_detail_file.php';
?>
<?php
//------------------------------------------------
// Receipt
//------------------------------------------------
require_once NOALYSS_TEMPLATE."/ledger_detail_sup_files.php";
?>
<div id="analytic_div<?php echo $div;?>" style="overflow:auto;display:<?php echo $a_tab['analytic_div']['display']?>">

View file

@ -0,0 +1,91 @@
<?php
/*
* This file is part of NOALYSS.
*
* NOALYSS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* NOALYSS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOALYSS; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
/**
* @file
* @brief show supplemental files and let you add one
@var $jr_id (int) JRN.JR_ID (inherited)
// @var $cn (Database) current conx
// @var $gDossier (int) folder id
*/
?>
<div id="supplemental_doc_div<?php echo $div;?>" class="myfieldset noprint" style="display:<?php echo $a_tab['supplemental_doc_div']['display']?>">
<div id="supplement_div_list<?=$div?>">
<?php
/**
* show existing supplemental files for this operation
*/
$q=new Jrn_Sup_Document_SQL($cn);
$a_row=$q->collect_objects(" where jr_id=$1 order by js_cbc_id", [$jr_id]);
$javascript=sprintf("Supplement_Document.input_file('%s','%s','%s')",
$gDossier,
$div,
$jr_id);
if ( count($a_row) > 0)
{
foreach ($a_row as $item) {
$export="export.php?";
$script="Supplement_Document.delete_document('$gDossier','$div','{$item->js_id}','$jr_id')";
$rowid=sprintf("row_js_%s_%s",$div,$item->js_id);
// @var $download (url) to send file
$download="export.php?". http_build_query(
[
"act"=>"RAW:suppl-document"
,"js_id"=>$item->js_id
,"gDossier"=>$gDossier
]);
?>
<div class="row" id="<?=$rowid?>">
<div class="col">
<a href="<?=$download?>" download> <?=$item->js_filename?></a>
</div>
<div class="col">
<?=$item->js_description?>
</div>
<div class="col">
<?=\Icon_Action::trash(uniqid("sdd"),$script)?>
</div>
</div>
<?php
}// end foreach $a_row
}// end if count
//download ALL files from this operation
$download="export.php?". http_build_query(
[
"act"=>"RAW:suppl-document"
,"js_id"=>0
,"gDossier"=>$gDossier
,'operation_id'=>$jr_id
]);
?>
<a href="<?=$download?>" download=""><?=_("Télécharger tous les documents")?>
</a>
</div>
<ul class="aligned-block">
<li>
<?=\HtmlInput::button_action(_("Ajout fichier"), $javascript);?>
</li>
</ul>
</div>

View file

@ -303,7 +303,7 @@ comment on sequence seq_doc_type_stdinv is 'Sequence for standard invoice';
INSERT INTO public.menu_ref (me_code, me_menu, me_file, me_url, me_description, me_parameter, me_javascript, me_type, me_description_etendue)
VALUES('RAW:xml-invoice', 'Exporte la facture XML', 'export_xml-invoice.php', NULL, 'export la facture électronique en XML', NULL, NULL, 'PR', NULL);
VALUES('RAW:xml-invoice', 'Exporte la facture XML', 'export_xml-invoice.php', NULL, 'exporte la facture électronique en XML', NULL, NULL, 'PR', NULL);
insert into profile_menu (me_code,p_id, p_type_display) select 'RAW:xml-invoice',p_id,'P' from profile;
@ -491,4 +491,11 @@ COMMENT ON COLUMN public.jrn_sup_document.js_mimetype IS 'Mimetype';
COMMENT ON COLUMN public.jrn_sup_document.js_lob IS 'OID';
COMMENT ON COLUMN public.jrn_sup_document.jr_id IS 'FK to jrn';
COMMENT ON COLUMN public.jrn_sup_document.js_description IS 'Description of document';
COMMENT ON COLUMN public.jrn_sup_document.js_cbc_id IS 'ID in XML';
COMMENT ON COLUMN public.jrn_sup_document.js_cbc_id IS 'ID in XML';
INSERT INTO public.menu_ref (me_code, me_menu, me_file, me_url, me_description, me_parameter, me_javascript, me_type, me_description_etendue)
VALUES('RAW:suppl-document', 'Exporte Document supplementaire', 'export_suppl-document.php', NULL, 'télécharge le document supp', NULL, NULL, 'PR', NULL);
insert into profile_menu (me_code,p_id, p_type_display) select 'RAW:suppl-document',p_id,'P' from profile;