Multiple instances of forms has data writing to first opened form - sapb1

I have this SAP B1 addon where a user can open multiple instances of a UDO from.
The form is loaded from XML.
SAPUtility.LoadFromXML(SboConnection.SboApplication, GUI.FormsPath, "SalesOrder.xml");
I have CFLs but when I open the 2nd form and select a customer on that 2nd form, the data writes to the form I opened first. I am using a user datasource for the CFLs.
oItem = _form.Items.Item("CardCode");
_cardCode = oItem.Specific;
_cCode = _form.DataSources.UserDataSources.Add("CardCode", SAPbouiCOM.BoDataType.dt_SHORT_TEXT, 50);
_cardCode.DataBind.SetBound(true, "", "CardCode");
_cardCode.Value = "";
...............................
if (oDataTable.UniqueID == "CFL_CarCod" || oDataTable.UniqueID == "CFL_CarNam")
{
if (oDataTable != null)
{
cardCode = System.Convert.ToString(oDataTable.GetValue(0, 0), null);
cardName = System.Convert.ToString(oDataTable.GetValue(1, 0), null);
}
RemoveContacts();
_cCode.ValueEx = cardCode;
_cName.ValueEx = cardName;
AddContacts();
}
In item events, I have this:
_form = SboConnection.SboApplication.Forms.Item(pVal.FormUID);
How do I fix this and make data write to the proper active form?

Related

Unable to set date values in SAP B1 matrix combobox

I am trying to set values in a matrix combobox but I cannot be able to set the first value of date to that combobox. It shows blank and when I select a date, it does not fill the field anyway.
The values I get from the DB are as follows:
Here is my code below including binding the combobox field to a userdatasource:
_expDate = _form.DataSources.UserDataSources.Add("iV_15", SAPbouiCOM.BoDataType.dt_DATE, 100);
oIColumns = oIMatrix.Columns;
_colExpDate = oIColumns.Item("iV_15");
_colExpDate.DataBind.SetBound(true, "", "iV_15");
The below code runs when there is a lost focus change event to the item selection field:
#region Item Change Event Expiry dates
_cmbExpDate = (SAPbouiCOM.ComboBox)oIMatrix.Columns.Item("iV_15").Cells.Item(pVal.Row).Specific;
int count = _cmbExpDate.ValidValues.Count;
if (count > 0)
{
_expDate.ValueEx = "";
for (int j = 0; j <= count - 1; j++)
_cmbExpDate.ValidValues.Remove(0, SAPbouiCOM.BoSearchKey.psk_Index);
}
var expDates = (from oi in _db.OITMs
join ob in _db.OBTNs
on oi.ItemCode equals ob.ItemCode
where ob.ItemCode == _itemNo.ValueEx && oi.OnHand > 0
orderby ob.ExpDate
select new
{
ExpDate = ob.ExpDate
}).Distinct().ToList();
if (expDates.Count > 0)
{
foreach (var item in expDates)
_cmbExpDate.ValidValues.Add(item.ExpDate?.ToString(), item.ExpDate?.ToString());
_cmbExpDate.Select(0, SAPbouiCOM.BoSearchKey.psk_Index);
_expDate.ValueEx = _cmbExpDate.Value;
}
#endregion
What could be wrong. Is there a better way to achieve what I need in SAP B1?
as a test try a different data type for your:
_expDate = _form.DataSources.UserDataSources.Add("iV_15", SAPbouiCOM.BoDataType.dt_DATE, 100);
test it with: SAPbouiCOM.BoDataType.dt_LONG_TEXT
you can also try just selecting the value on the combo, instead of setting uds as well.

Newly added row is not reflecting on UI instantly in SAP B1

