Create multiple DMN using Java Camunda Springboot starter - camunda

I would like to create a Java service that would build a Camunda DMN via code. I'm using camunda-springboot-starter dependency and I'm able to generate the DMN DecisionTable and output of one decision is used in another. I'm using InformationRequirement for same but when I write the model to file and open that file in modeler the arrow is not coming for information requirement and after deploying the decision is not able to get that output.
<
public String generateDMN(String name, String title) throws FileNotFoundException {
DmnModelInstance modelInstance = initializeEmptyDmnModel();
Decision decision = modelInstance.newInstance(Decision.class);
decision.setId(title);
decision.setName(name);
modelInstance.getDefinitions().addChildElement(decision);
List<String[]> rules = new ArrayList<>();
try (CSVReader reader = new CSVReader(new FileReader("/Users/rahulnehete/IdeaProjects/java-rules-engine/src/main/resources/file.csv"))) {
rules = reader.readAll();
} catch (Exception e) {
log.error("Error reading CSV file ", e);
}
DecisionTable decisionTable = modelInstance.newInstance(DecisionTable.class);
decisionTable.setId("DecisionTable_"+name+"_"+title);
decisionTable.setHitPolicy(HitPolicy.COLLECT);
decision.addChildElement(decisionTable);
Decision decision2 = modelInstance.newInstance(Decision.class);
decision2.setId(title + "_2");
decision2.setName(name + "_2");
modelInstance.getDefinitions().addChildElement(decision2);
DecisionTable decisionTable2 = modelInstance.newInstance(DecisionTable.class);
decisionTable2.setId("DecisionTable_"+name+"_"+title+"_2");
decisionTable2.setHitPolicy(HitPolicy.COLLECT);
decision2.addChildElement(decisionTable2);
InformationRequirement infoRequirement = modelInstance.newInstance(InformationRequirement.class, "info1");
decision2.getInformationRequirements().add(infoRequirement);
infoRequirement.setRequiredDecision(decision);
String[] header = rules.remove(0);
String[] varTypes = rules.remove(0);
String[] variables = rules.remove(0);
Long numOfInputs = Arrays.stream(header).filter(k -> k.equalsIgnoreCase("input")).count();
Long numOfOutputs = Arrays.stream(header).filter(k -> k.equalsIgnoreCase("output")).count();
for(int i=0; i<numOfInputs; i++) {
Input ip = generateElement(modelInstance, Input.class, "Input_"+i);
InputExpression inputExpression = generateElement(modelInstance, InputExpression.class);
Text text = modelInstance.newInstance(Text.class);
inputExpression.setText(text);
inputExpression.setTypeRef(varTypes[i]);
ip.setLabel("Input " + i);
ip.setCamundaInputVariable(variables[i]);
ip.setInputExpression(inputExpression);
decisionTable.addChildElement(ip);
}
for(int i=numOfInputs.intValue(); i<=numOfOutputs; i++) {
Output op = generateElement(modelInstance, Output.class, "Output_"+i);
op.setLabel("Output " + i);
op.setName(variables[i]);
op.setTypeRef(varTypes[i]);
decisionTable.addChildElement(op);
}
for(int i = 1; i<rules.size(); i++) {
String[] rule = rules.get(i);
Rule dmnRule = createRule(modelInstance, numOfInputs.intValue(), numOfOutputs.intValue(), rule);
decisionTable.addChildElement(dmnRule);
log.info("Rule {} added", i);
}
Input ip = generateElement(modelInstance, Input.class, "Input_A");
InputExpression inputExpression = generateElement(modelInstance, InputExpression.class);
Text text = modelInstance.newInstance(Text.class);
inputExpression.setText(text);
inputExpression.setTypeRef("string");
ip.setLabel("Input A");
ip.setCamundaInputVariable("minPlafond");
ip.setInputExpression(inputExpression);
decisionTable2.addChildElement(ip);
Output op = generateElement(modelInstance, Output.class, "Output_A");
op.setLabel("Output A");
op.setName("FinalOutput");
op.setTypeRef("string");
decisionTable2.addChildElement(op);
// TODO: variable names
String[] rule = new String[] {"-", "$(minPlafond + " + "\"_Success\")"};
Rule dmnRule = createRule(modelInstance, 1, 1, rule);
decisionTable2.addChildElement(dmnRule);
log.info("Rule {} added", "new");
Dmn.validateModel(modelInstance);
try {
FileOutputStream fos = null;
fos = new FileOutputStream(name + "_" + title + ".dmn");
Dmn.writeModelToStream(fos, modelInstance);
fos.close();
} catch (IOException e) {
log.error("Error writing model instance ", e);
return REConstants.FAILED;
}
return "DMN GENERATED";
}
private DmnModelInstance initializeEmptyDmnModel() {
DmnModelInstance dmnModel = Dmn.createEmptyModel();
Definitions definitions = generateNamedElement(dmnModel, Definitions.class, "definitions", "definitions");
definitions.setNamespace(DmnModelConstants.CAMUNDA_NS);
dmnModel.setDefinitions(definitions);
return dmnModel;
}
private <E extends DmnElement> E generateElement(DmnModelInstance modelInstance, Class<E> elementClass, String id) {
E element = modelInstance.newInstance(elementClass);
element.setId(id);
return element;
}
private <E extends NamedElement> E generateNamedElement(DmnModelInstance modelInstance, Class<E> elementClass, String name, String id) {
E element = generateElement(modelInstance, elementClass, id);
element.setName(name);
return element;
}
private <E extends DmnElement> E generateElement(DmnModelInstance modelInstance, Class<E> elementClass) {
String generatedId = elementClass.getSimpleName() + UUID.randomUUID();
return generateElement(modelInstance, elementClass, generatedId);
}
private Rule createRule(DmnModelInstance dmnModelInstance, int numberOfInputs, int numberOfOutputs, String[] ruleInput) {
Rule rule = dmnModelInstance.newInstance(Rule.class);
for(int i=0; i<numberOfOutputs; i++) {
OutputEntry outputEntry = createOutputEntry(dmnModelInstance, ruleInput[numberOfInputs + i]);
rule.getOutputEntries().add(outputEntry);
}
for (int i = 0; i < numberOfInputs; i++) {
InputEntry inputEntry = createInputEntry(dmnModelInstance, ruleInput[i]);
rule.getInputEntries().add(inputEntry);
}
return rule;
}
private InputEntry createInputEntry(DmnModelInstance dmnModelInstance, String expression) {
Text text = dmnModelInstance.newInstance(Text.class);
text.setTextContent(expression);
InputEntry inputEntry = dmnModelInstance.newInstance(InputEntry.class);
inputEntry.setText(text);
return inputEntry;
}
private OutputEntry createOutputEntry(DmnModelInstance dmnModelInstance, String expression) {
Text text = dmnModelInstance.newInstance(Text.class);
text.setTextContent(expression);
OutputEntry outputEntry = dmnModelInstance.newInstance(OutputEntry.class);
outputEntry.setText(text);
return outputEntry;
}
}

