E2029 delphi: ')' expected, but ',' found - oop

Compiler say that's wrong, why?
procedure TForm1.Button2Click(Sender: TObject);
Var
IniOrb, CurOrb : TOrbitData;
Orb : TOrbitData;
KepEl: TKepEl;
Cart: TCartesian;
Geo: TGeo;
D, T : TdateTime;
Epoch : TdateTime;
Time : real;
x, y, xstep : real;
begin
Dat := Frac( DateTimePicker1.Time );
Tim := Trunc ( DateTimePicker2.Date );
Epoch := D + T;
IniOrb := InitOrbit( Epoch, 1000, 0, 0, 0, 0, 60 * cToRad );
Time := 60;
Repeat
CurOrb := TOrbitData(Time, KepEl, Cart, Geo);
^
')' expected but ',' found
That's a record:
type TOrbitData = record // full orbit data
Epoch : TDateTime;
KepEl : TKepEl;
Cart : TCartesian;
Geo : TGeo;
end;
Error on the semicolon: ')' expected, but ';' found. What's wrong?

You cannot construct an instance of a record the way you are trying to.
But, you can add a constructor to your record type, eg:
type
TOrbitData = record // full orbit data
Epoch : TDateTime;
KepEl : TKepEl;
Cart : TCartesian;
Geo : TGeo;
constructor Create(AEpoch: TDateTime; AKepEl: TKepEl; ACart: TCartesian; AGeo: TGeo);
end;
constructor TOrbitData.Create(AEpoch: TDateTime; AKepEl: TKepEl; ACart: TCartesian; AGeo: TGeo);
begin
Epoch := AEpoch;
KepEl := AKepEl;
Cart := ACart;
Geo := AGeo;
end;
And then you can use it like this:
CurOrb := TOrbitData.Create(Time, KepEl, Cart, Geo);
Otherwise, you will have to define a standalone function to return an initialized instance of your record, like you did with InitOrbit().

Related

How to sum 1+2^2+3^3+...n^n in pascal?

I want to sum that thing but only use the 'for loop' (no power functions). I've already created a loop that generates powers:
Program powers;
Var
i, n, result : integer;
writeln('enter N'), read(n);
BEGIN
Result := 1;
for i := 1 to n do
begin
Result := Result * n;
end;
writeln('result=',result);
END.
But I neither have any idea on how to make that code generate multiple powers ( this code only generates n^n) nor how to make a loop that sums them together.
It's best to break problems down into smaller problems. In this case, you may wish to have a pow function to handle the exponentiation for you.
Hopefully the pow function is acceptable if it's not a library function.
function pow(n, exp : integer) : integer;
var
i, result : integer;
begin
result := n;
for i := 2 to exp do
result := result * n;
pow := result;
end;
Then the main portion of your program is simpler.
program powers;
var
n, i, sum : integer;
function pow(n, exp : integer) : integer;
var
i, result : integer;
begin
result := n;
for i := 2 to exp do
result := result * n;
pow := result;
end;
begin
sum := 0;
write('enter N:');
readln(n);
for i := 0 to n do
sum := sum + pow(i, i);
writeln('result=', sum);
end.
Now that I finally understand what you're asking, please try this:
Program powers;
Var
i, j, n, p, result : integer;
BEGIN
write('enter N:');
readln(n);
Result := 0;
for i := 1 to n do
begin
p := 1;
for j := 1 to i do
p := p * i;
Result := Result + p;
end;
writeln('result=', result);
END.

Does HelpNDoc Pascal Script support structures?

