Triggering Zapier on new Shopify order containing a specific product - shopify

I have a simple Zap that is triggered on a Shopify New Order (with line details) and then creates a new account in a system called Trainerize. Works perfectly, but it is triggered by ANY new Shopify order. I need to trigger the Zap for a specific product in the Shopify order. Is this possible in Zapier, and how would I go about it? It seems you can't talk to Zapier support unless you have a plan, and I don't want a plan if it is not possible!

Yes, it is possible. The exact implementation depends on how you want to identify the specific product. I am listing 2 possible ways
In case, the criteria to identify product is quite simple, you can use Filter by Zap. For example, if you want to identify product by product Id, you can just add a Filter by Zap and add the following conditions.
Line Items Product ID | Text Contains | Your Product ID - 12345
If you have some complex matching condition for your Product, you can also use Code by Zapier to run JavaScript code. To do so, pass the required data as input to code and return output that can be used later to see if the match was found. A simple example that gets LineItems productIds as input.
const TARGET_PRODUCT_ID = 12345;
const productIds = inputData.productIds.split(",");
output = {targetProductFound: false};
productIds.forEach(id => {
// Add more conditions if needed
if(Number(id) === TARGET_PRODUCT_ID){
output.targetProductFound = true;
}
});
return output
Then use Filter to proceed or abort.

Related

Apply a date field value to expiration date in inventory details subrecord

I'm a newbie in NetSuite Scripting and was recently asked to apply the value from a date field (custbody_expiration_date) on item receipt transaction body to the expiration date field in the inventory details of all items when the item receipt is created.
Since there is no way to create a workflow on inventory details, I've managed to work out below codes however I'm keeping getting all sorts of different error message. Below is one of them after I click on save on item receipt.
Notice (SuiteScript)
org.mozilla.javascript.EcmaError: TypeError: Cannot find function getCurrentLineItemValue in object standard record. (/SuiteScripts/ARROW/Expiration_date_apply_to_all (1).js#27)
I am very confused on the difference between dynamic and standard mode, which functions should be used in which mode? Also, I am a bit hesitated on whether user event script is the correct way to go?
/**
*#NApiVersion 2.0
*#NScriptType UserEventScript
*#NModuleScope Public
*/
define(['N/record','N/search'], function (record, search) {
function beforeSubmit(context) {
var IRrecord = context.newRecord;
var numberOfLineItems = IRrecord.getLineCount({
sublistId: 'item'
});
var expirationdate = IRrecord.getValue({
fieldId: 'custbody_expiration_date'
});
for (var i=1; i<=numberOfLineItems; i++){
IRrecord.setSublistValue({
sublistId: 'item',
fieldId: 'item',
line: i,
value: true
});
//First get Lot Number and Quantity
var lotNumber = IRrecord.getCurrentLineItemValue('item', 'receiptinventorynumber');
var quantity = IRrecord.getCurrentLineItemValue('item', 'quantity');
var inventoryDetail = IRrecord.createCurrentLineItemSubrecord('item','inventorydetail');
inventoryDetail.selectNewLineItem('inventoryassignment');
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'issueinventorynumber', lotNumber);
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'quantity', quantity);
inventoryDetail.setCurrentLineItemValue('inventoryassignment', 'expirationdate', expirationdate);
inventoryDetail.commitLineItem('inventoryassignment');
inventoryDetail.commit();
IRrecord.commitLineItem('item');
}
nlapiSubmitRecord(IRrecord);
}
return {
beforeSubmit: beforeSubmit
}
});
Dynamic records are the kind you see client-side (as a rule) - modify a field value and some other field becomes refreshed and updated in real time. Forms sometimes need to have their fields filled in a particular order to prevent form completion errors triggering or field sourcing to work. For example, when entering a sales order, selecting the customer then defaults the sales tax when items are added to the order. Errors may be thrown at any point before the record save because a field is triggering dynamic sourcing (updating other fields), based on what has been entered.
Standard mode is - less dynamic. You populate the fields of the record in any order you choose, and when the save is performed, you choose whether sourcing (updating other fields from the data available) is triggered. Any errors in data entry are reported when the save is performed. I think it also has a lower client-side load as there are fewer AJAX queries being triggered.
Both are available in client-side and server-side javascript, but some record types cannot be updated client-side and must be done server-side using workflow actions, User Event, Restlet, Suitelets, or scheduled scripts. To the best of my knowledge, inventory subrecords on fulfillments, receipts and the like are one such type.
The way lines are updated changes between dynamic and standard mode. In dynamic mode, lines are selected, updated then committed and the methods used would be :
selectLine
setCurrentLineItemValue
commitLine (only do this if actually changing the line)
For standard mode, the way of changing lines is only to use setSublistValue and include the line number in the parameters.
Workflow action scripts will load the record in dynamic mode, but the load method can be investigated using the isDynamic() method on the record.
The other thing is, in SuiteScript 2, sublist lines are indexed from 0, not from 1 as your script is using. What's confusing is, in Suitescript 1, indexing was from 1. The code is using a mix of v1 & v2. nlapiSubmitRecord is v1, IRrecord.save is v2.
And for more information, see SuiteAnswer 79715 which explains how to set a value on the inventory detail on an item receipt. The example reloads the record in standard mode and updates the inventoryStatus field. SuiteAnswer 45372 explains the Record object and the difference between standard and dynamic modes. Take a look at SuiteAnswer 67605 which explains the basics of SuiteScript v2. SuiteAnswers is an amazing resource and the search is surprisingly good. I can also recommend Eric T Grubaugh's site (#erictgrubaugh) which has some great videos including comparisons between v1 & v2.

