From 94c12cfb2e7df16adb926f966db8a8ac89d21259 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 22 Oct 2012 17:24:14 +0200 Subject: [PATCH 01/25] Task # 559 : start of price by quantity management --- htdocs/install/mysql/migration/3.2.0-3.3.0.sql | 14 ++++++++++++++ htdocs/langs/en_US/products.lang | 4 +++- htdocs/langs/fr_FR/products.lang | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql index 0600ddfe9a7..3eb339b57dd 100755 --- a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql +++ b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql @@ -781,3 +781,17 @@ ALTER TABLE llx_categorie MODIFY COLUMN label varchar(255) NOT NULL; ALTER TABLE llx_categorie ADD UNIQUE INDEX uk_categorie_ref (entity, fk_parent, label, type); ALTER TABLE llx_categorie ADD INDEX idx_categorie_type (type); ALTER TABLE llx_categorie ADD INDEX idx_categorie_label (label); + +-- [ task #559 ] Price by quantity management +CREATE TABLE llx_product_price_by_qty +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_product_price integer NOT NULL, + date_price timestamp, + price double (24,8) DEFAULT 0, + price_ttc double (24,8) DEFAULT NULL, + qty_min real DEFAULT 0, + qty_max real DEFAULT 99999 +)ENGINE=innodb; + +ALTER TABLE llx_product_price ADD price_by_qty INT NOT NULL DEFAULT 0; diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 5c107a7e50b..8881ce278f9 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -180,4 +180,6 @@ AddThisServiceCard=Create service card HelpAddThisServiceCard=This option allows you to create or clone a service if it does not exist. CurrentProductPrice=Current price AlwaysUseNewPrice=Always use current price of product/service -AlwaysUseFixedPrice=Use the fixed price \ No newline at end of file +AlwaysUseFixedPrice=Use the fixed price +PriceByQuantity=Price by quantity +PriceByQuantityRange=Quantity range \ No newline at end of file diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang index 37c70e544d9..c641adee29a 100644 --- a/htdocs/langs/fr_FR/products.lang +++ b/htdocs/langs/fr_FR/products.lang @@ -180,4 +180,6 @@ AddThisServiceCard=Créer fiche service HelpAddThisServiceCard=Cette option permet de créer ou de cloner une fiche service si elle n'existe pas. CurrentProductPrice=Prix actuel AlwaysUseNewPrice=Toujours utiliser le prix du jour -AlwaysUseFixedPrice=Utiliser le prix fixé \ No newline at end of file +AlwaysUseFixedPrice=Utiliser le prix fixé +PriceByQuantity=Prix par quantité +PriceByQuantityRange=Grille de quantités \ No newline at end of file From 8ba55f49f16eff4e89c57d98e38c20e3cbbcd3b4 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 22 Oct 2012 17:47:15 +0200 Subject: [PATCH 02/25] Task # 559 : start of price by quantity management --- htdocs/product/class/product.class.php | 107 ++++++++- htdocs/product/price.php | 294 ++++++++++++++++++++++++- 2 files changed, 392 insertions(+), 9 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index d6290ce6345..3599552b860 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -61,6 +61,11 @@ class Product extends CommonObject var $multiprices_ttc=array(); var $multiprices_base_type=array(); var $multiprices_tva_tx=array(); + //! Price by quantity arrays + var $price_by_qty; + var $prices_by_qty=array(); + var $prices_by_qty_id=array(); + var $prices_by_qty_list=array(); //! Default VAT rate of product var $tva_tx; //! French VAT NPR (0 or 1) @@ -214,6 +219,10 @@ class Product extends CommonObject if (empty($this->price)) $this->price = 0; if (empty($this->price_min)) $this->price_min = 0; + + // Price by quantity + if (empty($this->price_by_qty)) $this->price_by_qty = 0; + if (empty($this->status)) $this->status = 0; if (empty($this->status_buy)) $this->status_buy = 0; if (empty($this->finished)) $this->finished = 0; @@ -802,9 +811,9 @@ class Product extends CommonObject // Add new price $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price(price_level,date_price,fk_product,fk_user_author,price,price_ttc,price_base_type,tosell,tva_tx,recuperableonly,"; - $sql.= " localtax1_tx, localtax2_tx, price_min,price_min_ttc) "; + $sql.= " localtax1_tx, localtax2_tx, price_min,price_min_ttc,price_by_qty) "; $sql.= " VALUES(".($level?$level:1).", '".$this->db->idate($now)."',".$this->id.",".$user->id.",".$this->price.",".$this->price_ttc.",'".$this->price_base_type."',".$this->status.",".$this->tva_tx.",".$this->tva_npr.","; - $sql.= " ".$this->localtax1_tx.",".$this->localtax2_tx.",".$this->price_min.",".$this->price_min_ttc; + $sql.= " ".$this->localtax1_tx.",".$this->localtax2_tx.",".$this->price_min.",".$this->price_min_ttc.",".$this->price_by_qty; $sql.= ")"; dol_syslog(get_class($this)."_log_price sql=".$sql); @@ -941,9 +950,10 @@ class Product extends CommonObject * @param double $newminprice New price min * @param int $level 0=standard, >0 = level if multilevel prices * @param int $newnpr 0=Standard vat rate, 1=Special vat rate for French NPR VAT + * @param int $newpsq 1 if it has price by quantity * @return int <0 if KO, >0 if OK */ - function updatePrice($id, $newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0) + function updatePrice($id, $newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0, $newpsq=0) { global $conf,$langs; @@ -1032,6 +1042,9 @@ class Product extends CommonObject $this->localtax1_tx = $localtax1; $this->localtax2_tx = $localtax2; + // Price by quantity + $this->price_by_qty = $newpsq; + $this->_log_price($user,$level); // Appel des triggers @@ -1166,7 +1179,7 @@ class Product extends CommonObject for ($i=1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) { $sql = "SELECT price, price_ttc, price_min, price_min_ttc,"; - $sql.= " price_base_type, tva_tx, tosell"; + $sql.= " price_base_type, tva_tx, tosell, price_by_qty, rowid"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price"; $sql.= " WHERE price_level=".$i; $sql.= " AND fk_product = '".$this->id."'"; @@ -1183,6 +1196,39 @@ class Product extends CommonObject $this->multiprices_min_ttc[$i]=$result["price_min_ttc"]; $this->multiprices_base_type[$i]=$result["price_base_type"]; $this->multiprices_tva_tx[$i]=$result["tva_tx"]; + + // Price by quantity + $this->prices_by_qty[$i]=$result["price_by_qty"]; + $this->prices_by_qty_id[$i]=$result["rowid"]; + // Récuperation de la liste des prix selon qty si flag positionné + if ($this->prices_by_qty[$i] == 1) + { + $sql = "SELECT rowid,price, price_ttc,qty_min,qty_max"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; + $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[$i]."'"; + $sql.= " ORDER BY qty_min ASC"; + $resultat=array(); + $resql = $this->db->query($sql) ; + if ($resql) + { + $ii=0; + while ($result= $this->db->fetch_array($resql)) { + $resultat[$ii]=array(); + $resultat[$ii]["rowid"]=$result["rowid"]; + $resultat[$ii]["price"]= $result["price"]; + $resultat[$ii]["price_ttc"]= $result["price_ttc"]; + $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["qty_max"]= $result["qty_max"]; + $ii++; + } + $this->prices_by_qty_list[$i]=$resultat; + } + else + { + dol_print_error($this->db); + return -1; + } + } } else { @@ -1190,6 +1236,57 @@ class Product extends CommonObject return -1; } } + } else if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + { + $sql = "SELECT price, price_ttc, price_min, price_min_ttc,"; + $sql.= " price_base_type, tva_tx, tosell, price_by_qty, rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_price"; + $sql.= " WHERE fk_product = '".$this->id."'"; + $sql.= " ORDER BY date_price DESC"; + $sql.= " LIMIT 1"; + $resql = $this->db->query($sql); + if ($resql) + { + $result = $this->db->fetch_array($resql); + + // Price by quantity + $this->prices_by_qty[0]=$result["price_by_qty"]; + $this->prices_by_qty_id[0]=$result["rowid"]; + // Récuperation de la liste des prix selon qty si flag positionné + if ($this->prices_by_qty[0] == 1) + { + $sql = "SELECT rowid,price, price_ttc,qty_min,qty_max"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; + $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[0]."'"; + $sql.= " ORDER BY qty_min ASC"; + $resultat=array(); + $resql = $this->db->query($sql) ; + if ($resql) + { + $ii=0; + while ($result= $this->db->fetch_array($resql)) { + $resultat[$ii]=array(); + $resultat[$ii]["rowid"]=$result["rowid"]; + $resultat[$ii]["price"]= $result["price"]; + $resultat[$ii]["price_ttc"]= $result["price_ttc"]; + $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["qty_max"]= $result["qty_max"]; + $ii++; + } + $this->prices_by_qty_list[0]=$resultat; + } + else + { + dol_print_error($this->db); + return -1; + } + } + } + else + { + dol_print_error($this->db); + return -1; + } } $res=$this->load_stock(); @@ -2922,4 +3019,4 @@ class Product extends CommonObject $this->note='This is a comment (private)'; } } -?> +?> \ No newline at end of file diff --git a/htdocs/product/price.php b/htdocs/product/price.php index cd0ce9ba307..079d83b5d74 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -51,7 +51,7 @@ $object = new Product($db); if ($action == 'update_price' && ! $_POST["cancel"] && ($user->rights->produit->creer || $user->rights->service->creer)) { $result = $object->fetch($id); - + // MultiPrix if (! empty($conf->global->PRODUIT_MULTIPRICES)) { @@ -70,6 +70,8 @@ if ($action == 'update_price' && ! $_POST["cancel"] && ($user->rights->produit-> $newpricebase=$_POST["multiprices_base_type_".$i]; $newnpr=(preg_match('/\*/',$_POST["tva_tx_".$i]) ? 1 : 0); $newvat=str_replace('*','',$_POST["tva_tx_".$i]); + $newpsq=GETPOST('psqflag'); + $newpsq = empty($newpsq) ? 0 : $newpsq; break; // We found submited price } } @@ -82,9 +84,11 @@ if ($action == 'update_price' && ! $_POST["cancel"] && ($user->rights->produit-> $newpricebase=$_POST["price_base_type"]; $newnpr=(preg_match('/\*/',$_POST["tva_tx"]) ? 1 : 0); $newvat=str_replace('*','',$_POST["tva_tx"]); + $newpsq=GETPOST('psqflag'); + $newpsq = empty($newpsq) ? 0 : $newpsq; } - if ($object->updatePrice($object->id, $newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr) > 0) + if ($object->updatePrice($object->id, $newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr, $newpsq) > 0) { $action = ''; $mesg = '
'.$langs->trans("RecordSaved").'
'; @@ -101,6 +105,110 @@ else if ($action == 'delete' && $user->rights->produit->supprimer) if ($result < 0) $mesg='
'.$object->error.'
'; } +/***************************************************** + * Price by quantity + *****************************************************/ +if ($action == 'activate_price_by_qty') { // Activating product price by quantity add a new price, specified as by quantity + $result = $object->fetch($id); + $level=GETPOST('level'); + + $object->updatePrice($object->id, 0, $object->price_base_type, $user, $object->tva_tx, 0, $level, $object->tva_npr, 1); +} + +if ($action == 'edit_price_by_qty') { // Edition d'un prix par quantité + $rowid = GETPOST('rowid'); +} + +if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par quantité + $result = $object->fetch($id); + + // Récupération des variables + $rowid = GETPOST('rowid'); + $priceid=GETPOST('priceid'); + $newprice=price2num(GETPOST("price"),'MU'); + //$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management and discount management + $qtymin=GETPOST('qty_min'); + $qtymax=GETPOST('qty_max'); + + // Calcul des prix (HT et TTC) + if ($newprice!='' || $newprice==0) + { + if ($object->price_base_type == 'TTC') + { + $price_ttc = price2num($newprice,'MU'); + $price = price2num($newprice) / (1 + ($object->tva_tx / 100)); + $price = price2num($price,'MU'); + + /*if ($newminprice!='' || $newminprice==0) + { + $price_min_ttc = price2num($newminprice,'MU'); + $price_min = price2num($newminprice) / (1 + ($object->tva_tx / 100)); + $price_min = price2num($price_min,'MU'); + } + else + { + $price_min=0; + $price_min_ttc=0; + }*/ + } + else + { + $price = price2num($newprice,'MU'); + $price_ttc = price2num($newprice) * (1 + ($object->tva_tx / 100)); + $price_ttc = price2num($price_ttc,'MU'); + + /*if ($newminprice!='' || $newminprice==0) + { + $price_min = price2num($newminprice,'MU'); + $price_min_ttc = price2num($newminprice) * (1 + ($object->tva_tx / 100)); + $price_min_ttc = price2num($price_min_ttc,'MU'); + //print 'X'.$newminprice.'-'.$price_min; + } + else + { + $price_min=0; + $price_min_ttc=0; + }*/ + } + } + + // Ajout / mise à jour + if($rowid > 0) { + $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET"; + $sql.= " price='".$price."',"; + $sql.= " price_ttc=".$price_ttc.","; + $sql.= " qty_min=".$qtymin.","; + $sql.= " qty_max=".$qtymax; + $sql.= " WHERE rowid = ".GETPOST('rowid'); + + $result = $db->query($sql); + } else { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min,qty_max) values ("; + $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.','.$qtymax.')'; + + $result = $db->query($sql); + } +} + +if ($action == 'delete_price_by_qty') { + $rowid = GETPOST('rowid'); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty"; + $sql.= " WHERE rowid = ".GETPOST('rowid'); + + $result = $db->query($sql); +} + +if ($action == 'delete_all_price_by_qty') { + $priceid=GETPOST('priceid'); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_price_by_qty"; + $sql.= " WHERE fk_product_price = ".$priceid; + + $result = $db->query($sql); +} + + /* * View @@ -230,6 +338,104 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print price($object->multiprices_min["$i"]).' '.$langs->trans($object->multiprices_base_type["$i"]); } print ''; + + // Price by quantity + /*if($conf->global->PRODUIT_PRICE_BY_QTY) { + print ''.$langs->trans("PriceByQuantity").' '.$i.''; + if($object->prices_by_qty[$i] == 1) { + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + foreach ($object->prices_by_qty_list[$i] as $j=> $prices) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + print '
'.$langs->trans("PriceByQuantityRange").''.$langs->trans("HT").''.$langs->trans("TTC").' 
'.$prices['qty_min'].' - '.$prices['qty_max'].''.price($prices['price']).''.price($prices['price_ttc']).''; + print img_delete(); + print '
'; + } else { + print $langs->trans("No"); + } + print ''; + }*/ + + // Price by quantity + if($conf->global->PRODUIT_PRICE_BY_QTY) { + print ''.$langs->trans("PriceByQuantity").' '.$i; + print ''; + + if($object->prices_by_qty[$i] == 1) { + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + foreach ($object->prices_by_qty_list[$i] as $ii=> $prices) { + if($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } else { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + if($action != 'edit_price_by_qty') { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + + print '
'.$langs->trans("PriceByQuantityRange").' '.$i.''.$langs->trans("HT").''.$langs->trans("TTC").' 
- '; + print ' '.$object->price_base_type.' 
'.$prices['qty_min'].' - '.$prices['qty_max'].''.price($prices['price']).''.price($prices['price_ttc']).''; + if(($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print img_edit().''; + print ''; + print img_delete().''; + } else { + print ' '; + } + print '
- '; + print ' '.$object->price_base_type.' 
'; + } else { + print $langs->trans("No"); + print ' ('.$langs->trans("Activate").')'; + } + print ''; + } } } } @@ -261,6 +467,76 @@ else print price($object->price_min).' '.$langs->trans($object->price_base_type); } print ''; + + // Price by quantity + if($conf->global->PRODUIT_PRICE_BY_QTY) { + print ''.$langs->trans("PriceByQuantity"); + if($object->prices_by_qty[0] == 0) { + print ' '.$langs->trans("Activate"); + } + print ''; + + if($object->prices_by_qty[0] == 1) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + foreach ($object->prices_by_qty_list[0] as $ii=> $prices) { + if($action == 'edit_price_by_qty' && $rowid == $prices['rowid'] && ($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } else { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + if($action != 'edit_price_by_qty') { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + + print '
'.$langs->trans("PriceByQuantityRange").''.$langs->trans("HT").''.$langs->trans("TTC").' 
- '; + print ' '.$object->price_base_type.' 
'.$prices['qty_min'].' - '.$prices['qty_max'].''.price($prices['price']).''.price($prices['price_ttc']).''; + if(($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print img_edit().''; + print ''; + print img_delete().''; + } else { + print ' '; + } + print '
- '; + print ' '.$object->price_base_type.' 
'; + } else { + print $langs->trans("No"); + } + print ''; + } } // Status (to sell) @@ -426,7 +702,7 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights-> // Liste des evolutions du prix $sql = "SELECT p.rowid, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.recuperableonly,"; -$sql.= " p.price_level, p.price_min, p.price_min_ttc,"; +$sql.= " p.price_level, p.price_min, p.price_min_ttc,p.price_by_qty,"; $sql.= " p.date_price as dp, u.rowid as user_id, u.login"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price as p,"; $sql.= " ".MAIN_DB_PREFIX."user as u"; @@ -464,7 +740,11 @@ if ($result) if (! empty($conf->global->PRODUIT_MULTIPRICES)) { - print ''.$langs->trans("MultiPriceLevelsName").''; + print ''.$langs->trans("MultiPriceLevelsName").''; + } + if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + { + print ''.$langs->trans("Type").''; } print ''.$langs->trans("PriceBase").''; @@ -492,6 +772,12 @@ if ($result) { print ''.$objp->price_level.""; } + // Price by quantity + if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + { + $type = ($objp->price_by_qty == 1) ? 'PriceByQuantity' : 'Standard'; + print ''.$langs->trans($type).""; + } print ''.$langs->trans($objp->price_base_type).""; print ''.vatrate($objp->tva_tx,true,$objp->recuperableonly).""; From 35773d08ff21dbd0c531ffa41acc86cfdbb14692 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 24 Oct 2012 17:16:03 +0200 Subject: [PATCH 03/25] Task # 559 : mysql table creation + index and constraints --- .../install/mysql/migration/3.2.0-3.3.0.sql | 11 +++++-- .../tables/llx_product_price_by_qty.key.sql | 26 ++++++++++++++++ .../mysql/tables/llx_product_price_by_qty.sql | 30 +++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql create mode 100644 htdocs/install/mysql/tables/llx_product_price_by_qty.sql diff --git a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql index 3eb339b57dd..e32bacf6d9f 100755 --- a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql +++ b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql @@ -789,9 +789,14 @@ CREATE TABLE llx_product_price_by_qty fk_product_price integer NOT NULL, date_price timestamp, price double (24,8) DEFAULT 0, - price_ttc double (24,8) DEFAULT NULL, - qty_min real DEFAULT 0, - qty_max real DEFAULT 99999 + price_ttc double (24,8) DEFAULT 0, + qty_min real DEFAULT 0 )ENGINE=innodb; ALTER TABLE llx_product_price ADD price_by_qty INT NOT NULL DEFAULT 0; + +ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, qty_min); + +ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price); + +ALTER TABLE llx_product_price_by_qty ADD CONSTRAINT fk_product_price_by_qty_fk_product_price FOREIGN KEY (fk_product_price) REFERENCES llx_product_price (rowid); diff --git a/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql b/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql new file mode 100644 index 00000000000..e96af56e9c0 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql @@ -0,0 +1,26 @@ +-- ============================================================================ +-- Copyright (C) 2002-2003 Rodolphe Quiedeville +-- Copyright (C) 2005-2012 Regis Houssin +-- Copyright (C) 2010 Juanjo Menent +-- Copyright (C) 2012 Maxime Kohlhaas +-- +-- 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, see . +-- +-- ============================================================================ + +ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, qty_min); + +ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price); + +ALTER TABLE llx_product_price_by_qty ADD CONSTRAINT fk_product_price_by_qty_fk_product_price FOREIGN KEY (fk_product_price) REFERENCES llx_product_price (rowid); \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_product_price_by_qty.sql b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql new file mode 100644 index 00000000000..c101a211310 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql @@ -0,0 +1,30 @@ +-- ============================================================================ +-- Copyright (C) 2002-2003 Rodolphe Quiedeville +-- Copyright (C) 2005-2012 Regis Houssin +-- Copyright (C) 2010 Juanjo Menent +-- Copyright (C) 2012 Maxime Kohlhaas +-- +-- 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, see . +-- +-- ============================================================================ + +create table llx_product_price_by_qty +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_product_price integer NOT NULL, + date_price timestamp, + price double (24,8) DEFAULT 0, + price_ttc double (24,8) DEFAULT 0, + qty_min real DEFAULT 1 +)ENGINE=innodb; From 2ff77bb2f174a8d133ce0fbf5ae7768c8d0fb1e1 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 24 Oct 2012 17:18:11 +0200 Subject: [PATCH 04/25] Task # 559 : no need for a max quantity --- htdocs/product/class/product.class.php | 6 +-- htdocs/product/price.php | 57 +++++--------------------- 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 3599552b860..fb68e2e6472 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1203,7 +1203,7 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[$i] == 1) { - $sql = "SELECT rowid,price, price_ttc,qty_min,qty_max"; + $sql = "SELECT rowid,price, price_ttc,qty_min"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[$i]."'"; $sql.= " ORDER BY qty_min ASC"; @@ -1218,7 +1218,6 @@ class Product extends CommonObject $resultat[$ii]["price"]= $result["price"]; $resultat[$ii]["price_ttc"]= $result["price_ttc"]; $resultat[$ii]["qty_min"]= $result["qty_min"]; - $resultat[$ii]["qty_max"]= $result["qty_max"]; $ii++; } $this->prices_by_qty_list[$i]=$resultat; @@ -1255,7 +1254,7 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[0] == 1) { - $sql = "SELECT rowid,price, price_ttc,qty_min,qty_max"; + $sql = "SELECT rowid,price, price_ttc,qty_min"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[0]."'"; $sql.= " ORDER BY qty_min ASC"; @@ -1270,7 +1269,6 @@ class Product extends CommonObject $resultat[$ii]["price"]= $result["price"]; $resultat[$ii]["price_ttc"]= $result["price_ttc"]; $resultat[$ii]["qty_min"]= $result["qty_min"]; - $resultat[$ii]["qty_max"]= $result["qty_max"]; $ii++; } $this->prices_by_qty_list[0]=$resultat; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 079d83b5d74..2ff0a751e99 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -128,7 +128,6 @@ if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par qu $newprice=price2num(GETPOST("price"),'MU'); //$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management and discount management $qtymin=GETPOST('qty_min'); - $qtymax=GETPOST('qty_max'); // Calcul des prix (HT et TTC) if ($newprice!='' || $newprice==0) @@ -177,14 +176,13 @@ if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par qu $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET"; $sql.= " price='".$price."',"; $sql.= " price_ttc=".$price_ttc.","; - $sql.= " qty_min=".$qtymin.","; - $sql.= " qty_max=".$qtymax; + $sql.= " qty_min=".$qtymin; $sql.= " WHERE rowid = ".GETPOST('rowid'); $result = $db->query($sql); } else { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min,qty_max) values ("; - $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.','.$qtymax.')'; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min) values ("; + $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.')'; $result = $db->query($sql); } @@ -338,35 +336,6 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print price($object->multiprices_min["$i"]).' '.$langs->trans($object->multiprices_base_type["$i"]); } print ''; - - // Price by quantity - /*if($conf->global->PRODUIT_PRICE_BY_QTY) { - print ''.$langs->trans("PriceByQuantity").' '.$i.''; - if($object->prices_by_qty[$i] == 1) { - print ''; - - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - foreach ($object->prices_by_qty_list[$i] as $j=> $prices) { - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - } - print '
'.$langs->trans("PriceByQuantityRange").''.$langs->trans("HT").''.$langs->trans("TTC").' 
'.$prices['qty_min'].' - '.$prices['qty_max'].''.price($prices['price']).''.price($prices['price_ttc']).''; - print img_delete(); - print '
'; - } else { - print $langs->trans("No"); - } - print ''; - }*/ // Price by quantity if($conf->global->PRODUIT_PRICE_BY_QTY) { @@ -389,8 +358,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''; print ''; - print ' - '; - print ''; + print ''; print ' '.$object->price_base_type.''; print ' '; print ''; @@ -398,7 +366,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; } else { print ''; - print ''.$prices['qty_min'].' - '.$prices['qty_max'].''; + print ''.$prices['qty_min'].''; print ''.price($prices['price']).''; print ''.price($prices['price_ttc']).''; print ''; @@ -420,9 +388,8 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''; print ''; - print ' - '; - print ''; - print ' '.$object->price_base_type.''; + print ''; + print ' '.$object->price_base_type.''; print ' '; print ''; print ''; @@ -491,8 +458,7 @@ else print ''; print ''; print ''; - print ' - '; - print ''; + print ''; print ' '.$object->price_base_type.''; print ' '; print ''; @@ -500,7 +466,7 @@ else print ''; } else { print ''; - print ''.$prices['qty_min'].' - '.$prices['qty_max'].''; + print ''.$prices['qty_min'].''; print ''.price($prices['price']).''; print ''.price($prices['price_ttc']).''; print ''; @@ -522,9 +488,8 @@ else print ''; print ''; print ''; - print ' - '; - print ''; - print ' '.$object->price_base_type.''; + print ''; + print ' '.$object->price_base_type.''; print ' '; print ''; print ''; From fdc6ed90a42bb410b8f6b22183795caef1fbf686 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 24 Oct 2012 17:22:45 +0200 Subject: [PATCH 05/25] Task # 559 : forgot to update product_price table to add column --- htdocs/install/mysql/tables/llx_product_price.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_product_price.sql b/htdocs/install/mysql/tables/llx_product_price.sql index 12f1257f156..b2de59ff62c 100644 --- a/htdocs/install/mysql/tables/llx_product_price.sql +++ b/htdocs/install/mysql/tables/llx_product_price.sql @@ -36,6 +36,7 @@ create table llx_product_price localtax1_tx double(6,3) DEFAULT 0, localtax2_tx double(6,3) DEFAULT 0, fk_user_author integer, - tosell tinyint DEFAULT 1 + tosell tinyint DEFAULT 1, + price_by_qty integer NOT NULL DEFAULT 0 )ENGINE=innodb; From 03cf96ed318adc65b2c10754209aad18d500516b Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Thu, 25 Oct 2012 08:18:59 +0200 Subject: [PATCH 06/25] Task # 559 : add discount by qty as done in supplier prices --- .../install/mysql/migration/3.2.0-3.3.0.sql | 3 ++ .../mysql/tables/llx_product_price_by_qty.sql | 2 + htdocs/product/class/product.class.php | 8 +++- htdocs/product/price.php | 38 ++++++++++++------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql index e32bacf6d9f..aea6868f42a 100755 --- a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql +++ b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql @@ -800,3 +800,6 @@ ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_le ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price); ALTER TABLE llx_product_price_by_qty ADD CONSTRAINT fk_product_price_by_qty_fk_product_price FOREIGN KEY (fk_product_price) REFERENCES llx_product_price (rowid); + +ALTER TABLE `llx_product_price_by_qty` ADD `remise_percent` DOUBLE NOT NULL DEFAULT '0' AFTER `price_ttc` , +ADD `remise` DOUBLE NOT NULL DEFAULT '0' AFTER `remise_percent`; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_product_price_by_qty.sql b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql index c101a211310..e0585786235 100644 --- a/htdocs/install/mysql/tables/llx_product_price_by_qty.sql +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql @@ -26,5 +26,7 @@ create table llx_product_price_by_qty date_price timestamp, price double (24,8) DEFAULT 0, price_ttc double (24,8) DEFAULT 0, + remise_percent double NOT NULL DEFAULT 0, + remise double NOT NULL DEFAULT 0, qty_min real DEFAULT 1 )ENGINE=innodb; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index fb68e2e6472..ecedea4a10d 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1203,7 +1203,7 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[$i] == 1) { - $sql = "SELECT rowid,price, price_ttc,qty_min"; + $sql = "SELECT rowid,price, price_ttc, qty_min, remise_percent, remise"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[$i]."'"; $sql.= " ORDER BY qty_min ASC"; @@ -1218,6 +1218,8 @@ class Product extends CommonObject $resultat[$ii]["price"]= $result["price"]; $resultat[$ii]["price_ttc"]= $result["price_ttc"]; $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["remise_percent"]= $result["remise_percent"]; + $resultat[$ii]["remise"]= $result["remise"]; $ii++; } $this->prices_by_qty_list[$i]=$resultat; @@ -1254,7 +1256,7 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[0] == 1) { - $sql = "SELECT rowid,price, price_ttc,qty_min"; + $sql = "SELECT rowid,price, price_ttc, qty_min, remise_percent, remise"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[0]."'"; $sql.= " ORDER BY qty_min ASC"; @@ -1269,6 +1271,8 @@ class Product extends CommonObject $resultat[$ii]["price"]= $result["price"]; $resultat[$ii]["price_ttc"]= $result["price_ttc"]; $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["remise_percent"]= $result["remise_percent"]; + $resultat[$ii]["remise"]= $result["remise"]; $ii++; } $this->prices_by_qty_list[0]=$resultat; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 2ff0a751e99..42d6712be52 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -126,8 +126,10 @@ if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par qu $rowid = GETPOST('rowid'); $priceid=GETPOST('priceid'); $newprice=price2num(GETPOST("price"),'MU'); - //$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management and discount management + //$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management $qtymin=GETPOST('qty_min'); + $remise_percent=price2num(GETPOST('remise_percent')); + $remise=0; // TODO : allow dicsoun by amount when available on documents // Calcul des prix (HT et TTC) if ($newprice!='' || $newprice==0) @@ -176,13 +178,15 @@ if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par qu $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET"; $sql.= " price='".$price."',"; $sql.= " price_ttc=".$price_ttc.","; - $sql.= " qty_min=".$qtymin; + $sql.= " qty_min=".$qtymin.","; + $sql.= " remise_percent=".$remise_percent.","; + $sql.= " remise=".$remise; $sql.= " WHERE rowid = ".GETPOST('rowid'); $result = $db->query($sql); } else { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min) values ("; - $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.')'; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min,remise_percent,remise) values ("; + $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.','.$remise_percent.','.$remise.')'; $result = $db->query($sql); } @@ -349,6 +353,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''.$langs->trans("PriceByQuantityRange").' '.$i.''; print ''.$langs->trans("HT").''; print ''.$langs->trans("TTC").''; + print ''.$langs->trans("Discount").''; print ' '; print ''; foreach ($object->prices_by_qty_list[$i] as $ii=> $prices) { @@ -359,8 +364,9 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''; print ''; - print ' '.$object->price_base_type.''; - print ' '; + print ' '.$object->price_base_type.''; + //print ' '; + print '< %/td>'; print ''; print ''; print ''; @@ -369,6 +375,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''.$prices['qty_min'].''; print ''.price($prices['price']).''; print ''.price($prices['price_ttc']).''; + print ''.price($prices['remise_percent']).' %'; print ''; if(($user->rights->produit->creer || $user->rights->service->creer)) { print '
'; @@ -382,15 +389,16 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; } } - if($action != 'edit_price_by_qty') { + if($action != 'edit_price_by_qty' && ($user->rights->produit->creer || $user->rights->service->creer)) { print '
'; print ''; print ''; print ''; print ''; print ''; - print ' '.$object->price_base_type.''; - print ' '; + print ' '.$object->price_base_type.''; + //print ' '; + print ' %'; print ''; print ''; print '
'; @@ -449,6 +457,7 @@ else print ''.$langs->trans("PriceByQuantityRange").''; print ''.$langs->trans("HT").''; print ''.$langs->trans("TTC").''; + print ''.$langs->trans("Discount").''; print ' '; print ''; foreach ($object->prices_by_qty_list[0] as $ii=> $prices) { @@ -459,8 +468,9 @@ else print ''; print ''; print ''; - print ' '.$object->price_base_type.''; - print ' '; + print ' '.$object->price_base_type.''; + //print ' '; + print ' %'; print ''; print ''; print ''; @@ -469,6 +479,7 @@ else print ''.$prices['qty_min'].''; print ''.price($prices['price']).''; print ''.price($prices['price_ttc']).''; + print ''.price($prices['remise_percent']).' %'; print ''; if(($user->rights->produit->creer || $user->rights->service->creer)) { print '
'; @@ -489,8 +500,9 @@ else print ''; print ''; print ''; - print ' '.$object->price_base_type.''; - print ' '; + print ' '.$object->price_base_type.''; + //print ' '; + print ' %'; print ''; print ''; print ''; From 84df6bd6393c1352361da678d9d857c2b64f0952 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Thu, 25 Oct 2012 08:19:16 +0200 Subject: [PATCH 07/25] Task # 559 : forgot to update supplier prices sql table --- htdocs/install/mysql/tables/llx_product_fournisseur_price.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql b/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql index a6cb81527a6..4b7c0cc0306 100644 --- a/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql +++ b/htdocs/install/mysql/tables/llx_product_fournisseur_price.sql @@ -31,6 +31,8 @@ create table llx_product_fournisseur_price fk_availability integer, price double(24,8) DEFAULT 0, quantity double, + remise_percent double NOT NULL DEFAULT 0, + remise double NOT NULL DEFAULT 0, unitprice double(24,8) DEFAULT 0, charges double(24,8) DEFAULT 0, unitcharges double(24,8) DEFAULT 0, From 0f1617c31d4ddf12beba0d2c460890b595161607 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Fri, 26 Oct 2012 01:00:03 +0200 Subject: [PATCH 08/25] Task 559 : add use of price by qty in product selection (select and ajax search) --- htdocs/core/class/html.form.class.php | 367 ++++++++++++++++--------- htdocs/core/tpl/objectline_add.tpl.php | 12 +- htdocs/product/ajax/products.php | 37 ++- htdocs/product/price.php | 2 +- 4 files changed, 272 insertions(+), 146 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 32f76d60eeb..39f9dc167e1 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1148,6 +1148,18 @@ class Form { $sql.= ", pl.label as label_translated"; } + // Price by quantity + if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + { + $sql.= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid"; + if ($price_level >= 1) $sql.= " AND price_level=".$price_level; + $sql.= " ORDER BY date_price"; + $sql.= " DESC LIMIT 1) as price_rowid"; + $sql.= ", (SELECT pp.price_by_qty FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid"; + if ($price_level >= 1) $sql.= " AND price_level=".$price_level; + $sql.= " ORDER BY date_price"; + $sql.= " DESC LIMIT 1) as price_by_qty"; + } $sql.= " FROM ".MAIN_DB_PREFIX."product as p"; // Multilang : we add translation if (! empty($conf->global->MAIN_MULTILANGS)) @@ -1209,143 +1221,50 @@ class Form $i = 0; while ($num && $i < $num) { - $outkey=''; - $outval=''; - $outref=''; - $outlabel=''; - $outdesc=''; - $outtype=''; - $outprice_ht=''; - $outprice_ttc=''; - $outpricebasetype=''; - $outtva_tx=''; - - $objp = $this->db->fetch_object($result); - - $label=$objp->label; - if (! empty($objp->label_translated)) $label=$objp->label_translated; - if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','$1',$label,1); - - $outkey=$objp->rowid; - $outref=$objp->ref; - $outlabel=$objp->label; - $outdesc=$objp->description; - $outtype=$objp->fk_product_type; - - $opt = '\n"; - - // Add new entry - // "key" value of json key array is used by jQuery automatically as selected value - // "label" value of json key array is used by jQuery automatically as text for combo box - $outselect.=$opt; - array_push($outjson, array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx)); + $opt = ''; + $optJson = array(); + $objp = $this->db->fetch_object($result); + + if(!empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product + $sql = "SELECT rowid, qty_min, price, price_ttc, remise_percent, remise"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; + $sql.= " WHERE fk_product_price=".$objp->price_rowid; + + dol_syslog(get_class($this)."::select_produits_do search price by qty sql=".$sql); + $result2 = $this->db->query($sql); + if ($result2) + { + $nb_prices = $this->db->num_rows($result2); + $j = 0; + while ($nb_prices && $j < $nb_prices) { + $objp2 = $this->db->fetch_object($result2); + + $objp->quantity = $objp2->qty_min; + $objp->price = $objp2->price; + $objp->unitprice = $objp2->price; + $objp->remise_percent = $objp2->remise_percent; + $objp->remise = $objp2->remise; + $objp->price_by_qty_rowid = $objp2->rowid; + + $this->_construct_product_list_option($objp, $opt, $optJson, 0, $selected); + + $j++; + + // Add new entry + // "key" value of json key array is used by jQuery automatically as selected value + // "label" value of json key array is used by jQuery automatically as text for combo box + $outselect.=$opt; + array_push($outjson, $optJson); + } + } + } else { + $this->_construct_product_list_option($objp, $opt, $optJson, $price_level, $selected); + // Add new entry + // "key" value of json key array is used by jQuery automatically as selected value + // "label" value of json key array is used by jQuery automatically as text for combo box + $outselect.=$opt; + array_push($outjson, $optJson); + } $i++; } @@ -1363,6 +1282,180 @@ class Form } } + function _construct_product_list_option(&$objp, &$opt, &$optJson, $price_level, $selected) { + global $langs,$conf,$user,$db; + + $outkey=''; + $outval=''; + $outref=''; + $outlabel=''; + $outdesc=''; + $outtype=''; + $outprice_ht=''; + $outprice_ttc=''; + $outpricebasetype=''; + $outtva_tx=''; + $outqty=1; + $outdiscount=0; + + $label=$objp->label; + if (! empty($objp->label_translated)) $label=$objp->label_translated; + if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','$1',$label,1); + + $outkey=$objp->rowid; + $outref=$objp->ref; + $outlabel=$objp->label; + $outdesc=$objp->description; + $outtype=$objp->fk_product_type; + + $opt = '\n"; + $optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount); + } + /** * Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_do) * diff --git a/htdocs/core/tpl/objectline_add.tpl.php b/htdocs/core/tpl/objectline_add.tpl.php index d9f35ad6971..185656bf231 100644 --- a/htdocs/core/tpl/objectline_add.tpl.php +++ b/htdocs/core/tpl/objectline_add.tpl.php @@ -79,7 +79,9 @@ if (! empty($conf->margin->enabled)) { 'price_ht' => 'price_ht', 'origin_price_ht_cache' => 'price_ht', 'origin_tva_tx_cache' => 'tva_tx', - 'origin_price_ttc_cache' => 'price_ttc' + 'origin_price_ttc_cache' => 'price_ttc', + 'qty' => 'qty', + 'remise_percent' => 'discount' ), 'update_textarea' => array( 'product_desc' => 'desc' @@ -158,7 +160,7 @@ if (! empty($conf->margin->enabled)) { - % + % margin->enabled)) { @@ -225,7 +227,9 @@ $(document).ready(function() { $.post('/product/ajax/products.php', { 'action': 'fetch', 'id': $(this).val(), - 'price_level': price_level)?1:$buyer->price_level; ?>}, + 'price_level': price_level)?1:$buyer->price_level; ?>, + 'pbq': $("option:selected", this).attr('pbq') + }, function(data) { if (typeof data != 'undefined') { $('#product_ref').val(data.ref); @@ -237,6 +241,8 @@ $(document).ready(function() { $('#origin_tva_tx_cache').val(data.tva_tx); $('#select_type').val(data.type).attr('disabled','disabled').trigger('change'); //$('#price_base_type_area').show(); + $('#qty').val(data.qty); + $('#remise_percent').val(data.discount); if (typeof CKEDITOR == "object" && typeof CKEDITOR.instances != "undefined" && CKEDITOR.instances['product_desc'] != "undefined") { CKEDITOR.instances['product_desc'].setData(data.desc).focus(); diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index d1874d11eaa..f5702b72f8c 100644 --- a/htdocs/product/ajax/products.php +++ b/htdocs/product/ajax/products.php @@ -38,9 +38,10 @@ $type=GETPOST('type','int'); $mode=GETPOST('mode','int'); $status=((GETPOST('status','int') >= 0) ? GETPOST('status','int') : -1); $outjson=(GETPOST('outjson','int') ? GETPOST('outjson','int') : 0); -$pricelevel=GETPOST('price_level','int'); +$price_level=GETPOST('price_level','int'); $action=GETPOST('action', 'alpha'); $id=GETPOST('id', 'int'); +$price_by_qty_rowid=GETPOST('pbq', 'int'); /* * View @@ -65,11 +66,37 @@ if (! empty($action) && $action == 'fetch' && ! empty($id)) $outlabel=$object->label; $outdesc=$object->description; $outtype=$object->type; + $outqty=1; + $outdiscount=0; $found=false; + + // Price by qty + if (!empty($price_by_qty_rowid) && $price_by_qty_rowid >= 1) // If we need a particular price related to qty + { + $sql = "SELECT price, price_ttc, qty_min, remise_percent"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty "; + $sql.= " WHERE rowid=".$price_by_qty_rowid.""; + + $result = $db->query($sql); + if ($result) + { + $objp = $db->fetch_object($result); + if ($objp) + { + $found=true; + $outprice_ht=price($objp->price); + $outprice_ttc=price($objp->price_ttc); + $outpricebasetype=$object->price_base_type; + $outtva_tx=$object->tva_tx; + $outqty=$objp->qty_min; + $outdiscount=$objp->remise_percent; + } + } + } // Multiprice - if (isset($price_level) && $price_level >= 1) // If we need a particular price level (from 1 to 6) + if (! $found && isset($price_level) && $price_level >= 1) // If we need a particular price level (from 1 to 6) { $sql = "SELECT price, price_ttc, price_base_type, tva_tx"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price "; @@ -78,10 +105,10 @@ if (! empty($action) && $action == 'fetch' && ! empty($id)) $sql.= " ORDER BY date_price"; $sql.= " DESC LIMIT 1"; - $result = $this->db->query($sql); + $result = $db->query($sql); if ($result) { - $objp = $this->db->fetch_object($result); + $objp = $db->fetch_object($result); if ($objp) { $found=true; @@ -101,7 +128,7 @@ if (! empty($action) && $action == 'fetch' && ! empty($id)) $outtva_tx=$object->tva_tx; } - $outjson = array('ref'=>$outref, 'label'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx); + $outjson = array('ref'=>$outref, 'label'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount); } echo json_encode($outjson); diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 42d6712be52..7fe5aa5b89e 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -366,7 +366,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ' '.$object->price_base_type.''; //print ' '; - print '< %/td>'; + print ' %'; print ''; print ''; print ''; From fd5fb90649cfe41ae8dd9faddb182a0d040f130b Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Fri, 26 Oct 2012 01:07:11 +0200 Subject: [PATCH 09/25] Task # 559 : price defined on product page is unit price. Need to multiplicate this price by qty to have the right global price in the product list --- htdocs/core/class/html.form.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index d6824ce682e..d23a4b0b46c 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1389,8 +1389,8 @@ class Form } else { - $opt.= price($objp->price).' '.$currencytext."/".$objp->quantity; - $outval.= price($objp->price).' '.$currencytextnoent."/".$objp->quantity; + $opt.= price($objp->price * $objp->quantity).' '.$currencytext."/".$objp->quantity; + $outval.= price($objp->price * $objp->quantity).' '.$currencytextnoent."/".$objp->quantity; $opt.= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding $outval.=$langs->transnoentities("Units"); } From 7035ec42f1e047507178e68448110ededfea8a98 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 7 Nov 2012 00:38:53 +0100 Subject: [PATCH 10/25] Task # 559 : Modifications to store unitprice as in supplier prices --- htdocs/core/class/html.form.class.php | 37 +++--- .../tables/llx_product_price_by_qty.key.sql | 2 +- .../mysql/tables/llx_product_price_by_qty.sql | 12 +- htdocs/product/ajax/products.php | 8 +- htdocs/product/class/product.class.php | 16 +-- htdocs/product/price.php | 108 +++++++----------- 6 files changed, 81 insertions(+), 102 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 4c78faa6690..dad4173ec60 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1226,9 +1226,10 @@ class Form $objp = $this->db->fetch_object($result); if(!empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product - $sql = "SELECT rowid, qty_min, price, price_ttc, remise_percent, remise"; + $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price=".$objp->price_rowid; + $sql.= " ORDER BY quantity ASC"; dol_syslog(get_class($this)."::select_produits_do search price by qty sql=".$sql); $result2 = $this->db->query($sql); @@ -1239,9 +1240,9 @@ class Form while ($nb_prices && $j < $nb_prices) { $objp2 = $this->db->fetch_object($result2); - $objp->quantity = $objp2->qty_min; + $objp->quantity = $objp2->quantity; $objp->price = $objp2->price; - $objp->unitprice = $objp2->price; + $objp->unitprice = $objp2->unitprice; $objp->remise_percent = $objp2->remise_percent; $objp->remise = $objp2->remise; $objp->price_by_qty_rowid = $objp2->rowid; @@ -1313,14 +1314,8 @@ class Form $opt.= (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)?' pbq="'.$objp->price_by_qty_rowid.'"':''; if (! empty($conf->stock->enabled) && $objp->fk_product_type == 0 && isset($objp->stock)) { - if ($objp->stock > 0) - { - $opt.= ' style="background-color:#32CD32; color:#F5F5F5;"'; - } - else if ($objp->stock <= 0) - { - $opt.= ' style="background-color:#FF0000; color:#F5F5F5;"'; - } + if ($objp->stock > 0) $opt.= ' class="product_line_stock_ok"'; + else if ($objp->stock <= 0) $opt.= ' class="product_line_stock_too_low"'; } $opt.= '>'; $opt.= $objp->ref.' - '.dol_trunc($label,32).' - '; @@ -1382,21 +1377,21 @@ class Form $outdiscount=$objp->remise_percent; if ($objp->quantity == 1) { - $opt.= price($objp->price).' '.$currencytext."/"; - $outval.= price($objp->price).' '.$currencytextnoent."/"; + $opt.= price($objp->unitprice).' '.$currencytext."/"; + $outval.= price($objp->unitprice).' '.$currencytextnoent."/"; $opt.= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding $outval.=$langs->transnoentities("Unit"); } else { - $opt.= price($objp->price * $objp->quantity).' '.$currencytext."/".$objp->quantity; - $outval.= price($objp->price * $objp->quantity).' '.$currencytextnoent."/".$objp->quantity; + $opt.= price($objp->price).' '.$currencytext."/".$objp->quantity; + $outval.= price($objp->price).' '.$currencytextnoent."/".$objp->quantity; $opt.= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding $outval.=$langs->transnoentities("Units"); } - $outprice_ht=price($objp->price); - $outprice_ttc=price($objp->price_ttc); + $outprice_ht=price($objp->unitprice); + $outprice_ttc=price($objp->unitprice * (1 + ($objp->tva_tx / 100))); $outpricebasetype=$objp->price_base_type; $outtva_tx=$objp->tva_tx; } @@ -1573,8 +1568,12 @@ class Form $label = $objp->label; if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','$1',$label,1); - $opt.=$objp->ref.' ('.$objp->ref_fourn.') - '; - $outval.=$objRef.' ('.$objRefFourn.') - '; + $opt.=$objp->ref; + if (! empty($objp->idprodfournprice)) $opt.=' ('.$objp->ref_fourn.')'; + $opt.=' - '; + $outval.=$objRef; + if (! empty($objp->idprodfournprice)) $outval.=' ('.$objRefFourn.')'; + $outval.=' - '; $opt.=dol_trunc($objp->label,18).' - '; $outval.=dol_trunc($label,18).' - '; diff --git a/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql b/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql index e96af56e9c0..e6eec68f632 100644 --- a/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.key.sql @@ -19,7 +19,7 @@ -- -- ============================================================================ -ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, qty_min); +ALTER TABLE llx_product_price_by_qty ADD UNIQUE INDEX uk_product_price_by_qty_level (fk_product_price, quantity); ALTER TABLE llx_product_price_by_qty ADD INDEX idx_product_price_by_qty_fk_product_price (fk_product_price); diff --git a/htdocs/install/mysql/tables/llx_product_price_by_qty.sql b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql index e0585786235..556753c309d 100644 --- a/htdocs/install/mysql/tables/llx_product_price_by_qty.sql +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql @@ -21,12 +21,12 @@ create table llx_product_price_by_qty ( - rowid integer AUTO_INCREMENT PRIMARY KEY, + rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY, fk_product_price integer NOT NULL, - date_price timestamp, - price double (24,8) DEFAULT 0, - price_ttc double (24,8) DEFAULT 0, + date_price timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + price double(24,8) DEFAULT 0, + quantity double DEFAULT NULL, remise_percent double NOT NULL DEFAULT 0, - remise double NOT NULL DEFAULT 0, - qty_min real DEFAULT 1 + remise double NOT NULL DEFAULT 0, + unitprice double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index f5702b72f8c..9e20392fc34 100644 --- a/htdocs/product/ajax/products.php +++ b/htdocs/product/ajax/products.php @@ -74,7 +74,7 @@ if (! empty($action) && $action == 'fetch' && ! empty($id)) // Price by qty if (!empty($price_by_qty_rowid) && $price_by_qty_rowid >= 1) // If we need a particular price related to qty { - $sql = "SELECT price, price_ttc, qty_min, remise_percent"; + $sql = "SELECT price, unitprice, quantity, remise_percent"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty "; $sql.= " WHERE rowid=".$price_by_qty_rowid.""; @@ -85,11 +85,11 @@ if (! empty($action) && $action == 'fetch' && ! empty($id)) if ($objp) { $found=true; - $outprice_ht=price($objp->price); - $outprice_ttc=price($objp->price_ttc); + $outprice_ht=price($objp->unitprice); + $outprice_ttc=price($objp->unitprice * (1 + ($object->tva_tx / 100))); $outpricebasetype=$object->price_base_type; $outtva_tx=$object->tva_tx; - $outqty=$objp->qty_min; + $outqty=$objp->quantity; $outdiscount=$objp->remise_percent; } } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index ecedea4a10d..bf853d16e75 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1203,10 +1203,10 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[$i] == 1) { - $sql = "SELECT rowid,price, price_ttc, qty_min, remise_percent, remise"; + $sql = "SELECT rowid,price, unitprice, quantity, remise_percent, remise"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[$i]."'"; - $sql.= " ORDER BY qty_min ASC"; + $sql.= " ORDER BY quantity ASC"; $resultat=array(); $resql = $this->db->query($sql) ; if ($resql) @@ -1216,8 +1216,8 @@ class Product extends CommonObject $resultat[$ii]=array(); $resultat[$ii]["rowid"]=$result["rowid"]; $resultat[$ii]["price"]= $result["price"]; - $resultat[$ii]["price_ttc"]= $result["price_ttc"]; - $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["unitprice"]= $result["unitprice"]; + $resultat[$ii]["quantity"]= $result["quantity"]; $resultat[$ii]["remise_percent"]= $result["remise_percent"]; $resultat[$ii]["remise"]= $result["remise"]; $ii++; @@ -1256,10 +1256,10 @@ class Product extends CommonObject // Récuperation de la liste des prix selon qty si flag positionné if ($this->prices_by_qty[0] == 1) { - $sql = "SELECT rowid,price, price_ttc, qty_min, remise_percent, remise"; + $sql = "SELECT rowid,price, unitprice, quantity, remise_percent, remise"; $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; $sql.= " WHERE fk_product_price = '".$this->prices_by_qty_id[0]."'"; - $sql.= " ORDER BY qty_min ASC"; + $sql.= " ORDER BY quantity ASC"; $resultat=array(); $resql = $this->db->query($sql) ; if ($resql) @@ -1269,8 +1269,8 @@ class Product extends CommonObject $resultat[$ii]=array(); $resultat[$ii]["rowid"]=$result["rowid"]; $resultat[$ii]["price"]= $result["price"]; - $resultat[$ii]["price_ttc"]= $result["price_ttc"]; - $resultat[$ii]["qty_min"]= $result["qty_min"]; + $resultat[$ii]["unitprice"]= $result["unitprice"]; + $resultat[$ii]["quantity"]= $result["quantity"]; $resultat[$ii]["remise_percent"]= $result["remise_percent"]; $resultat[$ii]["remise"]= $result["remise"]; $ii++; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 7fe5aa5b89e..14d6600779d 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -108,6 +108,7 @@ else if ($action == 'delete' && $user->rights->produit->supprimer) /***************************************************** * Price by quantity *****************************************************/ +$error=0; if ($action == 'activate_price_by_qty') { // Activating product price by quantity add a new price, specified as by quantity $result = $object->fetch($id); $level=GETPOST('level'); @@ -127,68 +128,47 @@ if ($action == 'update_price_by_qty') { // Ajout / Mise à jour d'un prix par qu $priceid=GETPOST('priceid'); $newprice=price2num(GETPOST("price"),'MU'); //$newminprice=price2num(GETPOST("price_min"),'MU'); // TODO : Add min price management - $qtymin=GETPOST('qty_min'); + $quantity=GETPOST('quantity'); $remise_percent=price2num(GETPOST('remise_percent')); - $remise=0; // TODO : allow dicsoun by amount when available on documents + $remise=0; // TODO : allow dicsount by amount when available on documents - // Calcul des prix (HT et TTC) - if ($newprice!='' || $newprice==0) + if (empty($quantity)) { + $error++; + $mesg='
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Qty")).'
'; + } + if (empty($newprice)) + { + $error++; + $mesg='
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Price")).'
'; + } + if(!$error) { + // Calcul du prix HT et du prix unitaire if ($object->price_base_type == 'TTC') { - $price_ttc = price2num($newprice,'MU'); $price = price2num($newprice) / (1 + ($object->tva_tx / 100)); - $price = price2num($price,'MU'); - - /*if ($newminprice!='' || $newminprice==0) - { - $price_min_ttc = price2num($newminprice,'MU'); - $price_min = price2num($newminprice) / (1 + ($object->tva_tx / 100)); - $price_min = price2num($price_min,'MU'); - } - else - { - $price_min=0; - $price_min_ttc=0; - }*/ } - else - { - $price = price2num($newprice,'MU'); - $price_ttc = price2num($newprice) * (1 + ($object->tva_tx / 100)); - $price_ttc = price2num($price_ttc,'MU'); - - /*if ($newminprice!='' || $newminprice==0) - { - $price_min = price2num($newminprice,'MU'); - $price_min_ttc = price2num($newminprice) * (1 + ($object->tva_tx / 100)); - $price_min_ttc = price2num($price_min_ttc,'MU'); - //print 'X'.$newminprice.'-'.$price_min; - } - else - { - $price_min=0; - $price_min_ttc=0; - }*/ - } - } - - // Ajout / mise à jour - if($rowid > 0) { - $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET"; - $sql.= " price='".$price."',"; - $sql.= " price_ttc=".$price_ttc.","; - $sql.= " qty_min=".$qtymin.","; - $sql.= " remise_percent=".$remise_percent.","; - $sql.= " remise=".$remise; - $sql.= " WHERE rowid = ".GETPOST('rowid'); - $result = $db->query($sql); - } else { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,price_ttc,qty_min,remise_percent,remise) values ("; - $sql.= $priceid.','.$price.','.$price_ttc.','.$qtymin.','.$remise_percent.','.$remise.')'; - - $result = $db->query($sql); + $price = price2num($newprice,'MU'); + $unitPrice = price2num($price/$quantity,'MU'); + + // Ajout / mise à jour + if($rowid > 0) { + $sql = "UPDATE ".MAIN_DB_PREFIX."product_price_by_qty SET"; + $sql.= " price='".$price."',"; + $sql.= " unitprice=".$unitPrice.","; + $sql.= " quantity=".$quantity.","; + $sql.= " remise_percent=".$remise_percent.","; + $sql.= " remise=".$remise; + $sql.= " WHERE rowid = ".GETPOST('rowid'); + + $result = $db->query($sql); + } else { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."product_price_by_qty (fk_product_price,price,unitprice,quantity,remise_percent,remise) values ("; + $sql.= $priceid.','.$price.','.$unitPrice.','.$quantity.','.$remise_percent.','.$remise.')'; + + $result = $db->query($sql); + } } } @@ -352,7 +332,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''.$langs->trans("PriceByQuantityRange").' '.$i.''; print ''.$langs->trans("HT").''; - print ''.$langs->trans("TTC").''; + print ''.$langs->trans("UnitPrice").''; print ''.$langs->trans("Discount").''; print ' '; print ''; @@ -363,7 +343,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''; print ''; - print ''; + print ''; print ' '.$object->price_base_type.''; //print ' '; print ' %'; @@ -372,9 +352,9 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; } else { print ''; - print ''.$prices['qty_min'].''; + print ''.$prices['quantity'].''; print ''.price($prices['price']).''; - print ''.price($prices['price_ttc']).''; + print ''.price($prices['unitprice']).''; print ''.price($prices['remise_percent']).' %'; print ''; if(($user->rights->produit->creer || $user->rights->service->creer)) { @@ -395,7 +375,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; print ''; print ''; - print ''; + print ''; print ' '.$object->price_base_type.''; //print ' '; print ' %'; @@ -456,7 +436,7 @@ else print ''; print ''.$langs->trans("PriceByQuantityRange").''; print ''.$langs->trans("HT").''; - print ''.$langs->trans("TTC").''; + print ''.$langs->trans("UnitPrice").''; print ''.$langs->trans("Discount").''; print ' '; print ''; @@ -467,7 +447,7 @@ else print ''; print ''; print ''; - print ''; + print ''; print ' '.$object->price_base_type.''; //print ' '; print ' %'; @@ -476,9 +456,9 @@ else print ''; } else { print ''; - print ''.$prices['qty_min'].''; + print ''.$prices['quantity'].''; print ''.price($prices['price']).''; - print ''.price($prices['price_ttc']).''; + print ''.price($prices['unitprice']).''; print ''.price($prices['remise_percent']).' %'; print ''; if(($user->rights->produit->creer || $user->rights->service->creer)) { @@ -499,7 +479,7 @@ else print ''; print ''; print ''; - print ''; + print ''; print ' '.$object->price_base_type.''; //print ' '; print ' %'; From 69fa1e9d10af47b6a2ab3ffafd1995b65123819e Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sat, 1 Dec 2012 14:38:59 +0100 Subject: [PATCH 11/25] Fix : replace PRODUIT_PRICE_BY_QTY by PRODUIT_CUSTOMER_PRICES_BY_QTY --- htdocs/product/class/product.class.php | 2 +- htdocs/product/price.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 94889998f26..2b6e28c55f3 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1241,7 +1241,7 @@ class Product extends CommonObject return -1; } } - } else if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + } else if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) { $sql = "SELECT price, price_ttc, price_min, price_min_ttc,"; $sql.= " price_base_type, tva_tx, tosell, price_by_qty, rowid"; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 14d6600779d..390b09127e7 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -322,7 +322,7 @@ if (! empty($conf->global->PRODUIT_MULTIPRICES)) print ''; // Price by quantity - if($conf->global->PRODUIT_PRICE_BY_QTY) { + if($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) { print ''.$langs->trans("PriceByQuantity").' '.$i; print ''; @@ -424,7 +424,7 @@ else print ''; // Price by quantity - if($conf->global->PRODUIT_PRICE_BY_QTY) { + if($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) { print ''.$langs->trans("PriceByQuantity"); if($object->prices_by_qty[0] == 0) { print ' 
'.$langs->trans("Activate"); @@ -699,7 +699,7 @@ if ($result) { print ''.$langs->trans("MultiPriceLevelsName").''; } - if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) { print ''.$langs->trans("Type").''; } @@ -730,7 +730,7 @@ if ($result) print ''.$objp->price_level.""; } // Price by quantity - if (! empty($conf->global->PRODUIT_PRICE_BY_QTY)) + if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) { $type = ($objp->price_by_qty == 1) ? 'PriceByQuantity' : 'Standard'; print ''.$langs->trans($type).""; From 3c6c954cfce9ed76cf42ed92369932afc8ae5d3c Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 5 Dec 2012 01:08:42 +0100 Subject: [PATCH 12/25] Generate Create method in script to build webservice from class --- dev/skeletons/build_webservice_from_class.php | 21 +++++ dev/skeletons/skeleton_webservice_server.php | 77 ++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/dev/skeletons/build_webservice_from_class.php b/dev/skeletons/build_webservice_from_class.php index 435b068df35..f489f32201b 100644 --- a/dev/skeletons/build_webservice_from_class.php +++ b/dev/skeletons/build_webservice_from_class.php @@ -142,6 +142,27 @@ while($i\$'.$classmin.'->prop1,/', $varprop, $targetcontent); $targetcontent=preg_replace('/\'prop2\'=>\$'.$classmin.'->prop2,/', '', $targetcontent); +// Substitute get method parameters +$varprop="\n\t\t"; +$cleanparam=''; +$i=0; + +while($i'.$properties[$i].';'; + + $i++; + if ($i == count($properties)) + $varprop.="\n"; + else + $varprop.="\n\t\t"; +} +$targetcontent=preg_replace('/\$newobject->prop1=\$'.$classmin.'->prop1;/', $varprop, $targetcontent); +$targetcontent=preg_replace('/\$newobject->prop2=\$'.$classmin.'->prop2;/', '', $targetcontent); + + + // Build file $fp=fopen($outfile,"w"); if ($fp) diff --git a/dev/skeletons/skeleton_webservice_server.php b/dev/skeletons/skeleton_webservice_server.php index 2e2804790ca..c791c7b9968 100644 --- a/dev/skeletons/skeleton_webservice_server.php +++ b/dev/skeletons/skeleton_webservice_server.php @@ -118,11 +118,25 @@ $server->register( 'WS to get skeleton' ); +// Register WSDL +$server->register( + 'createSkeleton', + // Entry values + array('authentication'=>'tns:authentication','skeleton'=>'tns:skeleton'), + // Exit values + array('result'=>'tns:result','id'=>'xsd:string'), + $ns, + $ns.'#createSkeleton', + $styledoc, + $styleuse, + 'WS to create a skeleton' +); + /** - * Get produt or service + * Get Skeleton * * @param array $authentication Array of authentication information * @param int $id Id of object @@ -192,6 +206,67 @@ function getSkeleton($authentication,$id,$ref='',$ref_ext='') } +/** + * Create Skeleton + * + * @param array $authentication Array of authentication information + * @param Skeleton $skeleton $skeleton + * @return array Array result + */ +function createSkeleton($authentication,$skeleton) +{ + global $db,$conf,$langs; + + $now=dol_now(); + + dol_syslog("Function: createSkeleton login=".$authentication['login']); + + if ($authentication['entity']) $conf->entity=$authentication['entity']; + + // Init and check authentication + $objectresp=array(); + $errorcode='';$errorlabel=''; + $error=0; + $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel); + // Check parameters + + + if (! $error) + { + $newobject=new Skeleton($db); + $newobject->prop1=$skeleton->prop1; + $newobject->prop2=$skeleton->prop2; + //... + + $db->begin(); + + $result=$newobject->create($fuser); + if ($result <= 0) + { + $error++; + } + + if (! $error) + { + $db->commit(); + $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref); + } + else + { + $db->rollback(); + $error++; + $errorcode='KO'; + $errorlabel=$newobject->error; + } + } + + if ($error) + { + $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); + } + + return $objectresp; +} // Return the results. $server->service($HTTP_RAW_POST_DATA); From 771634c66b8ae3f768d8432c9f1de98f3367c41c Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 5 Dec 2012 02:11:11 +0100 Subject: [PATCH 13/25] Add contact info when get an user by webservice --- htdocs/webservices/server_user.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/webservices/server_user.php b/htdocs/webservices/server_user.php index e035b098b91..5804ed98521 100644 --- a/htdocs/webservices/server_user.php +++ b/htdocs/webservices/server_user.php @@ -107,7 +107,7 @@ $server->wsdl->addComplexType( 'pass_indatabase_crypted' => array('name'=>'pass_indatabase_crypted','type'=>'xsd:string'), 'datec' => array('name'=>'datec','type'=>'xsd:dateTime'), 'datem' => array('name'=>'datem','type'=>'xsd:dateTime'), - 'societe_id' => array('name'=>'societe_id','type'=>'xsd:string'), + 'fk_socpeople' => array('name'=>'fk_socpeople','type'=>'xsd:string'), 'fk_member' => array('name'=>'fk_member','type'=>'xsd:string'), 'datelastlogin' => array('name'=>'datelastlogin','type'=>'xsd:dateTime'), 'datepreviouslogin' => array('name'=>'datepreviouslogin','type'=>'xsd:dateTime'), @@ -251,6 +251,7 @@ function getUser($authentication,$id,$ref='',$ref_ext='') 'datec' => dol_print_date($user->datec,'dayhourrfc'), 'datem' => dol_print_date($user->datem,'dayhourrfc'), 'societe_id' => $user->societe_id, +'fk_socpeople' => $user->fk_socpeople, 'fk_member' => $user->fk_member, 'webcal_login' => $user->webcal_login, 'phenix_login' => $user->phenix_login, From 8ae10ef9f0f707b151417922ab4e07f0a5e1a66e Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 5 Dec 2012 03:47:25 +0100 Subject: [PATCH 14/25] New webservice methods for contact : - new method to get contact info - new method to create a contact - new method to get a list of contact for a thirdparty --- htdocs/webservices/server_contact.php | 541 ++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 htdocs/webservices/server_contact.php diff --git a/htdocs/webservices/server_contact.php b/htdocs/webservices/server_contact.php new file mode 100644 index 00000000000..cfda8c242a5 --- /dev/null +++ b/htdocs/webservices/server_contact.php @@ -0,0 +1,541 @@ + + * Copyright (C) 2012 JF FERRY + * + * 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, see . + */ + +/** + * \file htdocs/webservices/server_contact.php + * \brief File that is entry point to call Dolibarr WebServices + */ + +// This is to make Dolibarr working with Plesk +set_include_path($_SERVER['DOCUMENT_ROOT'].'/htdocs'); + +require_once("../master.inc.php"); +require_once(NUSOAP_PATH.'/nusoap.php'); // Include SOAP +require_once(DOL_DOCUMENT_ROOT."/core/lib/ws.lib.php"); +require_once(DOL_DOCUMENT_ROOT."/contact/class/contact.class.php"); + + +dol_syslog("Call Contact webservices interfaces"); + +// Enable and test if module web services is enabled +if (empty($conf->global->MAIN_MODULE_WEBSERVICES)) +{ + $langs->load("admin"); + dol_syslog("Call Dolibarr webservices interfaces with module webservices disabled"); + print $langs->trans("WarningModuleNotActive",'WebServices').'.

