Now I'm making a method, after which the data is successfully sent from the telegram bot to the user. Now I have made this option. However, the problem is that all data is sent separately.
And if we assume we have 20 books in the matrix, we get 21 messages with customer data.
How can I make everything is sent in one message?
private void Form_DataAddAfter(ref SAPbouiCOM.BusinessObjectInfo pVal)
{
SAPbouiCOM.EditText oEdit_Customer = (SAPbouiCOM.EditText)this.GetItem("4").Specific;
SAPbouiCOM.EditText oEdit_Name = (SAPbouiCOM.EditText)this.GetItem("54").Specific;
SAPbouiCOM.EditText oEdit_PostingDate = (SAPbouiCOM.EditText)this.GetItem("10").Specific;
SAPbouiCOM.EditText oEdit_Total = (SAPbouiCOM.EditText)this.GetItem("29").Specific;
SendTextMessage(($"Return of the book!\n\nCustomer: {oEdit_Customer.Value}\nCustomer's name: {oEdit_Name.Value}\nReturn date: {oEdit_PostingDate.Value}\nTotal: {oEdit_Total.Value} "));
for (int j = 1; j < Matrix0.RowCount-1; j++)
{
SAPbouiCOM.EditText cell_Description = (SAPbouiCOM.EditText)Matrix0.Columns.Item("1").Cells.Item(j).Specific;
SAPbouiCOM.EditText cell_Quantity = (SAPbouiCOM.EditText)Matrix0.Columns.Item("U_inUseQuantity").Cells.Item(j).Specific;
SendTextMessage(($"Book: {cell_Description.Value}\nQuantity: {cell_Quantity.Value}"));
}
}
Not tested this code but should work.
Store your "messages" in a string variable add the strings you are currently sending to it. You can then send the string "sendText" after the loop
string sendText = "";
for (int j = 1; j < Matrix0.RowCount-1; j++)
{
SAPbouiCOM.EditText cell_Description = (SAPbouiCOM.EditText)Matrix0.Columns.Item("1").Cells.Item(j).Specific;
SAPbouiCOM.EditText cell_Quantity = (SAPbouiCOM.EditText)Matrix0.Columns.Item("U_inUseQuantity").Cells.Item(j).Specific;
sendText += $"Book: {cell_Description.Value}\nQuantity: {cell_Quantity.Value}\n";
}
SendTextMessage(sendText);
Related
When making a request for HistoricalDataRequest on PX_LAST for a period of a month, I am getting back bulk data. What is wrong with my syntax because I keep getting "Cannot convert SEQUENCE to Element".
//FIELDS
Element fields = security.GetElement(FIELD_DATA);
if (fields.NumElements > 0)
{
int numElements = fields.NumElements;
for (int j = 0; j < numElements; ++j)
{
Element field = fields.GetElement(j);
if (field.Datatype == Schema.Datatype.SEQUENCE || field.IsArray)
{
processBulkField(field, ticker, response);
}
else
{
processRefField(field, ticker, response);
}
}
}
here is the process bulk fields: Error is on the line: Element bulkElement = refBulkfield.GetValueAsElement(i);
private static void processBulkField(Element refBulkfield, string ticker, List<BBGSecurity> response)
{
// Get the total number of Bulk data points
int numofBulkValues = refBulkfield.NumValues;
for (int i = 0; i < numofBulkValues; ++i)
{
Element bulkElement = refBulkfield.GetValueAsElement(i);
// Get the number of sub fields for each bulk data element
int numofBulkElements = bulkElement.NumElements;
// Read each field in Bulk data
for (int j = 0; j < numofBulkElements; ++j)
{
Element field = bulkElement.GetElement(j);
response.Add(new BBGSecurity { Security = ticker, DataDate = DateTime.Parse(d_dataDate), DataSessionID = d_dataSession, Field = field.Name.ToString(), PropertyValue = field.GetValueAsString() });
}
}
}
Thanks in advance!
Please remove field.Datatype == Schema.Datatype.SEQUENCE from the if condition, it should look like:
if (field.IsArray)
{
processBulkField(field, ticker, response);
}
else
{
processRefField(field, ticker, response);
}
Bulk fields are identified by property field.IsArray = True.
Bulk fields contains data set structured as a table with columns and rows, while SEQUENCE field contains data set represented like a C struct.
So my program lets me send requests using WSDL the class below is provided by the WSDL:
CreateCustomerNoteRequest createCustomerNotesRequestInfo = new CreateCustomerNoteRequest();
Using this class I have to set the variables like this:
//FIRST WRITING NOTE TO OLD ACCOUNT TO SAY ITS BEEN COMPRIMISED AND SHOW NEW CUSTOMER NUMBER:
createCustomerNotesRequestInfo.UserName = username;
createCustomerNotesRequestInfo.Password = password;
createCustomerNotesRequestInfo.SystemToken = "sysToken";
createCustomerNotesRequestInfo.Note = new CustomerNote();
createCustomerNotesRequestInfo.Note.CustomerNumber = cloneCustomerNumber;
createCustomerNotesRequestInfo.Note.Category = new CustomerServiceWSDL.LookupItem();
createCustomerNotesRequestInfo.Note.Category.Code = "GEN";
createCustomerNotesRequestInfo.Note.Details = "Account Takeover – Fraud. Acc – " + customerNumberTextBox.Text + " closed as compromised and new account " + newCloneCustomerNumber + " created matching existing data";
And to finish off I use this to get my response:
createCustomerNotesResponse = soapClient.CreateCustomerNote(createCustomerNotesRequestInfo);
Everything works fine. What I want to do now is because I have multiple Notes I want to loop this process so depending on how many Note there are it would create that many instances.
I do successfully get all the Notes into a list like this using notecount which provides how many number of notes there are (Given by WSDL) so all is good so far:
try
{
for (int i = 0; i <= notesCount; i++)
{
customerNotesArrayList.Add(getCustomerNotesResponse.Notes.Items[i]);
//i++;
}
}
What I want to do: Now depending on the notes count I want to create that many of this:
CreateCustomerNoteRequest createCustomerNotesRequestInfo = new CreateCustomerNoteRequest();
I tried this:
for (int i=0; i<=notesCount;i++)
{
CreateCustomerNoteRequest a[i] = new CreateCustomerNoteRequest();
}
But its not as easy as that so how can I loop to make this happen?
So I want a1, a2, a3 where Ill then loop all the notes in later which shouldn't be a problem. But creating these in the first place is the problem.
[EDIT]
//Create Notes and copy over array contents...
CreateCustomerNoteRequest request = new CreateCustomerNoteRequest();
for (int i = 0; i <= notesCount; i++)
{
request.UserName = username;
request.Password = password;
request.SystemToken = systemToken;
request.Note = new CustomerNote();
request.Note.CustomerNumber = newCloneCustomerNumber;
request.Note.Category = new CustomerServiceWSDL.LookupItem();
request.Note.Category.Code = customerNotesArrayList[i].NoteCategory.Code.ToString();
request.Note.Details = customerNotesArrayList[i].NoteText;
var response = soapClient.CreateCustomerNote(request);
}
You're declaring the array inside the loop, which means it won't be available afterwards. Furthermore you need to declare the array size beforehand:
CreateCustomerNoteRequest[] a = new CreateCustomerNoteRequest[notesCount];
for (int i = 0; i < notesCount; i++)
{
a[i] = new CreateCustomerNoteRequest();
}
// now you can use the array outside the loop as well
Instead of an array you could choose to use a List<CreateCustomerNoteRequest>, which doesn't need a size declaration first.
Note that if you're planning to get the notes inside the same loop, you won't need the array at all:
for (int i = 0; i < notesCount; i++)
{
CreateCustomerNoteRequest request = new CreateCustomerNoteRequest();
var response = soapClient.CreateCustomerNote(request);
// todo process response
}
I'm using a SOAP Web Reference in a C# service for this.
If I call (in my SForceManager class) CreateSForceCase() multiple times within the same connection, I receive the same exact CaseNumber until the connection times out and is reconnected (or if i create a new connection for each).
The problem with this, is that I'm needing to insert upto say 5000 cases, and at 3 seconds per case that will take ~4 hours to insert all 5000 cases. Is there a way to let the API know that I want a brand new case each and every time I create one without logging out?
Here's my Manager code:
public String CreateSForceCase(Case sfCase, out string errMsg)
{
//Verify that we are already authenticated, if not
//call the login function to do so
if (!isConnected()) login();
errMsg = "";
sObject[] objCases = new sObject[1];
for (int j = 0; j < objCases.Length; j++)
objCases[j] = sfCase;
//create the object(s) by sending the array to the web service
SaveResult[] sr = _Binding.create(objCases);
for (int j = 0; j < sr.Length; j++)
{
if (sr[j].success)
{
//save the account ids in a class array
if (_cases == null)
_cases = new string[] { sr[j].id };
else
{
string[] tempcases = null;
tempcases = new string[_cases.Length + 1];
for (int i = 0; i < _cases.Length; i++)
tempcases[i] = _cases[i];
tempcases[_cases.Length] = sr[j].id;
_cases = tempcases;
}
return getCaseNumberFromCaseId(_cases[0]);
}
else
{
//there were errors during the create call, go through the errors
//array and write them to the screen
for (int i = 0; i < sr[j].errors.Length; i++)
{
//get the next error
Error err = sr[j].errors[i];
errMsg = err.message;
}
}
}
return string.Empty;
}
and the call within for getting the case # is:
public String getCaseNumberFromCaseId(string caseId)
{
if (!isConnected()) login();
sObject[] ret = _Binding.retrieve("CaseNumber", "Case", new string[] { caseId });
if (ret != null)
return ((Case)ret[0]).CaseNumber;
else
return string.Empty;
}
so something like:
SForceManager manager = new SForceManager();
string case1 = manager.CreateSForceCase(...);
string case2 = manager.CreateSForceCase(...);
string case3 = manager.CreateSForceCase(...);
then case1 == case2 == case3
but if i do:
SForceManager manager = new SForceManager();
string case1 = manager.CreateSForceCase(...);
SForceManager manager = new SForceManager();
string case2 = manager.CreateSForceCase(...);
SForceManager manager = new SForceManager();
string case3 = manager.CreateSForceCase(...);
then case1 != case2 != case3 like i expect
So I figured out a way to perform this.
The idea is to actually take in a list of "Case objects" and send those all at once, then return a string array of case id's.
I'm not sure what would happen if I try opening too many such that the timeout period may pass in the middle of processing (so it could be improved yet):
public String[] CreateSForceCases(Case[] sfCase, out List<string> errMsg)
{
String[] toRet = new string[sfCase.Length];
errMsg = new List<string>();
//Verify that we are already authenticated, if not
//call the login function to do so
if (!isConnected()) login();
//errMsg = "";
sObject[] objCases = new sObject[sfCase.Length];
for (int j = 0; j < objCases.Length; j++)
objCases[j] = sfCase[j];
//create the object(s) by sending the array to the web service
SaveResult[] sr = _Binding.create(objCases);
for (int j = 0; j < sr.Length; j++)
{
if (sr[j].success)
{
//save the account ids in a class array
if (_cases == null)
_cases = new string[] { sr[j].id };
else
{
string[] tempcases = null;
tempcases = new string[_cases.Length + 1];
for (int i = 0; i < _cases.Length; i++)
tempcases[i] = _cases[i];
tempcases[_cases.Length] = sr[j].id;
_cases = tempcases;
}
toRet[j] = getCaseNumberFromCaseId(_cases[j]);
}
else
{
//there were errors during the create call, go through the errors
//array and write them to the screen
for (int i = 0; i < sr[j].errors.Length; i++)
{
//get the next error
Error err = sr[j].errors[i];
errMsg.Add(err.message);
}
}
}
return toRet;
//return null;
}
There was also a problem in the error handling process in the original, however this one fixes that. I figured I would post my solution in case anyone else has come across this issue...I was not able to find any answer to my question anywhere.
I'm trying to loop all the messages in specific inbox like using ActiveUp Mail C#:
Mailbox box = imap.AllMailboxes[0];
Fetch fetch = box.Fetch;
int messagesLeft = box.MessageCount; // return 31
int msgIndex = 0;
List<Email> list = new List<Email>();
for (int x = 1; x <= box.MessageCount; x++)
{
try
{
Message msg = fetch.MessageObject(x);
list.Add(new Email()
{
/// .....
});
}
catch { }
}
I'm getting an error for all the messages (except 1)..
Index and length must refer to a location within the string.
all of the messages (Except the 1 that working well) are from the same sender and has the same format (different content)
Imap4Client client = new Imap4Client();
client.Connect("server", 143);
client.Login("***", "***");
foreach (var box in client.AllMailboxes.OfType<Mailbox>())
{
for (int i = 1; i <= box.MessageCount; i++)
{
// a u wish
Header heade = box.Fetch.MessageObject(i);
}
}
i have set of addresses, which i use to load on the map,
im loading those addresses from cs file to javascript using HiddenField like
// In code behind
string []arr=new string[]
{
"51.482238,0.001581",
"51.473364,0.011966","51.471974,-0.000651",
"51.472108,-0.002196","51.474995,-0.003827",
"51.476492,-0.005629","51.477855,-0.006058",
"51.478443,-0.007045","51.479298,-0.007861",
"51.481202,-0.002136","51.481577,-0.0022"
};
for ( int j = 0; j < arr.Length ; j++ )
{
HiddenField1.Value += arr[j] + ":";
}
}
//in javascript
var hidValue= document.getElementById("<%=HiddenField1.ClientID%>").value;
var latlonArr = hidValue.split(':');
for (var i = 0; i < latlonArr.length - 1; i++)
{
//alert("item :"+ i + " : "+latlonArr[i]);
var latlonA = latlonArr[i].split(',');
var latlon = new google.maps.LatLng(latlonA[0],latlonA[1]);
arrCoords.push(latlon);
}
so, now if i have more no. of address, will it be okay to go with HiddenField for addresses ranging from 100 to 1000 or more..
Check the performance with the maximum number of addresses you might have, if the performance is OK then you should be fine.
If the performance is not OK then consider fetching the addresses asynchronusly, e.g. 100 at a time.
In code-behind you can use:
string []arr=new string[]
{
"51.482238,0.001581",
"51.473364,0.011966","51.471974,-0.000651",
"51.472108,-0.002196","51.474995,-0.003827",
"51.476492,-0.005629","51.477855,-0.006058",
"51.478443,-0.007045","51.479298,-0.007861",
"51.481202,-0.002136","51.481577,-0.0022"
};
HiddenField1.Value = arr.join(",");