I am creating a sample sales order on Netsuite and I do not want it to affect the inventory. Is there a script that I can modify to prevent this?
You could write a script but if you are wanting to approve the sales order and not have it commit inventory there is a Commit drop-down at the line-level that lets you select 'Do Not Commit'
If you need code the field Id is commitinventory and Do Not Commit has value 3 so a sample would be:
for( var i = soRec.getLineCount({sublistId:'item'})-1; i>= 0; i--){
soRec.setSublistValue({
sublistId:'item',
fieldId:'commitinventory',
value:3,
line: i
});
}
Related
I am trying to create a formula to obtain a list of items that have no open transactions.
I cant just filter out by status as this filters out transactions that are open, as opposed to showing me only items with nothing open.
So basically if an item has anything open then i dont want it on the search. I do need it on the search if it has all closed or it has no transactions at all.
Hoping someone can help put me in the right direction.
I am a little bit stuck at where to start with the formulas and tried a case formula.
You can use item saved search adding under criteria as "Transaction Fields-status-anyOf-select all closed/rejected/declined statuses" not in filter reason of saved search.
Thanks.
To get the value of non transaction items as well, You need to check the check box use expression under criteria in standard subtab use parens() with OR expression.
And add one more condition as "Transaction Fields-Internal Id-anyOf-none with
"Transaction Fields-status-anyOf-select all closed/rejected/declined statuses".
Add both condition with OR logic.
It will work for both items condition if it has transaction status with closed or with none of transaction internal ids.
Thanks.
I think this is possible in a saved search, and requires a change in the way the filtering is done. Rather than filtering on the "Filters", using grouping and summary calculations to determine if an item qualifies, basically :
Create the item saved search as you would normally, but don't include a "Standard" filter for the openness of the transaction.
In the results, group by item name (or internalid), and another fields you want to include in the top-level results.
In the Criteria - Summary list, add a Formula (Number) condition :
Summary Type= Sum (Count won't work here)
Formula = case when {transaction.status} = 'Open' then 1 else 0 end
Equal to 0
Whether this is more or less elegant than bknight's answer is debatable.
I don't think this is the sort of thing you can do with a single saved search.
It would be fairly easy to do with SuiteQL though.
The script below runs in the console and finds items that are not on any Pending Billing Sales Orders. It's adapted from a script with a different purpose but illustrates the concept.
You can get a list of the status values to use by creating a saved search that finds all the transactions with open statuses you want to exclude , take note of that saved search's id and running the second script in the console
require(['N/query'], query => {
const sqlStr = `
select item.id, itemid, count(po.tranid) as po, count(bill.tranId) as bill, max(bill.tranDate) as lastBilled, count(sale.tranId) as sales, count(tran.tranId) as trans
from item
left outer join transactionLine as line
on line.item = item.id
left outer join transaction as tran on line.transaction = tran.id
left outer join transaction as po on line.transaction = po.id and po.type = 'PurchOrd'
left outer join transaction as bill on line.transaction = bill.id and bill.type = 'VendBill'
left outer join transaction as sale on line.transaction = sale.id and sale.type in ('CustInvc', 'CashSale')
where item.id not in (select otl.item from transactionLine otl, transaction ot where
otl.transaction = ot.id and ot.status in ('SalesOrd:F'))
group by item.id, item.itemid
`;
console.log(sqlStr);
console.log(query.runSuiteQL({
query: sqlStr
}).asMappedResults().map((r, idx)=>{
if(!idx) console.log(JSON.stringify(r));
return `${r.id}\t${r.itemid}\t${r.po}\t${r.bill}\t${r.lastBilled}\t${r.sales}\t${r.trans}`;
}).join('\n'));
});
require(['N/search'], search=>{
const filters = search.load({id:304}).filters;
console.log(JSON.stringify(filters.find(f=>f.name == 'status'), null, ' '));
});
In terms of doing something with this you could run this in a saved search and email someone the results, show the results in a workbook in SuiteAnalytics or build a portlet to display the results - for this last Tim Dietrich has a nice write up on portlets and SuiteQL
I am fairly new to suitescript and would like to build a script that runs on a recurring schedule and only invoices based on item fulfillments (ie there is a one to one relationship between the invoice and item fulfillment but potentially a one to many relationship between the sales order and invoice/item fulfillments).
I am able to successfully run a script that transforms the sales order in total into an invoice - however this includes all items on sales order and not just the items that have been fulfilled (we have many situations in our business in which only partial fulfillment occurs and the order must then be closed out). At this point from my research I'm unable to find other examples of this script being successfully created. My initial idea is to somehow store the 'qtyfulfilled' on the sales order in an an array with the items and somehow create an invoice with this. However to me it seems that the transform function is the best way to retain a link between sales order and the invoice.
var invoice = record.transform({
fromType: record.Type.SALES_ORDER,
fromID: salesOrderId,
toType: record.Type.INVOICE,
isDynamic: true
});
This returns an invoice with all items from the sales order rather than just the fulfilled items.
EDIT:
I implemented a version of the code suggested where I just iterate over the lines of the sales order and replace each line quantity on the invoice with 'fulfilledquantity' - however I realized when the quantity is zero the invoice appears to be still storing that line at a zero value.
Downstream of the invoice script I'm passing the invoice record to our EDI provider via a NS integration. The invoices created via my script map into the EDI 810 (invoice record) with 0 quantity lines for the line items that werent fulfilled which cause errors in the EDI file.
I wrote the following to iterate through invoice lines after the quantity and remover the zero quantity lines but am getting the following error: "name":"USER_ERROR","message":"Please choose an item to add" -
for (var k = 0; k < lineCount; k++) {
var currentInvoiceLineQuantity = newInvoice.getSublistValue ({
sublistId: 'item',
fieldId: 'quantity',
line: k
});
if(currentInvoiceLineQuantity === 0){
newInvoice.removeSublistSubrecord({
sublistId: 'item',
fieldid: 'item',
line: k
});
k--;
lineCount--;
}
}
After you transform the sales order to an invoice, iterate through the lines and change the quantity to only invoice the amount that was fulfilled.
The sample below is from a legacy script written in SS1.0 but will translate pretty easily to SS2.0.
var lineCount = invoice.getLineItemCount('item');
for (var i = 1; i <= lineCount; i++) {
const quantity = invoice.getLineItemValue('item', 'quantity', i);
const remaining = invoice.getLineItemValue('item', 'quantityremaining', i);
invoice.setLineItemValue('item', 'quantity', i, quantity - remaining);
}
If you do this in an After Submit user event on Item Fulfillments you can transform the related Sales Order to an invoice and then walk backwards through the line times and delete the ones not on the fulfillment.
You should check quantities for the against the shipped quantities and you may need to have logic for billing any unfulfillable items ( I do that either the first fulfillment on an order or when there are no more lines to ship. )
Finally you may need to handle shipping charge logic to either charge the amount of shipping on each fulfillment or charge the fulfillment’s shipping up to the shipping charge on the original sales order.
I am trying to retrieve records in Netsuite via SuiteScript. I would like to use the lastmodifieddate column to fetch record after a certain timestamp.
I am currently doing:
var filters = [new nlobjSearchFilter('lastmodifieddate', null, 'notbefore', time)];
var columns = [new nlobjSearchColumn('lastmodifieddate')];
var newSearch = nlapiCreateSearch(table, filters, columns);
var searchResultSet = newSearch.runSearch();
var back = nextEndIndex - 1000
var results = searchResultSet.getResults(back, nextEndIndex);
Where time is a datetime JS, nextEndIndex index counter for results.
This works for some objects but majority of Netsuite objects do not have the lastmodifieddate column in the record browser. Is there a built in variable for the lastmodifieddate? And if there is, how can I use it in nlapiCreateSearch? If you have better ways to do it, I would be grateful for the info.
Here is a simple example for SuiteScript 2.0.
define(['N/search'],function(search){
function test(chkDate){
log.debug(chkDate);
var empSearch=search.create({
type:search.Type.EMPLOYEE,
columns:['internalid','firstname','lastmodifieddate'],
filters:['lastmodifieddate','after',chkDate]
}).run().each(function(result){
log.debug(JSON.stringify(result));
return true;
});
}
test('05/30/2017');
});
This example is searching for employees, since I was not sure which record type you were looking at. Below are links to the information you can use to build out your searches:
Records Browser (look at the bottom of each section in the filters and columns):
Search Operators (shows which ones to use for which field types)
API Docs
Transactions are slightly different than entities. Transactions have lines. If you are trying to determine the true last modified date of a transaction, you may need to consider using the "Line Last Modified" field in place of "Last Modified Date." Try writing a simple search to pull Sales orders. Include "Last Modified Date" and "Line Last Modified." Then write a simple formula to show those that don't match. When I did this, there were a number of mismatches, with instances of "Line Last Modified" being more than 1 month later than "Last Modified Date." So if you are looking for the true last modified date, you may need to use the max "Line Last Modified."
You could use a 'Max' Summary Filter on {systemnotes.date} - you will of course need to Group by record (document number or internal id for example) for this to show correct results.
When the billing schedule runs it auto generates invoices from sales order. When this happens - how can I create a link on the sales order that will allow me to load the corresponding invoice in code?
I need this so I can grab couple of field values from the invoice but I can't access the invoice directly from another entity which seems only related to sales order.
EDIT 1:
var fil = [];
fil[0] = new nlobjSearchFilter('createdfrom', null, 'is', nlapiGetRecordId())
var col = [];
col[0] = new nlobjSearchColumn('internalid');
var invoices = nlapiSearchRecord('invoice', null, fil, col);
nlapiLogExecution('DEBUG', 'field val', invoices);
Throws invalid operator or not in proper syntax: createdfrom.
Though adding a link on the Sales Order is a viable solution, it's not your only option. Alternatively, you could do a search for invoices where the createdfrom field is the internal ID of your Sales Order. Something like in SuiteScript 1.0:
var invoices = nlapiSearchRecord('invoice', null,
[['createdfrom', 'is', nlapiGetRecordId()]],
[/* create search columns for the fields you need off the invoice */]
) || [];
or in 2.0:
var invoices = search.create({
"type": search.Type.INVOICE,
"filters": [['createdfrom', 'is', context.currentRecord.id]],
"columns": [/* create search columns for the fields you need off the invoice */]
}).run().each(processResult);
This will get you a list of all the Invoices created from your Sales Order (which is likely only 1).
If you believe you need a link to the Invoice on the Sales Order, you could add the custom body field, then create a User Event on the Invoice record that populates this new field with its createdfrom value on the Before Submit event. But then what happens if your Sales Order gets paid via multiple Invoices?
For a future project we have been assigned to create a simple concept (inside Magento) that would has to do the following:
A customer has the ability to choose between different shipping methods, one of them being "Ship2Shop", which sends the product to a physical store of choice and the customer has to go an pick it up.
When a customer selects this "ship2shop" shipping method, a certain percentage (eg: 25%) of the total amount has to be paid online (via a pre-defined payment method) and the remaining 75% has to be paid in the physical store when the customer goes and pick up the products he ordered.
How would you go about this?
Idea that we were having is modify the checkout/order session and modify the "grand total" amount (saving the original in a session ofcourse). When the customer is then sent to the external payment processor the "modified grand total" is sent along. Once the customer returns on the magento platform we would modify the order by restoring the original grand total the way it was and updating the total paid and total due amount.
Anyone got any other ideas about this?
EDIT:
After feedback from Anton S below I managed to add an "advance payment total". However Im still having a problem
In the config.xml I have added the following in the tag:
acsystems_advancepayment/total_custom
grand_total
I want my advance payment to show AFTER the grand total, for some reason, magento won't do that...
EDIT2: Collect method
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
$quote = $address->getQuote();
$advancePaymentAmount = 0;
$baseAdvancePaymentAmount = 0;
$items = $address->getAllItems();
if (!count($items)) {
$address->setAdvancePaymentAmount($advancePaymentAmount);
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
return $this;
}
$address->setBaseAdvancePayment($address->getGrandTotal()*(0.25));
$address->setAdvancePayment($address->getGrandTotal()*(0.25));
$address->setAdvancePaymentAmount($address->getGrandTotal()*(0.25));
$address->setBaseAdvancePaymentAmount($address->getGrandTotal()*(0.25));
$address->setGrandTotal($address->getGrandTotal() - $address->getAdvancePaymentAmount());
$address->setBaseGrandTotal($address->getBaseGrandTotal()-$address->getBaseAdvancePaymentAmount());
return $this;
}
refer to this thread where adding total objects is explained Magento: adding duties/taxes to a quote during review
Basically you should add your own total object based on your shipping method selection, then it will also be shown in totals as separate row and you can show this in every e-mail or place where totals are exposed
public function collect(Mage_Sales_Model_Quote_Address $address)
{
//this is for the loop that you are in when totals are collected
parent::collect($address);
$quote = $address->getQuote();
//variables for your own object context
$advancePaymentAmount = 0;
$baseAdvancePaymentAmount = 0;
$items = $address->getAllItems();
if (!count($items)) {
$address->setAdvancePaymentAmount($advancePaymentAmount);
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
return $this;
}
//calculated based on other total object and don't edit other totals inside your own as your calculations would be always false and so would be next total object in the cycle and so on
$baseAdvancePaymentAmount = $address->getBaseGrandTotal()*(0.25);
$advancePaymentAmount = $address->getQuote()->getStore()->convertPrice($baseAdvancePaymentAmount, false);
//this is just for your own object context
$address->setBaseAdvancePaymentAmount($baseAdvancePaymentAmount);
$address->setAdvancePaymentAmount($advancePaymentAmount);
/*
* this is for the loop that you are in when totals are collected and
* those are set to 0 for each totals collecting cycle
*/
$this->_setBaseAmount($baseAdvancePaymentAmount);
$this->_setAmount($advancePaymentAmount);
return $this;
}
Another option is to change the "grand_total" in your payment module, that way the sessions aren't altered..