Subversion Repositories SmartDukaan

Rev

Rev 37543 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
23506 amit.gupta 1
$(function() {
27754 amit.gupta 2
	$(document).on('click', "a.view-returns", function() {
23638 amit.gupta 3
		viewReturnStores("main-content");
23506 amit.gupta 4
	});
27754 amit.gupta 5
	$(document).on('click', "a.pending-returns", function() {
23506 amit.gupta 6
		viewPendingReturns("main-content");
7
	});
27754 amit.gupta 8
	$(document).on('click', "a.approved-returns", function() {
23506 amit.gupta 9
		viewApprovedReturns("main-content");
10
	});
11
 
27754 amit.gupta 12
	$(document).on('click', "a.view-debit-note", function() {
23539 amit.gupta 13
		viewDebitNotes("main-content");
14
	});
15
 
36316 aman 16
	$(document).on('click', "a.unsettled-purchase-returns", function () {
17
		doAjaxRequestHandler(context + "/return/unsettled", "GET", function (response) {
18
			$('#main-content').html(response);
19
		});
20
	});
21
 
22
	$(document).on('click', "a.create-purchase-return", function () {
23
		doAjaxRequestHandler(context + "/return/unsettled/new", "GET", function (response) {
24
			$('#main-content').html(response);
25
		});
26
	});
27
 
27754 amit.gupta 28
	$(document).on('click', "a.wh-display-name", function() {
23506 amit.gupta 29
		var whId = $(this).closest('tr').data('id');
30
		$("#approved-returns-container").find("tr.filter").hide().filter('[data-id="' + whId + '"]').show();
23540 amit.gupta 31
		$(this).closest('table').find('tr').removeClass('warning');
23506 amit.gupta 32
		$(this).closest('tr').addClass('warning');
33
	});
23539 amit.gupta 34
 
27754 amit.gupta 35
	$(document).on('click', "a.debit-note", function() {
23539 amit.gupta 36
		var debitNoteId = $(this).closest('tr').data('id');
37
		$("#debit-note-items").find("tr.filter").hide().filter('[data-id="' + debitNoteId + '"]').show();
29937 amit.gupta 38
		$(this).closest('table').find('tr').removeClass('alert-warning');
39
		$(this).closest('tr').addClass('alert-warning');
23539 amit.gupta 40
	});
35998 amit 41
 
42
 
27754 amit.gupta 43
	$(document).on('click', "a.request-return", function() {
23506 amit.gupta 44
		if(confirm("Are you sure?")) {
45
			createReturnRequest($(this).data("inventoryitemid"), $(this));
46
		}
47
	});
27754 amit.gupta 48
	$(document).on('click', "a.approve-return", function() {
23506 amit.gupta 49
		if(confirm("Are you sure to Approve?")) {
23638 amit.gupta 50
			approveReturnRequest($(this).closest('td').data("returnid"), $(this).closest('td'));
23506 amit.gupta 51
		}
52
	});
27754 amit.gupta 53
	$(document).on('click', "a.deny-return", function() {
23506 amit.gupta 54
		if(confirm("Are you sure to Deny?")) {
23644 amit.gupta 55
			denyReturnRequest($(this).closest('td').data("returnid"), $(this).closest('td'));
23506 amit.gupta 56
		}
57
	});
35998 amit 58
 
27763 tejbeer 59
	$(document).on('click', '#inventory-container a', function (){
23638 amit.gupta 60
		itemId=$(this).data('id');
34142 tejus.loha 61
		if(!fofoId){
62
			fofoId =$('select[name="fofo-users"]').val();
63
			console.log("fofo Id -"+fofoId);
64
		}
23638 amit.gupta 65
		doAjaxRequestHandler(context+"/return/inventory/" + fofoId + "/" + itemId, "GET", function(response){
66
			returnsTable.rows().remove().rows.add($(response)).draw(false);
67
		});
68
	});
35998 amit 69
 
70
	$(document).on('click', '.vendor_return', function () {
71
		doAjaxRequestHandler(context + "/return/to/vendor", "GET", function (response) {
72
			$('#main-content').html(response);
73
		});
74
	});
75
 
76
	// Invoice Return
77
	$(document).on('click', 'a.invoice-return', function () {
78
		doAjaxRequestHandler(context + "/return/invoice", "GET", function (response) {
79
			$('#main-content').html(response);
80
		});
81
	});
82
 
83
	// Search by Debit Note Number
84
	$(document).on('click', '#search-debit-note-btn', function () {
85
		var debitNoteNumber = $('#debit-note-number-input').val();
86
		if (!debitNoteNumber) {
87
			alert("Please enter a debit note number");
88
			return;
89
		}
90
		doAjaxRequestHandler(context + "/return/search/debit-note?debitNoteNumber=" + encodeURIComponent(debitNoteNumber), "GET", function (response) {
91
			$('#invoice-return-results').html(response);
92
		});
93
	});
94
 
95
	$(document).on('click', '#return-invoice-button', function () {
96
		var invoiceNumber = $('#invoice-number-input').val();
97
		if (!invoiceNumber) {
98
			alert("Please enter an invoice number");
99
			return;
100
		}
101
		doAjaxRequestHandler(context + "/return/invoice/search?invoiceNumber=" + encodeURIComponent(invoiceNumber), "GET", function (response) {
102
			$('#invoice-return-results').html(response);
103
		});
104
	});
105
 
36408 amit 106
	// Date-range filter
107
	$(document).on('click', '#invoice-return-date-apply', function () {
108
		var fromDate = $('#invoice-return-from-date').val();
109
		var toDate = $('#invoice-return-to-date').val();
110
		if (!fromDate || !toDate) {
111
			alert("Please pick both From and To dates");
112
			return;
113
		}
114
		if (fromDate > toDate) {
115
			alert("From date must be on or before To date");
116
			return;
117
		}
118
		doAjaxRequestHandler(context + "/return/invoice?fromDate=" + encodeURIComponent(fromDate)
119
				+ "&toDate=" + encodeURIComponent(toDate), "GET", function (response) {
120
			$('#main-content').html(response);
121
		});
122
	});
123
 
35998 amit 124
	// Debit Note Details
125
	$(document).on('click', '.debit-note-details', function () {
126
		var debitNoteId = $(this).data("debitnote-id");
127
		doAjaxRequestHandler(context + "/return/debit-note/details/" + debitNoteId, "GET", function (response) {
128
			$('#main-content').html(response);
129
		});
130
	});
131
 
132
	// Receive Debit Note
133
	$(document).on('click', '.receive-debit-note', function () {
134
		var debitNoteId = $(this).data("debitnote-id");
135
		doAjaxRequestHandler(context + "/return/debit-note/receive/" + debitNoteId, "GET", function (response) {
136
			$('#main-content').html(response);
37543 amit 137
			applyDeclaredConditions();
35998 amit 138
		});
139
	});
140
 
37543 amit 141
	// Seed every condition dropdown from what the partner declared, then settle the dependent
142
	// sections. Doing both here keeps one source of truth - the row's data-declared attribute - and
143
	// guarantees the DOA radios are resolved on load, which a preselected BAD never triggers on its
144
	// own because no change event fires for it.
145
	//
146
	// The markup still renders `selected` server-side as the fallback. If this script fails to load,
147
	// a declared BAD must not quietly present as GOOD: the server reads any difference from
148
	// data-declared as the warehouse DISAGREEING with the partner and rejects the whole debit note.
149
	function applyDeclaredConditions() {
150
		$('#receive-debit-note-form .return-condition').each(function () {
151
			var declared = $(this).data('declared');
152
			if (declared) {
153
				$(this).val(declared);
154
			}
155
		});
156
		syncReceiveConditionState();
157
	}
158
 
37365 amit 159
	// A row whose selected condition differs from what the partner declared is a disagreement,
160
	// not a correction — the server rejects the whole debit note for it.
161
	function hasConditionMismatch() {
162
		var mismatch = false;
163
		$('#receive-debit-note-form tr[data-item-id]').each(function () {
164
			var select = $(this).find('.return-condition');
165
			if (select.val() !== select.data('declared')) {
166
				mismatch = true;
167
			}
168
		});
169
		return mismatch;
170
	}
171
 
37543 amit 172
	// Show/hide the DOA certificate section based on BAD selection on mobile items.
173
	//
174
	// Driven by the CURRENT state of the form, never by what the operator just touched, because the
175
	// form arrives with the partner's declared condition already selected. A partner declaring a
176
	// mobile as BAD - the ordinary DOA case - renders BAD preselected, so no change event ever
177
	// fires; leaving this logic in the change handler alone hid the DOA radios on exactly the rows
178
	// that need them, and the server then refused the receipt for a missing certificate the operator
179
	// was never shown.
180
	function syncReceiveConditionState() {
181
		if (!$('#receive-debit-note-form').length) {
182
			return;
183
		}
37365 amit 184
 
185
		// On a mismatch the receipt never happens, so the DOA certificate is not collected.
37543 amit 186
		if (hasConditionMismatch()) {
37365 amit 187
			$('#condition-mismatch-section').show();
188
			$('#doa-certificate-section').hide();
189
			$('#submit-receive').removeClass('btn-primary').addClass('btn-danger').text('Reject Return');
190
			return;
191
		}
192
		$('#condition-mismatch-section').hide();
193
		$('#submit-receive').removeClass('btn-danger').addClass('btn-primary').text('Confirm Receipt');
194
 
35998 amit 195
		var hasMobileBad = false;
196
		$('#receive-debit-note-form tr[data-category-id]').each(function () {
197
			var categoryId = $(this).data('category-id');
198
			var condition = $(this).find('.return-condition').val();
199
			if (condition === 'BAD' && categoryId == 10006) {
200
				hasMobileBad = true;
201
			}
202
		});
203
		if (hasMobileBad) {
204
			$('#doa-certificate-section').show();
205
		} else {
206
			$('#doa-certificate-section').hide();
207
		}
37543 amit 208
	}
35998 amit 209
 
37543 amit 210
	$(document).on('change', '.return-condition', syncReceiveConditionState);
211
 
35998 amit 212
	// Submit receive debit note form
213
	$(document).on('submit', '#receive-debit-note-form', function (e) {
214
		e.preventDefault();
215
 
37365 amit 216
		var mismatch = hasConditionMismatch();
217
 
218
		// Validate remarks: mandatory for BAD rows, and for any row whose condition was changed —
219
		// the remark is what the partner and the escalation chain see as the reason for rejection.
35998 amit 220
		var valid = true;
221
		$(this).find('tr[data-item-id]').each(function () {
37365 amit 222
			var select = $(this).find('.return-condition');
223
			var condition = select.val();
35998 amit 224
			var remark = $(this).find('.remark-field').val();
37365 amit 225
			if (condition !== select.data('declared') && !remark) {
226
				alert("Remark is required when you change the condition — it is sent to the partner as the rejection reason");
227
				valid = false;
228
				return false;
229
			}
35998 amit 230
			if (condition === 'BAD' && !remark) {
231
				alert("Remark is required for BAD/DOA returns");
232
				valid = false;
233
				return false;
234
			}
235
		});
236
		if (!valid) return;
237
 
37365 amit 238
		var debitNoteId = $(this).data('debitnote-id');
239
		var form = $(this);
240
 
241
		if (mismatch) {
242
			if (!confirm("The condition you selected does not match what the partner declared.\n\n"
243
					+ "This will REJECT the entire debit note and notify the partner, Logistics, RBM and Sales. "
244
					+ "No refund will be raised.\n\nProceed?")) {
245
				return;
35998 amit 246
			}
37365 amit 247
		} else {
248
			// Check DOA certificate if mobile BAD items exist
249
			var hasMobileBad = false;
250
			$(this).find('tr[data-category-id]').each(function () {
251
				if ($(this).data('category-id') == 10006 && $(this).find('.return-condition').val() === 'BAD') {
252
					hasMobileBad = true;
253
				}
254
			});
255
			if (hasMobileBad && !$('input[name="doaCertificateValid"]:checked').val()) {
256
				alert("Please select DOA certificate validity");
257
				return;
258
			}
259
			if (!confirm("Are you sure you want to confirm receipt for this debit note?")) {
260
				return;
261
			}
35998 amit 262
		}
263
 
37365 amit 264
		$.ajax({
265
			url: context + "/return/debit-note/receive/" + debitNoteId,
266
			type: "POST",
267
			data: form.serialize(),
268
			success: function (response) {
269
				if (response === 'true' || response.indexOf('true') >= 0) {
270
					alert(mismatch
271
						? "Debit note rejected due to condition mismatch. Partner and escalation chain notified."
272
						: "Debit note items received successfully");
273
					doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
274
						$('#main-content').html(resp);
275
					});
276
				} else {
277
					alert((mismatch ? "Rejection failed: " : "Receipt failed: ") + response);
35998 amit 278
				}
37365 amit 279
			},
280
			error: function (xhr) {
281
				alert("Error: " + xhr.responseText);
282
			}
283
		});
35998 amit 284
	});
