]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp
Ticket 37. In the TariffChangeIsAllowed() function return "" added and
[stg.git] / projects / stargazer / plugins / store / postgresql / postgresql_store_tariffs.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 /*
22  *  Tariffs manipulation methods
23  *
24  *  $Revision: 1.2 $
25  *  $Date: 2009/06/09 12:32:40 $
26  *
27  */
28
29 #include <string>
30 #include <vector>
31 #include <sstream>
32 #include <cmath>
33
34 #include <libpq-fe.h>
35
36 #include "stg/common.h"
37 #include "postgresql_store.h"
38 #include "stg/locker.h"
39
40 namespace
41 {
42
43 const int pt_mega = 1024 * 1024;
44
45 }
46
47 //-----------------------------------------------------------------------------
48 int POSTGRESQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
49 {
50 STG_LOCKER lock(&mutex);
51
52 if (PQstatus(connection) != CONNECTION_OK)
53     {
54     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
55     if (Reset())
56         {
57         strError = "Connection lost";
58         printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
59         return -1;
60         }
61     }
62
63 PGresult * result;
64
65 if (StartTransaction())
66     {
67     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to start transaction'\n");
68     return -1;
69     }
70
71 result = PQexec(connection, "SELECT name FROM tb_tariffs");
72
73 if (PQresultStatus(result) != PGRES_TUPLES_OK)
74     {
75     strError = PQresultErrorMessage(result);
76     PQclear(result);
77     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
78     if (RollbackTransaction())
79         {
80         printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to rollback transaction'\n");
81         }
82     return -1;
83     }
84
85 int tuples = PQntuples(result);
86
87 for (int i = 0; i < tuples; ++i)
88     {
89     tariffsList->push_back(PQgetvalue(result, i, 0));
90     }
91
92 PQclear(result);
93
94 if (CommitTransaction())
95     {
96     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to commit transaction'\n");
97     return -1;
98     }
99
100 return 0;
101 }
102
103 //-----------------------------------------------------------------------------
104 int POSTGRESQL_STORE::AddTariff(const std::string & name) const
105 {
106 STG_LOCKER lock(&mutex);
107
108 if (PQstatus(connection) != CONNECTION_OK)
109     {
110     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
111     if (Reset())
112         {
113         strError = "Connection lost";
114         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
115         return -1;
116         }
117     }
118
119 PGresult * result;
120
121 if (StartTransaction())
122     {
123     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to start transaction'\n");
124     return -1;
125     }
126
127 std::string ename = name;
128
129 if (EscapeString(ename))
130     {
131     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
132     if (RollbackTransaction())
133         {
134         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
135         }
136     return -1;
137     }
138
139 std::ostringstream query;
140 query << "SELECT sp_add_tariff('" << ename << "', " << DIR_NUM << ")";
141
142 result = PQexec(connection, query.str().c_str());
143
144 if (PQresultStatus(result) != PGRES_TUPLES_OK)
145     {
146     strError = PQresultErrorMessage(result);
147     PQclear(result);
148     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
149     if (RollbackTransaction())
150         {
151         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
152         }
153     return -1;
154     }
155
156 PQclear(result);
157
158 if (CommitTransaction())
159     {
160     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to commit transaction'\n");
161     return -1;
162     }
163
164 return 0;
165 }
166 //-----------------------------------------------------------------------------
167 int POSTGRESQL_STORE::DelTariff(const std::string & name) const
168 {
169 STG_LOCKER lock(&mutex);
170
171 if (PQstatus(connection) != CONNECTION_OK)
172     {
173     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
174     if (Reset())
175         {
176         strError = "Connection lost";
177         printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
178         return -1;
179         }
180     }
181
182 PGresult * result;
183
184 if (StartTransaction())
185     {
186     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to start transaction'\n");
187     return -1;
188     }
189
190 std::string ename = name;
191
192 if (EscapeString(ename))
193     {
194     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
195     if (RollbackTransaction())
196         {
197         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
198         }
199     return -1;
200     }
201
202 std::ostringstream query;
203 query << "DELETE FROM tb_tariffs WHERE name = '" << ename << "'";
204
205 result = PQexec(connection, query.str().c_str());
206
207 if (PQresultStatus(result) != PGRES_COMMAND_OK)
208     {
209     strError = PQresultErrorMessage(result);
210     PQclear(result);
211     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
212     if (RollbackTransaction())
213         {
214         printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to rollback transaction'\n");
215         }
216     return -1;
217     }
218
219 PQclear(result);
220
221 if (CommitTransaction())
222     {
223     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to commit transaction'\n");
224     return -1;
225     }
226
227 return 0;
228 }
229 //-----------------------------------------------------------------------------
230 int POSTGRESQL_STORE::SaveTariff(const TARIFF_DATA & td,
231                                  const std::string & tariffName) const
232 {
233 STG_LOCKER lock(&mutex);
234
235 if (PQstatus(connection) != CONNECTION_OK)
236     {
237     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
238     if (Reset())
239         {
240         strError = "Connection lost";
241         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
242         return -1;
243         }
244     }
245
246 PGresult * result;
247
248 if (StartTransaction())
249     {
250     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to start transaction'\n");
251     return -1;
252     }
253
254 std::string ename = tariffName;
255
256 if (EscapeString(ename))
257     {
258     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to escape name'\n");
259     if (RollbackTransaction())
260         {
261         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
262         }
263     return -1;
264     }
265
266     {
267     std::ostringstream query;
268     query << "SELECT pk_tariff FROM tb_tariffs WHERE name = '" << ename << "'";
269
270     result = PQexec(connection, query.str().c_str());
271     }
272
273 if (PQresultStatus(result) != PGRES_TUPLES_OK)
274     {
275     strError = PQresultErrorMessage(result);
276     PQclear(result);
277     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
278     if (RollbackTransaction())
279         {
280         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
281         }
282     return -1;
283     }
284
285 int tuples = PQntuples(result);
286
287 if (tuples != 1)
288     {
289     strError = "Failed to fetch tariff ID";
290     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
291     PQclear(result);
292     if (RollbackTransaction())
293         {
294         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
295         }
296     return -1;
297     }
298
299 int32_t id;
300
301     {
302     std::stringstream tuple;
303     tuple << PQgetvalue(result, 0, 0);
304
305     PQclear(result);
306
307     tuple >> id;
308     }
309
310     {
311     std::ostringstream query;
312     query << "UPDATE tb_tariffs SET \
313                   fee = " << td.tariffConf.fee << ", \
314                   free = " << td.tariffConf.free << ", \
315                   passive_cost = " << td.tariffConf.passiveCost << ", \
316                   traff_type = " << td.tariffConf.traffType;
317
318     if (version > 6)
319         query << ", period = '" << TARIFF::PeriodToString(td.tariffConf.period) << "'";
320
321     if (version > 7)
322         query << ", change_policy = '" << TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) << "', \
323                   change_policy_timeout = CAST('" << formatTime(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)";
324
325     query << " WHERE pk_tariff = " << id;
326
327     result = PQexec(connection, query.str().c_str());
328     }
329
330 if (PQresultStatus(result) != PGRES_COMMAND_OK)
331     {
332     strError = PQresultErrorMessage(result);
333     PQclear(result);
334     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
335     if (RollbackTransaction())
336         {
337         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
338         }
339     return -1;
340     }
341
342 PQclear(result);
343
344 for(int i = 0; i < DIR_NUM; i++)
345     {
346     double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
347     double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
348     double pna = 0;
349     double pnb = 0;
350
351     if (td.dirPrice[i].singlePrice)
352         {
353         pna = pda;
354         pnb = pdb;
355         }
356     else
357         {
358         pna = td.dirPrice[i].priceNightA * 1024 * 1024;
359         pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
360         }
361
362     int threshold = 0;
363     if (td.dirPrice[i].noDiscount)
364         {
365         threshold = 0xffFFffFF;
366         }
367     else
368         {
369         threshold = td.dirPrice[i].threshold;
370         }
371
372         {
373         std::ostringstream query;
374         query << "UPDATE tb_tariffs_params SET \
375                       price_day_a = " << pda << ", \
376                       price_day_b = " << pdb << ", \
377                       price_night_a = " << pna << ", \
378                       price_night_b = " << pnb << ", \
379                       threshold = " << threshold << ", \
380                       time_day_begins = CAST('" << td.dirPrice[i].hDay
381                                                 << ":"
382                                                 << td.dirPrice[i].mDay << "' AS TIME), \
383                       time_day_ends = CAST('" << td.dirPrice[i].hNight
384                                               << ":"
385                                               << td.dirPrice[i].mNight << "' AS TIME) \
386                  WHERE fk_tariff = " << id << " AND dir_num = " << i;
387
388         result = PQexec(connection, query.str().c_str());
389         }
390
391     if (PQresultStatus(result) != PGRES_COMMAND_OK)
392         {
393         strError = PQresultErrorMessage(result);
394         PQclear(result);
395         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
396         if (RollbackTransaction())
397             {
398             printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
399             }
400         return -1;
401         }
402
403     PQclear(result);
404     }
405
406 if (CommitTransaction())
407     {
408     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
409     return -1;
410     }
411
412 return 0;
413 }
414 //-----------------------------------------------------------------------------
415 int POSTGRESQL_STORE::RestoreTariff(TARIFF_DATA * td,
416                                   const std::string & tariffName) const
417 {
418 STG_LOCKER lock(&mutex);
419
420 if (PQstatus(connection) != CONNECTION_OK)
421     {
422     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
423     if (Reset())
424         {
425         strError = "Connection lost";
426         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
427         return -1;
428         }
429     }
430
431 PGresult * result;
432
433 if (StartTransaction())
434     {
435     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
436     return -1;
437     }
438
439 std::string ename = tariffName;
440
441 if (EscapeString(ename))
442     {
443     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
444     if (RollbackTransaction())
445         {
446         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
447         }
448     return -1;
449     }
450
451 td->tariffConf.name = tariffName;
452
453 std::ostringstream query;
454 query << "SELECT pk_tariff, \
455                  fee, \
456                  free, \
457                  passive_cost, \
458                  traff_type";
459
460 if (version > 6)
461     query << ", period";
462
463 if (version > 7)
464     query << ", change_policy \
465               , change_policy_timeout";
466
467 query << " FROM tb_tariffs WHERE name = '" << ename << "'";
468
469 result = PQexec(connection, query.str().c_str());
470
471 if (PQresultStatus(result) != PGRES_TUPLES_OK)
472     {
473     strError = PQresultErrorMessage(result);
474     PQclear(result);
475     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
476     if (RollbackTransaction())
477         {
478         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
479         }
480     return -1;
481     }
482
483 int tuples = PQntuples(result);
484
485 if (tuples != 1)
486     {
487     strError = "Failed to fetch tariff data";
488     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
489     PQclear(result);
490     if (RollbackTransaction())
491         {
492         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
493         }
494     return -1;
495     }
496
497 int id;
498
499     {
500     std::stringstream tuple;
501     tuple << PQgetvalue(result, 0, 0) << " ";
502     tuple << PQgetvalue(result, 0, 1) << " ";
503     tuple << PQgetvalue(result, 0, 2) << " ";
504     tuple << PQgetvalue(result, 0, 3) << " ";
505     tuple << PQgetvalue(result, 0, 4) << " ";
506
507     tuple >> id;
508     tuple >> td->tariffConf.fee;
509     tuple >> td->tariffConf.free;
510     tuple >> td->tariffConf.passiveCost;
511     tuple >> td->tariffConf.traffType;
512     }
513
514 if (version > 6)
515     td->tariffConf.period = TARIFF::StringToPeriod(PQgetvalue(result, 0, 5));
516
517 if (version > 7)
518     {
519     td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(PQgetvalue(result, 0, 6));
520     td->tariffConf.changePolicyTimeout = readTime(PQgetvalue(result, 0, 7));
521     }
522
523 PQclear(result);
524
525 query.str("");
526 query << "SELECT dir_num, \
527                  price_day_a, \
528                  price_day_b, \
529                  price_night_a, \
530                  price_night_b, \
531                  threshold, \
532                  EXTRACT(hour FROM time_day_begins), \
533                  EXTRACT(minute FROM time_day_begins), \
534                  EXTRACT(hour FROM time_day_ends), \
535                  EXTRACT(minute FROM time_day_ends) \
536           FROM tb_tariffs_params \
537           WHERE fk_tariff = " << id;
538
539 result = PQexec(connection, query.str().c_str());
540
541 if (PQresultStatus(result) != PGRES_TUPLES_OK)
542     {
543     strError = PQresultErrorMessage(result);
544     PQclear(result);
545     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
546     if (RollbackTransaction())
547         {
548         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
549         }
550     return -1;
551     }
552
553 tuples = PQntuples(result);
554
555 if (tuples != DIR_NUM)
556     {
557     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
558     }
559
560 for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
561     {
562     int dir;
563
564         {
565         std::stringstream tuple;
566         tuple << PQgetvalue(result, i, 0) << " ";
567         tuple << PQgetvalue(result, i, 1) << " ";
568         tuple << PQgetvalue(result, i, 2) << " ";
569         tuple << PQgetvalue(result, i, 3) << " ";
570         tuple << PQgetvalue(result, i, 4) << " ";
571         tuple << PQgetvalue(result, i, 5) << " ";
572         tuple << PQgetvalue(result, i, 6) << " ";
573         tuple << PQgetvalue(result, i, 7) << " ";
574         tuple << PQgetvalue(result, i, 8) << " ";
575         tuple << PQgetvalue(result, i, 9) << " ";
576
577         tuple >> dir;
578         tuple >> td->dirPrice[dir].priceDayA;
579         td->dirPrice[dir].priceDayA /= 1024 * 1024;
580         tuple >> td->dirPrice[dir].priceDayB;
581         td->dirPrice[dir].priceDayB /= 1024 * 1024;
582         tuple >> td->dirPrice[dir].priceNightA;
583         td->dirPrice[dir].priceNightA /= 1024 * 1024;
584         tuple >> td->dirPrice[dir].priceNightB;
585         td->dirPrice[dir].priceNightB /= 1024 * 1024;
586         tuple >> td->dirPrice[dir].threshold;
587         tuple >> td->dirPrice[dir].hDay;
588         tuple >> td->dirPrice[dir].mDay;
589         tuple >> td->dirPrice[dir].hNight;
590         tuple >> td->dirPrice[dir].mNight;
591         }
592
593     if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
594         std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
595         {
596         td->dirPrice[dir].singlePrice = true;
597         }
598     else
599         {
600         td->dirPrice[dir].singlePrice = false;
601         }
602     if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
603         {
604         td->dirPrice[dir].noDiscount = true;
605         }
606     else
607         {
608
609         td->dirPrice[dir].noDiscount = false;
610         }
611
612     }
613
614 PQclear(result);
615
616 if (CommitTransaction())
617     {
618     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
619     return -1;
620     }
621
622 return 0;
623 }
624 //-----------------------------------------------------------------------------
625