Uniconta Sales Quotation POST CRUD API - c#

I am trying to post a sales quotation using Uniconta CRUD API, I first created the Sales Quotation and then Sales Quotation Line. The Sales Quotation is getting created but it's throwing an error for Sales Quotation Lines as “SetMaster is not called for this class”. This is the code I am using:-
var acc = new DebtorOfferLine();
var accHeader = new DebtorOffer();
acc._Item = "8SC-PRO-1";
acc._LineNumber = 1;
acc._Price = 100;
acc._Qty = 1;
accHeader._DCAccount = "100";
accHeader._Lines = 1;
accHeader._YourRef = "TestQuo3";
capi.SetMaster(acc, accHeader);
var response = capi.Insert(acc).Result;

You need to first insert accHeader then only you can set it as master to acc.
var acc = new DebtorOfferLine();
var accHeader = new DebtorOffer();
acc._Item = "8SC-PRO-1";
acc._LineNumber = 1;
acc._Price = 100;
acc._Qty = 1;
accHeader._DCAccount = "100";
accHeader._Lines = 1;
accHeader._YourRef = "TestQuo3";
var responseOfferInsert = capi.Insert(accHeader).Result;
capi.SetMaster(acc, accHeader);
var response = capi.Insert(acc).Result;

I think your problem lies in the capi part
when you create the capi you initialize it as var capi = CrudAPI(baseApi); right?
if so you don't need the line setMaster as Uniconta will know all classes apart by the unique tableId in your class

Use it like this acc.SetMaster(accHeader); instead.

Related

