]> git.stg.codes - stg.git/commitdiff
Merge remote-tracking branch 'origin/master' into ticket
authorElena Mamontova <helenh463@gmail.com>
Mon, 28 Nov 2016 13:50:59 +0000 (15:50 +0200)
committerElena Mamontova <helenh463@gmail.com>
Mon, 28 Nov 2016 13:50:59 +0000 (15:50 +0200)
28 files changed:
include/stg/tariff.h
include/stg/tariff_conf.h
projects/sgconf/tariffs.cpp
projects/stargazer/inst/var/02-alter-03.postgresql.sql [new file with mode: 0644]
projects/stargazer/inst/var/02-alter-03.sql [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp
projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp
projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp
projects/stargazer/plugins/configuration/sgconfig/parser_tariffs.cpp
projects/stargazer/plugins/configuration/sgconfig/parser_users.cpp
projects/stargazer/plugins/store/files/file_store.cpp
projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp
projects/stargazer/plugins/store/mysql/mysql_store.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store.h
projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp
projects/stargazer/tariff_impl.cpp
projects/stargazer/tariff_impl.h
projects/stargazer/user_impl.cpp
stglibs/common.lib/common.cpp
stglibs/common.lib/include/stg/common.h
stglibs/conffiles.lib/conffiles.cpp
stglibs/conffiles.lib/include/stg/conffiles.h
stglibs/srvconf.lib/parsers/chg_tariff.cpp
stglibs/srvconf.lib/parsers/get_tariff.cpp
tests/test_tariff.cpp

index 5d01cba08886be4087aced98c1305b072e16ef05..4f5b4166a11a11d41383007fe6377fb237b4d13d 100644 (file)
@@ -32,10 +32,15 @@ struct TARIFF_DATA;
 
 class TARIFF {
 public:
+    enum CHANGE_POLICY { ALLOW = 0, TO_CHEAP, TO_EXPENSIVE, DENY };
+
     enum PERIOD { DAY = 0, MONTH };
 
     enum TRAFF_TYPE { TRAFF_UP = 0, TRAFF_DOWN, TRAFF_UP_DOWN, TRAFF_MAX };
 
+    static std::string ChangePolicyToString(CHANGE_POLICY changePolicy);
+    static CHANGE_POLICY StringToChangePolicy(const std::string& value);
+
     static std::string PeriodToString(PERIOD period);
     static PERIOD StringToPeriod(const std::string& value);
 
@@ -53,6 +58,8 @@ public:
     virtual double  GetFee() const = 0;
     virtual double  GetFree() const = 0;
     virtual PERIOD  GetPeriod() const = 0;
+    virtual CHANGE_POLICY GetChangePolicy() const = 0;
+    virtual time_t  GetChangePolicyTimeout() const = 0;
 
     virtual const   std::string & GetName() const = 0;
     virtual void    SetName(const std::string & name) = 0;
@@ -61,8 +68,34 @@ public:
     virtual int64_t GetTraffByType(uint64_t up, uint64_t down) const = 0;
     virtual int     GetThreshold(int dir) const = 0;
     virtual const TARIFF_DATA & GetTariffData() const = 0;
+    virtual std::string TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const = 0;
 };
 
+inline
+std::string TARIFF::ChangePolicyToString(TARIFF::CHANGE_POLICY changePolicy)
+{
+switch (changePolicy)
+    {
+    case ALLOW: return "allow";
+    case TO_CHEAP: return "to_cheap";
+    case TO_EXPENSIVE: return "to_expensive";
+    case DENY: return "deny";
+    }
+return "allow"; // Classic behaviour.
+}
+
+inline
+TARIFF::CHANGE_POLICY TARIFF::StringToChangePolicy(const std::string& value)
+{
+if (strcasecmp(value.c_str(), "to_cheap") == 0)
+    return TO_CHEAP;
+if (strcasecmp(value.c_str(), "to_expensive") == 0)
+    return TO_EXPENSIVE;
+if (strcasecmp(value.c_str(), "deny") == 0)
+    return DENY;
+return ALLOW; // Classic behaviour.
+}
+
 inline
 std::string TARIFF::PeriodToString(TARIFF::PERIOD period)
 {
index fe94b6e533b54b2b9bc2e0a3520591d473214fda..79ade2eb44bef6ddaee90bf705a8d421297b7dcf 100644 (file)
@@ -148,6 +148,8 @@ struct TARIFF_CONF
     double             passiveCost;
     std::string        name;
     TARIFF::PERIOD     period;
+    TARIFF::CHANGE_POLICY changePolicy;
+    time_t changePolicyTimeout;
 
     TARIFF_CONF()
         : fee(0),
@@ -155,7 +157,9 @@ struct TARIFF_CONF
           traffType(TARIFF::TRAFF_UP_DOWN),
           passiveCost(0),
           name(),
-          period(TARIFF::MONTH)
+          period(TARIFF::MONTH),
+          changePolicy(TARIFF::ALLOW),
+          changePolicyTimeout(0)
         {}
 
     TARIFF_CONF(const std::string & n)
@@ -164,7 +168,9 @@ struct TARIFF_CONF
           traffType(TARIFF::TRAFF_UP_DOWN),
           passiveCost(0),
           name(n),
-          period(TARIFF::MONTH)
+          period(TARIFF::MONTH),
+          changePolicy(TARIFF::ALLOW),
+          changePolicyTimeout(0)
         {}
 };
 //-----------------------------------------------------------------------------
@@ -176,7 +182,9 @@ struct TARIFF_CONF_RES
           traffType(),
           passiveCost(),
           name(),
-          period()
+          period(),
+          changePolicy(),
+          changePolicyTimeout()
         {}
 
     TARIFF_CONF_RES & operator=(const TARIFF_CONF & tc)
@@ -187,6 +195,8 @@ struct TARIFF_CONF_RES
         passiveCost = tc.passiveCost;
         name        = tc.name;
         period      = tc.period;
+        changePolicy = tc.changePolicy;
+        changePolicyTimeout = tc.changePolicyTimeout;
         return *this;
         }
 
@@ -199,6 +209,8 @@ struct TARIFF_CONF_RES
         passiveCost.maybeSet(tc.passiveCost);
         traffType.maybeSet(tc.traffType);
         period.maybeSet(tc.period);
+        changePolicy.maybeSet(tc.changePolicy);
+        changePolicyTimeout.maybeSet(tc.changePolicyTimeout);
         return tc;
         }
 
