forked from Wavyzz/dolibarr
NEW Added product attributes feature
This commit is contained in:
65
htdocs/attributes/admin/admin.php
Normal file
65
htdocs/attributes/admin/admin.php
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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();
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
$value = GETPOST('PRODUIT_ATTRIBUTES_HIDECHILD');
|
||||||
|
|
||||||
|
if (dolibarr_set_const($db, 'PRODUIT_ATTRIBUTES_HIDECHILD', $value, 'chaine', 0, '', $conf->entity)) {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = $langs->trans('ModuleSetup').' '.$langs->trans('ProductAttributes');
|
||||||
|
llxHeader('', $title);
|
||||||
|
|
||||||
|
$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
|
||||||
|
print load_fiche_titre($title,$linkback,'title_setup');
|
||||||
|
|
||||||
|
dol_fiche_head(array(), 'general', $tab, 0, 'product');
|
||||||
|
|
||||||
|
print '<form method="post">';
|
||||||
|
print '<table class="noborder" width="100%">';
|
||||||
|
print '<tr class="liste_titre">';
|
||||||
|
print '<td>'.$langs->trans("Parameters").'</td>'."\n";
|
||||||
|
print '<td align="right" width="60">'.$langs->trans("Value").'</td>'."\n";
|
||||||
|
print '<td width="80"> </td></tr>'."\n";
|
||||||
|
print '<tr><td>'.$langs->trans('HideProductCombinations').'</td><td>';
|
||||||
|
print $form->selectyesno("PRODUIT_ATTRIBUTES_HIDECHILD",$conf->global->PRODUIT_ATTRIBUTES_HIDECHILD,1).'</td></tr>';
|
||||||
|
print '</table>';
|
||||||
|
print '<br><div style="text-align: center"><input type="submit" value="'.$langs->trans('Save').'" class="button"></div>';
|
||||||
|
print '</form>';
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
|
|
||||||
|
$db->close();
|
||||||
|
|
||||||
0
htdocs/attributes/admin/index.html
Normal file
0
htdocs/attributes/admin/index.html
Normal file
50
htdocs/attributes/ajax/getCombinations.php
Normal file
50
htdocs/attributes/ajax/getCombinations.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('NOTOKENRENEWAL','1');
|
||||||
|
define('NOREQUIREMENU','1');
|
||||||
|
define('NOREQUIREHTML','1');
|
||||||
|
define('NOREQUIREAJAX','1');
|
||||||
|
define('NOREQUIRESOC','1');
|
||||||
|
|
||||||
|
require '../../main.inc.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$id = GETPOST('id');
|
||||||
|
|
||||||
|
if (!$id) {
|
||||||
|
print json_encode(array(
|
||||||
|
'error' => 'ID not set'
|
||||||
|
));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = new Product($db);
|
||||||
|
|
||||||
|
if ($product->fetch($id) < 0) {
|
||||||
|
print json_encode(array(
|
||||||
|
'error' => 'Product not found'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
echo json_encode($prodcomb->getUniqueAttributesAndValuesByFkProductParent($product->id));
|
||||||
61
htdocs/attributes/ajax/get_attribute_values.php
Normal file
61
htdocs/attributes/ajax/get_attribute_values.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('NOTOKENRENEWAL','1');
|
||||||
|
define('NOREQUIREMENU','1');
|
||||||
|
define('NOREQUIREHTML','1');
|
||||||
|
define('NOREQUIREAJAX','1');
|
||||||
|
define('NOREQUIRESOC','1');
|
||||||
|
|
||||||
|
require '../../main.inc.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$id = GETPOST('id');
|
||||||
|
|
||||||
|
if (!$id) {
|
||||||
|
print json_encode(array(
|
||||||
|
'error' => 'ID not set'
|
||||||
|
));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
|
||||||
|
if ($prodattr->fetch($id) < 0) {
|
||||||
|
print json_encode(array(
|
||||||
|
'error' => 'Attribute not found'
|
||||||
|
));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodattrval = new ProductAttributeValue($db);
|
||||||
|
|
||||||
|
$res = $prodattrval->fetchAllByProductAttribute($id);
|
||||||
|
|
||||||
|
if ($res == -1) {
|
||||||
|
print json_encode(array(
|
||||||
|
'error' => 'Internal error'
|
||||||
|
));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
print json_encode($res);
|
||||||
0
htdocs/attributes/ajax/index.html
Normal file
0
htdocs/attributes/ajax/index.html
Normal file
53
htdocs/attributes/ajax/orderAttribute.php
Normal file
53
htdocs/attributes/ajax/orderAttribute.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Disable token renewal
|
||||||
|
if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
|
||||||
|
if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
|
||||||
|
if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
|
||||||
|
if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1');
|
||||||
|
if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1');
|
||||||
|
if (! defined('NOREQUIREHOOK')) define('NOREQUIREHOOK','1'); // Disable "main.inc.php" hooks
|
||||||
|
|
||||||
|
require '../../main.inc.php';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* View
|
||||||
|
*/
|
||||||
|
|
||||||
|
top_httphead();
|
||||||
|
|
||||||
|
// Registering the location of boxes
|
||||||
|
if (isset($_POST['roworder'])) {
|
||||||
|
$roworder=GETPOST('roworder','alpha',2);
|
||||||
|
|
||||||
|
dol_syslog("AjaxOrderAttribute roworder=".$roworder, LOG_DEBUG);
|
||||||
|
|
||||||
|
$rowordertab = explode(',', $roworder);
|
||||||
|
|
||||||
|
foreach ($rowordertab as $value) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
$newrowordertab[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
|
||||||
|
ProductAttribute::bulkUpdateOrder($db, $newrowordertab);
|
||||||
|
}
|
||||||
|
|
||||||
245
htdocs/attributes/card.php
Normal file
245
htdocs/attributes/card.php
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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 'class/ProductAttribute.class.php';
|
||||||
|
require 'class/ProductAttributeValue.class.php';
|
||||||
|
|
||||||
|
$id = GETPOST('id');
|
||||||
|
$valueid = GETPOST('valueid');
|
||||||
|
$action = GETPOST('action');
|
||||||
|
$label = GETPOST('label');
|
||||||
|
$ref = GETPOST('ref');
|
||||||
|
$confirm = GETPOST('confirm');
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattrval = new ProductAttributeValue($db);
|
||||||
|
|
||||||
|
if ($prodattr->fetch($id) < 1) {
|
||||||
|
dol_print_error($db, $langs->trans('ErrorRecordNotFound'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
if ($action == 'edit') {
|
||||||
|
|
||||||
|
$prodattr->label = $label;
|
||||||
|
$prodattr->ref = $ref;
|
||||||
|
|
||||||
|
if ($prodattr->update() < 1) {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/card.php?id='.$id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
} elseif ($action == 'edit_value') {
|
||||||
|
|
||||||
|
if ($prodattrval->fetch($valueid) > 0) {
|
||||||
|
|
||||||
|
$prodattrval->ref = $ref;
|
||||||
|
$prodattrval->value = GETPOST('value');
|
||||||
|
|
||||||
|
if ($prodattrval->update() > 0) {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: '.dol_buildpath('/attributes/card.php?id='.$prodattr->id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($confirm == 'yes') {
|
||||||
|
if ($action == 'confirm_delete') {
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
$res = $prodattrval->deleteByFkAttribute($prodattr->id);
|
||||||
|
|
||||||
|
if ($res < 1 || ($prodattr->delete() < 1)) {
|
||||||
|
$db->rollback();
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
header('Location: '.dol_buildpath('/attributes/card.php?id='.$prodattr->id, 2));
|
||||||
|
} else {
|
||||||
|
$db->commit();
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/list.php', 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
die;
|
||||||
|
} elseif ($action == 'confirm_deletevalue') {
|
||||||
|
|
||||||
|
if ($prodattrval->fetch($valueid) > 0) {
|
||||||
|
|
||||||
|
if ($prodattrval->delete() < 1) {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: '.dol_buildpath('/attributes/card.php?id='.$prodattr->id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$langs->load('products');
|
||||||
|
|
||||||
|
$title = $langs->trans('ProductAttributeName', dol_htmlentities($prodattr->label));
|
||||||
|
$var = false;
|
||||||
|
|
||||||
|
llxHeader('', $title);
|
||||||
|
|
||||||
|
print_fiche_titre($title);
|
||||||
|
|
||||||
|
dol_fiche_head();
|
||||||
|
|
||||||
|
if ($action == 'edit') {
|
||||||
|
print '<form method="post">';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<table class="border" style="width: 100%">
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><?php echo $langs->trans('Ref') ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($action == 'edit') {
|
||||||
|
print '<input type="text" name="ref" value="'.$prodattr->ref.'">';
|
||||||
|
} else {
|
||||||
|
print dol_htmlentities($prodattr->ref);
|
||||||
|
} ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><?php echo $langs->trans('Label') ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($action == 'edit') {
|
||||||
|
print '<input type="text" name="label" value="'.$prodattr->label.'">';
|
||||||
|
} else {
|
||||||
|
print dol_htmlentities($prodattr->label);
|
||||||
|
} ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
dol_fiche_end();
|
||||||
|
|
||||||
|
if ($action == 'edit') { ?>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div class="inline-block divButAction">
|
||||||
|
<input type="submit" class="button" value="<?php echo $langs->trans('Save') ?>">
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>" class="butAction"><?php echo $langs->trans('Cancel') ?></a>
|
||||||
|
</div>
|
||||||
|
</div></form>
|
||||||
|
<?php } else {
|
||||||
|
|
||||||
|
if ($action == 'delete') {
|
||||||
|
$form = new Form($db);
|
||||||
|
|
||||||
|
print $form->formconfirm(
|
||||||
|
"card.php?id=".$prodattr->id,
|
||||||
|
$langs->trans('Delete'),
|
||||||
|
$langs->trans('ProductAttributeDeleteDialog'),
|
||||||
|
"confirm_delete",
|
||||||
|
'',
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
} elseif ($action == 'delete_value') {
|
||||||
|
|
||||||
|
if ($prodattrval->fetch($valueid) > 0) {
|
||||||
|
|
||||||
|
$form = new Form($db);
|
||||||
|
|
||||||
|
print $form->formconfirm(
|
||||||
|
"card.php?id=".$prodattr->id."&valueid=".$prodattrval->id,
|
||||||
|
$langs->trans('Delete'),
|
||||||
|
$langs->trans('ProductAttributeValueDeleteDialog', dol_htmlentities($prodattrval->value), dol_htmlentities($prodattrval->ref)),
|
||||||
|
"confirm_deletevalue",
|
||||||
|
'',
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="tabsAction">
|
||||||
|
<div class="inline-block divButAction">
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>&action=edit" class="butAction"><?php echo $langs->trans('Modify') ?></a>
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>&action=delete" class="butAction"><?php echo $langs->trans('Delete') ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($action == 'edit_value'): ?>
|
||||||
|
<form method="post">
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<table class="liste">
|
||||||
|
<tr class="liste_titre">
|
||||||
|
<th class="liste_titre"><?php echo $langs->trans('Ref') ?></th>
|
||||||
|
<th class="liste_titre"><?php echo $langs->trans('Value') ?></th>
|
||||||
|
<th class="liste_titre"></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php foreach ($prodattrval->fetchAllByProductAttribute($prodattr->id) as $attrval): ?>
|
||||||
|
<tr <?php echo $bc[!$var] ?>>
|
||||||
|
<?php if ($action == 'edit_value' && ($valueid == $attrval->id)): ?>
|
||||||
|
<td><input type="text" name="ref" value="<?php echo $attrval->ref ?>"></td>
|
||||||
|
<td><input type="text" name="value" value="<?php echo $attrval->value ?>"></td>
|
||||||
|
<td style="text-align: right">
|
||||||
|
<input type="submit" value="<?php echo $langs->trans('Save') ?>" class="button">
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>" class="butAction"><?php echo $langs->trans('Cancel') ?></a>
|
||||||
|
</td>
|
||||||
|
<?php else: ?>
|
||||||
|
<td><?php echo dol_htmlentities($attrval->ref) ?></td>
|
||||||
|
<td><?php echo dol_htmlentities($attrval->value) ?></td>
|
||||||
|
<td style="text-align: right">
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>&action=edit_value&valueid=<?php echo $attrval->id ?>"><?php echo img_edit() ?></a>
|
||||||
|
<a href="card.php?id=<?php echo $prodattr->id ?>&action=delete_value&valueid=<?php echo $attrval->id ?>"><?php echo img_delete() ?></a>
|
||||||
|
</td>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
$var = !$var;
|
||||||
|
endforeach
|
||||||
|
?>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php if ($action == 'edit_value'): ?>
|
||||||
|
</form>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<div class="tabsAction">
|
||||||
|
<div class="inline-block divButAction">
|
||||||
|
<a href="create_val.php?id=<?php echo $prodattr->id ?>" class="butAction"><?php echo $langs->trans('Create') ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
317
htdocs/attributes/class/ProductAttribute.class.php
Normal file
317
htdocs/attributes/class/ProductAttribute.class.php
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProductAttribute
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database handler
|
||||||
|
* @var DoliDB
|
||||||
|
*/
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id of the product attribute
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ref of the product attribute
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $ref;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label of the product attribute
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order of attribute.
|
||||||
|
* Lower ones will be shown first and higher ones last
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $rang;
|
||||||
|
|
||||||
|
public function __construct(DoliDB $db)
|
||||||
|
{
|
||||||
|
global $conf;
|
||||||
|
|
||||||
|
$this->db = $db;
|
||||||
|
$this->entity = $conf->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the properties of a product attribute
|
||||||
|
*
|
||||||
|
* @param int $id Attribute id
|
||||||
|
* @return int <1 KO, >1 OK
|
||||||
|
*/
|
||||||
|
public function fetch($id)
|
||||||
|
{
|
||||||
|
if (!$id) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT rowid, ref, label, rang FROM ".MAIN_DB_PREFIX."product_attribute WHERE rowid = ".(int) $id." AND entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$this->db->num_rows($query)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->db->fetch_object($query);
|
||||||
|
|
||||||
|
$this->id = $result->rowid;
|
||||||
|
$this->ref = $result->ref;
|
||||||
|
$this->label = $result->label;
|
||||||
|
$this->rang = $result->rang;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all product attributes
|
||||||
|
*
|
||||||
|
* @return ProductAttribute[]
|
||||||
|
*/
|
||||||
|
public function fetchAll()
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$return = array();
|
||||||
|
|
||||||
|
$sql = 'SELECT rowid, ref, label, rang FROM '.MAIN_DB_PREFIX."product_attribute WHERE entity IN (".getProductEntities($this->db).')';
|
||||||
|
$sql .= $this->db->order('rang', 'asc');
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
|
||||||
|
$tmp = new ProductAttribute($this->db);
|
||||||
|
$tmp->id = $result->rowid;
|
||||||
|
$tmp->ref = $result->ref;
|
||||||
|
$tmp->label = $result->label;
|
||||||
|
$tmp->rang = $result->rang;
|
||||||
|
|
||||||
|
$return[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a product attribute
|
||||||
|
*
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//Ref must be uppercase
|
||||||
|
$this->ref = strtoupper($this->ref);
|
||||||
|
|
||||||
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_attribute (ref, label, entity, rang)
|
||||||
|
VALUES ('".$this->db->escape($this->ref)."', '".$this->db->escape($this->label)."', ".(int) $this->entity.", ".(int) $this->rang.")";
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if ($query) {
|
||||||
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'product_attribute');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a product attribute
|
||||||
|
*
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
//Ref must be uppercase
|
||||||
|
$this->ref = strtoupper($this->ref);
|
||||||
|
|
||||||
|
$sql = "UPDATE ".MAIN_DB_PREFIX."product_attribute SET ref = '".$this->db->escape($this->ref)."', label = '".$this->db->escape($this->label)."', rang = ".(int) $this->rang." WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a product attribute
|
||||||
|
*
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_attribute WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of products that are using this attribute
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function countChildProducts()
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT COUNT(*) count FROM ".MAIN_DB_PREFIX."product_attribute_combination2val pac2v
|
||||||
|
LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac2v.fk_prod_combination = pac.rowid WHERE pac2v.fk_prod_attr = ".(int) $this->id." AND pac.entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
$result = $this->db->fetch_object($query);
|
||||||
|
|
||||||
|
return $result->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorders the order of the attributes.
|
||||||
|
* This is an internal function used by moveLine function
|
||||||
|
*
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
protected function reorderLines()
|
||||||
|
{
|
||||||
|
$tmp_order = array();
|
||||||
|
|
||||||
|
$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'product_attribute WHERE rang = 0';
|
||||||
|
$sql .= $this->db->order('rang, rowid', 'asc');
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
$tmp_order[] = $result->rowid;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($tmp_order as $order => $rowid) {
|
||||||
|
$tmp = new ProductAttribute($this->db);
|
||||||
|
$tmp->fetch($rowid);
|
||||||
|
$tmp->rang = $order+1;
|
||||||
|
|
||||||
|
if ($tmp->update() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function to handle moveUp and moveDown functions
|
||||||
|
*
|
||||||
|
* @param string $type up/down
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
private function moveLine($type)
|
||||||
|
{
|
||||||
|
if ($this->reorderLines() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->begin();
|
||||||
|
|
||||||
|
if ($type == 'up') {
|
||||||
|
$newrang = $this->rang - 1;
|
||||||
|
} else {
|
||||||
|
$newrang = $this->rang + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'UPDATE '.MAIN_DB_PREFIX.'product_attribute SET rang = '.$this->rang.' WHERE rang = '.$newrang;
|
||||||
|
|
||||||
|
if (!$this->db->query($sql)) {
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rang = $newrang;
|
||||||
|
|
||||||
|
if ($this->update() < 0) {
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->commit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows this attribute before others
|
||||||
|
*
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public function moveUp()
|
||||||
|
{
|
||||||
|
return $this->moveLine('up');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows this attribute after others
|
||||||
|
*
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public function moveDown()
|
||||||
|
{
|
||||||
|
return $this->moveLine('down');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the order of all attributes. Used by AJAX page for drag&drop
|
||||||
|
*
|
||||||
|
* @param DoliDB $db Database handler
|
||||||
|
* @param array $order Array with row id ordered in ascendent mode
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public static function bulkUpdateOrder(DoliDB $db, array $order)
|
||||||
|
{
|
||||||
|
$tmp = new ProductAttribute($db);
|
||||||
|
|
||||||
|
foreach ($order as $key => $attrid) {
|
||||||
|
if ($tmp->fetch($attrid) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmp->rang = $key;
|
||||||
|
|
||||||
|
if ($tmp->update() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
221
htdocs/attributes/class/ProductAttributeValue.class.php
Normal file
221
htdocs/attributes/class/ProductAttributeValue.class.php
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProductAttributeValue
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database handler
|
||||||
|
* @var DoliDB
|
||||||
|
*/
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute value id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product attribute id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_product_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute value ref
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $ref;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute value value
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
public function __construct(DoliDB $db)
|
||||||
|
{
|
||||||
|
global $conf;
|
||||||
|
|
||||||
|
$this->db = $db;
|
||||||
|
$this->entity = $conf->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a product attribute value
|
||||||
|
*
|
||||||
|
* @param int $valueid Product attribute value id
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function fetch($valueid)
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT rowid, fk_product_attribute, ref, value FROM ".MAIN_DB_PREFIX."product_attribute_value WHERE rowid = ".(int) $valueid." AND entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->db->num_rows($query)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->db->fetch_object($query);
|
||||||
|
|
||||||
|
$this->id = $result->rowid;
|
||||||
|
$this->fk_product_attribute = $result->fk_product_attribute;
|
||||||
|
$this->ref = $result->ref;
|
||||||
|
$this->value = $result->value;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all product attribute values of a product attribute
|
||||||
|
*
|
||||||
|
* @param int $prodattr_id Product attribute id
|
||||||
|
* @param bool $only_used Fetch only used attribute values
|
||||||
|
* @return ProductAttributeValue[]
|
||||||
|
*/
|
||||||
|
public function fetchAllByProductAttribute($prodattr_id, $only_used = false)
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$return = array();
|
||||||
|
|
||||||
|
$sql = 'SELECT ';
|
||||||
|
|
||||||
|
if ($only_used) {
|
||||||
|
$sql .= 'DISTINCT ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= 'v.fk_product_attribute, v.rowid, v.ref, v.value FROM '.MAIN_DB_PREFIX.'product_attribute_value v ';
|
||||||
|
|
||||||
|
if ($only_used) {
|
||||||
|
$sql .= 'LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute_combination2val c2v ON c2v.fk_prod_attr_val = v.rowid ';
|
||||||
|
$sql .= 'LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute_combination c ON c.rowid = c2v.fk_prod_combination ';
|
||||||
|
$sql .= 'LEFT JOIN '.MAIN_DB_PREFIX.'product p ON p.rowid = c.fk_product_child ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= 'WHERE v.fk_product_attribute = '.(int) $prodattr_id;
|
||||||
|
|
||||||
|
if ($only_used) {
|
||||||
|
$sql .= ' AND c2v.rowid IS NOT NULL AND p.tosell = 1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
|
||||||
|
$tmp = new ProductAttributeValue($this->db);
|
||||||
|
$tmp->fk_product_attribute = $result->fk_product_attribute;
|
||||||
|
$tmp->id = $result->rowid;
|
||||||
|
$tmp->ref = $result->ref;
|
||||||
|
$tmp->value = $result->value;
|
||||||
|
|
||||||
|
$return[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a value for a product attribute
|
||||||
|
*
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
if (!$this->fk_product_attribute) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ref must be uppercase
|
||||||
|
$this->ref = strtoupper($this->ref);
|
||||||
|
|
||||||
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_attribute_value (fk_product_attribute, ref, value, entity)
|
||||||
|
VALUES ('".(int) $this->fk_product_attribute."', '".$this->db->escape($this->ref)."',
|
||||||
|
'".$this->db->escape($this->value)."', ".(int) $this->entity.")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if ($query) {
|
||||||
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'product_attribute_value');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a product attribute value
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
//Ref must be uppercase
|
||||||
|
$this->ref = strtoupper($this->ref);
|
||||||
|
|
||||||
|
$sql = "UPDATE ".MAIN_DB_PREFIX."product_attribute_value
|
||||||
|
SET fk_product_attribute = '".(int) $this->fk_product_attribute."', ref = '".$this->db->escape($this->ref)."',
|
||||||
|
value = '".$this->db->escape($this->value)."' WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a product attribute value
|
||||||
|
*
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_attribute_value WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all product attribute values by a product attribute id
|
||||||
|
*
|
||||||
|
* @param int $fk_attribute Product attribute id
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function deleteByFkAttribute($fk_attribute)
|
||||||
|
{
|
||||||
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_attribute_value WHERE fk_product_attribute = ".(int) $fk_attribute;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
641
htdocs/attributes/class/ProductCombination.class.php
Normal file
641
htdocs/attributes/class/ProductCombination.class.php
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProductCombination
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database handler
|
||||||
|
* @var DoliDB
|
||||||
|
*/
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rowid of combination
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rowid of parent product
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_product_parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rowid of child product
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_product_child;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Price variation
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
public $variation_price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the price variation a relative variation?
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $variation_price_percentage = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weight variation
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
public $variation_weight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combination entity
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $entity;
|
||||||
|
|
||||||
|
public function __construct(DoliDB $db)
|
||||||
|
{
|
||||||
|
global $conf;
|
||||||
|
|
||||||
|
$this->db = $db;
|
||||||
|
$this->entity = $conf->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a combination by its rowid
|
||||||
|
*
|
||||||
|
* @param int $rowid Row id
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function fetch($rowid)
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT rowid, fk_product_parent, fk_product_child, variation_price, variation_price_percentage, variation_weight FROM ".MAIN_DB_PREFIX."product_attribute_combination WHERE rowid = ".(int) $rowid." AND entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->db->num_rows($query)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->db->fetch_object($query);
|
||||||
|
|
||||||
|
$this->id = $result->rowid;
|
||||||
|
$this->fk_product_parent = $result->fk_product_parent;
|
||||||
|
$this->fk_product_child = $result->fk_product_child;
|
||||||
|
$this->variation_price = $result->variation_price;
|
||||||
|
$this->variation_price_percentage = $result->variation_price_percentage;
|
||||||
|
$this->variation_weight = $result->variation_weight;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a product combination by a child product row id
|
||||||
|
*
|
||||||
|
* @param int $fk_child Product row id
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function fetchByFkProductChild($fk_child)
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT rowid, fk_product_parent, fk_product_child, variation_price, variation_price_percentage, variation_weight FROM ".MAIN_DB_PREFIX."product_attribute_combination WHERE fk_product_child = ".(int) $fk_child." AND entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->db->num_rows($query)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->db->fetch_object($query);
|
||||||
|
|
||||||
|
$this->id = $result->rowid;
|
||||||
|
$this->fk_product_parent = $result->fk_product_parent;
|
||||||
|
$this->fk_product_child = $result->fk_product_child;
|
||||||
|
$this->variation_price = $result->variation_price;
|
||||||
|
$this->variation_price_percentage = $result->variation_price_percentage;
|
||||||
|
$this->variation_weight = $result->variation_weight;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all product combinations by the product parent row id
|
||||||
|
*
|
||||||
|
* @param int $fk_product_parent Rowid of parent product
|
||||||
|
* @return int|ProductCombination[] <0 KO
|
||||||
|
*/
|
||||||
|
public function fetchAllByFkProductParent($fk_product_parent)
|
||||||
|
{
|
||||||
|
require_once __DIR__.'/../lib/product_attributes.lib.php';
|
||||||
|
|
||||||
|
$sql = "SELECT rowid, fk_product_parent, fk_product_child, variation_price, variation_price_percentage, variation_weight FROM ".MAIN_DB_PREFIX."product_attribute_combination WHERE fk_product_parent = ".(int) $fk_product_parent." AND entity IN (".getProductEntities($this->db).")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = array();
|
||||||
|
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
|
||||||
|
$tmp = new ProductCombination($this->db);
|
||||||
|
$tmp->id = $result->rowid;
|
||||||
|
$tmp->fk_product_parent = $result->fk_product_parent;
|
||||||
|
$tmp->fk_product_child = $result->fk_product_child;
|
||||||
|
$tmp->variation_price = $result->variation_price;
|
||||||
|
$tmp->variation_price_percentage = $result->variation_price_percentage;
|
||||||
|
$tmp->variation_weight = $result->variation_weight;
|
||||||
|
|
||||||
|
$return[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a product attribute combination
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_attribute_combination
|
||||||
|
(fk_product_parent, fk_product_child, variation_price, variation_price_percentage, variation_weight, entity)
|
||||||
|
VALUES (".(int) $this->fk_product_parent.", ".(int) $this->fk_product_child.",
|
||||||
|
".(float) $this->variation_price.", ".(int) $this->variation_price_percentage.",
|
||||||
|
".(float) $this->variation_weight.", ".(int) $this->entity.")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'product_attribute_combination');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a product combination
|
||||||
|
*
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$sql = "UPDATE ".MAIN_DB_PREFIX."product_attribute_combination
|
||||||
|
SET fk_product_parent = ".(int) $this->fk_product_parent.", fk_product_child = ".(int) $this->fk_product_child.",
|
||||||
|
variation_price = ".(float) $this->variation_price.", variation_price_percentage = ".(int) $this->variation_price_percentage.",
|
||||||
|
variation_weight = ".(float) $this->variation_weight." WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent = new Product($this->db);
|
||||||
|
$parent->fetch($this->fk_product_parent);
|
||||||
|
|
||||||
|
$this->updateProperties($parent);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a product combination
|
||||||
|
*
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$this->db->begin();
|
||||||
|
|
||||||
|
$comb2val = new ProductCombination2ValuePair($this->db);
|
||||||
|
$comb2val->deleteByFkCombination($this->id);
|
||||||
|
|
||||||
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_attribute_combination WHERE rowid = ".(int) $this->id;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
$this->db->commit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all product combinations of a parent product
|
||||||
|
*
|
||||||
|
* @param int $fk_product_parent Rowid of parent product
|
||||||
|
* @return int <0 KO >0 OK
|
||||||
|
*/
|
||||||
|
public function deleteByFkProductParent($fk_product_parent)
|
||||||
|
{
|
||||||
|
$this->db->begin();
|
||||||
|
|
||||||
|
foreach ($this->fetchAllByFkProductParent($fk_product_parent) as $prodcomb) {
|
||||||
|
|
||||||
|
$prodstatic = new Product($this->db);
|
||||||
|
|
||||||
|
$res = $prodstatic->fetch($prodcomb->fk_product_child);
|
||||||
|
|
||||||
|
if ($res > 0) {
|
||||||
|
$res = $prodcomb->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res > 0 && !$prodstatic->isObjectUsed($prodstatic->id)) {
|
||||||
|
$res = $prodstatic->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res < 0) {
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->commit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the weight of the child product. The price must be updated using Product::updatePrices
|
||||||
|
*
|
||||||
|
* @param Product $parent Parent product
|
||||||
|
* @return int >0 OK <0 KO
|
||||||
|
*/
|
||||||
|
public function updateProperties(Product $parent)
|
||||||
|
{
|
||||||
|
global $user, $conf;
|
||||||
|
|
||||||
|
$this->db->begin();
|
||||||
|
|
||||||
|
$child = new Product($this->db);
|
||||||
|
$child->fetch($this->fk_product_child);
|
||||||
|
$child->price_autogen = $parent->price_autogen;
|
||||||
|
$child->weight = $parent->weight + $this->variation_weight;
|
||||||
|
$child->weight_units = $parent->weight_units;
|
||||||
|
|
||||||
|
if ($child->update($child->id, $user) > 0) {
|
||||||
|
|
||||||
|
$new_vat = $parent->tva_tx;
|
||||||
|
$new_npr = $parent->tva_npr;
|
||||||
|
|
||||||
|
// MultiPrix
|
||||||
|
if (! empty($conf->global->PRODUIT_MULTIPRICES)) {
|
||||||
|
$new_type = $parent->multiprices_base_type[1];
|
||||||
|
$new_min_price = $parent->multiprices_min[1];
|
||||||
|
$new_psq = $parent->multiprices_recuperableonly[1];
|
||||||
|
|
||||||
|
if ($new_type == 'TTC') {
|
||||||
|
$new_price = $parent->multiprices_ttc[1];
|
||||||
|
} else {
|
||||||
|
$new_price = $parent->multiprices[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$new_type = $parent->price_base_type;
|
||||||
|
$new_min_price = $parent->price_min;
|
||||||
|
$new_psq = $parent->price_by_qty;
|
||||||
|
|
||||||
|
if ($new_type == 'TTC') {
|
||||||
|
$new_price = $parent->price_ttc;
|
||||||
|
} else {
|
||||||
|
$new_price = $parent->price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->variation_price_percentage) {
|
||||||
|
$new_price *= 1 + ($this->variation_price/100);
|
||||||
|
} else {
|
||||||
|
$new_price += $this->variation_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
$child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, 1, $new_npr, $new_psq);
|
||||||
|
|
||||||
|
$this->db->commit();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the combination that matches the given features.
|
||||||
|
*
|
||||||
|
* @param int $prodid Id of parent product
|
||||||
|
* @param array $features Format: [$attr] => $attr_val
|
||||||
|
* @return false|ProductCombination false if not found
|
||||||
|
*/
|
||||||
|
public function fetchByProductCombination2ValuePairs($prodid, array $features)
|
||||||
|
{
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination2ValuePair.class.php';
|
||||||
|
|
||||||
|
$actual_comp = array();
|
||||||
|
|
||||||
|
$prodcomb2val = new ProductCombination2ValuePair($this->db);
|
||||||
|
$prodcomb = new ProductCombination($this->db);
|
||||||
|
|
||||||
|
foreach ($features as $attr => $attr_val) {
|
||||||
|
$actual_comp[$attr] = $attr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($prodcomb->fetchAllByFkProductParent($prodid) as $prc) {
|
||||||
|
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
foreach ($prodcomb2val->fetchByFkCombination($prc->id) as $value) {
|
||||||
|
$values[$value->fk_prod_attr] = $value->fk_prod_attr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$check1 = count(array_diff_assoc($values, $actual_comp));
|
||||||
|
$check2 = count(array_diff_assoc($actual_comp, $values));
|
||||||
|
|
||||||
|
if (!$check1 && !$check2) {
|
||||||
|
return $prc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all unique attributres for a parent product
|
||||||
|
*
|
||||||
|
* @param int $productid Product rowid
|
||||||
|
* @return ProductAttribute[]
|
||||||
|
*/
|
||||||
|
public function getUniqueAttributesAndValuesByFkProductParent($productid)
|
||||||
|
{
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
|
||||||
|
$attributes = array();
|
||||||
|
|
||||||
|
//Attributes
|
||||||
|
$sql = "SELECT DISTINCT fk_prod_attr, a.rang
|
||||||
|
FROM ".MAIN_DB_PREFIX."product_attribute_combination2val c2v LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination c
|
||||||
|
ON c2v.fk_prod_combination = c.rowid
|
||||||
|
LEFT JOIN ".MAIN_DB_PREFIX."product p ON p.rowid = c.fk_product_child
|
||||||
|
LEFT JOIN ".MAIN_DB_PREFIX."product_attribute a ON a.rowid = fk_prod_attr
|
||||||
|
WHERE c.fk_product_parent = ".(int) $productid." AND p.tosell = 1";
|
||||||
|
|
||||||
|
$sql .= $this->db->order('a.rang', 'asc');
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
//Values
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
$attr = new ProductAttribute($this->db);
|
||||||
|
$attr->fetch($result->fk_prod_attr);
|
||||||
|
|
||||||
|
$tmp = new stdClass();
|
||||||
|
$tmp->id = $attr->id;
|
||||||
|
$tmp->ref = $attr->ref;
|
||||||
|
$tmp->label = $attr->label;
|
||||||
|
$tmp->values = array();
|
||||||
|
|
||||||
|
$attrval = new ProductAttributeValue($this->db);
|
||||||
|
foreach ($res = $attrval->fetchAllByProductAttribute($attr->id, true) as $val) {
|
||||||
|
$tmp->values[] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a product combination. Check usages to find more about its use
|
||||||
|
*
|
||||||
|
* Format of $combinations array:
|
||||||
|
* array(
|
||||||
|
* 0 => array(
|
||||||
|
* attr => value,
|
||||||
|
* attr2 => value
|
||||||
|
* [...]
|
||||||
|
* ),
|
||||||
|
* [...]
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @param Product $product Parent product
|
||||||
|
* @param array $combinations Attribute and value combinations.
|
||||||
|
* @param array $variations Price and weight variations
|
||||||
|
* @param bool $price_var_percent Is the price variation a relative variation?
|
||||||
|
* @param bool|float $forced_pricevar If the price variation is forced
|
||||||
|
* @param bool|float $forced_weightvar If the weight variation is forced
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public static function createProductCombination(Product $product, array $combinations, array $variations, $price_var_percent = false, $forced_pricevar = false, $forced_weightvar = false)
|
||||||
|
{
|
||||||
|
global $db, $user;
|
||||||
|
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
$newproduct = clone $product;
|
||||||
|
|
||||||
|
//Final weight impact
|
||||||
|
$weight_impact = $forced_weightvar;
|
||||||
|
|
||||||
|
if ($forced_weightvar === false) {
|
||||||
|
$weight_impact = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Final price impact
|
||||||
|
$price_impact = $forced_pricevar;
|
||||||
|
|
||||||
|
if ($forced_pricevar === false) {
|
||||||
|
$price_impact = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newcomb = new ProductCombination($db);
|
||||||
|
$existingCombination = $newcomb->fetchByProductCombination2ValuePairs($product->id, $combinations);
|
||||||
|
|
||||||
|
if ($existingCombination) {
|
||||||
|
$newcomb = $existingCombination;
|
||||||
|
} else {
|
||||||
|
$newcomb->fk_product_parent = $product->id;
|
||||||
|
|
||||||
|
if ($newcomb->create() < 0) {
|
||||||
|
$db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattrval = new ProductAttributeValue($db);
|
||||||
|
|
||||||
|
foreach ($combinations as $currcombattr => $currcombval) {
|
||||||
|
|
||||||
|
//This was checked earlier, so no need to double check
|
||||||
|
$prodattr->fetch($currcombattr);
|
||||||
|
$prodattrval->fetch($currcombval);
|
||||||
|
|
||||||
|
//If there is an existing combination, there is no need to duplicate the valuepair
|
||||||
|
if (!$existingCombination) {
|
||||||
|
$tmp = new ProductCombination2ValuePair($db);
|
||||||
|
$tmp->fk_prod_attr = $currcombattr;
|
||||||
|
$tmp->fk_prod_attr_val = $currcombval;
|
||||||
|
$tmp->fk_prod_combination = $newcomb->id;
|
||||||
|
|
||||||
|
if ($tmp->create() < 0) {
|
||||||
|
$db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($forced_weightvar === false) {
|
||||||
|
$weight_impact += (float) price2num($variations[$currcombattr][$currcombval]['weight']);
|
||||||
|
}
|
||||||
|
if ($forced_pricevar === false) {
|
||||||
|
$price_impact += (float) price2num($variations[$currcombattr][$currcombval]['price']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newproduct->ref .= '_'.$prodattrval->ref;
|
||||||
|
|
||||||
|
//The first one should not contain a linebreak
|
||||||
|
if ($newproduct->description) {
|
||||||
|
$newproduct->description .= '<br>';
|
||||||
|
}
|
||||||
|
$newproduct->description .= '<strong>'.$prodattr->label.':</strong> '.$prodattrval->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newcomb->variation_price_percentage = $price_var_percent;
|
||||||
|
$newcomb->variation_price = $price_impact;
|
||||||
|
$newcomb->variation_weight = $weight_impact;
|
||||||
|
|
||||||
|
$newproduct->weight += $weight_impact;
|
||||||
|
|
||||||
|
//To avoid wrong information in price history log
|
||||||
|
$newproduct->price = 0;
|
||||||
|
$newproduct->price_ttc = 0;
|
||||||
|
$newproduct->price_min = 0;
|
||||||
|
$newproduct->price_min_ttc = 0;
|
||||||
|
|
||||||
|
if ($newproduct->create($user) < 0) {
|
||||||
|
|
||||||
|
//In case the error is not related with an already existing product
|
||||||
|
if ($newproduct->error != 'ErrorProductAlreadyExists') {
|
||||||
|
$db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is an existing combination, then we update the prices and weight
|
||||||
|
* Otherwise, we try adding a random number to the ref
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ($newcomb->fk_product_child) {
|
||||||
|
$res = $newproduct->fetch($existingCombination->fk_product_child);
|
||||||
|
} else {
|
||||||
|
$orig_prod_ref = $newproduct->ref;
|
||||||
|
$i = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$newproduct->ref = $orig_prod_ref.$i;
|
||||||
|
$res = $newproduct->create($user);
|
||||||
|
|
||||||
|
if ($newproduct->error != 'ErrorProductAlreadyExists') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$i++;
|
||||||
|
} while ($res < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res < 0) {
|
||||||
|
$db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newproduct->weight += $weight_impact;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newcomb->fk_product_child = $newproduct->id;
|
||||||
|
|
||||||
|
if ($newcomb->update() < 0) {
|
||||||
|
$db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->commit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all product combinations from the origin product to the destination product
|
||||||
|
*
|
||||||
|
* @param int $origProductId Origin product id
|
||||||
|
* @param Product $destProduct Destination product
|
||||||
|
* @return int >0 OK <0 KO
|
||||||
|
*/
|
||||||
|
public function copyAll($origProductId, Product $destProduct)
|
||||||
|
{
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination2ValuePair.class.php';
|
||||||
|
|
||||||
|
//To prevent a loop
|
||||||
|
if ($origProductId == $destProduct->id) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodcomb = new ProductCombination($this->db);
|
||||||
|
$prodcomb2val = new ProductCombination2ValuePair($this->db);
|
||||||
|
|
||||||
|
//Retrieve all product combinations
|
||||||
|
$combinations = $prodcomb->fetchAllByFkProductParent($origProductId);
|
||||||
|
|
||||||
|
foreach ($combinations as $combination) {
|
||||||
|
|
||||||
|
$variations = array();
|
||||||
|
|
||||||
|
foreach ($prodcomb2val->fetchByFkCombination($combination->id) as $tmp_pc2v) {
|
||||||
|
$variations[$tmp_pc2v->fk_prod_attr] = $tmp_pc2v->fk_prod_attr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::createProductCombination(
|
||||||
|
$destProduct,
|
||||||
|
$variations,
|
||||||
|
array(),
|
||||||
|
$combination->variation_price_percentage,
|
||||||
|
$combination->variation_price,
|
||||||
|
$combination->variation_weight
|
||||||
|
) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
151
htdocs/attributes/class/ProductCombination2ValuePair.class.php
Normal file
151
htdocs/attributes/class/ProductCombination2ValuePair.class.php
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProductCombination2ValuePair
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database handler
|
||||||
|
* @var DoliDB
|
||||||
|
*/
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combination 2 value pair id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product combination id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_prod_combination;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product attribute id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_prod_attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product attribute value id
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $fk_prod_attr_val;
|
||||||
|
|
||||||
|
public function __construct(DoliDB $db)
|
||||||
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates this class to a human-readable string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($this->db);
|
||||||
|
$prodattrval = new ProductAttributeValue($this->db);
|
||||||
|
|
||||||
|
$prodattr->fetch($this->fk_prod_attr);
|
||||||
|
$prodattrval->fetch($this->fk_prod_attr_val);
|
||||||
|
|
||||||
|
return $prodattr->label.': '.$prodattrval->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a product combination 2 value pair
|
||||||
|
* @return int <0 KO, >0 OK
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_attribute_combination2val
|
||||||
|
(fk_prod_combination, fk_prod_attr, fk_prod_attr_val)
|
||||||
|
VALUES(".(int) $this->fk_prod_combination.", ".(int) $this->fk_prod_attr.", ".(int) $this->fk_prod_attr_val.")";
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if ($query) {
|
||||||
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'product_attribute_combination2val');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a product combination 2 value pair from its rowid
|
||||||
|
*
|
||||||
|
* @param int $fk_combination Fk combination to search
|
||||||
|
* @return int|ProductCombination2ValuePair[] -1 if KO
|
||||||
|
*/
|
||||||
|
public function fetchByFkCombination($fk_combination)
|
||||||
|
{
|
||||||
|
$sql = "SELECT
|
||||||
|
c.rowid,
|
||||||
|
c2v.fk_prod_attr_val,
|
||||||
|
c2v.fk_prod_attr,
|
||||||
|
c2v.fk_prod_combination
|
||||||
|
FROM ".MAIN_DB_PREFIX."product_attribute c LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination2val c2v ON c.rowid = c2v.fk_prod_attr
|
||||||
|
WHERE c2v.fk_prod_combination = ".(int) $fk_combination;
|
||||||
|
|
||||||
|
$sql .= $this->db->order('c.rang', 'asc');
|
||||||
|
|
||||||
|
$query = $this->db->query($sql);
|
||||||
|
|
||||||
|
if (!$query) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = array();
|
||||||
|
|
||||||
|
while ($result = $this->db->fetch_object($query)) {
|
||||||
|
$tmp = new ProductCombination2ValuePair($this->db);
|
||||||
|
$tmp->fk_prod_attr_val = $result->fk_prod_attr_val;
|
||||||
|
$tmp->fk_prod_attr = $result->fk_prod_attr;
|
||||||
|
$tmp->fk_prod_combination = $result->fk_prod_combination;
|
||||||
|
$tmp->id = $result->rowid;
|
||||||
|
|
||||||
|
$return[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a product combination 2 value pair
|
||||||
|
*
|
||||||
|
* @param int $fk_combination Rowid of the combination
|
||||||
|
* @return int >0 OK <0 KO
|
||||||
|
*/
|
||||||
|
public function deleteByFkCombination($fk_combination)
|
||||||
|
{
|
||||||
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_attribute_combination2val WHERE fk_prod_combination = ".(int) $fk_combination;
|
||||||
|
|
||||||
|
if ($this->db->query($sql)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
htdocs/attributes/class/index.html
Normal file
0
htdocs/attributes/class/index.html
Normal file
641
htdocs/attributes/combinations.php
Normal file
641
htdocs/attributes/combinations.php
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/product.lib.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination2ValuePair.class.php';
|
||||||
|
|
||||||
|
$langs->load("products");
|
||||||
|
$langs->load("other");
|
||||||
|
|
||||||
|
$var = false;
|
||||||
|
$id = GETPOST('id', 'int');
|
||||||
|
$valueid = GETPOST('valueid', 'int');
|
||||||
|
$ref = GETPOST('ref');
|
||||||
|
$weight_impact = (float) GETPOST('weight_impact');
|
||||||
|
$price_impact = (float) GETPOST('price_impact');
|
||||||
|
$price_impact_percent = (bool) GETPOST('price_impact_percent');
|
||||||
|
$form = new Form($db);
|
||||||
|
$action = GETPOST('action');
|
||||||
|
|
||||||
|
// Security check
|
||||||
|
$fieldvalue = (! empty($id) ? $id : $ref);
|
||||||
|
$fieldtype = (! empty($ref) ? 'ref' : 'rowid');
|
||||||
|
$result=restrictedArea($user,'produit|service',$fieldvalue,'product&product','','',$fieldtype);
|
||||||
|
|
||||||
|
$prodstatic = new Product($db);
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattr_val = new ProductAttributeValue($db);
|
||||||
|
|
||||||
|
$product = new Product($db);
|
||||||
|
|
||||||
|
$product->fetch($id);
|
||||||
|
|
||||||
|
if (!$product->isProduct()) {
|
||||||
|
header('Location: '.dol_buildpath('/product/card.php?id='.$product->id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
$prodcomb2val = new ProductCombination2ValuePair($db);
|
||||||
|
|
||||||
|
$productCombination2ValuePairs1 = array();
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
if ($action == 'add') {
|
||||||
|
|
||||||
|
$features = GETPOST('features', 'array');
|
||||||
|
|
||||||
|
if (!$features) {
|
||||||
|
setEventMessage($langs->trans('ErrorFieldsRequired'), 'errors');
|
||||||
|
} else {
|
||||||
|
$weight_impact = price2num($weight_impact);
|
||||||
|
$price_impact = price2num($price_impact);
|
||||||
|
$sanit_features = array();
|
||||||
|
|
||||||
|
//First, sanitize
|
||||||
|
foreach ($features as $feature) {
|
||||||
|
|
||||||
|
$explode = explode(':', $feature);
|
||||||
|
|
||||||
|
if ($prodattr->fetch($explode[0]) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prodattr_val->fetch($explode[1]) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Valuepair
|
||||||
|
$sanit_features[$explode[0]] = $explode[1];
|
||||||
|
|
||||||
|
$tmp = new ProductCombination2ValuePair($db);
|
||||||
|
$tmp->fk_prod_attr = $explode[0];
|
||||||
|
$tmp->fk_prod_attr_val = $explode[1];
|
||||||
|
|
||||||
|
$productCombination2ValuePairs1[] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
if (!$prodcomb->fetchByProductCombination2ValuePairs($id, $sanit_features)) {
|
||||||
|
if (ProductCombination::createProductCombination($product, $sanit_features, array(), $price_impact_percent, $price_impact, $weight_impact)) {
|
||||||
|
$db->commit();
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/combinations.php?id='.$id, 2));
|
||||||
|
die;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorRecordAlreadyExists'), 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->rollback();
|
||||||
|
}
|
||||||
|
} elseif ($action == 'bulk_actions') {
|
||||||
|
|
||||||
|
$prodarray = array_keys(GETPOST('select', 'array'));
|
||||||
|
$bulkaction = GETPOST('bulk_action');
|
||||||
|
$error = 0;
|
||||||
|
|
||||||
|
$prodstatic = new Product($db);
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
foreach ($prodarray as $prodid) {
|
||||||
|
|
||||||
|
if ($prodstatic->fetch($prodid) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bulkaction == 'on_sell') {
|
||||||
|
$prodstatic->status = 1;
|
||||||
|
$res = $prodstatic->update($prodstatic->id, $user);
|
||||||
|
} elseif ($bulkaction == 'on_buy') {
|
||||||
|
$prodstatic->status_buy = 1;
|
||||||
|
$res = $prodstatic->update($prodstatic->id, $user);
|
||||||
|
} elseif ($bulkaction == 'not_sell') {
|
||||||
|
$prodstatic->status = 0;
|
||||||
|
$res = $prodstatic->update($prodstatic->id, $user);
|
||||||
|
} elseif ($bulkaction == 'not_buy') {
|
||||||
|
$prodstatic->status_buy = 0;
|
||||||
|
$res = $prodstatic->update($prodstatic->id, $user);
|
||||||
|
} elseif ($bulkaction == 'delete') {
|
||||||
|
$res = $prodstatic->delete($prodstatic->id);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res <= 0) {
|
||||||
|
$error++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
$db->rollback();
|
||||||
|
|
||||||
|
if ($prodstatic->error) {
|
||||||
|
setEventMessage($langs->trans($prodstatic->error), 'errors');
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$db->commit();
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ($prodcomb->fetch($valueid) < 0) {
|
||||||
|
dol_print_error($db, $langs->trans('ErrorRecordNotFound'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodcomb->variation_price_percentage = $price_impact_percent;
|
||||||
|
$prodcomb->variation_price = $price_impact;
|
||||||
|
$prodcomb->variation_weight = $weight_impact;
|
||||||
|
|
||||||
|
if ($prodcomb->update() > 0) {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/combinations.php?id='.$id, 2));
|
||||||
|
die;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$productCombinations = $prodcomb->fetchAllByFkProductParent($id);
|
||||||
|
|
||||||
|
if ($action === 'confirm_deletecombination') {
|
||||||
|
|
||||||
|
if ($prodcomb->fetch($valueid) > 0) {
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
if ($prodcomb->delete() > 0 && $prodstatic->fetch($prodcomb->fk_product_child) > 0 && $prodstatic->delete() > 0) {
|
||||||
|
$db->commit();
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/combinations.php?id='.$product->id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->rollback();
|
||||||
|
setEventMessage($langs->trans('ProductCombinationAlreadyUsed'), 'errors');
|
||||||
|
$action = '';
|
||||||
|
}
|
||||||
|
} elseif ($action === 'edit') {
|
||||||
|
|
||||||
|
if ($prodcomb->fetch($valueid) < 0) {
|
||||||
|
dol_print_error($db, $langs->trans('ErrorRecordNotFound'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$weight_impact = $prodcomb->variation_weight;
|
||||||
|
$price_impact = $prodcomb->variation_price;
|
||||||
|
$price_impact_percent = $prodcomb->variation_price_percentage;
|
||||||
|
|
||||||
|
$productCombination2ValuePairs1 = $prodcomb2val->fetchByFkCombination($valueid);
|
||||||
|
} elseif ($action === 'confirm_copycombination') {
|
||||||
|
|
||||||
|
//Check destination product
|
||||||
|
$dest_product = GETPOST('dest_product');
|
||||||
|
|
||||||
|
if ($prodstatic->fetch('', $dest_product) > 0) {
|
||||||
|
|
||||||
|
//To prevent from copying to the same product
|
||||||
|
if ($prodstatic->ref != $product->ref) {
|
||||||
|
if ($prodcomb->copyAll($product->id, $prodstatic) > 0) {
|
||||||
|
header('Location: '.dol_buildpath('/attributes/combinations.php?id='.$prodstatic->id, 2));
|
||||||
|
die;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorCopyProductCombinations'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorDestinationProductNotFound'), 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* View
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (! empty($id) || ! empty($ref)) {
|
||||||
|
$object = new Product($db);
|
||||||
|
$result = $object->fetch($id, $ref);
|
||||||
|
|
||||||
|
llxHeader("", "", $langs->trans("CardProduct".$object->type));
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$head = product_prepare_head($object);
|
||||||
|
$titre = $langs->trans("CardProduct".$object->type);
|
||||||
|
$picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
|
||||||
|
|
||||||
|
dol_fiche_head($head, 'combinations', $titre, 0, $picto);
|
||||||
|
|
||||||
|
print '<table class="border" width="100%">';
|
||||||
|
|
||||||
|
// Reference
|
||||||
|
print '<tr>';
|
||||||
|
print '<td width="30%">'.$langs->trans("Ref").'</td><td colspan="3">';
|
||||||
|
print $form->showrefnav($object, 'id', '', 0);
|
||||||
|
print '</td>';
|
||||||
|
print '</tr>';
|
||||||
|
|
||||||
|
// Label
|
||||||
|
print '<tr><td>'.$langs->trans("Label").'</td><td colspan="3">'.$object->label.'</td></tr>';
|
||||||
|
|
||||||
|
// Status (to sell)
|
||||||
|
print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
|
||||||
|
print $object->getLibStatut(2, 0);
|
||||||
|
print '</td></tr>';
|
||||||
|
|
||||||
|
// Status (to buy)
|
||||||
|
print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
|
||||||
|
print $object->getLibStatut(2, 1);
|
||||||
|
print '</td></tr>';
|
||||||
|
|
||||||
|
print '</table>';
|
||||||
|
|
||||||
|
dol_fiche_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($action == 'add' || ($action == 'edit')) {
|
||||||
|
|
||||||
|
if ($action == 'add') {
|
||||||
|
$title = $langs->trans('NewProductCombination');
|
||||||
|
} else {
|
||||||
|
$title = $langs->trans('EditProductCombination');
|
||||||
|
}
|
||||||
|
|
||||||
|
print_fiche_titre($title);
|
||||||
|
|
||||||
|
if ($action == 'add') {
|
||||||
|
$prodattr_all = $prodattr->fetchAll();
|
||||||
|
|
||||||
|
if (!$selected) {
|
||||||
|
$selected = $prodattr_all[key($prodattr_all)]->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prodattr_alljson = array();
|
||||||
|
|
||||||
|
foreach ($prodattr_all as $each) {
|
||||||
|
$prodattr_alljson[$each->id] = $each;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
attributes_available = <?php echo json_encode($prodattr_alljson) ?>;
|
||||||
|
attributes_selected = {
|
||||||
|
index: [],
|
||||||
|
info: []
|
||||||
|
};
|
||||||
|
|
||||||
|
<?php foreach ($productCombination2ValuePairs1 as $pc2v):
|
||||||
|
$prodattr_val->fetch($pc2v->fk_prod_attr_val);
|
||||||
|
?>
|
||||||
|
attributes_selected.index.push(<?php echo $pc2v->fk_prod_attr ?>);
|
||||||
|
attributes_selected.info[<?php echo $pc2v->fk_prod_attr ?>] = {
|
||||||
|
attribute: attributes_available[<?php echo $pc2v->fk_prod_attr ?>],
|
||||||
|
value: {
|
||||||
|
id: <?php echo $pc2v->fk_prod_attr_val ?>,
|
||||||
|
label: '<?php echo $prodattr_val->value ?>'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
<?php endforeach ?>
|
||||||
|
|
||||||
|
restoreAttributes = function() {
|
||||||
|
jQuery("select[name=attribute]").empty().append('<option value=""></option>');
|
||||||
|
|
||||||
|
jQuery.each(attributes_available, function (key, val) {
|
||||||
|
if (jQuery.inArray(val.id, attributes_selected.index) == -1) {
|
||||||
|
jQuery("select[name=attribute]").append('<option value="' + val.id + '">' + val.label + '</option>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
paintAttributes = function() {
|
||||||
|
var select = jQuery("select#features");
|
||||||
|
|
||||||
|
select.empty();
|
||||||
|
jQuery("form#combinationform input[type=hidden]").detach();
|
||||||
|
|
||||||
|
jQuery.each(attributes_selected.index, function (key, val) {
|
||||||
|
var attr_info = attributes_selected.info[val];
|
||||||
|
|
||||||
|
var opt_key = val + ':' + attr_info.value.id;
|
||||||
|
var opt_label = attr_info.attribute.label + ': ' + attr_info.value.label;
|
||||||
|
|
||||||
|
//Add combination to the list
|
||||||
|
select.append('<option value="' + opt_key + '">' + opt_label + '</option>');
|
||||||
|
//Add hidden input to catch the new combination
|
||||||
|
jQuery("form#combinationform").append('<input type="hidden" name="features[]" value="' + opt_key + '">');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery(document).ready(function() {
|
||||||
|
|
||||||
|
jQuery("select#attribute").change(function () {
|
||||||
|
|
||||||
|
var select = jQuery("select#value");
|
||||||
|
|
||||||
|
if (!jQuery(this).val().length) {
|
||||||
|
select.empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.empty().append('<option value="">Loading...</option>');
|
||||||
|
|
||||||
|
jQuery.getJSON("<?php echo dol_buildpath('/attributes/ajax/get_attribute_values.php', 2) ?>", {
|
||||||
|
id: jQuery(this).val()
|
||||||
|
}, function(data) {
|
||||||
|
if (data.error) {
|
||||||
|
jQuery("select#value").empty();
|
||||||
|
return alert(data.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
select.empty();
|
||||||
|
|
||||||
|
jQuery(data).each(function (key, val) {
|
||||||
|
jQuery("select#value").append('<option value="' + val.id + '">' + val.value + '</option>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery("#addfeature").click(function () {
|
||||||
|
var selectedattr = jQuery("select[name=attribute] option:selected");
|
||||||
|
var selectedvalu = jQuery("select[name=value] option:selected");
|
||||||
|
|
||||||
|
if (!selectedattr.val().length || !selectedvalu.val().length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedattr_val = parseInt(selectedattr.val());
|
||||||
|
|
||||||
|
if (jQuery.inArray(selectedattr_val, attributes_selected.index) != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes_selected.index.push(selectedattr_val);
|
||||||
|
attributes_selected.info[selectedattr_val] = {
|
||||||
|
attribute: attributes_available[selectedattr_val],
|
||||||
|
value: {
|
||||||
|
id: selectedvalu.val(),
|
||||||
|
label: selectedvalu.html()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
paintAttributes();
|
||||||
|
|
||||||
|
selectedattr.detach();
|
||||||
|
jQuery("select[name=value] option").detach();
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery("#delfeature").click(function() {
|
||||||
|
jQuery("#features option:selected").each(function (key, val) {
|
||||||
|
var explode = jQuery(val).val().split(':');
|
||||||
|
var indexOf = attributes_selected.index.indexOf(parseInt(explode[0]));
|
||||||
|
|
||||||
|
if (indexOf != -1) {
|
||||||
|
attributes_selected.index.splice(indexOf, 1);
|
||||||
|
jQuery(attributes_selected.info[parseInt(explode[0])]).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(val).detach();
|
||||||
|
});
|
||||||
|
|
||||||
|
restoreAttributes();
|
||||||
|
paintAttributes();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
<form method="post" id="combinationform">
|
||||||
|
<table class="border" style="width: 100%">
|
||||||
|
<?php if ($action == 'add'): ?>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%"><label for="attribute"><?php echo $langs->trans('ProductAttribute') ?></label></td>
|
||||||
|
<td colspan="2"><select id="attribute" name="attribute">
|
||||||
|
<option value=""></option>
|
||||||
|
<?php foreach ($prodattr_all as $attr): ?>
|
||||||
|
<option value="<?php echo $attr->id ?>"><?php echo $attr->label ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%"><label for="value"><?php echo $langs->trans('Value') ?></label></td>
|
||||||
|
<td colspan="2">
|
||||||
|
<select id="value" name="value">
|
||||||
|
<option value=""></option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%" class="fieldrequired"><label for="features"><?php echo $langs->trans('Features') ?></label></td>
|
||||||
|
<td><select multiple style="width: 100%" id="features">
|
||||||
|
<?php
|
||||||
|
foreach ($productCombination2ValuePairs1 as $pc2v): ?>
|
||||||
|
<option value="<?php echo $pc2v->fk_prod_attr ?>:<?php echo $pc2v->fk_prod_attr_val ?>"><?php echo dol_htmlentities($pc2v) ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($action == 'add'): ?>
|
||||||
|
<a href="#" class="button" id="addfeature"><?php echo img_edit_add() ?></a><br><br>
|
||||||
|
<a href="#" class="button" id="delfeature"><?php echo img_edit_remove() ?></a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%"><label for="price_impact"><?php echo $langs->trans('PriceImpact') ?></label></td>
|
||||||
|
<td colspan="2"><input type="text" id="price_impact" name="price_impact" value="<?php echo price($price_impact) ?>">
|
||||||
|
<input type="checkbox" id="price_impact_percent" name="price_impact_percent" <?php echo $price_impact_percent ? ' checked' : '' ?>> <label for="price_impact_percent"><?php echo $langs->trans('PercentageVariation') ?></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%"><label for="weight_impact"><?php echo $langs->trans('WeightImpact') ?></label></td>
|
||||||
|
<td colspan="2"><input type="text" id="weight_impact" name="weight_impact" value="<?php echo price($weight_impact) ?>"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<div style="text-align: center"><input type="submit" value="<?php echo $action == 'add' ? $langs->trans('Create') : $langs->trans('Save') ?>" class="button"></div>
|
||||||
|
<?php foreach ($productCombination2ValuePairs1 as $pc2v): ?>
|
||||||
|
<input type="hidden" name="features[]" value="<?php echo $pc2v->fk_prod_attr.':'.$pc2v->fk_prod_attr_val ?>">
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ($action === 'delete') {
|
||||||
|
|
||||||
|
if ($prodcomb->fetch($valueid) > 0) {
|
||||||
|
$form = new Form($db);
|
||||||
|
$prodstatic->fetch($prodcomb->fk_product_child);
|
||||||
|
|
||||||
|
print $form->formconfirm(
|
||||||
|
"combinations.php?id=".$id."&valueid=".$valueid,
|
||||||
|
$langs->trans('Delete'),
|
||||||
|
$langs->trans('ProductCombinationDeleteDialog', $prodstatic->getNomUrl(1)),
|
||||||
|
"confirm_deletecombination",
|
||||||
|
'',
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif ($action === 'copy') {
|
||||||
|
|
||||||
|
$form = new Form($db);
|
||||||
|
|
||||||
|
print $form->formconfirm(
|
||||||
|
'combinations.php?id='.$id,
|
||||||
|
$langs->trans('CloneCombinationsProduct'),
|
||||||
|
$langs->trans('ConfirmCloneProductCombinations'),
|
||||||
|
'confirm_copycombination',
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'type' => 'text',
|
||||||
|
'label' => $langs->trans('CloneDestinationReference'),
|
||||||
|
'name' => 'dest_product'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$comb2val = new ProductCombination2ValuePair($db);
|
||||||
|
|
||||||
|
if ($productCombinations): ?>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
jQuery(document).ready(function() {
|
||||||
|
|
||||||
|
jQuery('input[name="select_all"]').click(function() {
|
||||||
|
|
||||||
|
if (jQuery(this).prop('checked')) {
|
||||||
|
var checked = true;
|
||||||
|
} else {
|
||||||
|
var checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery('table.liste input[type="checkbox"]').prop('checked', checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('input[name^="select["]').click(function() {
|
||||||
|
jQuery('input[name="select_all"]').prop('checked', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<label for="bulk_action"><?php echo $langs->trans('BulkActions') ?></label>
|
||||||
|
<select id="bulk_action" name="bulk_action" class="flat">
|
||||||
|
<option value="not_buy"><?php echo $langs->trans('ProductStatusNotOnBuy') ?></option>
|
||||||
|
<option value="not_sell"><?php echo $langs->trans('ProductStatusNotOnSell') ?></option>
|
||||||
|
<option value="on_buy"><?php echo $langs->trans('ProductStatusOnBuy') ?></option>
|
||||||
|
<option value="on_sell"><?php echo $langs->trans('ProductStatusOnSell') ?></option>
|
||||||
|
<option value="delete"><?php echo $langs->trans('Delete') ?></option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="action" value="bulk_actions">
|
||||||
|
<input type="submit" value="Aplicar" class="button">
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<table class="liste">
|
||||||
|
<tr class="liste_titre">
|
||||||
|
<th class="liste_titre">
|
||||||
|
<?php if ($productCombinations): ?>
|
||||||
|
<input type="checkbox" name="select_all">
|
||||||
|
<?php endif ?>
|
||||||
|
</th>
|
||||||
|
<th class="liste_titre"><?php echo $langs->trans('Product') ?></th>
|
||||||
|
<th class="liste_titre"><?php echo $langs->trans('Combination') ?></th>
|
||||||
|
<th class="liste_titre" style="text-align: center"><?php echo $langs->trans('PriceImpact') ?></th>
|
||||||
|
<th class="liste_titre" style="text-align: center"><?php echo $langs->trans('WeightImpact') ?></th>
|
||||||
|
<th class="liste_titre" style="text-align: center;"><?php echo $langs->trans('OnSell') ?></th>
|
||||||
|
<th class="liste_titre" style="text-align: center;"><?php echo $langs->trans('OnBuy') ?></th>
|
||||||
|
<th class="liste_titre"></th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($productCombinations as $currcomb):
|
||||||
|
$prodstatic->fetch($currcomb->fk_product_child); ?>
|
||||||
|
<tr <?php echo $bc[!$var] ?>>
|
||||||
|
<td><input type="checkbox" name="select[<?php echo $prodstatic->id ?>]"></td>
|
||||||
|
<td><?php echo $prodstatic->getNomUrl(1) ?></td>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$productCombination2ValuePairs = $comb2val->fetchByFkCombination($currcomb->id);
|
||||||
|
$iMax = count($productCombination2ValuePairs);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $iMax; $i++) {
|
||||||
|
echo dol_htmlentities($productCombination2ValuePairs[$i]);
|
||||||
|
|
||||||
|
if ($i !== ($iMax - 1)) {
|
||||||
|
echo ', ';
|
||||||
|
}
|
||||||
|
} ?>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right"><?php echo ($currcomb->variation_price >= 0 ? '+' : '').price($currcomb->variation_price).($currcomb->variation_price_percentage ? ' %' : '') ?></td>
|
||||||
|
<td style="text-align: right"><?php echo ($currcomb->variation_weight >= 0 ? '+' : '').price($currcomb->variation_weight).' '.measuring_units_string($prodstatic->weight_units, 'weight') ?></td>
|
||||||
|
<td style="text-align: center;"><?php echo $prodstatic->getLibStatut(2, 0) ?></td>
|
||||||
|
<td style="text-align: center;"><?php echo $prodstatic->getLibStatut(2, 1) ?></td>
|
||||||
|
<td style="text-align: right">
|
||||||
|
<a href="<?php echo dol_buildpath('/attributes/combinations.php?id='.$id.'&action=edit&valueid='.$currcomb->id, 2) ?>"><?php echo img_edit() ?></a>
|
||||||
|
<a href="<?php echo dol_buildpath('/attributes/combinations.php?id='.$id.'&action=delete&valueid='.$currcomb->id, 2) ?>"><?php echo img_delete() ?></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php $var = !$var; endforeach ?>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php if ($productCombinations): ?>
|
||||||
|
</form>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
print '<div class="tabsAction">';
|
||||||
|
print ' <div class="inline-block divButAction">';
|
||||||
|
if ($productCombinations) {
|
||||||
|
print ' <a href="combinations.php?id='.$id.'&action=copy" class="butAction">'.$langs->trans('Copy').'</a>';
|
||||||
|
}
|
||||||
|
print ' <a href="generator.php?id='.$id.'" class="butAction">'.$langs->trans('ProductCombinationGenerator').'</a>
|
||||||
|
<a href="combinations.php?id='.$id.'&action=add" class="butAction">'.$langs->trans('NewProductCombination').'</a>';
|
||||||
|
print ' </div>';
|
||||||
|
print '</div>';
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
73
htdocs/attributes/create.php
Normal file
73
htdocs/attributes/create.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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 'class/ProductAttribute.class.php';
|
||||||
|
|
||||||
|
$ref = GETPOST('ref');
|
||||||
|
$label = GETPOST('label');
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
if (empty($ref) || empty($label)) {
|
||||||
|
setEventMessage($langs->trans('ErrorFieldsRequired'), 'errors');
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattr->label = $label;
|
||||||
|
$prodattr->ref = $ref;
|
||||||
|
|
||||||
|
if ($prodattr->create()) {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/list.php', 2));
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorRecordAlreadyExists'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$langs->load('products');
|
||||||
|
|
||||||
|
$title = $langs->trans('NewProductAttribute');
|
||||||
|
|
||||||
|
llxHeader('', $title);
|
||||||
|
|
||||||
|
print_fiche_titre($title);
|
||||||
|
|
||||||
|
dol_fiche_head();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<form method="post">
|
||||||
|
<table class="border" style="width: 100%">
|
||||||
|
<tr>
|
||||||
|
<td class="fieldrequired"><label for="ref"><?php echo $langs->trans('Ref') ?></label></td>
|
||||||
|
<td><input type="text" id="ref" name="ref" value="<?php echo $ref ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="fieldrequired"><label for="label"><?php echo $langs->trans('Label') ?></label></td>
|
||||||
|
<td><input type="text" id="label" name="label" value="<?php echo $label ?>"></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
dol_fiche_end();
|
||||||
|
|
||||||
|
print '<div class="center"><input type="submit" class="button" value="'.$langs->trans("Create").'"></div></form>';
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
102
htdocs/attributes/create_val.php
Normal file
102
htdocs/attributes/create_val.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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 'class/ProductAttribute.class.php';
|
||||||
|
require 'class/ProductAttributeValue.class.php';
|
||||||
|
|
||||||
|
$id = GETPOST('id');
|
||||||
|
$ref = GETPOST('ref');
|
||||||
|
$value = GETPOST('value');
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattrval = new ProductAttributeValue($db);
|
||||||
|
|
||||||
|
if ($prodattr->fetch($id) < 1) {
|
||||||
|
dol_print_error($db, $langs->trans('ErrorRecordNotFound'));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
if (empty($ref) || empty($value)) {
|
||||||
|
setEventMessage($langs->trans('ErrorFieldsRequired'), 'errors');
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$prodattrval->fk_product_attribute = $prodattr->id;
|
||||||
|
$prodattrval->ref = $ref;
|
||||||
|
$prodattrval->value = $value;
|
||||||
|
|
||||||
|
if ($prodattrval->create() > 0) {
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/card.php?id='.$prodattr->id, 2));
|
||||||
|
die;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorCreatingProductAttributeValue'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$langs->load('products');
|
||||||
|
|
||||||
|
$title = $langs->trans('ProductAttributeName', dol_htmlentities($prodattr->label));
|
||||||
|
|
||||||
|
llxHeader('', $title);
|
||||||
|
|
||||||
|
print_fiche_titre($title);
|
||||||
|
|
||||||
|
dol_fiche_head();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<table class="border" style="width: 100%">
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><?php echo $langs->trans('Ref') ?></td>
|
||||||
|
<td><?php echo dol_htmlentities($prodattr->ref) ?>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><?php echo $langs->trans('Label') ?></td>
|
||||||
|
<td><?php echo dol_htmlentities($prodattr->label) ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
dol_fiche_end();
|
||||||
|
|
||||||
|
print_fiche_titre($langs->trans('NewProductAttributeValue'));
|
||||||
|
|
||||||
|
dol_fiche_head();
|
||||||
|
?>
|
||||||
|
<form method="post">
|
||||||
|
<table class="border" style="width: 100%">
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><label for="ref"><?php echo $langs->trans('Ref') ?></label></td>
|
||||||
|
<td><input id="ref" type="text" name="ref" value="<?php echo $ref ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 15%" class="fieldrequired"><label for="value"><?php echo $langs->trans('Value') ?></label></td>
|
||||||
|
<td><input id="value" type="text" name="value" value="<?php echo $value ?>"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<?php
|
||||||
|
dol_fiche_end();
|
||||||
|
|
||||||
|
print '<div class="center"><input type="submit" class="button" value="'.$langs->trans("Create").'"></div></form>';
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
393
htdocs/attributes/generator.php
Normal file
393
htdocs/attributes/generator.php
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/product.lib.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttribute.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductAttributeValue.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination2ValuePair.class.php';
|
||||||
|
|
||||||
|
$langs->load("products");
|
||||||
|
$langs->load('other');
|
||||||
|
|
||||||
|
$id = GETPOST('id', 'int');
|
||||||
|
$ref = GETPOST('ref');
|
||||||
|
$form = new Form($db);
|
||||||
|
|
||||||
|
// Security check
|
||||||
|
$fieldvalue = (! empty($id) ? $id : $ref);
|
||||||
|
$fieldtype = (! empty($ref) ? 'ref' : 'rowid');
|
||||||
|
$result=restrictedArea($user,'produit|service',$fieldvalue,'product&product','','',$fieldtype);
|
||||||
|
|
||||||
|
$prodattr = new ProductAttribute($db);
|
||||||
|
$prodattrval = new ProductAttributeValue($db);
|
||||||
|
$product = new Product($db);
|
||||||
|
|
||||||
|
$product->fetch($id);
|
||||||
|
|
||||||
|
if (!$product->isProduct()) {
|
||||||
|
header('Location: '.dol_buildpath('/product/card.php?id='.$product->id, 2));
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posible combinations. Format.
|
||||||
|
* attrval => array(
|
||||||
|
* valueid => array(
|
||||||
|
* price => ''
|
||||||
|
* weight => ''
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
$combinations = GETPOST('combinations', 'array');
|
||||||
|
$price_var_percent = (bool) GETPOST('price_var_percent');
|
||||||
|
$donotremove = true;
|
||||||
|
|
||||||
|
if ($_POST) {
|
||||||
|
|
||||||
|
$donotremove = (bool) GETPOST('donotremove');
|
||||||
|
|
||||||
|
//We must check if all those given combinations actually exist
|
||||||
|
$sanitized_values = array();
|
||||||
|
|
||||||
|
foreach ($combinations as $attr => $val) {
|
||||||
|
if ($prodattr->fetch($attr) > 0) {
|
||||||
|
foreach ($val as $valueid => $content) {
|
||||||
|
if ($prodattrval->fetch($valueid) > 0) {
|
||||||
|
$sanitized_values[$attr][$valueid] = $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sanitized_values) {
|
||||||
|
|
||||||
|
require DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
|
||||||
|
|
||||||
|
$adapted_values = array();
|
||||||
|
|
||||||
|
//Adapt the array to the cartesian function
|
||||||
|
foreach ($sanitized_values as $attr => $val) {
|
||||||
|
$adapted_values[$attr] = array_keys($val);
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->begin();
|
||||||
|
|
||||||
|
$combination = new ProductCombination($db);
|
||||||
|
|
||||||
|
$delete_prev_comb_res = 1;
|
||||||
|
|
||||||
|
if (!$donotremove) {
|
||||||
|
$delete_prev_comb_res = $combination->deleteByFkProductParent($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Current combinations will be deleted
|
||||||
|
if ($delete_prev_comb_res > 0) {
|
||||||
|
|
||||||
|
$res = 1;
|
||||||
|
|
||||||
|
foreach (cartesianArray($adapted_values) as $currcomb) {
|
||||||
|
|
||||||
|
$res = ProductCombination::createProductCombination($product, $currcomb, $sanitized_values, $price_var_percent);
|
||||||
|
|
||||||
|
if ($res < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res > 0) {
|
||||||
|
$db->commit();
|
||||||
|
setEventMessage($langs->trans('RecordSaved'));
|
||||||
|
header('Location: '.dol_buildpath('/attributes/combinations.php?id='.$id, 2));
|
||||||
|
die;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('CoreErrorMessage'), 'errors');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorDeletingGeneratedProducts'), 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->rollback();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorFieldsRequired'), 'errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* View
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (! empty($id) || ! empty($ref)) {
|
||||||
|
$object = new Product($db);
|
||||||
|
$result = $object->fetch($id, $ref);
|
||||||
|
|
||||||
|
llxHeader("", "", $langs->trans("CardProduct".$object->type));
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$head = product_prepare_head($object);
|
||||||
|
$titre = $langs->trans("CardProduct".$object->type);
|
||||||
|
$picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
|
||||||
|
|
||||||
|
dol_fiche_head($head, 'combinations', $titre, 0, $picto);
|
||||||
|
|
||||||
|
print '<table class="border" width="100%">';
|
||||||
|
|
||||||
|
// Reference
|
||||||
|
print '<tr>';
|
||||||
|
print '<td width="30%">'.$langs->trans("Ref").'</td><td colspan="3">';
|
||||||
|
print $form->showrefnav($object, 'id', '', 0);
|
||||||
|
print '</td>';
|
||||||
|
print '</tr>';
|
||||||
|
|
||||||
|
// Label
|
||||||
|
print '<tr><td>'.$langs->trans("Label").'</td><td colspan="3">'.$object->label.'</td></tr>';
|
||||||
|
|
||||||
|
// Status (to sell)
|
||||||
|
print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
|
||||||
|
print $object->getLibStatut(2, 0);
|
||||||
|
print '</td></tr>';
|
||||||
|
|
||||||
|
// Status (to buy)
|
||||||
|
print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
|
||||||
|
print $object->getLibStatut(2, 1);
|
||||||
|
print '</td></tr>';
|
||||||
|
|
||||||
|
print '</table>';
|
||||||
|
|
||||||
|
dol_fiche_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
print_fiche_titre($langs->trans('ProductCombinationGenerator'));
|
||||||
|
|
||||||
|
$dictionnary_attr = array();
|
||||||
|
|
||||||
|
foreach ($prodattr->fetchAll() as $attr) {
|
||||||
|
$dictionnary_attr[$attr->id] = $attr;
|
||||||
|
foreach ($prodattrval->fetchAllByProductAttribute($attr->id) as $attrval) {
|
||||||
|
$dictionnary_attr[$attr->id]->values[$attrval->id] = $attrval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
dictionnary_attr = <?php echo json_encode($dictionnary_attr) ?>;
|
||||||
|
weight_units = '<?php echo measuring_units_string($object->weight_units, 'weight') ?>';
|
||||||
|
attr_selected = {};
|
||||||
|
percentage_variation = jQuery('input#price_var_percent').prop('checked');
|
||||||
|
|
||||||
|
function parseSelectedFeatures(attr, val, inputs) {
|
||||||
|
|
||||||
|
var price = '';
|
||||||
|
var weight = '';
|
||||||
|
|
||||||
|
if (typeof(inputs) == 'object') {
|
||||||
|
price = inputs.price;
|
||||||
|
weight = inputs.weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attr_selected.hasOwnProperty(attr)) {
|
||||||
|
|
||||||
|
var label = dictionnary_attr[attr].label;
|
||||||
|
|
||||||
|
var table = jQuery(document.createElement('table'))
|
||||||
|
.attr('id', 'combinations_'+attr)
|
||||||
|
.css('width', '100%')
|
||||||
|
.addClass('liste')
|
||||||
|
.append(
|
||||||
|
jQuery(document.createElement('thead'))
|
||||||
|
.append(jQuery(document.createElement('tr'))
|
||||||
|
.addClass('liste_titre')
|
||||||
|
.append(
|
||||||
|
jQuery(document.createElement('th'))
|
||||||
|
.addClass('liste_titre')
|
||||||
|
.css('width', '40%')
|
||||||
|
.text(label),
|
||||||
|
jQuery(document.createElement('th')).addClass('liste_titre').css('text-align', 'center').html('<?php echo $langs->trans('PriceImpact') ?>'),
|
||||||
|
jQuery(document.createElement('th')).addClass('liste_titre').css('text-align', 'center').html('<?php echo $langs->trans('WeightImpact') ?>')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
jQuery('form#combinationsform').prepend(table);
|
||||||
|
|
||||||
|
attr_selected[attr] = [];
|
||||||
|
} else {
|
||||||
|
if (jQuery.inArray(val, attr_selected[attr]) != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var combinations_table = jQuery('table#combinations_' + attr);
|
||||||
|
var html = jQuery(document.createElement('tr'));
|
||||||
|
|
||||||
|
if (combinations_table.children('tbody').children('tr').length % 2 === 0) {
|
||||||
|
html.addClass('pair');
|
||||||
|
} else {
|
||||||
|
html.addClass('impair');
|
||||||
|
}
|
||||||
|
|
||||||
|
var percent_symbol_html = jQuery(document.createElement('span')).attr('id', 'percentsymbol').html(' %');
|
||||||
|
|
||||||
|
if (!percentage_variation) {
|
||||||
|
percent_symbol_html.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
html.append(
|
||||||
|
jQuery(document.createElement('td')).text(dictionnary_attr[attr].values[val].value),
|
||||||
|
jQuery(document.createElement('td')).css('text-align', 'center').append(
|
||||||
|
jQuery(document.createElement('input')).attr('type', 'text').css('width', '50px').attr('name', 'combinations[' + attr + '][' + val + '][price]').val(price),
|
||||||
|
percent_symbol_html
|
||||||
|
),
|
||||||
|
jQuery(document.createElement('td')).css('text-align', 'center').append(
|
||||||
|
jQuery(document.createElement('input')).attr('type', 'text').css('width', '50px').attr('name', 'combinations[' + attr + '][' + val + '][weight]').val(weight),
|
||||||
|
' ' + weight_units
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
combinations_table.append(html);
|
||||||
|
|
||||||
|
attr_selected[attr].push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showHidePercentageSymbol(checked) {
|
||||||
|
|
||||||
|
percentage_variation = checked;
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
jQuery('span#percentsymbol').show();
|
||||||
|
} else {
|
||||||
|
jQuery('span#percentsymbol').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(document).ready(function() {
|
||||||
|
|
||||||
|
var input_price_var_percent = jQuery('input#price_var_percent');
|
||||||
|
|
||||||
|
jQuery.each(<?php echo json_encode($combinations) ?>, function(key, val) {
|
||||||
|
jQuery.each(val, function(valkey, valcontent) {
|
||||||
|
parseSelectedFeatures(key, valkey, valcontent);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('#addfeature').click(function() {
|
||||||
|
jQuery('#features option:selected').each(function(selector) {
|
||||||
|
var explode = jQuery(this).val().split(':');
|
||||||
|
parseSelectedFeatures(explode[0], explode[1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('#delfeature').click(function() {
|
||||||
|
jQuery('#features option:selected').each(function(selector) {
|
||||||
|
var explode = jQuery(this).val().split(':');
|
||||||
|
|
||||||
|
if (attr_selected.hasOwnProperty(explode[0])) {
|
||||||
|
var tr = jQuery('input[name="combinations[' + explode[0] + '][' + explode[1] + '][price]"').parent().parent();
|
||||||
|
|
||||||
|
var index_value = jQuery.inArray(explode[1], attr_selected[explode[0]]);
|
||||||
|
|
||||||
|
attr_selected[explode[0]].splice(index_value, 1);
|
||||||
|
|
||||||
|
if (tr.parent().children('tr').length === 1) {
|
||||||
|
tr.parent().parent().detach();
|
||||||
|
delete attr_selected[explode[0]]
|
||||||
|
} else {
|
||||||
|
tr.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
input_price_var_percent.click(function() {
|
||||||
|
showHidePercentageSymbol(jQuery(this).prop('checked'));
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('input#donotremove').click(function() {
|
||||||
|
if (jQuery(this).prop('checked')) {
|
||||||
|
jQuery('div#info_donotremove').hide();
|
||||||
|
} else {
|
||||||
|
jQuery('div#info_donotremove').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div style="width: 100%;display:block; height: 300px">
|
||||||
|
|
||||||
|
<div style="float:right; width: 79%; margin-left: 1%">
|
||||||
|
|
||||||
|
<form method="post" id="combinationsform">
|
||||||
|
|
||||||
|
<p><?php echo $langs->trans('TooMuchCombinationsWarning', $langs->trans('DoNotRemovePreviousCombinations')) ?></p>
|
||||||
|
<input type="checkbox" name="price_var_percent"
|
||||||
|
id="price_var_percent"<?php echo $price_var_percent ? ' checked' : '' ?>> <label
|
||||||
|
for="price_var_percent"><?php echo $langs->trans('UsePercentageVariations') ?></label>
|
||||||
|
<br>
|
||||||
|
<input type="checkbox" name="donotremove"
|
||||||
|
id="donotremove"<?php echo $donotremove ? ' checked' : '' ?>> <label for="donotremove"><?php echo $langs->trans('DoNotRemovePreviousCombinations') ?></label>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<div id="info_donotremove" class="info" style="<?php echo $donotremove ? 'display: none' : '' ?>">
|
||||||
|
<?php echo img_warning() ?>
|
||||||
|
<?php echo $langs->trans('ProductCombinationGeneratorWarning') ?>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div style="text-align: center">
|
||||||
|
<input type="submit" value="<?php echo $langs->trans('Generate') ?>" class="button" name="submit">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="float:left; width: 20%">
|
||||||
|
|
||||||
|
<select id="features" multiple style="width: 100%; height: 300px; overflow: auto">
|
||||||
|
<?php foreach ($dictionnary_attr as $attr): ?>
|
||||||
|
<optgroup label="<?php echo $attr->label ?>">
|
||||||
|
<?php foreach ($attr->values as $attrval): ?>
|
||||||
|
<option value="<?php echo $attr->id.':'.$attrval->id ?>"<?php
|
||||||
|
if (isset($combinations[$attr->id][$attrval->id])) {
|
||||||
|
echo ' selected';
|
||||||
|
}
|
||||||
|
?>><?php echo dol_htmlentities($attrval->value) ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</optgroup>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a class="button" id="delfeature" style="float: right"><?php echo img_edit_remove() ?></a>
|
||||||
|
<a class="button" id="addfeature"><?php echo img_edit_add() ?></a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
|
}
|
||||||
0
htdocs/attributes/index.html
Normal file
0
htdocs/attributes/index.html
Normal file
0
htdocs/attributes/lib/index.html
Normal file
0
htdocs/attributes/lib/index.html
Normal file
31
htdocs/attributes/lib/product_attributes.lib.php
Normal file
31
htdocs/attributes/lib/product_attributes.lib.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entity of the products.
|
||||||
|
* @param DoliDB $db Database handler
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function getProductEntities(DoliDB $db)
|
||||||
|
{
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||||
|
|
||||||
|
$product = new Product($db);
|
||||||
|
|
||||||
|
return getEntity($product->element, 1);
|
||||||
|
}
|
||||||
140
htdocs/attributes/list.php
Normal file
140
htdocs/attributes/list.php
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 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 'class/ProductAttribute.class.php';
|
||||||
|
|
||||||
|
$rowid = GETPOST('rowid');
|
||||||
|
$action = GETPOST('action');
|
||||||
|
$object = new ProductAttribute($db);
|
||||||
|
|
||||||
|
if ($action == 'up') {
|
||||||
|
$object->fetch($rowid);
|
||||||
|
$object->moveUp();
|
||||||
|
|
||||||
|
header('Location: '.$_SERVER['PHP_SELF']);
|
||||||
|
die;
|
||||||
|
} elseif ($action == 'down') {
|
||||||
|
$object->fetch($rowid);
|
||||||
|
$object->moveDown();
|
||||||
|
|
||||||
|
header('Location: '.$_SERVER['PHP_SELF']);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$langs->load('products');
|
||||||
|
|
||||||
|
$var = false;
|
||||||
|
$title = $langs->trans($langs->trans('ProductAttributes'));
|
||||||
|
|
||||||
|
$attributes = $object->fetchAll();
|
||||||
|
|
||||||
|
llxHeader('', $title);
|
||||||
|
|
||||||
|
print_fiche_titre($title);
|
||||||
|
|
||||||
|
$forcereloadpage=empty($conf->global->MAIN_FORCE_RELOAD_PAGE)?0:1;
|
||||||
|
?>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
$(".imgupforline, .imgdownforline").hide();
|
||||||
|
$(".lineupdown").removeAttr('href');
|
||||||
|
$(".tdlineupdown")
|
||||||
|
.css("background-image", 'url(<?php echo DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/grip.png'; ?>)')
|
||||||
|
.css("background-repeat", "no-repeat")
|
||||||
|
.css("background-position", "center center")
|
||||||
|
.hover(
|
||||||
|
function () {
|
||||||
|
$(this).addClass('showDragHandle');
|
||||||
|
}, function () {
|
||||||
|
$(this).removeClass('showDragHandle');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$("#tablelines").tableDnD({
|
||||||
|
onDrop: function(table, row) {
|
||||||
|
console.log('drop');
|
||||||
|
var reloadpage = "<?php echo $forcereloadpage; ?>";
|
||||||
|
var roworder = cleanSerialize($("#tablelines").tableDnDSerialize());
|
||||||
|
$.post("<?php echo DOL_URL_ROOT; ?>/attributes/ajax/orderAttribute.php",
|
||||||
|
{
|
||||||
|
roworder: roworder
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
if (reloadpage == 1) {
|
||||||
|
location.href = '<?php echo $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING']; ?>';
|
||||||
|
} else {
|
||||||
|
$("#tablelines .drag").each(
|
||||||
|
function( intIndex ) {
|
||||||
|
$(this).removeClass("pair impair");
|
||||||
|
if (intIndex % 2 == 0) $(this).addClass('impair');
|
||||||
|
if (intIndex % 2 == 1) $(this).addClass('pair');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDragClass: "dragClass",
|
||||||
|
dragHandle: "tdlineupdown"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<table class="liste" id="tablelines">
|
||||||
|
<tr class="liste_titre nodrag nodrop">
|
||||||
|
<th class="liste_titre"><?php print $langs->trans('Ref') ?></th>
|
||||||
|
<th class="liste_titre"><?php print $langs->trans('Label') ?></th>
|
||||||
|
<th class="liste_titre"><?php print $langs->trans('NbProducts') ?></th>
|
||||||
|
<th class="liste_titre" colspan="2"></th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($attributes as $key => $attribute): ?>
|
||||||
|
<tr id="row-<?php echo $attribute->id ?>" <?php echo $bcdd[$var] ?>>
|
||||||
|
<td><a href="card.php?id=<?php echo $attribute->id ?>"><?php echo dol_htmlentities($attribute->ref) ?></a></td>
|
||||||
|
<td><a href="card.php?id=<?php echo $attribute->id ?>"><?php echo dol_htmlentities($attribute->label) ?></a></td>
|
||||||
|
<td><?php echo $attribute->countChildProducts() ?></td>
|
||||||
|
<td style="text-align: right">
|
||||||
|
<a href="card.php?id=<?php echo $attribute->id ?>&action=edit"><?php echo img_edit() ?></a>
|
||||||
|
<a href="card.php?id=<?php echo $attribute->id ?>&action=delete"><?php echo img_delete() ?></a>
|
||||||
|
</td>
|
||||||
|
<td align="center" class="linecolmove tdlineupdown">
|
||||||
|
<?php if ($key > 0): ?>
|
||||||
|
<a class="lineupdown"
|
||||||
|
href="<?php echo $_SERVER['PHP_SELF'] ?>?action=up&rowid=<?php echo $attribute->id ?>"><?php echo img_up('default', 0, 'imgupforline'); ?></a>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php if ($key < count($attributes)-1): ?>
|
||||||
|
<a class="lineupdown"
|
||||||
|
href="<?php echo $_SERVER['PHP_SELF'] ?>?action=down&rowid=<?php echo $attribute->id ?>"><?php echo img_down('default', 0, 'imgdownforline'); ?></a>
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
$var = !$var;
|
||||||
|
endforeach
|
||||||
|
?>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="tabsAction">
|
||||||
|
<div class="inline-block divButAction">
|
||||||
|
<a href="create.php" class="butAction"><?php echo $langs->trans('Create') ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
llxFooter();
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
||||||
|
* Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -48,6 +49,10 @@ if (! empty($conf->projet->enabled)) {
|
|||||||
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
|
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
}
|
||||||
|
|
||||||
$langs->load('companies');
|
$langs->load('companies');
|
||||||
$langs->load('propal');
|
$langs->load('propal');
|
||||||
$langs->load('compta');
|
$langs->load('compta');
|
||||||
@@ -655,7 +660,8 @@ if (empty($reshook))
|
|||||||
$predef='';
|
$predef='';
|
||||||
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
||||||
$price_ht = GETPOST('price_ht');
|
$price_ht = GETPOST('price_ht');
|
||||||
if (GETPOST('prod_entry_mode') == 'free')
|
$prod_entry_mode = GETPOST('prod_entry_mode');
|
||||||
|
if ($prod_entry_mode == 'free')
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
||||||
@@ -681,21 +687,35 @@ if (empty($reshook))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
||||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
|
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && $price_ht == '') // Unit price can be 0 but not ''. Also price can be negative for proposal.
|
if ($prod_entry_mode == 'free' && empty($idprod) && $price_ht == '') // Unit price can be 0 but not ''. Also price can be negative for proposal.
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
|
||||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
|
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$error && !empty($conf->attributes->enabled) && $prod_entry_mode != 'free') {
|
||||||
|
if ($combinations = GETPOST('combinations', 'array')) {
|
||||||
|
//Check if there is a product with the given combination
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
|
||||||
|
$idprod = $res->fk_product_child;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorProductCombinationNotFound'), 'errors');
|
||||||
|
$error ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
||||||
$pu_ht = 0;
|
$pu_ht = 0;
|
||||||
$pu_ttc = 0;
|
$pu_ttc = 0;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2011-2016 Philippe Grand <philippe.grand@atoo-net.com>
|
* Copyright (C) 2011-2016 Philippe Grand <philippe.grand@atoo-net.com>
|
||||||
* Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr>
|
* Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr>
|
||||||
* Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
||||||
@@ -51,6 +51,10 @@ if (! empty($conf->projet->enabled)) {
|
|||||||
}
|
}
|
||||||
require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
|
require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
}
|
||||||
|
|
||||||
$langs->load('orders');
|
$langs->load('orders');
|
||||||
$langs->load('sendings');
|
$langs->load('sendings');
|
||||||
$langs->load('companies');
|
$langs->load('companies');
|
||||||
@@ -621,7 +625,8 @@ if (empty($reshook))
|
|||||||
$predef='';
|
$predef='';
|
||||||
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
||||||
$price_ht = GETPOST('price_ht');
|
$price_ht = GETPOST('price_ht');
|
||||||
if (GETPOST('prod_entry_mode') == 'free')
|
$prod_entry_mode = GETPOST('prod_entry_mode');
|
||||||
|
if ($prod_entry_mode == 'free')
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
||||||
@@ -651,11 +656,11 @@ if (empty($reshook))
|
|||||||
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not ''
|
if ($prod_entry_mode == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not ''
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
@@ -664,11 +669,25 @@ if (empty($reshook))
|
|||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$error && !empty($conf->attributes->enabled) && $prod_entry_mode != 'free') {
|
||||||
|
if ($combinations = GETPOST('combinations', 'array')) {
|
||||||
|
//Check if there is a product with the given combination
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
|
||||||
|
$idprod = $res->fk_product_child;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorProductCombinationNotFound'), 'errors');
|
||||||
|
$error ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
||||||
// Clean parameters
|
// Clean parameters
|
||||||
$date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start'.$predef.'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year'));
|
$date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start'.$predef.'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year'));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
|
||||||
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -56,6 +56,10 @@ if (! empty($conf->projet->enabled)) {
|
|||||||
}
|
}
|
||||||
require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
|
require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
}
|
||||||
|
|
||||||
$langs->load('bills');
|
$langs->load('bills');
|
||||||
$langs->load('companies');
|
$langs->load('companies');
|
||||||
$langs->load('compta');
|
$langs->load('compta');
|
||||||
@@ -1322,7 +1326,8 @@ if (empty($reshook))
|
|||||||
$predef='';
|
$predef='';
|
||||||
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
||||||
$price_ht = GETPOST('price_ht');
|
$price_ht = GETPOST('price_ht');
|
||||||
if (GETPOST('prod_entry_mode') == 'free')
|
$prod_entry_mode = GETPOST('prod_entry_mode');
|
||||||
|
if ($prod_entry_mode == 'free')
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
$tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
|
||||||
@@ -1352,11 +1357,11 @@ if (empty($reshook))
|
|||||||
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && GETPOST('type') < 0) {
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not ''
|
if ($prod_entry_mode == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not ''
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
@@ -1365,7 +1370,7 @@ if (empty($reshook))
|
|||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) {
|
if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
@@ -1374,7 +1379,23 @@ if (empty($reshook))
|
|||||||
setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
|
setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
|
||||||
$error ++;
|
$error ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$error && !empty($conf->attributes->enabled) && $prod_entry_mode != 'free') {
|
||||||
|
if ($combinations = GETPOST('combinations', 'array')) {
|
||||||
|
//Check if there is a product with the given combination
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
|
||||||
|
$idprod = $res->fk_product_child;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorProductCombinationNotFound'), 'errors');
|
||||||
|
$error ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
|
||||||
|
|
||||||
$ret = $object->fetch($id);
|
$ret = $object->fetch($id);
|
||||||
if ($ret < 0) {
|
if ($ret < 0) {
|
||||||
dol_print_error($db, $object->error);
|
dol_print_error($db, $object->error);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
|
* Copyright (C) 2013 Christophe Battarel <christophe.battarel@altairis.fr>
|
||||||
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014-2016 Ferran Marcet <fmarcet@2byte.es>
|
* Copyright (C) 2014-2016 Ferran Marcet <fmarcet@2byte.es>
|
||||||
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -471,7 +471,7 @@ if (empty($reshook))
|
|||||||
unset($_POST["options_" . $key]);
|
unset($_POST["options_" . $key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $error)
|
if (! $error)
|
||||||
{
|
{
|
||||||
// Clean parameters
|
// Clean parameters
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2010-2014 Philippe Grand <philippe.grand@atoo-net.com>
|
* Copyright (C) 2010-2014 Philippe Grand <philippe.grand@atoo-net.com>
|
||||||
* Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
|
* Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
|
||||||
* Copyright (C) 2012-2014 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
* Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||||
* Copyright (C) 2014 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
|
* Copyright (C) 2014 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
|
||||||
@@ -1605,9 +1605,10 @@ class Form
|
|||||||
* @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
|
* @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
|
||||||
* @param array $ajaxoptions Options for ajax_autocompleter
|
* @param array $ajaxoptions Options for ajax_autocompleter
|
||||||
* @param int $socid Thirdparty Id (to get also price dedicated to this customer)
|
* @param int $socid Thirdparty Id (to get also price dedicated to this customer)
|
||||||
|
* @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...])
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function select_produits($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0)
|
function select_produits($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $selected_combinations = array())
|
||||||
{
|
{
|
||||||
global $langs,$conf;
|
global $langs,$conf;
|
||||||
|
|
||||||
@@ -1632,6 +1633,80 @@ class Form
|
|||||||
$urloption.='&socid='.$socid;
|
$urloption.='&socid='.$socid;
|
||||||
}
|
}
|
||||||
print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
|
print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
selected = <?php echo json_encode($selected_combinations) ?>;
|
||||||
|
combvalues = {};
|
||||||
|
|
||||||
|
jQuery(document).ready(function () {
|
||||||
|
|
||||||
|
jQuery("input[name='prod_entry_mode']").change(function () {
|
||||||
|
if (jQuery(this).val() == 'free') {
|
||||||
|
jQuery('div#attributes_box').empty();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery("input#<?php echo $htmlname ?>").change(function () {
|
||||||
|
|
||||||
|
if (!jQuery(this).val()) {
|
||||||
|
jQuery('div#attributes_box').empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery.getJSON("<?php echo dol_buildpath('/attributes/ajax/getCombinations.php', 2) ?>", {
|
||||||
|
id: jQuery(this).val()
|
||||||
|
}, function (data) {
|
||||||
|
jQuery('div#attributes_box').empty();
|
||||||
|
|
||||||
|
jQuery.each(data, function (key, val) {
|
||||||
|
|
||||||
|
combvalues[val.id] = val.values;
|
||||||
|
|
||||||
|
var span = jQuery(document.createElement('div')).css({
|
||||||
|
'display': 'table-row'
|
||||||
|
});
|
||||||
|
|
||||||
|
span.append(
|
||||||
|
jQuery(document.createElement('div')).text(val.label).css({
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'display': 'table-cell',
|
||||||
|
'text-align': 'right'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
var html = jQuery(document.createElement('select')).attr('name', 'combinations[' + val.id + ']').css({
|
||||||
|
'margin-left': '15px',
|
||||||
|
'white-space': 'pre'
|
||||||
|
}).append(
|
||||||
|
jQuery(document.createElement('option')).val('')
|
||||||
|
);
|
||||||
|
|
||||||
|
jQuery.each(combvalues[val.id], function (key, val) {
|
||||||
|
var tag = jQuery(document.createElement('option')).val(val.id).html(val.value);
|
||||||
|
|
||||||
|
if (selected[val.fk_product_attribute] == val.id) {
|
||||||
|
tag.attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
html.append(tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
span.append(html);
|
||||||
|
jQuery('div#attributes_box').append(span);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
<?php if ($selected): ?>
|
||||||
|
jQuery("input#<?php echo $htmlname ?>").change();
|
||||||
|
<?php endif ?>
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
|
if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
|
||||||
else if ($hidelabel > 1) {
|
else if ($hidelabel > 1) {
|
||||||
if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
|
if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
|
||||||
@@ -1709,7 +1784,17 @@ class Form
|
|||||||
{
|
{
|
||||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='". $langs->getDefaultLang() ."'";
|
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='". $langs->getDefaultLang() ."'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
|
||||||
|
$sql .= " LEFT JOIN llx_product_attribute_combination pac ON pac.fk_product_child = p.rowid";
|
||||||
|
}
|
||||||
|
|
||||||
$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
|
$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
|
||||||
|
|
||||||
|
if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
|
||||||
|
$sql .= " AND pac.rowid IS NULL";
|
||||||
|
}
|
||||||
|
|
||||||
if ($finished == 0)
|
if ($finished == 0)
|
||||||
{
|
{
|
||||||
$sql.= " AND p.finished = ".$finished;
|
$sql.= " AND p.finished = ".$finished;
|
||||||
@@ -1881,7 +1966,7 @@ class Form
|
|||||||
$outlabel=$objp->label;
|
$outlabel=$objp->label;
|
||||||
$outdesc=$objp->description;
|
$outdesc=$objp->description;
|
||||||
$outbarcode=$objp->barcode;
|
$outbarcode=$objp->barcode;
|
||||||
|
|
||||||
$outtype=$objp->fk_product_type;
|
$outtype=$objp->fk_product_type;
|
||||||
$outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
|
$outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
|
||||||
$outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
|
$outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
|
||||||
@@ -1898,13 +1983,13 @@ class Form
|
|||||||
$opt.= $objp->ref;
|
$opt.= $objp->ref;
|
||||||
if ($outbarcode) $opt.=' ('.$outbarcode.')';
|
if ($outbarcode) $opt.=' ('.$outbarcode.')';
|
||||||
$opt.=' - '.dol_trunc($label,$maxlengtharticle).' - ';
|
$opt.=' - '.dol_trunc($label,$maxlengtharticle).' - ';
|
||||||
|
|
||||||
$objRef = $objp->ref;
|
$objRef = $objp->ref;
|
||||||
if (! empty($filterkey) && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
|
if (! empty($filterkey) && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
|
||||||
$outval.=$objRef;
|
$outval.=$objRef;
|
||||||
if ($outbarcode) $outval.=' ('.$outbarcode.')';
|
if ($outbarcode) $outval.=' ('.$outbarcode.')';
|
||||||
$outval.=' - '.dol_trunc($label,$maxlengtharticle).' - ';
|
$outval.=' - '.dol_trunc($label,$maxlengtharticle).' - ';
|
||||||
|
|
||||||
$found=0;
|
$found=0;
|
||||||
|
|
||||||
// Multiprice
|
// Multiprice
|
||||||
@@ -2066,7 +2151,7 @@ class Form
|
|||||||
{
|
{
|
||||||
global $langs,$conf;
|
global $langs,$conf;
|
||||||
global $price_level, $status, $finished;
|
global $price_level, $status, $finished;
|
||||||
|
|
||||||
$selected_input_value='';
|
$selected_input_value='';
|
||||||
if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
|
if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
|
||||||
{
|
{
|
||||||
@@ -3174,7 +3259,7 @@ class Form
|
|||||||
{
|
{
|
||||||
dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
|
dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cat = new Categorie($this->db);
|
$cat = new Categorie($this->db);
|
||||||
$cate_arbo = $cat->get_full_arbo($type,$excludeafterid);
|
$cate_arbo = $cat->get_full_arbo($type,$excludeafterid);
|
||||||
|
|
||||||
@@ -3837,7 +3922,7 @@ class Form
|
|||||||
function form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
|
function form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
|
||||||
{
|
{
|
||||||
global $langs, $mysoc, $conf;
|
global $langs, $mysoc, $conf;
|
||||||
|
|
||||||
if ($htmlname != "none")
|
if ($htmlname != "none")
|
||||||
{
|
{
|
||||||
print '<form method="POST" action="'.$page.'">';
|
print '<form method="POST" action="'.$page.'">';
|
||||||
@@ -4107,7 +4192,7 @@ class Form
|
|||||||
$out.= '</option>';
|
$out.= '</option>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$out.= '</select>';
|
$out.= '</select>';
|
||||||
@@ -4204,7 +4289,7 @@ class Form
|
|||||||
$defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
|
$defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
|
||||||
}
|
}
|
||||||
//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
|
//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
|
||||||
|
|
||||||
// Check parameters
|
// Check parameters
|
||||||
if (is_object($societe_vendeuse) && ! $societe_vendeuse->country_code)
|
if (is_object($societe_vendeuse) && ! $societe_vendeuse->country_code)
|
||||||
{
|
{
|
||||||
@@ -4263,7 +4348,7 @@ class Form
|
|||||||
|
|
||||||
// Now we get list
|
// Now we get list
|
||||||
$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
|
$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
|
||||||
|
|
||||||
if ($num > 0)
|
if ($num > 0)
|
||||||
{
|
{
|
||||||
// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
|
// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
|
||||||
@@ -4304,7 +4389,7 @@ class Form
|
|||||||
$return.= '"';
|
$return.= '"';
|
||||||
if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
|
if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
|
||||||
{
|
{
|
||||||
if ($defaultcode == $rate['code']) $return.= ' selected';
|
if ($defaultcode == $rate['code']) $return.= ' selected';
|
||||||
}
|
}
|
||||||
elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
|
elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
|
||||||
{
|
{
|
||||||
@@ -5036,7 +5121,7 @@ class Form
|
|||||||
/* var_dump($val);
|
/* var_dump($val);
|
||||||
var_dump(array_key_exists('enabled', $val));
|
var_dump(array_key_exists('enabled', $val));
|
||||||
var_dump(!$val['enabled']);*/
|
var_dump(!$val['enabled']);*/
|
||||||
if (array_key_exists('enabled', $val) && isset($val['enabled']) && ! $val['enabled'])
|
if (array_key_exists('enabled', $val) && isset($val['enabled']) && ! $val['enabled'])
|
||||||
{
|
{
|
||||||
unset($array[$key]); // We don't want this field
|
unset($array[$key]); // We don't want this field
|
||||||
continue;
|
continue;
|
||||||
@@ -5221,17 +5306,17 @@ class Form
|
|||||||
else if ($objecttype == 'subscription') {
|
else if ($objecttype == 'subscription') {
|
||||||
$tplpath = 'adherents';
|
$tplpath = 'adherents';
|
||||||
}
|
}
|
||||||
|
|
||||||
global $linkedObjectBlock;
|
global $linkedObjectBlock;
|
||||||
$linkedObjectBlock = $objects;
|
$linkedObjectBlock = $objects;
|
||||||
|
|
||||||
if (empty($numoutput))
|
if (empty($numoutput))
|
||||||
{
|
{
|
||||||
$numoutput++;
|
$numoutput++;
|
||||||
|
|
||||||
print '<br>';
|
print '<br>';
|
||||||
print load_fiche_titre($langs->trans('RelatedObjects'), '', '');
|
print load_fiche_titre($langs->trans('RelatedObjects'), '', '');
|
||||||
|
|
||||||
print '<table class="noborder allwidth">';
|
print '<table class="noborder allwidth">';
|
||||||
|
|
||||||
print '<tr class="liste_titre">';
|
print '<tr class="liste_titre">';
|
||||||
@@ -5244,7 +5329,7 @@ class Form
|
|||||||
print '<td></td>';
|
print '<td></td>';
|
||||||
print '</tr>';
|
print '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output template part (modules that overwrite templates must declare this into descriptor)
|
// Output template part (modules that overwrite templates must declare this into descriptor)
|
||||||
$dirtpls=array_merge($conf->modules_parts['tpl'],array('/'.$tplpath.'/tpl'));
|
$dirtpls=array_merge($conf->modules_parts['tpl'],array('/'.$tplpath.'/tpl'));
|
||||||
foreach($dirtpls as $reldir)
|
foreach($dirtpls as $reldir)
|
||||||
@@ -5254,11 +5339,11 @@ class Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($numoutput)
|
if ($numoutput)
|
||||||
{
|
{
|
||||||
print '</table>';
|
print '</table>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $num;
|
return $num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5627,7 +5712,7 @@ class Form
|
|||||||
$ret.='</div>';
|
$ret.='</div>';
|
||||||
|
|
||||||
if ($morehtmlright) $ret.='<div class="inline-block floatleft">'.$morehtmlright.'</div>';
|
if ($morehtmlright) $ret.='<div class="inline-block floatleft">'.$morehtmlright.'</div>';
|
||||||
|
|
||||||
if ($previous_ref || $next_ref || $morehtml)
|
if ($previous_ref || $next_ref || $morehtml)
|
||||||
{
|
{
|
||||||
$ret.='<div class="pagination"><ul>';
|
$ret.='<div class="pagination"><ul>';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
|
/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||||
* Copyright (C) 2008-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
* Copyright (C) 2008-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
||||||
* Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
|
* Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
|
||||||
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2015 Ferran Marcet <fmarcet@2byte.es>
|
* Copyright (C) 2015 Ferran Marcet <fmarcet@2byte.es>
|
||||||
* Copyright (C) 2015-2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
* Copyright (C) 2015-2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||||
*
|
*
|
||||||
@@ -2058,4 +2058,31 @@ function colorStringToArray($stringcolor,$colorifnotfound=array(88,88,88))
|
|||||||
return array(hexdec($reg[1]),hexdec($reg[2]),hexdec($reg[3]));
|
return array(hexdec($reg[1]),hexdec($reg[2]),hexdec($reg[3]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the Cartesian product algorithm to an array
|
||||||
|
* Source: http://stackoverflow.com/a/15973172
|
||||||
|
*
|
||||||
|
* @param array $input Array of products
|
||||||
|
* @return array Array of combinations
|
||||||
|
*/
|
||||||
|
function cartesianArray(array $input) {
|
||||||
|
// filter out empty values
|
||||||
|
$input = array_filter($input);
|
||||||
|
|
||||||
|
$result = array(array());
|
||||||
|
|
||||||
|
foreach ($input as $key => $values) {
|
||||||
|
$append = array();
|
||||||
|
|
||||||
|
foreach($result as $product) {
|
||||||
|
foreach($values as $item) {
|
||||||
|
$product[$key] = $item;
|
||||||
|
$append[] = $product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $append;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
* Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
||||||
* Copyright (C) 2009-2010 Regis Houssin <regis.houssin@capnetworks.com>
|
* Copyright (C) 2009-2010 Regis Houssin <regis.houssin@capnetworks.com>
|
||||||
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||||
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -106,6 +106,23 @@ function product_prepare_head($object)
|
|||||||
$head[$h][2] = 'referers';
|
$head[$h][2] = 'referers';
|
||||||
$h++;
|
$h++;
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled) && $object->isProduct()) {
|
||||||
|
|
||||||
|
global $db;
|
||||||
|
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($prodcomb->fetchByFkProductChild($object->id) == -1) {
|
||||||
|
$head[$h][0] = DOL_URL_ROOT."/attributes/combinations.php?id=".$object->id;
|
||||||
|
$head[$h][1] = $langs->trans('ProductCombinations');
|
||||||
|
$head[$h][2] = 'combinations';
|
||||||
|
}
|
||||||
|
|
||||||
|
$h++;
|
||||||
|
}
|
||||||
|
|
||||||
if ($object->isProduct() || ($object->isService() && ! empty($conf->global->STOCK_SUPPORTS_SERVICES))) // If physical product we can stock (or service with option)
|
if ($object->isProduct() || ($object->isService() && ! empty($conf->global->STOCK_SUPPORTS_SERVICES))) // If physical product we can stock (or service with option)
|
||||||
{
|
{
|
||||||
if (! empty($conf->stock->enabled) && $user->rights->stock->lire)
|
if (! empty($conf->stock->enabled) && $user->rights->stock->lire)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
* Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||||
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -52,7 +52,7 @@ if (in_array($object->element,array('propal', 'supplier_proposal','facture','fac
|
|||||||
|
|
||||||
<!-- BEGIN PHP TEMPLATE objectline_create.tpl.php -->
|
<!-- BEGIN PHP TEMPLATE objectline_create.tpl.php -->
|
||||||
|
|
||||||
<tr class="liste_titre liste_titre_add nodrag nodrop">
|
<tr id="addline" class="liste_titre liste_titre_add nodrag nodrop">
|
||||||
<td class="linecoldescription" <?php echo (! empty($conf->global->MAIN_VIEW_LINE_NUMBER) ? ' colspan="2"' : ''); ?>>
|
<td class="linecoldescription" <?php echo (! empty($conf->global->MAIN_VIEW_LINE_NUMBER) ? ' colspan="2"' : ''); ?>>
|
||||||
<div id="add"></div><span class="hideonsmartphone"><?php echo $langs->trans('AddNewLine'); ?></span><?php // echo $langs->trans("FreeZone"); ?>
|
<div id="add"></div><span class="hideonsmartphone"><?php echo $langs->trans('AddNewLine'); ?></span><?php // echo $langs->trans("FreeZone"); ?>
|
||||||
</td>
|
</td>
|
||||||
@@ -178,7 +178,7 @@ else {
|
|||||||
|
|
||||||
if (empty($senderissupplier))
|
if (empty($senderissupplier))
|
||||||
{
|
{
|
||||||
$form->select_produits(GETPOST('idprod'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, 1, 2, '', 1, array(),$buyer->id);
|
$form->select_produits(GETPOST('idprod'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, 1, 2, '', 1, array(),$buyer->id, GETPOST('combinations', 'array'));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -210,7 +210,14 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) echo '<br>';
|
if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) {
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
echo '<div id="attributes_box"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<br>';
|
||||||
|
}
|
||||||
|
|
||||||
// Editor wysiwyg
|
// Editor wysiwyg
|
||||||
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
|
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
|
||||||
@@ -532,9 +539,9 @@ jQuery(document).ready(function() {
|
|||||||
$("#idprod, #idprodfournprice").change(function()
|
$("#idprod, #idprodfournprice").change(function()
|
||||||
{
|
{
|
||||||
console.log("#idprod, #idprodfournprice change triggered");
|
console.log("#idprod, #idprodfournprice change triggered");
|
||||||
|
|
||||||
setforpredef(); // TODO Keep vat combo visible and set it to first entry into list that match result of get_default_tva
|
setforpredef(); // TODO Keep vat combo visible and set it to first entry into list that match result of get_default_tva
|
||||||
|
|
||||||
jQuery('#trlinefordates').show();
|
jQuery('#trlinefordates').show();
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
@@ -555,13 +562,13 @@ jQuery(document).ready(function() {
|
|||||||
var defaultkey = '';
|
var defaultkey = '';
|
||||||
var defaultprice = '';
|
var defaultprice = '';
|
||||||
var bestpricefound = 0;
|
var bestpricefound = 0;
|
||||||
|
|
||||||
var bestpriceid = 0; var bestpricevalue = 0;
|
var bestpriceid = 0; var bestpricevalue = 0;
|
||||||
var pmppriceid = 0; var pmppricevalue = 0;
|
var pmppriceid = 0; var pmppricevalue = 0;
|
||||||
var costpriceid = 0; var costpricevalue = 0;
|
var costpriceid = 0; var costpricevalue = 0;
|
||||||
|
|
||||||
/* setup of margin calculation */
|
/* setup of margin calculation */
|
||||||
var defaultbuyprice = '<?php
|
var defaultbuyprice = '<?php
|
||||||
if (isset($conf->global->MARGIN_TYPE))
|
if (isset($conf->global->MARGIN_TYPE))
|
||||||
{
|
{
|
||||||
if ($conf->global->MARGIN_TYPE == '1') print 'bestsupplierprice';
|
if ($conf->global->MARGIN_TYPE == '1') print 'bestsupplierprice';
|
||||||
@@ -569,7 +576,7 @@ jQuery(document).ready(function() {
|
|||||||
if ($conf->global->MARGIN_TYPE == 'costprice') print 'costprice';
|
if ($conf->global->MARGIN_TYPE == 'costprice') print 'costprice';
|
||||||
} ?>';
|
} ?>';
|
||||||
console.log("we will set the field for margin. defaultbuyprice="+defaultbuyprice);
|
console.log("we will set the field for margin. defaultbuyprice="+defaultbuyprice);
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
$(data).each(function() {
|
$(data).each(function() {
|
||||||
if (this.id != 'pmpprice' && this.id != 'costprice')
|
if (this.id != 'pmpprice' && this.id != 'costprice')
|
||||||
@@ -586,7 +593,7 @@ jQuery(document).ready(function() {
|
|||||||
//console.log("id="+this.id+"-price="+this.price);
|
//console.log("id="+this.id+"-price="+this.price);
|
||||||
if ('pmp' == defaultbuyprice || 'costprice' == defaultbuyprice)
|
if ('pmp' == defaultbuyprice || 'costprice' == defaultbuyprice)
|
||||||
{
|
{
|
||||||
if (this.price > 0) {
|
if (this.price > 0) {
|
||||||
defaultkey = this.id; defaultprice = this.price; pmppriceid = this.id; pmppricevalue = this.price;
|
defaultkey = this.id; defaultprice = this.price; pmppriceid = this.id; pmppricevalue = this.price;
|
||||||
//console.log("pmppricevalue="+pmppricevalue);
|
//console.log("pmppricevalue="+pmppricevalue);
|
||||||
}
|
}
|
||||||
@@ -605,22 +612,22 @@ jQuery(document).ready(function() {
|
|||||||
options += '<option value="'+this.id+'" price="'+this.price+'">'+this.label+'</option>';
|
options += '<option value="'+this.id+'" price="'+this.price+'">'+this.label+'</option>';
|
||||||
});
|
});
|
||||||
options += '<option value="inputprice" price="'+defaultprice+'"><?php echo $langs->trans("InputPrice"); ?></option>';
|
options += '<option value="inputprice" price="'+defaultprice+'"><?php echo $langs->trans("InputPrice"); ?></option>';
|
||||||
|
|
||||||
console.log("finally selected defaultkey="+defaultkey+" defaultprice="+defaultprice);
|
console.log("finally selected defaultkey="+defaultkey+" defaultprice="+defaultprice);
|
||||||
|
|
||||||
$("#fournprice_predef").html(options).show();
|
$("#fournprice_predef").html(options).show();
|
||||||
if (defaultkey != '')
|
if (defaultkey != '')
|
||||||
{
|
{
|
||||||
$("#fournprice_predef").val(defaultkey);
|
$("#fournprice_predef").val(defaultkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At loading, no product are yet selected, so we hide field of buying_price */
|
/* At loading, no product are yet selected, so we hide field of buying_price */
|
||||||
$("#buying_price").hide();
|
$("#buying_price").hide();
|
||||||
|
|
||||||
/* Define default price at loading */
|
/* Define default price at loading */
|
||||||
var defaultprice = $("#fournprice_predef").find('option:selected').attr("price");
|
var defaultprice = $("#fournprice_predef").find('option:selected').attr("price");
|
||||||
$("#buying_price").val(defaultprice);
|
$("#buying_price").val(defaultprice);
|
||||||
|
|
||||||
$("#fournprice_predef").change(function() {
|
$("#fournprice_predef").change(function() {
|
||||||
console.log("change on fournprice_predef");
|
console.log("change on fournprice_predef");
|
||||||
/* Hide field buying_price according to choice into list (if 'inputprice' or not) */
|
/* Hide field buying_price according to choice into list (if 'inputprice' or not) */
|
||||||
@@ -672,8 +679,8 @@ function setforfree() {
|
|||||||
jQuery("#idprod").val('');
|
jQuery("#idprod").val('');
|
||||||
jQuery("#idprodfournprice").val('0'); // Set cursor on not selected product
|
jQuery("#idprodfournprice").val('0'); // Set cursor on not selected product
|
||||||
jQuery("#search_idprodfournprice").val('');
|
jQuery("#search_idprodfournprice").val('');
|
||||||
jQuery("#prod_entry_mode_free").prop('checked',true);
|
jQuery("#prod_entry_mode_free").prop('checked',true).change();
|
||||||
jQuery("#prod_entry_mode_predef").prop('checked',false);
|
jQuery("#prod_entry_mode_predef").prop('checked',false).change();
|
||||||
jQuery("#price_ht").show();
|
jQuery("#price_ht").show();
|
||||||
jQuery("#price_ttc").show(); // May no exists
|
jQuery("#price_ttc").show(); // May no exists
|
||||||
jQuery("#tva_tx").show();
|
jQuery("#tva_tx").show();
|
||||||
@@ -691,8 +698,8 @@ function setforfree() {
|
|||||||
function setforpredef() {
|
function setforpredef() {
|
||||||
console.log("Call setforpredef. We hide some fields");
|
console.log("Call setforpredef. We hide some fields");
|
||||||
jQuery("#select_type").val(-1);
|
jQuery("#select_type").val(-1);
|
||||||
jQuery("#prod_entry_mode_free").prop('checked',false);
|
jQuery("#prod_entry_mode_free").prop('checked',false).change();
|
||||||
jQuery("#prod_entry_mode_predef").prop('checked',true);
|
jQuery("#prod_entry_mode_predef").prop('checked',true).change();
|
||||||
jQuery("#price_ht").hide();
|
jQuery("#price_ht").hide();
|
||||||
jQuery("#price_ttc").hide(); // May no exists
|
jQuery("#price_ttc").hide(); // May no exists
|
||||||
jQuery("#tva_tx").hide();
|
jQuery("#tva_tx").hide();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Copyright (C) 2005-2016 Regis Houssin <regis.houssin@capnetworks.com>
|
* Copyright (C) 2005-2016 Regis Houssin <regis.houssin@capnetworks.com>
|
||||||
* Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2011-2015 Philippe Grand <philippe.grand@atoo-net.com>
|
* Copyright (C) 2011-2015 Philippe Grand <philippe.grand@atoo-net.com>
|
||||||
* Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014 Ion Agorria <ion@agorria.com>
|
* Copyright (C) 2014 Ion Agorria <ion@agorria.com>
|
||||||
*
|
*
|
||||||
@@ -50,6 +50,10 @@ if (!empty($conf->projet->enabled)) {
|
|||||||
}
|
}
|
||||||
require_once NUSOAP_PATH.'/nusoap.php'; // Include SOAP
|
require_once NUSOAP_PATH.'/nusoap.php'; // Include SOAP
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
}
|
||||||
|
|
||||||
$langs->load('admin');
|
$langs->load('admin');
|
||||||
$langs->load('orders');
|
$langs->load('orders');
|
||||||
$langs->load('sendings');
|
$langs->load('sendings');
|
||||||
@@ -285,7 +289,7 @@ if (empty($reshook))
|
|||||||
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
||||||
$date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start' . $predef . 'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year'));
|
$date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start' . $predef . 'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year'));
|
||||||
$date_end=dol_mktime(GETPOST('date_end'.$predef.'hour'), GETPOST('date_end'.$predef.'min'), GETPOST('date_end' . $predef . 'sec'), GETPOST('date_end'.$predef.'month'), GETPOST('date_end'.$predef.'day'), GETPOST('date_end'.$predef.'year'));
|
$date_end=dol_mktime(GETPOST('date_end'.$predef.'hour'), GETPOST('date_end'.$predef.'min'), GETPOST('date_end' . $predef . 'sec'), GETPOST('date_end'.$predef.'month'), GETPOST('date_end'.$predef.'day'), GETPOST('date_end'.$predef.'year'));
|
||||||
if (GETPOST('prod_entry_mode') == 'free')
|
if ($prod_entry_mode == 'free')
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$price_ht = GETPOST('price_ht');
|
$price_ht = GETPOST('price_ht');
|
||||||
@@ -313,22 +317,22 @@ if (empty($reshook))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode')=='free' && GETPOST('price_ht') < 0 && $qty < 0)
|
if ($prod_entry_mode =='free' && GETPOST('price_ht') < 0 && $qty < 0)
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPrice'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPrice'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && ! GETPOST('idprodfournprice') && GETPOST('type') < 0)
|
if ($prod_entry_mode =='free' && ! GETPOST('idprodfournprice') && GETPOST('type') < 0)
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='') // Unit price can be 0 but not ''
|
if ($prod_entry_mode =='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='') // Unit price can be 0 but not ''
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('UnitPrice'))), null, 'errors');
|
setEventMessages($langs->trans($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('UnitPrice'))), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && ! GETPOST('dp_desc'))
|
if ($prod_entry_mode =='free' && ! GETPOST('dp_desc'))
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
@@ -339,10 +343,24 @@ if (empty($reshook))
|
|||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ecrase $pu par celui du produit
|
if (!$error && !empty($conf->attributes->enabled) && $prod_entry_mode != 'free') {
|
||||||
|
if ($combinations = GETPOST('combinations', 'array')) {
|
||||||
|
//Check if there is a product with the given combination
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
|
||||||
|
$idprod = $res->fk_product_child;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorProductCombinationNotFound'), 'errors');
|
||||||
|
$error ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ecrase $pu par celui du produit
|
||||||
// Ecrase $desc par celui du produit
|
// Ecrase $desc par celui du produit
|
||||||
// Ecrase $txtva par celui du produit
|
// Ecrase $txtva par celui du produit
|
||||||
if ((GETPOST('prod_entry_mode') != 'free') && empty($error)) // With combolist mode idprodfournprice is > 0 or -1. With autocomplete, idprodfournprice is > 0 or ''
|
if (($prod_entry_mode != 'free') && empty($error)) // With combolist mode idprodfournprice is > 0 or -1. With autocomplete, idprodfournprice is > 0 or ''
|
||||||
{
|
{
|
||||||
$productsupplier = new ProductFournisseur($db);
|
$productsupplier = new ProductFournisseur($db);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2013-2015 Philippe Grand <philippe.grand@atoo-net.com>
|
* Copyright (C) 2013-2015 Philippe Grand <philippe.grand@atoo-net.com>
|
||||||
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
|
||||||
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -45,6 +45,10 @@ if (!empty($conf->projet->enabled)) {
|
|||||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
|
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled)) {
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$langs->load('bills');
|
$langs->load('bills');
|
||||||
$langs->load('compta');
|
$langs->load('compta');
|
||||||
@@ -668,7 +672,8 @@ if (empty($reshook))
|
|||||||
// Set if we used free entry or predefined product
|
// Set if we used free entry or predefined product
|
||||||
$predef='';
|
$predef='';
|
||||||
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
$product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
|
||||||
if (GETPOST('prod_entry_mode') == 'free')
|
$prod_entry_mode = GETPOST('prod_entry_mode');
|
||||||
|
if ($prod_entry_mode == 'free')
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$price_ht = GETPOST('price_ht');
|
$price_ht = GETPOST('price_ht');
|
||||||
@@ -699,22 +704,22 @@ if (empty($reshook))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode')=='free' && GETPOST('price_ht') < 0 && $qty < 0)
|
if ($prod_entry_mode =='free' && GETPOST('price_ht') < 0 && $qty < 0)
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPrice'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPrice'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && ! GETPOST('idprodfournprice') && GETPOST('type') < 0)
|
if ($prod_entry_mode =='free' && ! GETPOST('idprodfournprice') && GETPOST('type') < 0)
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='') // Unit price can be 0 but not ''
|
if ($prod_entry_mode =='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='') // Unit price can be 0 but not ''
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('UnitPrice'))), null, 'errors');
|
setEventMessages($langs->trans($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('UnitPrice'))), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
if (GETPOST('prod_entry_mode')=='free' && ! GETPOST('dp_desc'))
|
if ($prod_entry_mode =='free' && ! GETPOST('dp_desc'))
|
||||||
{
|
{
|
||||||
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
|
||||||
$error++;
|
$error++;
|
||||||
@@ -725,7 +730,21 @@ if (empty($reshook))
|
|||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode') != 'free') // With combolist mode idprodfournprice is > 0 or -1. With autocomplete, idprodfournprice is > 0 or ''
|
if (!$error && !empty($conf->attributes->enabled) && $prod_entry_mode != 'free') {
|
||||||
|
if ($combinations = GETPOST('combinations', 'array')) {
|
||||||
|
//Check if there is a product with the given combination
|
||||||
|
$prodcomb = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
|
||||||
|
$idprod = $res->fk_product_child;
|
||||||
|
} else {
|
||||||
|
setEventMessage($langs->trans('ErrorProductCombinationNotFound'), 'errors');
|
||||||
|
$error ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prod_entry_mode != 'free') // With combolist mode idprodfournprice is > 0 or -1. With autocomplete, idprodfournprice is > 0 or ''
|
||||||
{
|
{
|
||||||
$idprod=0;
|
$idprod=0;
|
||||||
$productsupplier=new ProductFournisseur($db);
|
$productsupplier=new ProductFournisseur($db);
|
||||||
|
|||||||
@@ -515,4 +515,3 @@ CREATE TABLE llx_oauth_state (
|
|||||||
|
|
||||||
ALTER TABLE llx_product_batch ADD UNIQUE INDEX uk_product_batch (fk_product_stock, batch);
|
ALTER TABLE llx_product_batch ADD UNIQUE INDEX uk_product_batch (fk_product_stock, batch);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,3 +39,39 @@ DROP TABLE llx_ecm_documents;
|
|||||||
|
|
||||||
ALTER TABLE llx_notify ADD COLUMN type_target varchar(16) NULL;
|
ALTER TABLE llx_notify ADD COLUMN type_target varchar(16) NULL;
|
||||||
|
|
||||||
|
-- Product attributes
|
||||||
|
CREATE TABLE llx_product_attribute
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
ref VARCHAR(255) NOT NULL,
|
||||||
|
label VARCHAR(255) NOT NULL,
|
||||||
|
rang INT DEFAULT 0 NOT NULL,
|
||||||
|
entity INT DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
|
ALTER TABLE llx_product_attribute ADD CONSTRAINT unique_ref UNIQUE (ref);
|
||||||
|
CREATE TABLE llx_product_attribute_combination
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_product_parent INT NOT NULL,
|
||||||
|
fk_product_child INT NOT NULL,
|
||||||
|
variation_price FLOAT NOT NULL,
|
||||||
|
variation_price_percentage INT NULL,
|
||||||
|
variation_weight FLOAT NOT NULL,
|
||||||
|
entity INT DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE llx_product_attribute_combination2val
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_prod_combination INT NOT NULL,
|
||||||
|
fk_prod_attr INT NOT NULL,
|
||||||
|
fk_prod_attr_val INT NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE llx_product_attribute_value
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_product_attribute INT NOT NULL,
|
||||||
|
ref VARCHAR(255) DEFAULT NULL,
|
||||||
|
value VARCHAR(255) DEFAULT NULL,
|
||||||
|
entity INT DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
|
ALTER TABLE llx_product_attribute_value ADD CONSTRAINT unique_ref UNIQUE (fk_product_attribute,ref);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
-- ===================================================================
|
-- ============================================================================
|
||||||
-- Copyright (C) 2012 Laurent Destailleur <eldy@users.sourceforge.net>
|
-- Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
|
||||||
--
|
--
|
||||||
-- This program is free software; you can redistribute it and/or modify
|
-- 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
|
-- it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,6 +14,6 @@
|
|||||||
-- You should have received a copy of the GNU General Public License
|
-- You should have received a copy of the GNU General Public License
|
||||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
--
|
--
|
||||||
-- ===================================================================
|
-- ============================================================================
|
||||||
|
|
||||||
ALTER TABLE llx_holiday_events ADD UNIQUE INDEX uk_holiday_name (name, entity);
|
ALTER TABLE llx_product_attribute ADD CONSTRAINT unique_ref UNIQUE (ref);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
-- ===================================================================
|
-- ============================================================================
|
||||||
-- Copyright (C) 2012 Laurent Destailleur <eldy@users.sourceforge.net>
|
-- Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
|
||||||
--
|
--
|
||||||
-- This program is free software; you can redistribute it and/or modify
|
-- 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
|
-- it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,13 +14,13 @@
|
|||||||
-- You should have received a copy of the GNU General Public License
|
-- You should have received a copy of the GNU General Public License
|
||||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
--
|
--
|
||||||
-- ===================================================================
|
-- ============================================================================
|
||||||
|
|
||||||
CREATE TABLE llx_holiday_events
|
CREATE TABLE llx_product_attribute
|
||||||
(
|
(
|
||||||
rowid integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
entity integer DEFAULT 1 NOT NULL, -- multi company id
|
ref VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR( 255 ) NOT NULL,
|
label VARCHAR(255) NOT NULL,
|
||||||
value TEXT NOT NULL
|
rang INT DEFAULT 0 NOT NULL,
|
||||||
)
|
entity INT DEFAULT 1 NOT NULL
|
||||||
ENGINE=innodb;
|
);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Copyright (C) 2016 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_attribute_combination
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_product_parent INT NOT NULL,
|
||||||
|
fk_product_child INT NOT NULL,
|
||||||
|
variation_price FLOAT NOT NULL,
|
||||||
|
variation_price_percentage INT NULL,
|
||||||
|
variation_weight FLOAT NOT NULL,
|
||||||
|
entity INT DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Copyright (C) 2016 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_attribute_combination2val
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_prod_combination INT NOT NULL,
|
||||||
|
fk_prod_attr INT NOT NULL,
|
||||||
|
fk_prod_attr_val INT NOT NULL
|
||||||
|
);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Copyright (C) 2016 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_attribute_value ADD CONSTRAINT unique_ref UNIQUE (fk_product_attribute,ref);
|
||||||
26
htdocs/install/mysql/tables/llx_product_attribute_value.sql
Normal file
26
htdocs/install/mysql/tables/llx_product_attribute_value.sql
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Copyright (C) 2016 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_attribute_value
|
||||||
|
(
|
||||||
|
rowid INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||||
|
fk_product_attribute INT NOT NULL,
|
||||||
|
ref VARCHAR(255) DEFAULT NULL,
|
||||||
|
value VARCHAR(255) DEFAULT NULL,
|
||||||
|
entity INT DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
@@ -759,3 +759,5 @@ SearchIntoContracts=Contracts
|
|||||||
SearchIntoCustomerShipments=Customer shipments
|
SearchIntoCustomerShipments=Customer shipments
|
||||||
SearchIntoExpenseReports=Expense reports
|
SearchIntoExpenseReports=Expense reports
|
||||||
SearchIntoLeaves=Leaves
|
SearchIntoLeaves=Leaves
|
||||||
|
|
||||||
|
BulkActions=Bulk actions
|
||||||
@@ -137,6 +137,7 @@ ConfirmCloneProduct=Are you sure you want to clone product or service <b>%s</b>
|
|||||||
CloneContentProduct=Clone all main informations of product/service
|
CloneContentProduct=Clone all main informations of product/service
|
||||||
ClonePricesProduct=Clone main informations and prices
|
ClonePricesProduct=Clone main informations and prices
|
||||||
CloneCompositionProduct=Clone packaged product/service
|
CloneCompositionProduct=Clone packaged product/service
|
||||||
|
CloneCombinationsProduct=Clone product combinations
|
||||||
ProductIsUsed=This product is used
|
ProductIsUsed=This product is used
|
||||||
NewRefForClone=Ref. of new product/service
|
NewRefForClone=Ref. of new product/service
|
||||||
SellingPrices=Selling prices
|
SellingPrices=Selling prices
|
||||||
@@ -226,7 +227,7 @@ ComposedProduct=Sub-product
|
|||||||
MinSupplierPrice=Minimum supplier price
|
MinSupplierPrice=Minimum supplier price
|
||||||
MinCustomerPrice=Minimum customer price
|
MinCustomerPrice=Minimum customer price
|
||||||
DynamicPriceConfiguration=Dynamic price configuration
|
DynamicPriceConfiguration=Dynamic price configuration
|
||||||
DynamicPriceDesc=On product card, with this module enabled, you should be able to set mathematic functions to calculate Customer or Supplier prices. Such function can use all mathematic operators, some constants and variables. You can set here the variables you want to be able and if the variable need an automatic update, the external URL to use to ask Dolibarr to update automaticaly the value.
|
DynamicPriceDesc=On product card, with this module enabled, you should be able to set mathematic functions to calculate Customer or Supplier prices. Such function can use all mathematic operators, some constants and variables. You can set here the variables you want to be able and if the variable need an automatic update, the external URL to use to ask Dolibarr to update automaticaly the value.
|
||||||
AddVariable=Add Variable
|
AddVariable=Add Variable
|
||||||
AddUpdater=Add Updater
|
AddUpdater=Add Updater
|
||||||
GlobalVariables=Global variables
|
GlobalVariables=Global variables
|
||||||
@@ -254,3 +255,38 @@ SizeUnits=Size unit
|
|||||||
DeleteProductBuyPrice=Delete buying price
|
DeleteProductBuyPrice=Delete buying price
|
||||||
ConfirmDeleteProductBuyPrice=Are you sure you want to delete this buying price?
|
ConfirmDeleteProductBuyPrice=Are you sure you want to delete this buying price?
|
||||||
|
|
||||||
|
|
||||||
|
#Attributes
|
||||||
|
ProductAttributes=Product attributes
|
||||||
|
ProductAttributeName=Attribute %s
|
||||||
|
ProductAttribute=Attribute
|
||||||
|
ProductAttributeDeleteDialog=Are you sure you want to delete this attribute? All values will be deleted
|
||||||
|
ProductAttributeValueDeleteDialog=Are you sure you want to delete the value "%s" with reference "%s" of this attribute?
|
||||||
|
ProductCombinationDeleteDialog=Are you sure want to delete the combination of the product "%s"?
|
||||||
|
ProductCombinationAlreadyUsed=There was an error while deleting the combination. Please check it is not being used in any object
|
||||||
|
ProductCombinations=Combinations
|
||||||
|
HideProductCombinations=Hide derived products from combinations in the product selector
|
||||||
|
ProductCombination=Combination
|
||||||
|
NewProductCombination=New combination
|
||||||
|
EditProductCombination=Editing combination
|
||||||
|
ProductCombinationGenerator=Combinations generator
|
||||||
|
Features=Features
|
||||||
|
PriceImpact=Price impact
|
||||||
|
WeightImpact=Weight impact
|
||||||
|
NewProductAttribute=New attribute
|
||||||
|
NewProductAttributeValue=New attribute value
|
||||||
|
ErrorCreatingProductAttributeValue=There was an error while creating the attribute value. It could be because there is already an existing value with that reference
|
||||||
|
ProductCombinationGeneratorWarning=If you continue, before generating new combinations, all previous ones will be DELETED. Already existing ones will be updated with the new values
|
||||||
|
TooMuchCombinationsWarning=Generating lots of combinations may result in high CPU, memory usage and Dolibarr not able to create them. Enabling the option "%s" may help reduce memory usage.
|
||||||
|
DoNotRemovePreviousCombinations=Do not remove previous combinations
|
||||||
|
UsePercentageVariations=Use percentage variations
|
||||||
|
PercentageVariation=Percentage variation
|
||||||
|
ErrorDeletingGeneratedProducts=There was an error while trying to delete existing product combinations
|
||||||
|
NbProducts=No. of products
|
||||||
|
ParentProduct=Parent product
|
||||||
|
HideChildProducts=Hide child products
|
||||||
|
ConfirmCloneProductCombinations=Would you like to copy all the product combinations to the product with the given reference?
|
||||||
|
CloneDestinationReference=Destination product reference
|
||||||
|
ErrorCopyProductCombinations=There was an error while copying the product combinations
|
||||||
|
ErrorDestinationProductNotFound=Destination product not found
|
||||||
|
ErrorProductCombinationNotFound=Product combination not found
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
|
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
|
||||||
* Copyright (C) 2006 Auguria SARL <info@auguria.org>
|
* Copyright (C) 2006 Auguria SARL <info@auguria.org>
|
||||||
* Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2013-2014 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2013-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
* Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||||
* Copyright (C) 2011-2016 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
|
* Copyright (C) 2011-2016 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
|
||||||
* Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
|
* Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
|
||||||
@@ -1574,6 +1574,22 @@ else
|
|||||||
print dol_print_url($object->url);
|
print dol_print_url($object->url);
|
||||||
print '</td></tr>';
|
print '</td></tr>';
|
||||||
|
|
||||||
|
//Parent product.
|
||||||
|
if (!empty($conf->attributes->enabled) && $object->isProduct()) {
|
||||||
|
|
||||||
|
$combination = new ProductCombination($db);
|
||||||
|
|
||||||
|
if ($combination->fetchByFkProductChild($object->id) > 0) {
|
||||||
|
$prodstatic = new Product($db);
|
||||||
|
$prodstatic->fetch($combination->fk_product_parent);
|
||||||
|
|
||||||
|
// Parent product
|
||||||
|
print '<tr><td>'.$langs->trans("ParentProduct").'</td><td colspan="2">';
|
||||||
|
print $prodstatic->getNomUrl(1);
|
||||||
|
print '</td></tr>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print '</table>';
|
print '</table>';
|
||||||
print '</div>';
|
print '</div>';
|
||||||
print '<div class="fichehalfright"><div class="ficheaddleft">';
|
print '<div class="fichehalfright"><div class="ficheaddleft">';
|
||||||
|
|||||||
@@ -839,6 +839,17 @@ class Product extends CommonObject
|
|||||||
|
|
||||||
if (! $error)
|
if (! $error)
|
||||||
{
|
{
|
||||||
|
if ($conf->attributes->enabled) {
|
||||||
|
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
|
||||||
|
$comb = new ProductCombination($this->db);
|
||||||
|
|
||||||
|
foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
|
||||||
|
$currcomb->updateProperties($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->db->commit();
|
$this->db->commit();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -944,6 +955,25 @@ class Product extends CommonObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
|
||||||
|
//If it is a parent product, then we remove the association with child products
|
||||||
|
$prodcomb = new ProductCombination($this->db);
|
||||||
|
|
||||||
|
if ($prodcomb->deleteByFkProductParent($id) < 0) {
|
||||||
|
$error++;
|
||||||
|
$this->errors[] = 'Error deleting combinations';
|
||||||
|
}
|
||||||
|
|
||||||
|
//We also check if it is a child product
|
||||||
|
if (!$error && ($prodcomb->fetchByFkProductChild($id) > 0) && ($prodcomb->delete() < 0)) {
|
||||||
|
$error++;
|
||||||
|
$this->errors[] = 'Error deleting child combination';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Delete product
|
// Delete product
|
||||||
if (! $error)
|
if (! $error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
||||||
* Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
|
* Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||||
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
||||||
* Copyright (C) 2012-2013 Marcos García <marcosgdf@gmail.com>
|
* Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
|
||||||
* Copyright (C) 2013-2016 Juanjo Menent <jmenent@2byte.es>
|
* Copyright (C) 2013-2016 Juanjo Menent <jmenent@2byte.es>
|
||||||
* Copyright (C) 2013-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
* Copyright (C) 2013-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||||
* Copyright (C) 2013 Jean Heimburger <jean@tiaris.info>
|
* Copyright (C) 2013 Jean Heimburger <jean@tiaris.info>
|
||||||
@@ -50,7 +50,7 @@ $sref=GETPOST("sref");
|
|||||||
$sbarcode=GETPOST("sbarcode");
|
$sbarcode=GETPOST("sbarcode");
|
||||||
$snom=GETPOST("snom");
|
$snom=GETPOST("snom");
|
||||||
$sall=GETPOST("sall");
|
$sall=GETPOST("sall");
|
||||||
$type=GETPOST("type","int");
|
$type= (int) GETPOST("type","int");
|
||||||
$search_sale = GETPOST("search_sale");
|
$search_sale = GETPOST("search_sale");
|
||||||
$search_categ = GETPOST("search_categ",'int');
|
$search_categ = GETPOST("search_categ",'int');
|
||||||
$tosell = GETPOST("tosell", 'int');
|
$tosell = GETPOST("tosell", 'int');
|
||||||
@@ -62,6 +62,13 @@ $search_accountancy_code_sell = GETPOST("search_accountancy_code_sell",'alpha');
|
|||||||
$search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
|
$search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
|
||||||
$optioncss = GETPOST('optioncss','alpha');
|
$optioncss = GETPOST('optioncss','alpha');
|
||||||
|
|
||||||
|
//Show/hide child products. Hidden by default
|
||||||
|
if (!$_POST) {
|
||||||
|
$search_hidechildproducts = 'on';
|
||||||
|
} else {
|
||||||
|
$search_hidechildproducts = GETPOST('search_hidechildproducts');
|
||||||
|
}
|
||||||
|
|
||||||
$limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit;
|
$limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit;
|
||||||
$sortfield = GETPOST("sortfield",'alpha');
|
$sortfield = GETPOST("sortfield",'alpha');
|
||||||
$sortorder = GETPOST("sortorder",'alpha');
|
$sortorder = GETPOST("sortorder",'alpha');
|
||||||
@@ -170,7 +177,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actions
|
* Actions
|
||||||
*/
|
*/
|
||||||
@@ -230,6 +237,9 @@ else
|
|||||||
$sql.= ' p.datec as date_creation, p.tms as date_update,';
|
$sql.= ' p.datec as date_creation, p.tms as date_update,';
|
||||||
//$sql.= ' pfp.ref_fourn as ref_supplier, ';
|
//$sql.= ' pfp.ref_fourn as ref_supplier, ';
|
||||||
$sql.= ' MIN(pfp.unitprice) as minsellprice';
|
$sql.= ' MIN(pfp.unitprice) as minsellprice';
|
||||||
|
if (!empty($conf->attributes->enabled) && $search_hidechildproducts && ($type === 0)) {
|
||||||
|
$sql .= ', pac.rowid prod_comb_id';
|
||||||
|
}
|
||||||
// Add fields from extrafields
|
// Add fields from extrafields
|
||||||
foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
|
foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
|
||||||
// Add fields from hooks
|
// Add fields from hooks
|
||||||
@@ -242,6 +252,10 @@ else
|
|||||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
|
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
|
||||||
// multilang
|
// multilang
|
||||||
if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'";
|
if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'";
|
||||||
|
if (!empty($conf->attributes->enabled) && $search_hidechildproducts && ($type === 0)) {
|
||||||
|
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
|
||||||
|
}
|
||||||
|
|
||||||
$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
|
$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
|
||||||
if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
|
if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
|
||||||
// if the type is not 1, we show all products (type = 0,2,3)
|
// if the type is not 1, we show all products (type = 0,2,3)
|
||||||
@@ -265,6 +279,12 @@ else
|
|||||||
if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell);
|
if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell);
|
||||||
if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
|
if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
|
||||||
// Add where from extra fields
|
// Add where from extra fields
|
||||||
|
|
||||||
|
if (!empty($conf->attributes->enabled) && $search_hidechildproducts && ($type === 0)) {
|
||||||
|
$sql .= " AND pac.rowid IS NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add where from extra fields
|
||||||
foreach ($search_array_options as $key => $val)
|
foreach ($search_array_options as $key => $val)
|
||||||
{
|
{
|
||||||
$crit=$val;
|
$crit=$val;
|
||||||
@@ -284,6 +304,9 @@ else
|
|||||||
$sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
|
$sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
|
||||||
$sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
|
$sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
|
||||||
$sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy';
|
$sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy';
|
||||||
|
if (!empty($conf->attributes->enabled) && $search_hidechildproducts && ($type === 0)) {
|
||||||
|
$sql .= ', pac.rowid';
|
||||||
|
}
|
||||||
// Add fields from extrafields
|
// Add fields from extrafields
|
||||||
foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : '');
|
foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : '');
|
||||||
// Add fields from hooks
|
// Add fields from hooks
|
||||||
@@ -415,6 +438,15 @@ else
|
|||||||
$moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1);
|
$moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1);
|
||||||
$moreforfilter.='</div>';
|
$moreforfilter.='</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Show/hide child products. Hidden by default
|
||||||
|
if (!empty($conf->attributes->enabled) && $type === 0) {
|
||||||
|
$moreforfilter.='<div class="divsearchfield">';
|
||||||
|
$moreforfilter.= '<input type="checkbox" id="search_hidechildproducts" name="search_hidechildproducts" value="on"'.($search_hidechildproducts ? 'checked="checked"' : '').'>';
|
||||||
|
$moreforfilter.= ' <label for="search_hidechildproducts">'.$langs->trans('HideChildProducts').'</label>';
|
||||||
|
$moreforfilter.='</div>';
|
||||||
|
}
|
||||||
|
|
||||||
if ($moreforfilter)
|
if ($moreforfilter)
|
||||||
{
|
{
|
||||||
print '<div class="liste_titre liste_titre_bydiv centpercent">';
|
print '<div class="liste_titre liste_titre_bydiv centpercent">';
|
||||||
@@ -614,7 +646,7 @@ else
|
|||||||
$product_static->status_buy = $objp->tobuy;
|
$product_static->status_buy = $objp->tobuy;
|
||||||
$product_static->status = $objp->tosell;
|
$product_static->status = $objp->tosell;
|
||||||
$product_static->entity = $objp->entity;
|
$product_static->entity = $objp->entity;
|
||||||
|
|
||||||
if (! empty($conf->stock->enabled) && $user->rights->stock->lire && $type != 1) // To optimize call of load_stock
|
if (! empty($conf->stock->enabled) && $user->rights->stock->lire && $type != 1) // To optimize call of load_stock
|
||||||
{
|
{
|
||||||
if ($objp->fk_product_type != 1) // Not a service
|
if ($objp->fk_product_type != 1) // Not a service
|
||||||
@@ -622,8 +654,8 @@ else
|
|||||||
$product_static->load_stock('nobatch'); // Load stock_reel + stock_warehouse. This also call load_virtual_stock()
|
$product_static->load_stock('nobatch'); // Load stock_reel + stock_warehouse. This also call load_virtual_stock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$var=!$var;
|
$var=!$var;
|
||||||
print '<tr '.$bc[$var].'>';
|
print '<tr '.$bc[$var].'>';
|
||||||
|
|
||||||
@@ -752,7 +784,7 @@ else
|
|||||||
print '<td align="center">';
|
print '<td align="center">';
|
||||||
print yn($objp->tobatch);
|
print yn($objp->tobatch);
|
||||||
print '</td>';
|
print '</td>';
|
||||||
}
|
}
|
||||||
// Accountancy code sell
|
// Accountancy code sell
|
||||||
if (! empty($arrayfields['p.accountancy_code_sell']['checked'])) print '<td>'.$objp->accountancy_code_sell.'</td>';
|
if (! empty($arrayfields['p.accountancy_code_sell']['checked'])) print '<td>'.$objp->accountancy_code_sell.'</td>';
|
||||||
// Accountancy code sell
|
// Accountancy code sell
|
||||||
|
|||||||
Reference in New Issue
Block a user