altocompta/include/class/tva_rate_mtable.class.php

497 lines
21 KiB
PHP

<?php
/*
* This file is part of NOALYSS.
*
* PhpCompta 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 PhpCompta; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright (2018) Author Dany De Bontridder <dany@alchimerys.be>
/**
* @file
* @brief Configure the tva : code , rate, label ...
*/
require_once NOALYSS_INCLUDE."/database/v_tva_rate_sql.class.php";
require_once NOALYSS_INCLUDE."/database/tva_rate_sql.class.php";
/**
* @class Tva_Rate_MTable
* @brief Configure the tva : code , rate, label ...
* When using Manage_Table_SQL
*/
class Tva_Rate_MTable extends Manage_Table_SQL
{
//!< previous tva_id, used to know if we update or insert,
private $previous_id;
private $a_comment; //!< Supplemental explanation
/**
*
* @param V_Tva_rate_SQL $p_table
* @example tva_parameter.php
*/
function __construct(V_Tva_rate_SQL $p_table)
{
parent::__construct($p_table);
$this->icon_mod='left';
$this->set_col_label("tva_id", _("id"));
$this->set_col_label("tva_code", _("Code"));
$this->set_col_label("tva_label", _("label"));
$this->set_col_label("tva_rate", _("taux"));
$this->set_col_label("tva_comment", _("Description"));
$this->set_col_label("tva_both_side", _("Autoliquidation"));
$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 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);
$this->set_col_type("tva_both_side", "select",
array(
["value"=>0, "label"=>_("Non")],
["value"=>1, "label"=>_("Oui")]
));
$this->set_col_type("tva_reverse_account", 'custom');
$this->set_property_updatable("tva_id", true);
$this->set_col_label("tva_payment_purchase",_("Exigible achat"));
$this->set_col_type("tva_payment_purchase","select",
array(
array("value"=>'O',"label"=>"Opération"),
array("value"=>'P',"label"=>"Paiement")
)
);
$this->set_col_label("tva_payment_sale",_("Exigible vente"));
$this->set_col_type("tva_payment_sale","select",
array(
array("value"=>'O',"label"=>"Opération"),
array("value"=>'P',"label"=>"Paiement")
)
);
$this->a_info=[
"tva_purchase"=>44,"tva_both_side"=>43,"tva_sale"=>45
,"tva_payment_sale"=>74,"tva_payment_purchase"=>74,'tva_reverse_account'=>88];
$this->previous_id=null;
$this->a_comment=array(
'tva_purchase'=>_("Ne donnez pas ce poste comptable si ce code n'est pas utilisé à l'achat"),
'tva_both_side'=>_("Autoliquidation : Utilisé en même temps au crédit et au débit"),
'tva_sale'=>_("Ne donnez pas ce poste comptable si ce code n'est pas utilisé à la vente"),
'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"),
'vx_code'=>_("Code exemption pour facture PEPPOL (ubl)")
);
}
/**
* @return int or null
*/
public function getPreviousId()
{
return $this->previous_id;
}
/**
*
* @param int $previous_id
*/
public function setPreviousId($previous_id): Tva_Rate_MTable
{
$this->previous_id = $previous_id;
return $this;
}
/**
* @brief display into a dialog box the datarow in order
* to be appended or modified. Can be override if you need
* a more complex form
*/
function input()
{
$nb_order=count($this->a_order);
$this->set_property_visible('tva_reverse_account', true);
$this->set_property_visible('tva_peppol_code', true);
echo "<table>";
for ($i=0; $i<$nb_order; $i++)
{
echo "<tr>";
$key=$this->a_order[$i];
$label=$this->a_label_displaid[$key];
$value=$this->table->get($key);
$error=$this->get_error($key);
$error=($error=="")?"":HtmlInput::errorbulle($error);
if ($this->get_property_visible($key)===TRUE)
{
$info="";
if ( isset($this->a_info[$key])) {
$info=Icon_Action::infobulle($this->a_info[$key]);
}
// Label
echo "<td> {$label} {$info} {$error}</td>";
if ($this->get_property_updatable($key)==TRUE)
{
echo "<td>";
if ($this->a_type[$key]=="select")
{
$select=new ISelect($key);
$select->value=$this->a_select[$key];
$select->selected=$value;
echo $select->input();
}
elseif ($key=="tva_rate")
{
$text=new INum($key);
$text->value=$value;
$text->prec=4;
$min_size=(strlen($value??"")<10)?10:strlen($value)+1;
$text->size=$min_size;
echo $text->input();
}
elseif ($key=='tva_purchase')
{
$text=new IPoste("tva_purchase");
$text->value=$value;
$min_size=10;
$text->size=$min_size;
$text->set_attribute('gDossier', Dossier::id());
$text->set_attribute('jrn', 0);
$text->set_attribute('account', 'tva_purchase');
echo $text->input();
$url="do.php?".http_build_query(array("gDossier"=>Dossier::id(),"ac"=>'C0PCMN','p_start'=>4));
echo HtmlInput::anchor(_("Configuration poste comptable"),$url,"",'target="_blank"');
}
elseif ($key=='tva_sale')
{
$text=new IPoste("tva_sale");
$text->value=$value;
$min_size=10;
$text->set_attribute('gDossier', Dossier::id());
$text->set_attribute('jrn', 0);
$text->set_attribute('account', 'tva_sale');
$text->size=$min_size;
echo $text->input();
}elseif ($key=='tva_peppol_code') {
$text=new ISelect('tva_peppol_code');
$text->selected=$value;
$text->transform(array(
null=>_('-')
,"S"=>_('S Taux standard')
,'AE'=>_('AE Autoliquidate mais pas INTRACOMM.')
,'Z'=>_("Z TVA à 0%")
,'K'=>_('K Autoliquidation INTRACOMM.')
,'G'=>_('G TVA exempt pour export hors Europe')
,'O'=>_('O TVA Hors périmètre application')
,'E'=>_('E Exempté de TVA')
));
echo $text->input();
} 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);
} elseif ($key=='tva_reverse_account')
{
$text=new IPoste("tva_reverse_account");
$text->value=$value;
$min_size=10;
$text->set_attribute('gDossier', Dossier::id());
$text->set_attribute('jrn', 0);
$text->set_attribute('account', 'tva_reverse_account');
$text->size=$min_size;
echo $text->input();
}elseif ($this->a_type[$key]=="text")
{
$text=new IText($key);
$text->value=$value;
$min_size=(strlen($value??"")<30)?30:strlen($value)+5;
$text->size=$min_size;
echo $text->input();
}
echo "</td>";
}
else
{
printf('<td>%s %s</td>', h($value),
HtmlInput::hidden($key, $value)
);
}
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>';
}
echo "</tr>";
}
echo "</table>";
}
/**
* @brief add the TVA_REVERSE_ACCOUNT
* @return void
*/
function from_request()
{
parent::from_request();
$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');
}
/**
* @brief save the data in TVA_RATE
* if tva_both_side is 1 and tva_purchase or tva_sale is empty then
it is equal to the other value
*
*/
function save()
{
if ( $this->previous_id === null ) {
throw new \Exception ("TVA184: no previous TVA id");
}
$cn=Dossier::connect();
// if tva_both_side is 1 and tva_purchase or tva_sale is empty then
// it is equal to the other value
if ($this->table->tva_both_side==1)
{
if ($this->table->tva_purchase=="#"||trim($this->table->tva_purchase)
=="#")
{
$this->table->tva_purchase=$this->table->tva_sale;
}
if ($this->table->tva_sale=="#"||trim($this->table->tva_sale)=="#")
{
$this->table->tva_sale=$this->table->tva_purchase;
}
}
$new_tva_id=$this->table->tva_id;
$tva_rate=new Tva_rate_SQL($cn);
$tva_rate->setp("tva_id",$new_tva_id);
$tva_rate->setp("tva_rate", $this->table->tva_rate);
$tva_rate->setp("tva_code", $this->table->tva_code);
$tva_rate->setp("tva_label", $this->table->tva_label);
$tva_rate->setp("tva_comment", $this->table->tva_comment);
$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;
$tva_sale=(trim($this->table->tva_sale)=="")?"#":$this->table->tva_sale;
$tva_rate->setp("tva_poste", $tva_purchase.",".$tva_sale);
$tva_rate->setp("tva_payment_sale", $this->table->tva_payment_sale);
$tva_rate->setp("tva_payment_purchase", $this->table->tva_payment_purchase);
if ( $this->previous_id == -1 ) {
$tva_rate->insert();
} else {
$tva_rate->update();
}
if ( $this->previous_id != - 1 && $this->previous_id != $new_tva_id) {
$cn->exec_sql("update tva_rate set tva_id = $1 where tva_id = $2",[$new_tva_id,$this->previous_id]);
$this->table->setp("tva_id",$new_tva_id);
}else {
$this->table->setp("tva_id",$tva_rate->getp("tva_id"));
}
}
/**
* @brief Check data are valid
* 1. tva_rate between 0 & 1
* 2. label is uniq
* 3. accounting must exist
* @return boolean
*/
function check()
{
global $g_parameter;
$cn=Dossier::connect();
if ( $this->previous_id === null ) {
throw new \Exception ("TVA184: no previous TVA id");
}
// both accounting can not be empty
if (trim($this->table->tva_purchase??"")==""&&trim($this->table->tva_sale??"")=="")
{
$this->set_error("tva_purchase",
_("Les 2 postes comptables ne peuvent être nuls"));
$this->set_error("tva_sale",
_("Les 2 postes comptables ne peuvent être nuls"));
}
// Check the tva rate
if (trim($this->table->tva_rate??"")==""||isNumber($this->table->tva_rate)==0||$this->table->tva_rate>1)
{
$this->set_error("tva_rate", _("Taux de TVA invalide"));
}
//Check the label must be unique
$count=$cn->get_value("select count(*) from tva_rate where tva_id<>$1 and lower(tva_label)=lower($2)",
[$this->getPreviousId(), $this->table->tva_label]);
if ($count>0)
{
$this->set_error("tva_label", _("Ce nom est déjà utilisé"));
}
// Check accounting exists for purchase
if (trim($this->table->tva_purchase??"")!=""&&$this->table->tva_purchase!="#")
{
$count=$cn->get_value("select count(*) from tmp_pcmn where pcm_val = $1",
[$this->table->tva_purchase]);
if ($count==0)
{
$this->set_error("tva_purchase", _("Poste comptable inexistant"));
}
}
// Check accounting exists for sale
if (trim($this->table->tva_sale??"")!=""&&$this->table->tva_sale!="#")
{
$count=$cn->get_value("select count(*) from tmp_pcmn where pcm_val = $1",
[$this->table->tva_sale]);
if ($count==0)
{
$this->set_error("tva_sale", _("Poste comptable inexistant"));
}
}
// check if tva_both_side is valid
if ($this->table->tva_both_side!=0&&$this->table->tva_both_side!=1)
{
$this->set_error("tva_both_side", _("Choix incorrect"));
}
$flag = true;
// Check that tva_id is a integer not a float (TVA_ID is an integer)
if ( isNumber($this->table->tva_id) == 0 || $this->table->tva_id != round($this->table->tva_id) )
{
$this->set_error("tva_id",_("Valeur invalide"));
$flag=false;
}
// Check if old tva_id was not overwritting something
if ( $flag && $this->previous_id != $this->table->tva_id && $cn->get_value("select count(*) from tva_rate where tva_id=$1",[$this->table->tva_id]) > 0)
{
$this->set_error("tva_id",_("Code TVA déjà utilisé"));
}
// Check that tva code is unique and remove not letter
$this->table->tva_code=strtoupper(trim( $this->table->tva_code));
$tva_code=$this->table->tva_code;
$tva_code=strtoupper($tva_code);
$tva_code=preg_replace("/[A-Z]/", "", $tva_code);
$tva_code=preg_replace("/[0-9]/", "", $tva_code);
if (strlen($tva_code)>0){
$this->set_error("tva_code", _("code tva : Uniquement des chiffres et des lettres"));
}
if (strlen($this->table->tva_code)>5){
$this->set_error("tva_code", _("code tva : Maximum 5 caractères"));
}
if (isNumber($this->table->tva_code) == 1){
$this->set_error("tva_code", _("code tva : doit aussi contenir des lettres"));
}
/**
* auto reverse VAT : check that the accounting is used
*/
if ( $this->table->tva_both_side==0 && trim($this->table->tva_reverse_account??"") != "")
{
$this->set_error("tva_reverse_account", _("Pas d'autoliquidation demandé"));
}
if ( $this->table->tva_both_side==1 && trim($this->table->tva_reverse_account??"") != "")
{
$count=$cn->get_value("select count(*) from tmp_pcmn where pcm_val = $1",
[$this->table->tva_reverse_account]);
if ($count==0)
{
$this->set_error("tva_reverse_account", _("Poste comptable inexistant"));
}
}
// label cannot be empty
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 ( $g_parameter->MY_INVOICE_FORMAT == 'UBL21BE' && 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 ( $g_parameter->MY_INVOICE_FORMAT == 'UBL21BE' && 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 ( $g_parameter->MY_INVOICE_FORMAT == 'UBL21BE'
&& ! 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;
}
/**
* delete if not used anywhere
*/
function delete()
{
$cn=Dossier::connect();
$count_purchase=$cn->get_value("select count(*) from quant_purchase where qp_vat_code = $1",[$this->table->tva_id]);
$count_sale=$cn->get_value("select count(*) from quant_sold where qs_vat_code = $1",[$this->table->tva_id]);
if ( $count_purchase > 0 || $count_sale > 0) {
throw new Exception(_("Effacement interdit : TVA utilisée"));
}
// Forbid to remove all tva
$count=$cn->get_value("select count(*) from tva_rate");
if ( $count < 2) {
throw new Exception(_("Vous ne pouvez pas effacer tous les taux. Si votre société n'utilise pas la TVA, changer dans le menu société"));
}
$cn->exec_sql("delete from tva_rate where tva_id=$1", [$this->table->tva_id]);
}
}