Rev 37543 | Blame | Compare with Previous | Last modification | View Log | RSS feed
$(function() {$(document).on('click', "a.view-returns", function() {viewReturnStores("main-content");});$(document).on('click', "a.pending-returns", function() {viewPendingReturns("main-content");});$(document).on('click', "a.approved-returns", function() {viewApprovedReturns("main-content");});$(document).on('click', "a.view-debit-note", function() {viewDebitNotes("main-content");});$(document).on('click', "a.unsettled-purchase-returns", function () {doAjaxRequestHandler(context + "/return/unsettled", "GET", function (response) {$('#main-content').html(response);});});$(document).on('click', "a.create-purchase-return", function () {doAjaxRequestHandler(context + "/return/unsettled/new", "GET", function (response) {$('#main-content').html(response);});});$(document).on('click', "a.wh-display-name", function() {var whId = $(this).closest('tr').data('id');$("#approved-returns-container").find("tr.filter").hide().filter('[data-id="' + whId + '"]').show();$(this).closest('table').find('tr').removeClass('warning');$(this).closest('tr').addClass('warning');});$(document).on('click', "a.debit-note", function() {var debitNoteId = $(this).closest('tr').data('id');$("#debit-note-items").find("tr.filter").hide().filter('[data-id="' + debitNoteId + '"]').show();$(this).closest('table').find('tr').removeClass('alert-warning');$(this).closest('tr').addClass('alert-warning');});$(document).on('click', "a.request-return", function() {if(confirm("Are you sure?")) {createReturnRequest($(this).data("inventoryitemid"), $(this));}});$(document).on('click', "a.approve-return", function() {if(confirm("Are you sure to Approve?")) {approveReturnRequest($(this).closest('td').data("returnid"), $(this).closest('td'));}});$(document).on('click', "a.deny-return", function() {if(confirm("Are you sure to Deny?")) {denyReturnRequest($(this).closest('td').data("returnid"), $(this).closest('td'));}});$(document).on('click', '#inventory-container a', function (){itemId=$(this).data('id');if(!fofoId){fofoId =$('select[name="fofo-users"]').val();console.log("fofo Id -"+fofoId);}doAjaxRequestHandler(context+"/return/inventory/" + fofoId + "/" + itemId, "GET", function(response){returnsTable.rows().remove().rows.add($(response)).draw(false);});});$(document).on('click', '.vendor_return', function () {doAjaxRequestHandler(context + "/return/to/vendor", "GET", function (response) {$('#main-content').html(response);});});// Invoice Return$(document).on('click', 'a.invoice-return', function () {doAjaxRequestHandler(context + "/return/invoice", "GET", function (response) {$('#main-content').html(response);});});// Search by Debit Note Number$(document).on('click', '#search-debit-note-btn', function () {var debitNoteNumber = $('#debit-note-number-input').val();if (!debitNoteNumber) {alert("Please enter a debit note number");return;}doAjaxRequestHandler(context + "/return/search/debit-note?debitNoteNumber=" + encodeURIComponent(debitNoteNumber), "GET", function (response) {$('#invoice-return-results').html(response);});});$(document).on('click', '#return-invoice-button', function () {var invoiceNumber = $('#invoice-number-input').val();if (!invoiceNumber) {alert("Please enter an invoice number");return;}doAjaxRequestHandler(context + "/return/invoice/search?invoiceNumber=" + encodeURIComponent(invoiceNumber), "GET", function (response) {$('#invoice-return-results').html(response);});});// Date-range filter$(document).on('click', '#invoice-return-date-apply', function () {var fromDate = $('#invoice-return-from-date').val();var toDate = $('#invoice-return-to-date').val();if (!fromDate || !toDate) {alert("Please pick both From and To dates");return;}if (fromDate > toDate) {alert("From date must be on or before To date");return;}doAjaxRequestHandler(context + "/return/invoice?fromDate=" + encodeURIComponent(fromDate)+ "&toDate=" + encodeURIComponent(toDate), "GET", function (response) {$('#main-content').html(response);});});// Debit Note Details$(document).on('click', '.debit-note-details', function () {var debitNoteId = $(this).data("debitnote-id");doAjaxRequestHandler(context + "/return/debit-note/details/" + debitNoteId, "GET", function (response) {$('#main-content').html(response);});});// Receive Debit Note$(document).on('click', '.receive-debit-note', function () {var debitNoteId = $(this).data("debitnote-id");doAjaxRequestHandler(context + "/return/debit-note/receive/" + debitNoteId, "GET", function (response) {$('#main-content').html(response);applyDeclaredConditions();});});// Seed every condition dropdown from what the partner declared, then settle the dependent// sections. Doing both here keeps one source of truth - the row's data-declared attribute - and// guarantees the DOA radios are resolved on load, which a preselected BAD never triggers on its// own because no change event fires for it.//// The markup still renders `selected` server-side as the fallback. If this script fails to load,// a declared BAD must not quietly present as GOOD: the server reads any difference from// data-declared as the warehouse DISAGREEING with the partner and rejects the whole debit note.function applyDeclaredConditions() {$('#receive-debit-note-form .return-condition').each(function () {var declared = $(this).data('declared');if (declared) {$(this).val(declared);}});syncReceiveConditionState();}// A row whose selected condition differs from what the partner declared is a disagreement,// not a correction — the server rejects the whole debit note for it.function hasConditionMismatch() {var mismatch = false;$('#receive-debit-note-form tr[data-item-id]').each(function () {var select = $(this).find('.return-condition');if (select.val() !== select.data('declared')) {mismatch = true;}});return mismatch;}// Show/hide the DOA certificate section based on BAD selection on mobile items.//// Driven by the CURRENT state of the form, never by what the operator just touched, because the// form arrives with the partner's declared condition already selected. A partner declaring a// mobile as BAD - the ordinary DOA case - renders BAD preselected, so no change event ever// fires; leaving this logic in the change handler alone hid the DOA radios on exactly the rows// that need them, and the server then refused the receipt for a missing certificate the operator// was never shown.function syncReceiveConditionState() {if (!$('#receive-debit-note-form').length) {return;}// On a mismatch the receipt never happens, so the DOA certificate is not collected.if (hasConditionMismatch()) {$('#condition-mismatch-section').show();$('#doa-certificate-section').hide();$('#submit-receive').removeClass('btn-primary').addClass('btn-danger').text('Reject Return');return;}$('#condition-mismatch-section').hide();$('#submit-receive').removeClass('btn-danger').addClass('btn-primary').text('Confirm Receipt');var hasMobileBad = false;$('#receive-debit-note-form tr[data-category-id]').each(function () {var categoryId = $(this).data('category-id');var condition = $(this).find('.return-condition').val();if (condition === 'BAD' && categoryId == 10006) {hasMobileBad = true;}});if (hasMobileBad) {$('#doa-certificate-section').show();} else {$('#doa-certificate-section').hide();}}$(document).on('change', '.return-condition', syncReceiveConditionState);// Submit receive debit note form$(document).on('submit', '#receive-debit-note-form', function (e) {e.preventDefault();var mismatch = hasConditionMismatch();// Validate remarks: mandatory for BAD rows, and for any row whose condition was changed —// the remark is what the partner and the escalation chain see as the reason for rejection.var valid = true;$(this).find('tr[data-item-id]').each(function () {var select = $(this).find('.return-condition');var condition = select.val();var remark = $(this).find('.remark-field').val();if (condition !== select.data('declared') && !remark) {alert("Remark is required when you change the condition — it is sent to the partner as the rejection reason");valid = false;return false;}if (condition === 'BAD' && !remark) {alert("Remark is required for BAD/DOA returns");valid = false;return false;}});if (!valid) return;var debitNoteId = $(this).data('debitnote-id');var form = $(this);if (mismatch) {if (!confirm("The condition you selected does not match what the partner declared.\n\n"+ "This will REJECT the entire debit note and notify the partner, Logistics, RBM and Sales. "+ "No refund will be raised.\n\nProceed?")) {return;}} else {// Check DOA certificate if mobile BAD items existvar hasMobileBad = false;$(this).find('tr[data-category-id]').each(function () {if ($(this).data('category-id') == 10006 && $(this).find('.return-condition').val() === 'BAD') {hasMobileBad = true;}});if (hasMobileBad && !$('input[name="doaCertificateValid"]:checked').val()) {alert("Please select DOA certificate validity");return;}if (!confirm("Are you sure you want to confirm receipt for this debit note?")) {return;}}$.ajax({url: context + "/return/debit-note/receive/" + debitNoteId,type: "POST",data: form.serialize(),success: function (response) {if (response === 'true' || response.indexOf('true') >= 0) {alert(mismatch? "Debit note rejected due to condition mismatch. Partner and escalation chain notified.": "Debit note items received successfully");doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});} else {alert((mismatch ? "Rejection failed: " : "Receipt failed: ") + response);}},error: function (xhr) {alert("Error: " + xhr.responseText);}});});// Refund Debit Note - opens refund view with receipt details$(document).on('click', '.refund-debit-note', function () {var debitNoteId = $(this).data("debitnote-id");doAjaxRequestHandler(context + "/return/debit-note/refund/" + debitNoteId, "GET", function (response) {$('#main-content').html(response);});});// Confirm refund with finance remark$(document).on('click', '.refund-debit-note-confirm', function () {var debitNoteId = $(this).data("debitnote-id");var financeRemark = $('#finance-remark').val();if (confirm("Are you sure you want to process refund for debit note " + debitNoteId + "?")) {doAjaxRequestHandler(context + "/return/debit-note/refund/" + debitNoteId + "?financeRemark=" + encodeURIComponent(financeRemark), "PUT", function (response) {if (response === 'true') {alert("Debit note refunded successfully");reloadReturnQueue();} else {alert("Refund failed: " + response);}}, approvalFailed);}});// Reject debit note return$(document).on('click', '.reject-debit-note-confirm', function () {var debitNoteId = $(this).data("debitnote-id");var rejectRemark = $('#reject-remark').val();if (!rejectRemark) {alert("Please enter a reject remark");return;}if (confirm("Are you sure you want to reject return for debit note " + debitNoteId + "? This will reverse all scans and quantities.")) {doAjaxRequestHandler(context + "/return/debit-note/reject/" + debitNoteId + "?rejectRemark=" + encodeURIComponent(rejectRemark), "PUT", function (response) {if (response === 'true') {alert("Return rejected successfully");doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});} else {alert("Rejection failed: " + response);}});}});// Approve Invoice Return (finance approval for shipped invoices)$(document).on('click', '.approve-invoice-return', function () {var proId = $(this).data("pro-id");if (confirm("Are you sure you want to approve and refund this invoice return?")) {doAjaxRequestHandler(context + "/return/invoice/approve/" + proId, "PUT", function (response) {if (response === 'true') {alert("Invoice return approved and refunded successfully");reloadReturnQueue();} else {alert("Approval failed: " + response);}}, approvalFailed);}});// ── Refund as B2C (Finance, same day as a NIC refusal for the buyer's GSTIN) ──$(document).on('click', '.b2c-refund', function () {var proId = $(this).data("pro-id");doAjaxRequestHandler(context + "/return/b2c-refund/" + proId, "GET", function (response) {$('#main-content').html(response);});});// Enable the button only when the typed amount equals the refund amount exactly, a remark is// entered and consent is ticked. The server repeats every one of these checks.$(document).on('input change', '#b2c-amount, #b2c-remark, #b2c-consent', function () {var $amount = $('#b2c-amount');var typed = $.trim($amount.val()).replace(/,/g, '');var expected = String($amount.data('expected'));var matches = typed !== '' && /^\d+$/.test(typed) && typed === expected;$('#b2c-amount-error').toggle(typed !== '' && !matches);var ready = matches && $.trim($('#b2c-remark').val()) !== '' && $('#b2c-consent').is(':checked');$('#b2c-refund-confirm').prop('disabled', !ready);});$(document).on('click', '.b2c-refund-confirm', function () {var $btn = $(this);var proId = $btn.data("pro-id");var amount = $.trim($('#b2c-amount').val()).replace(/,/g, '');var remark = $.trim($('#b2c-remark').val());if (!confirm("Refund Rs. " + $btn.data("amount-label") + " to " + $btn.data("partner") + " as B2C?\n"+ "Stock comes back to the warehouse and a local credit note is issued.\nThis cannot be undone.")) {return;}$btn.prop('disabled', true);doAjaxRequestHandler(context + "/return/b2c-refund/" + proId + "?amount=" + encodeURIComponent(amount)+ "&remark=" + encodeURIComponent(remark) + "&consent=true", "PUT", function (response) {var cnNumber = response;try { cnNumber = JSON.parse(response); } catch (e) { /* already a plain string */ }alert("Refunded Rs. " + $btn.data("amount-label") + ". Credit note " + cnNumber + " issued (B2C, no IRN).");reloadReturnQueue();}, function (xhr, msg) {alert("B2C refund failed: " + errorText(msg));$btn.prop('disabled', false);});});$(document).on('click', '.b2c-refund-cancel', function () {reloadReturnQueue();});// Reject Invoice Return — sale stands, no inventory/wallet/GST action$(document).on('click', '.reject-invoice-return', function () {var proId = $(this).data("pro-id");var rejectRemark = prompt("Reason for rejecting this invoice return? (sale will stand, no refund will be issued)");if (!rejectRemark) {return;}if (confirm("Reject invoice return and let the sale stand? This cannot be undone.")) {doAjaxRequestHandler(context + "/return/invoice/reject/" + proId + "?rejectRemark=" + encodeURIComponent(rejectRemark), "PUT", function (response) {if (response === 'true') {alert("Invoice return rejected");doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});} else {alert("Rejection failed: " + response);}});}});// Acknowledge rejected return — retailer confirms goods received back$(document).on('click', '.acknowledge-rejected-return', function () {var debitNoteId = $(this).data("debitnote-id");if (confirm("Confirm that you have received the rejected goods back? This will restore your inventory.")) {doAjaxRequestHandler(context + "/return/debit-note/reject/acknowledge/" + debitNoteId, "PUT", function (response) {if (response === 'true') {alert("Goods acknowledged. Inventory restored.");doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});} else {alert("Acknowledgment failed: " + response);}});}});// Process Invoice Return (non-GRN'd)$(document).on('click', '.process-invoice-return', function () {var invoiceNumber = $(this).data("invoice");var remark = $('#invoice-return-remark').val();if (confirm("Are you sure you want to process return for invoice " + invoiceNumber + "?")) {doAjaxRequestHandler(context + "/return/invoice/process?invoiceNumber=" + encodeURIComponent(invoiceNumber) + "&remark=" + encodeURIComponent(remark), "PUT", function (response) {if (response === 'true') {alert("Invoice return processed successfully");doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});} else {alert("Return failed: " + response);}});}});});function viewReturnStores(domId){doAjaxRequestHandler(context+"/return/stores", "GET", function(response){$('#' + domId).html(response);});}function viewPendingReturns(domId){doAjaxRequestHandler(context+"/return/pending", "GET", function(response){$('#' + domId).html(response);});}function viewApprovedReturns(domId){doAjaxRequestHandler(context+"/return/approved", "GET", function(response){$('#' + domId).html(response);$("#approved-returns").find('a:first').click();});}function viewDebitNotes(domId){doAjaxRequestHandler(context+"/return/debit-note-created", "GET", function(response){$('#' + domId).html(response);$("#debit-notes").find('a:first').click();});}function createReturnRequest(inventoryItemId, container){doAjaxRequestHandler(context+"/return/inventory/" + inventoryItemId, "PUT", function(response){if(response=='true') {container.closest('td').html('Return requested');}});}function approveReturnRequest(inventoryItemId, container){doAjaxRequestHandler(context+"/return/inventory/approve/" + inventoryItemId, "PUT", function(response){if(response=='true') {container.closest('td').html('Return Approved');}});}function denyReturnRequest(inventoryItemId, container){doAjaxRequestHandler(context+"/return/inventory/deny/" + inventoryItemId, "PUT", function(response){if(response=='true') {container.closest('td').html('Return denied');}});}function viewDebitNote(warehouseId){doAjaxRequestHandler(context+"/return/debit-note/view/" + warehouseId, "GET", function(response){//Download PDF code});}function generateDebitNote(warehouseId){doAjaxRequestHandler(context+"/return/debit-note/generate/" + warehouseId, "PUT", function(response){if(response=='true') {//Download the pdf}});}function getDebitNote(debitNotedId) {doAjaxRequestHandler(context+"/return/debit-note/" + debitNotedId, "GET", function(response){});}function reloadReturnQueue() {doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {$('#main-content').html(resp);});}// Pull the human-readable message out of an error body; fall back to the raw text.function errorText(msg) {try {var body = JSON.parse(msg);var r = body.response || body;return r.message || r.code || body.message || body.code || msg;} catch (e) {return msg;}}// A refused approval may have just opened the B2C option, so show the reason and reload the// queue - the row then carries the "Refund as B2C" button without a manual refresh.function approvalFailed(xhr, msg) {alert("Approval failed: " + errorText(msg));reloadReturnQueue();}