Displaying time difference in a lotus notes view - datetime

I have a computed field abc(of type Number) which holds the time difference between two dates and I have used this formula
#If(Start_time != "" & End_time != ""; #Round((ert - Untitled11)/ 3600) ; "0") ;
When I open the form, it shows me the difference in hours. Now I want the hours to be shown in a column in the view. Now in the column when I select the field as abc, it doesn't show any value in the column.
What can I do to display the hours in the view column?

After adding a field to a form in designer it is not automatically added to the documents that had been created before the field existed.
To do the calculation and add the item to the documents you have to open and save all documents or write an agent to refresh existing documents.
This agent can be a Formula agent, running on target none.
Formula: #Command([ToolsRefreshSelectedDocs]) or #Command([ToolsRefreshAllDocs])
Or it could be a LotusScript- Agent running on target All selected documents.
Code:
Dim ses as New NotesSession
Dim db as NotesDatabase
Dim dc as NotesDocumentCollection
Dim doc as NotesDocument
Set db = ses.CurrentDatabase
Set dc = db.Unprocesseddocuments
Set doc = dc.GetFirstDocument
While not doc is Nothing
Call doc.ComputeWithForm( False, False )
Call doc.Save( True, True, True )
Set doc = dc.GetNextDocument(dc)
Wend
After doing this, the item will be available in view columns.

Related

How to set a table field primary in design-time Firedac?

I want to make a not-null non-auto-inc integer my primary key, but I am unable to do so in design time with Firedac. There is no parameter for the TIntegerfield that allows me to make it primary. There is also no parameter of the TFDTable where I can choose the primary field out of all available fields.
I get that it may be possible doing it in code & combining it with my design time table but that beats the whole purpose of doing it all in design time.
Earlier I did have a auto-inc ID in my table, and this was automatically set to primary key. I deleted this field now because I need another integer to be the primary.
Also I can't find information about the primary key & TFDTable on the official Embacadero website.
It's best to experiment with this using a new table in your database and a minimal new Delphi project.
Update: See below for database DDL and Form's DFM.
You need to have your ID field marked as a primary key in your database.
After you've added an FDConnection and an FDTable to your project, select the FDTable's TableName from the drop down list. Then, click in the FDTable's IndexName field and you should find an automatically-named index on the table's Primary Key. Just select it so that the IndexName takes its value. That's all there is to it.
For the table created using the DDL below, the IndexName property of the FDTable appears as sqlite_autoindex_test_1
If you then dbl-click the FDTable and use the pop-up Fields editor to set up persistent fields on the FDTable and then select your ID field, you should find that if you examine its ProviderFlags, they should include pfInKey, which is what tells FireDAC to use the field as the table's primary key when generating the SQL to update it, do inserts, etc.
You should find that the ID field's Required field is autmatically set to True, btw.
If you want to supply the ID Field's value yourself when adding a new record, use the table's OnNewRecord to generate the ID value an assign it to the field.
DDL for test Sqlite database
create table test(
id int not null primary key,
AName nchar(12)
)
Project DFM extract
object Form2: TForm2
object DBGrid1: TDBGrid
DataSource = DataSource1
end
object DBNavigator1: TDBNavigator
DataSource = DataSource1
end
object FDConnection1: TFDConnection
Params.Strings = (
'Database=D:\aaad7\sqlite\MADB1.sqlite'
'DriverID=SQLite')
Connected = True
LoginPrompt = False
end
object DataSource1: TDataSource
DataSet = FDTable1
end
object FDTable1: TFDTable
IndexName = 'sqlite_autoindex_test_1'
Connection = FDConnection1
UpdateOptions.UpdateTableName = 'test'
TableName = 'test'
object FDTable1id: TIntegerField
FieldName = 'id'
Origin = 'id'
ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]
Required = True
end
object FDTable1AName: TWideStringField
FieldName = 'AName'
Origin = 'AName'
FixedChar = True
Size = 12
end
end
end

How should I persist validation info from validation page to upload/import page?