@@ -208,6 +220,8 @@ struct TARIFF_CONF_RES
     RESETABLE<double>             passiveCost;
     RESETABLE<std::string>        name;
     RESETABLE<TARIFF::PERIOD>     period;
+    RESETABLE<TARIFF::CHANGE_POLICY> changePolicy;
+    RESETABLE<time_t>             changePolicyTimeout;
 };
 //-----------------------------------------------------------------------------
 struct TARIFF_DATA
@@ -248,6 +262,14 @@ struct TARIFF_DATA_RES
           dirPrice(DIR_NUM)
         {}
 
+    TARIFF_DATA_RES & operator=(const TARIFF_DATA & td)
+        {
+        tariffConf = td.tariffConf;
+        for (size_t i = 0; i < DIR_NUM; ++i)
+            dirPrice[i] = td.dirPrice[i];
+        return *this;
+        }
+
     TARIFF_DATA GetData() const
         {
         TARIFF_DATA td;
index 3d63d2a8c6861f1b1fc0a666ef4af972ca9f3f69..6ab4e87107e69cbd19fad439e20fd74e62822b80 100644 (file)
@@ -28,6 +28,18 @@ if (level == 0)
 return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' ');
 }
 
+std::string ChangePolicyToString(TARIFF::CHANGE_POLICY changePolicy)
+{
+switch (changePolicy)
+    {
+    case TARIFF::ALLOW: return "allow";
+    case TARIFF::TO_CHEAP: return "to_cheap";
+    case TARIFF::TO_EXPENSIVE: return "to_expensive";
+    case TARIFF::DENY: return "deny";
+    }
+return "unknown";
+}
+
 std::string PeriodToString(TARIFF::PERIOD period)
 {
 switch (period)
@@ -67,6 +79,29 @@ else
     throw SGCONF::ACTION::ERROR("Period should be 'daily' or 'monthly'. Got: '" + value + "'");
 }
 
