KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencrx > kernel > layer > application > Contracts


1 /*
2  * ====================================================================
3  * Project: opencrx, http://www.opencrx.org/
4  * Name: $Id: Contracts.java,v 1.71 2006/03/31 00:15:18 wfro Exp $
5  * Description: openCRX application plugin
6  * Revision: $Revision: 1.71 $
7  * Owner: CRIXP AG, Switzerland, http://www.crixp.com
8  * Date: $Date: 2006/03/31 00:15:18 $
9  * ====================================================================
10  *
11  * This software is published under the BSD license
12  * as listed below.
13  *
14  * Copyright (c) 2004-2006, CRIXP Corp., Switzerland
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * * Redistributions of source code must retain the above copyright
22  * notice, this list of conditions and the following disclaimer.
23  *
24  * * Redistributions in binary form must reproduce the above copyright
25  * notice, this list of conditions and the following disclaimer in
26  * the documentation and/or other materials provided with the
27  * distribution.
28  *
29  * * Neither the name of CRIXP Corp. nor the names of the contributors
30  * to openCRX may be used to endorse or promote products derived
31  * from this software without specific prior written permission
32  *
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
35  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
36  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
39  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
41  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
43  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46  * POSSIBILITY OF SUCH DAMAGE.
47  *
48  * ------------------
49  *
50  * This product includes software developed by the Apache Software
51  * Foundation (http://www.apache.org/).
52  *
53  * This product includes software developed by contributors to
54  * openMDX (http://www.openmdx.org/)
55  */

