Skip to content

Commit

Permalink
Merge 3dab341 into f638182
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon6193 committed Jun 26, 2019
2 parents f638182 + 3dab341 commit 696f41a
Show file tree
Hide file tree
Showing 26 changed files with 1,027 additions and 123 deletions.
112 changes: 112 additions & 0 deletions button-merchant/src/main/java/com/usebutton/merchant/ApiRequest.java
@@ -0,0 +1,112 @@
/*
* ApiRequest.java
*
* Copyright (c) 2019 Button, Inc. (https://usebutton.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

package com.usebutton.merchant;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

/**
* Api request model for {@link ConnectionManager}
*/
class ApiRequest {

/**
* Request Method for the api request
*/
enum RequestMethod {
POST("POST");

private final String value;

RequestMethod(String value) {
this.value = value;
}

String getValue() {
return value;
}
}

private final RequestMethod requestMethod;
private final String path;
private final Map<String, String> headers;
private final JSONObject body;

private ApiRequest(Builder builder) {
this.requestMethod = builder.requestMethod;
this.path = builder.path;
this.headers = builder.headers;
this.body = builder.body;
}

RequestMethod getRequestMethod() {
return requestMethod;
}

String getPath() {
return path;
}

Map<String, String> getHeaders() {
return headers;
}

JSONObject getBody() {
return body;
}

/**
* Constructor
*/
static class Builder {

private final RequestMethod requestMethod;
private final String path;
private Map<String, String> headers = new HashMap<>();
private JSONObject body = new JSONObject();

Builder(RequestMethod requestMethod, String path) {
this.requestMethod = requestMethod;
this.path = path;
}

Builder addHeader(String key, String value) {
headers.put(key, value);
return this;
}

Builder setBody(JSONObject body) {
this.body = body;
return this;
}

ApiRequest build() {
return new ApiRequest(this);
}
}
}
Expand Up @@ -47,4 +47,9 @@ PostInstallLink getPendingLink(String applicationId, String ifa,
@WorkerThread
Void postActivity(String applicationId, String sourceToken, String timestamp, Order order)
throws ButtonNetworkException;

@Nullable
@WorkerThread
Void postOrder(Order order, String applicationId, String sourceToken,
@Nullable String advertisingId) throws ButtonNetworkException;
}
124 changes: 109 additions & 15 deletions button-merchant/src/main/java/com/usebutton/merchant/ButtonApiImpl.java
Expand Up @@ -32,9 +32,11 @@

