diff --git a/htdocs/core/actions_addupdatedelete.inc.php b/htdocs/core/actions_addupdatedelete.inc.php
index 82a76cf8718..1114e33f6f6 100644
--- a/htdocs/core/actions_addupdatedelete.inc.php
+++ b/htdocs/core/actions_addupdatedelete.inc.php
@@ -285,18 +285,20 @@ if ($action == 'confirm_validate' && $confirm == 'yes' && $permissiontoadd)
// Define output language
if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
{
- $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);
- }
- $model = $object->modelpdf;
- $ret = $object->fetch($id); // Reload to get new records
+ if (method_exists($object, 'generateDocument')) {
+ $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);
+ }
+ $model = $object->modelpdf;
+ $ret = $object->fetch($id); // Reload to get new records
- $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
+ $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
+ }
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
diff --git a/htdocs/core/class/commonobjectline.class.php b/htdocs/core/class/commonobjectline.class.php
index 59b0acee232..148c9baa67e 100644
--- a/htdocs/core/class/commonobjectline.class.php
+++ b/htdocs/core/class/commonobjectline.class.php
@@ -50,6 +50,16 @@ abstract class CommonObjectLine extends CommonObject
public $fk_unit;
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ $this->db = $db;
+ }
+
/**
* Returns the translation key from units dictionary.
* A langs->trans() must be called on result to get translated value.
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index d52478dbbdb..de8288b23ea 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -688,6 +688,7 @@ Method=Method
Receive=Receive
CompleteOrNoMoreReceptionExpected=Complete or nothing more expected
ExpectedValue=Expected Value
+ExpectedQty=Expected Qty
PartialWoman=Partial
TotalWoman=Total
NeverReceived=Never received
diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index 994eae20e04..4098024f651 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -236,4 +236,5 @@ ForceTo=Force to
AlwaysShowFullArbo=Display full tree of warehouse on popup of warehouse links (Warning: This may decrease dramatically performances)
StockAtDatePastDesc=You can view here the stock (real stock) at a given date in the past
StockAtDateFutureDesc=You can view here the stock (virtual stock) at a given date in future
-CurrentStock=Current stock
\ No newline at end of file
+CurrentStock=Current stock
+InventoryRealQtyHelp=Set value to 0 to reset qty Keep field empty, or remove line, to keep unchanged
\ No newline at end of file
diff --git a/htdocs/product/inventory/card.php b/htdocs/product/inventory/card.php
index 00401fa590b..6a2406d74b5 100644
--- a/htdocs/product/inventory/card.php
+++ b/htdocs/product/inventory/card.php
@@ -115,7 +115,7 @@ if (empty($reshook))
}
}
$triggermodname = 'STOCK_INVENTORY_MODIFY'; // Name of trigger action code to execute when we modify record
-
+
// Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen
include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
@@ -127,10 +127,10 @@ if (empty($reshook))
// Action to move up and down lines of object
//include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php';
-
+
// Action to build doc
include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
-
+
/*if ($action == 'set_thirdparty' && $permissiontoadd)
{
$object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, 'MYOBJECT_MODIFY');
@@ -139,7 +139,7 @@ if (empty($reshook))
{
$object->setProject(GETPOST('projectid', 'int'));
}
-
+
// Actions to send emails
$triggersendname = 'INVENTORY_SENTBYMAIL';
$autocopy='MAIN_MAIL_AUTOCOPY_INVENTORY_TO';
@@ -188,12 +188,12 @@ if ($action == 'create')
print '';
if ($backtopage) print '';
if ($backtopageforcancel) print '';
-
+
dol_fiche_head(array(), '');
// Set some default values
//if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue';
-
+
print '
'."\n";
// Common attributes
@@ -228,7 +228,7 @@ if (($id || $ref) && $action == 'edit')
print '';
if ($backtopage) print '';
if ($backtopageforcancel) print '';
-
+
dol_fiche_head();
print '
'."\n";
@@ -292,7 +292,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
*/
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220);
}
-
+
// Call Hook formConfirm
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
@@ -395,36 +395,33 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
print ''.$langs->trans("SetToDraft").'';
}
}
-
+
// Modify
- if ($permissiontoadd)
+ if ($object->status == $object::STATUS_DRAFT)
{
- print 'id.'&action=edit">'.$langs->trans("Modify").''."\n";
- } else {
- print ''.$langs->trans('Modify').''."\n";
+ if ($permissiontoadd)
+ {
+ print 'id.'&action=edit">'.$langs->trans("Modify").''."\n";
+ } else {
+ print ''.$langs->trans('Modify').''."\n";
+ }
}
-
+
// Validate
if ($object->status == $object::STATUS_DRAFT)
{
if ($permissiontoadd)
{
- if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0))
- {
- print ''.$langs->trans("Validate").'';
- } else {
- $langs->load("errors");
- print ''.$langs->trans("Validate").'';
- }
+ print ''.$langs->trans("Validate").' ('.$langs->trans("Start").')';
}
}
-
+
// Clone
/*if ($permissiontoadd)
{
print ''.$langs->trans("ToClone").''."\n";
}*/
-
+
// Delete (need delete permission, or if draft, just need create/modify permission)
if ($permissiontodelete || ($object->status == $object::STATUS_DRAFT && $permissiontoadd))
{
@@ -457,7 +454,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$delallowed = $user->rights->mymodule->myobject->write; // If you can create/edit, you can remove a file on card
print $formfile->showdocuments('mymodule:MyObject', $object->element.'/'.$objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
}
-
+
// Show links to link elements
$linktoelem = $form->showLinkToObjectBlock($object, null, array('inventory'));
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
@@ -482,7 +479,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
//Select mail models is same action as presend
if (GETPOST('modelselected')) $action = 'presend';
-
+
// Presend form
$modelmail='inventory';
$defaulttopic='InformationMessage';
diff --git a/htdocs/product/inventory/class/inventory.class.php b/htdocs/product/inventory/class/inventory.class.php
index 983a7a4acb9..eedafd5497d 100644
--- a/htdocs/product/inventory/class/inventory.class.php
+++ b/htdocs/product/inventory/class/inventory.class.php
@@ -228,7 +228,101 @@ class Inventory extends CommonObject
*/
public function create(User $user, $notrigger = false)
{
- return $this->createCommon($user, $notrigger);
+ $result = $this->createCommon($user, $notrigger);
+
+ return $result;
+ }
+
+ /**
+ * Validate inventory (start it)
+ *
+ * @param User $user User that creates
+ * @param bool $notrigger false=launch triggers after, true=disable triggers
+ * @return int <0 if KO, Id of created object if OK
+ */
+ public function validate(User $user, $notrigger = false)
+ {
+ $this->db->begin();
+
+ $result = 0;
+
+ if ($result >= 0) {
+ // Scan existing stock to prefill the inventory
+ $sql = 'SELECT ps.rowid, ps.fk_entrepot as fk_warehouse, ps.fk_product, ps.reel,';
+ $sql .= ' pb.batch, pb.qty';
+ $sql .= ' FROM '.MAIN_DB_PREFIX.'product_stock as ps';
+ $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_batch as pb ON pb.fk_product_stock = ps.rowid,';
+ $sql .= ' '.MAIN_DB_PREFIX.'product as p, '.MAIN_DB_PREFIX.'entrepot as e';
+ $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
+ $sql .= ' AND ps.fk_product = p.rowid AND ps.fk_entrepot = e.rowid';
+ if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) $sql .= " AND p.fk_product_type = 0";
+ if ($object->fk_product > 0) $sql .= ' AND ps.fk_product = '.$object->fk_product;
+ if ($object->fk_warehouse > 0) $sql .= ' AND ps.fk_entrepot = '.$object->fk_warehouse;
+
+ $inventoryline = new InventoryLine($this->db);
+
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ $num = $this->db->num_rows($resql);
+
+ $i = 0;
+ while ($i < $num)
+ {
+ $obj = $this->db->fetch_object($resql);
+
+ $inventoryline->fk_inventory = $this->id;
+ $inventoryline->fk_warehouse = $obj->fk_warehouse;
+ $inventoryline->fk_product = $obj->fk_product;
+ $inventoryline->batch = $obj->batch;
+ $inventoryline->qty_stock = ($obj->batch ? $obj->qty : $obj->reel); // If there is batch detail, we take qty for batch, else global qty
+ $inventoryline->datec = dol_now();
+
+ $resultline = $inventoryline->create($user);
+ if ($resultline <= 0) {
+ $this->error = $inventoryline->error;
+ $this->errors = $inventoryline->errors;
+ $result = -1;
+ break;
+ }
+
+ $i++;
+ }
+ } else {
+ $result = -1;
+ $this->error = $this->db->lasterror();
+ }
+ }
+
+ if ($result >= 0) {
+ $result = $this->setStatut($this::STATUS_VALIDATED, null, '', 'INVENTORY_VALIDATED');
+ }
+
+ if ($result > 0) {
+ $this->db->commit();
+ } else {
+ $this->db->rollback();
+ }
+ }
+
+ /**
+ * Go back to draft
+ *
+ * @param User $user User that creates
+ * @param bool $notrigger false=launch triggers after, true=disable triggers
+ * @return int <0 if KO, Id of created object if OK
+ */
+ public function setDraft(User $user, $notrigger = false)
+ {
+ $this->db->begin();
+
+ $result = $this->setStatut($this::STATUS_DRAFT, null, '', 'INVENTORY_DRAFT');
+
+ if ($result > 0) {
+ $this->db->commit();
+ } else {
+ $this->db->rollback();
+ }
}
/**
@@ -412,10 +506,13 @@ class Inventory extends CommonObject
$labelStatus = array();
$labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft');
- $labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled');
+ $labelStatus[self::STATUS_VALIDATED] = $langs->trans('Validated').' ('.$langs->trans('Started').')';
$labelStatus[self::STATUS_CANCELED] = $langs->trans('Canceled');
+ $labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft');
+ $labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Started');
+ $labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Canceled');
- return dolGetStatus($labelStatus[$status], $labelStatus[$status], '', 'status'.$status, $mode);
+ return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', 'status'.$status, $mode);
}
/**
@@ -506,7 +603,6 @@ class InventoryLine extends CommonObjectLine
*/
public $picto = 'stock';
-
/**
* 'type' if the field format.
* 'label' the translation key.
@@ -546,6 +642,28 @@ class InventoryLine extends CommonObjectLine
*/
public $rowid;
+ public $fk_inventory;
+ public $fk_warehouse;
+ public $fk_product;
+ public $batch;
+ public $datec;
+ public $tms;
+ public $qty_stock;
+ public $qty_view;
+ public $qty_regulated;
+
+
+ /**
+ * Create object in database
+ *
+ * @param User $user User that creates
+ * @param bool $notrigger false=launch triggers after, true=disable triggers
+ * @return int <0 if KO, >0 if OK
+ */
+ public function create(User $user, $notrigger = false)
+ {
+ return $this->createCommon($user, $notrigger);
+ }
/**
* Load object in memory from the database
diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php
index 5261b0432b8..0d91546ad56 100644
--- a/htdocs/product/inventory/inventory.php
+++ b/htdocs/product/inventory/inventory.php
@@ -250,7 +250,7 @@ if ($object->id > 0)
// Buttons for actions
- if ($action == 'edit') {
+ if ($action == 'record') {
print '