How to efficiently retrieve a list of all collections a product belongs to in Shopify?

I want to create a CSV export of product data from a Shopify store. For each product I'm exporting data like the product name, price, image URL etc... In this export I also want to list, for each product, all the collections the product belongs to, preferably in the hierarchal order the collections appear in the site's navigation menu (e.g Men > Shirts > Red Shirts).
If my understanding of the API is correct, for each product I need to make a separate call to the Collect API to get a list of collections it belongs to then another call to the Collections API to get the handle of each collection. This sounds like a lot of API calls for each product.
Is there a more efficient way to do this?
Is there any way to figure out the aforementioned hierarchy of collections?
Unfortunately, as you pointed out, I don't think there is an efficient way of doing this because of the way that the Shopify API is structured. It does not permit collections to be queried from products, rather only products queried from collections. That is, one can't see what collections a product belongs to, but can see what products belong to a collection.
The ShopifyAPI::Collect or ShopifyAPI::Collection REST resource does not return Product variant information, which is needed to get the price information as per the requirements. Furthermore, ShopifyAPI::Collect is limited to custom collections only, and would not work for products in ShopifyAPI::SmartCollection's. For this reason I suggest using GraphQL instead of REST to get the information needed.
query ($collectionCursor: String, $productCursor: String){
collections(first: 1, after: $collectionCursor) {
edges {
cursor
node {
id
handle
products(first: 8, after: $productCursor){
edges{
cursor
node{
id
title
variants(first: 100){
edges{
node{
price
}
}
}
}
}
}
}
}
}
}
{
"collectionCursor": null,
"productCursor": null
}
The $productCursor variable can be used to iterate over all of the products in a collection and the $collectionCursor to iterate over all collections. Note that only the first 100 variants need to be queried since Shopify has a hard limit on 100 variants per product.
The same query can be used to iterate over ShopifyAPI::SmartCollection's.
Alternatively the same query using the REST API would look something like this in Ruby.
collections = ShopifyAPI::Collection.all # paginate
collection.each do |collection|
collection.products.each do |product|
product.title
# note the extra call the Product API to get varint info
ShopifyAPI::Product.find(product.id).variants.each do |varaint|
variant.price
end
end
end
I don't see any way to address the inefficiencies with the REST query, but you might be able to improve on the GraphQL queries by using Shopify's GraphQL Bulk Operations.

