diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 81813c2bebe..186b20a051d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,3 +2,4 @@ open_collective: dolibarr custom: https://wiki.dolibarr.org/index.php/Subscribe +# github: [eldy] \ No newline at end of file diff --git a/README.md b/README.md index 5d4de0af909..f4ccc78e9dc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # DOLIBARR ERP & CRM ![Downloads per day](https://img.shields.io/sourceforge/dw/dolibarr.svg) -[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) |7|8|9|10|develop| |----------|----------|----------|----------|----------| diff --git a/htdocs/admin/system/perf.php b/htdocs/admin/system/perf.php index fbf6fa3bb14..e17756391f1 100644 --- a/htdocs/admin/system/perf.php +++ b/htdocs/admin/system/perf.php @@ -522,9 +522,9 @@ if ($resql) $nb=$obj->nb; if ($nb > $limitforoptim) { - if (empty($conf->global->THIRDPARTY_DONOTSEARCH_ANYWHERE)) + if (empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE)) { - print img_picto('', 'warning.png').' '.$langs->trans("YouHaveXObjectUseSearchOptim", $nb, $langs->transnoentitiesnoconv("ThirdParties"), 'THIRDPARTY_DONOTSEARCH_ANYWHERE'); + print img_picto('', 'warning.png').' '.$langs->trans("YouHaveXObjectUseSearchOptim", $nb, $langs->transnoentitiesnoconv("ThirdParties"), 'COMPANY_DONOTSEARCH_ANYWHERE'); } else { diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index dea2d0c0ed8..5b6a47fa998 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1758,15 +1758,16 @@ if ($action == 'create' && $usercancreate) $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); print $hookmanager->resPrint; if (empty($reshook)) { - if (! empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_ORDER)) - // copy from thirdparty - $tpExtrafields = new Extrafields($db); - $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element); - if ($soc->fetch_optionals() > 0) { - $object->array_options = array_merge($object->array_options, $soc->array_options); - } + if (! empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_ORDER)) { + // copy from thirdparty + $tpExtrafields = new Extrafields($db); + $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element); + if ($soc->fetch_optionals() > 0) { + $object->array_options = array_merge($object->array_options, $soc->array_options); + } }; - print $object->showOptionals($extrafields, 'edit'); + + print $object->showOptionals($extrafields, 'edit'); } // Template to use by default diff --git a/htdocs/compta/paiement.php b/htdocs/compta/paiement.php index ce36be991d2..e8fceebb03c 100644 --- a/htdocs/compta/paiement.php +++ b/htdocs/compta/paiement.php @@ -597,7 +597,11 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie print ''.$alreadypayedlabel.''; print ''.$remaindertopay.''; print ''.$langs->trans('PaymentAmount').''; - print ' '; + + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $facture, $action); // Note that $action and $object may have been modified by hook + + print ' '; print "\n"; $total=0; @@ -745,7 +749,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie print ""; $parameters=array(); - $reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $objp, $action); // Note that $action and $object may have been modified by hook + $reshook=$hookmanager->executeHooks('printFieldListValue', $parameters, $objp, $action); // Note that $action and $object may have been modified by hook // Warning print ''; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 3a69d8e6d42..5ee969a73a0 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1887,10 +1887,10 @@ class Form * @param int $forcecombo Force to use combo box * @param string $morecss Add more css on select * @param int $hidepriceinlabel 1=Hide prices in label - * @param string $warehouseStatus warehouse status filter, following comma separated filter options can be used - * 'warehouseopen' = select products from open warehouses, - * 'warehouseclosed' = select products from closed warehouses, - * 'warehouseinternal' = select products from warehouses for internal correct/transfer only + * @param string $warehouseStatus Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used + * 'warehouseopen' = count products from open warehouses, + * 'warehouseclosed' = count products from closed warehouses, + * 'warehouseinternal' = count products from warehouses for internal correct/transfer only * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) * @return void */ @@ -2042,10 +2042,10 @@ class Form * @param int $forcecombo Force to use combo box * @param string $morecss Add more css on select * @param int $hidepriceinlabel 1=Hide prices in label - * @param string $warehouseStatus warehouse status filter, following comma separated filter options can be used - * 'warehouseopen' = select products from open warehouses, - * 'warehouseclosed' = select products from closed warehouses, - * 'warehouseinternal' = select products from warehouses for internal correct/transfer only + * @param string $warehouseStatus Warehouse status filter to group/count stock. Following comma separated filter options can be used. + * 'warehouseopen' = count products from open warehouses, + * 'warehouseclosed' = count products from closed warehouses, + * 'warehouseinternal' = count products from warehouses for internal correct/transfer only * @return array Array of keys for json */ public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '') @@ -2075,7 +2075,14 @@ class Form } $selectFields = " p.rowid, p.label, p.ref, p.description, p.barcode, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.duration, p.fk_price_expression"; - (count($warehouseStatusArray)) ? $selectFieldsGrouped = ", sum(ps.reel) as stock" : $selectFieldsGrouped = ", p.stock"; + if (count($warehouseStatusArray)) + { + $selectFieldsGrouped = ", sum(".$db->ifsql("e.statut IS NULL", "0", "ps.reel").") as stock"; // e.statut is null if there is no record in stock + } + else + { + $selectFieldsGrouped = ", p.stock"; + } $sql = "SELECT "; $sql.= $selectFields . $selectFieldsGrouped; @@ -2126,7 +2133,8 @@ class Form if (count($warehouseStatusArray)) { $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")"; + $sql.= ' AND e.statut IN ('.$this->db->escape(implode(',', $warehouseStatusArray)).')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0. } // include search in supplier ref @@ -2154,10 +2162,6 @@ class Form } $sql.= ' WHERE p.entity IN ('.getEntity('product').')'; - if (count($warehouseStatusArray)) - { - $sql.= ' AND (p.fk_product_type = 1 OR e.statut IN ('.$this->db->escape(implode(',', $warehouseStatusArray)).'))'; - } if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) { $sql .= " AND pac.rowid IS NULL"; diff --git a/htdocs/core/tpl/contacts.tpl.php b/htdocs/core/tpl/contacts.tpl.php index 14534b3472e..1f7d403b575 100644 --- a/htdocs/core/tpl/contacts.tpl.php +++ b/htdocs/core/tpl/contacts.tpl.php @@ -149,7 +149,7 @@ if ($permission) { ?>
-
trans("Nature"); ?>
+
trans("NatureOfContact"); ?>
trans("ThirdParty"); ?>
trans("Users").'/'.$langs->trans("Contacts"); ?>
trans("ContactType"); ?>
diff --git a/htdocs/product/stock/class/entrepot.class.php b/htdocs/product/stock/class/entrepot.class.php index e857166e392..18d17f9acf0 100644 --- a/htdocs/product/stock/class/entrepot.class.php +++ b/htdocs/product/stock/class/entrepot.class.php @@ -686,6 +686,8 @@ class Entrepot extends CommonObject $label.= '
' . $langs->trans('Ref') . ': ' . (empty($this->ref)?(empty($this->label)?$this->libelle:$this->label):$this->ref); if (! empty($this->lieu)) $label.= '
' . $langs->trans('LocationSummary').': '.$this->lieu; + if (isset($this->statut)) + $label.= '
' . $langs->trans("Status").": ".$this->getLibStatut(5); $url = DOL_URL_ROOT.'/product/stock/card.php?id='.$this->id; diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index 8e19242d1c1..9426d2041b0 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -104,13 +104,19 @@ $form=new Form($db); $warehouse=new Entrepot($db); $sql = "SELECT e.rowid, e.ref, e.statut, e.lieu, e.address, e.zip, e.town, e.fk_pays, e.fk_parent,"; -$sql.= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue, SUM(ps.reel) as stockqty"; +$sql.= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue, SUM(ps.reel) as stockqty,"; // Add fields from extrafields -foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ", ef.".$key.' as options_'.$key : ''); +if (! empty($extrafields->attributes[$object->table_element]['label'])) + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.' as options_'.$key.', ' : ''); +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql=preg_replace('/, $/', '', $sql); $sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps ON e.rowid = ps.fk_entrepot"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON ps.fk_product = p.rowid"; -if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot_extrafields as ef on (e.rowid = ef.fk_object)"; +if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (e.rowid = ef.fk_object)"; $sql.= " WHERE e.entity IN (".getEntity('stock').")"; if ($search_ref) $sql.= natural_search("e.ref", $search_ref); // ref if ($search_label) $sql.= natural_search("e.lieu", $search_label); // label @@ -118,6 +124,10 @@ if ($search_status != '' && $search_status >= 0) $sql.= " AND e.statut = ".$sear if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall); // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; $sql.= " GROUP BY e.rowid, e.ref, e.statut, e.lieu, e.address, e.zip, e.town, e.fk_pays, e.fk_parent"; $totalnboflines=0; $result=$db->query($sql); @@ -241,6 +251,7 @@ if ($result) $warehouse->label = $obj->ref; $warehouse->lieu = $obj->lieu; $warehouse->fk_parent = $obj->fk_parent; + $warehouse->statut = $obj->statut; print ''; print '' . $warehouse->getNomUrl(1) . ''; diff --git a/htdocs/product/stock/movement_list.php b/htdocs/product/stock/movement_list.php index f62b732cf7e..149804ee966 100644 --- a/htdocs/product/stock/movement_list.php +++ b/htdocs/product/stock/movement_list.php @@ -420,7 +420,7 @@ $formproduct=new FormProduct($db); if (!empty($conf->projet->enabled)) $formproject=new FormProjets($db); $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tobatch, p.fk_product_type as type, p.entity,"; -$sql.= " e.ref as stock, e.rowid as entrepot_id, e.lieu,"; +$sql.= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu, e.fk_parent, e.statut,"; $sql.= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,"; $sql.= " m.batch, m.price,"; $sql.= " m.type_mouvement,"; @@ -988,8 +988,12 @@ if ($resql) $productlot->sellby= $objp->sellby; $warehousestatic->id=$objp->entrepot_id; - $warehousestatic->libelle=$objp->stock; + $warehousestatic->ref=$objp->warehouse_ref; + $warehousestatic->libelle=$objp->warehouse_ref; + $warehousestatic->label=$objp->warehouse_ref; $warehousestatic->lieu=$objp->lieu; + $warehousestatic->fk_parent = $objp->fk_parent; + $warehousestatic->statut = $objp->statut; $arrayofuniqueproduct[$objp->rowid]=$objp->produit; if(!empty($objp->fk_origin)) { diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php index 2c0515d309c..41c9b151865 100644 --- a/htdocs/product/stock/product.php +++ b/htdocs/product/stock/product.php @@ -827,7 +827,7 @@ if (! $variants) { print ''; } - $sql = "SELECT e.rowid, e.ref as label, e.lieu, ps.reel, ps.rowid as product_stock_id, p.pmp"; + $sql = "SELECT e.rowid, e.ref, e.lieu, e.fk_parent, e.statut, ps.reel, ps.rowid as product_stock_id, p.pmp"; $sql .= " FROM " . MAIN_DB_PREFIX . "entrepot as e,"; $sql .= " " . MAIN_DB_PREFIX . "product_stock as ps"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = ps.fk_product"; @@ -851,9 +851,15 @@ if (! $variants) { $var = false; while ($i < $num) { $obj = $db->fetch_object($resql); + $entrepotstatic->id = $obj->rowid; - $entrepotstatic->libelle = $obj->label; + $entrepotstatic->ref = $obj->ref; + $entrepotstatic->libelle = $obj->ref; + $entrepotstatic->label = $obj->ref; $entrepotstatic->lieu = $obj->lieu; + $entrepotstatic->fk_parent = $obj->fk_parent; + $entrepotstatic->statut = $obj->statut; + $stock_real = price2num($obj->reel, 'MS'); print ''; print '' . $entrepotstatic->getNomUrl(1) . ''; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index c8c9e2e9fc6..374cebb8583 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -3935,11 +3935,9 @@ class Societe extends CommonObject $outstandingOpened+=$obj->total_ttc - $paiement - $creditnotes - $deposits; } - + //if credit note is converted but not used if($mode == 'supplier' && $obj->type == FactureFournisseur::TYPE_CREDIT_NOTE && $tmpobject->isCreditNoteUsed())$outstandingOpened-=$tmpobject->getSumFromThisCreditNotesNotUsed(); - - } return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); // 'opened' is 'incl taxes' } diff --git a/test/phpunit/AllTests.php b/test/phpunit/AllTests.php index ee7ec9375d6..db3dc95e434 100644 --- a/test/phpunit/AllTests.php +++ b/test/phpunit/AllTests.php @@ -239,6 +239,8 @@ class AllTests require_once dirname(__FILE__).'/FormAdminTest.php'; $suite->addTestSuite('FormAdminTest'); + require_once dirname(__FILE__).'/FormTest.php'; + $suite->addTestSuite('FormTest'); require_once dirname(__FILE__).'/ModulesTest.php'; // At end because it's the longer $suite->addTestSuite('ModulesTest'); diff --git a/test/phpunit/FormAdminTest.php b/test/phpunit/FormAdminTest.php index 20c22a76cd8..b58b43b368b 100644 --- a/test/phpunit/FormAdminTest.php +++ b/test/phpunit/FormAdminTest.php @@ -119,7 +119,7 @@ class FormAdminTest extends PHPUnit\Framework\TestCase } /** - * testFactureCreate + * testSelectPaperFormat * * @return int */ diff --git a/test/phpunit/FormTest.php b/test/phpunit/FormTest.php new file mode 100644 index 00000000000..69594325b20 --- /dev/null +++ b/test/phpunit/FormTest.php @@ -0,0 +1,149 @@ + + * + * 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 3 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, see . + * or see http://www.gnu.org/ + */ + +/** + * \file test/phpunit/FormTest.php + * \ingroup test + * \brief PHPUnit test + * \remarks To run this script as CLI: phpunit filename.php + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/core/class/html.form.class.php'; + +if (empty($user->id)) +{ + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class FormTest extends PHPUnit\Framework\TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return FactureTest + */ + public function __construct() + { + parent::__construct(); + + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + // Static methods + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + // tear down after class + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + /** + * testSelectProduitsList + * + * @return int + */ + public function testSelectProduitsList() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new Form($this->savdb); + $result=$localobject->select_produits_list('', 'productid', '', 5, 0, '', 1, 2, 1); + + $this->assertEquals(count($result), 5); + print __METHOD__." result=".$result."\n"; + + $conf->global->ENTREPOT_EXTRA_STATUS = 1; + + // Exclude stock in warehouseinternal + $result=$localobject->select_produits_list('', 'productid', '', 5, 0, '', 1, 2, 1, 0, '1', 0, '', 0, 'warehouseclosed,warehouseopen'); + $this->assertEquals(count($result), 5); + print __METHOD__." result=".$result."\n"; + + return $result; + } +}