'; + print $langs->trans("ToActivateModule"); + exit; +} + +// Create the soap Object +$server = new nusoap_server(); +$server->soap_defencoding='UTF-8'; +$server->decode_utf8=false; +$ns='http://www.dolibarr.org/ns/'; +$server->configureWSDL('WebServicesDolibarrContact',$ns); +$server->wsdl->schemaTargetNamespace=$ns; + + +// Define WSDL Authentication object +$server->wsdl->addComplexType( + 'authentication', + 'complexType', + 'struct', + 'all', + '', + array( + 'dolibarrkey' => array('name'=>'dolibarrkey','type'=>'xsd:string'), + 'sourceapplication' => array('name'=>'sourceapplication','type'=>'xsd:string'), + 'login' => array('name'=>'login','type'=>'xsd:string'), + 'password' => array('name'=>'password','type'=>'xsd:string'), + 'entity' => array('name'=>'entity','type'=>'xsd:string'), + ) +); + +// Define WSDL Return object +$server->wsdl->addComplexType( + 'result', + 'complexType', + 'struct', + 'all', + '', + array( + 'result_code' => array('name'=>'result_code','type'=>'xsd:string'), + 'result_label' => array('name'=>'result_label','type'=>'xsd:string'), + ) +); + +// Define other specific objects +$server->wsdl->addComplexType( + 'contact', + 'complexType', + 'struct', + 'all', + '', + array( + 'id' => array('name'=>'id','type'=>'xsd:string'), + 'civilite_id' => array('name'=>'civilite_id','type'=>'xsd:string'), + 'lastname' => array('name'=>'lastname','type'=>'xsd:string'), + 'name' => array('name'=>'name','type'=>'xsd:string'), + 'firstname' => array('name'=>'firstname','type'=>'xsd:string'), + 'address' => array('name'=>'address','type'=>'xsd:string'), + 'cp' => array('name'=>'cp','type'=>'xsd:string'), + 'zip' => array('name'=>'zip','type'=>'xsd:string'), + 'town' => array('name'=>'town','type'=>'xsd:string'), + 'state_id' => array('name'=>'state_id','type'=>'xsd:string'), + 'state_code' => array('name'=>'state_code','type'=>'xsd:string'), + 'state' => array('name'=>'state','type'=>'xsd:string'), + 'fk_pays' => array('name'=>'fk_pays','type'=>'xsd:string'), + 'pays_code' => array('name'=>'pays_code','type'=>'xsd:string'), + 'pays' => array('name'=>'pays','type'=>'xsd:string'), + 'country_id' => array('name'=>'country_id','type'=>'xsd:string'), + 'country_code' => array('name'=>'country_code','type'=>'xsd:string'), + 'country' => array('name'=>'country','type'=>'xsd:string'), + 'socid' => array('name'=>'socid','type'=>'xsd:string'), + 'status' => array('name'=>'status','type'=>'xsd:string'), + 'code' => array('name'=>'code','type'=>'xsd:string'), + 'email' => array('name'=>'email','type'=>'xsd:string'), + 'birthday' => array('name'=>'birthday','type'=>'xsd:string'), + 'default_lang' => array('name'=>'default_lang','type'=>'xsd:string'), + 'note' => array('name'=>'note','type'=>'xsd:string'), + 'no_email' => array('name'=>'no_email','type'=>'xsd:string'), + 'ref_facturation' => array('name'=>'ref_facturation','type'=>'xsd:string'), + 'ref_contrat' => array('name'=>'ref_contrat','type'=>'xsd:string'), + 'ref_commande' => array('name'=>'ref_commande','type'=>'xsd:string'), + 'ref_propal' => array('name'=>'ref_propal','type'=>'xsd:string'), + 'user_id' => array('name'=>'user_id','type'=>'xsd:string'), + 'user_login' => array('name'=>'user_login','type'=>'xsd:string'), + 'civility_id' => array('name'=>'civility_id','type'=>'xsd:string'), + //... + ) +); + +$server->wsdl->addComplexType( + 'ContactsArray2', + 'complexType', + 'array', + 'sequence', + '', + array( + 'contact' => array( + 'name' => 'contact', + 'type' => 'tns:contact', + 'minOccurs' => '0', + 'maxOccurs' => 'unbounded' + ) + ) +); + + + + +// 5 styles: RPC/encoded, RPC/literal, Document/encoded (not WS-I compliant), Document/literal, Document/literal wrapped +// Style merely dictates how to translate a WSDL binding to a SOAP message. Nothing more. You can use either style with any programming model. +// http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/ +$styledoc='rpc'; // rpc/document (document is an extend into SOAP 1.0 to support unstructured messages) +$styleuse='encoded'; // encoded/literal/literal wrapped +// Better choice is document/literal wrapped but literal wrapped not supported by nusoap. + + +// Register WSDL +$server->register( + 'getContact', + // Entry values + array('authentication'=>'tns:authentication','id'=>'xsd:string','ref'=>'xsd:string','ref_ext'=>'xsd:string'), + // Exit values + array('result'=>'tns:result','contact'=>'tns:contact'), + $ns, + $ns.'#getContact', + $styledoc, + $styleuse, + 'WS to get contact' +); + +// Register WSDL +$server->register( + 'createContact', + // Entry values + array('authentication'=>'tns:authentication','contact'=>'tns:contact'), + // Exit values + array('result'=>'tns:result','id'=>'xsd:string'), + $ns, + $ns.'#createContact', + $styledoc, + $styleuse, + 'WS to create a contact' +); + +$server->register( + 'getContactsForThirdParty', + // Entry values + array('authentication'=>'tns:authentication','idthirdparty'=>'xsd:string'), + // Exit values + array('result'=>'tns:result','contacts'=>'tns:ContactsArray2'), + $ns, + $ns.'#getContactsForThirdParty', + $styledoc, + $styleuse, + 'WS to get all contacts of a third party' +); + + + + +/** + * Get Contact + * + * @param array $authentication Array of authentication information + * @param int $id Id of object + * @param string $ref Ref of object + * @param ref_ext $ref_ext Ref external of object + * @return mixed + */ +function getContact($authentication,$id,$ref='',$ref_ext='') +{ + global $db,$conf,$langs; + + dol_syslog("Function: getContact login=".$authentication['login']." id=".$id." ref=".$ref." ref_ext=".$ref_ext); + + if ($authentication['entity']) $conf->entity=$authentication['entity']; + + // Init and check authentication + $objectresp=array(); + $errorcode='';$errorlabel=''; + $error=0; + $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel); + // Check parameters + if (! $error && (($id && $ref) || ($id && $ref_ext) || ($ref && $ref_ext))) + { + $error++; + $errorcode='BAD_PARAMETERS'; $errorlabel="Parameter id, ref and ref_ext can't be both provided. You must choose one or other but not both."; + } + + if (! $error) + { + $fuser->getrights(); + + if ($fuser->rights->contact->read) + { + $contact=new Contact($db); + $result=$contact->fetch($id,$ref,$ref_ext); + if ($result > 0) + { + // Create + $objectresp = array( + 'result'=>array('result_code'=>'OK', 'result_label'=>''), + 'contact'=>array( + 'id' => $contact->id, + 'lastname' => $contact->lastname, + 'name' => $contact->name, + 'firstname' => $contact->firstname, + 'address' => $contact->address, + 'cp' => $contact->cp, + 'zip' => $contact->zip, + 'town' => $contact->town, + 'state_id' => $contact->state_id, + 'state_code' => $contact->state_code, + 'state' => $contact->state, + 'fk_pays' => $contact->fk_pays, + 'pays_code' => $contact->pays_code, + 'pays' => $contact->pays, + 'country_id' => $contact->country_id, + 'country_code' => $contact->country_code, + 'country' => $contact->country, + 'socid' => $contact->socid, + 'status' => $contact->status, + 'code' => $contact->code, + 'email' => $contact->email, + 'birthday' => $contact->birthday, + 'default_lang' => $contact->default_lang, + 'note' => $contact->note, + 'no_email' => $contact->no_email, + 'ref_facturation' => $contact->ref_facturation, + 'ref_contrat' => $contact->ref_contrat, + 'ref_commande' => $contact->ref_commande, + 'ref_propal' => $contact->ref_propal, + 'user_id' => $contact->user_id, + 'user_login' => $contact->user_login, + 'civility_id' => $contact->civility_id + ) + ); + } + else + { + $error++; + $errorcode='NOT_FOUND'; $errorlabel='Object not found for id='.$id.' nor ref='.$ref.' nor ref_ext='.$ref_ext; + } + } + else + { + $error++; + $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request'; + } + } + + if ($error) + { + $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); + } + + return $objectresp; +} + + +/** + * Create Contact + * + * @param array $authentication Array of authentication information + * @param Contact $contact $contact + * @return array Array result + */ +function createContact($authentication,$contact) +{ + global $db,$conf,$langs; + + $now=dol_now(); + + dol_syslog("Function: createContact login=".$authentication['login']); + + if ($authentication['entity']) $conf->entity=$authentication['entity']; + + // Init and check authentication + $objectresp=array(); + $errorcode='';$errorlabel=''; + $error=0; + $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel); + // Check parameters + + + if (! $error) + { + + + $newobject=new Contact($db); + + $newobject->id=$contact->id; + $newobject->civility_id=$contact->civility_id; + $newobject->lastname=$contact->lastname; + $newobject->name=$contact->name; + $newobject->firstname=$contact->firstname; + $newobject->address=$contact->address; + $newobject->zip=$contact->zip; + $newobject->town=$contact->town; + $newobject->state_id=$contact->state_id; + $newobject->state_code=$contact->state_code; + $newobject->state=$contact->state; + $newobject->fk_pays=$contact->fk_pays; + $newobject->pays_code=$contact->pays_code; + $newobject->pays=$contact->pays; + $newobject->country_id=$contact->country_id; + $newobject->country_code=$contact->country_code; + $newobject->country=$contact->country; + $newobject->socid=$contact->socid; + $newobject->status=$contact->status; + $newobject->code=$contact->code; + $newobject->email=$contact->email; + $newobject->birthday=$contact->birthday; + $newobject->default_lang=$contact->default_lang; + $newobject->note=$contact->note; + $newobject->no_email=$contact->no_email; + $newobject->ref_facturation=$contact->ref_facturation; + $newobject->ref_contrat=$contact->ref_contrat; + $newobject->ref_commande=$contact->ref_commande; + $newobject->ref_propal=$contact->ref_propal; + $newobject->user_id=$contact->user_id; + $newobject->user_login=$contact->user_login; + + + //... + + $db->begin(); + + $result=$newobject->create($fuser); + if ($result <= 0) + { + $error++; + } + + if (! $error) + { + $db->commit(); + $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref); + } + else + { + $db->rollback(); + $error++; + $errorcode='KO'; + $errorlabel=$newobject->error; + } + } + + if ($error) + { + $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); + } + + return $objectresp; +} + +/** + * Get list of contacts for third party + * + * @param array $authentication Array of authentication information + * @param int $idthirdparty Id thirdparty + * @return array Array result + */ +function getContactsForThirdParty($authentication,$idthirdparty) +{ + global $db,$conf,$langs; + + dol_syslog("Function: getContactsForThirdParty login=".$authentication['login']." idthirdparty=".$idthirdparty); + + if ($authentication['entity']) $conf->entity=$authentication['entity']; + + // Init and check authentication + $objectresp=array(); + $errorcode='';$errorlabel=''; + $error=0; + $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel); + // Check parameters + if (! $error && empty($idthirdparty)) + { + $error++; + $errorcode='BAD_PARAMETERS'; $errorlabel='Parameter id is not provided'; + } + + if (! $error) + { + $linesinvoice=array(); + + $sql = "SELECT c.rowid, c.fk_soc, c.civilite as civility_id, c.name as lastname, c.firstname,"; + $sql.= " c.address, c.cp as zip, c.ville as town,"; + $sql.= " c.fk_pays as country_id,"; + $sql.= " c.fk_departement,"; + $sql.= " c.birthday,"; + $sql.= " c.poste, c.phone, c.phone_perso, c.phone_mobile, c.fax, c.email, c.jabberid,"; + //$sql.= " c.priv, c.note, c.default_lang, c.no_email, c.canvas,"; + $sql.= " p.libelle as country, p.code as country_code,"; + $sql.= " d.nom as state, d.code_departement as state_code,"; + $sql.= " u.rowid as user_id, u.login as user_login,"; + $sql.= " s.nom as socname, s.address as socaddress, s.cp as soccp, s.ville as soccity, s.default_lang as socdefault_lang"; + $sql.= " FROM ".MAIN_DB_PREFIX."socpeople as c"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_pays as p ON c.fk_pays = p.rowid"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as d ON c.fk_departement = d.rowid"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON c.rowid = u.fk_socpeople"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON c.fk_soc = s.rowid"; + $sql.= " WHERE c.fk_soc=$idthirdparty"; + + + $resql=$db->query($sql); + if ($resql) + { + $num=$db->num_rows($resql); + $i=0; + while ($i < $num) + { + // En attendant remplissage par boucle + $obj=$db->fetch_object($resql); + + $contact=new Contact($db); + $contact->fetch($obj->rowid); + + + // Now define invoice + $linescontact[]=array( + 'id' => $contact->id, + 'ref' => $contact->ref, + 'civility_id' => $contact->civility_id?$contact->civility_id:'', + 'lastname' => $contact->lastname?$contact->lastname:'', + 'firstname' => $contact->firstname?$contact->firstname:'', + 'address' => $contact->address?$contact->address:'', + 'zip' => $contact->zip?$contact->zip:'', + 'town' => $contact->town?$contact->town:'', + + 'state_id' => $contact->state_id?$contact->state_id:'', + 'state_code' => $contact->state_code?$contact->state_code:'', + 'state' => $contact->state?$contact->state:'', + + 'fk_pays' => $contact->fk_pays?$contact->fk_pays:'', + 'country_id' => $contact->country_id?$contact->country_id:'', + 'pays_code' => $contact->pays_code?$contact->pays_code:'', + 'country_code' => $contact->country_code?$contact->country_code:'', + 'pays' => $contact->pays?$contact->pays:'', + 'country' => $contact->country?$contact->country:'', + + 'socid' => $contact->socid?$contact->socid:'', + 'socname' => $contact->socname?$contact->socname:'', + 'poste' => $contact->poste?$contact->poste:'', + + + + 'phone_pro' => $contact->phone_pro?$contact->phone_pro:'', + 'fax' => $contact->fax?$contact->fax:'', + 'phone_perso' => $contact->phone_perso?$contact->phone_perso:'', + 'phone_mobile' => $contact->phone_mobile?$contact->phone_mobile:'', + + 'email' => $contact->email?$contact->email:'', + 'jabberid' => $contact->jabberid?$contact->jabberid:'', + 'priv' => $contact->priv?$contact->priv:'', + 'mail' => $contact->mail?$contact->mail:'', + + 'birthday' => $contact->birthday?$contact->birthday:'', + 'default_lang' => $contact->default_lang?$contact->default_lang:'', + 'note' => $contact->note?$contact->note:'', + 'no_email' => $contact->no_email?$contact->no_email:'', + 'ref_facturation' => $contact->ref_facturation?$contact->ref_facturation:'', + 'ref_contrat' => $contact->ref_contrat?$contact->ref_contrat:'', + 'ref_commande' => $contact->ref_commande?$contact->ref_commande:'', + 'ref_propal' => $contact->ref_propal?$contact->ref_propal:'', + 'user_id' => $contact->user_id?$contact->user_id:'', + 'user_login' => $contact->no_email?$contact->user_login:'' + + + + + + ); + + $i++; + } + + $objectresp=array( + 'result'=>array('result_code'=>'OK', 'result_label'=>''), + 'contacts'=>$linescontact + + ); + } + else + { + $error++; + $errorcode=$db->lasterrno(); $errorlabel=$db->lasterror(); + } + } + + if ($error) + { + $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); + } + + return $objectresp; +} + +// Return the results. +$server->service($HTTP_RAW_POST_DATA); + +?> From 9a8f81c740da38d455ffef526fa11baf75cc30ce Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 5 Dec 2012 06:42:05 +0100 Subject: [PATCH 15/25] Remove deprecated fields fix : data is an array, not an object --- htdocs/webservices/server_contact.php | 76 +++++++++++---------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/htdocs/webservices/server_contact.php b/htdocs/webservices/server_contact.php index cfda8c242a5..bb846309307 100644 --- a/htdocs/webservices/server_contact.php +++ b/htdocs/webservices/server_contact.php @@ -89,20 +89,14 @@ $server->wsdl->addComplexType( '', array( 'id' => array('name'=>'id','type'=>'xsd:string'), - 'civilite_id' => array('name'=>'civilite_id','type'=>'xsd:string'), 'lastname' => array('name'=>'lastname','type'=>'xsd:string'), - 'name' => array('name'=>'name','type'=>'xsd:string'), 'firstname' => array('name'=>'firstname','type'=>'xsd:string'), 'address' => array('name'=>'address','type'=>'xsd:string'), - 'cp' => array('name'=>'cp','type'=>'xsd:string'), 'zip' => array('name'=>'zip','type'=>'xsd:string'), 'town' => array('name'=>'town','type'=>'xsd:string'), 'state_id' => array('name'=>'state_id','type'=>'xsd:string'), 'state_code' => array('name'=>'state_code','type'=>'xsd:string'), 'state' => array('name'=>'state','type'=>'xsd:string'), - 'fk_pays' => array('name'=>'fk_pays','type'=>'xsd:string'), - 'pays_code' => array('name'=>'pays_code','type'=>'xsd:string'), - 'pays' => array('name'=>'pays','type'=>'xsd:string'), 'country_id' => array('name'=>'country_id','type'=>'xsd:string'), 'country_code' => array('name'=>'country_code','type'=>'xsd:string'), 'country' => array('name'=>'country','type'=>'xsd:string'), @@ -120,7 +114,7 @@ $server->wsdl->addComplexType( 'ref_propal' => array('name'=>'ref_propal','type'=>'xsd:string'), 'user_id' => array('name'=>'user_id','type'=>'xsd:string'), 'user_login' => array('name'=>'user_login','type'=>'xsd:string'), - 'civility_id' => array('name'=>'civility_id','type'=>'xsd:string'), + 'civility_id' => array('name'=>'civility_id','type'=>'xsd:string') //... ) ); @@ -241,18 +235,13 @@ function getContact($authentication,$id,$ref='',$ref_ext='') 'contact'=>array( 'id' => $contact->id, 'lastname' => $contact->lastname, - 'name' => $contact->name, 'firstname' => $contact->firstname, 'address' => $contact->address, - 'cp' => $contact->cp, 'zip' => $contact->zip, 'town' => $contact->town, 'state_id' => $contact->state_id, 'state_code' => $contact->state_code, 'state' => $contact->state, - 'fk_pays' => $contact->fk_pays, - 'pays_code' => $contact->pays_code, - 'pays' => $contact->pays, 'country_id' => $contact->country_id, 'country_code' => $contact->country_code, 'country' => $contact->country, @@ -319,7 +308,10 @@ function createContact($authentication,$contact) $error=0; $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel); // Check parameters - + if (empty($contact['lastname'])) + { + $error++; $errorcode='KO'; $errorlabel="Name is mandatory."; + } if (! $error) { @@ -327,37 +319,33 @@ function createContact($authentication,$contact) $newobject=new Contact($db); - $newobject->id=$contact->id; - $newobject->civility_id=$contact->civility_id; - $newobject->lastname=$contact->lastname; - $newobject->name=$contact->name; - $newobject->firstname=$contact->firstname; - $newobject->address=$contact->address; - $newobject->zip=$contact->zip; - $newobject->town=$contact->town; - $newobject->state_id=$contact->state_id; - $newobject->state_code=$contact->state_code; - $newobject->state=$contact->state; - $newobject->fk_pays=$contact->fk_pays; - $newobject->pays_code=$contact->pays_code; - $newobject->pays=$contact->pays; - $newobject->country_id=$contact->country_id; - $newobject->country_code=$contact->country_code; - $newobject->country=$contact->country; - $newobject->socid=$contact->socid; - $newobject->status=$contact->status; - $newobject->code=$contact->code; - $newobject->email=$contact->email; - $newobject->birthday=$contact->birthday; - $newobject->default_lang=$contact->default_lang; - $newobject->note=$contact->note; - $newobject->no_email=$contact->no_email; - $newobject->ref_facturation=$contact->ref_facturation; - $newobject->ref_contrat=$contact->ref_contrat; - $newobject->ref_commande=$contact->ref_commande; - $newobject->ref_propal=$contact->ref_propal; - $newobject->user_id=$contact->user_id; - $newobject->user_login=$contact->user_login; + $newobject->id=$contact['id']; + $newobject->civility_id=$contact['civility_id']; + $newobject->lastname=$contact['lastname']; + $newobject->firstname=$contact['firstname']; + $newobject->address=$contact['address']; + $newobject->zip=$contact['zip']; + $newobject->town=$contact['town']; + $newobject->state_id=$contact['state_id']; + $newobject->state_code=$contact['state_code']; + $newobject->state=$contact['state']; + $newobject->country_id=$contact['country_id']; + $newobject->country_code=$contact['country_code']; + $newobject->country=$contact['country']; + $newobject->socid=$contact['socid']; + $newobject->status=$contact['status']; + $newobject->code=$contact['code']; + $newobject->email=$contact['email']; + $newobject->birthday=$contact['birthday']; + $newobject->default_lang=$contact['default_lang']; + $newobject->note=$contact['note']; + $newobject->no_email=$contact['no_email']; + $newobject->ref_facturation=$contact['ref_facturation']; + $newobject->ref_contrat=$contact['ref_contrat']; + $newobject->ref_commande=$contact['ref_commande']; + $newobject->ref_propal=$contact['ref_propal']; + $newobject->user_id=$contact['user_id']; + $newobject->user_login=$contact['user_login']; //... From 3d4621327c6f9450289fddf85e8efcd1f9e4a79b Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 5 Dec 2012 11:18:45 +0100 Subject: [PATCH 16/25] =?UTF-8?q?Fix:=20EOL=20!!=20tant=20que=20ce=20probl?= =?UTF-8?q?=C3=A8me=20sera=20pr=C3=A9sent,=20les=20risques=20de=20probl?= =?UTF-8?q?=C3=A8mes=20de=20merge=20et=20de=20conflits=20sera=20pr=C3=A9se?= =?UTF-8?q?nt=20!!=20il=20faut=20utiliser=20la=20derni=C3=A8re=20version?= =?UTF-8?q?=20d'Eclipse=20et=20de=20Egit...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/class/conf.class.php | 38 ++++++++++---------- htdocs/core/lib/functions.lib.php | 8 ++--- htdocs/core/modules/syslog/logHandler.php | 12 +++---- htdocs/install/fileconf.php | 42 +++++++++++------------ htdocs/product/price.php | 2 +- htdocs/societe/class/societe.class.php | 20 +++++------ htdocs/user/class/user.class.php | 2 +- 7 files changed, 62 insertions(+), 62 deletions(-) diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 5c8954d6664..1555222cbd5 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -458,26 +458,26 @@ class Conf if (is_object($mc)) $mc->setValues($this); } - // We init log handlers - if (defined('SYSLOG_HANDLERS')) $handlers = json_decode(constant('SYSLOG_HANDLERS')); - else $handlers = array(); - foreach ($handlers as $handler) - { - $file = DOL_DOCUMENT_ROOT.'/core/modules/syslog/'.$handler.'.php'; - if (!file_exists($file)) - { - throw new Exception('Missing log handler file '.$handler.'.php'); - } - - require_once $file; - $loghandlerinstance = new $handler(); - if (!$loghandlerinstance instanceof LogHandlerInterface) - { - throw new Exception('Log handler does not extend LogHandlerInterface'); - } + // We init log handlers + if (defined('SYSLOG_HANDLERS')) $handlers = json_decode(constant('SYSLOG_HANDLERS')); + else $handlers = array(); + foreach ($handlers as $handler) + { + $file = DOL_DOCUMENT_ROOT.'/core/modules/syslog/'.$handler.'.php'; + if (!file_exists($file)) + { + throw new Exception('Missing log handler file '.$handler.'.php'); + } - $this->loghandlers[]=$loghandlerinstance; - } + require_once $file; + $loghandlerinstance = new $handler(); + if (!$loghandlerinstance instanceof LogHandlerInterface) + { + throw new Exception('Log handler does not extend LogHandlerInterface'); + } + + $this->loghandlers[]=$loghandlerinstance; + } } } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 78d9b653b87..a897009d78b 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -547,10 +547,10 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0) if (! empty($ident)) { - foreach ($conf->loghandlers as $loghandlerinstance) - { - $loghandlerinstance->setIdent($ident); - } + foreach ($conf->loghandlers as $loghandlerinstance) + { + $loghandlerinstance->setIdent($ident); + } } } diff --git a/htdocs/core/modules/syslog/logHandler.php b/htdocs/core/modules/syslog/logHandler.php index 8bce8a0d2a1..d2fba9bd9d7 100644 --- a/htdocs/core/modules/syslog/logHandler.php +++ b/htdocs/core/modules/syslog/logHandler.php @@ -62,14 +62,14 @@ class LogHandler return array(); } - /** - * Set current ident. + /** + * Set current ident. * * @param int $ident 1=Increase ident of 1, -1=Decrease ident of 1 - * @return void - */ - public function setIdent($ident) + * @return void + */ + public function setIdent($ident) { $this->ident+=$ident; - } + } } \ No newline at end of file diff --git a/htdocs/install/fileconf.php b/htdocs/install/fileconf.php index 9044cb53d74..349de13771a 100644 --- a/htdocs/install/fileconf.php +++ b/htdocs/install/fileconf.php @@ -38,27 +38,27 @@ $langs->load("errors"); dolibarr_install_syslog("Fileconf: Entering fileconf.php page"); -// You can force preselected values of the config step of Dolibarr by adding a file -// install.forced.php into directory htdocs/install (This is the case with some wizard -// installer like DoliWamp, DoliMamp or DoliBuntu). -// We first init "forced values" to nothing. -if (! isset($force_install_noedit)) $force_install_noedit=''; // 1=To block var specific to distrib, 2 to block all technical parameters -if (! isset($force_install_type)) $force_install_type=''; -if (! isset($force_install_dbserver)) $force_install_dbserver=''; -if (! isset($force_install_port)) $force_install_port=''; -if (! isset($force_install_database)) $force_install_database=''; -if (! isset($force_install_prefix)) $force_install_prefix=''; -if (! isset($force_install_createdatabase)) $force_install_createdatabase=''; -if (! isset($force_install_databaselogin)) $force_install_databaselogin=''; -if (! isset($force_install_databasepass)) $force_install_databasepass=''; -if (! isset($force_install_databaserootlogin)) $force_install_databaserootlogin=''; -if (! isset($force_install_databaserootpass)) $force_install_databaserootpass=''; -// Now we load forced value from install.forced.php file. -$useforcedwizard=false; -$forcedfile="./install.forced.php"; -if ($conffile == "/etc/dolibarr/conf.php") $forcedfile="/etc/dolibarr/install.forced.php"; // Must be after inc.php -if (@file_exists($forcedfile)) { - $useforcedwizard=true; include_once $forcedfile; +// You can force preselected values of the config step of Dolibarr by adding a file +// install.forced.php into directory htdocs/install (This is the case with some wizard +// installer like DoliWamp, DoliMamp or DoliBuntu). +// We first init "forced values" to nothing. +if (! isset($force_install_noedit)) $force_install_noedit=''; // 1=To block var specific to distrib, 2 to block all technical parameters +if (! isset($force_install_type)) $force_install_type=''; +if (! isset($force_install_dbserver)) $force_install_dbserver=''; +if (! isset($force_install_port)) $force_install_port=''; +if (! isset($force_install_database)) $force_install_database=''; +if (! isset($force_install_prefix)) $force_install_prefix=''; +if (! isset($force_install_createdatabase)) $force_install_createdatabase=''; +if (! isset($force_install_databaselogin)) $force_install_databaselogin=''; +if (! isset($force_install_databasepass)) $force_install_databasepass=''; +if (! isset($force_install_databaserootlogin)) $force_install_databaserootlogin=''; +if (! isset($force_install_databaserootpass)) $force_install_databaserootpass=''; +// Now we load forced value from install.forced.php file. +$useforcedwizard=false; +$forcedfile="./install.forced.php"; +if ($conffile == "/etc/dolibarr/conf.php") $forcedfile="/etc/dolibarr/install.forced.php"; // Must be after inc.php +if (@file_exists($forcedfile)) { + $useforcedwizard=true; include_once $forcedfile; } //$force_install_message='This is the message'; diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 390b09127e7..491c5aab681 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -432,7 +432,7 @@ else print ''; if($object->prices_by_qty[0] == 1) { - print ''; + print '
'; print ''; print ''; print ''; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 6a43e5e4396..f59b123663c 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -1044,19 +1044,19 @@ class Societe extends CommonObject // Remove extrafields if (! $error) { - $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_extrafields WHERE fk_object = ".$id; - dol_syslog(get_class($this)."::delete sql=".$sql); - if (! $this->db->query($sql)) - { - $error++; - $this->error = $this->db->lasterror(); - dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR); - } + $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_extrafields WHERE fk_object = ".$id; + dol_syslog(get_class($this)."::delete sql=".$sql); + if (! $this->db->query($sql)) + { + $error++; + $this->error = $this->db->lasterror(); + dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR); + } } // Remove third party - if (! $error) - { + if (! $error) + { $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe"; $sql.= " WHERE rowid = " . $id; dol_syslog(get_class($this)."::delete sql=".$sql, LOG_DEBUG); diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index 8276f4adaca..ed91ad5beeb 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -700,7 +700,7 @@ class User extends CommonObject $sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user WHERE fk_user = ".$this->id; if (! $error && ! $this->db->query($sql)) { - $error++; + $error++; $this->error = $this->db->lasterror(); dol_syslog(get_class($this)."::delete error -2 ".$this->error, LOG_ERR); } From a4f0b7f0df994d97dd4fdd2322746c93d35f81ea Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 5 Dec 2012 11:36:10 +0100 Subject: [PATCH 17/25] Fix: avoid error with external modules --- htdocs/core/ajax/saveinplace.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/ajax/saveinplace.php b/htdocs/core/ajax/saveinplace.php index fa1fe128138..f67f9d71803 100644 --- a/htdocs/core/ajax/saveinplace.php +++ b/htdocs/core/ajax/saveinplace.php @@ -79,6 +79,7 @@ if (! empty($field) && ! empty($element) && ! empty($table_element) && ! empty($ $newelement = 'fournisseur'; $subelement = 'facture'; } + else $newelement = $element; if (! empty($user->rights->$newelement->creer) || ! empty($user->rights->$newelement->write) || (isset($subelement) && (! empty($user->rights->$newelement->$subelement->creer) || ! empty($user->rights->$newelement->$subelement->write))) From 5992ebcdbc1cd1696094895a1f0a4182bb6ab0d6 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 6 Feb 2013 11:52:49 +0100 Subject: [PATCH 18/25] New : option to reset numbering to 0 every month using @99 in the mask --- htdocs/core/lib/functions2.lib.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 90a2b1b3698..b50785e4fb9 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -607,6 +607,7 @@ function get_next_value($db,$mask,$table,$field,$where='',$objsoc='',$date='',$m if ($maskraz > 0) // A reset is required { + if ($maskraz == 99) $maskraz = date('m'); if ($maskraz > 12) return 'ErrorBadMaskBadRazMonth'; // Define posy, posm and reg From 28242784149cd8e28e538a5a19b6f823335260c9 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 5 Dec 2012 14:56:29 +0100 Subject: [PATCH 19/25] Trans : counter to 0 every month translations --- htdocs/langs/en_US/admin.lang | 2 +- htdocs/langs/fr_FR/admin.lang | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 0919133f936..ae78d55415e 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -276,7 +276,7 @@ YouCanSubmitFile=Select module: CurrentVersion=Dolibarr current version CallUpdatePage=Go to the page that updates the database structure and datas: %s. LastStableVersion=Last stable version -GenericMaskCodes=You may enter any numbering mask. In this mask, the following tags could be used:
{000000} corresponds to a number which will be incremented on each %s. Enter as many zeros as the desired length of the counter. The counter will be completed by zeros from the left in order to have as many zeros as the mask.
{000000+000} same as previous but an offset corresponding to the number to the right of the + sign is applied starting on first %s.
{000000@x} same as previous but the counter is reset to zero when month x is reached (x between 1 and 12, or 0 to use the early months of fiscal year defined in your configuration). If this option is used and x is 2 or higher, then sequence {yy}{mm} or {yyyy}{mm} is also required.
{dd} day (01 to 31).
{mm} month (01 to 12).
{yy}, {yyyy} or {y} year over 2, 4 or 1 numbers.
+GenericMaskCodes=You may enter any numbering mask. In this mask, the following tags could be used:
{000000} corresponds to a number which will be incremented on each %s. Enter as many zeros as the desired length of the counter. The counter will be completed by zeros from the left in order to have as many zeros as the mask.
{000000+000} same as previous but an offset corresponding to the number to the right of the + sign is applied starting on first %s.
{000000@x} same as previous but the counter is reset to zero when month x is reached (x between 1 and 12, or 0 to use the early months of fiscal year defined in your configuration, or 99 to reset to zero every month). If this option is used and x is 2 or higher, then sequence {yy}{mm} or {yyyy}{mm} is also required.
{dd} day (01 to 31).
{mm} month (01 to 12).
{yy}, {yyyy} or {y} year over 2, 4 or 1 numbers.
GenericMaskCodes2={cccc} the client code
{cccc000} the client code on n characters is followed by a client's ref counter without offset and zeroized with the global counter.
{tttt} The code of company type on n characters (see dictionnary-company types).
GenericMaskCodes3=All other characters in the mask will remain intact.
Spaces are not allowed.
GenericMaskCodes4a=Example on the 99th %s of the third party TheCompany done 2007-01-31:
diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 67c1c1f6e19..72782df79bb 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -276,7 +276,7 @@ YouCanSubmitFile=Sélectionner le module: CurrentVersion= Version en cours de Dolibarr CallUpdatePage= Appeler la page de l'outil de mise à jour de la structure et données de la base: %s. LastStableVersion= Dernière version stable disponible -GenericMaskCodes= Vous pouvez saisir tout masque de numérotation. Dans ce masque, les balises suivantes peuvent être utilisées:
{000000} correspond à un numéro qui sera incrémenté à chaque %s. Mettre autant de zéro que la longueur désirée du compteur. Le compteur sera complété par des 0 à gauche afin d'avoir autant de zéro que dans le masque.
{000000+000} idem précédemment mais un offset correspondant au nombre à droite du + est appliqué dès la première %s.
{000000@x} idem précédemment mais le compteur est remis à zéro le xème mois de l'année (x entre 1 et 12, ou 0 pour utiliser le mois de début d'exercice fiscal défini dans votre configuration). Si cette option est utilisée et x vaut 2 ou plus, alors la séquence {yy}{mm} ou {yyyy}{mm} est obligatoire.
{dd} jour (01 à 31).
{mm} mois (01 à 12).
{yy}, {yyyy} ou {y} année sur 2, 4 ou 1 chiffres.
+GenericMaskCodes= Vous pouvez saisir tout masque de numérotation. Dans ce masque, les balises suivantes peuvent être utilisées:
{000000} correspond à un numéro qui sera incrémenté à chaque %s. Mettre autant de zéro que la longueur désirée du compteur. Le compteur sera complété par des 0 à gauche afin d'avoir autant de zéro que dans le masque.
{000000+000} idem précédemment mais un offset correspondant au nombre à droite du + est appliqué dès la première %s.
{000000@x} idem précédemment mais le compteur est remis à zéro le xème mois de l'année (x entre 1 et 12, ou 0 pour utiliser le mois de début d'exercice fiscal défini dans votre configuration, ou 99 pour remise à zéro chaque mois). Si cette option est utilisée et x vaut 2 ou plus, alors la séquence {yy}{mm} ou {yyyy}{mm} est obligatoire.
{dd} jour (01 à 31).
{mm} mois (01 à 12).
{yy}, {yyyy} ou {y} année sur 2, 4 ou 1 chiffres.
GenericMaskCodes2= {cccc} le code client sur n lettres
{cccc000} le code client sur n lettres est suivi d'un compteur propre au client sans offset, complété par des zéros pour en avoir autant que dans le masque, et remis à zéro en même temps que le compteur global.
{tttt} Le code type entreprise sur n caractères (voir dictionnaires-types de sociétés).
GenericMaskCodes3= Tout autre caractère dans le masque sera laissé inchangé.
Les espaces ne sont pas permis.
GenericMaskCodes4a= Exemple sur la 99eme %s du tiers LaCompanie faite le 31/03/2007:
From 64f5d59ddf972a1b68f99c5707c852db4b24b0da Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 5 Dec 2012 15:42:59 +0100 Subject: [PATCH 20/25] Fix : on supplier bill validation, question about stock was asking for stock decrease instead of increase --- htdocs/fourn/facture/fiche.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/facture/fiche.php b/htdocs/fourn/facture/fiche.php index 6986b743dfd..f079f0a48fd 100644 --- a/htdocs/fourn/facture/fiche.php +++ b/htdocs/fourn/facture/fiche.php @@ -1274,7 +1274,7 @@ else //'text' => $langs->trans("ConfirmClone"), //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), //array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), - array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse'),'idwarehouse','',1))); + array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockIncrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse'),'idwarehouse','',1))); } $ret=$form->form_confirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateBill'), $langs->trans('ConfirmValidateBill', $object->ref), 'confirm_valid', $formquestion, 1, 1, 240); From 2a4261db2852516a0f5dae65534d5018284b3796 Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Wed, 5 Dec 2012 18:48:02 +0100 Subject: [PATCH 21/25] add linked object storage in fichinter --- htdocs/fichinter/class/fichinter.class.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index 3ebee6ed04a..86b7a8a067d 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -156,6 +156,14 @@ class Fichinter extends CommonObject if ($result) { $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX."fichinter"); + + // Add linked object + if (! $error && $this->origin && $this->origin_id) + { + $ret = $this->add_object_linked(); + if (! $ret) dol_print_error($this->db); + } + $this->db->commit(); // Appel des triggers From 0c064c777ae040a78730ea5648129619cca4f12d Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Wed, 5 Dec 2012 19:01:18 +0100 Subject: [PATCH 22/25] add ability to fichinter to be created from an order (services only) --- htdocs/fichinter/fiche.php | 206 ++++++++++++++++++++++++++++++++++--- 1 file changed, 194 insertions(+), 12 deletions(-) diff --git a/htdocs/fichinter/fiche.php b/htdocs/fichinter/fiche.php index d0b09b22279..e821bc3ab91 100644 --- a/htdocs/fichinter/fiche.php +++ b/htdocs/fichinter/fiche.php @@ -141,16 +141,144 @@ else if ($action == 'add' && $user->rights->ficheinter->creer) if ($object->socid > 0) { - $result = $object->create(); - if ($result > 0) - { - $id=$result; // Force raffraichissement sur fiche venant d'etre cree - } - else - { - $langs->load("errors"); - $mesg='
'.$langs->trans($object->error).'
'; - $action = 'create'; + // If creation from another object of another module (Example: origin=propal, originid=1) + if ($_POST['origin'] && $_POST['originid']) + { + // Parse element/subelement (ex: project_task) + $element = $subelement = $_POST['origin']; + if (preg_match('/^([^_]+)_([^_]+)/i',$_POST['origin'],$regs)) + { + $element = $regs[1]; + $subelement = $regs[2]; + } + + // For compatibility + if ($element == 'order') { $element = $subelement = 'commande'; } + if ($element == 'propal') { $element = 'comm/propal'; $subelement = 'propal'; } + if ($element == 'contract') { $element = $subelement = 'contrat'; } + + $object->origin = $_POST['origin']; + $object->origin_id = $_POST['originid']; + + // Possibility to add external linked objects with hooks + $object->linked_objects[$object->origin] = $object->origin_id; + if (is_array($_POST['other_linked_objects']) && ! empty($_POST['other_linked_objects'])) + { + $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']); + } + + $object_id = $object->create($user); + + if ($object_id > 0) + { + dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); + + $classname = ucfirst($subelement); + $srcobject = new $classname($db); + + dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines"); + $result=$srcobject->fetch($object->origin_id); + if ($result > 0) + { + $srcobject->fetch_thirdparty(); + $lines = $srcobject->lines; + if (empty($lines) && method_exists($srcobject,'fetch_lines')) $lines = $srcobject->fetch_lines(); + + $fk_parent_line=0; + $num=count($lines); + + for ($i=0;$i<$num;$i++) + { + $product_type=($lines[$i]->product_type?$lines[$i]->product_type:0); + + if ($product_type == 1) { //only services + // service prédéfini + if ($lines[$i]->fk_product > 0) + { + $product_static = new Product($db); + + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $prod = new Product($db, $lines[$i]->fk_product); + + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); + if (empty($newlang)) $newlang=$srcobject->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["libelle"])) ? $prod->multilangs[$outputlangs->defaultlang]["libelle"] : $lines[$i]->product_label; + } + else + { + $label = $lines[$i]->product_label; + } + + $product_static->type=$lines[$i]->fk_product_type; + $product_static->id=$lines[$i]->fk_product; + $product_static->ref=$lines[$i]->ref; + $product_static->libelle=$label; + $desc=$product_static->getNomUrl(0); + $desc.= ' - '.$label; + $desc .= ' ('.$langs->trans('Quantity').': '.$lines[$i]->qty.')'; + if ($conf->global->PRODUIT_DESC_IN_FORM) + $desc .= ($lines[$i]->desc && $lines[$i]->desc!=$lines[$i]->libelle)?'
'.dol_htmlentitiesbr($lines[$i]->desc):''; + } + else { + $desc = dol_htmlentitiesbr($lines[$i]->desc); + $desc .= ' ('.$langs->trans('Quantity').': '.$lines[$i]->qty.')'; + } + $timearray=dol_getdate(mktime()); + $date_intervention=dol_mktime(0,0,0,$timearray['mon'],$timearray['mday'],$timearray['year']); + $duration = 3600; + + $result = $object->addline( + $object_id, + $desc, + $date_intervention, + $duration + ); + + if ($result < 0) + { + $error++; + break; + } + + } + } + + } + else + { + $mesg=$srcobject->error; + $error++; + } + } + else + { + $mesg=$object->error; + $error++; + } + } + else + { + $result = $object->create(); + if ($result > 0) + { + $id=$result; // Force raffraichissement sur fiche venant d'etre cree + } + else + { + $langs->load("errors"); + $mesg='
'.$langs->trans($object->error).'
'; + $action = 'create'; + } } } else @@ -732,6 +860,54 @@ if ($action == 'create') dol_htmloutput_mesg($mesg); + if ($socid) $res=$soc->fetch($socid); + + if (GETPOST('origin') && GETPOST('originid')) + { + // Parse element/subelement (ex: project_task) + $element = $subelement = GETPOST('origin'); + if (preg_match('/^([^_]+)_([^_]+)/i',GETPOST('origin'),$regs)) + { + $element = $regs[1]; + $subelement = $regs[2]; + } + + if ($element == 'project') + { + $projectid=GETPOST('originid'); + } + else + { + // For compatibility + if ($element == 'order' || $element == 'commande') { $element = $subelement = 'commande'; } + if ($element == 'propal') { $element = 'comm/propal'; $subelement = 'propal'; } + if ($element == 'contract') { $element = $subelement = 'contrat'; } + + dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); + + $classname = ucfirst($subelement); + $objectsrc = new $classname($db); + $objectsrc->fetch(GETPOST('originid')); + if (empty($objectsrc->lines) && method_exists($objectsrc,'fetch_lines')) $objectsrc->fetch_lines(); + $objectsrc->fetch_thirdparty(); + + $projectid = (!empty($objectsrc->fk_project)?$objectsrc->fk_project:''); + + $soc = $objectsrc->client; + + $note_private = (! empty($objectsrc->note) ? $objectsrc->note : (! empty($objectsrc->note_private) ? $objectsrc->note_private : '')); + $note_public = (! empty($objectsrc->note_public) ? $objectsrc->note_public : ''); + + // Object source contacts list + $srccontactslist = $objectsrc->liste_contact(-1,'external',1); + } + } + else { + $projectid = GETPOST('projectid','int'); + $note_private = ''; + $note_public = ''; + } + if (! $conf->global->FICHEINTER_ADDON) { dol_print_error($db,$langs->trans("Error")." ".$langs->trans("Error_FICHEINTER_ADDON_NotDefined")); @@ -802,7 +978,7 @@ if ($action == 'create') print '
'; print ''; print ''; // Private note @@ -811,7 +987,7 @@ if ($action == 'create') print ''; print ''; print ''; } @@ -821,6 +997,12 @@ if ($action == 'create') print '
'.$langs->trans("PriceByQuantityRange").''.$langs->trans("HT").'
'.$langs->trans('NotePublic').''; - print ''; + print ''; print '
'.$langs->trans('NotePrivate').''; - print ''; + print ''; print '
'; + if (is_object($objectsrc)) + { + print ''; + print ''; + } + print '

'; print ''; print '
'; From b68153ce9a6af243ab7ee6f2ed5661fcf8d4830a Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Wed, 5 Dec 2012 19:07:07 +0100 Subject: [PATCH 23/25] add button in order to create intervention from services ordered --- htdocs/commande/fiche.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/htdocs/commande/fiche.php b/htdocs/commande/fiche.php index e7533d0055d..7bd1544fe14 100644 --- a/htdocs/commande/fiche.php +++ b/htdocs/commande/fiche.php @@ -2221,6 +2221,24 @@ if ($action == 'send' && ! GETPOST('addfile') && ! GETPOST('removedfile') && ! G } } + // Create intervention + if ($conf->ficheinter->enabled) + { + $langs->load("interventions"); + + if ($object->statut > 0 && $object->statut < 3 && $object->getNbOfServicesLines() > 0) + { + if ($user->rights->ficheinter->creer) + { + print '
'.$langs->trans('AddIntervention').''; + } + else + { + print ''.$langs->trans('AddIntervention').''; + } + } + } + // Reopen a closed order if ($object->statut == 3) { From 88db3da002e3f2c1a2f2c50f14ffe8675473acde Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Wed, 5 Dec 2012 19:51:25 +0100 Subject: [PATCH 24/25] allowing product search by supplier ref --- htdocs/fourn/product/liste.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/htdocs/fourn/product/liste.php b/htdocs/fourn/product/liste.php index 943afb272a9..5661e136b6f 100644 --- a/htdocs/fourn/product/liste.php +++ b/htdocs/fourn/product/liste.php @@ -3,6 +3,7 @@ * Copyright (C) 2004-2012 Laurent Destailleur * Copyright (C) 2005-2007 Regis Houssin * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel * * 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 @@ -99,6 +100,10 @@ if ($_POST["mode"] == 'search') { $sql .= " AND (p.ref LIKE '%".$_POST["sall"]."%'"; $sql .= " OR p.label LIKE '%".$_POST["sall"]."%')"; + if ($sRefSupplier) + { + $sql .= " AND ppf.ref_fourn LIKE '%".$sRefSupplier."%'"; + } } else { From bbc470b3ae870b4ac05ec401bf163eb565b16777 Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Wed, 5 Dec 2012 19:56:23 +0100 Subject: [PATCH 25/25] add search box to find product by supplier ref --- htdocs/main.inc.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index a0b28c7ff25..f5ab6d7d718 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -8,6 +8,7 @@ * Copyright (C) 2011 Philippe Grand * Copyright (C) 2008 Matteli * Copyright (C) 2011 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel * * 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 @@ -1419,6 +1420,13 @@ function left_menu($menu_array_before, $helppagename='', $moresearchform='', $me $searchform.=printSearchForm(DOL_URL_ROOT.'/product/liste.php', DOL_URL_ROOT.'/product/liste.php', img_object('','product').' '.$langs->trans("Products")."/".$langs->trans("Services"), 'products', 'sall'); } + if (((! empty($conf->product->enabled) && $user->rights->produit->lire) || (! empty($conf->service->enabled) && $user->rights->service->lire)) + && ! empty($conf->global->MAIN_SEARCHFORM_PRODUITSERVICE)) + { + $langs->load("products"); + $searchform.=printSearchForm(DOL_URL_ROOT.'/fourn/product/liste.php', DOL_URL_ROOT.'/fourn/product/liste.php', img_object('','product').' '.$langs->trans("SupplierRef"), 'products', 'srefsupplier'); + } + if (! empty($conf->adherent->enabled) && ! empty($conf->global->MAIN_SEARCHFORM_ADHERENT) && $user->rights->adherent->lire) { $langs->load("members");