Work on inventory

This commit is contained in:
Laurent Destailleur 2020-08-05 12:25:26 +02:00
parent 201c3f87ca
commit 1f02b33195
7 changed files with 212 additions and 65 deletions

View File

@ -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');

View File

@ -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.

View File

@ -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

View File

@ -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
CurrentStock=Current stock
InventoryRealQtyHelp=Set value to 0 to reset qty<br>Keep field empty, or remove line, to keep unchanged

View File

@ -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 '<input type="hidden" name="action" value="add">';
if ($backtopage) print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
if ($backtopageforcancel) print '<input type="hidden" name="backtopageforcancel" value="'.$backtopageforcancel.'">';
dol_fiche_head(array(), '');
// Set some default values
//if (! GETPOSTISSET('fieldname')) $_POST['fieldname'] = 'myvalue';
print '<table class="border centpercent tableforfieldcreate">'."\n";
// Common attributes
@ -228,7 +228,7 @@ if (($id || $ref) && $action == 'edit')
print '<input type="hidden" name="id" value="'.$object->id.'">';
if ($backtopage) print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
if ($backtopageforcancel) print '<input type="hidden" name="backtopageforcancel" value="'.$backtopageforcancel.'">';
dol_fiche_head();
print '<table class="border centpercent tableforfieldedit">'."\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 '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes">'.$langs->trans("SetToDraft").'</a>';
}
}
// Modify
if ($permissiontoadd)
if ($object->status == $object::STATUS_DRAFT)
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit">'.$langs->trans("Modify").'</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
if ($permissiontoadd)
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit">'.$langs->trans("Modify").'</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\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 '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_validate&confirm=yes">'.$langs->trans("Validate").'</a>';
} else {
$langs->load("errors");
print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>';
}
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_validate&confirm=yes">'.$langs->trans("Validate").' ('.$langs->trans("Start").')</a>';
}
}
// Clone
/*if ($permissiontoadd)
{
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&socid='.$object->socid.'&action=clone&object=myobject">'.$langs->trans("ToClone").'</a>'."\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';

View File

@ -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

View File

@ -250,7 +250,7 @@ if ($object->id > 0)
// Buttons for actions
if ($action == 'edit') {
if ($action == 'record') {
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="update">';
@ -276,19 +276,36 @@ if ($object->id > 0)
{
if ($permissiontoadd)
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=edit">'.$langs->trans("Edit").'</a>'."\n";
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_validate&confirm=yes">'.$langs->trans("Validate").' ('.$langs->trans("Start").')</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Edit').'</a>'."\n";
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Validate').' ('.$langs->trans("Start").')</a>'."\n";
}
}
if ($object->status == Inventory::STATUS_DRAFT)
if ($object->status == Inventory::STATUS_VALIDATED)
{
if ($permissiontoadd)
{
if ($conf->barcode->enabled) {
print '<a href="#" class="butAction">'.$langs->trans("UpdateByScanningProductBarcode").'</a>';
}
if ($conf->productbatch->enabled) {
print '<a href="#" class="butAction">'.$langs->trans('UpdateByScaningLot').'</a>';
}
//print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=savecurrent">'.$langs->trans("Save").'</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Save').'</a>'."\n";
}
}
if ($object->status == Inventory::STATUS_VALIDATED)
{
if ($permissiontoadd)
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=validate">'.$langs->trans("Validate").'</a>'."\n";
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=record">'.$langs->trans("Finish").'</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Validate').'</a>'."\n";
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Finish').'</a>'."\n";
}
}
@ -325,24 +342,25 @@ if ($object->id > 0)
print $langs->trans("Batch");
print '</td>';
}
print '<td class="right">'.$langs->trans("RecordedQty").'</td>';
print '<td class="right">'.$langs->trans("RealQty").'</td>';
print '<td>';
print '<td class="right">'.$langs->trans("ExpectedQty").'</td>';
print '<td class="center">';
print $form->textwithpicto($langs->trans("RealQty"), $langs->trans("InventoryRealQtyHelp"));
print '</td>';
// Actions
print '<td class="center">';
print '</td>';
print '</tr>';
$sql = 'SELECT ps.rowid, ps.fk_entrepot as fk_warehouse, ps.fk_product';
$sql .= ' FROM '.MAIN_DB_PREFIX.'product_stock as ps, '.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;
// Request to show lines of inventory (prefilled during creation)
$sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,';
$sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated';
$sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id';
$sql .= ' WHERE id.fk_inventory = '.$object->id;
$cacheOfProducts = array();
$cacheOfWarehouses = array();
//$sql = '';
$resql = $db->query($sql);
if ($resql)
{
@ -386,18 +404,18 @@ if ($object->id > 0)
if ($conf->productbatch->enabled) {
print '<td>';
print '';
print $obj->batch;
print '</td>';
}
print '<td>';
print '';
print '<td class="right">';
print 'TODO';
print '</td>';
print '<td>';
print '';
print '<td class="center">';
print '<input type="text" class="maxwidth75" name="id_'.$obj->rowid.' value="'.GETPOST("id_".$obj->rowid).'">';
print '</td>';
print '<td>';
print '';
print '<td class="right">';
print img_delete();
print '</td>';
print '</tr>';