import com.usebutton.merchant.exception.ButtonNetworkException;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -69,14 +71,19 @@ public PostInstallLink getPendingLink(String applicationId, String ifa,

try {
// Create request body
JSONObject request = new JSONObject();
request.put("application_id", applicationId);
request.put("ifa", ifa);
request.put("ifa_limited", limitAdTrackingEnabled);
request.put("signals", new JSONObject(signalsMap));
JSONObject requestBody = new JSONObject();
requestBody.put("application_id", applicationId);
requestBody.put("ifa", ifa);
requestBody.put("ifa_limited", limitAdTrackingEnabled);
requestBody.put("signals", new JSONObject(signalsMap));

ApiRequest apiRequest = new ApiRequest.Builder(ApiRequest.RequestMethod.POST,
"/v1/web/deferred-deeplink")
.setBody(requestBody)
.build();

// Execute POST request and parse response
NetworkResponse response = connectionManager.post("/v1/web/deferred-deeplink", request);
NetworkResponse response = connectionManager.executeRequest(apiRequest);
JSONObject responseBody = response.getBody().optJSONObject("object");
if (responseBody != null) {
boolean match = responseBody.getBoolean("match");
Expand Down Expand Up @@ -107,17 +114,104 @@ public Void postActivity(String applicationId, String sourceToken, String timest

try {
// Create request body
JSONObject request = new JSONObject();
request.put("app_id", applicationId);
request.put("user_local_time", timestamp);
request.put("btn_ref", sourceToken);
request.put("order_id", order.getId());
request.put("total", order.getAmount());
request.put("currency", order.getCurrencyCode());
request.put("source", "merchant-library");
JSONObject requestBody = new JSONObject();
requestBody.put("app_id", applicationId);
requestBody.put("user_local_time", timestamp);
requestBody.put("btn_ref", sourceToken);
requestBody.put("order_id", order.getId());
requestBody.put("total", order.getAmount());
requestBody.put("currency", order.getCurrencyCode());
requestBody.put("source", "merchant-library");

ApiRequest apiRequest = new ApiRequest.Builder(ApiRequest.RequestMethod.POST,
"/v1/activity/order")
.setBody(requestBody)
.build();

// Execute POST request and parse response
connectionManager.post("/v1/activity/order", request);
connectionManager.executeRequest(apiRequest);
} catch (JSONException e) {
Log.e(TAG, "Error creating request body", e);
throw new ButtonNetworkException(e);
}

return null;
}

@Nullable
@Override
public Void postOrder(Order order, String applicationId, String sourceToken,
@Nullable String advertisingId) throws ButtonNetworkException {

try {
// Create request body
JSONObject requestBody = new JSONObject();
requestBody.put("currency", order.getCurrencyCode());
requestBody.put("btn_ref", sourceToken);
requestBody.put("order_id", order.getId());
requestBody.put("purchase_date", ButtonUtil.formatDate(order.getPurchaseDate()));
requestBody.put("customer_order_id", order.getCustomerOrderId());

for (Order.LineItem lineItem : order.getLineItems()) {
JSONArray lineItemsJson = new JSONArray();
JSONObject lineItemJson = new JSONObject();

List<String> lineItemCategory = lineItem.getCategory();
if (lineItemCategory != null) {
JSONArray categoryJson = new JSONArray();
for (String category : lineItemCategory) {
categoryJson.put(category);
}

lineItemJson.put("category", categoryJson);
}

lineItemJson.put("identifier", lineItem.getId());
lineItemJson.put("quantity", lineItem.getQuantity());
lineItemJson.put("total", lineItem.getTotal());

Map<String, String> lineItemAttributes = lineItem.getAttributes();
if (lineItemAttributes != null) {
JSONObject attributesJson = new JSONObject();
for (Map.Entry<String, String> entry : lineItemAttributes.entrySet()) {
attributesJson.put(entry.getKey(), entry.getValue());
}

lineItemJson.put("attributes", attributesJson);
}

lineItemJson.put("upc", lineItem.getUpc());
lineItemJson.put("description", lineItem.getDescription());
lineItemJson.put("sku", lineItem.getSku());

lineItemsJson.put(lineItemJson);
requestBody.put("line_items", lineItemsJson);
}

Order.Customer customer = order.getCustomer();
if (customer != null) {
JSONObject customerJson = new JSONObject();
customerJson.put("id", customer.getId());

String email = customer.getEmail();
if (email != null) {
// TODO ADD EMAIL REGEX CHECK
email = ButtonUtil.sha256Encode(email.toLowerCase());
customerJson.put("email_sha256", email);
}

customerJson.put("device_id", advertisingId);
requestBody.put("customer", customerJson);
}

applicationId = ButtonUtil.base64Encode(applicationId + ":");
ApiRequest apiRequest = new ApiRequest.Builder(ApiRequest.RequestMethod.POST,
"/v1/mobile-order")
.addHeader("Authorization", String.format("Basic %s", applicationId))
.setBody(requestBody)
.build();

connectionManager.executeRequest(apiRequest);
} catch (JSONException e) {
Log.e(TAG, "Error creating request body", e);
throw new ButtonNetworkException(e);
Expand Down
Expand Up @@ -57,4 +57,7 @@ void removeAttributionTokenListener(ButtonRepository buttonRepository, @NonNull

void handlePostInstallIntent(ButtonRepository buttonRepository,
PostInstallIntentListener listener, String packageName, DeviceManager deviceManager);

void reportOrder(ButtonRepository buttonRepository, DeviceManager deviceManager, Order order,
@Nullable OrderListener orderListener);
}
Expand Up @@ -225,6 +225,39 @@ public void run() {
}, deviceManager);
}

@Override
public void reportOrder(ButtonRepository buttonRepository, DeviceManager deviceManager,
Order order, @Nullable final OrderListener orderListener) {

if (buttonRepository.getApplicationId() == null) {
executor.execute(new Runnable() {
@Override
public void run() {
if (orderListener != null) {
orderListener.onResult(new ApplicationIdNotFoundException());
}
}
});
return;
}

buttonRepository.postOrder(order, deviceManager, new Task.Listener() {
@Override
public void onTaskComplete(@Nullable Object object) {
if (orderListener != null) {
orderListener.onResult(null);
}
}

@Override
public void onTaskError(Throwable throwable) {
if (orderListener != null) {
orderListener.onResult(throwable);
}
}
});
}

/**
* Sets the attribution token in the {@link ButtonRepository} and updates all
* {@link ButtonInternalImpl#attributionTokenListeners} if the token has changed.
Expand Down
Expand Up @@ -78,7 +78,8 @@ public static void trackIncomingIntent(@NonNull Context context, @NonNull Intent
*
* @param order {@link Order}
* @param userActivityListener {@link UserActivityListener}
* @deprecated
*
* @deprecated Use {@link ButtonMerchant#reportOrder(Context, Order, OrderListener)}
*/
@Deprecated
public static void trackOrder(@NonNull Context context, @NonNull Order order,
Expand All @@ -87,6 +88,20 @@ public static void trackOrder(@NonNull Context context, @NonNull Order order,
userActivityListener);
}

/**
* Report orders
*
* @param context a {@link Context) instance that can be used to access app resources like
* SharedPreferences.
* @param order {@link Order}
* @param orderListener {@link OrderListener}
*/
public static void reportOrder(@NonNull Context context, @NonNull Order order,
@Nullable OrderListener orderListener) {
buttonInternal.reportOrder(getButtonRepository(context), getDeviceManager(context), order,
orderListener);
}

/**
* The {@code attributionToken} from the last inbound Button attributed {@link Intent}.
*
Expand Down
Expand Up @@ -51,4 +51,6 @@ interface ButtonRepository {
boolean checkedDeferredDeepLink();

void updateCheckDeferredDeepLink(boolean checkedDeferredDeepLink);

void postOrder(Order order, DeviceManager deviceManager, Task.Listener listener);
}
Expand Up @@ -100,10 +100,10 @@ public void getPendingLink(Task.Listener<PostInstallLink> listener,
}

@Override
public void postUserActivity(DeviceManager manager, Order order, Task.Listener listener) {
public void postUserActivity(DeviceManager deviceManager, Order order, Task.Listener listener) {
executorService.submit(
new UserActivityTask(listener, buttonApi, getApplicationId(), getSourceToken(),
manager, order));
deviceManager, order));
}

@Override
Expand All @@ -115,4 +115,11 @@ public boolean checkedDeferredDeepLink() {
public void updateCheckDeferredDeepLink(boolean checkedDeferredDeepLink) {
persistenceManager.updateCheckDeferredDeepLink(checkedDeferredDeepLink);
}

@Override
public void postOrder(Order order, DeviceManager deviceManager, Task.Listener listener) {
executorService.submit(
new PostOrderTask(listener, buttonApi, order, getApplicationId(),
getSourceToken(), deviceManager));
}
}

0 comments on commit 696f41a

Please sign in to comment.