+void ConvChangePolicy(const std::string & value, RESETABLE<TARIFF::CHANGE_POLICY> & res)
+{
+std::string lowered = ToLower(value);
+if (lowered == "allow")
+    res = TARIFF::ALLOW;
+else if (lowered == "to_cheap")
+    res = TARIFF::TO_CHEAP;
+else if (lowered == "to_expensive")
+    res = TARIFF::TO_EXPENSIVE;
+else if (lowered == "deny")
+    res = TARIFF::DENY;
+else
+    throw SGCONF::ACTION::ERROR("Change policy should be 'allow', 'to_cheap', 'to_expensive' or 'deny'. Got: '" + value + "'");
+}
+
+void ConvChangePolicyTimeout(const std::string & value, RESETABLE<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+    throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
 void ConvTraffType(const std::string & value, RESETABLE<TARIFF::TRAFF_TYPE> & res)
 {
 std::string lowered = ToLower(value);
@@ -214,7 +249,9 @@ std::cout << Indent(level, true) << "name: " << conf.name << "\n"
           << Indent(level)       << "free mb: " << conf.free << "\n"
           << Indent(level)       << "passive cost: " << conf.passiveCost << "\n"
           << Indent(level)       << "traff type: " << TraffTypeToString(conf.traffType) << "\n"
-          << Indent(level)       << "period: " << PeriodToString(conf.period) << "\n";
+          << Indent(level)       << "period: " << PeriodToString(conf.period) << "\n"
+          << Indent(level)       << "change policy: " << ChangePolicyToString(conf.changePolicy) << "\n"
+          << Indent(level)       << "change policy timeout: " << formatTime(conf.changePolicyTimeout) << "\n";
 }
 
 void PrintTariff(const STG::GET_TARIFF::INFO & info, size_t level = 0)
@@ -233,6 +270,8 @@ params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traff
 params.push_back(SGCONF::API_ACTION::PARAM("passive-cost", "<cost>", "\tpassive cost"));
 params.push_back(SGCONF::API_ACTION::PARAM("traff-type", "<type>", "\ttraffic type (up, down, up+down, max)"));
 params.push_back(SGCONF::API_ACTION::PARAM("period", "<period>", "\ttarification period (daily, monthly)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy", "<policy>", "tariff change policy (allow, to_cheap, to_expensive, deny)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy-timeout", "<yyyy-mm-dd hh:mm:ss>", "tariff change policy timeout"));
 params.push_back(SGCONF::API_ACTION::PARAM("times", "<hh:mm-hh:mm, ...>", "coma-separated day time-spans for each direction"));
 params.push_back(SGCONF::API_ACTION::PARAM("day-prices", "<price/price, ...>", "coma-separated day prices for each direction"));
 params.push_back(SGCONF::API_ACTION::PARAM("night-prices", "<price/price, ...>", "coma-separated night prices for each direction"));
@@ -337,6 +376,8 @@ SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
 SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
 SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
 SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
 SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
 SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
 SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
@@ -370,6 +411,8 @@ SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
 SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
 SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
 SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
 SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
 SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
 SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
diff --git a/projects/stargazer/inst/var/02-alter-03.postgresql.sql b/projects/stargazer/inst/var/02-alter-03.postgresql.sql
new file mode 100644 (file)
index 0000000..e8b248b
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  DB migration from v02 to v03 (postgres)
+ */
+BEGIN;
+
+CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS TEXT NOT NULL
+    CONSTRAINT valid_value CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
+
+ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
+ALTER TABLE tb_tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:00';
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
+
+UPDATE tb_info SET version = 8;
+
+COMMIT;
diff --git a/projects/stargazer/inst/var/02-alter-03.sql b/projects/stargazer/inst/var/02-alter-03.sql
new file mode 100644 (file)
index 0000000..d274520
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  DB migration from v02 to v03 (firebird)
+ */
+
+CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS  VARCHAR(32) NOT NULL
+    CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny'));
+
+ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow';
+ALTER TABLE tb_tariffs ADD change_policy_timeout DM_MOMENT DEFAULT '1970-01-01 00:00:00';
+
+UPDATE tb_tariffs SET change_policy = 'allow', change_policy_timeout = '1970-01-01 00:00:00';
+
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT;
+ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT;
+
+UPDATE tb_info SET version = 2;
index 26b4e993b719067fae180f47b9c1d1792b1da204..7c023e25fd37c3a4bf96abddab964e2d3b652173 100644 (file)
@@ -1,6 +1,7 @@
 #include <ostream> // xmlrpc-c devs have missed something :)
 
 #include "tariff_helper.h"
+#include "stg/common.h"
 
 void TARIFF_HELPER::GetTariffInfo(xmlrpc_c::value * info) const
 {
@@ -13,6 +14,8 @@ structVal["freemb"] = xmlrpc_c::value_double(data.tariffConf.free);
 structVal["passivecost"] = xmlrpc_c::value_double(data.tariffConf.passiveCost);
 structVal["traffType"] = xmlrpc_c::value_int(data.tariffConf.traffType);
 structVal["period"] = xmlrpc_c::value_string(TARIFF::PeriodToString(data.tariffConf.period));
+structVal["changePolicy"] = xmlrpc_c::value_string(TARIFF::ChangePolicyToString(data.tariffConf.changePolicy));
+structVal["changePolicyTimeout"] = xmlrpc_c::value_string(formatTime(data.tariffConf.changePolicyTimeout));
 
 std::vector<xmlrpc_c::value> prices(DIR_NUM);
 
@@ -71,6 +74,16 @@ if ((it = structVal.find("period")) != structVal.end())
     data.tariffConf.period = TARIFF::StringToPeriod(xmlrpc_c::value_string(it->second));
     }
 
+if ((it = structVal.find("changePolicy")) != structVal.end())
+    {
+    data.tariffConf.changePolicy = TARIFF::StringToChangePolicy(xmlrpc_c::value_string(it->second));
+    }
+
+if ((it = structVal.find("changePolicyTimeout")) != structVal.end())
+    {
+    data.tariffConf.changePolicyTimeout = readTime(xmlrpc_c::value_string(it->second));
+    }
+
 if ((it = structVal.find("dirprices")) != structVal.end())
     {
     std::vector<xmlrpc_c::value> prices(
index 89c41587f8527862de5932bbc4cbe52e63ab0c37..ac6e72615a95e43ec6da8feacc7fe796be59f042 100644 (file)
@@ -433,13 +433,27 @@ if ((it = structVal.find("tariff")) != structVal.end())
         tariff = tariff.substr(0, pos);
         }
 
-    if (tariffs->FindByName(tariff))
-        if (ptr->GetProperty().tariffName.Get() != tariff)
-            if (!ptr->GetProperty().tariffName.Set(tariff,
-                                               admin,
-                                               login,
-                                               &store))
-                return true;
+    const TARIFF * newTariff = tariffs->FindByName(tariff);
+    if (newTariff)
+        {
+        const TARIFF * currentTariff = ptr->GetTariff();
+        std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
+        if (message.empty())
+            {
+            if (ptr->GetProperty().tariffName.Get() != tariff)
+                {
+                if (!ptr->GetProperty().tariffName.Set(tariff,
+                                                   admin,
+                                                   login,
+                                                   &store))
+                    return true;
+                }
+            }
+        else
+            {
+            GetStgLogger()("Tariff change is prohibited for user %s. %s", ptr->GetLogin().c_str(), message.c_str());
+            }
+        }
 
     if (nextTariff != "" &&
         tariffs->FindByName(nextTariff))
index 5adbf44131905750cfa52fefbf1398b0842b2dd0..56167bc2cdaee25e9ec7ee6dd489c43980f0b34c 100644 (file)
@@ -381,16 +381,29 @@ if (tariffs->FindByName(tariff))
         }
     else
         {
-        if (u->GetProperty().tariffName.Set(tariff,
+        const TARIFF * newTariff = tariffs->FindByName(tariff);
+        if (newTariff)
+            {
+            const TARIFF * currentTariff = u->GetTariff();
+            std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime);
+            if (message.empty())
+                {
+                if (u->GetProperty().tariffName.Set(tariff,
                                             admin,
                                             login,
                                             store,
                                             comment))
-            {
-            u->ResetNextTariff();
-            u->WriteConf();
-            *retvalPtr = xmlrpc_c::value_boolean(true);
-            return;
+                    {
+                    u->ResetNextTariff();
+                    u->WriteConf();
+                    *retvalPtr = xmlrpc_c::value_boolean(true);
+                    return;
+                    }
+                }
+            else
+                {
+                GetStgLogger()("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
+                }
             }
         }
     }
index 0607db6fb12fbde08147a0af3418250ae3743bb3..9c75267480e9591544e920ddb2b28788ff3f08ac 100644 (file)
@@ -114,6 +114,8 @@ void GET_TARIFFS::CreateAnswer()
                   "<Free value=\"" + x2str(it->tariffConf.free) + "\"/>" +
                   "<TraffType value=\"" + TARIFF::TraffTypeToString(it->tariffConf.traffType) + "\"/>" +
                   "<Period value=\"" + TARIFF::PeriodToString(it->tariffConf.period) + "\"/>" +
+                  "<ChangePolicy value=\"" + TARIFF::ChangePolicyToString(it->tariffConf.changePolicy) + "\"/>" +
+                  "<ChangePolicyTimeout value=\"" + x2str(it->tariffConf.changePolicyTimeout) + "\"/>" +
                   "</tariff>";
         }
 
@@ -170,7 +172,11 @@ int CHG_TARIFF::Start(void *, const char * el, const char ** attr)
     {
         if (strcasecmp(el, m_tag.c_str()) == 0)
         {
-            td.tariffConf.name = attr[1];
+            const TARIFF * tariff = m_tariffs.FindByName(attr[1]);
+            if (tariff != NULL)
+                td = tariff->GetTariffData();
+            else
+                return -1;
             return 0;
         }
     }
@@ -288,6 +294,20 @@ int CHG_TARIFF::Start(void *, const char * el, const char ** attr)
             td.tariffConf.period = TARIFF::StringToPeriod(attr[1]);
             return 0;
         }
+
+        if (strcasecmp(el, "ChangePolicy") == 0)
+        {
+            td.tariffConf.changePolicy = TARIFF::StringToChangePolicy(attr[1]);
+            return 0;
+        }
+
+        if (strcasecmp(el, "ChangePolicyTimeout") == 0)
+        {
+            int64_t policyTime = 0;
+            if (str2x(attr[1], policyTime) == 0)
+                td.tariffConf.changePolicyTimeout = (time_t)policyTime;
+            return 0;
+        }
     }
     return -1;
 }
