Vision
I found most of ideas related to DRS is talking about measuring the existing quantity of the product (or size or weight ,..etc) and based on certain threshold device purchase new quantity. This idea is fine in case if customer doesn't know his normal/average usage, this happen for example if he uses this product occasionally. But if customer consume this product always and for long period, usually he will now how much he consumes during certain period. This project will use "Amazon CloudWatch Events - Schedule" to schedule purchasing items based on predefined schedule for each item. This schedule is prepared based on customer prior knowledge of how much he consume this product in certain period.
The Idea
As proof of concept we implement this idea on a Zoo or Farm that contains many kind of animals. Each animal has certain type of foods and consume certain quantity during certain period. One product is created "Zooproduct" which contains many slots, one for each animal.
Note: For simplicity, this projects contain 2 Slots only (Cow Food & Chicken Food).
The usage for each item during certain period is known. As you can see in below screen next time to purchase "Cow Food" item will be 20 Jan 2017 (as in "purchaseDate" field). This item should be purchased every 15 days (as in "everyPeriod" field) based on this item known usage. So in 20 Jan, purchase request will be placed using Amazon DRS and "purchaseDate" field will be updated with next purchase date (5 Feb 2017). All data about the items are saved in DynamoDB table.
Everyday "CloudWatch Events - Schedule: CheckZooStuffScheduledEvent" launch Lambda function "zooStaffSchadule" to check items ,in "zooProducts" DynamoDB table, that should be purchased in this date
Create security profile
To create an LWA security profile " Amazon DRS Developer Challenge", follow this link
Create DRS
To create new device "zooProduct" & slots, follow wizard in this link. For simplicity I left only 2 slots (Cow Food & Chicken Food) in the device.
SNS
To create an SNS topic "ZooProductsSNS", follow this link.
Create lambda function
Follow below screens to create new Lambda function ("zooStuffSchadule") and add "Amazon CloudWatch Events - Schedule" as a trigger to Lambda function. Trigger will be fired once per day. Note that it is recommended to disable this trigger till you finish implementing and testing the whole solution.
Create tables
To create new table "zooProducts" in DynamoDB, follow steps in this tutorial
Each row in table will represent an item. Each item is represent a slot in DRS product. For each item we saved information such: access token, refresh token, client ID, client secret, slot ID as replenishment URL, next purchase date and period in days between 2 successful purchases.
Gate Way API
Follow steps in this tutorial . This is needed to publish Lambda function so Amazon DRS can return back to lambda function with refresh & access tokens.
Dash Replenishment Account Setup
Follow below steps to setup Dash replenishment account
step 1: Get authorization code for first time - done only once
for each item we need to get the authorization code that will be used to get refresh & access token for the first time.
create an HTML page to redirect you to Amazon DRS, in this HTML page write below script
window.open("https://www.amazon.com/ap/oa?client_id=amzn1.application-oa2-client......&scope=dash%3Areplenish&scope_data=%7B%22dash%3Areplenish%22%3A%7B%22device_model%22%3A%222d0f.....%22%2C%22serial%22%3A%22zoo1233567%22%2C%22is_test_device%22%3Atrue%7D%7D&response_type=code&redirect_uri=https%3A%2F%2F9o.....amazonaws.com%2Fprod%2FzooStaffSchadule");
Note that "is_test_device" should be true as we don't have a real product and we just testing the idea.
Below screens show steps needed
From last step you get the authorization code for the "Cow Food" item. Copy & paste this code in lambda function URL
https://.........amazonaws.com/prod/zooStaffSchadule?product=Cow Food&code=ANVYvnQyGYegnXcqTkZV
This will trigger code inside the Lambda function to
- Get product saved info in DynamoDB
- Get the refresh & access token
- Saved them in Dynamo DB
getProductInfo( productName ,
function(product)
{
getRefreshToken(code , product , context ,
function (refresh_token , access_token)
{
product.everyPeriod = 0 ;
product.refreshToken = refresh_token ;
product.accessToken = access_token ;
updateRefreshToken( product ,
function()
{
context.succeed();
}
);
}
);
}
);
Code to get the refresh & access tokens is h ereunder. product Object is packing all product information needed to call Amazon DRS API.
var output = "";
var para = "grant_type=authorization_code&code="+ encodeURIComponent(code) +"&client_id="+encodeURIComponent(product.clientID)+"&client_secret="+encodeURIComponent(product.clientSecret)+ "&redirect_uri="+encodeURIComponent(redirect_uri);
var options = {
host: DRS_URL,
port: 443,
path: DRS_PATH,
method: 'POST',
agent: false,
headers:
{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': para.length
}
};
var req = https.request(options,
function(res) {
res.setEncoding('utf8');
var access_token = output[access_token] ;
var refresh_token = output[refresh_token] ;
var responseString = '';
res.on('data', function (chunk) {
responseString += chunk;
});
res.on('end', function() {
output = JSON.parse(responseString);
access_token = output.access_token ;
refresh_token = output.refresh_token ;
callback(refresh_token , access_token);
});
});
req.on('error', context.fail);
req.write(para);
req.end();
Above steps should be repeated to get & save tokens for 2nd product "Chicken Food" as in below video
Video Description: This step needed to be done only once per project to get the refresh code that will be used later in DRS requests. This done by visiting product page which is a simple html file that will redirect you to amazon to select which slot (product) you need. This should be repeated twice to get refresh code for "Chicken Food" & "Cow Food". In Video we are working on "Chicken Food" this is why we skipped the first slot and select the 2nd one. Once this has done, amazon return with Authorization code for 2nd slot. We take manually the authorization code and concatenate it to the Lambda function URL (We go the URL from Gateway API). Lambda URL takes 2 parameters: product name & authorization code. Once Lambda function is launched, it checks on those 2 parameters. if found then function will call amazon to get the refresh code from the authorization code and save it in product row in Dynamo DB table.
step 2: Daily Schedule - Done based on "CloudWatch Events - Schedule"
"zooStuffSchadule" Lambda function has 2 triggers:
- API gateway so lambada function will have a published URL that can be used through communication with DRS API
- CloudWatch event - schedule which will trigger the Lambda function daily.
When Lambda function is launched by CloudWatch event schedule, it will read from Dynamo table all items that should be purchased at this date and for each item
- get new access & refresh tokens for this item based on its old saved refresh token
- Update refresh token & access tokens in DynaoDB
- Call Amazon DRS replenishment API
readSchadule(
function ( productsArray )
{
var productNumber = 0 ;
productsArray.forEach (
function(product) {
productNumber++;
getAccessTokenFromRefreshToken( product , context,
function (refresh_token , access_token)
{
product.refreshToken = refresh_token ;
product.accessToken = access_token ;
updateRefreshToken( product ,
function()
{
dashReplenish( product ,
function()
{
context.succeed();
}
);
}
);
}
);
}
);
}
);
Calling replenishment API code is hereunder
var para = "" ;
var options = {
host: 'dash-replenishment-service-na.amazon.com',
port: 443,
path: product.replenishPath ,
method: 'POST',
agent: false,
headers: {
'Authorization' : 'Bearer ' + product.accessToken ,
'x-amzn-accept-type': 'com.amazon.dash.replenishment.DrsReplenishResult@1.0', 'x-amzn-type-version': 'com.amazon.dash.replenishment.DrsReplenishInput@1.0'
}
};
var req = https.request(options, (res) => {
res.on('data', (d) => {
process.stdout.write(d);
});
});
req.on('error', (e) => {
console.error(e);
});
req.end();
When purchased order is done, confirmation email is received.
Below video show a live trial for above steps
Video Description: This video is recorded in 8th of Jan. table contains 2 items for 2 products: "Chicken food" & "Cow Food". Purchase date for "Cat Food" is 13 Jan while "Chicken Food" should be in 8th of Jan. old logs has been deleted. Lambda function has 2 triggers. The API gateway & Cloud event schedule. schedule is disabled & configured to run every minute for the sake of this demo. Enable the schedule and go to check log file. Lambda function fetch only products that has purchase date equal to 8 Jan so it fetch only one product "Chicken Food". Lambda function gets the details of this product: refresh code, period that will be added to current date to get the new purchase date, replenishment URL,...etc. Then Lambda function calculate the new date, ask for new refresh & access tokens and place an order. at the end of Video we checked the table to find that purchased date has been updated to new date
Comments