diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 7cdedae55fd..eb8c384e37e 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -7,7 +7,7 @@ * Copyright (C) 2013 Florian Henry * Copyright (C) 2013 Marcos García * Copyright (C) 2014 Cedric GROSS - * Copyright (C) 2014-2015 Francis Appels + * Copyright (C) 2014-2017 Francis Appels * Copyright (C) 2015 Claudio Aschieri * Copyright (C) 2016 Ferran Marcet * Copyright (C) 2016 Yasser Carreón @@ -69,6 +69,7 @@ $id = $origin_id; if (empty($origin_id)) $origin_id = GETPOST('origin_id','int'); // Id of order or propal if (empty($origin_id)) $origin_id = GETPOST('object_id','int'); // Id of order or propal $ref=GETPOST('ref','alpha'); +$line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; // Security check $socid=''; @@ -598,6 +599,201 @@ if (empty($reshook)) } } + /* + * delete a line + */ + elseif ($action == 'deleteline' && ! empty($line_id)) + { + $object->fetch($id); + $lines = $object->lines; + $line = new ExpeditionLigne($db); + + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) + { + if (count($lines[$i]->details_entrepot) > 1) + { + // delete multi warehouse lines + foreach ($lines[$i]->details_entrepot as $details_entrepot) { + $line->id = $details_entrepot->line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + else + { + // delete single warehouse line + $line->id = $line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + unset($_POST["lineid"]); + } + + if(! $error) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + } + } + + /* + * Update a line + */ + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('save')) + { + // Clean parameters + + $qty=0; + $entrepot_id = 0; + $batch_id = 0; + + $lines = $object->lines; + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) + { + // line to update + $line = new ExpeditionLigne($db); + // Extrafields Lines + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $line->array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline); + // Unset extrafield POST Data + if (is_array($extralabelsline)) { + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + $line->fk_product = $lines[$i]->fk_product; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + // line with lot + foreach ($lines[$i]->detail_batch as $detail_batch) + { + $lotStock = new Productbatch($db); + $batch="batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock; + $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id; + $batch_id = GETPOST($batch,'int'); + $batch_qty = GETPOST($qty, 'int'); + if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->dluo_qty)) + { + if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) + { + if ($lines[$i]->entrepot_id != 0) + { + // allow update line entrepot_id if not multi warehouse shipping + $line->entrepot_id = $lotStock->warehouseid; + } + $line->detail_batch->fk_origin_stock = $batch_id; + $line->detail_batch->batch = $lotStock->batch; + $line->detail_batch->id = $detail_batch->id; + $line->detail_batch->entrepot_id = $lotStock->warehouseid; + $line->detail_batch->dluo_qty = $batch_qty; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + setEventMessages($lotStock->error, $lotStock->errors, 'errors'); + $error++; + } + } + unset($_POST[$batch]); + unset($_POST[$qty]); + } + } + else + { + // line without lot + if ($lines[$i]->entrepot_id > 0) + { + // single warehouse shipment line + $stockLocation="entl".$line_id; + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->entrepot_id = GETPOST($stockLocation,'int'); + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + // multi warehouse shipment lines + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if (! $error) { + $stockLocation="entl".$detail_entrepot->line_id; + $qty = "qtyl".$detail_entrepot->line_id; + $warehouse = GETPOST($stockLocation,'int'); + if (!empty ($warehouse)) + { + $line->id = $detail_entrepot->line_id; + $line->entrepot_id = $warehouse; + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + } + } + } + } + } + + unset($_POST["lineid"]); + + if (! $error) { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) + $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + $ret = $object->fetch($object->id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + } + + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; // Actions to send emails @@ -1733,6 +1929,15 @@ else if ($id || $ref) /* * Lines of products */ + if ($action == 'editline') + { + print '
+ + + + + '; + } print '
'; print '
'; @@ -1744,34 +1949,62 @@ else if ($id || $ref) } print ''.$langs->trans("Products").''; print ''.$langs->trans("QtyOrdered").''; - if ($object->statut <= 1) - { - print ''.$langs->trans("QtyToShip").''; - } - else - { - print ''.$langs->trans("QtyShipped").''; - } - if ($origin && $origin_id > 0) { - print ''.$langs->trans("QtyInOtherShipments").''; + print ''.$langs->trans("QtyInOtherShipments").''; + } + if ($action == 'editline') + { + $editColspan = 3; + if (empty($conf->stock->enabled)) $editColspan--; + if (empty($conf->productbatch->enabled)) $editColspan--; + print ''; + if ($object->statut <= 1) + { + print $langs->trans("QtyToShip").' - '; + } + else + { + print $langs->trans("QtyShipped").' - '; + } + if (! empty($conf->stock->enabled)) + { + print $langs->trans("WarehouseSource").' - '; + } + if (! empty($conf->productbatch->enabled)) + { + print $langs->trans("Batch"); + } + print ''; + } + else + { + if ($object->statut <= 1) + { + print ''.$langs->trans("QtyToShip").''; + } + else + { + print ''.$langs->trans("QtyShipped").''; + } + if (! empty($conf->stock->enabled)) + { + print ''.$langs->trans("WarehouseSource").''; + } + + if (! empty($conf->productbatch->enabled)) + { + print ''.$langs->trans("Batch").''; + } } - print ''.$langs->trans("CalculatedWeight").''; print ''.$langs->trans("CalculatedVolume").''; //print ''.$langs->trans("Size").''; - - if (! empty($conf->stock->enabled)) + if ($object->statut == 0) { - print ''.$langs->trans("WarehouseSource").''; + print ''; + print ''; } - - if (! empty($conf->productbatch->enabled)) - { - print ''.$langs->trans("Batch").''; - } - print "\n"; $var=false; @@ -1895,9 +2128,6 @@ else if ($id || $ref) // Qty ordered print ''.$lines[$i]->qty_asked.''; - // Qty to ship or shipped - print ''.$lines[$i]->qty_shipped.''; - // Qty in other shipments (with shipment and warehouse used) if ($origin && $origin_id > 0) { @@ -1929,6 +2159,116 @@ else if ($id || $ref) } print ''; + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + // edit mode + print ''; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + $line = new ExpeditionLigne($db); + foreach ($lines[$i]->detail_batch as $detail_batch) + { + print ''; + // Qty to ship or shipped + print ''; + // Batch number managment + if ($lines[$i]->entrepot_id == 0) + { + // only show lot numbers from src warehouse when shipping from multiple warehouses + $line->fetch($detail_batch->fk_expeditiondet); + } + print ''; + print ''; + } + } + else if (! empty($conf->stock->enabled)) + { + if ($lines[$i]->entrepot_id > 0) + { + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + else if (count($lines[$i]->details_entrepot) > 1) + { + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + } + print '
' . '' . '' . $formproduct->selectLotStock($detail_batch->fk_origin_stock, 'batchl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->fk_origin_stock, '', 1, 0, $lines[$i]->fk_product, $line->entrepot_id). '
' . '' . '' . $formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1). ' - ' . $langs->trans("NA") . '
' . '' . '' . $formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl'.$detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1) . ' - ' . $langs->trans("NA") . '
'; + } + else + { + // Qty to ship or shipped + print ''.$lines[$i]->qty_shipped.''; + + // Warehouse source + if (! empty($conf->stock->enabled)) + { + print ''; + if ($lines[$i]->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($lines[$i]->entrepot_id); + print $entrepot->getNomUrl(1); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + $detail = ''; + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if ($detail_entrepot->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($detail_entrepot->entrepot_id); + $detail.= $langs->trans("DetailWarehouseFormat",$entrepot->libelle,$detail_entrepot->qty_shipped).'
'; + } + } + print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"),$detail); + } + print ''; + } + + // Batch number managment + if (! empty($conf->productbatch->enabled)) + { + if (isset($lines[$i]->detail_batch)) + { + print ''; + if ($lines[$i]->product_tobatch) + { + $detail = ''; + foreach ($lines[$i]->detail_batch as $dbatch) + { + $detail.= $langs->trans("DetailBatchFormat",$dbatch->batch,dol_print_date($dbatch->eatby,"day"),dol_print_date($dbatch->sellby,"day"),$dbatch->dluo_qty).'
'; + } + print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); + } + else + { + print $langs->trans("NA"); + } + print ''; + } else { + print ''; + } + } + } + // Weight print ''; if ($lines[$i]->fk_product_type == 0) print $lines[$i]->weight*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->weight_units,"weight"); @@ -1944,55 +2284,28 @@ else if ($id || $ref) // Size //print ''.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume").''; - // Warehouse source - if (! empty($conf->stock->enabled)) + if ($action == 'editline' && $lines[$i]->id == $line_id) { - print ''; - if ($lines[$i]->entrepot_id > 0) - { - $entrepot = new Entrepot($db); - $entrepot->fetch($lines[$i]->entrepot_id); - print $entrepot->getNomUrl(1); - } - else if (count($lines[$i]->details_entrepot) > 1) - { - $detail = ''; - foreach ($lines[$i]->details_entrepot as $detail_entrepot) - { - if ($detail_entrepot->entrepot_id > 0) - { - $entrepot = new Entrepot($db); - $entrepot->fetch($detail_entrepot->entrepot_id); - $detail.= $langs->trans("DetailWarehouseFormat",$entrepot->libelle,$detail_entrepot->qty_shipped).'
'; - } - } - print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"),$detail); - } - print ''; + print ''; + print '
'; + print '
'; } - - // Batch number managment - if (! empty($conf->productbatch->enabled)) + else if ($object->statut == 0) { - if (isset($lines[$i]->detail_batch)) + // edit-delete buttons + print ''; + print 'id . '">' . img_edit() . ''; + print ''; + print ''; + print 'id . '">' . img_delete() . ''; + print ''; + + // Display lines extrafields + if (! empty($rowExtrafieldsStart)) { - print ''; - if ($lines[$i]->product_tobatch) - { - $detail = ''; - foreach ($lines[$i]->detail_batch as $dbatch) - { - $detail.= $langs->trans("DetailBatchFormat",$dbatch->batch,dol_print_date($dbatch->eatby,"day"),dol_print_date($dbatch->sellby,"day"),$dbatch->dluo_qty).'
'; - } - print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); - } - else - { - print $langs->trans("NA"); - } - print ''; - } else { - print ''; + print $rowExtrafieldsStart; + print $rowExtrafieldsView; + print $rowEnd; } } print ""; @@ -2003,11 +2316,16 @@ else if ($id || $ref) $line = new ExpeditionLigne($db); $line->fetch_optionals($lines[$i]->id,$extralabelslines); print ''; - print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + else + { + print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } print ''; } - - } // TODO Show also lines ordered but not delivered @@ -2115,7 +2433,7 @@ else if ($id || $ref) * Documents generated */ - if ($action != 'presend') + if ($action != 'presend' && $action != 'editline') { print '
'; diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 995805116b6..3e341e6d5be 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -7,7 +7,7 @@ * Copyright (C) 2013 Florian Henry * Copyright (C) 2014 Cedric GROSS * Copyright (C) 2014-2015 Marcos García - * Copyright (C) 2014-2015 Francis Appels + * Copyright (C) 2014-2017 Francis Appels * Copyright (C) 2015 Claudio Aschieri * Copyright (C) 2016 Ferran Marcet * @@ -373,48 +373,18 @@ class Expedition extends CommonObject */ function create_line($entrepot_id, $origin_line_id, $qty,$array_options=0) { - global $conf; - $error = 0; - $line_id = 0; + $expeditionline = new ExpeditionLigne($this->db); + $expeditionline->fk_expedition = $this->id; + $expeditionline->entrepot_id = $entrepot_id; + $expeditionline->fk_origin_line = $origin_line_id; + $expeditionline->qty = $qty; + $expeditionline->array_options = $array_options; - $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet ("; - $sql.= "fk_expedition"; - $sql.= ", fk_entrepot"; - $sql.= ", fk_origin_line"; - $sql.= ", qty"; - $sql.= ") VALUES ("; - $sql.= $this->id; - $sql.= ", ".($entrepot_id?$entrepot_id:'null'); - $sql.= ", ".$origin_line_id; - $sql.= ", ".$qty; - $sql.= ")"; - - dol_syslog(get_class($this)."::create_line", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) + if (($lineId = $expeditionline->insert()) < 0) { - $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet"); + $this->error[]=$expeditionline->error; } - else - { - $error++; - } - - if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used - { - $expeditionline = new ExpeditionLigne($this->db); - $expeditionline->array_options=$array_options; - $expeditionline->id= $this->db->last_insert_id(MAIN_DB_PREFIX.$expeditionline->table_element); - $result=$expeditionline->insertExtraFields(); - if ($result < 0) - { - $this->error[]=$expeditionline->error; - $error++; - } - } - - if (! $error) return $line_id; - else return -1; + return $lineId; } @@ -1366,6 +1336,7 @@ class Expedition extends CommonObject $detail_entrepot = new stdClass; $detail_entrepot->entrepot_id = $obj->fk_entrepot; $detail_entrepot->qty_shipped = $obj->qty_shipped; + $detail_entrepot->line_id = $obj->line_id; $line->details_entrepot[] = $detail_entrepot; $line->line_id = $obj->line_id; @@ -2238,13 +2209,30 @@ class Expedition extends CommonObject */ class ExpeditionLigne extends CommonObjectLine { - var $db; + public $element='expeditiondet'; + public $table_element='expeditiondet'; + + public $fk_origin_line; + + /** + * Id of shipment + * @var int + */ + public $fk_expedition; + + var $db; // From llx_expeditiondet var $qty; var $qty_shipped; var $fk_product; var $detail_batch; + /** + * Id of warehouse + * @var int + */ + public $entrepot_id; + // From llx_commandedet or llx_propaldet var $qty_asked; @@ -2261,10 +2249,7 @@ class ExpeditionLigne extends CommonObjectLine var $total_localtax1; // Total Local tax 1 var $total_localtax2; // Total Local tax 2 - public $element='expeditiondet'; - public $table_element='expeditiondet'; - - public $fk_origin_line; + // Deprecated /** @@ -2283,15 +2268,404 @@ class ExpeditionLigne extends CommonObjectLine */ var $libelle; - /** - * Constructor - * - * @param DoliDB $db Database handler - */ + /** + * Constructor + * + * @param DoliDB $db Database handler + */ function __construct($db) { $this->db=$db; } + /** + * Load line expedition + * + * @param int $rowid Id line order + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT ed.rowid, ed.fk_expedition, ed.fk_entrepot, ed.fk_origin_line, ed.qty, ed.rang'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as ed'; + $sql.= ' WHERE ed.rowid = '.$rowid; + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); + $this->id = $objp->rowid; + $this->fk_expedition = $objp->fk_expedition; + $this->entrepot_id = $objp->fk_entrepot; + $this->fk_origin_line = $objp->fk_origin_line; + $this->qty = $objp->qty; + $this->rang = $objp->rang; + + $this->db->free($result); + + return 1; + } + else + { + $this->errors[] = $this->db->lasterror(); + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Insert line into database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int <0 if KO, line id >0 if OK + */ + function insert($user=null, $notrigger=0) + { + global $langs, $conf; + + $error=0; + + // Check parameters + if (empty($this->fk_expedition) || empty($this->fk_origin_line) || empty($this->qty)) + { + $this->errors[] = 'ErrorMandatoryParametersNotProvided'; + return -1; + } + // Clean parameters + if (empty($this->entrepot_id)) $this->entrepot_id='null'; + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet ("; + $sql.= "fk_expedition"; + $sql.= ", fk_entrepot"; + $sql.= ", fk_origin_line"; + $sql.= ", qty"; + $sql.= ") VALUES ("; + $sql.= $this->fk_expedition; + $sql.= ", ".$this->entrepot_id; + $sql.= ", ".$this->fk_origin_line; + $sql.= ", ".$this->qty; + $sql.= ")"; + + dol_syslog(get_class($this)."::insert", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet"); + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_INSERT',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + + if (! $error) { + $this->db->commit(); + return $this->id; + } + + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $error++; + } + } + + /** + * Delete shipment line. + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int >0 if OK, <0 if KO + */ + function delete($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + $this->db->begin(); + + // delete batch expedition line + if ($conf->productbatch->enabled) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch"; + $sql.= " WHERE fk_expeditiondet = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + } + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet"; + $sql.= " WHERE rowid = ".$this->id; + + if (! $error && $this->db->query($sql)) + { + // Remove extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_DELETE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + } + else + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + + if (! $error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + /** + * Update a line in database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int < 0 if KO, > 0 if OK + */ + function update($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + dol_syslog(get_class($this)."::update id=$this->id, entrepot_id=$this->entrepot_id, product_id=$this->fk_product, qty=$this->qty"); + + + + $this->db->begin(); + + // Clean parameters + if (empty($this->qty)) $this->qty=0; + $qty=price2num($this->qty); + $remainingQty = 0; + $batch = null; + $batch_id = null; + $expedition_batch_id = null; + if (is_array($this->detail_batch)) + { + if (count($this->detail_batch) > 1) + { + dol_syslog(get_class($this).'::update only possible for one batch', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + else + { + $batch = $this->detail_batch[0]->batch; + $batch_id = $this->detail_batch[0]->fk_origin_stock; + $expedition_batch_id = $this->detail_batch[0]->id; + if ($this->entrepot_id != $this->detail_batch[0]->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch[0]->dluo_qty); + } + } + else if (! empty($this->detail_batch)) + { + $batch = $this->detail_batch->batch; + $batch_id = $this->detail_batch->fk_origin_stock; + $expedition_batch_id = $this->detail_batch->id; + if ($this->entrepot_id != $this->detail_batch->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch->dluo_qty); + } + + // check parameters + if (! isset($this->id) || ! isset($this->entrepot_id)) + { + dol_syslog(get_class($this).'::update missing line id and/or warehouse id', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + return -1; + } + + // update lot + + if (! empty($batch) && $conf->productbatch->enabled) + { + dol_syslog(get_class($this)."::update expedition batch id=$expedition_batch_id, batch_id=$batch_id, batch=$batch"); + + if (empty($batch_id) || empty($expedition_batch_id) || empty($this->fk_product)) { + dol_syslog(get_class($this).'::update missing fk_origin_stock (batch_id) and/or fk_product', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + } + + // fetch remaining lot qty + require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php'; + if (($lotArray = ExpeditionLineBatch::fetchAll($this->db, $this->id)) < 0) + { + $this->errors[]=$this->db->lasterror()." - ExpeditionLineBatch::fetchAll"; + $error++; + } + else + { + // caculate new total line qty + foreach ($lotArray as $lot) + { + if ($expedition_batch_id != $lot->id) + { + $remainingQty += $lot->dluo_qty; + } + } + $qty += $remainingQty; + + //fetch lot details + + // fetch from product_lot + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; + $lot = new Productlot($this->db); + if ($lot->fetch(0,$this->fk_product,$batch) < 0) + { + $this->errors[] = $lot->errors; + $error++; + } + else + { + // delete lot expedition line + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch"; + $sql.= " WHERE fk_expeditiondet = ".$this->id; + $sql.= " AND rowid = ".$expedition_batch_id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + else if ($qty > 0) + { + if (isset($lot->id)) + { + $shipmentLot = new ExpeditionLineBatch($this->db); + $shipmentLot->batch = $lot->batch; + $shipmentLot->eatby = $lot->eatby; + $shipmentLot->sellby = $lot->sellby; + $shipmentLot->entrepot_id = $this->detail_batch->entrepot_id; + $shipmentLot->dluo_qty = $this->detail_batch->dluo_qty; + $shipmentLot->fk_origin_stock = $batch_id; + if ($shipmentLot->create($this->id) < 0) + { + $this->errors[]=$shipmentLot->errors; + $error++; + } + } + } + } + } + } + if (! $error) + { + // update line + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + $sql.= " fk_entrepot = ".$this->entrepot_id; + $sql.= " , qty = ".$qty; + $sql.= " WHERE rowid = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + else + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_UPDATE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + if (!$error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } } diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index 8d4ddc4705d..68e80454b22 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2016 Francis Appels + * Copyright (C) 2015-2017 Francis Appels * * 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 @@ -34,6 +34,7 @@ class FormProduct // Cache arrays var $cache_warehouses=array(); + var $cache_lot=array(); /** @@ -329,5 +330,157 @@ class FormProduct return $return; } -} + /** + * Return list of lot numbers (stock from product_batch) with stock location and stock qty + * + * @param int $selected Id of preselected lot stock id ('' for no value, 'ifone'=select value if one value otherwise no value) + * @param string $htmlname Name of html select html + * @param string $filterstatus lot status filter, following comma separated filter options can be used + * @param int $empty 1=Can be empty, 0 if not + * @param int $disabled 1=Select is disabled + * @param int $fk_product show lot numbers of product with id fk_product. All from objectLines if 0. + * @param int $fk_entrepot filter lot numbers for warehouse with id fk_entrepot. All if 0. + * @param array $objectLines Only cache lot numbers for products in lines of object. If no lines only for fk_product. If no fk_product, all. + * @param string $empty_label Empty label if needed (only if $empty=1) + * @param int $forcecombo 1=Force combo iso ajax select2 + * @param array $events Events to add to select2 + * @param string $morecss Add more css classes to HTML select + * + * @return string HTML select + */ + function selectLotStock($selected='',$htmlname='batch_id',$filterstatus='',$empty=0,$disabled=0,$fk_product=0,$fk_entrepot=0,$objectLines = array(),$empty_label='', $forcecombo=0, $events=array(), $morecss='minwidth200') + { + global $langs; + dol_syslog(get_class($this)."::selectLot $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $fk_entrepot, $empty_label, $showstock, $forcecombo, $morecss",LOG_DEBUG); + + $out=''; + $productIdArray = array(); + if (! is_array($objectLines) || ! count($objectLines)) + { + if (! empty($fk_product)) $productIdArray[] = $fk_product; + } + else + { + foreach ($objectLines as $line) { + if ($line->fk_product) $productIdArray[] = $line->fk_product; + } + } + + $nboflot = $this->loadLotStock($productIdArray); + + if ($conf->use_javascript_ajax && ! $forcecombo) + { + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; + $comboenhancement = ajax_combobox($htmlname, $events); + $out.= $comboenhancement; + } + + $out.=''; + if ($disabled) $out.=''; + + return $out; + } + + /** + * Load in cache array list of lot available in stock from a given list of products + * + * @param array $productIdArray array of product id's from who to get lot numbers. A + * + * @return int Nb of loaded lines, 0 if nothing loaded, <0 if KO + */ + private function loadLotStock($productIdArray = array()) + { + global $conf, $langs; + + $cacheLoaded = false; + if (empty($productIdArray)) + { + // only Load lot stock for given products + $this->cache_lot = array(); + return 0; + } + if (count($productIdArray) && count($this->cache_lot)) + { + // check cache already loaded for product id's + foreach ($productIdArray as $productId) + { + $cacheLoaded = ! empty($this->cache_lot[$productId]) ? true : false; + } + } + if ($cacheLoaded) + { + return count($this->cache_lot); + } + else + { + // clear cache + $this->cache_lot = array(); + $productIdList = implode(',', $productIdArray); + $sql = "SELECT pb.batch, pb.rowid, ps.fk_entrepot, pb.qty, e.label, ps.fk_product"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_batch as pb"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.rowid = pb.fk_product_stock"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on e.rowid = ps.fk_entrepot AND e.entity IN (".getEntity('stock').")"; + if (!empty($productIdList)) + { + $sql.= " WHERE ps.fk_product IN (".$productIdList.")"; + } + $sql.= " ORDER BY e.label, pb.batch"; + + dol_syslog(get_class($this).'::loadLotStock', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + $this->cache_lot[$obj->fk_product][$obj->rowid]['id'] =$obj->rowid; + $this->cache_lot[$obj->fk_product][$obj->rowid]['batch']=$obj->batch; + $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_id']=$obj->fk_entrepot; + $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_label']=$obj->label; + $this->cache_lot[$obj->fk_product][$obj->rowid]['qty'] = $obj->qty; + $i++; + } + + return $num; + } + else + { + dol_print_error($this->db); + return -1; + } + } + } +} \ No newline at end of file