index 2e9d70872a82e3a7ac1ff92236c36c306060d582..5707b726200e97b5792646496667f6ffe7aa2755 100644 (file)
@@ -594,11 +594,21 @@ int CHG_USER::ApplyChanges()
 
     if (!m_ucr.tariffName.empty())
     {
-        if (m_tariffs.FindByName(m_ucr.tariffName.const_data()))
+        const TARIFF * newTariff = m_tariffs.FindByName(m_ucr.tariffName.const_data());
+        if (newTariff)
         {
-            if (!u->GetProperty().tariffName.Set(m_ucr.tariffName.const_data(), &m_currAdmin, m_login, &m_store))
-                return -1;
-            u->ResetNextTariff();
+            const TARIFF * tariff = u->GetTariff();
+            std::string message = tariff->TariffChangeIsAllowed(*newTariff, stgTime);
+            if (message.empty())
+            {
+                if (!u->GetProperty().tariffName.Set(m_ucr.tariffName.const_data(), &m_currAdmin, m_login, &m_store))
+                    return -1;
+                u->ResetNextTariff();
+            }
+            else
+            {
+                GetStgLogger()("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str());
+            }
         }
         else
         {
index 96add48fe14a4b2de738ea617add82770e7fe265..f63d96869552c48b8cdcdaa85502c00445bf3b43 100644 (file)
@@ -1518,6 +1518,19 @@ if (conf.ReadString("Period", &str, "month") < 0)
     td->tariffConf.period = TARIFF::MONTH;
 else
     td->tariffConf.period = TARIFF::StringToPeriod(str);
+
+if (conf.ReadString("ChangePolicy", &str, "allow") < 0)
+    td->tariffConf.changePolicy = TARIFF::ALLOW;
+else
+    td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str);
+
+if (conf.ReadTime("ChangePolicyTimeout", &td->tariffConf.changePolicyTimeout, 0) < 0)
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter ChangePolicyTimeout";
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - changepolicytimeout read failed for tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -1579,6 +1592,8 @@ std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
     cf.WriteDouble("Free", td.tariffConf.free);
     cf.WriteString("TraffType", TARIFF::TraffTypeToString(td.tariffConf.traffType));
     cf.WriteString("Period", TARIFF::PeriodToString(td.tariffConf.period));
+    cf.WriteString("ChangePolicy", TARIFF::ChangePolicyToString(td.tariffConf.changePolicy));
+    cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout);
     }
 
 return 0;
index 138a9ed92a8a72a2c13086b168e0ccf286165b0e..6f8177cab11bc04445b85d1503b090a0bdfd4124 100644 (file)
@@ -150,36 +150,44 @@ try
     int32_t id;
     st->Get(1, id);
     st->Close();
+
+    std::string query = "update tb_tariffs set \
+                            fee = ?, \
+                            free = ?, \
+                            passive_cost = ?, \
+                            traff_type = ?";
+
+    if (schemaVersion > 0)
+        query += ", period = ?";
+    if (schemaVersion > 1)
+        query += ", change_policy = ?, \
+                    change_policy_timeout = ?";
+
+    query += " where pk_tariff = ?";
+
+    unsigned num = 5;
+    st->Prepare(query);
+    st->Set(1, td.tariffConf.fee);
+    st->Set(2, td.tariffConf.free);
+    st->Set(3, td.tariffConf.passiveCost);
+    st->Set(4, td.tariffConf.traffType);
+
     if (schemaVersion > 0)
         {
-        st->Prepare("update tb_tariffs set \
-                fee = ?, \
-                free = ?, \
-                passive_cost = ?, \
-                traff_type = ?, \
-                period = ? \
-                where pk_tariff = ?");
-        st->Set(1, td.tariffConf.fee);
-        st->Set(2, td.tariffConf.free);
-        st->Set(3, td.tariffConf.passiveCost);
-        st->Set(4, td.tariffConf.traffType);
         st->Set(5, TARIFF::PeriodToString(td.tariffConf.period));
-        st->Set(6, id);
+        ++num;
         }
-    else
+
+    if (schemaVersion > 1)
         {
-        st->Prepare("update tb_tariffs set \
-                fee = ?, \
-                free = ?, \
-                passive_cost = ?, \
-                traff_type = ? \
-                where pk_tariff = ?");
-        st->Set(1, td.tariffConf.fee);
-        st->Set(2, td.tariffConf.free);
-        st->Set(3, td.tariffConf.passiveCost);
-        st->Set(4, td.tariffConf.traffType);
-        st->Set(5, id);
+        st->Set(6, TARIFF::ChangePolicyToString(td.tariffConf.changePolicy));
+        IBPP::Timestamp policyTimeout;
+        time_t2ts(td.tariffConf.changePolicyTimeout, &policyTimeout);
+        st->Set(7, policyTimeout);
+        num += 2;
         }
+
+    st->Set(num, id);
     st->Execute();
     st->Close();
 
@@ -285,6 +293,11 @@ try
     td->tariffConf.traffType = TARIFF::IntToTraffType(Get<int>(st, 6));
     if (schemaVersion > 0)
         td->tariffConf.period = TARIFF::StringToPeriod(Get<std::string>(st, 7));
+    if (schemaVersion > 1)
+        {
+        td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(Get<std::string>(st, 8));
+        td->tariffConf.changePolicyTimeout = ts2time_t(Get<IBPP::Timestamp>(st, 9));
+        }
     st->Close();
     st->Prepare("select * from tb_tariffs_params where fk_tariff = ?");
     st->Set(1, id);
index 6b16a99daff8ca1ed337e5644c5d765c71d6a84a..198b5f3b812375fcfe88ef3fa532865f45eb1cac 100644 (file)
@@ -7,6 +7,7 @@
 #include <mysql.h>
 #include <errmsg.h>
 
+#include "stg/common.h"
 #include "stg/user_ips.h"
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
@@ -368,7 +369,9 @@ if(!IsTablePresent("tariffs",sock))
     
     res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"
         "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '',"
-        "period VARCHAR(32) NOT NULL DEFAULT 'month')";
+        "period VARCHAR(32) NOT NULL DEFAULT 'month',"
+        "change_policy VARCHAR(32) NOT NULL DEFAULT 'allow',"
+        "change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0)";
     
     if(MysqlQuery(res.c_str(),sock))
     {
@@ -422,7 +425,8 @@ if(!IsTablePresent("tariffs",sock))
     
     res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
         "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
-        "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month'";
+        "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month',"\
+        "change_policy='allow', change_policy_timeout=0";
     
     if(MysqlQuery(res.c_str(),sock))
     {
@@ -441,7 +445,7 @@ if(!IsTablePresent("tariffs",sock))
         mysql_close(sock);
         return -1;
     }
-    schemaVersion = 1;
+    schemaVersion = 2;
 }
 
 //users-----------------------------------------------------------------------
