source: trunk/Ean.pas

Last change on this file was 12, checked in by chronos, 13 days ago
  • Added: Min/max interval position navigation buttons.
  • Modified: Remember last interval position.
File size: 10.5 KB
Line 
1unit Ean;
2
3interface
4
5uses
6 Classes, SysUtils, Generics.Collections, Generics.Defaults, DateUtils, DOM,
7 XML, SpotPrice;
8
9type
10
11 { TEanValue }
12
13 TEanValue = record
14 Time: TDateTime;
15 ValueIn: Currency;
16 ValueOut: Currency;
17 class function Create(Time: TDateTime; ValueIn, ValueOut: Currency): TEanValue; static;
18 function GetShared: Double;
19 procedure LoadFromXmlNode(Node: TDOMNode);
20 procedure SaveToXmlNode(Node: TDOMNode);
21 end;
22
23 { TEanValues }
24
25 TEanValues = class(TList<TEanValue>)
26 function Comparer(constref Left, Right: TEanValue): Integer;
27 procedure LoadFromXmlNode(Node: TDOMNode);
28 procedure SaveToXmlNode(Node: TDOMNode);
29 end;
30
31 TEanKind = (ekSupply, ekConsumption);
32
33 { TEan }
34
35 TEan = class
36 Number: string;
37 Owner: string;
38 Address: string;
39 DistributionTariff: string;
40 PriceLow: Double;
41 PriceHigh: Double;
42 PriceSpot: Double;
43 Values: TEanValues;
44 Kind: TEanKind;
45 function GetTotalIn(TimeFrom, TimeTo: TDateTime): Double;
46 function GetTotalOut(TimeFrom, TimeTo: TDateTime): Double;
47 function GetShared(TimeFrom, TimeTo: TDateTime): Double;
48 function GetSharedPercent(TimeFrom, TimeTo: TDateTime): Double;
49 function GetSavings(TimeFrom, TimeTo: TDateTime; SpotPrices: TSpotPrices): Currency;
50 function GetPrice(TimeFrom, TimeTo: TDateTime; SpotPrices: TSpotPrices; MinPrice: Currency): Currency;
51 procedure LoadFromXmlNode(Node: TDOMNode);
52 procedure SaveToXmlNode(Node: TDOMNode);
53 constructor Create;
54 destructor Destroy; override;
55 end;
56
57 { TEans }
58
59 TEans = class(TObjectList<TEan>)
60 function GetMaxTime: TDateTime;
61 function GetMinTime: TDateTime;
62 function SearchByNumber(Number: string): TEan;
63 function SearchByOwnerKind(Owner: string; Kind: TEanKind): TEan;
64 procedure LoadToStrings(Strings: TStrings; AllowNone: Boolean = False);
65 procedure LoadFromXmlNode(Node: TDOMNode);
66 procedure SaveToXmlNode(Node: TDOMNode);
67 end;
68
69var
70 EanKindText: array[TEanKind] of string;
71
72procedure Translate;
73
74const
75 EansName = 'Eans';
76 EanName = 'Ean';
77 EanValueName = 'EanValue';
78 EanValuesName = 'EanValues';
79 FifteenMinute = 15 * OneMinute;
80
81
82implementation
83
84resourcestring
85 SSupply = 'Supply';
86 SConsumption = 'Consumption';
87
88procedure Translate;
89begin
90 EanKindText[ekSupply] := SSupply;
91 EanKindText[ekConsumption] := SConsumption;
92end;
93
94{ TEanValue }
95
96class function TEanValue.Create(Time: TDateTime; ValueIn, ValueOut: Currency
97 ): TEanValue;
98begin
99 Result.Time := Time;
100 Result.ValueIn := ValueIn;
101 Result.ValueOut := ValueOut;
102end;
103
104function TEanValue.GetShared: Double;
105begin
106 if ValueIn <> 0 then Result := (1 - ValueOut / ValueIn) * 100
107 else Result := 0;
108end;
109
110procedure TEanValue.LoadFromXmlNode(Node: TDOMNode);
111begin
112 Time := ReadDateTime(Node, 'Time', Time);
113 ValueIn := ReadCurrency(Node, 'ValueIn', 0);
114 ValueOut := ReadCurrency(Node, 'ValueOut', 0);
115end;
116
117procedure TEanValue.SaveToXmlNode(Node: TDOMNode);
118begin
119 if Time <> 0 then WriteDateTime(Node, 'Time', Time);
120 if ValueIn <> 0 then WriteCurrency(Node, 'ValueIn', ValueIn);
121 if ValueOut <> 0 then WriteCurrency(Node, 'ValueOut', ValueOut);
122end;
123
124{ TEanValues }
125
126function TEanValues.Comparer(constref Left, Right: TEanValue): Integer;
127begin
128 Result := CompareDateTime(Left.Time, Right.Time);
129end;
130
131procedure TEanValues.LoadFromXmlNode(Node: TDOMNode);
132var
133 Node2: TDOMNode;
134 EanValue: TEanValue;
135begin
136 Node2 := Node.FirstChild;
137 while Assigned(Node2) and (Node2.NodeName = EanValueName) do begin
138 EanValue.LoadFromXmlNode(Node2);
139 Add(EanValue);
140 Node2 := Node2.NextSibling;
141 end;
142end;
143
144procedure TEanValues.SaveToXmlNode(Node: TDOMNode);
145var
146 Node2: TDOMNode;
147 I: Integer;
148begin
149 for I := 0 to Count - 1 do begin
150 Node2 := Node.OwnerDocument.CreateElement(EanValueName);
151 Items[I].SaveToXmlNode(Node2);
152 Node.AppendChild(Node2);
153 end;
154end;
155
156{ TEan }
157
158function TEan.GetTotalIn(TimeFrom, TimeTo: TDateTime): Double;
159var
160 I: Integer;
161begin
162 Result := 0;
163 for I := 0 to Values.Count - 1 do
164 if (Values[I].Time >= TimeFrom) and (Values[I].Time < TimeTo) then
165 Result := Result + Values[I].ValueIn;
166end;
167
168function TEan.GetTotalOut(TimeFrom, TimeTo: TDateTime): Double;
169var
170 I: Integer;
171begin
172 Result := 0;
173 for I := 0 to Values.Count - 1 do
174 if (Values[I].Time >= TimeFrom) and (Values[I].Time < TimeTo) then
175 Result := Result + Values[I].ValueOut;
176end;
177
178function TEan.GetShared(TimeFrom, TimeTo: TDateTime): Double;
179var
180 TotalIn: Double;
181 TotalOut: Double;
182begin
183 TotalIn := GetTotalIn(TimeFrom, TimeTo);
184 TotalOut := GetTotalOut(TimeFrom, TimeTo);
185 Result := TotalIn - TotalOut;
186end;
187
188function TEan.GetSharedPercent(TimeFrom, TimeTo: TDateTime): Double;
189var
190 TotalIn: Double;
191 TotalOut: Double;
192begin
193 TotalIn := GetTotalIn(TimeFrom, TimeTo);
194 TotalOut := GetTotalOut(TimeFrom, TimeTo);
195 Result := (1 - TotalOut / TotalIn) * 100;
196end;
197
198function TEan.GetSavings(TimeFrom, TimeTo: TDateTime; SpotPrices: TSpotPrices): Currency;
199var
200 TotalIn: Double;
201 TotalOut: Double;
202 I: Integer;
203 SpotPrice: TSpotPrice;
204 SpotPriceIndex: Integer;
205begin
206 if PriceLow = 0 then begin
207 Result := 0;
208 for I := 0 to Values.Count - 1 do
209 if (Values[I].Time >= TimeFrom) and (Values[I].Time < TimeTo) then begin
210 SpotPriceIndex := SpotPrices.SearchByTime(Values[I].Time);
211 if SpotPriceIndex <> -1 then
212 Result := Result + (Values[I].ValueIn - Values[I].ValueOut) * (SpotPrices[SpotPriceIndex].Value - PriceSpot);
213 end;
214 end else begin
215 TotalIn := GetTotalIn(TimeFrom, TimeTo);
216 TotalOut := GetTotalOut(TimeFrom, TimeTo);
217 Result := (TotalIn - TotalOut) * PriceLow;
218 end;
219end;
220
221function TEan.GetPrice(TimeFrom, TimeTo: TDateTime; SpotPrices: TSpotPrices; MinPrice: Currency): Currency;
222var
223 I: Integer;
224 SpotPriceIndex: Integer;
225 SpotPrice: Currency;
226begin
227 if PriceLow = 0 then begin
228 Result := 0;
229 for I := 0 to Values.Count - 1 do
230 if (Values[I].Time >= TimeFrom) and (Values[I].Time < TimeTo) then begin
231 SpotPriceIndex := SpotPrices.SearchByTime(Values[I].Time);
232 if (SpotPriceIndex <> -1) then begin
233 SpotPrice := SpotPrices[SpotPriceIndex].Value - PriceSpot;
234 if SpotPrice > MinPrice then
235 Result := Result + Values[I].ValueIn * SpotPrice;
236 end;
237 end;
238 end else Result := GetTotalIn(TimeFrom, TimeTo) * PriceLow;
239end;
240
241procedure TEan.LoadFromXmlNode(Node: TDOMNode);
242var
243 NewNode: TDOMNode;
244begin
245 Number := ReadString(Node, 'Number', Number);
246 Owner := ReadString(Node, 'Owner', Owner);
247 Address := ReadString(Node, 'Address', Address);
248 DistributionTariff := ReadString(Node, 'DistributionTariff', DistributionTariff);
249 PriceLow := ReadDouble(Node, 'PriceLow', PriceLow);
250 PriceHigh := ReadDouble(Node, 'PriceHigh', PriceHigh);
251 PriceSpot := ReadDouble(Node, 'PriceSpot', PriceSpot);
252 Kind := TEanKind(ReadInteger(Node, 'Kind', Integer(Kind)));
253
254 NewNode := Node.FindNode(EanValuesName);
255 if Assigned(NewNode) then
256 Values.LoadFromXmlNode(NewNode);
257end;
258
259procedure TEan.SaveToXmlNode(Node: TDOMNode);
260var
261 NewNode: TDOMNode;
262begin
263 if Number <> '' then WriteString(Node, 'Number', Number);
264 if Owner <> '' then WriteString(Node, 'Owner', Owner);
265 if Address <> '' then WriteString(Node, 'Address', Address);
266 if DistributionTariff <> '' then WriteString(Node, 'DistributionTariff', DistributionTariff);
267 if PriceLow <> 0 then WriteDouble(Node, 'PriceLow', PriceLow);
268 if PriceHigh <> 0 then WriteDouble(Node, 'PriceHigh', PriceHigh);
269 if PriceSpot <> 0 then WriteDouble(Node, 'PriceSpot', PriceSpot);
270 WriteInteger(Node, 'Kind', Integer(Kind));
271
272 if Values.Count > 0 then begin
273 NewNode := Node.OwnerDocument.CreateElement(EanValuesName);
274 Node.AppendChild(NewNode);
275 Values.SaveToXmlNode(NewNode);
276 end;
277end;
278
279constructor TEan.Create;
280begin
281 Values := TEanValues.Create;
282end;
283
284destructor TEan.Destroy;
285begin
286 FreeAndNil(Values);
287 inherited;
288end;
289
290{ TEans }
291
292function TEans.GetMaxTime: TDateTime;
293var
294 I: Integer;
295 Found: Boolean;
296begin
297 Found := False;
298 for I := 0 to Count - 1 do
299 with Items[I] do
300 if Values.Count > 0 then begin
301 if not Found then begin
302 Result := Values[Values.Count - 1].Time;
303 Found := True;
304 end
305 else if Values[Values.Count - 1].Time > Result then begin
306 Result := Values[Values.Count - 1].Time;
307 end;
308 end;
309 if not Found then Result := Now;
310end;
311
312function TEans.GetMinTime: TDateTime;
313var
314 I: Integer;
315 Found: Boolean;
316begin
317 Found := False;
318 for I := 0 to Count - 1 do
319 with Items[I] do
320 if Values.Count > 0 then begin
321 if not Found then begin
322 Result := Values[0].Time;
323 Found := True;
324 end
325 else if Values[0].Time < Result then begin
326 Result := Values[0].Time;
327 end;
328 end;
329 if not Found then Result := Now;
330end;
331
332function TEans.SearchByNumber(Number: string): TEan;
333var
334 I: Integer;
335begin
336 I := 0;
337 while (I < Count) and (Items[I].Number <> Number) do Inc(I);
338 if I < Count then Result := Items[I]
339 else Result := nil;
340end;
341
342function TEans.SearchByOwnerKind(Owner: string; Kind: TEanKind): TEan;
343var
344 I: Integer;
345begin
346 I := 0;
347 while (I < Count) and ((Items[I].Owner <> Owner) or (Items[I].Kind <> Kind)) do Inc(I);
348 if I < Count then Result := Items[I]
349 else Result := nil;
350end;
351
352procedure TEans.LoadToStrings(Strings: TStrings; AllowNone: Boolean = False);
353var
354 I: Integer;
355 Shift: Integer;
356 Text: string;
357begin
358 if AllowNone then Shift := 1 else Shift := 0;
359 Strings.BeginUpdate;
360 try
361 while Strings.Count > Count + Shift do Strings.Delete(Strings.Count - 1);
362 while Strings.Count < Count + Shift do Strings.Add('');
363 for I := 0 to Count - 1 do begin
364 Text := EanKindText[Items[I].Kind];
365 if Items[I].Address <> '' then Text := Items[I].Address + ', ' + Text;
366 if Items[I].Owner <> '' then Text := Items[I].Owner + ', ' + Text;
367 Text := Items[I].Number + ' (' + Text + ')';
368 Strings[I + Shift] := Text;
369 Strings.Objects[I + Shift] := Items[I];
370 end;
371 finally
372 Strings.EndUpdate;
373 end;
374end;
375
376procedure TEans.LoadFromXmlNode(Node: TDOMNode);
377var
378 Node2: TDOMNode;
379 Ean: TEan;
380begin
381 Node2 := Node.FirstChild;
382 while Assigned(Node2) and (Node2.NodeName = EanName) do begin
383 Ean := TEan.Create;
384 Ean.LoadFromXmlNode(Node2);
385 Add(Ean);
386 Node2 := Node2.NextSibling;
387 end;
388end;
389
390procedure TEans.SaveToXmlNode(Node: TDOMNode);
391var
392 Node2: TDOMNode;
393 I: Integer;
394begin
395 for I := 0 to Count - 1 do begin
396 Node2 := Node.OwnerDocument.CreateElement(EanName);
397 Items[I].SaveToXmlNode(Node2);
398 Node.AppendChild(Node2);
399 end;
400end;
401
402end.
403
Note: See TracBrowser for help on using the repository browser.