285
 
286
	// Refund Debit Note - opens refund view with receipt details
287
	$(document).on('click', '.refund-debit-note', function () {
288
		var debitNoteId = $(this).data("debitnote-id");
289
		doAjaxRequestHandler(context + "/return/debit-note/refund/" + debitNoteId, "GET", function (response) {
290
			$('#main-content').html(response);
291
		});
292
	});
293
 
294
	// Confirm refund with finance remark
295
	$(document).on('click', '.refund-debit-note-confirm', function () {
296
		var debitNoteId = $(this).data("debitnote-id");
297
		var financeRemark = $('#finance-remark').val();
298
		if (confirm("Are you sure you want to process refund for debit note " + debitNoteId + "?")) {
299
			doAjaxRequestHandler(context + "/return/debit-note/refund/" + debitNoteId + "?financeRemark=" + encodeURIComponent(financeRemark), "PUT", function (response) {
300
				if (response === 'true') {
301
					alert("Debit note refunded successfully");
37791 amit 302
					reloadReturnQueue();
35998 amit 303
				} else {
304
					alert("Refund failed: " + response);
305
				}
37791 amit 306
			}, approvalFailed);
35998 amit 307
		}
308
	});
309
 
310
	// Reject debit note return
311
	$(document).on('click', '.reject-debit-note-confirm', function () {
312
		var debitNoteId = $(this).data("debitnote-id");
313
		var rejectRemark = $('#reject-remark').val();
314
		if (!rejectRemark) {
315
			alert("Please enter a reject remark");
316
			return;
317
		}
318
		if (confirm("Are you sure you want to reject return for debit note " + debitNoteId + "? This will reverse all scans and quantities.")) {
319
			doAjaxRequestHandler(context + "/return/debit-note/reject/" + debitNoteId + "?rejectRemark=" + encodeURIComponent(rejectRemark), "PUT", function (response) {
320
				if (response === 'true') {
321
					alert("Return rejected successfully");
322
					doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
323
						$('#main-content').html(resp);
324
					});
325
				} else {
326
					alert("Rejection failed: " + response);
327
				}
328
			});
329
		}
