001: /*
002: * Created on Mar 2, 2004
003: */
004: package org.openedit.store;
005:
006: import java.text.ParseException;
007: import java.text.SimpleDateFormat;
008: import java.util.ArrayList;
009: import java.util.Collection;
010: import java.util.Collections;
011: import java.util.Date;
012: import java.util.HashMap;
013: import java.util.HashSet;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Set;
018: import org.apache.commons.collections.map.ListOrderedMap;
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.openedit.money.Money;
022: import com.openedit.OpenEditRuntimeException;
023:
024: /**
025: * @author cburkey
026: *
027: */
028: public class Product {
029: protected String fieldName;
030: protected String fieldDescription;
031: protected String fieldId;
032: protected String fieldHandlingChargeLevel;
033: protected Set fieldCatalogs;
034: protected List fieldInventoryItems;
035: protected Category fieldDefaultCatalog;
036: protected Map fieldProperties;
037: protected String fieldDepartment;
038: protected PriceSupport fieldPriceSupport;
039: protected List fieldKeywords;
040: protected boolean fieldAvailable = true;
041: protected List fieldOptions;
042: protected boolean fieldCustomPrice = false;
043: protected boolean fieldTaxExempt = false;
044: protected int fieldOrdering = -1; //the order that these product should be shown in a list
045: protected String fieldShippingMethodId;
046: protected List fieldRelatedProductIds;
047: protected String fieldDeliveryType;
048:
049: private static final Log log = LogFactory.getLog(Product.class);
050:
051: public Product() {
052: }
053:
054: public Product(String inName) {
055: setName(inName);
056: }
057:
058: public int getOrdering() {
059: return fieldOrdering;
060: }
061:
062: public void setOrdering(int inOrdering) {
063: fieldOrdering = inOrdering;
064: }
065:
066: public String getName() {
067: return fieldName;
068: }
069:
070: public void setName(String inName) {
071: fieldName = inName;
072: }
073:
074: /**
075: * This is an optional field
076: * @return
077: */
078:
079: public String getShortDescription() {
080: return getProperty("shortdescription");
081: }
082:
083: public void setShortDescription(String inDescription) {
084: addProperty("shortdescription", inDescription);
085: }
086:
087: public String toString() {
088: return fieldName;
089: }
090:
091: public String getId() {
092: return fieldId;
093: }
094:
095: public void setId(String inString) {
096: fieldId = inString;
097: }
098:
099: public String get(String inAttribute) {
100: if ("name".equals(inAttribute)) {
101: return getName();
102: }
103: String value = (String) getProperties().get(inAttribute);
104: // if ( value instanceof PageProperty)
105: // {
106: // PageProperty prop = (PageProperty)value;
107: // return prop.getValue();
108: // }
109: if (value == null) {
110: //Loop over all the catalogs and look for hit
111: if (getDefaultCatalog() != null) {
112: value = getDefaultCatalog().get(inAttribute);
113: }
114: if (value == null) {
115: for (Iterator iter = getCatalogs().iterator(); iter
116: .hasNext();) {
117: Category cat = (Category) iter.next();
118: if (cat != getDefaultCatalog()) {
119: value = cat.get(inAttribute);
120: if (value != null) {
121: return value;
122: }
123: }
124: }
125: }
126: }
127: return value;
128: }
129:
130: public void addProperty(String inKey, String inValue) {
131: if (inValue == null || inValue.length() == 0) {
132: getProperties().remove(inKey);
133: } else {
134: getProperties().put(inKey, inValue);
135: }
136: }
137:
138: public void removeProperty(String inKey) {
139: if (inKey != null && inKey.length() > 0) {
140: getProperties().remove(inKey);
141: }
142: }
143:
144: /**
145: * @param inCatid
146: */
147: public void addCatalog(Category inCatid) {
148: addCategory(inCatid);
149: }
150:
151: public void addCategory(Category inCatid) {
152: if (inCatid == null) {
153: throw new IllegalArgumentException(
154: "Catalogs cannot be null");
155: }
156: if (!isInCatalog(inCatid)) {
157: getCatalogs().add(inCatid);
158: }
159: }
160:
161: public void removeCatalog(Category inCatid) {
162: Category found = null;
163: for (Iterator iter = getCatalogs().iterator(); iter.hasNext();) {
164: Category element = (Category) iter.next();
165: if (element.getId().equals(inCatid.getId())) {
166: found = element;
167: break;
168: }
169: }
170: if (found != null) {
171: getCatalogs().remove(found);
172: }
173: }
174:
175: public Set getCatalogs() {
176: if (fieldCatalogs == null) {
177: fieldCatalogs = new HashSet();
178: }
179: return fieldCatalogs;
180: }
181:
182: public boolean isInCatalog(Category inCat) {
183: for (Iterator iter = getCatalogs().iterator(); iter.hasNext();) {
184: Category element = (Category) iter.next();
185: if (element.getId().equals(inCat.getId())) {
186: return true;
187: }
188: }
189: return false;
190: }
191:
192: public Option getDefaultColor() {
193: if (hasColor()) {
194: return (Option) getColors().iterator().next();
195: }
196: return null;
197: }
198:
199: public Option getDefaultSize() {
200: if (hasSize()) {
201: return (Option) getSizesSorted().iterator().next();
202: }
203: return null;
204: }
205:
206: public List getSizes() {
207: List sizes = new ArrayList();
208: for (Iterator iter = getInventoryItems().iterator(); iter
209: .hasNext();) {
210: InventoryItem item = (InventoryItem) iter.next();
211: if (item.hasSize()) {
212: Option size = item.getSize();
213: if (!sizes.contains(size)) {
214: sizes.add(item.getSize());
215: }
216: }
217: }
218: return sizes;
219: }
220:
221: public List getSizesSorted() {
222: List sizes = getSizes();
223: Collections.sort(sizes);
224: return sizes;
225: }
226:
227: public List getColors() {
228: List colors = new ArrayList();
229: for (Iterator iter = getInventoryItems().iterator(); iter
230: .hasNext();) {
231: InventoryItem item = (InventoryItem) iter.next();
232: if (item.hasColor() && !colors.contains(item.getColor())) {
233: colors.add(item.getColor());
234: }
235: }
236: return colors;
237: }
238:
239: /**
240: * List all the colors available in this size
241: * @param inSize
242: * @return
243: */
244: public List colorsInSize(Option inSize) {
245: if (inSize == null || "na".equals(inSize.getValue())) {
246: return getColors();
247: }
248: List colors = new ArrayList();
249: for (Iterator iter = getInventoryItems().iterator(); iter
250: .hasNext();) {
251: InventoryItem item = (InventoryItem) iter.next();
252: //if( item.isInStock())
253: //{
254: boolean add = false;
255: if (item.getSize() == null) {
256: add = true;
257: } else if (inSize.equals(item.getSize())) {
258: add = true;
259: }
260: if (item.getColor() == null
261: || colors.contains(item.getColor())) {
262: add = false;
263: }
264: if (add) {
265: colors.add(item.getColor());
266: }
267: //}
268: }
269: return colors;
270: }
271:
272: public List getInventoryItems() {
273: if (fieldInventoryItems == null) {
274: fieldInventoryItems = new ArrayList();
275: }
276: return fieldInventoryItems;
277: }
278:
279: public void setInventoryItems(List inItems) {
280: fieldInventoryItems = inItems;
281: }
282:
283: public boolean hasSizes() {
284: return getSizes().size() > 1;
285: }
286:
287: public boolean hasColors() {
288: return getColors().size() > 1;
289: }
290:
291: public boolean hasSize() {
292: if (getSizes().size() == 0) {
293: return false;
294: }
295: return true;
296: }
297:
298: public boolean hasColor() {
299: if (getColors().size() == 0) {
300: return false;
301: }
302: return true;
303: }
304:
305: public Category getDefaultCatalog() {
306: if (fieldDefaultCatalog == null && getCatalogs().size() >= 1) {
307: //grab the one
308: return (Category) getCatalogs().iterator().next();
309: }
310: return fieldDefaultCatalog;
311: }
312:
313: public Category getDefaultCategory() {
314: return getDefaultCatalog();
315: }
316:
317: public Collection getRelatedCatalogs() {
318: Category cat = getDefaultCatalog();
319: if (cat.getParentCatalog() != null) {
320: return cat.getParentCatalog().getChildren();
321: } else {
322: List list = new ArrayList();
323: list.add(cat);
324: return list;
325: }
326: }
327:
328: public void setDefaultCatalog(Category inDefaultCatalog) {
329: fieldDefaultCatalog = inDefaultCatalog;
330: }
331:
332: public Map getProperties() {
333: if (fieldProperties == null) {
334: fieldProperties = ListOrderedMap.decorate(new HashMap());
335: }
336: return fieldProperties;
337: }
338:
339: public String getProperty(String inKey) {
340: String value = (String) getProperties().get(inKey);
341: return value;
342: }
343:
344: public void setProperties(Map inAttributes) {
345: fieldProperties = inAttributes;
346: }
347:
348: public void putAttribute(String inKey, String inValue) {
349: putProperty(inKey, inValue);
350: }
351:
352: public void putProperty(String inKey, String inValue) {
353: if (inValue != null) {
354: getProperties().put(inKey, inValue);
355: } else {
356: getProperties().remove(inKey);
357: }
358: }
359:
360: /**
361: *
362: */
363: public void clearUserCatalogs() {
364: Category[] copy = (Category[]) getCatalogs().toArray(
365: new Category[getCatalogs().size()]);
366: for (int i = 0; i < copy.length; i++) {
367: if (copy[i].isUserSelected()) {
368: removeCatalog(copy[i]);
369: }
370: }
371: }
372:
373: public void clearItems() {
374: if (fieldInventoryItems != null) {
375: getInventoryItems().clear();
376: }
377: }
378:
379: public String getDepartment() {
380: return fieldDepartment;
381: }
382:
383: public void setDepartment(String fieldDepartment) {
384: this .fieldDepartment = fieldDepartment;
385: }
386:
387: public boolean isInStock() {
388: for (Iterator iter = getInventoryItems().iterator(); iter
389: .hasNext();) {
390: InventoryItem item = (InventoryItem) iter.next();
391: if (item.isInStock()) {
392: return true;
393: }
394: }
395: return false;
396: }
397:
398: public boolean isPartlyOutOfStock() {
399: for (Iterator iter = getInventoryItems().iterator(); iter
400: .hasNext();) {
401: InventoryItem item = (InventoryItem) iter.next();
402: if (!item.isInStock()) {
403: return true;
404: }
405: }
406: return false;
407: }
408:
409: public boolean isOnSale() {
410: if (hasProductLevelPricing()) {
411: return getPriceSupport().isOnSale();
412: }
413: InventoryItem item = getInventoryItem(0);
414: if (item != null) {
415: return item.isOnSale();
416: }
417: /* for ( Iterator iter = getInventoryItems().iterator(); iter.hasNext(); )
418: {
419: Item item = (Item) iter.next();
420: if ( item.isOnSale() )
421: {
422: return true;
423: }
424: }
425: */return false;
426: }
427:
428: public void addInventoryItem(InventoryItem inItem) {
429: inItem.setProduct(this );
430: getInventoryItems().add(inItem);
431: }
432:
433: /**
434: * @param inI
435: * @return
436: */
437: public InventoryItem getInventoryItem(int inI) {
438: if (getInventoryItems().size() > inI) {
439: return (InventoryItem) getInventoryItems().get(inI);
440: }
441: return null;
442: }
443:
444: public InventoryItem getInventoryItemBySku(String inSku) {
445: for (Iterator iter = getInventoryItems().iterator(); iter
446: .hasNext();) {
447: InventoryItem element = (InventoryItem) iter.next();
448: if (element.getSku().equals(inSku)) {
449: return element;
450: }
451: }
452: return null;
453: }
454:
455: public InventoryItem getInventoryItemByOptions(Collection inOptions) {
456: for (Iterator iter = getInventoryItems().iterator(); iter
457: .hasNext();) {
458: InventoryItem element = (InventoryItem) iter.next();
459: if (element.isExactMatch(inOptions)) {
460: return element;
461: }
462: }
463: return null;
464: }
465:
466: public InventoryItem getCloseInventoryItemByOptions(Set inOptions) {
467: //First check for exact match. Then size color only, then size only then color only
468: for (Iterator iter = getInventoryItems().iterator(); iter
469: .hasNext();) {
470: InventoryItem element = (InventoryItem) iter.next();
471: if (element.isExactMatch((inOptions))) {
472: return element;
473: }
474: }
475: //size color
476: for (Iterator iter = getInventoryItems().iterator(); iter
477: .hasNext();) {
478: InventoryItem element = (InventoryItem) iter.next();
479: if (element.isCloseMatch((inOptions))) {
480: return element;
481: }
482: }
483: for (Iterator iter = getInventoryItems().iterator(); iter
484: .hasNext();) {
485: InventoryItem element = (InventoryItem) iter.next();
486: if (element.isAnyMatch(inOptions)) {
487: return element;
488: }
489: }
490: if (getInventoryItemCount() > 0) {
491: return (InventoryItem) getInventoryItems().get(0);
492: }
493: return null;
494: }
495:
496: public boolean hasProductLevelPricing() {
497: return fieldPriceSupport != null;
498: }
499:
500: public PriceSupport getPriceSupport() {
501: return fieldPriceSupport;
502: }
503:
504: public void setPriceSupport(PriceSupport priceSupport) {
505: fieldPriceSupport = priceSupport;
506: }
507:
508: public Money getRetailUnitPrice() {
509: //return getPriceSupport().getPrice();
510: return getPriceSupport().getRetailPrice();
511:
512: }
513:
514: //** this is the lowest price avialable
515: public Money getYourPrice() {
516: if (hasProductLevelPricing()) {
517: Money price = getPriceSupport().getYourPriceByQuantity(1);
518: return price;
519: } else if (getInventoryItemCount() > 0) {
520: // ask cb
521: Money price = getInventoryItem(0).getYourPrice();
522: if (price != null) {
523: return price;
524: } else {
525: return Money.ZERO;
526: }
527: } else {
528: return Money.ZERO;
529: }
530: }
531:
532: public Money getRetailPrice() {
533: Money price = null;
534: if (hasProductLevelPricing()) {
535: price = getPriceSupport().getRetailPrice();
536: } else if (getInventoryItemCount() > 0) {
537: price = getInventoryItem(0).getRetailPrice();
538: } else {
539: price = Money.ZERO;
540: }
541: return price;
542: }
543:
544: /**
545: * @param inQuantity
546: * @param money
547: */
548: public void addTierPrice(int inQuantity, Price inPrice) {
549: if (getPriceSupport() == null) {
550: setPriceSupport(new PriceSupport());
551: }
552: getPriceSupport().addTierPrice(inQuantity, inPrice);
553: }
554:
555: public boolean hasKeywords() {
556: return fieldKeywords != null && fieldKeywords.size() > 0;
557: }
558:
559: public List getKeywords() {
560: if (fieldKeywords == null) {
561: fieldKeywords = new ArrayList();
562: }
563: return fieldKeywords;
564: }
565:
566: public boolean isAvailable() {
567: return fieldAvailable;
568: }
569:
570: public void setAvailable(boolean inAvailable) {
571: fieldAvailable = inAvailable;
572: }
573:
574: /**
575: * @return
576: */
577: public int getInventoryItemCount() {
578: return getInventoryItems().size();
579: }
580:
581: /**
582: *
583: */
584: public void clearCatalogs() {
585: getCatalogs().clear();
586: }
587:
588: public List getOptions() {
589: if (fieldOptions == null) {
590: fieldOptions = new ArrayList();
591: }
592: return fieldOptions;
593: }
594:
595: public List getAllOptions() {
596: List optionsMap = new ArrayList();
597: for (Iterator iter = getOptions().iterator(); iter.hasNext();) {
598: Option option = (Option) iter.next();
599: optionsMap.add(option);
600: }
601: if (getDefaultCatalog() != null) {
602: List catalogOptions = getDefaultCatalog().getAllOptions();
603: for (Iterator iter = catalogOptions.iterator(); iter
604: .hasNext();) {
605: Option option = (Option) iter.next();
606: optionsMap.add(option);
607: }
608: }
609: return optionsMap;
610: }
611:
612: public void setOptions(List inOptions) {
613: fieldOptions = inOptions;
614: }
615:
616: public void addOption(Option inOption) {
617: removeOption(inOption.getId());
618: getOptions().add(inOption);
619: }
620:
621: public void removeOption(String id) {
622: List options = getOptions();
623: for (int i = 0; i < options.size(); i++) {
624: Option option = (Option) options.get(i);
625: if (option.getId().equals(id)) {
626: getOptions().remove(i);
627: }
628: }
629: }
630:
631: public void clearOptions() {
632: getOptions().clear();
633: }
634:
635: public Option getOption(String inOptionId) {
636: for (Iterator it = getOptions().iterator(); it.hasNext();) {
637: Option option = (Option) it.next();
638: if (inOptionId.equals(option.getId())) {
639: return option;
640: }
641: }
642:
643: if (getDefaultCatalog() != null) {
644: return getDefaultCatalog().getOption(inOptionId);
645: }
646:
647: return null;
648: }
649:
650: public String getHandlingChargeLevel() {
651: return fieldHandlingChargeLevel;
652: }
653:
654: public void setHandlingChargeLevel(String inHandlingChargeLevel) {
655: fieldHandlingChargeLevel = inHandlingChargeLevel;
656: }
657:
658: public boolean isCustomPrice() {
659: return fieldCustomPrice;
660: }
661:
662: public void setCustomPrice(boolean inCustomPrice) {
663: fieldCustomPrice = inCustomPrice;
664: }
665:
666: public boolean isTaxExempt() {
667: return fieldTaxExempt;
668: }
669:
670: public void setTaxExempt(boolean inTaxExempt) {
671: fieldTaxExempt = inTaxExempt;
672: }
673:
674: public boolean hasProperty(String inKey) {
675: String value = getProperty(inKey);
676: if (value != null) {
677: return true;
678: }
679: for (Iterator iter = getInventoryItems().iterator(); iter
680: .hasNext();) {
681: InventoryItem item = (InventoryItem) iter.next();
682: value = item.getProperty(inKey);
683: if (value != null) {
684: return true;
685: }
686: List prop = item.getPropertiesStartingWith(inKey);
687: if (prop.size() > 0) {
688: return true;
689: }
690: }
691: return false;
692: }
693:
694: //this is a fixed method, this is optional since the cart has a range of methods available
695: public String getShippingMethodId() {
696: return fieldShippingMethodId;
697: }
698:
699: public void setShippingMethodId(String inShippingMethodId) {
700: fieldShippingMethodId = inShippingMethodId;
701: }
702:
703: public List getRelatedProductIds() {
704: if (fieldRelatedProductIds == null) {
705: fieldRelatedProductIds = new ArrayList();
706:
707: }
708:
709: return fieldRelatedProductIds;
710:
711: }
712:
713: public String getRelatedProductId() {
714: if (fieldRelatedProductIds == null
715: || getRelatedProductIds().size() == 0) {
716: return null;
717: }
718: return (String) getRelatedProductIds().get(0); //grab the first one
719: }
720:
721: public void addRelatedProductId(String inProductId) {
722: if (!getRelatedProductIds().contains(inProductId)) {
723: getRelatedProductIds().add(inProductId);
724: }
725: }
726:
727: public void clearRelatedProductIds() {
728: if (fieldRelatedProductIds != null) {
729: getRelatedProductIds().clear();
730: }
731: }
732:
733: public void removeRelatedProductId(String inProductId) {
734: getRelatedProductIds().remove(inProductId);
735: }
736:
737: public String getDescription() {
738: return fieldDescription;
739: }
740:
741: public void setDescription(String inDescription) {
742: fieldDescription = inDescription;
743: }
744:
745: public void addKeyword(String inString) {
746: if (inString == null) {
747: log.debug("Null keyword");
748: } else {
749: getKeywords().add(inString);
750: }
751: }
752:
753: public String getDeliveryType() {
754: return fieldDeliveryType;
755: }
756:
757: public void setDeliveryType(String inDeliveryType) {
758: fieldDeliveryType = inDeliveryType;
759: }
760:
761: public Date getDate(String inField, String inDateFormat) {
762: String date = getProperty(inField);
763: if (date != null) {
764: SimpleDateFormat format = new SimpleDateFormat(inDateFormat);
765: try {
766: return format.parse(date);
767: } catch (ParseException e) {
768: throw new OpenEditRuntimeException(e);
769: }
770: }
771: return null;
772: }
773:
774: public boolean isRelated(String inId) {
775: return getRelatedProductIds().contains(inId);
776: }
777:
778: public void setKeywords(List inKeywords) {
779: fieldKeywords = inKeywords;
780: }
781:
782: public void clearKeywords() {
783: if (fieldKeywords != null) {
784: fieldKeywords.clear();
785: }
786: }
787:
788: public void incrementProperty(String property, int delta)
789: throws Exception {
790: String currentValue = getProperty(property);
791: int current = Integer.parseInt(currentValue);
792: current = current + delta;
793: putProperty(property, Integer.toString(current));
794: }
795:
796: public boolean hasRelatedProducts() {
797: if (fieldRelatedProductIds != null
798: && fieldRelatedProductIds.size() > 0) {
799: return true;
800: }
801: return false;
802: }
803:
804: public Product copy(String newId) {
805: if (newId == null) {
806: newId = getId();
807: }
808: Product product = new Product();
809: product.setId(newId);
810: product.setName(getName());
811: product.setDescription(getDescription());
812: product.setHandlingChargeLevel(getHandlingChargeLevel());
813: product.setOptions(getOptions());
814: product.setOrdering(getOrdering());
815: product.setDepartment(getDepartment());
816: product.setPriceSupport(getPriceSupport());
817: product.setKeywords(getKeywords());
818: product.setProperties(new HashMap(getProperties()));
819: product.setAvailable(isAvailable());
820:
821: product.setDefaultCatalog(getDefaultCatalog());
822: product.setDeliveryType(getDeliveryType());
823: product.setShippingMethodId(getShippingMethodId());
824: product.setCustomPrice(isCustomPrice());
825: product.setTaxExempt(isTaxExempt());
826:
827: product.setInventoryItems(null);
828: int count = 1;
829: for (Iterator iterator = getInventoryItems().iterator(); iterator
830: .hasNext();) {
831: InventoryItem newItem, item = (InventoryItem) iterator
832: .next();
833: newItem = item.copy();
834: newItem.setProduct(product);
835: newItem.setSku(product.getId() + "-" + count);
836: product.addInventoryItem(newItem);
837: }
838:
839: Set catalogs = getCatalogs();
840: for (Iterator iter = catalogs.iterator(); iter.hasNext();) {
841: Category element = (Category) iter.next();
842: product.addCatalog(element);
843: }
844:
845: product.setOptions(null);
846: for (Iterator iterator = getOptions().iterator(); iterator
847: .hasNext();) {
848: Option newOption = ((Option) iterator.next()).copy();
849: product.addOption(newOption);
850: }
851:
852: product.setKeywords(null);
853: for (Iterator iterator = getKeywords().iterator(); iterator
854: .hasNext();) {
855: product.addKeyword((String) iterator.next());
856: }
857:
858: product.getRelatedProductIds().clear();
859: for (Iterator iterator = getRelatedProductIds().iterator(); iterator
860: .hasNext();) {
861: product.addRelatedProductId((String) iterator.next());
862: }
863:
864: return product;
865: }
866:
867: public Product copy() {
868: return copy(null);
869: }
870:
871: public void setCatalogs(Set inCatalogs) {
872: fieldCatalogs = inCatalogs;
873: }
874: }
|