You implemented the decisions, decisions table, input and output as well as info requirement correctly on model level (xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"). (Dmn.writeModelToFile(new File("src/main/resources/my.dmn"), modelInstance); is little more compact than writing the stream yourself.)
When you compare to a model created by the Modeler, you see that it uses additional namespaces such as xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/". This namespaces defines the diagram information separately from the model, e.g:
<dmndi:DMNDI>
<dmndi:DMNDiagram id="DMNDiagram_12sfwjw">
<dmndi:DMNShape id="DMNShape_1m8k4eq" dmnElementRef="Decision1">
<dc:Bounds height="80" width="180" x="150" y="80" />
</dmndi:DMNShape>
<dmndi:DMNShape id="DMNShape_15h0omx" dmnElementRef="Decision2">
<dc:Bounds height="80" width="180" x="240" y="200" />
</dmndi:DMNShape>
<dmndi:DMNEdge id="DMNEdge_15fnvnh" dmnElementRef="InformationRequirement_0a97hay">
<di:waypoint x="330" y="200" />
<di:waypoint x="240" y="180" />
<di:waypoint x="240" y="160" />
</dmndi:DMNEdge>
</dmndi:DMNDiagram>
</dmndi:DMNDI>
Unfortunately, the Camunda API currently offers no way of auto-generating or creating this diagram information.You would have to approach this a level lower with an XML library.
The model is executable without the diagram information. So, you will have a working model. Maybe that is acceptable and only if a human cares about the DRD it can be created manually?
An alternative would be to abandon the Java approach and try https://bpmn.io/toolkit/dmn-js/.

Related

Export table in Postgis to a shape file without a specific column

I Would like to export a postgreSQL (Postgis) table to a Shape file, but without a cetrain column. I don't want to delete the column in the db first. How do I exclude this certain column?
This is the export function:
private void exportShapeFile(String name, String path) {
try {
DataStore pgDatastore = Snippets.createPostgisDataStore();
SimpleFeatureCollection sfc = Snippets.getSimpleFeatureCollection(pgDatastore, name);
final SimpleFeatureType TYPE = Snippets.getPostgisSimpleFeatureType(pgDatastore, name);
String filename = path + "\\" + name + ".shp";
File newFile = new File(filename);
CoordinateReferenceSystem sourceCRS = Snippets.getCRS(name);
Object[] a = sourceCRS.getIdentifiers().toArray();
String crsOrig = a[0].toString();
String wkt = null;
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
Map<String, Serializable> params = new HashMap<String, Serializable>();
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
File directory = new File(txtFieldDir.getText());
ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
newDataStore.createSchema(TYPE);
Transaction transaction = new DefaultTransaction("create");
String typeName = newDataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
if (featureSource instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(sfc);
transaction.commit();
} catch (Exception problem) {
problem.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
pgDatastore.dispose();
newDataStore.dispose();
}
} else {
Snippets.appendToPane(txtLog,"ERROR:" + typeName + " does not support read/write access.\n", MainDialog.colRed);
}
} catch (MalformedURLException e) {
Snippets.appendToPane(txtLog,e.toString() + "\n", MainDialog.colRed);
e.printStackTrace();
} catch (IOException e) {
Snippets.appendToPane(txtLog,e.toString() + "\n", MainDialog.colRed);
e.printStackTrace();
}
You need to generate a new schema for your shapefile and then retype your features to that schema. DataUtilities provides useful methods for this, createSubType to generate a new schema limited to a shorter list of attributes, and reType to change a filter into one that matches the new schema.

How to set HtmlSaveOptions to save html and resources to stream using Aspose PDF

I am trying to use Aspose.PDF to load PDF from databases, convert it to HTML and render them to our web page.I want to know if we can save both the document and the resource to stream since current example in the document of Aspose.PDF saves css and images to a local path. I have tried this but the is and error that Aspose.Pdf.SaveFormat.Html is not supported.
Aspose.Pdf.Document PDFDocument = new Aspose.Pdf.Document(PDFStream);
MemoryStream HTMLStreamFromPDF = new MemoryStream();
PDFDocument.Save(HTMLStreamFromPDF, Aspose.Pdf.SaveFormat.Html);
If it can be done, how to write the parameters of CustomResourceSavingStrategy, CustomCssSavingStrategy, and CustomStrategyOfCssUrlCreation of HtmlSaveOptions. I am sorry that I am not quite familiar with delegate in C#
Thanks!
Finally found a way to save all files to stream.
MemoryStream HTMLStreamFromPDF = new MemoryStream();
List<MemoryStream> ResourseStreamList = new List<MemoryStream>();
List<string> ResourceNameList = new List<string>();
MemoryStream CSSStream = new MemoryStream();
Aspose.Pdf.HtmlSaveOptions saveOptions = new Aspose.Pdf.HtmlSaveOptions();
CustomResourcesProcessingBind customResourcesProcessingBind = new CustomResourcesProcessingBind((_1) => CustomResourcesProcessing(ResourseStreamList,ResourceNameList, RequestURL, _1));
saveOptions.CustomResourceSavingStrategy = new Aspose.Pdf.HtmlSaveOptions.ResourceSavingStrategy(customResourcesProcessingBind);
CssUrlCreationCustomStrategyBind cssUrlCreationCustomStrategyBind = new CssUrlCreationCustomStrategyBind((_1) => CssUrlCreationCustomStrategy(RequestURL, _1));
saveOptions.CustomStrategyOfCssUrlCreation = new Aspose.Pdf.HtmlSaveOptions.CssUrlMakingStrategy(cssUrlCreationCustomStrategyBind);
CustomCssSavingProcessingBind customCssSavingProcessingBind = new CustomCssSavingProcessingBind((_1) => CustomCssSavingProcessing(CSSStream, _1));
saveOptions.CustomCssSavingStrategy = new Aspose.Pdf.HtmlSaveOptions.CssSavingStrategy(customCssSavingProcessingBind);
saveOptions.HtmlMarkupGenerationMode = Aspose.Pdf.HtmlSaveOptions.HtmlMarkupGenerationModes.WriteOnlyBodyContent;
PDFDocument.Save(HTMLStreamFromPDF, saveOptions);
private delegate string CustomResourcesProcessingBind(Aspose.Pdf.SaveOptions.ResourceSavingInfo resourceSavingInfo);
private static string CustomResourcesProcessing(List<MemoryStream> ResourseStreamList, List<string> ResourceNameList, string RequestURL, Aspose.Pdf.SaveOptions.ResourceSavingInfo resourceSavingInfo)
{
MemoryStream newResource = new MemoryStream();
resourceSavingInfo.ContentStream.CopyTo(newResource);
ResourceNameList.Add(resourceSavingInfo.SupposedFileName);
ResourseStreamList.Add(newResource);
string urlThatWillBeUsedInHtml = RequestURL +"/"+ Path.GetFileName(resourceSavingInfo.SupposedFileName);
return urlThatWillBeUsedInHtml;
}
private delegate string CssUrlCreationCustomStrategyBind(Aspose.Pdf.HtmlSaveOptions.CssUrlRequestInfo requestInfo);
private static string CssUrlCreationCustomStrategy(string RequestURL,Aspose.Pdf.HtmlSaveOptions.CssUrlRequestInfo requestInfo)
{
return RequestURL + "/css_style.css";
}
private delegate void CustomCssSavingProcessingBind(Aspose.Pdf.HtmlSaveOptions.CssSavingInfo resourceInfo);
private static void CustomCssSavingProcessing(MemoryStream CSSStream, Aspose.Pdf.HtmlSaveOptions.CssSavingInfo resourceInfo)
{
resourceInfo.ContentStream.CopyTo(CSSStream);
}
Check the following sample code regarding how to use parameters CustomResourceSavingStrategy, CustomCssSavingStrategy and CustomStrategyOfCssUrlCreation of HtmlSaveOptions when converting from PDF to HTML.
static string _folderForReferencedResources;
static void Main(string[] args)
{
Document pdfDocument = new Document(#"F:\ExternalTestsData\input.pdf");
string outHtmlFile = #"F:\ExternalTestsData\output.html";
_folderForReferencedResources = #"F:\ExternalTestsData\resources\";
//-----------------------------------------------------
// 2)clean results if they already present
//-----------------------------------------------------
if (Directory.Exists(_folderForReferencedResources))
{
Directory.Delete(_folderForReferencedResources, true);
}
File.Delete(outHtmlFile);
//-----------------------------------------------------
// create HtmlSaveOption with tested feature
//-----------------------------------------------------
HtmlSaveOptions saveOptions = new HtmlSaveOptions();
saveOptions.CustomResourceSavingStrategy = new HtmlSaveOptions.ResourceSavingStrategy(Strategy_11_CUSTOM_SAVE_OF_FONTS_AND_IMAGES);
saveOptions.CustomCssSavingStrategy = new HtmlSaveOptions.CssSavingStrategy(Strategy_11_CSS_WriteCssToPredefinedFolder);
saveOptions.CustomStrategyOfCssUrlCreation = new HtmlSaveOptions.CssUrlMakingStrategy(Strategy_11_CSS_ReturnResultPathInPredefinedTestFolder);
using (Stream outStream = File.OpenWrite(outHtmlFile))
{
pdfDocument.Save(outStream, saveOptions);
}
}
private static void Strategy_11_CSS_WriteCssToPredefinedFolder(HtmlSaveOptions.CssSavingInfo resourceInfo)
{
if (!Directory.Exists(_folderForReferencedResources))
{
Directory.CreateDirectory(_folderForReferencedResources);
}
string path = _folderForReferencedResources + Path.GetFileName(resourceInfo.SupposedURL);
System.IO.BinaryReader reader = new BinaryReader(resourceInfo.ContentStream);
System.IO.File.WriteAllBytes(path, reader.ReadBytes((int)resourceInfo.ContentStream.Length));
}
private static string Strategy_11_CSS_ReturnResultPathInPredefinedTestFolder(HtmlSaveOptions.CssUrlRequestInfo requestInfo)
{
return "file:///" + _folderForReferencedResources.Replace(#"\", "/") + "css_style{0}.css";
}
private static string Strategy_11_CUSTOM_SAVE_OF_FONTS_AND_IMAGES(SaveOptions.ResourceSavingInfo resourceSavingInfo)
{
if (!Directory.Exists(_folderForReferencedResources))
{
Directory.CreateDirectory(_folderForReferencedResources);
}
string path = _folderForReferencedResources + Path.GetFileName(resourceSavingInfo.SupposedFileName);
// first path of this method is for saving of font
System.IO.BinaryReader contentReader = new BinaryReader(resourceSavingInfo.ContentStream);
System.IO.File.WriteAllBytes(path, contentReader.ReadBytes((int)resourceSavingInfo.ContentStream.Length));
string urlThatWillBeUsedInHtml = "file:///" + _folderForReferencedResources.Replace(#"\", "/") + Path.GetFileName(resourceSavingInfo.SupposedFileName);
return urlThatWillBeUsedInHtml;
}
The details are available here.
P.S. I am Social Media Developer at Aspose.

Test class not covering method fully?

Hi i have a custom controller which clones opportunity with a new currency,clones quote and all its quote line item.A button on Quote page layout does all this.While writing a test class to cover this code,i could not cover certain lines and do not know why.The code is as follows :
CloneOppNewCurrencyController.cls :
public with sharing class CloneOppNewCurrencyController {
public List<DatedConversionRate>lstCurrencies{get;set;}
public String selectedCurrency{get;set;}
public List<SelectOption> cTypes{get;set;}
public boolean flag{get;set;}
public Date closeDate;
public String qId{get;set;}
public Quote qObj{get;set;}
public Quote qClone{get;set;}
public Opportunity oppObj;
public Opportunity oppClone{get;set;}
public List<QuoteLineItem> lstQuoteLineItems;
public List<QuoteLineItem> lstClonedQuoteLineItems;
public QuoteLineItem clonedQuoteLineItem;
public Double exchangeRate;
public Map<String,Double>mapExchangeRates;
public List<PriceBookEntry> pbe;
public List<Id>pb;
public Quote testClone{get;set;}
public Map<Id,PricebookEntry>mapProIdNpBookEntry;
public List<Renewed_Entitlement__c> lstRE;
public List<Quoted_Asset__c> lstQuotedAsset;
public Renewed_Entitlement__c cloneRE;
public Quoted_Asset__c cloneQA;
//Constructor
public CloneOppNewCurrencyController() {
pb = new List<Id>();
lstRE = new List<Renewed_Entitlement__c>();
lstQuotedAsset = new List<Quoted_Asset__c>();
lstclonedQuoteLineItems = new List<QuoteLineItem>();
mapProIdNpBookEntry = new Map<Id,PriceBookEntry>();
//get quote Id from Page
qId=Apexpages.currentPage().getParameters().get('id');
//Get the Opp Id
qObj=[Select q.Total_Price__c, q.Total_Margin__c, q.Total_Cost__c, q.TotalPrice, q.Tax, q.SystemModstamp, q.Subtotal,
q.Status, q.Siebel_Id__c, q.ShippingStreet, q.ShippingState, q.ShippingPostalCode, q.ShippingName, q.ShippingHandling,
q.ShippingCountry, q.ShippingCity, q.Revision_Number__c, q.Quote_Expiry__c, q.Quote_Date__c, q.QuoteToStreet,
q.QuoteToState, q.QuoteToPostalCode, q.QuoteToName, q.QuoteToCountry, q.QuoteToCity, q.QuoteNumber, q.Pricebook2Id,
q.Price_Book__c, q.Phone, q.Opportunity.Id, q.OpportunityId, q.Name, q.LineItemCount, q.LastModifiedDate,
q.LastModifiedById, q.IsSyncing, q.IsDeleted, q.Internal_Notes__c, q.Id, q.GrandTotal, q.Fax, q.Email, q.Discount,
q.Description, q.Default_Payment_Terms__c, q.Customer_Comments__c, q.CurrencyIsoCode, q.CreatedDate, q.CreatedById,
q.ContactId, q.BillingStreet, q.BillingState, q.BillingPostalCode, q.BillingName, q.BillingCountry, q.BillingCity, q.Opportunity.CloseDate,
q.AdditionalStreet, q.AdditionalState, q.AdditionalPostalCode, q.AdditionalName, q.AdditionalCountry, q.AdditionalCity,
q.Account_Number__c, q.Account_Manager__c, q.Account_Manager_Phone__c, q.Account_Manager_Fax__c, q.Account_Manager_Email__c ,
q.Pricebook2.Organisation__c, q.Pricebook2.External_Id__c, q.Pricebook2.IsStandard, q.Pricebook2.Description, q.Pricebook2.IsActive,
q.Pricebook2.CurrencyIsoCode, q.Pricebook2.Name
From Quote q
where q.Id =:qId];
closeDate = qObj.Opportunity.CloseDate;
cTypes=new List<SelectOption>();
mapExchangeRates = new Map<String,Double>();
cTypes.add(new SelectOption('None','None'));
for(DatedConversionRate d:[Select StartDate, NextStartDate, IsoCode, Id, ConversionRate From DatedConversionRate where StartDate<=:closeDate and NextStartDate >=:closeDate]){
cTypes.add(new SelectOption(d.IsoCode,d.IsoCode));
mapExchangeRates.put(d.IsoCode,d.ConversionRate);
}
//query all fields in Opp which has this quote to clone it
oppObj = [Select o.X18_Character_Id__c, o.Win_Loss_Reason_Details__c, o.Win_Loss_Cancelled_Reason__c, o.Where_is_A_End__c,
o.Upload_Date_Time__c, o.Type, o.Total_Price__c, o.Total_Margin_in_Account_Currency__c, o.Total_Margin__c,
o.Total_Cost__c, o.Timescale__c, o.Technology_Margin__c, o.SystemModstamp, o.SyncedQuoteId, o.Suspended__c,
o.Start_of_Close_Date_FY__c, o.Start_of_Close_Date_FY_2__c, o.Start_of_Close_Date_FY_1__c, o.StageName,
o.Solution_Type__c, o.Solution_Description__c, o.Signed_SOW_Received__c, o.Siebel_Id__c, o.Service_Start_Date__c,
o.SecureCall_Margin__c, o.Salesforce_Opportunity_Id__c, o.Risk_Level__c, o.Regional_Contact_for_SFOne__c,
o.RecordTypeId, o.RFSDate__c, o.Probability, o.Primary_Competitor__c, o.Pricebook2Id, o.PS_Margin__c,
o.PO_Number__c, o.Owner_Affiliates__c, o.OwnerId, o.Other_Margin__c, o.Organisation__c,
o.OpenAir_Project_Reference__c, o.Number_of_Line_items__c, o.Non_Portfolio__c, o.NextStep, o.Need__c,
o.Name, o.NTT_Service_Family_Name__c, o.Maintenance_Margin__c, o.MSS_Margin__c, o.Lost_to__c, o.LeadSource,
o.Last_Update_Date_of_Phase__c, o.LastModifiedDate, o.LastModifiedById, o.LastActivityDate, o.Large_Deal__c,
o.IsWon, o.IsDeleted, o.IsClosed, o.Id, o.HasOpportunityLineItem, o.Group_Collaborator_s_Name__c,
o.ForecastCategoryName, o.ForecastCategory, o.FiscalYear, o.FiscalQuarter, o.Fiscal, o.ExpectedRevenue,
o.End_Customer__c, o.Description, o.CurrencyIsoCode, o.CreatedDate, o.CreatedById, o.Contract_Term__c,
o.Collaborate_with__c, o.Closed_Won_Status__c, o.Close_Date_this_FY__c, o.Close_Date_Last_FY__c, o.Pricebook2.CurrencyIsoCode,
o.CloseDate, o.CampaignId, o.Budget__c, o.Authority__c, o.Approval_Status__c, o.Amount, o.Account_Owner_Id__c, o.Pricebook2.IsActive,
o.Pricebook2.Organisation__c, o.Pricebook2.External_Id__c, o.Pricebook2.IsStandard, o.Pricebook2.Description, o.Pricebook2.Name ,
o.Account_Currency__c, o.AccountId, o.A_End_or_B_End_or_C_End__c
From Opportunity o
where o.Id =: qObj.OpportunityId];
lstQuoteLineItems = [Select q.Vendor_Cost_Name__c, q.UnitPrice, q.Total_Price__c, q.Total_Exchanged_Cost__c, q.Takeover_PPP__c, q.SystemModstamp,
q.Subtotal_Price__c, q.Subtotal, q.SortOrder, q.Single_Creation__c, q.Siebel_Id__c, q.Service_Start_Date__c,
q.Service_End_Date__c, q.Service_Calendar_Business_Hours__c, q.ServiceDate, q.Requested_Ship_Date__c, q.Renewed_Entitlement__c,
q.Renewal_Product__c, q.QuoteId, q.Quantity, q.PricebookEntryId, q.Price__c, q.Organisation__c, q.ListPrice, q.Line_No__c,
q.LineNumber, q.LastModifiedDate, q.LastModifiedById, q.IsDeleted, q.Install_Post_Code__c, q.Install_County_State__c,
q.Install_Country__c, q.Install_Contact__c, q.Install_City__c, q.Id, q.Exchanged_Cost__c, q.Exchange_Rate__c,
q.Discount__c, q.Discount, q.Description, q.Customer_Note__c, q.CurrencyIsoCode, q.CreatedDate, q.CreatedById,
q.Covered_Product__c, q.Covered_Asset__c, q.Cost__c, q.Cost_Price_Original__c, q.Cost_Exchange_Date__c,
q.Cost_Currency__c, q.Consolidated_Entitlement__c, q.Comments__c, q.Asset_Expires__c, q.Address_2__c, q.Vendor_RRP__c,
q.PricebookEntry.IsDeleted, q.PricebookEntry.ProductCode, q.PricebookEntry.SystemModstamp, q.PricebookEntry.LastModifiedById,
q.PricebookEntry.LastModifiedDate, q.PricebookEntry.CreatedById, q.PricebookEntry.CreatedDate, q.PricebookEntry.UseStandardPrice,
q.PricebookEntry.IsActive, q.PricebookEntry.UnitPrice, q.PricebookEntry.CurrencyIsoCode, q.PricebookEntry.Product2Id,
q.PricebookEntry.Pricebook2Id, q.PricebookEntry.Name, q.PricebookEntry.Id,
q.Address_1__c From QuoteLineItem q
where q.QuoteId =:qObj.Id];
for(QuoteLineItem oLineItem : lstQuoteLineItems) {
pb.add(oLineItem.PricebookEntry.Product2Id);
}
//query renewal entitlements under the query to clone it
lstRE = [Select r.Quote__c, r.Quote_Status__c, r.Quote_Line_Item__c, r.Opportunity__c, r.Name, r.Id, r.Entitlement__c,
r.Entitlement_Start_Date__c, r.Entitlement_Service_Calendar__c, r.Entitlement_Part_Code__c, r.Entitlement_End_Date__c,
r.CurrencyIsoCode
From Renewed_Entitlement__c r
where r.Quote__c =:qId ];
//query quoted assets under the query to clone it
lstQuotedAsset = [Select q.Quote__c, q.Name, q.Id, q.CurrencyIsoCode, q.Asset__c
From Quoted_Asset__c q
where q.Quote__c =:qId];
}
public void proceed() {
try {
if(selectedCurrency == 'None' || selectedCurrency == '') {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Please select a currency in order to proceed'));
}
pbe = [Select p.UnitPrice, p.Product2Id, p.Pricebook2Id, p.Name, p.IsActive, p.Id, p.CurrencyIsoCode From PricebookEntry p
where p.CurrencyIsoCode =:selectedCurrency and p.Pricebook2Id =:oppObj.Pricebook2Id and p.Product2Id in :pb];
for(PricebookEntry pbe : pbe) {
mapProIdNpBookEntry.put(pbe.Product2Id,pbe);
}
for(QuoteLineItem oLine:lstQuoteLineItems) {
if(!mapProIdNpBookEntry.containsKey(oLine.PricebookEntry.Product2Id)) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'No pricebook entry exists for this particular currency.Hence kindly create an entry with the selected currency before cloning Opportunity.'));
return;
}
}
if(selectedCurrency!='None') {
if(oppObj.StageName!='Qualification') {
oppClone = oppObj.clone(false,true);
oppClone.ForecastCategoryName = 'Omitted';
oppClone.CurrencyIsoCode = selectedCurrency;
System.debug('Pricebook2Id::::' +oppClone.Pricebook2Id);
oppClone.Pricebook2Id = oppObj.Pricebook2Id;
oppClone.Name = selectedCurrency + oppObj.Name;
Database.insert(oppClone);
System.debug('Inserted Opp Currency >>> ' + oppClone.CurrencyIsoCode);
if(qObj.IsSyncing != true) {
qClone = qObj.clone();
qClone.Name = selectedCurrency + qObj.Name;
qClone.OpportunityId = oppClone.Id;
Database.insert(qClone);
System.debug('Inserted Quote Currency >>> ' + qClone.CurrencyIsoCode);
testClone= [SELECT Id, CurrencyIsoCode FROM Quote WHERE ID=:qClone.Id];
oppClone.SyncedQuoteId = qClone.Id;
}
else {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Synced Quote cannot be cloned.Please stop sync before cloning'));
}
Database.update(oppClone);
System.debug('Inserted Quote Currency >>> ' + testClone.CurrencyIsoCode);
}
if((lstRE!=null || !(lstRE.isEmpty())) && qClone.Id !=null) {
for(Renewed_Entitlement__c re:lstRE) {
cloneRE = new Renewed_Entitlement__c();
cloneRE = re.clone();
cloneRE.Quote__c = qClone.Id;
Database.insert(cloneRE);
}
}
if((lstQuotedAsset!=null || !(lstQuotedAsset.isEmpty())) && qClone.Id !=null) {
for(Quoted_Asset__c qa:lstQuotedAsset) {
cloneQA = new Quoted_Asset__c();
cloneQA = qa.clone();
cloneQA.Quote__c = qClone.Id;
Database.insert(cloneQA);
}
}
System.debug('^^^aaa^^^^^^^^'+mapProIdNpBookEntry);
if(qClone!=null) {
if(lstQuoteLineItems!=null) { System.debug('not null line items');//tbd
for(QuoteLineItem oLine:lstQuoteLineItems) {
clonedQuoteLineItem = new QuoteLineItem();
clonedQuoteLineItem = oLine.clone();
system.debug('^^12111111' + oLine.PricebookEntry.Product2Id);
if(mapProIdNpBookEntry.containsKey(oLine.PricebookEntry.Product2Id)) {
clonedQuoteLineItem.PricebookEntryId=mapProIdNpBookEntry.get(oLine.PricebookEntry.Product2Id).Id;
}
clonedQuoteLineItem.QuoteId = qClone.Id;
System.debug('Quote line Iso Code'+clonedQuoteLineItem.CurrencyIsoCode);
//update price,margin and vendors
if(mapExchangeRates.containsKey(selectedCurrency)) { System.debug('$$$containsKey iruku$$$'+'###value is###'+mapExchangeRates.get(selectedCurrency));
if(oLine.Price__c!=null && mapExchangeRates.get(selectedCurrency)!=0) {
clonedQuoteLineItem.Price__c = oLine.Price__c / mapExchangeRates.get(clonedQuoteLineItem.CurrencyIsoCode);
}
if(oLine.UnitPrice != null && mapExchangeRates.get(selectedCurrency)!=0) {
clonedQuoteLineItem.UnitPrice = oLine.UnitPrice / mapExchangeRates.get(clonedQuoteLineItem.CurrencyIsoCode);
}
if(oLine.Vendor_RRP__c != null && mapExchangeRates.get(selectedCurrency)!=0) {
clonedQuoteLineItem.Vendor_RRP__c = oLine.Vendor_RRP__c / mapExchangeRates.get(clonedQuoteLineItem.CurrencyIsoCode);
}
}
lstclonedQuoteLineItems.add(clonedQuoteLineItem);
}
System.debug(' >>> ' + lstclonedQuoteLineItems);
if(lstclonedQuoteLineItems.size()>0) {
insert lstclonedQuoteLineItems;
}
}
}
}
}catch(Exception e) {
}
}
public pageReference cancel() {
return null;
}
}
testCloneNewCurrencyController.cls
#isTest(SeeALLData=true)
private class testCloneNewCurrencyController {
static testMethod void myUnitTest() {
// TO DO: implement unit test
Account account=new Account(Name='Test');
insert account;
Contact cn=new Contact(Accountid=account.id);
cn.LastName='test';
insert cn;
// set up opportunity name and price book id
String opportunityName = 'My Opportunity';
String standardPriceBookId = '';
PriceBook2 pb2Standard = [select Id from Pricebook2 where isStandard=true];
standardPriceBookId = pb2Standard.Id;
// set up opp and Verify that the results are as expected.
Opportunity o = new Opportunity(AccountId=account.Id, Name=opportunityName,
StageName='Prospecting', CloseDate=Date.today(),Contract_Term__c = 6);
insert o;
Opportunity opp = [SELECT Name FROM Opportunity WHERE Id = :o.Id];
System.assertEquals(opportunityName, opp.Name);
// set up product2 and Verify that the results are as expected.
Product2 p2 = new Product2(Name='Test Product',isActive=true,Product_Code_Upload__c = 'Test Product 1' , ProductCode = 'Test Product 1');
insert p2;
Product2 p2ex = [SELECT Name FROM Product2 WHERE Id = :p2.Id];
System.assertEquals('Test Product', p2ex.Name);
// set up PricebookEntry and Verify that the results are as expected.
PricebookEntry pbe = new PricebookEntry(Pricebook2Id=standardPriceBookId, Product2Id=p2.Id, UnitPrice=99, isActive=true );
insert pbe;
PricebookEntry pbeex = [SELECT Pricebook2Id FROM PricebookEntry WHERE Id = :pbe.Id];
System.assertEquals(standardPriceBookId, pbeex.Pricebook2Id);
// set up OpportunityLineItem and Verify that the results are as expected.
OpportunityLineItem oli = new OpportunityLineItem(PriceBookEntryId=pbe.Id, OpportunityId=o.Id, Quantity=1, UnitPrice=99 , Cost_Currency__c = 'USD',Cost__c=2000);
insert oli;
OpportunityLineItem oliex = [SELECT PriceBookEntryId FROM OpportunityLineItem WHERE Id = :oli.Id];
oli.Cost_Currency__C = 'GBP';
update oli;
update account;
Quote quot1 = new Quote(Name='Quote1',OpportunityId=o.Id,Pricebook2Id=standardPriceBookId);
insert quot1;
// set up OpportunityLineItem and Verify that the results are as expected.
QuoteLineItem qli = new QuoteLineItem(QuoteId = quot1.Id,PriceBookEntryId=pbe.Id,UnitPrice=1000, Quantity=1, Price__c=3500 , Cost_Currency__c = 'USD',Cost__c=2000);
insert qli;
// Create two Asset records and relate them to the oli through Ordered Asset records
Asset ass1 = new Asset(Name='Asset1',SerialNumber='12345',AccountId=account.Id,ContactId=cn.Id);
insert ass1;
Asset ass2 = new Asset(Name='Asset1',SerialNumber='678910',AccountId=account.Id,ContactId=cn.Id);
insert ass2;
Quoted_Asset__c ordass1 = new Quoted_Asset__c(Asset__c=ass1.Id,Quote_Line_Item__c=qli.Id,Quote__c=quot1.Id);
insert ordass1;
Quoted_Asset__c ordass2 = new Quoted_Asset__c(Asset__c=ass2.Id,Quote_Line_Item__c=qli.Id,Quote__c=quot1.Id);
insert ordass2;
// Check that the Serial numbers field on the QLI is as expected
QuoteLineItem quot1test = [SELECT LineNumber, Serial_Numbers__c FROM QuoteLineItem WHERE Id =: qli.Id];
Test.startTest();
Test.setCurrentPage(new Pagereference('/apex/CloneOppNewCurrency?id='+quot1.Id));
CloneOppNewCurrencyController c = new CloneOppNewCurrencyController();
c.selectedCurrency = 'USD';
system.assertEquals(c.selectedCurrency, 'USD');
//c.qObj = quot1;
c.proceed();
c.selectedCurrency = 'USD';
System.debug('%%%%%'+c.oppClone+'$$$$$'+c.selectedCurrency+'Opp OBj is:'+c.oppObj);
Test.setCurrentPage(new Pagereference('/apex/CloneOppNewCurrency?id='+quot1.Id));
CloneOppNewCurrencyController c1 = new CloneOppNewCurrencyController();
c1.selectedCurrency = 'None';
Pagereference pr = c1.cancel();
Test.stopTest();
}
}
Lines from 127 are not covered.The proceed method is not covered.Can anyone help me please?
What line does 127 correspond to in your example? Is it if(selectedCurrency!='None') { in the proceed() method?
I'd suggest to extend your exception handling. You basically have:
public void proceed() {
try {
// Most of method body here
} catch(Exception e) {
}
}
It is likely that an exception has occured and has been ignored/lost due to the empty Exception handling. Minimally, write the exception out to the log:
} catch(Exception e) {
System.debug(LoggingLevel.Error, 'BANG! ' + e);
}
That may well reveal in the debug log where your test method is failing.

pig puzzle: re-writing an involved reducer as a simple pig script?

There are account ids, each with a timestamp grouped by username. foreach of these username groups I want all pairs of (oldest account, other account).
I have a java reducer that does that, can I rewrite it as a simple pig script?
Schema:
{group:(username),A: {(id , create_dt)}
Input:
(batman,{(id1,100), (id2,200), (id3,50)})
(lulu ,{(id7,100), (id9,50)})
Desired output:
(batman,{(id3,id1), (id3,id2)})
(lulu ,{(id9,id7)})
Not that anyone seems to care, but here goes. You have to create a UDF:
desired = foreach my_input generate group as n, FIND_PAIRS(A) as pairs_bag;
And the UDF:
public class FindPairs extends EvalFunc<DataBag> {
#Override
public DataBag exec(Tuple input) throws IOException {
Long pivotCreatedDate = Long.MAX_VALUE;
Long pivot = null;
DataBag accountsBag = (DataBag) input.get(0);
for (Tuple account : accountsBag){
Long accountId = Long.parseLong(account.get(0).toString());
Long creationDate = Long.parseLong(account.get(4).toString());
if (creationDate < pivotCreatedDate ) {
// pivot is the one with the minimal creation_dt
pivot = accountId;
pivotCreatedDate = creationDate;
}
}
DataBag allPairs = BagFactory.getInstance().newDefaultBag();
if (pivot != null){
for (Tuple account : accountsBag){
Long accountId = Long.parseLong(account.get(0).toString());
Long creationDate = Long.parseLong(account.get(4).toString());
if (!accountId.equals(pivot)) {
// we don't want any self-pairs
Tuple output = TupleFactory.getInstance().newTuple(2);
if (pivot < accountId){
output.set(0, pivot.toString());
output.set(1, accountId.toString());
}
else {
output.set(0, accountId.toString());
output.set(1, pivot.toString());
}
allPairs.add(output);
}
}
return allPairs;
}
and if you wanna play real nicely, add this:
/**
* Letting pig know that we emit a bag with tuples, each representing a pair of accounts
*/
#Override
public Schema outputSchema(Schema input) {
try{
Schema pairSchema = new Schema();
pairSchema.add(new FieldSchema(null, DataType.BYTEARRAY));
pairSchema.add(new FieldSchema(null, DataType.BYTEARRAY));
return new Schema(
new FieldSchema(null,
new Schema(pairSchema), DataType.BAG));
}catch (Exception e){
return null;
}
}
}

how to generate fake data using moq for unit test?

I need to generate some data to unit test my repositories. i was using a loop to generate a list of objects, see codes below. I learned moq is a great mocking library, Can I use moq to generate that and how do I do it?
public IQueryable<Category> GetCategories()
{
IList<Category> result = new List<Category>();
for (int i = 1; i <= 2; i++)
{
Category c = new Category();
c.ID = i;
c.Name = "Parent" + i.ToString();
c.ParentID = 0;
for (int x = i*10; x < i*10+5; x++)
{
Category sub = new Category();
sub.ID = x;
sub.Name = "Sub" + x.ToString();
sub.ParentID = i;
result.Add(sub);
}
result.Add(c);
}
return result.AsQueryable<Category>();
}
You can't use Moq to create the data, but you can use AutoFixture:
public IQueryable<Category> GetCategories()
{
return fixture.CreateMany<Category>().AsQueryable();
}
However, this will not give you a hierarchical tree. It will return objects like this:
Object 1:
- ID = 0
- ParentID = 1
Object 2:
- ID = 2
- ParentID = 3
etc.
If you really need to have this hierarchical data, you would need to use the following code:
public IQueryable<Category> GetCategories()
{
var result = new List<Category>();
// Create the parents
var parents = fixture.Build<Category>()
.Without(x => x.ParentID)
.CreateMany());
result.AddRange(parents);
result.AddRange(parents.SelectMany(p => fixture.Build<Category>()
.With(x => x.ParentID, p.ID)
.CreateMany()));
return result.AsQueryable();
}
This will add multiple parents with multiple subs for each parent.
You can use faker.net to generate fake data. for Example: for dotnet core project its Faker.NETCore.
dotnet add package Faker.NETCore -v 1.0.1
and then use the same in your code in the following manner:-
public void GetStudent()
{
var st = new Student()
st.FirstName = Faker.Name.First();
st.LastName = Faker.Name.Last();
st.Mobile = Faker.Phone.Number();
}