Merge branch '11.0' of git@github.com:Dolibarr/dolibarr.git into develop

Conflicts:
	htdocs/product/stock/class/mouvementstock.class.php
This commit is contained in:
Laurent Destailleur 2020-01-18 20:20:25 +01:00
commit 24d439845b
17 changed files with 113 additions and 94 deletions

View File

@ -20,7 +20,7 @@
/**
* \file htdocs/comm/multiprix.php
* \ingroup societe
* \brief Onglet choix du niveau de prix
* \brief Tab to set the price level of a thirdparty
*/
require '../main.inc.php';
@ -64,20 +64,11 @@ $userstatic = new User($db);
if ($_socid > 0)
{
// On recupere les donnees societes par l'objet
// We load data of thirdparty
$objsoc = new Societe($db);
$objsoc->id = $_socid;
$objsoc->fetch($_socid, $to);
if ($errmesg)
{
print '<div class="error">'.$errmesg.'</div><br>';
}
/*
* Affichage onglets
*/
$head = societe_prepare_head($objsoc);
@ -91,7 +82,7 @@ if ($_socid > 0)
dol_fiche_head($head, $tabchoice, $langs->trans("ThirdParty"), 0, 'company');
print '<table class="border centpercent">';
print '<table class="border centpercent tableforfield">';
print '<tr><td class="titlefieldcreate">';
print $langs->trans("PriceLevel").'</td><td>'.$objsoc->price_level."</td></tr>";

View File

@ -3968,7 +3968,7 @@ elseif ($id > 0 || !empty($ref))
if ($result > 0) {
print '. <span class="opacitymediumbycolor">'.$langs->trans(
"GeneratedFromTemplate",
'<a href="'.DOL_MAIN_URL_ROOT.'/compta/facture/fiche-rec.php?facid='.$tmptemplate->id.'">'.$tmptemplate->ref.'</a>'
'<a href="'.DOL_MAIN_URL_ROOT.'/compta/facture/card-rec.php?facid='.$tmptemplate->id.'">'.$tmptemplate->ref.'</a>'
).'</span>';
}
}

View File

@ -604,7 +604,7 @@ if ($id > 0)
*/
$sql = "SELECT p.rowid, p.num_paiement, datep as dp, p.amount,";
$sql .= " c.code as type_code,c.libelle as paiement_type,";
$sql .= ' ba.rowid as baid, ba.ref as baref, ba.label, ba.number as banumber, ba.account_number, ba.fk_accountancy_journal';
$sql .= ' ba.rowid as baid, ba.ref as baref, ba.label, ba.number as banumber, ba.account_number, ba.currency_code as bacurrency_code, ba.fk_accountancy_journal';
$sql .= " FROM ".MAIN_DB_PREFIX."paiementcharge as p";
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid';
@ -653,6 +653,7 @@ if ($id > 0)
$bankaccountstatic->ref = $objp->baref;
$bankaccountstatic->label = $objp->baref;
$bankaccountstatic->number = $objp->banumber;
$bankaccountstatic->currency_code = $objp->bacurrency_code;
if (!empty($conf->accounting->enabled)) {
$bankaccountstatic->account_number = $objp->account_number;

View File

@ -33,7 +33,7 @@ if ($action == 'setnote_public' && ! empty($permissionnote) && ! GETPOST('cancel
if (empty($action) || ! is_object($object) || empty($id)) dol_print_error('', 'Include of actions_setnotes.inc.php was done but required variable was not set before');
if (empty($object->id)) $object->fetch($id); // Fetch may not be already done
$result_update=$object->update_note(dol_html_entity_decode(GETPOST('note_public', 'none'), ENT_QUOTES), '_public');
$result_update = $object->update_note(dol_html_entity_decode(GETPOST('note_public', 'none'), ENT_QUOTES, 'UTF-8', 1), '_public');
if ($result_update < 0) setEventMessages($object->error, $object->errors, 'errors');
elseif (in_array($object->table_element, array('supplier_proposal', 'propal', 'commande_fournisseur', 'commande', 'facture_fourn', 'facture')))

View File

@ -213,7 +213,7 @@ class Form
$valuetoshow = price2num($editvalue ? $editvalue : $value);
$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ?price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').'>';
}
elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata))
elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) // if wysiwyg is enabled $typeofdata = 'ckeditor'
{
$tmp = explode(':', $typeofdata);
$cols = $tmp[2];
@ -225,8 +225,10 @@ class Form
}
$valuetoshow = ($editvalue ? $editvalue : $value);
$ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'">';
// textarea convert automatically entities chars into simple chars.
// So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwig is off.
$valuetoshow = str_replace('&', '&amp;', $valuetoshow);
$ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
$ret .= '</textarea>';
}

View File

