package bf.io.openshop.ux.fragments; import android.app.ProgressDialog; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.TextInputLayout; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import org.json.JSONException; import org.json.JSONObject; import java.util.List; import bf.io.openshop.CONST; import bf.io.openshop.MyApplication; import bf.io.openshop.R; import bf.io.openshop.SettingsMy; import bf.io.openshop.api.EndPoints; import bf.io.openshop.api.GsonRequest; import bf.io.openshop.entities.User; import bf.io.openshop.entities.cart.Cart; import bf.io.openshop.entities.cart.CartProductItem; import bf.io.openshop.entities.delivery.Delivery; import bf.io.openshop.entities.delivery.DeliveryRequest; import bf.io.openshop.entities.delivery.Payment; import bf.io.openshop.entities.delivery.Shipping; import bf.io.openshop.entities.order.Order; import bf.io.openshop.interfaces.PaymentDialogInterface; import bf.io.openshop.interfaces.ShippingDialogInterface; import bf.io.openshop.listeners.OnSingleClickListener; import bf.io.openshop.utils.Analytics; import bf.io.openshop.utils.JsonUtils; import bf.io.openshop.utils.MsgUtils; import bf.io.openshop.utils.Utils; import bf.io.openshop.ux.MainActivity; import bf.io.openshop.ux.dialogs.LoginExpiredDialogFragment; import bf.io.openshop.ux.dialogs.OrderCreateSuccessDialogFragment; import bf.io.openshop.ux.dialogs.PaymentDialogFragment; import bf.io.openshop.ux.dialogs.ShippingDialogFragment; import timber.log.Timber; /** * Fragment allowing the user to create order. */ public class OrderCreateFragment extends Fragment { public static final String MSG_LOGIN_EXPIRED_DIALOG_FRAGMENT = "loginExpiredDialogFragment"; private ProgressDialog progressDialog; private ScrollView scrollLayout; private LinearLayout cartItemsLayout; private Cart cart; private double orderTotalPrice; private TextView cartItemsTotalPrice; private TextView orderTotalPriceTv; // View with user information used to create order private TextInputLayout nameInputWrapper; private TextInputLayout streetInputWrapper; private TextInputLayout houseNumberInputWrapper; private TextInputLayout cityInputWrapper; private TextInputLayout zipInputWrapper; private TextInputLayout phoneInputWrapper; private TextInputLayout emailInputWrapper; private TextInputLayout noteInputWrapper; // Shipping and payment private Delivery delivery; private Payment selectedPayment; private Shipping selectedShipping; private ProgressBar deliveryProgressBar; private View deliveryShippingLayout; private View deliveryPaymentLayout; private TextView selectedShippingNameTv; private TextView selectedShippingPriceTv; private TextView selectedPaymentNameTv; private TextView selectedPaymentPriceTv; private GsonRequest<Order> postOrderRequest; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Timber.d("%s - onCreateView", this.getClass().getSimpleName()); MainActivity.setActionBarTitle(getString(R.string.Order_summary)); View view = inflater.inflate(R.layout.fragment_order_create, container, false); progressDialog = Utils.generateProgressDialog(getActivity(), false); scrollLayout = (ScrollView) view.findViewById(R.id.order_create_scroll_layout); cartItemsLayout = (LinearLayout) view.findViewById(R.id.order_create_cart_items_layout); cartItemsTotalPrice = (TextView) view.findViewById(R.id.order_create_total_price); orderTotalPriceTv = (TextView) view.findViewById(R.id.order_create_summary_total_price); TextView termsAndConditionsTv = (TextView) view.findViewById(R.id.order_create_summary_terms_and_condition); termsAndConditionsTv.setText(Html.fromHtml(getString(R.string.Click_on_Order_to_allow_our_Terms_and_Conditions))); termsAndConditionsTv.setOnClickListener(new OnSingleClickListener() { @Override public void onSingleClick(View view) { if (getActivity() instanceof MainActivity) ((MainActivity) getActivity()).onTermsAndConditionsSelected(); } }); prepareFields(view); prepareDeliveryLayout(view); Button finishOrder = (Button) view.findViewById(R.id.order_create_finish); finishOrder.setOnClickListener(new OnSingleClickListener() { @Override public void onSingleClick(View v) { if (isRequiredFieldsOk()) { // Prepare data Order order = new Order(); order.setName(Utils.getTextFromInputLayout(nameInputWrapper)); order.setCity(Utils.getTextFromInputLayout(cityInputWrapper)); order.setStreet(Utils.getTextFromInputLayout(streetInputWrapper)); order.setHouseNumber(Utils.getTextFromInputLayout(houseNumberInputWrapper)); order.setZip(Utils.getTextFromInputLayout(zipInputWrapper)); order.setEmail(Utils.getTextFromInputLayout(emailInputWrapper)); order.setShippingType(selectedShipping.getId()); if (selectedPayment != null) { order.setPaymentType(selectedPayment.getId()); } else { order.setPaymentType(-1); } order.setPhone(Utils.getTextFromInputLayout(phoneInputWrapper)); order.setNote(Utils.getTextFromInputLayout(noteInputWrapper)); // Hide keyboard v.clearFocus(); InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); postOrder(order); } } }); showSelectedShipping(selectedShipping); showSelectedPayment(selectedPayment); getUserCart(); return view; } /** * Prepare content views, adapters and listeners. * * @param view fragment base view. */ private void prepareFields(View view) { nameInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_name_wrapper); streetInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_street_wrapper); houseNumberInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_houseNumber_wrapper); cityInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_city_wrapper); zipInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_zip_wrapper); phoneInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_phone_wrapper); emailInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_email_wrapper); noteInputWrapper = (TextInputLayout) view.findViewById(R.id.order_create_note_wrapper); User user = SettingsMy.getActiveUser(); if (user != null) { Utils.setTextToInputLayout(nameInputWrapper, user.getName()); Utils.setTextToInputLayout(streetInputWrapper, user.getStreet()); Utils.setTextToInputLayout(houseNumberInputWrapper, user.getHouseNumber()); Utils.setTextToInputLayout(cityInputWrapper, user.getCity()); Utils.setTextToInputLayout(zipInputWrapper, user.getZip()); Utils.setTextToInputLayout(emailInputWrapper, user.getEmail()); Utils.setTextToInputLayout(phoneInputWrapper, user.getPhone()); } else { LoginExpiredDialogFragment loginExpiredDialogFragment = new LoginExpiredDialogFragment(); loginExpiredDialogFragment.show(getFragmentManager(), MSG_LOGIN_EXPIRED_DIALOG_FRAGMENT); } } /** * Check if all input fields are filled and also that is selected shipping and payment. * Method highlights all unfilled input fields. * * @return true if everything is Ok. */ private boolean isRequiredFieldsOk() { // Check and show all missing values String fieldRequired = getString(R.string.Required_field); boolean nameCheck = Utils.checkTextInputLayoutValueRequirement(nameInputWrapper, fieldRequired); boolean streetCheck = Utils.checkTextInputLayoutValueRequirement(streetInputWrapper, fieldRequired); boolean houseNumberCheck = Utils.checkTextInputLayoutValueRequirement(houseNumberInputWrapper, fieldRequired); boolean cityCheck = Utils.checkTextInputLayoutValueRequirement(cityInputWrapper, fieldRequired); boolean zipCheck = Utils.checkTextInputLayoutValueRequirement(zipInputWrapper, fieldRequired); boolean phoneCheck = Utils.checkTextInputLayoutValueRequirement(phoneInputWrapper, fieldRequired); boolean emailCheck = Utils.checkTextInputLayoutValueRequirement(emailInputWrapper, fieldRequired); if (nameCheck && streetCheck && houseNumberCheck && cityCheck && zipCheck && phoneCheck && emailCheck) { // Check if shipping and payment is selected if (selectedShipping == null) { MsgUtils.showToast(getActivity(), MsgUtils.TOAST_TYPE_MESSAGE, getString(R.string.Choose_shipping_method), MsgUtils.ToastLength.SHORT); scrollLayout.smoothScrollTo(0, deliveryShippingLayout.getTop()); return false; } if (selectedPayment == null) { MsgUtils.showToast(getActivity(), MsgUtils.TOAST_TYPE_MESSAGE, getString(R.string.Choose_payment_method), MsgUtils.ToastLength.SHORT); scrollLayout.smoothScrollTo(0, deliveryShippingLayout.getTop()); return false; } return true; } else { return false; } } private void prepareDeliveryLayout(View view) { deliveryProgressBar = (ProgressBar) view.findViewById(R.id.delivery_progress); // final View deliveryShippingBtn = view.findViewById(R.id.order_create_delivery_shipping_button); // final View deliveryPaymentBtn = view.findViewById(R.id.order_create_delivery_payment_button); this.deliveryShippingLayout = view.findViewById(R.id.order_create_delivery_shipping_layout); this.deliveryPaymentLayout = view.findViewById(R.id.order_create_delivery_payment_layout); selectedShippingNameTv = (TextView) view.findViewById(R.id.order_create_delivery_shipping_name); selectedShippingPriceTv = (TextView) view.findViewById(R.id.order_create_delivery_shipping_price); selectedPaymentNameTv = (TextView) view.findViewById(R.id.order_create_delivery_payment_name); selectedPaymentPriceTv = (TextView) view.findViewById(R.id.order_create_delivery_payment_price); deliveryShippingLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ShippingDialogFragment shippingDialogFragment = ShippingDialogFragment.newInstance(delivery, selectedShipping, new ShippingDialogInterface() { @Override public void onShippingSelected(Shipping shipping) { // Save selected value selectedShipping = shipping; // Update shipping related values showSelectedShipping(shipping); // Continue for payment selectedPayment = null; selectedPaymentNameTv.setText(getString(R.string.Choose_payment_method)); selectedPaymentPriceTv.setText(""); deliveryPaymentLayout.performClick(); } }); shippingDialogFragment.show(getFragmentManager(), ShippingDialogFragment.class.getSimpleName()); } }); deliveryPaymentLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { PaymentDialogFragment paymentDialogFragment = PaymentDialogFragment.newInstance(selectedShipping, selectedPayment, new PaymentDialogInterface() { @Override public void onPaymentSelected(Payment payment) { selectedPayment = payment; showSelectedPayment(payment); } }); paymentDialogFragment.show(getFragmentManager(), "PaymentDialog"); } }); } /** * Show and update shipping related values. * * @param shipping values to show. */ private void showSelectedShipping(Shipping shipping) { if (shipping != null && selectedShippingNameTv != null && selectedShippingPriceTv != null) { selectedShippingNameTv.setText(shipping.getName()); if (shipping.getPrice() != 0) { selectedShippingPriceTv.setText(shipping.getPriceFormatted()); } else { selectedShippingPriceTv.setText(getText(R.string.free)); } // Set total order price orderTotalPrice = shipping.getTotalPrice(); orderTotalPriceTv.setText(shipping.getTotalPriceFormatted()); deliveryPaymentLayout.setVisibility(View.VISIBLE); } else { Timber.e("Showing selected shipping with null values."); } } /** * Show and update payment related values. * * @param payment values to show. */ private void showSelectedPayment(Payment payment) { if (payment != null && selectedPaymentNameTv != null && selectedPaymentPriceTv != null) { selectedPaymentNameTv.setText(payment.getName()); if (payment.getPrice() != 0) { selectedPaymentPriceTv.setText(payment.getPriceFormatted()); } else { selectedPaymentPriceTv.setText(getText(R.string.free)); } // Set total order price orderTotalPrice = payment.getTotalPrice(); orderTotalPriceTv.setText(payment.getTotalPriceFormatted()); } else { Timber.e("Showing selected payment with null values."); } } private void getUserCart() { final User user = SettingsMy.getActiveUser(); if (user != null) { String url = String.format(EndPoints.CART, SettingsMy.getActualNonNullShop(getActivity()).getId()); progressDialog.show(); GsonRequest<Cart> getCart = new GsonRequest<>(Request.Method.GET, url, null, Cart.class, new Response.Listener<Cart>() { @Override public void onResponse(@NonNull Cart cart) { if (progressDialog != null) progressDialog.cancel(); refreshScreenContent(cart, user); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (progressDialog != null) progressDialog.cancel(); Timber.e("Get request cart error: %s", error.getMessage()); MsgUtils.logAndShowErrorMessage(getActivity(), error); if (getActivity() instanceof MainActivity) ((MainActivity) getActivity()).onDrawerBannersSelected(); } }, getFragmentManager(), user.getAccessToken()); getCart.setRetryPolicy(MyApplication.getDefaultRetryPolice()); getCart.setShouldCache(false); MyApplication.getInstance().addToRequestQueue(getCart, CONST.ORDER_CREATE_REQUESTS_TAG); } else { LoginExpiredDialogFragment loginExpiredDialogFragment = new LoginExpiredDialogFragment(); loginExpiredDialogFragment.show(getFragmentManager(), MSG_LOGIN_EXPIRED_DIALOG_FRAGMENT); } } private void refreshScreenContent(@NonNull Cart cart, User user) { this.cart = cart; List<CartProductItem> cartProductItems = cart.getItems(); if (cartProductItems == null || cartProductItems.isEmpty()) { Timber.e(new RuntimeException(), "Received null cart during order creation."); if (getActivity() instanceof MainActivity) ((MainActivity) getActivity()).onDrawerBannersSelected(); } else { LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); for (int i = 0; i < cartProductItems.size(); i++) { LinearLayout llRow = (LinearLayout) inflater.inflate(R.layout.order_create_cart_item, cartItemsLayout, false); TextView tvItemName = (TextView) llRow.findViewById(R.id.order_create_cart_item_name); tvItemName.setText(cartProductItems.get(i).getVariant().getName()); TextView tvItemPrice = (TextView) llRow.findViewById(R.id.order_create_cart_item_price); tvItemPrice.setText(cartProductItems.get(i).getTotalItemPriceFormatted()); TextView tvItemQuantity = (TextView) llRow.findViewById(R.id.order_create_cart_item_quantity); tvItemQuantity.setText(getString(R.string.format_quantity, cartProductItems.get(i).getQuantity())); TextView tvItemDetails = (TextView) llRow.findViewById(R.id.order_create_cart_item_details); tvItemDetails.setText(getString(R.string.format_string_division, cartProductItems.get(i).getVariant().getColor().getValue(), cartProductItems.get(i).getVariant().getSize().getValue())); cartItemsLayout.addView(llRow); } if (cart.getDiscounts() != null) { for (int i = 0; i < cart.getDiscounts().size(); i++) { LinearLayout llRow = (LinearLayout) inflater.inflate(R.layout.order_create_cart_item, cartItemsLayout, false); TextView tvItemName = (TextView) llRow.findViewById(R.id.order_create_cart_item_name); TextView tvItemPrice = (TextView) llRow.findViewById(R.id.order_create_cart_item_price); tvItemName.setText(cart.getDiscounts().get(i).getDiscount().getName()); tvItemPrice.setText(cart.getDiscounts().get(i).getDiscount().getValueFormatted()); tvItemPrice.setTextColor(ContextCompat.getColor(getContext(), R.color.colorAccent)); cartItemsLayout.addView(llRow); } } cartItemsTotalPrice.setText(cart.getTotalPriceFormatted()); orderTotalPriceTv.setText(cart.getTotalPriceFormatted()); // TODO pull to scroll could be cool here String url = String.format(EndPoints.CART_DELIVERY_INFO, SettingsMy.getActualNonNullShop(getActivity()).getId()); deliveryProgressBar.setVisibility(View.VISIBLE); GsonRequest<DeliveryRequest> getDelivery = new GsonRequest<>(Request.Method.GET, url, null, DeliveryRequest.class, new Response.Listener<DeliveryRequest>() { @Override public void onResponse(@NonNull DeliveryRequest deliveryResp) { Timber.d("GetDelivery: %s", deliveryResp.toString()); delivery = deliveryResp.getDelivery(); deliveryProgressBar.setVisibility(View.GONE); deliveryShippingLayout.setVisibility(View.VISIBLE); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Timber.e("Get request cart error: %s", error.getMessage()); MsgUtils.logAndShowErrorMessage(getActivity(), error); deliveryProgressBar.setVisibility(View.GONE); if (getActivity() instanceof MainActivity) ((MainActivity) getActivity()).onDrawerBannersSelected(); } }, getFragmentManager(), user.getAccessToken()); getDelivery.setRetryPolicy(MyApplication.getDefaultRetryPolice()); getDelivery.setShouldCache(false); MyApplication.getInstance().addToRequestQueue(getDelivery, CONST.ORDER_CREATE_REQUESTS_TAG); } } private void postOrder(final Order order) { final User user = SettingsMy.getActiveUser(); if (user != null) { JSONObject jo; try { jo = JsonUtils.createOrderJson(order); } catch (JSONException e) { Timber.e(e, "Post order Json exception."); MsgUtils.showToast(getActivity(), MsgUtils.TOAST_TYPE_INTERNAL_ERROR, null, MsgUtils.ToastLength.SHORT); return; } Timber.d("Post order jo: %s", jo.toString()); String url = String.format(EndPoints.ORDERS, SettingsMy.getActualNonNullShop(getActivity()).getId()); progressDialog.show(); postOrderRequest = new GsonRequest<>(Request.Method.POST, url, jo.toString(), Order.class, new Response.Listener<Order>() { @Override public void onResponse(Order order) { Timber.d("response: %s", order.toString()); progressDialog.cancel(); Analytics.logOrderCreatedEvent(cart, order.getRemoteId(), orderTotalPrice, selectedShipping); updateUserData(user, order); MainActivity.updateCartCountNotification(); DialogFragment thankYouDF = OrderCreateSuccessDialogFragment.newInstance(false); thankYouDF.show(getFragmentManager(), OrderCreateSuccessDialogFragment.class.getSimpleName()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { progressDialog.cancel(); // Return 501 for sample application. if (postOrderRequest != null && postOrderRequest.getStatusCode() == 501) { DialogFragment thankYouDF = OrderCreateSuccessDialogFragment.newInstance(true); thankYouDF.show(getFragmentManager(), OrderCreateSuccessDialogFragment.class.getSimpleName()); } else { MsgUtils.logAndShowErrorMessage(getActivity(), error); } } }, getFragmentManager(), user.getAccessToken()); postOrderRequest.setRetryPolicy(MyApplication.getDefaultRetryPolice()); postOrderRequest.setShouldCache(false); MyApplication.getInstance().addToRequestQueue(postOrderRequest, CONST.ORDER_CREATE_REQUESTS_TAG); } else { LoginExpiredDialogFragment loginExpiredDialogFragment = new LoginExpiredDialogFragment(); loginExpiredDialogFragment.show(getFragmentManager(), MSG_LOGIN_EXPIRED_DIALOG_FRAGMENT); } } /** * Update user information after successful order. * * @param user actual user which will be updated * @param order order response for obtain user information */ private void updateUserData(User user, Order order) { if (user != null) { if (order.getName() != null && !order.getName().isEmpty()) { user.setName(order.getName()); } user.setEmail(order.getEmail()); user.setPhone(order.getPhone()); user.setCity(order.getCity()); user.setStreet(order.getStreet()); user.setZip(order.getZip()); user.setHouseNumber(order.getHouseNumber()); SettingsMy.setActiveUser(user); } else { Timber.e(new NullPointerException(), "Null user after successful order."); } } @Override public void onStop() { super.onStop(); MyApplication.getInstance().cancelPendingRequests(CONST.ORDER_CREATE_REQUESTS_TAG); if (progressDialog != null) progressDialog.cancel(); if (deliveryProgressBar != null) deliveryProgressBar.setVisibility(View.GONE); } }