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); 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) { 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))) 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/class/html.form.class.php b/htdocs/core/class/html.form.class.php index f031750cb5b..e0c12b2c221 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1153,6 +1153,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)) @@ -1214,137 +1226,51 @@ 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, 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); + 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->quantity; + $objp->price = $objp2->price; + $objp->unitprice = $objp2->unitprice; + $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++; } @@ -1362,6 +1288,174 @@ 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) * @@ -1536,7 +1630,7 @@ class Form } } else - { + { $opt.= $langs->trans("NoPriceDefinedForThisSupplier"); $outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier"); } 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/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 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/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/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 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 ''.$langs->trans('NotePublic').''; print ''; - print ''; + print ''; print ''; // Private note @@ -811,7 +987,7 @@ if ($action == 'create') print ''; print ''.$langs->trans('NotePrivate').''; print ''; - print ''; + print ''; print ''; } @@ -821,6 +997,12 @@ if ($action == 'create') print ''; + if (is_object($objectsrc)) + { + print ''; + print ''; + } + print '

'; print ''; print '
'; 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); 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 { 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/install/mysql/migration/3.2.0-3.3.0.sql b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql index 0dcc01bd8e5..e81a3275532 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 @@ -801,6 +801,28 @@ ALTER TABLE llx_categorie ADD UNIQUE INDEX uk_categorie_ref (entity, fk_parent, 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 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); + +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`; + -- Change index name to be compliant with SQL standard, index name must be unique in database schema ALTER TABLE llx_c_actioncomm DROP INDEX code, ADD UNIQUE uk_c_actioncomm (code); ALTER TABLE llx_c_civilite DROP INDEX code, ADD UNIQUE uk_c_civilite (code); @@ -811,13 +833,11 @@ ALTER TABLE llx_c_typent DROP INDEX code, ADD UNIQUE uk_c_typent (code); ALTER TABLE llx_c_effectif DROP INDEX code, ADD UNIQUE uk_c_effectif (code); ALTER TABLE llx_c_paiement DROP INDEX code, ADD UNIQUE uk_c_paiement (code); - delete from llx_c_actioncomm where id = 40; INSERT INTO llx_c_actioncomm (id, code, type, libelle, module, position) values ( 40, 'AC_OTH_AUTO','systemauto', 'Other (automatically inserted events)' ,NULL, 20); UPDATE llx_c_actioncomm SET libelle = 'Other (manually inserted events)' WHERE code = 'AC_OTH'; UPDATE llx_c_actioncomm SET active = 0 WHERE code in ('AC_PROP', 'AC_COM', 'AC_FAC', 'AC_SHIP', 'AC_SUP_ORD', 'AC_SUP_INV'); - -- Update dictionnary of table llx_c_paper_format DELETE FROM llx_c_paper_format; @@ -850,8 +870,6 @@ INSERT INTO llx_c_paper_format (rowid, code, label, width, height, unit, active) -- increase field size ALTER TABLE llx_bank_account MODIFY COLUMN code_banque varchar(8); - - create table llx_user_extrafields ( rowid integer AUTO_INCREMENT PRIMARY KEY, @@ -860,5 +878,4 @@ create table llx_user_extrafields import_key varchar(14) -- import key )ENGINE=innodb; -ALTER TABLE llx_user_extrafields ADD INDEX idx_user_extrafields (fk_object); - +ALTER TABLE llx_user_extrafields ADD INDEX idx_user_extrafields (fk_object); \ No newline at end of file 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, 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; 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..e6eec68f632 --- /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, quantity); + +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..556753c309d --- /dev/null +++ b/htdocs/install/mysql/tables/llx_product_price_by_qty.sql @@ -0,0 +1,32 @@ +-- ============================================================================ +-- 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 NOT NULL AUTO_INCREMENT PRIMARY KEY, + fk_product_price integer NOT NULL, + 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, + unitprice double(24,8) DEFAULT 0 +)ENGINE=innodb; 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/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/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:
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 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"); diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index d1874d11eaa..9e20392fc34 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, unitprice, quantity, 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->unitprice); + $outprice_ttc=price($objp->unitprice * (1 + ($object->tva_tx / 100))); + $outpricebasetype=$object->price_base_type; + $outtva_tx=$object->tva_tx; + $outqty=$objp->quantity; + $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/class/product.class.php b/htdocs/product/class/product.class.php index 698e4794678..2b6e28c55f3 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; @@ -806,9 +815,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); @@ -945,9 +954,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; @@ -1036,6 +1046,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 @@ -1170,7 +1183,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."'"; @@ -1187,6 +1200,40 @@ 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, 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 quantity 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]["unitprice"]= $result["unitprice"]; + $resultat[$ii]["quantity"]= $result["quantity"]; + $resultat[$ii]["remise_percent"]= $result["remise_percent"]; + $resultat[$ii]["remise"]= $result["remise"]; + $ii++; + } + $this->prices_by_qty_list[$i]=$resultat; + } + else + { + dol_print_error($this->db); + return -1; + } + } } else { @@ -1194,6 +1241,58 @@ class Product extends CommonObject return -1; } } + } 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"; + $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, 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 quantity 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]["unitprice"]= $result["unitprice"]; + $resultat[$ii]["quantity"]= $result["quantity"]; + $resultat[$ii]["remise_percent"]= $result["remise_percent"]; + $resultat[$ii]["remise"]= $result["remise"]; + $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(); diff --git a/htdocs/product/price.php b/htdocs/product/price.php index cd0ce9ba307..491c5aab681 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,92 @@ else if ($action == 'delete' && $user->rights->produit->supprimer) if ($result < 0) $mesg='
'.$object->error.'
'; } +/***************************************************** + * 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'); + + $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 + $quantity=GETPOST('quantity'); + $remise_percent=price2num(GETPOST('remise_percent')); + $remise=0; // TODO : allow dicsount by amount when available on documents + + 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 = price2num($newprice) / (1 + ($object->tva_tx / 100)); + } + + $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); + } + } +} + +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 +320,77 @@ 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_CUSTOMER_PRICES_BY_QTY) { + print ''.$langs->trans("PriceByQuantity").' '.$i; + print ''; + + if($object->prices_by_qty[$i] == 1) { + print ''; + + 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 ''; + print ''; + } else { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + if($action != 'edit_price_by_qty' && ($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + //print ''; + print ''; + print ''; + print ''; + print ''; + } + + print '
'.$langs->trans("PriceByQuantityRange").' '.$i.''.$langs->trans("HT").''.$langs->trans("UnitPrice").''.$langs->trans("Discount").' 
 '.$object->price_base_type.'  %
'.$prices['quantity'].''.price($prices['price']).''.price($prices['unitprice']).''.price($prices['remise_percent']).' %'; + if(($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print img_edit().''; + print ''; + print img_delete().''; + } else { + print ' '; + } + print '
 '.$object->price_base_type.'  %
'; + } else { + print $langs->trans("No"); + print ' ('.$langs->trans("Activate").')'; + } + print ''; + } } } } @@ -261,6 +422,78 @@ else print price($object->price_min).' '.$langs->trans($object->price_base_type); } print ''; + + // Price by quantity + if($conf->global->PRODUIT_CUSTOMER_PRICES_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 ''; + 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 ''; + print ''; + } else { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } + } + if($action != 'edit_price_by_qty') { + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + //print ''; + print ''; + print ''; + print ''; + print ''; + } + + print '
'.$langs->trans("PriceByQuantityRange").''.$langs->trans("HT").''.$langs->trans("UnitPrice").''.$langs->trans("Discount").' 
 '.$object->price_base_type.'  %
'.$prices['quantity'].''.price($prices['price']).''.price($prices['unitprice']).''.price($prices['remise_percent']).' %'; + if(($user->rights->produit->creer || $user->rights->service->creer)) { + print ''; + print img_edit().''; + print ''; + print img_delete().''; + } else { + print ' '; + } + print '
 '.$object->price_base_type.'  %
'; + } else { + print $langs->trans("No"); + } + print ''; + } } // Status (to sell) @@ -426,7 +659,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 +697,11 @@ if ($result) if (! empty($conf->global->PRODUIT_MULTIPRICES)) { - print ''.$langs->trans("MultiPriceLevelsName").''; + print ''.$langs->trans("MultiPriceLevelsName").''; + } + if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) + { + print ''.$langs->trans("Type").''; } print ''.$langs->trans("PriceBase").''; @@ -492,6 +729,12 @@ if ($result) { print ''.$objp->price_level.""; } + // Price by quantity + if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_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).""; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index e9b8fd96f25..bd9b7cd87c6 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); } diff --git a/htdocs/webservices/server_contact.php b/htdocs/webservices/server_contact.php new file mode 100644 index 00000000000..bb846309307 --- /dev/null +++ b/htdocs/webservices/server_contact.php @@ -0,0 +1,529 @@ + + * 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'), + 'lastname' => array('name'=>'lastname','type'=>'xsd:string'), + 'firstname' => array('name'=>'firstname','type'=>'xsd:string'), + 'address' => array('name'=>'address','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'), + '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, + 'firstname' => $contact->firstname, + 'address' => $contact->address, + 'zip' => $contact->zip, + 'town' => $contact->town, + 'state_id' => $contact->state_id, + 'state_code' => $contact->state_code, + 'state' => $contact->state, + '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 (empty($contact['lastname'])) + { + $error++; $errorcode='KO'; $errorlabel="Name is mandatory."; + } + + if (! $error) + { + + + $newobject=new Contact($db); + + $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']; + + + //... + + $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); + +?> 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,