I am developing a spreadsheet uploader tool which creates/updates contacts, which will be added as a new option to my website.
The spreadsheet has the following columns:
Full Name
Job Title
Salutation
Qualifications
Company Name
Address Line 1
Address Line 2
Address Line 3
The database table structure is as below:
Contact(contact_id INT PK IDENTITY(1,1), fullname VARCHAR(30), jobtitle VARCHAR(100), salutation VARCHAR(100), qualifications VARCHAR(100), companyname VARCHAR(100) , address1 VARCHAR(100), address2 VARCHAR(100), address3 VARCHAR(100))
The rules are:
1. The Full name must contain at least one space (leading and/or trailing spaces will be trimmed).
2. Total length of the full name must not exceed 30 characters (including any space(s)).
3. 'Full Name' is the key field to identify an existing contact in the system. As such, raise a validation error if this field is
blank.
4. If a match is found on the 'Full Name', then the other fields of the contact will be updated with the values populated in the
spreadsheet.
5. If a match is not found on the key field, then create a new contact with the details.
6. When creating/updating a contact a value must be populated in at least one other column (in addition to the 'Full Name'), otherwise
raise a validation error.
The process:
There are two phases called 'Validation Phase' and 'Actual Upload' phase.
- When the spreadsheet is uploaded the spreadsheet has to be validated as per the rules above and display the validation/status messages (on screen):
For example:
Row 1 is the header row so it will not be validated.
Row 2: Error - Full Name cannot be empty
Row 3: OK - A contact will be created
Row 4: OK - Contact will be updated
Row 5: Error - Full Name must contain at least one space
Row 6: Error - At least one other column must be populated in addition to the 'Full Name'
The user will have two options here:
Cancel - Then the upload will not be proceeded any further (so the user will have a choice to correct the rows as per validation messages then re-upload it).
Continue - Then the upload will move to 'Actual Upload' phase and the contacts will either be created or updated (if there are no validation errors as per the rules above).
Also, the validation/status message (similar to the messages in validation phase) should be displayed on screen after the successful upload.
I have managed to work out everything I had illustrated above, but I had to re-validate each row in 'Actual Upload' phase (i.e. I'm doing the same checks twice).
My question is, is there a way to preserve the results from the validation phase so I don't have to re-validate each record in the second phase?
I'm develioping this using the NativeExcel libraries on .NET Framework (Version 4.0.30319.34209) using VB.NET/ASP.NET (and No VISUAL STUDIO).
Please note all the code will be written in the code-behind page using VB.NET (I have no choice here, sorry).
Any suggestions/help will be much appreciated.
Save the validation status messages as a List(Of String) and then make that a session variable so that you can use it as a prompt during the upload phase.
To read the Excel file:
right-click References>COM>Office xx.x Object Application
Microsoft.Office.Interop.Excel.Application exlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook exlWb = exlApp.Workbooks.Open(#"C:\Users\user\Excelfile.xls");
Microsoft.Office.Interop.Excel.Worksheet exlWs = exlWb.Sheets["Sheet1"];
int col = Convert.ToInt32(usedRange.Columns.Count);
int row = Convert.ToInt32(usedRange.Rows.Count);
exlApp.Visible = true;
string[,] cellValue = new string[row + 1, col + 1];
for (int j = 1; j <= row - 1; j++)
{
for (int k = 1; k <= col - 1; k++)
{
cellValue[j, k] = exlWs.Cells[j, k + 1].ToString();
}
}
exlWb.Close();
exlWs = null;
exlWb = null;
exlApp.Quit();
exlApp = null;

Difference between two date/time fields - Lotus Notes

I have three editable date/time fields which the first two is (field1 and field2), style: Calendar/time control. Both of them are showing the time: hour and minutes, eg: 15:51.
The third field also (editable) which I want to show the difference between field1 and field2.
Eg: If field1 is 14:41 and field2 is 14:30, then field3 = 00:11. I've tried field1-field2 but isn't working. The form has automatic refresh fields property. Thanks!
Your third field needs to be computed, not editable.
If it HAS to be editable for some reason, and you want it to update when the other two fields are changed, do this:
Create a new field and make it computed-for-display and hidden. Give it a formula like this
#If(field1=null | field2=null; #Return(""); "");
seconds := field1-field2;
hours := #Integer(seconds/3600);
minutes := #Modulo(#Integer(seconds/60); 60);
output := #Right("00" + #Text(hours); 2) + ":" + #Right("00" + #Text(minutes); 2);
#setfield("field3"; output);
#Command([ViewRefreshFields]);
""
Phil
I wrote this code, much easier...
Fields 'StartTime' and 'EndTime':
Type Date/Time, use Calendar/Time control, set it to only display time.
Check the property "Run Exiting/OnChange events after value changes".
The Exiting event should look like this:
Sub Exiting(Source As Field)
Call UpdateDuration()
End Sub
Field 'Duration':
Editable text field, but hidden.
Field 'dspDuration':
Computed for display text field. Value is just "Duration" (no quotes).
Then add the following code to the forms Global section:
Sub UpdateDuration()
Dim ws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim starttime As NotesDateTime
Dim endtime As NotesDateTime
Dim duration As Integer
Set uidoc = ws.CurrentDocument
'*** Exit if not both times are entered
If uidoc.FieldGetText("StartTime") = "" Then
Exit Sub
Elseif uidoc.FieldGetText("StartTime") = "" Then
Exit Sub
End If
'*** Calculate duration in seconds and update field
Set starttime = New NotesDateTime( uidoc.FieldGetText("StartTime") )
Set endtime = New NotesDateTime( uidoc.FieldGetText("EndTime") )
duration = endtime.TimeDifference( starttime )
Call uidoc.FieldSetText("Duration", Cstr(duration) )
Call uidoc.Refresh()
End Sub
That's it. Easy, isn't it? If you want to modify the output (duration), you can easily do that, perhaps change it into minutes by diving it by 60.
Make sure you are getting the difference between two date time fields. If you need to, you can use the #TextToTime formula to convert text to a datetime type.
Then just subtract the first date from the second date and you'll get the difference in seconds.
Then divide that by 60 to get the difference in minutes.

Using a Repeater with a dynamically generated table, ie, so unknown field names

I'm trying to produce a repeater showing amounts of money taken by various payment types into a table.
Payment types available come from a global settings file as an array, I am creating a dataTable by looping this list and extracting sales reports (there might be a more efficient way than this loop, but this is not my concern at the minute).
My question: How do I bind this to a repeater and display it when I dont necessarily know the table column names?
I've tried various methods to give the table a header row and give the columns numerical names from a for > next loop, but am either getting no results, or
System.Data.DataRowView' does not contain a property with the name '7'. < or whatever number
This is where I currently am:
EDIT: JUST REALISED MY CODE WAS AWFUL, SO UPDATED:
Dim paymentTable As New DataTable("paymentTable")
For j = 0 To UBound(paymentTypes)
Dim Type = Trim(paymentTypes(j))
Dim headers As DataColumn = New DataColumn(j.ToString)
paymentTable.Columns.Add(headers)
Next
Dim titleRow As DataRow = paymentTable.NewRow()
For k = 0 To UBound(paymentTypes)
Dim Type = Trim(paymentTypes(k))
titleRow.Item(k) = Type
Next
paymentTable.Rows.Add(titleRow)
Dim newRow As DataRow = paymentTable.NewRow()
For i = 0 To UBound(paymentTypes)
Dim Type = Trim(paymentTypes(i))
Try
newRow.Item(i) = '' GO OFF AND GET STUFF FROM DB
Catch
newRow.Item(i) = "0 "
End Try
Next
paymentTable.Rows.Add(newRow)
THIS EDITED CODE WORKS BUT I ONLY GET ONE ITEM
What I was hoping for would look something like:
card | cash | paypal ... etc (headings row)
£250 | £54 | £78 ... etc (values row)
Obviously there're a million ways this can be done, but this makes sense for my application, which has to be expandable and contractable depending on payment types available and this whole table needs to be repeated for multiple locations (also variable depending on who's viewing, and the number of locations in the system)
No, dont give up but just dont name columns by absolute number with no string before try
Dim headers As DataColumn = New DataColumn("col"+ j.ToString)

Format XML data to display on a gridview

I am trying to format XML data to display on a grid.
Page1.aspx. This inserts XML data stored a xmldatatype:
WorkHistory workhis = js.Deserialize<WorkHistory>(json);
XmlDocument work = (XmlDocument)JsonConvert.DeserializeXmlNode(json, "root");
objBLL.insert_XMLWork(work, Convert.ToInt64(ui.id));
Page2.aspx retrieves it and display on a grid:
DataTable FBWorkDt = objBLL.get_FacebookWork(FacebookUserId);
GrdWork.DataSource = FBWorkDt;
GrdWorkPub.DataBind();
get_FacebookWork(select workinfo from Fprofiles where Userid = FacebookUserId)
returns a DataTable
It displays in this format exactly.
WorkInfo
<root><work><employer><id>208571635850052</id><name>Netizen Apps</name></employer></work><id>1076483621</id></root>
How do I make a normal display instead of XML format?
Thanks
Sun
It depends a good deal on the shape of the DataTable you're returning, but assuming you want the display to be something like this:
`ID Name
-------------------- ---------------------
208571635850052 Netizen Apps`
You could use LINQ:
DataTable FBWorkDt = objBLL.get_FacebookWork(FacebookUserId);
var query = from x in FBWorkDt.AsEnumerable()
select new {
id = x.ID,
name = x.Name
};
GrdWork.DataSource = query.ToList();
GrdWorkPub.DataBind();
I haven't tried the code out, so there may be minor syntatic changes, but essentially what it's doing is:
Use LINQ to get a collection of a new anonymous type that has one entry per row with the id and name from the table. You have to use AsEnumerable() [contained in System.Data.DataSetExtensions].
Convert the LINQ result set to a List via .ToList() and bind it to the GridView.
If you can post a little more information - what exactly you mean by display, and the expected shape of the returned DataTable (i.e., what the columns in each row are) we can give you a better answer.
UPDATE
If you're storing the XML document above in your datastore and that is being returned in the table, try this code:
DataTable FBWorkDt = objBLL.get_FacebookWork(FacebookUserId);
XDocument xDoc = XDocument.Load(FBWorkDt.Rows[0][0].ToString());
var query = from x in xDoc.Descendants("employer")
select new
{
id = (string)x.Element("id"),
name = (string)x.Element("name")
}
GrdWork.DataSource = query.ToList();
GrdWorkPub.DataBind();
Same basic principal as above, except this time your querying over an XDocument instead of a DataTable.

Resources