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