diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 8df2c1d36a4..803ba1823f1 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -91,7 +91,7 @@ $hookmanager->initHooks(array('admin')); // Put here declaration of dictionaries properties // Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this. -$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 0, 25, 0); +$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 41, 0, 15, 30, 0, 37, 42, 0, 25, 0); // Name of SQL tables of dictionaries $tabname = array(); @@ -136,6 +136,7 @@ $tabname[38] = MAIN_DB_PREFIX."c_socialnetworks"; $tabname[39] = MAIN_DB_PREFIX."c_prospectcontactlevel"; $tabname[40] = MAIN_DB_PREFIX."c_stcommcontact"; $tabname[41] = MAIN_DB_PREFIX."c_transport_mode"; +$tabname[42] = MAIN_DB_PREFIX."c_product_nature"; // Dictionary labels $tablib = array(); @@ -180,6 +181,7 @@ $tablib[38] = "DictionarySocialNetworks"; $tablib[39] = "DictionaryProspectContactLevel"; $tablib[40] = "DictionaryProspectContactStatus"; $tablib[41] = "DictionaryTransportMode"; +$tablib[42] = "DictionaryProductNature"; // Requests to extract data $tabsql = array(); @@ -224,6 +226,7 @@ $tabsql[38] = "SELECT rowid, entity, code, label, url, icon, active FROM ".MAIN_ $tabsql[39] = "SELECT code, label as libelle, sortorder, active FROM ".MAIN_DB_PREFIX."c_prospectcontactlevel"; $tabsql[40] = "SELECT id as rowid, code, libelle, picto, active FROM ".MAIN_DB_PREFIX."c_stcommcontact"; $tabsql[41] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_transport_mode"; +$tabsql[42] = "SELECT rowid as rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_product_nature"; // Criteria to sort dictionaries $tabsqlsort = array(); @@ -268,6 +271,7 @@ $tabsqlsort[38] = "rowid, code ASC"; $tabsqlsort[39] = "sortorder ASC"; $tabsqlsort[40] = "code ASC"; $tabsqlsort[41] = "code ASC"; +$tabsqlsort[42] = "code ASC"; // Field names in select result for dictionary display $tabfield = array(); @@ -312,6 +316,7 @@ $tabfield[38] = "code,label,url,icon,entity"; $tabfield[39] = "code,libelle,sortorder"; $tabfield[40] = "code,libelle,picto"; $tabfield[41] = "code,label"; +$tabfield[42] = "code,label"; // Edit field names for editing a record $tabfieldvalue = array(); @@ -356,6 +361,7 @@ $tabfieldvalue[38] = "code,label,url,icon"; $tabfieldvalue[39] = "code,libelle,sortorder"; $tabfieldvalue[40] = "code,libelle,picto"; $tabfieldvalue[41] = "code,label"; +$tabfieldvalue[42] = "code,label"; // Field names in the table for inserting a record $tabfieldinsert = array(); @@ -401,6 +407,7 @@ $tabfieldinsert[38] = "code,label,url,icon,entity"; $tabfieldinsert[39] = "code,label,sortorder"; $tabfieldinsert[40] = "code,libelle,picto"; $tabfieldinsert[41] = "code,label"; +$tabfieldinsert[42] = "code,label"; // Rowid name of field depending if field is autoincrement on or off.. // Use "" if id field is "rowid" and has autoincrement on @@ -447,6 +454,7 @@ $tabrowid[38] = ""; $tabrowid[39] = "code"; $tabrowid[40] = "id"; $tabrowid[41] = ""; +$tabrowid[42] = "rowid"; // Condition to show dictionary in setup page $tabcond = array(); @@ -491,6 +499,7 @@ $tabcond[38] = !empty($conf->socialnetworks->enabled); $tabcond[39] = (!empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)); $tabcond[40] = (!empty($conf->societe->enabled) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)); $tabcond[41] = !empty($conf->intracommreport->enabled); +$tabcond[42] = !empty($conf->product->enabled); // List of help for fields $tabhelp = array(); @@ -535,6 +544,7 @@ $tabhelp[38] = array('code'=>$langs->trans("EnterAnyCode"), 'url' => $langs->tra $tabhelp[39] = array('code'=>$langs->trans("EnterAnyCode")); $tabhelp[40] = array('code'=>$langs->trans("EnterAnyCode"), 'picto'=>$langs->trans("PictoHelp")); $tabhelp[41] = array('code'=>$langs->trans("EnterAnyCode")); +$tabhelp[42] = array('code'=>$langs->trans("EnterAnyCode")); // List of check for fields (NOT USED YET) $tabfieldcheck = array(); @@ -579,6 +589,7 @@ $tabfieldcheck[38] = array(); $tabfieldcheck[39] = array(); $tabfieldcheck[40] = array(); $tabfieldcheck[41] = array(); +$tabfieldcheck[42] = array(); // Complete all arrays with entries found into modules complete_dictionary_with_modules($taborder, $tabname, $tablib, $tabsql, $tabsqlsort, $tabfield, $tabfieldvalue, $tabfieldinsert, $tabrowid, $tabcond, $tabhelp, $tabfieldcheck); @@ -1614,6 +1625,9 @@ if ($id) $valuetoshow = ($obj->label && $key != strtoupper($obj->label) ? $key : $obj->{$fieldlist[$field]}); } elseif ($fieldlist[$field] == 'code' && $id == 3) { $valuetoshow = $obj->state_code; + } elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_product_nature') { + $langs->load("products"); + $valuetoshow = $langs->trans($obj->{$fieldlist[$field]}); } $class .= ($class ? ' ' : '').'tddict'; if ($fieldlist[$field] == 'note' && $id == 10) $class .= ' tdoverflowmax200'; @@ -1631,7 +1645,7 @@ if ($id) $iserasable = 1; $canbedisabled = 1; $canbemodified = 1; - if (isset($obj->code) && $id != 10) + if (isset($obj->code) && $id != 10 && $id != 42) { if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) { $iserasable = 0; $canbedisabled = 0; } elseif ($obj->code == 'RECEP') { $iserasable = 0; $canbedisabled = 0; } elseif ($obj->code == 'EF0') { $iserasable = 0; $canbedisabled = 0; } } @@ -1643,6 +1657,7 @@ if ($id) if (isset($obj->type) && in_array($obj->type, array('system', 'systemauto'))) { $iserasable = 0; } if (in_array($obj->code, array('AC_OTH', 'AC_OTH_AUTO')) || in_array($obj->type, array('systemauto'))) { $canbedisabled = 0; $canbedisabled = 0; } $canbemodified = $iserasable; + if ($obj->code == 'RECEP') $canbemodified = 1; if ($tabname[$id] == MAIN_DB_PREFIX."c_actioncomm") $canbemodified = 1; diff --git a/htdocs/core/class/cproductnature.class.php b/htdocs/core/class/cproductnature.class.php new file mode 100644 index 00000000000..d098f56d82b --- /dev/null +++ b/htdocs/core/class/cproductnature.class.php @@ -0,0 +1,362 @@ + + * Copyright (C) 2020 Florian HENRY + * + * 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 . + */ + +/** + * \file htdocs/core/class/cproductnature.class.php + * \ingroup core + * \brief This file is CRUD class file (Create/Read/Update/Delete) for c_units dictionary + */ + + +/** + * Class of dictionary of nature of product (used by imports) + */ +class CProductNature // extends CommonObject +{ + /** + * @var DoliDB Database handler. + */ + public $db; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string[] Error codes (or messages) + */ + public $errors = array(); + public $records = array(); + + public $element='cproductnbature'; + public $table_element='c_product_nature'; + + /** + * @var int ID + */ + public $id; + + public $code; + public $label; + public $active; + + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } + + + /** + * Create object into database + * + * @param User $user User that create + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + + if (isset($this->id)) $this->id = (int) $this->id; + if (isset($this->code)) $this->code = trim($this->code); + if (isset($this->label)) $this->libelle = trim($this->label); + if (isset($this->active)) $this->active = trim($this->active); + + // Check parameters + // Put here code to add control on parameters values + + // Insert request + $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element."("; + $sql .= "rowid,"; + $sql .= "code,"; + $sql .= "label,"; + $sql .= "active"; + $sql .= ") VALUES ("; + $sql .= " ".(!isset($this->id) ? 'NULL' : ((int) $this->id)) .","; + $sql .= " ".(!isset($this->code) ? 'NULL' : ((int) $this->code)).","; + $sql .= " ".(!isset($this->label) ? 'NULL' : "'".$this->db->escape($this->label)."'").","; + $sql .= " ".(!isset($this->active) ? 'NULL' : ((int) $this->db->escape($this->active))).","; + $sql .= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + if (!$error) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element); + } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return $this->id; + } + } + + + /** + * Load object in memory from database + * + * @param int $id Id of CUnit object to fetch (rowid) + * @param string $code Code + * @return int <0 if KO, >0 if OK + */ + public function fetch($id, $code = '') + { + global $langs; + + $sql = "SELECT"; + $sql .= " t.rowid,"; + $sql .= " t.code,"; + $sql .= " t.label,"; + $sql .= " t.active"; + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql_where = array(); + if ($id) $sql_where[] = " t.rowid = ".$id; + if ($code>=0) $sql_where[] = " t.code = ". ((int) $code); + if (count($sql_where) > 0) { + $sql .= ' WHERE '.implode(' AND ', $sql_where); + } + + $resql = $this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->code = $obj->code; + $this->label = $obj->label; + $this->active = $obj->active; + } + $this->db->free($resql); + + return 1; + } else { + $this->error = "Error ".$this->db->lasterror(); + return -1; + } + } + + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $sql = 'SELECT'; + $sql .= " t.rowid,"; + $sql .= " t.code,"; + $sql .= " t.label,"; + $sql .= " t.active"; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key == 't.rowid' || $key == 't.active' || $key == 't.code') { + $sqlwhere[] = $key.'='.(int) $value; + } elseif (strpos($key, 'date') !== false) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key == 't.label') { + $sqlwhere[] = $key.' = \''.$this->db->escape($value).'\''; + } else { + $sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' WHERE ('.implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' '.$this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $this->records = array(); + $num = $this->db->num_rows($resql); + if ($num > 0) { + while ($obj = $this->db->fetch_object($resql)) + { + $record = new self($this->db); + + $record->id = $obj->rowid; + $record->code = $obj->code; + $record->label = $obj->label; + $this->records[$record->id] = $record; + } + } + $this->db->free($resql); + + return $this->records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + + /** + * Update object into database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update($user = null, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + if (isset($this->code)) $this->code = trim($this->code); + if (isset($this->label)) $this->label = trim($this->label); + if (isset($this->active)) $this->active = trim($this->active); + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + $sql .= " code=".(isset($this->code) ? ((int) $this->code) : "null").","; + $sql .= " label=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").","; + $sql .= " active=".(isset($this->active) ? ((int) $this->active) : "null"); + $sql .= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + + /** + * Delete object in database + * + * @param User $user User that delete + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::delete", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { $error++; $this->errors[] = "Error ".$this->db->lasterror(); } + + // Commit or rollback + if ($error) + { + foreach ($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + + /** + * Get unit from code + * @param string $code code of unit + * @param string $mode 0= id , short_label=Use short label as value, code=use code + * @return int <0 if KO, Id of code if OK + */ + public function getProductNatureFromCode($code, $mode = 'code') + { + if ($mode == 'label') { + return dol_getIdFromCode($this->db, $code, $this->table_element, 'label', 'code'); + } elseif ($mode == 'code'){ + return dol_getIdFromCode($this->db, $code, $this->table_element, 'code', 'code'); + } + + return $code; + } +} diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index 7eef5043c81..3ed99741715 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -477,7 +477,14 @@ class modProduct extends DolibarrModules 'class' => 'Ccountry', 'method' => 'fetch', 'dict' => 'DictionaryCountry' - ) + ), + 'p.finished'=> array( + 'rule' => 'fetchidfromcodeorlabel', + 'classfile' => '/core/class/cproductnature.class.php', + 'class' => 'CProductNature', + 'method' => 'fetch', + 'dict' => 'DictionaryProductNature' + ), ); $this->import_regex_array[$r] = array( @@ -488,7 +495,6 @@ class modProduct extends DolibarrModules 'p.fk_product_type' => '^[0|1]$', 'p.datec' => '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$', 'p.recuperableonly' => '^[0|1]$', - 'p.finished' => '^[0|1]$' ); if (!empty($conf->stock->enabled)) {//if Stock module enabled @@ -578,7 +584,7 @@ class modProduct extends DolibarrModules 'p.surface_units' => 'm2', // Use a unit of measure from the dictionary. m2/cm2/mm2 etc....matches field "Short label" for unit type "surface" in table "' . MAIN_DB_PREFIX . 'c_units', 'p.volume' => "", 'p.volume_units' => 'm3', //Use a unit of measure from the dictionary. m3/cm3/mm3 etc....matches field "Short label" for unit type "volume" in table "' . MAIN_DB_PREFIX . 'c_units', - 'p.finished' => '0 (raw material) / 1 (finished goods)' + 'p.finished' => '0 (raw material) / 1 (finished goods), matches field "code" in dictionary table "'.MAIN_DB_PREFIX.'c_product_nature"' ); //clauses copied from import_fields_array if (!empty($conf->stock->enabled)) $import_sample = array_merge($import_sample, array( diff --git a/htdocs/install/mysql/data/llx_c_product_nature.sql b/htdocs/install/mysql/data/llx_c_product_nature.sql new file mode 100644 index 00000000000..8351ff2ab79 --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_product_nature.sql @@ -0,0 +1,28 @@ +-- Copyright (C) 2020 florian HENRY florian.henry@scopen.fr +-- +-- 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 . +-- +-- + +-- +-- Do not place a comment at the end of the line, this file is parsed when +-- from the install and all '--' are removed. +-- +-- Ne pas placer de commentaire en fin de ligne, ce fichier est parsé lors +-- de l'install et tous les sigles '--' sont supprimés. +-- + +INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); + diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 55cf12dc909..389d7dc478e 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -406,3 +406,18 @@ ALTER TABLE llx_projet_task_time MODIFY COLUMN datec datetime; DELETE FROM llx_user_rights WHERE fk_id IN (SELECT id FROM llx_rights_def where module = 'holiday' and perms = 'lire_tous'); DELETE FROM llx_rights_def where module = 'holiday' and perms = 'lire_tous'; +CREATE TABLE llx_c_product_nature ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code tinyint NOT NULL, + label varchar(100), + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; + +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code, active); + +INSERT INTO llx_c_product_nature (code, label, active) VALUES (0, 'RowMaterial', 1); +INSERT INTO llx_c_product_nature (code, label, active) VALUES (1, 'Finished', 1); + +ALTER TABLE llx_product MODIFY COLUMN finished tinyint DEFAULT NULL; +ALTER TABLE llx_product ADD CONSTRAINT fk_product_finished FOREIGN KEY (finished) REFERENCES llx_c_product_nature (code); + diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.key.sql b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql new file mode 100644 index 00000000000..b6a3d2130bf --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_product_nature.key.sql @@ -0,0 +1 @@ +ALTER TABLE llx_c_product_nature ADD UNIQUE INDEX uk_c_product_nature(code, active); diff --git a/htdocs/install/mysql/tables/llx_c_product_nature.sql b/htdocs/install/mysql/tables/llx_c_product_nature.sql new file mode 100644 index 00000000000..3c467ce7cf8 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_product_nature.sql @@ -0,0 +1,24 @@ +-- ======================================================================== +-- Copyright (C) 2020 Florian HENRY +-- +-- 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 . +-- +-- ======================================================================== + +CREATE TABLE llx_c_product_nature ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code tinyint NOT NULL, + label varchar(100), + active tinyint DEFAULT 1 NOT NULL +) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_product.key.sql b/htdocs/install/mysql/tables/llx_product.key.sql index c3dd33c88c5..c0526a8f2cc 100644 --- a/htdocs/install/mysql/tables/llx_product.key.sql +++ b/htdocs/install/mysql/tables/llx_product.key.sql @@ -33,6 +33,7 @@ ALTER TABLE llx_product ADD INDEX idx_product_fk_barcode_type (fk_barcode_type); ALTER TABLE llx_product ADD INDEX idx_product_fk_project (fk_project); ALTER TABLE llx_product ADD UNIQUE INDEX uk_product_barcode (barcode, fk_barcode_type, entity); ALTER TABLE llx_product ADD CONSTRAINT fk_product_fk_unit FOREIGN KEY (fk_unit) REFERENCES llx_c_units (rowid); +ALTER TABLE llx_product ADD CONSTRAINT fk_product_finished FOREIGN KEY (finished) REFERENCES llx_c_product_nature (code); ALTER TABLE llx_product ADD CONSTRAINT fk_product_fk_country FOREIGN KEY (fk_country) REFERENCES llx_c_country (rowid); ALTER TABLE llx_product ADD CONSTRAINT fk_product_barcode_type FOREIGN KEY (fk_barcode_type) REFERENCES llx_c_barcode_type (rowid); diff --git a/htdocs/install/mysql/tables/llx_product.sql b/htdocs/install/mysql/tables/llx_product.sql index bc583a76ce2..2431c884c62 100644 --- a/htdocs/install/mysql/tables/llx_product.sql +++ b/htdocs/install/mysql/tables/llx_product.sql @@ -92,7 +92,7 @@ create table llx_product lifo double(24,8), -- To store valuation of stock calculated using lifo method, for this product. TODO Not used, should be replaced by stock value stored into movement table. fk_default_warehouse integer DEFAULT NULL, canvas varchar(32) DEFAULT NULL, - finished tinyint DEFAULT NULL, -- 1=manufactured product, 0=matiere premiere + finished tinyint DEFAULT NULL, -- see dictionnary c_product_nature hidden tinyint DEFAULT 0, -- Not used. Deprecated. import_key varchar(14), -- Import key model_pdf varchar(255), -- model save dodument used diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index e887b29879d..b2fb44dca4d 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2065,3 +2065,4 @@ TemplateUpdated=Template updated TemplateDeleted=Template deleted MailToSendEventPush=Template for event reminder emails SwitchThisForABetterSecurity=Switching this value to %s is recommended for more security +DictionaryProductNature= Nature of product diff --git a/htdocs/product/card.php b/htdocs/product/card.php index e3467e871c8..62813ee2a57 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -321,8 +321,19 @@ if (empty($reshook)) $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit $object->volume = GETPOST('volume'); $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit - $object->finished = GETPOST('finished', 'alpha'); - $object->fk_unit = GETPOST('units', 'alpha'); // This is the fk_unit of sale + $finished = GETPOST('finished', 'int'); + if ($finished > 0) { + $object->finished = $finished; + } else { + $object->finished = null; + } + + $units = GETPOST('units', 'int'); + if ($units > 0) { + $object->fk_unit = $units; + } else { + $object->fk_unit = null; + } $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha'); $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha'); @@ -435,10 +446,15 @@ if (empty($reshook)) $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit $object->volume = GETPOST('volume'); $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit - $object->finished = GETPOST('finished', 'alpha'); + + $finished = GETPOST('finished', 'int'); + if ($finished >= 0) { + $object->finished = $finished; + } else { + $object->finished = null; + } $units = GETPOST('units', 'int'); - if ($units > 0) { $object->fk_unit = $units; } else { @@ -1547,8 +1563,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) } else { // Nature print ''.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).''; - $statutarray = array('-1'=>' ', '1' => $langs->trans("Finished"), '0' => $langs->trans("RowMaterial")); - print $form->selectarray('finished', $statutarray, $object->finished); + print $formproduct->selectProductNature('finished', $object->finished); print ''; // Brut Weight diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index a0fd2bdb10c..0de89bf78ff 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -425,6 +425,75 @@ class FormProduct return $return; } + /** + * Return a combo box with list of units + * NAture of product labels are defined in llx_c_product_nature + * + * @param string $name Name of HTML field + * @param string $selected Preselected value + * @param int $mode 1=Use label as value, 0=Use code + * @param int $showempty 1=show empty value, 0= no + * @return string + */ + public function selectProductNature($name = 'finished', $selected = '', $mode = 0, $showempty = 1) + { + global $langs, $db; + + $langs->load('products'); + + $return = ''; + + // TODO Use a cache + require_once DOL_DOCUMENT_ROOT.'/core/class/cproductnature.class.php'; + $productNature = new CProductNature($db); + + $filter = array(); + $filter['t.active'] = 1; + + $result = $productNature->fetchAll( + '', + '', + 0, + 0, + $filter + ); + if ($result < 0) { + dol_print_error($db); + return -1; + } else { + $return .= ''; + } + + return $return; + } + /** * Return list of lot numbers (stock from product_batch) with stock location and stock qty * diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index bc5f764d108..2aa9b3330e3 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -983,7 +983,7 @@ class Product extends CommonObject $sql .= ", tosell = ".(int) $this->status; $sql .= ", tobuy = ".(int) $this->status_buy; $sql .= ", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ? '0' : (int) $this->status_batch); - $sql .= ", finished = ".((!isset($this->finished) || $this->finished < 0) ? "null" : (int) $this->finished); + $sql .= ", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished == '') ? "null" : (int) $this->finished); $sql .= ", net_measure = ".($this->net_measure != '' ? "'".$this->db->escape($this->net_measure)."'" : 'null'); $sql .= ", net_measure_units = ".($this->net_measure_units != '' ? "'".$this->db->escape($this->net_measure_units)."'" : 'null'); $sql .= ", weight = ".($this->weight != '' ? "'".$this->db->escape($this->weight)."'" : 'null'); @@ -4685,10 +4685,21 @@ class Product extends CommonObject global $langs; $langs->load('products'); - if ($this->finished == '0') { return $langs->trans("RowMaterial"); - } - if ($this->finished == '1') { return $langs->trans("Finished"); + if (isset($this->finished) && $this->finished>=0) { + $sql = 'SELECT label, code FROM '.MAIN_DB_PREFIX.'c_product_nature where code='.((int) $this->finished).' AND active=1'; + $resql = $this->db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + $res = $this->db->fetch_array($resql); + $label = $langs->trans($res['label']); + $this->db->free($resql); + return $label; + } else { + $this->error = $this->db->error().' sql='.$sql; + dol_syslog(__METHOD__.' Error '.$this->error, LOG_ERR); + return -1; + } } + return ''; } diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 4abf8fd4a8b..db77e7714f1 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -40,6 +40,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; if (!empty($conf->categorie->enabled)) require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; @@ -75,6 +76,7 @@ $search_accountancy_code_sell_export = GETPOST("search_accountancy_code_sell_exp $search_accountancy_code_buy = GETPOST("search_accountancy_code_buy", 'alpha'); $search_accountancy_code_buy_intra = GETPOST("search_accountancy_code_buy_intra", 'alpha'); $search_accountancy_code_buy_export = GETPOST("search_accountancy_code_buy_export", 'alpha'); +$search_finished = GETPOST("search_finished", 'int'); $optioncss = GETPOST('optioncss', 'alpha'); $type = GETPOST("type", "int"); @@ -109,6 +111,7 @@ $hookmanager->initHooks(array('productservicelist')); $extrafields = new ExtraFields($db); $form = new Form($db); $formcompany = new FormCompany($db); +$formproduct = new FormProduct($db); // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); @@ -212,7 +215,7 @@ $arrayfields = array( 'p.tobatch'=>array('label'=>$langs->trans("ManageLotSerial"), 'checked'=>0, 'enabled'=>(!empty($conf->productbatch->enabled)), 'position'=>60), 'p.fk_country'=>array('label'=>$langs->trans("Country"), 'checked'=>0, 'position'=>100), 'p.fk_state'=>array('label'=>$langs->trans("State"), 'checked'=>0, 'position'=>101), - 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0, 'position'=>400), + 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0, 'position'=>400), 'p.accountancy_code_sell_intra'=>array('label'=>$langs->trans("ProductAccountancySellIntraCode"), 'checked'=>0, 'enabled'=>$isInEEC, 'position'=>401), 'p.accountancy_code_sell_export'=>array('label'=>$langs->trans("ProductAccountancySellExportCode"), 'checked'=>0, 'position'=>402), 'p.accountancy_code_buy'=>array('label'=>$langs->trans("ProductAccountancyBuyCode"), 'checked'=>0, 'position'=>403), @@ -285,6 +288,7 @@ if (empty($reshook)) $search_state = ""; $search_vatrate = ""; $search_tobatch = ''; + $search_finished = ''; //$search_type=''; // There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type. $show_childproducts = ''; @@ -409,6 +413,7 @@ if ($fourn_id > 0) $sql .= " AND pfp.fk_soc = ".$fourn_id; if ($search_tobatch != '' && $search_tobatch >= 0) $sql .= " AND p.tobatch = ".$db->escape($search_tobatch); if ($search_country) $sql .= " AND p.fk_country = ".$search_country; if ($search_state) $sql .= " AND p.fk_state = ".$search_state; +if ($search_finished>=0 && $search_finished!=='') $sql .= " AND p.finished = ".$search_finished; if ($search_accountancy_code_sell) $sql .= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell); if ($search_accountancy_code_sell_intra) $sql .= natural_search('p.accountancy_code_sell_intra', $search_accountancy_code_sell_intra); if ($search_accountancy_code_sell_export) $sql .= natural_search('p.accountancy_code_sell_export', $search_accountancy_code_sell_export); @@ -522,6 +527,7 @@ if ($resql) if ($search_accountancy_code_buy) $param = "&search_accountancy_code_buy=".urlencode($search_accountancy_code_buy); if ($search_accountancy_code_buy_intra) $param = "&search_accountancy_code_buy_intra=".urlencode($search_accountancy_code_buy_intra); if ($search_accountancy_code_buy_export) $param = "&search_accountancy_code_buy_export=".urlencode($search_accountancy_code_buy_export); + if ($search_finished) $param = "&search_finished=".urlencode($search_finished); // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; @@ -677,6 +683,7 @@ if ($resql) if (!empty($arrayfields['p.finished']['checked'])) { print ''; + print $formproduct->selectProductNature('search_finished', $search_finished); print ''; } // Weight