How to IndexKeysDefinitionBuilder change to IndexKeysDefinition (MongoDB in C#)

I have the following code where I am stuck a little bit:
var indexBuilder = Builders<T>.IndexKeys;
if (setting.IsDescending)
indexBuilder.Descending(setting.Column);
else
indexBuilder.Ascending(setting.Column);
var indexOptions = new CreateIndexOptions();
if (setting.IsUnique)
indexOptions.Unique = true;
var model = new CreateIndexModel<T>(indexBuilder, indexOptions);
I got the following error:
Argument 1: cannot convert from 'MongoDB.Driver.IndexKeysDefinitionBuilder' to 'MongoDB.Driver.IndexKeysDefinition'
I am not sure why as I have done the same as it is in official documentation.
You need to create a variable with IndexKeysDefinition<T> and pass it to the CreateIndexModel as below:
IndexKeysDefinition<T> index;
var indexBuilder = Builders<T>.IndexKeys;
if (setting.IsDescending)
index = indexBuilder.Descending(setting.Column);
else
index = indexBuilder.Ascending(setting.Column);
var indexOptions = new CreateIndexOptions();
if (setting.IsUnique)
indexOptions.Unique = true;
var model = new CreateIndexModel<T>(index, indexOptions);
Demo

C# MVC Loop through list and update each record efficiently

I have a list of 'Sites' that are stored in my database. The list is VERY big and contains around 50,000+ records.
I am trying to loop through each record and update it. This takes ages, is there a better more efficient way of doing this?
using (IRISInSiteLiveEntities DB = new IRISInSiteLiveEntities())
{
var allsites = DB.Sites.ToList();
foreach( var sitedata in allsites)
{
var siterecord = DB.Sites.Find(sitedata.Id);
siterecord.CabinOOB = "Test";
siterecord.TowerOOB = "Test";
siterecord.ManagedOOB = "Test";
siterecord.IssueDescription = "Test";
siterecord.TargetResolutionDate = "Test";
DB.Entry(siterecord).State = EntityState.Modified;
}
DB.SaveChanges();
}
I have cut the stuff out of the code to get to the point. The proper function code I am using basically pulls a list out from Excel, then matches the records in the sites list and updates each record that matches accordingly. The DB.Find is slowing the loop down dramatically.
[HttpPost]
public ActionResult UploadUpdateOOBList()
{
CheckPermissions("UpdateOOBList");
string[] typesallowed = new string[] { ".xls", ".xlsx" };
HttpPostedFileBase file = Request.Files[0];
var fname = file.FileName;
if (!typesallowed.Any(fname.Contains))
{
return Json("NotAllowed");
}
file.SaveAs(Server.MapPath("~/Uploads/OOB List/") + fname);
//Create empty OOB data list
List<OOBList.OOBDetails> oob_data = new List<OOBList.OOBDetails>();
//Using ClosedXML rather than Interop Excel....
//Interop Excel: 30 seconds for 750 rows
//ClosedXML: 3 seconds for 750 rows
string fileName = Server.MapPath("~/Uploads/OOB List/") + fname;
using (var excelWorkbook = new XLWorkbook(fileName))
{
var nonEmptyDataRows = excelWorkbook.Worksheet(2).RowsUsed();
foreach (var dataRow in nonEmptyDataRows)
{
//for row number check
if (dataRow.RowNumber() >= 4 )
{
string siteno = dataRow.Cell(1).GetValue<string>();
string sitename = dataRow.Cell(2).GetValue<string>();
string description = dataRow.Cell(4).GetValue<string>();
string cabinoob = dataRow.Cell(5).GetValue<string>();
string toweroob = dataRow.Cell(6).GetValue<string>();
string manageoob = dataRow.Cell(7).GetValue<string>();
string resolutiondate = dataRow.Cell(8).GetValue<string>();
string resolutiondate_converted = resolutiondate.Substring(resolutiondate.Length - 9);
oob_data.Add(new OOBList.OOBDetails
{
SiteNo = siteno,
SiteName = sitename,
Description = description,
CabinOOB = cabinoob,
TowerOOB = toweroob,
ManageOOB = manageoob,
TargetResolutionDate = resolutiondate_converted
});
}
}
}
//Now delete file.
System.IO.File.Delete(Server.MapPath("~/Uploads/OOB List/") + fname);
Debug.Write("DOWNLOADING LIST ETC....\n");
using (IRISInSiteLiveEntities DB = new IRISInSiteLiveEntities())
{
var allsites = DB.Sites.ToList();
//Loop through sites and the OOB list and if they match then tell us
foreach( var oobdata in oob_data)
{
foreach( var sitedata in allsites)
{
var indexof = sitedata.SiteName.IndexOf(' ');
if( indexof > 0 )
{
var OOBNo = oobdata.SiteNo;
var OOBName = oobdata.SiteName;
var SiteNo = sitedata.SiteName;
var split = SiteNo.Substring(0, indexof);
if (OOBNo == split && SiteNo.Contains(OOBName) )
{
var siterecord = DB.Sites.Find(sitedata.Id);
siterecord.CabinOOB = oobdata.CabinOOB;
siterecord.TowerOOB = oobdata.TowerOOB;
siterecord.ManagedOOB = oobdata.ManageOOB;
siterecord.IssueDescription = oobdata.Description;
siterecord.TargetResolutionDate = oobdata.TargetResolutionDate;
DB.Entry(siterecord).State = EntityState.Modified;
Debug.Write("Updated Site ID/Name Record: " + sitedata.Id + "/" + sitedata.SiteName);
}
}
}
}
DB.SaveChanges();
}
var nowdate = DateTime.Now.ToString("dd/MM/yyyy");
System.IO.File.WriteAllText(Server.MapPath("~/Uploads/OOB List/lastupdated.txt"),nowdate);
return Json("Success");
}
Looks like you are using Entity Framework (6 or Core). In either case both
var siterecord = DB.Sites.Find(sitedata.Id);
and
DB.Entry(siterecord).State = EntityState.Modified;
are redundant, because the siteData variable is coming from
var allsites = DB.Sites.ToList();
This not only loads the whole Site table in memory, but also EF change tracker keeps reference to every object from that list. You can easily verify that with
var siterecord = DB.Sites.Find(sitedata.Id);
Debug.Assert(siterecord == sitedata);
The Find (when the data is already in memory) and Entry methods themselves are fast. But the problem is that they by default trigger automatic DetectChanges, which leads to quadratic time complexity - in simple words, very slow.
With that being said, simply remove them:
if (OOBNo == split && SiteNo.Contains(OOBName))
{
sitedata.CabinOOB = oobdata.CabinOOB;
sitedata.TowerOOB = oobdata.TowerOOB;
sitedata.ManagedOOB = oobdata.ManageOOB;
sitedata.IssueDescription = oobdata.Description;
sitedata.TargetResolutionDate = oobdata.TargetResolutionDate;
Debug.Write("Updated Site ID/Name Record: " + sitedata.Id + "/" + sitedata.SiteName);
}
This way EF will detect changes just once (before SaveChanges) and also will update only the modified record fields.
I have followed Ivan Stoev's suggestion and have changed the code by removing the DB.Find and the EntitySate Modified - It now takes about a minute and a half compared to 15 minutes beforehand. Very suprising as I didn't know that you dont actually require that to update the records. Clever. The code is now:
using (IRISInSiteLiveEntities DB = new IRISInSiteLiveEntities())
{
var allsites = DB.Sites.ToList();
Debug.Write("Starting Site Update loop...");
//Loop through sites and the OOB list and if they match then tell us
//750 records takes around 15-20 minutes.
foreach( var oobdata in oob_data)
{
foreach( var sitedata in allsites)
{
var indexof = sitedata.SiteName.IndexOf(' ');
if( indexof > 0 )
{
var OOBNo = oobdata.SiteNo;
var OOBName = oobdata.SiteName;
var SiteNo = sitedata.SiteName;
var split = SiteNo.Substring(0, indexof);
if (OOBNo == split && SiteNo.Contains(OOBName) )
{
sitedata.CabinOOB = oobdata.CabinOOB;
sitedata.TowerOOB = oobdata.TowerOOB;
sitedata.ManagedOOB = oobdata.ManageOOB;
sitedata.IssueDescription = oobdata.Description;
sitedata.TargetResolutionDate = oobdata.TargetResolutionDate;
Debug.Write("Thank you, next: " + sitedata.Id + "\n");
}
}
}
}
DB.SaveChanges();
}
So first of all you should turn your HTTPPost in an async function
more info https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
What you then should do is create the tasks and add them to a list. Then wait for them to complete (if you want/need to) by calling Task.WaitAll()
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitall?view=netframework-4.7.2
This will allow your code to run in parallel on multiple threads optimizing performance quite a bit already.
You can also use linq to for example reduce the size of allsites beforehand by doing something that will roughly look like this
var sitedataWithCorrectNames = allsites.Where(x => x //evaluate your condition here)
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities
and then start you foreach (var oobdata) with the now foreach(sitedate in sitedataWithCorrectNames)
Same goes for SiteNo.Contains(OOBName)
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/getting-started-with-linq
P.S. Most db sdk's also provide asynchornous functions so use those aswell.
P.P.S. I didn't have an IDE so I eyeballed the code but the links should provide you with plenty of samples. Reply if you need more help.

Creating the BuildDefinition in rally using C#

I was trying to create a build definition. I tried as below one.
But i do think the code below doesn't create a buildDefinition. Like it asks for BuildDefinitionRef in the code "newBuild["BuildDefinition"] = ;" I am unable to know what exactly to put which reference.
RallyRestApi RestApi = new RallyRestApi("_abcd","https://rally1.rallydev.com");
String workspaceRef = "/workspace/27154845988";
String projectRef = "/project/48152113168";
DynamicJsonObject newBuild = new DynamicJsonObject();
newBuild["Workspace"] = workspaceRef;
newBuild["Duration"] = 0.75;
newBuild["Message"] = "Master 4683 Success";
//newBuild["CreationDate"] = "";
newBuild["Status"] = "FAILURE";
newBuild["Number"] = "4683";
// newBuild["Uri"] = "http://jenkins-build:8080/hudson/view/master/job/master-deploy/4683/";
// newBuild["BuildDefinition"] = ;
If any body has any idea of first how to create the BuildDefinition.
BuildDefinition should be a createable type in WSAPI. You just need to create that first, and then when you're creating your Build object just pass the ref of the created BuildDefinition:
newBuild["BuildDefinition"] = "/builddefinition/12345";

XML with elements of the same name

How do I edit the data in each Address Line, since they all have the same name?
<StructuredAddress>
<AddressLine></AddressLine>
<AddressLine></AddressLine>
<AddressLine></AddressLine>
</StructuredAddress>
My code so far, which doesn't work, is this. How do I isolate each AddressLine indivisually and insert the appropriate data?
XElement StructuredAddress = PatientAddress.Descendants("StructuredAddress").First();
StructuredAddress.Element("AddresLine").Value = cc.address1;
StructuredAddress.Element("AddresLine").Value = cc.address2;
StructuredAddress.Element("AddresLine").Value = cc.address3;
You may want to access each <AddressLine> using it's index :
XElement StructuredAddress = PatientAddress.Descendants("StructuredAddress").First();
var address = StructuredAddress.Elements("AddresLine").ToList();
address[0].Value = cc.address1;
address[1].Value = cc.address2;
address[2].Value = cc.address3;
You could iterate them which will present them in ordinal order:
foreach (var addressLine in StructuredAddress.Elements("AddressLine"))
{
addressLine.Value = ...
}
Or by index;
var lines = StructuredAddress.Elements("AddressLine").ToList();
lines[0].Value = "...";

DateTime missing from WCF request?

I have a program that is consuming an external web service. 1 of the fields I need to send in the request is a DateTime field however it seems to never be present even though I have set it, along with many others in the same object, and they are passed fine.
I put a message inspector and had a look at what it is sending, here is the request:
<bettingRequest xmlns="">
<accountPin>0</accountPin>
<betDetailsRequestList>
<acceptPartial>0</acceptPartial>
<accumulatorBet>false</accumulatorBet>
<accumulatorId>0</accumulatorId>
<allUpFormula>0</allUpFormula>
<betAmountList>
<amountInvested>25</amountInvested>
<returnsPerBet>0</returnsPerBet>
</betAmountList>
<betRefId>0</betRefId>
<betType>Parimutuel</betType>
<scheduledType>1</scheduledType>
<fixedOddsProdCode>0</fixedOddsProdCode>
<flexiBet>false</flexiBet>
<legList>
<prodCode>1</prodCode>
<propositionNumber>0</propositionNumber>
<raceNumber>2</raceNumber>
<selectionList>
<selectionName>TIM FIN</selectionName>
<selectionNumber>6</selectionNumber>
<selectionSeparator />
</selectionList>
</legList>
<mystery>false</mystery>
<notifyMethod>0</notifyMethod>
<numMultiParlayBet>0</numMultiParlayBet>
<ordinalNumber>1</ordinalNumber>
<meetingCode>13</meetingCode>
</betDetailsRequestList>
</bettingRequest>
and here is what creates it:
bettingRequest betReq = new bettingRequest();
betDetailsReq betDetReq = new betDetailsReq();
List<legDetailsReq> leglist = new List<legDetailsReq>();
List<betSelection> sellist = new List<betSelection>();
List<betAmount> betamtlist = new List<betAmount>();
List<betDetailsReq> betdetaillist = new List<betDetailsReq>();
betSelection sel = new betSelection();
sel.selectionNumber = selection.ToString();
sel.selectionName = Runner;
sel.selectionSeparator = "";
sellist.Add(sel);
legDetailsReq leg = new legDetailsReq();
leg.prodCode = 1;
leg.propositionNumber = 0;
leg.raceNumber = racenum;
leg.selectionList = sellist.ToArray();
leglist.Add(leg);
betAmount betAmt = new betAmount();
betAmt.amountInvested = betamt;
betAmt.returnsPerBet = "0";
betamtlist.Add(betAmt);
betDetReq.betType = "Parimutuel";
betDetReq.betAmountList = betamtlist.ToArray();
betDetReq.legList = leglist.ToArray();
betDetReq.allUpFormula = "0";
betDetReq.acceptPartial = 0;
betDetReq.accumulatorBet = false;
betDetReq.betRefId = 0;
betDetReq.scheduledType = 1;
betDetReq.fixedOddsProdCode = 0;
betDetReq.flexiBet = false;
betDetReq.mystery = false;
betDetReq.notifyMethod = 0;
betDetReq.ordinalNumber = 1;
betDetReq.meetingCode = meetingcode;
betDetReq.meetingDate = DateTime.Now;
betdetaillist.Add(betDetReq);
betReq.betDetailsRequestList = betdetaillist.ToArray();
bettingResponse resp = bet.validateBet(meta, betReq);
and here is the code for the serialization:
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=11)]
public System.DateTime meetingDate {
get {
return this.meetingDateField;
}
set {
this.meetingDateField = value;
this.RaisePropertyChanged("meetingDate");
}
}
The attribute that is missing is the betDetReq.meetingDate, the WSDL can be viewed at https://api.tab.com.au/tabapi/services/betting?wsdl
Can someone tell me where I am going wrong please? I have tried many different variations of DataTime all with the same missing result.
Thanks
Dean
Ensure you have set the "Specified" property to true.
betDetReq.meetingDate = DateTime.Now;
betDetReq.meetingDateSpecified = true;
If you have an optional field (i.e. one where the minOccurs attribute is 0), then the proxy includes a "Specified" property. Unless you set this to true, the field does not get added to the request body.

Categories