1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portlet.shopping.util;
21  
22  import com.liferay.portal.PortalException;
23  import com.liferay.portal.SystemException;
24  import com.liferay.portal.kernel.language.LanguageUtil;
25  import com.liferay.portal.kernel.portlet.LiferayWindowState;
26  import com.liferay.portal.kernel.util.Constants;
27  import com.liferay.portal.kernel.util.GetterUtil;
28  import com.liferay.portal.kernel.util.HttpUtil;
29  import com.liferay.portal.kernel.util.MathUtil;
30  import com.liferay.portal.kernel.util.OrderByComparator;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.theme.ThemeDisplay;
34  import com.liferay.portal.util.WebKeys;
35  import com.liferay.portlet.shopping.NoSuchCartException;
36  import com.liferay.portlet.shopping.model.ShoppingCart;
37  import com.liferay.portlet.shopping.model.ShoppingCartItem;
38  import com.liferay.portlet.shopping.model.ShoppingCategory;
39  import com.liferay.portlet.shopping.model.ShoppingCoupon;
40  import com.liferay.portlet.shopping.model.ShoppingItem;
41  import com.liferay.portlet.shopping.model.ShoppingItemField;
42  import com.liferay.portlet.shopping.model.ShoppingItemPrice;
43  import com.liferay.portlet.shopping.model.ShoppingOrder;
44  import com.liferay.portlet.shopping.model.ShoppingOrderItem;
45  import com.liferay.portlet.shopping.model.impl.ShoppingCartImpl;
46  import com.liferay.portlet.shopping.model.impl.ShoppingCouponImpl;
47  import com.liferay.portlet.shopping.model.impl.ShoppingItemPriceImpl;
48  import com.liferay.portlet.shopping.model.impl.ShoppingOrderImpl;
49  import com.liferay.portlet.shopping.service.ShoppingCartLocalServiceUtil;
50  import com.liferay.portlet.shopping.service.ShoppingCategoryLocalServiceUtil;
51  import com.liferay.portlet.shopping.service.ShoppingOrderItemLocalServiceUtil;
52  import com.liferay.portlet.shopping.service.persistence.ShoppingItemPriceUtil;
53  import com.liferay.portlet.shopping.util.comparator.ItemMinQuantityComparator;
54  import com.liferay.portlet.shopping.util.comparator.ItemNameComparator;
55  import com.liferay.portlet.shopping.util.comparator.ItemPriceComparator;
56  import com.liferay.portlet.shopping.util.comparator.ItemSKUComparator;
57  import com.liferay.portlet.shopping.util.comparator.OrderDateComparator;
58  
59  import java.text.NumberFormat;
60  
61  import java.util.ArrayList;
62  import java.util.HashMap;
63  import java.util.HashSet;
64  import java.util.Iterator;
65  import java.util.List;
66  import java.util.Locale;
67  import java.util.Map;
68  import java.util.Set;
69  
70  import javax.portlet.PortletRequest;
71  import javax.portlet.PortletSession;
72  import javax.portlet.PortletURL;
73  import javax.portlet.RenderRequest;
74  import javax.portlet.RenderResponse;
75  import javax.portlet.WindowState;
76  
77  import javax.servlet.jsp.PageContext;
78  
79  /**
80   * <a href="ShoppingUtil.java.html"><b><i>View Source</i></b></a>
81   *
82   * @author Brian Wing Shun Chan
83   *
84   */
85  public class ShoppingUtil {
86  
87      public static double calculateActualPrice(ShoppingItem item) {
88          return item.getPrice() - calculateDiscountPrice(item);
89      }
90  
91      public static double calculateActualPrice(ShoppingItem item, int count)
92          throws PortalException, SystemException {
93  
94          return calculatePrice(item, count) -
95              calculateDiscountPrice(item, count);
96      }
97  
98      public static double calculateActualPrice(ShoppingItemPrice itemPrice) {
99          return itemPrice.getPrice() - calculateDiscountPrice(itemPrice);
100     }
101 
102     public static double calculateActualSubtotal(
103             Map<ShoppingCartItem, Integer> items)
104         throws PortalException, SystemException {
105 
106         return calculateSubtotal(items) - calculateDiscountSubtotal(items);
107     }
108 
109     public static double calculateActualSubtotal(
110         List<ShoppingOrderItem> orderItems) {
111 
112         double subtotal = 0.0;
113 
114         for (ShoppingOrderItem orderItem : orderItems) {
115             subtotal += orderItem.getPrice() * orderItem.getQuantity();
116         }
117 
118         return subtotal;
119     }
120 
121     public static double calculateAlternativeShipping(
122             Map<ShoppingCartItem, Integer> items, int altShipping)
123         throws PortalException, SystemException {
124 
125         double shipping = calculateShipping(items);
126         double alternativeShipping = shipping;
127 
128         ShoppingPreferences prefs = null;
129 
130         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
131             items.entrySet().iterator();
132 
133         while (itr.hasNext()) {
134             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
135 
136             ShoppingCartItem cartItem = entry.getKey();
137 
138             ShoppingItem item = cartItem.getItem();
139 
140             if (prefs == null) {
141                 ShoppingCategory category = item.getCategory();
142 
143                 prefs = ShoppingPreferences.getInstance(
144                     category.getCompanyId(), category.getGroupId());
145 
146                 break;
147             }
148         }
149 
150         // Calculate alternative shipping if shopping is configured to use
151         // alternative shipping and shipping price is greater than 0
152 
153         if ((prefs != null) &&
154             (prefs.useAlternativeShipping()) && (shipping > 0)) {
155 
156             double altShippingDelta = 0.0;
157 
158             try {
159                 altShippingDelta = GetterUtil.getDouble(
160                     prefs.getAlternativeShipping()[1][altShipping]);
161             }
162             catch (Exception e) {
163                 return alternativeShipping;
164             }
165 
166             if (altShippingDelta > 0) {
167                 alternativeShipping = shipping * altShippingDelta;
168             }
169         }
170 
171         return alternativeShipping;
172     }
173 
174     public static double calculateCouponDiscount(
175             Map<ShoppingCartItem, Integer> items, ShoppingCoupon coupon)
176         throws PortalException, SystemException {
177 
178         return calculateCouponDiscount(items, null, coupon);
179     }
180 
181     public static double calculateCouponDiscount(
182             Map<ShoppingCartItem, Integer> items, String stateId,
183             ShoppingCoupon coupon)
184         throws PortalException, SystemException {
185 
186         double discount = 0.0;
187 
188         if ((coupon == null) || !coupon.isActive() ||
189             !coupon.hasValidDateRange()) {
190 
191             return discount;
192         }
193 
194         String[] categoryIds = StringUtil.split(coupon.getLimitCategories());
195         String[] skus = StringUtil.split(coupon.getLimitSkus());
196 
197         if ((categoryIds.length > 0) || (skus.length > 0)) {
198             Set<String> categoryIdsSet = new HashSet<String>();
199 
200             for (String categoryId : categoryIds) {
201                 categoryIdsSet.add(categoryId);
202             }
203 
204             Set<String> skusSet = new HashSet<String>();
205 
206             for (String sku : skus) {
207                 skusSet.add(sku);
208             }
209 
210             Map<ShoppingCartItem, Integer> newItems =
211                 new HashMap<ShoppingCartItem, Integer>();
212 
213             Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
214                 items.entrySet().iterator();
215 
216             while (itr.hasNext()) {
217                 Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
218 
219                 ShoppingCartItem cartItem = entry.getKey();
220                 Integer count = entry.getValue();
221 
222                 ShoppingItem item = cartItem.getItem();
223 
224                 if (((categoryIdsSet.size() > 0) &&
225                      (categoryIdsSet.contains(
226                         new Long(item.getCategoryId())))) ||
227                     ((skusSet.size() > 0) &&
228                      (skusSet.contains(item.getSku())))) {
229 
230                     newItems.put(cartItem, count);
231                 }
232             }
233 
234             items = newItems;
235         }
236 
237         double actualSubtotal = calculateActualSubtotal(items);
238 
239         if ((coupon.getMinOrder() > 0) &&
240             (coupon.getMinOrder() > actualSubtotal)) {
241 
242             return discount;
243         }
244 
245         String type = coupon.getDiscountType();
246 
247         if (type.equals(ShoppingCouponImpl.DISCOUNT_TYPE_PERCENTAGE)) {
248             discount = actualSubtotal * coupon.getDiscount();
249         }
250         else if (type.equals(ShoppingCouponImpl.DISCOUNT_TYPE_ACTUAL)) {
251             discount = coupon.getDiscount();
252         }
253         else if (type.equals(ShoppingCouponImpl.DISCOUNT_TYPE_FREE_SHIPPING)) {
254             discount = calculateShipping(items);
255         }
256         else if (type.equals(ShoppingCouponImpl.DISCOUNT_TYPE_TAX_FREE)) {
257             if (stateId != null) {
258                 discount = calculateTax(items, stateId);
259             }
260         }
261 
262         return discount;
263     }
264 
265     public static double calculateDiscountPercent(
266             Map<ShoppingCartItem, Integer> items)
267         throws PortalException, SystemException {
268 
269         double discount =
270             calculateDiscountSubtotal(items) / calculateSubtotal(items);
271 
272         if (Double.isNaN(discount) || Double.isInfinite(discount)) {
273             discount = 0.0;
274         }
275 
276         return discount;
277     }
278 
279     public static double calculateDiscountPrice(ShoppingItem item) {
280         return item.getPrice() * item.getDiscount();
281     }
282 
283     public static double calculateDiscountPrice(ShoppingItem item, int count)
284         throws PortalException, SystemException {
285 
286         ShoppingItemPrice itemPrice = _getItemPrice(item, count);
287 
288         return itemPrice.getPrice() * itemPrice.getDiscount() * count;
289     }
290 
291     public static double calculateDiscountPrice(ShoppingItemPrice itemPrice) {
292         return itemPrice.getPrice() * itemPrice.getDiscount();
293     }
294 
295     public static double calculateDiscountSubtotal(
296             Map<ShoppingCartItem, Integer> items)
297         throws PortalException, SystemException {
298 
299         double subtotal = 0.0;
300 
301         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
302             items.entrySet().iterator();
303 
304         while (itr.hasNext()) {
305             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
306 
307             ShoppingCartItem cartItem = entry.getKey();
308             Integer count = entry.getValue();
309 
310             ShoppingItem item = cartItem.getItem();
311 
312             subtotal += calculateDiscountPrice(item, count.intValue());
313         }
314 
315         return subtotal;
316     }
317 
318     public static double calculateInsurance(
319             Map<ShoppingCartItem, Integer> items)
320         throws PortalException, SystemException {
321 
322         double insurance = 0.0;
323         double subtotal = 0.0;
324 
325         ShoppingPreferences prefs = null;
326 
327         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
328             items.entrySet().iterator();
329 
330         while (itr.hasNext()) {
331             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
332 
333             ShoppingCartItem cartItem = entry.getKey();
334             Integer count = entry.getValue();
335 
336             ShoppingItem item = cartItem.getItem();
337 
338             if (prefs == null) {
339                 ShoppingCategory category = item.getCategory();
340 
341                 prefs = ShoppingPreferences.getInstance(
342                     category.getCompanyId(), category.getGroupId());
343             }
344 
345             ShoppingItemPrice itemPrice =
346                 _getItemPrice(item, count.intValue());
347 
348             subtotal += calculateActualPrice(itemPrice) * count.intValue();
349         }
350 
351         if ((prefs != null) && (subtotal > 0)) {
352             double insuranceRate = 0.0;
353 
354             double[] range = ShoppingPreferences.INSURANCE_RANGE;
355 
356             for (int i = 0; i < range.length - 1; i++) {
357                 if (subtotal > range[i] && subtotal <= range[i + 1]) {
358                     int rangeId = i / 2;
359                     if (MathUtil.isOdd(i)) {
360                         rangeId = (i + 1) / 2;
361                     }
362 
363                     insuranceRate = GetterUtil.getDouble(
364                         prefs.getInsurance()[rangeId]);
365                 }
366             }
367 
368             String formula = prefs.getInsuranceFormula();
369 
370             if (formula.equals("flat")) {
371                 insurance += insuranceRate;
372             }
373             else if (formula.equals("percentage")) {
374                 insurance += subtotal * insuranceRate;
375             }
376         }
377 
378         return insurance;
379     }
380 
381     public static double calculatePrice(ShoppingItem item, int count)
382         throws PortalException, SystemException {
383 
384         ShoppingItemPrice itemPrice = _getItemPrice(item, count);
385 
386         return itemPrice.getPrice() * count;
387     }
388 
389     public static double calculateShipping(Map<ShoppingCartItem, Integer> items)
390         throws PortalException, SystemException {
391 
392         double shipping = 0.0;
393         double subtotal = 0.0;
394 
395         ShoppingPreferences prefs = null;
396 
397         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
398             items.entrySet().iterator();
399 
400         while (itr.hasNext()) {
401             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
402 
403             ShoppingCartItem cartItem = entry.getKey();
404             Integer count = entry.getValue();
405 
406             ShoppingItem item = cartItem.getItem();
407 
408             if (prefs == null) {
409                 ShoppingCategory category = item.getCategory();
410 
411                 prefs = ShoppingPreferences.getInstance(
412                     category.getCompanyId(), category.getGroupId());
413             }
414 
415             if (item.isRequiresShipping()) {
416                 ShoppingItemPrice itemPrice =
417                     _getItemPrice(item, count.intValue());
418 
419                 if (itemPrice.isUseShippingFormula()) {
420                     subtotal +=
421                         calculateActualPrice(itemPrice) * count.intValue();
422                 }
423                 else {
424                     shipping += itemPrice.getShipping() * count.intValue();
425                 }
426             }
427         }
428 
429         if ((prefs != null) && (subtotal > 0)) {
430             double shippingRate = 0.0;
431 
432             double[] range = ShoppingPreferences.SHIPPING_RANGE;
433 
434             for (int i = 0; i < range.length - 1; i++) {
435                 if (subtotal > range[i] && subtotal <= range[i + 1]) {
436                     int rangeId = i / 2;
437                     if (MathUtil.isOdd(i)) {
438                         rangeId = (i + 1) / 2;
439                     }
440 
441                     shippingRate = GetterUtil.getDouble(
442                         prefs.getShipping()[rangeId]);
443                 }
444             }
445 
446             String formula = prefs.getShippingFormula();
447 
448             if (formula.equals("flat")) {
449                 shipping += shippingRate;
450             }
451             else if (formula.equals("percentage")) {
452                 shipping += subtotal * shippingRate;
453             }
454         }
455 
456         return shipping;
457     }
458 
459     public static double calculateSubtotal(Map<ShoppingCartItem, Integer> items)
460         throws PortalException, SystemException {
461 
462         double subtotal = 0.0;
463 
464         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
465             items.entrySet().iterator();
466 
467         while (itr.hasNext()) {
468             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
469 
470             ShoppingCartItem cartItem = entry.getKey();
471             Integer count = entry.getValue();
472 
473             ShoppingItem item = cartItem.getItem();
474 
475             subtotal += calculatePrice(item, count.intValue());
476         }
477 
478         return subtotal;
479     }
480 
481     public static double calculateTax(
482             Map<ShoppingCartItem, Integer> items, String stateId)
483         throws PortalException, SystemException {
484 
485         double tax = 0.0;
486 
487         ShoppingPreferences prefs = null;
488 
489         Iterator<Map.Entry<ShoppingCartItem, Integer>> itr =
490             items.entrySet().iterator();
491 
492         while (itr.hasNext()) {
493             Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
494 
495             ShoppingCartItem cartItem = entry.getKey();
496 
497             ShoppingItem item = cartItem.getItem();
498 
499             if (prefs == null) {
500                 ShoppingCategory category = item.getCategory();
501 
502                 prefs = ShoppingPreferences.getInstance(
503                     category.getCompanyId(), category.getGroupId());
504 
505                 break;
506             }
507         }
508 
509         if ((prefs != null) &&
510             (prefs.getTaxState().equals(stateId))) {
511 
512             double subtotal = 0.0;
513 
514             itr = items.entrySet().iterator();
515 
516             while (itr.hasNext()) {
517                 Map.Entry<ShoppingCartItem, Integer> entry = itr.next();
518 
519                 ShoppingCartItem cartItem = entry.getKey();
520                 Integer count = entry.getValue();
521 
522                 ShoppingItem item = cartItem.getItem();
523 
524                 if (item.isTaxable()) {
525                     subtotal += calculatePrice(item, count.intValue());
526                 }
527             }
528 
529             tax = prefs.getTaxRate() * subtotal;
530         }
531 
532         return tax;
533     }
534 
535     public static double calculateTotal(
536             Map<ShoppingCartItem, Integer> items, String stateId,
537             ShoppingCoupon coupon, int altShipping, boolean insure)
538         throws PortalException, SystemException {
539 
540         double actualSubtotal = calculateActualSubtotal(items);
541         double tax = calculateTax(items, stateId);
542         double shipping = calculateAlternativeShipping(items, altShipping);
543 
544         double insurance = 0.0;
545         if (insure) {
546             insurance = calculateInsurance(items);
547         }
548 
549         double couponDiscount = calculateCouponDiscount(items, stateId, coupon);
550 
551         double total =
552             actualSubtotal + tax + shipping + insurance - couponDiscount;
553 
554         if (total < 0) {
555             total = 0.0;
556         }
557 
558         return total;
559     }
560 
561     public static double calculateTotal(ShoppingOrder order)
562         throws SystemException {
563 
564         List<ShoppingOrderItem> orderItems =
565             ShoppingOrderItemLocalServiceUtil.getOrderItems(order.getOrderId());
566 
567         double total =
568             calculateActualSubtotal(orderItems) + order.getTax() +
569                 order.getShipping() + order.getInsurance() -
570                     order.getCouponDiscount();
571 
572         if (total < 0) {
573             total = 0.0;
574         }
575 
576         return total;
577     }
578 
579     public static String getBreadcrumbs(
580             long categoryId, PageContext pageContext,
581             RenderRequest renderRequest, RenderResponse renderResponse)
582         throws Exception {
583 
584         ShoppingCategory category = null;
585 
586         try {
587             category = ShoppingCategoryLocalServiceUtil.getCategory(categoryId);
588         }
589         catch (Exception e) {
590         }
591 
592         return getBreadcrumbs(
593             category, pageContext, renderRequest, renderResponse);
594     }
595 
596     public static String getBreadcrumbs(
597             ShoppingCategory category, PageContext pageContext,
598             RenderRequest renderRequest, RenderResponse renderResponse)
599         throws Exception {
600 
601         PortletURL categoriesURL = renderResponse.createRenderURL();
602 
603         WindowState windowState = renderRequest.getWindowState();
604 
605         if (windowState.equals(LiferayWindowState.POP_UP)) {
606             categoriesURL.setWindowState(LiferayWindowState.POP_UP);
607 
608             categoriesURL.setParameter(
609                 "struts_action", "/shopping/select_category");
610         }
611         else {
612             //categoriesURL.setWindowState(WindowState.MAXIMIZED);
613 
614             categoriesURL.setParameter("struts_action", "/shopping/view");
615             categoriesURL.setParameter("tabs1", "categories");
616         }
617 
618         String categoriesLink =
619             "<a href=\"" + categoriesURL.toString() + "\">" +
620                 LanguageUtil.get(pageContext, "categories") + "</a>";
621 
622         if (category == null) {
623             return "<span class=\"first last\">" + categoriesLink + "</span>";
624         }
625 
626         String breadcrumbs = StringPool.BLANK;
627 
628         if (category != null) {
629             for (int i = 0;; i++) {
630                 category = category.toEscapedModel();
631 
632                 PortletURL portletURL = renderResponse.createRenderURL();
633 
634                 if (windowState.equals(LiferayWindowState.POP_UP)) {
635                     portletURL.setWindowState(LiferayWindowState.POP_UP);
636 
637                     portletURL.setParameter(
638                         "struts_action", "/shopping/select_category");
639                     portletURL.setParameter(
640                         "categoryId", String.valueOf(category.getCategoryId()));
641                 }
642                 else {
643                     //portletURL.setWindowState(WindowState.MAXIMIZED);
644 
645                     portletURL.setParameter("struts_action", "/shopping/view");
646                     portletURL.setParameter("tabs1", "categories");
647                     portletURL.setParameter(
648                         "categoryId", String.valueOf(category.getCategoryId()));
649                 }
650 
651                 String categoryLink =
652                     "<a href=\"" + portletURL.toString() + "\">" +
653                         category.getName() + "</a>";
654 
655                 if (i == 0) {
656                     breadcrumbs =
657                         "<span class=\"last\">" + categoryLink + "</span>";
658                 }
659                 else {
660                     breadcrumbs = categoryLink + " &raquo; " + breadcrumbs;
661                 }
662 
663                 if (category.isRoot()) {
664                     break;
665                 }
666 
667                 category = ShoppingCategoryLocalServiceUtil.getCategory(
668                     category.getParentCategoryId());
669             }
670         }
671 
672         breadcrumbs =
673             "<span class=\"first\">" + categoriesLink + " &raquo; </span>" +
674                 breadcrumbs;
675 
676         return breadcrumbs;
677     }
678 
679     public static ShoppingCart getCart(ThemeDisplay themeDisplay) {
680         ShoppingCart cart = new ShoppingCartImpl();
681 
682         cart.setGroupId(themeDisplay.getScopeGroupId());
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.getScopeGroupId();
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.getScopeGroupId(),
715                     cart.getItemIds(), cart.getCouponCodes(),
716                     cart.getAltShipping(), cart.isInsure());
717             }
718             else {
719                 try {
720                     cart = ShoppingCartLocalServiceUtil.getCart(
721                         themeDisplay.getUserId(),
722                         themeDisplay.getScopeGroupId());
723                 }
724                 catch (NoSuchCartException nsce) {
725                     cart = getCart(themeDisplay);
726 
727                     cart = ShoppingCartLocalServiceUtil.updateCart(
728                         themeDisplay.getUserId(),
729                         themeDisplay.getScopeGroupId(), 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}