Merge branch '251029-einvoice' into unstable
* 251029-einvoice: QuickCode : default = base for accounting + card name Cosmetic : set layer correctly ICARD: improve, action in javascript after cleaning the input of the qcode VAT : fix bug when VAT not usable for ledger or purchase cosmetic : padding inner_box COSMETIC: z-index computed properly for managetable and search_account FIX : problem with VAT SELECT: cannot update the right DOMID E-INVOICE : VATEX filter on the country E-INVOICE : add VATEX CODE in C0VAT E-INVOICE vatex code check when computing an invoice Improve SELECT_BOX PHP8.2 deprecated: dynamic properties + cosmetic menu Code improvement and ergonomy for menu display e-invoice : import creditNote and create a PDF use protected instead of private, remove debug info e-invoice : make a PDF with credit note Supplementary documents for an operation, an operation can have several attached documents Improve: message for uploading , compute ini value and color red for the trash can E-INVOICE extract all documents from XML and store in DB E-INVOICE: Peppol id is used to compose the UBL21, improve check and use
This commit is contained in:
commit
64c42b1c20
67 changed files with 2647 additions and 707 deletions
|
|
@ -314,76 +314,61 @@ class Acc_Document extends Document {
|
|||
jr_id=$2",
|
||||
[$oid,$this->d_id]);
|
||||
|
||||
$xmlreader= XMLInvoice_Reader::build_from_file($a_file['filename']);
|
||||
$xmlreader= \Noalyss\XMLDocument\XML_Reader::build_from_file($a_file['filename']);
|
||||
|
||||
//@var $embedded_file (array) keys = filecontent: binary data
|
||||
//,mimecode mimetype and filename (string)
|
||||
try
|
||||
{
|
||||
$embedded_file=$xmlreader->get_embedded_document();
|
||||
if ($embedded_file == false)
|
||||
{
|
||||
$embedded_file=array();
|
||||
// create a PDF with standard information
|
||||
$pdf=$xmlreader->to_pdf($this->db);
|
||||
$file_oid=$this->db->lo_write($pdf->Output("S"));
|
||||
$embedded_file['filename']="invoice.pdf";
|
||||
$embedded_file['mimecode']="application/pdf";
|
||||
}
|
||||
else
|
||||
{
|
||||
$file_oid=$this->db->lo_write($embedded_file['filecontent']);
|
||||
if ( $file_oid == false )
|
||||
{
|
||||
// create a PDF with standard information
|
||||
$pdf=$xmlreader->to_pdf($this->db);
|
||||
$file_oid=$this->db->lo_write($pdf->Output("S"));
|
||||
}
|
||||
}
|
||||
|
||||
// create a PDF with standard information
|
||||
$pdf=$xmlreader->to_pdf($this->db);
|
||||
$file_oid=$this->db->lo_write($pdf->Output("S"));
|
||||
|
||||
//@var $file_oid OID of the large object saved in DB
|
||||
$this->d_name="invoice.pdf";
|
||||
$this->d_description="Auto generated invoice";
|
||||
$this->d_lob=$file_oid;
|
||||
$this->d_mimetype="application/pdf";
|
||||
|
||||
// save extracted document into DB
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_id=$4",
|
||||
array(
|
||||
$this->d_lob
|
||||
, $this->d_name
|
||||
, $this->d_description
|
||||
, $this->d_id
|
||||
)
|
||||
);
|
||||
// save all the documents into the DB
|
||||
// @var embedded_file (array of Noalyss\XML\Document_Reference)
|
||||
$embedded_file=$xmlreader->get_embedded_document();
|
||||
$nb_file = count($embedded_file);
|
||||
for ($i=0;$i <$nb_file ; $i++)
|
||||
{
|
||||
// other documents save in jrn_sup_document
|
||||
// @var $file (Binary File from XML)
|
||||
$binary=$embedded_file[$i]->getBinary_object();
|
||||
|
||||
//@var $sup_oid : oid of the supplemental
|
||||
$sup_oid=$this->db->lo_write($binary->filecontent);
|
||||
|
||||
$jrn_sup_document=new Jrn_Sup_Document_SQL($this->db);
|
||||
$jrn_sup_document->jr_id=$this->d_id;
|
||||
$jrn_sup_document->js_mimetype=$binary->mimecode;
|
||||
$jrn_sup_document->js_filename=$binary->filename;
|
||||
$jrn_sup_document->js_lob=$sup_oid;
|
||||
$jrn_sup_document->js_description=$embedded_file[$i]->getDescription();
|
||||
$jrn_sup_document->js_cbc_id=$embedded_file[$i]->getId();
|
||||
$jrn_sup_document->save();
|
||||
}
|
||||
|
||||
$this->d_name=$embedded_file['filename'];
|
||||
$this->d_description=$embedded_file['filename'];
|
||||
$this->d_lob=$file_oid;
|
||||
$this->d_mimetype=$embedded_file['mimecode'];
|
||||
// save extracted document into DB
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_id=$4",
|
||||
array(
|
||||
$this->d_lob
|
||||
, $this->d_name
|
||||
, $this->d_description
|
||||
, $this->d_id
|
||||
)
|
||||
);
|
||||
return $file_oid;
|
||||
} catch (\Exception $e ) {
|
||||
\record_log($e);
|
||||
// if exception is not too many document or document corrupted
|
||||
// then rethrow the exception
|
||||
if ( !in_array(e->getCode(),[110,116]) )
|
||||
{
|
||||
throw new \Exception("X281 ",281,$e);
|
||||
}
|
||||
throw new \Exception("X281 ",281,$e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// save new document
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_id=$4",
|
||||
array(
|
||||
$oid
|
||||
, $_FILES['pj']['name']
|
||||
, $_FILES['pj']['type']
|
||||
, $this->d_id
|
||||
)
|
||||
);
|
||||
$this->d_name=$_FILES['pj']['name'];
|
||||
$this->d_description=$_FILES['pj']['name'];
|
||||
$this->d_lob=$oid;
|
||||
$this->d_mimetype=$_FILES['pj']['type'];
|
||||
$this->db->commit();
|
||||
|
||||
return $oid;
|
||||
|
|
@ -410,5 +395,42 @@ class Acc_Document extends Document {
|
|||
.'</a>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
static function display_supplementary_doc($cn,$div,$jr_id)
|
||||
{
|
||||
$gDossier=\Dossier::id();
|
||||
$q=new Jrn_Sup_Document_SQL($cn);
|
||||
$a_row=$q->collect_objects(" where jr_id=$1 order by js_cbc_id", [$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>O
|
||||
<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
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1113,7 +1113,6 @@ class Acc_Ledger extends jrn_def_sql
|
|||
|
||||
$quick_code->value=(isset(${'qc_'.$i}))?${'qc_'.$i}:"";
|
||||
$quick_code->readonly=$p_readonly;
|
||||
|
||||
$label='';
|
||||
if ($quick_code->value!='')
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1492,6 +1492,7 @@ class Acc_Ledger_Purchase extends Acc_Ledger
|
|||
$W1->name="e_march".$i;
|
||||
$W1->value=$march;
|
||||
$W1->table=0;
|
||||
$W1->setAfter_clean("compute_all_ledger()");
|
||||
$W1->set_dblclick("fill_ipopcard(this);");
|
||||
$W1->set_attribute('ipopup','ipopcard');
|
||||
|
||||
|
|
|
|||
|
|
@ -1623,6 +1623,7 @@ EOF;
|
|||
$W1->name = "e_march" . $i;
|
||||
$W1->value = $march;
|
||||
$W1->table = 0;
|
||||
$W1->setAfter_clean("compute_all_ledger()");
|
||||
$W1->set_attribute('typecard', 'cred');
|
||||
$W1->set_dblclick("fill_ipopcard(this);");
|
||||
$W1->set_attribute('ipopup', 'ipopcard');
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ class Acc_Ledger_Search
|
|||
$f_qcode->javascript=sprintf(' onchange="fill_data_onchange(%s);" ',
|
||||
$f_qcode->name);
|
||||
$f_qcode->value=$http->request($this->div.'qcode',"string","");
|
||||
|
||||
$f_qcode->setAfter_clean("");
|
||||
/* $f_txt_qcode=new IText('qcode');
|
||||
$f_txt_qcode->value=(isset($_REQUEST['qcode']))?$_REQUEST['qcode']:'';
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"comment"=>"tva_comment",
|
||||
"account"=>"tva_poste"
|
||||
tva_peppol_code
|
||||
'vx_code'
|
||||
* );
|
||||
|
||||
*/
|
||||
|
|
@ -45,7 +46,9 @@ class Acc_Tva
|
|||
"both_side"=>'tva_both_side',
|
||||
'tva_reverse_account'=>'tva_reverse_account',
|
||||
'tva_code'=>'tva_code',
|
||||
"tva_peppol_code"=>"tva_peppol_code"
|
||||
"tva_peppol_code"=>"tva_peppol_code",
|
||||
'vx_code'=>'vx_code'
|
||||
|
||||
);
|
||||
public $tva_id,
|
||||
$tva_label,
|
||||
|
|
@ -55,7 +58,8 @@ class Acc_Tva
|
|||
$tva_both_side,
|
||||
$tva_code,
|
||||
$tva_reverse_account,
|
||||
$tva_peppol_code
|
||||
$tva_peppol_code,
|
||||
$vx_code
|
||||
;
|
||||
|
||||
private $cn; //!< Database connection
|
||||
|
|
@ -75,6 +79,7 @@ class Acc_Tva
|
|||
$this->tva_code=&$this->tva_rate_sql->tva_code;
|
||||
$this->tva_reverse_account=&$this->tva_rate_sql->tva_reverse_account;
|
||||
$this->tva_peppol_code=&$this->tva_rate_sql->tva_peppol_code;
|
||||
$this->vx_code=&$this->tva_rate_sql->vx_code;
|
||||
|
||||
}
|
||||
/**
|
||||
|
|
@ -110,7 +115,7 @@ class Acc_Tva
|
|||
{
|
||||
$idx=self::$variable[$p_string];
|
||||
$this->$idx=$p_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Exception("ACC108"."Attribut inexistant $p_string",EXC_INVALID);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ class Anc_Balance_Double extends Anc_Print
|
|||
*
|
||||
* \return string
|
||||
*/
|
||||
|
||||
public $from_poste2;
|
||||
public $to_poste2;
|
||||
public $pa_id2;
|
||||
function display_html ()
|
||||
{
|
||||
if ($this->pa_id == $this->pa_id2) throw new Exception(_("Pas de croisement avec un seul plan"),1000);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@
|
|||
|
||||
class Anc_Table extends Anc_Acc_Link
|
||||
{
|
||||
public $card_poste;
|
||||
private $aheader;
|
||||
private $sql;
|
||||
private $arow;
|
||||
function __construct($p_cn)
|
||||
{
|
||||
parent::__construct($p_cn);
|
||||
|
|
|
|||
|
|
@ -224,12 +224,25 @@ class Card_Property
|
|||
}
|
||||
|
||||
if ($this->ad_id == ATTR_DEF_TVA) {
|
||||
$result['input'] = new ITva_Popup('popup_tva');
|
||||
$result['input'] = new ITva_Popup( "av_text" . $this->ad_id);
|
||||
$result['input']->table = 0;
|
||||
$result['input']->value = $this->av_text;
|
||||
$result['label']=$this->ad_text;
|
||||
return $result;
|
||||
}
|
||||
// Warning length quickcode
|
||||
if ($this->ad_id == ATTR_DEF_QUICKCODE) {
|
||||
$result['input'] = new IText();
|
||||
$result['input']->css_size = "100%";
|
||||
$result['input']->label = $this->ad_text;
|
||||
$result['input']->name = "av_text" . $this->ad_id;
|
||||
$result['input']->value = $this->av_text;
|
||||
$result['input']->placeholder= "999NOM";
|
||||
$result['bulle'] = Icon_Action::warnbulle(76);
|
||||
$result['label']=$this->ad_text;
|
||||
return $result;
|
||||
}
|
||||
|
||||
switch ($this->ad_type) {
|
||||
case 'text':
|
||||
$result['input'] = new IText();
|
||||
|
|
@ -303,10 +316,7 @@ class Card_Property
|
|||
$result['bulle'] = Icon_Action::infobulle(21);
|
||||
}
|
||||
|
||||
// Warning length quickcode
|
||||
if ($this->ad_id == ATTR_DEF_QUICKCODE) {
|
||||
$result['bulle'] = Icon_Action::warnbulle(76);
|
||||
}
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -524,6 +524,16 @@ class Fiche
|
|||
{
|
||||
$p_array["av_text".ATTR_DEF_QUICKCODE]="";
|
||||
}
|
||||
// by default the quick_code is the base account of the class + first letters of the name
|
||||
if ( $p_array["av_text".ATTR_DEF_QUICKCODE] =="")
|
||||
{
|
||||
$base_acc=$this->cn->get_value("select fd_class_base from fiche_def where fd_id = $1",
|
||||
[$p_fiche_def]);
|
||||
$p_array["av_text".ATTR_DEF_QUICKCODE]=sprintf("%s%s"
|
||||
, substr($base_acc,0, 3)
|
||||
, substr($p_array["av_text".ATTR_DEF_NAME], 0, 4)
|
||||
);
|
||||
}
|
||||
$sql=sprintf("select insert_quick_code(%d,'%s')", $fiche_id,
|
||||
sql_string($p_array['av_text'.ATTR_DEF_QUICKCODE]));
|
||||
$this->cn->exec_sql($sql);
|
||||
|
|
@ -553,9 +563,9 @@ class Fiche
|
|||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
record_log("FIC603".$e->getMessage()." ".$e->getTraceAsString());
|
||||
record_log($e);
|
||||
$this->cn->rollback();
|
||||
throw ($e);
|
||||
throw (new \Exception ("F561 ". __CLASS__.".".__FUNCTION__,561,$e));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ EOF;
|
|||
/**
|
||||
* @brief Display each row for the global
|
||||
* @param $obj Parm_Periode_SQL
|
||||
* @param $p_nb not used so far
|
||||
* @param $p_nb used to highlight odd rows
|
||||
* @param $p_js javascript variable
|
||||
*/
|
||||
static function display_row_global(Parm_Periode_SQL $obj, $p_nb, $p_js)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
$this->set_col_label("tva_reverse_account", _('Poste comptable autoliquidation'));
|
||||
$this->set_col_label("tva_sale", _("TVA Vente (C)"));
|
||||
$this->set_col_label("tva_purchase", _("TVA Achat (D)"));
|
||||
$this->set_col_label("tva_peppol_code", _("Code Facture électronique"));
|
||||
$this->set_col_label("tva_peppol_code", _("Code Facture électronique UBL"));
|
||||
$this->set_col_label("vx_code", _("Code Exemption TVA (vatex)"));
|
||||
|
||||
$this->set_property_visible('tva_reverse_account', false);
|
||||
$this->set_property_visible('tva_peppol_code', false);
|
||||
|
|
@ -93,7 +94,8 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
'tva_payment_purchase'=>_('TVA due ou récupérable quand l\'opération est payée ou exécutée'),
|
||||
'tva_payment_sale'=>_('TVA due ou récupérable quand l\'opération est payée ou exécutée'),
|
||||
'tva_reverse_account'=>_("Forcer ce poste comptable pour autoliquidation : par défault, le poste d'autoliquidation est calculé : soit celui qui est en contrepartie, soit le même (voir manuel)"),
|
||||
'tva_peppol_code'=>_("Code TVA est utilisé pour les factures électroniques, plus d'information dans le manuel")
|
||||
'tva_peppol_code'=>_("Code TVA est utilisé pour les factures électroniques, plus d'information dans le manuel"),
|
||||
'vx_code'=>_("Code exemption pour facture PEPPOL (ubl)")
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -200,7 +202,19 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
,'E'=>_('E Exempté de TVA')
|
||||
));
|
||||
echo $text->input();
|
||||
}elseif ($key == "tva_id") {
|
||||
} elseif ($key == 'vx_code')
|
||||
{
|
||||
$text=\HtmlInput::hidden("vx_code",$value);
|
||||
echo $text;
|
||||
if ( $value !="") {
|
||||
$value= \Icon_Action::trash(uniqid(),"vat_code.select_value('xx')").$value;
|
||||
}
|
||||
echo span($value,'id="vx_value"');
|
||||
$js=sprintf("vat_code.list_vatex()");
|
||||
echo \Icon_Action::icon_magnifier(uniqid(),$js );
|
||||
|
||||
}
|
||||
elseif ($key == "tva_id") {
|
||||
$inum=new INum($key,$value);
|
||||
echo $inum->input();
|
||||
echo \HtmlInput::hidden("old_tva_id",$value);
|
||||
|
|
@ -231,9 +245,21 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
HtmlInput::hidden($key, $value)
|
||||
);
|
||||
}
|
||||
echo '<td class="text-muted">';
|
||||
echo '<td >';
|
||||
if (isset ($this->a_comment[$key])) {
|
||||
print '<p class="text-muted">';
|
||||
echo $this->a_comment[$key];
|
||||
print '</p>';
|
||||
}
|
||||
if( $key == 'vx_code') {
|
||||
echo '<span id="vx_code_description">';
|
||||
$row=$this->table->cn->get_row("select vx_code,vx_code_name,vx_description,vx_remark from vatex_code where vx_code=$1",
|
||||
[$value]);
|
||||
if ( ! empty ($row)) {
|
||||
echo $row['vx_description'].span($row['vx_remark'],' class="text-muted" ');
|
||||
|
||||
}
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</td>';
|
||||
}
|
||||
|
|
@ -252,6 +278,7 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
$http=new \HttpInput();
|
||||
$this->table->tva_reverse_account=$http->request('tva_reverse_account');
|
||||
$this->table->tva_peppol_code=$http->request('tva_peppol_code');
|
||||
$this->table->vx_code=$http->request('vx_code');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -290,6 +317,7 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
$tva_rate->setp("tva_both_side", $this->table->tva_both_side);
|
||||
$tva_rate->setp("tva_reverse_account", $this->table->tva_reverse_account);
|
||||
$tva_rate->setp("tva_peppol_code", $this->table->tva_peppol_code);
|
||||
$tva_rate->setp("vx_code", $this->table->vx_code);
|
||||
|
||||
// TVA accounting must be joined and separated with a comma
|
||||
$tva_purchase=(trim($this->table->tva_purchase)=="")?"#":$this->table->tva_purchase;
|
||||
|
|
@ -422,6 +450,23 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
if ( trim($this->table->tva_label??"")=="") {
|
||||
$this->set_error("tva_label", _('Le label ne peut être vide'));
|
||||
}
|
||||
|
||||
// if vatex is set then code invoice must be different from S and Z
|
||||
if ( trim($this->table->vx_code??"") != "" && in_array($this->table->tva_peppol_code,['S','Z'] ))
|
||||
{
|
||||
$this->set_error("vx_code",_("Le code d'exemption TVA ne peut être utilisé avec ce code Facture électronique UBL "));
|
||||
}
|
||||
// if vatex is set then code invoice must be different from S and Z
|
||||
if ( trim($this->table->vx_code??"") != "" && $this->table->tva_peppol_code=="")
|
||||
{
|
||||
$this->set_error("vx_code",_("Le code d'exemption TVA n' pas de sens sans code Facture électronique"));
|
||||
}
|
||||
// if tva_peppol_code is not S or Z then a VATEX code must be supplied
|
||||
if ( ! in_array($this->table->tva_peppol_code??"",["Z","S"]) && trim($this->table->vx_code??"" ) =="")
|
||||
{
|
||||
$this->set_error("vx_code",_("Un code d'exemption de TVA doit être fourni, voyez le manuel"));
|
||||
|
||||
}
|
||||
if ($this->count_error()!=0)
|
||||
return false;
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue