Barcode Scan + Barcode Print
This commit is contained in:
@@ -28,6 +28,359 @@ class Items extends CI_Controller {
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function item_barcodes($item_id)
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "draft_items",
|
||||
"item_id" => $item_id
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('items/barcode_sn', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function load_data_barcode($item_id)
|
||||
{
|
||||
$item = $this->db
|
||||
->where('id', $item_id)
|
||||
->get('items')
|
||||
->row();
|
||||
|
||||
if (!$item) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Data barang tidak ditemukan.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$next = $this->db
|
||||
->where('item_id', $item_id)
|
||||
->where('serial_number IS NULL', NULL, false)
|
||||
->order_by('id', 'ASC')
|
||||
->get('item_barcodes')
|
||||
->row();
|
||||
|
||||
$list = $this->db
|
||||
->where('item_id', $item_id)
|
||||
->order_by('id', 'ASC')
|
||||
->get('item_barcodes')
|
||||
->result();
|
||||
|
||||
$total = count($list);
|
||||
|
||||
$done = 0;
|
||||
foreach ($list as $row) {
|
||||
if (!empty($row->serial_number)) {
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'item_status' => $item->status,
|
||||
'next' => $next,
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'done' => $done,
|
||||
'percent' => $total > 0 ? round(($done / $total) * 100) : 0
|
||||
]);
|
||||
}
|
||||
|
||||
public function print_barcode($item_id)
|
||||
{
|
||||
require_once APPPATH.'third_party/fpdf/fpdf.php';
|
||||
require_once APPPATH.'libraries/phpqrcode/qrlib.php';
|
||||
|
||||
$barcodes = $this->db
|
||||
->where('item_id',$item_id)
|
||||
->order_by('id','ASC')
|
||||
->get('item_barcodes')
|
||||
->result();
|
||||
|
||||
if(empty($barcodes)){
|
||||
show_error('Barcode tidak ditemukan.');
|
||||
}
|
||||
|
||||
$column=(int)$this->input->get('column');
|
||||
if(!in_array($column,[1,2,3])){
|
||||
$column=3;
|
||||
}
|
||||
|
||||
$duplicate=(int)$this->input->get('duplicat');
|
||||
if($duplicate<1){
|
||||
$duplicate=1;
|
||||
}
|
||||
|
||||
$labelWidth=33.3;
|
||||
$labelHeight=23.2;
|
||||
|
||||
$spaceX=0;
|
||||
$spaceY=0;
|
||||
|
||||
$rowPerPage=6;
|
||||
|
||||
$paperWidth=$labelWidth*$column;
|
||||
$paperHeight=$labelHeight*$rowPerPage;
|
||||
|
||||
$marginLeft=0;
|
||||
$marginTop=0;
|
||||
|
||||
$labelPerPage=$column*$rowPerPage;
|
||||
|
||||
$pdf=new FPDF('P','mm',array($paperWidth,$paperHeight));
|
||||
$pdf->SetMargins(0,0,0);
|
||||
$pdf->SetAutoPageBreak(false);
|
||||
$pdf->AddPage();
|
||||
|
||||
$tempDir=FCPATH.'uploads/temp_qr/';
|
||||
if(!is_dir($tempDir)){
|
||||
mkdir($tempDir,0777,true);
|
||||
}
|
||||
|
||||
$printData=[];
|
||||
foreach($barcodes as $row){
|
||||
for($i=0;$i<$duplicate;$i++){
|
||||
$printData[]=$row;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($printData as $i=>$row){
|
||||
|
||||
if($i>0 && $i%$labelPerPage==0){
|
||||
$pdf->AddPage();
|
||||
}
|
||||
|
||||
$pageIndex=$i%$labelPerPage;
|
||||
|
||||
$col=$pageIndex%$column;
|
||||
$line=floor($pageIndex/$column);
|
||||
|
||||
// $x=$marginLeft+(($labelWidth+$spaceX)*$col);
|
||||
// $y=$marginTop+(($labelHeight+$spaceY)*$line);
|
||||
|
||||
$x=$col*$labelWidth;
|
||||
$y=$line*$labelHeight;
|
||||
|
||||
$qrFile=$tempDir.$row->barcode.'.png';
|
||||
|
||||
if(!file_exists($qrFile)){
|
||||
QRcode::png(
|
||||
$row->barcode,
|
||||
$qrFile,
|
||||
QR_ECLEVEL_L,
|
||||
4,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
$qrSize=15;
|
||||
|
||||
$pdf->Image(
|
||||
$qrFile,
|
||||
$x+16,
|
||||
$y+4,
|
||||
$qrSize,
|
||||
$qrSize
|
||||
);
|
||||
|
||||
$textWidth=14;
|
||||
|
||||
$pdf->SetFont('Arial','B',7);
|
||||
|
||||
$pdf->SetXY($x+2,$y+4);
|
||||
|
||||
$pdf->MultiCell(
|
||||
$textWidth,
|
||||
3,
|
||||
$row->barcode,
|
||||
0,
|
||||
'L'
|
||||
);
|
||||
|
||||
$serial=empty($row->serial_number)?'-':$row->serial_number;
|
||||
|
||||
$pdf->SetFont('Arial','B',4.5);
|
||||
|
||||
$pdf->SetXY($x+2,$y+11);
|
||||
|
||||
$pdf->MultiCell(
|
||||
$textWidth+2,
|
||||
3,
|
||||
'SN: ' . $serial,
|
||||
0,
|
||||
'L'
|
||||
);
|
||||
}
|
||||
|
||||
$pdf->Output(
|
||||
'I',
|
||||
'Barcode-'.$item_id.'.pdf'
|
||||
);
|
||||
}
|
||||
|
||||
public function save_serial_number()
|
||||
{
|
||||
$barcode_id = $this->input->post('barcode_id');
|
||||
$serial = trim($this->input->post('serial_number'));
|
||||
|
||||
if($serial==""){
|
||||
echo json_encode(array(
|
||||
'status'=>false,
|
||||
'message'=>'Serial Number wajib diisi'
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
$cek = $this->db
|
||||
->where('serial_number',$serial)
|
||||
->count_all_results('item_barcodes');
|
||||
if($cek){
|
||||
echo json_encode(array(
|
||||
'status'=>false,
|
||||
'message'=>'Serial Number sudah digunakan'
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
$barcode = $this->db
|
||||
->where('id',$barcode_id)
|
||||
->get('item_barcodes')
|
||||
->row();
|
||||
$this->db->where('id',$barcode_id);
|
||||
$this->db->update('item_barcodes',array(
|
||||
'serial_number'=>$serial
|
||||
));
|
||||
// langsung kirim data terbaru
|
||||
$_GET['item_id']=$barcode->item_id;
|
||||
$this->load_data_barcode($barcode->item_id);
|
||||
}
|
||||
|
||||
public function delete_serial_number()
|
||||
{
|
||||
$barcode_id = (int)$this->input->post('barcode_id');
|
||||
|
||||
if ($barcode_id <= 0) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Barcode tidak valid.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ambil data barcode
|
||||
$barcode = $this->db
|
||||
->where('id', $barcode_id)
|
||||
->get('item_barcodes')
|
||||
->row();
|
||||
|
||||
if (!$barcode) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Barcode tidak ditemukan.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hapus Serial Number
|
||||
$this->db
|
||||
->where('id', $barcode_id)
|
||||
->update('item_barcodes', [
|
||||
'serial_number' => NULL
|
||||
]);
|
||||
|
||||
// Kirim ulang data terbaru
|
||||
$this->load_data_barcode($barcode->item_id);
|
||||
}
|
||||
|
||||
public function get_barcode_item()
|
||||
{
|
||||
$barcode = trim($this->input->post('barcode'));
|
||||
|
||||
if ($barcode == '') {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Barcode kosong.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$row = $this->db
|
||||
->select('
|
||||
ib.id AS barcode_id,
|
||||
ib.barcode,
|
||||
ib.serial_number,
|
||||
i.id AS item_id,
|
||||
i.kode_detail,
|
||||
i.nama_barang,
|
||||
i.status,
|
||||
i.harga_beli,
|
||||
i.harga_jual
|
||||
')
|
||||
->from('item_barcodes ib')
|
||||
->join('items i','i.id=ib.item_id')
|
||||
->where('ib.barcode',$barcode)
|
||||
->get()
|
||||
->row();
|
||||
|
||||
if(!$row){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Barcode tidak ditemukan.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status'=>true,
|
||||
'data'=>$row
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_list_barcode_id($item_id)
|
||||
{
|
||||
// $item_id = trim($this->input->post('item_id'));
|
||||
|
||||
if ($item_id == '') {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Item belum dipilih'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$row = $this->db
|
||||
->select('
|
||||
ib.id AS barcode_id,
|
||||
ib.barcode,
|
||||
ib.serial_number,
|
||||
i.id AS item_id,
|
||||
i.kode_detail,
|
||||
i.nama_barang,
|
||||
i.status,
|
||||
i.harga_beli,
|
||||
i.harga_jual
|
||||
')
|
||||
->from('item_barcodes ib')
|
||||
->join('items i','i.id=ib.item_id')
|
||||
->where('ib.item_id',$item_id)
|
||||
// ->where('ib.status','warehouse')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
if(!$row){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Item barang tidak ditemukan.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
echo json_encode($row);
|
||||
}
|
||||
|
||||
|
||||
// =========================
|
||||
// GET DATA (FIX)
|
||||
// =========================
|
||||
@@ -51,6 +404,7 @@ class Items extends CI_Controller {
|
||||
items.stok,
|
||||
items.status,
|
||||
items.kode_id,
|
||||
kode.need_serial_number,
|
||||
(
|
||||
SELECT GROUP_CONCAT(DISTINCT w.nama SEPARATOR ", ")
|
||||
FROM stock_logs sl
|
||||
@@ -58,6 +412,8 @@ class Items extends CI_Controller {
|
||||
WHERE sl.item_id = items.id
|
||||
) as gudang
|
||||
');
|
||||
|
||||
$this->db->join('kode_barang kode', 'items.kode_id = kode.id', 'left');
|
||||
|
||||
if ($status !== 'all') {
|
||||
$this->db->where('items.status', $status);
|
||||
@@ -70,72 +426,66 @@ class Items extends CI_Controller {
|
||||
$this->db->from('items');
|
||||
|
||||
$data = $this->db->get()->result();
|
||||
|
||||
// $this->db->select('
|
||||
// items.id,
|
||||
// items.nama_barang,
|
||||
// items.kode_detail,
|
||||
// items.harga_beli,
|
||||
// items.harga_jual,
|
||||
// items.tanggal_pembelian,
|
||||
// items.created_at,
|
||||
// items.stok,
|
||||
// items.status,
|
||||
// items.kode_id,
|
||||
// (
|
||||
// SELECT GROUP_CONCAT(DISTINCT w.nama SEPARATOR ", ")
|
||||
// FROM stock_logs sl
|
||||
// LEFT JOIN warehouses w ON sl.warehouse_id = w.id
|
||||
// WHERE sl.item_id = items.id
|
||||
// ) as gudang
|
||||
// ');
|
||||
|
||||
// if ($status !== 'all') {
|
||||
// $this->db->where('items.status', $status);
|
||||
// }
|
||||
|
||||
// // 🔥 filter utama per kode_id
|
||||
// $this->db->where("
|
||||
// (items.stok > 0)
|
||||
// OR
|
||||
// (
|
||||
// items.stok = 0
|
||||
// AND items.tanggal_pembelian = (
|
||||
// SELECT MAX(i2.tanggal_pembelian)
|
||||
// FROM items i2
|
||||
// WHERE i2.stok = 0
|
||||
// AND i2.kode_id = items.kode_id
|
||||
// )
|
||||
// )
|
||||
// ", null, false);
|
||||
|
||||
// // urutan
|
||||
// $this->db->order_by('items.stok = 0', 'ASC', false);
|
||||
// $this->db->order_by('items.tanggal_pembelian', 'ASC');
|
||||
|
||||
// $this->db->from('items');
|
||||
|
||||
// $data = $this->db->get()->result();
|
||||
|
||||
|
||||
$result = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($data as $row){
|
||||
|
||||
$btnDetail = '<button class="btn btn-info btn-sm btn-detail m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Detail</button>';
|
||||
$btnEdit = '<button class="btn btn-secondary btn-sm btn-editItem m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Edit</button>';
|
||||
$btnDelete = '<button class="btn btn-danger btn-sm btn-delete m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Delete</button>';
|
||||
$btnDetail = '<button class="btn btn-info btn-sm btn-detail m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Detail</button>';
|
||||
$btnEdit = '<button class="btn btn-secondary btn-sm btn-editItem m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Edit</button>';
|
||||
$btnDelete = '<button class="btn btn-danger btn-sm btn-delete m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Delete</button>';
|
||||
$btnInsertSn = '<a href="'.base_url('items/item_barcodes/'.$row->id).'" class="btn btn-secondary btn-sm m-1">Barcode</a>';
|
||||
$btnPrintBarcode = '<button class="btn btn-secondary btn-sm btn-print m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'"><i class="bi bi-printer"></i> Print Barcode</button>';
|
||||
|
||||
if ($row->need_serial_number == 'true') {
|
||||
|
||||
$list = $this->db
|
||||
->where('item_id', $row->id)
|
||||
->order_by('id', 'ASC')
|
||||
->get('item_barcodes')
|
||||
->result();
|
||||
|
||||
$total = count($list);
|
||||
|
||||
$done = 0;
|
||||
foreach ($list as $barcode) {
|
||||
if (!empty($barcode->serial_number)) {
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
|
||||
$total_sn = $total;
|
||||
$done_sn = $done;
|
||||
|
||||
if ($row->status == 'draft') {
|
||||
if ($total_sn == $done_sn) {
|
||||
$btnSN = $btnInsertSn . $btnPrintBarcode;
|
||||
} else {
|
||||
$btnSN = $btnInsertSn ;
|
||||
}
|
||||
} else {
|
||||
$btnSN = $btnPrintBarcode;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$btnSN = $btnPrintBarcode;
|
||||
}
|
||||
|
||||
if($row->status == 'draft'){
|
||||
$btnPost = '<button class="btn btn-success btn-sm btn-updatePosting m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Posting</button>';
|
||||
$action = $btnDetail . $btnPost . $btnDelete;
|
||||
$action = $btnDetail . $btnPost . $btnDelete . $btnSN;
|
||||
|
||||
} else {
|
||||
|
||||
if($this->session->userdata('role') == 'Admin') {
|
||||
$btnAdjust = '<button class="btn btn-warning btn-sm btn-adjust m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Adjust</button>';
|
||||
} else {
|
||||
$btnAdjust = '';
|
||||
}
|
||||
$action = $btnDetail . $btnEdit . $btnAdjust . $btnDelete;
|
||||
$action = $btnDetail . $btnEdit . $btnAdjust . $btnDelete . $btnSN;
|
||||
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
@@ -221,6 +571,7 @@ class Items extends CI_Controller {
|
||||
$account_kas = $this->input->post('account_kas');
|
||||
$kode_id = $this->input->post('kode_id');
|
||||
$tanggal_beli = $this->input->post('tanggal_beli');
|
||||
$tracking_qty = $this->input->post('tracking_qty');
|
||||
$status = $this->input->post('status');
|
||||
|
||||
// ================= VALIDASI =================
|
||||
@@ -246,6 +597,33 @@ class Items extends CI_Controller {
|
||||
$tanggal_kode = date('dmy', strtotime($tanggal_beli));
|
||||
$kode_detail = $kode->kode_barang . '-' . $tanggal_kode;
|
||||
|
||||
if ($kode->tracking_type != 'UNIT') {
|
||||
|
||||
if (empty($tracking_qty) || $tracking_qty <= 0) {
|
||||
echo json_encode(array(
|
||||
'status' => false,
|
||||
'message' => 'Jumlah Per (Roll, Box, Dus) harus diisi'
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($qty % $tracking_qty != 0) {
|
||||
echo json_encode(array(
|
||||
'status' => false,
|
||||
'message' => 'Jumlah Barang harus habis dibagi Jumlah Per (Roll, Box, Dus)'
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($kode->tracking_type == 'UNIT') {
|
||||
$unit_qty = $qty;
|
||||
$tracking_qty = 1;
|
||||
} else {
|
||||
$unit_qty = $qty / $tracking_qty;
|
||||
}
|
||||
|
||||
$total = $qty * $harga_beli;
|
||||
|
||||
$this->db->trans_start();
|
||||
@@ -274,6 +652,68 @@ class Items extends CI_Controller {
|
||||
'created_at'=>date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// ================= Item Barcode Masuk =================
|
||||
for ($i = 1; $i <= $unit_qty; $i++) {
|
||||
|
||||
$barcode = sprintf('%s-%04d', $kode_detail, $i);
|
||||
|
||||
$this->db->insert('item_barcodes',[
|
||||
'item_id' => $item_id,
|
||||
'barcode' => $barcode,
|
||||
'serial_number' => null,
|
||||
'warehouse_id' => $warehouse_id,
|
||||
'qty_awal' => $tracking_qty,
|
||||
'qty_sisa' => $tracking_qty,
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
$barcode_id = $this->db->insert_id();
|
||||
|
||||
$this->db->insert('item_movements',[
|
||||
'item_id' => $item_id,
|
||||
'barcode_id' => $barcode_id,
|
||||
'qty' => $tracking_qty,
|
||||
'from_type' => 'supplier', //enum('supplier','warehouse','technician','customer')
|
||||
'to_type' => 'warehouse', //enum('supplier','warehouse','technician','customer')
|
||||
'movement_type' => 'purchase', //enum('purchase','transfer','installation','uninstallation','supplier_return','customer_return','adjustment')
|
||||
'notes' => 'Pembelian barang dari supplier',
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
}
|
||||
// CREATE TABLE `item_barcodes` (
|
||||
// `id` int NOT NULL AUTO_INCREMENT,
|
||||
// `item_id` int NOT NULL,
|
||||
// `barcode` varchar(100) NOT NULL,
|
||||
// `serial_number` varchar(100) DEFAULT NULL,
|
||||
// `warehouse_id` int DEFAULT NULL,
|
||||
// `qty_awal` decimal(15,2) DEFAULT NULL,
|
||||
// `qty_sisa` decimal(15,2) DEFAULT NULL,
|
||||
// `status` enum('available','reserved','installed','damaged','lost','returned_supplier') DEFAULT 'available',
|
||||
// `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
// PRIMARY KEY (`id`),
|
||||
// UNIQUE KEY `uk_barcode` (`barcode`),
|
||||
// KEY `idx_item` (`item_id`),
|
||||
// KEY `idx_warehouse` (`warehouse_id`),
|
||||
// CONSTRAINT `fk_barcode_item` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
|
||||
// CREATE TABLE `item_movements` (
|
||||
// `id` int NOT NULL AUTO_INCREMENT,
|
||||
// `item_id` int NOT NULL,
|
||||
// `barcode_id` int DEFAULT NULL,
|
||||
// `qty` decimal(15,2) NOT NULL DEFAULT '1.00',
|
||||
// `from_type` enum('supplier','warehouse','technician','customer') DEFAULT NULL,
|
||||
// `from_id` int DEFAULT NULL,
|
||||
// `to_type` enum('supplier','warehouse','technician','customer') DEFAULT NULL,
|
||||
// `to_id` int DEFAULT NULL,
|
||||
// `movement_type` enum('purchase','transfer','installation','uninstallation','supplier_return','customer_return','adjustment') NOT NULL,
|
||||
// `reference_type` varchar(50) DEFAULT NULL,
|
||||
// `reference_id` int DEFAULT NULL,
|
||||
// `notes` varchar(255) DEFAULT NULL,
|
||||
// `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
|
||||
// ================= JURNAL =================
|
||||
$no_ref = 'BLI-'.date('Ymd').'-'.$item_id;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user