001: /*
002: * ItemConfigurationTree.java
003: *
004: * Created on 1 ottobre 2003, 17.16
005: */
006:
007: package org.ofbiz.manufacturing.bom;
008:
009: import java.util.Date;
010: import java.util.Map;
011: import java.util.List;
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.HashMap;
015:
016: import org.ofbiz.base.util.UtilMisc;
017: import org.ofbiz.entity.util.EntityUtil;
018:
019: import org.ofbiz.entity.GenericValue;
020: import org.ofbiz.entity.GenericDelegator;
021: import org.ofbiz.entity.GenericEntityException;
022:
023: /** It represents an (in-memory) bill of materials (in which each
024: * component is an ItemConfigurationNode)
025: * Useful for tree traversal (breakdown, explosion, implosion).
026: * @author <a href="mailto:tiz@sastau.it">Jacopo Cappellato</a>
027: */
028:
029: public class ItemConfigurationTree {
030:
031: ItemConfigurationNode root;
032: float rootQuantity;
033: Date inDate;
034: String bomTypeId;
035:
036: /** Creates a new instance of ItemConfigurationTree by reading downward
037: * the productId's bill of materials (explosion).
038: * If virtual products are found, it tries to configure them by running
039: * the Product Configurator.
040: * @param productId The product for which we want to get the bom.
041: * @param bomTypeId The bill of materials type (e.g. manufacturing, engineering, ...)
042: * @param inDate Validity date (if null, today is used).
043: *
044: * @param delegator The delegator used.
045: * @throws GenericEntityException If a db problem occurs.
046: *
047: */
048: public ItemConfigurationTree(String productId, String bomTypeId,
049: Date inDate, GenericDelegator delegator)
050: throws GenericEntityException {
051: this (productId, bomTypeId, inDate, true, delegator);
052: }
053:
054: /** Creates a new instance of ItemConfigurationTree by reading
055: * the productId's bill of materials (upward or downward).
056: * If virtual products are found, it tries to configure them by running
057: * the Product Configurator.
058: * @param productId The product for which we want to get the bom.
059: * @param bomTypeId The bill of materials type (e.g. manufacturing, engineering, ...)
060: * @param inDate Validity date (if null, today is used).
061: *
062: * @param explosion if true, a downward visit is performed (explosion);
063: * otherwise an upward visit is done (implosion).
064: *
065: * @param delegator The delegator used.
066: * @throws GenericEntityException If a db problem occurs.
067: *
068: */
069: public ItemConfigurationTree(String productId, String bomTypeId,
070: Date inDate, boolean explosion, GenericDelegator delegator)
071: throws GenericEntityException {
072: // If the parameters are not valid, return.
073: if (productId == null || bomTypeId == null || delegator == null)
074: return;
075: // If the date is null, set it to today.
076: if (inDate == null)
077: inDate = new Date();
078:
079: String productIdForRules = productId;
080: // The selected product features are loaded
081: List productFeatures = delegator.findByAnd(
082: "ProductFeatureAppl", UtilMisc.toMap("productId",
083: productId, "productFeatureApplTypeId",
084: "STANDARD_FEATURE"));
085:
086: // If the product is manufactured as a different product,
087: // load the new product
088: GenericValue manufacturedAsProduct = manufacturedAsProduct(
089: productId, inDate, delegator);
090: // We load the information about the product that needs to be manufactured
091: // from Product entity
092: GenericValue product = delegator
093: .findByPrimaryKey(
094: "Product",
095: UtilMisc
096: .toMap(
097: "productId",
098: (manufacturedAsProduct != null ? manufacturedAsProduct
099: .getString("productIdTo")
100: : productId)));
101: if (product == null)
102: return;
103: // If the product hasn't a bill of materials we try to retrieve
104: // the bill of materials of its virtual product (if the current
105: // product is variant).
106: if (!hasBom(product, inDate)
107: && product.get("isVariant") != null
108: && product.getString("isVariant").equals("Y")) {
109: List virtualProducts = product.getRelatedByAnd(
110: "AssocProductAssoc", UtilMisc.toMap(
111: "productAssocTypeId", "PRODUCT_VARIANT"));
112: virtualProducts = EntityUtil.filterByDate(virtualProducts,
113: inDate);
114: if (virtualProducts != null && virtualProducts.size() > 0) {
115: GenericValue virtualProduct = (GenericValue) virtualProducts
116: .get(0);
117: // If the virtual product is manufactured as a different product,
118: // load the new product
119: productIdForRules = virtualProduct
120: .getString("productId");
121: manufacturedAsProduct = manufacturedAsProduct(
122: virtualProduct.getString("productId"), inDate,
123: delegator);
124: product = delegator
125: .findByPrimaryKey(
126: "Product",
127: UtilMisc
128: .toMap(
129: "productId",
130: (manufacturedAsProduct != null ? manufacturedAsProduct
131: .getString("productIdTo")
132: : virtualProduct
133: .get("productId"))));
134: }
135: }
136: if (product == null)
137: return;
138: try {
139: root = new ItemConfigurationNode(product);
140: root.setProductForRules(productIdForRules);
141: if (explosion) {
142: root.loadChildren(bomTypeId, inDate, productFeatures);
143: } else {
144: root.loadParents(bomTypeId, inDate, productFeatures);
145: }
146: } catch (GenericEntityException gee) {
147: root = null;
148: }
149: this .bomTypeId = bomTypeId;
150: this .inDate = inDate;
151: rootQuantity = 1;
152: }
153:
154: private GenericValue manufacturedAsProduct(String productId,
155: Date inDate, GenericDelegator delegator)
156: throws GenericEntityException {
157: List manufacturedAsProducts = delegator.findByAnd(
158: "ProductAssoc", UtilMisc.toMap("productId", productId,
159: "productAssocTypeId", "PRODUCT_MANUFACTURED"));
160: manufacturedAsProducts = EntityUtil.filterByDate(
161: manufacturedAsProducts, inDate);
162: GenericValue manufacturedAsProduct = null;
163: if (manufacturedAsProducts != null
164: && manufacturedAsProducts.size() > 0) {
165: manufacturedAsProduct = (GenericValue) manufacturedAsProducts
166: .get(0);
167: }
168: return manufacturedAsProduct;
169: }
170:
171: private boolean hasBom(GenericValue product, Date inDate)
172: throws GenericEntityException {
173: List children = product.getRelatedByAnd("MainProductAssoc",
174: UtilMisc.toMap("productAssocTypeId", bomTypeId));
175: children = EntityUtil.filterByDate(children, inDate);
176: return (children != null && children.size() > 0);
177: }
178:
179: /** It tells if the current (in-memory) tree representing
180: * a product's bill of materials is completely configured
181: * or not.
182: * @return true if no virtual nodes (products) are present in the tree.
183: *
184: */
185: public boolean isConfigured() {
186: ArrayList notConfiguredParts = new ArrayList();
187: root.isConfigured(notConfiguredParts);
188: return (notConfiguredParts.size() == 0);
189: }
190:
191: /** Getter for property rootQuantity.
192: * @return Value of property rootQuantity.
193: *
194: */
195: public float getRootQuantity() {
196: return rootQuantity;
197: }
198:
199: /** Setter for property rootQuantity.
200: * @param rootQuantity New value of property rootQuantity.
201: *
202: */
203: public void setRootQuantity(float rootQuantity) {
204: this .rootQuantity = rootQuantity;
205: }
206:
207: /** Getter for property root.
208: * @return Value of property root.
209: *
210: */
211: public ItemConfigurationNode getRoot() {
212: return root;
213: }
214:
215: /** Getter for property inDate.
216: * @return Value of property inDate.
217: *
218: */
219: public Date getInDate() {
220: return inDate;
221: }
222:
223: /** Getter for property bomTypeId.
224: * @return Value of property bomTypeId.
225: *
226: */
227: public String getBomTypeId() {
228: return bomTypeId;
229: }
230:
231: /** It visits the in-memory tree that represents a bill of materials
232: * and it collects info of its nodes in the StringBuffer.
233: * Method used for debug purposes.
234: * @param sb The StringBuffer used to collect tree info.
235: */
236: public void print(StringBuffer sb) {
237: if (root != null) {
238: root.print(sb, getRootQuantity(), 0);
239: }
240: }
241:
242: /** It visits the in-memory tree that represents a bill of materials
243: * and it collects info of its nodes in the ArrayList.
244: * Method used for bom breakdown (explosion/implosion).
245: * @param arr The ArrayList used to collect tree info.
246: */
247: public void print(ArrayList arr) {
248: if (root != null) {
249: root.print(arr, getRootQuantity(), 0);
250: }
251: }
252:
253: /** It visits the in-memory tree that represents a bill of materials
254: * and it collects info of its nodes in the HashMap.
255: * Method used for bom summarized explosion.
256: * @param quantityPerNode The HashMap that will contain the summarized quantities per productId.
257: */
258: public void sumQuantities(HashMap quantityPerNode) {
259: if (root != null) {
260: root.sumQuantity(quantityPerNode);
261: }
262: }
263:
264: /** It visits the in-memory tree that represents a bill of materials
265: * and it collects all the productId it contains.
266: * @return ArrayLsit conatining all the tree's productId.
267: */
268: public ArrayList getAllProductsId() {
269: ArrayList nodeArr = new ArrayList();
270: ArrayList productsId = new ArrayList();
271: print(nodeArr);
272: for (int i = 0; i < nodeArr.size(); i++) {
273: productsId.add(((ItemConfigurationNode) nodeArr.get(i))
274: .getPart().getString("productId"));
275: }
276: return productsId;
277: }
278: }
|