Skip to content

Commit 6b1bfe7

Browse files
authored
Customizable isMergeable behavior (#100)
Make the `ShoppingCart::isMergeable()` behavior customizable for users of the SDK.
1 parent 1eb15ef commit 6b1bfe7

File tree

3 files changed

+68
-28
lines changed

3 files changed

+68
-28
lines changed

core/src/main/java/io/snabble/sdk/ShoppingCart.java

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
import io.snabble.sdk.codes.templates.CodeTemplate;
3030
import io.snabble.sdk.coupons.Coupon;
3131
import io.snabble.sdk.coupons.CouponType;
32+
import io.snabble.sdk.customization.IsMergeable;
3233
import io.snabble.sdk.utils.Dispatch;
3334
import io.snabble.sdk.utils.GsonHolder;
34-
import io.snabble.sdk.utils.Logger;
3535

3636
/**
3737
* Class representing the snabble shopping cart
@@ -232,7 +232,7 @@ public Iterator<Item> iterator() {
232232
/**
233233
* Returns a cart item that contains the given product, if that cart item
234234
* can be merged.
235-
*
235+
* <p>
236236
* A cart item is not mergeable if it uses encoded data of a scanned code (e.g. a different price)
237237
*/
238238
public Item getExistingMergeableProduct(Product product) {
@@ -288,7 +288,7 @@ public void remove(int index) {
288288

289289
/**
290290
* The number items in the cart.
291-
*
291+
* <p>
292292
* This is not the sum of articles.
293293
*/
294294
public int size() {
@@ -304,7 +304,7 @@ public boolean isEmpty() {
304304

305305
/**
306306
* Backups the cart, so it can be restured using {@link #restore()} later.
307-
*
307+
* <p>
308308
* A cart is restorable for up to 5 minutes.
309309
*/
310310
public void backup() {
@@ -336,7 +336,7 @@ public void restore() {
336336
if (isRestorable()) {
337337
data = oldData;
338338
data.applyShoppingCart(this);
339-
339+
340340
clearBackup();
341341
checkLimits();
342342
updatePrices(false);
@@ -346,6 +346,7 @@ public void restore() {
346346

347347
/**
348348
* The last time the cart was backed up by using {@link #backup()}
349+
*
349350
* @return
350351
*/
351352
public long getBackupTimestamp() {
@@ -481,10 +482,10 @@ public int getModCount() {
481482

482483
/**
483484
* Generate a new uuid.
484-
*
485+
* <p>
485486
* UUID's are used to uniquely identify a specific purchase made by the user. If a new UUID
486487
* is generated a new checkout can be made.
487-
*
488+
* <p>
488489
* If a checkout already exist with the same UUID, the checkout will get continued.
489490
*/
490491
public void generateNewUUID() {
@@ -494,10 +495,10 @@ public void generateNewUUID() {
494495

495496
/**
496497
* The UUID of the cart
497-
*
498+
* <p>
498499
* UUID's are used to uniquely identify a specific purchase made by the user. If a new UUID
499500
* is generated a new checkout can be made.
500-
*
501+
* <p>
501502
* If a checkout already exist with the same UUID, the checkout will get continued.
502503
*/
503504
public String getUUID() {
@@ -540,7 +541,7 @@ public boolean hasInvalidDepositReturnVoucher() {
540541

541542
/**
542543
* Returns the total price of the cart.
543-
*
544+
* <p>
544545
* If the cart was updated by the backend, the online price is used. If no update was made
545546
* a locally calculated price will be used
546547
*/
@@ -923,15 +924,24 @@ public boolean isEditableInDialog() {
923924
* Returns true if the item can be merged with items that conain the same product and type
924925
*/
925926
public boolean isMergeable() {
927+
@Nullable final IsMergeable isMergeableOverride = Snabble.getInstance().isMergeable();
928+
final boolean isMergeable = isMergeableDefault();
929+
if (isMergeableOverride == null) {
930+
return isMergeable;
931+
} else {
932+
return isMergeableOverride.isMergeable(this, isMergeable);
933+
}
934+
}
935+
936+
private boolean isMergeableDefault() {
926937
if (product == null && lineItem != null) return false;
927938
if (coupon != null) return false;
928939

929-
boolean b = product.getType() == Product.Type.Article
940+
return product.getType() == Product.Type.Article
930941
&& getUnit() != PIECE
931942
&& product.getPrice(cart.project.getCustomerCardId()) != 0
932943
&& scannedCode.getEmbeddedData() == 0
933944
&& !isUsingSpecifiedQuantity;
934-
return b;
935945
}
936946

937947
/**
@@ -1043,7 +1053,7 @@ public String getDisplayName() {
10431053

10441054
/**
10451055
* Gets text displaying quantity, can be a weight or price depending on the type
1046-
*
1056+
* <p>
10471057
* E.g. "1" or "100g" or "2,03 €"
10481058
*/
10491059
public String getQuantityText() {
@@ -1070,7 +1080,7 @@ public String getQuantityText() {
10701080

10711081
/**
10721082
* Gets text displaying price, including the calculation.
1073-
*
1083+
* <p>
10741084
* E.g. "2 * 3,99 € = 7,98 €"
10751085
*/
10761086
public String getFullPriceText() {
@@ -1115,7 +1125,7 @@ public String getTotalPriceText() {
11151125

11161126
/**
11171127
* Gets text displaying price, including the calculation.
1118-
*
1128+
* <p>
11191129
* E.g. "3,99 €" or "2,99 € /kg = 0,47 €"
11201130
*/
11211131
public String getPriceText() {
@@ -1530,13 +1540,16 @@ public void onTaxationChanged(ShoppingCart list, Taxation taxation) {
15301540
}
15311541

15321542
@Override
1533-
public void onCheckoutLimitReached(ShoppingCart list) {}
1543+
public void onCheckoutLimitReached(ShoppingCart list) {
1544+
}
15341545

15351546
@Override
1536-
public void onOnlinePaymentLimitReached(ShoppingCart list) {}
1547+
public void onOnlinePaymentLimitReached(ShoppingCart list) {
1548+
}
15371549

15381550
@Override
1539-
public void onViolationDetected(@NonNull List<ViolationNotification> violations) {}
1551+
public void onViolationDetected(@NonNull List<ViolationNotification> violations) {
1552+
}
15401553

15411554
@Override
15421555
public void onCartDataChanged(ShoppingCart list) {
@@ -1648,4 +1661,4 @@ private void notifyCleared(final ShoppingCart list) {
16481661
}
16491662
});
16501663
}
1651-
}
1664+
}

core/src/main/java/io/snabble/sdk/Snabble.kt

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.google.gson.JsonObject
1717
import io.snabble.sdk.auth.TokenRegistry
1818
import io.snabble.sdk.checkin.CheckInLocationManager
1919
import io.snabble.sdk.checkin.CheckInManager
20+
import io.snabble.sdk.customization.IsMergeable
2021
import io.snabble.sdk.payment.PaymentCredentialsStore
2122
import io.snabble.sdk.utils.*
2223
import okhttp3.OkHttpClient
@@ -36,6 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean
3637
* The heart of the snabble SDK. Initialization and object access is provided via this facade.
3738
*/
3839
object Snabble {
40+
3941
/**
4042
* Retrieve the global instance of snabble.
4143
*
@@ -303,7 +305,12 @@ object Snabble {
303305
*/
304306
var error: Error? = null
305307
private set
306-
308+
309+
/**
310+
* Set to take control over [ShoppingCart.Item.isMergeable] default behavior.
311+
*/
312+
var isMergeable: IsMergeable? = null
313+
307314
/**
308315
* Setup the snabble SDK.
309316
*
@@ -355,7 +362,8 @@ object Snabble {
355362
Logger.setLogEventHandler { message, args -> Events.logErrorEvent(null, message, *args) }
356363

357364
if (!this.config.endpointBaseUrl.startsWith("http://")
358-
&& !this.config.endpointBaseUrl.startsWith("https://")) {
365+
&& !this.config.endpointBaseUrl.startsWith("https://")
366+
) {
359367
dispatchError(Error.CONFIG_ERROR)
360368
return
361369
}
@@ -382,14 +390,16 @@ object Snabble {
382390
paymentCredentialsStore = PaymentCredentialsStore()
383391

384392
checkInLocationManager = CheckInLocationManager(application)
385-
checkInManager = CheckInManager(this,
393+
checkInManager = CheckInManager(
394+
this,
386395
checkInLocationManager,
387396
this.config.checkInRadius,
388397
this.config.checkOutRadius,
389398
this.config.lastSeenThreshold
390399
)
391400

392-
metadataDownloader = MetadataDownloader(okHttpClient, this.config.bundledMetadataAssetPath, this.config.bundledMetadataRawResId)
401+
metadataDownloader =
402+
MetadataDownloader(okHttpClient, this.config.bundledMetadataAssetPath, this.config.bundledMetadataRawResId)
393403

394404
if (this.config.bundledMetadataAssetPath != null || this.config.bundledMetadataRawResId != 0) {
395405
dispatchOnReady()
@@ -478,10 +488,12 @@ object Snabble {
478488

479489
private fun registerNetworkCallback(app: Application) {
480490
val cm = app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
481-
cm.registerNetworkCallback(NetworkRequest.Builder()
482-
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
483-
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(),
484-
networkCallback)
491+
cm.registerNetworkCallback(
492+
NetworkRequest.Builder()
493+
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
494+
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(),
495+
networkCallback
496+
)
485497
}
486498

487499
/**
@@ -708,6 +720,7 @@ object Snabble {
708720
* Interface for notifying when our metadata is getting updated
709721
*/
710722
fun interface OnMetadataUpdateListener {
723+
711724
/**
712725
* Gets called when our metadata has updated
713726
*/
@@ -760,6 +773,7 @@ object Snabble {
760773
* Exception used for SDK initialization errors
761774
*/
762775
class SnabbleException internal constructor(val error: Error?) : Exception() {
776+
763777
override fun toString(): String {
764778
return "SnabbleException{" +
765779
"error=" + error +
@@ -771,6 +785,7 @@ object Snabble {
771785
* Enum describing the error types, which can occur during initialization of the SDK
772786
*/
773787
enum class Error {
788+
774789
UNSPECIFIED_ERROR,
775790
NO_APPLICATION_SET,
776791
CONFIG_ERROR,
@@ -784,4 +799,4 @@ object Snabble {
784799
fun setDebugLoggingEnabled(enabled: Boolean) {
785800
Logger.setEnabled(enabled)
786801
}
787-
}
802+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.snabble.sdk.customization
2+
3+
import io.snabble.sdk.ShoppingCart
4+
5+
/**
6+
* Implement the interface and set [Snabble.isMergeable] to make use of the
7+
* custom ShoppingCart.Item.isMergeable implementation
8+
*/
9+
fun interface IsMergeable {
10+
11+
fun isMergeable(item: ShoppingCart.Item, isMergeable: Boolean): Boolean
12+
}

0 commit comments

Comments
 (0)