When I add new row into the database and call loadfromdatasource method, it is not reflecting. I need to re-log to check newly added row. How can I instantly refresh data in matrix?
Code:
oUserTable.Code = "Temp1"; oUserTable.UserFields.Fields.Item("U_barcode").Value = oEditTxt.String; oUserTable.UserFields.Fields.Item("U_keyword").Value = oEditTxt1.String; oUserTable.UserFields.Fields.Item("U_pdocentry").Value = DocEntry; oUserTable.UserFields.Fields.Item("U_pobjtype").Value = "17"; int i = oUserTable.Add(); SAPbouiCOM.Form oForm = Application.SBO_Application.OpenForm(SAPbouiCOM.BoFormObjectEnum.fo_Order, "", DocEntry.ToString()); if (i != 0){ oApp.SetStatusBarMessage("Error" + oCompany.GetLastErrorDescription(), SAPbouiCOM.BoMessageTime.bmt_Medium, false); }else{ oApp.SetStatusBarMessage("Successfully inserted data" + oCompany.GetLastErrorDescription(), SAPbouiCOM.BoMessageTime.bmt_Medium, false); oMatrix.LoadFromDataSource();}}}

Installable Trigger Failing with Test Add-On

I have been wrestling with an installable trigger issue for a couple of days now. All of my research indicates that an add-on should allow for an installable onEdit() trigger within a spreadsheet, but my attempts keep erroring out. I have simplified my project code a bit to exemplify my issue.
The error message:
Execution failed: Test add-on attempted to perform an action that is not allowed.
My code (listing functions is the order that they are called):
function onOpen() //creates custom menu for the evaluation tool ***FOR ADMININSTRATORS ONLY***
{
var ui = SpreadsheetApp.getUi();
if(!PropertiesService.getDocumentProperties().getProperty('initialized'))
{
ui.createMenu('Evaluation Menu') // Menu Title
.addItem('Create Installable OnEdit Trigger', 'createInstallableOnEditTrigger')
.addToUi();
}
else
{
ui.createMenu('Evaluation Menu') // Menu Title
.addSubMenu(ui.createMenu('Manage Observations & Evidence')
.addSubMenu(ui.createMenu('Create New Observation')
.addItem('Formal', 'createNewFormalObservation')
.addItem('Informal', 'createNewInformalObservation')
)
.addToUi();
}
}
function createInstallableOnEditTrigger() { // installable trigger to create employee look-up listener when user edits the EIN fields on the Documentation Sheet.
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('onEditListener')
.forSpreadsheet(ss)
.onOpen()
.create();
PropertiesService.getDocumentProperties().setProperty('initialized','true');
}
function onEditListener(event) //this function conitnually listens to all edit, but only engages only certain conditions such as when a timestamp is determined to be needed or the Documentation Sheet needs to be auto-populated
{
//Determine whether or not the conditions are correct for continuing this function
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName(); //determines the name of the currently active sheet
if (sheetName.indexOf("Evidence") > -1) // if the active sheet is an evidence collection sheet, a timestamp may be needed
{
populateEvidenceTimeStamp(event, sheetName);
}
else if (sheetName == "Documentation Sheet") //if the active sheet is the "Documentation Sheet" than auto-population and EIN lookups may be needed
{
employeeLookup(event, sheetName);
}
}
What am I missing? Any help is greatly appreciated!!
The below code has been added as requested by #Mogsdad.
populateEvidenceTimeStamp() is dependent upon generateTimeStamp() which is also included below:
function populateEvidenceTimeStamp(event, sheetName)
{
var evidenceColumnName = "Evidence";
var timeStampColumnName = "Timestamp";
var sheet = event.source.getSheetByName(sheetName);
var actRng = event.source.getActiveRange();
var indexOfColumnBeingEdited = actRng.getColumn();
var indexOfRowBeingEdited = actRng.getRowIndex();
var columnHeadersArr = sheet.getRange(3, 1, 1, sheet.getLastColumn()).getValues(); // grabs the column headers found in the 3rd row of the evidence sheet
var timeStampColumnIndex = columnHeadersArr[0].indexOf(timeStampColumnName); //determines the index of the Timestamp column based on its title
var evidenceColumnIndex = columnHeadersArr[0].indexOf(evidenceColumnName); evidenceColumnIndex = evidenceColumnIndex+1; //determines the index of the evidence column based on its title
var cell = sheet.getRange(indexOfRowBeingEdited, timeStampColumnIndex + 1); //determines the individual timestap cell that will be updated
if (timeStampColumnIndex > -1 && indexOfRowBeingEdited > 3 && indexOfColumnBeingEdited == evidenceColumnIndex && cell.getValue() == "") // only create a timestamp if 1) the timeStampColumn exists, 2) you are not actually editing the row containing the column headers and 3) there isn't already a timestamp in the Timestamp column for that row
{
cell.setValue(generateTimeStamp());
}
}
function generateTimeStamp()
{
var timezone = "GMT-7"; // Arizona's time zone
var timestamp_format = "MM.dd.yyyy hh:mm:ss a"; // timestamp format based on the Java SE SimpleDateFormat class. http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
var currTimeStamp = Utilities.formatDate(new Date(), timezone, timestamp_format);
return currTimeStamp;
}
Below is the employeeLookup() function which is dependent upon lookupEIN()
function employeeLookup(event, sheetName)
{
if(sheetName == "Documentation Sheet" && !PropertiesService.getDocumentProperties().getProperty('initialized')) // if the activeSheet is "Documentation Sheet" and the sheet has not yet been initialized
{
var actRng = event.source.getActiveRange();
Logger.log("employeeLookup(): actRng: "+actRng.getRow()+" , "+actRng.getColumn());
if(actRng.getRow() == 4 && actRng.getColumn() == 9 && event.source.getActiveRange().getValue() != "") //if the "Teacher EIN" cell is the active range and it's not empty
{
var ein = actRng.getValue();
clearDocumentationSheetTeacherProfile(); //first clear the teacher profile information to avoid the possibility of EIN/Teacher Info mismatch if previous search did not yield results
var teacherDataArr = lookupEIN(ein, "Teachers");
if(teacherDataArr)
{
//write retrieved teacher data to Documentation Spreadsheet
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Documentation Sheet");
sheet.getRange(5, 9, 1, 1).setValue(teacherDataArr[1]); // Teacher First Name
sheet.getRange(6, 9, 1, 1).setValue(teacherDataArr[2]); // Teacher Last Name
sheet.getRange(7, 9, 1, 1).setValue(teacherDataArr[3]); // Teacher Email
sheet.getRange(11, 9, 1, 1).setValue(teacherDataArr[4]); // School Name
sheet.getRange(11, 39, 1, 1).setValue(teacherDataArr[5]); // Site Code
sheet.getRange(10, 30, 1, 1).setValue(calculateSchoolYear()); //School Year
}
else
{
Logger.log("employeeLookup(): type:Teachers 'died. lookupEIN() did not return a valid array'"); //alert message already sent by lookUpEIN
}
}
else if (actRng.getRow() == 4 && actRng.getColumn() == 30 && actRng.getValue() != "" && !PropertiesService.getDocumentProperties().getProperty('initialized')) //if the "Observer EIN" cell is the active range
{
Logger.log("employeeLookup(): 'active range is Observer EIN'");
var ein = actRng.getValue();
clearDocumentationSheetObserverProfile(); //first clear the teacher profile information to avoid the possibility of EIN/Observer Info mismatch if previous search did not yield results
var observerDataArr = lookupEIN(ein, "Observers");
if(observerDataArr)
{
//write retrieved observer data to Documentation Spreadsheet
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Documentation Sheet");
sheet.getRange(5, 30, 1, 1).setValue(observerDataArr[1]); // Observer First Name
sheet.getRange(6, 30, 1, 1).setValue(observerDataArr[2]); // Observer Last Name
sheet.getRange(7, 30, 1, 1).setValue(observerDataArr[3]); // Observer Email
}
else
{
Logger.log("employeeLookup(): type:Observers 'died. lookupEIN() did not return a valid array'"); //alert message already sent by lookUpEIN
}
}
else
{
Logger.log("employeeLookup(): 'active range is not a trigger'");
//do nothing (not the right cell)
}
}
else
{
//Observer log has already been initialized and documentation cannot be altered. notify user
Logger.log("employeeLookup(): 'log already saved.... alerting user'");
logAlreadyInitializedDialogue();
restoreDocumentationSheetData();
}
}
function lookupEIN(ein, type)
{
Logger.log ("lookUpEIN(): 'engaged'");
var ss = SpreadsheetApp.openById(teacherObserverIndex_GID);
var sheet = ss.getSheetByName(type); //lookup type aligns with the individual sheet names on the teacherObserverIndex_GID document
var values = sheet.getDataRange().getValues();
var val = sheet.getDataRange();
for (var i = 1; i < values.length; i++)
{
if(values[i][0] == ein)
{
Logger.log ("lookUpEIN(): values[i]: "+values[i]);
return values[i];
}
else
{
Logger.log ("lookUpEIN(): 'no match found'");
}
}
//a match could not be found
Logger.log("An EIN match could not be found"); // create a feedback pop-up
einNotFoundDialogue(type); //alert user that there is a problem with the provided ein
}
Triggers can't be created when running a script as Test as add-on.
From https://developers.google.com/apps-script/add-ons/test :
There are a number of things to keep in mind while testing add-ons:
Installable triggers are currently not supported when testing.
Functionality that depends on installable triggers will not be
testable.
Some possible workarounds
For on open and on edit installable triggers, temporally add simple triggers to call the functions of the installable triggers. This might only work if the execution time of is less than the simple triggers limit.
Call the functions from the installable triggers from functions that create object that emulates the corresponding event object
Instead of using a stand-alone project use bounded projects. You might use CLASP or an extension like Google Apps Script GitHub Assistant Chrome extension to make it easier to copy the code from the stand-alone project to a bounded project.
Related
How can I test a trigger function in GAS?
In my experience onEdit() is not available for test as Add-On.
I agree the documentation is not clear, it seems to be referring to only "Installable Triggers" but I think it applies to all Triggers except for the "onInstall" trigger that is run as soon as you start the test. (see: Testing Google Sheet Addon Triggers for more details)

SharePoint get value of rich text box control created programatically

I'm writing a custom web part that need to use a couple of rich text box controls. I'm placing the controls onto the web part programatically. When the web part gets a save postback I'm able to capture the data from all the fields except the two rich text box ones. What's the trick to be able to get the value of a rich text box?
The code I"m using to place my form controls is:
private void CreateInputControls()
{
inputPanel.Controls.Clear();
SPList list = SPContext.Current.Site.RootWeb.Lists["MyList"];
SPContentType cType = list.ContentTypes[0];
Table table = new Table();
table.CellPadding = 3;
table.CellSpacing = 0;
SPContext newContext = SPContext.GetContext(System.Web.HttpContext.Current, list.DefaultView.ID, list.ID, list.ParentWeb);
foreach (SPField field in cType.Fields)
{
if (!field.Hidden && field.CanBeDisplayedInEditForm)
{
FieldLabel fieldLabel = new FieldLabel();
fieldLabel.ControlMode = SPControlMode.New;
fieldLabel.ListId = list.ID;
fieldLabel.FieldName = field.InternalName;
fieldLabel.ItemContext = newContext;
fieldLabel.RenderContext = newContext;
fieldLabel.Field.Required = fieldLabel.Field.Required;
FormField formField = new FormField();
formField.ControlMode = SPControlMode.New;
formField.ListId = list.ID;
formField.FieldName = field.InternalName;
formField.ItemContext = newContext;
formField.RenderContext = newContext;
formField.ID = field.InternalName;
formField.EnableViewState = true;
TableRow row = new TableRow();
table.Rows.Add(row);
TableCell cellLabel = new TableCell();
TableCell cellField = new TableCell();
cellLabel.Controls.Add(fieldLabel);
cellField.Controls.Add(formField);
row.Cells.Add(cellLabel);
row.Cells.Add(cellField);
}
}
inputPanel.Controls.Add(table);
}
The code I'm using to save a new item is:
private void UpdateItem(string bannerImageURL, string thumbnailImageURL)
{
SPList list = SPContext.Current.Site.RootWeb.Lists["MyList"];
SPContentType cType = list.ContentTypes[0];
SPItem item = list.AddItem();
foreach (SPField field in cType.Fields)
{
if (!field.Hidden && field.CanBeDisplayedInEditForm)
{
FormField formField = (FormField)inputPanel.FindControl(field.InternalName);
if (formField != null)
{
// Saves data for all fields EXCEPT for rich text box (sharepoint multiline columns).
item[field.Title] = formField.Value;
}
}
}
item.Update();
}
Maybe there's an issue with the field name. Try to use the InternalName.
item[field.InternalName] = formField.Value;
I have been struggling with this and am using a workaround which I thought I'd post as this was quite frustrating.
The problem is that the RTE control is rendered empty and then populated from a hidden control with JavaScript on the client. However this hidden control is accessible server side thus:
switch (formField.Field.Type)
{
case SPFieldType.Note:
var rtf = (RichTextField)formField.Controls[0];
item[field.Title] = rtf.HiddenInput.Value;
break;
default:
item[field.Title] = formField.Value;
break;
}
This may need extending for other field types but you get the idea...

Cannot add an entity that already exists. (LINQ to SQL)

in my database there are 3 tables
CustomerType
CusID
EventType
EventTypeID
CustomerEventType
CusID
EventTypeID
alt text http://img706.imageshack.us/img706/8806/inserevent.jpg
Dim db = new CustomerEventDataContext
Dim newEvent = new EventType
newEvent.EventTypeID = txtEventID.text
db.EventType.InsertOnSubmit(newEvent)
db.SubmitChanges()
'To select the last ID of event'
Dim lastEventID = (from e in db.EventType Select e.EventTypeID Order By EventTypeID Descending).first()
Dim chkbx As CheckBoxList = CType(form1.FindControl("CheckBoxList1"), CheckBoxList)
Dim newCustomerEventType = New CustomerEventType
Dim i As Integer
For i = 0 To chkbx.Items.Count - 1 Step i + 1
If (chkbx.Items(i).Selected) Then
newCustomerEventType.INTEVENTTYPEID = lastEventID
newCustomerEventType.INTSTUDENTTYPEID = chkbxStudentType.Items(i).Value
db.CustomerEventType.InsertOnSubmit(newCustomerEventType)
db.SubmitChanges()
End If
Next
It works fine when I checked only 1 Single ID of CustomerEventType from CheckBoxList1. It inserts data into EventType with ID 1 and CustomerEventType ID 1. However, when I checked both of them, the error message said
Cannot add an entity that already exists.
Any suggestions please? Thx in advance.
Did you change the EventID before you pressed the button again. To me it looks as you did not. This would result that the code tries to insert the event with the ID 1 into the database, although, it is already there.
Maybe try increasing the event ID automatically or check whether the event is alreay present before trying to insert it.
Edit:
OK, here is what I think you want to do ... if I understood it correctly (it's in C# as I am more fluent in that language - however you should be able to easily convert the algorithm to VB - so just take it as pseudo code):
var db = new CustomerEventDataContext();
var newEvent = db.EventTypeSingleOrDefault(x => x.EventTypeId == txtEventID.Text);
if (newEvent != null) {
newEvent = new EventType();
newEvent.EventTypeId = txtEventID.Text;
db.EventType.InsertOnSubmit();
}
var chkbx = (CheckBoxList) form1.FindControl("CheckBoxList1");
for (int i = 0; i < chkbx.Items.Count; i++) {
var value = chkbxStudentType.Items(i).Value;
if (db.CustomerEventTypes.SingleOrDefault(x => x.EventTypeId == newEvent.EventTypeId) != null) {
// item already exists
} else {
var newCustomerEventType = new CustomerEventType();
newCustomerEventType.INTEVENTTYPEID = newEvent.EventTypeId;
newCustomerEventType.INTSTUDENTTYPEID = value;
db.CustomerEventType.InsertOnSubmit(newCustomerEventType);
}
}
db.SubmitChanges();
Two things I noticed:
You were adding the new EventType and then selecting the last event type based upon the id. This may not result in the item you just added.
You do not have to call SubmitChanges after each InsertOnSubmit. The DataBaseContext implementaton holds the inserted objects for you and you can reference them. Then you do a single submit to commit all changes. Note, however, in some complex circumstances a separate SubmitChanges is necessary, but this is rarely the case.