330
	});
36022 amit 331
 
36027 amit 332
	// Approve Invoice Return (finance approval for shipped invoices)
333
	$(document).on('click', '.approve-invoice-return', function () {
334
		var proId = $(this).data("pro-id");
335
		if (confirm("Are you sure you want to approve and refund this invoice return?")) {
336
			doAjaxRequestHandler(context + "/return/invoice/approve/" + proId, "PUT", function (response) {
337
				if (response === 'true') {
338
					alert("Invoice return approved and refunded successfully");
37791 amit 339
					reloadReturnQueue();
36027 amit 340
				} else {
341
					alert("Approval failed: " + response);
342
				}
37791 amit 343
			}, approvalFailed);
36027 amit 344
		}
345
	});
346
 
37791 amit 347
	// ── Refund as B2C (Finance, same day as a NIC refusal for the buyer's GSTIN) ──
348
 
349
	$(document).on('click', '.b2c-refund', function () {
350
		var proId = $(this).data("pro-id");
351
		doAjaxRequestHandler(context + "/return/b2c-refund/" + proId, "GET", function (response) {
352
			$('#main-content').html(response);
353
		});
354
	});
355
 
356
	// Enable the button only when the typed amount equals the refund amount exactly, a remark is
357
	// entered and consent is ticked. The server repeats every one of these checks.