@@ -599,6 +603,27 @@ if (schemaVersion  < 1)
     schemaVersion = 1;
     logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
     }
+
+if (schemaVersion  < 2)
+    {
+    if (MysqlQuery("ALTER TABLE tariffs ADD change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'", sock) ||
+        MysqlQuery("ALTER TABLE tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0", sock))
+        {
+        errorStr = "Couldn't update tariffs table to version 2. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    if (MysqlQuery("UPDATE info SET version = 2", sock))
+        {
+        errorStr = "Couldn't update DB schema version to 2. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    schemaVersion = 2;
+    logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
+    }
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -1639,6 +1664,40 @@ else
     td->tariffConf.period = TARIFF::MONTH;
     }
 
+if (schemaVersion > 1)
+    {
+    str = row[6+8*DIR_NUM];
+    param = "ChangePolicy";
+
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str);
+
+    str = row[7+8*DIR_NUM];
+    param = "ChangePolicyTimeout";
+
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    td->tariffConf.changePolicyTimeout = readTime(str);
+    }
+else
+    {
+    td->tariffConf.changePolicy = TARIFF::ALLOW;
+    td->tariffConf.changePolicyTimeout = 0;
+    }
+
 mysql_free_result(res);
 mysql_close(sock);
 return 0;
@@ -1706,6 +1765,10 @@ res += " TraffType='" + TARIFF::TraffTypeToString(td.tariffConf.traffType) + "'"
 if (schemaVersion > 0)
     res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'";
 
+if (schemaVersion > 1)
+    res += ", change_policy='" + TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) + "'"\
+           ", change_policy_timeout='" + formatTime(td.tariffConf.changePolicy) + "'";
+
 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
 res += param;
 
index 72a2c22c01c951fbd7bed410f12189036456776b..6bcb3cd05dbe4b8b9001a6f6e8e3ea0fd73ea228 100644 (file)
@@ -128,9 +128,6 @@ private:
 
     int EscapeString(std::string & value) const;
 
-    std::string Int2TS(time_t value) const;
-    time_t TS2Int(const std::string & value) const;
-
     int SaveStat(const USER_STAT & stat, const std::string & login, int year = 0, int month = 0) const;
 
     int SaveUserServices(uint32_t uid, const std::vector<std::string> & services) const;
index 27401e268ff874bdded9fde809e1e5d025395c07..42a190732d5368b3ba32273f581818ff08a83aa8 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <libpq-fe.h>
 
+#include "stg/common.h"
 #include "postgresql_store.h"
 #include "stg/locker.h"
 #include "stg/message.h"
@@ -89,8 +90,8 @@ query << "SELECT sp_add_message("
       << "'" << elogin << "', "
       << "CAST(1 AS SMALLINT), " // Here need to be a version, but, it's uninitiated actually
       << "CAST(" << msg->header.type << " AS SMALLINT), "
-      << "CAST('" << Int2TS(msg->header.lastSendTime) << "' AS TIMESTAMP), "
-      << "CAST('" << Int2TS(msg->header.creationTime) << "' AS TIMESTAMP), "
+      << "CAST('" << formatTime(msg->header.lastSendTime) << "' AS TIMESTAMP), "
+      << "CAST('" << formatTime(msg->header.creationTime) << "' AS TIMESTAMP), "
       << msg->header.showTime << ", "
       << "CAST(" << msg->header.repeat << " AS SMALLINT), "
       << msg->header.repeatPeriod << ", "
@@ -192,8 +193,8 @@ query << "UPDATE tb_messages SET "
           << "fk_user = (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
           << "ver = " << msg.header.ver << ", "
           << "msg_type = " << msg.header.type << ", "
-          << "last_send_time = CAST('" << Int2TS(msg.header.lastSendTime) << "' AS TIMESTAMP), "
-          << "creation_time = CAST('" << Int2TS(msg.header.creationTime) << "' AS TIMESTAMP), "
+          << "last_send_time = CAST('" << formatTime(msg.header.lastSendTime) << "' AS TIMESTAMP), "
+          << "creation_time = CAST('" << formatTime(msg.header.creationTime) << "' AS TIMESTAMP), "
           << "show_time = " << msg.header.showTime << ", "
           << "repeat = " << msg.header.repeat << ", "
           << "repeat_period = " << msg.header.repeatPeriod << ", "
@@ -287,8 +288,8 @@ if (tuples != 1)
 
 str2x(PQgetvalue(result, 0, 0), msg->header.ver);
 str2x(PQgetvalue(result, 0, 1), msg->header.type);
-msg->header.lastSendTime = static_cast<unsigned int>(TS2Int(PQgetvalue(result, 0, 2)));
-msg->header.creationTime = static_cast<unsigned int>(TS2Int(PQgetvalue(result, 0, 3)));
+msg->header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 2)));
+msg->header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, 0, 3)));
 str2x(PQgetvalue(result, 0, 4), msg->header.showTime);
 str2x(PQgetvalue(result, 0, 5), msg->header.repeat);
 str2x(PQgetvalue(result, 0, 6), msg->header.repeatPeriod);
@@ -424,8 +425,8 @@ for (int i = 0; i < tuples; ++i)
     tuple << PQgetvalue(result, i, 0) << " ";
     tuple << PQgetvalue(result, i, 1) << " ";
     tuple << PQgetvalue(result, i, 2) << " ";
-    header.lastSendTime = static_cast<unsigned int>(TS2Int(PQgetvalue(result, i, 3)));
-    header.creationTime = static_cast<unsigned int>(TS2Int(PQgetvalue(result, i, 4)));
+    header.lastSendTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 3)));
+    header.creationTime = static_cast<unsigned int>(readTime(PQgetvalue(result, i, 4)));
     tuple << PQgetvalue(result, i, 5) << " ";
     tuple << PQgetvalue(result, i, 6) << " ";
     tuple << PQgetvalue(result, i, 7) << " ";
index 045411b1499f822400cfc860831a1ebd6661d1d9..fd0b38bca4f9a6056a52d9d3d9ca178290435c86 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <libpq-fe.h>
 
+#include "stg/common.h"
 #include "postgresql_store.h"
 #include "stg/locker.h"
 
@@ -317,6 +318,10 @@ int32_t id;
     if (version > 6)
         query << ", period = '" << TARIFF::PeriodToString(td.tariffConf.period) << "'";
 
+    if (version > 7)
+        query << ", change_policy = '" << TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) << "', \
+                  change_policy_timeout = CAST('" << formatTime(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)";
+
     query << " WHERE pk_tariff = " << id;
 
     result = PQexec(connection, query.str().c_str());
