22
33import android .os .Handler ;
44import android .os .Looper ;
5+
56import com .google .gson .Gson ;
67import com .google .gson .GsonBuilder ;
78import com .google .gson .JsonParseException ;
1213import java .io .IOException ;
1314import java .io .InputStream ;
1415import java .nio .charset .Charset ;
16+ import java .util .concurrent .CountDownLatch ;
1517
1618import io .snabble .sdk .utils .Logger ;
1719import okhttp3 .Call ;
@@ -50,6 +52,18 @@ private static class ApiWeighing {
5052 private String encodingUnit ;
5153 }
5254
55+ private static class ApiProductGroup {
56+ private ApiProduct [] products ;
57+ }
58+
59+ private interface ApiProductGroupCallback {
60+ void onProductsAvailable (Product [] products );
61+
62+ void onProductsNotFound ();
63+
64+ void onError ();
65+ }
66+
5367 private Gson gson ;
5468 private SnabbleSdk sdkInstance ;
5569 private OkHttpClient okHttpClient ;
@@ -128,6 +142,117 @@ public void findByWeighItemId(String weighItemId, final OnProductAvailableListen
128142 get (url , productAvailableListener );
129143 }
130144
145+ private void getBundlesOfProduct (final String sku , final ApiProductGroupCallback callback ) {
146+ String url = sdkInstance .getBundlesOfProductUrl ();
147+ if (url == null ) {
148+ Logger .e ("Could not check product bundles online, no bundlesOfProduct url provided in metadata" );
149+
150+ // return not found, so that normal product requests still work even when not bundle url is provided
151+ callback .onProductsNotFound ();
152+ return ;
153+ }
154+
155+ if (sku == null ) {
156+ callback .onProductsNotFound ();
157+ return ;
158+ }
159+
160+ url = url .replace ("{bundledSku}" , sku );
161+
162+ final Request request = new Request .Builder ()
163+ .url (sdkInstance .absoluteUrl (url ))
164+ .get ()
165+ .build ();
166+
167+ okHttpClient .newCall (request ).enqueue (new Callback () {
168+ @ Override
169+ public void onResponse (Call call , Response response ) throws IOException {
170+ if (response .isSuccessful ()) {
171+ ResponseBody body = response .body ();
172+ if (body == null ) {
173+ callback .onError ();
174+ return ;
175+ }
176+
177+ InputStream inputStream = body .byteStream ();
178+ String json = IOUtils .toString (inputStream , Charset .forName ("UTF-8" ));
179+ inputStream .close ();
180+
181+ try {
182+ final ApiProductGroup apiProductGroup = gson .fromJson (json , ApiProductGroup .class );
183+ if (apiProductGroup != null && apiProductGroup .products != null ) {
184+ final Product [] products = new Product [apiProductGroup .products .length ];
185+ final CountDownLatch countDownLatch = new CountDownLatch (apiProductGroup .products .length );
186+ final boolean [] error = new boolean [1 ];
187+
188+ for (int i = 0 ; i < apiProductGroup .products .length ; i ++) {
189+ final int index = i ;
190+ final ApiProduct apiProduct = apiProductGroup .products [i ];
191+
192+ getDepositProduct (apiProduct , new OnProductAvailableListener () {
193+ @ Override
194+ public void onProductAvailable (Product product , boolean wasOnlineProduct ) {
195+ countDownLatch .countDown ();
196+ products [index ] = toProduct (apiProduct , product , null );
197+ }
198+
199+ @ Override
200+ public void onProductNotFound () {
201+ countDownLatch .countDown ();
202+ error [1 ] = true ;
203+ }
204+
205+ @ Override
206+ public void onError () {
207+ countDownLatch .countDown ();
208+ error [1 ] = true ;
209+ }
210+ });
211+ }
212+
213+ countDownLatch .await ();
214+
215+ if (error [0 ]) {
216+ callback .onError ();
217+ } else {
218+ callback .onProductsAvailable (products );
219+ }
220+ } else {
221+ if (apiProductGroup != null ) {
222+ callback .onProductsNotFound ();
223+ } else {
224+ callback .onError ();
225+ }
226+ }
227+ } catch (JsonParseException e ) {
228+ callback .onError ();
229+ } catch (InterruptedException e ) {
230+ callback .onError ();
231+ }
232+ } else {
233+ if (response .code () == 404 ) {
234+ callback .onProductsNotFound ();
235+ } else {
236+ callback .onError ();
237+ }
238+ }
239+ }
240+
241+ @ Override
242+ public void onFailure (Call call , IOException e ) {
243+ callback .onError ();
244+ }
245+ });
246+ }
247+
248+ private void getDepositProduct (final ApiProduct apiProduct , final OnProductAvailableListener productAvailableListener ) {
249+ if (apiProduct .depositProduct != null && !apiProduct .depositProduct .equals ("" )) {
250+ findBySku (apiProduct .depositProduct , productAvailableListener );
251+ } else {
252+ productAvailableListener .onProductAvailable (null , true );
253+ }
254+ }
255+
131256 private void get (final String url , final OnProductAvailableListener productAvailableListener ) {
132257 final Request request = new Request .Builder ()
133258 .url (sdkInstance .absoluteUrl (url ))
@@ -155,88 +280,94 @@ public void run() {
155280
156281 try {
157282 final ApiProduct apiProduct = gson .fromJson (json , ApiProduct .class );
158- if (apiProduct .depositProduct != null && !apiProduct .depositProduct .equals ("" )) {
159- findBySku (apiProduct .depositProduct , new OnProductAvailableListener () {
160- @ Override
161- public void onProductAvailable (final Product product , boolean wasOnlineProduct ) {
162- handler .post (new Runnable () {
163- @ Override
164- public void run () {
165- productAvailableListener .onProductAvailable (toProduct (apiProduct , product ), true );
166- }
167- });
168- }
169-
170- @ Override
171- public void onProductNotFound () {
172- handler .post (new Runnable () {
173- @ Override
174- public void run () {
175- productAvailableListener .onProductNotFound ();
176- }
177- });
178- }
179-
180- @ Override
181- public void onError () {
182- handler .post (new Runnable () {
183- @ Override
184- public void run () {
185- productAvailableListener .onError ();
186- }
187- });
188- }
189- });
190- } else {
191- handler .post (new Runnable () {
192- @ Override
193- public void run () {
194- productAvailableListener .onProductAvailable (toProduct (apiProduct , null ), true );
195- }
196- });
197- }
198- } catch (JsonParseException e ) {
199- handler .post (new Runnable () {
283+ getDepositProduct (apiProduct , new OnProductAvailableListener () {
200284 @ Override
201- public void run () {
202- productAvailableListener .onError ();
285+ public void onProductAvailable (final Product product , boolean wasOnlineProduct ) {
286+ getBundlesOfProduct (apiProduct .sku , new ApiProductGroupCallback () {
287+ @ Override
288+ public void onProductsAvailable (final Product [] products ) {
289+ Product p = toProduct (apiProduct , product , products );
290+ success (productAvailableListener , p );
291+ }
292+
293+ @ Override
294+ public void onProductsNotFound () {
295+ Product p = toProduct (apiProduct , product , null );
296+ success (productAvailableListener , p );
297+ }
298+
299+ @ Override
300+ public void onError () {
301+ error (productAvailableListener );
302+ }
303+ });
304+ }
305+
306+ @ Override
307+ public void onProductNotFound () {
308+ notFound (productAvailableListener );
309+ }
310+
311+ @ Override
312+ public void onError () {
313+ error (productAvailableListener );
203314 }
204315 });
316+ } catch (JsonParseException e ) {
317+ error (productAvailableListener );
205318 }
206319 } else {
207- handler .post (new Runnable () {
208- @ Override
209- public void run () {
210- if (response .code () == 404 ) {
211- productAvailableListener .onProductNotFound ();
212- } else {
213- productAvailableListener .onError ();
214- }
215- }
216- });
320+ if (response .code () == 404 ) {
321+ notFound (productAvailableListener );
322+ } else {
323+ error (productAvailableListener );
324+ }
217325 }
218326 }
219327
220328 @ Override
221329 public void onFailure (Call call , IOException e ) {
222- handler .post (new Runnable () {
223- @ Override
224- public void run () {
225- productAvailableListener .onError ();
226- }
227- });
330+ error (productAvailableListener );
331+ }
332+ });
333+ }
334+
335+ private void success (final OnProductAvailableListener onProductAvailableListener , final Product product ) {
336+ handler .post (new Runnable () {
337+ @ Override
338+ public void run () {
339+ onProductAvailableListener .onProductAvailable (product , true );
340+ }
341+ });
342+ }
343+
344+ private void notFound (final OnProductAvailableListener onProductAvailableListener ) {
345+ handler .post (new Runnable () {
346+ @ Override
347+ public void run () {
348+ onProductAvailableListener .onProductNotFound ();
349+ }
350+ });
351+ }
352+
353+ private void error (final OnProductAvailableListener onProductAvailableListener ) {
354+ handler .post (new Runnable () {
355+ @ Override
356+ public void run () {
357+ onProductAvailableListener .onError ();
228358 }
229359 });
230360 }
231361
232- private Product toProduct (ApiProduct apiProduct , Product depositProduct ) {
362+ private Product toProduct (ApiProduct apiProduct , Product depositProduct , Product [] bundleProducts ) {
233363 Product .Builder builder = new Product .Builder ()
234364 .setSku (apiProduct .sku )
235365 .setName (apiProduct .name )
236366 .setDescription (apiProduct .description )
237367 .setSubtitle (apiProduct .subtitle )
238368 .setBoost (apiProduct .boost )
239369 .setDepositProduct (depositProduct )
370+ .setBundleProducts (bundleProducts )
240371 .setIsDeposit ("deposit" .equals (apiProduct .productType ))
241372 .setImageUrl (apiProduct .imageUrl )
242373 .setScannableCodes (apiProduct .eans )
@@ -252,7 +383,7 @@ private Product toProduct(ApiProduct apiProduct, Product depositProduct) {
252383 if (apiProduct .weighing .weighByCustomer ) {
253384 builder .setType (Product .Type .UserWeighed );
254385 } else {
255- if ("piece" .equals (apiProduct .weighing .encodingUnit )) {
386+ if ("piece" .equals (apiProduct .weighing .encodingUnit )) {
256387 builder .setType (Product .Type .Article );
257388 } else {
258389 builder .setType (Product .Type .PreWeighed );
0 commit comments