Etsy Order Manager

Using Angular and Node

Posted on 2016-03-11 21:46:00 in angular, nodejs, API
Update: Since writing this, the screenshots have been lost. Sorry for the inconvenience.

The Problem

We have an Etsy shop that sells planner stickers. We have had it for a few months now, and more and more orders are coming in. It's exciting, but it is also a lot of work to keep track of and ship multiple orders a day.

Etsy looks nice and has some good seller tools, but as I analyzed Terra's process all the way from getting a sale to shipping the order, I saw some things that could be improved.

  1. She keeps track of which orders she has printed in a text file on her computer. As she completes each one, she checks them off.

  2. She doesn't know ahead of time how many of each sticker sheet she needs to print. For example, let's say she gets 5 orders. Etsy will show them like this:

Customer 1: Sticker Sheet A
Customer 2: Sticker Sheet B
Customer 3: Sticker Sheet A, B, C
Customer 4: Sticker Sheet B, A
Customer 5: Sticker Sheet A, D, C

She could go down the list, printing each sheet as goes, but she can actually fit more than one sticker sheet on a page. So she tries to save paper and time by printing all "Sticker Sheet A's" at the same time and all "Sticker Sheet B's" at the same time. This requires her to scroll up and down quite a bit and keep a mental note of too many things.

I asked her to describe the ideal "Etsy Order Manager" and she helped me come up with this wireframe...


Wireframe

(missing photo)

With a layout like this she can always see her progress, and she can see how many of each sticker sheet type remain for her to print.


Using the Etsy API

The Etsy API let me do everything I needed with just one request!

(missing photo)

This let me find all of the receipts with an "open" status, which is exactly what Terra looks at to see which orders she needs to ship next. The results of this call included everything I needed except for the name of the buyer and information about the product they orders.

Luckily, this endpoint lets you append "associations" to your request. Here are the associations available for all "receipt" endpoints:

(missing photo)

The receipts' transactions contain the buyer name and information about the products they ordered. So, all I had to do to get all this information was add this to my API call: ?includes=Transactions

Then, I just opened up a route on my express server which requested this info from the Etsy API:

app.get('/getReceipts', function(req, res) {

    var getReceipts = new Promise(function(resolve, reject){

    client.auth(process.env.CONSUMER_KEY, 
        process.env.CONSUMER_SECRET
        ).get(
        '/shops/'+process.env.SHOP_NAME+'/receipts/open', 
        {limit: 100, includes: 'Transactions'}, function(err, status, body, headers) {
            if (err) {
                console.log(err);
            }
            if (body) {
                resolve(body.results);
            }
        })
    });

    getReceipts.then( function(receipts){
	res.send(receipts);
        // keep promise resolution in case we need more API calls
    });
});

Then, I could call that server route from my angular controller to put the data into the view:

$scope.getReceipts = function(chosen_date){
    return $http.get('/getReceipts')
        .success(function(data) {
                storeData(data, chosen_date);
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });
}


Conclusion

I left quite a bit out in this post. I learned a LOT about angular and node, especially about asynchronous calls. At one point, I believed I had to make a separate call for every single receipt. I found out the hard way that "for" loops don't work the same way in node as they do in other languages, but I've learned to love the asynchronous nature of node. Modules like "async" make API data collection very fast and simple. And angular was the perfect tool for keeping all the checkboxes in sync.

After a few days of work in between classes, here is the final result:

(missing photo)

See it on Github