56
57 package org.opencrx.kernel.layer.application;
58
59 import java.io.ByteArrayOutputStream JavaDoc;
60 import java.io.PrintWriter JavaDoc;
61 import java.math.BigDecimal JavaDoc;
62 import java.text.DateFormat JavaDoc;
63 import java.text.ParseException JavaDoc;
64 import java.util.ArrayList JavaDoc;
65 import java.util.Arrays JavaDoc;
66 import java.util.Date JavaDoc;
67 import java.util.HashMap JavaDoc;
68 import java.util.HashSet JavaDoc;
69 import java.util.Iterator JavaDoc;
70 import java.util.List JavaDoc;
71 import java.util.Locale JavaDoc;
72 import java.util.Map JavaDoc;
73 import java.util.Set JavaDoc;
74
75 import org.opencrx.kernel.generic.OpenCrxException;
76 import org.openmdx.application.log.AppLog;
77 import org.openmdx.base.accessor.jmi.cci.RefPackage_1_0;
78 import org.openmdx.base.exception.ServiceException;
79 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSelectors;
80 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSpecifier;
81 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject;
82 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0;
83 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest;
84 import org.openmdx.compatibility.base.dataprovider.cci.Directions;
85 import org.openmdx.compatibility.base.dataprovider.cci.Orders;
86 import org.openmdx.compatibility.base.dataprovider.cci.RequestCollection;
87 import org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader;
88 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes;
89 import org.openmdx.compatibility.base.marshalling.Marshaller;
90 import org.openmdx.compatibility.base.naming.Path;
91 import org.openmdx.compatibility.base.query.FilterOperators;
92 import org.openmdx.compatibility.base.query.FilterProperty;
93 import org.openmdx.compatibility.base.query.Quantors;
94 import org.openmdx.kernel.exception.BasicException;
95 import org.openmdx.model1.accessor.basic.cci.Model_1_0;
96
97 public class Contracts {
98
99     //-----------------------------------------------------------------------
100
public Contracts(
101         Model_1_0 model,
102         OpenCrxKernel_1 plugin,
103         RequestCollection delegation,
104         RefPackage_1_0 rootPkg
105     ) {
106         this.model = model;
107         this.plugin = plugin;
108         this.delegation = delegation;
109         this.cloning = new Cloneable JavaDoc(
110             model,
111             plugin,
112             delegation,
113             rootPkg
114         );
115         this.rootPkg = rootPkg;
116     }
117
118     //-------------------------------------------------------------------------
119
static void copyAbstractContract(
120         DataproviderObject_1_0 from,
121         DataproviderObject to
122     ) throws ServiceException {
123         to.addClones(from, true);
124     }
125
126     //-------------------------------------------------------------------------
127
static void copyAbstractContractPosition(
128         DataproviderObject_1_0 from,
129         DataproviderObject to
130     ) throws ServiceException {
131         to.addClones(from, true);
132     }
133
134     //-------------------------------------------------------------------------
135
private DataproviderObject_1_0 getCachedDescription(
136         Path path,
137         int contractLanguage
138     ) throws ServiceException {
139         String JavaDoc key = path + ":" + contractLanguage;
140         DataproviderObject_1_0 description = (DataproviderObject_1_0)this.cachedDescriptions.get(key);
141         if((description == null) && !this.cachedDescriptions.containsKey(key)) {
142             description = this.plugin.getAdditionalDescription(
143                 path,
144                 contractLanguage
145             );
146             this.cachedDescriptions.put(
147                 key,
148                 description
149             );
150         }
151         return description;
152     }
153     
154     //-------------------------------------------------------------------------
155
private DataproviderObject_1_0 getCachedObject(
156         ServiceHeader header,
157         Path path
158     ) throws ServiceException {
159         DataproviderObject_1_0 object = (DataproviderObject_1_0)this.cachedObjects.get(path);
160         if((object == null) && !this.cachedObjects.containsKey(path)) {
161             object = this.plugin.retrieveObjectFromLocal(
162                 header,
163                 path
164             );
165             this.cachedObjects.put(
166                 object.path(),
167                 object
168             );
169         }
170         return object;
171     }
172     
173     //-------------------------------------------------------------------------
174
public void calculateContractPosition(
175         ServiceHeader header,
176         DataproviderObject_1_0 contract,
177         DataproviderObject_1_0 position
178     ) throws ServiceException {
179
180       // Retrieve DeliveryInformation and calculate quantity shipped
181
List JavaDoc deliveryInformations = this.delegation.addFindRequest(
182           position.path().getChild("deliveryInformation"),
183           null,
184           AttributeSelectors.ALL_ATTRIBUTES,
185           0,
186           Integer.MAX_VALUE,
187           Directions.ASCENDING
188       );
189       BigDecimal JavaDoc quantityShipped = new BigDecimal JavaDoc(0);
190       for(
191           Iterator JavaDoc i = deliveryInformations.iterator();
192           i.hasNext();
193       ) {
194         DataproviderObject deliveryInformation = (DataproviderObject)i.next();
195         quantityShipped = quantityShipped.add(
196             (BigDecimal JavaDoc)deliveryInformation.values("quantityShipped").get(0)
197         );
198       }
199       
200       // quantity
201
BigDecimal JavaDoc quantity = position.values("quantity").size() > 0
202           ? (BigDecimal JavaDoc)position.values("quantity").get(0)
203           : new BigDecimal JavaDoc(0);
204       BigDecimal JavaDoc adjustedQuantity = quantity;
205       BigDecimal JavaDoc minQuantity = position.values("minQuantity").size() > 0
206           ? (BigDecimal JavaDoc)position.values("minQuantity").get(0)
207           : new BigDecimal JavaDoc(0);
208       BigDecimal JavaDoc maxQuantity = position.values("maxQuantity").size() > 0
209           ? (BigDecimal JavaDoc)position.values("maxQuantity").get(0)
210           : new BigDecimal JavaDoc(Double.MAX_VALUE);
211       BigDecimal JavaDoc offsetQuantity = position.values("offsetQuantity").size() > 0
212           ? (BigDecimal JavaDoc)position.values("offsetQuantity").get(0)
213           : new BigDecimal JavaDoc(0);
214       short minMaxQuantityHandling = position.values("minMaxQuantityHandling").size() > 0
215           ? ((Number JavaDoc)position.values("minMaxQuantityHandling").get(0)).shortValue()
216           : MIN_MAX_QUANTITY_HANDLING_NA;
217       if(minMaxQuantityHandling == MIN_MAX_QUANTITY_HANDLING_LIMIT) {
218           adjustedQuantity = adjustedQuantity.subtract(offsetQuantity).max(minQuantity).min(maxQuantity);
219       }
220       
221       // baseAmount
222
BigDecimal JavaDoc pricePerUnit = position.values("pricePerUnit").size() > 0
223           ? (BigDecimal JavaDoc)position.values("pricePerUnit").get(0)
224           : new BigDecimal JavaDoc(0);
225       BigDecimal JavaDoc uomScaleFactor = new BigDecimal JavaDoc(1.0);
226       if(
227           (position.values("uom").size() > 0) &&
228           (position.values("priceUom").size() > 0) &&
229           !position.values("uom").get(0).equals(position.values("priceUom").get(0))
230       ) {
231           DataproviderObject_1_0 priceUom = this.plugin.retrieveObjectFromLocal(
232               header,
233               (Path)position.values("priceUom").get(0)
234           );
235           BigDecimal JavaDoc priceUomQuantity = priceUom.values("quantity").size() > 0
236               ? (BigDecimal JavaDoc)priceUom.values("quantity").get(0)
237               : new BigDecimal JavaDoc(0.0);
238           uomScaleFactor = position.values("uom").get(0).equals(priceUom.values("baseUom").get(0))
239               ? priceUomQuantity.signum() == 0
240                   ? new BigDecimal JavaDoc(0.0)
241                   : new BigDecimal JavaDoc(1.0 / priceUomQuantity.doubleValue())
242               : new BigDecimal JavaDoc(0.0);
243       }
244       BigDecimal JavaDoc baseAmount = adjustedQuantity.multiply(pricePerUnit.multiply(uomScaleFactor));
245       // discount
246
Boolean JavaDoc discountIsPercentage = position.values("discountIsPercentage").size() > 0
247           ? (Boolean JavaDoc)position.values("discountIsPercentage").get(0)
248           : Boolean.FALSE;
249       BigDecimal JavaDoc discount = position.values("discount").size() > 0
250           ? (BigDecimal JavaDoc)position.values("discount").get(0)
251           : new BigDecimal JavaDoc(0);
252       // Discount is per piece in case of !discountIsPercentage
253
BigDecimal JavaDoc discountAmount = discountIsPercentage.booleanValue()
254           ? baseAmount.multiply(discount.divide(new BigDecimal JavaDoc(100.0), BigDecimal.ROUND_UP))
255           : adjustedQuantity.multiply(discount.multiply(uomScaleFactor));
256
257       position.clearValues("baseAmount").add(baseAmount);
258       position.clearValues("discountAmount").add(discountAmount);
259       position.clearValues("quantityShipped").add(quantityShipped);
260       position.clearValues("quantityBackOrdered").add(
261         quantity.subtract(quantityShipped)
262       );
263       
264       // taxAmount
265
BigDecimal JavaDoc salesTaxRate = new BigDecimal JavaDoc(0);
266       if(position.values("salesTaxType").size() > 0) {
267         try {
268           DataproviderObject_1_0 salesTaxType = this.getCachedObject(
269               header,
270               (Path)position.values("salesTaxType").get(0)
271           );
272           if(salesTaxType.values("rate").size() > 0) {
273             salesTaxRate = (BigDecimal JavaDoc)salesTaxType.values("rate").get(0);
274           }
275         } catch(Exception JavaDoc e) {}
276       }
277       BigDecimal JavaDoc taxAmount = baseAmount.subtract(discountAmount).multiply(salesTaxRate.divide(new BigDecimal JavaDoc(100), BigDecimal.ROUND_UP));
278       position.clearValues("taxAmount").add(taxAmount);
279
280       // amount
281
BigDecimal JavaDoc amount = baseAmount.subtract(discountAmount).add(taxAmount);
282       position.clearValues("amount").add(amount);
283       
284       // get contract language and calculate descriptions
285
int contractLanguage = contract.values("contractLanguage").size() < 1
286         ? 0
287         : ((Number JavaDoc)contract.values("contractLanguage").get(0)).intValue();
288
289       // get product description
290
if(position.values("product").size() > 0) {
291         try {
292           DataproviderObject_1_0 product = this.delegation.addGetRequest(
293             (Path)position.values("product").get(0),
294             AttributeSelectors.ALL_ATTRIBUTES,
295             new AttributeSpecifier[]{}
296           );
297           position.clearValues("productDescription").add(
298             product.values("description").get(0)
299           );
300           position.clearValues("productDetailedDescription").add(
301             product.values("detailedDescription").get(0)
302           );
303           DataproviderObject_1_0 additionalDescription = this.getCachedDescription(
304               product.path(),
305               contractLanguage
306           );
307           if(additionalDescription != null) {
308             position.clearValues("productDescription").add(
309               additionalDescription.values("description").get(0)
310             );
311             position.clearValues("productDetailedDescription").add(
312               additionalDescription.values("detailedDescription").get(0)
313             );
314           }
315         }
316         catch(Exception JavaDoc e) {
317           new ServiceException(e).log();
318           position.clearValues("productDescription").add("#ERR");
319           position.clearValues("productDetailedDescription").add("#ERR");
320         }
321       }
322       else {
323         position.clearValues("productDescription").add("N/A");
324         position.clearValues("productDetailedDescription").add("N/A");
325       }
326       
327       // Complete uom derived attributes
328
if(position.values("uom").size() > 0) {
329         try {
330           DataproviderObject_1_0 uom = this.getCachedObject(
331               header,
332               (Path)position.values("uom").get(0)
333           );
334           position.clearValues("uomDescription").add(
335             uom.values("description").get(0)
336           );
337           position.clearValues("uomDetailedDescription").add(
338             uom.values("detailedDescription").get(0)
339           );
340           DataproviderObject_1_0 additionalDescription = this.getCachedDescription(
341               uom.path(),
342               contractLanguage
343           );
344           if(additionalDescription != null) {
345             position.clearValues("uomDescription").add(
346               additionalDescription.values("description").get(0)
347             );
348             position.clearValues("uomDetailedDescription").add(
349               additionalDescription.values("detailedDescription").get(0)
350             );
351           }
352         }
353         catch(Exception JavaDoc e) {
354           new ServiceException(e).log();
355           position.clearValues("uomDescription").add("#ERR");
356           position.clearValues("uomDetailedDescription").add("#ERR");
357         }
358       }
359       else {
360         position.clearValues("uomDescription").add("N/A");
361         position.clearValues("uomDetailedDescription").add("N/A");
362       }
363       
364       // Complete priceUom derived attributes
365
if(position.values("priceUom").size() > 0) {
366           try {
367             DataproviderObject_1_0 priceUom = this.getCachedObject(
368                 header,
369                 (Path)position.values("priceUom").get(0)
370             );
371             position.clearValues("priceUomDescription").add(
372                 priceUom.values("description").get(0)
373             );
374             position.clearValues("priceUomDetailedDescription").add(
375                 priceUom.values("detailedDescription").get(0)
376             );
377             DataproviderObject_1_0 additionalDescription = this.getCachedDescription(
378                 priceUom.path(),
379                 contractLanguage
380             );
381             if(additionalDescription != null) {
382               position.clearValues("priceUomDescription").add(
383                   additionalDescription.values("description").get(0)
384               );
385               position.clearValues("priceUomDetailedDescription").add(
386                   additionalDescription.values("detailedDescription").get(0)
387               );
388             }
389           }
390           catch(Exception JavaDoc e) {
391               new ServiceException(e).log();
392               position.clearValues("priceUomDescription").add("#ERR");
393               position.clearValues("priceUomDetailedDescription").add("#ERR");
394           }
395       }
396       else {
397           position.clearValues("priceUomDescription").add("N/A");
398           position.clearValues("priceUomDetailedDescription").add("N/A");
399       }
400       
401       // Complete salesTaxType derived attributes
402
if(position.values("salesTaxType").size() > 0) {
403         try {
404           DataproviderObject_1_0 salesTaxType = this.getCachedObject(
405               header,
406               (Path)position.values("salesTaxType").get(0)
407           );
408           position.clearValues("salesTaxTypeDescription").add(
409             salesTaxType.values("description").get(0)
410           );
411           position.clearValues("salesTaxTypeDetailedDescription").add(
412             salesTaxType.values("detailedDescription").get(0)
413           );
414           DataproviderObject_1_0 additionalDescription = this.getCachedDescription(
415               salesTaxType.path(),
416               contractLanguage
417           );
418           if(additionalDescription != null) {
419             position.clearValues("salesTaxTypeDescription").add(
420               additionalDescription.values("description").get(0)
421             );
422             position.clearValues("salesTaxTypeDetailedDescription").add(
423               additionalDescription.values("detailedDescription").get(0)
424             );
425           }
426         }
427         catch(Exception JavaDoc e) {
428           new ServiceException(e).log();
429           position.clearValues("salesTaxTypeDescription").add("#ERR");
430           position.clearValues("salesTaxTypeDetailedDescription").add("#ERR");
431         }
432       }
433       else {
434         position.clearValues("salesTaxTypeDescription").add("N/A");
435         position.clearValues("salesTaxTypeDetailedDescription").add("N/A");
436       }
437     }
438
439     //-------------------------------------------------------------------------
440
public void calculateContract(
441         ServiceHeader header,
442         DataproviderObject_1_0 contract,
443         Set JavaDoc fetchSet
444     ) throws ServiceException {
445         if(!this.plugin.isLead(contract)) {
446             Set JavaDoc derivedAttributes = new HashSet JavaDoc(
447                 Arrays.asList(new String JavaDoc[]{"totalBaseAmount", "totalBaseAmount", "totalBaseAmount", "totalTaxAmount", "totalAmountIncludingTax", "totalSalesCommission"})
448             );
449             Path contractIdentity = new Path((String JavaDoc)contract.values(SystemAttributes.OBJECT_IDENTITY).get(0));
450             // Calculate only if object identity matches the access path and derived
451
// attributes are in fetchSet
452
if(
453                 contractIdentity.equals(contract.path()) &&
454                 ((fetchSet == null) || derivedAttributes.removeAll(fetchSet))
455             ) {
456                 BigDecimal JavaDoc totalBaseAmount = new BigDecimal JavaDoc(0);
457                 BigDecimal JavaDoc totalDiscountAmount = new BigDecimal JavaDoc(0);
458                 BigDecimal JavaDoc totalTaxAmount = new BigDecimal JavaDoc(0);
459                 BigDecimal JavaDoc totalSalesCommission = new BigDecimal JavaDoc(0);
460                 List JavaDoc positions = this.delegation.addFindRequest(
461                     contract.path().getChild("position"),
462                     null,
463                     AttributeSelectors.ALL_ATTRIBUTES,
464                     0,
465                     Integer.MAX_VALUE,
466                     Directions.ASCENDING
467                 );
468                 for(
469                     Iterator JavaDoc i = positions.iterator();
470                     i.hasNext();
471                 ) {
472                     DataproviderObject_1_0 position = (DataproviderObject_1_0)i.next();
473                     this.calculateContractPosition(
474                         header,
475                         contract,
476                         position
477                     );
478                     totalBaseAmount = totalBaseAmount.add(
479                       (BigDecimal JavaDoc)position.values("baseAmount").get(0)
480                     );
481                     BigDecimal JavaDoc discountAmount = (BigDecimal JavaDoc)position.values("discountAmount").get(0);
482                     totalDiscountAmount = totalDiscountAmount.add(discountAmount);
483                     totalTaxAmount = totalTaxAmount.add(
484                       (BigDecimal JavaDoc)position.values("taxAmount").get(0)
485                     );
486                     BigDecimal JavaDoc salesCommission = position.values("salesCommission").size() > 0
487                       ? (BigDecimal JavaDoc)position.values("salesCommission").get(0)
488                       : new BigDecimal JavaDoc(0);
489                     BigDecimal JavaDoc baseAmount = (BigDecimal JavaDoc)position.values("baseAmount").get(0);
490                     totalSalesCommission = totalSalesCommission.add(
491                       (position.values("salesCommissionIsPercentage").size() > 0) &&
492                       (((Boolean JavaDoc)position.values("salesCommissionIsPercentage").get(0)).booleanValue())
493                       ? baseAmount.subtract(discountAmount).multiply(salesCommission.divide(new BigDecimal JavaDoc(100), BigDecimal.ROUND_UP))
494                       : salesCommission
495                     );
496                 }
497                 BigDecimal JavaDoc totalAmount = totalBaseAmount.subtract(totalDiscountAmount);
498                 contract.clearValues("totalBaseAmount").add(totalBaseAmount);
499                 contract.clearValues("totalDiscountAmount").add(totalDiscountAmount);
500                 contract.clearValues("totalAmount").add(totalAmount);
501                 contract.clearValues("totalTaxAmount").add(totalTaxAmount);
502                 contract.clearValues("totalAmountIncludingTax").add(totalAmount.add(totalTaxAmount));
503                 contract.clearValues("totalSalesCommission").add(totalSalesCommission);
504             }
505         }
506     }
507     
508     //-------------------------------------------------------------------------
509
/**
510      * calculate forward references, i.e.
511      * Lead --> Opportunity
512      * Opportunity --> Quote
513      * Quote --> SalesOrder
514      * SalesOrder --> Invoice
515      */

516     void calculateForwardReferences(
517         DataproviderObject_1_0 contract,
518         Set JavaDoc fetchSet
519     ) throws ServiceException {
520       String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
521       String JavaDoc referenceName = null;
522       if("org:opencrx:kernel:contract1:Lead".equals(contractType)) {
523           referenceName = "opportunity";
524       }
525       else if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
526           referenceName = "quote";
527       }
528       else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
529           referenceName = "salesOrder";
530       }
531       else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
532           referenceName = "invoice";
533       }
534       if(
535           (referenceName != null) &&
536           ((fetchSet == null) || fetchSet.contains(referenceName))
537       ) {
538           Path contractIdentity = new Path((String JavaDoc)contract.values(SystemAttributes.OBJECT_IDENTITY).get(0));
539           List JavaDoc referencedContracts =
540               this.delegation.addFindRequest(
541                   contractIdentity.getParent().getParent().getChild(referenceName),
542                   new FilterProperty[]{
543                       new FilterProperty(
544                           Quantors.THERE_EXISTS,
545                           "origin",
546                           FilterOperators.IS_IN,
547                           new Object JavaDoc[]{
548                               contractIdentity
549                           }
550                       )
551                   }
552               );
553           contract.clearValues(referenceName);
554           for(Iterator JavaDoc i = referencedContracts.iterator(); i.hasNext(); ) {
555               contract.values(referenceName).add(
556                   ((DataproviderObject_1_0)i.next()).path()
557               );
558           }
559       }
560     }
561
562     //-----------------------------------------------------------------------
563
DataproviderObject createInvoice(
564         ServiceHeader header,
565         DataproviderObject_1_0 source
566     ) throws ServiceException {
567         Map JavaDoc objectMarshallers = new HashMap JavaDoc();
568         objectMarshallers.put(
569           "org:opencrx:kernel:contract1:SalesOrder",
570           new Marshaller() {
571             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
572               DataproviderObject_1_0 salesOrder = (DataproviderObject_1_0)s;
573               DataproviderObject invoice = new DataproviderObject(new Path(""));
574               copyAbstractContract(
575                   salesOrder,
576                   invoice
577               );
578               invoice.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:Invoice");
579               invoice.clearValues("contractState").add(new Short JavaDoc((short)0));
580               return invoice;
581             }
582             public Object JavaDoc unmarshal(Object JavaDoc s) {
583               throw new UnsupportedOperationException JavaDoc();
584             }
585           }
586         );
587         objectMarshallers.put(
588           "org:opencrx:kernel:contract1:SalesOrderPosition",
589           new Marshaller() {
590             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
591               DataproviderObject_1_0 salesOrderPosition = (DataproviderObject_1_0)s;
592               DataproviderObject invoicePosition = new DataproviderObject(new Path(""));
593               copyAbstractContractPosition(
594                   salesOrderPosition,
595                   invoicePosition
596               );
597               invoicePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoicePosition");
598               invoicePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
599               return invoicePosition;
600             }
601             public Object JavaDoc unmarshal(Object JavaDoc s) {
602                 throw new UnsupportedOperationException JavaDoc();
603             }
604           }
605         );
606         objectMarshallers.put(
607           "org:opencrx:kernel:contract1:SalesOrderBundledProductPosition",
608           new Marshaller() {
609             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
610               DataproviderObject_1_0 salesOrderPosition = (DataproviderObject_1_0)s;
611               DataproviderObject invoicePosition = new DataproviderObject(new Path(""));
612               copyAbstractContractPosition(
613                   salesOrderPosition,
614                   invoicePosition
615               );
616               invoicePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceBundledProductPosition");
617               invoicePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
618               return invoicePosition;
619             }
620             public Object JavaDoc unmarshal(Object JavaDoc s) {
621                 throw new UnsupportedOperationException JavaDoc();
622             }
623           }
624         );
625         objectMarshallers.put(
626           "org:opencrx:kernel:contract1:SalesOrderProductBundlePosition",
627           new Marshaller() {
628             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
629               DataproviderObject_1_0 salesOrderPosition = (DataproviderObject_1_0)s;
630               DataproviderObject invoicePosition = new DataproviderObject(new Path(""));
631               copyAbstractContractPosition(
632                   salesOrderPosition,
633                   invoicePosition
634               );
635               invoicePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceProductBundlePosition");
636               invoicePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
637               return invoicePosition;
638             }
639             public Object JavaDoc unmarshal(Object JavaDoc s) {
640                 throw new UnsupportedOperationException JavaDoc();
641             }
642           }
643         );
644         objectMarshallers.put(
645           "org:opencrx:kernel:contract1:SalesOrderProductOfferingPosition",
646           new Marshaller() {
647             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
648               DataproviderObject_1_0 salesOrderPosition = (DataproviderObject_1_0)s;
649               DataproviderObject invoicePosition = new DataproviderObject(new Path(""));
650               copyAbstractContractPosition(
651                   salesOrderPosition,
652                   invoicePosition
653               );
654               invoicePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceProductOfferingPosition");
655               invoicePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
656               return invoicePosition;
657             }
658             public Object JavaDoc unmarshal(Object JavaDoc s) {
659                 throw new UnsupportedOperationException JavaDoc();
660             }
661           }
662         );
663         DataproviderObject invoice =
664             this.plugin.retrieveObjectForModification(
665                 this.cloning.cloneAndUpdateReferences(
666                     header,
667                     source,
668                     source.path().getParent().getParent().getChild("invoice"),
669                     objectMarshallers,
670                     DEFAULT_REFERENCE_FILTER,
671                     false
672                 ).path()
673             );
674         invoice.clearValues("origin").add(source.path());
675         if(invoice.values("salesRep").size() == 0) {
676             this.plugin.assignToMe(
677                 header,
678                 invoice,
679                 null,
680                 true,
681                 null
682             );
683         }
684         return invoice;
685     }
686     
687     //-----------------------------------------------------------------------
688
DataproviderObject createSalesOrder(
689         ServiceHeader header,
690         DataproviderObject_1_0 source
691     ) throws ServiceException {
692         Map JavaDoc objectMarshallers = new HashMap JavaDoc();
693         objectMarshallers.put(
694           "org:opencrx:kernel:contract1:Quote",
695           new Marshaller() {
696             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
697               DataproviderObject_1_0 quote = (DataproviderObject_1_0)s;
698               DataproviderObject salesOrder = new DataproviderObject(new Path(""));
699               copyAbstractContract(
700                   quote,
701                   salesOrder
702               );
703               salesOrder.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrder");
704               salesOrder.clearValues("contractState").add(new Short JavaDoc((short)0));
705               return salesOrder;
706             }
707             public Object JavaDoc unmarshal(Object JavaDoc s) {
708               throw new UnsupportedOperationException JavaDoc();
709             }
710           }
711         );
712         objectMarshallers.put(
713           "org:opencrx:kernel:contract1:QuotePosition",
714           new Marshaller() {
715             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
716               DataproviderObject_1_0 quotePosition = (DataproviderObject_1_0)s;
717               DataproviderObject salesOrderPosition = new DataproviderObject(new Path(""));
718               copyAbstractContractPosition(
719                 quotePosition,
720                 salesOrderPosition
721               );
722               salesOrderPosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderPosition");
723               salesOrderPosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
724               return salesOrderPosition;
725             }
726             public Object JavaDoc unmarshal(Object JavaDoc s) {
727               throw new UnsupportedOperationException JavaDoc();
728             }
729           }
730         );
731         objectMarshallers.put(
732           "org:opencrx:kernel:contract1:QuoteBundledProductPosition",
733           new Marshaller() {
734             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
735               DataproviderObject_1_0 quotePosition = (DataproviderObject_1_0)s;
736               DataproviderObject salesOrderPosition = new DataproviderObject(new Path(""));
737               copyAbstractContractPosition(
738                 quotePosition,
739                 salesOrderPosition
740               );
741               salesOrderPosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderBundledProductPosition");
742               salesOrderPosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
743               return salesOrderPosition;
744             }
745             public Object JavaDoc unmarshal(Object JavaDoc s) {
746               throw new UnsupportedOperationException JavaDoc();
747             }
748           }
749         );
750         objectMarshallers.put(
751           "org:opencrx:kernel:contract1:QuoteProductBundlePosition",
752           new Marshaller() {
753             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
754               DataproviderObject_1_0 quotePosition = (DataproviderObject_1_0)s;
755               DataproviderObject salesOrderPosition = new DataproviderObject(new Path(""));
756               copyAbstractContractPosition(
757                 quotePosition,
758                 salesOrderPosition
759               );
760               salesOrderPosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderProductBundlePosition");
761               salesOrderPosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
762               return salesOrderPosition;
763             }
764             public Object JavaDoc unmarshal(Object JavaDoc s) {
765               throw new UnsupportedOperationException JavaDoc();
766             }
767           }
768         );
769         objectMarshallers.put(
770           "org:opencrx:kernel:contract1:QuoteProductOfferingPosition",
771           new Marshaller() {
772             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
773               DataproviderObject_1_0 quotePosition = (DataproviderObject_1_0)s;
774               DataproviderObject salesOrderPosition = new DataproviderObject(new Path(""));
775               copyAbstractContractPosition(
776                 quotePosition,
777                 salesOrderPosition
778               );
779               salesOrderPosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderProductOfferingPosition");
780               salesOrderPosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
781               return salesOrderPosition;
782             }
783             public Object JavaDoc unmarshal(Object JavaDoc s) {
784               throw new UnsupportedOperationException JavaDoc();
785             }
786           }
787         );
788         DataproviderObject salesOrder =
789             this.plugin.retrieveObjectForModification(
790                 this.cloning.cloneAndUpdateReferences(
791                     header,
792                     source,
793                     source.path().getParent().getParent().getChild("salesOrder"),
794                     objectMarshallers,
795                     DEFAULT_REFERENCE_FILTER,
796                     false
797                 ).path()
798            );
799         salesOrder.clearValues("origin").add(source.path());
800         if(salesOrder.values("salesRep").size() == 0) {
801             this.plugin.assignToMe(
802                 header,
803                 salesOrder,
804                 null,
805                 true,
806                 null
807             );
808         }
809         return salesOrder;
810     }
811     
812     //-----------------------------------------------------------------------
813
DataproviderObject createQuote(
814         ServiceHeader header,
815         DataproviderObject_1_0 source
816     ) throws ServiceException {
817         Map JavaDoc objectMarshallers = new HashMap JavaDoc();
818         objectMarshallers.put(
819           "org:opencrx:kernel:contract1:Opportunity",
820           new Marshaller() {
821             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
822               DataproviderObject_1_0 opportunity = (DataproviderObject_1_0)s;
823               DataproviderObject quote = new DataproviderObject(new Path(""));
824               copyAbstractContract(
825                 opportunity,
826                 quote
827               );
828               quote.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:Quote");
829               quote.clearValues("contractState").add(new Short JavaDoc((short)0));
830               return quote;
831             }
832             public Object JavaDoc unmarshal(Object JavaDoc s) {
833               throw new UnsupportedOperationException JavaDoc();
834             }
835           }
836         );
837         objectMarshallers.put(
838           "org:opencrx:kernel:contract1:OpportunityPosition",
839           new Marshaller() {
840             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
841               DataproviderObject_1_0 opportunityPosition = (DataproviderObject_1_0)s;
842               DataproviderObject quotePosition = new DataproviderObject(new Path(""));
843               copyAbstractContractPosition(
844                 opportunityPosition,
845                 quotePosition
846               );
847               quotePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuotePosition");
848               quotePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
849               return quotePosition;
850             }
851             public Object JavaDoc unmarshal(Object JavaDoc s) {
852               throw new UnsupportedOperationException JavaDoc();
853             }
854           }
855         );
856         objectMarshallers.put(
857           "org:opencrx:kernel:contract1:OpportunityBundledProductPosition",
858           new Marshaller() {
859             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
860               DataproviderObject_1_0 opportunityPosition = (DataproviderObject_1_0)s;
861               DataproviderObject quotePosition = new DataproviderObject(new Path(""));
862               copyAbstractContractPosition(
863                 opportunityPosition,
864                 quotePosition
865               );
866               quotePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteBundledProductPosition");
867               quotePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
868               return quotePosition;
869             }
870             public Object JavaDoc unmarshal(Object JavaDoc s) {
871               throw new UnsupportedOperationException JavaDoc();
872             }
873           }
874         );
875         objectMarshallers.put(
876           "org:opencrx:kernel:contract1:OpportunityProductBundlePosition",
877           new Marshaller() {
878             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
879               DataproviderObject_1_0 opportunityPosition = (DataproviderObject_1_0)s;
880               DataproviderObject quotePosition = new DataproviderObject(new Path(""));
881               copyAbstractContractPosition(
882                 opportunityPosition,
883                 quotePosition
884               );
885               quotePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteProductBundlePosition");
886               quotePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
887               return quotePosition;
888             }
889             public Object JavaDoc unmarshal(Object JavaDoc s) {
890               throw new UnsupportedOperationException JavaDoc();
891             }
892           }
893         );
894         objectMarshallers.put(
895           "org:opencrx:kernel:contract1:OpportunityProductOfferingPosition",
896           new Marshaller() {
897             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
898               DataproviderObject_1_0 opportunityPosition = (DataproviderObject_1_0)s;
899               DataproviderObject quotePosition = new DataproviderObject(new Path(""));
900               copyAbstractContractPosition(
901                 opportunityPosition,
902                 quotePosition
903               );
904               quotePosition.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteProductOfferingPosition");
905               quotePosition.clearValues("contractPositionState").add(new Short JavaDoc((short)0));
906               return quotePosition;
907             }
908             public Object JavaDoc unmarshal(Object JavaDoc s) {
909               throw new UnsupportedOperationException JavaDoc();
910             }
911           }
912         );
913         DataproviderObject quote =
914             this.plugin.retrieveObjectForModification(
915             this.cloning.cloneAndUpdateReferences(
916                 header,
917                 source,
918                 source.path().getParent().getParent().getChild("quote"),
919                 objectMarshallers,
920                 DEFAULT_REFERENCE_FILTER,
921                 false
922             ).path()
923         );
924         quote.clearValues("origin").add(source.path());
925         if(quote.values("salesRep").size() == 0) {
926             this.plugin.assignToMe(
927                 header,
928                 quote,
929                 null,
930                 true,
931                 null
932             );
933         }
934         return quote;
935     }
936     
937     //-----------------------------------------------------------------------
938
DataproviderObject createOpportunity(
939         ServiceHeader header,
940         DataproviderObject_1_0 source
941     ) throws ServiceException {
942         Map JavaDoc objectMarshallers = new HashMap JavaDoc();
943         objectMarshallers.put(
944           "org:opencrx:kernel:contract1:Lead",
945           new Marshaller() {
946             public Object JavaDoc marshal(Object JavaDoc s) throws ServiceException {
947               DataproviderObject_1_0 lead = (DataproviderObject_1_0)s;
948               DataproviderObject opportunity = new DataproviderObject(new Path(""));
949               copyAbstractContract(
950                 lead,
951                 opportunity
952               );
953               opportunity.clearValues(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:Opportunity");
954               opportunity.clearValues("contractState").add(new Short JavaDoc((short)0));
955               return opportunity;
956             }
957             public Object JavaDoc unmarshal(Object JavaDoc s) {
958               throw new UnsupportedOperationException JavaDoc();
959             }
960           }
961         );
962         DataproviderObject opportunity =
963             this.plugin.retrieveObjectForModification(
964                 this.cloning.cloneAndUpdateReferences(
965                     header,
966                     source,
967                     source.path().getParent().getParent().getChild("opportunity"),
968                     objectMarshallers,
969                     DEFAULT_REFERENCE_FILTER,
970                     false
971                 ).path()
972             );
973         opportunity.clearValues("origin").add(source.path());
974         if(opportunity.values("salesRep").size() == 0) {
975             this.plugin.assignToMe(
976                 header,
977                 opportunity,
978                 null,
979                 true,
980                 null
981             );
982         }
983         return opportunity;
984     }
985     
986     //-------------------------------------------------------------------------
987
public boolean updateContractPositionPrice(
988         DataproviderObject_1_0 contract,
989         DataproviderObject position,
990         DataproviderObject_1_0 oldValues,
991         DataproviderObject_1_0 product,
992         boolean priceEnabledOverridesPosition
993     ) throws ServiceException {
994
995         if(contract == null) return false;
996         if(position == null) return false;
997         if(product == null) return false;
998         Path productIdentity = product.path();
999         
1000        // pricingRule
1001
Path pricingRuleIdentity = null;
1002        if(oldValues == null) {
1003            pricingRuleIdentity = (Path)position.values("pricingRule").get(0);
1004        }
1005        else {
1006            pricingRuleIdentity = (position.getValues("pricingRule") != null) && (position.values("pricingRule").size() > 0)
1007                ? (Path)position.values("pricingRule").get(0)
1008                : (Path)oldValues.values("pricingRule").get(0);
1009        }
1010        if(pricingRuleIdentity == null) return false;
1011        // quantity
1012
BigDecimal JavaDoc quantity = null;
1013        if(oldValues == null) {
1014            quantity = (BigDecimal JavaDoc)position.values("quantity").get(0);
1015        }
1016        else {
1017            quantity = (position.getValues("quantity") != null) && (position.values("quantity").size() > 0)
1018                ? (BigDecimal JavaDoc)position.values("quantity").get(0)
1019                : (BigDecimal JavaDoc)oldValues.values("quantity").get(0);
1020        }
1021        if(quantity == null) return false;
1022        // pricingDate
1023
String JavaDoc pricingDate = null;
1024        if(oldValues == null) {
1025            pricingDate = (String JavaDoc)position.values("pricingDate").get(0);
1026        }
1027        else {
1028            pricingDate = (position.getValues("pricingDate") != null) && (position.values("pricingDate").size() > 0)
1029                ? (String JavaDoc)position.values("pricingDate").get(0)
1030                : (String JavaDoc)oldValues.values("pricingDate").get(0);
1031        }
1032        // priceUom
1033
Path priceUomIdentity = (position.getValues("priceUom") != null) && (position.values("priceUom").size() > 0)
1034            ? (Path)position.values("priceUom").get(0)
1035            : position.values("uom").size() > 0
1036                ? (Path)position.values("uom").get(0)
1037                : oldValues.values("priceUom").size() > 0
1038                    ? (Path)oldValues.values("priceUom").get(0)
1039                    : (Path)oldValues.values("uom").get(0);
1040        // priceLevel
1041
Path priceLevelIdentity = null;
1042        if(position.getValues("priceLevel") != null) {
1043            priceLevelIdentity = (Path)position.values("priceLevel").get(0);
1044        }
1045        else {
1046            try {
1047                org.opencrx.kernel.product1.cci.GetPriceLevelResult res =
1048                    this.plugin.products.getPriceLevel(
1049                        pricingRuleIdentity == null
1050                            ? null
1051                            : (org.opencrx.kernel.product1.cci.PricingRule)this.rootPkg.refObject(pricingRuleIdentity.toXri()),
1052                        (org.opencrx.kernel.contract1.cci.AbstractContract)this.rootPkg.refObject(contract.path().toXri()),
1053                        productIdentity == null
1054                            ? null
1055                            : (org.opencrx.kernel.product1.cci.AbstractProduct)this.rootPkg.refObject(productIdentity.toXri()),
1056                        priceUomIdentity == null
1057                            ? null
1058                            : (org.opencrx.kernel.uom1.cci.Uom)this.rootPkg.refObject(priceUomIdentity.toXri()),
1059                        quantity,
1060                        pricingDate == null
1061                            ? new Date JavaDoc()
1062                            : org.openmdx.base.text.format.DateFormat.getInstance().parse(pricingDate)
1063                      );
1064                priceLevelIdentity = (Path)res.refDelegate().objGetValue("priceLevel");
1065            }
1066            catch(ParseException JavaDoc e) {
1067                throw new ServiceException(e);
1068            }
1069        }
1070        position.clearValues("priceLevel");
1071        if(priceLevelIdentity != null) {
1072            position.values("priceLevel").add(priceLevelIdentity);
1073        }
1074        // Find price matching price list and quantity
1075
List JavaDoc prices = new ArrayList JavaDoc();
1076        DataproviderObject_1_0 listPrice = null;
1077        if(priceLevelIdentity != null) {
1078            // Find product prices
1079
// priceLevel and priceUom must match
1080
prices = this.delegation.addFindRequest(
1081                productIdentity.getChild("basePrice"),
1082                    new FilterProperty[]{
1083                        new FilterProperty(
1084                            Quantors.THERE_EXISTS,
1085                            "priceLevel",
1086                            FilterOperators.IS_IN,
1087                            new Object JavaDoc[]{priceLevelIdentity}
1088                        ),
1089                        new FilterProperty(
1090                            Quantors.THERE_EXISTS,
1091                            "uom",
1092                            FilterOperators.IS_IN,
1093                            new Object JavaDoc[]{priceUomIdentity}
1094                        )
1095                    },
1096                    AttributeSelectors.ALL_ATTRIBUTES,
1097                    0,
1098                    Integer.MAX_VALUE,
1099                    Directions.ASCENDING
1100            );
1101            // Check quantity
1102
for(
1103                Iterator JavaDoc i = prices.iterator();
1104                i.hasNext();
1105            ) {
1106                DataproviderObject_1_0 current = (DataproviderObject_1_0)i.next();
1107                boolean quantityFromMatches =
1108                    (current.values("quantityFrom").size() == 0) ||
1109                    (quantity == null) ||
1110                    ((BigDecimal JavaDoc)current.values("quantityFrom").get(0)).compareTo(quantity) >= 0;
1111                boolean quantityToMatches =
1112                    (current.values("quantityTo").size() == 0) ||
1113                    (quantity == null) ||
1114                    ((BigDecimal JavaDoc)current.values("quantityTo").get(0)).compareTo(quantity) < 0;
1115                if(quantityFromMatches && quantityToMatches) {
1116                    listPrice = current;
1117                    break;
1118                }
1119            }
1120        }
1121        // List price found?
1122
if(listPrice != null) {
1123            position.clearValues("listPrice").add(
1124                listPrice.path()
1125            );
1126            position.clearValues("pricingState").add(
1127                new Short JavaDoc(PRICING_STATE_OK)
1128            );
1129            // Position creation
1130
if(oldValues == null) {
1131                if(position.getValues("pricePerUnit") == null) {
1132                    position.values("pricePerUnit").addAll(
1133                        listPrice.values("price")
1134                    );
1135                    position.clearValues("discount").addAll(
1136                        listPrice.values("discount")
1137                    );
1138                    position.clearValues("discountIsPercentage").addAll(
1139                        listPrice.values("discountIsPercentage")
1140                    );
1141                }
1142                if(position.getValues("priceUom") == null) {
1143                    position.values("priceUom").addAll(listPrice.values("uom"));
1144                }
1145            }
1146            // Position update
1147
else {
1148                boolean pricePerUnitModified = (position.getValues("pricePerUnit") != null) && (position.getValues("pricePerUnit").size() > 0) && (oldValues.getValues("pricePerUnit").size() > 0)
1149                    ? ((BigDecimal JavaDoc)position.getValues("pricePerUnit").get(0)).compareTo((BigDecimal JavaDoc)oldValues.values("pricePerUnit").get(0)) != 0
1150                    : position.getValues("pricePerUnit").size() > 0;
1151                boolean priceUomModified = (position.getValues("priceUom") != null) && (position.getValues("priceUom").size() > 0) && (oldValues.getValues("priceUom").size() > 0)
1152                    ? position.getValues("priceUom").get(0).equals(oldValues.values("priceUom").get(0))
1153                    : position.getValues("priceUom").size() > 0;
1154                if(priceEnabledOverridesPosition && !pricePerUnitModified) {
1155                    position.clearValues("pricePerUnit").addAll(
1156                        listPrice.values("price")
1157                    );
1158                    position.clearValues("discount").addAll(
1159                        listPrice.values("discount")
1160                    );
1161                    position.clearValues("discountIsPercentage").addAll(
1162                        listPrice.values("discountIsPercentage")
1163                    );
1164                }
1165                if(priceEnabledOverridesPosition && !priceUomModified) {
1166                    position.clearValues("priceUom").addAll(listPrice.values("uom"));
1167                }
1168            }
1169        }
1170        return listPrice != null;
1171    }
1172    
1173    //-------------------------------------------------------------------------
1174
public int getMaxLineItemNumber(
1175        DataproviderObject_1_0 contract,
1176        Path parentPositionIdentity
1177    ) throws ServiceException {
1178        int maxLineItemNumber = 0;
1179        List JavaDoc positions = this.delegation.addFindRequest(
1180            contract.path().getChild("position"),
1181            parentPositionIdentity == null
1182                ? null
1183                : new FilterProperty[]{
1184                      new FilterProperty(
1185                          Quantors.THERE_EXISTS,
1186                          "parentPosition",
1187                          FilterOperators.IS_IN,
1188                          new Path[]{parentPositionIdentity}
1189                      )
1190                  },
1191            AttributeSelectors.ALL_ATTRIBUTES,
1192            0,
1193            Integer.MAX_VALUE,
1194            Directions.ASCENDING
1195        );
1196        for(
1197            Iterator JavaDoc i = positions.iterator();
1198            i.hasNext();
1199        ) {
1200            DataproviderObject_1_0 pos = (DataproviderObject_1_0)i.next();
1201            if(
1202                (pos.values("lineItemNumber").size() > 0) &&
1203                (((Number JavaDoc)pos.values("lineItemNumber").get(0)).intValue() > maxLineItemNumber)
1204            ) {
1205                maxLineItemNumber = ((Number JavaDoc)pos.values("lineItemNumber").get(0)).intValue();
1206            }
1207        }
1208        return maxLineItemNumber;
1209    }
1210
1211    //-------------------------------------------------------------------------
1212
public void updateContractPosition(
1213        ServiceHeader header,
1214        DataproviderObject_1_0 contract,
1215        DataproviderObject position,
1216        DataproviderObject_1_0 oldValues,
1217        DataproviderObject_1_0 product,
1218        boolean reprice
1219    ) {
1220        try {
1221            
1222            // Update uoms
1223
Path positionUomIdentity = null;
1224            Path priceUomIdentity = null;
1225            // Create
1226
if(oldValues == null) {
1227                // Get from position or take from defaultUom specified on price enabled
1228
positionUomIdentity = (position.getValues("uom") != null) && (position.values("uom").size() > 0)
1229                    ? (Path)position.values("uom").get(0)
1230                    : (product != null) && (product.values("defaultUom").size() > 0)
1231                        ? (Path)product.values("defaultUom").get(0)
1232                        : null;
1233                priceUomIdentity = (position.getValues("priceUom") != null) && (position.values("priceUom").size() > 0)
1234                    ? (Path)position.values("priceUom").get(0)
1235                    : null;
1236            }
1237            // Replace
1238
else {
1239                // Get uom from position if supplied, else leave unchanged
1240
positionUomIdentity = position.getValues("uom") != null
1241                    ? (Path)position.values("uom").get(0)
1242                    : (Path)oldValues.values("uom").get(0);
1243                priceUomIdentity = position.getValues("priceUom") != null
1244                    ? (Path)position.values("priceUom").get(0)
1245                    : (Path)oldValues.values("priceUom").get(0);
1246            }
1247            // Update uom
1248
if(position.getValues("uom") != null) {
1249                position.clearValues("uom");
1250            }
1251            if(positionUomIdentity != null) {
1252                position.values("uom").add(positionUomIdentity);
1253            }
1254            // Set priceUom
1255
if(position.getValues("priceUom") != null) {
1256                position.clearValues("priceUom");
1257            }
1258            if(priceUomIdentity != null) {
1259                position.values("priceUom").add(priceUomIdentity);
1260            }
1261            
1262            // Update sales tax type
1263
Path salesTaxTypeIdentity = null;
1264            // Create
1265
if(oldValues == null) {
1266                // Get from position or take from defaultUom specified on product
1267
salesTaxTypeIdentity = (position.getValues("salesTaxType") != null) && (position.values("salesTaxType").size() > 0)
1268                    ? (Path)position.values("salesTaxType").get(0)
1269                    : (product != null) && (product.values("salesTaxType").size() > 0)
1270                        ? (Path)product.values("salesTaxType").get(0)
1271                        : null;
1272            }
1273            // Replace
1274
else {
1275                salesTaxTypeIdentity = position.getValues("salesTaxType") != null
1276                    ? (Path)position.values("salesTaxType").get(0)
1277                    : (Path)oldValues.values("salesTaxType").get(0);
1278            }
1279            position.clearValues("salesTaxType");
1280            if(salesTaxTypeIdentity != null) {
1281                position.values("salesTaxType").add(salesTaxTypeIdentity);
1282            }
1283
1284            // Update pricing rule
1285
Path pricingRuleIdentity = null;
1286            // Create
1287
if(oldValues == null) {
1288                pricingRuleIdentity = (position.getValues("pricingRule") != null) && (position.values("pricingRule").size() > 0)
1289                    ? (Path)position.values("pricingRule").get(0)
1290                    : (Path)contract.values("pricingRule").get(0);
1291                if(pricingRuleIdentity == null) {
1292                    // Get default pricing rule
1293
List JavaDoc pricingRules = this.delegation.addFindRequest(
1294                        product.path().getPrefix(5).getChild("pricingRule"),
1295                        new FilterProperty[]{
1296                            new FilterProperty(
1297                                Quantors.THERE_EXISTS,
1298                                "isDefault",
1299                                FilterOperators.IS_IN,
1300                                new Object JavaDoc[]{Boolean.TRUE}
1301                            )
1302                        }
1303                    );
1304                    if(pricingRules.size() > 0) {
1305                        pricingRuleIdentity = ((DataproviderObject_1_0)pricingRules.iterator().next()).path();
1306                    }
1307                }
1308            }
1309            // Replace
1310
else {
1311                pricingRuleIdentity = position.getValues("pricingRule") != null
1312                    ? (Path)position.values("pricingRule").get(0)
1313                    : (Path)oldValues.values("pricingRule").get(0);
1314            }
1315            position.clearValues("pricingRule");
1316            if(pricingRuleIdentity != null) {
1317                position.values("pricingRule").add(pricingRuleIdentity);
1318            }
1319            // Reprice
1320
if(reprice) {
1321                this.updateContractPositionPrice(
1322                    contract,
1323                    position,
1324                    oldValues,
1325                    product,
1326                    true
1327                );
1328            }
1329        }
1330        catch(ServiceException e) {
1331            AppLog.info(e.getMessage(), e.getCause(), 1);
1332        }
1333    }
1334    
1335    //-------------------------------------------------------------------------
1336
public DataproviderObject createContractPosition(
1337        ServiceHeader header,
1338        DataproviderObject_1_0 contract,
1339        DataproviderObject param
1340    ) {
1341        DataproviderObject position = null;
1342        try {
1343            position = new DataproviderObject(
1344                contract.path().getDescendant(new String JavaDoc[]{"position", this.plugin.getUidAsString()})
1345            );
1346            String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
1347            if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
1348                position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:OpportunityPosition");
1349            }
1350            else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
1351                position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuotePosition");
1352            }
1353            else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
1354                position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderPosition");
1355            }
1356            else if("org:opencrx:kernel:contract1:Invoice".equals(contractType)) {
1357                position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoicePosition");
1358            }
1359            else {
1360                return null;
1361            }
1362            
1363            // lineItemNumber
1364
position.values("lineItemNumber").add(
1365                new Integer JavaDoc(
1366                    100000 * (this.getMaxLineItemNumber(contract, null) / 100000 + 1)
1367                )
1368            );
1369            // name
1370
if(param.values("name").size() > 0) {
1371                position.values("name").addAll(param.values("name"));
1372            }
1373            else {
1374                position.values("name").add("Position " + position.values("lineItemNumber").get(0));
1375            }
1376            // quantity
1377
if(param.values("quantity").size() > 0) {
1378                position.values("quantity").addAll(param.values("quantity"));
1379            }
1380            else {
1381                position.values("quantity").add(new BigDecimal JavaDoc(1));
1382            }
1383            // pricingDate
1384
if(param.values("pricingDate").size() > 0) {
1385                position.values("pricingDate").addAll(param.values("pricingDate"));
1386            }
1387            else {
1388                position.values("pricingDate").add(
1389                    contract.values("pricingDate").size() > 0
1390                        ? contract.values("pricingDate").get(0)
1391                        : org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc())
1392                );
1393            }
1394            // product
1395
Path productIdentity = (Path)param.values("product").get(0);
1396            DataproviderObject_1_0 product = productIdentity == null
1397                ? null
1398                : this.plugin.retrieveObjectFromDelegation(productIdentity);
1399            // uom (only touch if specified as param
1400
if(param.values("uom").size() > 0) {
1401                position.values("uom").addAll(
1402                    param.values("uom")
1403                );
1404            }
1405            // priceUom (only touch if specified as param
1406
if(param.values("priceUom").size() > 0) {
1407                position.values("priceUom").addAll(
1408                    param.values("priceUom")
1409                );
1410            }
1411            // pricingRule
1412
if(param.values("pricingRule").size() > 0) {
1413                position.values("pricingRule").addAll(
1414                    param.values("pricingRule")
1415                );
1416            }
1417            // Update position
1418
this.updateContractPosition(
1419                header,
1420                contract,
1421                position,
1422                null,
1423                product,
1424                true
1425            );
1426            position.clearValues("product");
1427            if(productIdentity != null) {
1428                position.values("product").add(productIdentity);
1429            }
1430            
1431            // Create position
1432
this.delegation.addCreateRequest(
1433                position
1434            );
1435            // Clone configurations
1436
this.plugin.products.cloneProductConfigurationSet(
1437                header,
1438                productIdentity,
1439                position.path(),
1440                false,
1441                true
1442            );
1443        }
1444        catch(ServiceException e) {
1445            AppLog.info(e.getMessage(), e.getCause(), 1);
1446        }
1447        return position;
1448    }
1449    
1450    //-------------------------------------------------------------------------
1451
private int calculateTimeDistributionOpenContracts(
1452        ServiceHeader header,
1453        Path reference,
1454        String JavaDoc objectClass,
1455        int[] timeDistribution,
1456        String JavaDoc distributionOnAttribute,
1457        int closedThreshold
1458    ) {
1459      try {
1460        List JavaDoc objects = this.delegation.addFindRequest(
1461          reference,
1462          new FilterProperty[]{
1463              new FilterProperty(
1464                  Quantors.THERE_EXISTS,
1465                  SystemAttributes.OBJECT_CLASS,
1466                  FilterOperators.IS_IN,
1467                  new String JavaDoc[]{objectClass}
1468              ),
1469              new FilterProperty(
1470                  Quantors.THERE_EXISTS,
1471                  "contractState",
1472                  FilterOperators.IS_LESS,
1473                  new Number JavaDoc[]{new Short JavaDoc((short)closedThreshold)}
1474              )
1475          },
1476          AttributeSelectors.ALL_ATTRIBUTES,
1477          0,
1478          Contracts.BATCHING_MODE_SIZE,
1479          Directions.ASCENDING
1480        );
1481        int count = 0;
1482        for(Iterator JavaDoc i = objects.iterator(); i.hasNext(); ) {
1483          DataproviderObject_1_0 object = (DataproviderObject_1_0)i.next();
1484          Date JavaDoc dt = new Date JavaDoc();
1485          try {
1486            dt = org.openmdx.base.text.format.DateFormat.getInstance().parse(
1487              (String JavaDoc)object.values(distributionOnAttribute).get(0)
1488            );
1489          } catch(Exception JavaDoc e) {}
1490
1491          long delayInDays = (System.currentTimeMillis() - dt.getTime()) / 86400000;
1492          if(delayInDays < 0) timeDistribution[0]++;
1493          else if(delayInDays < 1) timeDistribution[1]++;
1494          else if(delayInDays < 2) timeDistribution[2]++;
1495          else if(delayInDays < 3) timeDistribution[3]++;
1496          else if(delayInDays < 4) timeDistribution[4]++;
1497          else if(delayInDays < 5) timeDistribution[5]++;
1498          else if(delayInDays < 6) timeDistribution[6]++;
1499          else if(delayInDays < 7) timeDistribution[7]++;
1500          else if(delayInDays < 8) timeDistribution[8]++;
1501          else if(delayInDays < 15) timeDistribution[9]++;
1502          else if(delayInDays < 31) timeDistribution[10]++;
1503          else if(delayInDays < 91) timeDistribution[11]++;
1504          else if(delayInDays < 181) timeDistribution[12]++;
1505          else if(delayInDays < 361) timeDistribution[13]++;
1506          else timeDistribution[14]++;
1507          
1508          count++;
1509        }
1510        return count;
1511      }
1512      catch(ServiceException e) {
1513        return 0;
1514      }
1515    }
1516
1517    //-------------------------------------------------------------------------
1518
DataproviderObject[] calculateUserHomeCharts(
1519        ServiceHeader header,
1520        Path userHome,
1521        Path chartReference
1522    ) throws ServiceException {
1523
1524      DateFormat JavaDoc dateFormat =
1525          DateFormat.getDateInstance(DateFormat.SHORT, new Locale JavaDoc("en_US"));
1526      DateFormat JavaDoc timeFormat =
1527          DateFormat.getTimeInstance(DateFormat.SHORT, new Locale JavaDoc("en_US"));
1528      String JavaDoc createdAt = dateFormat.format(new Date JavaDoc()) + " " + timeFormat.format(new Date JavaDoc());
1529        
1530      // try to get full name of contact
1531
String JavaDoc fullName = "";
1532      try {
1533          fullName = (String JavaDoc)this.plugin.retrieveObjectFromLocal(
1534              header,
1535              (Path)this.plugin.retrieveObjectFromLocal(header, userHome).values("contact").get(0)
1536          ).values("fullName").get(0);
1537      } catch(Exception JavaDoc e) {}
1538      
1539      DataproviderObject[] charts = new DataproviderObject[2];
1540      String JavaDoc chartTitle = null;
1541      
1542      /**
1543       * Contracts Overview
1544       */

1545      chartTitle = (fullName.length() == 0 ? "" : fullName + ": ") + "Assigned Open Contracts Overview (" + createdAt + ")";
1546      
1547      charts[0] = new DataproviderObject(
1548        chartReference.getChild("0")
1549      );
1550      charts[0].values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:home1:Chart");
1551      charts[0].values("description").add(chartTitle);
1552      ByteArrayOutputStream JavaDoc os = new ByteArrayOutputStream JavaDoc();
1553      PrintWriter JavaDoc pw = new PrintWriter JavaDoc(os);
1554
1555      pw.println("BEGIN:VND.OPENDMDX-CHART");
1556      pw.println("VERSION:1.0");
1557      pw.println("COUNT:1");
1558
1559      // Sales Process Overview
1560
pw.println("CHART[0].TYPE:HORIZBAR");
1561      pw.println("CHART[0].LABEL:" + chartTitle);
1562      pw.println("CHART[0].SCALEXTITLE:#Contracts");
1563      pw.println("CHART[0].SCALEYTITLE:Contract type");
1564      pw.println("CHART[0].COUNT:5");
1565      
1566      pw.println("CHART[0].LABEL[0]:Invoices");
1567      pw.println("CHART[0].LABEL[1]:Sales Orders");
1568      pw.println("CHART[0].LABEL[2]:Quotes");
1569      pw.println("CHART[0].LABEL[3]:Opportunities");
1570      pw.println("CHART[0].LABEL[4]:Leads");
1571      
1572      int[] counts = new int[]{0, 0, 0, 0, 0};
1573      int[] timeDistribution = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1574      Path assignedContractReference = userHome.getChild("assignedContract");
1575      counts[0] = this.calculateTimeDistributionOpenContracts(
1576          header,
1577          assignedContractReference,
1578          "org:opencrx:kernel:contract1:Invoice",
1579          timeDistribution,
1580          SystemAttributes.MODIFIED_AT,
1581          CLOSED_THRESHOLD_INVOICE
1582      );
1583      counts[1] = this.calculateTimeDistributionOpenContracts(
1584          header,
1585          assignedContractReference,
1586          "org:opencrx:kernel:contract1:SalesOrder",
1587          timeDistribution,
1588          SystemAttributes.MODIFIED_AT,
1589          CLOSED_THRESHOLD_SALES_ORDER
1590      );
1591      counts[2] = this.calculateTimeDistributionOpenContracts(
1592          header,
1593          assignedContractReference,
1594          "org:opencrx:kernel:contract1:Quote",
1595          timeDistribution,
1596          SystemAttributes.MODIFIED_AT,
1597          CLOSED_THRESHOLD_QUOTE
1598      );
1599      counts[3] = this.calculateTimeDistributionOpenContracts(
1600          header,
1601          assignedContractReference,
1602          "org:opencrx:kernel:contract1:Opportunity",
1603          timeDistribution,
1604          SystemAttributes.MODIFIED_AT,
1605          CLOSED_THRESHOLD_OPPORTUNITY
1606      );
1607      counts[4] = this.calculateTimeDistributionOpenContracts(
1608          header,
1609          assignedContractReference,
1610          "org:opencrx:kernel:contract1:Lead",
1611          timeDistribution,
1612          SystemAttributes.MODIFIED_AT,
1613          CLOSED_THRESHOLD_LEAD
1614      );
1615          
1616      int maxValue = 0;
1617      for(int i = 0; i < counts.length; i++) {
1618        pw.println("CHART[0].VAL[" + i + "]:" + counts[i]);
1619        pw.println("CHART[0].BORDER[" + i + "]:#000066");
1620        pw.println("CHART[0].FILL[" + i + "]:#F6D66D");
1621        maxValue = Math.max(maxValue, counts[i]);
1622      }
1623
1624      pw.println("CHART[0].MINVALUE:0");
1625      pw.println("CHART[0].MAXVALUE:" + maxValue);
1626
1627      pw.println("END:VND.OPENDMDX-CHART");
1628
1629      try {
1630        pw.flush();
1631        os.close();
1632      } catch(Exception JavaDoc e) {}
1633      charts[0].values("chart").add(
1634        os.toByteArray()
1635      );
1636      charts[0].values("chartMimeType").add("application/vnd.openmdx-chart");
1637      charts[0].values("chartName").add(
1638        this.plugin.toFilename(chartTitle + ".txt")
1639      );
1640      
1641      /**
1642       * Contracts Age Distribution
1643       */

1644      chartTitle = (fullName.length() == 0 ? "" : fullName + ": ") + "Assigned Open Contracts Age Distribution (" + createdAt + ")";
1645      
1646      charts[1] = new DataproviderObject(
1647        chartReference.getChild("1")
1648      );
1649      charts[1].values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:home1:Chart");
1650      charts[1].values("description").add(chartTitle);
1651      os = new ByteArrayOutputStream JavaDoc();
1652      pw = new PrintWriter JavaDoc(os);
1653
1654      pw.println("BEGIN:VND.OPENDMDX-CHART");
1655      pw.println("VERSION:1.0");
1656      pw.println("COUNT:1");
1657
1658      pw.println("CHART[0].TYPE:VERTBAR");
1659      pw.println("CHART[0].LABEL:" + chartTitle);
1660      pw.println("CHART[0].SCALEXTITLE:#Days");
1661      pw.println("CHART[0].SCALEYTITLE:#Contracts");
1662      pw.println("CHART[0].COUNT:14");
1663      
1664      pw.println("CHART[0].LABEL[0]:new");
1665      pw.println("CHART[0].LABEL[1]:1");
1666      pw.println("CHART[0].LABEL[2]:2");
1667      pw.println("CHART[0].LABEL[3]:3");
1668      pw.println("CHART[0].LABEL[4]:4");
1669      pw.println("CHART[0].LABEL[5]:5");
1670      pw.println("CHART[0].LABEL[6]:6");
1671      pw.println("CHART[0].LABEL[7]:7");
1672      pw.println("CHART[0].LABEL[8]:..14");
1673      pw.println("CHART[0].LABEL[9]:..30");
1674      pw.println("CHART[0].LABEL[10]:..90");
1675      pw.println("CHART[0].LABEL[11]:..180");
1676      pw.println("CHART[0].LABEL[12]:..360");
1677      pw.println("CHART[0].LABEL[13]:>360 days");
1678      
1679      maxValue = 0;
1680      // skip value @ 0: modifiedAt is always < now --> contracts modified
1681
// in the future should not occur
1682
for(int i = 0; i < 14; i++) {
1683        pw.println("CHART[0].VAL[" + i + "]:" + timeDistribution[i+1]);
1684        pw.println("CHART[0].BORDER[" + i + "]:#000066");
1685        pw.println("CHART[0].FILL[" + i + "]:#F6D66D");
1686        maxValue = Math.max(maxValue, timeDistribution[i+1]);
1687      }
1688
1689      pw.println("CHART[0].MINVALUE:0");
1690      pw.println("CHART[0].MAXVALUE:" + maxValue);
1691
1692      pw.println("END:VND.OPENDMDX-CHART");
1693      
1694      try {
1695        pw.flush();
1696        os.close();
1697      } catch(Exception JavaDoc e) {}
1698      charts[1].values("chart").add(
1699        os.toByteArray()
1700      );
1701      charts[1].values("chartMimeType").add("application/vnd.openmdx-chart");
1702      charts[1].values("chartName").add(
1703        this.plugin.toFilename(chartTitle + ".txt")
1704      );
1705
1706      return charts;
1707    }
1708
1709    //-------------------------------------------------------------------------
1710
public void markAsClosed(
1711        Path contractIdentity,
1712        DataproviderObject params
1713    ) throws ServiceException {
1714        DataproviderObject contract = this.plugin.retrieveObjectForModification(contractIdentity);
1715        String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
1716        Number JavaDoc newContractState = null;
1717        if("org:opencrx:kernel:contract1:Lead".equals(contractType)) {
1718            newContractState = (Number JavaDoc)params.values("leadState").get(0);
1719        }
1720        else if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
1721            newContractState = (Number JavaDoc)params.values("opportunityState").get(0);
1722        }
1723        else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
1724            newContractState = (Number JavaDoc)params.values("quoteState").get(0);
1725        }
1726        else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
1727            newContractState = (Number JavaDoc)params.values("salesOrderState").get(0);
1728        }
1729        else if("org:opencrx:kernel:contract1:Invoice".equals(contractType)) {
1730            newContractState = (Number JavaDoc)params.values("invoiceState").get(0);
1731        }
1732        else {
1733            throw new ServiceException(
1734                BasicException.Code.DEFAULT_DOMAIN,
1735                BasicException.Code.NOT_SUPPORTED,
1736                new BasicException.Parameter[]{
1737                    new BasicException.Parameter("contract type", contractType)
1738                },
1739                "Unsupported contract type. Supported are [Lead|Opportunity|Quote|SalesOrder|Invoice]"
1740            );
1741        }
1742        contract.clearValues("closedOn").add(
1743            org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc())
1744        );
1745        contract.clearValues("contractState").add(
1746            newContractState
1747        );
1748    }
1749    
1750    //-------------------------------------------------------------------------
1751
public boolean allowPositionRemoval(
1752        Path contractIdentity,
1753        DataproviderObject_1_0 productRole,
1754        Path parentPositionIdentity
1755    ) throws ServiceException {
1756        List JavaDoc positions = this.delegation.addFindRequest(
1757            contractIdentity.getChild("position"),
1758            parentPositionIdentity == null
1759                ? null
1760                : new FilterProperty[]{
1761                      new FilterProperty(
1762                          Quantors.THERE_EXISTS,
1763                          "parentPosition",
1764                          FilterOperators.IS_IN,
1765                          new Path[]{parentPositionIdentity}
1766                      )
1767                  },
1768            AttributeSelectors.ALL_ATTRIBUTES,
1769            0,
1770            Integer.MAX_VALUE,
1771            Directions.ASCENDING
1772        );
1773        int nPositions = 0;
1774        for(
1775            Iterator JavaDoc i = positions.iterator();
1776            i.hasNext();
1777        ) {
1778            DataproviderObject_1_0 pos = (DataproviderObject_1_0)i.next();
1779            if(productRole.path().equals(pos.values("basedOn").get(0))) {
1780                nPositions++;
1781            }
1782        }
1783        return nPositions > ((Number JavaDoc)productRole.values("minPositions").get(0)).intValue();
1784    }
1785
1786    //-------------------------------------------------------------------------
1787
public boolean allowPositionCreation(
1788        Path contractIdentity,
1789        DataproviderObject_1_0 productRole,
1790        Path parentPositionIdentity
1791    ) throws ServiceException {
1792        List JavaDoc positions = this.delegation.addFindRequest(
1793            contractIdentity.getChild("position"),
1794            parentPositionIdentity == null
1795                ? null
1796                : new FilterProperty[]{
1797                      new FilterProperty(
1798                          Quantors.THERE_EXISTS,
1799                          "parentPosition",
1800                          FilterOperators.IS_IN,
1801                          new Path[]{parentPositionIdentity}
1802                      )
1803                  },
1804            AttributeSelectors.ALL_ATTRIBUTES,
1805            0,
1806            Integer.MAX_VALUE,
1807            Directions.ASCENDING
1808        );
1809        int nPositions = 0;
1810        for(
1811            Iterator JavaDoc i = positions.iterator();
1812            i.hasNext();
1813        ) {
1814            DataproviderObject_1_0 pos = (DataproviderObject_1_0)i.next();
1815            if(productRole.path().equals(pos.values("basedOn").get(0))) {
1816                nPositions++;
1817            }
1818        }
1819        return nPositions < ((Number JavaDoc)productRole.values("maxPositions").get(0)).intValue();
1820    }
1821
1822    //-------------------------------------------------------------------------
1823
public void removeContractPosition(
1824        ServiceHeader header,
1825        DataproviderObject_1_0 position,
1826        boolean checkForMinPositions
1827    ) throws ServiceException {
1828        Path contractIdentity = position.path().getPrefix(position.path().size() - 2);
1829        Path productRoleIdentity = (Path)position.values("basedOn").get(0);
1830        if(productRoleIdentity != null) {
1831            DataproviderObject_1_0 productRole = this.plugin.retrieveObjectFromDelegation(productRoleIdentity);
1832            Path parentPositionIdentity = (Path)position.values("parentPosition").get(0);
1833            if(checkForMinPositions && !this.allowPositionRemoval(contractIdentity, productRole, parentPositionIdentity)) {
1834                throw new ServiceException(
1835                    OpenCrxException.DOMAIN,
1836                    OpenCrxException.CONTRACT_MIN_POSITIONS_REACHED,
1837                    new BasicException.Parameter[]{
1838                         new BasicException.Parameter("param0", productRole.values("minPositions").get(0)),
1839                         new BasicException.Parameter("param1", position.values("name").get(0))
1840                    },
1841                    "Removal not allowed. Min positions reached."
1842                );
1843            }
1844            // Remove all contained positions
1845
List JavaDoc positions = this.delegation.addFindRequest(
1846                contractIdentity.getChild("position"),
1847                new FilterProperty[]{
1848                    new FilterProperty(
1849                        Quantors.THERE_EXISTS,
1850                        "parentPosition",
1851                        FilterOperators.IS_IN,
1852                        new Path[]{position.path()}
1853                    )
1854                },
1855                AttributeSelectors.ALL_ATTRIBUTES,
1856                0,
1857                Integer.MAX_VALUE,
1858                Directions.ASCENDING
1859            );
1860            for(
1861                Iterator JavaDoc i = positions.iterator();
1862                i.hasNext();
1863            ) {
1864                DataproviderObject_1_0 childPosition = (DataproviderObject_1_0)i.next();
1865                this.removeContractPosition(
1866                    header,
1867                    childPosition,
1868                    false
1869                );
1870            }
1871        }
1872        this.plugin.removeObject(position.path());
1873    }
1874    
1875    //-------------------------------------------------------------------------
1876
/**
1877     * Copy depot references from product role to contract position.
1878     */

