I am newbie to NetSuite and wanted to show vendor names in specific format while displaying. Currently each vendor has auto-generated id with some prefix e.g.
ABC0001
ABC0002
ABC0003
These vendors are then shown as a sublist in other pages as following:
ABC0001 Mr. Vendor A
ABC0002 Mr. Vendor B
ABC0003 Mr. Vendor C
I want to show vendor name as Name only, without the id in sublists like below:
Mr. Vendor A
Mr. Vendor B
Mr. Vendor C
How is that possible? Currently I tried to use following SuiteScript, but its not working:
define(["N/record"], function (record) {
/**
*#NApiVersion 2.0
*#NScriptType ClientScript
*/
function pageInit(context) {
var itemRecord = record.load({
type: record.Type.INVENTORY_ITEM,
id: context.currentRecord.id,
isDynamic: false,
});
var lines = itemRecord.getLineCount({ sublistId: "itemvendor" });
for (var i = 0; i < lines; i++) {
var vendorName = itemRecord.getSublistText({
sublistId: "itemvendor",
fieldId: "vendor",
line: i,
});
var parts = vendorName.split(" ");
parts.shift();
vendorName = parts.join(" ");
itemRecord.setSublistText({
sublistId: "itemvendor",
fieldId: "vendor",
line: i,
text: vendorName
});
}
itemRecord.save();
}
return {
pageInit: pageInit,
};
});
Any idea what am I doing wrong here?
You want to change the "entityid" field on the Vendor itself not in the Item sublist. So probably when the vendors are saved you will want to update the entityId to display whatever you want it to show up as in LOV's.
You may have to change some preferences depending on how your Auto Generated Numbers are setup. Go to Setup > Company > Auto-Generated Numbers and make sure that you are allowing override on the vendors.
Related
Is there a jQuery or vanilla JS function that will group items of matching text content, without me prompting class names, elements, etc?
More specifically for this project, I need to group modules together, and I do not know how many will eventually be made. I can name them all similarly, say "Module 1 DOC, Module 1 XLSX, Module 1 PPT, Module 2 DOC, Module 2 XLSX, Module 2 PPT," etc, so it could be something like:
$("div#page").each(function(index) {
// check titles for generic matching content
if ($(this).find("h1:contains('*[words-that-match]')").length > 0) {
}
});
or [same-title] something like that? I'm not sure what the syntax would look like.
I apologize that my JS/JQ knowledge is so lacking, I am pretty new to this. Thanks in advance!
If you can, I recommend separating your grouping logic from the display, that way you can easily change the label without impacting the logic.
For example instead of only having a name make it into an object that looked something like:
{
displayName: "Module 1 PPT",
fileType: "PPT"
}
Then you could use the JS Array.reduce function to group objects together.
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
const moduleFiles = [
{
displayName: "Module 1 PTT",
fileType: "PTT"
},{
displayName: "Module 1 DOC",
fileType: "DOC"
},{
displayName: "Module 2 PTT",
fileType: "PTT"
},{
displayName: "Module 2 DOC",
fileType: "DOC"
}
]
console.log(groupBy(moduleFiles, 'fileType'));
The above code was copied from: Another SO answer
EDIT: The solution I used ended up using relied on a using a .nextAll().first() element search and targeting with a fake class. Disclosure: I'm working front-end in an LMS without access to any stylesheets or PHP.
$(document).ready(function(index) {
var URL = "li.modtype_url"
var BOOK = "li.modtype_book"
var H5P = "li.modtype_h5pactivity"
// select only items titled module...
if ($(this).find("p.instancename:contains('module')").length > 0) {
//-- CHANGE THE URL MODTYPE TITLE
$(URL).each(function(index) {
// variables
let oldTitle = $(this).find(".snap-asset-link")
let newTitle = $(this).find(".snap-asset-content .contentafterlink a.tile-title")
// save the title, remove it, and add to new location
oldTitle.remove();
newTitle.append(oldTitle);
/// hide or remove additional unwanted asset styling
$(this).find(".snap-assettype").css("height", "0px");
$(this).find(".snap-asset-content .no-overflow").removeClass("no-overflow");
});
//-- MOVE ICONS
$(this).each(function () {
var oldIcon = $(".snap-header-card .snap-header-card-icons .snap-asset-completion-tracking img")
var newIcon = ".snap-asset-content .contentafterlink div.tile-completion"
// first of set
$(this).each(function () {
// find the first of each, add empty class to mark
let oldIcon_URL = $(URL).first().find(oldIcon).addClass("moved")
let oldIcon_BOOK = $(BOOK).first().addClass("moved").find(oldIcon)
let oldIcon_H5P = $(H5P).first().addClass("moved").find(oldIcon)
let newIconLocation = $(URL).first().addClass("moved").find(newIcon)
// relocated all moved-targeted items to new location
newIconLocation.append(oldIcon_URL).append(oldIcon_H5P).append(oldIcon_BOOK);
});
//next of each modtype, repeated
setInterval(function() {
// find the first non-targeted of each, add empty class to mark
let oldIcon_URL = $("li.modtype_url:not(.moved)").first().find(oldIcon).addClass("moved")
let oldIcon_BOOK = $("li.modtype_book:not(.moved)").first().addClass("moved").find(oldIcon)
let oldIcon_H5P = $("li.modtype_h5pactivity:not(.moved)").first().addClass("moved").find(oldIcon)
let newIconLocation = $("li.modtype_url:not(.moved)").first().addClass("moved").find(newIcon)
// relocated all moved-targeted items to new location
newIconLocation.append(oldIcon_URL).append(oldIcon_H5P).append(oldIcon_BOOK);
});
});
};
});
This solution is a) majorly convoluted and b) while it is an automated process, is relies modules to cascade (ie 1, 2, 3 only) to group. Not ideal.
I don't know how to add res.partner object in below screen.js
print_xml: function() {
var env = {
widget: this,
pos: this.pos,
order: this.pos.get_order(),
receipt: this.pos.get_order().export_for_printing(),
paymentlines: this.pos.get_order().get_paymentlines()
};
render_receipt: function() {
var order = this.pos.get_order();
this.$('.pos-receipt-container').html(QWeb.render('PosTicket',{
widget:this,
order: order,
partner:partner,
receipt: order.export_for_printing(),
orderlines: order.get_orderlines(),
paymentlines: order.get_paymentlines(),
}));
};
};
I have tried to add the partner object in above javascript but it's not working.
I am new in odoo and i have also not munch knowledge of JavaScript so pls help me to solve this issue.
If i am able to add res.partner object in this javascript file then and then only i m available to access the res.partner objcet in my pos.xml file.
I wan't the address details of company and it's not in res_company so how can i fetch the street and other address from res_partner for company ?
You can get it using get_client() method.
You will get full object of the partner of current order then you can use it as like a py file eg. partner.city etc. in the receipt template.
render_receipt: function() {
var order = this.pos.get_order();
this.$('.pos-receipt-container').html(QWeb.render('PosTicket',{
widget:this,
order: order,
partner:this.pos.get_order().get_client(),
receipt: order.export_for_printing(),
orderlines: order.get_orderlines(),
paymentlines: order.get_paymentlines(),
}));
};
Update:
To add address fields in res.company model in js.
var module = require('point_of_sale.models');
var models = module.PosModel.prototype.models;
for(var i=0; i<models.length; i++){
var model=models[i];
if(model.model === 'res.company'){
model.fields.push('street');
model.fields.push('city');
model.fields.push('state_id');
model.fields.push('country_id');
// other field you want to pull from the res.company table.
}
}
Then you will get it in the company:this.pos.company.
Now you can use it in template eg. company.street, company.city etc.
For country and state use company.state_id[1] and company.country_id[1] in template.
I am a little surprised I am not finding anything out there on this. My question is really 2 parts:
Is it possible to generate a form select field (preferably with Autoform) with all of the options being registered users emails or names? If so could anyone please provide an example?
Is it possible (again autoform is preferred) to have conditional form field rules. EX: I have a client with multiple locations. One select would be for the client, and depending on what is selected here would populate another select that generates all of this clients locations. Again ANY examples would be appreciated!
Thanks so much!
Really not answering but rather just giving a better visual of the code I added. I am getting an input box but not a select box. There is nothing inside the input. Here is what I added:
inspector: {
type: String,
autoform: {
type: "selectize",
options: function() {
return Meteor.users.find({}, fields: {
emails: 1,
profile: 1
}).map(function(c) {
var optionsArray = [];
for (var i = 0; i < c.length; i++) {
optionsArray[i] = {};
optionsArray[i].label = c[name][i];
optionsArray[i].value = c[name][i];
}
return optionsArray;
})[0];
},
defaultValue: function() {
return "Choose a User";
},
}
},
Just curious what I got wrong.
Autoform is awesome work done by aldeed. So much of functionality inside it, it would take some time to read and understand the documentation. I will try to help with an example.
Is it possible to generate a form select field (preferably with Autoform) with all of the options being registered users emails or names? If so could anyone please provide an example?
var myAutoForm = new SimpleSchema({
"formSelectField": {
type: String,
autoform: {
type: "selectize",
options: function() {
return collectionName.find({ criteria to get the registered user names }).map(function(c) {
var optionsArray = [];
for (var i = 0; i < c.length; i++) {
optionsArray[i] = {}; // creates a new object
optionsArray[i].label = c[name][i];
optionsArray[i].value = c[name][i];
}
return optionsArray;
})[0];
},
defaultValue: function() {
return the default value to be picked on the select dropdown
},
}
},
});
Is it possible (again autoform is preferred) to have conditional form field rules. EX: I have a client with multiple locations. One select would be for the client, and depending on what is selected here would populate another select that generates all of this clients locations. Again ANY examples would be appreciated!
For this, I will put only the options part of the autoform
options: function() {
if(AutoForm.getFieldValue('fieldName', 'formId')==='something')
})
return someValue;
},
When I design interfaces, I can't be bothered to create believable dummy text. At the same time, however, I don't want to just copy and paste the same exact data over and over, because then the interface doesn't look terribly realistic.
I have generated a Master JSON Schema that contains the most common types of data I use. I'd like to be able to do something like this when I'm writing HTML:
<ul>
<li>{first_name}</li>
<li>{first_name}</li>
...
<li>{first_name}</li>
</ul>
OR
<ul>
<li data="{first_name}"></li>
<li data="{first_name}"></li>
...
<li data="{first_name}"></li>
</ul>
...whereby every instance of {first_name} is replaced with a random first name from my JSON file. Likewise for any other variable I have in there ( last_name, email, address, country, sentence, etc... )
Is there a way to do this without PHP in something like jQuery? I imagine it'd have to be something like:
foreach(var) {
return randomData(var);
}
Ideally I'd have a very simple, generalized function that would comb through the UI looking for any and all tags and replace each one with a random piece of data from the master schema JSON file.
Click below to see solution I came up with thanks to Billy's help:http://jsfiddle.net/JonMoore/5Lcfz838/2
between http://chancejs.com/ and http://handlebarsjs.com/ you can generate lots of repeatable, seeded random data structures...
// get references to DOM elements
var tplElm = document.getElementById('template');
var tgtElm = document.getElementById('target');
// compile handlebars template
var template = Handlebars.compile(tplElm.innerText);
// initialise chance with seed
// change the seed to change the output data
var chance = new Chance(1234567890);
// create array of random data
var people = [];
for(var i=0;i<10;i++){
people.push({
first_name: chance.name()
});
}
// apply data to template, and insert into page
tgtElm.innerHTML = template({
people: people
});
<!-- load dependencies -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/0.5.6/chance.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.min.js"></script>
<!-- define template -->
<script id="template" type="text/template">
<ul>
{{#people}}
<li>{{first_name}}</li>
{{/people}}
</ul>
</script>
<!-- placeholder for output -->
<div id="target"></div>
Something like this will give you what you want:
var json = [{ "first_name": "bob"}, {"first_name": "sam"}, {"first_name": "bill"}];
var randomnum = Math.floor((Math.random() * 3));
console.log(json[randomnum].first_name);
You can access this data using AJAX and then get elements using Math.random.
Then, with the help of jQuery you can dynamically generate li items.
Let's suppose you have a div element like <div id="anyId"></div> where you will put your ul and lis.
function getElementsFromMasterSchema(count, callback) {
var items = [];
var usedIds = {};
$("h3").text("Request sent...Loading...");
timer = setInterval(function() {
$("h3").text("Loading..." + (time++) + " seconds passed.");
}, 1000);
$.ajax({
url: "https://www.mockaroo.com/37dcc3b0/download?count=100&key=37b5a7c0",
method: "GET"
}).done(function(dt) {
var length = dt.length;
while (items.length < count) {
var randomItem = dt[Math.round(Math.random() * length)];
if (usedIds[randomItem.id] !== true) {
usedIds[randomItem.id] = true;
items.push(randomItem);
}
}
callback(items);
});
}
getElementsFromMasterSchema(10, function(result) {
var ul = $("<ul/>");
for (var i = 0; i < result.length; i++) {
$("<li/>").text(result.first_name).appendTo(ul);
}
$("#anyId").append(ul);
});
Note that you need to make requests from the same domain or set Access-Control-Allow-Origin header in order to make cross-domain requests.
However, this method is working slowly. It takes from 5 to 20 seconds to load this file. Loading a large file from a server and using only some of data is a bad approach.
You definitely need to implement this algorithm on a server side. Something like SQL SELECT TOP n FROM x ORDER BY newid() (SELECT * FROM x ORDER BY RAND() LIMIT n).
I've got a JSON file which has a size of 1Mb.
I tried to implement typeahead.js with a simple example like this:
<div class="container">
<p class="example-description">Prefetches data, stores it in localStorage, and searches it on the client: </p>
<input id="my-input" class="typeahead" type="text" placeholder="input a country name">
</div>
<script type="text/javascript">
// Waiting for the DOM ready...
$(function(){
// applied typeahead to the text input box
$('#my-input').typeahead({
name: 'products',
// data source
prefetch: '../php/products.json',
// max item numbers list in the dropdown
limit: 10
});
});
</script>
But when I launch it Chrome says:
Uncaught QuotaExceededError: Failed to execute 'setItem' on 'Storage':
Setting the value of '__products__itemHash' exceeded the quota.
What can I do? I'm using the typeahead.min.js
You are seeing that error because typeahead prefetch uses localStorage to store the data.
Firstly, storing 1MB of data on the client side is not really good in term of user experience.
Given that, you can still solve the problem with multiple-datasets. This is just a workaround and may not be the most elegant solution but it works perfectly.
The sample data I tested with was >1MB and looks like this
You can view the sample here (It takes a while to open)
Procedure:
First download the entire data using $.getJSON
Then split the data into chunks of 10,000 (just a magical number that worked for me across browsers. Find yours)
Created sets of bloodhounds for each chunk and store everything in an array.
Then initialize typeahead with that array
Code:
$.getJSON('data.json').done(function(data) { // download the entire data
var dataSources = [];
var data = data['friends'];
var i, j, data, chunkSize = 10000; // break the data into chunks of 10,000
for (i = 0, j = data.length; i < j; i += chunkSize) {
tempArray = data.slice(i, i + chunkSize);
var d = $.map(tempArray, function(item) {
return {
item: item
};
});
dataSources.push(getDataSources(d)); // push each bloodhound to dataSources array
}
initTypeahead(dataSources); // initialize typeahead
});
function getDataSources(data) {
var dataset = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('item'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data,
limit: 1 // limited each dataset to 1 because with 76,000 items I have 8 chunks and each chunk gives me 1. So overall suggestion length was 8
});
dataset.initialize();
var src = {
displayKey: 'item',
source: dataset.ttAdapter(),
}
return src;
}
function initTypeahead(data) {
$('.typeahead').typeahead({
highlight: true
}, data); // here is where you use the array of bloodhounds
}
I created a demo here with 20 items and chunkSize of 2 just to show how multiple-datasets would generally work. (Search for Sean or Benjamin)
Hope this helps.