diff --git a/htdocs/admin/workflow.php b/htdocs/admin/workflow.php index 717a25aa8b3..75b0ce6d808 100644 --- a/htdocs/admin/workflow.php +++ b/htdocs/admin/workflow.php @@ -80,6 +80,7 @@ $workflowcodes=array( // For the following 2 options, if module invoice is disabled, they does not exists, so "Classify billed" for order must be done manually from order card. 'WORKFLOW_INVOICE_CLASSIFY_BILLED_ORDER'=>array('family'=>'classify', 'position'=>40, 'enabled'=>'! empty($conf->facture->enabled) && ! empty($conf->commande->enabled)', 'picto'=>'bill','warning'=>'WarningCloseAlways'), 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER'=>array('family'=>'classify', 'position'=>50, 'enabled'=>'! empty($conf->facture->enabled) && ! empty($conf->commande->enabled)', 'picto'=>'bill','warning'=>'WarningCloseAlways'), + 'WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING'=>array('family'=>'classify', 'position'=>30, 'enabled'=>'! empty($conf->expedition->enabled) && ! empty($conf->commande->enabled)', 'picto'=>'order'), ); if (! empty($conf->modules_parts['workflow']) && is_array($conf->modules_parts['workflow'])) diff --git a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php index fd97edc8089..a24ca28c40a 100644 --- a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php +++ b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php @@ -159,6 +159,61 @@ class InterfaceWorkflowManager extends DolibarrTriggers } } + if ($action=='SHIPPING_VALIDATE') { + dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); + + + if (! empty($conf->commande->enabled) && ! empty($conf->expedition->enabled) && ! empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING)) + { + $qtyshipped=array(); + $qtyordred=array(); + require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; + + //find all shippement on order origin + $order = new Commande($this->db); + $ret=$order->fetch($this->origin_id); + if ($ret<0) { + $this->error=$order->error; $this->errors=$order->errors; + return $ret; + } + var_dump($order); + exit; + $ret=$order->fetchObjectLinked($order->id,'commande',null,'shipping'); + if ($ret<0) { + $this->error=$order->error; $this->errors=$order->errors; + return $ret; + } + //Build array of quantity shipped by product for an order + if (is_array($order->linkedObjects) && count($order->linkedObjects)>0) { + foreach($order->linkedObjects as $shipping) { + if (is_array($shipping->lines) && count($shipping->lines)>0) { + foreach($shipping->lines as $shippingline) { + $qtyshipped[$shippingline->fk_product]+=$shippingline->qty; + } + } + } + } + //Build array of quantity ordered by product + if (is_array($order->lines) && count($order->lines)>0) { + foreach($order->lines as $orderline) { + $qtyordred[$orderline->fk_product]+=$orderline->qty; + } + } + dol_syslog(var_export($qtyordred,true)); + dol_syslog(var_export($qtyshipped,true)); + //Compare array + $diff_array=array_diff_assoc($qtyordred,$qtyshipped); + if (count($diff_array)==0) { + //No diff => mean everythings is shipped + $ret=$object->setStatut(Commande::STATUS_CLOSED, $this->origin_id, $this->origin); + if ($ret<0) { + $this->error=$object->error; $this->errors=$object->errors; + return $ret; + } + } + } + } + return 0; } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index bb8cb9bcdda..9b3bb0681c8 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -37,7 +37,7 @@ if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propa if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php'; - + /** * Class to manage shipments */ @@ -93,13 +93,13 @@ class Expedition extends CommonObject var $meths; var $listmeths; // List of carriers - + const STATUS_DRAFT = 0; const STATUS_VALIDATED = 1; const STATUS_CLOSED = 2; - - - + + + /** * Constructor * @@ -290,7 +290,7 @@ class Expedition extends CommonObject $error++; } } - + // Actions on extra fields (by external module or standard code) // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('expeditiondao')); @@ -389,7 +389,7 @@ class Expedition extends CommonObject { $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); @@ -419,7 +419,7 @@ class Expedition extends CommonObject { $error = 0; $stockLocationQty = array(); // associated array with batch qty in stock location - + $tab=$line_ext->detail_batch; // create stockLocation Qty array foreach ($tab as $detbatch) @@ -447,7 +447,7 @@ class Expedition extends CommonObject { $error++; } - } + } } } } @@ -554,7 +554,7 @@ class Expedition extends CommonObject * Thirparty */ $result=$this->fetch_thirdparty(); - + // Retrieve all extrafields for expedition // fetch optionals attributes and labels require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; @@ -697,29 +697,29 @@ class Expedition extends CommonObject //var_dump($this->lines[$i]); $mouvS = new MouvementStock($this->db); $mouvS->origin = &$this; - + if (empty($obj->edbrowid)) { // line without batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr",$numref)); if ($result < 0) { - $error++; - $this->errors[]=$mouvS->error; + $error++; + $this->errors[]=$mouvS->error; break; } } else { // line with batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version) $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr",$numref), '', $obj->eatby, $obj->sellby, $obj->batch, $obj->fk_origin_stock); if ($result < 0) { - $error++; - $this->errors[]=$mouvS->error; + $error++; + $this->errors[]=$mouvS->error; break; } } @@ -731,9 +731,7 @@ class Expedition extends CommonObject $this->error=$this->db->error(); return -2; } - - // FIXME Set status of order to "delivered" if check box "set order as delivered if remain to ship is 0" is on and if sum of all validated shipment = products or order to ship (because we are in case of stock movement on shipment validation) - + } // Change status of order to "shipment in process" @@ -742,7 +740,7 @@ class Expedition extends CommonObject { $error++; } - + if (! $error && ! $notrigger) { // Call trigger @@ -903,11 +901,11 @@ class Expedition extends CommonObject } } } - + // extrafields if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used $line->array_options = $array_options; - + $this->lines[$num] = $line; } @@ -960,7 +958,7 @@ class Expedition extends CommonObject return -1; } } - + //var_dump($linebatch); } } @@ -972,7 +970,7 @@ class Expedition extends CommonObject // extrafields if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used $line->array_options = $array_options; - + //var_dump($line); $this->lines[$num] = $line; return 1; @@ -1132,13 +1130,13 @@ class Expedition extends CommonObject { dol_syslog(get_class($this)."::delete movement index ".$i); $obj = $this->db->fetch_object($resql); - + $mouvS = new MouvementStock($this->db); // we do not log origin because it will be deleted $mouvS->origin = null; // get lot/serial $lotArray = null; - if ($conf->productbatch->enabled) + if ($conf->productbatch->enabled) { $lotArray = ExpeditionLineBatch::fetchAll($this->db,$obj->expeditiondet_id); if (! is_array($lotArray)) @@ -1157,7 +1155,7 @@ class Expedition extends CommonObject break; } } - else + else { // We increment stock of batches // We use warehouse selected for each line @@ -1171,7 +1169,7 @@ class Expedition extends CommonObject } } if ($error) break; // break for loop incase of error - } + } } } else @@ -1179,7 +1177,7 @@ class Expedition extends CommonObject $error++;$this->errors[]="Error ".$this->db->lasterror(); } } - + // delete batch expedition line if (! $error && $conf->productbatch->enabled) { @@ -1188,7 +1186,7 @@ class Expedition extends CommonObject $error++;$this->errors[]="Error ".$this->db->lasterror(); } } - + if (! $error) { $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet"; @@ -1227,7 +1225,7 @@ class Expedition extends CommonObject } } } - + if (! $error) { $this->db->commit(); @@ -1376,7 +1374,7 @@ class Expedition extends CommonObject $line->volume_units = $obj->volume_units; $line->pa_ht = $obj->pa_ht; - + // For invoicing $tabprice = calcul_price_total($obj->qty_shipped, $obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->fk_product_type, $mysoc); // We force type to 0 $line->desc = $obj->description; // We need ->desc because some code into CommonObject use desc (property defined for other elements) @@ -1398,8 +1396,8 @@ class Expedition extends CommonObject $this->total_ttc+= $tabprice[2]; $this->total_localtax1+= $tabprice[9]; $this->total_localtax2+= $tabprice[10]; - - if ($originline != $obj->fk_origin_line) + + if ($originline != $obj->fk_origin_line) { $line->detail_batch = array(); } @@ -1770,7 +1768,7 @@ class Expedition extends CommonObject } - + /** * Forge an set tracking url * @@ -1816,9 +1814,9 @@ class Expedition extends CommonObject global $conf,$langs,$user; $error=0; - + $this->db->begin(); - + $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut='.self::STATUS_CLOSED; $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; @@ -1830,9 +1828,9 @@ class Expedition extends CommonObject { $order = new Commande($this->db); $order->fetch($this->origin_id); - + $order->loadExpeditions(self::STATUS_CLOSED); // Fill $order->expeditions = array(orderlineid => qty) - + $shipments_match_order = 1; foreach($order->lines as $line) { @@ -1848,21 +1846,21 @@ class Expedition extends CommonObject } if ($shipments_match_order) { - dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for shipments with status Expedition::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order'); + dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for shipments with status Expedition::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order'); $order->cloture($user); } } - + $this->statut=self::STATUS_CLOSED; - + // If stock increment is done on closing if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - + $langs->load("agenda"); - + // Loop on each product line to add a stock movement // TODO possibilite d'expedier a partir d'une propale ou autre origine ? $sql = "SELECT cd.fk_product, cd.subprice,"; @@ -1873,7 +1871,7 @@ class Expedition extends CommonObject $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; $sql.= " WHERE ed.fk_expedition = ".$this->id; $sql.= " AND cd.rowid = ed.fk_origin_line"; - + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); $resql=$this->db->query($sql); if ($resql) @@ -1892,14 +1890,14 @@ class Expedition extends CommonObject } if ($qty <= 0) continue; dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - + $mouvS = new MouvementStock($this->db); $mouvS->origin = &$this; - + if (empty($obj->edbrowid)) { // line without batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref)); if ($result < 0) { @@ -1911,7 +1909,7 @@ class Expedition extends CommonObject else { // line with batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref), '', $obj->eatby, $obj->sellby, $obj->batch, $obj->fk_origin_stock); if ($result < 0) { @@ -1928,7 +1926,7 @@ class Expedition extends CommonObject $error++; } } - + // Call trigger if (! $error) { @@ -1941,9 +1939,9 @@ class Expedition extends CommonObject else { dol_print_error($this->db); - $error++; + $error++; } - + if (! $error) { $this->db->commit(); @@ -1964,7 +1962,7 @@ class Expedition extends CommonObject function set_billed() { $error=0; - + $this->db->begin(); $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=2, billed=1'; // TODO Update only billed @@ -1975,18 +1973,18 @@ class Expedition extends CommonObject { $this->statut=2; $this->billed=1; - + // Call trigger $result=$this->call_trigger('SHIPPING_BILLED',$user); - if ($result < 0) { + if ($result < 0) { $error++; } - + } else { $error++; $this->errors[]=$this->db->lasterror; } - + if (empty($error)) { $this->db->commit(); return 1; @@ -2008,9 +2006,9 @@ class Expedition extends CommonObject global $conf,$langs,$user; $error=0; - + $this->db->begin(); - + $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=1'; $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; @@ -2019,14 +2017,14 @@ class Expedition extends CommonObject { $this->statut=1; $this->billed=0; - + // If stock increment is done on closing if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - + $langs->load("agenda"); - + // Loop on each product line to add a stock movement // TODO possibilite d'expedier a partir d'une propale ou autre origine $sql = "SELECT cd.fk_product, cd.subprice,"; @@ -2037,7 +2035,7 @@ class Expedition extends CommonObject $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; $sql.= " WHERE ed.fk_expedition = ".$this->id; $sql.= " AND cd.rowid = ed.fk_origin_line"; - + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); $resql=$this->db->query($sql); if ($resql) @@ -2056,15 +2054,15 @@ class Expedition extends CommonObject } if ($qty <= 0) continue; dol_syslog(get_class($this)."::reopen expedition movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - + //var_dump($this->lines[$i]); $mouvS = new MouvementStock($this->db); $mouvS->origin = &$this; - + if (empty($obj->edbrowid)) { // line without batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref)); if ($result < 0) { @@ -2076,7 +2074,7 @@ class Expedition extends CommonObject else { // line with batch detail - + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref), '', $obj->eatby, $obj->sellby, $obj->batch, $obj->fk_origin_stock); if ($result < 0) { @@ -2093,7 +2091,7 @@ class Expedition extends CommonObject $error++; } } - + if (! $error) { // Call trigger @@ -2102,13 +2100,13 @@ class Expedition extends CommonObject $error++; } } - + } else { $error++; $this->errors[]=$this->db->lasterror(); } - - if (! $error) + + if (! $error) { $this->db->commit(); return 1; @@ -2119,7 +2117,7 @@ class Expedition extends CommonObject return -1; } } - + /** * Create a document onto disk according to template module. * @@ -2205,7 +2203,7 @@ class ExpeditionLigne extends CommonObjectLine public $element='expeditiondet'; public $table_element='expeditiondet'; - + public $fk_origin_line; // Deprecated diff --git a/htdocs/langs/en_US/workflow.lang b/htdocs/langs/en_US/workflow.lang index e18f93f65ab..6002180ad09 100644 --- a/htdocs/langs/en_US/workflow.lang +++ b/htdocs/langs/en_US/workflow.lang @@ -9,4 +9,5 @@ descWORKFLOW_ORDER_AUTOCREATE_INVOICE=Automatically create a customer invoice af descWORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL=Classify linked source proposal to billed when customer order is set to paid descWORKFLOW_INVOICE_CLASSIFY_BILLED_ORDER=Classify linked source customer order(s) to billed when customer invoice is set to paid descWORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER=Classify linked source customer order(s) to billed when customer invoice is validated -descWORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL=Classify linked source proposal to billed when customer invoice is validated \ No newline at end of file +descWORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL=Classify linked source proposal to billed when customer invoice is validated +descWORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING=Classify shipped linked source order on shipping validate if quantity shipped is the same as in order \ No newline at end of file