358
	$(document).on('input change', '#b2c-amount, #b2c-remark, #b2c-consent', function () {
359
		var $amount = $('#b2c-amount');
360
		var typed = $.trim($amount.val()).replace(/,/g, '');
361
		var expected = String($amount.data('expected'));
362
		var matches = typed !== '' && /^\d+$/.test(typed) && typed === expected;
363
		$('#b2c-amount-error').toggle(typed !== '' && !matches);
364
		var ready = matches && $.trim($('#b2c-remark').val()) !== '' && $('#b2c-consent').is(':checked');
365
		$('#b2c-refund-confirm').prop('disabled', !ready);
366
	});
367
 
368
	$(document).on('click', '.b2c-refund-confirm', function () {
369
		var $btn = $(this);
370
		var proId = $btn.data("pro-id");
371
		var amount = $.trim($('#b2c-amount').val()).replace(/,/g, '');
372
		var remark = $.trim($('#b2c-remark').val());
373
		if (!confirm("Refund Rs. " + $btn.data("amount-label") + " to " + $btn.data("partner") + " as B2C?\n"
374
				+ "Stock comes back to the warehouse and a local credit note is issued.\nThis cannot be undone.")) {
375
			return;
376
		}
377
		$btn.prop('disabled', true);
378
		doAjaxRequestHandler(context + "/return/b2c-refund/" + proId + "?amount=" + encodeURIComponent(amount)
379
				+ "&remark=" + encodeURIComponent(remark) + "&consent=true", "PUT", function (response) {
380
			var cnNumber = response;
381
			try { cnNumber = JSON.parse(response); } catch (e) { /* already a plain string */ }
382
			alert("Refunded Rs. " + $btn.data("amount-label") + ". Credit note " + cnNumber + " issued (B2C, no IRN).");
383
			reloadReturnQueue();
384
		}, function (xhr, msg) {
385
			alert("B2C refund failed: " + errorText(msg));
386
			$btn.prop('disabled', false);
387
		});
388
	});
