function mouvement(&$PDOdb, &$object, $fk_product, $qty, $fk_warehouse_from, $fk_warehouse_to) { global $db, $user, $langs; dol_include_once('/product/stock/class/mouvementstock.class.php'); dol_include_once('/product/class/product.class.php'); /*var_dump($fk_product, $qty,$fk_warehouse_from, $fk_warehouse_to); exit; */ $stock = new MouvementStock($db); $label = ''; if (method_exists($object, 'getNomUrl')) { $label .= $object->getNomUrl(1); } if (!empty($conf->global->ROUTING_INFO_ALERT)) { $product = new Product($db); $product->fetch($fk_product); $msg = $product->getNomUrl(0) . ' ' . $product->label . ' ' . $langs->trans('MoveFrom') . ' ' . $wh_from_label . ' ' . $langs->trans('MoveTo') . ' ' . $wh_to_label; setEventMessage($msg); } $stock->origin = $object; $stock->reception($user, $fk_product, $fk_warehouse_to, $qty, 0, $label); $stock->livraison($user, $fk_product, $fk_warehouse_from, $qty, 0, $label); }
/** * Save a receiving into the tracking table of receiving (commande_fournisseur_dispatch) and add product into stock warehouse. * * @param User $user User object making change * @param int $product Id of product to dispatch * @param double $qty Qty to dispatch * @param int $entrepot Id of warehouse to add product * @param double $price Unit Price for PMP value calculation (Unit price without Tax and taking into account discount) * @param string $comment Comment for stock movement * @param date $eatby eat-by date * @param date $sellby sell-by date * @param string $batch Lot number * @param int $fk_commandefourndet Id of supplier order line * @param int $notrigger 1 = notrigger * @return int <0 if KO, >0 if OK */ function dispatchProduct($user, $product, $qty, $entrepot, $price = 0, $comment = '', $eatby = '', $sellby = '', $batch = '', $fk_commandefourndet = 0, $notrigger = 0) { global $conf, $langs; $error = 0; require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; // Check parameters (if test are wrong here, there is bug into caller) if ($entrepot <= 0) { $this->error = 'ErrorBadValueForParameterWarehouse'; return -1; } if ($qty <= 0) { $this->error = 'ErrorBadValueForParameterQty'; return -1; } $dispatchstatus = 1; if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) { $dispatchstatus = 0; } // Setting dispatch status (a validation step after receiving products) will be done manually to 1 or 2 if this option is on $now = dol_now(); if ($this->statut == 3 || $this->statut == 4 || $this->statut == 5) { $this->db->begin(); $sql = "INSERT INTO " . MAIN_DB_PREFIX . "commande_fournisseur_dispatch"; $sql .= " (fk_commande, fk_product, qty, fk_entrepot, fk_user, datec, fk_commandefourndet, status, comment, eatby, sellby, batch) VALUES"; $sql .= " ('" . $this->id . "','" . $product . "','" . $qty . "'," . ($entrepot > 0 ? "'" . $entrepot . "'" : "null") . ",'" . $user->id . "','" . $this->db->idate($now) . "','" . $fk_commandefourndet . "', " . $dispatchstatus . ", '" . $this->db->escape($comment) . "', "; $sql .= ($eatby ? "'" . $this->db->idate($eatby) . "'" : "null") . ", " . ($sellby ? "'" . $this->db->idate($sellby) . "'" : "null") . ", " . ($batch ? "'" . $batch . "'" : "null"); $sql .= ")"; dol_syslog(get_class($this) . "::dispatchProduct", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { if (!$notrigger) { global $conf, $langs, $user; // Call trigger $result = $this->call_trigger('LINEORDER_SUPPLIER_DISPATCH', $user); if ($result < 0) { $error++; return -1; } // End call triggers } } else { $this->error = $this->db->lasterror(); $error++; } // Si module stock gere et que incrementation faite depuis un dispatching en stock if (!$error && $entrepot > 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { $mouv = new MouvementStock($this->db); if ($product > 0) { // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on) $mouv->origin =& $this; $result = $mouv->reception($user, $product, $entrepot, $qty, $price, $comment, $eatby, $sellby, $batch); if ($result < 0) { $this->error = $mouv->error; $this->errors = $mouv->errors; dol_syslog(get_class($this) . "::dispatchProduct " . $this->error . " " . join(',', $this->errors), LOG_ERR); $error++; } } } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = 'BadStatusForObject'; return -2; } }
/** * Delete shipment. * Warning, do not delete a shipment if a delivery is linked to (with table llx_element_element) * * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO */ function delete() { global $conf, $langs, $user; require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; if ($conf->productbatch->enabled) { require_once DOL_DOCUMENT_ROOT . '/expedition/class/expeditionbatch.class.php'; } $error = 0; $this->error = ''; // Add a protection to refuse deleting if shipment has at least one delivery $this->fetchObjectLinked($this->id, 'shipping', 0, 'delivery'); // Get deliveries linked to this shipment if (count($this->linkedObjectsIds) > 0) { $this->error = 'ErrorThereIsSomeDeliveries'; return -1; } $this->db->begin(); // Stock control if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SHIPMENT && $this->statut > 0) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $langs->load("agenda"); // Loop on each product line to add a stock movement $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.rowid as expeditiondet_id"; $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd,"; $sql .= " " . MAIN_DB_PREFIX . "expeditiondet as ed"; $sql .= " WHERE ed.fk_expedition = " . $this->id; $sql .= " AND cd.rowid = ed.fk_origin_line"; dol_syslog(get_class($this) . "::delete select details", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { $cpt = $this->db->num_rows($resql); for ($i = 0; $i < $cpt; $i++) { 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) { $lotArray = ExpeditionLineBatch::fetchAll($this->db, $obj->expeditiondet_id); if (!is_array($lotArray)) { $error++; $this->errors[] = "Error " . $this->db->lasterror(); } } if (empty($lotArray)) { // no lot/serial // We increment stock of product (and sub-products) // We use warehouse selected for each line $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref)); // Price is set to 0, because we don't want to see WAP changed if ($result < 0) { $error++; $this->errors = $this->errors + $mouvS->errors; break; } } else { // We increment stock of batches // We use warehouse selected for each line foreach ($lotArray as $lot) { $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->dluo_qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, $lot->batch); // Price is set to 0, because we don't want to see WAP changed if ($result < 0) { $error++; $this->errors = $this->errors + $mouvS->errors; break; } } if ($error) { break; } // break for loop incase of error } } } else { $error++; $this->errors[] = "Error " . $this->db->lasterror(); } } // delete batch expedition line if (!$error && $conf->productbatch->enabled) { if (ExpeditionLineBatch::deletefromexp($this->db, $this->id) < 0) { $error++; $this->errors[] = "Error " . $this->db->lasterror(); } } if (!$error) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . "expeditiondet"; $sql .= " WHERE fk_expedition = " . $this->id; if ($this->db->query($sql)) { // Delete linked object $res = $this->deleteObjectLinked(); if ($res < 0) { $error++; } if (!$error) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . "expedition"; $sql .= " WHERE rowid = " . $this->id; if ($this->db->query($sql)) { // Call trigger $result = $this->call_trigger('SHIPPING_DELETE', $user); if ($result < 0) { $error++; } // End call triggers if (!$error) { $this->db->commit(); // We delete PDFs $ref = dol_sanitizeFileName($this->ref); if (!empty($conf->expedition->dir_output)) { $dir = $conf->expedition->dir_output . '/sending/' . $ref; $file = $dir . '/' . $ref . '.pdf'; if (file_exists($file)) { if (!dol_delete_file($file)) { return 0; } } if (file_exists($dir)) { if (!dol_delete_dir_recursive($dir)) { $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir); return 0; } } } return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -3; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -2; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -1; } } else { $this->db->rollback(); return -1; } }
private function quitSotck($lines, $isreturn = false) { global $db, $langs; require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $userstatic = new User($db); $userstatic->fetch($_SESSION['uid']); $error = 0; $cash = new Cash($db); $terminal = $_SESSION['TERMINAL_ID']; $cash->fetch($terminal); $warehouse = $cash->fk_warehouse; foreach ($lines as $line) { if (sizeof($line) > 0) { if ($line['idProduct']) { $mouvP = new MouvementStock($db); // We decrease stock for product if (!$isreturn) { $result = $mouvP->livraison($userstatic, $line['idProduct'], $warehouse, $line['cant'], $line['price'], $langs->trans("TicketCreatedInDolibarr")); } else { $result = $mouvP->reception($userstatic, $line['idProduct'], $warehouse, $line['cant'], $line['price'], $langs->trans("TicketCreatedInDolibarr")); } if ($result < 0) { $error++; } } } } return $error; }
/** * Adjust stock in a warehouse for product with batch number * * @param User $user user asking change * @param int $id_entrepot id of warehouse * @param double $nbpiece nb of units * @param int $movement 0 = add, 1 = remove * @param string $label Label of stock movement * @param double $price Price to use for stock eval * @param date $dlc eat-by date * @param date $dluo sell-by date * @param string $lot Lot number * @param string $inventorycode Inventory code * @return int <0 if KO, >0 if OK */ function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label = '', $price = 0, $dlc = '', $dluo = '', $lot = '', $inventorycode = '') { if ($id_entrepot) { $this->db->begin(); require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $op[0] = "+" . trim($nbpiece); $op[1] = "-" . trim($nbpiece); $movementstock = new MouvementStock($this->db); $result = $movementstock->_create($user, $this->id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode, '', $dlc, $dluo, $lot); if ($result >= 0) { $this->db->commit(); return 1; } else { $this->error = $movementstock->error; $this->errors = $movementstock->errors; $this->db->rollback(); return -1; } } }
/** * Delete shipment. * Warning, do not delete a shipment if a delivery is linked to (with table llx_element_element) * * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO */ function delete() { global $conf, $langs, $user; require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; $error = 0; // Add a protection to refuse deleting if shipment has at least one delivery $this->fetchObjectLinked($this->id, 'shipping', 0, 'delivery'); // Get deliveries linked to this shipment if (count($this->linkedObjectsIds) > 0) { $this->error = 'ErrorThereIsSomeDeliveries'; return -1; } $this->db->begin(); if ($conf->productbatch->enabled) { require_once DOL_DOCUMENT_ROOT . '/expedition/class/expeditionbatch.class.php'; if (ExpeditionLigneBatch::deletefromexp($this->db, $this->id) < 0) { $error++; $this->errors[] = "Error " . $this->db->lasterror(); } } // Stock control if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SHIPMENT && $this->statut > 0) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $langs->load("agenda"); // Loop on each product line to add a stock movement $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot"; $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd,"; $sql .= " " . MAIN_DB_PREFIX . "expeditiondet as ed"; $sql .= " WHERE ed.fk_expedition = " . $this->id; $sql .= " AND cd.rowid = ed.fk_origin_line"; dol_syslog(get_class($this) . "::delete select details sql=" . $sql); $resql = $this->db->query($sql); if ($resql) { $cpt = $this->db->num_rows($resql); for ($i = 0; $i < $cpt; $i++) { dol_syslog(get_class($this) . "::delete movement index " . $i); $obj = $this->db->fetch_object($resql); //var_dump($this->lines[$i]); $mouvS = new MouvementStock($this->db); $mouvS->origin =& $this; // We decrement stock of product (and sub-products) // We use warehouse selected for each line $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, $obj->subprice, $langs->trans("ShipmentDeletedInDolibarr", $this->ref)); if ($result < 0) { $error++; break; } } } else { $error++; } } if (!$error) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . "expeditiondet"; $sql .= " WHERE fk_expedition = " . $this->id; if ($this->db->query($sql)) { // Delete linked object $res = $this->deleteObjectLinked(); if ($res < 0) { $error++; } if (!$error) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . "expedition"; $sql .= " WHERE rowid = " . $this->id; if ($this->db->query($sql)) { // Call triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface = new Interfaces($this->db); $result = $interface->run_triggers('SHIPPING_DELETE', $this, $user, $langs, $conf); if ($result < 0) { $error++; $this->errors = $interface->errors; } // End call triggers if (!$error) { $this->db->commit(); // We delete PDFs $ref = dol_sanitizeFileName($this->ref); if (!empty($conf->expedition->dir_output)) { $dir = $conf->expedition->dir_output . '/sending/' . $ref; $file = $dir . '/' . $ref . '.pdf'; if (file_exists($file)) { if (!dol_delete_file($file)) { return 0; } } if (file_exists($dir)) { if (!dol_delete_dir($dir)) { $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir); return 0; } } } return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -3; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -2; } } else { $this->error = $this->db->lasterror() . " - sql={$sql}"; $this->db->rollback(); return -1; } } else { $this->db->rollback(); return -1; } }
$result = $product->correct_stock($user, $id, $_POST["nbpiece"], $_POST["mouvement"], $_POST["label"], 0); // We do not change value of stock for a correction if ($result > 0) { header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id); exit; } } else { $action = ''; } } /* * View */ $productstatic = new Product($db); $warehousestatic = new Entrepot($db); $movement = new MouvementStock($db); $userstatic = new User($db); $form = new Form($db); $formother = new FormOther($db); $formproduct = new FormProduct($db); $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.fk_product_type as type,"; $sql .= " e.label as stock, e.rowid as entrepot_id,"; $sql .= " m.rowid as mid, m.value, m.datem, m.fk_user_author, m.label, m.fk_origin, m.origintype,"; $sql .= " u.login"; $sql .= " FROM (" . MAIN_DB_PREFIX . "entrepot as e,"; $sql .= " " . MAIN_DB_PREFIX . "product as p,"; $sql .= " " . MAIN_DB_PREFIX . "stock_mouvement as m)"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as u ON m.fk_user_author = u.rowid"; $sql .= " WHERE m.fk_product = p.rowid"; $sql .= " AND m.fk_entrepot = e.rowid"; $sql .= " AND e.entity = " . $conf->entity;
/** * Set draft status * * @param User $user Object user that modify * @param int $idwarehouse Id warehouse to use for stock change. * @return int <0 if KO, >0 if OK */ function set_draft($user, $idwarehouse = -1) { global $conf, $langs; $error = 0; if ($this->statut == self::STATUS_DRAFT) { dol_syslog(get_class($this) . "::set_draft already draft status", LOG_WARNING); return 0; } $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "facture"; $sql .= " SET fk_statut = " . self::STATUS_DRAFT; $sql .= " WHERE rowid = " . $this->id; dol_syslog(get_class($this) . "::set_draft", LOG_DEBUG); $result = $this->db->query($sql); if ($result) { // Si on decremente le produit principal et ses composants a la validation de facture, on réincrement if ($this->type != self::TYPE_DEPOSIT && $result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $langs->load("agenda"); $num = count($this->lines); for ($i = 0; $i < $num; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); $mouvP->origin =& $this; // We decrease stock for product if ($this->type == self::TYPE_CREDIT_NOTE) { $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); } else { $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); } // we use 0 for price, to not change the weighted average value } } } if ($error == 0) { $old_statut = $this->statut; $this->brouillon = 1; $this->statut = self::STATUS_DRAFT; // Call trigger $result = $this->call_trigger('BILL_UNVALIDATE', $user); if ($result < 0) { $error++; $this->statut = $old_statut; $this->brouillon = 0; } // End call triggers } else { $this->db->rollback(); return -1; } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->error(); $this->db->rollback(); return -1; } }
/** * testMouvementCreate * * @return int */ public function testMouvementCreate() { global $conf, $user, $langs, $db; $conf = $this->savconf; $user = $this->savuser; $langs = $this->savlangs; $db = $this->savdb; // We create a product for tests $product1 = new Product($db); $product1->initAsSpecimen(); $product1->ref .= ' 1'; $product1->label .= ' 1'; $product1id = $product1->create($user); $product2 = new Product($db); $product2->initAsSpecimen(); $product2->ref .= ' 2'; $product2->label .= ' 2'; $product2id = $product2->create($user); // We create a product for tests $warehouse1 = new Entrepot($db); $warehouse1->initAsSpecimen(); $warehouse1->libelle .= ' 1'; $warehouse1->description .= ' 1'; $warehouse1id = $warehouse1->create($user); $warehouse2 = new Entrepot($db); $warehouse2->initAsSpecimen(); $warehouse2->libelle .= ' 2'; $warehouse2->description .= ' 2'; $warehouse2id = $warehouse2->create($user); $localobject = new MouvementStock($this->savdb); // Do a list of movement into warehouse 1 // Create an input movement (type = 3) of price 9.9 -> shoul dupdate PMP to 9.9 $result = $localobject->_create($user, $product1id, $warehouse1id, 10, 3, 9.9, 'Movement for unit test 1', 'Inventory Code Test'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an input movement (type = 3) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse1id, 10, 3, 9.699999999999999, 'Movement for unit test 2', 'Inventory Code Test'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 2) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse1id, -5, 2, 999, 'Movement for unit test 3', 'Inventory Code Test'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 1) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse1id, 1, 0, 0, 'Input from transfer', 'Transfert X'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 1) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse1id, -2, 1, 0, 'Output from transfer', 'Transfert Y'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Do same but into warehouse 2 // Create an input movement (type = 3) of price 9.9 -> shoul dupdate PMP to 9.9 $result = $localobject->_create($user, $product1id, $warehouse2id, 10, 3, 9.9, 'Movement for unit test 1 wh 2', 'Inventory Code Test 2'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an input movement (type = 3) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse2id, 10, 3, 9.699999999999999, 'Movement for unit test 2 wh 2', 'Inventory Code Test 2'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 2) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse2id, -5, 2, 999, 'Movement for unit test 3 wh 2', 'Inventory Code Test 2'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 1) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse2id, 1, 0, 0, 'Input from transfer wh 2', 'Transfert X 2'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); // Create an output movement (type = 1) of price 9.7 -> shoul dupdate PMP to 9.9/9.7 = 9.8 $result = $localobject->_create($user, $product1id, $warehouse2id, -2, 1, 0, 'Output from transfer wh 2', 'Transfert Y 2'); print __METHOD__ . " result=" . $result . "\n"; $this->assertLessThan($result, 0); return $localobject; }
/** * Validate object and update stock if option enabled * @param user Object user that validate * @return int */ function valid($user) { global $conf, $langs; require_once(DOL_DOCUMENT_ROOT."/lib/files.lib.php"); dol_syslog("Expedition::valid"); // Protection if ($this->statut) { dol_syslog("Expedition::valid no draft status", LOG_WARNING); return 0; } if (! $user->rights->expedition->valider) { $this->error='Permission denied'; dol_syslog("Expedition::valid ".$this->error, LOG_ERR); return -1; } $this->db->begin(); $error = 0; // Define new ref $soc = new Societe($this->db); $soc->fetch($this->socid); // Class of company linked to order $result=$soc->set_as_client(); // Define new ref if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref))) { $numref = $this->getNextNumRef($soc); } else { $numref = "EXP".$this->id; } $now=dol_now(); // Validate $sql = "UPDATE ".MAIN_DB_PREFIX."expedition SET"; $sql.= " ref='".$numref."'"; $sql.= ", fk_statut = 1"; $sql.= ", date_valid = '".$this->db->idate($now)."'"; $sql.= ", fk_user_valid = ".$user->id; $sql.= " WHERE rowid = ".$this->id; dol_syslog("Expedition::valid update expedition sql=".$sql); $resql=$this->db->query($sql); if (! $resql) { dol_syslog("Expedition::valid Echec update - 10 - sql=".$sql, LOG_ERR); $this->error=$this->db->lasterror(); $error++; } // If stock increment is done on sending (recommanded choice) if (! $error && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SHIPMENT) { 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, ed.qty, ed.fk_entrepot"; $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd"; $sql.= ", ".MAIN_DB_PREFIX."expeditiondet as ed"; $sql.= " WHERE ed.fk_expedition = ".$this->id; $sql.= " AND cd.rowid = ed.fk_origin_line"; dol_syslog("Expedition::valid select details sql=".$sql); $resql=$this->db->query($sql); if ($resql) { $num = $this->db->num_rows($resql); $i=0; while($i < $num) { dol_syslog("Expedition::valid movement index ".$i); $obj = $this->db->fetch_object($resql); //var_dump($this->lines[$i]); $mouvS = new MouvementStock($this->db); // We decrement stock of product (and sub-products) // We use warehouse selected for each line $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, $obj->subprice); if ($result < 0) { $error++; break; } $i++; } } else { $this->db->rollback(); $this->error=$this->db->error(); dol_syslog("Expedition::valid ".$this->error, LOG_ERR); return -2; } } if (! $error) { // On efface le repertoire de pdf provisoire $expeditionref = dol_sanitizeFileName($this->ref); if ($conf->expedition->dir_output) { $dir = $conf->expedition->dir_output . "/" . $expeditionref; $file = $dir . "/" . $expeditionref . ".pdf"; if (file_exists($file)) { if (!dol_delete_file($file)) { $this->error=$langs->trans("ErrorCanNotDeleteFile",$file); } } if (file_exists($dir)) { if (!dol_delete_dir($dir)) { $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir); } } } } // Set new ref and current status if (! $error) { $this->ref = $numref; $this->statut = 1; } if (! $error) { // Appel des triggers include_once(DOL_DOCUMENT_ROOT."/core/class/interfaces.class.php"); $interface=new Interfaces($this->db); $result=$interface->run_triggers('SHIPPING_VALIDATE',$this,$user,$langs,$conf); if ($result < 0) { $error++; $this->errors=$interface->errors; } // Fin appel triggers } if (! $error) { $this->db->commit(); return 1; } else { foreach($this->errors as $errmsg) { dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR); $this->error.=($this->error?', '.$errmsg:$errmsg); } $this->db->rollback(); return -1*$error; } }
/** * Set draft status * * @param User $user Object user that modify * @param int $idwarehouse Id warehouse to use for stock change. * @return int <0 if KO, >0 if OK */ function set_draft($user, $idwarehouse = -1) { global $conf, $langs; $error = 0; if ($this->statut == self::STATUS_DRAFT) { dol_syslog(get_class($this) . "::set_draft already draft status", LOG_WARNING); return 0; } $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn"; $sql .= " SET fk_statut = 0"; $sql .= " WHERE rowid = " . $this->id; dol_syslog(get_class($this) . "::set_draft", LOG_DEBUG); $result = $this->db->query($sql); if ($result) { // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $langs->load("agenda"); $cpt = count($this->lines); for ($i = 0; $i < $cpt; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We increase stock for product $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); } } } // Triggers call if (!$error && empty($notrigger)) { // Call trigger $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user); if ($result < 0) { $error++; } // End call triggers } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->error(); $this->db->rollback(); return -1; } }
/** * Set draft status * @param user Object user that modify * @param int <0 if KO, >0 if OK */ function set_draft($user) { global $conf,$langs; $error=0; if ($this->statut == 0) { dol_syslog("FactureFournisseur::set_draft already draft status", LOG_WARNING); return 0; } $this->db->begin(); $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn"; $sql.= " SET fk_statut = 0"; $sql.= " WHERE rowid = ".$this->id; dol_syslog("FactureFournisseur::set_draft sql=".$sql, LOG_DEBUG); if ($this->db->query($sql)) { // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente if ($result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) { require_once(DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php"); $langs->load("agenda"); for ($i = 0 ; $i < sizeof($this->lines) ; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We increase stock for product $entrepot_id = "1"; // TODO ajouter possibilite de choisir l'entrepot $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $entrepot_id, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref)); } } } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error=$this->db->error(); $this->db->rollback(); return -1; } }
/** * Add a product into a stock warehouse. * * @param User $user User object making change * @param int $product Id of product to dispatch * @param double $qty Qty to dispatch * @param int $entrepot Id of warehouse to add product * @param double $price Unit Price for PMP value calculation (Unit price without Tax and taking into account discount) * @param string $comment Comment for stock movement * @param date $eatby eat-by date * @param date $sellby sell-by date * @param string $batch Lot number * @return int <0 if KO, >0 if OK */ function DispatchProduct($user, $product, $qty, $entrepot, $price = 0, $comment = '', $eatby = '', $sellby = '', $batch = '') { global $conf; $error = 0; require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; // Check parameters if ($entrepot <= 0 || $qty <= 0) { $this->error = 'BadValueForParameter'; return -1; } $now = dol_now(); if ($this->statut == 3 || $this->statut == 4 || $this->statut == 5) { $this->db->begin(); $sql = "INSERT INTO " . MAIN_DB_PREFIX . "commande_fournisseur_dispatch "; $sql .= " (fk_commande,fk_product, qty, fk_entrepot, fk_user, datec) VALUES "; $sql .= " ('" . $this->id . "','" . $product . "','" . $qty . "'," . ($entrepot > 0 ? "'" . $entrepot . "'" : "null") . ",'" . $user->id . "','" . $this->db->idate($now) . "')"; dol_syslog(get_class($this) . "::DispatchProduct sql=" . $sql); $resql = $this->db->query($sql); if ($resql) { if (!$notrigger) { global $conf, $langs, $user; // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface = new Interfaces($this->db); $result = $interface->run_triggers('LINEORDER_SUPPLIER_DISPATCH', $this, $user, $langs, $conf); if ($result < 0) { $error++; $this->errors = $interface->errors; $this->db->rollback(); return -1; } // Fin appel triggers } $this->db->commit(); } else { $this->error = $this->db->lasterror(); $error++; } // Si module stock gere et que incrementation faite depuis un dispatching en stock if (!$error && $entrepot > 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { $mouv = new MouvementStock($this->db); if ($product > 0) { // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on) $mouv->origin =& $this; $result = $mouv->reception($user, $product, $entrepot, $qty, $price, $comment, $eatby, $sellby, $batch); if ($result < 0) { $this->error = $mouv->error; dol_syslog(get_class($this) . "::DispatchProduct " . $this->error, LOG_ERR); $error++; } } } //TODO: Check if there is a current transaction in DB but seems not. if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = 'BadStatusForObject'; return -2; } }
if ($resultcreate > 0) { $warehouseidtodecrease = isset($_SESSION["CASHDESK_ID_WAREHOUSE"]) ? $_SESSION["CASHDESK_ID_WAREHOUSE"] : 0; if (!empty($conf->global->CASHDESK_NO_DECREASE_STOCK)) { $warehouseidtodecrease = 0; } // If a particular stock is defined, we disable choice $resultvalid = $invoice->validate($user, $obj_facturation->numInvoice(), 0); if ($warehouseidtodecrease > 0) { // Decrease require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $langs->load("agenda"); // Loop on each line $cpt = count($invoice->lines); for ($i = 0; $i < $cpt; $i++) { if ($invoice->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($db); $mouvP->origin =& $invoice; // We decrease stock for product if ($invoice->type == $invoice::TYPE_CREDIT_NOTE) { $result = $mouvP->reception($user, $invoice->lines[$i]->fk_product, $warehouseidtodecrease, $invoice->lines[$i]->qty, $invoice->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarrFromPos", $invoice->newref)); } else { $result = $mouvP->livraison($user, $invoice->lines[$i]->fk_product, $warehouseidtodecrease, $invoice->lines[$i]->qty, $invoice->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarrFromPos", $invoice->newref)); } if ($result < 0) { $error++; } } } } $id = $invoice->id; // Add the payment
/** * \brief Set draft status * \param user Object user that modify * \param int <0 if KO, >0 if OK */ function set_draft($user) { global $conf, $langs; $error = 0; if ($this->statut == 0) { dol_syslog("Ticket::set_draft already draft status", LOG_WARNING); return 0; } $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "pos_ticket"; $sql .= " SET fk_statut = 0"; $sql .= " WHERE rowid = " . $this->id; dol_syslog("Ticket::set_draft sql=" . $sql, LOG_DEBUG); if ($this->db->query($sql)) { // Si active on decremente le produit principal et ses composants a la validation de ticket if ($result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_BILL) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; for ($i = 0; $i < sizeof($this->lines); $i++) { if ($this->lines[$i]->fk_product && $this->lines[$i]->product_type == 0) { $mouvP = new MouvementStock($this->db); // We decrease stock for product $entrepot_id = "1"; // TODO ajouter possibilite de choisir l'entrepot $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $entrepot_id, $this->lines[$i]->qty, $this->lines[$i]->subprice); } } } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->error(); $this->db->rollback(); return -1; } }
/** * Set draft status * * @param User $user Object user that modify * @param int $idwarehouse Id warehouse to use for stock change. * @return int <0 if KO, >0 if OK */ function set_draft($user, $idwarehouse = -1) { global $conf, $langs; $error = 0; if ($this->statut == 0) { dol_syslog(get_class($this) . "::set_draft already draft status", LOG_WARNING); return 0; } $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "facture"; $sql .= " SET fk_statut = 0"; $sql .= " WHERE rowid = " . $this->id; dol_syslog(get_class($this) . "::set_draft sql=" . $sql, LOG_DEBUG); $result = $this->db->query($sql); if ($result) { // Si on decremente le produit principal et ses composants a la validation de facture, on réincrement if ($this->type != 3 && $result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_BILL) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $langs->load("agenda"); $num = count($this->lines); for ($i = 0; $i < $num; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We decrease stock for product if ($this->type == 2) { $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); } else { $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); } } } } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error = $this->db->error(); $this->db->rollback(); return -1; } }
/** * \brief Cancel an order * \return int <0 if KO, >0 if OK * \remarks If stock is decremented on order validation, we must reincrement it */ function cancel($user) { global $conf; $error = 0; if ($user->rights->commande->valider) { $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "commande"; $sql .= " SET fk_statut = -1"; $sql .= " WHERE rowid = " . $this->id; $sql .= " AND fk_statut = 1"; dol_syslog("Commande::cancel sql=" . $sql, LOG_DEBUG); if ($this->db->query($sql)) { // If stock is decremented on validate order, we must reincrement it if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $langs->load("agenda"); if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We increment stock of product (and sub-products) $entrepot_id = "1"; //Todo: ajouter possibilite de choisir l'entrepot $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $entrepot_id, $this->lines[$i]->qty, $this->lines[$i]->subprice); if ($result < 0) { $error++; } } } if (!$error) { // Appel des triggers include_once DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php"; $interface = new Interfaces($this->db); $result = $interface->run_triggers('ORDER_CANCEL', $this, $user, $langs, $conf); if ($result < 0) { $error++; $this->errors = $interface->errors; } // Fin appel triggers } if (!$error) { $this->statut = -1; $this->db->commit(); return 1; } else { $this->error = $mouvP->error; $this->db->rollback(); return -1; } } else { $this->error = $this->db->error(); $this->db->rollback(); dol_syslog($this->error, LOG_ERR); return -1; } } }
/** * Add a product into a stock warehouse. * @param $user User object making change * @param $product Id of product to dispatch * @param $qty Qty to dispatch * @param $entrepot Id of warehouse to add product * @param $price Price for PMP value calculation * @param $comment Comment for stock movement * @return int <0 if KO, >0 if OK */ function DispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='') { global $conf; $error = 0; require_once DOL_DOCUMENT_ROOT ."/product/stock/class/mouvementstock.class.php"; // Check parameters if ($entrepot <= 0 || $qty <= 0) { $this->error='BadValueForParameter'; return -1; } $now=dol_now(); if (($this->statut == 3 || $this->statut == 4 || $this->statut == 5)) { $this->db->begin(); $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur_dispatch "; $sql.= " (fk_commande,fk_product, qty, fk_entrepot, fk_user, datec) VALUES "; $sql.= " ('".$this->id."','".$product."','".$qty."',".($entrepot>0?"'".$entrepot."'":"null").",'".$user->id."','".$this->db->idate($now)."')"; dol_syslog("CommandeFournisseur::DispatchProduct sql=".$sql); $resql = $this->db->query($sql); if (! $resql) { $this->error=$this->db->lasterror(); $error++; } // Si module stock gere et que incrementation faite depuis un dispatching en stock if (!$error && $entrepot > 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) { $mouv = new MouvementStock($this->db); if ($product > 0) { $result=$mouv->reception($user, $product, $entrepot, $qty, $price, $comment); if ($result < 0) { $this->error=$mouv->error; dol_syslog("CommandeFournisseur::DispatchProduct ".$this->error, LOG_ERR); $error++; } } $i++; } if ($error == 0) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } } else { $this->error='BadStatusForObject'; return -2; } }
/** * Cancel an order * If stock is decremented on order validation, we must reincrement it * * @param int $idwarehouse Id warehouse to use for stock change. * @return int <0 if KO, >0 if OK */ function cancel($idwarehouse = -1) { global $conf, $user, $langs; $error = 0; $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "commande"; $sql .= " SET fk_statut = " . self::STATUS_CANCELED; $sql .= " WHERE rowid = " . $this->id; $sql .= " AND fk_statut = " . self::STATUS_VALIDATED; dol_syslog(get_class($this) . "::cancel", LOG_DEBUG); if ($this->db->query($sql)) { // If stock is decremented on validate order, we must reincrement it if (!empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $langs->load("agenda"); $num = count($this->lines); for ($i = 0; $i < $num; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We increment stock of product (and sub-products) $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderCanceledInDolibarr", $this->ref)); // price is 0, we don't want WAP to be changed if ($result < 0) { $error++; $this->error = $mouvP->error; break; } } } } if (!$error) { // Call trigger $result = $this->call_trigger('ORDER_CANCEL', $user); if ($result < 0) { $error++; } // End call triggers } if (!$error) { $this->statut = self::STATUS_CANCELED; $this->db->commit(); return 1; } else { foreach ($this->errors as $errmsg) { dol_syslog(get_class($this) . "::cancel " . $errmsg, LOG_ERR); $this->error .= $this->error ? ', ' . $errmsg : $errmsg; } $this->db->rollback(); return -1 * $error; } } else { $this->error = $this->db->error(); $this->db->rollback(); return -1; } }
/** * Adjust stock in a warehouse for product * * @param User $user user asking change * @param int $id_entrepot id of warehouse * @param double $nbpiece nb of units * @param int $movement 0 = add, 1 = remove * @param string $label Label of stock movement * @param double $price Price to use for stock eval * @return int <0 if KO, >0 if OK */ function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0) { if ($id_entrepot) { $this->db->begin(); require_once(DOL_DOCUMENT_ROOT ."/product/stock/class/mouvementstock.class.php"); $op[0] = "+".trim($nbpiece); $op[1] = "-".trim($nbpiece); $movementstock=new MouvementStock($this->db); $result=$movementstock->_create($user,$this->id,$id_entrepot,$op[$movement],$movement,$price,'',$label); if ($result >= 0) { $this->db->commit(); return 1; } else { dol_print_error($this->db); $this->db->rollback(); return -1; } } }
$result = $product->correct_stock($user, $id, $_POST["nbpiece"], $_POST["mouvement"], $_POST["label"], 0); // We do not change value of stock for a correction if ($result > 0) { header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id); exit; } } else { $action = ''; } } /* * View */ $productstatic = new Product($db); $warehousestatic = new Entrepot($db); $movement = new MouvementStock($db); $userstatic = new User($db); $form = new Form($db); $formother = new FormOther($db); $formproduct = new FormProduct($db); $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.fk_product_type as type,"; $sql .= " e.label as stock, e.rowid as entrepot_id,"; $sql .= " m.rowid as mid, m.value, m.datem, m.fk_user_author, m.label, m.fk_origin, m.origintype,"; $sql .= " u.login"; // Checkpoint: obtener el checkbox $sql .= ", m.checked"; $sql .= " FROM (" . MAIN_DB_PREFIX . "entrepot as e,"; $sql .= " " . MAIN_DB_PREFIX . "product as p,"; $sql .= " " . MAIN_DB_PREFIX . "stock_mouvement as m)"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as u ON m.fk_user_author = u.rowid"; $sql .= " WHERE m.fk_product = p.rowid";
static function addStockMouvementDolibarr($fk_product, $qty, $description, $fk_entrepot, $price = 0) { global $db, $user, $conf; require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $mouvS = new MouvementStock($db); $conf->global->PRODUIT_SOUSPRODUITS = false; // Dans le cas asset il ne faut pas de destocke recurssif if ($fk_entrepot > 0) { if ($qty > 0) { $result = $mouvS->reception($user, $fk_product, $fk_entrepot, $qty, $price, $description); } else { $result = $mouvS->livraison($user, $fk_product, $fk_entrepot, -$qty, $price, $description); } } }