prepare( "SELECT sku, product_name, uom FROM md_product WHERE company_id = :company_id AND sku = :sku AND status > 0 LIMIT 1" ); $sth->execute([':company_id' => $company_id, ':sku' => $sku]); return $sth->fetch(PDO::FETCH_ASSOC); } function activeStockLotExists(PDO $pdo, int $company_id, string $sku, string $lot): bool { $warehouses = $pdo->prepare( "SELECT id FROM md_warehouse WHERE company_id = :company_id AND status = 1" ); $warehouses->execute([':company_id' => $company_id]); foreach ($warehouses->fetchAll(PDO::FETCH_COLUMN) as $warehouse_id) { $table = stockTableNameFromWarehouseId((int)$warehouse_id); $sth = $pdo->prepare( "SELECT ROUND(SUM(COALESCE(`in`, 0)) - SUM(COALESCE(`out`, 0)), 2) AS balance FROM `{$table}` WHERE company_id = :company_id AND product_sku = :product_sku AND lot_number = :lot_number AND status = 1" ); $sth->execute([ ':company_id' => $company_id, ':product_sku' => $sku, ':lot_number' => $lot, ]); if ((float)$sth->fetchColumn() > 0) return true; } return false; } function findLot(PDO $pdo, int $company_id, string $sku, string $lot): array|false { $sth = $pdo->prepare( "SELECT l.product_sku, l.lot_number, l.expiry_date, p.product_name, p.uom FROM md_lot l INNER JOIN md_product p ON p.company_id = l.company_id AND p.sku = l.product_sku WHERE l.company_id = :company_id AND l.product_sku = :product_sku AND l.lot_number = :lot_number AND p.status > 0 LIMIT 1" ); $sth->execute([ ':company_id' => $company_id, ':product_sku' => $sku, ':lot_number' => $lot, ]); $row = $sth->fetch(PDO::FETCH_ASSOC); if ($row) return $row; $product = findProduct($pdo, $company_id, $sku); if (!$product || !activeStockLotExists($pdo, $company_id, $sku, $lot)) return false; return [ 'product_sku' => $product['sku'], 'lot_number' => $lot, 'expiry_date' => null, 'product_name' => $product['product_name'], 'uom' => $product['uom'], ]; } function listLabels(PDO $pdo, int $company_id, string $sku, string $lot): array { $params = [':company_id' => $company_id]; $where = "WHERE b.company_id = :company_id"; if ($sku !== '') { $where .= " AND b.product_sku = :product_sku"; $params[':product_sku'] = $sku; } if ($lot !== '') { $where .= " AND b.lot_number = :lot_number"; $params[':lot_number'] = $lot; } $sth = $pdo->prepare( "SELECT b.id, b.product_sku, b.lot_number, b.serial_number, b.barcode, b.status, b.print_count, b.last_printed_dt, b.created_dt, p.product_name FROM md_barcode b LEFT JOIN md_product p ON p.company_id = b.company_id AND p.sku = b.product_sku {$where} AND b.barcode_type = 'sku' ORDER BY b.created_dt DESC, b.id DESC" ); $sth->execute($params); return $sth->fetchAll(PDO::FETCH_ASSOC); } $label_action = $data['label_action'] ?? 'read'; $product_sku = trim($data['product_sku'] ?? ''); $lot_number = trim($data['lot_number'] ?? ''); if (in_array($label_action, ['create', 'print', 'disable', 'enable'], true)) { require_role($user_role, ['owner', 'admin', 'staff']); } if ($label_action === 'print') { $barcode = trim($data['barcode'] ?? ''); if ($barcode === '') { $answer['message'] = 'No barcode provided.'; http_response_code(400); exit(json_encode($answer)); } $sth = $pdo2->prepare( "UPDATE md_barcode SET print_count = print_count + 1, last_printed_dt = NOW() WHERE company_id = :company_id AND barcode = :barcode AND barcode_type = 'sku' AND status = 1" ); $sth->execute([':company_id' => $company_id, ':barcode' => $barcode]); $answer['success'] = 1; exit(json_encode($answer)); } if ($label_action === 'disable') { $barcode = trim($data['barcode'] ?? ''); if ($barcode === '') { $answer['message'] = 'No barcode provided.'; http_response_code(400); exit(json_encode($answer)); } $sth = $pdo2->prepare( "UPDATE md_barcode SET status = 0 WHERE company_id = :company_id AND barcode = :barcode AND barcode_type = 'sku' AND status = 1" ); $sth->execute([':company_id' => $company_id, ':barcode' => $barcode]); $answer['success'] = 1; exit(json_encode($answer)); } if ($label_action === 'create') { $serial_number = trim($data['serial_number'] ?? ''); $allow_unlisted = !empty($data['allow_unlisted']); if ($product_sku === '' || $lot_number === '' || $serial_number === '') { $answer['message'] = 'SKU, lot no, and serial no are required.'; http_response_code(400); exit(json_encode($answer)); } $lot = findLot($pdo2, $company_id, $product_sku, $lot_number); if (!$lot) { if (!$allow_unlisted) { $answer['message'] = 'Lot not found.'; http_response_code(404); exit(json_encode($answer)); } $product = findProduct($pdo2, $company_id, $product_sku); if (!$product) { $answer['message'] = 'SKU not found.'; http_response_code(404); exit(json_encode($answer)); } $lot = [ 'product_sku' => $product['sku'], 'lot_number' => $lot_number, 'expiry_date' => null, 'product_name' => $product['product_name'], 'uom' => $product['uom'], ]; } $barcode = "SKU|{$product_sku}|{$lot_number}|{$serial_number}"; $sth = $pdo2->prepare( "INSERT INTO md_barcode (company_id, barcode_type, barcode, product_sku, lot_number, serial_number) VALUES (:company_id, 'sku', :barcode, :product_sku, :lot_number, :serial_number) ON DUPLICATE KEY UPDATE barcode_type = VALUES(barcode_type), product_sku = VALUES(product_sku), lot_number = VALUES(lot_number), serial_number = VALUES(serial_number), status = 1" ); $sth->execute([ ':company_id' => $company_id, ':product_sku' => $product_sku, ':lot_number' => $lot_number, ':serial_number' => $serial_number, ':barcode' => $barcode, ]); $answer['success'] = 1; $answer['output'] = [ 'product_sku' => $product_sku, 'product_name' => $lot['product_name'], 'lot_number' => $lot_number, 'serial_number' => $serial_number, 'barcode' => $barcode, ]; exit(json_encode($answer)); } $answer['success'] = 1; $answer['output'] = listLabels($pdo2, $company_id, $product_sku, $lot_number); exit(json_encode($answer)); ?>