(function ($) { "use strict"; var cfg = window.SALES_PAGE, cart = [], selectedItem = null, selectedBars = [], fileBag = new DataTransfer(); function esc(v) { return $("
") .text(v == null ? "" : v) .html(); } function number(v) { if (typeof v === "number") return v; v = String(v || "").replace(/Rp|\s/g, ""); if (v.indexOf(",") >= 0) v = v.replace(/\./g, "").replace(",", "."); else if (/^\d{1,3}(\.\d{3})+$/.test(v)) v = v.replace(/\./g, ""); return Number(v) || 0; } function money(v) { return ( "Rp " + new Intl.NumberFormat("id-ID", { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(Number(v) || 0) ); } function toast(icon, title) { if (window.AppAlert && AppAlert.toast) return AppAlert.toast(title, icon); return Swal.fire({ toast: true, position: "top-end", icon: icon, title: title, showConfirmButton: false, timer: 2800, timerProgressBar: true, }); } function request(url, data, files) { data = data || {}; if (data instanceof FormData) { if (!data.has(cfg.csrfName)) data.append(cfg.csrfName, cfg.csrfHash); } else data[cfg.csrfName] = cfg.csrfHash; return $.ajax({ url: url, type: "POST", data: data, processData: !files, contentType: files ? false : "application/x-www-form-urlencoded; charset=UTF-8", dataType: "json", }); } function modal(id) { return bootstrap.Modal.getOrCreateInstance(document.getElementById(id)); } function loadCustomers() { return $.getJSON(cfg.base + "sales/lookup_customers", { q: "" }).done( function (r) { $("#customerLookup").html( '' + r.rows .map(function (x) { return ( '" ); }) .join(""), ); }, ); } function loadItems() { return $.getJSON(cfg.base + "sales/lookup_items", { q: "" }).done( function (r) { $("#itemLookup").html( '' + r.rows .map(function (x) { return ( '" ); }) .join(""), ); }, ); } function loadWarehouses() { return $.getJSON(cfg.base + "sales/warehouses").done(function (r) { $("#warehouseLookup").html( '' + r.rows .map(function (x) { return ( '" ); }) .join(""), ); }); } $("#newInvoice").on("click", function () { cart = []; $("#appendId").val(""); $("#invoiceForm")[0].reset(); $( "#invoiceForm [name=customer_id],#invoiceForm [name=invoice_type],#invoiceForm [name=recognition_policy],#invoiceForm [name=period_start],#invoiceForm [name=period_end],#invoiceForm [name=due_date]", ).prop("disabled", false); $(".invoiceModalTitle").text("Buat Invoice"); Promise.all([loadCustomers(), loadItems(), loadWarehouses()]) .then(function () { renderCart(); modal("invoiceModal").show(); }) .catch(fail); }); $(document).on("click", ".append-invoice", function () { cart = []; var id = $(this).data("id"); $("#appendId").val(id); Promise.all([loadItems(), loadWarehouses()]) .then(function () { $( "#invoiceForm [name=customer_id],#invoiceForm [name=invoice_type],#invoiceForm [name=recognition_policy],#invoiceForm [name=period_start],#invoiceForm [name=period_end],#invoiceForm [name=due_date]", ).prop("disabled", true); renderCart(); modal("invoiceModal").show(); }) .catch(fail); }); $("#itemLookup").on("change", function () { var o = this.options[this.selectedIndex]; selectedItem = o && o.dataset.row ? JSON.parse(decodeURIComponent(o.dataset.row)) : null; if (selectedItem) $("#linePrice").val(formatInput(selectedItem.harga_jual)); }); $("#chooseBarcode").on("click", function () { if (!selectedItem || !$("#warehouseLookup").val()) return toast("warning", "Pilih barang dan gudang terlebih dahulu."); $.getJSON(cfg.base + "sales/lookup_barcodes", { item_id: selectedItem.id, warehouse_id: $("#warehouseLookup").val(), }).done(function (r) { selectedBars = []; $("#barcodeChoices").html( r.rows.length ? r.rows .map(function (b) { var available = number(b.qty_sisa) - number(b.reserved_qty) - number(b.return_reserved_qty); return ( '" ); }) .join("") : 'Tidak ada barcode tersedia.', ); }); }); $(document).on("change", ".bar-check", function () { var b = JSON.parse(decodeURIComponent(this.dataset.row)); if (this.checked) { var qty = selectedItem && selectedItem.tracking_type === "QTY" ? Math.min( number(b.qty_sisa) - number(b.reserved_qty) - number(b.return_reserved_qty), Math.max(0, number($("#lineQty").val())), ) : 1; selectedBars.push({ id: b.id, barcode: b.barcode, qty: qty }); } else selectedBars = selectedBars.filter(function (x) { return Number(x.id) !== Number(b.id); }); }); $("#addLine").on("click", function () { var qty = number($("#lineQty").val()), price = number($("#linePrice").val()); if (!selectedItem || !$("#warehouseLookup").val() || qty <= 0 || price < 0) return toast("warning", "Lengkapi barang, gudang, qty, dan harga."); var bqty = selectedBars.reduce(function (s, b) { return s + number(b.qty); }, 0); if (Math.abs(bqty - qty) > 0.0001) return toast( "warning", "Total qty barcode (" + bqty + ") harus sama dengan qty barang (" + qty + ").", ); cart.push({ item_id: selectedItem.id, item_code: selectedItem.kode_barang, item_name: selectedItem.nama_barang, warehouse_id: $("#warehouseLookup").val(), service_date: $("#invoiceForm [name=date]").val(), qty: qty, unit_price: price, discount_amount: 0, tax_rate: 0, specification: "", barcodes: selectedBars.slice(), }); selectedBars = []; $("#barcodeChoices").empty(); renderCart(); }); function renderCart() { var total = 0; $("#invoiceCart tbody").html( cart .map(function (x, i) { var sub = Math.max(0, x.qty * x.unit_price - x.discount_amount) * (1 + x.tax_rate / 100); total += sub; return ( '' + esc(x.item_code + " - " + x.item_name) + '' + x.barcodes.length + ' barcode' + x.qty + "" + money(x.unit_price) + '' + money(sub) + '' ); }) .join(""), ); $("#cartTotal").text(money(total)); } $(document).on( "input change", ".cart-discount,.cart-tax,.cart-date,.cart-spec", function () { var tr = $(this).closest("tr"), x = cart[tr.data("index")]; x.discount_amount = number(tr.find(".cart-discount").val()); x.tax_rate = number(tr.find(".cart-tax").val()); x.service_date = tr.find(".cart-date").val(); x.specification = tr.find(".cart-spec").val(); renderCart(); }, ); $(document).on("click", ".cart-remove", function () { cart.splice($(this).closest("tr").data("index"), 1); renderCart(); }); $("#invoiceForm").on("submit", function (e) { e.preventDefault(); if (!cart.length) return toast("warning", "Tambahkan minimal satu barang."); var f = new FormData(this), id = $("#appendId").val(); f.append("rows", JSON.stringify(cart)); var url = id ? cfg.base + "sales/append_invoice/" + id : cfg.base + "sales/create_invoice"; request(url, f, true) .done(function (r) { if (!r.status) return toast("error", r.message); modal("invoiceModal").hide(); toast("success", r.message); setTimeout(function () { location.reload(); }, 600); }) .fail(fail); }); function fail(xhr) { var m = "Transaksi tidak dapat diproses."; try { m = JSON.parse(xhr.responseText).message || m; } catch (e) {} toast("error", m); } $(document).on("click", ".sale-action", function () { var btn = $(this), url = btn.data("url"); Swal.fire({ icon: "question", title: btn.data("confirm"), showCancelButton: true, confirmButtonText: "Ya, lanjutkan", cancelButtonText: "Batal", }).then(function (r) { if (!r.isConfirmed) return; btn.prop("disabled", true); request(url, {}) .done(function (x) { if (!x.status) { btn.prop("disabled", false); return toast("error", x.message); } toast("success", x.message); setTimeout(function () { location.reload(); }, 600); }) .fail(function (x) { btn.prop("disabled", false); fail(x); }); }); }); $(document).on("click", ".reject-invoice", function () { var id = $(this).data("id"); Swal.fire({ icon: "warning", title: "Tolak invoice?", input: "textarea", inputLabel: "Alasan penolakan", inputValidator: function (v) { return !String(v || "").trim() ? "Alasan wajib diisi." : undefined; }, showCancelButton: true, confirmButtonText: "Tolak", }).then(function (r) { if (r.isConfirmed) request(cfg.base + "sales/reject_invoice/" + id, { reason: r.value }) .done(function (x) { if (x.status) location.reload(); else toast("error", x.message); }) .fail(fail); }); }); $(document).on("click", ".pdf-open", function () { $("#pdfModal iframe").attr("src", $(this).data("url")); modal("pdfModal").show(); }); document .getElementById("pdfModal") .addEventListener("hidden.bs.modal", function () { $("#pdfModal iframe").attr("src", "about:blank"); }); function qty(v) { v = number(v); return Math.round(v) === v ? new Intl.NumberFormat("id-ID").format(v) : new Intl.NumberFormat("id-ID", { maximumFractionDigits: 4 }).format(v); } function table(rows, cols) { return ( '
' + cols .map(function (c) { return ""; }) .join("") + "" + rows .map(function (r) { return ( "" + cols .map(function (c) { return ""; }) .join("") + "" ); }) .join("") + "
" + c[0] + "
" + c[1](r) + "
" ); } $(document).on("click", ".detail-invoice", function () { $.getJSON(cfg.base + "sales/invoice_detail/" + $(this).data("id")) .done(function (r) { if (!r.status) return toast("error", r.message); var i = r.invoice, body = '
Customer
' + esc(i.customer_name) + "

" + esc(i.customer_address || "-") + '

Invoice
' + esc(i.no_invoice) + "

" + esc(i.period_start + " — " + i.period_end) + " · " + esc( i.recognition_policy === "accrual" ? "Akrual" : "Setelah pembayaran", ) + '

Ringkasan Barang
' + table(r.lines, [ [ "Tanggal", function (x) { return esc(x.service_date); }, ], [ "Barang", function (x) { return ( "" + esc(x.item_code + " - " + x.nama_item) + "" + esc(x.specification || "-") + "" ); }, ], [ "Qty", function (x) { return qty(x.qty); }, ], [ "Harga", function (x) { return money(x.harga); }, ], [ "Subtotal", function (x) { return money(x.subtotal); }, ], ]) + '
Detail Barcode
' + table(r.barcodes, [ [ "Surat Jalan", function (x) { return esc(x.delivery_no || "-"); }, ], [ "Barang", function (x) { return esc(x.item_code + " - " + x.nama_barang); }, ], [ "Barcode / SN", function (x) { return ( "" + esc(x.barcode) + "" + esc(x.serial_number || "-") + "" ); }, ], [ "Qty", function (x) { return qty(x.qty); }, ], [ "Gudang", function (x) { return esc(x.warehouse_name || "-"); }, ], ]) + '
Pembayaran
' + table(r.payments, [ [ "Tanggal", function (x) { return esc(x.tanggal); }, ], [ "Nomor", function (x) { return esc(x.payment_no); }, ], [ "Alokasi", function (x) { return money(x.allocated); }, ], ]) + '
Surat Jalan
' + r.deliveries .map(function (x) { return ( "

" + esc(x.delivery_no) + " · " + esc(x.delivery_date) + " · " + esc(x.status) + "

" ); }) .join("") + "
"; $("#detailBody").html(body); modal("detailModal").show(); }) .fail(fail); }); $(document).on("click", ".detail-delivery", function () { $.getJSON(cfg.base + "sales/delivery_detail/" + $(this).data("id")) .done(function (r) { if (!r.status) return toast("error", r.message); var d = r.delivery; $("#detailBody").html( '
' + esc(d.delivery_no) + "

" + esc(d.customer_name) + "
" + esc(d.customer_address || "-") + '

' + esc(d.no_invoice || "-") + "

" + esc(d.delivery_date) + " · " + esc(d.warehouse_name || "-") + " · " + esc(d.status) + '

' + table(r.lines, [ [ "Barang", function (x) { return ( "" + esc(x.description) + "" + esc(x.specification || "-") + "" ); }, ], [ "Qty", function (x) { return qty(x.qty) + " " + esc(x.unit || ""); }, ], [ "Dikembalikan", function (x) { return qty(x.returned_qty); }, ], ]) + '
Barcode / Serial
' + table(r.barcodes, [ [ "Barcode", function (x) { return esc(x.barcode); }, ], [ "Serial", function (x) { return esc(x.serial_number || "-"); }, ], [ "Qty", function (x) { return qty(x.qty); }, ], [ "Status", function (x) { return esc(x.status); }, ], ]) + "
", ); modal("detailModal").show(); }) .fail(fail); }); $(document).on("click", ".detail-return", function () { $.getJSON(cfg.base + "sales/return_detail/" + $(this).data("id")) .done(function (r) { if (!r.status) return toast("error", r.message); var x = r.return; $("#detailBody").html( '
' + esc(x.return_no) + "

" + esc(x.customer_name) + " · " + esc(x.no_invoice) + '

' + esc(x.status) + "

" + esc(x.reason) + '

' + table(r.lines, [ [ "Barang", function (l) { return esc(l.kode_barang + " - " + l.nama_barang); }, ], [ "Qty", function (l) { return qty(l.qty); }, ], [ "Kondisi", function (l) { return esc(l.physical_condition); }, ], [ "Nilai", function (l) { return money(number(l.net_amount) + number(l.tax_amount)); }, ], ]) + '
Riwayat
' + r.history .map(function (h) { return ( "

" + esc(h.to_status) + " · " + esc(h.created_at) + " · " + esc(h.user_name || "-") + "" + esc(h.notes || "") + "

" ); }) .join("") + "
", ); modal("detailModal").show(); }) .fail(fail); }); function accountSelect() { return ( '" ); } function addSource(amount) { $("#paymentSources").append( '
' + accountSelect() + '
', ); } $(document).on("click", ".pay-invoice", function () { $.getJSON(cfg.base + "sales/invoice_detail/" + $(this).data("id")) .done(function (r) { if (!r.status) return toast("error", r.message); var i = r.invoice; $("#paymentForm")[0].reset(); fileBag = new DataTransfer(); renderFiles(); $("#paymentForm [name=customer_id]").val(i.customer_id); $("#paymentOrder").html( '
Customer
' + esc(i.customer_name) + "
" + esc(i.no_invoice) + "" + table(r.lines, [ [ "Barang", function (x) { return esc(x.item_code + " - " + x.nama_item); }, ], [ "Qty", function (x) { return qty(x.qty); }, ], [ "Subtotal", function (x) { return money(x.subtotal); }, ], ]) + '
Total invoice' + money(i.total) + "
Sudah dibayar" + money(i.total_bayar) + "
Sisa piutang" + money(i.sisa_piutang) + '
', ); $("#paymentSources").empty(); addSource(i.sisa_piutang); calcPayment(); modal("paymentModal").show(); }) .fail(fail); }); $("#addPaymentSource").on("click", function () { addSource(0); }); $(document).on("click", ".remove-source", function () { if ($(".pay-source").length > 1) $(this).closest(".pay-source").remove(); else $(this).closest(".pay-source").find("input").val(""); calcPayment(); }); $(document).on("input", ".pay-source-amount,.allocation", calcPayment); function calcPayment() { var a = 0, s = 0; $(".allocation").each(function () { a += number(this.value); }); $(".pay-source-amount").each(function () { s += number(this.value); }); $("#payAllocated").text(money(a)); $("#paySources").text(money(s)); $("#payDiff") .text(money(s - a)) .toggleClass("text-danger", Math.abs(s - a) > 0.001); } $("#paymentForm").on("submit", function (e) { e.preventDefault(); var f = new FormData(this), sources = [], alloc = {}; $(".pay-source").each(function () { sources.push({ account_id: $(this).find(".pay-account").val(), amount: $(this).find(".pay-source-amount").val(), }); }); $(".allocation").each(function () { alloc[$(this).data("id")] = this.value; }); f.append("sources", JSON.stringify(sources)); f.append("allocations", JSON.stringify(alloc)); request(cfg.base + "sales/payment", f, true) .done(function (r) { if (!r.status) return toast("error", r.message); modal("paymentModal").hide(); Swal.fire({ icon: "success", title: r.message, showCancelButton: true, confirmButtonText: "Lihat Bukti Penerimaan", cancelButtonText: "Tutup", }).then(function (x) { if (x.isConfirmed) { $("#pdfModal iframe").attr( "src", cfg.base + "sales/receipt_pdf/" + r.result.payment_id, ); modal("pdfModal").show(); } else location.reload(); }); }) .fail(fail); }); $("#payFiles input").on("change", function () { Array.from(this.files).forEach(function (f) { fileBag.items.add(f); }); this.files = fileBag.files; renderFiles(); }); function renderFiles() { $("#payFiles .file-thumb").remove(); Array.from(fileBag.files).forEach(function (f, i) { var url = f.type.indexOf("image/") === 0 ? URL.createObjectURL(f) : ""; $("#payFiles").append( '
' + (url ? '' : '') + '' + esc(f.name.slice(0, 12)) + "
", ); }); $("#payFiles input")[0].files = fileBag.files; } $(document).on("click", "#payFiles .file-thumb button", function () { var next = new DataTransfer(), remove = Number(this.dataset.file); Array.from(fileBag.files).forEach(function (f, i) { if (i !== remove) next.items.add(f); }); fileBag = next; renderFiles(); }); $(document).on("click", ".new-return", function () { $.getJSON(cfg.base + "sales/delivery_detail/" + $(this).data("id")) .done(function (r) { if (!r.status) return toast("error", r.message); $("#returnForm")[0].reset(); $("#returnForm [name=sales_delivery_id]").val(r.delivery.id); $("#returnLines").html( "
Barcode yang dapat diretur
" + r.barcodes .filter(function (b) { return number(b.qty) - number(b.returned_qty) > 0; }) .map(function (b) { var left = number(b.qty) - number(b.returned_qty); return ( '
' ); }) .join(""), ); modal("returnModal").show(); }) .fail(fail); }); $("#returnForm").on("submit", function (e) { e.preventDefault(); var rows = []; $(".return-check:checked").each(function () { var x = $(this).closest(".return-row"); rows.push({ sales_delivery_barcode_id: $(this).data("id"), qty: x.find(".return-qty").val(), physical_condition: x.find(".return-condition").val(), notes: x.find(".return-note").val(), }); }); if (!rows.length) return toast("warning", "Pilih minimal satu barcode."); var f = new FormData(this); f.append("rows", JSON.stringify(rows)); request(cfg.base + "sales/create_return", f, true) .done(function (r) { if (r.status) { modal("returnModal").hide(); toast("success", r.message); setTimeout(function () { location.reload(); }, 600); } else toast("error", r.message); }) .fail(fail); }); $(document).on("click", ".new-return", function () { if (!$('#returnForm [name="attachments[]"]').length) $("#returnLines").before( '
Maksimal 10 file, masing-masing 5 MB.
', ); }); $(document).on("click", ".detail-delivery", function () { var id = $(this).data("id"); $.getJSON(cfg.base + "sales/delivery_detail/" + id).done(function (r) { if (!r.status || r.delivery.status !== "draft") return; setTimeout(function () { if ($("#deliveryEditForm").length) return; var d = r.delivery; $("#detailBody").append( '
Lengkapi Data & Bukti Pengiriman
', ); $("#deliveryEditForm").on("submit", function (e) { e.preventDefault(); request( cfg.base + "sales/update_delivery/" + id, new FormData(this), true, ) .done(function (x) { if (x.status) { toast("success", x.message); modal("detailModal").hide(); setTimeout(function () { location.reload(); }, 500); } else toast("error", x.message); }) .fail(fail); }); }, 120); }); }); function formatInput(v) { return new Intl.NumberFormat("id-ID", { minimumFractionDigits: 0, maximumFractionDigits: 2, }).format(Number(v) || 0); } $(document).on( "blur", ".money-field,.pay-source-amount,.allocation", function () { this.value = formatInput(number(this.value)); }, ); if (cfg.sourceOrder) { Promise.all([ loadCustomers(), loadItems(), loadWarehouses(), $.getJSON(cfg.base + "salesdocuments/detail/" + cfg.sourceOrder), ]) .then(function (result) { var source = result[3]; if (!source.status) return toast("error", source.message); $("#invoiceForm").append( '', ); $("#customerLookup").val(source.document.customer_id); $("#invoiceForm [name=customer_id]").prop("disabled", false); $(".line-builder").prepend( '
Sumber ' + esc(source.document.document_no) + "
" + source.lines .map(function (x) { return esc( (x.kode_barang || "") + " - " + (x.nama_barang || x.description) + " · " + qty(x.qty), ); }) .join("
") + 'Pilih kembali setiap barang, gudang, dan barcode agar stok yang dikirim tervalidasi.
', ); modal("invoiceModal").show(); }) .catch(fail); } if (cfg.focus) { setTimeout(function () { $('.detail-invoice[data-id="' + Number(cfg.focus) + '"]').trigger( "click", ); }, 100); } })(jQuery);