Merge pull request #18554 from atm-adrien/NEW_develop_virtual_product_DragAndDrop
NEW : Allow drag and drop on kits
This commit is contained in:
commit
9951ea8310
@ -99,6 +99,8 @@ if (GETPOST('roworder', 'alpha', 3) && GETPOST('table_element_line', 'aZ09', 3)
|
|||||||
$perm = 1;
|
$perm = 1;
|
||||||
} elseif ($table_element_line == 'ecm_files' && $fk_element == 'fk_ticket' && !empty($user->rights->ticket->write)) {
|
} elseif ($table_element_line == 'ecm_files' && $fk_element == 'fk_ticket' && !empty($user->rights->ticket->write)) {
|
||||||
$perm = 1;
|
$perm = 1;
|
||||||
|
} elseif ($table_element_line == 'product_association' && $fk_element == 'fk_product' && !empty($user->rights->produit->creer)) {
|
||||||
|
$perm = 1;
|
||||||
} elseif ($table_element_line == 'projet_task' && $fk_element == 'fk_projet' && $user->rights->projet->creer) {
|
} elseif ($table_element_line == 'projet_task' && $fk_element == 'fk_projet' && $user->rights->projet->creer) {
|
||||||
$perm = 1;
|
$perm = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -3038,7 +3038,7 @@ abstract class CommonObject
|
|||||||
*
|
*
|
||||||
* @param int $rowid Id of line
|
* @param int $rowid Id of line
|
||||||
* @param int $rang Position
|
* @param int $rang Position
|
||||||
* @return void
|
* @return int <0 if KO, >0 if OK
|
||||||
*/
|
*/
|
||||||
public function updateRangOfLine($rowid, $rang)
|
public function updateRangOfLine($rowid, $rang)
|
||||||
{
|
{
|
||||||
@ -3054,10 +3054,13 @@ abstract class CommonObject
|
|||||||
dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
|
dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
|
||||||
if (!$this->db->query($sql)) {
|
if (!$this->db->query($sql)) {
|
||||||
dol_print_error($this->db);
|
dol_print_error($this->db);
|
||||||
}
|
return -1;
|
||||||
|
} else {
|
||||||
$parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
|
$parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
|
||||||
$action='';
|
$action='';
|
||||||
$reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
|
$reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||||
|
|||||||
@ -103,6 +103,7 @@ ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_categorie_ro
|
|||||||
ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_ticket_rowid FOREIGN KEY (fk_ticket) REFERENCES llx_ticket (rowid);
|
ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_ticket_rowid FOREIGN KEY (fk_ticket) REFERENCES llx_ticket (rowid);
|
||||||
ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN ref_fourn varchar(128);
|
ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN ref_fourn varchar(128);
|
||||||
ALTER TABLE llx_product_customer_price MODIFY COLUMN ref_customer varchar(128);
|
ALTER TABLE llx_product_customer_price MODIFY COLUMN ref_customer varchar(128);
|
||||||
|
ALTER TABLE llx_product_association ADD COLUMN rang integer DEFAULT 0;
|
||||||
|
|
||||||
-- -- add action trigger
|
-- -- add action trigger
|
||||||
INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) VALUES ('ORDER_SUPPLIER_CANCEL','Supplier order request canceled','Executed when a supplier order is canceled','order_supplier',13);
|
INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) VALUES ('ORDER_SUPPLIER_CANCEL','Supplier order request canceled','Executed when a supplier order is canceled','order_supplier',13);
|
||||||
|
|||||||
@ -23,6 +23,7 @@ create table llx_product_association
|
|||||||
fk_product_pere integer NOT NULL DEFAULT 0, -- id du produit maitre
|
fk_product_pere integer NOT NULL DEFAULT 0, -- id du produit maitre
|
||||||
fk_product_fils integer NOT NULL DEFAULT 0, -- id du sous-produit
|
fk_product_fils integer NOT NULL DEFAULT 0, -- id du sous-produit
|
||||||
qty double NULL,
|
qty double NULL,
|
||||||
incdec integer DEFAULT 1 -- when set to 1 changing stock of product will change stock of linked product too
|
incdec integer DEFAULT 1, -- when set to 1 changing stock of product will change stock of linked product too
|
||||||
|
rang integer DEFAULT 0
|
||||||
)ENGINE=innodb;
|
)ENGINE=innodb;
|
||||||
|
|
||||||
|
|||||||
@ -401,11 +401,10 @@ DeleteLinkedProduct=Delete the child product linked to the combination
|
|||||||
AmountUsedToUpdateWAP=Amount to use to update the Weighted Average Price
|
AmountUsedToUpdateWAP=Amount to use to update the Weighted Average Price
|
||||||
PMPValue=Weighted average price
|
PMPValue=Weighted average price
|
||||||
PMPValueShort=WAP
|
PMPValueShort=WAP
|
||||||
|
|
||||||
mandatoryperiod=Mandatory periods
|
mandatoryperiod=Mandatory periods
|
||||||
mandatoryPeriodNeedTobeSet=Attention periods not entered and mandatory
|
mandatoryPeriodNeedTobeSet=Attention periods not entered and mandatory
|
||||||
mandatoryPeriodNeedTobeSetMsgValidate=A service requires a start and end period
|
mandatoryPeriodNeedTobeSetMsgValidate=A service requires a start and end period
|
||||||
mandatoryHelper=Message to the user on the need to enter a start date and an end date on a service when creating / validating an invoice, commercial proposal, sales order. <br> This action is not blocking in the process of confirmation
|
mandatoryHelper=Message to the user on the need to enter a start date and an end date on a service when creating / validating an invoice, commercial proposal, sales order. <br> This action is not blocking in the process of confirmation
|
||||||
DefaultBOM=Default BOM
|
DefaultBOM=Default BOM
|
||||||
DefaultBOMDesc=The default BOM recommended to use to manufacture this product. This field can be set only if nature of product is '%s'.
|
DefaultBOMDesc=The default BOM recommended to use to manufacture this product. This field can be set only if nature of product is '%s'.
|
||||||
|
Rank=Rank
|
||||||
|
|||||||
@ -399,6 +399,7 @@ ProductSupplierExtraFields=Attributs supplémentaires (Prix fournisseur)
|
|||||||
DeleteLinkedProduct=Supprimer le produit enfant lié à la combinaison
|
DeleteLinkedProduct=Supprimer le produit enfant lié à la combinaison
|
||||||
PMPValue=Prix moyen pondéré (PMP)
|
PMPValue=Prix moyen pondéré (PMP)
|
||||||
PMPValueShort=PMP
|
PMPValueShort=PMP
|
||||||
|
Rank=Rang
|
||||||
mandatoryperiod=Périodes obligatoires
|
mandatoryperiod=Périodes obligatoires
|
||||||
mandatoryPeriodNeedTobeSet=Attention périodes non saisies et obligatoires
|
mandatoryPeriodNeedTobeSet=Attention périodes non saisies et obligatoires
|
||||||
mandatoryPeriodNeedTobeSetMsgValidate=Un service nécessite une période de début et de fin
|
mandatoryPeriodNeedTobeSetMsgValidate=Un service nécessite une période de début et de fin
|
||||||
|
|||||||
@ -4021,28 +4021,31 @@ class Product extends CommonObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check not already father of id_pere (to avoid father -> child -> father links)
|
// Check not already father of id_pere (to avoid father -> child -> father links)
|
||||||
$sql = 'SELECT fk_product_pere from '.MAIN_DB_PREFIX.'product_association';
|
$sql = "SELECT fk_product_pere from ".MAIN_DB_PREFIX."product_association";
|
||||||
$sql .= ' WHERE fk_product_pere = '.((int) $id_fils).' AND fk_product_fils = '.((int) $id_pere);
|
$sql .= " WHERE fk_product_pere = ".((int) $id_fils)." AND fk_product_fils = ".((int) $id_pere);
|
||||||
if (!$this->db->query($sql)) {
|
if (!$this->db->query($sql)) {
|
||||||
dol_print_error($this->db);
|
dol_print_error($this->db);
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
$result = $this->db->query($sql);
|
//Selection of the highest row
|
||||||
if ($result) {
|
$sql = "SELECT MAX(rang) as max_rank FROM ".MAIN_DB_PREFIX."product_association";
|
||||||
$num = $this->db->num_rows($result);
|
$sql .= " WHERE fk_product_pere = ".((int) $id_pere);
|
||||||
if ($num > 0) {
|
$resql = $this->db->query($sql);
|
||||||
$this->error = "isFatherOfThis";
|
if ($resql > 0) {
|
||||||
return -1;
|
$obj = $this->db->fetch_object($resql);
|
||||||
} else {
|
$rank = $obj->max_rank + 1;
|
||||||
$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_association(fk_product_pere,fk_product_fils,qty,incdec)';
|
//Addition of a product with the highest rank +1
|
||||||
$sql .= ' VALUES ('.((int) $id_pere).', '.((int) $id_fils).', '.((float) $qty).', '.((int) $incdec).')';
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
|
||||||
|
$sql .= " VALUES (".((int) $id_pere).", ".((int) $id_fils).", ".((float) $qty).", ".((float) $incdec).", ".$this->db->escape($rank).")";
|
||||||
if (! $this->db->query($sql)) {
|
if (! $this->db->query($sql)) {
|
||||||
dol_print_error($this->db);
|
dol_print_error($this->db);
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
dol_print_error($this->db);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4115,6 +4118,24 @@ class Product extends CommonObject
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Updated ranks so that none are missing
|
||||||
|
$sqlrank = 'SELECT rowid, rang FROM '.MAIN_DB_PREFIX.'product_association';
|
||||||
|
$sqlrank.= ' WHERE fk_product_pere = '.$this->db->escape($fk_parent);
|
||||||
|
$sqlrank.= ' ORDER BY rang';
|
||||||
|
$resqlrank = $this->db->query($sqlrank);
|
||||||
|
if ($resqlrank) {
|
||||||
|
$cpt = 0;
|
||||||
|
while ($objrank = $this->db->fetch_object($resqlrank)) {
|
||||||
|
$cpt++;
|
||||||
|
$sql = 'UPDATE '.MAIN_DB_PREFIX.'product_association';
|
||||||
|
$sql.= ' SET rang ='.$cpt;
|
||||||
|
$sql.= ' WHERE rowid ='.$this->db->escape($objrank->rowid);
|
||||||
|
if (! $this->db->query($sql)) {
|
||||||
|
dol_print_error($this->db);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4679,12 +4700,14 @@ class Product extends CommonObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
|
$sql = "SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
|
||||||
$sql .= " pa.qty as qty, pa.fk_product_fils as id, pa.incdec";
|
$sql .= " pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
|
||||||
|
$sql .= " pa.rowid as fk_association, pa.rang";
|
||||||
$sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
|
$sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
|
||||||
$sql .= " ".MAIN_DB_PREFIX."product_association as pa";
|
$sql .= " ".MAIN_DB_PREFIX."product_association as pa";
|
||||||
$sql .= " WHERE p.rowid = pa.fk_product_fils";
|
$sql .= " WHERE p.rowid = pa.fk_product_fils";
|
||||||
$sql .= " AND pa.fk_product_pere = ".((int) $id);
|
$sql .= " AND pa.fk_product_pere = ".((int) $id);
|
||||||
$sql .= " AND pa.fk_product_fils <> ".((int) $id); // This should not happens, it is to avoid infinite loop if it happens
|
$sql .= " AND pa.fk_product_fils <> ".((int) $id); // This should not happens, it is to avoid infinite loop if it happens
|
||||||
|
$sql.= " ORDER BY pa.rang";
|
||||||
|
|
||||||
dol_syslog(get_class($this).'::getChildsArbo id='.$id.' level='.$level, LOG_DEBUG);
|
dol_syslog(get_class($this).'::getChildsArbo id='.$id.' level='.$level, LOG_DEBUG);
|
||||||
|
|
||||||
@ -4711,7 +4734,9 @@ class Product extends CommonObject
|
|||||||
2=>$rec['fk_product_type'],
|
2=>$rec['fk_product_type'],
|
||||||
3=>$this->db->escape($rec['label']),
|
3=>$this->db->escape($rec['label']),
|
||||||
4=>$rec['incdec'],
|
4=>$rec['incdec'],
|
||||||
5=>$rec['ref']
|
5=>$rec['ref'],
|
||||||
|
6=>$rec['fk_association'],
|
||||||
|
7=>$rec['rang']
|
||||||
);
|
);
|
||||||
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty'],2=>$rec['fk_product_type']);
|
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty'],2=>$rec['fk_product_type']);
|
||||||
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty']);
|
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty']);
|
||||||
|
|||||||
@ -132,6 +132,8 @@ if ($action == 'add_prod' && ($user->rights->produit->creer || $user->rights->se
|
|||||||
setEventMessages('RecordSaved', null);
|
setEventMessages('RecordSaved', null);
|
||||||
}
|
}
|
||||||
$action = '';
|
$action = '';
|
||||||
|
header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,8 +270,18 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
|
|
||||||
$prodsfather = $object->getFather(); // Parent Products
|
$prodsfather = $object->getFather(); // Parent Products
|
||||||
$object->get_sousproduits_arbo(); // Load $object->sousprods
|
$object->get_sousproduits_arbo(); // Load $object->sousprods
|
||||||
|
$parent_label = $object->label;
|
||||||
$prods_arbo = $object->get_arbo_each_prod();
|
$prods_arbo = $object->get_arbo_each_prod();
|
||||||
|
|
||||||
|
$tmpid = $id;
|
||||||
|
if (! empty($conf->use_javascript_ajax)) {
|
||||||
|
$nboflines = $prods_arbo;
|
||||||
|
$table_element_line='product_association';
|
||||||
|
|
||||||
|
include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
|
||||||
|
}
|
||||||
|
$id = $tmpid;
|
||||||
|
|
||||||
$nbofsubsubproducts = count($prods_arbo); // This include sub sub product into nb
|
$nbofsubsubproducts = count($prods_arbo); // This include sub sub product into nb
|
||||||
$prodschild = $object->getChildsArbo($id, 1);
|
$prodschild = $object->getChildsArbo($id, 1);
|
||||||
$nbofsubproducts = count($prodschild); // This include only first level of childs
|
$nbofsubproducts = count($prodschild); // This include only first level of childs
|
||||||
@ -323,9 +335,10 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
print '<input type="hidden" name="action" value="save_composed_product" />';
|
print '<input type="hidden" name="action" value="save_composed_product" />';
|
||||||
print '<input type="hidden" name="id" value="'.$id.'" />';
|
print '<input type="hidden" name="id" value="'.$id.'" />';
|
||||||
|
|
||||||
print '<table class="liste">';
|
print '<table id="tablelines" class="ui-sortable liste">';
|
||||||
|
|
||||||
print '<tr class="liste_titre">';
|
print '<tr class="liste_titre nodrag nodrop">';
|
||||||
|
print '<td>'.$langs->trans('Rank').'</td>';
|
||||||
print '<td>'.$langs->trans('ComposedProduct').'</td>';
|
print '<td>'.$langs->trans('ComposedProduct').'</td>';
|
||||||
print '<td>'.$langs->trans('Label').'</td>';
|
print '<td>'.$langs->trans('Label').'</td>';
|
||||||
print '<td class="right" colspan="2">'.$langs->trans('MinSupplierPrice').'</td>';
|
print '<td class="right" colspan="2">'.$langs->trans('MinSupplierPrice').'</td>';
|
||||||
@ -335,6 +348,7 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
}
|
}
|
||||||
print '<td class="center">'.$langs->trans('Qty').'</td>';
|
print '<td class="center">'.$langs->trans('Qty').'</td>';
|
||||||
print '<td class="center">'.$langs->trans('ComposedProductIncDecStock').'</td>';
|
print '<td class="center">'.$langs->trans('ComposedProductIncDecStock').'</td>';
|
||||||
|
print '<td class="linecolmove" style="width: 10px"></td>';
|
||||||
print '</tr>'."\n";
|
print '</tr>'."\n";
|
||||||
|
|
||||||
$totalsell = 0;
|
$totalsell = 0;
|
||||||
@ -343,7 +357,9 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
$productstatic->fetch($value['id']);
|
$productstatic->fetch($value['id']);
|
||||||
|
|
||||||
if ($value['level'] <= 1) {
|
if ($value['level'] <= 1) {
|
||||||
print '<tr class="oddeven">';
|
print '<tr id="'.$object->sousprods[$parent_label][$value['id']][6].'" class="drag drop oddeven level1">';
|
||||||
|
|
||||||
|
print '<td>'.$object->sousprods[$parent_label][$value['id']][7].'</td>';
|
||||||
|
|
||||||
$notdefined = 0;
|
$notdefined = 0;
|
||||||
$nb_of_subproduct = $value['nb'];
|
$nb_of_subproduct = $value['nb'];
|
||||||
@ -407,6 +423,8 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
print '<td>'.($value['incdec'] == 1 ? 'x' : '').'</td>';
|
print '<td>'.($value['incdec'] == 1 ? 'x' : '').'</td>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print '<td class="linecolmove tdlineupdown center">';
|
||||||
|
print '</td>';
|
||||||
print '</tr>'."\n";
|
print '</tr>'."\n";
|
||||||
} else {
|
} else {
|
||||||
$hide = '';
|
$hide = '';
|
||||||
@ -414,10 +432,11 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
$hide = ' hideobject'; // By default, we do not show this. It makes screen very difficult to understand
|
$hide = ' hideobject'; // By default, we do not show this. It makes screen very difficult to understand
|
||||||
}
|
}
|
||||||
|
|
||||||
print '<tr class="oddeven'.$hide.'" id="sub-'.$value['id_parent'].'">';
|
print '<tr class="oddeven'.$hide.'" id="sub-'.$value['id_parent'].'" data-ignoreidfordnd=1>';
|
||||||
|
|
||||||
//$productstatic->ref=$value['label'];
|
//$productstatic->ref=$value['label'];
|
||||||
$productstatic->ref = $value['ref'];
|
$productstatic->ref = $value['ref'];
|
||||||
|
print '<td></td>';
|
||||||
print '<td>';
|
print '<td>';
|
||||||
for ($i = 0; $i < $value['level']; $i++) {
|
for ($i = 0; $i < $value['level']; $i++) {
|
||||||
print ' '; // Add indentation
|
print ' '; // Add indentation
|
||||||
@ -437,6 +456,7 @@ if ($id > 0 || !empty($ref)) {
|
|||||||
}
|
}
|
||||||
print '<td class="center">'.$value['nb'].'</td>';
|
print '<td class="center">'.$value['nb'].'</td>';
|
||||||
print '<td> </td>';
|
print '<td> </td>';
|
||||||
|
print '<td> </td>';
|
||||||
|
|
||||||
print '</tr>'."\n";
|
print '</tr>'."\n";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user