001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.product.config;
019:
020: import java.io.Serializable;
021: import java.util.ArrayList;
022: import java.util.Date;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.HashMap;
027: import java.util.Locale;
028:
029: import org.ofbiz.base.util.UtilMisc;
030: import org.ofbiz.base.util.UtilValidate;
031: import org.ofbiz.entity.GenericDelegator;
032: import org.ofbiz.entity.GenericValue;
033: import org.ofbiz.entity.util.EntityUtil;
034: import org.ofbiz.service.LocalDispatcher;
035:
036: /**
037: * Product Config Wrapper: gets product config to display
038: */
039:
040: public class ProductConfigWrapper implements Serializable {
041:
042: public static final String module = ProductConfigWrapper.class
043: .getName();
044:
045: protected LocalDispatcher dispatcher;
046: protected GenericValue product = null; // the aggregated product
047: protected double basePrice = 0.0;
048: protected List questions = null; // ProductConfigs
049:
050: /** Creates a new instance of ProductConfigWrapper */
051: public ProductConfigWrapper() {
052: }
053:
054: public ProductConfigWrapper(GenericDelegator delegator,
055: LocalDispatcher dispatcher, String productId,
056: String productStoreId, String catalogId, String webSiteId,
057: String currencyUomId, Locale locale,
058: GenericValue autoUserLogin) throws Exception {
059: init(delegator, dispatcher, productId, productStoreId,
060: catalogId, webSiteId, currencyUomId, locale,
061: autoUserLogin);
062: }
063:
064: public ProductConfigWrapper(ProductConfigWrapper pcw) {
065: product = GenericValue.create(pcw.product);
066: basePrice = pcw.basePrice;
067: questions = new ArrayList();
068: for (int i = 0; i < pcw.questions.size(); i++) {
069: questions.add(new ConfigItem((ConfigItem) pcw.questions
070: .get(i)));
071: }
072: }
073:
074: private void init(GenericDelegator delegator,
075: LocalDispatcher dispatcher, String productId,
076: String productStoreId, String catalogId, String webSiteId,
077: String currencyUomId, Locale locale,
078: GenericValue autoUserLogin) throws Exception {
079: product = delegator.findByPrimaryKey("Product", UtilMisc.toMap(
080: "productId", productId));
081: if (product == null
082: || !product.getString("productTypeId").equals(
083: "AGGREGATED")) {
084: throw new ProductConfigWrapperException("Product "
085: + productId + " is not an AGGREGATED product.");
086: }
087: this .dispatcher = dispatcher;
088:
089: // get the base price
090: Map priceContext = UtilMisc.toMap("product", product,
091: "prodCatalogId", catalogId, "webSiteId", webSiteId,
092: "productStoreId", productStoreId, "currencyUomId",
093: currencyUomId, "autoUserLogin", autoUserLogin);
094: Map priceMap = dispatcher.runSync("calculateProductPrice",
095: priceContext);
096: Double price = (Double) priceMap.get("price");
097: if (price != null) {
098: basePrice = price.doubleValue();
099: }
100: questions = new ArrayList();
101: List questionsValues = new ArrayList();
102: if (product.getString("productTypeId") != null
103: && product.getString("productTypeId").equals(
104: "AGGREGATED")) {
105: questionsValues = delegator.findByAnd("ProductConfig",
106: UtilMisc.toMap("productId", productId), UtilMisc
107: .toList("sequenceNum"));
108: questionsValues = EntityUtil.filterByDate(questionsValues);
109: Iterator questionsValuesIt = questionsValues.iterator();
110: HashMap itemIds = new HashMap();
111: while (questionsValuesIt.hasNext()) {
112: ConfigItem oneQuestion = new ConfigItem(
113: (GenericValue) questionsValuesIt.next());
114: oneQuestion.setContent(locale, "text/html"); // TODO: mime-type shouldn't be hardcoded
115: if (itemIds.containsKey(oneQuestion.getConfigItem()
116: .getString("configItemId"))) {
117: oneQuestion.setFirst(false);
118: } else {
119: itemIds.put(oneQuestion.getConfigItem().getString(
120: "configItemId"), null);
121: }
122: questions.add(oneQuestion);
123: List configOptions = delegator.findByAnd(
124: "ProductConfigOption", UtilMisc.toMap(
125: "configItemId", oneQuestion
126: .getConfigItemAssoc()
127: .getString("configItemId")),
128: UtilMisc.toList("sequenceNum"));
129: Iterator configOptionsIt = configOptions.iterator();
130: while (configOptionsIt.hasNext()) {
131: ConfigOption option = new ConfigOption(delegator,
132: dispatcher, (GenericValue) configOptionsIt
133: .next(), catalogId, webSiteId,
134: currencyUomId, autoUserLogin);
135: oneQuestion.addOption(option);
136: }
137: }
138: }
139: }
140:
141: public void resetConfig() {
142: for (int i = 0; i < questions.size(); i++) {
143: ConfigItem ci = (ConfigItem) questions.get(i);
144: if (!ci.isStandard()) {
145: List options = ci.getOptions();
146: for (int j = 0; j < options.size(); j++) {
147: ConfigOption co = (ConfigOption) options.get(j);
148: co.setSelected(false);
149: }
150: }
151: }
152: }
153:
154: public void setDefaultConfig() {
155: resetConfig();
156: for (int i = 0; i < questions.size(); i++) {
157: ConfigItem ci = (ConfigItem) questions.get(i);
158: if (ci.isMandatory()) {
159: if (ci.getOptions().size() > 0) {
160: ConfigOption co = (ConfigOption) ci.getOptions()
161: .get(0);
162: co.setSelected(true);
163: }
164: }
165: }
166: }
167:
168: public boolean equals(Object obj) {
169: if (obj == null || !(obj instanceof ProductConfigWrapper)) {
170: return false;
171: }
172: ProductConfigWrapper cw = (ProductConfigWrapper) obj;
173: if (!product.getString("productId").equals(
174: cw.getProduct().getString("productId"))) {
175: return false;
176: }
177: List cwq = cw.getQuestions();
178: if (questions.size() != cwq.size()) {
179: return false;
180: }
181: for (int i = 0; i < questions.size(); i++) {
182: ConfigItem ci = (ConfigItem) questions.get(i);
183: if (!ci.equals(cwq.get(i))) {
184: return false;
185: }
186: }
187: return true;
188: }
189:
190: public String toString() {
191: return "" + questions;
192: }
193:
194: public List getQuestions() {
195: return questions;
196: }
197:
198: public GenericValue getProduct() {
199: return product;
200: }
201:
202: public void setSelected(int question, int option) throws Exception {
203: ConfigItem ci = (ConfigItem) questions.get(question);
204: List avalOptions = ci.getOptions();
205: if (ci.isSingleChoice()) {
206: for (int j = 0; j < avalOptions.size(); j++) {
207: ConfigOption oneOption = (ConfigOption) avalOptions
208: .get(j);
209: oneOption.setSelected(false);
210: }
211: }
212: ConfigOption theOption = null;
213: if (option >= 0 && option < avalOptions.size()) {
214: theOption = (ConfigOption) avalOptions.get(option);
215: }
216: if (theOption != null) {
217: theOption.setSelected(true);
218: }
219: }
220:
221: public List getSelectedOptions() {
222: List selectedOptions = new ArrayList();
223: for (int i = 0; i < questions.size(); i++) {
224: ConfigItem ci = (ConfigItem) questions.get(i);
225: if (ci.isStandard()) {
226: selectedOptions.addAll(ci.getOptions());
227: } else {
228: Iterator availOptions = ci.getOptions().iterator();
229: while (availOptions.hasNext()) {
230: ConfigOption oneOption = (ConfigOption) availOptions
231: .next();
232: if (oneOption.isSelected()) {
233: selectedOptions.add(oneOption);
234: }
235: }
236: }
237: }
238: return selectedOptions;
239: }
240:
241: public double getTotalPrice() {
242: double totalPrice = basePrice;
243: List options = getSelectedOptions();
244: for (int i = 0; i < options.size(); i++) {
245: ConfigOption oneOption = (ConfigOption) options.get(i);
246: totalPrice += oneOption.getPrice();
247: }
248: return totalPrice;
249: }
250:
251: public boolean isCompleted() {
252: boolean completed = true;
253: for (int i = 0; i < questions.size(); i++) {
254: ConfigItem ci = (ConfigItem) questions.get(i);
255: if (!ci.isStandard() && ci.isMandatory()) {
256: Iterator availOptions = ci.getOptions().iterator();
257: while (availOptions.hasNext()) {
258: ConfigOption oneOption = (ConfigOption) availOptions
259: .next();
260: if (oneOption.isSelected()) {
261: completed = true;
262: break;
263: } else {
264: completed = false;
265: }
266: }
267: if (!completed) {
268: break;
269: }
270: }
271: }
272: return completed;
273: }
274:
275: public class ConfigItem implements java.io.Serializable {
276: GenericValue configItem = null;
277: GenericValue configItemAssoc = null;
278: ProductConfigItemContentWrapper content = null;
279: List options = null;
280: boolean first = true;
281:
282: public ConfigItem(GenericValue questionAssoc) throws Exception {
283: configItemAssoc = questionAssoc;
284: configItem = configItemAssoc
285: .getRelatedOne("ConfigItemProductConfigItem");
286: options = new ArrayList();
287: }
288:
289: public ConfigItem(ConfigItem ci) {
290: configItem = GenericValue.create(ci.configItem);
291: configItemAssoc = GenericValue.create(ci.configItemAssoc);
292: options = new ArrayList();
293: for (int i = 0; i < ci.options.size(); i++) {
294: options.add(new ConfigOption((ConfigOption) ci.options
295: .get(i)));
296: }
297: first = ci.first;
298: content = ci.content; // FIXME: this should be cloned
299: }
300:
301: public void setContent(Locale locale, String mimeTypeId) {
302: content = new ProductConfigItemContentWrapper(dispatcher,
303: configItem, locale, mimeTypeId);
304: }
305:
306: public ProductConfigItemContentWrapper getContent() {
307: return content;
308: }
309:
310: public GenericValue getConfigItem() {
311: return configItem;
312: }
313:
314: public GenericValue getConfigItemAssoc() {
315: return configItemAssoc;
316: }
317:
318: public boolean isStandard() {
319: return configItemAssoc.getString("configTypeId").equals(
320: "STANDARD");
321: }
322:
323: public boolean isSingleChoice() {
324: return configItem.getString("configItemTypeId").equals(
325: "SINGLE");
326: }
327:
328: public boolean isMandatory() {
329: return configItemAssoc.getString("isMandatory") != null
330: && configItemAssoc.getString("isMandatory").equals(
331: "Y");
332: }
333:
334: public boolean isFirst() {
335: return first;
336: }
337:
338: public void setFirst(boolean newValue) {
339: first = newValue;
340: }
341:
342: public void addOption(ConfigOption option) {
343: options.add(option);
344: }
345:
346: public List getOptions() {
347: return options;
348: }
349:
350: public String getQuestion() {
351: String question = "";
352: if (UtilValidate.isNotEmpty(configItemAssoc
353: .getString("description"))) {
354: question = configItemAssoc.getString("description");
355: } else {
356: if (content != null) {
357: question = content.get("DESCRIPTION");
358: } else {
359: question = (configItem.getString("description") != null ? configItem
360: .getString("description")
361: : "");
362: }
363: }
364: return question;
365: }
366:
367: public String getDescription() {
368: String description = "";
369: if (UtilValidate.isNotEmpty(configItemAssoc
370: .getString("longDescription"))) {
371: description = configItemAssoc
372: .getString("longDescription");
373: } else {
374: if (content != null) {
375: description = content.get("LONG_DESCRIPTION");
376: } else {
377: description = (configItem
378: .getString("longDescription") != null ? configItem
379: .getString("longDescription")
380: : "");
381: }
382: }
383: return description;
384: }
385:
386: public boolean isSelected() {
387: if (isStandard())
388: return true;
389: Iterator availOptions = getOptions().iterator();
390: while (availOptions.hasNext()) {
391: ConfigOption oneOption = (ConfigOption) availOptions
392: .next();
393: if (oneOption.isSelected()) {
394: return true;
395: }
396: }
397: return false;
398: }
399:
400: public ConfigOption getSelected() {
401: Iterator availOptions = getOptions().iterator();
402: while (availOptions.hasNext()) {
403: ConfigOption oneOption = (ConfigOption) availOptions
404: .next();
405: if (oneOption.isSelected()) {
406: return oneOption;
407: }
408: }
409: return null;
410: }
411:
412: public boolean equals(Object obj) {
413: if (obj == null || !(obj instanceof ConfigItem)) {
414: return false;
415: }
416: ConfigItem ci = (ConfigItem) obj;
417: if (!configItem.getString("configItemId").equals(
418: ci.getConfigItem().getString("configItemId"))) {
419: return false;
420: }
421: List opts = ci.getOptions();
422: if (options.size() != opts.size()) {
423: return false;
424: }
425: for (int i = 0; i < options.size(); i++) {
426: ConfigOption co = (ConfigOption) options.get(i);
427: if (!co.equals(opts.get(i))) {
428: return false;
429: }
430: }
431: return true;
432: }
433:
434: public String toString() {
435: return configItem.getString("configItemId");
436: }
437: }
438:
439: public class ConfigOption implements java.io.Serializable {
440: double optionPrice = 0;
441: Date availabilityDate = null;
442: List componentList = null; // lists of ProductConfigProduct
443: GenericValue configOption = null;
444: boolean selected = false;
445: boolean available = true;
446:
447: public ConfigOption(GenericDelegator delegator,
448: LocalDispatcher dispatcher, GenericValue option,
449: String catalogId, String webSiteId,
450: String currencyUomId, GenericValue autoUserLogin)
451: throws Exception {
452: configOption = option;
453: componentList = option
454: .getRelated("ConfigOptionProductConfigProduct");
455: Iterator componentsIt = componentList.iterator();
456: while (componentsIt.hasNext()) {
457: double price = 0;
458: GenericValue oneComponent = (GenericValue) componentsIt
459: .next();
460: // Get the component's price
461: Map fieldMap = UtilMisc.toMap("product", oneComponent
462: .getRelatedOne("ProductProduct"),
463: "prodCatalogId", catalogId, "webSiteId",
464: webSiteId, "currencyUomId", currencyUomId,
465: "productPricePurposeId", "COMPONENT_PRICE",
466: "autoUserLogin", autoUserLogin);
467: Map priceMap = dispatcher.runSync(
468: "calculateProductPrice", fieldMap);
469: Double componentPrice = (Double) priceMap.get("price");
470: double mult = 1;
471: if (oneComponent.getDouble("quantity") != null) {
472: mult = oneComponent.getDouble("quantity")
473: .doubleValue();
474: }
475: if (mult == 0) {
476: mult = 1;
477: }
478: if (componentPrice != null) {
479: price = componentPrice.doubleValue();
480: } else {
481: fieldMap.put("productPricePurposeId", "PURCHASE");
482: Map purchasePriceResultMap = dispatcher.runSync(
483: "calculateProductPrice", fieldMap);
484: Double purchasePrice = (Double) purchasePriceResultMap
485: .get("price");
486: if (purchasePrice != null) {
487: price = purchasePrice.doubleValue();
488: }
489: }
490: optionPrice += (price * mult);
491: // TODO: get the component's availability date
492: }
493: }
494:
495: public ConfigOption(ConfigOption co) {
496: configOption = GenericValue.create(co.configOption);
497: componentList = new ArrayList();
498: for (int i = 0; i < co.componentList.size(); i++) {
499: componentList
500: .add(GenericValue
501: .create((GenericValue) co.componentList
502: .get(i)));
503: }
504: optionPrice = co.optionPrice;
505: available = co.available;
506: selected = co.selected;
507: }
508:
509: public String getDescription() {
510: return (configOption.getString("description") != null ? configOption
511: .getString("description")
512: : "no description");
513: }
514:
515: public double getPrice() {
516: return optionPrice;
517: }
518:
519: public boolean isSelected() {
520: return selected;
521: }
522:
523: public void setSelected(boolean newValue) {
524: selected = newValue;
525: }
526:
527: public boolean isAvailable() {
528: return available;
529: }
530:
531: public void setAvailable(boolean newValue) {
532: available = newValue;
533: }
534:
535: public List getComponents() {
536: return componentList;
537: }
538:
539: public boolean equals(Object obj) {
540: if (obj == null || !(obj instanceof ConfigOption)) {
541: return false;
542: }
543: ConfigOption co = (ConfigOption) obj;
544: // TODO: we should compare also the GenericValues
545:
546: return isSelected() == co.isSelected();
547: }
548:
549: public String toString() {
550: return configOption.getString("configItemId") + "/"
551: + configOption.getString("configOptionId")
552: + (isSelected() ? "*" : "");
553: }
554:
555: }
556:
557: }
|