Merge remote-tracking branch 'Upstream/develop' into develop-71

This commit is contained in:
aspangaro
2015-11-02 06:44:16 +01:00
20 changed files with 469 additions and 95 deletions

View File

@@ -56,7 +56,7 @@ JsTimezoneDetect 1.0.4 MIT License Yes
Raven.js 1.1.19 MIT License Yes Used for client-side error logging with Sentry logger
For licenses compatibility informations:
http://www.fsf.org/licensing/licenses/index_html
http://www.gnu.org/licenses/licenses.en.html
Copyright

View File

@@ -66,12 +66,12 @@ if (GETPOST('action','alpha') == 'set')
if (! $error)
{
$db->commit();
setEventMessage($langs->trans("SetupSaved"));
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
}
else
{
$db->rollback();
setEventMessage($langs->trans("Error"), 'errors');
setEventMessages($langs->trans("Error"), null, 'errors');
}
}

View File

@@ -155,7 +155,7 @@ if ($action == 'add' && $user->rights->categorie->creer)
}
else
{
setEventMessage($object->error,'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
}

View File

@@ -151,8 +151,7 @@ if (empty($reshook))
$result=$cat->del_type($object,$elementtype);
if ($result < 0)
{
setEventMessage($cat->error,'errors');
setEventMessage($cat->errors,'errors');
setEventMessages($cat->error, $cat->errors, 'errors');
}
}
@@ -199,17 +198,17 @@ if (empty($reshook))
$result=$cat->add_type($object,$elementtype);
if ($result >= 0)
{
setEventMessage($langs->trans("WasAddedSuccessfully",$cat->label));
setEventMessages($langs->trans("WasAddedSuccessfully",$cat->label), null, 'mesgs');
}
else
{
if ($cat->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
{
setEventMessage($langs->trans("ObjectAlreadyLinkedToCategory"),'warnings');
setEventMessages($langs->trans("ObjectAlreadyLinkedToCategory"), null, 'warnings');
}
else
{
setEventMessages( $cat->error, $cat->errors, 'errors' );
setEventMessages($cat->error, $cat->errors, 'errors');
}
}
}

View File