389
 
390
	$(document).on('click', '.b2c-refund-cancel', function () {
391
		reloadReturnQueue();
392
	});
393
 
36408 amit 394
	// Reject Invoice Return — sale stands, no inventory/wallet/GST action
395
	$(document).on('click', '.reject-invoice-return', function () {
396
		var proId = $(this).data("pro-id");
397
		var rejectRemark = prompt("Reason for rejecting this invoice return? (sale will stand, no refund will be issued)");
398
		if (!rejectRemark) {
399
			return;
400
		}
401
		if (confirm("Reject invoice return and let the sale stand? This cannot be undone.")) {
402
			doAjaxRequestHandler(context + "/return/invoice/reject/" + proId + "?rejectRemark=" + encodeURIComponent(rejectRemark), "PUT", function (response) {
403
				if (response === 'true') {
404
					alert("Invoice return rejected");
405
					doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
406
						$('#main-content').html(resp);
407
					});
408
				} else {
409
					alert("Rejection failed: " + response);
410
				}
411
			});
412
		}
413
	});
414
 
36447 amit 415
	// Acknowledge rejected return — retailer confirms goods received back
416
	$(document).on('click', '.acknowledge-rejected-return', function () {
417
		var debitNoteId = $(this).data("debitnote-id");
418
		if (confirm("Confirm that you have received the rejected goods back? This will restore your inventory.")) {
419
			doAjaxRequestHandler(context + "/return/debit-note/reject/acknowledge/" + debitNoteId, "PUT", function (response) {
420
				if (response === 'true') {
421
					alert("Goods acknowledged. Inventory restored.");
422
					doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
423
						$('#main-content').html(resp);
424
					});
425
				} else {
426
					alert("Acknowledgment failed: " + response);
427
				}
428
			});
429
		}
430
	});
431
 
36022 amit 432
	// Process Invoice Return (non-GRN'd)