1879    private Set JavaDoc createDepotReferences(
1880        ServiceHeader header,
1881        Path depotHolderIdentity,
1882        Path positionIdentity,
1883        Set JavaDoc excludeDepotUsage
1884    ) throws ServiceException {
1885        Set JavaDoc depotUsages = new HashSet JavaDoc();
1886        List JavaDoc depotReferences = this.delegation.addFindRequest(
1887            depotHolderIdentity.getChild("depotReference"),
1888            null,
1889            AttributeSelectors.ALL_ATTRIBUTES,
1890            0,
1891            Integer.MAX_VALUE,
1892            Directions.ASCENDING
1893        );
1894        for(
1895            Iterator JavaDoc i = depotReferences.iterator();
1896            i.hasNext();
1897        ) {
1898            DataproviderObject_1_0 depotReference = (DataproviderObject_1_0)i.next();
1899            Integer JavaDoc depotUsage = new Integer JavaDoc(((Number JavaDoc)depotReference.values("depotUsage").get(0)).intValue());
1900            if(!excludeDepotUsage.contains(depotUsage)) {
1901                this.plugin.cloneable.cloneAndUpdateReferences(
1902                    header,
1903                    depotReference,
1904                    positionIdentity.getChild("depotReference"),
1905                    null,
1906                    "",
1907                    true
1908                );
1909            }
1910            depotUsages.add(depotUsage);
1911        }
1912        return depotUsages;
1913    }
1914    
1915    //-------------------------------------------------------------------------
1916
public DataproviderObject createProductOfferingPosition(
1917        ServiceHeader header,
1918        Path contractIdentity,
1919        Path productOfferingIdentity,
1920        BigDecimal JavaDoc quantity
1921    ) throws ServiceException {
1922        DataproviderObject_1_0 contract = this.plugin.retrieveObjectFromLocal(
1923            header,
1924            contractIdentity
1925        );
1926        if(productOfferingIdentity == null) {
1927            throw new ServiceException(
1928                OpenCrxException.DOMAIN,
1929                OpenCrxException.CONTRACT_MISSING_PRODUCT_OFFERING,
1930                null,
1931                "missing product offering"
1932            );
1933        }
1934        DataproviderObject_1_0 productOffering = this.plugin.retrieveObjectFromLocal(
1935            header,
1936            productOfferingIdentity
1937        );
1938        if(!this.allowPositionCreation(contractIdentity, productOffering, null)) {
1939            throw new ServiceException(
1940                OpenCrxException.DOMAIN,
1941                OpenCrxException.CONTRACT_MAX_POSITIONS_REACHED,
1942                new BasicException.Parameter[]{
1943                     new BasicException.Parameter("param0", productOffering.values("maxPositions").get(0))
1944                },
1945                "Creation not allowed. Max positions reached."
1946            );
1947        }
1948        
1949        String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
1950        DataproviderObject position = new DataproviderObject(
1951            contractIdentity.getDescendant(new String JavaDoc[]{"position", this.plugin.getUidAsString()})
1952        );
1953        if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
1954            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:OpportunityProductOfferingPosition");
1955        }
1956        else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
1957            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteProductOfferingPosition");
1958        }
1959        else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
1960            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderProductOfferingPosition");
1961        }
1962        else if("org:opencrx:kernel:contract1:Invoice".equals(contractType)) {
1963            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceProductOfferingPosition");
1964        }
1965        else {
1966            throw new ServiceException(
1967                BasicException.Code.DEFAULT_DOMAIN,
1968                BasicException.Code.NOT_SUPPORTED,
1969                new BasicException.Parameter[]{
1970                    new BasicException.Parameter("contract type", contractType)
1971                },
1972                "Unsupported contract type. Supported are [Lead|Opportunity|Quote|SalesOrder|Invoice]"
1973            );
1974        }
1975        position.values("basedOn").add(productOfferingIdentity);
1976        position.values("lineItemNumber").add(
1977            new Integer JavaDoc(
1978                100000 * (this.getMaxLineItemNumber(contract, null) / 100000 + 1)
1979            )
1980        );
1981        position.values("name").addAll(productOffering.values("name"));
1982        position.values("description").addAll(productOffering.values("description"));
1983        position.values("contractPositionState").add(
1984            new Integer JavaDoc(0)
1985        );
1986        quantity = (quantity == null) || quantity.compareTo(new BigDecimal JavaDoc(0)) == 0
1987            ? productOffering.values("defaultQuantity").size() == 0
1988                ? new BigDecimal JavaDoc(1)
1989                : (BigDecimal JavaDoc)productOffering.values("defaultQuantity").get(0)
1990            : quantity;
1991        position.values("quantity").add(quantity);
1992        position.values("minQuantity").addAll(productOffering.values("minQuantity"));
1993        position.values("maxQuantity").addAll(productOffering.values("maxQuantity"));
1994        position.values("offsetQuantity").addAll(productOffering.values("offsetQuantity"));
1995        position.values("minMaxQuantityHandling").addAll(productOffering.values("minMaxQuantityHandling"));
1996        position.values("discountIsPercentage").addAll(productOffering.values("discountIsPercentage"));
1997        position.values("discount").addAll(productOffering.values("discount"));
1998        this.updateContractPositionPrice(
1999            contract,
2000            position,
2001            null,
2002            productOffering,
2003            true
2004        );
2005        // Reset pricePerUnit if offering does not override
2006
if(
2007            (productOffering.values("overridePrice").size() == 0) || !((Boolean JavaDoc)productOffering.values("overridePrice").get(0)).booleanValue()
2008        ) {
2009            position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2010        }
2011        this.delegation.addCreateRequest(
2012            position
2013        );
2014        
2015        // Create depot references
2016
this.createDepotReferences(
2017            header,
2018            productOffering.path(),
2019            position.path(),
2020            new HashSet JavaDoc()
2021        );
2022        
2023        // Create product bundle positions
2024
List JavaDoc productBundles = this.delegation.addFindRequest(
2025            productOffering.path().getChild("productBundle"),
2026            null,
2027            AttributeSelectors.ALL_ATTRIBUTES,
2028            new AttributeSpecifier[]{
2029                new AttributeSpecifier("itemNumber", 0, Orders.ASCENDING)
2030            },
2031            0,
2032            Integer.MAX_VALUE,
2033            Directions.ASCENDING
2034        );
2035        for(
2036            Iterator JavaDoc i = productBundles.iterator();
2037            i.hasNext();
2038        ) {
2039            DataproviderObject_1_0 productBundle = (DataproviderObject_1_0)i.next();
2040            int defaultPositions = productBundle.values("defaultPositions").size() == 0
2041                ? 0
2042                : ((Number JavaDoc)productBundle.values("defaultPositions").get(0)).intValue();
2043            for(
2044                int j = 0;
2045                j < defaultPositions;
2046                j++
2047            ) {
2048                BigDecimal JavaDoc positionQuantity = (BigDecimal JavaDoc)position.values("quantity").get(0);
2049                this.createProductBundlePosition(
2050                    header,
2051                    position.path(),
2052                    contractIdentity,
2053                    productBundle.path(),
2054                    positionQuantity.multiply((BigDecimal JavaDoc)productBundle.values("defaultQuantity").get(0))
2055                );
2056            }
2057        }
2058        return position;
2059    }
2060
2061    //-------------------------------------------------------------------------
2062
public DataproviderObject createProductBundlePosition(
2063        ServiceHeader header,
2064        Path parentPositionIdentity,
2065        Path contractIdentity,
2066        Path productBundleIdentity,
2067        BigDecimal JavaDoc quantity
2068    ) throws ServiceException {
2069        DataproviderObject_1_0 contract = this.plugin.retrieveObjectFromLocal(
2070            header,
2071            contractIdentity
2072        );
2073        DataproviderObject_1_0 parentPosition = this.plugin.retrieveObjectFromLocal(
2074            header,
2075            parentPositionIdentity
2076        );
2077        DataproviderObject_1_0 productBundle = this.plugin.retrieveObjectFromLocal(
2078            header,
2079            productBundleIdentity
2080        );
2081        if(!this.allowPositionCreation(contractIdentity, productBundle, parentPositionIdentity)) {
2082            throw new ServiceException(
2083                OpenCrxException.DOMAIN,
2084                OpenCrxException.CONTRACT_MAX_POSITIONS_REACHED,
2085                new BasicException.Parameter[]{
2086                     new BasicException.Parameter("param0", productBundle.values("maxPositions").get(0))
2087                },
2088                "Creation not allowed. Max positions reached."
2089            );
2090        }
2091        DataproviderObject_1_0 productBundleType = this.plugin.retrieveObjectFromLocal(
2092            header,
2093            (Path)productBundle.values("bundleType").get(0)
2094        );
2095        DataproviderObject_1_0 productOffering = this.plugin.retrieveObjectFromLocal(
2096            header,
2097            productBundleIdentity.getPrefix(productBundleIdentity.size() - 2)
2098        );
2099        String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
2100        DataproviderObject position = new DataproviderObject(
2101            contractIdentity.getDescendant(new String JavaDoc[]{"position", this.plugin.getUidAsString()})
2102        );
2103        if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
2104            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:OpportunityProductBundlePosition");
2105        }
2106        else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
2107            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteProductBundlePosition");
2108        }
2109        else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
2110            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderProductBundlePosition");
2111        }
2112        else if("org:opencrx:kernel:contract1:Invoice".equals(contractType)) {
2113            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceProductBundlePosition");
2114        }
2115        else {
2116            throw new ServiceException(
2117                BasicException.Code.DEFAULT_DOMAIN,
2118                BasicException.Code.NOT_SUPPORTED,
2119                new BasicException.Parameter[]{
2120                    new BasicException.Parameter("contract type", contractType)
2121                },
2122                "Unsupported contract type. Supported are [Lead|Opportunity|Quote|SalesOrder|Invoice]"
2123            );
2124        }
2125        position.values("basedOn").add(productBundleIdentity);
2126        position.values("parentPosition").add(parentPositionIdentity);
2127        position.values("lineItemNumber").add(
2128            new Integer JavaDoc(
2129                java.lang.Math.max(
2130                    this.getMaxLineItemNumber(contract, parentPositionIdentity) + 100,
2131                    ((Number JavaDoc)parentPosition.values("lineItemNumber").get(0)).intValue() + 100
2132                )
2133            )
2134        );
2135        position.values("name").addAll(productBundle.values("name"));
2136        position.values("description").addAll(productBundle.values("description"));
2137        position.values("contractPositionState").add(
2138            new Integer JavaDoc(0)
2139        );
2140        position.values("quantity").add(
2141            quantity == null
2142                ? productBundle.values("defaultQuantity").get(0)
2143                : quantity
2144        );
2145        position.values("minQuantity").addAll(productBundle.values("minQuantity"));
2146        position.values("maxQuantity").addAll(productBundle.values("maxQuantity"));
2147        position.values("offsetQuantity").addAll(productBundle.values("offsetQuantity"));
2148        position.values("minMaxQuantityHandling").addAll(productBundle.values("minMaxQuantityHandling"));
2149        position.values("discountIsPercentage").addAll(productBundle.values("discountIsPercentage"));
2150        position.values("discount").addAll(productBundle.values("discount"));
2151        // if product bundle does not override price fall back to product bundle type
2152
if(
2153            ((productBundle.values("overridePrice").size() == 0) || !((Boolean JavaDoc)productBundle.values("overridePrice").get(0)).booleanValue())
2154        ) {
2155            boolean priceSet = this.updateContractPositionPrice(
2156                contract,
2157                position,
2158                null,
2159                productBundleType,
2160                true
2161            );
2162            // Reset pricePerUnit if bundle type does not override
2163
if(
2164                ((productBundleType.values("overridePrice").size() == 0) || !((Boolean JavaDoc)productBundleType.values("overridePrice").get(0)).booleanValue())
2165            ) {
2166                position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2167            }
2168            // If product bundle type does not set price fall back to product bundle
2169
if(!priceSet) {
2170                this.updateContractPositionPrice(
2171                    contract,
2172                    position,
2173                    null,
2174                    productBundle,
2175                    true
2176                );
2177                // and reset pricePerUnit because product bundle does not override
2178
position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2179            }
2180        }
2181        // product bundle overrides price
2182
else {
2183            this.updateContractPositionPrice(
2184                contract,
2185                position,
2186                null,
2187                productBundle,
2188                true
2189            );
2190        }
2191        // Reset pricePerUnit if offering does override
2192
if(
2193            ((productOffering.values("overridePrice").size() > 0) && ((Boolean JavaDoc)productOffering.values("overridePrice").get(0)).booleanValue())
2194        ) {
2195            position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2196        }
2197        this.delegation.addCreateRequest(
2198            position
2199        );
2200        
2201        // Create depot references
2202
this.createDepotReferences(
2203            header,
2204            productBundle.path(),
2205            position.path(),
2206            new HashSet JavaDoc()
2207        );
2208        
2209        // Create bundled product positions
2210
List JavaDoc bundledProducts = this.delegation.addFindRequest(
2211            productBundleType.path().getChild("bundledProduct"),
2212            null,
2213            AttributeSelectors.ALL_ATTRIBUTES,
2214            new AttributeSpecifier[]{
2215                new AttributeSpecifier("itemNumber", 0, Orders.ASCENDING)
2216            },
2217            0,
2218            Integer.MAX_VALUE,
2219            Directions.ASCENDING
2220        );
2221        for(
2222            Iterator JavaDoc i = bundledProducts.iterator();
2223            i.hasNext();
2224        ) {
2225            DataproviderObject_1_0 bundledProduct = (DataproviderObject_1_0)i.next();
2226            int defaultPositions = bundledProduct.values("defaultPositions").size() == 0
2227                ? 0
2228                : ((Number JavaDoc)bundledProduct.values("defaultPositions").get(0)).intValue();
2229            for(
2230                int j = 0;
2231                j < defaultPositions;
2232                j++
2233            ) {
2234                BigDecimal JavaDoc positionQuantity = (BigDecimal JavaDoc)position.values("quantity").get(0);
2235                this.createBundledProductPosition(
2236                    header,
2237                    position.path(),
2238                    contractIdentity,
2239                    bundledProduct.path(),
2240                    positionQuantity.multiply((BigDecimal JavaDoc)bundledProduct.values("defaultQuantity").get(0))
2241                );
2242            }
2243        }
2244        return position;
2245    }
2246
2247    //-------------------------------------------------------------------------
2248
public DataproviderObject createBundledProductPosition(
2249        ServiceHeader header,
2250        Path parentPositionIdentity,
2251        Path contractIdentity,
2252        Path bundledProductIdentity,
2253        BigDecimal JavaDoc quantity
2254    ) throws ServiceException {
2255        DataproviderObject_1_0 contract = this.plugin.retrieveObjectFromLocal(
2256            header,
2257            contractIdentity
2258        );
2259        DataproviderObject_1_0 parentPosition = this.plugin.retrieveObjectFromLocal(
2260            header,
2261            parentPositionIdentity
2262        );
2263        DataproviderObject_1_0 productBundle = this.plugin.retrieveObjectFromLocal(
2264            header,
2265            (Path)parentPosition.values("basedOn").get(0)
2266        );
2267        DataproviderObject_1_0 productBundleType = this.plugin.retrieveObjectFromLocal(
2268            header,
2269            (Path)productBundle.values("bundleType").get(0)
2270        );
2271        DataproviderObject_1_0 bundledProduct = this.plugin.retrieveObjectFromLocal(
2272            header,
2273            bundledProductIdentity
2274        );
2275        if(!this.allowPositionCreation(contractIdentity, bundledProduct, parentPositionIdentity)) {
2276            throw new ServiceException(
2277                OpenCrxException.DOMAIN,
2278                OpenCrxException.CONTRACT_MAX_POSITIONS_REACHED,
2279                new BasicException.Parameter[]{
2280                     new BasicException.Parameter("param0", bundledProduct.values("maxPositions").get(0))
2281                },
2282                "Creation not allowed. Max positions reached."
2283            );
2284        }
2285        DataproviderObject_1_0 product = this.plugin.retrieveObjectFromLocal(
2286            header,
2287            (Path)bundledProduct.values("product").get(0)
2288        );
2289        DataproviderObject_1_0 productOffering = this.plugin.retrieveObjectFromLocal(
2290            header,
2291            productBundle.path().getPrefix(productBundle.path().size() - 2)
2292        );
2293        String JavaDoc contractType = (String JavaDoc)contract.values(SystemAttributes.OBJECT_CLASS).get(0);
2294        
2295        // Create position
2296
DataproviderObject position = new DataproviderObject(
2297            contractIdentity.getDescendant(new String JavaDoc[]{"position", this.plugin.getUidAsString()})
2298        );
2299        if("org:opencrx:kernel:contract1:Opportunity".equals(contractType)) {
2300            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:OpportunityBundledProductPosition");
2301        }
2302        else if("org:opencrx:kernel:contract1:Quote".equals(contractType)) {
2303            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:QuoteBundledProductPosition");
2304        }
2305        else if("org:opencrx:kernel:contract1:SalesOrder".equals(contractType)) {
2306            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:SalesOrderBundledProductPosition");
2307        }
2308        else if("org:opencrx:kernel:contract1:Invoice".equals(contractType)) {
2309            position.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:contract1:InvoiceBundledProductPosition");
2310        }
2311        else {
2312            throw new ServiceException(
2313                BasicException.Code.DEFAULT_DOMAIN,
2314                BasicException.Code.NOT_SUPPORTED,
2315                new BasicException.Parameter[]{
2316                    new BasicException.Parameter("contract type", contractType)
2317                },
2318                "Unsupported contract type. Supported are [Lead|Opportunity|Quote|SalesOrder|Invoice]"
2319            );
2320        }
2321        position.values("basedOn").add(bundledProductIdentity);
2322        position.values("parentPosition").add(parentPositionIdentity);
2323        position.values("lineItemNumber").add(
2324            new Integer JavaDoc(
2325                java.lang.Math.max(
2326                    this.getMaxLineItemNumber(contract, parentPositionIdentity) + 1,
2327                    ((Number JavaDoc)parentPosition.values("lineItemNumber").get(0)).intValue() + 1
2328                )
2329            )
2330        );
2331        position.values("name").addAll(bundledProduct.values("name"));
2332        position.values("description").addAll(bundledProduct.values("description"));
2333        position.values("contractPositionState").add(
2334            new Integer JavaDoc(0)
2335        );
2336        position.values("quantity").add(
2337            quantity == null
2338                ? bundledProduct.values("defaultQuantity").get(0)
2339                : quantity
2340        );
2341        position.values("minQuantity").addAll(bundledProduct.values("minQuantity"));
2342        position.values("maxQuantity").addAll(bundledProduct.values("maxQuantity"));
2343        position.values("offsetQuantity").addAll(bundledProduct.values("offsetQuantity"));
2344        position.values("minMaxQuantityHandling").addAll(bundledProduct.values("minMaxQuantityHandling"));
2345        position.values("discountIsPercentage").addAll(bundledProduct.values("discountIsPercentage"));
2346        position.values("discount").addAll(bundledProduct.values("discount"));
2347        position.values("product").addAll(bundledProduct.values("product"));
2348        boolean priceSet = this.updateContractPositionPrice(
2349            contract,
2350            position,
2351            null,
2352            bundledProduct,
2353            true
2354        );
2355        // Reset pricePerUnit if not bundled product does not override
2356
if(
2357            ((bundledProduct.values("overridePrice").size() == 0) || !((Boolean JavaDoc)bundledProduct.values("overridePrice").get(0)).booleanValue())
2358        ) {
2359            position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2360        }
2361        if(!priceSet) {
2362            this.updateContractPositionPrice(
2363                contract,
2364                position,
2365                null,
2366                product,
2367                true
2368            );
2369        }
2370        // Reset pricePerUnit if not defined on offering, bundle or bundle type
2371
if(
2372            ((productBundle.values("overridePrice").size() > 0) && ((Boolean JavaDoc)productBundle.values("overridePrice").get(0)).booleanValue()) ||
2373            ((productBundleType.values("overridePrice").size() > 0) && ((Boolean JavaDoc)productBundleType.values("overridePrice").get(0)).booleanValue()) ||
2374            ((productOffering.values("overridePrice").size() > 0) && ((Boolean JavaDoc)productOffering.values("overridePrice").get(0)).booleanValue())
2375        ) {
2376            position.clearValues("pricePerUnit").add(new BigDecimal JavaDoc(0.0));
2377        }
2378        this.delegation.addCreateRequest(
2379            position
2380        );
2381        // Create depot references
2382
// Take from bundled product
2383
Set JavaDoc depotUsages = this.createDepotReferences(
2384            header,
2385            bundledProduct.path(),
2386            position.path(),
2387            new HashSet JavaDoc()
2388        );
2389        // Take from product but exclude depot usages
2390
// defined on bundled product
2391
this.createDepotReferences(
2392            header,
2393            product.path(),
2394            position.path(),
2395            depotUsages
2396        );
2397        // Clone configurations
2398
this.plugin.products.cloneProductConfigurationSet(
2399            header,
2400            bundledProductIdentity,
2401            position.path(),
2402            true,
2403            true
2404        );
2405        return position;
2406    }
2407
2408    //-------------------------------------------------------------------------
2409
public DataproviderObject createSelectableProductBundleFromContractPosition(
2410        Path offeringPositionIdentity,
2411        int itemNumber,
2412        DataproviderObject_1_0 contractPosition
2413    ) throws ServiceException {
2414        DataproviderObject_1_0 productBundle = this.plugin.retrieveObjectFromDelegation(
2415            (Path)contractPosition.values("basedOn").get(0)
2416        );
2417        // Take qualifier from position for selectable product bundles created from a position
2418
DataproviderObject selectableBundle = new DataproviderObject(
2419            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", MODIFY_PRODUCT_BUNDLE_POSITION + ":position=" + contractPosition.path().getBase()})
2420        );
2421        selectableBundle.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableProductBundle");
2422        selectableBundle.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2423        selectableBundle.values("name").addAll(contractPosition.values("name"));
2424        selectableBundle.values("description").addAll(contractPosition.values("description"));
2425        selectableBundle.values("selector").add(Boolean.TRUE);
2426        selectableBundle.values("quantity").addAll(contractPosition.values("quantity"));
2427        selectableBundle.values("minQuantity").addAll(productBundle.values("minQuantity"));
2428        selectableBundle.values("maxQuantity").addAll(productBundle.values("maxQuantity"));
2429        selectableBundle.values("defaultQuantity").addAll(productBundle.values("defaultQuantity"));
2430        selectableBundle.values("basedOn").add(productBundle.path());
2431        selectableBundle.values("owningUser").addAll(contractPosition.values("owningUser"));
2432        selectableBundle.values("owningGroup").addAll(contractPosition.values("owningGroup"));
2433        selectableBundle.values(SystemAttributes.OBJECT_IDENTITY).add(selectableBundle.path().toXri());
2434        selectableBundle.values(SystemAttributes.CREATED_AT).addAll(contractPosition.values(SystemAttributes.CREATED_AT));
2435        selectableBundle.values(SystemAttributes.MODIFIED_AT).addAll(contractPosition.values(SystemAttributes.MODIFIED_AT));
2436        selectableBundle.values(SystemAttributes.CREATED_BY).addAll(contractPosition.values(SystemAttributes.CREATED_BY));
2437        selectableBundle.values(SystemAttributes.MODIFIED_BY).addAll(contractPosition.values(SystemAttributes.MODIFIED_BY));
2438        return selectableBundle;
2439    }
2440    
2441    //-------------------------------------------------------------------------
2442
public DataproviderObject createSelectableProductBundleFromProductBundle(
2443        Path offeringPositionIdentity,
2444        int itemNumber,
2445        DataproviderObject_1_0 productBundle
2446    ) throws ServiceException {
2447        // Take qualifier from product bundle for selectable product bundles created from a product bundle
2448
DataproviderObject selectableBundle = new DataproviderObject(
2449            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", NEW_PRODUCT_BUNDLE_POSITION + ":parent=" + offeringPositionIdentity.getBase() + ":productBundleId=" + productBundle.path().getBase()})
2450        );
2451        selectableBundle.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableProductBundle");
2452        selectableBundle.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2453        selectableBundle.values("name").addAll(productBundle.values("name"));
2454        selectableBundle.values("description").addAll(productBundle.values("description"));
2455        selectableBundle.values("selector").add(Boolean.FALSE);
2456        selectableBundle.values("quantity").addAll(productBundle.values("defaultQuantity"));
2457        selectableBundle.values("minQuantity").addAll(productBundle.values("minQuantity"));
2458        selectableBundle.values("maxQuantity").addAll(productBundle.values("maxQuantity"));
2459        selectableBundle.values("defaultQuantity").addAll(productBundle.values("defaultQuantity"));
2460        selectableBundle.values("basedOn").add(productBundle.path());
2461        selectableBundle.values("owningUser").addAll(productBundle.values("owningUser"));
2462        selectableBundle.values("owningGroup").addAll(productBundle.values("owningGroup"));
2463        selectableBundle.values(SystemAttributes.OBJECT_IDENTITY).add(selectableBundle.path().toXri());
2464        selectableBundle.values(SystemAttributes.CREATED_AT).addAll(productBundle.values(SystemAttributes.CREATED_AT));
2465        selectableBundle.values(SystemAttributes.MODIFIED_AT).addAll(productBundle.values(SystemAttributes.MODIFIED_AT));
2466        selectableBundle.values(SystemAttributes.CREATED_BY).addAll(productBundle.values(SystemAttributes.CREATED_BY));
2467        selectableBundle.values(SystemAttributes.MODIFIED_BY).addAll(productBundle.values(SystemAttributes.MODIFIED_BY));
2468        return selectableBundle;
2469    }
2470    
2471    //-------------------------------------------------------------------------
2472
public DataproviderObject createSelectableBundledProductFromContractPosition(
2473        Path offeringPositionIdentity,
2474        int itemNumber,
2475        DataproviderObject_1_0 contractPosition
2476    ) throws ServiceException {
2477        DataproviderObject_1_0 bundledProduct = this.plugin.retrieveObjectFromDelegation(
2478            (Path)contractPosition.values("basedOn").get(0)
2479        );
2480        // Take qualifier from position for selectable bundled products created from a position
2481
DataproviderObject selectableBundledProduct = new DataproviderObject(
2482            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", MODIFY_BUNDLED_PRODUCT_POSITION + ":position=" + contractPosition.path().getBase()})
2483        );
2484        selectableBundledProduct.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableBundledProduct");
2485        selectableBundledProduct.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2486        selectableBundledProduct.values("name").addAll(contractPosition.values("name"));
2487        selectableBundledProduct.values("description").addAll(contractPosition.values("description"));
2488        selectableBundledProduct.values("selector").add(Boolean.TRUE);
2489        selectableBundledProduct.values("quantity").addAll(contractPosition.values("quantity"));
2490        selectableBundledProduct.values("minQuantity").addAll(bundledProduct.values("minQuantity"));
2491        selectableBundledProduct.values("maxQuantity").addAll(bundledProduct.values("maxQuantity"));
2492        selectableBundledProduct.values("defaultQuantity").addAll(bundledProduct.values("defaultQuantity"));
2493        selectableBundledProduct.values("basedOn").add(bundledProduct.path());
2494        selectableBundledProduct.values("owningUser").addAll(contractPosition.values("owningUser"));
2495        selectableBundledProduct.values("owningGroup").addAll(contractPosition.values("owningGroup"));
2496        selectableBundledProduct.values(SystemAttributes.OBJECT_IDENTITY).add(selectableBundledProduct.path().toXri());
2497        selectableBundledProduct.values(SystemAttributes.CREATED_AT).addAll(bundledProduct.values(SystemAttributes.CREATED_AT));
2498        selectableBundledProduct.values(SystemAttributes.MODIFIED_AT).addAll(bundledProduct.values(SystemAttributes.MODIFIED_AT));
2499        selectableBundledProduct.values(SystemAttributes.CREATED_BY).addAll(bundledProduct.values(SystemAttributes.CREATED_BY));
2500        selectableBundledProduct.values(SystemAttributes.MODIFIED_BY).addAll(bundledProduct.values(SystemAttributes.MODIFIED_BY));
2501        return selectableBundledProduct;
2502    }
2503
2504    //-------------------------------------------------------------------------
2505
public DataproviderObject createSelectableBundledProductFromBundledProduct(
2506        Path offeringPositionIdentity,
2507        Path productBundlePositionIdentity,
2508        int itemNumber,
2509        DataproviderObject_1_0 bundledProduct
2510    ) throws ServiceException {
2511        DataproviderObject selectableBundledProduct = new DataproviderObject(
2512            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", NEW_BUNDLED_PRODUCT_POSITION + ":parent=" + productBundlePositionIdentity.getBase() + ":bundledProductId=" + bundledProduct.path().getBase()})
2513        );
2514        selectableBundledProduct.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableBundledProduct");
2515        selectableBundledProduct.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2516        selectableBundledProduct.values("name").addAll(bundledProduct.values("name"));
2517        selectableBundledProduct.values("description").addAll(bundledProduct.values("description"));
2518        selectableBundledProduct.values("selector").add(Boolean.FALSE);
2519        selectableBundledProduct.values("quantity").addAll(bundledProduct.values("defaultQuantity"));
2520        selectableBundledProduct.values("minQuantity").addAll(bundledProduct.values("minQuantity"));
2521        selectableBundledProduct.values("maxQuantity").addAll(bundledProduct.values("maxQuantity"));
2522        selectableBundledProduct.values("defaultQuantity").addAll(bundledProduct.values("defaultQuantity"));
2523        selectableBundledProduct.values("basedOn").add(bundledProduct.path());
2524        selectableBundledProduct.values("owningUser").addAll(bundledProduct.values("owningUser"));
2525        selectableBundledProduct.values("owningGroup").addAll(bundledProduct.values("owningGroup"));
2526        selectableBundledProduct.values(SystemAttributes.OBJECT_IDENTITY).add(selectableBundledProduct.path().toXri());
2527        selectableBundledProduct.values(SystemAttributes.CREATED_AT).addAll(bundledProduct.values(SystemAttributes.CREATED_AT));
2528        selectableBundledProduct.values(SystemAttributes.MODIFIED_AT).addAll(bundledProduct.values(SystemAttributes.MODIFIED_AT));
2529        selectableBundledProduct.values(SystemAttributes.CREATED_BY).addAll(bundledProduct.values(SystemAttributes.CREATED_BY));
2530        selectableBundledProduct.values(SystemAttributes.MODIFIED_BY).addAll(bundledProduct.values(SystemAttributes.MODIFIED_BY));
2531        return selectableBundledProduct;
2532    }
2533    
2534    //-------------------------------------------------------------------------
2535
public DataproviderObject createSelectableProductConfigurationFromContractPosition(
2536        Path offeringPositionIdentity,
2537        Path contractPosition,
2538        int itemNumber,
2539        DataproviderObject_1_0 productConfiguration
2540    ) throws ServiceException {
2541        DataproviderObject selectableProductConfiguration = new DataproviderObject(
2542            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", MODIFY_CONFIGURATION + ":position=" + contractPosition.getBase() + ":configId=" + productConfiguration.path().getBase()})
2543        );
2544        selectableProductConfiguration.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableProductConfiguration");
2545        selectableProductConfiguration.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2546        selectableProductConfiguration.values("name").addAll(productConfiguration.values("name"));
2547        selectableProductConfiguration.values("description").addAll(productConfiguration.values("description"));
2548        selectableProductConfiguration.values("selector").add(Boolean.TRUE);
2549        selectableProductConfiguration.values("basedOn").add(productConfiguration.path());
2550        selectableProductConfiguration.values("owningUser").addAll(productConfiguration.values("owningUser"));
2551        selectableProductConfiguration.values("owningGroup").addAll(productConfiguration.values("owningGroup"));
2552        selectableProductConfiguration.values(SystemAttributes.OBJECT_IDENTITY).add(selectableProductConfiguration.path().toXri());
2553        selectableProductConfiguration.values(SystemAttributes.CREATED_AT).addAll(productConfiguration.values(SystemAttributes.CREATED_AT));
2554        selectableProductConfiguration.values(SystemAttributes.MODIFIED_AT).addAll(productConfiguration.values(SystemAttributes.MODIFIED_AT));
2555        selectableProductConfiguration.values(SystemAttributes.CREATED_BY).addAll(productConfiguration.values(SystemAttributes.CREATED_BY));
2556        selectableProductConfiguration.values(SystemAttributes.MODIFIED_BY).addAll(productConfiguration.values(SystemAttributes.MODIFIED_BY));
2557        return selectableProductConfiguration;
2558    }
2559    
2560    //-------------------------------------------------------------------------
2561
public DataproviderObject createSelectableProductConfigurationFromBundledProduct(
2562        Path offeringPositionIdentity,
2563        Path bundledProductPositionIdentity,
2564        int itemNumber,
2565        DataproviderObject_1_0 productConfiguration
2566    ) throws ServiceException {
2567        DataproviderObject selectableProductConfiguration = new DataproviderObject(
2568            offeringPositionIdentity.getDescendant(new String JavaDoc[]{"selectableItem", NEW_CONFIGURATION + ":parent=" + bundledProductPositionIdentity.getBase() + ":configId=" + productConfiguration.path().getBase()})
2569        );
2570        selectableProductConfiguration.values(SystemAttributes.OBJECT_CLASS).add("org:opencrx:kernel:product1:SelectableProductConfiguration");
2571        selectableProductConfiguration.values("itemNumber").add(new Integer JavaDoc(itemNumber));
2572        selectableProductConfiguration.values("name").addAll(productConfiguration.values("name"));
2573        selectableProductConfiguration.values("description").addAll(productConfiguration.values("description"));
2574        selectableProductConfiguration.values("selector").add(Boolean.FALSE);
2575        selectableProductConfiguration.values("basedOn").add(productConfiguration.path());
2576        selectableProductConfiguration.values("owningUser").addAll(productConfiguration.values("owningUser"));
2577        selectableProductConfiguration.values("owningGroup").addAll(productConfiguration.values("owningGroup"));
2578        selectableProductConfiguration.values(SystemAttributes.OBJECT_IDENTITY).add(selectableProductConfiguration.path().toXri());
2579        selectableProductConfiguration.values(SystemAttributes.CREATED_AT).addAll(productConfiguration.values(SystemAttributes.CREATED_AT));
2580        selectableProductConfiguration.values(SystemAttributes.MODIFIED_AT).addAll(productConfiguration.values(SystemAttributes.MODIFIED_AT));
2581        selectableProductConfiguration.values(SystemAttributes.CREATED_BY).addAll(productConfiguration.values(SystemAttributes.CREATED_BY));
2582        selectableProductConfiguration.values(SystemAttributes.MODIFIED_BY).addAll(productConfiguration.values(SystemAttributes.MODIFIED_BY));
2583        return selectableProductConfiguration;
2584    }
2585        
2586    //-------------------------------------------------------------------------
2587
public void processSelectableItem(
2588        ServiceHeader header,
2589        DataproviderRequest request
2590    ) throws ServiceException {
2591        
2592        String JavaDoc selectableItemId = request.path().getBase();
2593        DataproviderObject newValue = request.object();
2594        Boolean JavaDoc selector = request.object().getValues("selector") == null
2595            ? null
2596            : (Boolean JavaDoc)request.object().getValues("selector").get(0);
2597        String JavaDoc command = selectableItemId.substring(0, selectableItemId.indexOf(":"));
2598
2599        if(MODIFY_PRODUCT_BUNDLE_POSITION.equals(command)) {
2600            String JavaDoc positionId = selectableItemId.substring(selectableItemId.indexOf(":position=")+10);
2601            if(selector != null) {
2602                // Remove product bundle position
2603
if(!selector.booleanValue()) {
2604                    try {
2605                        DataproviderObject_1_0 productBundlePosition = this.plugin.retrieveObjectFromLocal(
2606                            header,
2607                            request.path().getPrefix(request.path().size()-3).getChild(positionId)
2608                        );
2609                        this.removeContractPosition(
2610                            header,
2611                            productBundlePosition,
2612                            true
2613                        );
2614                    }
2615                    catch(ServiceException e) {
2616                        if(e.getExceptionCode() != BasicException.Code.NOT_FOUND) {
2617                            throw e;
2618                        }
2619                    }
2620                }
2621            }
2622            // Modify product bundle position
2623
else {
2624                DataproviderObject_1_0 productBundlePosition = this.plugin.retrieveObjectFromLocal(
2625                    header,
2626                    request.path().getPrefix(request.path().size()-3).getChild(positionId)
2627                );
2628                if(
2629                    (newValue.containsAttributeName("name") && !newValue.values("name").get(0).equals(productBundlePosition.values("name").get(0))) ||
2630                    (newValue.containsAttributeName("description") && !newValue.values("description").get(0).equals(productBundlePosition.values("description").get(0))) ||
2631                    (newValue.containsAttributeName("quantity") && (((BigDecimal JavaDoc)newValue.values("quantity").get(0)).compareTo(productBundlePosition.values("quantity").get(0)) != 0))
2632                ) {
2633                    DataproviderObject modifiedProductBundlePosition = this.plugin.retrieveObjectForModification(
2634                        request.path().getPrefix(request.path().size()-3).getChild(positionId)
2635                    );
2636                    if(newValue.containsAttributeName("name")) {
2637                        modifiedProductBundlePosition.clearValues("name").addAll(
2638                            newValue.values("name")
2639                        );
2640                    }
2641                    if(newValue.containsAttributeName("description")) {
2642                        modifiedProductBundlePosition.clearValues("description").addAll(
2643                            newValue.values("description")
2644                        );
2645                    }
2646                    if(newValue.containsAttributeName("quantity")) {
2647                        modifiedProductBundlePosition.clearValues("quantity").addAll(
2648                            newValue.values("quantity")
2649                        );
2650                    }
2651                }
2652            }
2653        }
2654        else if(NEW_PRODUCT_BUNDLE_POSITION.equals(command)) {
2655            // Create product bundle position
2656
if((selector != null) && selector.booleanValue()) {
2657                String JavaDoc parentId = selectableItemId.substring(
2658                    selectableItemId.indexOf(":parent=")+8,
2659                    selectableItemId.indexOf(":productBundleId=")
2660                );
2661                DataproviderObject_1_0 offeringPosition = this.plugin.retrieveObjectFromLocal(
2662                    header,
2663                    request.path().getPrefix(request.path().size()-3).getChild(parentId)
2664                );
2665                String JavaDoc productBundleId = selectableItemId.substring(
2666                    selectableItemId.indexOf(":productBundleId=")+17
2667                );
2668                this.createProductBundlePosition(
2669                    header,
2670                    offeringPosition.path(),
2671                    offeringPosition.path().getPrefix(offeringPosition.path().size()-2),
2672                    ((Path)offeringPosition.values("basedOn").get(0)).getDescendant(new String JavaDoc[]{"productBundle", productBundleId}),
2673                    (BigDecimal JavaDoc)newValue.values("quantity").get(0)
2674                );
2675            }
2676        }
2677        else if(MODIFY_BUNDLED_PRODUCT_POSITION.equals(command)) {
2678            String JavaDoc positionId = selectableItemId.substring(selectableItemId.indexOf(":position=")+10);
2679            if(selector != null) {
2680                // Remove bundled product position
2681
if(!selector.booleanValue()) {
2682                    try {
2683                        DataproviderObject_1_0 bundledProductPosition = this.plugin.retrieveObjectFromLocal(
2684                            header,
2685                            request.path().getPrefix(request.path().size()-3).getChild(positionId)
2686                        );
2687                        this.removeContractPosition(
2688                            header,
2689                            bundledProductPosition,
2690                            true
2691                        );
2692                    }
2693                    catch(ServiceException e) {
2694                        if(e.getExceptionCode() != BasicException.Code.NOT_FOUND) {
2695                            throw e;
2696                        }
2697                    }
2698                }
2699            }
2700            // Modify bundled product position
2701
else {
2702                DataproviderObject_1_0 bundledProductPosition = this.plugin.retrieveObjectFromLocal(
2703                    header,
2704                    request.path().getPrefix(request.path().size()-3).getChild(positionId)
2705                );
2706                if(
2707                    (newValue.containsAttributeName("name") && !newValue.values("name").get(0).equals(bundledProductPosition.values("name").get(0))) ||
2708                    (newValue.containsAttributeName("description") && !newValue.values("description").get(0).equals(bundledProductPosition.values("description").get(0))) ||
2709                    (newValue.containsAttributeName("quantity") && (((BigDecimal JavaDoc)newValue.values("quantity").get(0)).compareTo(bundledProductPosition.values("quantity").get(0)) != 0))
2710                ) {
2711                    DataproviderObject modifiedBundledProductPosition = this.plugin.retrieveObjectForModification(
2712                        request.path().getPrefix(request.path().size()-3).getChild(positionId)
2713                    );
2714                    if(newValue.containsAttributeName("name")) {
2715                        modifiedBundledProductPosition.clearValues("name").addAll(
2716                            newValue.values("name")
2717                        );
2718                    }
2719                    if(newValue.containsAttributeName("description")) {
2720                        modifiedBundledProductPosition.clearValues("description").addAll(
2721                            newValue.values("description")
2722                        );
2723                    }
2724                    if(newValue.containsAttributeName("quantity")) {
2725                        modifiedBundledProductPosition.clearValues("quantity").addAll(
2726                            newValue.values("quantity")
2727                        );
2728                    }
2729                }
2730            }
2731        }
2732        else if(NEW_BUNDLED_PRODUCT_POSITION.equals(command)) {
2733            // Create bundled product position
2734
if((selector != null) && selector.booleanValue()) {
2735                String JavaDoc parentId = selectableItemId.substring(
2736                    selectableItemId.indexOf(":parent=")+8,
2737                    selectableItemId.indexOf(":bundledProductId=")
2738                );
2739                DataproviderObject_1_0 productBundlePosition = this.plugin.retrieveObjectFromLocal(
2740                    header,
2741                    request.path().getPrefix(request.path().size()-3).getChild(parentId)
2742                );
2743                String JavaDoc bundledProductId = selectableItemId.substring(
2744                    selectableItemId.indexOf(":bundledProductId=")+18
2745                );
2746                DataproviderObject_1_0 productBundle = this.plugin.retrieveObjectFromLocal(
2747                    header,
2748                    (Path)productBundlePosition.values("basedOn").get(0)
2749                );
2750                this.createBundledProductPosition(
2751                    header,
2752                    productBundlePosition.path(),
2753                    productBundlePosition.path().getPrefix(productBundlePosition.path().size()-2),
2754                    ((Path)productBundle.values("bundleType").get(0)).getDescendant(new String JavaDoc[]{"bundledProduct", bundledProductId}),
2755                    (BigDecimal JavaDoc)newValue.values("quantity").get(0)
2756                );
2757            }
2758        }
2759        else if(MODIFY_CONFIGURATION.equals(command)) {
2760            String JavaDoc positionId = selectableItemId.substring(
2761                selectableItemId.indexOf(":position=")+10,
2762                selectableItemId.indexOf(":configId=")
2763            );
2764            Path bundledProductPositionIdentity =
2765                request.path().getPrefix(request.path().size()-3).getChild(positionId);
2766            String JavaDoc configId = selectableItemId.substring(
2767                selectableItemId.indexOf(":configId=")+10
2768            );
2769            Path configIdentity = bundledProductPositionIdentity.getDescendant(
2770                    new String JavaDoc[]{"configuration", configId}
2771                );
2772            if(selector != null) {
2773                // Remove configuration and reset current config on position
2774
if(!selector.booleanValue()) {
2775                    try {
2776                        this.plugin.removeObject(
2777                            configIdentity
2778                        );
2779                        DataproviderObject bundledProductPosition = this.plugin.retrieveObjectForModification(
2780                            bundledProductPositionIdentity
2781                        );
2782                        if(
2783                            (bundledProductPosition.getValues("currentConfig") != null) &&
2784                            configIdentity.equals(bundledProductPosition.values("currentConfig").get(0))
2785                        ) {
2786                            bundledProductPosition.clearValues("currentConfig");
2787                        }
2788                    }
2789                    catch(ServiceException e) {
2790                        if(e.getExceptionCode() != BasicException.Code.NOT_FOUND) {
2791                            throw e;
2792                        }
2793                    }
2794                }
2795            }
2796            // Modify configuration
2797
else {
2798                // nothing to modify
2799
}
2800        }
2801        else if(NEW_CONFIGURATION.equals(command)) {
2802            // Create configuration
2803
if((selector != null) && selector.booleanValue()) {
2804                String JavaDoc parentId = selectableItemId.substring(
2805                    selectableItemId.indexOf(":parent=")+8,
2806                    selectableItemId.indexOf(":configId=")
2807                );
2808                Path bundledProductPositionIdentity =
2809                    request.path().getPrefix(request.path().size()-3).getChild(parentId);
2810                DataproviderObject bundledProductPosition = this.plugin.retrieveObjectForModification(
2811                    bundledProductPositionIdentity
2812                );
2813                String JavaDoc configId = selectableItemId.substring(
2814                    selectableItemId.indexOf(":configId=")+10
2815                );
2816                DataproviderObject_1_0 configuration = this.plugin.retrieveObjectFromLocal(
2817                    header,
2818                    ((Path)bundledProductPosition.values("basedOn").get(0)).getDescendant(
2819                        new String JavaDoc[]{"configuration", configId}
2820                    )
2821                );
2822                DataproviderObject_1_0 newConfiguration =
2823                    this.cloning.cloneAndUpdateReferences(
2824                        header,
2825                        configuration,
2826                        bundledProductPositionIdentity.getChild("configuration"),
2827                        null,
2828                        "property",
2829                        true
2830                    );
2831                bundledProductPosition.clearValues("currentConfig").add(
2832                    newConfiguration.path()
2833                );
2834            }
2835        }
2836    }
2837    
2838    //-------------------------------------------------------------------------
2839
public Path updateInventory(
2840        ServiceHeader header,
2841        DataproviderObject_1_0 contract,
2842        Boolean JavaDoc cancelPreviousInventoryUpdate
2843    ) throws ServiceException {
2844
2845        // Do not update inventory if a booking already exists
2846
if(contract.values("inventoryCb").size() > 0) {
2847            return null;
2848        }
2849        DataproviderObject_1_0 deliveryDepot = null;
2850        
2851        // Test depots of contract. It must have at least
2852
// a goods delivery depot.
2853
List JavaDoc depotReferences = this.delegation.addFindRequest(
2854            contract.path().getChild("depotReference"),
2855            null,
2856            AttributeSelectors.ALL_ATTRIBUTES,
2857            0,
2858            Integer.MAX_VALUE,
2859            Directions.ASCENDING
2860        );
2861        boolean hasDepotGoodsDelivery = false;
2862        for(
2863            Iterator JavaDoc j = depotReferences.iterator();
2864            j.hasNext();
2865        ) {
2866            DataproviderObject_1_0 depotReference = (DataproviderObject_1_0)j.next();
2867            Number JavaDoc depotUsage = (Number JavaDoc)depotReference.values("depotUsage").get(0);
2868            if((depotUsage != null) && (depotUsage.shortValue() == Depots.DEPOT_USAGE_GOODS_DELIVERY)) {
2869                hasDepotGoodsDelivery = true;
2870                deliveryDepot = this.plugin.retrieveObjectFromLocal(
2871                    header,
2872                    (Path)depotReference.values("depot").get(0)
2873                );
2874            }
2875        }
2876        if(!hasDepotGoodsDelivery) {
2877            throw new ServiceException(
2878                OpenCrxException.DOMAIN,
2879                OpenCrxException.CONTRACT_MISSING_DEPOT_GOODS_DELIVERY,
2880                new BasicException.Parameter[]{
2881                     new BasicException.Parameter("param0", contract.values("name").get(0)),
2882                },
2883                "Missing goods delivery depot."
2884            );
2885        }
2886
2887        // Test depots of all positions. Each position must have
2888
// a depot with usage=DEPOT_USAGE_GOODS_ISSUE and
2889
// usage=DEPOT_USAGE_GOODS_RETURN
2890
List JavaDoc contractPositions = this.delegation.addFindRequest(
2891            contract.path().getChild("position"),
2892            null,
2893            AttributeSelectors.ALL_ATTRIBUTES,
2894            0,
2895            Integer.MAX_VALUE,
2896            Directions.ASCENDING
2897        );
2898
2899        // Create positions
2900
DataproviderObject_1_0[] issueDepotPositions = new DataproviderObject_1_0[contractPositions.size()];
2901        DataproviderObject_1_0[] returnDepotPositions = new DataproviderObject_1_0[contractPositions.size()];
2902        DataproviderObject_1_0[] deliveryDepotPositions = new DataproviderObject_1_0[contractPositions.size()];
2903        int ii = 0;
2904        for(
2905            Iterator JavaDoc i = contractPositions.iterator();
2906            i.hasNext();
2907            ii++
2908        ) {
2909            DataproviderObject_1_0 position = (DataproviderObject_1_0)i.next();
2910            
2911            depotReferences = this.delegation.addFindRequest(
2912                position.path().getChild("depotReference"),
2913                null,
2914                AttributeSelectors.ALL_ATTRIBUTES,
2915                0,
2916                Integer.MAX_VALUE,
2917                Directions.ASCENDING
2918            );
2919            DataproviderObject_1_0 issueDepot = null;
2920            DataproviderObject_1_0 returnDepot = null;
2921            boolean holderQualifiesPosition = false;
2922            for(
2923                Iterator JavaDoc j = depotReferences.iterator();
2924                j.hasNext();
2925            ) {
2926                DataproviderObject_1_0 depotReference = (DataproviderObject_1_0)j.next();
2927                Number JavaDoc depotUsage = (Number JavaDoc)depotReference.values("depotUsage").get(0);
2928                if((depotUsage != null) && (depotUsage.shortValue() == Depots.DEPOT_USAGE_GOODS_ISSUE)) {
2929                    issueDepot = this.plugin.retrieveObjectFromLocal(
2930                        header,
2931                        (Path)depotReference.values("depot").get(0)
2932                    );
2933                    // The issue depot determines the useDepotPositionQualifier
2934
holderQualifiesPosition = depotReference.values("holderQualifiesPosition").size() > 0
2935                        ? ((Boolean JavaDoc)depotReference.values("holderQualifiesPosition").get(0)).booleanValue()
2936                        : false;
2937                }
2938                if((depotUsage != null) && (depotUsage.shortValue() == Depots.DEPOT_USAGE_GOODS_RETURN)) {
2939                    returnDepot = this.plugin.retrieveObjectFromLocal(
2940                        header,
2941                        (Path)depotReference.values("depot").get(0)
2942                    );
2943                }
2944            }
2945            if(issueDepot == null) {
2946                throw new ServiceException(
2947                    OpenCrxException.DOMAIN,
2948                    OpenCrxException.CONTRACT_MISSING_DEPOT_GOODS_ISSUE,
2949                    new BasicException.Parameter[]{
2950                         new BasicException.Parameter("param0", position.values("lineItemNumber").get(0)),
2951                    },
2952                    "Missing goods issue depot."
2953                );
2954            }
2955            if(returnDepot == null) {
2956                throw new ServiceException(
2957                    OpenCrxException.DOMAIN,
2958                    OpenCrxException.CONTRACT_MISSING_DEPOT_GOODS_RETURN,
2959                    new BasicException.Parameter[]{
2960                         new BasicException.Parameter("param0", position.values("lineItemNumber").get(0)),
2961                    },
2962                    "Missing goods return depot."
2963                );
2964            }
2965
2966            // delivery depot position
2967
deliveryDepotPositions[ii] =
2968                this.plugin.depots.openDepotPosition(
2969                    header,
2970                    deliveryDepot,
2971                    null,
2972                    null,
2973                    org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc()),
2974                    holderQualifiesPosition ? (String JavaDoc)position.values("positionNumber").get(0) : null,
2975                    (Path)position.values("basedOn").get(0),
2976                    null,
2977                    Boolean.FALSE
2978                );
2979
2980            // issue depot position
2981
issueDepotPositions[ii] =
2982                this.plugin.depots.openDepotPosition(
2983                    header,
2984                    issueDepot,
2985                    null,
2986                    null,
2987                    org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc()),
2988                    holderQualifiesPosition ? (String JavaDoc)position.values("positionNumber").get(0) : null,
2989                    (Path)position.values("basedOn").get(0),
2990                    null,
2991                    Boolean.FALSE
2992                );
2993
2994            // return depot position
2995
returnDepotPositions[ii] =
2996                this.plugin.depots.openDepotPosition(
2997                    header,
2998                    returnDepot,
2999                    null,
3000                    null,
3001                    org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc()),
3002                    holderQualifiesPosition ? (String JavaDoc)position.values("positionNumber").get(0) : null,
3003                    (Path)position.values("basedOn").get(0),
3004                    null,
3005                    Boolean.FALSE
3006                );
3007        }
3008        
3009        // Create booking
3010
Path[] creditPositions = new Path[contractPositions.size()];
3011        Path[] debitPositions = new Path[contractPositions.size()];
3012        BigDecimal JavaDoc[] quantities = new BigDecimal JavaDoc[contractPositions.size()];
3013        String JavaDoc[] bookingTextNames = new String JavaDoc[contractPositions.size()];
3014        Path[] productConfigurationSets = new Path[contractPositions.size()];
3015        Path[] originIdentities = new Path[contractPositions.size()];
3016        
3017        ii = 0;
3018        for(
3019            Iterator JavaDoc i = contractPositions.iterator();
3020            i.hasNext();
3021            ii++
3022        ) {
3023            DataproviderObject_1_0 contractPosition = (DataproviderObject_1_0)i.next();
3024            BigDecimal JavaDoc quantity = (BigDecimal JavaDoc)contractPosition.values("quantity").get(0);
3025            if(quantity.compareTo(new BigDecimal JavaDoc(0)) < 0) {
3026                creditPositions[ii] = returnDepotPositions[ii].path();
3027                debitPositions[ii] = deliveryDepotPositions[ii].path();
3028                bookingTextNames[ii] = BOOKING_TEXT_NAME_RETURN_GOODS;
3029            }
3030            else {
3031                creditPositions[ii] = deliveryDepotPositions[ii].path();
3032                debitPositions[ii] = issueDepotPositions[ii].path();
3033                bookingTextNames[ii] = BOOKING_TEXT_NAME_DELIVER_GOODS;
3034            }
3035            String JavaDoc contractPositionType = (String JavaDoc)contractPosition.values(SystemAttributes.OBJECT_CLASS).get(0);
3036            if(this.model.isSubtypeOf(contractPositionType, "org:opencrx:kernel:product1:ProductInUseDescriptor")) {
3037                productConfigurationSets[ii] = contractPosition.path();
3038            }
3039            originIdentities[ii] = contractPosition.path();
3040            quantities[ii] = quantity.abs();
3041        }
3042        DataproviderObject_1_0 booking = this.plugin.depots.createCompoundBooking(
3043            header,
3044            deliveryDepot.path().getPrefix(7),
3045            org.openmdx.base.text.format.DateFormat.getInstance().format(new Date JavaDoc()),
3046            Depots.BOOKING_TYPE_STANDARD,
3047            quantities,
3048            bookingTextNames,
3049            null,
3050            creditPositions,
3051            debitPositions,
3052            productConfigurationSets,
3053            originIdentities,
3054            null
3055        );
3056        
3057        DataproviderObject modifiedContract = this.plugin.retrieveObjectForModification(contract.path());
3058        modifiedContract.clearValues("inventoryCb").add(booking.path());
3059        
3060        return booking.path();
3061    }
3062    
3063    //-------------------------------------------------------------------------
3064
public void cancelInventoryUpdate(
3065        ServiceHeader header,
3066        DataproviderObject_1_0 contract
3067    ) throws ServiceException {
3068        if(contract.values("inventoryCb").size() > 0) {
3069            this.plugin.depots.removeCompoundBooking(
3070                header,
3071                (Path)contract.values("inventoryCb").get(0)
3072            );
3073            DataproviderObject modifiedContract = this.plugin.retrieveObjectForModification(contract.path());
3074            modifiedContract.clearValues("inventoryCb");
3075        }
3076    }
3077    
3078    //-------------------------------------------------------------------------
3079
public void updateContractPosition(
3080        ServiceHeader header,
3081        DataproviderObject object,
3082        DataproviderObject_1_0 oldValues
3083    ) throws ServiceException {
3084        String JavaDoc objectClass = (String JavaDoc)object.values(SystemAttributes.OBJECT_CLASS).get(0);
3085        if(this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:ContractPosition")) {
3086            Path productIdentity = (object.getValues("product") != null) && (object.values("product").size() > 0)
3087                ? (Path)object.values("product").get(0)
3088                : (Path)oldValues.values("product").get(0);
3089            if(productIdentity != null) {
3090                DataproviderObject_1_0 product = this.plugin.retrieveObjectFromDelegation(productIdentity);
3091                DataproviderObject_1_0 contract = this.plugin.retrieveObjectFromLocal(
3092                    header,
3093                    object.path().getParent().getParent()
3094                );
3095                this.updateContractPosition(
3096                    header,
3097                    contract,
3098                    object,
3099                    oldValues,
3100                    product,
3101                    false
3102                );
3103            }
3104        }
3105    }
3106
3107    //-------------------------------------------------------------------------
3108
public void repriceContractPosition(
3109        ServiceHeader header,
3110        DataproviderObject_1_0 object
3111    ) throws ServiceException {
3112        String JavaDoc objectClass = (String JavaDoc)object.values(SystemAttributes.OBJECT_CLASS).get(0);
3113        if(this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:ContractPosition")) {
3114            Path productIdentity = (Path)object.values("product").get(0);
3115            if(productIdentity != null) {
3116                DataproviderObject_1_0 product = this.plugin.retrieveObjectFromDelegation(productIdentity);
3117                DataproviderObject_1_0 contract = this.plugin.retrieveObjectFromLocal(
3118                    header,
3119                    object.path().getParent().getParent()
3120                );
3121                DataproviderObject position = this.plugin.retrieveObjectForModification(
3122                    object.path()
3123                );
3124                // Force recalc of priceLevel
3125
position.attributeNames().remove("priceLevel");
3126                this.updateContractPosition(
3127                    header,
3128                    contract,
3129                    position,
3130                    object,
3131                    product,
3132                    true
3133                );
3134            }
3135        }
3136    }
3137    
3138    //-------------------------------------------------------------------------
3139
public void repriceContract(
3140        ServiceHeader header,
3141        DataproviderObject_1_0 object
3142    ) throws ServiceException {
3143        String JavaDoc objectClass = (String JavaDoc)object.values(SystemAttributes.OBJECT_CLASS).get(0);
3144        if(this.model.isSubtypeOf(objectClass, "org:opencrx:kernel:contract1:AbstractContract")) {
3145            List JavaDoc positions = this.delegation.addFindRequest(
3146                object.path().getChild("position"),
3147                null,
3148                AttributeSelectors.ALL_ATTRIBUTES,
3149                0,
3150                Integer.MAX_VALUE,
3151                Directions.ASCENDING
3152            );
3153            for(Iterator JavaDoc i = positions.iterator(); i.hasNext(); ) {
3154                  this.repriceContractPosition(
3155                      header,
3156                      (DataproviderObject_1_0)i.next()
3157                  );
3158            }
3159        }
3160    }
3161
3162    //-------------------------------------------------------------------------
3163
public void replaceContractPosition(
3164        ServiceHeader header,
3165        DataproviderRequest request
3166    ) throws ServiceException {
3167        // Set pricingState to dirty in case pricePerUnit is modified
3168
if(request.object().getValues("pricePerUnit") != null) {
3169            DataproviderObject newValues = request.object();
3170            DataproviderObject position = this.plugin.retrieveObjectForModification(request.path());
3171            boolean priceIsModified = (newValues.getValues("pricePerUnit") == null) || (position.getValues("pricePerUnit") == null)
3172                ? newValues.values("pricePerUnit").get(0) != position.values("pricePerUnit").get(0)
3173                : ((BigDecimal JavaDoc)newValues.values("pricePerUnit").get(0)).compareTo((BigDecimal JavaDoc)position.values("pricePerUnit").get(0)) != 0;
3174            if(priceIsModified) {
3175                position.clearValues("pricingState").add(
3176                    new Short JavaDoc(PRICING_STATE_DIRTY)
3177                );
3178            }
3179        }
3180    }
3181
3182    //-------------------------------------------------------------------------
3183
// Members
3184
//-------------------------------------------------------------------------
3185
private static final String JavaDoc DEFAULT_REFERENCE_FILTER = ":*, :*/:*/:*, :*/:*/:*/:*/:*";
3186    
3187    private final static int BATCHING_MODE_SIZE = 1000;
3188    
3189    // Closed Thresholds
3190
private static final short CLOSED_THRESHOLD_LEAD = 1110;
3191    private static final short CLOSED_THRESHOLD_OPPORTUNITY = 1210;
3192    private static final short CLOSED_THRESHOLD_QUOTE = 1310;
3193    private static final short CLOSED_THRESHOLD_SALES_ORDER = 1410;
3194    private static final short CLOSED_THRESHOLD_INVOICE = 1510;
3195
3196    // Min/Max Quantity Handling
3197
private static final int MIN_MAX_QUANTITY_HANDLING_NA = 0;
3198    private static final int MIN_MAX_QUANTITY_HANDLING_INFORMATIONAL = 1;
3199    private static final int MIN_MAX_QUANTITY_HANDLING_STRICT = 2;
3200    private static final int MIN_MAX_QUANTITY_HANDLING_LIMIT = 3;
3201    
3202    // Pricing Status
3203
private static final short PRICING_STATE_DIRTY = 10;
3204    private static final short PRICING_STATE_OK = 20;
3205    
3206    // Selectable item commands
3207
private static final String JavaDoc MODIFY_PRODUCT_BUNDLE_POSITION = "MODIFY_BUNDLE";
3208    private static final String JavaDoc NEW_PRODUCT_BUNDLE_POSITION = "NEW_BUNDLE";
3209    private static final String JavaDoc MODIFY_BUNDLED_PRODUCT_POSITION = "MODIFY_BUNDLED_PRODUCT";
3210    private static final String JavaDoc NEW_BUNDLED_PRODUCT_POSITION = "NEW_BUNDLED_PRODUCT";
3211    private static final String JavaDoc MODIFY_CONFIGURATION = "MODIFY_CONFIG";
3212    private static final String JavaDoc NEW_CONFIGURATION = "NEW_CONFIG";
3213    
3214    // Booking texts
3215
private static final String JavaDoc BOOKING_TEXT_NAME_RETURN_GOODS = "return goods";
3216    private static final String JavaDoc BOOKING_TEXT_NAME_DELIVER_GOODS = "deliver goods";
3217            
3218    private final Model_1_0 model;
3219    private final OpenCrxKernel_1 plugin;
3220    private final RequestCollection delegation;
3221    private final RefPackage_1_0 rootPkg;
3222    private final Cloneable JavaDoc cloning;
3223    private final Map JavaDoc cachedObjects = new HashMap JavaDoc();
3224    private final Map JavaDoc cachedDescriptions = new HashMap JavaDoc();
3225        
3226}
3227
3228//--- End of File -----------------------------------------------------------
3229
Popular Tags