@@ -140,7 +140,7 @@ if ($action == 'confirm_clone' && $confirm == 'yes')
{
if (1 == 0 && ! GETPOST('clone_content') && ! GETPOST('clone_receivers'))
{
setEventMessage($langs->trans("NoCloneOptionsSpecified"), 'errors');
setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
}
else
{
@@ -151,7 +151,7 @@ if ($action == 'confirm_clone' && $confirm == 'yes')
header("Location: " . $_SERVER['PHP_SELF'] . '?id=' . $result);
exit();
} else {
setEventMessage($object->error, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
}
}
@@ -347,7 +347,7 @@ if ($action == 'add')
$db->rollback();
$langs->load("errors");
$error=$langs->trans($object->error);
setEventMessage($error,'errors');
setEventMessages($error, null, 'errors');
$action = 'create'; $donotclearsession=1;
}
}
@@ -551,8 +551,7 @@ if ($action == 'mupdate')
$result=$object->update($user);
if ($result < 0)
{
setEventMessage($object->error,'errors');
setEventMessage($object->errors,'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
if (! empty($backtopage))

View File

@@ -114,7 +114,7 @@ if (empty($reshook))
{
if (1 == 0 && ! GETPOST('clone_content') && ! GETPOST('clone_receivers'))
{
setEventMessage($langs->trans("NoCloneOptionsSpecified"), 'errors');
setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
}
else
{
@@ -123,8 +123,10 @@ if (empty($reshook))
if ($result > 0) {
header("Location: " . $_SERVER['PHP_SELF'] . '?id=' . $result);
exit();
} else {
setEventMessage($object->error, 'errors');
}
else
{
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
}
}
@@ -140,7 +142,7 @@ if (empty($reshook))
exit();
} else {
$langs->load("errors");
setEventMessage($langs->trans($object->error), 'errors');
setEventMessages($langs->trans($object->error), null, 'errors');
}
}
@@ -198,8 +200,8 @@ if (empty($reshook))
}
} else {
$langs->load("errors");
if (count($object->errors) > 0) setEventMessage($object->errors, 'errors');
else setEventMessage($langs->trans($object->error), 'errors');
if (count($object->errors) > 0) setEventMessages($object->error, $object->errors, 'errors');
else setEventMessages($langs->trans($object->error), null, 'errors');
}
}
@@ -249,7 +251,7 @@ if (empty($reshook))
$id = $object->create_from($user);
} else {
setEventMessage($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_askpricesupplier')), 'errors');
setEventMessages($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_askpricesupplier')), null, 'errors');
}
} else {
$object->ref = GETPOST('ref');
@@ -484,7 +486,7 @@ if (empty($reshook))
if ($object->id > 0) {
$result = $object->insert_discount($_POST["remise_id"]);
if ($result < 0) {
setEventMessage($object->error, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
@@ -674,7 +676,7 @@ if (empty($reshook))
if (! empty($price_min) && (price2num($pu_ht) * (1 - price2num($remise_percent) / 100) < price2num($price_min))) {
$mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency));
setEventMessage($mesg, 'errors');
setEventMessages($mesg, null, 'errors');
} else {
// Insert line
$ref_fourn = GETPOST('fourn_ref');
@@ -716,7 +718,7 @@ if (empty($reshook))
} else {
$db->rollback();
setEventMessage($object->error, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
@@ -774,7 +776,7 @@ if (empty($reshook))
$label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
if ($price_min && (price2num($pu_ht) * (1 - price2num(GETPOST('remise_percent')) / 100) < price2num($price_min))) {
setEventMessage($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)), 'errors');
setEventMessages($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)), null, 'errors');
$error ++;
}
} else {
@@ -823,7 +825,7 @@ if (empty($reshook))
} else {
$db->rollback();
setEventMessage($object->error, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
@@ -865,9 +867,9 @@ if (empty($reshook))
$file = $upload_dir . '/' . GETPOST('file');
$ret = dol_delete_file($file, 0, 0, 0, $object);
if ($ret)
setEventMessage($langs->trans("FileWasRemoved", GETPOST('file')));
setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs');
else
setEventMessage($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), 'errors');
setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), null, 'errors');
}
}
@@ -1325,7 +1327,7 @@ if ($action == 'create')
$numref = $object->getNextNumRef($soc);
if (empty($numref)) {
$error ++;
setEventMessage($object->error, 'errors');
setEventMessages($object->error, $object->errors, 'errors');
}
} else {
$numref = $object->ref;

View File

@@ -3,6 +3,7 @@
* Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2009-2010 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
*
* 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
@@ -166,6 +167,15 @@ function product_admin_prepare_head()
$head[$h][2] = 'general';
$h++;
if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
$head[$h] = array(
0 => DOL_URL_ROOT."/product/admin/price_rules.php",
1 => $langs->trans('MultipriceRules'),
2 => 'generator'
);
$h++;
}
// Show more tabs from modules
// Entries must be declared in modules descriptor with line
// $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab

View File

