Update history peralatan di bawah teknisi
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
# CodeGraph data files — local to each machine, not for committing.
|
||||||
|
# Ignore everything in .codegraph/ except this file itself, so transient
|
||||||
|
# files (the database, daemon.pid, sockets, logs) never show up in git.
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
@@ -35,5 +35,7 @@ user_guide_src/cilexer/pycilexer.egg-info/*
|
|||||||
*.sublime-project
|
*.sublime-project
|
||||||
/tests/tests/
|
/tests/tests/
|
||||||
/tests/results/
|
/tests/results/
|
||||||
|
/dev-docs/
|
||||||
|
/ai-rules/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,345 @@
|
|||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
class Teknisi extends CI_Controller {
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->load->model('PeralatanTeknisi_model', 'ptm');
|
||||||
|
|
||||||
|
if (!$this->session->userdata('logged_in')) {
|
||||||
|
redirect('auth');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
"active_menu" => "peralatan_teknisi",
|
||||||
|
"teknisi_list" => $this->ptm->get_teknisi_list()
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->load->view('partials/header', $data);
|
||||||
|
$this->load->view('peralatan_teknisi/layout', $data);
|
||||||
|
$this->load->view('partials/footer');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_data()
|
||||||
|
{
|
||||||
|
$user_id = $this->input->get('user_id');
|
||||||
|
$status = $this->input->get('status') ?: 'active';
|
||||||
|
|
||||||
|
log_message('debug', '[get_data] user_id: ' . var_export($user_id, true) . ', status: ' . $status);
|
||||||
|
|
||||||
|
$data = $this->ptm->get_barang_dibawa($user_id, $status);
|
||||||
|
|
||||||
|
log_message('debug', '[get_data] query returned ' . count($data) . ' rows');
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$no = 1;
|
||||||
|
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$result[] = [
|
||||||
|
$no++,
|
||||||
|
htmlspecialchars($row->barcode, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->nama_barang, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->serial_number, ENT_QUOTES, 'UTF-8'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
log_message('debug', '[get_data] response: ' . json_encode(['data' => $result]));
|
||||||
|
echo json_encode(['data' => $result]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scan_item()
|
||||||
|
{
|
||||||
|
$barcode = trim($this->input->get('barcode'));
|
||||||
|
|
||||||
|
if (empty($barcode)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'QR Code tidak boleh kosong']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $this->ptm->get_item_by_barcode($barcode);
|
||||||
|
|
||||||
|
if (!$item) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Barcode tidak ditemukan']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$teknisi = $this->ptm->get_current_teknisi($item->barcode);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'status' => true,
|
||||||
|
'message' => 'Barang ditemukan',
|
||||||
|
'data' => [
|
||||||
|
'barcode' => $item->barcode,
|
||||||
|
'nama_barang' => $item->nama_barang,
|
||||||
|
'serial_number' => $item->serial_number,
|
||||||
|
'barcode_id' => $item->barcode_id,
|
||||||
|
'item_id' => $item->item_id,
|
||||||
|
'teknisi_id' => $teknisi ? $teknisi->user_id : null,
|
||||||
|
'teknisi_name' => $teknisi ? $teknisi->full_name : null,
|
||||||
|
'teknisi_code' => $teknisi ? $teknisi->employee_code : null
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batch_kembalikan()
|
||||||
|
{
|
||||||
|
$barcodes = $this->input->post('barcodes');
|
||||||
|
|
||||||
|
if (empty($barcodes) || !is_array($barcodes)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Tidak ada barcode yang dipilih']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->ptm->batch_kembalikan($barcodes);
|
||||||
|
echo json_encode($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batch_dibawa()
|
||||||
|
{
|
||||||
|
$barcodes = $this->input->post('barcodes');
|
||||||
|
$user_id = (int)$this->input->post('user_id');
|
||||||
|
|
||||||
|
if (empty($barcodes) || !is_array($barcodes)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Tidak ada barcode yang dipilih']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($user_id)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Pilih teknisi terlebih dahulu']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->ptm->batch_dibawa($barcodes, $user_id);
|
||||||
|
echo json_encode($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_table()
|
||||||
|
{
|
||||||
|
$draw = (int)$this->input->get('draw');
|
||||||
|
$start = (int)$this->input->get('start');
|
||||||
|
$length = (int)$this->input->get('length');
|
||||||
|
$search = $this->input->get('search')['value'] ?? '';
|
||||||
|
$order_col = (int)$this->input->get('order')[0]['column'] ?? 1;
|
||||||
|
$order_dir = $this->input->get('order')[0]['dir'] ?? 'asc';
|
||||||
|
|
||||||
|
$data = $this->ptm->get_teknisi_table_data($start, $length, $search, $order_col, $order_dir);
|
||||||
|
|
||||||
|
$total_filtered = $this->ptm->count_filtered_teknisi($search);
|
||||||
|
$total_all = $this->ptm->count_all_teknisi();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$no = $start + 1;
|
||||||
|
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$item_count = (int)$row->item_count;
|
||||||
|
$item_text = $item_count . ' Item';
|
||||||
|
|
||||||
|
$aksi = '<button class="btn btn-info btn-sm btn-detail-teknisi" data-id="'.$row->id.'" title="Detail">
|
||||||
|
<i class="bi bi-eye"></i>
|
||||||
|
</button>';
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
$no++,
|
||||||
|
htmlspecialchars($row->full_name, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->employee_code, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->department_name, ENT_QUOTES, 'UTF-8') ?: '-',
|
||||||
|
$item_text,
|
||||||
|
$aksi
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'draw' => $draw,
|
||||||
|
'recordsTotal' => $total_all,
|
||||||
|
'recordsFiltered' => $total_filtered,
|
||||||
|
'data' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function teknisi_detail()
|
||||||
|
{
|
||||||
|
$user_id = (int)$this->input->get('user_id');
|
||||||
|
|
||||||
|
if (!$user_id) {
|
||||||
|
echo json_encode(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = $this->ptm->get_teknisi_info($user_id);
|
||||||
|
echo json_encode($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_items()
|
||||||
|
{
|
||||||
|
$user_id = (int)$this->input->get('user_id');
|
||||||
|
$draw = (int)$this->input->get('draw');
|
||||||
|
$start = (int)$this->input->get('start');
|
||||||
|
$length = (int)$this->input->get('length');
|
||||||
|
$search = $this->input->get('search')['value'] ?? '';
|
||||||
|
$order_col = (int)$this->input->get('order')[0]['column'] ?? 2;
|
||||||
|
$order_dir = $this->input->get('order')[0]['dir'] ?? 'asc';
|
||||||
|
|
||||||
|
if (!$user_id) {
|
||||||
|
echo json_encode(['draw' => $draw, 'recordsTotal' => 0, 'recordsFiltered' => 0, 'data' => []]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->ptm->get_teknisi_items_data($user_id, $start, $length, $search, $order_col, $order_dir);
|
||||||
|
|
||||||
|
$total_filtered = $this->ptm->count_filtered_teknisi_items($user_id, $search);
|
||||||
|
$total_all = $this->ptm->count_all_teknisi_items($user_id);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$no = $start + 1;
|
||||||
|
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$badge = $row->status == 'active'
|
||||||
|
? '<span class="badge bg-success">Dibawa</span>'
|
||||||
|
: '<span class="badge bg-secondary">' . htmlspecialchars($row->status, ENT_QUOTES, 'UTF-8') . '</span>';
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
$no++,
|
||||||
|
htmlspecialchars($row->barcode, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->nama_barang, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->serial_number, ENT_QUOTES, 'UTF-8') ?: '-',
|
||||||
|
htmlspecialchars($row->qty_sisa, ENT_QUOTES, 'UTF-8') ?: '0',
|
||||||
|
$badge
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'draw' => $draw,
|
||||||
|
'recordsTotal' => $total_all,
|
||||||
|
'recordsFiltered' => $total_filtered,
|
||||||
|
'data' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_transfer_data()
|
||||||
|
{
|
||||||
|
$data = $this->ptm->get_transfer_data();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$no = 1;
|
||||||
|
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$result[] = [
|
||||||
|
$no++,
|
||||||
|
htmlspecialchars($row->barcode, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->nama_barang, ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars(($row->from_code ?? '') . ' - ' . ($row->from_name ?? ''), ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars(($row->to_code ?? '') . ' - ' . ($row->to_name ?? ''), ENT_QUOTES, 'UTF-8'),
|
||||||
|
htmlspecialchars($row->created_at, ENT_QUOTES, 'UTF-8'),
|
||||||
|
'<span class="badge bg-success">Selesai</span>'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['data' => $result]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batch_transfer()
|
||||||
|
{
|
||||||
|
$barcodes = $this->input->post('barcodes');
|
||||||
|
$from_user_id = (int)$this->input->post('from_user_id');
|
||||||
|
$to_user_id = (int)$this->input->post('to_user_id');
|
||||||
|
|
||||||
|
$technician = $this->ptm->get_teknisi_info($to_user_id);
|
||||||
|
|
||||||
|
log_message('debug', 'batch_transfer POST: ' . json_encode([
|
||||||
|
'barcodes' => $barcodes,
|
||||||
|
'from_user_id' => $from_user_id,
|
||||||
|
'to_user_id' => $to_user_id
|
||||||
|
]));
|
||||||
|
|
||||||
|
if (empty($barcodes) || !is_array($barcodes)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Tidak ada barcode yang dipilih']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($from_user_id) || empty($to_user_id)) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Pilih teknisi asal dan tujuan']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($from_user_id == $to_user_id) {
|
||||||
|
echo json_encode(['status' => false, 'message' => 'Teknisi tujuan tidak boleh sama dengan teknisi asal']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$this->db->trans_start();
|
||||||
|
|
||||||
|
foreach ($barcodes as $barcode) {
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if ($barcode == '') continue;
|
||||||
|
|
||||||
|
$item = $this->db
|
||||||
|
->select('it.*, ib.id as barcode_id, tec.full_name as teknisi_name')
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->join('k_employees tec', 'tec.id = it.user_id', 'left')
|
||||||
|
->where('it.barcode', $barcode)
|
||||||
|
->where('it.status', 'active')
|
||||||
|
->where('it.user_id', $from_user_id)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
|
||||||
|
if (!$item) {
|
||||||
|
$errors[] = "Barcode $barcode tidak ditemukan pada teknisi asal";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_message('debug', 'batch_transfer item: ' . json_encode($item));
|
||||||
|
|
||||||
|
$this->db
|
||||||
|
->where('barcode', $item->barcode)
|
||||||
|
->where('user_id', $from_user_id)
|
||||||
|
->where('status', 'active')
|
||||||
|
->update('item_technician', [
|
||||||
|
'user_id' => $to_user_id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->db->insert('item_movements', [
|
||||||
|
'item_id' => $item->item_id,
|
||||||
|
'barcode_id' => $item->barcode_id,
|
||||||
|
'qty' => 1,
|
||||||
|
'from_type' => 'technician',
|
||||||
|
'from_id' => $from_user_id,
|
||||||
|
'to_type' => 'technician',
|
||||||
|
'to_id' => $to_user_id,
|
||||||
|
'movement_type' => 'transfer',
|
||||||
|
'notes' => 'Transfer Barang dari: ' . $item->teknisi_name . ' ke ' . $technician->full_name,
|
||||||
|
'created_at' => $now
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->trans_complete();
|
||||||
|
|
||||||
|
if ($this->db->trans_status() === FALSE) {
|
||||||
|
$db_error = $this->db->error();
|
||||||
|
log_message('error', 'batch_transfer gagal: ' . json_encode($db_error));
|
||||||
|
echo json_encode([
|
||||||
|
'status' => false,
|
||||||
|
'message' => 'Gagal memproses transfer',
|
||||||
|
'debug' => $db_error['message'] ?? 'Unknown database error'
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$success_count = count($barcodes) - count($errors);
|
||||||
|
$msg = "$success_count barang berhasil ditransfer";
|
||||||
|
if (count($errors) > 0) {
|
||||||
|
$msg .= '. ' . implode(', ', $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['status' => true, 'message' => $msg, 'errors' => $errors]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ class PDF extends FPDF
|
|||||||
// Judul
|
// Judul
|
||||||
$this->SetFont('Arial', 'B', 13);
|
$this->SetFont('Arial', 'B', 13);
|
||||||
$this->SetTextColor(245, 140, 0);
|
$this->SetTextColor(245, 140, 0);
|
||||||
$this->Cell(0, 7, 'LAPORAN NERACA SALDO', 0, 1, 'C');
|
$this->Cell(0, 7, 'LAPORAN KEUANGAN', 0, 1, 'C');
|
||||||
$this->SetTextColor(0, 0, 0);
|
$this->SetTextColor(0, 0, 0);
|
||||||
|
|
||||||
// Periode
|
// Periode
|
||||||
|
|||||||
@@ -0,0 +1,486 @@
|
|||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
class PeralatanTeknisi_model extends CI_Model {
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_list()
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->select('e.id, e.employee_code, e.full_name, p.position_name, d.department_name')
|
||||||
|
->from('k_employees e')
|
||||||
|
->join('k_positions p', 'p.id = e.position_id', 'left')
|
||||||
|
->join('k_departments d', 'd.id = e.department_id', 'left')
|
||||||
|
->where('(e.resign_date IS NULL OR e.resign_date = \'0000-00-00\')')
|
||||||
|
->where_in('LOWER(p.position_name)', ['teknisi', 'noc'])
|
||||||
|
->order_by('e.full_name', 'ASC')
|
||||||
|
->get()
|
||||||
|
->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_barang_dibawa($user_id = null, $status = 'active')
|
||||||
|
{
|
||||||
|
$this->db
|
||||||
|
->select("
|
||||||
|
it.barcode,
|
||||||
|
it.user_id,
|
||||||
|
it.item_id,
|
||||||
|
it.status,
|
||||||
|
it.created_at,
|
||||||
|
ib.serial_number,
|
||||||
|
i.nama_barang,
|
||||||
|
i.kode_detail,
|
||||||
|
ke.full_name as teknisi_name,
|
||||||
|
ke.employee_code
|
||||||
|
")
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->join('items i', 'i.id = it.item_id', 'left')
|
||||||
|
->join('k_employees ke', 'ke.id = it.user_id', 'left');
|
||||||
|
|
||||||
|
if ($user_id) {
|
||||||
|
$this->db->where('it.user_id', $user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status && in_array($status, ['active', 'inactive'])) {
|
||||||
|
$this->db->where('it.status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->order_by('it.created_at', 'DESC');
|
||||||
|
|
||||||
|
return $this->db->get()->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_item_by_barcode($barcode)
|
||||||
|
{
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if ($barcode == '') return null;
|
||||||
|
|
||||||
|
$row = $this->db
|
||||||
|
->select('ib.id as barcode_id, ib.item_id, ib.barcode, ib.serial_number, ib.qty_sisa, ib.status as barcode_status, i.nama_barang, i.kode_detail')
|
||||||
|
->from('item_barcodes ib')
|
||||||
|
->join('items i', 'i.id = ib.item_id', 'left')
|
||||||
|
->where('ib.barcode', $barcode)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
$row = $this->db
|
||||||
|
->select('ib.id as barcode_id, ib.item_id, ib.barcode, ib.serial_number, ib.qty_sisa, ib.status as barcode_status, i.nama_barang, i.kode_detail')
|
||||||
|
->from('item_barcodes ib')
|
||||||
|
->join('items i', 'i.id = ib.item_id', 'left')
|
||||||
|
->where('ib.serial_number', $barcode)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_current_teknisi($barcode)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->select('it.user_id, ke.full_name, ke.employee_code')
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('k_employees ke', 'ke.id = it.user_id', 'left')
|
||||||
|
->where('it.barcode', $barcode)
|
||||||
|
->where('it.status', 'active')
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batch_kembalikan(array $barcodes)
|
||||||
|
{
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$this->db->trans_start();
|
||||||
|
|
||||||
|
foreach ($barcodes as $barcode) {
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if ($barcode == '') continue;
|
||||||
|
|
||||||
|
$item = $this->db
|
||||||
|
->select('it.*, ib.id as barcode_id, tec.full_name as teknisi_name')
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->join('k_employees tec', 'tec.id = it.user_id', 'left')
|
||||||
|
->where('it.barcode', $barcode)
|
||||||
|
->where('it.status', 'active')
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
|
||||||
|
if (!$item) {
|
||||||
|
$errors[] = "Barcode $barcode tidak ditemukan atau sudah dikembalikan";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->insert('item_movements', [
|
||||||
|
'item_id' => $item->item_id,
|
||||||
|
'barcode_id' => $item->barcode_id,
|
||||||
|
'qty' => 1,
|
||||||
|
'from_type' => 'technician',
|
||||||
|
'from_id' => $item->user_id,
|
||||||
|
'to_type' => 'warehouse',
|
||||||
|
'to_id' => null,
|
||||||
|
'movement_type' => 'transfer',
|
||||||
|
'notes' => 'Pengembalian dari: ' . $item->teknisi_name . ' ke gudang',
|
||||||
|
'created_at' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->db
|
||||||
|
->where('barcode', $barcode)
|
||||||
|
->where('status', 'active')
|
||||||
|
->update('item_technician', [
|
||||||
|
'status' => 'inactive',
|
||||||
|
'deleted_at' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($item->barcode_id) {
|
||||||
|
$this->db
|
||||||
|
->where('id', $item->barcode_id)
|
||||||
|
->update('item_barcodes', [
|
||||||
|
'status' => 'available'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->trans_complete();
|
||||||
|
|
||||||
|
if ($this->db->trans_status() === FALSE) {
|
||||||
|
return ['status' => false, 'message' => 'Gagal memproses pengembalian'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$success_count = count($barcodes) - count($errors);
|
||||||
|
$msg = "$success_count barang berhasil dikembalikan";
|
||||||
|
if (count($errors) > 0) {
|
||||||
|
$msg .= '. ' . implode(', ', $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['status' => true, 'message' => $msg, 'errors' => $errors];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batch_dibawa(array $barcodes, $user_id)
|
||||||
|
{
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$errors = [];
|
||||||
|
$skipped = 0;
|
||||||
|
|
||||||
|
$technician = $this->db
|
||||||
|
->select('id, full_name, employee_code')
|
||||||
|
->from('k_employees')
|
||||||
|
->where('id', $user_id)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
|
||||||
|
$this->db->trans_start();
|
||||||
|
|
||||||
|
foreach ($barcodes as $barcode) {
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if ($barcode == '') continue;
|
||||||
|
|
||||||
|
$barcode_row = $this->db
|
||||||
|
->select('ib.id as barcode_id, ib.item_id, ib.barcode')
|
||||||
|
->from('item_barcodes ib')
|
||||||
|
->where('ib.barcode', $barcode)
|
||||||
|
->where_not_in('ib.status', ['damaged', 'lost', 'returned_supplier', 'sold_out'])
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
|
||||||
|
if (!$barcode_row) {
|
||||||
|
$errors[] = "Barcode $barcode tidak valid atau tidak tersedia";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$already = $this->db
|
||||||
|
->where('barcode', $barcode_row->barcode)
|
||||||
|
->where('status', 'active')
|
||||||
|
->get('item_technician')
|
||||||
|
->row();
|
||||||
|
|
||||||
|
if ($already) {
|
||||||
|
if ($already->user_id == $user_id) {
|
||||||
|
$skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$errors[] = "Barang $barcode sedang dibawa teknisi lain";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->insert('item_technician', [
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'barcode' => $barcode_row->barcode,
|
||||||
|
'item_id' => $barcode_row->item_id,
|
||||||
|
'status' => 'active',
|
||||||
|
'created_at' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
$last_movement = $this->db
|
||||||
|
->where('barcode_id', $barcode_row->barcode_id)
|
||||||
|
->order_by('id', 'DESC')
|
||||||
|
->limit(1)
|
||||||
|
->get('item_movements')
|
||||||
|
->row();
|
||||||
|
|
||||||
|
$from_type = 'warehouse';
|
||||||
|
$from_id = null;
|
||||||
|
if ($last_movement) {
|
||||||
|
$from_type = $last_movement->to_type;
|
||||||
|
$from_id = $last_movement->to_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->insert('item_movements', [
|
||||||
|
'item_id' => $barcode_row->item_id,
|
||||||
|
'barcode_id' => $barcode_row->barcode_id,
|
||||||
|
'qty' => 1,
|
||||||
|
'from_type' => $from_type,
|
||||||
|
'from_id' => $from_id,
|
||||||
|
'to_type' => 'technician',
|
||||||
|
'to_id' => $user_id,
|
||||||
|
'movement_type' => 'transfer',
|
||||||
|
'notes' => 'Dibawa oleh: ' . $technician->full_name . ' dari gudang',
|
||||||
|
'created_at' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->db
|
||||||
|
->where('id', $barcode_row->barcode_id)
|
||||||
|
->update('item_barcodes', [
|
||||||
|
'status' => 'installed'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->trans_complete();
|
||||||
|
|
||||||
|
if ($this->db->trans_status() === FALSE) {
|
||||||
|
return ['status' => false, 'message' => 'Gagal memproses penugasan barang'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$success_count = count($barcodes) - count($errors) - $skipped;
|
||||||
|
$msg = "$success_count barang berhasil ditugaskan";
|
||||||
|
if ($skipped > 0) {
|
||||||
|
$msg .= ". $skipped barang sudah ditugaskan ke teknisi yang sama";
|
||||||
|
}
|
||||||
|
if (count($errors) > 0) {
|
||||||
|
$msg .= '. ' . implode(', ', $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['status' => true, 'message' => $msg, 'errors' => $errors];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_table_data($start, $length, $search, $order_col, $order_dir)
|
||||||
|
{
|
||||||
|
$sort_cols = [
|
||||||
|
1 => 'e.full_name',
|
||||||
|
2 => 'e.employee_code',
|
||||||
|
3 => 'd.department_name',
|
||||||
|
4 => 'item_count'
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->db
|
||||||
|
->select("
|
||||||
|
e.id,
|
||||||
|
e.full_name,
|
||||||
|
e.employee_code,
|
||||||
|
p.position_name,
|
||||||
|
d.department_name,
|
||||||
|
(SELECT COUNT(*) FROM item_technician it WHERE it.user_id = e.id AND it.status = 'active') as item_count
|
||||||
|
")
|
||||||
|
->from('k_employees e')
|
||||||
|
->join('k_positions p', 'p.id = e.position_id', 'left')
|
||||||
|
->join('k_departments d', 'd.id = e.department_id', 'left')
|
||||||
|
->where('(e.resign_date IS NULL OR e.resign_date = \'0000-00-00\')')
|
||||||
|
->where_in('LOWER(p.position_name)', ['teknisi', 'noc']);
|
||||||
|
|
||||||
|
if (!empty($search)) {
|
||||||
|
$this->db->group_start()
|
||||||
|
->like('LOWER(e.full_name)', strtolower($search))
|
||||||
|
->or_like('LOWER(e.employee_code)', strtolower($search))
|
||||||
|
->or_like('LOWER(d.department_name)', strtolower($search))
|
||||||
|
->group_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($sort_cols[$order_col])) {
|
||||||
|
$this->db->order_by($sort_cols[$order_col], $order_dir);
|
||||||
|
} else {
|
||||||
|
$this->db->order_by('e.full_name', 'ASC');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($length > 0) {
|
||||||
|
$this->db->limit($length, $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->get()->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count_all_teknisi()
|
||||||
|
{
|
||||||
|
$this->db
|
||||||
|
->from('k_employees e')
|
||||||
|
->join('k_positions p', 'p.id = e.position_id', 'left')
|
||||||
|
->where('(e.resign_date IS NULL OR e.resign_date = \'0000-00-00\')')
|
||||||
|
->where_in('LOWER(p.position_name)', ['teknisi', 'noc']);
|
||||||
|
|
||||||
|
return $this->db->count_all_results();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count_filtered_teknisi($search)
|
||||||
|
{
|
||||||
|
$this->db
|
||||||
|
->from('k_employees e')
|
||||||
|
->join('k_positions p', 'p.id = e.position_id', 'left')
|
||||||
|
->join('k_departments d', 'd.id = e.department_id', 'left')
|
||||||
|
->where('(e.resign_date IS NULL OR e.resign_date = \'0000-00-00\')')
|
||||||
|
->where_in('LOWER(p.position_name)', ['teknisi', 'noc']);
|
||||||
|
|
||||||
|
if (!empty($search)) {
|
||||||
|
$this->db->group_start()
|
||||||
|
->like('LOWER(e.full_name)', strtolower($search))
|
||||||
|
->or_like('LOWER(e.employee_code)', strtolower($search))
|
||||||
|
->or_like('LOWER(d.department_name)', strtolower($search))
|
||||||
|
->group_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->count_all_results();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_info($user_id)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->select('e.id, e.full_name, e.employee_code, p.position_name, d.department_name')
|
||||||
|
->from('k_employees e')
|
||||||
|
->join('k_positions p', 'p.id = e.position_id', 'left')
|
||||||
|
->join('k_departments d', 'd.id = e.department_id', 'left')
|
||||||
|
->where('e.id', $user_id)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_teknisi_items_data($user_id, $start, $length, $search, $order_col, $order_dir)
|
||||||
|
{
|
||||||
|
$sort_cols = [
|
||||||
|
1 => 'it.barcode',
|
||||||
|
2 => 'i.nama_barang',
|
||||||
|
3 => 'ib.serial_number',
|
||||||
|
4 => 'it.status'
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->db
|
||||||
|
->select("
|
||||||
|
it.barcode,
|
||||||
|
i.nama_barang,
|
||||||
|
ib.serial_number,
|
||||||
|
ib.qty_sisa,
|
||||||
|
it.status,
|
||||||
|
it.created_at
|
||||||
|
")
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('items i', 'i.id = it.item_id', 'left')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->where('it.user_id', $user_id)
|
||||||
|
->where('it.status', 'active');
|
||||||
|
|
||||||
|
if (!empty($search)) {
|
||||||
|
$this->db->group_start()
|
||||||
|
->like('it.barcode', $search)
|
||||||
|
->or_like('LOWER(i.nama_barang)', strtolower($search))
|
||||||
|
->or_like('ib.serial_number', $search)
|
||||||
|
->group_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($sort_cols[$order_col])) {
|
||||||
|
$this->db->order_by($sort_cols[$order_col], $order_dir);
|
||||||
|
} else {
|
||||||
|
$this->db->order_by('it.created_at', 'DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($length > 0) {
|
||||||
|
$this->db->limit($length, $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->get()->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count_all_teknisi_items($user_id)
|
||||||
|
{
|
||||||
|
$this->db
|
||||||
|
->from('item_technician it')
|
||||||
|
->where('it.user_id', $user_id)
|
||||||
|
->where('it.status', 'active');
|
||||||
|
|
||||||
|
return $this->db->count_all_results();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count_filtered_teknisi_items($user_id, $search)
|
||||||
|
{
|
||||||
|
$this->db
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('items i', 'i.id = it.item_id', 'left')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->where('it.user_id', $user_id)
|
||||||
|
->where('it.status', 'active');
|
||||||
|
|
||||||
|
if (!empty($search)) {
|
||||||
|
$this->db->group_start()
|
||||||
|
->like('it.barcode', $search)
|
||||||
|
->or_like('LOWER(i.nama_barang)', strtolower($search))
|
||||||
|
->or_like('ib.serial_number', $search)
|
||||||
|
->group_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->count_all_results();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_transfer_data()
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->select("
|
||||||
|
it.barcode,
|
||||||
|
i.nama_barang,
|
||||||
|
ib.serial_number,
|
||||||
|
from_ke.full_name as from_name,
|
||||||
|
from_ke.employee_code as from_code,
|
||||||
|
to_ke.full_name as to_name,
|
||||||
|
to_ke.employee_code as to_code,
|
||||||
|
im.created_at,
|
||||||
|
im.movement_type
|
||||||
|
")
|
||||||
|
->from('item_movements im')
|
||||||
|
->join('items i', 'i.id = im.item_id', 'left')
|
||||||
|
->join('item_barcodes ib', 'ib.id = im.barcode_id', 'left')
|
||||||
|
->join('k_employees from_ke', 'from_ke.id = im.from_id', 'left')
|
||||||
|
->join('k_employees to_ke', 'to_ke.id = im.to_id', 'left')
|
||||||
|
->where('im.movement_type', 'installation')
|
||||||
|
->where('im.from_type', 'technician')
|
||||||
|
->where('im.to_type', 'technician')
|
||||||
|
->order_by('im.created_at', 'DESC')
|
||||||
|
->limit(200)
|
||||||
|
->get()
|
||||||
|
->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail_by_barcode($barcode)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->select("
|
||||||
|
it.*,
|
||||||
|
ib.serial_number,
|
||||||
|
ib.qty_sisa,
|
||||||
|
ib.status as barcode_status,
|
||||||
|
i.nama_barang,
|
||||||
|
i.kode_detail,
|
||||||
|
ke.full_name as teknisi_name,
|
||||||
|
ke.employee_code
|
||||||
|
")
|
||||||
|
->from('item_technician it')
|
||||||
|
->join('item_barcodes ib', 'ib.barcode = it.barcode', 'left')
|
||||||
|
->join('items i', 'i.id = it.item_id', 'left')
|
||||||
|
->join('k_employees ke', 'ke.id = it.user_id', 'left')
|
||||||
|
->where('it.barcode', $barcode)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,7 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h4 class="mb-0 fw-bold">Laporan Keuangan</h4>
|
<h4 class="mb-0 fw-bold">Laporan Keuangan</h4>
|
||||||
|
|
||||||
<button type="button" class="btn btn-danger" id="generate_pdf">
|
|
||||||
Generate PDF
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
@@ -24,10 +22,13 @@
|
|||||||
value="<?= date('Y-m-t'); ?>">
|
value="<?= date('Y-m-t'); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-2 d-flex align-items-end">
|
<div class="col-md-2 d-flex align-items-end gap-2">
|
||||||
<button class="btn btn-primary w-100" id="btnFilter">
|
<button class="btn btn-warning w-100" id="btnFilter">
|
||||||
Tampilkan
|
Tampilkan
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="generate_pdf">
|
||||||
|
PDF
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['warehouses','items', 'kode_barang', 'draft_items']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
<a class="nav-link dropdown-toggle <?= in_array($active_menu, ['warehouses','items', 'kode_barang', 'draft_items', 'peralatan_teknisi']) ? 'active' : '' ?>" href="#" data-bs-toggle="dropdown">
|
||||||
<i class="bi bi-box-seam"></i> Gudang
|
<i class="bi bi-box-seam"></i> Gudang
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
@@ -191,6 +191,12 @@
|
|||||||
href="<?= base_url('kodebarang'); ?>">
|
href="<?= base_url('kodebarang'); ?>">
|
||||||
<i class="bi bi-code me-2"></i> Daftar Kode Barang
|
<i class="bi bi-code me-2"></i> Daftar Kode Barang
|
||||||
</a>
|
</a>
|
||||||
|
</li><hr class="dropdown-divider">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item <?= ($active_menu == 'peralatan_teknisi') ? 'active' : '' ?>"
|
||||||
|
href="<?= base_url('teknisi'); ?>">
|
||||||
|
<i class="bi bi-tools me-2"></i> Peralatan Teknisi
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user