@@ -455,6 +460,10 @@ query << "SELECT pk_tariff, \
 if (version > 6)
     query << ", period";
 
+if (version > 7)
+    query << ", change_policy \
+              , change_policy_timeout";
+
 query << " FROM tb_tariffs WHERE name = '" << ename << "'";
 
 result = PQexec(connection, query.str().c_str());
@@ -505,6 +514,12 @@ int id;
 if (version > 6)
     td->tariffConf.period = TARIFF::StringToPeriod(PQgetvalue(result, 0, 5));
 
+if (version > 7)
+    {
+    td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(PQgetvalue(result, 0, 6));
+    td->tariffConf.changePolicyTimeout = readTime(PQgetvalue(result, 0, 7));
+    }
+
 PQclear(result);
 
 query.str("");
index db2717acb0496e8da8f7b8b8f2a9bd62e7b01c5b..1ab5d0e8c2c806e28974c30065975727efc9bfa4 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <libpq-fe.h>
 
+#include "stg/common.h"
 #include "stg/const.h"
 #include "stg/locker.h"
 #include "../../../stg_timer.h"
@@ -270,9 +271,9 @@ std::ostringstream query;
 query << "UPDATE tb_users SET "
             "cash = " << stat.cash << ", "
             "free_mb = " << stat.freeMb << ", "
-            "last_activity_time = CAST('" << Int2TS(stat.lastActivityTime) << "' AS TIMESTAMP), "
+            "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
             "last_cash_add = " << stat.lastCashAdd << ", "
-            "last_cash_add_time = CAST('" << Int2TS(stat.lastCashAddTime) << "' AS TIMESTAMP), "
+            "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
             "passive_time = " << stat.passiveTime << " "
          "WHERE name = '" << elogin << "'";
 
@@ -527,7 +528,7 @@ query << "UPDATE tb_users SET "
              "address = '" << eaddress << "', "
              "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
              "credit = " << conf.credit << ", "
-             "credit_expire = CAST('" << Int2TS(conf.creditExpire) << "' AS TIMESTAMP), "
+             "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
              "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
              "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
              "email = '" << eemail << "', "
@@ -681,9 +682,9 @@ if (tuples != 1)
     std::stringstream tuple;
     tuple << PQgetvalue(result, 0, 0) << " ";
     tuple << PQgetvalue(result, 0, 1) << " ";
-    stat->lastActivityTime = TS2Int(PQgetvalue(result, 0, 2));
+    stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
     tuple << PQgetvalue(result, 0, 3) << " ";
-    stat->lastCashAddTime = TS2Int(PQgetvalue(result, 0, 4));
+    stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
     tuple << PQgetvalue(result, 0, 5) << " ";
 
     PQclear(result);
@@ -699,7 +700,7 @@ if (tuples != 1)
     query << "SELECT dir_num, upload, download "
              "FROM tb_stats_traffic "
              "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
-                   "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP))";
+                   "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
 
     result = PQexec(connection, query.str().c_str());
     }
@@ -832,7 +833,7 @@ uint32_t uid;
     conf->address = PQgetvalue(result, 0, 1);               // address
     conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
     tuple << PQgetvalue(result, 0, 3) << " ";               // credit
-    conf->creditExpire = TS2Int(PQgetvalue(result, 0, 4));  // creditExpire
+    conf->creditExpire = readTime(PQgetvalue(result, 0, 4));  // creditExpire
     conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
     conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
     conf->email = PQgetvalue(result, 0, 7);                 // email
@@ -1078,7 +1079,7 @@ query << "SELECT sp_add_param_log_entry("
             "'" << eadminLogin << "', CAST('"
             << inet_ntostring(admIP) << "/32' AS INET), "
             "'" << eparam << "', "
-            "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+            "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
             "'" << eold << "', "
             "'" << enew << "', "
             "'" << emessage << "')";
@@ -1149,7 +1150,7 @@ if (version < 6)
     {
     query << "SELECT sp_add_session_log_entry("
                  "'" << elogin << "', "
-                 "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                 "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                  "'c', CAST('"
                  << inet_ntostring(ip) << "/32' AS INET), 0)";
     }
@@ -1157,7 +1158,7 @@ else
     {
     query << "SELECT sp_add_session_log_entry("
                  "'" << elogin << "', "
-                 "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                 "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                  "'c', CAST('"
                  << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
     }
@@ -1249,7 +1250,7 @@ if (EscapeString(ereason))
         // Old database version - no freeMb logging support
         query << "SELECT sp_add_session_log_entry("
                     "'" << elogin << "', "
-                    "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                    "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                     "'d', CAST('0.0.0.0/0' AS INET), "
                     << cash << ")";
         }
@@ -1257,7 +1258,7 @@ if (EscapeString(ereason))
         {
         query << "SELECT sp_add_session_log_entry("
                     "'" << elogin << "', "
-                    "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                    "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                     "'d', CAST('0.0.0.0/0' AS INET), "
                     << cash << ", " << freeMb << ", '" << ereason << "')";
         }
@@ -1397,8 +1398,8 @@ for (it = statTree.begin(); it != statTree.end(); ++it)
                 "(till_time, from_time, fk_user, "
                  "dir_num, ip, download, upload, cost) "
              "VALUES ("
-                "CAST('" << Int2TS(currTime) << "' AS TIMESTAMP), "
-                "CAST('" << Int2TS(lastStat) << "' AS TIMESTAMP), "
+                "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
+                "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
                 "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
                 << it->first.dir << ", "
                 << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
index ef70505389fc372eb2425398903256a805e4882f..9a5101e121c04a605e1698f08305445e31687818 100644 (file)
@@ -113,35 +113,6 @@ delete[] buf;
 return 0;
 }
 
-std::string POSTGRESQL_STORE::Int2TS(time_t ts) const
-{
-struct tm brokenTime;
-
-brokenTime.tm_wday = 0;
-brokenTime.tm_yday = 0;
-brokenTime.tm_isdst = 0;
-
-gmtime_r(&ts, &brokenTime);
-
-char buf[32];
-strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
-
-return buf;
-}
-
-time_t POSTGRESQL_STORE::TS2Int(const std::string & ts) const
-{
-struct tm brokenTime;
-
-brokenTime.tm_wday = 0;
-brokenTime.tm_yday = 0;
-brokenTime.tm_isdst = 0;
-
-stg_strptime(ts.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime);
-
-return stg_timegm(&brokenTime);
-}
-
 void POSTGRESQL_STORE::MakeDate(std::string & date, int year, int month) const
 {
 struct tm brokenTime;
index c6785cead85c26f71ea5e273014f0d71428a8d5f..2daaeeb3756c6bc8f8e7da3dc19bf22a78444efa 100644 (file)
@@ -145,3 +145,27 @@ else
     return tariffData.dirPrice[dir].priceDayA;
 }
 //-----------------------------------------------------------------------------
