Perubahan barcode dan inventory

This commit is contained in:
Wian Drs
2026-07-12 22:10:02 +07:00
parent 3ac6316da4
commit 3113d77242
21 changed files with 2989 additions and 1138 deletions
+339 -322
View File
@@ -34,7 +34,7 @@
<!-- MODAL -->
<div class="modal fade" id="modalItem">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-dialog modal-dialog-centered modal-xl">
<div class="modal-content">
<div class="modal-header bg-warning text-white">
@@ -45,44 +45,146 @@
<input type="hidden" id="id">
<div id="group_tanggal">
<label>Tanggal Pembelian</label>
<input type="date" id="tanggal_beli" class="form-control">
</div>
<div id="group_kode">
<label class="mt-2">Kode Barang</label>
<select id="kode_barang" class="form-control select-search"></select>
<div class="row">
<div class="col-md-6">
<div id="group_tanggal">
<label>Tanggal Pembelian</label>
<input type="date" id="tanggal_beli" class="form-control">
</div>
</div>
<div class="col-md-6">
<div id="group_kode">
<label class="mt-2">Kode Barang</label>
<select id="kode_barang" class="form-control select-search"></select>
</div>
</div>
</div>
<label>Nama Barang</label>
<input type="text" id="nama_barang" class="form-control">
<div id="group_qty">
<label class="mt-2">Jumlah Barang</label>
<input type="number" id="qty" class="form-control">
<div class="row">
<div class="col-md-2">
<div id="group_qty">
<label class="mt-2">Jumlah Barang</label>
<input type="number" id="qty" class="form-control">
</div>
</div>
<div class="col-md-2">
<div id="group_tracking_qty">
<label class="mt-2">Jml / (Roll, Box, Dus)</label>
<input type="number" id="tracking_qty" class="form-control">
</div>
</div>
<div class="col-md-4">
<label class="mt-2">Harga Beli</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="text" id="harga_beli" class="form-control format-rupiah">
</div>
</div>
<div class="col-md-4">
<label class="mt-2">Harga Jual</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="text" id="harga_jual" class="form-control format-rupiah">
</div>
</div>
</div>
<div id="group_tracking_qty">
<label class="mt-2">Jumlah Per (Roll, Box, Dus)</label>
<input type="number" id="tracking_qty" class="form-control">
</div>
<label class="mt-2">Harga Beli</label>
<input type="text" id="harga_beli" class="form-control format-rupiah">
<label class="mt-2">Harga Jual</label>
<input type="text" id="harga_jual" class="form-control format-rupiah">
<div id="group_warehouse">
<label class="mt-2">Gudang</label>
<select id="warehouse_id" class="form-control"></select>
</div>
<div id="group_account">
<!-- <div class="row">
<label class="mt-2">Akun Kas</label>
<select id="account_kas" class="form-control"></select>
<div class="col-md-7">
<div id="group_account">
<select id="account_kas" class="form-control"></select>
</div>
</div>
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="text" id="account[]" class="form-control format-rupiah">
</div>
</div>
</div>
<button class="btn btn-warning btn-sm mt-4">Tambah Account</button> -->
<hr>
<label class="font-weight-bold">
Pembayaran
</label>
<div id="accountContainer">
<div class="row account-row mb-2">
<div class="col-md-6">
<select
name="account_kas[]"
class="form-control account_kas">
</select>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">Rp</span>
<input
type="text"
name="nominal[]"
class="form-control nominal format-rupiah">
</div>
</div>
<div class="col-md-2">
<button
type="button"
class="btn btn-sm btn-danger btn-remove-account w-100"
disabled>
Hapus
</button>
</div>
</div>
</div>
<div class="mt-2">
<button
type="button"
id="btnTambahAccount"
class="btn btn-warning btn-sm">
+ Tambah Account
</button>
</div>
<div class="mt-3">
<div class="row">
<div class="col-md-4">
<!-- total qty * harga beli -->
<h5>
Total :
<span id="totalHppBarang">
Rp 0
</span>
</h5>
</div>
<div class="col-md-4">
<!-- total accounting -->
<h5>
Total :
<span id="totalAccount">
Rp 0
</span>
</h5>
</div>
<div class="col-md-4">
<!-- balance accounting + total hpp barang -->
<h5>
Total :
<span id="totalAll">
Rp 0
</span>
</h5>
</div>
</div>
</div>
</div>
@@ -94,59 +196,6 @@
</div>
</div>
<!-- MODAL BARANAG KELUAR -->
<div class="modal fade" id="modalKeluar">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5>Barang Keluar</h5>
</div>
<div class="modal-body">
<div id="group_account_biaya">
<label class="mt-2">Akun Biaya</label>
<select id="account_biaya" class="form-control"></select>
</div>
<div>
<label>Tanggal</label>
<input type="date" id="tanggal_keluar" class="form-control">
</div>
<div>
<label class="mt-2">Gudang</label>
<select id="warehouse_id_keluar" class="form-control"></select>
</div>
<div class="d-none" id="group_barang_keluar">
<label class="mt-2">Barang</label>
<select id="barang_id" class="form-control select-search"></select>
</div>
<div class="d-none" id="group_qty_keluar">
<label class="mt-2">Jumlah Barang</label>
<input type="number" id="qty_keluar" class="form-control">
</div>
<div class="mb-2 d-none" id="group_keterangan">
<label for="keterangan" class="form-label">Keterangan</label>
<textarea class="form-control" id="keterangan_keluar" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger" id="btnKeluar">Keluarkan</button>
</div>
</div>
</div>
</div>
<!-- MODAL DETAIL -->
<div class="modal fade" id="modalDetail">
<div class="modal-dialog modal-lg">
@@ -163,46 +212,13 @@
</div>
<div class="modal fade" id="modalAdjust">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-warning">
<h5>Penyesuaian Stok</h5>
</div>
<div class="modal-body">
<input type="hidden" id="adjust_item_id">
<label>Qty Adjustment</label>
<input type="number" id="adjust_qty" class="form-control">
<small>Gunakan minus (-) jika mengurangi</small>
<label class="mt-2">Gudang</label>
<select id="adjust_warehouse" class="form-control"></select>
<label class="mt-2">Keterangan</label>
<input type="text" id="adjust_ket" class="form-control">
</div>
<div class="modal-footer">
<button class="btn btn-warning" id="btnAdjust">Simpan</button>
</div>
</div>
</div>
</div>
<script>
$(function(){
let action = 'add';
let selectedItemId = null;
let accountOption = '';
// ================= DATATABLE =================
let table = $('#tableItems').DataTable({
@@ -215,24 +231,26 @@ let table = $('#tableItems').DataTable({
});
// ================= LOAD AKUN KAS =================
// function loadKas(){
// $.get("<?= base_url('items/get_accounts'); ?>",res=>{
// let opt='<option value="">-- PILIH KAS --</option>';
// res.forEach(a=>{
// opt += `<option value="${a.id}">${a.nama_akun}</option>`;
// });
// $('#account_kas').html(opt);
// },'json');
// }
function loadKas(){
$.get("<?= base_url('items/get_accounts'); ?>",res=>{
let opt='<option value="">-- PILIH KAS --</option>';
res.forEach(a=>{
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
$.get("<?= base_url('items/get_accounts'); ?>",function(res){
accountOption = '<option value="">-- PILIH KAS --</option>';
res.forEach(function(a){
accountOption += `
<option value="${a.id}">
${a.nama_akun}
</option>
`;
});
$('#account_kas').html(opt);
},'json');
}
// ================= LOAD AKUN KAS =================
function loadKasOut(){
$.get("<?= base_url('items/get_accounts_biaya'); ?>",res=>{
let opt='<option value="">-- PILIH KAS --</option>';
res.forEach(a=>{
opt += `<option value="${a.id}">${a.nama_akun}</option>`;
});
$('#account_biaya').html(opt);
$('.account_kas').html(accountOption);
},'json');
}
@@ -246,26 +264,6 @@ function loadGudang(){
$('#warehouse_id, #adjust_warehouse').html(opt);
},'json');
}
// ================= LOAD GUDANG =================
function loadGudangList(){
$.get("<?= base_url('warehouses/list'); ?>",res=>{
let opt='<option value="">-- PILIH GUDANG --</option>';
res.forEach(w=>{
opt += `<option value="${w.id}">${w.nama}</option>`;
});
$('#warehouse_id_keluar').html(opt);
},'json');
}
// function loadKode(){
// $.get("<?= base_url('kodebarang/list'); ?>",res=>{
// let opt='<option value="">-- PILIH KODE --</option>';
// res.forEach(a=>{
// opt += `<option value="${a.id}" data-type="${a.tracking_type}">${a.kode_barang} - ${a.nama}</option>`;
// });
// $('#kode_barang').html(opt);
// },'json');
// }
function loadKode() {
$.get("<?= base_url('kodebarang/list'); ?>", function(res) {
@@ -285,6 +283,40 @@ function loadKode() {
}, 'json');
}
function addAccountRow(){
let html = `
<div class="row account-row mb-2">
<div class="col-md-6">
<select
name="account_kas[]"
class="form-control account_kas">
${accountOption}
</select>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">
Rp
</span>
<input
type="text"
name="nominal[]"
class="form-control nominal format-rupiah">
</div>
</div>
<div class="col-md-2">
<button
type="button"
class="btn btn-sm btn-danger btn-remove-account w-100">
Hapus
</button>
</div>
</div>
`;
$('#accountContainer').append(html);
hitungTotal();
}
$(document).on('change', '#kode_barang', function () {
let type = $(this).find(':selected').data('type');
@@ -298,6 +330,39 @@ $(document).on('change', '#kode_barang', function () {
});
$('#btnTambahAccount').click(function(){
addAccountRow();
});
$(document).on('click','.btn-remove-account',function(){
$(this).closest('.account-row').remove();
hitungTotal();
});
// function hitungTotal(){
// let total = 0;
// $('.nominal').each(function(){
// let angka = $(this)
// .val()
// .replace(/\./g,'')
// .replace(/,/g,'');
// total += Number(angka || 0);
// });
// $('#totalAccount').text(formatRupiah(total.toString()));
// }
$(document).on('keyup','.nominal',function(){
hitungTotal();
});
$(document).on('keyup','#harga_beli',function(){
hitungTotal();
});
$(document).on('keyup change','#qty',function(){
hitungTotal();
});
// ================= RESET FORM =================
function resetForm(){
$('#id').val('');
@@ -308,6 +373,42 @@ function resetForm(){
$('#tanggal_beli').val('');
$('#tracking_qty').val('');
$('#group_tracking_qty').hide();
$('#accountContainer').html(`
<div class="row account-row mb-2">
<div class="col-md-6">
<select
name="account_kas[]"
class="form-control account_kas">
${accountOption}
</select>
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">Rp</span>
<input
type="text"
name="nominal[]"
class="form-control nominal format-rupiah">
</div>
</div>
<div class="col-md-2">
<button
class="btn btn-sm btn-danger btn-remove-account w-100"
disabled>
Hapus
</button>
</div>
</div>
`);
$('#totalAccount').text('Rp 0');
$('#totalHppBarang').text('Rp 0');
$('#totalAll')
.text('Balance')
.removeClass('text-danger')
.addClass('text-success');
$('#btnSimpan').prop('disabled',true);
}
// ================= INIT LOAD =================
@@ -362,6 +463,40 @@ $('#btnSimpan').click(function(){
let btn = $(this);
let qtys = parseFloat($('#qty').val()) || 0;
let totalHpp = qtys * rupiahToNumber($('#harga_beli').val());
let totalAccount = 0;
$('.nominal').each(function(){
totalAccount += rupiahToNumber($(this).val());
});
if(totalHpp != totalAccount){
Swal.fire({
icon:'warning',
title:'Belum Balance',
text:'Total pembayaran harus sama dengan Total Harga Beli.'
});
return;
}
let account = [];
$('.account-row').each(function(){
account.push({
account_id: $(this).find('.account_kas').val(),
nominal: $(this)
.find('.nominal')
.val()
});
});
// data.accounts = account;
let data = {
id: $('#id').val(),
kode_id: $('#kode_barang').val(),
@@ -370,7 +505,8 @@ $('#btnSimpan').click(function(){
harga_beli: $('#harga_beli').val(),
harga_jual: $('#harga_jual').val(),
warehouse_id: $('#warehouse_id').val(),
account_kas: $('#account_kas').val(),
// account_kas: $('#account_kas').val(),
account_kas: account,
tanggal_beli: $('#tanggal_beli').val(),
tracking_qty: $('#tracking_qty').val(),
status: `draft`
@@ -423,122 +559,6 @@ $('#btnSimpan').click(function(){
});
// =====================================================
// ================= START URUSAN KELUAR ===============
// =====================================================
// ================= RESET FORM KELUAR =================
function resetFormKeluar(){
$('#tanggal_keluar').val('');
$('#qty_keluar').val('');
$('#keterangan_keluar').val('');
}
loadKasOut();
loadGudangList();
// ================= BARANG KELUAR ================= account_biaya warehouse_id barang_id
$('.btn-out').click(function(){
// action='add';
resetFormKeluar();
$('#warehouse_id').closest('div').show();
$('#account_biaya').closest('div').show();
$('#modalKeluar').modal('show');
loadGudangList();
loadKasOut();
});
$('#warehouse_id_keluar').on('change', function(){
let warehouse_id = $(this).val();
// $('#wrap_item_select').addClass('d-none');
$('#barang_id').html('<option value="">Loading...</option>');
loadItems(warehouse_id);
});
// ================= ITEMS =================
function loadItems(warehouse_id){
return $.get("<?= base_url('items/get_items_by_wh_id/'); ?>" + warehouse_id, function(res){
if(res && res.length){
let opt = '<option value="">-- PILIH BARANG --</option>';
res.forEach(i=>{
opt += `<option value="${i.id}">
${i.kode_detail} - ${i.nama_barang} (Stok: ${i.stok})
</option>`;
});
$('#barang_id').html(opt);
$('#group_barang_keluar').removeClass('d-none');
$('#group_qty_keluar').removeClass('d-none');
$('#group_keterangan').removeClass('d-none');
} else {
$('#barang_id').html(opt);
}
}, 'json');
}
// ================= SAVE =================
$('#btnKeluar').click(function(){
let btn = $(this);
let data = {
account_biaya: $('#account_biaya').val(),
tanggal_keluar: $('#tanggal_keluar').val(),
warehouse_id_keluar: $('#warehouse_id_keluar').val(),
barang_id: $('#barang_id').val(),
qty_keluar: $('#qty_keluar').val(),
keterangan_keluar: $('#keterangan_keluar').val()
};
let url = "<?= base_url('items/keluarkan'); ?>";
// 🔥 loading state
btn.prop('disabled', true).html('Menyimpan...');
$.post(url, data, function(res){
if(res.status){
$('#modalItem').modal('hide');
table.ajax.reload(null,false);
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: res.message || 'Data berhasil disimpan',
timer: 1500,
showConfirmButton: false
});
}else{
Swal.fire({
icon: 'error',
title: 'Gagal',
text: res.message || 'Terjadi kesalahan'
});
}
},'json')
.fail(function(){
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Koneksi ke server gagal'
});
})
.always(function(){
btn.prop('disabled', false).html('Keluarkan');
});
});
// =====================================================
// ================= END URUSAN KELUAR ===============
// =====================================================
// ================= PRINT BARCODE =================
$(document).on('click', '.btn-print', function () {
@@ -787,78 +807,75 @@ $(document).on('click','.btn-detail',function(){
});
// ================= OPEN ADJUST =================
$(document).on('click','.btn-adjust',function(){
function rupiahToNumber(value){
let id = $(this).data('id');
if(!value) return 0;
if(!id){
alert('Pilih item dari tabel (gunakan tombol Adjust di baris)');
return;
}
return parseInt(
value.toString()
.replace(/[^\d]/g,'')
) || 0;
selectedItemId = id;
$('#adjust_item_id').val(id);
$('#adjust_qty').val('');
$('#adjust_ket').val('');
}
$('#modalAdjust').modal('show');
});
function hitungTotal(){
// ================= SAVE ADJUST =================
$('#btnAdjust').click(function(){
// ==========================
// HPP BARANG
// ==========================
let btn = $(this);
let qty = parseFloat($('#qty').val()) || 0;
let hargaBeli = rupiahToNumber($('#harga_beli').val());
let data = {
item_id: $('#adjust_item_id').val(),
qty: $('#adjust_qty').val(),
warehouse_id: $('#adjust_warehouse').val(),
keterangan: $('#adjust_ket').val()
};
let totalHpp = qty * hargaBeli;
// 🔥 loading state
btn.prop('disabled', true).html('Menyimpan...');
$.post("<?= base_url('items/adjust'); ?>", data, function(res){
// ==========================
// ACCOUNTING
// ==========================
if(res.status){
let totalAccount = 0;
$('#modalAdjust').modal('hide');
table.ajax.reload(null,false);
$('.nominal').each(function(){
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: res.message || 'Stok berhasil disesuaikan',
timer: 1500,
showConfirmButton: false
});
totalAccount += rupiahToNumber($(this).val());
}else{
Swal.fire({
icon: 'error',
title: 'Gagal',
text: res.message || 'Gagal melakukan penyesuaian'
});
}
},'json')
.fail(function(){
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Koneksi ke server gagal'
});
})
.always(function(){
btn.prop('disabled', false).html('Simpan');
});
});
// ==========================
// BALANCE
// ==========================
let balance = totalAccount - totalHpp;
$('#totalHppBarang').text(formatRupiah(totalHpp.toString()));
$('#totalAccount').text(formatRupiah(totalAccount.toString()));
if(balance == 0){
$('#totalAll')
.removeClass('text-danger')
.addClass('text-success')
.text('Balance');
$('#btnSimpan').prop('disabled',false);
}else{
let prefix = balance > 0 ? '+' : '-';
$('#totalAll')
.removeClass('text-success')
.addClass('text-danger')
.text(prefix + ' ' + formatRupiah(Math.abs(balance).toString()));
$('#btnSimpan').prop('disabled',true);
}
}
});
</script>
+406
View File
@@ -0,0 +1,406 @@
<style>
body {
background: #f5f7fb;
}
/* ===========================
CARD
=========================== */
.main-card,
.scanner-card,
.table-card {
border: none;
border-radius: 18px;
overflow: hidden;
/*box-shadow: 0 8px 25px rgba(0, 0, 0, .08);*/
}
/* ===========================
HEADER
=========================== */
.header-gradient {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: #fff;
padding: 22px 28px;
}
.info-box {
background: rgba(255,255,255,.18);
border-radius: 12px;
padding: 12px 16px;
}
.progress {
height: 8px;
border-radius: 20px;
}
/* ===========================
SCANNER
=========================== */
.barcode-avatar {
width: 110px;
height: 110px;
margin: auto;
border-radius: 50%;
background: #fff7e6;
color: #f59e0b;
display: flex;
justify-content: center;
align-items: center;
font-size: 45px;
}
.barcode-code {
font-size: 22px;
font-weight: 700;
letter-spacing: 2px;
}
.form-control-lg {
height: 60px;
font-size: 22px;
border-radius: 12px;
}
.form-control:focus {
border-color: #f59e0b;
box-shadow: 0 0 0 .2rem rgba(245, 158, 11, .2);
}
.scan-note {
color: #6c757d;
font-size: 13px;
}
.camera-btn {
height: 55px;
border-radius: 12px;
font-size: 17px;
}
/* ===========================
TABLE
=========================== */
.table thead th {
background: #d97706;
color: #fff;
border: none;
vertical-align: middle;
}
.table tbody td {
vertical-align: middle;
}
.table tbody tr:hover {
background: #fffaf0;
}
/* ===========================
BADGE
=========================== */
.badge-success-soft {
display: inline-block;
padding: 6px 14px;
border-radius: 30px;
background: #d1fae5;
color: #065f46;
font-weight: 600;
}
.badge-danger-soft {
display: inline-block;
padding: 6px 14px;
border-radius: 30px;
background: #fee2e2;
color: #991b1b;
font-weight: 600;
}
.badge-warning-soft {
display: inline-block;
padding: 6px 14px;
border-radius: 30px;
background: #fef3c7;
color: #92400e;
font-weight: 600;
}
#reader{
width:100%;
min-height:280px;
border-radius:12px;
overflow:hidden;
}
</style>
<div class="container mt-4">
<div class="card main-card">
<!-- HEADER -->
<div class="header-gradient">
<div class="row align-items-center">
<div class="col-md-8">
<h3 class="mb-1">
<i class="fa fa-barcode"></i>
Riwayat Perpindahan Barang
</h3>
<div class="small">
Silahkan scan / input QR id Barang
</div>
</div>
<div class="col-md-4 text-right">
</div>
</div>
</div>
<!-- BODY -->
<div class="card-body">
<div class="row">
<!-- LEFT -->
<div class="col-lg-4 mb-4">
<div class="card scanner-card">
<div class="card-body">
<div class="barcode-avatar">
<i class="bi bi-qr-code-scan"></i>
</div>
<div class="text-center mt-3">
<div class="scan-note mt-2">
Scan QR ID
</div>
</div>
<hr>
<center>
<div id="scannerArea">
<input
type="text"
id="serial_number"
class="form-control form-control-lg text-center"
placeholder="Scan / Input QR ID"
autocomplete="off"
autofocus>
<small class="scan-note">
Scanner akan otomatis memanggil riwayat.
</small>
<button
type="button"
class="btn btn-warning btn-block camera-btn mt-4"
id="btnCamera">
<i class="fa fa-camera mr-2"></i>
Scan dengan Kamera
</button>
</div>
<div id="cameraArea" style="display:none;">
<div id="reader"></div>
<small class="scan-note d-block mt-2">
Arahkan QR Code ke kamera.
</small>
<button
type="button"
class="btn btn-secondary btn-block mt-3"
id="btnCloseCamera">
Tutup Kamera
</button>
</div>
</center>
<input type="hidden" id="barcode_id">
</div>
</div>
</div>
<!-- RIGHT -->
<div class="col-lg-8">
<div class="card table-card">
<div class="card-header bg-white">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">
Riwayat Perpindahan Barang
</h5>
</div>
</div>
<div class="card-body border-bottom" id="itemInfo">
Belum ada data
</div>
<div class="table-responsive">
<table class="table table-hover mb-0" id="tableBarcode">
<thead>
<tr>
<th width="60">No</th>
<th>Date</th>
<th>Type</th>
<th>From</th>
<th>To</th>
<th>NOtes</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$("#serial_number").keypress(function(e){
if(e.which==13){
searchHistory();
}
});
function searchHistory(){
let barcode=$("#serial_number").val().trim();
if(barcode=="") return;
$.ajax({
url: `<?= base_url("items/scan_history"); ?>`,
type:"POST",
dataType:"json",
data:{
barcode:barcode
},
beforeSend:function(){
$("#serial_number").prop("disabled",true);
},
success:function(r){
$("#serial_number")
.prop("disabled",false)
.val("")
.focus();
if(!r.status){
Swal.fire({
icon:"error",
text:r.message
});
return;
}
renderItem(r.item);
renderHistory(r.history);
}
});
}
function renderItem(item){
let html='';
html+='<div class="row">';
html+=' <div class="col-md-6">';
html+=' <h4 class="mb-3"><b>'+item.nama_barang+'</b></h4>';
html+=' <div class="row mb-2">';
html+=' <div class="col-4 font-weight-bold">Kode</div>';
html+=' <div class="col-1">:</div>';
html+=' <div class="col-7">'+item.kode_detail+'</div>';
html+=' </div>';
html+=' <div class="row mb-2">';
html+=' <div class="col-4 font-weight-bold">Barcode</div>';
html+=' <div class="col-1">:</div>';
html+=' <div class="col-7">'+item.barcode+'</div>';
html+=' </div>';
html+=' </div>';
html+=' <div class="col-md-6">';
html+=' <div class="row mb-2">';
html+=' <div class="col-4 font-weight-bold">Serial Number</div>';
html+=' <div class="col-1">:</div>';
html+=' <div class="col-7">'+(item.serial_number ? item.serial_number : '-')+'</div>';
html+=' </div>';
html+=' <div class="row mb-2">';
html+=' <div class="col-4 font-weight-bold">Status</div>';
html+=' <div class="col-1">:</div>';
html+=' <div class="col-7">'+item.status+'</div>';
html+=' </div>';
html+=' <div class="row mb-2">';
html+=' <div class="col-4 font-weight-bold">Qty</div>';
html+=' <div class="col-1">:</div>';
html+=' <div class="col-7">'+item.qty_sisa+' / '+item.qty_awal+'</div>';
html+=' </div>';
html+=' </div>';
html+='</div>';
$("#itemInfo").html(html);
}
function renderHistory(list){
let html='';
$.each(list,function(i,v){
html+="<tr>";
html+="<td>"+(i+1)+"</td>";
html+="<td>"+v.created_at+"</td>";
html+="<td>"+v.movement_type+"</td>";
html+="<td>"+(v.from_warehouse??v.from_type)+"</td>";
html+="<td>"+(v.to_warehouse??v.to_type)+"</td>";
html+="<td>"+v.notes+"</td>";
html+="</tr>";
});
$("#tableBarcode tbody").html(html);
}
let html5QrCode=null;
$("#btnCamera").click(function(){
$("#scannerArea").hide();
$("#cameraArea").show();
html5QrCode=new Html5Qrcode("reader");
html5QrCode.start(
{
facingMode:"environment"
},
{
fps:10,
qrbox:220
},
function(decodedText){
html5QrCode.stop().then(function(){
$("#cameraArea").hide();
$("#scannerArea").show();
$("#serial_number")
.val(decodedText);
saveSerial();
});
}
);
});
$("#btnCloseCamera").click(function(){
if(html5QrCode){
html5QrCode.stop().then(function(){
$("#cameraArea").hide();
$("#scannerArea").show();
$("#serial_number").focus();
});
}
});
</script>
+306 -123
View File
@@ -108,12 +108,12 @@
type="text"
id="serial_number"
class="form-control form-control-lg text-center"
placeholder="Scan QR Barang"
placeholder="Scan Barcode / Serial Number / Nama Barang"
autocomplete="off"
autofocus>
<small class="scan-note">
Scanner akan otomatis menyimpan.
Scan atau ketik Barcode / Serial Number / Nama Barang, lalu Enter.
</small><br>
<button
@@ -147,7 +147,9 @@
</div>
</center>
<div id="tableBarcode"></div>
<div style="max-height: 200px; overflow: auto;">
<div class="mt-2" id="tableBarcode"></div>
</div>
<hr>
<div id="group_account_biaya">
@@ -246,29 +248,53 @@
// URUSAN BARCODE INPUT DAN CAMSCANNER
let daftarBarang = [];
let isSaving = false;
let searchTimer = null;
$(document).ready(function () {
$("#serial_number").focus();
$("#serial_number").keypress(function(e){
$("#serial_number").on("keypress", function(e){
if(e.which==13){
e.preventDefault();
if(searchTimer){
clearTimeout(searchTimer);
}
if(!isSaving){
getBarcodeId();
getBarcodeId(true);
}
}
});
$("#serial_number").on("input", function(){
let keyword = ($(this).val() || "").trim();
if(searchTimer){
clearTimeout(searchTimer);
}
if(keyword === ""){
daftarBarang = [];
renderTable();
return;
}
searchTimer = setTimeout(function(){
if(!isSaving){
getBarcodeId(false);
}
}, 300);
});
});
function getBarcodeId(){
function getBarcodeId(isScanner = false){
let barcode = ($("#serial_number").val() || "").trim();
if(barcode==""){
return;
}
$.post(
"<?=base_url('items/get_barcode_item');?>",
{
barcode:barcode
},
{ barcode: barcode },
function(r){
if(!r.status){
Swal.fire({
@@ -279,99 +305,174 @@ function getBarcodeId(){
$("#serial_number").val("").focus();
return;
}
let exist = daftarBarang.find(function(v){
return v.barcode_id == r.data.barcode_id;
});
if(exist){
let rows = Array.isArray(r.data) ? r.data : [];
if(rows.length === 0){
Swal.fire({
icon: "warning",
title: "Barcode sudah discan",
timer: 1000,
showConfirmButton: false
icon:"warning",
title:"Data kosong",
text:"Tidak ada barang yang cocok."
});
$("#serial_number").val("").focus();
return;
}
daftarBarang.push(r.data);
daftarBarang = rows;
renderTable();
$("#serial_number").val("").focus();
if(isScanner){
$("#serial_number").val("").focus();
}
},
"json"
);
}
function renderTable(){
function renderTable() {
let html='';
let html = '';
html+='<div class="table-responsive">';
html+='<table class="table table-bordered table-hover table-sm mb-0">';
html+='<thead>';
html+='<tr>';
html+='<th width="50">No</th>';
html+='<th width="180">Barcode</th>';
html+='<th width="150">Kode Barang</th>';
html+='<th>Nama Barang</th>';
html+='<th width="180">Serial Number</th>';
html+='<th width="80" class="text-center">Action</th>';
html+='</tr>';
html+='</thead>';
html+='<tbody>';
html += '<div class="table-responsive">';
html += '<table class="table table-bordered table-hover table-sm mb-0">';
html += '<thead>';
html += '<tr>';
html += '<th width="50">No</th>';
html += '<th width="180">Barcode</th>';
html += '<th width="120">Kode Barang</th>';
html += '<th>Nama Barang</th>';
html += '<th width="180">Serial Number</th>';
html += '<th width="70" class="text-center">Pilih</th>';
html += '</tr>';
html += '</thead>';
html += '<tbody>';
if(daftarBarang.length==0){
if (daftarBarang.length == 0) {
html+='<tr>';
html+='<td colspan="6" class="text-center text-muted py-4">';
html+='Belum ada barcode yang discan.';
html+='</td>';
html+='</tr>';
html += `
<tr>
<td colspan="6" class="text-center text-muted py-4">
Belum ada barang yang discan.
</td>
</tr>
`;
}else{
} else {
$.each(daftarBarang,function(i,v){
$.each(daftarBarang, function (i, v) {
html+='<tr>';
html+='<td>'+(i+1)+'</td>';
html+='<td><strong>'+v.barcode+'</strong></td>';
html+='<td>'+v.kode_detail+'</td>';
html+='<td>'+v.nama_barang+'</td>';
html+='<td>'+(v.serial_number?v.serial_number:'-')+'</td>';
html+='<td class="text-center">';
html+='<button class="btn btn-sm btn-outline-danger btnRemove" data-id="'+v.barcode_id+'">';
html+='<i class="bi bi-trash"></i>';
html+='</button>';
html+='</td>';
html+='</tr>';
html += `
<tr>
<td>${i + 1}</td>
<td><strong>${v.barcode}</strong></td>
<td>${v.kode_detail}</td>
<td>${v.nama_barang}</td>
<td>${v.serial_number ? v.serial_number : '-'}</td>
<td class="text-center align-middle">
<div class="form-check d-flex justify-content-center mb-0">
<input
class="form-check-input pilihBarang"
type="checkbox"
value="${v.barcode_id}"
data-barcode="${v.barcode}">
</div>
</td>
</tr>
`;
});
}
html+='</tbody>';
html+='</table>';
html+='</div>';
html += '</tbody>';
html += '</table>';
html += '</div>';
$("#tableBarcode").html(html);
$('#tableBarcode').html(html);
if (daftarBarang.length === 1) {
$(".pilihBarang").prop("checked", false);
$(".pilihBarang").first().prop("checked", true);
}
}
$(document).on("click",".btnRemove",function(){
// function renderTable(){
let id=$(this).data("id");
// let html='';
daftarBarang=daftarBarang.filter(function(v){
return v.barcode_id!=id;
});
// html+='<div class="table-responsive">';
// html+='<table class="table table-bordered table-hover table-sm mb-0">';
// html+='<thead>';
// html+='<tr>';
// html+='<th width="50">No</th>';
// html+='<th width="180">Barcode</th>';
// html+='<th width="150">Kode Barang</th>';
// html+='<th>Nama Barang</th>';
// html+='<th width="180">Serial Number</th>';
// html+='<th width="80" class="text-center">Action</th>';
// html+='</tr>';
// html+='</thead>';
// html+='<tbody>';
renderTable();
// if(daftarBarang.length==0){
$("#serial_number").focus();
// html+='<tr>';
// html+='<td colspan="6" class="text-center text-muted py-4">';
// html+='Belum ada barcode yang discan.';
// html+='</td>';
// html+='</tr>';
// }else{
// $.each(daftarBarang,function(i,v){
// html+='<tr>';
// html+='<td>'+(i+1)+'</td>';
// html+='<td><strong>'+v.barcode+'</strong></td>';
// html+='<td>'+v.kode_detail+'</td>';
// html+='<td>'+v.nama_barang+'</td>';
// html+='<td>'+(v.serial_number?v.serial_number:'-')+'</td>';
// html+='<td class="text-center">';
// html+='<button class="btn btn-sm btn-outline-danger btnRemove" data-id="'+v.barcode_id+'">';
// html+='<i class="bi bi-trash"></i>';
// html+='</button>';
// html+='</td>';
// html+='</tr>';
// });
// }
// html+='</tbody>';
// html+='</table>';
// html+='</div>';
// $("#tableBarcode").html(html);
// }
$(document).on("change", ".pilihBarang", function(){
if($(this).is(":checked")){
$(".pilihBarang").not(this).prop("checked", false);
}
});
function getSelectedBarcodeRows(){
let selectedIds = $(".pilihBarang:checked").map(function(){
return String($(this).val());
}).get();
if(selectedIds.length === 0){
return [];
}
return daftarBarang.filter(function(v){
return selectedIds.indexOf(String(v.barcode_id)) !== -1;
});
}
let html5QrCode=null;
@@ -400,7 +501,7 @@ $("#btnCamera").click(function(){
$("#serial_number")
.val(decodedText);
saveSerial();
getBarcodeId();
});
@@ -625,8 +726,9 @@ $('#btnSimpan').click(function(){
// ================= RESET FORM KELUAR =================
function resetFormKeluar(){
$('#tanggal_keluar').val('');
$('#qty_keluar').val('');
$('#keterangan_keluar').val('');
daftarBarang = [];
renderTable();
}
loadKasOut();
@@ -683,28 +785,41 @@ function loadItems(warehouse_id){
$('#btnKeluar').click(function(){
let btn = $(this);
let selectedRows = getSelectedBarcodeRows();
if(selectedRows.length !== 1){
Swal.fire({
icon: 'warning',
title: 'Pilih 1 barang',
text: 'Pengeluaran hanya boleh 1 barcode item per proses.'
});
return;
}
let selected = selectedRows[0];
let data = {
account_biaya: $('#account_biaya').val(),
tanggal_keluar: $('#tanggal_keluar').val(),
warehouse_id_keluar: $('#warehouse_id_keluar').val(),
barang_id: $('#barang_id').val(),
qty_keluar: $('#qty_keluar').val(),
keterangan_keluar: $('#keterangan_keluar').val()
account_biaya: $('#account_biaya').val(),
tanggal_keluar: $('#tanggal_keluar').val(),
keterangan_keluar: $('#keterangan_keluar').val(),
selected_barcode: selected.barcode_id
};
let url = "<?= base_url('items/keluarkan'); ?>";
// 🔥 loading state
btn.prop('disabled', true).html('Menyimpan...');
$.post(url, data, function(res){
if(res.status){
$('#modalItem').modal('hide');
$('#modalKeluar').modal('hide');
table.ajax.reload(null,false);
daftarBarang = [];
renderTable();
$("#serial_number").val("");
Swal.fire({
icon: 'success',
title: 'Berhasil',
@@ -741,68 +856,68 @@ $('#btnKeluar').click(function(){
// ================= END URUSAN KELUAR ===============
// =====================================================
// ================= DELETE =================
$(document).on('click','.btn-delete',function(){
// // ================= DELETE =================
// $(document).on('click','.btn-delete',function(){
let id = $(this).data('id');
let btn = $(this);
// let id = $(this).data('id');
// let btn = $(this);
Swal.fire({
title: 'Hapus data?',
text: "Data tidak bisa dikembalikan!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
// Swal.fire({
// title: 'Hapus data?',
// text: "Data tidak bisa dikembalikan!",
// icon: 'warning',
// showCancelButton: true,
// confirmButtonColor: '#d33',
// cancelButtonColor: '#3085d6',
// confirmButtonText: 'Ya, hapus!',
// cancelButtonText: 'Batal'
// }).then((result) => {
if(result.isConfirmed){
// if(result.isConfirmed){
btn.prop('disabled', true).html('Menghapus...');
// btn.prop('disabled', true).html('Menghapus...');
$.get("<?= base_url('items/delete/'); ?>"+id,function(res){
// $.get("<?= base_url('items/delete/'); ?>"+id,function(res){
if(res.status){
// if(res.status){
table.ajax.reload(null,false);
// table.ajax.reload(null,false);
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: res.message || 'Data berhasil dihapus',
timer: 1500,
showConfirmButton: false
});
// Swal.fire({
// icon: 'success',
// title: 'Berhasil',
// text: res.message || 'Data berhasil dihapus',
// timer: 1500,
// showConfirmButton: false
// });
}else{
// }else{
Swal.fire({
icon: 'error',
title: 'Gagal',
text: res.message || 'Gagal menghapus data'
});
}
// Swal.fire({
// icon: 'error',
// title: 'Gagal',
// text: res.message || 'Gagal menghapus data'
// });
// }
},'json')
.fail(function(){
// },'json')
// .fail(function(){
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Koneksi ke server gagal'
});
// Swal.fire({
// icon: 'error',
// title: 'Error',
// text: 'Koneksi ke server gagal'
// });
})
.always(function(){
btn.prop('disabled', false).html('Hapus');
});
// })
// .always(function(){
// btn.prop('disabled', false).html('Hapus');
// });
}
});
// }
// });
});
// });
// ================= DETAIL =================
$(document).on('click','.btn-detail',function(){
@@ -920,5 +1035,73 @@ $('#btnAdjust').click(function(){
});
// ================= PRINT BARCODE =================
$(document).on('click', '.btn-print', function () {
let id = $(this).data('id');
Swal.fire({
title: 'Cetak Barcode',
html: `
<div class="text-left">
<div class="form-group">
<label for="print_column" class="font-weight-bold">
Jumlah Kolom
</label>
<select id="print_column" class="form-control">
<option value="1">1 Kolom</option>
<option value="2">2 Kolom</option>
<option value="3" selected>3 Kolom (Rekomendasi)</option>
</select>
</div>
<div class="form-group mb-0">
<label for="duplicat" class="font-weight-bold">
Jumlah Cetak per Barcode
</label>
<select id="duplicat" class="form-control">
<option value="1" selected>1 Label</option>
<option value="2">2 Label</option>
</select>
</div>
</div>
`,
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Cetak',
cancelButtonText: 'Batal',
confirmButtonColor: '#f0ad4e',
preConfirm: () => {
let column = $('#print_column').val();
let duplicat = $('#duplicat').val();
return {
column: column,
duplicat: duplicat
};
}
}).then((result) => {
if (!result.isConfirmed) {
return;
}
window.open(
"<?= base_url('items/print_barcode/'); ?>" +
id +
"?column=" + result.value.column +
"&duplicat=" + result.value.duplicat,
"_blank"
);
});
});
});
</script>