From a5ae2f9b47a183d0b5c59879f7729c6889b6b061 Mon Sep 17 00:00:00 2001 From: Mike Tomko Date: Wed, 10 Jan 2024 15:04:16 -0700 Subject: [PATCH] Release 306 --- clover-android-connector-sdk/build.gradle | 2 +- .../connector/sdk/v3/IPaymentServiceV3.aidl | 10 + .../connector/sdk/v3/PaymentConnector.java | 36 ++ .../sdk/v3/connector/IPaymentConnector.java | 11 +- clover-android-loyalty-kit/build.gradle | 2 +- clover-android-sdk-examples/build.gradle | 2 +- clover-android-sdk-retrofit/build.gradle | 2 +- clover-android-sdk/build.gradle | 6 +- clover-android-sdk/lib/calc-jvm.jar | Bin 54548 -> 55178 bytes .../sdk/v3/order/IOnOrderUpdateListener2.aidl | 2 + .../clover/sdk/v3/order/IOrderService.aidl | 1 + .../sdk/v3/order/IOrderServiceV3_1.aidl | 33 ++ .../clover/common2/payments/PayIntent.java | 59 ++- .../java/com/clover/sdk/util/Platform2.java | 49 ++- .../main/java/com/clover/sdk/v1/Intents.java | 29 ++ .../sdk/v1/printer/ReceiptContract.java | 5 + .../clover/sdk/v3/inventory/ItemOverride.java | 380 ++++++++++++++++ .../sdk/v3/inventory/LayoutOverride.java | 414 +++++++++++++++++ .../sdk/v3/inventory/ModifierOverride.java | 416 ++++++++++++++++++ .../com/clover/sdk/v3/inventory/OrderFee.java | 41 +- .../com/clover/sdk/v3/order/OrderCalc.java | 36 ++ .../sdk/v3/order/OrderV31Connector.java | 81 ++++ .../clover/sdk/v3/order/OrderV3Connector.java | 18 + .../com/clover/sdk/v3/payments/Payment.java | 124 ++++-- .../sdk/v3/payments/PaymentBatchInfo.java | 247 +++++++++++ .../sdk/v3/payments/ServiceFeeRequest.java | 32 +- .../api/PaymentRequestIntentBuilder.java | 16 + .../api/TipAdjustRequestIntentBuilder.java | 30 +- .../common2/payments/PayIntentTest.java | 108 +++++ .../java/com/clover/sdk/util/Platform2Test.kt | 79 ++++ .../clover/sdk/v3/order/OrderCalcTest.java | 67 +++ scripts/README.install_apps.md | 18 +- scripts/install_apps.py | 28 +- versions.gradle | 5 +- 34 files changed, 2305 insertions(+), 84 deletions(-) create mode 100644 clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ItemOverride.java create mode 100644 clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/LayoutOverride.java create mode 100644 clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ModifierOverride.java create mode 100644 clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/PaymentBatchInfo.java create mode 100644 clover-android-sdk/src/test/java/com/clover/sdk/util/Platform2Test.kt diff --git a/clover-android-connector-sdk/build.gradle b/clover-android-connector-sdk/build.gradle index 571ea855f..5cfeb42be 100644 --- a/clover-android-connector-sdk/build.gradle +++ b/clover-android-connector-sdk/build.gradle @@ -14,7 +14,7 @@ * limitations under the License. */ group = 'com.clover.sdk' -version = '304' +version = '306' apply from: file("${project.rootDir}/lib.gradle") diff --git a/clover-android-connector-sdk/src/main/aidl/com/clover/connector/sdk/v3/IPaymentServiceV3.aidl b/clover-android-connector-sdk/src/main/aidl/com/clover/connector/sdk/v3/IPaymentServiceV3.aidl index 8dc684f80..c4054cfd9 100644 --- a/clover-android-connector-sdk/src/main/aidl/com/clover/connector/sdk/v3/IPaymentServiceV3.aidl +++ b/clover-android-connector-sdk/src/main/aidl/com/clover/connector/sdk/v3/IPaymentServiceV3.aidl @@ -218,4 +218,14 @@ interface IPaymentServiceV3 { void resetDevice(); void vaultCardWithRequest(in VaultCardRequest request); + + /** + * PreAuth method to obtain a Pre-Auth for a card, with high availability. + * When using preAuthV2, you might not be able to capture immediately by using this method. + * The client will have to wait for the order to sync for the capture to be successful. + * The Authorization request(%s/v3/merchants/%s/authorizations) can be skipped on the client and will be handled by the server. + * + * @param request - + **/ + void preAuthV2(in PreAuthRequest request); } diff --git a/clover-android-connector-sdk/src/main/java/com/clover/connector/sdk/v3/PaymentConnector.java b/clover-android-connector-sdk/src/main/java/com/clover/connector/sdk/v3/PaymentConnector.java index 854f14585..21eb5e0d3 100644 --- a/clover-android-connector-sdk/src/main/java/com/clover/connector/sdk/v3/PaymentConnector.java +++ b/clover-android-connector-sdk/src/main/java/com/clover/connector/sdk/v3/PaymentConnector.java @@ -1097,6 +1097,42 @@ protected Object doInBackground(Object[] objects) { } } + /** + * PreAuth method to obtain a Pre-Auth for a card + * + * @param request - + **/ + @Override + public void preAuthV2(final PreAuthRequest request) { + try { + if (request != null) { + request.setVersion(2); // this version supports validation + } + if (paymentV3Connector != null) { + if (paymentV3Connector.isConnected()) { + paymentV3Connector.getService().preAuthV2(request); + } else { + this.paymentV3Connector.connect(); + waitingTask = new AsyncTask() { + @Override + protected Object doInBackground(Object[] params) { + try { + paymentV3Connector.getService().preAuthV2(request); + } catch (RemoteException e) { + Log.e(this.getClass().getSimpleName(), " preAuthV2", e); + } + return null; + } + }; + } + } + } catch (IllegalArgumentException e) { + Log.e(this.getClass().getSimpleName(), " preAuthV2", e); + } catch (RemoteException e) { + Log.e(this.getClass().getSimpleName(), " preAuthV2", e); + } + } + public static String getAppVersion(Context context) { String version = "Unknown"; try { diff --git a/clover-android-connector-sdk/src/main/java/com/clover/sdk/v3/connector/IPaymentConnector.java b/clover-android-connector-sdk/src/main/java/com/clover/sdk/v3/connector/IPaymentConnector.java index 71baddb50..85557c99f 100644 --- a/clover-android-connector-sdk/src/main/java/com/clover/sdk/v3/connector/IPaymentConnector.java +++ b/clover-android-connector-sdk/src/main/java/com/clover/sdk/v3/connector/IPaymentConnector.java @@ -168,4 +168,13 @@ public interface IPaymentConnector extends IDeviceConnector{ * needs to be used cautiously as a last resort */ void resetDevice(); -} \ No newline at end of file + + /** + * PreAuth method to obtain a Pre-Auth for a card, with high availability. + * When using preAuthV2, you might not be able to capture immediately by using this method. + * The client will have to wait for the order to sync for the capture to be successful. + * The Authorization request(%s/v3/merchants/%s/authorizations) can be skipped on the client and will be handled by the server. + * + * @param request - + **/ + void preAuthV2(PreAuthRequest request);} \ No newline at end of file diff --git a/clover-android-loyalty-kit/build.gradle b/clover-android-loyalty-kit/build.gradle index c279ef689..9dee6f5c6 100644 --- a/clover-android-loyalty-kit/build.gradle +++ b/clover-android-loyalty-kit/build.gradle @@ -14,7 +14,7 @@ * limitations under the License. */ group = 'com.clover.sdk' -version = '304' +version = '306' apply from: file("${project.rootDir}/lib.gradle") diff --git a/clover-android-sdk-examples/build.gradle b/clover-android-sdk-examples/build.gradle index 94d3d12eb..cd2094ccf 100644 --- a/clover-android-sdk-examples/build.gradle +++ b/clover-android-sdk-examples/build.gradle @@ -14,7 +14,7 @@ * limitations under the License. */ group = 'com.clover.sdk' -version = '304' +version = '306' apply from: file("${project.rootDir}/app.gradle") apply plugin: 'kotlin-android' diff --git a/clover-android-sdk-retrofit/build.gradle b/clover-android-sdk-retrofit/build.gradle index a7c3de4b8..23f7bbbea 100644 --- a/clover-android-sdk-retrofit/build.gradle +++ b/clover-android-sdk-retrofit/build.gradle @@ -14,7 +14,7 @@ * limitations under the License. */ group = 'com.clover.sdk' -version = '304' +version = '306' apply from: file("${project.rootDir}/lib.gradle") diff --git a/clover-android-sdk/build.gradle b/clover-android-sdk/build.gradle index 3214d1f51..9d06b7f7d 100644 --- a/clover-android-sdk/build.gradle +++ b/clover-android-sdk/build.gradle @@ -14,9 +14,10 @@ * limitations under the License. */ group = 'com.clover.sdk' -version = '304' +version = '306' apply from: file("${project.rootDir}/lib.gradle") +apply plugin: 'kotlin-android' android { defaultConfig { @@ -51,7 +52,8 @@ afterEvaluate { classpath += project.files(variant.javaCompileProvider.get().classpath.files) // https://stackoverflow.com/a/34572606 classpath += project.files(project.android.getBootClasspath().join(File.pathSeparator)) options.addBooleanOption "Xdoclint:none", true - options.addBooleanOption "-frames", true + options.addBooleanOption "-frames", true // https://bugs.openjdk.org/browse/JDK-8202961 + options.addBooleanOption "-no-module-directories", true // https://stackoverflow.com/a/52603413 options.links 'https://developer.android.com/reference/' options.overview 'overview.html' destinationDir = file("build/docs/javadoc/${variant.name}/") diff --git a/clover-android-sdk/lib/calc-jvm.jar b/clover-android-sdk/lib/calc-jvm.jar index 8ab42f9e806416f180faf26f4c6dbd8bb3c86081..99cfcf7e1bf7c6fd69d557992df7ec416cf1df11 100644 GIT binary patch delta 19883 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¬Xz>CDT*~ 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 lineItemIds, in List modificationIds); + void onOrderFeeAdded(String orderId, String orderFeeLineItemId); + void onOrderFeeDeleted(String orderId, String orderFeeLineItemId); } diff --git a/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderService.aidl b/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderService.aidl index c50fc95a1..ae3ee504a 100644 --- a/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderService.aidl +++ b/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderService.aidl @@ -17,6 +17,7 @@ import com.clover.sdk.v3.pay.PaymentRequest; import com.clover.sdk.v3.pay.PaymentRequestCardDetails; import com.clover.sdk.v3.order.VoidReason; import com.clover.sdk.v3.payments.Authorization; +import com.clover.sdk.v3.order.LineItem; /** * An interface for interacting with the Clover order service. The order diff --git a/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderServiceV3_1.aidl b/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderServiceV3_1.aidl index 03d3be42d..ac51c0b9d 100644 --- a/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderServiceV3_1.aidl +++ b/clover-android-sdk/src/main/aidl/com/clover/sdk/v3/order/IOrderServiceV3_1.aidl @@ -32,6 +32,7 @@ import com.clover.common.payments.TerminalManagementComponent; import com.clover.common.payments.VoidExtraData; import com.clover.sdk.v3.payments.AdditionalChargeAmount; import com.clover.sdk.v3.payments.AuthorizationFdParcelable; +import com.clover.sdk.v3.order.LineItem; /** * An interface for interacting with the Clover order service. @@ -870,4 +871,36 @@ interface IOrderServiceV3_1 { */ OrderFdParcelable queueVoid(String orderId, String paymentId, String iccContainer, in PaymentRequestCardDetails card, in TransactionInfo transactionInfo, in Map passThroughExtras, in VoidReason reason, in VoidExtraData voidExtraData, String source, out ResultStatus resultStatus); + /** + * This method can be used to apply an order fee to the order + * @clover.perm ORDERS_W + */ + OrderFdParcelable addOrderFee(String orderId, in String orderFeeId, out ResultStatus status); + + /** + * This method can be used to remove an order fee from the order + * @clover.perm ORDERS_W + */ + OrderFdParcelable deleteOrderFee(String orderId, in String orderFeeLineItemId, out ResultStatus status); + + + /** + * Send all line items added in the List to the kitchen or order printer. Only prints + * items that have tags (also called labels) associating them with a printer. + * + * Line items will always be sent to prniter even if they are already printed they will be refired. + * + * @param orderId the ID of the order to fire. + * @param lineItemList line items list to be printed. + * @return true if items are printed, returns false line items or printers are empty. + * @clover.perm ORDERS_W + */ + boolean fireLineItems(String sourceOrderid, in List lineItemList, out ResultStatus status); + + + /** + * Not available to non-Clover apps. + * @y.exclude + */ + OrderFdParcelable capturePreAuthorization(String orderId, in PaymentFdParcelable preAuth, in PaymentFdParcelable closingPayment, in LineItemListFdParcelable fdLineItems, out ResultStatus status); } diff --git a/clover-android-sdk/src/main/java/com/clover/common2/payments/PayIntent.java b/clover-android-sdk/src/main/java/com/clover/common2/payments/PayIntent.java index fb324ab67..fb28b176e 100644 --- a/clover-android-sdk/src/main/java/com/clover/common2/payments/PayIntent.java +++ b/clover-android-sdk/src/main/java/com/clover/common2/payments/PayIntent.java @@ -165,6 +165,8 @@ public static class Builder { private String thresholdManagerId; private String thresholdManagerName; private String ebtManualCardEntryScreenFlow; + private String paymentType; + private Boolean createAuth; public Builder intent(Intent intent) { action = intent.getAction(); @@ -319,6 +321,15 @@ public Builder intent(Intent intent) { if (intent.hasExtra(Intents.EXTRA_EBT_MANUAL_CARD_ENTRY_SCREEN_FLOW)){ ebtManualCardEntryScreenFlow = intent.getStringExtra(Intents.EXTRA_EBT_MANUAL_CARD_ENTRY_SCREEN_FLOW); } + + if (intent.hasExtra(Intents.EXTRA_PAYMENT_TYPE)) { + paymentType = intent.getStringExtra(Intents.EXTRA_PAYMENT_TYPE); + } + + if (intent.hasExtra(Intents.EXTRA_CREATE_AUTH)) { + createAuth = intent.getBooleanExtra(Intents.EXTRA_CREATE_AUTH, false); + } + // As a general rule, the transactionSettings assignment should always be the last one // prior to the return statement. This is to ensure any new/added overrides don't get // reset by follow-on assignments and aids in preventing backward compatibility issues. @@ -456,6 +467,8 @@ public Builder payIntent(PayIntent payIntent) { this.thresholdManagerName = payIntent.thresholdManagerName; this.thresholdManagerId = payIntent.thresholdManagerId; this.ebtManualCardEntryScreenFlow = payIntent.ebtManualCardEntryScreenFlow; + this.paymentType = payIntent.paymentType; + this.createAuth = payIntent.createAuth; // As a general rule, the transactionSettings assignment should always be the last one // prior to the return statement. This is to ensure any new/added overrides don't get // reset by follow-on assignments and aids in preventing backward compatibility issues. @@ -832,6 +845,16 @@ public Builder ebtManualCardEntryScreenFlow(String ebtManualCardEntryScreenFlow) return this; } + public Builder paymentType(String paymentType) { + this.paymentType = paymentType; + return this; + } + + public Builder createAuth(Boolean createAuth) { + this.createAuth = createAuth; + return this; + } + @Deprecated public Builder testing(boolean isTesting) { this.isTesting = isTesting; @@ -848,7 +871,7 @@ public PayIntent build() { originatingPayment != null ? originatingPayment.getCardTransaction() : originatingTransaction, themeName, originatingPayment, originatingCredit, passThroughValues, applicationSpecificValues, refund, customerTender, isDisableCreditSurcharge, isPresentQrcOnly, isManualCardEntryByPassMode,isAllowManualCardEntryOnMFD, quickPaymentTransactionUuid, - authorization,tokenizeCardRequest,tokenizeCardResponse, dataReadMode, refundReason, thresholdManagerName, thresholdManagerId, ebtManualCardEntryScreenFlow); + authorization,tokenizeCardRequest,tokenizeCardResponse, dataReadMode, refundReason, thresholdManagerName, thresholdManagerId, ebtManualCardEntryScreenFlow, paymentType, createAuth); } } @@ -956,6 +979,8 @@ public PayIntent build() { public String thresholdManagerName; public String thresholdManagerId; public String ebtManualCardEntryScreenFlow; + public String paymentType; + public Boolean createAuth; private PayIntent(String action, Long amount, Long tippableAmount, @@ -973,7 +998,9 @@ private PayIntent(String action, Long amount, Long tippableAmount, Themes themeName, Payment originatingPayment, Credit originatingCredit, Map passThroughValues, Map applicationSpecificValues, Refund refund, Tender customerTender, boolean isDisableCreditSurcharge, boolean isPresntQrcOnly, boolean isManualCardEntryByPassMode, boolean isAllowManualCardEntryOnMFD, String quickPaymentTransactionUuid, - Authorization authorization,TokenizeCardRequest tokenizeCardRequest, TokenizeCardResponse tokenizeCardResponse, String dataReadMode, String refundReason, String thresholdManagerName, String thresholdManagerId, String ebtManualCardEntryScreenFlow) { + Authorization authorization,TokenizeCardRequest tokenizeCardRequest, TokenizeCardResponse tokenizeCardResponse, String dataReadMode, + String refundReason, String thresholdManagerName, String thresholdManagerId, String ebtManualCardEntryScreenFlow, + String paymentType, Boolean createAuth) { this.action = action; this.amount = amount; this.tippableAmount = tippableAmount; @@ -1032,6 +1059,8 @@ private PayIntent(String action, Long amount, Long tippableAmount, this.thresholdManagerName = thresholdManagerName; this.thresholdManagerId = thresholdManagerId; this.ebtManualCardEntryScreenFlow = ebtManualCardEntryScreenFlow; + this.paymentType = paymentType; + this.createAuth = createAuth; this.vasSettings = vasSettings; this.passThroughValues = passThroughValues; this.applicationSpecificValues = applicationSpecificValues; @@ -1323,10 +1352,20 @@ public void addTo(Intent intent) { if (originatingPaymentPackage != null) { intent.putExtra(Intents.EXTRA_ORIGINATING_PAYMENT_PACKAGE, originatingPaymentPackage); } + intent.putExtra(Intents.EXTRA_USE_LAST_SWIPE, useLastSwipe); + if (themeName != null) { intent.putExtra(Intents.EXTRA_THEME_NAME, (Parcelable) themeName); } + + if (createAuth != null) { + intent.putExtra(Intents.EXTRA_CREATE_AUTH, createAuth); + } + + if (paymentType != null) { + intent.putExtra(Intents.EXTRA_PAYMENT_TYPE, paymentType); + } } @Override @@ -1389,6 +1428,8 @@ public String toString() { ", thresholdManagerName=" + thresholdManagerName + ", thresholdManagerId=" + thresholdManagerId + ", ebtManualCardEntryScreenFlow=" + ebtManualCardEntryScreenFlow + + ", paymentType=" + paymentType + + ", createAuth=" + createAuth + '}'; } @@ -1595,6 +1636,14 @@ public void writeToParcel(Parcel out, int flags) { bundle.putString(Intents.EXTRA_EBT_MANUAL_CARD_ENTRY_SCREEN_FLOW, ebtManualCardEntryScreenFlow); } + if (paymentType != null) { + bundle.putString(Intents.EXTRA_PAYMENT_TYPE, paymentType); + } + + if (createAuth != null) { + bundle.putBoolean(Intents.EXTRA_CREATE_AUTH, createAuth); + } + // write out out.writeBundle(bundle); } @@ -1835,6 +1884,12 @@ public PayIntent createFromParcel(Parcel in) { if (bundle.containsKey(Intents.EXTRA_EBT_MANUAL_CARD_ENTRY_SCREEN_FLOW)) { builder.ebtManualCardEntryScreenFlow(bundle.getString(Intents.EXTRA_EBT_MANUAL_CARD_ENTRY_SCREEN_FLOW)); } + + if (bundle.containsKey(Intents.EXTRA_PAYMENT_TYPE)) { + builder.paymentType(bundle.getString(Intents.EXTRA_PAYMENT_TYPE)); + } + + builder.createAuth(bundle.getBoolean(Intents.EXTRA_CREATE_AUTH, false)); // build return builder.build(); } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/util/Platform2.java b/clover-android-sdk/src/main/java/com/clover/sdk/util/Platform2.java index 75a15fcbe..42178e6e7 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/util/Platform2.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/util/Platform2.java @@ -16,11 +16,13 @@ package com.clover.sdk.util; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.graphics.Point; import android.os.Build; import android.view.Surface; import android.view.WindowManager; @@ -171,7 +173,7 @@ public boolean isSupported(Context context) { } }, /** - * Device has a secure touch screen. + * Device has a secure touch screen(eg: flex, mini) or a secure keypad(eg: pinetree) */ SECURE_TOUCH { @Override @@ -185,7 +187,8 @@ protected boolean isSupported(Context context) { return true; } - return context.getPackageManager().hasSystemFeature("clover.hardware.secure_touch"); + return context.getPackageManager().hasSystemFeature("clover.hardware.secure_touch") + || context.getPackageManager().hasSystemFeature("clover.hardware.secure_keypad"); } }, /** @@ -285,7 +288,9 @@ public static boolean supportsFeature(Context context, Feature f) { private static Orientation defaultOrientation; /** - * Get the default orientation under which this device is normally used. + * Get the default orientation under which this device is normally used, for the default + * display. + * * This method does not return the current orientation! */ public static Orientation defaultOrientation(Context context) { @@ -310,4 +315,42 @@ public static Orientation defaultOrientation(Context context) { return defaultOrientation; } + /** + * If the ratio of the the largest screen dimension to the smallest screen dimension is + * less or equal to this value then we consider the display to be "square". + */ + public static final float CLOSE_TO_SQUARE_ASPECT_RATIO = 4.0f / 3; // 1.3333... + + /** + * Answer if this device's default display is "square". A display is square if + * the ratio of it's largest to smallest screen dimension is + * {@link #CLOSE_TO_SQUARE_ASPECT_RATIO} or less. + *

+ * Applications should avoid changing the screen orientation (e.g. by calling + * {@link Activity#setRequestedOrientation(int)}) when running on + * square displays. The results of doing so are not well defined. + *

+ * Android has no official "square" screen orientation. On square displays, + * {@link #defaultOrientation(Context)} may return either {@link Orientation#LANDSCAPE} + * or {@link Orientation#PORTRAIT}. + * + * @see #CLOSE_TO_SQUARE_ASPECT_RATIO + * @see #defaultOrientation(Context) + */ + public static boolean isSquareDisplay(Context context) { + final Point size = new Point(); + final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getSize(size); + + if ((size.x >= size.y) && + ((float) size.x / size.y <= CLOSE_TO_SQUARE_ASPECT_RATIO)) { + return true; + } + if ((size.x < size.y) && + ((float) size.y / size.x <= CLOSE_TO_SQUARE_ASPECT_RATIO)) { + return true; + } + + return false; + } } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v1/Intents.java b/clover-android-sdk/src/main/java/com/clover/sdk/v1/Intents.java index 8a4a08116..5dc64a00c 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v1/Intents.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v1/Intents.java @@ -1806,4 +1806,33 @@ public static class PAYMENT_TOKEN_TYPE { */ public static final String EXTRA_IMMERSIVE_MODE = "immersive_mode"; + /** + * Intent to track payment sub types + */ + public static final String EXTRA_PAYMENT_TYPE = "payment_type"; + + /** + * Intent to track create an auth + */ + public static final String EXTRA_CREATE_AUTH = "create_auth"; + + /** + * The transaction name + * (held in the Terminal apps' settings) + */ + public static final String EXTRA_TRANSACTION_NAME = "transaction_name"; + + /** + * {@link Boolean} whether or not to apply taxes to a transaction + * (held in the Terminal apps' settings) + */ + public static final String EXTRA_APPLY_TAXES_AND_FEES = "apply_taxes_and_fees"; + + /** + * {@link String} Summary line showing taxes and fees, e.g. + * "Tax Rate + Fees: 30% + $2.00" + * (held in the Terminal apps' settings) + */ + public static final String EXTRA_TAXES_AND_FEES_BREAKDOWN = "taxes_and_fees_breakdown"; + } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v1/printer/ReceiptContract.java b/clover-android-sdk/src/main/java/com/clover/sdk/v1/printer/ReceiptContract.java index b122ed68b..5846997c6 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v1/printer/ReceiptContract.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v1/printer/ReceiptContract.java @@ -97,6 +97,11 @@ public final class ReceiptContract { */ public static final String PARAM_RECEIPT_WIDTH = "receipt_width"; + /** + * The payment ID of the receipt to be printed. + */ + public static final String PARAM_PAYMENT_ID = "payment_id"; + /** * Column name for returning text-only receipt data. Must map to a string column value. */ diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ItemOverride.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ItemOverride.java new file mode 100644 index 000000000..d93f23559 --- /dev/null +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ItemOverride.java @@ -0,0 +1,380 @@ +/** + * Autogenerated by Avro + * + * DO NOT EDIT DIRECTLY + */ + +/* + * Copyright (C) 2019 Clover Network, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.clover.sdk.v3.inventory; + +import com.clover.sdk.GenericClient; +import com.clover.sdk.GenericParcelable; + +/** + * This is an auto-generated Clover data object. + *

+ * An Override of a particular Item in Menus. + *

+ *

Fields

+ *
    + *
  • {@link #getId id}
  • + *
  • {@link #getSortOrder sortOrder}
  • + *
  • {@link #getPrice price}
  • + *
  • {@link #getModifiedTime modifiedTime}
  • + *
  • {@link #getCreatedTime createdTime}
  • + *
  • {@link #getDeletedTime deletedTime}
  • + *
+ */ +@SuppressWarnings("all") +public class ItemOverride extends GenericParcelable implements com.clover.sdk.v3.Validator, com.clover.sdk.JSONifiable { + + /** + * Unique Clover identifier. + */ + public String getId() { + return genClient.cacheGet(CacheKey.id); + } + + /** + * Integer used to determine how this item sorted against other items. + */ + public Integer getSortOrder() { + return genClient.cacheGet(CacheKey.sortOrder); + } + + /** + * Price of the item. + */ + public Long getPrice() { + return genClient.cacheGet(CacheKey.price); + } + + /** + * Timestamp when item was modified. + */ + public Long getModifiedTime() { + return genClient.cacheGet(CacheKey.modifiedTime); + } + + /** + * Timestamp when item was created. + */ + public Long getCreatedTime() { + return genClient.cacheGet(CacheKey.createdTime); + } + + /** + * Timestamp when item was deleted. + */ + public Long getDeletedTime() { + return genClient.cacheGet(CacheKey.deletedTime); + } + + + + + private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { + id + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + sortOrder + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Integer.class)), + price + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + modifiedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + createdTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + deletedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + ; + + private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; + + private CacheKey(com.clover.sdk.extractors.ExtractionStrategy s) { + extractionStrategy = s; + } + + @Override + public com.clover.sdk.extractors.ExtractionStrategy getExtractionStrategy() { + return extractionStrategy; + } + } + + private final GenericClient genClient; + + /** + * Constructs a new empty instance. + */ + public ItemOverride() { + genClient = new GenericClient(this); + } + + @Override + protected GenericClient getGenericClient() { + return genClient; + } + + /** + * Constructs a new empty instance. + */ + protected ItemOverride(boolean noInit) { + genClient = null; + } + + /** + * Constructs a new instance from the given JSON String. + */ + public ItemOverride(String json) throws IllegalArgumentException { + this(); + genClient.initJsonObject(json); + } + + /** + * Construct a new instance backed by the given JSONObject, the parameter is not copied so changes to it will be + * reflected in this instance and vice-versa. + */ + public ItemOverride(org.json.JSONObject jsonObject) { + this(); + genClient.setJsonObject(jsonObject); + } + + /** + * Constructs a new instance that is a deep copy of the source instance. It does not copy the bundle or changelog. + */ + public ItemOverride(ItemOverride src) { + this(); + if (src.genClient.getJsonObject() != null) { + genClient.setJsonObject(com.clover.sdk.v3.JsonHelper.deepCopy(src.genClient.getJSONObject())); + } + } + + /** + * Returns the internal JSONObject backing this instance, the return value is not a copy so changes to it will be + * reflected in this instance and vice-versa. + */ + public org.json.JSONObject getJSONObject() { + return genClient.getJSONObject(); + } + + @Override + public void validate() { + genClient.validateCloverId(CacheKey.id, getId()); + } + + /** Checks whether the 'id' field is set and is not null */ + public boolean isNotNullId() { + return genClient.cacheValueIsNotNull(CacheKey.id); + } + + /** Checks whether the 'sortOrder' field is set and is not null */ + public boolean isNotNullSortOrder() { + return genClient.cacheValueIsNotNull(CacheKey.sortOrder); + } + + /** Checks whether the 'price' field is set and is not null */ + public boolean isNotNullPrice() { + return genClient.cacheValueIsNotNull(CacheKey.price); + } + + /** Checks whether the 'modifiedTime' field is set and is not null */ + public boolean isNotNullModifiedTime() { + return genClient.cacheValueIsNotNull(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field is set and is not null */ + public boolean isNotNullCreatedTime() { + return genClient.cacheValueIsNotNull(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field is set and is not null */ + public boolean isNotNullDeletedTime() { + return genClient.cacheValueIsNotNull(CacheKey.deletedTime); + } + + + + /** Checks whether the 'id' field has been set, however the value could be null */ + public boolean hasId() { + return genClient.cacheHasKey(CacheKey.id); + } + + /** Checks whether the 'sortOrder' field has been set, however the value could be null */ + public boolean hasSortOrder() { + return genClient.cacheHasKey(CacheKey.sortOrder); + } + + /** Checks whether the 'price' field has been set, however the value could be null */ + public boolean hasPrice() { + return genClient.cacheHasKey(CacheKey.price); + } + + /** Checks whether the 'modifiedTime' field has been set, however the value could be null */ + public boolean hasModifiedTime() { + return genClient.cacheHasKey(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field has been set, however the value could be null */ + public boolean hasCreatedTime() { + return genClient.cacheHasKey(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field has been set, however the value could be null */ + public boolean hasDeletedTime() { + return genClient.cacheHasKey(CacheKey.deletedTime); + } + + + /** + * Sets the field 'id'. + */ + public ItemOverride setId(String id) { + return genClient.setOther(id, CacheKey.id); + } + + /** + * Sets the field 'sortOrder'. + */ + public ItemOverride setSortOrder(Integer sortOrder) { + return genClient.setOther(sortOrder, CacheKey.sortOrder); + } + + /** + * Sets the field 'price'. + */ + public ItemOverride setPrice(Long price) { + return genClient.setOther(price, CacheKey.price); + } + + /** + * Sets the field 'modifiedTime'. + */ + public ItemOverride setModifiedTime(Long modifiedTime) { + return genClient.setOther(modifiedTime, CacheKey.modifiedTime); + } + + /** + * Sets the field 'createdTime'. + */ + public ItemOverride setCreatedTime(Long createdTime) { + return genClient.setOther(createdTime, CacheKey.createdTime); + } + + /** + * Sets the field 'deletedTime'. + */ + public ItemOverride setDeletedTime(Long deletedTime) { + return genClient.setOther(deletedTime, CacheKey.deletedTime); + } + + + /** Clears the 'id' field, the 'has' method for this field will now return false */ + public void clearId() { + genClient.clear(CacheKey.id); + } + /** Clears the 'sortOrder' field, the 'has' method for this field will now return false */ + public void clearSortOrder() { + genClient.clear(CacheKey.sortOrder); + } + /** Clears the 'price' field, the 'has' method for this field will now return false */ + public void clearPrice() { + genClient.clear(CacheKey.price); + } + /** Clears the 'modifiedTime' field, the 'has' method for this field will now return false */ + public void clearModifiedTime() { + genClient.clear(CacheKey.modifiedTime); + } + /** Clears the 'createdTime' field, the 'has' method for this field will now return false */ + public void clearCreatedTime() { + genClient.clear(CacheKey.createdTime); + } + /** Clears the 'deletedTime' field, the 'has' method for this field will now return false */ + public void clearDeletedTime() { + genClient.clear(CacheKey.deletedTime); + } + + + /** + * Returns true if this instance has any changes. + */ + public boolean containsChanges() { + return genClient.containsChanges(); + } + + /** + * Reset the log of changes made to this instance, calling copyChanges() after this would return an empty instance. + */ + public void resetChangeLog() { + genClient.resetChangeLog(); + } + + /** + * Create a copy of this instance that contains only fields that were set after the constructor was called. + */ + public ItemOverride copyChanges() { + ItemOverride copy = new ItemOverride(); + copy.mergeChanges(this); + copy.resetChangeLog(); + return copy; + } + + /** + * Copy all the changed fields from the given source to this instance. + */ + public void mergeChanges(ItemOverride src) { + if (src.genClient.getChangeLog() != null) { + genClient.mergeChanges(new ItemOverride(src).getJSONObject(), src.genClient); + } + } + + public static final android.os.Parcelable.Creator CREATOR = new android.os.Parcelable.Creator() { + @Override + public ItemOverride createFromParcel(android.os.Parcel in) { + ItemOverride instance = new ItemOverride(com.clover.sdk.v3.JsonParcelHelper.ObjectWrapper.CREATOR.createFromParcel(in).unwrap()); + instance.genClient.setBundle(in.readBundle(getClass().getClassLoader())); + instance.genClient.setChangeLog(in.readBundle()); + return instance; + } + + @Override + public ItemOverride[] newArray(int size) { + return new ItemOverride[size]; + } + }; + + public static final com.clover.sdk.JSONifiable.Creator JSON_CREATOR = new com.clover.sdk.JSONifiable.Creator() { + public Class getCreatedClass() { + return ItemOverride.class; + } + + @Override + public ItemOverride create(org.json.JSONObject jsonObject) { + return new ItemOverride(jsonObject); + } + }; + + public interface Constraints { + public static final boolean ID_IS_REQUIRED = false; + public static final long ID_MAX_LEN = 127; + public static final boolean SORTORDER_IS_REQUIRED = false; + public static final boolean PRICE_IS_REQUIRED = false; + public static final boolean MODIFIEDTIME_IS_REQUIRED = false; + public static final boolean CREATEDTIME_IS_REQUIRED = false; + public static final boolean DELETEDTIME_IS_REQUIRED = false; + } + +} diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/LayoutOverride.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/LayoutOverride.java new file mode 100644 index 000000000..0d6525031 --- /dev/null +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/LayoutOverride.java @@ -0,0 +1,414 @@ +/** + * Autogenerated by Avro + * + * DO NOT EDIT DIRECTLY + */ + +/* + * Copyright (C) 2019 Clover Network, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.clover.sdk.v3.inventory; + +import com.clover.sdk.GenericClient; +import com.clover.sdk.GenericParcelable; + +/** + * This is an auto-generated Clover data object. + *

+ * An Override of a particular Layout in Menus. + *

+ *

Fields

+ *
    + *
  • {@link #getId id}
  • + *
  • {@link #getSortOrder sortOrder}
  • + *
  • {@link #getColorCode colorCode}
  • + *
  • {@link #getEnabled enabled}
  • + *
  • {@link #getModifiedTime modifiedTime}
  • + *
  • {@link #getCreatedTime createdTime}
  • + *
  • {@link #getDeletedTime deletedTime}
  • + *
+ */ +@SuppressWarnings("all") +public class LayoutOverride extends GenericParcelable implements com.clover.sdk.v3.Validator, com.clover.sdk.JSONifiable { + + /** + * Unique Clover identifier. + */ + public String getId() { + return genClient.cacheGet(CacheKey.id); + } + + /** + * Integer used to determine how this layout sorted against other layout. + */ + public Integer getSortOrder() { + return genClient.cacheGet(CacheKey.sortOrder); + } + + /** + * Color code. + */ + public String getColorCode() { + return genClient.cacheGet(CacheKey.colorCode); + } + + /** + * Layout override enabled. + */ + public Boolean getEnabled() { + return genClient.cacheGet(CacheKey.enabled); + } + + /** + * Timestamp when layout was modified. + */ + public Long getModifiedTime() { + return genClient.cacheGet(CacheKey.modifiedTime); + } + + /** + * Timestamp when layout was created. + */ + public Long getCreatedTime() { + return genClient.cacheGet(CacheKey.createdTime); + } + + /** + * Timestamp when layout was deleted. + */ + public Long getDeletedTime() { + return genClient.cacheGet(CacheKey.deletedTime); + } + + + + + private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { + id + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + sortOrder + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Integer.class)), + colorCode + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + enabled + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Boolean.class)), + modifiedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + createdTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + deletedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + ; + + private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; + + private CacheKey(com.clover.sdk.extractors.ExtractionStrategy s) { + extractionStrategy = s; + } + + @Override + public com.clover.sdk.extractors.ExtractionStrategy getExtractionStrategy() { + return extractionStrategy; + } + } + + private final GenericClient genClient; + + /** + * Constructs a new empty instance. + */ + public LayoutOverride() { + genClient = new GenericClient(this); + } + + @Override + protected GenericClient getGenericClient() { + return genClient; + } + + /** + * Constructs a new empty instance. + */ + protected LayoutOverride(boolean noInit) { + genClient = null; + } + + /** + * Constructs a new instance from the given JSON String. + */ + public LayoutOverride(String json) throws IllegalArgumentException { + this(); + genClient.initJsonObject(json); + } + + /** + * Construct a new instance backed by the given JSONObject, the parameter is not copied so changes to it will be + * reflected in this instance and vice-versa. + */ + public LayoutOverride(org.json.JSONObject jsonObject) { + this(); + genClient.setJsonObject(jsonObject); + } + + /** + * Constructs a new instance that is a deep copy of the source instance. It does not copy the bundle or changelog. + */ + public LayoutOverride(LayoutOverride src) { + this(); + if (src.genClient.getJsonObject() != null) { + genClient.setJsonObject(com.clover.sdk.v3.JsonHelper.deepCopy(src.genClient.getJSONObject())); + } + } + + /** + * Returns the internal JSONObject backing this instance, the return value is not a copy so changes to it will be + * reflected in this instance and vice-versa. + */ + public org.json.JSONObject getJSONObject() { + return genClient.getJSONObject(); + } + + @Override + public void validate() { + genClient.validateCloverId(CacheKey.id, getId()); + + genClient.validateNotNull(CacheKey.sortOrder, getSortOrder()); + } + + /** Checks whether the 'id' field is set and is not null */ + public boolean isNotNullId() { + return genClient.cacheValueIsNotNull(CacheKey.id); + } + + /** Checks whether the 'sortOrder' field is set and is not null */ + public boolean isNotNullSortOrder() { + return genClient.cacheValueIsNotNull(CacheKey.sortOrder); + } + + /** Checks whether the 'colorCode' field is set and is not null */ + public boolean isNotNullColorCode() { + return genClient.cacheValueIsNotNull(CacheKey.colorCode); + } + + /** Checks whether the 'enabled' field is set and is not null */ + public boolean isNotNullEnabled() { + return genClient.cacheValueIsNotNull(CacheKey.enabled); + } + + /** Checks whether the 'modifiedTime' field is set and is not null */ + public boolean isNotNullModifiedTime() { + return genClient.cacheValueIsNotNull(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field is set and is not null */ + public boolean isNotNullCreatedTime() { + return genClient.cacheValueIsNotNull(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field is set and is not null */ + public boolean isNotNullDeletedTime() { + return genClient.cacheValueIsNotNull(CacheKey.deletedTime); + } + + + + /** Checks whether the 'id' field has been set, however the value could be null */ + public boolean hasId() { + return genClient.cacheHasKey(CacheKey.id); + } + + /** Checks whether the 'sortOrder' field has been set, however the value could be null */ + public boolean hasSortOrder() { + return genClient.cacheHasKey(CacheKey.sortOrder); + } + + /** Checks whether the 'colorCode' field has been set, however the value could be null */ + public boolean hasColorCode() { + return genClient.cacheHasKey(CacheKey.colorCode); + } + + /** Checks whether the 'enabled' field has been set, however the value could be null */ + public boolean hasEnabled() { + return genClient.cacheHasKey(CacheKey.enabled); + } + + /** Checks whether the 'modifiedTime' field has been set, however the value could be null */ + public boolean hasModifiedTime() { + return genClient.cacheHasKey(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field has been set, however the value could be null */ + public boolean hasCreatedTime() { + return genClient.cacheHasKey(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field has been set, however the value could be null */ + public boolean hasDeletedTime() { + return genClient.cacheHasKey(CacheKey.deletedTime); + } + + + /** + * Sets the field 'id'. + */ + public LayoutOverride setId(String id) { + return genClient.setOther(id, CacheKey.id); + } + + /** + * Sets the field 'sortOrder'. + */ + public LayoutOverride setSortOrder(Integer sortOrder) { + return genClient.setOther(sortOrder, CacheKey.sortOrder); + } + + /** + * Sets the field 'colorCode'. + */ + public LayoutOverride setColorCode(String colorCode) { + return genClient.setOther(colorCode, CacheKey.colorCode); + } + + /** + * Sets the field 'enabled'. + */ + public LayoutOverride setEnabled(Boolean enabled) { + return genClient.setOther(enabled, CacheKey.enabled); + } + + /** + * Sets the field 'modifiedTime'. + */ + public LayoutOverride setModifiedTime(Long modifiedTime) { + return genClient.setOther(modifiedTime, CacheKey.modifiedTime); + } + + /** + * Sets the field 'createdTime'. + */ + public LayoutOverride setCreatedTime(Long createdTime) { + return genClient.setOther(createdTime, CacheKey.createdTime); + } + + /** + * Sets the field 'deletedTime'. + */ + public LayoutOverride setDeletedTime(Long deletedTime) { + return genClient.setOther(deletedTime, CacheKey.deletedTime); + } + + + /** Clears the 'id' field, the 'has' method for this field will now return false */ + public void clearId() { + genClient.clear(CacheKey.id); + } + /** Clears the 'sortOrder' field, the 'has' method for this field will now return false */ + public void clearSortOrder() { + genClient.clear(CacheKey.sortOrder); + } + /** Clears the 'colorCode' field, the 'has' method for this field will now return false */ + public void clearColorCode() { + genClient.clear(CacheKey.colorCode); + } + /** Clears the 'enabled' field, the 'has' method for this field will now return false */ + public void clearEnabled() { + genClient.clear(CacheKey.enabled); + } + /** Clears the 'modifiedTime' field, the 'has' method for this field will now return false */ + public void clearModifiedTime() { + genClient.clear(CacheKey.modifiedTime); + } + /** Clears the 'createdTime' field, the 'has' method for this field will now return false */ + public void clearCreatedTime() { + genClient.clear(CacheKey.createdTime); + } + /** Clears the 'deletedTime' field, the 'has' method for this field will now return false */ + public void clearDeletedTime() { + genClient.clear(CacheKey.deletedTime); + } + + + /** + * Returns true if this instance has any changes. + */ + public boolean containsChanges() { + return genClient.containsChanges(); + } + + /** + * Reset the log of changes made to this instance, calling copyChanges() after this would return an empty instance. + */ + public void resetChangeLog() { + genClient.resetChangeLog(); + } + + /** + * Create a copy of this instance that contains only fields that were set after the constructor was called. + */ + public LayoutOverride copyChanges() { + LayoutOverride copy = new LayoutOverride(); + copy.mergeChanges(this); + copy.resetChangeLog(); + return copy; + } + + /** + * Copy all the changed fields from the given source to this instance. + */ + public void mergeChanges(LayoutOverride src) { + if (src.genClient.getChangeLog() != null) { + genClient.mergeChanges(new LayoutOverride(src).getJSONObject(), src.genClient); + } + } + + public static final android.os.Parcelable.Creator CREATOR = new android.os.Parcelable.Creator() { + @Override + public LayoutOverride createFromParcel(android.os.Parcel in) { + LayoutOverride instance = new LayoutOverride(com.clover.sdk.v3.JsonParcelHelper.ObjectWrapper.CREATOR.createFromParcel(in).unwrap()); + instance.genClient.setBundle(in.readBundle(getClass().getClassLoader())); + instance.genClient.setChangeLog(in.readBundle()); + return instance; + } + + @Override + public LayoutOverride[] newArray(int size) { + return new LayoutOverride[size]; + } + }; + + public static final com.clover.sdk.JSONifiable.Creator JSON_CREATOR = new com.clover.sdk.JSONifiable.Creator() { + public Class getCreatedClass() { + return LayoutOverride.class; + } + + @Override + public LayoutOverride create(org.json.JSONObject jsonObject) { + return new LayoutOverride(jsonObject); + } + }; + + public interface Constraints { + public static final boolean ID_IS_REQUIRED = false; + public static final long ID_MAX_LEN = 127; + public static final boolean SORTORDER_IS_REQUIRED = true; + public static final boolean COLORCODE_IS_REQUIRED = false; + public static final boolean ENABLED_IS_REQUIRED = false; + public static final boolean MODIFIEDTIME_IS_REQUIRED = false; + public static final boolean CREATEDTIME_IS_REQUIRED = false; + public static final boolean DELETEDTIME_IS_REQUIRED = false; + } + +} diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ModifierOverride.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ModifierOverride.java new file mode 100644 index 000000000..1b2a47a58 --- /dev/null +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/ModifierOverride.java @@ -0,0 +1,416 @@ +/** + * Autogenerated by Avro + * + * DO NOT EDIT DIRECTLY + */ + +/* + * Copyright (C) 2019 Clover Network, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.clover.sdk.v3.inventory; + +import com.clover.sdk.GenericClient; +import com.clover.sdk.GenericParcelable; + +/** + * This is an auto-generated Clover data object. + *

+ * An Override of a particular Modifier in Menus. + *

+ *

Fields

+ *
    + *
  • {@link #getId id}
  • + *
  • {@link #getEnabled enabled}
  • + *
  • {@link #getReasonCode reasonCode}
  • + *
  • {@link #getFiltered filtered}
  • + *
  • {@link #getModifiedTime modifiedTime}
  • + *
  • {@link #getCreatedTime createdTime}
  • + *
  • {@link #getDeletedTime deletedTime}
  • + *
+ */ +@SuppressWarnings("all") +public class ModifierOverride extends GenericParcelable implements com.clover.sdk.v3.Validator, com.clover.sdk.JSONifiable { + + /** + * Unique Clover identifier. + */ + public String getId() { + return genClient.cacheGet(CacheKey.id); + } + + /** + * Modifier override enabled. + */ + public Boolean getEnabled() { + return genClient.cacheGet(CacheKey.enabled); + } + + /** + * Reason code. + */ + public String getReasonCode() { + return genClient.cacheGet(CacheKey.reasonCode); + } + + /** + * Modifier override filtered. + */ + public Boolean getFiltered() { + return genClient.cacheGet(CacheKey.filtered); + } + + /** + * Timestamp when modifier was modified. + */ + public Long getModifiedTime() { + return genClient.cacheGet(CacheKey.modifiedTime); + } + + /** + * Timestamp when modifier was created. + */ + public Long getCreatedTime() { + return genClient.cacheGet(CacheKey.createdTime); + } + + /** + * Timestamp when modifier was deleted. + */ + public Long getDeletedTime() { + return genClient.cacheGet(CacheKey.deletedTime); + } + + + + + private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { + id + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + enabled + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Boolean.class)), + reasonCode + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + filtered + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Boolean.class)), + modifiedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + createdTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + deletedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + ; + + private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; + + private CacheKey(com.clover.sdk.extractors.ExtractionStrategy s) { + extractionStrategy = s; + } + + @Override + public com.clover.sdk.extractors.ExtractionStrategy getExtractionStrategy() { + return extractionStrategy; + } + } + + private final GenericClient genClient; + + /** + * Constructs a new empty instance. + */ + public ModifierOverride() { + genClient = new GenericClient(this); + } + + @Override + protected GenericClient getGenericClient() { + return genClient; + } + + /** + * Constructs a new empty instance. + */ + protected ModifierOverride(boolean noInit) { + genClient = null; + } + + /** + * Constructs a new instance from the given JSON String. + */ + public ModifierOverride(String json) throws IllegalArgumentException { + this(); + genClient.initJsonObject(json); + } + + /** + * Construct a new instance backed by the given JSONObject, the parameter is not copied so changes to it will be + * reflected in this instance and vice-versa. + */ + public ModifierOverride(org.json.JSONObject jsonObject) { + this(); + genClient.setJsonObject(jsonObject); + } + + /** + * Constructs a new instance that is a deep copy of the source instance. It does not copy the bundle or changelog. + */ + public ModifierOverride(ModifierOverride src) { + this(); + if (src.genClient.getJsonObject() != null) { + genClient.setJsonObject(com.clover.sdk.v3.JsonHelper.deepCopy(src.genClient.getJSONObject())); + } + } + + /** + * Returns the internal JSONObject backing this instance, the return value is not a copy so changes to it will be + * reflected in this instance and vice-versa. + */ + public org.json.JSONObject getJSONObject() { + return genClient.getJSONObject(); + } + + @Override + public void validate() { + genClient.validateCloverId(CacheKey.id, getId()); + + genClient.validateNotNull(CacheKey.reasonCode, getReasonCode()); + genClient.validateLength(CacheKey.reasonCode, getReasonCode(), 127); + } + + /** Checks whether the 'id' field is set and is not null */ + public boolean isNotNullId() { + return genClient.cacheValueIsNotNull(CacheKey.id); + } + + /** Checks whether the 'enabled' field is set and is not null */ + public boolean isNotNullEnabled() { + return genClient.cacheValueIsNotNull(CacheKey.enabled); + } + + /** Checks whether the 'reasonCode' field is set and is not null */ + public boolean isNotNullReasonCode() { + return genClient.cacheValueIsNotNull(CacheKey.reasonCode); + } + + /** Checks whether the 'filtered' field is set and is not null */ + public boolean isNotNullFiltered() { + return genClient.cacheValueIsNotNull(CacheKey.filtered); + } + + /** Checks whether the 'modifiedTime' field is set and is not null */ + public boolean isNotNullModifiedTime() { + return genClient.cacheValueIsNotNull(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field is set and is not null */ + public boolean isNotNullCreatedTime() { + return genClient.cacheValueIsNotNull(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field is set and is not null */ + public boolean isNotNullDeletedTime() { + return genClient.cacheValueIsNotNull(CacheKey.deletedTime); + } + + + + /** Checks whether the 'id' field has been set, however the value could be null */ + public boolean hasId() { + return genClient.cacheHasKey(CacheKey.id); + } + + /** Checks whether the 'enabled' field has been set, however the value could be null */ + public boolean hasEnabled() { + return genClient.cacheHasKey(CacheKey.enabled); + } + + /** Checks whether the 'reasonCode' field has been set, however the value could be null */ + public boolean hasReasonCode() { + return genClient.cacheHasKey(CacheKey.reasonCode); + } + + /** Checks whether the 'filtered' field has been set, however the value could be null */ + public boolean hasFiltered() { + return genClient.cacheHasKey(CacheKey.filtered); + } + + /** Checks whether the 'modifiedTime' field has been set, however the value could be null */ + public boolean hasModifiedTime() { + return genClient.cacheHasKey(CacheKey.modifiedTime); + } + + /** Checks whether the 'createdTime' field has been set, however the value could be null */ + public boolean hasCreatedTime() { + return genClient.cacheHasKey(CacheKey.createdTime); + } + + /** Checks whether the 'deletedTime' field has been set, however the value could be null */ + public boolean hasDeletedTime() { + return genClient.cacheHasKey(CacheKey.deletedTime); + } + + + /** + * Sets the field 'id'. + */ + public ModifierOverride setId(String id) { + return genClient.setOther(id, CacheKey.id); + } + + /** + * Sets the field 'enabled'. + */ + public ModifierOverride setEnabled(Boolean enabled) { + return genClient.setOther(enabled, CacheKey.enabled); + } + + /** + * Sets the field 'reasonCode'. + */ + public ModifierOverride setReasonCode(String reasonCode) { + return genClient.setOther(reasonCode, CacheKey.reasonCode); + } + + /** + * Sets the field 'filtered'. + */ + public ModifierOverride setFiltered(Boolean filtered) { + return genClient.setOther(filtered, CacheKey.filtered); + } + + /** + * Sets the field 'modifiedTime'. + */ + public ModifierOverride setModifiedTime(Long modifiedTime) { + return genClient.setOther(modifiedTime, CacheKey.modifiedTime); + } + + /** + * Sets the field 'createdTime'. + */ + public ModifierOverride setCreatedTime(Long createdTime) { + return genClient.setOther(createdTime, CacheKey.createdTime); + } + + /** + * Sets the field 'deletedTime'. + */ + public ModifierOverride setDeletedTime(Long deletedTime) { + return genClient.setOther(deletedTime, CacheKey.deletedTime); + } + + + /** Clears the 'id' field, the 'has' method for this field will now return false */ + public void clearId() { + genClient.clear(CacheKey.id); + } + /** Clears the 'enabled' field, the 'has' method for this field will now return false */ + public void clearEnabled() { + genClient.clear(CacheKey.enabled); + } + /** Clears the 'reasonCode' field, the 'has' method for this field will now return false */ + public void clearReasonCode() { + genClient.clear(CacheKey.reasonCode); + } + /** Clears the 'filtered' field, the 'has' method for this field will now return false */ + public void clearFiltered() { + genClient.clear(CacheKey.filtered); + } + /** Clears the 'modifiedTime' field, the 'has' method for this field will now return false */ + public void clearModifiedTime() { + genClient.clear(CacheKey.modifiedTime); + } + /** Clears the 'createdTime' field, the 'has' method for this field will now return false */ + public void clearCreatedTime() { + genClient.clear(CacheKey.createdTime); + } + /** Clears the 'deletedTime' field, the 'has' method for this field will now return false */ + public void clearDeletedTime() { + genClient.clear(CacheKey.deletedTime); + } + + + /** + * Returns true if this instance has any changes. + */ + public boolean containsChanges() { + return genClient.containsChanges(); + } + + /** + * Reset the log of changes made to this instance, calling copyChanges() after this would return an empty instance. + */ + public void resetChangeLog() { + genClient.resetChangeLog(); + } + + /** + * Create a copy of this instance that contains only fields that were set after the constructor was called. + */ + public ModifierOverride copyChanges() { + ModifierOverride copy = new ModifierOverride(); + copy.mergeChanges(this); + copy.resetChangeLog(); + return copy; + } + + /** + * Copy all the changed fields from the given source to this instance. + */ + public void mergeChanges(ModifierOverride src) { + if (src.genClient.getChangeLog() != null) { + genClient.mergeChanges(new ModifierOverride(src).getJSONObject(), src.genClient); + } + } + + public static final android.os.Parcelable.Creator CREATOR = new android.os.Parcelable.Creator() { + @Override + public ModifierOverride createFromParcel(android.os.Parcel in) { + ModifierOverride instance = new ModifierOverride(com.clover.sdk.v3.JsonParcelHelper.ObjectWrapper.CREATOR.createFromParcel(in).unwrap()); + instance.genClient.setBundle(in.readBundle(getClass().getClassLoader())); + instance.genClient.setChangeLog(in.readBundle()); + return instance; + } + + @Override + public ModifierOverride[] newArray(int size) { + return new ModifierOverride[size]; + } + }; + + public static final com.clover.sdk.JSONifiable.Creator JSON_CREATOR = new com.clover.sdk.JSONifiable.Creator() { + public Class getCreatedClass() { + return ModifierOverride.class; + } + + @Override + public ModifierOverride create(org.json.JSONObject jsonObject) { + return new ModifierOverride(jsonObject); + } + }; + + public interface Constraints { + public static final boolean ID_IS_REQUIRED = false; + public static final long ID_MAX_LEN = 127; + public static final boolean ENABLED_IS_REQUIRED = false; + public static final boolean REASONCODE_IS_REQUIRED = true; + public static final long REASONCODE_MAX_LEN = 127; + public static final boolean FILTERED_IS_REQUIRED = false; + public static final boolean MODIFIEDTIME_IS_REQUIRED = false; + public static final boolean CREATEDTIME_IS_REQUIRED = false; + public static final boolean DELETEDTIME_IS_REQUIRED = false; + } + +} diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/OrderFee.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/OrderFee.java index e71d3898d..087e9888d 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/OrderFee.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/inventory/OrderFee.java @@ -42,6 +42,7 @@ *
  • {@link #getModifiedTime modifiedTime}
  • *
  • {@link #getDeletedTime deletedTime}
  • *
  • {@link #getType type}
  • + *
  • {@link #getServiceChargeUuid serviceChargeUuid}
  • * */ @SuppressWarnings("all") @@ -89,21 +90,21 @@ public java.util.List getTaxRates() { } /** - * Timestamp when the menu item was created + * Timestamp when the order fee was created */ public Long getCreatedTime() { return genClient.cacheGet(CacheKey.createdTime); } /** - * Timestamp when the menu item was last modified + * Timestamp when the order fee was last modified */ public Long getModifiedTime() { return genClient.cacheGet(CacheKey.modifiedTime); } /** - * Timestamp when menu item was last deleted + * Timestamp when order fee was last deleted */ public Long getDeletedTime() { return genClient.cacheGet(CacheKey.deletedTime); @@ -116,6 +117,13 @@ public String getType() { return genClient.cacheGet(CacheKey.type); } + /** + * Original service charge uuid + */ + public String getServiceChargeUuid() { + return genClient.cacheGet(CacheKey.serviceChargeUuid); + } + @@ -144,6 +152,8 @@ private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), type (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + serviceChargeUuid + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), ; private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; @@ -224,6 +234,8 @@ public void validate() { genClient.validateMin(CacheKey.amount, getAmount(), 0L); genClient.validateMinMax(CacheKey.percentage, getPercentage(), 0L, 1000000L); + + genClient.validateLength(CacheKey.serviceChargeUuid, getServiceChargeUuid(), 13); } /** Checks whether the 'id' field is set and is not null */ @@ -289,6 +301,11 @@ public boolean isNotNullType() { return genClient.cacheValueIsNotNull(CacheKey.type); } + /** Checks whether the 'serviceChargeUuid' field is set and is not null */ + public boolean isNotNullServiceChargeUuid() { + return genClient.cacheValueIsNotNull(CacheKey.serviceChargeUuid); + } + /** Checks whether the 'id' field has been set, however the value could be null */ @@ -351,6 +368,11 @@ public boolean hasType() { return genClient.cacheHasKey(CacheKey.type); } + /** Checks whether the 'serviceChargeUuid' field has been set, however the value could be null */ + public boolean hasServiceChargeUuid() { + return genClient.cacheHasKey(CacheKey.serviceChargeUuid); + } + /** * Sets the field 'id'. @@ -438,6 +460,13 @@ public OrderFee setType(String type) { return genClient.setOther(type, CacheKey.type); } + /** + * Sets the field 'serviceChargeUuid'. + */ + public OrderFee setServiceChargeUuid(String serviceChargeUuid) { + return genClient.setOther(serviceChargeUuid, CacheKey.serviceChargeUuid); + } + /** Clears the 'id' field, the 'has' method for this field will now return false */ public void clearId() { @@ -487,6 +516,10 @@ public void clearDeletedTime() { public void clearType() { genClient.clear(CacheKey.type); } + /** Clears the 'serviceChargeUuid' field, the 'has' method for this field will now return false */ + public void clearServiceChargeUuid() { + genClient.clear(CacheKey.serviceChargeUuid); + } /** @@ -566,6 +599,8 @@ public interface Constraints { public static final boolean MODIFIEDTIME_IS_REQUIRED = false; public static final boolean DELETEDTIME_IS_REQUIRED = false; public static final boolean TYPE_IS_REQUIRED = false; + public static final boolean SERVICECHARGEUUID_IS_REQUIRED = false; + public static final long SERVICECHARGEUUID_MAX_LEN = 13; } } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderCalc.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderCalc.java index 82d28054f..379724de2 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderCalc.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderCalc.java @@ -288,6 +288,23 @@ public Decimal getSplitPercent() { } return HUNDRED; } + + @Nullable + @Override + public Decimal getPercentage() { + if (line.isNotNullPercentage()) { + return new Decimal(line.getPercentage()).divide(SERVICE_CHARGE_DIVISOR); + } + return null; + } + + @Override + public boolean isOrderFee() { + if (line.isNotNullIsOrderFee()){ + return line.getIsOrderFee(); + } + return false; + } } /** @@ -476,4 +493,23 @@ public long getPriceWithVAT(LineItem lineItem) { public List getAdditionalChargeSummaries(final Collection lines) { return getCalc().getAdditionalChargeSummaries(toCalcLines(lines)); } + + /** + * Get an orderFee price based on passed orderFeeLineItem's percentage + * + * @param orderFeeLineItem order fee line item for which price needs to be calculated + * @return long price for given orderFeeLineItem + */ + public long getOrderFeePrice(LineItem orderFeeLineItem) { + return getCalc().getOrderFeePrice(new CalcLineItem(orderFeeLineItem)).getCents(); + } + + /** + * Get the total orderFee amount for given order + * + * @return long total of order fees applied to given order + */ + public long getTotalOrderFees() { + return getCalc().getOrderFee().getCents(); + } } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV31Connector.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV31Connector.java index 40b126129..e3cd3b4de 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV31Connector.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV31Connector.java @@ -825,6 +825,22 @@ public Boolean call(IOrderServiceV3_1 service, ResultStatus status) throws Remot }); } + /** + * Send all line items added in the List to the kitchen or order printer. Only prints + * items that have tags (also called labels) associating them with a printer + * + * @param orderId the ID of the order to fire. + * @param lineItemList list of line item items to be printed. + * @return true if items are printed, returns false line items or printers are empty. + */ + public boolean fireLineItems(final String orderId, + List lineItemList) + throws RemoteException, ClientException, ServiceException, BindingException { + return execute((service, status) -> { + return service.fireLineItems(orderId, lineItemList, status); + }); + } + /** * Not available to non-Clover apps. * @y.exclude @@ -915,6 +931,19 @@ public Order call(IOrderServiceV3_1 service, ResultStatus status) throws RemoteE }); } + /** + * This method has been deprecated because the payment used for the preauth is no longer the same as the payment for capture. + * Please use {@link #capturePreAuthorization(String, Payment, Payment, List)} + * @param orderId + * @param preAuth + * @param lineItems + * @return + * @throws RemoteException + * @throws ClientException + * @throws ServiceException + * @throws BindingException + */ + @Deprecated public Order capturePreAuth(final String orderId, final Payment preAuth, final List lineItems) throws RemoteException, ClientException, ServiceException, BindingException { return execute(new ServiceCallable() { @Override @@ -992,6 +1021,14 @@ default void onLineItemModificationsDeleted(String orderId, List lineIte void onRefundProcessed(String orderId, String refundId); void onCreditProcessed(String orderId, String creditId); + + // making it default to not break existing implementers of OnOrderUpdateListener2 + default void onOrderFeeAdded(String orderId, String orderFeeLineItemId) { + } + + // making it default to not break existing implementers of OnOrderUpdateListener2 + default void onOrderFeeDeleted(String orderId, String orderFeeLineItemId) { + } } private static class OnOrderUpdateListenerParent2 extends IOnOrderUpdateListener2.Stub { @@ -1167,6 +1204,16 @@ public void run(OnOrderUpdateListener2 listener) { }); } + @Override + public void onOrderFeeAdded(String orderId, String orderFeeLineItemId) throws RemoteException { + postChange(listener -> listener.onOrderFeeAdded(orderId, orderFeeLineItemId)); + } + + @Override + public void onOrderFeeDeleted(String orderId, String orderFeeLineItemId) throws RemoteException { + postChange(listener -> listener.onOrderFeeDeleted(orderId, orderFeeLineItemId)); + } + // This method must be called when the callback is no longer needed to prevent a memory leak. Due to the design of // AIDL services Android unnecessarily retains pointers to otherwise unreferenced instances of this class which in // turn are referencing Context objects that consume large amounts of memory. @@ -1398,4 +1445,38 @@ public Order call(IOrderServiceV3_1 service, ResultStatus status) throws RemoteE } }); } + + public Order addOrderFee(final String orderId, final String orderFeeId) throws RemoteException, ClientException, ServiceException, BindingException { + return execute((service, status) -> { + return getValue(service.addOrderFee(orderId, orderFeeId, status)); + }); + } + + public Order deleteOrderFee(final String orderId, final String orderFeeLineItemId) throws RemoteException, ClientException, ServiceException, BindingException { + return execute((service, status) -> { + return getValue(service.deleteOrderFee(orderId, orderFeeLineItemId, status)); + }); + } + + /** + * This method is used to capture a preauthorized payment. + * @param orderId -- ID of the order that the preauth and captured payment are associated with. + * @param preAuth -- The original preauth payment + * @param closingPayment -- The successfully captured payment. + * @param lineItems -- the line items associated with the payment. + * @return updated Order object + * @throws RemoteException + * @throws ClientException + * @throws ServiceException + * @throws BindingException + */ + public Order capturePreAuthorization(final String orderId, final Payment preAuth, final Payment closingPayment, final List lineItems) throws RemoteException, ClientException, ServiceException, BindingException { + return execute(new ServiceCallable() { + @Override + public Order call(IOrderServiceV3_1 service, ResultStatus status) throws RemoteException { + return getValue(service.capturePreAuthorization(orderId, new PaymentFdParcelable(preAuth), new PaymentFdParcelable(closingPayment), new LineItemListFdParcelable(lineItems), status)); + } + }); + } + } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV3Connector.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV3Connector.java index 1cf628053..39d44c4de 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV3Connector.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/order/OrderV3Connector.java @@ -745,6 +745,14 @@ default void onLineItemModificationsDeleted(String orderId, List lineIte void onRefundProcessed(String orderId, String refundId); void onCreditProcessed(String orderId, String creditId); + + // making it default to not break existing implementers of OnOrderUpdateListener2 + default void onOrderFeeAdded(String orderId, String orderFeeLineItemId) { + } + + // making it default to not break existing implementers of OnOrderUpdateListener2 + default void onOrderFeeDeleted(String orderId, String orderFeeLineItemId) { + } } private static class OnOrderUpdateListenerParent2 extends IOnOrderUpdateListener2.Stub { @@ -920,6 +928,16 @@ public void run(OnOrderUpdateListener2 listener) { }); } + @Override + public void onOrderFeeAdded(String orderId, String orderFeeLineItemId) throws RemoteException { + postChange(listener -> listener.onOrderFeeAdded(orderId, orderFeeLineItemId)); + } + + @Override + public void onOrderFeeDeleted(String orderId, String orderFeeLineItemId) throws RemoteException { + postChange(listener -> listener.onOrderFeeDeleted(orderId, orderFeeLineItemId)); + } + // This method must be called when the callback is no longer needed to prevent a memory leak. Due to the design of // AIDL services Android unnecessarily retains pointers to otherwise unreferenced instances of this class which in // turn are referencing Context objects that consume large amounts of memory. diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/Payment.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/Payment.java index 744155ebf..d3bdb710c 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/Payment.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/Payment.java @@ -74,6 +74,7 @@ *
  • {@link #getOceanGatewayInfo oceanGatewayInfo}
  • *
  • {@link #getTerminalManagementComponents terminalManagementComponents}
  • *
  • {@link #getEmiInfo emiInfo}
  • + *
  • {@link #getPaymentBatchInfo paymentBatchInfo}
  • * */ @SuppressWarnings("all") @@ -351,98 +352,104 @@ public com.clover.sdk.v3.payments.PaymentEmiInfo getEmiInfo() { return genClient.cacheGet(CacheKey.emiInfo); } - - + /** + * Information about the Batch used for payments + */ + public com.clover.sdk.v3.payments.PaymentBatchInfo getPaymentBatchInfo() { + return genClient.cacheGet(CacheKey.paymentBatchInfo); + } private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { id - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), order - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), device - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), tender - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Tender.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Tender.JSON_CREATOR)), amount - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), tipAmount - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), taxAmount - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), cashbackAmount - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), cashTendered - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), externalPaymentId - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), employee - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), createdTime - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), clientCreatedTime - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), gatewayProcessingTime - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), modifiedTime - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Long.class)), offline - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Boolean.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.Boolean.class)), result - (com.clover.sdk.extractors.EnumExtractionStrategy.instance(com.clover.sdk.v3.payments.Result.class)), + (com.clover.sdk.extractors.EnumExtractionStrategy.instance(com.clover.sdk.v3.payments.Result.class)), cardTransaction - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.CardTransaction.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.CardTransaction.JSON_CREATOR)), serviceCharge - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.ServiceChargeAmount.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.ServiceChargeAmount.JSON_CREATOR)), attributes - (com.clover.sdk.extractors.MapExtractionStrategy.instance()), + (com.clover.sdk.extractors.MapExtractionStrategy.instance()), additionalCharges - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.AdditionalChargeAmount.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.AdditionalChargeAmount.JSON_CREATOR)), taxRates - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.PaymentTaxRate.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.PaymentTaxRate.JSON_CREATOR)), refunds - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.Refund.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.Refund.JSON_CREATOR)), note - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), lineItemPayments - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.LineItemPayment.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.LineItemPayment.JSON_CREATOR)), authorization - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), voidPaymentRef - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), voidReason - (com.clover.sdk.extractors.EnumExtractionStrategy.instance(com.clover.sdk.v3.order.VoidReason.class)), + (com.clover.sdk.extractors.EnumExtractionStrategy.instance(com.clover.sdk.v3.order.VoidReason.class)), voidReasonDetails - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.order.VoidReasonDetails.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.order.VoidReasonDetails.JSON_CREATOR)), dccInfo - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.DCCInfo.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.DCCInfo.JSON_CREATOR)), transactionSettings - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.TransactionSettings.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.TransactionSettings.JSON_CREATOR)), germanInfo - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.GermanInfo.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.GermanInfo.JSON_CREATOR)), appTracking - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.apps.AppTracking.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.apps.AppTracking.JSON_CREATOR)), cashAdvanceExtra - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.CashAdvanceExtra.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.CashAdvanceExtra.JSON_CREATOR)), transactionInfo - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.TransactionInfo.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.TransactionInfo.JSON_CREATOR)), signatureDisclaimer - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.SignatureDisclaimer.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.SignatureDisclaimer.JSON_CREATOR)), externalReferenceId - (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), merchant - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.base.Reference.JSON_CREATOR)), increments - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.IncrementalAuthorization.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.IncrementalAuthorization.JSON_CREATOR)), purchaseCardL2 - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PurchaseCardL2.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PurchaseCardL2.JSON_CREATOR)), purchaseCardL3 - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PurchaseCardL3.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PurchaseCardL3.JSON_CREATOR)), oceanGatewayInfo - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.OceanGatewayInfo.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.OceanGatewayInfo.JSON_CREATOR)), terminalManagementComponents - (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.TerminalManagementComponent.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordListExtractionStrategy.instance(com.clover.sdk.v3.payments.TerminalManagementComponent.JSON_CREATOR)), emiInfo - (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PaymentEmiInfo.JSON_CREATOR)), + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PaymentEmiInfo.JSON_CREATOR)), + paymentBatchInfo + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.PaymentBatchInfo.JSON_CREATOR)), ; private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; @@ -768,6 +775,10 @@ public boolean isNotNullEmiInfo() { return genClient.cacheValueIsNotNull(CacheKey.emiInfo); } + /** Checks whether the 'paymentBatchInfo' field is set and is not null */ + public boolean isNotNullPaymentBatchInfo() { + return genClient.cacheValueIsNotNull(CacheKey.paymentBatchInfo); + } /** Checks whether the 'id' field has been set, however the value could be null */ @@ -990,6 +1001,10 @@ public boolean hasEmiInfo() { return genClient.cacheHasKey(CacheKey.emiInfo); } + /** Checks whether the 'paymentBatchInfo' field has been set, however the value could be null */ + public boolean hasPaymentBatchInfo() { + return genClient.cacheHasKey(CacheKey.paymentBatchInfo); + } /** * Sets the field 'id'. @@ -1353,6 +1368,15 @@ public Payment setEmiInfo(com.clover.sdk.v3.payments.PaymentEmiInfo emiInfo) { return genClient.setRecord(emiInfo, CacheKey.emiInfo); } + /** + * Sets the field 'paymentBatchInfo'. + * + * The parameter is not copied so changes to it will be reflected in this instance and vice-versa. + */ + public Payment setPaymentBatchInfo(com.clover.sdk.v3.payments.PaymentBatchInfo paymentBatchInfo) { + return genClient.setRecord(paymentBatchInfo, CacheKey.paymentBatchInfo); + } + /** Clears the 'id' field, the 'has' method for this field will now return false */ public void clearId() { @@ -1530,7 +1554,10 @@ public void clearTerminalManagementComponents() { public void clearEmiInfo() { genClient.clear(CacheKey.emiInfo); } - + /** Clears the 'paymentBatchInfo' field, the 'has' method for this field will now return false */ + public void clearPaymentBatchInfo() { + genClient.clear(CacheKey.paymentBatchInfo); + } /** * Returns true if this instance has any changes. @@ -1639,6 +1666,7 @@ public interface Constraints { public static final boolean OCEANGATEWAYINFO_IS_REQUIRED = false; public static final boolean TERMINALMANAGEMENTCOMPONENTS_IS_REQUIRED = false; public static final boolean EMIINFO_IS_REQUIRED = false; + public static final boolean PAYMENTBATCHINFO_IS_REQUIRED = false; } -} +} \ No newline at end of file diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/PaymentBatchInfo.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/PaymentBatchInfo.java new file mode 100644 index 000000000..efbb4124d --- /dev/null +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/PaymentBatchInfo.java @@ -0,0 +1,247 @@ +/** + * Autogenerated by Avro + * + * DO NOT EDIT DIRECTLY + */ + +/* + * Copyright (C) 2019 Clover Network, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.clover.sdk.v3.payments; + +import com.clover.sdk.GenericClient; +import com.clover.sdk.GenericParcelable; + +/** + * This is an auto-generated Clover data object. + *

    + *

    Fields

    + *
      + *
    • {@link #getBatchUuid batchUuid}
    • + *
    • {@link #getBatchModifiedTime batchModifiedTime}
    • + *
    + */ +@SuppressWarnings("all") +public class PaymentBatchInfo extends GenericParcelable implements com.clover.sdk.v3.Validator, com.clover.sdk.JSONifiable { + + public String getBatchUuid() { + return genClient.cacheGet(CacheKey.batchUuid); + } + + /** + * Modified time of batch + */ + public Long getBatchModifiedTime() { + return genClient.cacheGet(CacheKey.batchModifiedTime); + } + + + + + private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { + batchUuid + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(String.class)), + batchModifiedTime + (com.clover.sdk.extractors.BasicExtractionStrategy.instance(Long.class)), + ; + + private final com.clover.sdk.extractors.ExtractionStrategy extractionStrategy; + + private CacheKey(com.clover.sdk.extractors.ExtractionStrategy s) { + extractionStrategy = s; + } + + @Override + public com.clover.sdk.extractors.ExtractionStrategy getExtractionStrategy() { + return extractionStrategy; + } + } + + private final GenericClient genClient; + + /** + * Constructs a new empty instance. + */ + public PaymentBatchInfo() { + genClient = new GenericClient(this); + } + + @Override + protected GenericClient getGenericClient() { + return genClient; + } + + /** + * Constructs a new empty instance. + */ + protected PaymentBatchInfo(boolean noInit) { + genClient = null; + } + + /** + * Constructs a new instance from the given JSON String. + */ + public PaymentBatchInfo(String json) throws IllegalArgumentException { + this(); + genClient.initJsonObject(json); + } + + /** + * Construct a new instance backed by the given JSONObject, the parameter is not copied so changes to it will be + * reflected in this instance and vice-versa. + */ + public PaymentBatchInfo(org.json.JSONObject jsonObject) { + this(); + genClient.setJsonObject(jsonObject); + } + + /** + * Constructs a new instance that is a deep copy of the source instance. It does not copy the bundle or changelog. + */ + public PaymentBatchInfo(PaymentBatchInfo src) { + this(); + if (src.genClient.getJsonObject() != null) { + genClient.setJsonObject(com.clover.sdk.v3.JsonHelper.deepCopy(src.genClient.getJSONObject())); + } + } + + /** + * Returns the internal JSONObject backing this instance, the return value is not a copy so changes to it will be + * reflected in this instance and vice-versa. + */ + public org.json.JSONObject getJSONObject() { + return genClient.getJSONObject(); + } + + @Override + public void validate() { + genClient.validateCloverId(CacheKey.batchUuid, getBatchUuid()); + } + + /** Checks whether the 'batchUuid' field is set and is not null */ + public boolean isNotNullBatchUuid() { + return genClient.cacheValueIsNotNull(CacheKey.batchUuid); + } + + /** Checks whether the 'batchModifiedTime' field is set and is not null */ + public boolean isNotNullBatchModifiedTime() { + return genClient.cacheValueIsNotNull(CacheKey.batchModifiedTime); + } + + + + /** Checks whether the 'batchUuid' field has been set, however the value could be null */ + public boolean hasBatchUuid() { + return genClient.cacheHasKey(CacheKey.batchUuid); + } + + /** Checks whether the 'batchModifiedTime' field has been set, however the value could be null */ + public boolean hasBatchModifiedTime() { + return genClient.cacheHasKey(CacheKey.batchModifiedTime); + } + + + /** + * Sets the field 'batchUuid'. + */ + public PaymentBatchInfo setBatchUuid(String batchUuid) { + return genClient.setOther(batchUuid, CacheKey.batchUuid); + } + + /** + * Sets the field 'batchModifiedTime'. + */ + public PaymentBatchInfo setBatchModifiedTime(Long batchModifiedTime) { + return genClient.setOther(batchModifiedTime, CacheKey.batchModifiedTime); + } + + + /** Clears the 'batchUuid' field, the 'has' method for this field will now return false */ + public void clearBatchUuid() { + genClient.clear(CacheKey.batchUuid); + } + /** Clears the 'batchModifiedTime' field, the 'has' method for this field will now return false */ + public void clearBatchModifiedTime() { + genClient.clear(CacheKey.batchModifiedTime); + } + + + /** + * Returns true if this instance has any changes. + */ + public boolean containsChanges() { + return genClient.containsChanges(); + } + + /** + * Reset the log of changes made to this instance, calling copyChanges() after this would return an empty instance. + */ + public void resetChangeLog() { + genClient.resetChangeLog(); + } + + /** + * Create a copy of this instance that contains only fields that were set after the constructor was called. + */ + public PaymentBatchInfo copyChanges() { + PaymentBatchInfo copy = new PaymentBatchInfo(); + copy.mergeChanges(this); + copy.resetChangeLog(); + return copy; + } + + /** + * Copy all the changed fields from the given source to this instance. + */ + public void mergeChanges(PaymentBatchInfo src) { + if (src.genClient.getChangeLog() != null) { + genClient.mergeChanges(new PaymentBatchInfo(src).getJSONObject(), src.genClient); + } + } + + public static final android.os.Parcelable.Creator CREATOR = new android.os.Parcelable.Creator() { + @Override + public PaymentBatchInfo createFromParcel(android.os.Parcel in) { + PaymentBatchInfo instance = new PaymentBatchInfo(com.clover.sdk.v3.JsonParcelHelper.ObjectWrapper.CREATOR.createFromParcel(in).unwrap()); + instance.genClient.setBundle(in.readBundle(getClass().getClassLoader())); + instance.genClient.setChangeLog(in.readBundle()); + return instance; + } + + @Override + public PaymentBatchInfo[] newArray(int size) { + return new PaymentBatchInfo[size]; + } + }; + + public static final com.clover.sdk.JSONifiable.Creator JSON_CREATOR = new com.clover.sdk.JSONifiable.Creator() { + public Class getCreatedClass() { + return PaymentBatchInfo.class; + } + + @Override + public PaymentBatchInfo create(org.json.JSONObject jsonObject) { + return new PaymentBatchInfo(jsonObject); + } + }; + + public interface Constraints { + public static final boolean BATCHUUID_IS_REQUIRED = false; + public static final long BATCHUUID_MAX_LEN = 13; + public static final boolean BATCHMODIFIEDTIME_IS_REQUIRED = false; + } + +} diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/ServiceFeeRequest.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/ServiceFeeRequest.java index 897bcfb7b..8620420af 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/ServiceFeeRequest.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/ServiceFeeRequest.java @@ -34,6 +34,7 @@ *
  • {@link #getOrderId orderId}
  • *
  • {@link #getSourcePaymentId sourcePaymentId}
  • *
  • {@link #getVaultedCard vaultedCard}
  • + *
  • {@link #getSourcePayment sourcePayment}
  • * */ @SuppressWarnings("all") @@ -67,6 +68,14 @@ public com.clover.sdk.v3.payments.VaultedCard getVaultedCard() { return genClient.cacheGet(CacheKey.vaultedCard); } + /** + * Only required when using auth server + * Payment object + * /auth/service_fees/payments + */ + public com.clover.sdk.v3.payments.Payment getSourcePayment() { + return genClient.cacheGet(CacheKey.sourcePayment); + } @@ -77,6 +86,8 @@ private enum CacheKey implements com.clover.sdk.ExtractionStrategyEnum { (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), sourcePaymentId (com.clover.sdk.extractors.BasicExtractionStrategy.instance(java.lang.String.class)), + sourcePayment + (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.Payment.JSON_CREATOR)), vaultedCard (com.clover.sdk.extractors.RecordExtractionStrategy.instance(com.clover.sdk.v3.payments.VaultedCard.JSON_CREATOR)), ; @@ -177,7 +188,9 @@ public boolean isNotNullVaultedCard() { return genClient.cacheValueIsNotNull(CacheKey.vaultedCard); } - + public boolean isNotNullSourcePayment() { + return genClient.cacheValueIsNotNull(CacheKey.sourcePayment); + } /** Checks whether the 'amount' field has been set, however the value could be null */ public boolean hasAmount() { @@ -199,6 +212,10 @@ public boolean hasVaultedCard() { return genClient.cacheHasKey(CacheKey.vaultedCard); } + /** Checks whether the 'sourcePayment' field has been set, however the value could be null */ + public boolean hasSourcePayment() { + return genClient.cacheHasKey(CacheKey.sourcePayment); + } /** * Sets the field 'amount'. @@ -230,6 +247,14 @@ public ServiceFeeRequest setVaultedCard(com.clover.sdk.v3.payments.VaultedCard v return genClient.setRecord(vaultedCard, CacheKey.vaultedCard); } + /** + * Sets the field 'sourcePayment'. + * + * The parameter is not copied so changes to it will be reflected in this instance and vice-versa. + */ + public ServiceFeeRequest setSourcePayment(com.clover.sdk.v3.payments.Payment sourcePayment) { + return genClient.setRecord(sourcePayment, CacheKey.sourcePayment); + } /** Clears the 'amount' field, the 'has' method for this field will now return false */ public void clearAmount() { @@ -248,6 +273,10 @@ public void clearVaultedCard() { genClient.clear(CacheKey.vaultedCard); } + /** Clears the 'sourcePayment' field, the 'has' method for this field will now return false */ + public void clearSourcePayment() { + genClient.clear(CacheKey.sourcePayment); + } /** * Returns true if this instance has any changes. @@ -315,6 +344,7 @@ public interface Constraints { public static final boolean SOURCEPAYMENTID_IS_REQUIRED = false; public static final long SOURCEPAYMENTID_MAX_LEN = 13; public static final boolean VAULTEDCARD_IS_REQUIRED = false; + public static final boolean SOURCE_PAYMENT_IS_REQUIRED = false; } } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/PaymentRequestIntentBuilder.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/PaymentRequestIntentBuilder.java index ad00dc82d..615452528 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/PaymentRequestIntentBuilder.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/PaymentRequestIntentBuilder.java @@ -21,6 +21,7 @@ public class PaymentRequestIntentBuilder extends BaseIntentBuilder { private String externalPaymentId; private Long amount; private Long taxAmount; + private String orderId; private Boolean preferOnScreen = null; private CardOptions cardOptions = null; private TipOptions tipOptions = null; @@ -137,6 +138,17 @@ public PaymentRequestIntentBuilder taxAmount(Long taxAmount) { return this; } + + /** + * Set the id of the order, to which the payment will be added + * @param orderId - id of an existing order + * @return PaymentRequestIntentBuilder object with new orderId + */ + public PaymentRequestIntentBuilder orderId(String orderId) { + this.orderId = orderId; + return this; + } + /** * return a single-use Intent to be used by Integrator POS to initiate payment * @@ -297,6 +309,10 @@ public Intent build(Context context) throws IllegalArgumentException { i.putExtra(Intents.EXTRA_EXTERNAL_REFERENCE_ID, externalReferenceId); } + if (orderId != null) { + i.putExtra(Intents.EXTRA_ORDER_ID, orderId); + } + return i; } diff --git a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/TipAdjustRequestIntentBuilder.java b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/TipAdjustRequestIntentBuilder.java index 1362a4ebd..709d04373 100644 --- a/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/TipAdjustRequestIntentBuilder.java +++ b/clover-android-sdk/src/main/java/com/clover/sdk/v3/payments/api/TipAdjustRequestIntentBuilder.java @@ -4,6 +4,8 @@ import android.content.Context; import android.content.Intent; +import androidx.annotation.Nullable; + import com.clover.sdk.internal.util.Strings; import com.clover.sdk.v1.Intents; @@ -21,13 +23,19 @@ public class TipAdjustRequestIntentBuilder extends BaseIntentBuilder { * Create the build with a required paymentId of the payment to apply the tip * @param paymentId */ + @Deprecated public TipAdjustRequestIntentBuilder(String paymentId) { - if(Strings.isNullOrEmpty(paymentId)) { + if (Strings.isNullOrEmpty(paymentId)) { throw new IllegalArgumentException("payment id is required."); } this.paymentId = paymentId; } + private TipAdjustRequestIntentBuilder(String paymentId, Long tipAmount) { + this.paymentId = paymentId; + this.tipAmount = tipAmount; + } + /** * The amount of the tip. If null, the Clover Tip app will open for the user * to enter the tip for the payment @@ -39,8 +47,20 @@ public TipAdjustRequestIntentBuilder tipAmount(Long tipAmount) { return this; } + /** + * Use to create a Tip Adjust request to adjust a payment. + * + * @param paymentId + * @param tipAmount - this is optional. If included, it will be a headless tip adjust. If null, + * you will have the opportunity to enter a tip amount within the Tips app. + * @return + */ + public static TipAdjustRequestIntentBuilder AdjustTip(String paymentId, @Nullable Long tipAmount) { + return new TipAdjustRequestIntentBuilder(paymentId, tipAmount); + } + @Override - public Intent build(Context context) { + public Intent build(Context context) throws IllegalArgumentException { if (context == null) { throw new IllegalArgumentException("context must be populated with a non null value"); @@ -48,10 +68,12 @@ public Intent build(Context context) { Intent i = super.build(context); i.setComponent(new ComponentName("com.clover.payment.builder.pay", "com.clover.payment.builder.pay.handler.TipAdjustRequestHandler")); - if (paymentId != null) { - i.putExtra(Intents.EXTRA_PAYMENT_ID, paymentId); + if (Strings.isNullOrEmpty(paymentId)) { + throw new IllegalArgumentException("payment id is required."); } + i.putExtra(Intents.EXTRA_PAYMENT_ID, paymentId); + if (tipAmount != null) { i.putExtra(Intents.EXTRA_TIP_AMOUNT, tipAmount); } diff --git a/clover-android-sdk/src/test/java/com/clover/common2/payments/PayIntentTest.java b/clover-android-sdk/src/test/java/com/clover/common2/payments/PayIntentTest.java index a72e7b197..37a86ceb5 100644 --- a/clover-android-sdk/src/test/java/com/clover/common2/payments/PayIntentTest.java +++ b/clover-android-sdk/src/test/java/com/clover/common2/payments/PayIntentTest.java @@ -447,4 +447,112 @@ public void testEBTManualCardEntryScreenFlow_serialization() { assertNotNull(fromParcel.ebtManualCardEntryScreenFlow); assertEquals(ebtManualCardData, fromParcel.ebtManualCardEntryScreenFlow); } + + @Test + public void testPaymentType() { + PayIntent payIntent = new PayIntent.Builder().build(); + assertNull(payIntent.paymentType); + + String paymentType = "TEST_PAYMENT_TYPE"; + + payIntent = new PayIntent.Builder().paymentType(paymentType).build(); + assertNotNull(payIntent.paymentType); + assertEquals("TEST_PAYMENT_TYPE", payIntent.paymentType); + } + + @Test + public void testPaymentType_fromIntent() { + Intent sourceIntent = new Intent(); + PayIntent payIntent = new PayIntent.Builder().intent(sourceIntent).build(); + assertNull(payIntent.paymentType); + + String paymentType = "TEST_PAYMENT_TYPE"; + + sourceIntent = new Intent(); + sourceIntent.putExtra(Intents.EXTRA_PAYMENT_TYPE, paymentType); + payIntent = new PayIntent.Builder().intent(sourceIntent).build(); + assertNotNull(payIntent.paymentType); + assertEquals("TEST_PAYMENT_TYPE", payIntent.paymentType); + } + + @Test + public void testPaymentType_fromPayIntent() { + PayIntent sourcePayIntent = new PayIntent.Builder().build(); + PayIntent payIntent = new PayIntent.Builder().payIntent(sourcePayIntent).build(); + assertNull(payIntent.paymentType); + + String paymentType = "TEST_PAYMENT_TYPE"; + + sourcePayIntent = new PayIntent.Builder().paymentType(paymentType).build(); + payIntent = new PayIntent.Builder().payIntent(sourcePayIntent).build(); + assertEquals("TEST_PAYMENT_TYPE", payIntent.paymentType); + } + + @Test + public void testPaymentType_serialization() { + String paymentType = "TEST_PAYMENT_TYPE"; + PayIntent payIntent = new PayIntent.Builder().paymentType(paymentType).build(); + + Parcel p = Parcel.obtain(); + payIntent.writeToParcel(p, 0); + + p.setDataPosition(0); + PayIntent fromParcel = PayIntent.CREATOR.createFromParcel(p); + assertNotNull(fromParcel.paymentType); + assertEquals("TEST_PAYMENT_TYPE", fromParcel.paymentType); + } + + @Test + public void testCreateAuth() { + PayIntent payIntent = new PayIntent.Builder().build(); + assertNull(payIntent.createAuth); + + Boolean createAuth = true; + + payIntent = new PayIntent.Builder().createAuth(createAuth).build(); + assertNotNull(payIntent.createAuth); + assertTrue(payIntent.createAuth); + } + + @Test + public void testCreateAuth_fromIntent() { + Intent sourceIntent = new Intent(); + PayIntent payIntent = new PayIntent.Builder().intent(sourceIntent).build(); + assertNull(payIntent.createAuth); + + Boolean createAuth = true; + + sourceIntent = new Intent(); + sourceIntent.putExtra(Intents.EXTRA_CREATE_AUTH, createAuth); + payIntent = new PayIntent.Builder().intent(sourceIntent).build(); + assertNotNull(payIntent.createAuth); + assertTrue(payIntent.createAuth); + } + + @Test + public void testCreateAuth_fromPayIntent() { + PayIntent sourcePayIntent = new PayIntent.Builder().build(); + PayIntent payIntent = new PayIntent.Builder().payIntent(sourcePayIntent).build(); + assertNull(payIntent.createAuth); + + Boolean createAuth = true; + + sourcePayIntent = new PayIntent.Builder().createAuth(createAuth).build(); + payIntent = new PayIntent.Builder().payIntent(sourcePayIntent).build(); + assertTrue(payIntent.createAuth); + } + + @Test + public void testCreateAuth_serialization() { + Boolean createAuth = true; + PayIntent payIntent = new PayIntent.Builder().createAuth(createAuth).build(); + + Parcel p = Parcel.obtain(); + payIntent.writeToParcel(p, 0); + + p.setDataPosition(0); + PayIntent fromParcel = PayIntent.CREATOR.createFromParcel(p); + assertNotNull(fromParcel.createAuth); + assertTrue(fromParcel.createAuth); + } } diff --git a/clover-android-sdk/src/test/java/com/clover/sdk/util/Platform2Test.kt b/clover-android-sdk/src/test/java/com/clover/sdk/util/Platform2Test.kt new file mode 100644 index 000000000..b67c9a9d8 --- /dev/null +++ b/clover-android-sdk/src/test/java/com/clover/sdk/util/Platform2Test.kt @@ -0,0 +1,79 @@ +package com.clover.sdk.util + +import android.content.Context +import android.graphics.Point +import android.view.Display +import android.view.WindowManager +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.* +import org.mockito.stubbing.Answer +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class Platform2Test { + private lateinit var mockContext: Context + private lateinit var mockWindowManager: WindowManager + private lateinit var mockDisplay: Display + + @Before + fun setup() { + mockDisplay = mock(Display::class.java) + + mockWindowManager = mock(WindowManager::class.java) + `when`(mockWindowManager.defaultDisplay).thenReturn(mockDisplay) + + mockContext = mock(Context::class.java) + `when`(mockContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mockWindowManager) + } + + @Test + fun testSquareDisplay() { + doAnswer(Answer { invocation -> + val point = invocation.getArgument(0) + point.x = 480 + point.y = 480 + null + }).`when`(mockDisplay).getSize(any(Point::class.java)) + + Assert.assertTrue(Platform2.isSquareDisplay(mockContext)) + } + + @Test + fun testAlmostSquareDisplay() { + doAnswer(Answer { invocation -> + val point = invocation.getArgument(0) + point.x = 480 + point.y = 600 + null + }).`when`(mockDisplay).getSize(any(Point::class.java)) + + Assert.assertTrue(Platform2.isSquareDisplay(mockContext)) + } + + @Test + fun testPortDisplay() { + doAnswer(Answer { invocation -> + val point = invocation.getArgument(0) + point.x = 720 + point.y = 1280 + null + }).`when`(mockDisplay).getSize(any(Point::class.java)) + + Assert.assertFalse(Platform2.isSquareDisplay(mockContext)) + } + + @Test + fun testLandDisplay() { + doAnswer(Answer { invocation -> + val point = invocation.getArgument(0) + point.x = 1920 + point.y = 1080 + null + }).`when`(mockDisplay).getSize(any(Point::class.java)) + + Assert.assertFalse(Platform2.isSquareDisplay(mockContext)) + } +} \ No newline at end of file diff --git a/clover-android-sdk/src/test/java/com/clover/sdk/v3/order/OrderCalcTest.java b/clover-android-sdk/src/test/java/com/clover/sdk/v3/order/OrderCalcTest.java index af8e450fb..f2edfc20d 100644 --- a/clover-android-sdk/src/test/java/com/clover/sdk/v3/order/OrderCalcTest.java +++ b/clover-android-sdk/src/test/java/com/clover/sdk/v3/order/OrderCalcTest.java @@ -231,4 +231,71 @@ public void testGetAdditionalChargeSummaries_noChargesAvailable() { assertEquals(0, additionalChargeSummaries.size()); } + + @Test + public void testGetOrderFeePrice() { + List lineItems = createDummyLineItems(); + + LineItem orderFeeLineItem = new LineItem(); + orderFeeLineItem.setIsOrderFee(true); + orderFeeLineItem.setPercentage(150000L); + lineItems.add(orderFeeLineItem); + + orderCalc.order.setLineItems(lineItems); + + assertEquals(45L, orderCalc.getOrderFeePrice(orderFeeLineItem)); + } + + @Test + public void testGetOrderFeePrice_nonOrderFeeLineItem() { + List lineItems = createDummyLineItems(); + + assertEquals(0L, orderCalc.getOrderFeePrice(lineItems.get(1))); + } + + @Test + public void testGetTotalOrderFees() { + LineItem orderFeeLineItem1 = new LineItem(); + orderFeeLineItem1.setIsOrderFee(true); + orderFeeLineItem1.setPercentage(150000L); + orderFeeLineItem1.setPrice(15L); + + LineItem orderFeeLineItem2 = new LineItem(); + orderFeeLineItem2.setIsOrderFee(true); + orderFeeLineItem2.setPercentage(150000L); + orderFeeLineItem2.setPrice(35L); + + List lineItems = new ArrayList<>(); + lineItems.add(orderFeeLineItem1); + lineItems.add(orderFeeLineItem2); + + orderCalc.order.setLineItems(lineItems); + + assertEquals(50L, orderCalc.getTotalOrderFees()); + } + + @Test + public void testGetTotalOrderFees_noLineItems() { + assertEquals(0L, orderCalc.getTotalOrderFees()); + } + + @Test + public void testGetTotalOrderFees_noOrderFeeLineItems() { + orderCalc.order.setLineItems(createDummyLineItems()); + + assertEquals(0L, orderCalc.getTotalOrderFees()); + } + + private List createDummyLineItems() { + LineItem lineItem1 = new LineItem(); + lineItem1.setPrice(100L); + LineItem lineItem2 = new LineItem(); + lineItem2.setPrice(200L); + + List lineItems = new ArrayList<>(); + lineItems.add(lineItem1); + lineItems.add(lineItem2); + + return lineItems; + } } diff --git a/scripts/README.install_apps.md b/scripts/README.install_apps.md index 6d3f4c77c..ee800fafc 100644 --- a/scripts/README.install_apps.md +++ b/scripts/README.install_apps.md @@ -20,12 +20,13 @@ uid=0(root) gid=0(root) groups=0(root)... ``` $ ./install_apps.py -h Usage: install_apps.py [--debug] [--version] [--dry_run] [--keep] [--help] [--downgrade] - --debug or -d : print extended debug information - --version or -v : print version (and exit) - --dry-run or -r : show actions but do not perform them (do not download or install APKs - --keep or -k : keep temporary files (temp files are located under: /tmp) - --downgrade or -o: only downgrade, if current version is less than installed version; do not update - --help or -h : show this message (and exit) + --debug or -d : print extended debug information + --version or -v : print version (and exit) + --dry-run or -r : show actions but do not perform them (do not download or install APKs + --keep or -k : keep temporary files (temp files are located under: /tmp) + --downgrade or -o : only downgrade, if current version is less than installed version; do not update + --serial SERIAL or -s SERIAL: use device with given serial (overrides $ANDROID_SERIAL) + --help or -h : show this message (and exit) ``` ### --version or -v @@ -74,5 +75,10 @@ adb install -r -d /tmp/com.clover.engine-6528.apk ### --debug or -d Print extended debug information. This output is extremely verbose and is probably not useful unless you are experiencing problems with the script. +### --serial SERIAL or -s SERIAL +Use the Android device with the given serial. Useful when more than one device is connected. You can list all of your connected devices with the command `$ adb devices`. + +It is also possible to set the serial by setting the environment variable `ANDROID_SERIAL`. Note that the `-s` option overrides `$ANDROID_SERIAL`. + ### --help or -h Print help / usage. diff --git a/scripts/install_apps.py b/scripts/install_apps.py index 7d647c786..934ac84ad 100755 --- a/scripts/install_apps.py +++ b/scripts/install_apps.py @@ -11,18 +11,21 @@ import tempfile import os import shutil +import shlex debug = False dry_run = False keep_files = False downgrade = False +serial = None -version = "1.2" +version = "1.2.1" # Version information: # 0.1 : Initial release # 1.0.1: Update to fix downgrade with no current app # 1.1 : Require python3, use shutil to resolve adb executable # 1.2 : Query apps instead of pulling apps database +# 1.2.1: Add -s argument to specify a device serial # def eprint(*args, **kwargs): @@ -43,12 +46,13 @@ def run_command(command, no_print=False): def print_help(): eprint('Usage: ' + os.path.basename(__file__) + ' [--debug] [--version] [--dry_run] [--keep] [--help] [--downgrade]') - eprint('\t--debug or -d : print extended debug information') - eprint('\t--version or -v : print version (and exit)') - eprint('\t--dry-run or -r : show actions but do not perform them (do not download or install APKs') - eprint('\t--keep or -k : keep temporary files (temp files are located under: {})'.format(tempfile.gettempdir())) - eprint('\t--downgrade or -o: only downgrade, if current version is less than installed version; do not update') - eprint('\t--help or -h : show this message (and exit)') + eprint(' --debug or -d : print extended debug information') + eprint(' --version or -v : print version (and exit)') + eprint(' --dry-run or -r : show actions but do not perform them (do not download or install APKs') + eprint(' --keep or -k : keep temporary files (temp files are located under: {})'.format(tempfile.gettempdir())) + eprint(' --downgrade or -o : only downgrade, if current version is less than installed version; do not update') + eprint(' --serial SERIAL or -s SERIAL: use device with given serial (overrides $ANDROID_SERIAL)') + eprint(' --help or -h : show this message (and exit)') def run_contains(command, s): return_code, lines = run_command(command, no_print=True) @@ -103,13 +107,15 @@ def main(argv): global dry_run global keep_files global downgrade + global serial try: - opts, args = getopt.getopt(argv, 'dvrkoh', ['debug', 'version', 'dry-run', 'keep', 'downgrade', 'help']) + opts, args = getopt.getopt( + argv, 'dvrkos:h', ['debug', 'version', 'dry-run', 'keep', 'downgrade', 'serial', 'help']) except getopt.GetoptError: print_help() sys.exit(2) - + for opt, arg in opts: if opt == '--help' or opt == '-h': print_help() @@ -125,11 +131,15 @@ def main(argv): sys.exit(0) if opt == '--downgrade' or opt == '-o': downgrade = True + if opt == '--serial' or opt == '-s': + serial = arg adb = shutil.which('adb') if debug: print("adb={}".format(adb)) if adb is None: sys.exit('"adb" command not found. Ensure it is in your path.') + if serial: + adb = '{} -s {}'.format(adb, shlex.quote(serial)) run_command('{} root'.format(adb)) diff --git a/versions.gradle b/versions.gradle index 092e6b69f..5614c8d5c 100644 --- a/versions.gradle +++ b/versions.gradle @@ -118,11 +118,14 @@ ext { HILT_VERSION = "2.44" // Calc version - CALC_VERSION = "2.1.0" + CALC_VERSION = "2.2.0" // Heap Analytics version HEAP_VERSION = "1.10.6" + // Rapid Deposit version + ANDROID_RAPID_DEPOSIT_VERSION = "1.0.0" + // Java 8+ API desugaring support // https://developer.android.com/studio/write/java8-support CORE_LIBRARY_DESUGARING_VERSION = "1.1.8"