How to attach multiple parameters to an API request?

I built my own simple REST API with Express and now I'm consuming it from my client (Vue.js)
So in my page I access all the data from this endpoint: GET /api/books, and it works fine
Now I also have a "sort by" button where I want to get the data by the latest entries. I don't know if that's a good way or if I have to handle this in the backend but what I do is calling the same endpoint which is GET /api/books and sorting the data to get them the right way
For ex:
sortByLatest() {
axios
.get("/api/books")
.then(res => {
const books = res.data;
const sortedBooks = books.sort((a, b) => b.createdAt > a.createdAt ? 1 : -1
);
this.books = sortedBooks;
})
// catch block
}
I do that for everything. If I need a limited number of results or a specific property from the data I have to write some logic in the axios .then block to sort or filter what I want. Is this bad practice?
But that's not my actual problem
My problem is, in addition of sorting by the latest entries, I also want to filter the results by a specific property. The problem is when I click the A button it's gonna filter the books by a specific property, and when I click the B button it's gonna sort them buy the latest entries, but not both at the same time!
And what if I want additionnal things like limit the number of results to 10, filter by other properties etc... I want to be able to create requests that ask all those things at once. How can I do that? Do I have to build that in the backend?
I saw some websites using url parameters to filter stuff, like /genre=horror&sort=latest, is that the key of doing it?
Thank you for your time

Wix Corvid database connection with online Store Products and Collections

Lets say I need to have some logic in this use case scenario. The user is on the WIX Online Store's Product page for a particular product and clicks on QTY to order more units of the product. The logic to add is to check against the inventory at that moment and send a Twilio SMS message to the Store owner as a warning(this use case is somewhat contrived).
The thing is I dont seem to see any examples on WIX online training that shows how the Corvid Database can be connected to existing WIX Online stores which have Products and Collections already defined (which I assume is kept in some database). How does the Corvid Database and the Online Store Products/Collections map and how is it done and how can Corvid js code access that ? By the way, the Corvid uses the term "Collections" which does not seem related to Product Collections which must be a source of confusion for many.
You can access your Wix-Stores products collection using the wix-data module.
import wixStoresBackend from 'wix-stores-backend'; // Not needed here but try in the editor
import wixData from 'wix-data';
const WIX_STORES_PRODUCT_TABLE = 'Stores/Products';
const getProducts = () => {
return wixData.query(WIX_STORES_PRODUCT_TABLE)
.find()
.then((data) => {
let wixInventory = data.items;
return wixInventory
}
If you start there you will see all the items in your Wix-Stores. You can further query the database/collection by narrowing down the query. There are some good starter examples in the Corvid documentation for query here.
Just as a note - Because the Wix-Stores collections are read only you can query them but you can't write to them. If you have a look at wixStoresBackend within the Corvid editor the code completion there shows that you can update some parameters of a product however, you will need to modify a product's item if you want to adjust things like quantity.

Xero API - ability to load data by tracking category?

We need to load invoices whose lines are tagged with a specific tracking category.
Right now the way to do this is to load ALL invoices, which gets invoice header info, then load invoice Lines, which finally gets tracking info, then filter out the ones I need.
This seems very inefficient. Is there a better way to do this? I do not want to load all invoices, then load them one by one just to find the few which are using the specific tracking category.
Use paging to get the invoices with the lines included, it should mean fewer calls will be required to the API.
Here is a snippet from one of my projects that uses paging for invoices. c# version
var api = XeroApiHelper.CoreApi();
api.SummarizeErrors(false);
var invoices = new List<Invoice>();
var invoicep = new List<Invoice>();
int i = 1;
do
{
invoicep = api.Invoices.Where("Contact.ContactID == Guid(\"" + xeroId + "\")").Page(i).Find().ToList();
invoices.AddRange(invoicep);
i++;
} while (invoicep.Any());