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