load("scrap"); if (!$user->rights->scrap->read) accessforbidden(); $action = GETPOST('action', 'alpha'); $id = (int) GETPOST('id', 'int'); /* --------------------------------------------------------------------- DELETE SCRAP + RESTORE STOCK --------------------------------------------------------------------- */ if ($action === 'delete' && $id > 0) { $token = GETPOST('token', 'alpha'); if (empty($token) || $token !== $_SESSION['newtoken']) accessforbidden('Invalid CSRF token'); $sqlCheck = "SELECT s.rowid, s.fk_product, s.fk_warehouse, s.qty, s.cost, s.reason, p.ref AS product_ref, p.label AS product_label FROM " . MAIN_DB_PREFIX . "scrap s LEFT JOIN " . MAIN_DB_PREFIX . "product p ON s.fk_product = p.rowid WHERE s.rowid = " . ((int)$id); $resCheck = $db->query($sqlCheck); $objCheck = $db->fetch_object($resCheck); if ($objCheck) { $db->begin(); $movement = new MouvementStock($db); $movement->origin_type = 'scrap'; $movement->origin_id = $id; $movement->setOrigin('scrap', $id); // $desc = $langs->trans('ScrapDeletedAndStockRestored') . ' (' . $objCheck->product_ref . ' - ' . $objCheck->product_label . ')'; $userInitials = strtoupper(substr($user->firstname, 0, 1) . substr($user->lastname, 0, 1)); $dateStr = dol_print_date(dol_now(), 'dayhour'); $qtyStr = (fmod($objCheck->qty, 1) == 0) ? intval($objCheck->qty) : number_format($objCheck->qty, 2); $totalCost = price2num($objCheck->cost * $objCheck->qty, 'MU'); $desc = sprintf( "ScrapDeletedAndStockRestored: %s | Product: %s - %s | Qty Restored: %s | UnitCost: %s | TotalCost: %s | Reason: %s | By: %s", $dateStr, $objCheck->product_ref, $objCheck->product_label, $qtyStr, price2num($objCheck->cost, 'MU'), $totalCost, (!empty($objCheck->reason) ? $objCheck->reason : 'N/A'), $userInitials ); $result = $movement->reception( $user, (int)$objCheck->fk_product, (int)$objCheck->fk_warehouse, abs((float)$objCheck->qty), (float)$objCheck->cost, $desc ); if ($result > 0) { // โœ… Delete scrap record $db->query("DELETE FROM " . MAIN_DB_PREFIX . "scrap WHERE rowid = " . ((int)$id)); $db->commit(); // ๐Ÿ’ฐ Compute total cost (qty ร— unit cost) $total_cost = (float)$objCheck->qty * (float)$objCheck->cost; // ๐Ÿงฉ Load product & warehouse details require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php'; $product = new Product($db); $warehouse = new Entrepot($db); $product->fetch($objCheck->fk_product); $warehouse->fetch($objCheck->fk_warehouse); // ๐Ÿงพ Detailed confirmation message setEventMessages( $langs->trans("ScrapDeletedAndStockRestored") . "
" . $langs->trans("Product") . ": " . dol_escape_htmltag($product->ref . " - " . $product->label) . "
" . $langs->trans("Warehouse") . ": " . dol_escape_htmltag($warehouse->ref) . "
" . $langs->trans("Qty") . ": " . number_format($objCheck->qty, 0) . "
" . $langs->trans("Unit Cost") . ": " . price($objCheck->cost, 0, $langs, 0, 0, -1) . "
" . $langs->trans("Total Cost") . ": " . price($total_cost, 0, $langs, 0, 0, -1) . "
" . $langs->trans("Reason") . ": " . (!empty($objCheck->reason) ? dol_escape_htmltag($objCheck->reason) : $langs->trans("NoReasonProvided")), null, 'mesgs' ); } else { $db->rollback(); // โŒ Detailed error message $total_cost = (float)$objCheck->qty * (float)$objCheck->cost; setEventMessages( $langs->trans("StockRestoreFailed") . "
" . $langs->trans("Product") . ": " . dol_escape_htmltag($product->ref . " - " . $product->label) . "
" . $langs->trans("Qty") . ": " . number_format($objCheck->qty, 0) . "
" . $langs->trans("Unit Cost") . ": " . price($objCheck->cost, 0, $langs, 0, 0, -1) . "
" . $langs->trans("Total Cost") . ": " . price($total_cost, 0, $langs, 0, 0, -1) . "
" . $langs->trans("Error") . ": " . dol_escape_htmltag($movement->error), null, 'errors' ); } } else { setEventMessages($langs->trans("ScrapNotFound"), null, 'errors'); } } /* --------------------------------------------------------------------- SEARCH + PAGINATION --------------------------------------------------------------------- */ $search = trim(GETPOST('search', 'alpha')); $page = max(0, (int) GETPOST('page', 'int')); $limit = 20; $offset = $page * $limit; $sql = "SELECT s.rowid, s.qty, s.cost, s.reason, s.scrap_date, p.rowid as prod_id, p.ref as product_ref, p.label as product_label, e.ref as warehouse_ref, u.firstname, u.lastname FROM " . MAIN_DB_PREFIX . "scrap s LEFT JOIN " . MAIN_DB_PREFIX . "product p ON s.fk_product = p.rowid LEFT JOIN " . MAIN_DB_PREFIX . "entrepot e ON s.fk_warehouse = e.rowid LEFT JOIN " . MAIN_DB_PREFIX . "user u ON s.fk_user_scrap = u.rowid WHERE s.entity = " . ((int)$conf->entity); if ($search) { $sql .= " AND (p.ref LIKE '%" . $db->escape($search) . "%' OR p.label LIKE '%" . $db->escape($search) . "%' OR s.reason LIKE '%" . $db->escape($search) . "%')"; } $sql .= " ORDER BY s.scrap_date DESC LIMIT $limit OFFSET $offset"; $resql = $db->query($sql); llxHeader('', $langs->trans("ScrapManagement")); print load_fiche_titre($langs->trans("ScrapManagement")); /* --------------------------------------------------------------------- ACTION BUTTONS BAR --------------------------------------------------------------------- */ print '
'; /* Add Scrap */ print '' . $langs->trans("AddScrap") . ''; /* Search */ print '
'; print ''; print ''; if ($search) { print '' . $langs->trans("ResetFilter") . ''; } print '
'; print '

'; /* --------------------------------------------------------------------- SCRAP TABLE --------------------------------------------------------------------- */ print '
'; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; // โœ… initialize total sum $sumTotalCost = 0; if ($resql && $db->num_rows($resql) > 0) { while ($obj = $db->fetch_object($resql)) { $totalCost = price2num($obj->qty * $obj->cost, 'MU'); $sumTotalCost += $totalCost; $userInitials = ($obj->firstname || $obj->lastname) ? strtoupper(substr($obj->firstname, 0, 1) . substr($obj->lastname, 0, 1)) : ''; $qtyDisplay = (fmod($obj->qty, 1) == 0) ? intval($obj->qty) : rtrim(rtrim(number_format($obj->qty, 2, '.', ''), '0'), '.'); print ''; print ''; print ''; print ''; print ''; $totalCost = price2num($obj->qty * $obj->cost, 'MU'); print ''; print ''; print ''; print ''; print ''; print ''; } } else { print ''; } // --- Totals row --- print ''; print ''; print ''; print ''; print ''; print '
' . $langs->trans('Product') . '' . $langs->trans('Warehouse') . '' . $langs->trans('Qty') . '' . $langs->trans('Unit Cost') . '' . $langs->trans('Total Cost') . '' . $langs->trans('Reason') . '' . $langs->trans("Date") . '' . $langs->trans("AddedBy") . '' . $langs->trans("Events") . '
' . dol_escape_htmltag($obj->product_ref) . '' . dol_escape_htmltag($obj->warehouse_ref) . '' . $qtyDisplay . '' . price($obj->cost, 0, $langs, 0, 0, 0, $conf->currency) . '' . price($totalCost, 0, $langs, 0, 0, 0, $conf->currency) . '' . dol_escape_htmltag($obj->reason) . '' . dol_print_date(dol_stringtotime($obj->scrap_date), 'dayhour') . '' . $userInitials . ' ' . $langs->trans("Delete") . '
' . $langs->trans("NoScrapFound") . '
' . $langs->trans('Total Cost') . '' . price($sumTotalCost, 0, $langs, 0, 0, 0, $conf->currency) . '
'; print '
'; /* --------------------------------------------------------------------- PAGINATION --------------------------------------------------------------------- */ print ''; ?>

trans("ConfirmDeletion"); ?>

close(); ?>