I am trying to create a structure:
MyTopic
TopicID : String;
HelpID : Integer;
I wanted to create an array of these structures so I could sort them.
I have tried using this type / record syntax but it is failing.
Update
I defined this type and procedure:
type
TMyTopicRecord = record
idTopic : String;
idContextHelp : integer;
End;
procedure GetSortedTopicIDs(aTopics : array of String; size : Integer);
var
aMyTopicRecords : array of TMyTopicRecord;
temp : TMyTopicRecord;
iTopic, i, j : Integer;
begin
// Init the array
SetLength(aMyTopicRecords, size);
// Fill the array with the existing topid ids.
// Get the context ids at the same time.
for iTopic := 0 to size - 1 do
aMyTopicRecords[iTopic].idTopic := aTopics[iTopic];
aMyTopicRecords[iTopic].idContextHelp := HndTopics.GetTopicHelpContext(aTopics[iTopic]);
// Sort the array on context id
for i := size-1 DownTo 1 do
for j := 2 to i do
if (aMyTopicRecords[j-1].idContextHelp > aMyTopicRecords[j].idContextHelp) Then
begin
temp := aMyTopicRecords[j-1];
aMyTopicRecords[j-1] := aMyTopicRecords[j];
aMyTopicRecords[j] := temp;
end;
// Rebuild the original array of topic ids
for iTopic := 0 to size - 1 do
aTopics[iTopic] := aMyTopicRecords[iTopic].idTopic;
end;
The procedure gets called in a loop of the parent function (code snipped):
function GetKeywordsAsHtml(): string;
var
aKeywordList: THndKeywordsInfoArray;
aAssociatedTopics: array of string;
nBlocLevel, nDif, nClose, nCurKeywordLevel, nCurKeywordChildrenCnt: Integer;
nCurKeyword, nCurKeywordTopic: Integer;
nCountAssociatedTopics: Integer;
sCurrentKeyword, sKeywordLink, sKeywordRelated: string;
sKeywordJsCaption: string;
begin
Result := '<ul>';
nBlocLevel := 0;
try
aKeywordList := HndKeywords.GetKeywordList(False);
for nCurKeyword := 0 to length(aKeywordList) - 1 do
begin
sCurrentKeyword := aKeywordList[nCurKeyword].id;
nCurKeywordLevel := HndKeywords.GetKeywordLevel(sCurrentKeyword);
nCurKeywordChildrenCnt := HndKeywords.GetKeywordDirectChildrenCount(sCurrentKeyword);
sKeywordLink := '#';
sKeywordRelated := '[]';
aAssociatedTopics := HndTopicsKeywords.GetTopicsAssociatedWithKeyword(sCurrentKeyword);
nCountAssociatedTopics := Length(aAssociatedTopics);
if nCountAssociatedTopics > 0 then
begin
GetSortedTopicIDs(aAssociatedTopics, nCountAssociatedTopics);
// Code snipped
end;
end;
finally
Result := Result + '</ul>';
end;
end;
The script compiled in the HelpNDoc internal editor with no issues. But when I go to actually build my HTML documentation I encounter a problem:
The HelpNDoc API is explained here.
Is there something wrong with my code?
I decided to go about it a different way and used a simpler technique:
procedure GetSortedTopicIDs(var aTopics : array of String; iNumTopics : Integer);
var
iTopic : Integer;
// List of output
aList: TStringList;
begin
// Init list
aList := TStringList.Create;
// Build a new array of "nnn x"
// - nnn is the help context id
// - x is the topid id
// Note: I know that the context ID values are within the range 0 - 200
for iTopic := 0 to iNumTopics - 1 do
// We pad the context id with 0. We could increase the padding width to
// make the script mre useful
aList.Add(Format('%0.3d %s', [
HndTopics.GetTopicHelpContext(aTopics[iTopic]),
aTopics[iTopic]
]));
// Now we sort the new array (which basically sorts it by context id)
aList.Sort;
// Update original array
for iTopic := 0 to iNumTopics - 1 do
// We ignore the "nnn " part of the string to get just the topic id
aTopics[iTopic] := copy(aList[iTopic],5, length(aList[iTopic])-4);
// Tidy up
aList.Free;
end;
This compiles and I get the sorted array of topic IDs at the end of it. So the pop-up help is now listed as I want.

Implement an interface with class wide operations in Ada 95

