1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.shopping.util;
16  
17  import com.liferay.portal.kernel.exception.PortalException;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.language.LanguageUtil;
20  import com.liferay.portal.kernel.portlet.LiferayWindowState;
21  import com.liferay.portal.kernel.util.Constants;
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.HttpUtil;
24  import com.liferay.portal.kernel.util.MathUtil;
25  import com.liferay.portal.kernel.util.OrderByComparator;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.theme.ThemeDisplay;
30  import com.liferay.portal.util.WebKeys;
31  import com.liferay.portlet.shopping.NoSuchCartException;
32  import com.liferay.portlet.shopping.model.ShoppingCart;
33  import com.liferay.portlet.shopping.model.ShoppingCartItem;
34  import com.liferay.portlet.shopping.model.ShoppingCategory;
35  import com.liferay.portlet.shopping.model.ShoppingCoupon;
36  import com.liferay.portlet.shopping.model.ShoppingCouponConstants;
37  import com.liferay.portlet.shopping.model.ShoppingItem;
38  import com.liferay.portlet.shopping.model.ShoppingItemField;
39  import com.liferay.portlet.shopping.model.ShoppingItemPrice;
40  import com.liferay.portlet.shopping.model.ShoppingItemPriceConstants;
41  import com.liferay.portlet.shopping.model.ShoppingOrder;
42  import com.liferay.portlet.shopping.model.ShoppingOrderConstants;
43  import com.liferay.portlet.shopping.model.ShoppingOrderItem;
44  import com.liferay.portlet.shopping.model.impl.ShoppingCartImpl;
45  import com.liferay.portlet.shopping.service.ShoppingCartLocalServiceUtil;
46  import com.liferay.portlet.shopping.service.ShoppingCategoryLocalServiceUtil;
47  import com.liferay.portlet.shopping.service.ShoppingOrderItemLocalServiceUtil;
48  import com.liferay.portlet.shopping.service.persistence.ShoppingItemPriceUtil;
49  import com.liferay.portlet.shopping.util.comparator.ItemMinQuantityComparator;
50  import com.liferay.portlet.shopping.util.comparator.ItemNameComparator;
51  import com.liferay.portlet.shopping.util.comparator.ItemPriceComparator;
52  import com.liferay.portlet.shopping.util.comparator.ItemSKUComparator;
53  import com.liferay.portlet.shopping.util.comparator.OrderDateComparator;
54  
55  import java.text.NumberFormat;
56  
57  import java.util.ArrayList;
58  import java.util.HashMap;
59  import java.util.HashSet;
60  import java.util.Iterator;
61  import java.util.List;
62  import java.util.Locale;
63  import java.util.Map;
64  import java.util.Set;
65  
66  import javax.portlet.PortletRequest;
67  import javax.portlet.PortletSession;
68  import javax.portlet.PortletURL;
69  import javax.portlet.RenderRequest;
70  import javax.portlet.RenderResponse;
71  import javax.portlet.WindowState;
72  
73  import javax.servlet.jsp.PageContext;
74  
75  /**
76   * <a href="ShoppingUtil.java.html"><b><i>View Source</i></b></a>
77   *
78   * @author Brian Wing Shun Chan
79   */
80  public class ShoppingUtil {
81  
82      public static double calculateActualPrice(ShoppingItem item) {
83          return item.getPrice() - calculateDiscountPrice(item);
84      }
85  
86      public static double calculateActualPrice(ShoppingItem item, int count)
87          throws PortalException, SystemException {
88  
89          return calculatePrice(item, count) -
90              calculateDiscountPrice(item, count);
91      }
92  
93      public static double calculateActualPrice(ShoppingItemPrice itemPrice) {
94          return itemPrice.getPrice() - calculateDiscountPrice(itemPrice);
95      }
96  
97      public static double calculateActualSubtotal(
98              Map<ShoppingCartItem, Integer> items)
99          throws PortalException, SystemException {
100 
101         return calculateSubtotal(items) - calculateDiscountSubtotal(items);
102     }
103 
104     public static double calculateActualSubtotal(
105         List<ShoppingOrderItem> orderItems) {
106 
107         double subtotal = 0.0;
108 
109         for (ShoppingOrderItem orderItem : orderItems) {
110             subtotal += orderItem.getPrice() * orderItem.getQuantity();
111         }
112 
113         return subtotal;
114     }
115 
116     public static double calculateAlternativeShipping(
117             Map<ShoppingCartItem, Integer> items, int altShipping)
118         throws PortalException, SystemException {
119 
120         double shipping = calculateShipping(items);
121         double alternativeShipping = shipping;
122 
123         ShoppingPreferences preferences = null;
124 
125         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
126             items.entrySet().iterator();
127 
128         while (itr.hasNext()) {
129             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
130 
131             ShoppingCartItem cartItem = entry.getKey();
132 
133             ShoppingItem item = cartItem.getItem();
134 
135             if (preferences == null) {
136                 ShoppingCategory category = item.getCategory();
137 
138                 preferences = ShoppingPreferences.getInstance(
139                     category.getCompanyId(), category.getGroupId());
140 
141                 break;
142             }
143         }
144 
145         // Calculate alternative shipping if shopping is configured to use
146         // alternative shipping and shipping price is greater than 0
147 
148         if ((preferences != null) &&
149             (preferences.useAlternativeShipping()) && (shipping > 0)) {
150 
151             double altShippingDelta = 0.0;
152 
153             try {
154                 altShippingDelta = GetterUtil.getDouble(
155                     preferences.getAlternativeShipping()[1][altShipping]);
156             }
157             catch (Exception e) {
158                 return alternativeShipping;
159             }
160 
161             if (altShippingDelta > 0) {
162                 alternativeShipping = shipping * altShippingDelta;
163             }
164         }
165 
166         return alternativeShipping;
167     }
168 
169     public static double calculateCouponDiscount(
170             Map<ShoppingCartItem, Integer> items, ShoppingCoupon coupon)
171         throws PortalException, SystemException {
172 
173         return calculateCouponDiscount(items, null, coupon);
174     }
175 
176     public static double calculateCouponDiscount(
177             Map<ShoppingCartItem, Integer> items, String stateId,
178             ShoppingCoupon coupon)
179         throws PortalException, SystemException {
180 
181         double discount = 0.0;
182 
183         if ((coupon == null) || !coupon.isActive() ||
184             !coupon.hasValidDateRange()) {
185 
186             return discount;
187         }
188 
189         String[] categoryIds = StringUtil.split(coupon.getLimitCategories());
190         String[] skus = StringUtil.split(coupon.getLimitSkus());
191 
192         if ((categoryIds.length > 0) || (skus.length > 0)) {
193             Set<String> categoryIdsSet = new HashSet<String>();
194 
195             for (String categoryId : categoryIds) {
196                 categoryIdsSet.add(categoryId);
197             }
198 
199             Set<String> skusSet = new HashSet<String>();
200 
201             for (String sku : skus) {
202                 skusSet.add(sku);
203             }
204 
205             Map<ShoppingCartItem, Integer> newItems =
206                 new HashMap<ShoppingCartItem, Integer>();
207 
208             Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
209                 items.entrySet().iterator();
210 
211             while (itr.hasNext()) {
212                 Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
213 
214                 ShoppingCartItem cartItem = entry.getKey();
215                 Integer count = entry.getValue();
216 
217                 ShoppingItem item = cartItem.getItem();
218 
219                 if (((categoryIdsSet.size() > 0) &&
220                      (categoryIdsSet.contains(
221                         new Long(item.getCategoryId())))) ||
222                     ((skusSet.size() > 0) &&
223                      (skusSet.contains(item.getSku())))) {
224 
225                     newItems.put(cartItem, count);
226                 }
227             }
228 
229             items = newItems;
230         }
231 
232         double actualSubtotal = calculateActualSubtotal(items);
233 
234         if ((coupon.getMinOrder() > 0) &&
235             (coupon.getMinOrder() > actualSubtotal)) {
236 
237             return discount;
238         }
239 
240         String type = coupon.getDiscountType();
241 
242         if (type.equals(ShoppingCouponConstants.DISCOUNT_TYPE_PERCENTAGE)) {
243             discount = actualSubtotal * coupon.getDiscount();
244         }
245         else if (type.equals(ShoppingCouponConstants.DISCOUNT_TYPE_ACTUAL)) {
246             discount = coupon.getDiscount();
247         }
248         else if (type.equals(
249                     ShoppingCouponConstants.DISCOUNT_TYPE_FREE_SHIPPING)) {
250 
251             discount = calculateShipping(items);
252         }
253         else if (type.equals(ShoppingCouponConstants.DISCOUNT_TYPE_TAX_FREE)) {
254             if (stateId != null) {
255                 discount = calculateTax(items, stateId);
256             }
257         }
258 
259         return discount;
260     }
261 
262     public static double calculateDiscountPercent(
263             Map<ShoppingCartItem, Integer> items)
264         throws PortalException, SystemException {
265 
266         double discount =
267             calculateDiscountSubtotal(items) / calculateSubtotal(items);
268 
269         if (Double.isNaN(discount) || Double.isInfinite(discount)) {
270             discount = 0.0;
271         }
272 
273         return discount;
274     }
275 
276     public static double calculateDiscountPrice(ShoppingItem item) {
277         return item.getPrice() * item.getDiscount();
278     }
279 
280     public static double calculateDiscountPrice(ShoppingItem item, int count)
281         throws PortalException, SystemException {
282 
283         ShoppingItemPrice itemPrice = _getItemPrice(item, count);
284 
285         return itemPrice.getPrice() * itemPrice.getDiscount() * count;
286     }
287 
288     public static double calculateDiscountPrice(ShoppingItemPrice itemPrice) {
289         return itemPrice.getPrice() * itemPrice.getDiscount();
290     }
291 
292     public static double calculateDiscountSubtotal(
293             Map<ShoppingCartItem, Integer> items)
294         throws PortalException, SystemException {
295 
296         double subtotal = 0.0;
297 
298         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
299             items.entrySet().iterator();
300 
301         while (itr.hasNext()) {
302             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
303 
304             ShoppingCartItem cartItem = entry.getKey();
305             Integer count = entry.getValue();
306 
307             ShoppingItem item = cartItem.getItem();
308 
309             subtotal += calculateDiscountPrice(item, count.intValue());
310         }
311 
312         return subtotal;
313     }
314 
315     public static double calculateInsurance(
316             Map<ShoppingCartItem, Integer> items)
317         throws PortalException, SystemException {
318 
319         double insurance = 0.0;
320         double subtotal = 0.0;
321 
322         ShoppingPreferences preferences = null;
323 
324         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
325             items.entrySet().iterator();
326 
327         while (itr.hasNext()) {
328             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
329 
330             ShoppingCartItem cartItem = entry.getKey();
331             Integer count = entry.getValue();
332 
333             ShoppingItem item = cartItem.getItem();
334 
335             if (preferences == null) {
336                 ShoppingCategory category = item.getCategory();
337 
338                 preferences = ShoppingPreferences.getInstance(
339                     category.getCompanyId(), category.getGroupId());
340             }
341 
342             ShoppingItemPrice itemPrice =
343                 _getItemPrice(item, count.intValue());
344 
345             subtotal += calculateActualPrice(itemPrice) * count.intValue();
346         }
347 
348         if ((preferences != null) && (subtotal > 0)) {
349             double insuranceRate = 0.0;
350 
351             double[] range = ShoppingPreferences.INSURANCE_RANGE;
352 
353             for (int i = 0; i < range.length - 1; i++) {
354                 if (subtotal > range[i] && subtotal <= range[i + 1]) {
355                     int rangeId = i / 2;
356                     if (MathUtil.isOdd(i)) {
357                         rangeId = (i + 1) / 2;
358                     }
359 
360                     insuranceRate = GetterUtil.getDouble(
361                         preferences.getInsurance()[rangeId]);
362                 }
363             }
364 
365             String formula = preferences.getInsuranceFormula();
366 
367             if (formula.equals("flat")) {
368                 insurance += insuranceRate;
369             }
370             else if (formula.equals("percentage")) {
371                 insurance += subtotal * insuranceRate;
372             }
373         }
374 
375         return insurance;
376     }
377 
378     public static double calculatePrice(ShoppingItem item, int count)
379         throws PortalException, SystemException {
380 
381         ShoppingItemPrice itemPrice = _getItemPrice(item, count);
382 
383         return itemPrice.getPrice() * count;
384     }
385 
386     public static double calculateShipping(Map<ShoppingCartItem, Integer> items)
387         throws PortalException, SystemException {
388 
389         double shipping = 0.0;
390         double subtotal = 0.0;
391 
392         ShoppingPreferences preferences = null;
393 
394         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
395             items.entrySet().iterator();
396 
397         while (itr.hasNext()) {
398             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
399 
400             ShoppingCartItem cartItem = entry.getKey();
401             Integer count = entry.getValue();
402 
403             ShoppingItem item = cartItem.getItem();
404 
405             if (preferences == null) {
406                 ShoppingCategory category = item.getCategory();
407 
408                 preferences = ShoppingPreferences.getInstance(
409                     category.getCompanyId(), category.getGroupId());
410             }
411 
412             if (item.isRequiresShipping()) {
413                 ShoppingItemPrice itemPrice =
414                     _getItemPrice(item, count.intValue());
415 
416                 if (itemPrice.isUseShippingFormula()) {
417                     subtotal +=
418                         calculateActualPrice(itemPrice) * count.intValue();
419                 }
420                 else {
421                     shipping += itemPrice.getShipping() * count.intValue();
422                 }
423             }
424         }
425 
426         if ((preferences != null) && (subtotal > 0)) {
427             double shippingRate = 0.0;
428 
429             double[] range = ShoppingPreferences.SHIPPING_RANGE;
430 
431             for (int i = 0; i < range.length - 1; i++) {
432                 if (subtotal > range[i] && subtotal <= range[i + 1]) {
433                     int rangeId = i / 2;
434                     if (MathUtil.isOdd(i)) {
435                         rangeId = (i + 1) / 2;
436                     }
437 
438                     shippingRate = GetterUtil.getDouble(
439                         preferences.getShipping()[rangeId]);
440                 }
441             }
442 
443             String formula = preferences.getShippingFormula();
444 
445             if (formula.equals("flat")) {
446                 shipping += shippingRate;
447             }
448             else if (formula.equals("percentage")) {
449                 shipping += subtotal * shippingRate;
450             }
451         }
452 
453         return shipping;
454     }
455 
456     public static double calculateSubtotal(Map<ShoppingCartItem, Integer> items)
457         throws PortalException, SystemException {
458 
459         double subtotal = 0.0;
460 
461         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
462             items.entrySet().iterator();
463 
464         while (itr.hasNext()) {
465             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
466 
467             ShoppingCartItem cartItem = entry.getKey();
468             Integer count = entry.getValue();
469 
470             ShoppingItem item = cartItem.getItem();
471 
472             subtotal += calculatePrice(item, count.intValue());
473         }
474 
475         return subtotal;
476     }
477 
478     public static double calculateTax(
479             Map<ShoppingCartItem, Integer> items, String stateId)
480         throws PortalException, SystemException {
481 
482         double tax = 0.0;
483 
484         ShoppingPreferences preferences = null;
485 
486         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
487             items.entrySet().iterator();
488 
489         while (itr.hasNext()) {
490             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
491 
492             ShoppingCartItem cartItem = entry.getKey();
493 
494             ShoppingItem item = cartItem.getItem();
495 
496             if (preferences == null) {
497                 ShoppingCategory category = item.getCategory();
498 
499                 preferences = ShoppingPreferences.getInstance(
500                     category.getCompanyId(), category.getGroupId());
501 
502                 break;
503             }
504         }
505 
506         if ((preferences != null) &&
507             (preferences.getTaxState().equals(stateId))) {
508 
509             double subtotal = 0.0;
510 
511             itr = items.entrySet().iterator();
512 
513             while (itr.hasNext()) {
514                 Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
515 
516                 ShoppingCartItem cartItem = entry.getKey();
517                 Integer count = entry.getValue();
518 
519                 ShoppingItem item = cartItem.getItem();
520 
521                 if (item.isTaxable()) {
522                     subtotal += calculatePrice(item, count.intValue());
523                 }
524             }
525 
526             tax = preferences.getTaxRate() * subtotal;
527         }
528 
529         return tax;
530     }
531 
532     public static double calculateTotal(
533             Map<ShoppingCartItem, Integer> items, String stateId,
534             ShoppingCoupon coupon, int altShipping, boolean insure)
535         throws PortalException, SystemException {
536 
537         double actualSubtotal = calculateActualSubtotal(items);
538         double tax = calculateTax(items, stateId);
539         double shipping = calculateAlternativeShipping(items, altShipping);
540 
541         double insurance = 0.0;
542         if (insure) {
543             insurance = calculateInsurance(items);
544         }
545 
546         double couponDiscount = calculateCouponDiscount(items, stateId, coupon);
547 
548         double total =
549             actualSubtotal + tax + shipping + insurance - couponDiscount;
550 
551         if (total < 0) {
552             total = 0.0;
553         }
554 
555         return total;
556     }
557 
558     public static double calculateTotal(ShoppingOrder order)
559         throws SystemException {
560 
561         List<ShoppingOrderItem> orderItems =
562             ShoppingOrderItemLocalServiceUtil.getOrderItems(order.getOrderId());
563 
564         double total =
565             calculateActualSubtotal(orderItems) + order.getTax() +
566                 order.getShipping() + order.getInsurance() -
567                     order.getCouponDiscount();
568 
569         if (total < 0) {
570             total = 0.0;
571         }
572 
573         return total;
574     }
575 
576     public static String getBreadcrumbs(
577             long categoryId, PageContext pageContext,
578             RenderRequest renderRequest, RenderResponse renderResponse)
579         throws Exception {
580 
581         ShoppingCategory category = null;
582 
583         try {
584             category = ShoppingCategoryLocalServiceUtil.getCategory(categoryId);
585         }
586         catch (Exception e) {
587         }
588 
589         return getBreadcrumbs(
590             category, pageContext, renderRequest, renderResponse);
591     }
592 
593     public static String getBreadcrumbs(
594             ShoppingCategory category, PageContext pageContext,
595             RenderRequest renderRequest, RenderResponse renderResponse)
596         throws Exception {
597 
598         PortletURL categoriesURL = renderResponse.createRenderURL();
599 
600         WindowState windowState = renderRequest.getWindowState();
601 
602         if (windowState.equals(LiferayWindowState.POP_UP)) {
603             categoriesURL.setWindowState(LiferayWindowState.POP_UP);
604 
605             categoriesURL.setParameter(
606                 "struts_action", "/shopping/select_category");
607         }
608         else {
609             //categoriesURL.setWindowState(WindowState.MAXIMIZED);
610 
611             categoriesURL.setParameter("struts_action", "/shopping/view");
612             categoriesURL.setParameter("tabs1", "categories");
613         }
614 
615         String categoriesLink =
616             "<a href=\"" + categoriesURL.toString() + "\">" +
617                 LanguageUtil.get(pageContext, "categories") + "</a>";
618 
619         if (category == null) {
620             return "<span class=\"first last\">" + categoriesLink + "</span>";
621         }
622 
623         String breadcrumbs = StringPool.BLANK;
624 
625         if (category != null) {
626             for (int i = 0;; i++) {
627                 category = category.toEscapedModel();
628 
629                 PortletURL portletURL = renderResponse.createRenderURL();
630 
631                 if (windowState.equals(LiferayWindowState.POP_UP)) {
632                     portletURL.setWindowState(LiferayWindowState.POP_UP);
633 
634                     portletURL.setParameter(
635                         "struts_action", "/shopping/select_category");
636                     portletURL.setParameter(
637                         "categoryId", String.valueOf(category.getCategoryId()));
638                 }
639                 else {
640                     //portletURL.setWindowState(WindowState.MAXIMIZED);
641 
642                     portletURL.setParameter("struts_action", "/shopping/view");
643                     portletURL.setParameter("tabs1", "categories");
644                     portletURL.setParameter(
645                         "categoryId", String.valueOf(category.getCategoryId()));
646                 }
647 
648                 String categoryLink =
649                     "<a href=\"" + portletURL.toString() + "\">" +
650                         category.getName() + "</a>";
651 
652                 if (i == 0) {
653                     breadcrumbs =
654                         "<span class=\"last\">" + categoryLink + "</span>";
655                 }
656                 else {
657                     breadcrumbs = categoryLink + " &raquo; " + breadcrumbs;
658                 }
659 
660                 if (category.isRoot()) {
661                     break;
662                 }
663 
664                 category = ShoppingCategoryLocalServiceUtil.getCategory(
665                     category.getParentCategoryId());
666             }
667         }
668 
669         breadcrumbs =
670             "<span class=\"first\">" + categoriesLink + " &raquo; </span>" +
671                 breadcrumbs;
672 
673         return breadcrumbs;
674     }
675 
676     public static ShoppingCart getCart(ThemeDisplay themeDisplay) {
677         ShoppingCart cart = new ShoppingCartImpl();
678 
679         cart.setGroupId(themeDisplay.getScopeGroupId());
680         cart.setCompanyId(themeDisplay.getCompanyId());
681         cart.setUserId(themeDisplay.getUserId());
682         cart.setItemIds(StringPool.BLANK);
683         cart.setCouponCodes(StringPool.BLANK);
684         cart.setAltShipping(0);
685         cart.setInsure(false);
686 
687         return cart;
688     }
689 
690     public static ShoppingCart getCart(PortletRequest portletRequest)
691         throws PortalException, SystemException {
692 
693         PortletSession portletSession = portletRequest.getPortletSession();
694 
695         ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
696             WebKeys.THEME_DISPLAY);
697 
698         String sessionCartId =
699             ShoppingCart.class.getName() + themeDisplay.getScopeGroupId();
700 
701         if (themeDisplay.isSignedIn()) {
702             ShoppingCart cart = (ShoppingCart)portletSession.getAttribute(
703                 sessionCartId);
704 
705             if (cart != null) {
706                 portletSession.removeAttribute(sessionCartId);
707             }
708 
709             if ((cart != null) && (cart.getItemsSize() > 0)) {
710                 cart = ShoppingCartLocalServiceUtil.updateCart(
711                     themeDisplay.getUserId(), themeDisplay.getScopeGroupId(),
712                     cart.getItemIds(), cart.getCouponCodes(),
713                     cart.getAltShipping(), cart.isInsure());
714             }
715             else {
716                 try {
717                     cart = ShoppingCartLocalServiceUtil.getCart(
718                         themeDisplay.getUserId(),
719                         themeDisplay.getScopeGroupId());
720                 }
721                 catch (NoSuchCartException nsce) {
722                     cart = getCart(themeDisplay);
723 
724                     cart = ShoppingCartLocalServiceUtil.updateCart(
725                         themeDisplay.getUserId(),
726                         themeDisplay.getScopeGroupId(), cart.getItemIds(),
727                         cart.getCouponCodes(), cart.getAltShipping(),
728                         cart.isInsure());
729                 }
730             }
731 
732             return cart;
733         }
734         else {
735             ShoppingCart cart = (ShoppingCart)portletSession.getAttribute(
736                 sessionCartId);
737 
738             if (cart == null) {
739                 cart = getCart(themeDisplay);
740 
741                 portletSession.setAttribute(sessionCartId, cart);
742             }
743 
744             return cart;
745         }
746     }
747 
748     public static int getFieldsQuantitiesPos(
749         ShoppingItem item, ShoppingItemField[] itemFields,
750         String[] fieldsArray) {
751 
752         Set<String> fieldsValues = new HashSet<String>();
753 
754         for (String fields : fieldsArray) {
755             int pos = fields.indexOf("=");
756 
757             String fieldValue = fields.substring(
758                 pos + 1, fields.length()).trim();
759 
760             fieldsValues.add(fieldValue);
761         }
762 
763         List<String> names = new ArrayList<String>();
764         List<String[]> values = new ArrayList<String[]>();
765 
766         for (int i = 0; i < itemFields.length; i++) {
767             names.add(itemFields[i].getName());
768             values.add(StringUtil.split(itemFields[i].getValues()));
769         }
770 
771         int numOfRows = 1;
772 
773         for (String[] vArray : values) {
774             numOfRows = numOfRows * vArray.length;
775         }
776 
777         int rowPos = 0;
778 
779         for (int i = 0; i < numOfRows; i++) {
780             boolean match = true;
781 
782             for (int j = 0; j < names.size(); j++) {
783                 int numOfRepeats = 1;
784 
785                 for (int k = j + 1; k < values.size(); k++) {
786                     String[] vArray = values.get(k);
787 
788                     numOfRepeats = numOfRepeats * vArray.length;
789                 }
790 
791                 String[] vArray = values.get(j);
792 
793                 int arrayPos;
794                 for (arrayPos = i / numOfRepeats;
795                      arrayPos >= vArray.length;
796                      arrayPos = arrayPos - vArray.length) {
797                 }
798 
799                 if (!fieldsValues.contains(vArray[arrayPos].trim())) {
800                     match = false;
801 
802                     break;
803                 }
804             }
805 
806             if (match) {
807                 rowPos = i;
808 
809                 break;
810             }
811         }
812 
813         return rowPos;
814     }
815 
816     public static long getItemId(String itemId) {
817         int pos = itemId.indexOf(StringPool.PIPE);
818 
819         if (pos != -1) {
820             itemId = itemId.substring(0, pos);
821         }
822 
823         return GetterUtil.getLong(itemId);
824     }
825 
826     public static String getItemFields(String itemId) {
827         int pos = itemId.indexOf(StringPool.PIPE);
828 
829         if (pos == -1) {
830             return StringPool.BLANK;
831         }
832         else {
833             return itemId.substring(pos + 1, itemId.length());
834         }
835     }
836 
837     public static OrderByComparator getItemOrderByComparator(
838         String orderByCol, String orderByType) {
839 
840         boolean orderByAsc = false;
841 
842         if (orderByType.equals("asc")) {
843             orderByAsc = true;
844         }
845 
846         OrderByComparator orderByComparator = null;
847 
848         if (orderByCol.equals("min-qty")) {
849             orderByComparator = new ItemMinQuantityComparator(orderByAsc);
850         }
851         else if (orderByCol.equals("name")) {
852             orderByComparator = new ItemNameComparator(orderByAsc);
853         }
854         else if (orderByCol.equals("price")) {
855             orderByComparator = new ItemPriceComparator(orderByAsc);
856         }
857         else if (orderByCol.equals("sku")) {
858             orderByComparator = new ItemSKUComparator(orderByAsc);
859         }
860         else if (orderByCol.equals("order-date")) {
861             orderByComparator = new OrderDateComparator(orderByAsc);
862         }
863 
864         return orderByComparator;
865     }
866 
867     public static int getMinQuantity(ShoppingItem item)
868         throws PortalException, SystemException {
869 
870         int minQuantity = item.getMinQuantity();
871 
872         List<ShoppingItemPrice> itemPrices = item.getItemPrices();
873 
874         for (ShoppingItemPrice itemPrice : itemPrices) {
875             if (minQuantity > itemPrice.getMinQuantity()) {
876                 minQuantity = itemPrice.getMinQuantity();
877             }
878         }
879 
880         return minQuantity;
881     }
882 
883     public static String getPayPalNotifyURL(ThemeDisplay themeDisplay) {
884         return themeDisplay.getPortalURL() + themeDisplay.getPathMain() +
885             "/shopping/notify";
886     }
887 
888     public static String getPayPalRedirectURL(
889         ShoppingPreferences preferences, ShoppingOrder order, double total,
890         String returnURL, String notifyURL) {
891 
892         String payPalEmailAddress = HttpUtil.encodeURL(
893             preferences.getPayPalEmailAddress());
894 
895         NumberFormat doubleFormat = NumberFormat.getNumberInstance(
896             Locale.ENGLISH);
897 
898         doubleFormat.setMaximumFractionDigits(2);
899         doubleFormat.setMinimumFractionDigits(2);
900 
901         String amount = doubleFormat.format(total);
902 
903         returnURL = HttpUtil.encodeURL(returnURL);
904         notifyURL = HttpUtil.encodeURL(notifyURL);
905 
906         String firstName = HttpUtil.encodeURL(order.getBillingFirstName());
907         String lastName = HttpUtil.encodeURL(order.getBillingLastName());
908         String address1 = HttpUtil.encodeURL(order.getBillingStreet());
909         String city = HttpUtil.encodeURL(order.getBillingCity());
910         String state = HttpUtil.encodeURL(order.getBillingState());
911         String zip = HttpUtil.encodeURL(order.getBillingZip());
912 
913         String currencyCode = preferences.getCurrencyId();
914 
915         StringBundler sb = new StringBundler(45);
916 
917         sb.append("https://www.paypal.com/cgi-bin/webscr?");
918         sb.append("cmd=_xclick&");
919         sb.append("business=").append(payPalEmailAddress).append("&");
920         sb.append("item_name=").append(order.getNumber()).append("&");
921         sb.append("item_number=").append(order.getNumber()).append("&");
922         sb.append("invoice=").append(order.getNumber()).append("&");
923         sb.append("amount=").append(amount).append("&");
924         sb.append("return=").append(returnURL).append("&");
925         sb.append("notify_url=").append(notifyURL).append("&");
926         sb.append("first_name=").append(firstName).append("&");
927         sb.append("last_name=").append(lastName).append("&");
928         sb.append("address1=").append(address1).append("&");
929         sb.append("city=").append(city).append("&");
930         sb.append("state=").append(state).append("&");
931         sb.append("zip=").append(zip).append("&");
932         sb.append("no_note=1&");
933         sb.append("currency_code=").append(currencyCode).append("");
934 
935         return sb.toString();
936     }
937 
938     public static String getPayPalReturnURL(
939         PortletURL portletURL, ShoppingOrder order) {
940 
941         portletURL.setParameter(
942             "struts_action", "/shopping/checkout");
943         portletURL.setParameter(Constants.CMD, Constants.VIEW);
944         portletURL.setParameter("orderId", String.valueOf(order.getOrderId()));
945 
946         return portletURL.toString();
947     }
948 
949     public static String getPpPaymentStatus(String ppPaymentStatus) {
950         if ((ppPaymentStatus == null) || (ppPaymentStatus.length() < 2) ||
951             (ppPaymentStatus.equals("checkout"))) {
952 
953             return ShoppingOrderConstants.STATUS_CHECKOUT;
954         }
955         else {
956             return Character.toUpperCase(ppPaymentStatus.charAt(0)) +
957                 ppPaymentStatus.substring(1, ppPaymentStatus.length());
958         }
959     }
960 
961     public static String getPpPaymentStatus(
962         ShoppingOrder order, PageContext pageContext) {
963 
964         String ppPaymentStatus = order.getPpPaymentStatus();
965 
966         if (ppPaymentStatus.equals(ShoppingOrderConstants.STATUS_CHECKOUT)) {
967             ppPaymentStatus = "checkout";
968         }
969         else {
970             ppPaymentStatus = ppPaymentStatus.toLowerCase();
971         }
972 
973         return LanguageUtil.get(pageContext, ppPaymentStatus);
974     }
975 
976     public static boolean isInStock(ShoppingItem item) {
977         if (!item.isFields()) {
978             if (item.getStockQuantity() > 0) {
979                 return true;
980             }
981             else {
982                 return false;
983             }
984         }
985         else {
986             String[] fieldsQuantities = item.getFieldsQuantitiesArray();
987 
988             for (int i = 0; i < fieldsQuantities.length; i++) {
989                 if (GetterUtil.getInteger(fieldsQuantities[i]) > 0) {
990                     return true;
991                 }
992             }
993 
994             return false;
995         }
996     }
997 
998     public static boolean isInStock(
999         ShoppingItem item, ShoppingItemField[] itemFields,
1000        String[] fieldsArray, Integer orderedQuantity) {
1001
1002        if (!item.isFields()) {
1003            int stockQuantity = item.getStockQuantity();
1004
1005            if ((stockQuantity > 0)  &&
1006                (stockQuantity >= orderedQuantity.intValue())) {
1007
1008                return true;
1009            }
1010            else {
1011                return false;
1012            }
1013        }
1014        else {
1015            int rowPos = getFieldsQuantitiesPos(item, itemFields, fieldsArray);
1016
1017            String[] fieldsQuantities = item.getFieldsQuantitiesArray();
1018
1019            int stockQuantity = GetterUtil.getInteger(fieldsQuantities[rowPos]);
1020
1021            try {
1022                if ((stockQuantity > 0) &&
1023                    (stockQuantity >= orderedQuantity.intValue())) {
1024
1025                    return true;
1026                }
1027            }
1028            catch (Exception e) {
1029            }
1030
1031            return false;
1032        }
1033    }
1034
1035    public static boolean meetsMinOrder(
1036            ShoppingPreferences preferences,
1037            Map<ShoppingCartItem, Integer> items)
1038        throws PortalException, SystemException {
1039
1040        if ((preferences.getMinOrder() > 0) &&
1041            (calculateSubtotal(items) < preferences.getMinOrder())) {
1042
1043            return false;
1044        }
1045        else {
1046            return true;
1047        }
1048    }
1049
1050    private static ShoppingItemPrice _getItemPrice(ShoppingItem item, int count)
1051        throws PortalException, SystemException {
1052
1053        ShoppingItemPrice itemPrice = null;
1054
1055        List<ShoppingItemPrice> itemPrices = item.getItemPrices();
1056
1057        for (ShoppingItemPrice temp : itemPrices) {
1058            int minQty = temp.getMinQuantity();
1059            int maxQty = temp.getMaxQuantity();
1060
1061            if ((temp.getStatus() !=
1062                    ShoppingItemPriceConstants.STATUS_INACTIVE)) {
1063
1064                if ((count >= minQty) && ((count <= maxQty) || (maxQty == 0))) {
1065                    return temp;
1066                }
1067
1068                if ((count > maxQty) &&
1069                    ((itemPrice == null) ||
1070                     (itemPrice.getMaxQuantity() < maxQty))) {
1071
1072                    itemPrice = temp;
1073                }
1074            }
1075        }
1076
1077        if (itemPrice == null) {
1078            return ShoppingItemPriceUtil.create(0);
1079        }
1080
1081        return itemPrice;
1082    }
1083
1084}