+std::string TARIFF_IMPL::TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const
+{
+time_t timeout = GetChangePolicyTimeout();
+if ((currentTime > timeout) && (timeout != 0))
+    return "";
+switch (GetChangePolicy())
+    {
+    case TARIFF::ALLOW:
+        return "";
+    case TARIFF::TO_CHEAP:
+        if (to.GetFee() < GetFee())
+            return "";
+        else
+            return "New tariff '" + to.GetName() + "' is more expensive than current tariff '" + GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'.";
+    case TARIFF::TO_EXPENSIVE:
+        if (to.GetFee() >= GetFee())
+            return "";
+        else
+            return "New tariff '" + to.GetName() + "' is more cheap than current tariff '" + GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'.";
+    case TARIFF::DENY:
+        return "Current tariff '" + GetName() + "', new tariff '" + to.GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'.";
+    }
+}
+//-----------------------------------------------------------------------------
index f2f84d2630889f73432e9a191459c8174c37adf3..0619d50bb5f852f725833a6294e613b8e31c88b5 100644 (file)
@@ -72,6 +72,8 @@ public:
     double  GetFee() const { return tariffData.tariffConf.fee; }
     double  GetFree() const { return tariffData.tariffConf.free; }
     PERIOD  GetPeriod() const { return tariffData.tariffConf.period; }
+    CHANGE_POLICY GetChangePolicy() const { return tariffData.tariffConf.changePolicy; }
+    time_t GetChangePolicyTimeout() const { return tariffData.tariffConf.changePolicyTimeout; }
 
     void    Print() const;
 
@@ -87,6 +89,7 @@ public:
     TARIFF_IMPL & operator=(const TARIFF_IMPL & t);
     bool     operator==(const TARIFF_IMPL & rhs) const { return GetName() == rhs.GetName(); }
     bool     operator!=(const TARIFF_IMPL & rhs) const { return GetName() != rhs.GetName(); }
+    std::string TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const;
 
 private:
     TARIFF_DATA     tariffData;
index c160db75cb8a39ec8fd402a076fefe41d504780c..0e92975c2c0c064e97d1f8497cd78148aa27b086 100644 (file)
@@ -1178,10 +1178,24 @@ if (nextTariff.ConstData() != "")
     {
     const TARIFF * nt = tariffs->FindByName(nextTariff);
     if (nt == NULL)
+        {
         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
                      login.c_str(), property.tariffName.Get().c_str());
+        }
     else
-        property.tariffName.Set(nextTariff, sysAdmin, login, store);
+        {
+        std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
+        if (message.empty())
+            {
+            property.tariffName.Set(nextTariff, sysAdmin, login, store);
+            }
+        else
+            {
+            WriteServLog("Tariff change is prohibited for user %s. %s",
+                         login.c_str(),
+                         message.c_str());
+            }
+        }
     ResetNextTariff();
     WriteConf();
     }
index 76a1b42144b38aaec9382d516c73b8d991e6a61d..a4722a00f3e301b9bc84dc6a500552d802dfefbb 100644 (file)
@@ -749,6 +749,38 @@ void SwapBytes(int64_t & value)
     value = temp;
 }
 //---------------------------------------------------------------------------
+std::string formatTime(time_t ts)
+{
+char buf[32];
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+gmtime_r(&ts, &brokenTime);
+
+strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
+
+return buf;
+}
+//---------------------------------------------------------------------------
+time_t readTime(const std::string & ts)
+{
+if (ts == "0000-00-00 00:00:00")
+    return 0;
+
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+stg_strptime(ts.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime);
+
+return stg_timegm(&brokenTime);
+}
+//---------------------------------------------------------------------------
 int str2x(const std::string & str, int32_t & x)
 {
 x = static_cast<int32_t>(strtol(str.c_str(), NULL, 10));
index 623d82d073aed1552bf531df2e40e4d86080f560..6201233d2b94941bad3fe04575925e3412800169 100644 (file)
@@ -159,6 +159,8 @@ bool WriteAll(int sd, const void * source, size_t size);
 
 std::string ToPrintable(const std::string & src);
 
+std::string formatTime(time_t value);
+time_t readTime(const std::string & value);
 //-----------------------------------------------------------------------------
 int str2x(const std::string & str, int32_t & x);
 int str2x(const std::string & str, uint32_t & x);
index ed2e4447744679b8e9bc2928018198b5f03c9ec8..a9c3e555093a87e8e60cc7c7d946cfdf347865b8 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <cerrno> // E*
 #include <cstring>
+#include <sstream>
 #include <cstdlib>
 #include <cstdio>
 
@@ -345,6 +346,14 @@ param_val[param] = buf;
 changed = true;
 }
 //---------------------------------------------------------------------------
+void CONFIGFILE::WriteTime(const std::string & param, time_t val)
+{
+std::stringstream ss;
+ss<<val;
+param_val[param] = ss.str();
+changed = true;
+}
+//---------------------------------------------------------------------------
 int CONFIGFILE::ReadDouble(const std::string & param, double * val, double defaultVal) const
 {
 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
index 48e07b6282bd2be594b35deee7d5f69a206d4779..49bb6ff336565ea6e47b4f2ff5ac5156df605d30 100644 (file)
@@ -67,6 +67,7 @@ public:
     void WriteString(const std::string & param, const std::string& val);
     void WriteInt(const std::string & param, int64_t val);
     void WriteDouble(const std::string & param, double val);
+    void WriteTime(const std::string & param, time_t val);
 
     int Error() const;
     int Flush() const;
index 158e6f890642af0a744525691ea825774e429901..16c4b198dbf1d4e605de0a51d22c39f46abf8d4e 100644 (file)
@@ -69,6 +69,16 @@ if (!data.tariffConf.period.empty())
         case TARIFF::MONTH: stream << "<period value=\"month\"/>"; break;
         }
 
