Merge pull request #5533 from marcosgdf/prod-attr
Feature Request: NEW Added product attributes feature
This commit is contained in:
commit
b24f244f67
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();
|
||||||
321
htdocs/attributes/class/ProductAttribute.class.php
Normal file
321
htdocs/attributes/class/ProductAttribute.class.php
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
<?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
|
||||||
|
* Used to represent a product attribute
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
225
htdocs/attributes/class/ProductAttributeValue.class.php
Normal file
225
htdocs/attributes/class/ProductAttributeValue.class.php
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
<?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
|
||||||
|
* Used to represent a product attribute value
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
645
htdocs/attributes/class/ProductCombination.class.php
Normal file
645
htdocs/attributes/class/ProductCombination.class.php
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
<?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
|
||||||
|
* Used to represent a product combination
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
155
htdocs/attributes/class/ProductCombination2ValuePair.class.php
Normal file
155
htdocs/attributes/class/ProductCombination2ValuePair.class.php
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<?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
|
||||||
|
* Used to represent the relation between a product combination, a product attribute and a product attribute value
|
||||||
|
*/
|
||||||
|
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
|
||||||
@ -50,6 +51,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');
|
||||||
@ -682,7 +687,8 @@ if (empty($reshook))
|
|||||||
$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');
|
||||||
$price_ht_devise = GETPOST('multicurrency_price_ht');
|
$price_ht_devise = GETPOST('multicurrency_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);
|
||||||
@ -708,21 +714,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 == '' && $price_ht_devise == '') // Unit price can be 0 but not ''. Also price can be negative for proposal.
|
if ($prod_entry_mode == 'free' && empty($idprod) && $price_ht == '' && $price_ht_devise == '') // 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');
|
||||||
@ -640,7 +644,8 @@ if (empty($reshook))
|
|||||||
$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');
|
||||||
$price_ht_devise = GETPOST('multicurrency_price_ht');
|
$price_ht_devise = GETPOST('multicurrency_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);
|
||||||
@ -670,11 +675,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 == '') && (! ($price_ht_devise >= 0) || $price_ht_devise == '')) // Unit price can be 0 but not ''
|
if ($prod_entry_mode == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '') && (! ($price_ht_devise >= 0) || $price_ht_devise == '')) // 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++;
|
||||||
@ -683,11 +688,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');
|
||||||
@ -1362,7 +1366,8 @@ if (empty($reshook))
|
|||||||
$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');
|
||||||
$price_ht_devise = GETPOST('multicurrency_price_ht');
|
$price_ht_devise = GETPOST('multicurrency_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);
|
||||||
@ -1392,7 +1397,7 @@ 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'))
|
if (!$prod_entry_mode)
|
||||||
{
|
{
|
||||||
if (GETPOST('type') < 0 && ! GETPOST('search_idprod'))
|
if (GETPOST('type') < 0 && ! GETPOST('search_idprod'))
|
||||||
{
|
{
|
||||||
@ -1400,11 +1405,11 @@ if (empty($reshook))
|
|||||||
$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 == '') && $price_ht_devise == '') // Unit price can be 0 but not ''
|
if ($prod_entry_mode == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '') && $price_ht_devise == '') // 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 ++;
|
||||||
@ -1413,7 +1418,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 ++;
|
||||||
}
|
}
|
||||||
@ -1422,7 +1427,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
|
||||||
|
|||||||
@ -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>
|
||||||
@ -1644,9 +1644,10 @@ class Form
|
|||||||
* 'warehouseopen' = select products from open warehouses,
|
* 'warehouseopen' = select products from open warehouses,
|
||||||
* 'warehouseclosed' = select products from closed warehouses,
|
* 'warehouseclosed' = select products from closed warehouses,
|
||||||
* 'warehouseinternal' = select products from warehouses for internal correct/transfer only
|
* 'warehouseinternal' = select products from warehouses for internal correct/transfer only
|
||||||
|
* @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, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='')
|
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, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations = array())
|
||||||
{
|
{
|
||||||
global $langs,$conf;
|
global $langs,$conf;
|
||||||
|
|
||||||
@ -1671,6 +1672,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").'"';
|
||||||
@ -1785,11 +1860,21 @@ 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 (count($warehouseStatusArray))
|
if (count($warehouseStatusArray))
|
||||||
{
|
{
|
||||||
$sql.= ' AND (p.fk_product_type = 1 OR e.statut IN ('.implode(',',$warehouseStatusArray).'))';
|
$sql.= ' AND (p.fk_product_type = 1 OR e.statut IN ('.implode(',',$warehouseStatusArray).'))';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|||||||
@ -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>
|
||||||
*
|
*
|
||||||
@ -2084,4 +2084,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
|
||||||
@ -94,6 +94,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)
|
||||||
|
|||||||
137
htdocs/core/modules/modAttributes.class.php
Normal file
137
htdocs/core/modules/modAttributes.class.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
||||||
|
* Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||||
|
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup produit Module product attributes
|
||||||
|
* \brief Module to manage product combinations based on product attributes
|
||||||
|
* \file htdocs/core/modules/modAttributes.class.php
|
||||||
|
* \ingroup produit
|
||||||
|
* \brief File to describe module to manage catalog of predefined products
|
||||||
|
*/
|
||||||
|
include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description and activation class for module Product attributes
|
||||||
|
*/
|
||||||
|
class modAttributes extends DolibarrModules
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor. Define names, constants, directories, boxes, permissions
|
||||||
|
*
|
||||||
|
* @param DoliDB $db Database handler
|
||||||
|
*/
|
||||||
|
public function __construct($db)
|
||||||
|
{
|
||||||
|
global $langs,$conf;
|
||||||
|
|
||||||
|
$this->db = $db;
|
||||||
|
|
||||||
|
// Id for module (must be unique).
|
||||||
|
// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
|
||||||
|
$this->numero = 610;
|
||||||
|
// Key text used to identify module (for permissions, menus, etc...)
|
||||||
|
$this->rights_class = 'attributes';
|
||||||
|
|
||||||
|
// Family can be 'crm','financial','hr','projects','products','ecm','technic','other'
|
||||||
|
// It is used to group modules in module setup page
|
||||||
|
$this->family = "products";
|
||||||
|
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
|
||||||
|
$this->name = preg_replace('/^mod/i','',get_class($this));
|
||||||
|
// Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
|
||||||
|
$this->description = 'Allows creating product combinations based on product attributes';
|
||||||
|
// Possible values for version are: 'development', 'experimental', 'dolibarr' or version
|
||||||
|
$this->version = 'dolibarr';
|
||||||
|
// Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase)
|
||||||
|
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
|
||||||
|
// Where to store the module in setup page (0=common,1=interface,2=others,3=very specific)
|
||||||
|
$this->special = 0;
|
||||||
|
// Name of image file used for this module.
|
||||||
|
// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
|
||||||
|
// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
|
||||||
|
$this->picto='product';
|
||||||
|
|
||||||
|
// Defined all module parts (triggers, login, substitutions, menus, css, etc...)
|
||||||
|
$this->module_parts = array();
|
||||||
|
|
||||||
|
// Data directories to create when module is enabled.
|
||||||
|
// Example: this->dirs = array("/mymodule/temp");
|
||||||
|
$this->dirs = array();
|
||||||
|
|
||||||
|
// Config pages. Put here list of php page, stored into mymodule/admin directory, to use to setup module.
|
||||||
|
$this->config_page_url = array(
|
||||||
|
'admin.php@attributes'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
$this->hidden = false; // A condition to hide module
|
||||||
|
$this->depends = array(
|
||||||
|
'modProduct'
|
||||||
|
); // List of modules id that must be enabled if this module is enabled
|
||||||
|
$this->requiredby = array(); // List of modules id to disable if this one is disabled
|
||||||
|
$this->conflictwith = array(); // List of modules id this module is in conflict with
|
||||||
|
$this->phpmin = array(5,0); // Minimum version of PHP required by module
|
||||||
|
$this->need_dolibarr_version = array(3,0); // Minimum version of Dolibarr required by module
|
||||||
|
$this->langfiles = array("products");
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
$this->const = array();
|
||||||
|
|
||||||
|
// Array to add new pages in new tabs
|
||||||
|
$this->tabs = array(
|
||||||
|
// 'product:+combinations:Combinaciones:products:1:/attributes/combinations.php?id=__ID__'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dictionaries
|
||||||
|
if (! isset($conf->mymodule->enabled))
|
||||||
|
{
|
||||||
|
$conf->mymodule=new stdClass();
|
||||||
|
$conf->mymodule->enabled=0;
|
||||||
|
}
|
||||||
|
$this->dictionaries=array();
|
||||||
|
|
||||||
|
// Boxes
|
||||||
|
// Add here list of php file(s) stored in core/boxes that contains class to show a box.
|
||||||
|
$this->boxes = array(); // List of boxes
|
||||||
|
|
||||||
|
// Permissions
|
||||||
|
$this->rights = array(); // Permission array used by this module
|
||||||
|
|
||||||
|
// Main menu entries
|
||||||
|
$this->menu = array(
|
||||||
|
array(
|
||||||
|
'fk_menu' => 'fk_mainmenu=products,fk_leftmenu=product',
|
||||||
|
'type' => 'left',
|
||||||
|
'titre' => $langs->trans('Attributes'),
|
||||||
|
'mainmenu' => 'products',
|
||||||
|
'leftmenu' => 'product',
|
||||||
|
'url' => '/attributes/list.php',
|
||||||
|
'langs' => 'products',
|
||||||
|
'position' => 100,
|
||||||
|
'enabled' => '$conf->product->enabled',
|
||||||
|
'perms' => 1,
|
||||||
|
'target' => '',
|
||||||
|
'user' => 0
|
||||||
|
)
|
||||||
|
); // List of menus to add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -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
|
||||||
@ -57,6 +57,7 @@ $nolinesbefore=(count($this->lines) == 0);
|
|||||||
if ($nolinesbefore) {
|
if ($nolinesbefore) {
|
||||||
?>
|
?>
|
||||||
<tr class="liste_titre<?php echo (($nolinesbefore || $object->element=='contrat')?'':' liste_titre_add') ?> nodrag nodrop">
|
<tr class="liste_titre<?php echo (($nolinesbefore || $object->element=='contrat')?'':' 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>
|
||||||
@ -191,11 +192,11 @@ else {
|
|||||||
if ($conf->global->ENTREPOT_EXTRA_STATUS)
|
if ($conf->global->ENTREPOT_EXTRA_STATUS)
|
||||||
{
|
{
|
||||||
// hide products in closed warehouse, but show products for internal transfer
|
// hide products in closed warehouse, but show products for internal transfer
|
||||||
$form->select_produits(GETPOST('idprod'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, 1, 2, '', 1, array(),$buyer->id, '1', 0, '', 0, 'warehouseopen,warehouseinternal');
|
$form->select_produits(GETPOST('idprod'), 'idprod', $filtertype, $conf->product->limit_size, $buyer->price_level, 1, 2, '', 1, array(),$buyer->id, '1', 0, '', 0, 'warehouseopen,warehouseinternal', GETPOST('combinations', 'array'));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$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, '1', 0, '', 0, '', GETPOST('combinations', 'array'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -237,7 +238,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';
|
||||||
@ -701,8 +709,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("#multicurrency_price_ht").show();
|
jQuery("#multicurrency_price_ht").show();
|
||||||
jQuery("#price_ttc").show(); // May no exists
|
jQuery("#price_ttc").show(); // May no exists
|
||||||
@ -721,8 +729,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("#multicurrency_price_ht").hide();
|
jQuery("#multicurrency_price_ht").hide();
|
||||||
jQuery("#price_ttc").hide(); // May no exists
|
jQuery("#price_ttc").hide(); // May no exists
|
||||||
|
|||||||
@ -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');
|
||||||
@ -284,7 +288,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')==='' && $price_ht_devise === '') // Unit price can be 0 but not ''
|
if ($prod_entry_mode =='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='' && $price_ht_devise === '') // 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);
|
||||||
|
|
||||||
@ -2718,9 +2736,7 @@ elseif (! empty($object->id))
|
|||||||
print '</form>';
|
print '</form>';
|
||||||
print "<br>";
|
print "<br>";
|
||||||
}
|
}
|
||||||
|
if ($action != 'makeorder')
|
||||||
|
|
||||||
if ($action != 'makeorder')
|
|
||||||
{
|
{
|
||||||
print '<div class="fichecenter"><div class="fichehalfleft">';
|
print '<div class="fichecenter"><div class="fichehalfleft">';
|
||||||
|
|
||||||
@ -2743,48 +2759,48 @@ elseif (! empty($object->id))
|
|||||||
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
|
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
|
||||||
|
|
||||||
print '</div><div class="fichehalfright"><div class="ficheaddleft">';
|
print '</div><div class="fichehalfright"><div class="ficheaddleft">';
|
||||||
|
if ($user->rights->fournisseur->commande->receptionner && ($object->statut == 3 || $object->statut == 4))
|
||||||
|
{
|
||||||
|
// Set status to received (action=livraison)
|
||||||
|
print '<!-- form to record supplier order received -->'."\n";
|
||||||
|
print '<form action="card.php?id='.$object->id.'" method="post">';
|
||||||
|
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||||
|
print '<input type="hidden" name="action" value="livraison">';
|
||||||
|
print load_fiche_titre($langs->trans("Receive"),'','');
|
||||||
|
|
||||||
|
print '<table class="noborder" width="100%">';
|
||||||
|
//print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Receive").'</td></tr>';
|
||||||
|
print '<tr><td>'.$langs->trans("DeliveryDate").'</td><td>';
|
||||||
|
print $form->select_date('','',1,1,'',"commande",1,0,1);
|
||||||
|
print "</td></tr>\n";
|
||||||
|
|
||||||
if ($user->rights->fournisseur->commande->receptionner && ($object->statut == 3 || $object->statut == 4))
|
print "<tr><td>".$langs->trans("Delivery")."</td><td>\n";
|
||||||
{
|
$liv = array();
|
||||||
// Set status to received (action=livraison)
|
$liv[''] = ' ';
|
||||||
print '<!-- form to record supplier order received -->'."\n";
|
$liv['tot'] = $langs->trans("CompleteOrNoMoreReceptionExpected");
|
||||||
print '<form action="card.php?id='.$object->id.'" method="post">';
|
$liv['par'] = $langs->trans("PartialWoman");
|
||||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
$liv['nev'] = $langs->trans("NeverReceived");
|
||||||
print '<input type="hidden" name="action" value="livraison">';
|
$liv['can'] = $langs->trans("Canceled");
|
||||||
print load_fiche_titre($langs->trans("Receive"),'','');
|
|
||||||
|
|
||||||
print '<table class="noborder" width="100%">';
|
print $form->selectarray("type",$liv);
|
||||||
//print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Receive").'</td></tr>';
|
|
||||||
print '<tr><td>'.$langs->trans("DeliveryDate").'</td><td>';
|
|
||||||
print $form->select_date('','',1,1,'',"commande",1,0,1);
|
|
||||||
print "</td></tr>\n";
|
|
||||||
|
|
||||||
print "<tr><td>".$langs->trans("Delivery")."</td><td>\n";
|
print '</td></tr>';
|
||||||
$liv = array();
|
print '<tr><td>'.$langs->trans("Comment").'</td><td><input size="40" type="text" name="comment"></td></tr>';
|
||||||
$liv[''] = ' ';
|
print '<tr><td align="center" colspan="2"><input type="submit" class="button" value="'.$langs->trans("Receive").'"></td></tr>';
|
||||||
$liv['tot'] = $langs->trans("CompleteOrNoMoreReceptionExpected");
|
print "</table>\n";
|
||||||
$liv['par'] = $langs->trans("PartialWoman");
|
print "</form>\n";
|
||||||
$liv['nev'] = $langs->trans("NeverReceived");
|
print "<br>";
|
||||||
$liv['can'] = $langs->trans("Canceled");
|
|
||||||
|
|
||||||
print $form->selectarray("type",$liv);
|
|
||||||
|
|
||||||
print '</td></tr>';
|
|
||||||
print '<tr><td>'.$langs->trans("Comment").'</td><td><input size="40" type="text" name="comment"></td></tr>';
|
|
||||||
print '<tr><td align="center" colspan="2"><input type="submit" class="button" value="'.$langs->trans("Receive").'"></td></tr>';
|
|
||||||
print "</table>\n";
|
|
||||||
print "</form>\n";
|
|
||||||
print "<br>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of actions on element
|
|
||||||
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
|
|
||||||
$formactions=new FormActions($db);
|
|
||||||
$somethingshown=$formactions->showactions($object,'order_supplier',$socid,0,'listaction'.($genallowed?'largetitle':''));
|
|
||||||
|
|
||||||
print '</div></div></div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List of actions on element
|
||||||
|
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
|
||||||
|
$formactions=new FormActions($db);
|
||||||
|
$somethingshown=$formactions->showactions($object,'order_supplier',$socid,0,'listaction'.($genallowed?'largetitle':''));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print '</div></div></div>';}
|
||||||
}
|
}
|
||||||
|
|
||||||
print '</td></tr></table>';
|
print '</td></tr></table>';
|
||||||
|
|||||||
@ -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>
|
||||||
* Copyright (C) 2016 Alexandre Spangaro <aspangaro@zendsi.com>
|
* Copyright (C) 2016 Alexandre Spangaro <aspangaro@zendsi.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
|
||||||
@ -46,6 +46,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');
|
||||||
@ -878,7 +882,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');
|
||||||
@ -910,22 +915,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')==='' && $price_ht_devise==='') // Unit price can be 0 but not ''
|
if ($prod_entry_mode =='free' && GETPOST('price_ht')==='' && GETPOST('price_ttc')==='' && $price_ht_devise==='') // 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++;
|
||||||
@ -936,7 +941,21 @@ if (empty($reshook))
|
|||||||
$error++;
|
$error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GETPOST('prod_entry_mode') != 'free' && empty($error)) // 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' && empty($error)) // 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);
|
||||||
|
|||||||
@ -250,3 +250,40 @@ ALTER TABLE llx_projet_task ADD UNIQUE INDEX uk_projet_task_ref (ref, entity);
|
|||||||
|
|
||||||
ALTER TABLE llx_contrat ADD COLUMN fk_user_modif integer;
|
ALTER TABLE llx_contrat ADD COLUMN fk_user_modif integer;
|
||||||
|
|
||||||
|
|
||||||
|
-- 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);
|
||||||
19
htdocs/install/mysql/tables/llx_product_attribute.key.sql
Normal file
19
htdocs/install/mysql/tables/llx_product_attribute.key.sql
Normal file
@ -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 ADD CONSTRAINT unique_ref UNIQUE (ref);
|
||||||
26
htdocs/install/mysql/tables/llx_product_attribute.sql
Normal file
26
htdocs/install/mysql/tables/llx_product_attribute.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
|
||||||
|
(
|
||||||
|
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
|
||||||
|
);
|
||||||
@ -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
|
||||||
|
);
|
||||||
@ -812,3 +812,5 @@ SearchIntoContracts=Contracts
|
|||||||
SearchIntoCustomerShipments=Customer shipments
|
SearchIntoCustomerShipments=Customer shipments
|
||||||
SearchIntoExpenseReports=Expense reports
|
SearchIntoExpenseReports=Expense reports
|
||||||
SearchIntoLeaves=Leaves
|
SearchIntoLeaves=Leaves
|
||||||
|
|
||||||
|
BulkActions=Bulk actions
|
||||||
@ -142,6 +142,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
|
||||||
@ -259,3 +260,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?
|
||||||
SubProduct=Sub product
|
SubProduct=Sub product
|
||||||
|
|
||||||
|
#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>
|
||||||
@ -1603,6 +1603,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">';
|
||||||
|
|||||||
@ -960,6 +960,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;
|
||||||
}
|
}
|
||||||
@ -1081,6 +1092,26 @@ class Product extends CommonObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination.class.php';
|
||||||
|
require_once DOL_DOCUMENT_ROOT.'/attributes/class/ProductCombination2ValuePair.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');
|
||||||
@ -242,6 +249,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
|
||||||
@ -254,6 +264,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)
|
||||||
@ -277,6 +291,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;
|
||||||
@ -296,6 +316,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
|
||||||
@ -426,6 +449,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">';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user