@@ -26,9 +26,9 @@
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(1, 5,'EXECBOARD', 'Executive board', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(2, 10, 'MANAGDIR', 'Managing director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(3, 15, 'ACCOUNTMANAG', 'Account manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(3, 20, 'ENGAGDIR', 'Engagement director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(4, 25, 'DIRECTOR', 'Director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(5, 30, 'PROJMANAG', 'Project manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(6, 35, 'DEPHEAD', 'Department head', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(7, 40, 'SECRETAR', 'Secretary', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(8, 45, 'EMPLOYEE', 'Department employee', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(4, 20, 'ENGAGDIR', 'Engagement director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(5, 25, 'DIRECTOR', 'Director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(6, 30, 'PROJMANAG', 'Project manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(7, 35, 'DEPHEAD', 'Department head', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(8, 40, 'SECRETAR', 'Secretary', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(9, 45, 'EMPLOYEE', 'Department employee', 0, 1);

View File

@@ -71,7 +71,6 @@ ALTER TABLE llx_contrat ADD COLUMN ref_customer varchar(30);
ALTER TABLE llx_commande ADD COLUMN fk_warehouse integer DEFAULT NULL after fk_shipping_method;
ALTER TABLE llx_ecm_directories MODIFY COLUMN fullpath varchar(750);
ALTER TABLE llx_ecm_directories DROP INDEX idx_ecm_directories;
ALTER TABLE llx_ecm_directories ADD UNIQUE INDEX uk_ecm_directories (label, fk_parent, entity);
--ALTER TABLE llx_ecm_directories ADD UNIQUE INDEX uk_ecm_directories_fullpath(fullpath);
@@ -134,12 +133,12 @@ CREATE TABLE IF NOT EXISTS llx_c_hrm_function
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(1, 5, 'EXECBOARD', 'Executive board', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(2, 10, 'MANAGDIR', 'Managing director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(3, 15, 'ACCOUNTMANAG', 'Account manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(3, 20, 'ENGAGDIR', 'Engagement director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(4, 25, 'DIRECTOR', 'Director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(5, 30, 'PROJMANAG', 'Project manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(6, 35, 'DEPHEAD', 'Department head', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(7, 40, 'SECRETAR', 'Secretary', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(8, 45, 'EMPLOYEE', 'Department employee', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(4, 20, 'ENGAGDIR', 'Engagement director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(5, 25, 'DIRECTOR', 'Director', 1, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(6, 30, 'PROJMANAG', 'Project manager', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(7, 35, 'DEPHEAD', 'Department head', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(8, 40, 'SECRETAR', 'Secretary', 0, 1);
INSERT INTO llx_c_hrm_function (rowid, pos, code, label, c_level, active) VALUES(9, 45, 'EMPLOYEE', 'Department employee', 0, 1);
CREATE TABLE IF NOT EXISTS llx_c_hrm_department
(
@@ -255,3 +254,15 @@ ALTER TABLE llx_budget_lines ADD CONSTRAINT fk_budget_lines_budget FOREIGN KEY (
ALTER TABLE llx_c_typent ADD COLUMN position integer NOT NULL DEFAULT 0;
ALTER TABLE llx_c_forme_juridique ADD COLUMN position integer NOT NULL DEFAULT 0;
ALTER TABLE llx_c_type_fees ADD COLUMN position integer NOT NULL DEFAULT 0;
-- NEW Level multiprice generator based on per cent variations over base price
CREATE TABLE llx_product_pricerules
(
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
level INT NOT NULL, -- Which price level is this rule for?
fk_level INT NOT NULL, -- Price variations are made over price of X
var_percent FLOAT NOT NULL, -- Price variation over based price
var_min_percent FLOAT NOT NULL -- Min price discount over general price
);
ALTER TABLE llx_product ADD COLUMN price_autogen TINYINT(1) DEFAULT 0;
ALTER TABLE llx_product_pricerules ADD CONSTRAINT unique_level UNIQUE (level);

View File

@@ -46,7 +46,7 @@ create table llx_product
price_base_type varchar(3) DEFAULT 'HT',
tva_tx double(6,3), -- Default VAT rate of product
recuperableonly integer NOT NULL DEFAULT '0', -- French NPR VAT
localtax1_tx double(6,3) DEFAULT 0, -- Spanish local VAT 1
localtax1_tx double(6,3) DEFAULT 0, -- Spanish local VAT 1
localtax2_tx double(6,3) DEFAULT 0, -- Spanish local VAT 2
fk_user_author integer DEFAULT NULL, -- user making creation
fk_user_modif integer, -- user making last change
@@ -81,5 +81,6 @@ create table llx_product
import_key varchar(14), -- Import key
fk_price_expression integer, -- Link to the rule for dynamic price calculation
desiredstock integer DEFAULT 0,
fk_unit integer DEFAULT NULL
fk_unit integer DEFAULT NULL,
price_autogen TINYINT DEFAULT 0
)ENGINE=innodb;

View File

@@ -0,0 +1,19 @@
-- ============================================================================
-- Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- ===========================================================================
ALTER TABLE llx_product_pricerules ADD CONSTRAINT unique_level UNIQUE (level);

View File

@@ -0,0 +1,26 @@
-- ============================================================================
-- Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- ===========================================================================
CREATE TABLE llx_product_pricerules
(
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
level INT NOT NULL, -- Which price level is this rule for?
fk_level INT NOT NULL, -- Price variations are made over price of X
var_percent FLOAT NOT NULL, -- Price variation over based price
var_min_percent FLOAT NOT NULL -- Min price discount over general price
);

View File

@@ -173,6 +173,7 @@ ErrorFieldMustBeAnInteger=Field <b>%s</b> must be an integer
ErrorMandatoryParametersNotProvided=Mandatory parameter(s) not provided
ErrorOppStatusRequiredIfAmount=You set an estimated amount for this opportunity/lead. So you must also enter its status
ErrorBadDefinitionOfMenuArrayInModuleDescriptor=Bad Definition Of Menu Array In Module Descriptor (bad value for key fk_menu)
ErrorSavingChanges=An error has ocurred when saving the changes
# Warnings
WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.

View File

@@ -23,3 +23,9 @@ PAYPAL_PAYONLINE_SENDEMAIL=EMail to warn after a payment (success or not)
ReturnURLAfterPayment=Return URL after payment
ValidationOfPaypalPaymentFailed=Validation of Paypal payment failed
PaypalConfirmPaymentPageWasCalledButFailed=Payment confirmation page for Paypal was called by Paypal but confirmation failed
SetExpressCheckoutAPICallFailed=SetExpressCheckout API call failed.
DoExpressCheckoutPaymentAPICallFailed=DoExpressCheckoutPayment API call failed.
DetailedErrorMessage=Detailed Error Message
ShortErrorMessage=Short Error Message
ErrorCode=Error Code
ErrorSeverityCode=Error Severity Code

View File

@@ -235,6 +235,10 @@ PriceByQuantityRange=Quantity range
ProductsDashboard=Products/Services summary
UpdateOriginalProductLabel=Modify original label
HelpUpdateOriginalProductLabel=Allows to edit the name of the product
MultipriceRules=Price level rules
UseMultipriceRules=Use price level rules
PercentVariationOver=%% variation over %s
PercentDiscountOver=%% discount over %s
### composition fabrication
Building=Production and items dispatchment
Build=Produce

View File

@@ -406,11 +406,11 @@ function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$re
$ErrorLongMsg = urldecode($resArray["L_LONGMESSAGE0"]);
$ErrorSeverityCode = urldecode($resArray["L_SEVERITYCODE0"]);
echo "SetExpressCheckout API call failed. <br>\n";
echo "Detailed Error Message: " . $ErrorLongMsg." <br>\n";
echo "Short Error Message: " . $ErrorShortMsg." <br>\n";
echo "Error Code: " . $ErrorCode." <br>\n";
echo "Error Severity Code: " . $ErrorSeverityCode." <br>\n";
echo $langs->trans('SetExpressCheckoutAPICallFailed') . "<br>\n";
echo $langs->trans('DetailedErrorMessage') . ": " . $ErrorLongMsg."<br>\n";
echo $langs->trans('ShortErrorMessage') . ": " . $ErrorShortMsg."<br>\n";
echo $langs->trans('ErrorCode') . ": " . $ErrorCode."<br>\n";
echo $langs->trans('ErrorSeverityCode') . ": " . $ErrorSeverityCode."<br>\n";
}
}

View File

@@ -0,0 +1,196 @@
<?php
/*
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
$langs->load("admin");
$langs->load("products");
// Security check
if (! $user->admin || (empty($conf->product->enabled) && empty($conf->service->enabled)))
accessforbidden();
/**
* Actions
*/
if ($_POST) {
$var_percent = GETPOST('var_percent', 'array');
$var_min_percent = GETPOST('var_min_percent', 'array');
$fk_level = GETPOST('fk_level', 'array');
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
$check = isset($var_min_percent[$i]);
if ($i != 1) {
$check = $check && isset($var_percent[$i]) && isset($fk_level[$i]);
}
if (!$check) {
continue;
}
if ($i != 1) {
$i_var_percent = (float) price2num($var_percent[$i]);
} else {
$i_var_percent = 0;
}
$i_var_min_percent = (float) price2num($var_min_percent[$i]);
$i_fk_level = (int) $fk_level[$i];
if ($i == 1) {
$check1 = true;
$check2 = $i_var_min_percent;
} else {
$check1 = $i_fk_level >= 1 && $i_fk_level <= $conf->global->PRODUIT_MULTIPRICES_LIMIT;
$check2 = $i_var_percent && $i_var_min_percent;
}
if (!$check1 || !$check2) {
//If the level is between range but percent fields are empty, then we ensure it does not exist in DB
if ($check1 && !$check2) {
$db->query("DELETE FROM ".MAIN_DB_PREFIX."product_pricerules WHERE level = ".(int) $i);
}
continue;
}
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_pricerules
SET level = ".(int) $i.", fk_level = ".$db->escape($i_fk_level).", var_percent = ".$i_var_percent.", var_min_percent = ".$i_var_min_percent;
if (!$db->query($sql)) {
//If we could not create, then we try updating
$sql = "UPDATE ".MAIN_DB_PREFIX."product_pricerules
SET fk_level = ".$db->escape($i_fk_level).", var_percent = ".$i_var_percent.", var_min_percent = ".$i_var_min_percent." WHERE level = ".$i;
if (!$db->query($sql)) {
setEventMessage($langs->trans('ErrorSavingChanges'), 'errors');
}
}
}
setEventMessage($langs->trans("RecordSaved"));
}
/*
* View
*/
$sql = "SELECT * FROM ".MAIN_DB_PREFIX."product_pricerules";
$query = $db->query($sql);
$rules = array();
while ($result = $db->fetch_object($query)) {
$rules[$result->level] = $result;
}
$title = $langs->trans('ProductServiceSetup');
$tab = $langs->trans("ProductsAndServices");
if (empty($conf->produit->enabled)) {
$title = $langs->trans('ServiceSetup');
$tab = $langs->trans('Services');
} elseif (empty($conf->service->enabled)) {
$title = $langs->trans('ProductSetup');
$tab = $langs->trans('Products');
}
llxHeader('', $langs->trans('MultipriceRules'));
$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($title,$linkback,'title_setup');
$head = product_admin_prepare_head();
dol_fiche_head($head, 'generator', $tab, 0, 'product');
print load_fiche_titre($langs->trans('MultipriceRules'));
//Array that contains the number of prices available
$price_options = array();
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
$price_options[$i] = $langs->trans('SellingPrice').' '.$i;
}
$genPriceOptions = function($level) use ($price_options) {
$return = array();
for ($i = 1; $i < $level; $i++) {
$return[$i] = $price_options[$i];
}
return $return;
};
?>
<form method="post">
<table class="noborder">
<tr class="liste_titre">
<td style="text-align: center"><?php echo $langs->trans('PriceLevel') ?></td>
<td style="text-align: center"><?php echo $langs->trans('Price') ?></td>
<td style="text-align: center"><?php echo $langs->trans('MinPrice') ?></td></tr>
<tr>
<td class="fieldrequired" style="text-align: center"><?php echo $langs->trans('SellingPrice') ?> 1</td>
<td></td>
<td style="text-align: center"><input type="text" style="text-align: right" name="var_min_percent[1]" size="5" value="<?php echo isset($rules[1]) ? price($rules[1]->var_min_percent, 2) : '' ?>"> <?php echo $langs->trans('PercentDiscountOver', $langs->trans('SellingPrice').' 1') ?></td>
</tr>
<?php for ($i = 2; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++): ?>
<tr>
<td class="fieldrequired" style="text-align: center"><?php
echo $langs->trans('SellingPrice').' '.$i;
// Label of price
if (! empty($conf->global->{"PRODUIT_MULTIPRICES_LABEL$i"})) {
print ' - '.$langs->trans($conf->global->$keyforlabel);
}
?>
</td>
<td style="text-align: center">
<input type="text" style="text-align: right" name="var_percent[<?php echo $i ?>]" size="5" value="<?php echo isset($rules[$i]) ? price($rules[$i]->var_percent, 2) : '' ?>">
<?php echo $langs->trans('PercentVariationOver', Form::selectarray("fk_level[$i]", $genPriceOptions($i), (isset($rules[$i]) ? $rules[$i]->fk_level : null))) ?>
</td>
<td style="text-align: center">
<input type="text" style="text-align: right" name="var_min_percent[<?php echo $i ?>]" size="5" value="<?php echo isset($rules[$i]) ? price($rules[$i]->var_min_percent, 2) : '' ?>">
<?php echo $langs->trans('PercentDiscountOver', $langs->trans('SellingPrice').' '.$i) ?>
</td>
</tr>
<?php endfor ?>
</table>
<br>
<div style="text-align: center">
<input type="submit" value="<?php echo $langs->trans('Save') ?>" class="button">
</div>
</form>
<?php
llxFooter();

View File

@@ -191,6 +191,12 @@ class Product extends CommonObject
*/
public $fk_unit;
/**
* Price is generated using multiprice rules
* @var int
*/
public $price_autogen = 0;
/**
* Regular product
*/
@@ -710,6 +716,7 @@ class Product extends CommonObject
$sql.= ", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell)."'";
$sql.= ", desiredstock = " . ((isset($this->desiredstock) && $this->desiredstock != '') ? $this->desiredstock : "null");
$sql.= ", fk_unit= " . (!$this->fk_unit ? 'NULL' : $this->fk_unit);
$sql.= ", price_autogen = " . (!$this->price_autogen ? 0 : 1);
$sql.= " WHERE rowid = " . $id;
dol_syslog(get_class($this)."::update", LOG_DEBUG);
@@ -1337,9 +1344,10 @@ class Product extends CommonObject
* @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
* @param int $ignore_autogen Used to avoid infinite loops
* @return int <0 if KO, >0 if OK
*/
function updatePrice($newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0, $newpsq=0)
function updatePrice($newprice, $newpricebase, $user, $newvat='',$newminprice='', $level=0, $newnpr=0, $newpsq=0, $ignore_autogen = 0)
{
global $conf,$langs;
@@ -1353,6 +1361,13 @@ class Product extends CommonObject
// Check parameters
if ($newvat == '') $newvat=$this->tva_tx;
//If multiprices are enabled, then we check if the current product is subject to price autogeneration
//Price will be modified ONLY when the first one is the one that is being modified
if (!empty($conf->global->PRODUIT_MULTIPRICES) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
return $this->generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpsq);
}
if (! empty($newminprice) && ($newminprice > $newprice))
{
$this->error='ErrorPriceCantBeLowerThanMinPrice';
@@ -1531,7 +1546,7 @@ class Product extends CommonObject
$sql.= " weight, weight_units, length, length_units, surface, surface_units, volume, volume_units, barcode, fk_barcode_type, finished,";
$sql.= " accountancy_code_buy, accountancy_code_sell, stock, pmp,";
$sql.= " datec, tms, import_key, entity, desiredstock, tobatch, fk_unit";
$sql.= " , fk_price_expression";
$sql.= " , fk_price_expression, price_autogen";
$sql.= " FROM ".MAIN_DB_PREFIX."product";
if ($id) $sql.= " WHERE rowid = ".$this->db->escape($id);
else
@@ -1608,6 +1623,7 @@ class Product extends CommonObject
$this->ref_ext = $obj->ref_ext;
$this->fk_price_expression = $obj->fk_price_expression;
$this->fk_unit = $obj->fk_unit;
$this->price_autogen = $obj->price_autogen;
$this->db->free($resql);
@@ -3992,4 +4008,64 @@ class Product extends CommonObject
return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
}
/**
* Generates prices for a product based on product multiprice generation rules
*
* @param User $user User that updates the prices
* @param float $baseprice Base price
* @param string $price_type Base price type
* @param float $price_vat VAT % tax
* @param int $npr NPR
* @param string $psq ¿?
* @return int -1 KO, 1 OK
*/
public function generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
{
global $conf, $db;
$sql = "SELECT * FROM ".MAIN_DB_PREFIX."product_pricerules";
$query = $db->query($sql);
$rules = array();
while ($result = $db->fetch_object($query)) {
$rules[$result->level] = $result;
}
//Because prices can be based on other level's prices, we temporarily store them
$prices = array(
1 => $baseprice
);
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
$price = $baseprice;
$price_min = 0;
if ($i > 1) {
//We have to make sure it does exist and it is > 0
if (isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
$price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent/100));
}
}
$prices[$i] = $price;
//We have to make sure it does exist and it is > 0
if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
$price_min = $price * (1 - ($rules[$i]->var_min_percent/100));
}
if ($price == $this->multiprices[$i] && ($price_min == $this->multiprices_min[$i])) {
continue;
}
if ($this->updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, true) < 0) {
return -1;
}
}
return 1;
}
}

View File

@@ -115,35 +115,35 @@ if (empty($reshook))
if (($action == 'update_price') && !$cancel && ($user->rights->produit->creer || $user->rights->service->creer))
{
$newprice = '';
$newprice_min = '';
$newpricebase = '';
$newvat = '';
$maxpricesupplier = $object->min_recommended_price();
$object->fk_price_expression = empty($eid) ? 0 : $eid; //0 discards expression
// MultiPrix
if (! empty($conf->global->PRODUIT_MULTIPRICES))
{
$newprice = '';
$newprice_min = '';
$newpricebase = '';
$newvat = '';
if (!empty($conf->global->PRODUIT_MULTIPRICES)) {
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i ++)
{
if (isset($_POST ["price_" . $i]))
{
//Shall we generate prices using price rules?
$object->price_autogen = GETPOST('usePriceRules') == 'on' ? true : false;
$object->update($object->id, $user);
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i ++) {
if (isset($_POST ["price_".$i])) {
$level = $i;
$newprice = price2num($_POST ["price_" . $i], 'MU');
$newprice_min = price2num($_POST ["price_min_" . $i], 'MU');
$newpricebase = $_POST ["multiprices_base_type_" . $i];
$newnpr = (preg_match('/\*/', $_POST ["tva_tx_" . $i]) ? 1 : 0);
$newvat = str_replace('*', '', $_POST ["tva_tx_" . $i]);
$newprice = price2num($_POST ["price_".$i], 'MU');
$newprice_min = price2num($_POST ["price_min_".$i], 'MU');
$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
}
}
}
else
{
} else {
$level = 0;
$newprice = price2num($_POST ["price"], 'MU');
$newprice_min = price2num($_POST ["price_min"], 'MU');
@@ -154,42 +154,39 @@ if (empty($reshook))
$newpsq = empty($newpsq) ? 0 : $newpsq;
}
if (! empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE) && $newprice_min < $maxpricesupplier)
{
setEventMessage($langs->trans("MinimumPriceLimit",price($maxpricesupplier,0,'',1,-1,-1,'auto')),'errors');
$error++;
$action='edit_price';
if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE) && $newprice_min < $maxpricesupplier) {
setEventMessage($langs->trans("MinimumPriceLimit", price($maxpricesupplier, 0, '', 1, - 1, - 1, 'auto')), 'errors');
$error ++;
$action = 'edit_price';
}
if ($newprice < $newprice_min && ! empty($object->fk_price_expression))
{
if ($newprice < $newprice_min && !empty($object->fk_price_expression)) {
$newprice = $newprice_min; //Set price same as min, the user will not see the
}
if ($object->updatePrice($newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr, $newpsq) > 0)
{
$res = $object->updatePrice($newprice, $newpricebase, $user, $newvat, $newprice_min, $level, $newnpr, $newpsq);
if ($res) {
if ($object->fk_price_expression != 0) {
//Check the expression validity by parsing it
$priceparser = new PriceParser($db);
$price_result = $priceparser->parseProduct($object);
if ($price_result < 0) { //Expression is not valid
$error++;
$action='edit_price';
$error ++;
$action = 'edit_price';
setEventMessage($priceparser->translatedError(), 'errors');
}
}
if (empty($error) && ! empty($conf->dynamicprices->enabled))
{
$ret=$object->setPriceExpression($object->fk_price_expression);
if ($ret < 0)
{
$error++;
$action='edit_price';
if (empty($error) && !empty($conf->dynamicprices->enabled)) {
$ret = $object->setPriceExpression($object->fk_price_expression);
if ($ret < 0) {
$error ++;
$action = 'edit_price';
setEventMessage($object->error, 'errors');
}
}
if (empty($error))
{
if (empty($error)) {
$action = '';
setEventMessage($langs->trans("RecordSaved"));
}
@@ -199,6 +196,7 @@ if (empty($reshook))
}
}
if ($action == 'delete' && $user->rights->produit->supprimer)
{
$result = $object->log_price_delete($user, $_GET ["lineid"]);
@@ -889,7 +887,32 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights->
{
dol_fiche_head('');
for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i ++)
?>
<script>
var showHidePriceRules = function () {
var otherPrices = $('div.fiche form:not(:first)');
var minPrice1 = $('div.fiche form:first tr:eq(3)');
if (jQuery('input#usePriceRules').prop('checked')) {
otherPrices.hide();
minPrice1.hide();
} else {
otherPrices.show();
minPrice1.show();
}
};
jQuery(document).ready(function () {
showHidePriceRules();
jQuery('input#usePriceRules').click(showHidePriceRules);
});
</script>
<?php
for($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i ++)
{
if ($i > 1) print '<br>';
@@ -907,6 +930,7 @@ if ($action == 'edit_price' && ($user->rights->produit->creer || $user->rights->
// VAT
if (! empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL))
{
print '<tr><td>' . $langs->trans('UseMultipriceRules'). '</td><td><input type="checkbox" id="usePriceRules" name="usePriceRules" '.($object->price_autogen ? 'checked' : '').'></td></tr>';
print '<tr><td>' . $langs->trans("VATRate") . '</td><td>';
print $form->load_tva("tva_tx_" . $i, $object->multiprices_tva_tx["$i"], $mysoc, '', $object->id);
print '</td></tr>';

View File

@@ -224,11 +224,11 @@ if ($PAYPALTOKEN)
$ErrorLongMsg = urldecode($resArray["L_LONGMESSAGE0"]);
$ErrorSeverityCode = urldecode($resArray["L_SEVERITYCODE0"]);
echo "DoExpressCheckoutPayment API call failed.<br>\n";
echo "Detailed Error Message: " . $ErrorLongMsg."<br>\n";
echo "Short Error Message: " . $ErrorShortMsg."<br>\n";
echo "Error Code: " . $ErrorCode."<br>\n";
echo "Error Severity Code: " . $ErrorSeverityCode."<br>\n";
echo $langs->trans('DoExpressCheckoutPaymentAPICallFailed') . "<br>\n";
echo $langs->trans('DetailedErrorMessage') . ": " . $ErrorLongMsg."<br>\n";
echo $langs->trans('ShortErrorMessage') . ": " . $ErrorShortMsg."<br>\n";
echo $langs->trans('ErrorCode') . ": " . $ErrorCode."<br>\n";
echo $langs->trans('ErrorSeverityCode') . ": " . $ErrorSeverityCode."<br>\n";
if ($mysoc->email) echo "\nPlease, send a screenshot of this page to ".$mysoc->email."<br>\n";