1 17 18 package org.ofbiz.manufacturing.bom; 19 20 import java.sql.Timestamp ; 21 import java.util.ArrayList ; 22 import java.util.Date ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.Map ; 27 28 import org.ofbiz.base.util.Debug; 29 import org.ofbiz.base.util.UtilDateTime; 30 import org.ofbiz.base.util.UtilMisc; 31 import org.ofbiz.entity.GenericDelegator; 32 import org.ofbiz.entity.GenericEntityException; 33 import org.ofbiz.entity.GenericValue; 34 import org.ofbiz.entity.util.EntityUtil; 35 import org.ofbiz.service.GenericServiceException; 36 import org.ofbiz.service.LocalDispatcher; 37 38 41 42 public class BOMNode { 43 public static final String module = BOMNode.class.getName(); 44 45 protected LocalDispatcher dispatcher = null; 46 protected GenericDelegator delegator = null; 47 protected GenericValue userLogin = null; 48 49 private BOMTree tree; private BOMNode parentNode; private BOMNode substitutedNode; private GenericValue ruleApplied; private String productForRules; 54 private GenericValue product; private GenericValue productAssoc; private ArrayList children; private ArrayList childrenNodes; private double quantityMultiplier; private double scrapFactor; private int depth; private double quantity; private String bomTypeId; 65 public BOMNode(GenericValue product, LocalDispatcher dispatcher, GenericValue userLogin) { 66 this.product = product; 67 this.delegator = product.getDelegator(); 68 this.dispatcher = dispatcher; 69 this.userLogin = userLogin; 70 children = new ArrayList (); 71 childrenNodes = new ArrayList (); 72 parentNode = null; 73 productForRules = null; 74 bomTypeId = null; 75 quantityMultiplier = 1; 76 scrapFactor = 1; 77 depth = 0; 79 quantity = 0; 80 } 81 82 public BOMNode(String productId, GenericDelegator delegator, LocalDispatcher dispatcher, GenericValue userLogin) throws GenericEntityException { 83 this(delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId", productId)), dispatcher, userLogin); 84 } 85 86 protected void loadChildren(String partBomTypeId, Date inDate, List productFeatures, int type) throws GenericEntityException { 87 if (product == null) { 88 throw new GenericEntityException("product is null"); 89 } 90 if (inDate == null) inDate = new Date (); 92 bomTypeId = partBomTypeId; 93 List rows = delegator.findByAnd("ProductAssoc", 95 UtilMisc.toMap("productId", product.get("productId"), 96 "productAssocTypeId", partBomTypeId), 97 UtilMisc.toList("sequenceNum")); 98 rows = EntityUtil.filterByDate(rows, inDate); 99 if ((rows == null || rows.size() == 0) && substitutedNode != null) { 100 rows = delegator.findByAnd("ProductAssoc", 103 UtilMisc.toMap("productId", substitutedNode.getProduct().get("productId"), 104 "productAssocTypeId", partBomTypeId), 105 UtilMisc.toList("sequenceNum")); 106 rows = EntityUtil.filterByDate(rows, inDate); 107 } 108 children = new ArrayList (rows); 109 childrenNodes = new ArrayList (); 110 Iterator childrenIterator = children.iterator(); 111 GenericValue oneChild = null; 112 BOMNode oneChildNode = null; 113 while(childrenIterator.hasNext()) { 114 oneChild = (GenericValue)childrenIterator.next(); 115 oneChildNode = configurator(oneChild, productFeatures, getRootNode().getProductForRules(), inDate); 117 if (oneChildNode != null) { 119 oneChildNode.setParentNode(this); 120 switch (type) { 121 case BOMTree.EXPLOSION: 122 oneChildNode.loadChildren(partBomTypeId, inDate, productFeatures, BOMTree.EXPLOSION); 123 break; 124 case BOMTree.EXPLOSION_MANUFACTURING: 125 if (!oneChildNode.isWarehouseManaged()) { 126 oneChildNode.loadChildren(partBomTypeId, inDate, productFeatures, type); 127 } 128 break; 129 } 130 } 131 childrenNodes.add(oneChildNode); 132 } 133 } 134 135 private BOMNode substituteNode(BOMNode oneChildNode, List productFeatures, List productPartRules) throws GenericEntityException { 136 if (productPartRules != null) { 137 GenericValue rule = null; 138 for (int i = 0; i < productPartRules.size(); i++) { 139 rule = (GenericValue)productPartRules.get(i); 140 String ruleCondition = (String )rule.get("productFeature"); 141 String ruleOperator = (String )rule.get("ruleOperator"); 142 String newPart = (String )rule.get("productIdInSubst"); 143 double ruleQuantity = 0; 144 try { 145 ruleQuantity = rule.getDouble("quantity").doubleValue(); 146 } catch(Exception exc) { 147 ruleQuantity = 0; 148 } 149 150 GenericValue feature = null; 151 boolean ruleSatisfied = false; 152 if (ruleCondition == null || ruleCondition.equals("")) { 153 ruleSatisfied = true; 154 } else { 155 if (productFeatures != null) { 156 for (int j = 0; j < productFeatures.size(); j++) { 157 feature = (GenericValue)productFeatures.get(j); 158 if (ruleCondition.equals((String )feature.get("productFeatureId"))) { 159 ruleSatisfied = true; 160 break; 161 } 162 } 163 } 164 } 165 if (ruleSatisfied && ruleOperator.equals("OR")) { 166 BOMNode tmpNode = oneChildNode; 167 if (newPart == null || newPart.equals("")) { 168 oneChildNode = null; 169 } else { 170 BOMNode origNode = oneChildNode; 171 oneChildNode = new BOMNode(newPart, delegator, dispatcher, userLogin); 172 oneChildNode.setTree(tree); 173 oneChildNode.setSubstitutedNode(tmpNode); 174 oneChildNode.setRuleApplied(rule); 175 oneChildNode.setProductAssoc(origNode.getProductAssoc()); 176 oneChildNode.setScrapFactor(origNode.getScrapFactor()); 177 if (ruleQuantity > 0) { 178 oneChildNode.setQuantityMultiplier(ruleQuantity); 179 } else { 180 oneChildNode.setQuantityMultiplier(origNode.getQuantityMultiplier()); 181 } 182 } 183 break; 184 } 185 } 188 } 189 return oneChildNode; 190 } 191 192 private BOMNode configurator(GenericValue node, List productFeatures, String productIdForRules, Date inDate) throws GenericEntityException { 193 BOMNode oneChildNode = new BOMNode((String )node.get("productIdTo"), delegator, dispatcher, userLogin); 194 oneChildNode.setTree(tree); 195 oneChildNode.setProductAssoc(node); 196 try { 197 oneChildNode.setQuantityMultiplier(node.getDouble("quantity").doubleValue()); 198 } catch(Exception nfe) { 199 oneChildNode.setQuantityMultiplier(1); 200 } 201 try { 202 double percScrapFactor = node.getDouble("scrapFactor").doubleValue(); 203 if (percScrapFactor >= 0 && percScrapFactor < 100) { 204 percScrapFactor = 1 + percScrapFactor / 100; 205 } else { 206 percScrapFactor = 1; 207 } 208 oneChildNode.setScrapFactor(percScrapFactor); 209 } catch(Exception nfe) { 210 oneChildNode.setScrapFactor(1); 211 } 212 BOMNode newNode = oneChildNode; 213 if (oneChildNode.isVirtual()) { 215 List productPartRules = delegator.findByAnd("ProductManufacturingRule", 219 UtilMisc.toMap("productId", productIdForRules, 220 "productIdFor", node.get("productId"), 221 "productIdIn", node.get("productIdTo"))); 222 if (substitutedNode != null) { 223 productPartRules.addAll(delegator.findByAnd("ProductManufacturingRule", 224 UtilMisc.toMap("productId", productIdForRules, 225 "productIdFor", substitutedNode.getProduct().getString("productId"), 226 "productIdIn", node.get("productIdTo")))); 227 } 228 productPartRules = EntityUtil.filterByDate(productPartRules, inDate); 229 newNode = substituteNode(oneChildNode, productFeatures, productPartRules); 230 if (newNode == oneChildNode) { 231 List genericLinkRules = delegator.findByAnd("ProductManufacturingRule", 234 UtilMisc.toMap("productIdFor", node.get("productId"), 235 "productIdIn", node.get("productIdTo"))); 236 if (substitutedNode != null) { 237 genericLinkRules.addAll(delegator.findByAnd("ProductManufacturingRule", 238 UtilMisc.toMap("productIdFor", substitutedNode.getProduct().getString("productId"), 239 "productIdIn", node.get("productIdTo")))); 240 } 241 genericLinkRules = EntityUtil.filterByDate(genericLinkRules, inDate); 242 newNode = null; 243 newNode = substituteNode(oneChildNode, productFeatures, genericLinkRules); 244 if (newNode == oneChildNode) { 245 List genericNodeRules = delegator.findByAnd("ProductManufacturingRule", 248 UtilMisc.toMap("productIdIn", node.get("productIdTo")), 249 UtilMisc.toList("ruleSeqId")); 250 genericNodeRules = EntityUtil.filterByDate(genericNodeRules, inDate); 251 newNode = null; 252 newNode = substituteNode(oneChildNode, productFeatures, genericNodeRules); 253 if (newNode == oneChildNode) { 254 if (genericNodeRules != null && genericNodeRules.size() > 0) { 257 } 260 if (newNode == oneChildNode) { 263 Map selectedFeatures = new HashMap (); 264 if (productFeatures != null) { 265 GenericValue feature = null; 266 for (int j = 0; j < productFeatures.size(); j++) { 267 feature = (GenericValue)productFeatures.get(j); 268 selectedFeatures.put((String )feature.get("productFeatureTypeId"), (String )feature.get("productFeatureId")); } 270 } 271 272 if (selectedFeatures.size() > 0) { 273 Map context = new HashMap (); 274 context.put("productId", node.get("productIdTo")); 275 context.put("selectedFeatures", selectedFeatures); 276 Map storeResult = null; 277 GenericValue variantProduct = null; 278 try { 279 storeResult = dispatcher.runSync("getProductVariant", context); 280 List variantProducts = (List ) storeResult.get("products"); 281 if (variantProducts.size() == 1) { 282 variantProduct = (GenericValue)variantProducts.get(0); 283 } 284 } catch (GenericServiceException e) { 285 String service = e.getMessage(); 286 if (Debug.infoOn()) Debug.logInfo("Error calling getProductVariant service", module); 287 } 288 if (variantProduct != null) { 289 newNode = new BOMNode(variantProduct, dispatcher, userLogin); 290 newNode.setTree(tree); 291 newNode.setSubstitutedNode(oneChildNode); 292 newNode.setQuantityMultiplier(oneChildNode.getQuantityMultiplier()); 293 newNode.setScrapFactor(oneChildNode.getScrapFactor()); 294 newNode.setProductAssoc(oneChildNode.getProductAssoc()); 295 } 296 } 297 298 } 299 } 301 } 302 } 303 } return newNode; 305 } 306 307 protected void loadParents(String partBomTypeId, Date inDate, List productFeatures) throws GenericEntityException { 308 if (product == null) { 309 throw new GenericEntityException("product is null"); 310 } 311 if (inDate == null) inDate = new Date (); 313 314 bomTypeId = partBomTypeId; 315 List rows = delegator.findByAnd("ProductAssoc", 317 UtilMisc.toMap("productIdTo", product.get("productId"), 318 "productAssocTypeId", partBomTypeId), 319 UtilMisc.toList("sequenceNum")); 320 rows = EntityUtil.filterByDate(rows, inDate); 321 if ((rows == null || rows.size() == 0) && substitutedNode != null) { 322 rows = delegator.findByAnd("ProductAssoc", 325 UtilMisc.toMap("productIdTo", substitutedNode.getProduct().get("productId"), 326 "productAssocTypeId", partBomTypeId), 327 UtilMisc.toList("sequenceNum")); 328 rows = EntityUtil.filterByDate(rows, inDate); 329 } 330 children = new ArrayList (rows); 331 childrenNodes = new ArrayList (); 332 Iterator childrenIterator = children.iterator(); 333 GenericValue oneChild = null; 334 BOMNode oneChildNode = null; 335 while(childrenIterator.hasNext()) { 336 oneChild = (GenericValue)childrenIterator.next(); 337 oneChildNode = new BOMNode(oneChild.getString("productId"), delegator, dispatcher, userLogin); 338 if (oneChildNode != null) { 342 oneChildNode.setParentNode(this); 343 oneChildNode.setTree(tree); 344 oneChildNode.loadParents(partBomTypeId, inDate, productFeatures); 345 } 346 childrenNodes.add(oneChildNode); 347 } 348 } 349 350 351 355 public BOMNode getParentNode() { 356 return parentNode; 357 } 358 359 public BOMNode getRootNode() { 360 return (parentNode != null? getParentNode(): this); 361 } 362 366 public void setParentNode(BOMNode parentNode) { 367 this.parentNode = parentNode; 368 } 369 public void print(StringBuffer sb, double quantity, int depth) { 372 for (int i = 0; i < depth; i++) { 373 sb.append("<b> * </b>"); 374 } 375 sb.append(product.get("productId")); 376 sb.append(" - "); 377 sb.append("" + quantity); 378 GenericValue oneChild = null; 379 BOMNode oneChildNode = null; 380 depth++; 381 for (int i = 0; i < children.size(); i++) { 382 oneChild = (GenericValue)children.get(i); 383 double bomQuantity = 0; 384 try { 385 bomQuantity = oneChild.getDouble("quantity").doubleValue(); 386 } catch(Exception exc) { 387 bomQuantity = 1; 388 } 389 oneChildNode = (BOMNode)childrenNodes.get(i); 390 sb.append("<br/>"); 391 if (oneChildNode != null) { 392 oneChildNode.print(sb, (quantity * bomQuantity), depth); 393 } 394 } 395 } 396 397 public void print(ArrayList arr, double quantity, int depth, boolean excludeWIPs) { 398 this.depth = depth; 401 String serviceName = null; 403 if (this.productAssoc != null && this.productAssoc.getString("estimateCalcMethod") != null) { 404 try { 405 GenericValue genericService = productAssoc.getRelatedOne("CustomMethod"); 406 if (genericService != null && genericService.getString("customMethodName") != null) { 407 serviceName = genericService.getString("customMethodName"); 408 } 409 } catch(Exception exc) { 410 } 411 } 412 if (serviceName != null) { 413 Map resultContext = null; 414 Map arguments = UtilMisc.toMap("neededQuantity", new Double (quantity * quantityMultiplier), "amount", new Double ((tree!=null? tree.getRootAmount():0))); 415 Double width = null; 416 if (getProduct().get("productWidth") != null) { 417 width = getProduct().getDouble("productWidth"); 418 } 419 if (width == null) { 420 width = new Double (0); 421 } 422 arguments.put("width", width); 423 Map inputContext = UtilMisc.toMap("arguments", arguments, "userLogin", userLogin); 424 try { 425 resultContext = dispatcher.runSync(serviceName, inputContext); 426 Double calcQuantity = (Double )resultContext.get("quantity"); 427 if (calcQuantity != null) { 428 this.quantity = calcQuantity.doubleValue(); 429 } 430 } catch (GenericServiceException e) { 431 } 433 } else { 434 this.quantity = quantity * quantityMultiplier * scrapFactor; 435 } 436 arr.add(this); 438 GenericValue oneChild = null; 440 BOMNode oneChildNode = null; 441 depth++; 442 for (int i = 0; i < children.size(); i++) { 443 oneChild = (GenericValue)children.get(i); 444 oneChildNode = (BOMNode)childrenNodes.get(i); 445 if (excludeWIPs && "WIP".equals(oneChildNode.getProduct().getString("productTypeId"))) { 446 continue; 447 } 448 if (oneChildNode != null) { 449 oneChildNode.print(arr, this.quantity, depth, excludeWIPs); 450 } 451 } 452 } 453 454 public void getProductsInPackages(ArrayList arr, double quantity, int depth, boolean excludeWIPs) { 455 this.depth = depth; 458 this.quantity = quantity * quantityMultiplier * scrapFactor; 460 if (this.getProduct().getString("shipmentBoxTypeId") != null) { 462 arr.add(this); 463 } else { 464 GenericValue oneChild = null; 465 BOMNode oneChildNode = null; 466 depth++; 467 for (int i = 0; i < children.size(); i++) { 468 oneChild = (GenericValue)children.get(i); 469 oneChildNode = (BOMNode)childrenNodes.get(i); 470 if (excludeWIPs && "WIP".equals(oneChildNode.getProduct().getString("productTypeId"))) { 471 continue; 472 } 473 if (oneChildNode != null) { 474 oneChildNode.getProductsInPackages(arr, this.quantity, depth, excludeWIPs); 475 } 476 } 477 } 478 } 479 480 public void sumQuantity(HashMap nodes) { 481 BOMNode sameNode = (BOMNode)nodes.get(product.getString("productId")); 483 if (sameNode == null) { 485 sameNode = new BOMNode(product, dispatcher, userLogin); 486 nodes.put(product.getString("productId"), sameNode); 487 } 488 sameNode.setQuantity(sameNode.getQuantity() + quantity); 490 BOMNode oneChildNode = null; 492 for (int i = 0; i < childrenNodes.size(); i++) { 493 oneChildNode = (BOMNode)childrenNodes.get(i); 494 if (oneChildNode != null) { 495 oneChildNode.sumQuantity(nodes); 496 } 497 } 498 } 499 500 public String createManufacturingOrder(String orderId, String orderItemSeqId, String shipmentId, String facilityId, Date date, boolean useSubstitute) throws GenericEntityException { 501 String productionRunId = null; 502 if (isManufactured()) { 503 BOMNode oneChildNode = null; 504 ArrayList childProductionRuns = new ArrayList (); 505 for (int i = 0; i < childrenNodes.size(); i++) { 506 oneChildNode = (BOMNode)childrenNodes.get(i); 507 if (oneChildNode != null) { 508 String childProductionRunId = oneChildNode.createManufacturingOrder(null, null, shipmentId, facilityId, date, false); 509 if (childProductionRunId != null) { 510 childProductionRuns.add(childProductionRunId); 511 } 512 } 513 } 514 515 Timestamp startDate = UtilDateTime.toTimestamp(UtilDateTime.toDateTimeString(date)); 516 Map serviceContext = new HashMap (); 517 if (!useSubstitute) { 518 serviceContext.put("productId", getProduct().getString("productId")); 519 serviceContext.put("facilityId", getProduct().getString("facilityId")); 520 } else { 521 serviceContext.put("productId", getSubstitutedNode().getProduct().getString("productId")); 522 serviceContext.put("facilityId", getSubstitutedNode().getProduct().getString("facilityId")); 523 } 524 if (facilityId != null) { 525 serviceContext.put("facilityId", facilityId); 526 } 527 if (shipmentId != null) { 528 serviceContext.put("workEffortName", "SP_" + shipmentId + "_" + serviceContext.get("productId")); 529 } 530 serviceContext.put("pRQuantity", new Double (getQuantity())); 531 serviceContext.put("startDate", startDate); 532 serviceContext.put("userLogin", userLogin); 533 Map resultService = null; 534 try { 535 resultService = dispatcher.runSync("createProductionRun", serviceContext); 536 productionRunId = (String )resultService.get("productionRunId"); 537 } catch (GenericServiceException e) { 538 Debug.logError("Problem calling the createProductionRun service", module); 539 } 540 try { 541 if (productionRunId != null) { 542 if (orderId != null && orderItemSeqId != null) { 543 delegator.create("WorkOrderItemFulfillment", UtilMisc.toMap("workEffortId", productionRunId, "orderId", orderId, "orderItemSeqId", orderItemSeqId)); 544 } 545 for (int i = 0; i < childProductionRuns.size(); i++) { 546 delegator.create("WorkEffortAssoc", UtilMisc.toMap("workEffortIdFrom", (String )childProductionRuns.get(i), "workEffortIdTo", productionRunId, "workEffortAssocTypeId", "WORK_EFF_PRECEDENCY", "fromDate", startDate)); 547 } 548 } 549 } catch (GenericEntityException e) { 550 } 552 } 553 return productionRunId; 554 } 555 556 public boolean isWarehouseManaged() { 557 boolean isWarehouseManaged = false; 558 try { 559 if ("WIP".equals(getProduct().getString("productTypeId"))) { 560 return false; 561 } 562 List pfs = getProduct().getRelatedCache("ProductFacility"); 563 Iterator pfsIt = pfs.iterator(); 564 GenericValue pf = null; 565 boolean found = false; 566 while(pfsIt.hasNext()) { 567 found = true; 568 pf = (GenericValue)pfsIt.next(); 569 if (pf.getDouble("minimumStock") != null && pf.getDouble("minimumStock").doubleValue() > 0) { 570 isWarehouseManaged = true; 571 } 572 } 573 if (!found && getSubstitutedNode() != null) { 575 pfs = getSubstitutedNode().getProduct().getRelatedCache("ProductFacility"); 576 pfsIt = pfs.iterator(); 577 pf = null; 578 while(pfsIt.hasNext()) { 579 pf = (GenericValue)pfsIt.next(); 580 if (pf.getDouble("minimumStock") != null && pf.getDouble("minimumStock").doubleValue() > 0) { 581 isWarehouseManaged = true; 582 } 583 } 584 } 585 } catch(GenericEntityException gee) { 586 Debug.logError("Problem in BOMNode.isWarehouseManaged()", module); 587 } 588 return isWarehouseManaged; 589 } 590 591 public boolean isManufactured() { 592 return childrenNodes.size() > 0; 593 } 594 595 public boolean isVirtual() { 596 return (product.get("isVirtual") != null? product.get("isVirtual").equals("Y"): false); 597 } 598 599 public void isConfigured(ArrayList arr) { 600 if (isVirtual()) { 602 arr.add(this); 603 } 604 GenericValue oneChild = null; 606 BOMNode oneChildNode = null; 607 for (int i = 0; i < children.size(); i++) { 608 oneChild = (GenericValue)children.get(i); 609 oneChildNode = (BOMNode)childrenNodes.get(i); 610 if (oneChildNode != null) { 611 oneChildNode.isConfigured(arr); 612 } 613 } 614 } 615 616 617 621 public double getQuantity() { 622 return quantity; 623 } 624 625 public void setQuantity(double quantity) { 626 this.quantity = quantity; 627 } 628 629 633 634 public int getDepth() { 635 return depth; 636 } 637 638 public GenericValue getProduct() { 639 return product; 640 } 641 642 646 public BOMNode getSubstitutedNode() { 647 return substitutedNode; 648 } 649 650 654 public void setSubstitutedNode(BOMNode substitutedNode) { 655 this.substitutedNode = substitutedNode; 656 } 657 658 public String getRootProductForRules() { 659 return getParentNode().getProductForRules(); 660 } 661 662 666 public String getProductForRules() { 667 return productForRules; 668 } 669 670 674 public void setProductForRules(String productForRules) { 675 this.productForRules = productForRules; 676 } 677 678 682 public java.lang.String getBomTypeId() { 683 return bomTypeId; 684 } 685 686 690 public double getQuantityMultiplier() { 691 return quantityMultiplier; 692 } 693 694 698 public void setQuantityMultiplier(double quantityMultiplier) { 699 this.quantityMultiplier = quantityMultiplier; 700 } 701 702 706 public org.ofbiz.entity.GenericValue getRuleApplied() { 707 return ruleApplied; 708 } 709 710 714 public void setRuleApplied(org.ofbiz.entity.GenericValue ruleApplied) { 715 this.ruleApplied = ruleApplied; 716 } 717 718 722 public double getScrapFactor() { 723 return scrapFactor; 724 } 725 726 730 public void setScrapFactor(double scrapFactor) { 731 this.scrapFactor = scrapFactor; 732 } 733 734 738 public java.util.ArrayList getChildrenNodes() { 739 return childrenNodes; 740 } 741 742 746 public void setChildrenNodes(java.util.ArrayList childrenNodes) { 747 this.childrenNodes = childrenNodes; 748 } 749 750 754 public org.ofbiz.entity.GenericValue getProductAssoc() { 755 return productAssoc; 756 } 757 758 762 public void setProductAssoc(org.ofbiz.entity.GenericValue productAssoc) { 763 this.productAssoc = productAssoc; 764 } 765 766 public void setTree(BOMTree tree) { 767 this.tree = tree; 768 } 769 770 public BOMTree getTree() { 771 return tree; 772 } 773 774 } 775 776 | Popular Tags |