@ -5701,14 +5701,19 @@ function dol_htmlcleanlastbr($stringtodecode)
/**
* Replace html_entity_decode functions to manage errors
*
* @param string $a Operand a
* @param string $b Operand b (ENT_QUOTES=convert simple and double quotes)
* @param string $c Operand c
* @return string String decoded
* @param string $a Operand a
* @param string $b Operand b (ENT_QUOTES=convert simple and double quotes)
* @param string $c Operand c
* @param string $keepsomeentities Entities but &amp;, <, >, " are not converted.
* @return string String decoded
*/
function dol_html_entity_decode($a, $b, $c = 'UTF-8')
function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
{
return html_entity_decode($a, $b, $c);
$newstring = $a;
if ($keepsomeentities) $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
$newstring = html_entity_decode($newstring, $b, $c);
if ($keepsomeentities) $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
return $newstring;
}
/**

View File

@ -620,7 +620,7 @@ if (!empty($usemargins) && $user->rights->margins->creer)
/* When changing predefined product, we reload list of supplier prices required for margin combo */
$("#idprod, #idprodfournprice").change(function()
{
console.log("#idprod, #idprodfournprice change triggered this.val = "+$(this).val());
console.log("Call method change() after change on #idprod or #idprodfournprice. this.val = "+$(this).val());
setforpredef(); // TODO Keep vat combo visible and set it to first entry into list that match result of get_default_tva
@ -631,6 +631,7 @@ if (!empty($usemargins) && $user->rights->margins->creer)
{
?>
// Get the HT price for the product and display it
console.log("Load price without tax and set it into #price_ht");
$.post('<?php echo DOL_URL_ROOT; ?>/product/ajax/products.php?action=fetch',
{ 'id': $(this).val(), 'socid' : <?php print $object->socid; ?> },
function(data) { jQuery("#price_ht").val(data.price_ht); },

View File

@ -705,7 +705,7 @@ class CommandeFournisseur extends CommonOrder
*/
public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
{
global $langs, $conf;
global $langs, $conf, $user;
$result = '';
$label = '<u>'.$langs->trans("ShowOrder").'</u>';

View File

@ -2253,7 +2253,7 @@ class FactureFournisseur extends CommonInvoice
*/
public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
{
global $langs, $conf;
global $langs, $conf, $user;
$result = '';

View File

@ -267,7 +267,7 @@ WEBSITE_PAGEURL=URL of page
WEBSITE_TITLE=Title
WEBSITE_DESCRIPTION=Description
WEBSITE_IMAGE=Image
WEBSITE_IMAGEDesc=Relative path of the image media. You can keep this empty as this is rarely used (it can be used by dynamic content to show a preview of a list of blog posts).
WEBSITE_IMAGEDesc=Relative path of the image media. You can keep this empty as this is rarely used (it can be used by dynamic content to show a thumbnail in a list of blog posts). Use __WEBSITEKEY__ in the path if path depends on website name.
WEBSITE_KEYWORDS=Keywords
LinesToImport=Lines to import

View File

@ -59,8 +59,9 @@ dol_syslog(join(',', $_GET));
if (!empty($action) && $action == 'fetch' && !empty($id))
{
// When action='fetch', id must be the product id.
// action='fetch' is used to get product information on a product. So when action='fetch', id must be the product id.
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
$outjson = array();
@ -77,6 +78,13 @@ if (!empty($action) && $action == 'fetch' && !empty($id))
$found = false;
$price_level = 1;
if ($socid > 0 && !empty($conf->global->PRODUIT_MULTIPRICES)) {
$thirdpartytemp = new Societe($db);
$thirdpartytemp->fetch($socid);
$price_level = $thirdpartytemp->price_level;
}
// Price by qty
if (!empty($price_by_qty_rowid) && $price_by_qty_rowid >= 1 && (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY))) // If we need a particular price related to qty
{
@ -100,14 +108,13 @@ if (!empty($action) && $action == 'fetch' && !empty($id))
}
// Multiprice
if (!$found && isset($price_level) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES))) // If we need a particular price
// level (from 1 to 6)
if (!$found && isset($price_level) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES))) // 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 ";
$sql .= " WHERE fk_product='".$id."'";
$sql .= " WHERE fk_product = '".$id."'";
$sql .= " AND entity IN (".getEntity('productprice').")";
$sql .= " AND price_level=".$price_level;
$sql .= " AND price_level = ".((int) $price_level);
$sql .= " ORDER BY date_price";
$sql .= " DESC LIMIT 1";
@ -160,8 +167,7 @@ else
{
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
$langs->load("products");
$langs->load("main");
$langs->loadLangs(array("main", "products"));
top_httphead();
@ -186,6 +192,7 @@ else
$searchkey = (($idprod && GETPOST($idprod, 'alpha')) ? GETPOST($idprod, 'alpha') : (GETPOST($htmlname, 'alpha') ? GETPOST($htmlname, 'alpha') : ''));
$form = new Form($db);
if (empty($mode) || $mode == 1) { // mode=1: customer
$arrayresult = $form->select_produits_list("", $htmlname, $type, 0, $price_level, $searchkey, $status, $finished, $outjson, $socid, '1', 0, '', $hidepriceinlabel, $warehouseStatus);
} elseif ($mode == 2) { // mode=2: supplier

View File

@ -1596,11 +1596,19 @@ class Products extends DolibarrApi
}
if ($includestockdata) {
$this->product->load_stock();
$this->product->load_stock();
if (is_array($this->product->stock_warehouse)) {
foreach($this->product->stock_warehouse as $keytmp => $valtmp) {
if (is_array($this->product->stock_warehouse[$keytmp]->detail_batch)) {
foreach($this->product->stock_warehouse[$keytmp]->detail_batch as $keytmp2 => $valtmp2) {
unset($this->product->stock_warehouse[$keytmp]->detail_batch[$keytmp2]->db);
}
}
}
}
}
if ($includesubproducts) {
$childsArbo = $this->product->getChildsArbo($id, 1);

View File

@ -154,51 +154,42 @@ class StockMovements extends DolibarrApi
return $obj_ret;
}
/*
* @param int $product_id Id product id {@min 1}
* @param int $warehouse_id Id warehouse {@min 1}
* @param float $qty Qty to add (Use negative value for a stock decrease) {@min 0} {@message qty must be higher than 0}
* @param string $lot Lot
* @param string $movementcode Movement code {@example INV123}
* @param string $movementlabel Movement label {@example Inventory number 123}
* @param string $price To update AWP (Average Weighted Price) when you make a stock increase (qty must be higher then 0).
*/
/**
* Create stock movement object.
* You can use the following message to test this RES API:
* { "product_id": 1, "warehouse_id": 1, "qty": 1, "lot": "", "movementcode": "INV123", "movementlabel": "Inventory 123", "price": 0 }
* $price Can be set to update AWP (Average Weighted Price) when you make a stock increase
* $dlc Eat-by date. Will be used if lot does not exists yet and will be created.
* $dluo Sell-by date. Will be used if lot does not exists yet and will be created.
*
* @param int $product_id Id product id {@min 1} {@from body} {@required true}
* @param int $warehouse_id Id warehouse {@min 1} {@from body} {@required true}
* @param float $qty Qty to add (Use negative value for a stock decrease) {@min 0} {@message qty must be higher than 0} {@from body} {@required true}
* @param string $lot Lot {@from body}
* @param string $movementcode Movement code {@example INV123} {@from body}
* @param string $movementlabel Movement label {@example Inventory number 123} {@from body}
* @param string $price To update AWP (Average Weighted Price) when you make a stock increase (qty must be higher then 0). {@from body}
* @param string $dlc Eat-by date. {@from body} {@type date}
* @param string $dluo Sell-by date. {@from body} {@type date}
*
* @param array $request_data Request data
* @return int ID of stock movement
* @throws RestException
*/
//function post($product_id, $warehouse_id, $qty, $lot='', $movementcode='', $movementlabel='', $price=0)
public function post($request_data = null)
public function post($product_id, $warehouse_id, $qty, $lot = '', $movementcode = '', $movementlabel = '', $price = '', $dlc = '', $dluo = '')
{
if(! DolibarrApiAccess::$user->rights->stock->creer) {
throw new RestException(401);
}
// Check mandatory fields
//$result = $this->_validate($request_data);
foreach($request_data as $field => $value) {
//$this->stockmovement->$field = $value;
if ($field == 'product_id') $product_id = $value;
if ($field == 'warehouse_id') $warehouse_id = $value;
if ($field == 'qty') $qty = $value;
if ($field == 'lot') $lot = $value;
if ($field == 'movementcode') $movementcode = $value;
if ($field == 'movementlabel') $movementlabel = $value;
if ($field == 'price') $price = $value;
if ($qty == 0) {
throw new RestException(503, "Making a stock movement with a quentity of 0 is not possible");
}
// Type increase or decrease
if ($qty >= 0) $type = 3;
else $type = 2;
if($this->stockmovement->_create(DolibarrApiAccess::$user, $product_id, $warehouse_id, $qty, $type, $price, $movementlabel, $movementcode, '', '', '', $lot) <= 0) {
if($this->stockmovement->_create(DolibarrApiAccess::$user, $product_id, $warehouse_id, $qty, $type, $price, $movementlabel, $movementcode, '', $dlc, $dluo, $lot) <= 0) {
throw new RestException(503, 'Error when create stock movement : '.$this->stockmovement->error);
}
@ -342,7 +333,7 @@ class StockMovements extends DolibarrApi
private function _validate($data)
{
$stockmovement = array();
foreach (Warehouses::$FIELDS as $field) {
foreach (self::$FIELDS as $field) {
if (!isset($data[$field]))
throw new RestException(400, "$field field missing");
$stockmovement[$field] = $data[$field];

View File

@ -158,6 +158,8 @@ class MouvementStock extends CommonObject
$result = $product->fetch($fk_product);
if ($result < 0)
{
$this->error = $product->error;
$this->errors = $product->errors;
dol_print_error('', "Failed to fetch product");
return -1;
}
@ -399,7 +401,8 @@ class MouvementStock extends CommonObject
}
else
{
$this->errors[] = $this->db->lasterror();
$this->error = $this->db->lasterror();
$this->errors[] = $this->error;
$error = -1;
}

View File

@ -5,7 +5,7 @@
* Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2008 Patrick Raguin <patrick.raguin@auguria.net>
* Copyright (C) 2010-2016 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2011-2013 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
@ -1070,13 +1070,13 @@ else
$linkback = "";
print load_fiche_titre($langs->trans("NewThirdParty"), $linkback, 'building');
if (!empty($conf->use_javascript_ajax) && !empty($conf->global->THIRDPARTY_SUGGEST_ALSO_ADDRESS_CREATION))
{
print "\n".'<script type="text/javascript">';
print '$(document).ready(function () {
if (!empty($conf->use_javascript_ajax)) {
if (!empty($conf->global->THIRDPARTY_SUGGEST_ALSO_ADDRESS_CREATION)) {
print "\n" . '<script type="text/javascript">';
print '$(document).ready(function () {
id_te_private=8;
id_ef15=1;
is_private='.$private.';
is_private=' . $private . ';
if (is_private) {
$(".individualline").show();
} else {
@ -1103,7 +1103,7 @@ else
});
function init_customer_categ() {
console.log("is customer or prospect = "+jQuery("#customerprospect").val());
if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || '.(empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER) ? '1' : '0').'))
if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || ' . (empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER) ? '1' : '0') . '))
{
jQuery(".visibleifcustomer").hide();
}
@ -1134,28 +1134,38 @@ else
document.formsoc.submit();
});
});';
print '</script>'."\n";
print '</script>' . "\n";
print '<div id="selectthirdpartytype">';
print '<div class="hideonsmartphone float">';
print $langs->trans("ThirdPartyType").': &nbsp; &nbsp; ';
print '</div>';
print '<label for="radiocompany" class="radiocompany">';
print '<input type="radio" id="radiocompany" class="flat" name="private" value="0"'.($private ? '' : ' checked').'>';
print '&nbsp;';
print $langs->trans("CreateThirdPartyOnly");
print '</label>';
print ' &nbsp; &nbsp; ';
print '<label for="radioprivate" class="radioprivate">';
$text = '<input type="radio" id="radioprivate" class="flat" name="private" value="1"'.($private ? ' checked' : '').'>';
$text .= '&nbsp;';
$text .= $langs->trans("CreateThirdPartyAndContact");
$htmltext = $langs->trans("ToCreateContactWithSameName");
print $form->textwithpicto($text, $htmltext, 1, 'help', '', 0, 3);
print '</label>';
print '</div>';
print "<br>\n";
}
print '<div id="selectthirdpartytype">';
print '<div class="hideonsmartphone float">';
print $langs->trans("ThirdPartyType") . ': &nbsp; &nbsp; ';
print '</div>';
print '<label for="radiocompany" class="radiocompany">';
print '<input type="radio" id="radiocompany" class="flat" name="private" value="0"' . ($private ? '' : ' checked') . '>';
print '&nbsp;';
print $langs->trans("CreateThirdPartyOnly");
print '</label>';
print ' &nbsp; &nbsp; ';
print '<label for="radioprivate" class="radioprivate">';
$text = '<input type="radio" id="radioprivate" class="flat" name="private" value="1"' . ($private ? ' checked' : '') . '>';
$text .= '&nbsp;';
$text .= $langs->trans("CreateThirdPartyAndContact");
$htmltext = $langs->trans("ToCreateContactWithSameName");
print $form->textwithpicto($text, $htmltext, 1, 'help', '', 0, 3);
print '</label>';
print '</div>';
print "<br>\n";
} else {
print '<script type="text/javascript">';
print '$(document).ready(function () {
$("#selectcountry_id").change(function() {
document.formsoc.action.value="create";
document.formsoc.submit();
});
});';
print '</script>' . "\n";
}
}
dol_htmloutput_mesg(is_numeric($error) ? '' : $error, $errors, 'error');