PEPPOL: allow to verify that the customer has is on PEPPOL (Belgium only)
This commit is contained in:
parent
81623d9c6f
commit
a1c59f6cf0
6 changed files with 460 additions and 4 deletions
|
|
@ -45,6 +45,7 @@ $http=new HttpInput();
|
|||
try {
|
||||
$op= $http->request("op");
|
||||
if ($op =='check_vatnumber') session_write_close();
|
||||
if ($op =='search_peppol') session_write_close();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
exit();
|
||||
|
|
@ -376,6 +377,8 @@ $path = array(
|
|||
, 'email_setting'=>'ajax_email_setting'
|
||||
// check iban number
|
||||
, 'check_ibannumber'=>'ajax_check_ibannumber'
|
||||
// related to peppol : search
|
||||
,'search_peppol'=>'ajax_search_peppol'
|
||||
) ;
|
||||
|
||||
if (array_key_exists($op, $path)) {
|
||||
|
|
|
|||
|
|
@ -417,8 +417,52 @@ category_card.check_ibannumber = function (p_domid) {
|
|||
console.error(e.message);
|
||||
}
|
||||
}
|
||||
category_card.search_peppol_participant=function(p_domid) {
|
||||
|
||||
/**
|
||||
* Display a dialog box to search the PEPPOL ID of someone
|
||||
* @parameter p_domid (string) ID of the DOM Element to update
|
||||
*/
|
||||
category_card.display_search_peppol = function (p_domid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dgbox = "peppol_id_search_div";
|
||||
waiting_box();
|
||||
var queryString = {
|
||||
op:'search_peppol'
|
||||
,ctl:p_domid
|
||||
}
|
||||
if (id$("peppol_id_search_div_frm")) {
|
||||
queryString['query']=$F("query");
|
||||
queryString['filter']=$F("filter");
|
||||
}
|
||||
|
||||
var action = new Ajax.Request(
|
||||
"ajax_misc.php",
|
||||
{
|
||||
method: 'GET',
|
||||
parameters: queryString,
|
||||
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_box', html: loading(), style: div_style, drag: false});
|
||||
$(dgbox).update( req.responseText);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (e)
|
||||
{
|
||||
alert_box(e.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-->
|
||||
|
||||
|
|
|
|||
217
include/ajax/ajax_search_peppol.php
Normal file
217
include/ajax/ajax_search_peppol.php
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
<?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 (2016) Author Dany De Bontridder <dany@alchimerys.be>
|
||||
|
||||
if (!defined('ALLOWED'))
|
||||
die('Appel direct ne sont pas permis');
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief search Peppol ID.
|
||||
*
|
||||
* Parameters :
|
||||
* - query : string to search
|
||||
* - ctl : DOMID to udpate (useless)
|
||||
* - filter: query on name , VAT id or Enterprise ID
|
||||
*/
|
||||
$http = new HttpInput();
|
||||
try {
|
||||
/* @var $query (string) string to search */
|
||||
$query = $http->request('query', 'string', '');
|
||||
|
||||
/* @$ctl_id (string) DOM ID of the element to update */
|
||||
$ctl_id = $http->request('ctl', 'string');
|
||||
|
||||
/* @filter (string) search on name, VAT ID or enterprise ID */
|
||||
$filter = $http->request('filter', 'string', '');
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @brief Found PEPPOL Elements, inner class
|
||||
*/
|
||||
class PEPPOL_Match_Record
|
||||
{
|
||||
|
||||
var $participantID;
|
||||
var array $docTypeID;
|
||||
var $entity;
|
||||
}
|
||||
|
||||
class PEPPOL_Entity_Record
|
||||
{
|
||||
var $name;
|
||||
var $countryCode;
|
||||
var $regDate;
|
||||
}
|
||||
$msg = _("La recherche par nom et numéro de TVA sont limitées à la Belgique");
|
||||
|
||||
echo \HtmlInput::title_box(_("Recherche PEPPOL Directory"), 'peppol_id_search_div');
|
||||
?>
|
||||
<div class="content">
|
||||
<form method="GET" id="peppol_id_search_div_frm" onsubmit="category_card.display_search_peppol('<?= $ctl_id ?>');return false;">
|
||||
<p class="text-muted">
|
||||
<?= $msg ?>
|
||||
</p>
|
||||
<?php
|
||||
echo \HtmlInput::hidden("op", "search_peppol");
|
||||
echo \HtmlInput::hidden("ctl_id", $ctl_id);
|
||||
|
||||
$input_query = new IText("query", $query);
|
||||
$select_filter = new ISelect("filter");
|
||||
$select_filter->transform(["vatid" => _("Numéro de TVA"), "entid" => _("Numéro entreprise"), "name" => _("Nom")]);
|
||||
$select_filter->selected = $filter
|
||||
?>
|
||||
<?= $select_filter->input() ?>
|
||||
<?= $input_query->input() ?>
|
||||
<ul class="aligned-block">
|
||||
<li>
|
||||
<?php
|
||||
echo \HtmlInput::submit("search", _("Chercher"));
|
||||
?>
|
||||
</li>
|
||||
<li>
|
||||
<?php
|
||||
echo \HtmlInput::button_close('peppol_id_search_div');
|
||||
?>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
<?php
|
||||
if (trim($query) == '')
|
||||
{
|
||||
echo '</div>'; // div class content
|
||||
return;
|
||||
}
|
||||
//------------------------------------------------
|
||||
// if a query has been submitted, show the result
|
||||
//------------------------------------------------
|
||||
$search = null;
|
||||
switch ($filter)
|
||||
{
|
||||
case 'name':
|
||||
$search = http_build_query(["name" => $query, 'countryCode' => 'BE']);
|
||||
break;
|
||||
case "vatid":
|
||||
if (stripos("x" . $query, "BE") == 0)
|
||||
{
|
||||
print _("Numéro de TVA invalide: doit commencer par BE");
|
||||
break;
|
||||
}
|
||||
$search = http_build_query(["participant" => 'iso6523-actorid-upis::9925:' . $query]);
|
||||
break;
|
||||
case 'entid':
|
||||
if (strlen(trim($query ?? "")) != 10)
|
||||
{
|
||||
print _("Numéro entreprise belge valide: 10 chiffres");
|
||||
break;
|
||||
}
|
||||
$search = http_build_query(["participant" => 'iso6523-actorid-upis::0208:' . $query]);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception("ASP129 unknown filter",129);
|
||||
}
|
||||
$str = file_get_contents("https://directory.peppol.eu/search/1.0/xml?" . $search);
|
||||
//$str= file_get_contents("/tmp/result.xml");
|
||||
$xml = new DOMDocument();
|
||||
$xml->loadXML($str);
|
||||
$root = $xml->getElementsByTagName("resultlist");
|
||||
if (count($root) == 0)
|
||||
{
|
||||
echo span(_("Aucun résultat"),' class="notice" ');
|
||||
echo '</div>'; // div class content
|
||||
return ;
|
||||
} else
|
||||
{
|
||||
printf(_("Résultat %d"), $root[0]->getAttribute("total-result-count"));
|
||||
}
|
||||
|
||||
$a_match = $xml->getElementsByTagName("match");
|
||||
$nb_match = $a_match->count();
|
||||
|
||||
$result=array();
|
||||
for ($i = 0; $i < $nb_match; $i++)
|
||||
{
|
||||
$node = $a_match->item($i);
|
||||
$obj = new PEPPOL_Match_Record();
|
||||
for ($e = 0; $e < $node->childElementCount; $e++)
|
||||
{
|
||||
if ($node->childNodes->item($e)->nodeType != XML_ELEMENT_NODE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($node->childNodes->item($e)->tagName == 'participantID')
|
||||
{
|
||||
$obj->participantID = $node->childNodes->item($e)->textContent;
|
||||
} elseif ($node->childNodes->item($e)->tagName == 'docTypeID')
|
||||
{
|
||||
$obj->docTypeID[] = $node->childNodes->item($e)->textContent;
|
||||
} elseif ($node->childNodes->item($e)->tagName == 'entity')
|
||||
{
|
||||
$obj->entity = new PEPPOL_Entity_Record();
|
||||
for ($f=0;$f< $node->childNodes->item($e)->childElementCount;$f++)
|
||||
{
|
||||
if ( $node->childNodes->item($e)->childNodes->item($f)->tagName == 'name')
|
||||
$obj->entity->name=$node->childNodes->item($e)->childNodes->item($f)->textContent;
|
||||
if ($node->childNodes->item($e)->childNodes->item($f)->tagName=='countryCode')
|
||||
$obj->entity->countryCode=$node->childNodes->item($e)->childNodes->item($f)->textContent;
|
||||
if ($node->childNodes->item($e)->childNodes->item($f)->tagName=='regDate')
|
||||
$obj->entity->regDate=$node->childNodes->item($e)->childNodes->item($f)->textContent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ($obj->participantID != null) $result[]=clone $obj;
|
||||
|
||||
}
|
||||
if (empty($result))
|
||||
{
|
||||
echo span(_("Aucun résultat"),' class="notice" ');
|
||||
return;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// display result
|
||||
//------------------------------------------------
|
||||
$nb_result=count($result);
|
||||
?>
|
||||
|
||||
<?php
|
||||
for ($i=0;$i < $nb_result;$i++)
|
||||
{
|
||||
?>
|
||||
<div style="display:flex;align-content: space-evenly">
|
||||
<div style="width:20rem;">
|
||||
<a href="javascript:void(0)" onclick="$('<?=$ctl?>').value='<?=$result[$i]->participantID?>';removeDiv('peppol_id_search_div')">
|
||||
<?=$result[$i]->participantID?>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<?=$result[$i]->entity->name?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} // end for ($i)
|
||||
echo '</div>'; // div class content
|
||||
?>
|
||||
|
||||
|
|
@ -217,7 +217,10 @@ class Card_Property
|
|||
}
|
||||
if ( $this->ad_id == ATTR_DEF_PEPPOLID)
|
||||
{
|
||||
|
||||
/// Propose a button to check VAT
|
||||
$result['input']=new IPEPPOL_ID( "av_text" . $this->ad_id,$this->av_text);
|
||||
$result['label']=$this->ad_text;
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($this->ad_id == ATTR_DEF_TVA) {
|
||||
|
|
|
|||
86
include/lib/ipeppol_id.class.php
Normal file
86
include/lib/ipeppol_id.class.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?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 13/05/24
|
||||
/*!
|
||||
* \file
|
||||
* \brief input of the VAT Number of a supplier / customer, propose a button to check VAT
|
||||
*/
|
||||
|
||||
class IPEPPOL_ID extends HtmlInput
|
||||
{
|
||||
private $itext;
|
||||
|
||||
function __construct($name = '', $value = '', $p_id = "")
|
||||
{
|
||||
|
||||
$p_id = ($p_id=="")?uniqid("peppol_id"):$p_id;
|
||||
|
||||
$this->itext = new IText($name,$value,$p_id);
|
||||
$this->itext->title = _("PEPPOL_ID");
|
||||
$this->itext->placeholder = "9999:9999999999";
|
||||
$this->itext->extra = "";
|
||||
$this->itext->style = ' class="input_text" ';
|
||||
$this->autofocus = false;
|
||||
}
|
||||
|
||||
function input()
|
||||
{
|
||||
if ( $this->readOnly==true) return $this->display();
|
||||
|
||||
$return = $this->itext->input();
|
||||
$return .= $this->button_check_peppol();
|
||||
$return.=sprintf('<div id="info%s" class="notice" style="margin:0px;font-size:80%%;width:auto"></div>',$this->itext->id);
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function getIText(): IText
|
||||
{
|
||||
return $this->itext;
|
||||
}
|
||||
|
||||
public function setIText(IText $itext): IPEPPOL_ID
|
||||
{
|
||||
$this->itext = $itext;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function button_check_peppol()
|
||||
{
|
||||
$button=new \IButton(uniqid());
|
||||
$button->javascript=sprintf("category_card.display_search_peppol('%s')",
|
||||
$this->itext->id);
|
||||
$button->extra='style="padding-bottom:0px"';
|
||||
$button->label=_("Vérifie");
|
||||
return $button->input();
|
||||
|
||||
|
||||
}
|
||||
function display()
|
||||
{
|
||||
return $this->itext->display();
|
||||
|
||||
}
|
||||
|
||||
static function testme()
|
||||
{
|
||||
$ivatnumber=new IPEPPOL_ID("av_text13");
|
||||
|
||||
echo $ivatnumber->input();
|
||||
}
|
||||
}
|
||||
105
sql/upgrade.sql
105
sql/upgrade.sql
|
|
@ -16,7 +16,7 @@ update "parameter" set pr_id='MY_POSTCODE' where pr_id='MY_CP';
|
|||
update "parameter" set pr_id='MY_CITY' where pr_id='MY_COMMUNE';
|
||||
update "parameter" set pr_id='MY_COUNTRY' where pr_id='MY_PAYS';
|
||||
|
||||
insert into attr_def (ad_id,ad_text,ad_type,ad_size,ad_search_followup,ad_default_order) values(55,'SIRENE','text',20,1,14);
|
||||
insert into attr_def (ad_id,ad_text,ad_type,ad_size,ad_search_followup,ad_default_order) values(55,'SIREN','text',20,1,14);
|
||||
insert into attr_def (ad_id,ad_text,ad_type,ad_size,ad_search_followup,ad_default_order) values(56,'SIRET','text',20,1,15);
|
||||
|
||||
insert into attr_def (ad_id,ad_text,ad_type,ad_size,ad_search_followup,ad_default_order) values(58,'PEPPOL ID','text',20,1,15);
|
||||
|
|
@ -369,3 +369,106 @@ insert into profile_menu
|
|||
select me_code,'CFG',1,2,'E',0,(select distinct m2.pm_id from profile_menu m2 where m2.me_code='CFG' limit 1) from menu_ref where me_code='C0ML';
|
||||
|
||||
|
||||
create table parameter_internal (pi_id text not null primary key, pi_value text);
|
||||
comment on table parameter_internal is 'Internal parameter, used by the application , it can''t not be changed by the interface';
|
||||
|
||||
create or replace function comptaproc.fill_internal_parameter()
|
||||
returns text
|
||||
as
|
||||
$$
|
||||
declare
|
||||
str_country text;
|
||||
n_found int;
|
||||
begin
|
||||
select lower(pr_value) into str_country from "parameter" where pr_id = 'MY_COUNTRY';
|
||||
if str_country = 'belgique' or str_country = 'be' then
|
||||
insert into parameter_internal values ('COUNTRY_CODE','BE') on conflict do nothing;
|
||||
return 'BE';
|
||||
end if ;
|
||||
if str_country = 'france' or str_country = 'fr' then
|
||||
insert into parameter_internal values ('COUNTRY_CODE','FR') on conflict do nothing;
|
||||
return 'FR';
|
||||
end if ;
|
||||
|
||||
select 1 into n_found from bilan where b_file_template='document/fr_fr/fr_plan_abrege_perso_cr1000.form';
|
||||
|
||||
if n_found is NULL then
|
||||
insert into parameter_internal values ('COUNTRY_CODE','BE') on conflict do nothing;
|
||||
return 'BE';
|
||||
end if;
|
||||
insert into parameter_internal values ('COUNTRY_CODE','FR') on conflict do nothing;
|
||||
return 'FR';
|
||||
end;
|
||||
$$
|
||||
language plpgsql;
|
||||
|
||||
select comptaproc.fill_internal_parameter();
|
||||
-- insert new attributes for PEPPOL, SIREN and QUANTYTI
|
||||
insert into jnt_fic_attr (fd_id,ad_id,jnt_order)
|
||||
select f1.fd_id , 58,15
|
||||
from fiche_def f1
|
||||
join fiche_def f2 on (f1.fd_id=f2.fd_id)
|
||||
where f2.frd_id in (8,9)
|
||||
on conflict do nothing;
|
||||
|
||||
insert into jnt_fic_attr (fd_id,ad_id,jnt_order)
|
||||
select f1.fd_id , 57,16
|
||||
from fiche_def f1
|
||||
join fiche_def f2 on (f1.fd_id=f2.fd_id)
|
||||
where f2.frd_id in (8,9)
|
||||
on conflict do nothing;
|
||||
|
||||
insert into jnt_fic_attr (fd_id,ad_id,jnt_order)
|
||||
select f1.fd_id , 55,16
|
||||
from fiche_def f1
|
||||
join fiche_def f2 on (f1.fd_id=f2.fd_id)
|
||||
where f2.frd_id in (8,9)
|
||||
on conflict do nothing;
|
||||
|
||||
insert into jnt_fic_attr (fd_id,ad_id,jnt_order)
|
||||
select f1.fd_id , 59,90
|
||||
from fiche_def f1
|
||||
join fiche_def f2 on (f1.fd_id=f2.fd_id)
|
||||
where f2.frd_id in (1,2)
|
||||
on conflict do nothing;
|
||||
|
||||
-- Add a attribute PEPPOL ID for customer and supplier in Belgium only
|
||||
-- for the card category
|
||||
-- Plus, compute a default value
|
||||
--
|
||||
CREATE OR REPLACE FUNCTION comptaproc.update_peppol ()
|
||||
RETURNS int2
|
||||
/*- SETOF menu_tree : (TABLE FUNCTION) menu_tree is a type of a rowtype create type menu_tree as (code text,description text);
|
||||
- int2, text,varchar...
|
||||
- trigger : if called from a trigger
|
||||
- void : nothing
|
||||
- boolean
|
||||
*/ AS
|
||||
$BODY$
|
||||
declare
|
||||
/*
|
||||
* Section for variables
|
||||
*/
|
||||
n_card_id int;
|
||||
vat_number text;
|
||||
record_card RECORD;
|
||||
result_fct int;
|
||||
begin
|
||||
|
||||
result_fct := 0;
|
||||
|
||||
for record_card in select * from fiche_detail where ad_id=13 and LOWER (ad_value ) like 'be%'
|
||||
loop
|
||||
vat_number := regexp_replace(record_card.ad_value,'\D','','g');
|
||||
if length(vat_number) = 10 then
|
||||
update fiche_detail set ad_value = '0208:'||vat_number where f_id=record_card.f_id and ad_id=58;
|
||||
RESULT_fct := result_fct + 1;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return result_fct;
|
||||
end;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
|
||||
select comptaproc.update_peppol();
|
||||
Loading…
Add table
Add a link
Reference in a new issue