I'm creating a program with Ada 95 and I have a problem. Specifically, I'm trying to implement a class which executes functors given as parameters.
The behavior I want to achieve is:
Declare an interface IF with a procedure Execute.
Derive from IF with a class C and implement Execute.
Create a class D which has a field that is an array of IF. Since IF cannot be instantiated, I use an array of access IF.
Instantiate an object of class D giving it several instances of C as parameters.
Call Execute on every instance of C contained in the array of D.
I've been able to implement the above and compile it, but when I execute it I obtain the error accessibility check failed when trying to assign an object of class C to a component of the array in D.
I know that the error I obtain is because the assignment I'm doing can lead to a danging pointer error according to the Ada policies, so my question is what is the proper way to implement this in Ada 95?
The source code is below. The error is raised in the file elevators.adb, in the procedure Add_Event_Handler, I have commented the statement that causes it.
Functors.ads
package Functors is
type IFunctor is abstract tagged null record;
procedure Execute(Self : in out IFunctor) is abstract;
end Functors;
Elevators.ads
with Functors; use Functors;
package Elevators is
NOT_A_FLOOR : constant := -1;
MAX_EVENT_HANDLERS : constant := 255;
type Floor is new Integer range NOT_A_FLOOR .. 4;
type Elevator is private;
subtype Event_Handler is IFunctor'Class; --'
type Event_Handler_Index is new Integer range 0 .. MAX_EVENT_HANDLERS;
type Event_Handers is array(Event_Handler_Index) of access Event_Handler;
function Create_Elevator return Elevator;
procedure Add_Stop_Handler(Self : in out Elevator; Handler : access Event_Handler);
procedure Add_Moving_Handler(Self : in out Elevator; Handler : access Event_Handler);
procedure Add_Called_Handler(Self : in out Elevator; Handler : access Event_Handler);
procedure Add_Button_Pressed_Handler(Self : in out Elevator; Handler : access Event_Handler);
procedure Run_Simulation(Self : in out Elevator);
private
type Elevator is
record
Current_Floor : Floor := 0;
Is_Moving : Boolean := False;
Next_Floor : Floor := NOT_A_FLOOR;
Stop : Event_Handers := (others => null);
Moving : Event_Handers := (others => null);
Called : Event_Handers := (others => null);
Button_Pressed : Event_Handers := (others => null);
end record;
procedure On_Stop(Self : in out Elevator);
procedure On_Moving(Self : in out Elevator);
procedure On_Called(Self : in out Elevator);
procedure On_Button_Pressed(Self : in out Elevator);
procedure Add_Event_Handler(Self : out Event_Handers; Handler : access Event_Handler);
procedure Exec_All_Events(Self : in out Elevator; EH : in Event_Handers);
end Elevators;
Elevators.adb
with Ada.Text_IO; use Ada.Text_IO;
package body Elevators is
function Create_Elevator return Elevator is
elev : Elevator;
begin
return elev;
end;
procedure Add_Stop_Handler(self : in out Elevator; Handler : access Event_Handler) is
begin
Add_Event_Handler(self.Stop, Handler);
end;
procedure Add_Moving_Handler(self : in out Elevator; Handler : access Event_Handler) is
begin
Add_Event_Handler(self.Moving, Handler);
end;
procedure Add_Called_Handler(self : in out Elevator; Handler : access Event_Handler) is
begin
Add_Event_Handler(self.Called, Handler);
end;
procedure Add_Button_Pressed_Handler(self : in out Elevator; Handler : access Event_Handler) is
begin
Add_Event_Handler(self.Button_Pressed, Handler);
end;
procedure Run_Simulation(self : in out Elevator) is
begin
Put_Line("Floor: " & Floor'Image(self.Current_Floor)); --'
self.Next_Floor := 3;
On_Called(self);
On_Moving(self);
On_Stop(self);
end;
procedure On_Stop(self : in out Elevator) is
begin
self.Current_Floor := self.Next_Floor;
self.Is_Moving := False;
self.Next_Floor := NOT_A_FLOOR;
Put_Line("Stopped. Current floor = " & Floor'Image(self.Current_Floor)); --'
Exec_All_Events(self, self.Stop);
end;
procedure On_Moving(self : in out Elevator) is
begin
self.Is_Moving := True;
self.Current_Floor := NOT_A_FLOOR;
Put_Line("Moving to floor " & Floor'Image(self.Next_Floor)); --'
Exec_All_Events(self, self.Moving);
end;
procedure On_Called(self : in out Elevator) is
begin
Put_Line("Calling button pressed (" & Floor'Image(self.Next_Floor) & ")..."); --'
Exec_All_Events(self, self.Moving);
end;
procedure On_Button_Pressed(self : in out Elevator) is
begin
null;
end;
procedure Add_Event_Handler(Self : out Event_Handers; Handler : access Event_Handler) is
I : Event_Handler_Index := Event_Handler_Index'First; --'
begin
while I < Event_Handler_Index'Last loop --'
if Self(I) = null then
Self(I) := Handler; -- ======> The error is raised here <======
exit;
end if;
I := I + 1;
end loop;
end;
procedure Exec_All_Events(self : in out Elevator; EH : in Event_Handers) is
I : Event_Handler_Index := Event_Handler_Index'First; --'
begin
while I < Event_Handler_Index'Last loop --'
if EH(I) /= null then
EH(I).Execute;
end if;
I := I + 1;
end loop;
end;
end Elevators;
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Functors; use Functors;
with Elevators; use Elevators;
procedure Main is
type My_Functor is new IFunctor with
record
I : Integer := 0;
end record;
overriding
procedure Execute(Self : in out My_Functor) is
begin
Put_Line("Executing functor, I is " & Integer'Image(Self.I)); --'
Self.I := Self.I + 1;
end;
Generic_Functor : aliased My_Functor;
Elev : Elevator := Create_Elevator;
begin
Add_Stop_Handler(elev, Generic_Functor'Access); --'
Add_Moving_Handler(elev, Generic_Functor'Access); --'
Add_Called_Handler(elev, Generic_Functor'Access); --'
Run_Simulation(Elev);
end;
EDIT
I have done the following changes in order to fix the mentioned runtime error, but I still obtain the accessibility check failed.
elevators.ads
...
type Event_Handler_Generic_Ptr is access all Event_Handler;
type Event_Handers is array(Event_Handler_Index) of Event_Handler_Generic_Ptr;
...
elevators.adb
procedure Add_Event_Handler(Self : out Event_Handers; Handler : access Event_Handler) is
I : Event_Handler_Index := Event_Handler_Index'First; --'
begin
while I < Event_Handler_Index'Last loop --'
if Self(I) = null then
-- Notice the casting here
Self(I) := Event_Handler_Generic_Ptr(Handler); -- ======> The error is raised here <======
exit;
end if;
I := I + 1;
end loop;
end;
Since you store a pointer generated with 'Access in Event_Handlers, you must declare it with access all, so that it is a general access type:
type Event_Handers is array(Event_Handler_Index) of access all Event_Handler;
If you miss all, it is a pool-specific access type. See Ada 95 RM, 3.10 Access Types, (8) and (10). pool-specific access types may only hold pointers to objects allocated in a storage pool, which your object is not.

IBQuery insert - Column unknown / Unsupported feature

Im trying to insert a row into a firebird database (embedded), but geting an exception when calling:
datamodule1.IBQuery1.prepare
Project xyz.exe raised exception class EIBInterBaseError with message
'Dynamic SQL Error SQL error code = -206 Column unknown INDEX_ At
line, column 25'.
with datamodule1.IBQuery1 do
begin
close;
With SQL do
begin
clear;
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
Add( 'VALUES (:eventindex, :state_, :event_, :param_, :date_, :time_, :devid_, :gateway_') );
end;
//
GeneratorField.Field := 'Nr_';
GeneratorField.Generator := 'GEN_MST_EVENTS_ID';
//
Params[0].AsInteger := FMst.EventRecordIndex;
Params[1].AsSmallInt := FMst.EventRecordState;
Params[2].AsString := eventToStr(FMst.EventRecordEvent);
Params[3].AsSmallInt := 0;
Params[4].AsDate := FMst.EventRecordDate;
Params[5].AsTime := FMst.EventRecordTime;
Params[6].AsLongWord := FMst.EventRecordDevID;
Params[7].AsString := FMst.EventRecordIP;
//
if ( prepared = false ) then
prepare; //Throws an exception here (SOLVED)
execSQL; //Now getting exception here
end;
I have the following components tied together:
IBDatabase
IBTransaction
DataSource
IBQuery
Above problem solved - Edit >>
Ok, i have changed
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
to
Add( 'INSERT INTO MST_EVENTS ("eventindex", "state_", "event_", "param_", "date_", "time_", "devID_", "gateway_")' );
... (so im using quotation marks) and now it finds the fields, but get another exception at line:
IBQuery1.execSQL:
Exception class EIBClientError with message 'Unsupported feature'
My fields are:
Nr_ : INTEGER
eventindex : INTEGER
state_ : SMALLINT
event_ : VARCHAR(50)
param_ : SMALLINT
date_ : DATE
time_ : TIME
devID_ : BIGINT
gateway_ : VARCHAR(50)
Firebird version is 2.5 embedded 32bit
I took out all the string and date/time parameters, yet i get the exception.
Using IBExpert and the same client/server .dll i can insert the row flawlessly (using all the values).
The solution was changing line
Params[6].AsLongWord := FMst.EventRecordDevID;
to
Params[6].AsLargeInt := FMst.EventRecordDevID;
But please how to auto-increment the field 'Nr_'?
with datamodule1.IBQuery1 do
begin
close;
With SQL do
begin
clear;
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
Add( 'VALUES (:eventindex, :state_, :event_, :param_, :date_, :time_, :devid_, :gateway_') );
end;
//
GeneratorField.Field := 'Nr_';
GeneratorField.Generator := 'GEN_MST_EVENTS_ID';
//
Params[0].AsInteger := FMst.EventRecordIndex;
Params[1].AsSmallInt := FMst.EventRecordState;
Params[2].AsString := eventToStr(FMst.EventRecordEvent);
Params[3].AsSmallInt := 0;
Params[4].AsDate := FMst.EventRecordDate;
Params[5].AsTime := FMst.EventRecordTime;
Params[6].AsLargeInt := FMst.EventRecordDevID;
Params[7].AsString := FMst.EventRecordIP;
//
if ( prepared = false ) then
prepare; //Throws an exception here (SOLVED)
execSQL; //Now getting exception here
end;
I made the generator in flamerobin.
But getting exception (at calling 'execSQL'):
EDIT >>
I set up a generator and a BEFORE INSERT trigger in IBExpert:
And now its ok.

Hotel prices spanning multiple dates issue

Question is somehow related to this one, with the exception that I use parameters.
I have this on my button click :
procedure TForm1.Button1Click(Sender: TObject);
begin
with ABSQuery1 do begin
ABSQuery1.Close;
ABSQuery1.SQL.Clear;
ABSQuery1.SQL.Add('select * from ROOM_RATES where CENIK_ID = :a4 and ROOM_TYPE = :A1');
ABSQuery1.SQL.Add('and rate_Start_DATE < :a3 AND rate_End_DATE > :a2 ORDER BY rate_Start_DATE ASC ');
ABSQuery1.Params.ParamByName('a1').Value:= cxLookupComboBox2.Text;
ABSQuery1.Params.ParamByName('a2').Value:= cxDateEdit1.Date;
ABSQuery1.Params.ParamByName('a3').Value := cxDateEdit2.Date;
ABSQuery1.Params.ParamByName('a4').Value := cxLookupComboBox1.Text;
ABSQuery1.Open;
end;
end;
This kind of works but not what I want actually.Problem is related to this one:
Hotel Booking Rates SQL Problem
Problem is with the overlapping dates like in the mentioned hyperlink.Right now I am getting this :
How can I obtain result similar in the mentioned hyperlink with the above example ?
This is the snapshot of the db table :
Update (NEW):
This is the code on the button click :
procedure TForm1.AdvGlowButton1Click(Sender: TObject);
var
nxt : integer;
mem_from : TDateTime;
mem_to : TDateTime;
mem_RATE_ID : integer;
mem_ROOM_TYPE : string[10];
mem_Start_DATE_1 : TDateTime;
mem_End_DATE_1 : TDateTime;
mem_RATE_Price_1 : Currency;
mem_calc_END : TDateTime;
mem_calc_DAYS : integer;
c_from : TDateTime;
c_to : TDateTime;
c_from_test : TDateTime;
c_to_test : TDateTime;
begin
ABSQuery2.Close;
ABSQuery2.SQL.Text:='DELETE from TEMP';
ABSQuery2.ExecSQL;
ABSQuery2.SQL.Text:='SELECT * from TEMP ORDER BY ID ';
ABSQuery2.Open;
c_from := cxDateEdit1.Date;
c_to := cxDateEdit2.Date;
mem_from := cxDateEdit1.Date;
mem_to := cxDateEdit2.Date;
with ABSQuery1 do begin
ABSQuery1.Close;
ABSQuery1.SQL.Clear;
ABSQuery1.SQL.Add('select * from ROOM_RATES where CENIK_ID = :a4 and ROOM_TYPE = :A1');
ABSQuery1.SQL.Add('and rate_Start_DATE < :a3 AND rate_End_DATE > :a2 ORDER BY rate_Start_DATE ASC ');
ABSQuery1.Params.ParamByName('a1').Value:= cxLookupComboBox2.Text;
ABSQuery1.Params.ParamByName('a2').Value:= cxDateEdit1.Date;
ABSQuery1.Params.ParamByName('a3').Value := cxDateEdit2.Date;
ABSQuery1.Params.ParamByName('a4').Value := cxLookupComboBox1.Text;
ABSQuery1.Open;
nxt := 1;
mem_RATE_ID := ABSQuery1.FieldByName('RATE_ID').AsInteger;
mem_ROOM_TYPE := ABSQuery1.FieldByName('ROOM_TYPE').AsString ;
mem_Start_DATE_1 := ABSQuery1.FieldByName('RATE_START_DATE').AsDateTime;
mem_End_DATE_1 := ABSQuery1.FieldByName('RATE_END_DATE').AsDateTime;
mem_RATE_Price_1 := ABSQuery1.FieldByName('RATE_PRICE').AsCurrency;
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
end;
if ABSQuery1.RecordCount > nxt then ABSQuery1.Next;
with ABSQuery2 do begin
open;
Insert;
ABSQuery2.FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
ABSQuery2.FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
ABSQuery2.FieldByName('DATE_FROM').AsDateTime:=mem_from;
ABSQuery2.FieldByName('DATE_TO').AsDateTime:= mem_to;//mem_calc_END;
ABSQuery2.FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
ABSQuery2.FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
ABSQuery2.FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end; ///////////////////////////////////////////////////////////////////
if ABSQuery1.RecordCount > nxt then begin
inc(nxt);
if mem_to < ABSQuery1.FieldByName('rate_End_DATE').AsDateTime then begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime,mem_calc_END);
end else begin
mem_calc_END := ABSQuery1.FieldByName('rate_End_DATE').AsDateTime;
mem_calc_DAYS := Daysbetween(ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime, ABSQuery1.FieldByName('rate_End_DATE').AsDateTime);
end;
mem_RATE_ID := ABSQuery1.FieldByName('RATE_ID').AsInteger;
mem_ROOM_TYPE := ABSQuery1.FieldByName('ROOM_TYPE').AsString;
mem_Start_DATE_1 := ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime;
mem_End_DATE_1 := ABSQuery1.FieldByName('rate_End_DATE').AsDateTime;
mem_Rate_Price_1 := ABSQuery1.FieldByName('RATE_PRICE').AsCurrency;
// calculation : second row.
with ABSQuery2 do begin
Insert;
FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
FieldByName('DATE_FROM').AsDateTime:=mem_Start_DATE_1;
FieldByName('DATE_TO').AsDateTime:= mem_calc_END;
FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
ABSQuery2.refresh;
end;
end;
The result I get is this :
As you can see from the database snapshot, prices are set OK.
Tested with Delphi 2010.
Your only one DBGrid, are associated with the dataset-table-pricelist
matches two rows of dataset-table-pricelist and so in your ABSQuery1 DBGrid
Row 1 from price list is shown.
Row 3 from price list is shown.
Now for both Rows procedure ABSQuery1CalcFields(DataSet: TDataSet);
is called with the same values !!
Daysbetween(cxDateEdit1.Date,cxDateEdit2.Date) = allways 19
.
procedure TForm1.ABSQuery1CalcFields(DataSet: TDataSet);
begin
ABSQuery1.FieldByName('Days').Value := IntToStr(Daysbetween(cxDateEdit1.Date,cxDateEdit2.Date));
ABSQuery1.FieldByName('TOTAL').AsCurrency :=ABSQuery1.FieldByName('Days').Value * ABSQuery1.FieldByName('RATE_PRICE').Value ;
end;
Therefore you have in your DBGrid twice Days are 19
The two fields From and To come also from the Table Price List.
Therefore, you can not see your own data From and To.
You should have 2 tables
Price list
calculation
With a loop on the table pricelist, fetch the required data of the price list.
clear calculation.
insert the data you get from Table price list.
Because I do not know exactly how your table is set up, you have to adapt the code to the database and your table.
In order to show the necessary steps better, here the following code.
Update : Here, now the complete code.
unit PriceList;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, DBGrids, Db, ZAbstractRODataset, ZAbstractDataset,
ZDataset, ZConnection;
type
TForm1 = class(TForm)
ZConnection1: TZConnection;
ABSQuery1: TZQuery;
calculation: TZQuery;
DataSource1: TDataSource;
DataSource2: TDataSource;
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
DoCalc: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
RATE_ID: TLargeintField;
CENIK_ID: TLargeintField;
ROOM_TYPE: TWideStringField;
RATE_START_DATE: TDateTimeField;
RATE_END_DATE: TDateTimeField;
RATE_PRICE: TFloatField;
calculationID: TLargeintField;
calcRATE_ID: TLargeintField;
calcROOM_TYPE: TWideStringField;
calcDFROM: TDateTimeField;
calcDTO: TDateTimeField;
calcRATE_PRICE: TFloatField;
calcDAYS: TLargeintField;
calcTOTAL: TFloatField;
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses DateUtils;
procedure TForm1.DoCalcClick(Sender: TObject);
var
nxt : integer;
mem_from : TDateTime;
mem_to : TDateTime;
mem_RATE_ID : integer;
mem_ROOM_TYPE : string[20];
mem_Start_DATE_1 : TDateTime;
mem_End_DATE_1 : TDateTime;
mem_RATE_Price_1 : Currency;
mem_calc_END : TDateTime;
mem_calc_DAYS : integer;
c_from : string[19];
c_to : string[19];
c_from_test : string[19];
c_to_test : string[19];
begin
calculation.Close;
calculation.SQL.Text:='DELETE from calculation';
calculation.ExecSQL;
calculation.SQL.Text:='SELECT * from calculation ORDER BY ID ';
calculation.Open;
c_from := Edit3.Text;
c_to := Edit4.Text;
c_from_test := copy(Edit3.Text,7,4)+'.'+copy(Edit3.Text,4,2)+'.'+copy(Edit3.Text,1,2); // From 01.01.2013
c_to_test := copy(Edit4.Text,7,4)+'.'+copy(Edit4.Text,4,2)+'.'+copy(Edit4.Text,1,2);
mem_from := StrToDateTime(c_from);
mem_to := StrToDateTime(c_to);
with ABSQuery1 do begin
Close;
SQL.Clear;
SQL.Add('select * from ROOM_RATES where CENIK_ID = "'+Edit1.Text+'" and ROOM_TYPE = "'+Edit2.Text+'"');
SQL.Add('and RATE_START_DATE < '''+c_to_test+''' AND RATE_END_DATE > '''+c_from_test+''' ORDER BY RATE_START_DATE ASC ');
Open;
nxt := 1;
mem_RATE_ID := RATE_ID.AsLargeInt;
mem_ROOM_TYPE := ROOM_TYPE.AsString ;
mem_Start_DATE_1 := RATE_START_DATE.AsDateTime;
mem_End_DATE_1 := RATE_END_DATE.AsDateTime;
mem_RATE_Price_1 := RATE_PRICE.AsCurrency;
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
end;
if ABSQuery1.RecordCount > nxt then ABSQuery1.Next;
with calculation do begin
open;
Insert;
calculation.FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
calculation.FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
calculation.FieldByName('DFROM').AsDateTime:=mem_from;
calculation.FieldByName('DTO').AsDateTime:= mem_calc_END;
calculation.FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
calculation.FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
calculation.FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
if ABSQuery1.RecordCount > nxt then begin
inc(nxt);
if mem_to < rate_End_DATE.AsDateTime then begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(rate_Start_DATE.AsDateTime,mem_calc_END);
end else begin
mem_calc_END := rate_End_DATE.AsDateTime;
mem_calc_DAYS := Daysbetween(rate_Start_DATE.AsDateTime, rate_End_DATE.AsDateTime);
end;
mem_RATE_ID := RATE_ID.AsInteger;
mem_ROOM_TYPE := ROOM_TYPE.AsString;
mem_Start_DATE_1 := rate_Start_DATE.AsDateTime;
mem_End_DATE_1 := rate_End_DATE.AsDateTime;
mem_Rate_Price_1 := RATE_PRICE.AsCurrency;
with calculation do begin
Insert;
FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
FieldByName('DFROM').AsDateTime:=mem_Start_DATE_1;
FieldByName('DTO').AsDateTime:= mem_calc_END;
FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
end;
calculation.refresh;
end;
end.
Of time constraints the code is not optimized. It is only to show the necessary steps.
TABLE room_rates
DROP TABLE IF EXISTS `room_rates`;
CREATE TABLE `room_rates` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CENIK_ID` int(10) unsigned NOT NULL,
`ROOM_TYPE` varchar(45) NOT NULL,
`RATE_START_DATE` datetime NOT NULL,
`RATE_END_DATE` datetime NOT NULL,
`RATE_PRICE` decimal(5,2) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
TABLE calculation
DROP TABLE IF EXISTS `calculation`;
CREATE TABLE `calculation` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`RATE_ID` int(10) unsigned NOT NULL,
`ROOM_TYPE` varchar(45) NOT NULL,
`DFROM` datetime NOT NULL,
`DTO` datetime NOT NULL,
`RATE_PRICE` decimal(5,2) NOT NULL,
`DAYS` int(10) unsigned NOT NULL,
`TOTAL` decimal(7,2) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Update :
Search for if mem_to > mem_End_DATE_1
To change Total 0,00€ You have to expand
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
Update 2 : above, now the complete code.
Update 3 : but still I get from 14/4/2013 to 26/4/2013 11 DAYS ! user763539
This behavior comes from DaysBetween(..,..) and not from my code.
DaysBetween is a delphi function!
I ask you 3 times .
Did you check what you get from cxDateEdit1.Date and cxDateEdit2.Date.
It must be to accurately 14-04-2013 00:00:00 and 26-04-2013 00:00:00 .
Create a new test programm.
Controlling what you get with.
DateTimeToString(formattedDateTime, 'c', cxDateEdit1.Date);
Memo1.Lines.Add(formattedDateTime);
With a loop over all ROOM_RATES records You should also check all date fields in ROOM_RATES.
DateTimeToString(formattedDateTime, 'c', ABSQuery1.FieldByName('RATE_START_DATE').AsDateTime);
Memo1.Lines.Add(formattedDateTime);
All times should be 00:00:00
For example:
DaysBetween .. 14-04-2013 12:15:10and26-04-2013 12:15:05==11 Days`
more accurately: 11 Days : 23 Hours : 59 minutes : 55 seconds.