433
	$(document).on('click', '.process-invoice-return', function () {
434
		var invoiceNumber = $(this).data("invoice");
435
		var remark = $('#invoice-return-remark').val();
436
		if (confirm("Are you sure you want to process return for invoice " + invoiceNumber + "?")) {
437
			doAjaxRequestHandler(context + "/return/invoice/process?invoiceNumber=" + encodeURIComponent(invoiceNumber) + "&remark=" + encodeURIComponent(remark), "PUT", function (response) {
438
				if (response === 'true') {
439
					alert("Invoice return processed successfully");
440
					doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
441
						$('#main-content').html(resp);
442
					});
443
				} else {
444
					alert("Return failed: " + response);
445
				}
446
			});
447
		}
448
	});
23506 amit.gupta 449
});
450
 
23638 amit.gupta 451
function viewReturnStores(domId){
452
	doAjaxRequestHandler(context+"/return/stores", "GET", function(response){
23506 amit.gupta 453
		$('#' + domId).html(response);
454
	});
455
}
456
 
457
function viewPendingReturns(domId){
458
	doAjaxRequestHandler(context+"/return/pending", "GET", function(response){
459
		$('#' + domId).html(response);
460
	});
461
}
462
 
463
function viewApprovedReturns(domId){
464
	doAjaxRequestHandler(context+"/return/approved", "GET", function(response){
465
		$('#' + domId).html(response);
466
		$("#approved-returns").find('a:first').click();
467
	});
468
}
469
 
23539 amit.gupta 470
function viewDebitNotes(domId){
471
	doAjaxRequestHandler(context+"/return/debit-note-created", "GET", function(response){
472
		$('#' + domId).html(response);
473
		$("#debit-notes").find('a:first').click();
474
	});
475
}
476
 
23506 amit.gupta 477
function createReturnRequest(inventoryItemId, container){
478
	doAjaxRequestHandler(context+"/return/inventory/" + inventoryItemId, "PUT", function(response){
479
		if(response=='true') {
480
			container.closest('td').html('Return requested');
481
		}
482
	});
483
}
484
 
485
function approveReturnRequest(inventoryItemId, container){
486
	doAjaxRequestHandler(context+"/return/inventory/approve/" + inventoryItemId, "PUT", function(response){
487
		if(response=='true') {
488
			container.closest('td').html('Return Approved');
489
		}
490
	});
491
}
492
 
493
function denyReturnRequest(inventoryItemId, container){
494
	doAjaxRequestHandler(context+"/return/inventory/deny/" + inventoryItemId, "PUT", function(response){
495
		if(response=='true') {
496
			container.closest('td').html('Return denied');
497
		}
498
	});
499
}
500
 
501
function viewDebitNote(warehouseId){
502
	doAjaxRequestHandler(context+"/return/debit-note/view/" + warehouseId, "GET", function(response){
503
		//Download PDF code
504
	});
505
}
506
 
507
function generateDebitNote(warehouseId){
508
	doAjaxRequestHandler(context+"/return/debit-note/generate/" + warehouseId, "PUT", function(response){
509
		if(response=='true') {
35998 amit 510
			//Download the pdf
23506 amit.gupta 511
		}
35998 amit 512
	});
23506 amit.gupta 513
}
514
 
515
function getDebitNote(debitNotedId) {
516
	doAjaxRequestHandler(context+"/return/debit-note/" + debitNotedId, "GET", function(response){
35998 amit 517
 
23506 amit.gupta 518
	});
519
}
37791 amit 520
 
521
function reloadReturnQueue() {
522
	doAjaxRequestHandler(context + "/return/invoice", "GET", function (resp) {
523
		$('#main-content').html(resp);
524
	});
525
}
526
 
527
// Pull the human-readable message out of an error body; fall back to the raw text.
528
function errorText(msg) {
529
	try {
530
		var body = JSON.parse(msg);
531
		var r = body.response || body;
532
		return r.message || r.code || body.message || body.code || msg;
533
	} catch (e) {
534
		return msg;
535
	}
536
}
537
 
538
// A refused approval may have just opened the B2C option, so show the reason and reload the
539
// queue - the row then carries the "Refund as B2C" button without a manual refresh.
540
function approvalFailed(xhr, msg) {
541
	alert("Approval failed: " + errorText(msg));
542
	reloadReturnQueue();
543
}