We can use this solution to customize return authorization in the MyAccount section by adding customized form fields.
JavaScript:
Entry Point:
define("JJ.Return.Authorization", [
"JJ.Return.Authorization.View",
"ReturnAuthorization.Form.View",
"jj_return_authorization.tpl",
"ReturnAuthorization.Form.Item.Actions.View",
"jj_return_authorization_form.tpl",
'Backbone.View',
'Transaction.Line.Views.Cell.SelectableActionableNavigable.View',
'jj_transaction_line_views_cell_selectable_actionable_navigable.tpl'
], function (
AuthorizationViewInmodelFAQ,
ReturnAuthorizationFormView,
jj_return_authorization_tpl,
ReturnAuthorizationFormItemActionsView,
jj_return_authorization_form_tpl,
BackboneView,
TransactionLineViewsCellSelectableActionableNavigableView,
jj_transaction_line_views_cell_selectable_actionable_navigable_tpl
) {
"use strict";
return {
mountToApp: function mountToApp(container) {
//ReturnAuthorization.Form.Item.Actions.View is extending for the adding new field to the return form.
_.extend(ReturnAuthorizationFormItemActionsView.prototype, {
template: jj_return_authorization_tpl,
events: _.extend(
{},
ReturnAuthorizationFormItemActionsView.prototype.events,
{
'click [data-action="set-return-option"]': "setReturnOption",
'change #return-authorization-item-damaged': "setItemDamaged",
'change #return-authorization-item-used': "setItemUsed",
'change #return-authorization-is-in-pakage': "setItemInPackage",
'change [data-action="reasons"]': "setReasons",
'change [data-action="reason-text"]': "setReasonsText",
}
),
//setReasonsText function is using for updating the other reason that is entered in the text box.
setReasonsText: function (e) {
let reason = this.model.get('reason');
reason.text = e.currentTarget.value
this.model.set('reason', reason);
this.render();
},
//setReasons function is using to set the reason that selected in the reason selection box.
setReasons: function (e) {
let isOther = e.currentTarget.value === '9' ? true : false;
let text = e.currentTarget[e.currentTarget.value].innerText;
this.model.set('reason', { isOther : isOther, text : text, value : e.currentTarget.value});
this.render();
},
//setItemDamaged function is using to set the item damaged value that selected in the item damaged selection box.
setItemDamaged: function (e) {
this.model.set('itemDamaged', e.currentTarget.value);
this.render();
},
//setItemUsed function is using to set the item used value that selected in the item used selection box.
setItemUsed: function (e) {
this.model.set('itemUsed', e.currentTarget.value);
this.render();
},
//setItemInPackage function is using to set the item is in package value that selected in the item is in package selection box.
setItemInPackage: function (e) {
this.model.set('itemInPackage', e.currentTarget.value);
this.render();
},
//setReturnOption function is used to prevent the reloading page while entering the customized options.
setReturnOption: function (e) {
e.preventDefault();
},
//ReturnAuthorization.Form.Item.Actions.View getContext is extending for the seting up of option values after render.
getContext: _.wrap(ReturnAuthorizationFormItemActionsView.prototype.getContext,function (fn) {
let original = fn.apply(this, _.toArray(arguments).slice(1));
try {
const current_reason = this.model.get('reason') || {};
original.isOtherReasonSelected = current_reason ? current_reason.isOther : false;
let itemId = this.model.id;
_.delay(() => {
this.model.get('reason') ? $('[data-id="'+ itemId + '"] [data-action="reasons"]').val(this.model.get('reason').value) : undefined;
this.model.get('reason') ? $('[data-id="'+ itemId + '"] [data-action="reason-text"]').val(this.model.get('reason').text) : undefined;
this.model.get('itemDamaged') ? $('[data-id="'+ itemId + '"] #return-authorization-item-damaged').val(this.model.get('itemDamaged')) : undefined;
this.model.get('itemUsed') ? $('[data-id="'+ itemId + '"] #return-authorization-item-used').val(this.model.get('itemUsed')) : undefined;
this.model.get('itemInPackage') ? $('[data-id="'+ itemId + '"] #return-authorization-is-in-pakage').val(this.model.get('itemInPackage')) : undefined;
},50)
} catch (error) {
console.error("Error @ ReturnAuthorization.Form.View getContext",error);
}
return original;
}
),
});
//ReturnAuthorization.Form.View is extending for the validation of newfields and passing value to Suitescript.
_.extend(ReturnAuthorizationFormView.prototype, {
template: jj_return_authorization_form_tpl,
events: _.extend({},ReturnAuthorizationFormView.prototype.events,{
'click [data-action="show-faq-inmodel"]': "showFAQ",
'submit form': "saveForm",
}),
//applyReasonHandler function is extensding for the setting up the same values when we click apply to all function.
applyReasonHandler: function (e){
const currentLine = this.getLine(this.getLineId(e.target));
e.preventDefault();
e.stopPropagation();
return this.setActiveLines({
reason: currentLine.get('reason'),
textReason: currentLine.get('textReason'),
itemDamaged: currentLine.get('itemDamaged'),
itemUsed: currentLine.get('itemUsed'),
itemInPackage: currentLine.get('itemInPackage')
}).render();
},
//showFAQ function is using to show the FAQ content as popup.
showFAQ: function (e) {
let layout = this.application.getLayout();
let view = new AuthorizationViewInmodelFAQ({
container: container
});
view.render();
layout.showInModal(view);
},
//saveForm function is using to extend the functionality and validation of return form.
saveForm: function (e) {
if (this.preValidate()) {
let createdFrom = this.createdFromModel,
data = {
id: createdFrom.get('internalid'),
type: createdFrom.recordtype,
lines: this.getActiveLinesData(),
comments: this.comments || ''
};
if (e.preventDefault(), this.isValid(data)) return BackboneView.prototype.saveForm.call(this, e, this.model, data)
}
e.preventDefault();
},
//preValidate function is using to extend the validation of newly added fields.
preValidate: function () {
try {
let lines = this.lines.models;
let isAllFilled = true;
_.each(lines, (item) => {
let islineSelected = $('[data-id="'+ item.id+'"] .transaction-line-views-cell-selectable-actionable-navigable-select input')[0].checked;
if (islineSelected) {
if (!(item.get('itemDamaged') != null) || !(item.get('itemUsed') != null) || !(item.get('itemInPackage') != null)) {
isAllFilled = false;
}
let reason = item.get('reason');
if (reason) {
reason.isOther === true && (reason.text === '' || reason.text === 'Other') ? isAllFilled === false && this.showError('Please enter value other reason.') : true;
}
}
})
isAllFilled === false ? this.showError('Please answer the required questions to proceed.') : true;
return isAllFilled;
} catch (error) {
console.error('Error @ preValidate: ', error);
}
},
//getActiveLinesData function is extending for updating the line data.
getActiveLinesData: function() {
try {
let reason = null;
let selected_reason;
return _.map(this.getActiveLines(), function(line) {
reason = line.get('reason');
selected_reason = null;
if (reason) {
selected_reason = reason.isOther ? line.get('textReason') : reason.text;
}
return {
id: line.get('internalid'),
quantity: line.get('returnQty') || line.get('quantity'),
reason: selected_reason,
custcol_jj_returns_item_damaged : line.get('itemDamaged'),
custcol_jj_returns_item_used : line.get('itemUsed'),
custcol_jj_returns_item_inpackage : line.get('itemInPackage')
};
});
} catch (error) {
console.error('Error @ getActiveLinesData: ', error);
}
},
//ReturnAuthorizationFormView is using for disabling the return for non returnable items.
getContext: _.wrap(ReturnAuthorizationFormView.prototype.getContext, function (fn) {
let context = fn.apply(this, _.toArray(arguments).slice(1));
try {
_.each(this.lines.models, (line) => {
if (line.get('item').get('custitem_returnable') === false) {
line.set('checked', false);
}
})
} catch (error) {
console.error('Error @ ReturnAuthorizationFormView getContext: ', error);
}
return context;
})
});
//TransactionLineViewsCellSelectableActionableNavigableView is using to show the error messages for non-returnable items.
_.extend(TransactionLineViewsCellSelectableActionableNavigableView.prototype, {
template: jj_transaction_line_views_cell_selectable_actionable_navigable_tpl,
getContext: _.wrap(TransactionLineViewsCellSelectableActionableNavigableView.prototype.getContext, function (fn) {
let context = fn.apply(this, _.toArray(arguments).slice(1));
try {
if (context.actionType === "return-line") {
context.isReturnable = this.model.get('item').get('custitem_returnable');
}
} catch (error) {
console.error('Error @ TransactionLineViewsCellSelectableActionableNavigableView getContext: ', error);
}
return context;
})
});
},
};
});
Template:
jj_return_authorization_form.tpl
{{#if showBackToAccount}}
<a href="/" class="return-authorization-form-button-back">
<i class="return-authorization-form-button-back-icon"></i>
{{translate 'Back to Account'}}
</a>
{{/if}}
<section class="return-authorization-form">
<header>
<h2 class="return-authorization-form-title">{{pageHeader}}</h2>
</header>
<div data-type="alert-placeholder"></div>
<form class="return-authorization-form-form">
<fieldset class="return-authorization-form-items-fieldset">
<p class="return-authorization-form-items-info">
{{translate '<label class="return-authorization-form-items-fieldset-from-label">From: </label><a href="$(0)">Purchase #$(1)</a>' createdFromURL model.tranid}}
</p>
<input type="hidden" name="type" value="{{model.recordtype}}">
<div class="view-faq-contents">View <a data-action="show-faq-inmodel" class="faq-show-model">Frequently Asked Questions</a></div>
<h5 class="return-authorization-form-products-title">{{translate 'Select products to return'}}</h5>
<input type="hidden" name="id" value="{{model.internalid}}">
<div data-view="ListHeader"></div>
<div class="return-authorization-form-list">
<table class="return-authorization-form-returnable-products-table md2sm">
<tbody data-view="Returnable.Lines.Collection"></tbody>
</table>
</div>
<p>
<small class="return-authorization-form-counter-legend">
{{#if activeLinesLengthGreaterThan1}}
{{translate '<b>$(0)</b> products selected' activeLinesLength}}
{{else}}
{{translate '<b>$(0)</b> product selected' activeLinesLength}}
{{/if}}
</small>
</p>
<p>
<small class="return-authorization-form-counter-legend">
{{#if itemsToReturnLengthGreaterThan1}}
{{translate '<b>$(0)</b> items in total to return' itemsToReturnLength}}
{{else}}
{{translate '<b>$(0)</b> item in total to return' itemsToReturnLength}}
{{/if}}
</small>
</p>
</fieldset>
{{#if showInvalidLines}}
<div class="return-authorization-form-accordion-divider">
<div class="return-authorization-form-accordion-head">
<a class="return-authorization-form-accordion-head-toggle collapsed" data-toggle="collapse" data-target="#return-authorization-form-products" aria-expanded="true" aria-controls="return-authorization-form-products">
{{translate 'Products from original order not eligible for return ($(0))' invalidLinesLength}}
<i class="return-authorization-form-accordion-toggle-icon"></i>
</a>
</div>
<div class="return-authorization-form-accordion-body collapse" id="return-authorization-form-products" role="tabpanel" data-target="#return-authorization-form-products">
<div data-content="items-body">
<table class="return-authorization-form-products-list">
<thead class="return-authorization-form-table-products-header">
<th class="return-authorization-form-table-products-header-image"></th>
<th class="return-authorization-form-table-products-header-product">{{translate 'Product'}}</th>
<th class="return-authorization-form-table-products-header-qty">{{translate 'Qty'}}</th>
<th class="return-authorization-form-table-products-header-unit-price">{{translate 'Unit price'}}</th>
<th class="return-authorization-form-table-products-header-amount">{{translate 'Amount'}}</th>
</thead>
<tbody data-view="Invalid.Lines.Collection"></tbody>
</table>
</div>
</div>
</div>
{{/if}}
<fieldset class="return-authorization-form-comment-fieldset">
<label class="return-authorization-form-comment-label" for="comment">{{translate 'Add a comment <span class="return-authorization-form-comment-label-optional">(optional)</span>'}}</label>
<textarea data-action="comments" class="return-authorization-form-comment" rows="4">{{comments}}</textarea>
</fieldset>
<div class="form-actions">
<button type="submit" class="return-authorization-form-submit-button" {{#unless hasAtLeastOneActiveLine}}disabled{{/unless}}>{{translate 'Submit Request'}}</button>
</div>
</form>
</section>
{{!----
The context variables for this template are not currently documented. Use the {{log this}} helper to view the context variables in the Console of your browser's developer tools.
----}}
jj_return_authorization.tpl
{{#if isLineActive}}
<label class="return-authorization-form-item-actions-label" for="reason">
{{translate 'Why are you returning the item?'}} <span class="return-authorization-form-item-actions-required">*</span>
</label>
{{#if showReasons}}
<select data-action="reasons" name="reason" class="return-authorization-form-item-actions-options" data-toggle="false">
<option value="null">{{translate 'Select a reason'}}</option>
{{#each reasons}}
<option value="{{id}}" {{#if isSelected}}selected{{/if}} data-toggle="false">{{text}}</option>
{{/each}}
{{!-- <option value="other" {{#if isOtherReasonSelected}}selected{{/if}}>{{translate 'Other'}}</option> --}}
</select>
{{#if isOtherReasonSelected}}
<input type="text" data-action="reason-text" name="reason-text" value="{{textReason}}" data-toggle="false" class="return-authorization-form-item-actions-other-reason-input">
{{/if}}
<div class="return-authorization-form-group" data-validation="control-group">
<label class="return-authorization-form-group-label" for="itemDamaged">
{{translate 'Is the item damaged?'}}
<span class="return-authorization-form-label-required">*</span>
</label>
<div class="return-authorization-form-controls" data-validation="control">
<select name="itemDamaged" id="return-authorization-item-damaged" data-toggle="false" class="return-authorization-form-item-actions-options">
<option data-toggle="false" disabled selected value="null">Select an option</option>
<option data-toggle="false" value="1">Yes</option>
<option data-toggle="false" value="2">No</option>
</select>
</div>
</div>
<div class="return-authorization-form-group" data-validation="control-group">
<label class="return-authorization-form-group-label" for="itemUsed">
{{translate 'Has the item been used?'}}
<span class="return-authorization-form-label-required">*</span>
</label>
<div class="return-authorization-form-controls" data-validation="control">
<select name="itemUsed" id="return-authorization-item-used" data-toggle="false" class="return-authorization-form-item-actions-options">
<option data-toggle="false" disabled selected value="null">Select an option</option>
<option data-toggle="false" value="1">Yes</option>
<option data-toggle="false" value="2">No</option>
</select>
</div>
</div>
<div class="return-authorization-form-group" data-validation="control-group">
<label class="return-authorization-form-group-label" for="isInpakage">
{{translate 'Do you still have or is it still in the original packaging?'}}
<span class="return-authorization-form-label-required">*</span>
</label>
<div class="return-authorization-form-controls" data-validation="control">
<select name="isInpakage" id="return-authorization-is-in-pakage" data-toggle="false" class="return-authorization-form-item-actions-options">
<option data-toggle="false" disabled selected value="null">Select an option</option>
<option data-toggle="false" value="1">Yes</option>
<option data-toggle="false" value="2">No</option>
</select>
</div>
</div>
{{#if activeLinesLengthGreaterThan1}}
<a href="#" class="return-authorization-form-item-actions-apply-reason-button" data-action="apply-reason" data-toggle="false">{{translate 'Apply to all'}}</a>
{{/if}}
{{else}}
<input type="text" data-action="reason-text" name="reason-text" value="{{textReason}}" data-toggle="false" class="return-authorization-form-item-actions-other-reason-text">
{{/if}}
{{/if}}
{{!----
The context variables for this template are not currently documented. Use the {{log this}} helper to view the context variables in the Console of your browser's developer tools.
----}}
jj_transaction_line_views_cell_selectable_actionable_navigable.tpl
<tr class="transaction-line-views-cell-selectable-actionable-navigable-row{{#if isLineChecked}} selected{{/if}}" data-action="{{actionType}}" data-id="{{lineId}}">
<td class="transaction-line-views-cell-selectable-actionable-navigable-select">
{{#if isReturnable}} <input type="checkbox" value="{{itemId}}" data-action="select" {{#if isLineChecked}}checked{{/if}}> {{/if}}
</td>
<td class="transaction-line-views-cell-selectable-actionable-navigable-thumbnail">
<img class="transaction-line-views-cell-selectable-actionable-navigable-thumbnail-image" src="{{resizeImage thumbnail.url 'thumbnail'}}" alt="{{thumbnail.altimagetext}}">
</td>
<td class="transaction-line-views-cell-selectable-actionable-navigable-details">
<div class="transaction-line-views-cell-selectable-actionable-navigable-name">
{{#if isNavigable}}
<a {{{linkAttributes}}} class="">
{{itemName}}
</a>
{{else}}
<span class="transaction-line-views-cell-selectable-actionable-navigable-viewonly">
{{itemName}}
</span>
{{/if}}
{{#unless isReturnable}}
<span class="global-views-message global-views-message-error alert">Sorry, this is a non-returnable item.</span>
{{/unless}}
</div>
<div class="transaction-line-views-cell-selectable-actionable-navigable-price">
<div data-view="Item.Price"></div>
</div>
<div data-view="Item.Sku"></div>
<div class="transaction-line-views-cell-selectable-actionable-navigable-options">
<div data-view="Item.SelectedOptions"></div>
</div>
</td>
<td class="transaction-line-views-cell-selectable-actionable-navigable-extras">
<div class="" data-view="Item.Summary.View"></div>
</td>
<td class="transaction-line-views-cell-selectable-actionable-navigable-actions">
<div data-view="Item.Actions.View" class=""></div>
</td>
</tr>
{{!----
The context variables for this template are not currently documented. Use the {{log this}} helper to view the context variables in the Console of your browser's developer tools.
----}}
Suite Script:
// JJ.Return.Authorization.js
// Load all your starter dependencies in backend for your extension here
// ----------------
define('JJ.Return.Authorization'
, [
'ReturnAuthorization.Model',
'Application',
'underscore'
]
, function (
ReturnAuthorizationModel, Application, _
)
{
'use strict';
_.extend(ReturnAuthorizationModel, {
// @method create
// @param data
// @return {Number}
//create function is extending for storing the newfield values in Return form of NetSuite.
create: function (data) {
const returnAuthorization = nlapiTransformRecord(
data.type,
data.id,
'returnauthorization'
);
const CURRENT_LINE = this.getTransactionLines(data.id);
this.setLines(returnAuthorization, data.lines, CURRENT_LINE);
returnAuthorization.setFieldValue('memo', data.comments);
_.each(data.lines, function (line, key) {
returnAuthorization.setLineItemValue('item', 'custcol_jj_returns_item_used', key + 1, line.custcol_jj_returns_item_used);
returnAuthorization.setLineItemValue('item', 'custcol_jj_returns_item_damaged', key + 1, line.custcol_jj_returns_item_damaged);
returnAuthorization.setLineItemValue('item', 'custcol_jj_returns_item_inpackage', key + 1, line.custcol_jj_returns_item_inpackage);
});
return nlapiSubmitRecord(returnAuthorization);
},
})
});