Pull reports from Shopify - ruby-on-rails

I am trying to pull reports automatically from shopify admin portal. From source page I can see that javascript function makes this call -
var shopifyQL = "**SHOW** quantity_count, total_sales BY product_type, product_title, sku, shipping_city, traffic_source, source, variant_title, host, shipping_country, shipping_province, day, month, referrer FROM **products** SINCE xxx UNTIL yyy ORDER BY total_sales DESC";
var options = {"category":"product_reports","id":wwwwww,"name":"Product Report by SKU","shopify_ql":"SHOW quantity_count, total_sales BY product_type, product_title, sku, shipping_city, traffic_source, source, variant_title, host, shipping_country, shipping_province, day, month, referrer FROM products SINCE xxxx UNTIL yyyy ORDER BY total_sales DESC","updated_at":"zzz"};
However looking at the product API (https://docs.shopify.com/api/product) I do not see most of the attributes. I am assuming some join tables or seperate calls to the model. Also I tried to pull single sku information but it pulls everything.
ShopifyAPI::Product.find(:all, :params => {:variants => {:sku => 'zzzz'}})
Does anybody had any experience to work with reports??

You need to grab the data from the api and play with it. The available objects are clearly stated on the Shopify API docs. Admin dashboard data can't be pulled like the way you seem to envision unless you play with JavaScript injection (tampermonkey...) which is highly not recommended.

It would go like this for you. First off, if you pull products, you have do so in chunks of 250. The :all symbol gives you up to 250. Supplying a page and limit parameter would help there.
Second, you cannot filter by SKU. Instead, download all the products, and then inside each product are the variants. A variant has a SKU, so you'd search that way.
Doing that, you could setup your own nice reference data structure, ready to be used in reporting as you see fit.

Related

Rails DRY RESTful design of API endpoints with filters

I am developming a JSON API with Rails 4.2 which looks like this:
GET api/v1/car => app/controller/api/v1/car_controller#index
GET api/v1/car/:id/installment => app/controller/api/v1/carresources/installment_controller#index
Now i would like to extend these endpoint with filters.
api/v1/carresources/installment#index:
all installments for a specific car during a specific time period
all installments for a specific car by payment type (cash, mobile money, <- mobile money provider)
api/v1/car#index:
all cars by region
all cars by dealer
all cars by loan schema
The way i implemented is the following:
app/controller/api/v1/car_controller.rb
def index
res = []
if params.key?('start_date') and parms.key?('end_date')
res = Car.index_period(params['start_date'], params['stop_date']
elsif params.key?('loanstructure')
res = Car.index_loan_strucuture(params['loan_strucuture'])
....
end
end
Which is working, but not such a nice solution to put completely semantically different logic behind these if-"graves".
It would be possible to create a new endpoint for each filter, but i have the feeling that this bloats the routing and controller structure.
I would also like to avoid these if clauses, because these is also some authorization on the users role going on -which i skipped showing - which is also done with if clauses
Is there another clever way, or should i spent an extra route for each filter, where i then need to copy the whole authorization structure.
Many thanks in advance
Many thanks in advance
OP I would suggest breaking the filtering code little separately by handling the request.query.params in a filter class.
This filter class helps in de-coupling the code by
Allowing validation of the filters which are being passed so you can have a parseFilters function which does that.
You can use the hashtable which points to
{('start_date','end_date'): "index_period(params['start_date'], params['stop_date']", etc }
this will help you to apply the filters directly from the parsefilters.
This will ensure that your code is decoupled and also can be reused in other scenarios.

Want to count number of visits on my blogs

I want to count the number of visits on my blog? Can someone please suggest the overall method to implement this feature?
It is just an idea. You can add a count_view column in the database into blogs table with default value 0.
And in the show action of BlogsController add the following code
def show
#blog = Blog.where('id = ?', params[:id]).first
#blog.update_column('count_view', #blog.count_view + 1) if #blog.present?
end
You can modify this logic as per your requirement.
You can check the hit counter gem or the impressionist gem.
You could also use an existing (free) analytics solutions if you want to get much more data than the number of times the action was called (please note that if the same user refreshes the browser 5 times, you get 5 hits):
http://www.google.com/analytics/
Using these you can get data like unique visitors, referral URL, locations data, browser, OS, and a lot of different stuff to make informed decisions. There are several other options (paid, free, real time) available as well:
https://mixpanel.com
https://www.kissmetrics.com/

Magento SalesOrderList... is there a ligth weight version of this, or a way to trim down the returned value

I am attempting to get all the orders from a magento instance. Once a day we grab all the orders.. (sometimes a few thousand)
Extra stuff that's more why I ask:
I'm using ruby-on-rails to grab the orders. This involves sending the soap call to the magento instance. It's easy as.
Once I have the response, I convert it into a Hash (a tree) and then pick out the increment id's of the orders and proceed to call getOrder with the increment id.
I have two problems with what's going on now, one operational, and one religious.
Grabbing the XML response to the list request takes really really long and when you tack on the work involved in converting the XML to a hash, I'm seeing a really slow processes.
The religious bit is that I just want the increment_ids so why do I have to pay for the processing/bandwidth to support a hugely bloated response.
Ok so the question...
Is there a way to set the response returned from Magento, to include only specific fields? Only the updated_at and the increment_id for instance.
If not, is there another call I'm not aware of, that can get just the increment_ids and date?
Edit
Below is an example of what I'm looking for from magento but it's for ebay. I send this xml up to ebay, and get back a really really specific bit of info about the product. It works for orders and such too. I can say "only this" and get just that. I want the same from Magento
<GetItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<SKU>b123-332</SKU><OutputSelector>ItemId</OutputSelector>
</GetItemRequest>
I've created a rubygem that gives you your salesOrderList response in the form of a hash, and you can do what you want with the orders after you've received them back (i.e. select the fields you want including increment_id). Just run
gem install magento_api_wrapper
To do what you want to do, you would do something like this:
api = MagentoApiWrapper::Sales.new(magento_url: "yourmagentostore.com/index.php", magento_username: "soap_api_username", magento_api_key: "userkey123")
orders = api.order_list(simple_filters: [{key: "status" value: "complete"}])
orders.map {|o| [o.increment_id, o.items.first.sku] }
Rough guess, but you get the idea. You would get the array of hashes back and you can do what you want with them after that. Good luck!

How to efficiently update many ShopifyAPI::Product instances using ShopifyAPI (Ruby on Rails)?

I am writing an app which will sit between a vendors proprietary inventory management system and their Shopify shop. The app will periodically update Shopify from new data generated by the inventory management system. It will also provide end-points for Shopify webhooks.
I am currently doing something like this (pseudo-ruby with much stuff omitted):
def update_product_with_proxy(product_proxy)
product_proxy.variant_proxies.dirty.each do |variant_proxy|
update_variant_with_proxy(variant_proxy)
end
if product_proxy.dirty_proxy
shopify_product = ShopifyAPI::Product.find(product_proxy.shopify_id)
shopify_product.update_attributes({some attributes here})
end
end
Elsewhere:
def update_variant_with_proxy(variant_proxy)
shopify_variant = ShopifyAPI::Variant.find(variant_proxy.shopify_id)
shopify_variant.update_attributes({some attributes here})
end
This seems terribly inefficient as I have to fetch each updated ShopifyAPI::Product and ShopifyAPI::Variant before I can update them (I have their id's cached locally). It takes about 25 minutes for an update cycle updating 24 products each with 16 variants. Rails spends less than 2 seconds updating my product/variant proxies. The other 99% of the time is spent talking to Shopify. I must be doing something wrong.
Given that I know the id of the remote object is there a way to updated it directly without having to fetch it first?
cheers,
-tomek
First things first: You can update variants through their parent product. Once you've grabbed the product it'll have the variant info with it so you can edit them, save, and the changes will be persisted in a single API call. That'll save you some time.
Second: You can create an object locally using the gem, give it an id, and then call save to initiate the PUT request without first fetching the object from Shopify. Something like this should do the trick:
product = ShopifyAPI::Product.new(:id => 1, :title => "My new title")
product.save
Putting those two things together should give you what you want: The ability to update a product's variants in a single API call.
Note: For future reference, the shopify_api gem is built on Active Resource, so anything you can do with that library you can do with the gem.

RESTful nested conventional routing

I have the model:
User -1---n- Transaction(amount,description, date)
User -1---n- TransactionImport -1---n- TransactonImportField(name,value)
(personal expense tracking app).
What I want to achieve is this:
User opens URL and pastes the CSV with the list of transactions.
User submits it.
System extracts data from CSV into TransactionImport (row) + TransactionImportField (cell).
User can choose which column means what (amount, description, date) from the imported data in TransactionImport(Field).
User click save and the system transfers TransactionImport into the Transaction.
What I can't seem to get right is the fact that step 3 creates multiple records of TransactionImport (and related TransactionImportField).
So doing POST /transaction_imports?csv=abcd is expected to produce one record if we would be RESTful. But the code is supposed to be something like this:
# TransactionImportsController
def create
result = TransactionImports.parse(params[:csv])
flash[:notice] = result.message
redirect_to transaction_imports_path
end
I am probably approaching the task from a wrong angle as I feel that implementation doesn't fit in tp the inherited_resources.
Could you please advise what would be the most conventional way of implementing this?
Thanks,
Dmytrii.
REST/HTTP has no expectation that doing POST will only create one record. That maybe the default rails behaviour, but you should not constrain your design because of that.

Resources