+if (!data.tariffConf.changePolicy.empty())
+    switch (data.tariffConf.changePolicy.data())
+        {
+        case TARIFF::ALLOW: stream << "<changePolicy value=\"allow\"/>"; break;
+        case TARIFF::TO_CHEAP: stream << "<changePolicy value=\"to_cheap\"/>"; break;
+        case TARIFF::TO_EXPENSIVE: stream << "<changePolicy value=\"to_expensive\"/>"; break;
+        case TARIFF::DENY: stream << "<changePolicy value=\"deny\"/>"; break;
+        }
+
+appendResetableTag(stream, "changePolicyTimeout", data.tariffConf.changePolicyTimeout);
 for (size_t i = 0; i < DIR_NUM; ++i)
     if (!data.dirPrice[i].hDay.empty() &&
         !data.dirPrice[i].mDay.empty() &&
index 0804b269ac3d8980ae20b33b84c6d0375e3750d8..e2066363b6eef02925a5b0433e8ca45a1cc2af73 100644 (file)
@@ -97,6 +97,34 @@ else
 return true;
 }
 
+template <typename T>
+bool GetChangePolicy(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+std::string type(attr[1]);
+if (type == "allow")
+        value = TARIFF::ALLOW;
+else if (type == "to_cheap")
+        value = TARIFF::TO_CHEAP;
+else if (type == "to_expensive")
+        value = TARIFF::TO_EXPENSIVE;
+else if (type == "deny")
+        value = TARIFF::DENY;
+else
+    return false;
+return true;
+}
+
+template <typename T>
+bool GetChangePolicyTimeout(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+value = readTime(attr[1]);
+return true;
+}
+
 template <typename A, typename T>
 bool GetSlashedValue(const char ** attr, A & array, T A::value_type:: * field)
 {
@@ -131,6 +159,8 @@ GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     AddParser(propertyParsers, "free", info.tariffConf.free);
     AddParser(propertyParsers, "traffType", info.tariffConf.traffType, GetTraffType);
     AddParser(propertyParsers, "period", info.tariffConf.period, GetPeriod);
+    AddParser(propertyParsers, "changePolicy", info.tariffConf.changePolicy, GetChangePolicy);
+    AddParser(propertyParsers, "changePolicyTimeout", info.tariffConf.changePolicyTimeout, GetChangePolicyTimeout);
     for (size_t i = 0; i < DIR_NUM; ++i)
         AddParser(propertyParsers, "time" + unsigned2str(i), info.dirPrice[i], GetTimeSpan);
     AddAOSParser(propertyParsers, "priceDayA", info.dirPrice, &DIRPRICE_DATA::priceDayA, GetSlashedValue);
index 7252a2378a13cb63e77083584363d00fe2b9f765..188aee8a1802cdad240568d766ab392ca783e7a5 100644 (file)
@@ -343,5 +343,113 @@ namespace tut
         ensure_equals("1101 == 0", tariff.GetPriceWithTraffType(0, 6 * 1024 * 1024, 0, 1286461245), 0); // Near 17:30, 6 > 4 DA (ignore night)
         ensure_equals("1110 == 0", tariff.GetPriceWithTraffType(0, 0 * 1024 * 1024, 0, 1286479245), 0); // Near 22:30, 0 < 4 DA (ignore night)
         ensure_equals("1111 == 0", tariff.GetPriceWithTraffType(0, 6 * 1024 * 1024, 0, 1286479245), 0); // Near 22:30, 6 > 4 DA (ignore night)
+   }
+
+    template<>
+    template<>
+    void testobject::test<7>()
+    {
+        set_test_name("Check changePolicy - ALLOW");
+
+        TARIFF_DATA td("test");
+        td.tariffConf.changePolicy = TARIFF::ALLOW;
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL tariff(td);
+
+        td.tariffConf.fee = 50;
+        TARIFF_IMPL cheaper(td);
+
+        ensure_equals("Allow cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), true);
+
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL equal(td);
+
+        ensure_equals("Allow equal", tariff.TariffChangeIsAllowed(equal).empty(), true);
+
+        td.tariffConf.fee = 150;
+        TARIFF_IMPL expensive(td);
+
+        ensure_equals("Allow expensive", tariff.TariffChangeIsAllowed(expensive).empty(), true);
+    }
+
+    template<>
+    template<>
+    void testobject::test<8>()
+    {
+        set_test_name("Check changePolicy - TO_CHEAP");
+
+        TARIFF_DATA td("test");
+        td.tariffConf.changePolicy = TARIFF::TO_CHEAP;
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL tariff(td);
+
+        td.tariffConf.fee = 50;
+        TARIFF_IMPL cheaper(td);
+
+        ensure_equals("Allow cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), true);
+
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL equal(td);
+
+        ensure_equals("Prohibit equal", tariff.TariffChangeIsAllowed(equal).empty(), false);
+
+        td.tariffConf.fee = 150;
+        TARIFF_IMPL expensive(td);
+
+        ensure_equals("Prohibit expensive", tariff.TariffChangeIsAllowed(expensive).empty(), false);
+    }
+
+    template<>
+    template<>
+    void testobject::test<9>()
+    {
+        set_test_name("Check changePolicy - TO_EXPENSIVE");
+
+        TARIFF_DATA td("test");
+        td.tariffConf.changePolicy = TARIFF::TO_EXPENSIVE;
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL tariff(td);
+
+        td.tariffConf.fee = 50;
+        TARIFF_IMPL cheaper(td);
+
+        ensure_equals("Prohibit cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), false);
+
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL equal(td);
+
+        ensure_equals("Allow equal", tariff.TariffChangeIsAllowed(equal).empty(), true);
+
+        td.tariffConf.fee = 150;
+        TARIFF_IMPL expensive(td);
+
+        ensure_equals("Allow expensive", tariff.TariffChangeIsAllowed(expensive).empty(), true);
+    }
+
+    template<>
+    template<>
+    void testobject::test<10>()
+    {
+        set_test_name("Check changePolicy - DENY");
+
+        TARIFF_DATA td("test");
+        td.tariffConf.changePolicy = TARIFF::DENY;
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL tariff(td);
+
+        td.tariffConf.fee = 50;
+        TARIFF_IMPL cheaper(td);
+
+        ensure_equals("Prohibit cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), false);
+
+        td.tariffConf.fee = 100;
+        TARIFF_IMPL equal(td);
+
+        ensure_equals("Prohibit equal", tariff.TariffChangeIsAllowed(equal).empty(), false);
+
+        td.tariffConf.fee = 150;
+        TARIFF_IMPL expensive(td);
+
+        ensure_equals("Prohibit expensive", tariff.TariffChangeIsAllowed(expensive).empty(), false);
     }
 }