diff --git a/include/category_card.inc.php b/include/category_card.inc.php index d91537fc6..018adecd0 100644 --- a/include/category_card.inc.php +++ b/include/category_card.inc.php @@ -70,15 +70,21 @@ $f=new Fiche($cn, $f_id); echo '
'; echo $f->get_gestion_title(); -$menu=array( - array('href'=>$root."&sc=dc", 'label'=>_('Fiche'), 'alt'=>_('Détail de la fiche')), - array('href'=>$root.'&sc=sv', 'label'=>_('Suivi'), 'alt'=>_('Suivi Fournisseur, client, banque, devis, bon de commande, courrier')), - array('href'=>$root.'&sc=cn', 'label'=>_('Contact'), 'alt'=>_('Liste de contacts')), - array('href'=>$root.'&sc=op', 'label'=>_('Opérations'), 'alt'=>_('Toutes les opérations')), - array('href'=>$root.'&sc=bal', 'label'=>_('Balance'), 'alt'=>_('Balance du tiers')), - array('href'=>$root.'&sc=balag', 'label'=>_('Balance âgée'), 'alt'=>_('Balance âgée du tiers')), - array('href'=>$root.'&sc=let', 'label'=>_('Lettrage'), 'alt'=>_('Opérations & Lettrages')) -); + +$from=$http->request("ac"); + + +$menu[]= array('href'=>$root."&sc=dc", 'label'=>_('Fiche'), 'alt'=>_('Détail de la fiche')); +$menu[]=array('href'=>$root.'&sc=sv', 'label'=>_('Suivi'), 'alt'=>_('Suivi Fournisseur, client, banque, devis, bon de commande, courrier')); +// No submenu CONTACT for the menu CONTACT +if ( strpos($from,"CONTACT") === false) { + $menu[]=array('href'=>$root.'&sc=cn', 'label'=>_('Contact'), 'alt'=>_('Liste de contacts')); +} +$menu[]=array('href'=>$root.'&sc=op', 'label'=>_('Opérations'), 'alt'=>_('Toutes les opérations')); +$menu[]=array('href'=>$root.'&sc=bal', 'label'=>_('Balance'), 'alt'=>_('Balance du tiers')); +$menu[]=array('href'=>$root.'&sc=balag', 'label'=>_('Balance âgée'), 'alt'=>_('Balance âgée du tiers')); +$menu[]=array('href'=>$root.'&sc=let', 'label'=>_('Lettrage'), 'alt'=>_('Opérations & Lettrages')); + echo '
get("query","string",""); $sql = ""; if (isset($_GET['cat'])) { $cat=$http->get("cat","number"); - if ($cat!= -1 ) $sql = sprintf(" and fd_id = %s", $cat); + $contact->filter_category($cat); } if (isset($_GET['sel_company'])) { $sel_company=$http->get("sel_company"); - if ($sel_company != '' && $sel_company != "-1") - { - - $client->company=$sel_company; - } + $contact->filter_company($sel_company); } echo '
'; - echo $client->Summary($search,"contact",$sql); + echo $contact->Summary($search,"contact",$sql); echo '
'; @@ -128,7 +127,7 @@ if ($low_action == "list") $f_add_button->label = _('Créer une nouvelle fiche'); $f_add_button->set_attribute('win_refresh', 'yes'); $f_add_button->set_attribute('type_cat', FICHE_TYPE_CONTACT); - $f_add_button->javascript = " select_card_type(this);"; + $f_add_button->javascript = "select_card_type(this);"; echo $f_add_button->input(); $f_cat_button=new IButton('add_cat'); diff --git a/include/database/v_contact_sql.class.php b/include/database/v_contact_sql.class.php new file mode 100644 index 000000000..36e93a7e5 --- /dev/null +++ b/include/database/v_contact_sql.class.php @@ -0,0 +1,88 @@ + + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** +* class_user_filter_sql.php +* +* @file +* @brief abstract of the view public.v_contact +*/ + +/** +* @class User_filter_SQL +* @brief ORM abstract of the view public.v_contact_sql +*/ + +class V_Contact_SQL extends Data_SQL +{ + function __construct($p_cn, $p_id = -1) + { + $this->table="public.v_contact"; + $this->primary_key="f_id"; + $a_name=explode(",","f_id,contact_fname,contact_name,contact_qcode,contact_company,contact_mobile,contact_phone,contact_email,contact_fax,card_category"); + $this->type=[]; + foreach ($a_name as $key) { + $this->type[trim($key)]="text"; + $this->name[trim($key)]=$key; + } + $this->type['f_id']="number"; + $this->type['card_category']="number"; + + parent::__construct($p_cn, $p_id); + } + + + function insert() + { + throw new Exception("not implemented"); + } + + function delete() + { + throw new Exception("not implemented"); + } + + function update() + { + throw new Exception("not implemented"); + } + + function load() + { + $array=$this->cn->get_row("select * from ".$this->table." where f_id=$1",array($this->f_id)); + if (empty ($array) ) { $this->f_id=-1;return false;} + $this->to_row($array); + return true; + } + + function seek($cond = '', $p_array = null) + { + throw new Exception("not implemented"); + } + + function count($p_where = "", $p_array = null) + { + throw new Exception("not implemented"); + } + + function exist() + { + throw new Exception("not implemented"); + } +} \ No newline at end of file diff --git a/include/lib/data_sql.class.php b/include/lib/data_sql.class.php index 61b685cc6..1629148fa 100644 --- a/include/lib/data_sql.class.php +++ b/include/lib/data_sql.class.php @@ -241,6 +241,16 @@ abstract class Data_SQL return $array; } + /** + * @brief turns a row fetched from the DB into a SQL object in updating all his attribute + * @param $p_array + * @return void + */ + public function to_row($p_array) { + foreach ($this->name as $name) { + $this->$name=$p_array[$name]; + } + } /** * @brief retrieve array of object thanks a condition * @param $cond condition (where clause) (optional by default all the rows are fetched) diff --git a/include/sql/patch/upgrade177.sql b/include/sql/patch/upgrade177.sql new file mode 100644 index 000000000..7c77c5a9c --- /dev/null +++ b/include/sql/patch/upgrade177.sql @@ -0,0 +1,25 @@ +begin; + + +create or replace view v_contact as +with contact_data as (select f.f_id , f.fd_id from fiche f join fiche_def fd on (f.fd_id=fd.fd_id) where fd.frd_id=16) +select f_id, + (select ad_value from fiche_detail where ad_id=32 and f_id=cd.f_id) as contact_fname, + (select ad_value from fiche_detail where ad_id=1 and f_id=cd.f_id) as contact_name, + (select ad_value from fiche_detail where ad_id=23 and f_id=cd.f_id) as contact_qcode, + (select ad_value from fiche_detail where ad_id=25 and f_id=cd.f_id) as contact_company, + (select ad_value from fiche_detail where ad_id=27 and f_id=cd.f_id) as contact_mobile, + (select ad_value from fiche_detail where ad_id=17 and f_id=cd.f_id) as contact_phone, + (select ad_value from fiche_detail where ad_id=18 and f_id=cd.f_id) as contact_email, + (select ad_value from fiche_detail where ad_id=26 and f_id=cd.f_id) as contact_fax, + cd.fd_id as card_category +from contact_data cd ; + +insert into attr_min values (16,32); + +insert into jnt_fic_attr (fd_id,jnt_order,ad_id) select fd_id,10,32 from fiche_def where frd_id=16 on conflict(fd_id,ad_id) do nothing; +update attr_def set ad_text='Tél. Portable' where ad_id=27; + + +insert into version (val,v_description) values (178,'Correct contact'); +commit; \ No newline at end of file diff --git a/include/template/contact-summary.php b/include/template/contact-summary.php new file mode 100644 index 000000000..d13a34695 --- /dev/null +++ b/include/template/contact-summary.php @@ -0,0 +1,96 @@ +request("ac","string",""); +?> + + + + + + + + + + + + + request('ac'); + foreach ($step_contact as $contact): + $even_odd=($idx%2==0)?'even':'odd'; + $idx++; + $url=NOALYSS_URL."/do.php?".http_build_query(["gDossier"=>$dossier_id,"ac"=>$ac,"sb"=>"detail","f_id"=>$contact['f_id']]); + ?> + + + + + + + + + + + + +
+ + + + + + + + + + + + + get_by_qcode(trim($contact['contact_company']),false); + $l_company_name=$l_company->strAttribut(ATTR_DEF_NAME,0); + + // add popup for detail if the company does exist + if ( $l_company_name !="") + { + echo HtmlInput::card_detail($contact['contact_company'],$l_company_name,'style="text-decoration:underline;"'); + } + } + + ?> + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/sql/upgrade.sql b/sql/upgrade.sql index 34d3b0373..e69de29bb 100644 --- a/sql/upgrade.sql +++ b/sql/upgrade.sql @@ -1,171 +0,0 @@ --- auto-generated definition -create table acc_other_tax -( - ac_id serial constraint acc_other_tax_pk primary key, - ac_label text not null, - ac_rate numeric (5,2) not null, - ajrn_def_id integer[], - ac_accounting account_type not null -); -comment on table acc_other_tax is 'Additional tax for Sale or Purchase '; -comment on column acc_other_tax.ac_label is 'Label of the tax'; -comment on column acc_other_tax.ac_rate is 'rate of the tax in percent'; -comment on column acc_other_tax.ajrn_def_id is 'array of to FK jrn_def (jrn_def_id)'; -comment on column acc_other_tax.ac_accounting is 'FK tmp_pcmn (pcm_val)'; - - -ALTER TABLE public.jrn drop CONSTRAINT jrn_pkey ; -ALTER TABLE public.jrn ADD CONSTRAINT jrn_pkey PRIMARY KEY (jr_id); - --- public.jrn_tax definition - --- Drop table - --- DROP TABLE public.jrn_tax; - -CREATE TABLE public.jrn_tax ( - jt_id int4 NOT NULL GENERATED ALWAYS AS IDENTITY, - j_id int8 NOT NULL, -- fk jrnx - pcm_val public."account_type" NOT NULL, -- FK tmp_pcmn - ac_id int4 NOT NULL, -- FK to acc_other_tax - CONSTRAINT jrn_tax_pk PRIMARY KEY (jt_id) -); - --- Column comments - -COMMENT ON COLUMN public.jrn_tax.j_id IS 'fk jrnx'; -COMMENT ON COLUMN public.jrn_tax.pcm_val IS 'FK tmp_pcmn'; -COMMENT ON COLUMN public.jrn_tax.ac_id IS 'FK to acc_other_tax'; - - --- public.jrn_tax foreign keys - -ALTER TABLE public.jrn_tax ADD CONSTRAINT jrn_tax_acc_other_tax_fk FOREIGN KEY (ac_id) REFERENCES public.acc_other_tax(ac_id); -ALTER TABLE public.jrn_tax ADD CONSTRAINT jrn_tax_fk FOREIGN KEY (j_id) REFERENCES public.jrnx(j_id); - -drop view if exists v_detail_sale; -create or replace view v_detail_sale - (jr_id, jr_date, jr_date_paid, jr_ech, jr_tech_per, jr_comment, jr_pj_number, jr_internal, jr_def_id, - j_poste, j_text, j_qcode, jr_rapt, item_card, item_name, qs_client, tiers_name, quick_code, tva_label, - tva_comment, tva_both_side, vat_sided, vat_code, vat, price, quantity, price_per_unit, htva, tot_vat, - tot_tva_np,other_tax_amount, oc_amount, oc_vat_amount, cr_code_iso) -as -WITH m AS ( - SELECT sum(quant_sold_1.qs_price) AS htva, - sum(quant_sold_1.qs_vat) AS tot_vat, - sum(quant_sold_1.qs_vat_sided) AS tot_tva_np, - jrn_1.jr_id - FROM quant_sold quant_sold_1 - JOIN jrnx jrnx_1 USING (j_id) - JOIN jrn jrn_1 ON jrnx_1.j_grpt = jrn_1.jr_grpt_id - GROUP BY jrn_1.jr_id -),other_tax as ( - select j_grpt , sum(case when j_debit is true then 0-j_montant else j_montant end) other_tax_amount from jrnx join jrn_tax using (j_id) group by j_grpt ) -SELECT jrn.jr_id, - jrn.jr_date, - jrn.jr_date_paid, - jrn.jr_ech, - jrn.jr_tech_per, - jrn.jr_comment, - jrn.jr_pj_number, - jrn.jr_internal, - jrn.jr_def_id, - jrnx.j_poste, - jrnx.j_text, - jrnx.j_qcode, - jrn.jr_rapt, - quant_sold.qs_fiche AS item_card, - a.name AS item_name, - quant_sold.qs_client, - b.vw_name AS tiers_name, - b.quick_code, - tva_rate.tva_label, - tva_rate.tva_comment, - tva_rate.tva_both_side, - quant_sold.qs_vat_sided AS vat_sided, - quant_sold.qs_vat_code AS vat_code, - quant_sold.qs_vat AS vat, - quant_sold.qs_price AS price, - quant_sold.qs_quantite AS quantity, - quant_sold.qs_price / quant_sold.qs_quantite AS price_per_unit, - m.htva, - m.tot_vat, - m.tot_tva_np, - ot.other_tax_amount, - oc.oc_amount, - oc.oc_vat_amount, - (SELECT currency.cr_code_iso - FROM currency - WHERE jrn.currency_id = currency.id) AS cr_code_iso -FROM jrn - JOIN jrnx ON jrn.jr_grpt_id = jrnx.j_grpt - JOIN quant_sold USING (j_id) - JOIN vw_fiche_name a ON quant_sold.qs_fiche = a.f_id - JOIN vw_fiche_attr b ON quant_sold.qs_client = b.f_id - LEFT JOIN tva_rate ON quant_sold.qs_vat_code = tva_rate.tva_id - JOIN m ON m.jr_id = jrn.jr_id - LEFT JOIN operation_currency oc ON oc.j_id = jrnx.j_id - left join other_tax ot on ot.j_grpt=jrn.jr_grpt_id; - -drop view if exists public.v_detail_purchase; - -create VIEW public.v_detail_purchase -AS WITH m AS ( - SELECT sum(quant_purchase_1.qp_price) AS htva, - sum(quant_purchase_1.qp_vat) AS tot_vat, - sum(quant_purchase_1.qp_vat_sided) AS tot_tva_np, - jrn_1.jr_id - FROM quant_purchase quant_purchase_1 - JOIN jrnx jrnx_1 USING (j_id) - JOIN jrn jrn_1 ON jrnx_1.j_grpt = jrn_1.jr_grpt_id - GROUP BY jrn_1.jr_id -),other_tax as ( - select j_grpt , sum(case when j_debit is false then 0-j_montant else j_montant end) other_tax_amount from jrnx join jrn_tax using (j_id) group by j_grpt ) - SELECT jrn.jr_id, - jrn.jr_date, - jrn.jr_date_paid, - jrn.jr_ech, - jrn.jr_tech_per, - jrn.jr_comment, - jrn.jr_pj_number, - jrn.jr_internal, - jrn.jr_def_id, - jrnx.j_poste, - jrnx.j_text, - jrnx.j_qcode, - jrn.jr_rapt, - quant_purchase.qp_fiche AS item_card, - a.name AS item_name, - quant_purchase.qp_supplier, - b.vw_name AS tiers_name, - b.quick_code, - tva_rate.tva_label, - tva_rate.tva_comment, - tva_rate.tva_both_side, - quant_purchase.qp_vat_sided AS vat_sided, - quant_purchase.qp_vat_code AS vat_code, - quant_purchase.qp_vat AS vat, - quant_purchase.qp_price AS price, - quant_purchase.qp_quantite AS quantity, - quant_purchase.qp_price / quant_purchase.qp_quantite AS price_per_unit, - quant_purchase.qp_nd_amount AS non_ded_amount, - quant_purchase.qp_nd_tva AS non_ded_tva, - quant_purchase.qp_nd_tva_recup AS non_ded_tva_recup, - m.htva, - m.tot_vat, - m.tot_tva_np, - ot.other_tax_amount, - oc.oc_amount, - oc.oc_vat_amount, - ( SELECT currency.cr_code_iso - FROM currency - WHERE jrn.currency_id = currency.id) AS cr_code_iso - FROM jrn - JOIN jrnx ON jrn.jr_grpt_id = jrnx.j_grpt - JOIN quant_purchase USING (j_id) - JOIN vw_fiche_name a ON quant_purchase.qp_fiche = a.f_id - JOIN vw_fiche_attr b ON quant_purchase.qp_supplier = b.f_id - LEFT JOIN tva_rate ON quant_purchase.qp_vat_code = tva_rate.tva_id - JOIN m ON m.jr_id = jrn.jr_id - LEFT JOIN operation_currency oc ON oc.j_id = jrnx.j_id - left join other_tax ot on ot.j_grpt=jrn.jr_grpt_id; \ No newline at end of file diff --git a/unit-test/include/class/contactTest.php b/unit-test/include/class/contactTest.php index e3e6d4517..f6b792687 100644 --- a/unit-test/include/class/contactTest.php +++ b/unit-test/include/class/contactTest.php @@ -28,12 +28,11 @@ */ use PHPUnit\Framework\TestCase; +require DIRTEST.'/global.php'; /** * @backupGlobals enabled * @coversDefaultClass \Contact */ -require DIRTEST.'/global.php'; - class ContactTest extends TestCase { @@ -41,6 +40,7 @@ class ContactTest extends TestCase * @var Fiche */ protected $object; + protected $connection; /** * Sets up the fixture, for example, opens a network connection. @@ -48,10 +48,11 @@ class ContactTest extends TestCase */ protected function setUp():void { - include 'global.php'; + $this->object = new stdClass(); $this->object->fiche_def=0; $this->object->card_to_clean=array(); + $this->connection=Dossier::connect(); } /** @@ -60,8 +61,9 @@ class ContactTest extends TestCase */ protected function tearDown():void { - include 'global.php'; - global $g_connection; + if ( ! is_object($this->object->fiche_def)) return; + include_once DIRTEST.'/global.php'; + $g_connection=Dossier::connect(); $sql=new ArrayObject(); $sql->append("delete from fiche_detail where f_id in (select f_id from fiche where fd_id = $1 )"); $sql->append("delete from fiche where f_id not in (select f_id from fiche_detail where $1=$1)"); @@ -101,9 +103,9 @@ class ContactTest extends TestCase */ public function createContact() { - include_once 'global.php'; + include_once DIRTEST.'/global.php'; - global $g_connection; + $g_connection=Dossier::connect(); // create a category of card, type Charges $fiche_def=new Fiche_Def($g_connection); $aParam=["nom_mod"=>"Test.Contact", @@ -127,7 +129,8 @@ class ContactTest extends TestCase */ public function createContactCard() { - global $g_connection; + include_once DIRTEST.'/global.php'; + if ( $this->object->fiche_def == 0) { $this->createContact(); } @@ -139,7 +142,7 @@ class ContactTest extends TestCase $aName[]=['name'=>'Daniel','company'=>'FOURNI']; $aName[]=['name'=>'Geert','company'=>'FOURNI']; foreach ($aName as $param ) { - $fiche=new Fiche($g_connection); + $fiche=new Fiche($this->connection); $fiche->fiche_def=$this->object->fiche_def->id; $fiche->load(); $fiche->setAttribut(ATTR_DEF_NAME, $param['name']); @@ -157,6 +160,7 @@ class ContactTest extends TestCase */ public function testSummary() { + include_once DIRTEST.'/global.php'; global $g_connection; if ( $this->object->fiche_def == 0) { $this->createContactCard(); @@ -164,14 +168,110 @@ class ContactTest extends TestCase $contact=new Contact($g_connection); $_SERVER['REQUEST_URI']="?"; $_SERVER['PHP_SELF']=__FILE__; - $r=$contact->summary(); - $this->assertEquals(count($this->object->card_to_clean)*2 , substr_count($r,'fill_ipopcard')," 1. Missing card"); - $contact->company=' fourni '; - $r=$contact->summary(); - $this->assertEquals(6, substr_count($r,'fill_ipopcard') , 'not found all the contacts from FOURNI'); - $r=$contact->summary('william'); - $this->assertEquals(2, substr_count($r,'fill_ipopcard') , 'Search does not filter'); + put_global(array( + ["key"=>"offset","value"=>0], + ["key"=>"ac","value"=>"CONTACT"], + ["key"=>"page","value"=>1])); + ob_start(); + $contact->summary(); + $r=ob_get_contents(); + ob_end_clean(); + $path=__DIR__."/file/"; + $filename="contact-summary-1.html"; + \Noalyss\Facility::save_file($path,$filename,$r); + print "File saved into $path/$filename"; + $this->assertEquals(4983, filesize ($path."/".$filename)," File not valide (1)"); + $this->assertEquals(5 , preg_match_all('/filter_company(' fourni '); + ob_start(); + $contact->summary(); + $r=ob_get_contents(); + ob_end_clean(); + $filename="contact-summary-2.html"; + \Noalyss\Facility::save_file($path,$filename,$r); + + print "File saved into $path/$filename"; + $this->assertEquals(3457,filesize ($path."/".$filename)," File not valide (2)"); + $this->assertEquals(3 , preg_match_all('/assertEquals(2018,filesize ($path."/".$filename)," File not valide (3)"); + $this->assertEquals(1, preg_match_all('/assertEquals(['search'=>'search_sql'],$contact->getFilter(),'Search not set'); + + $contact->filter_search("other_sql"); + $this->assertEquals(['search'=>'other_sql'],$contact->getFilter(),'Search not replaced'); + + $contact->filter_company("company_sql"); + $this->assertEquals(['search'=>'other_sql','company'=>'COMPANY_SQL'],$contact->getFilter(),'company not set'); + + $contact->filter_category(1); + $this->assertEquals(['search'=>'other_sql','company'=>'COMPANY_SQL','category'=>1], + $contact->getFilter(),'category not set'); + + $contact->filter_category(null); + $this->assertEquals(['search'=>'other_sql','company'=>'COMPANY_SQL'],$contact->getFilter(),'category not removed'); + + } + + /** + * @depends testFilter + * @return void + */ + function testBuildSQL() + { + $contact=new Contact($this->connection); + $contact->filter_category(1); + $contact->filter_search("search_sql"); + $expected=strtoupper(preg_replace("/\s+/",'',"SELECT f_id,contact_fname, + contact_name, + contact_qcode, + contact_company, + contact_mobile, + contact_phone, + contact_email, + contact_fax + FROM public.v_contact + where f_id in (select distinct f_id from fiche_detail where ad_value ilike '%search_sql%') and fd_id=1")); + $this->assertEquals($expected,strtoupper(preg_replace("/\s+/",'',$contact->build_sql([]))),' SQL Incorrect'); + + } + + /** + * @testdox Test SQL V_Contact_SQL + * @return void + */ + function testObjectSQL() + { + if ( $this->object->fiche_def == 0) { + $this->createContactCard(); + } + // take a card + $f_id=$this->object->card_to_clean[0]; + $contact_sql=new V_Contact_SQL($this->connection,$f_id); + $this->assertTrue($contact_sql->load()," Cannot load existing card"); + $this->assertTrue($contact_sql->contact_name=='Chantal','Data not updated'); + $this->assertTrue($contact_sql->getp("contact_name")=='Chantal','Data not updated'); + } + + }