ugrás a tartalomhoz

MySQL bonyolódás

Termes · 2017. Aug. 3. (Cs), 13.17
Sziasztok!

Kicsit belebonyolódtam. Egy jutalékszámító részleten dolgozom, ami fejtörést okozott.

Adott 3 csomag (id->7,8,9), amit választani lehet a tagságnál. Az ügynök, aki eladja jutalékot kap az üzletből, amit ennek a kódrészletnek kellene kiszámítania. Az első csomag utáni összeget 3 hónapra elosztva kell kifizetni, a többi csomag után járó jutalékot egy összegben. Ezt kell ellenőrizni, hogy jár-e egyáltalán jutalék és, ha igen, akkor mennyi.

Köszi előre is a segítségeket.

<?php
//...
$result_bonusz = mysql_query(
    'SELECT
        *
    FROM
        mt_merchant
    WHERE
        year(date_created) = ' . $ev . '
    AND
        month(date_created) = ' . $ho . '
    AND
        status="active"
    AND
        ugynok = ' . $i . '');
$bonusz_row = mysql_fetch_array($result_bonusz);

if ($bonusz_row['package_id'] == 8) {
    $bonusz_1 = 30000;
    $kifizetheto = 1;
} elseif ($bonusz_row['package_id'] == 9) {
    $bonusz_2 = 50000;
    $kifizetheto = 1;
} elseif ($bonusz_row['package_id'] == 7) {

    $result_bonusz_ell_3 = mysql_query(
        'SELECT
            merchant_id
        FROM
            mt_merchant
        WHERE
            package_id = 7
            AND (
                date_created BETWEEN (
                    NOW(), INTERVAL 3 MONTH
                ) AND (
                    NOW(), INTERVAL 2 MONTH
                )
            ) AND
                status="active"
            AND
                ugynok = ' . $i . '');
    if (mysql_num_rows($result_bonusz_ell_3) != 1) {
        $bonusz_3 = 0;
    } elseif (mysql_num_rows($result_bonusz_ell_3) == 1) {
        $bonusz_3 = 10000;
    } else {
        $bonusz_3 = 0;
    }

    $result_bonusz_ell_4 = mysql_query(
        'SELECT
            merchant_id
        FROM
            mt_merchant
        WHERE
            package_id = 7
            AND (
                date_created BETWEEN (
                    NOW(), INTERVAL 2 MONTH
                ) AND (
                    NOW(), INTERVAL 1 MONTH
                )
            ) AND
                status="active"
            AND
                ugynok = ' . $i . '');
    if (mysql_num_rows($result_bonusz_ell_4) != 1) {
        $bonusz_4 = 0;
    } elseif (mysql_num_rows($result_bonusz_ell_4) == 1) {
        $bonusz_4 = 10000;
    } else {
        $bonusz_4 = 0;
    }

    $bonusz_3 = 10000;
    $kifizetheto = 3;

} else {
    $bonusz_3 = 0;
    $kifizetheto = 0;
}

$bonusz = $bonusz_1 + $bonusz_2 + $bonusz_3 + $bonusz_4;

print $i . " | " . $jutalek . " + " . $bonusz . " <br>";
//...
 
1

Problemak

janoszen · 2017. Aug. 3. (Cs), 13.34
Eloszor is, nemi problemak vannak a koddal:

1. Legkozelebb legyszives formazd meg a kodot hogy ne a kepernyo jobb szelen kezdodjon es ne legyen 300+ karakter hosszu egy sor. Ezt most megtettem helyetted.
2. A mysql fuggvenyek deprecated-ek es PHP 7-ben mar nem mukodnek. Helyette allj at a mysqli-re vagy PDO-ra.
3. A kodot SQL injection gyanus, melegen ajanlom a prepared statementekkel valo megismerkedest. (Ha nem tudod mi ez, gondolj a BKK-s bruhahara.)

Ezen felul a problemad megoldasara ha javasolhatom a tesztek irasat. Olvasd ki a szukseges adatokat MySQL-bol es az uzleti logikadat PHP-ban ird meg, ne SQL-ben. Ha ugyesen levalasztod az adatbetoltest, akkor a tesztjeid akar adatbazis nelkul is tudnak mukodni.

Ami a konkret problemadat illeti, sajnos nem nagyon tudunk segiteni mert nem irtad le a szabalyokat hogy ki mikor mennyi bonuszt kap. Sztem ird le magyar mondatokban kod nelkul, listaba szedve hogy kinek mikor jar a jutalek, es akkor jobban tudunk segiteni.

Bonusz pontok:

- A kodod lehetoleg olyan legyen, hogy azt angolul tudo ember programozasi tudas nelkul el tudja olvasni. Ugy kisebb a valoszinusege a hibanak.
- Javaslom, hogy szervezd at a kododat ugy, hogy a csomagokhoz tartozo jutalek ne a kodba legyen beegetve, hanem szinten az adatbazisban keruljon eltarolasra, mert az uzleti vezetoseg tuti fog olyan otlettel jonni, hogy jo lenne ha lenne meg csomag.
2

Köszi

Termes · 2017. Aug. 3. (Cs), 13.56
1. Rendben. A kimásolt kódrészlet a formázások miatt tolódott el ennyire, erre nem figyeltem.

2. Még nem 7-es PHP fut a szerveren, pontosan a módosítások miatt.. idővel :)

3. Köszi.

Ezt a szkriptet cron futtatná le minden hó utolsó napján adott időpontban.
Feladata (lenne) az adatbázisban szereplő ügyfeleket lefuttatni és a jutalékokat kiszámolni, majd beszúrni az adatbázisba.

A csomagok után jutalékot kap az ügynök, illetve egy egyszeri bónuszt a friss kötésért ugyanarra a csomagra. Pl: 1. csomag (id->7) egyszeri bónusz (30000 ft -> 3 hónapra lebontva) és a hozzá tartozó jutalék havonta 3000 forint, amíg aktiv a csomag, tehát fizetve van.

A többi csomag esetén egyszeri bónusz van 30000 és 50000, valamint a jutalék 2000 és 1000 ft.

A bontásban akadtam el igazából. Meg kellene nézni, hogy az aktuális hónapban létezik-e olyan ügyfél, akinek van regisztrációja és aktív (id->7) csomagja. Ha van, akkor 10000 forintot jóváír. Ha nincs, akkor ellenőrzi, hogy az elmúlt 1 hónapban volt-e regisztráció és jelenleg aktív-e a csomagja, ha igen, akkor újra 10000 ft-ot ír jóvá. És így az elmúlt 2 hónapra nézve is ugyanígy jár el. Csak akkor jár a bónusz, ha aktív a csomag.

Azt hiszem erre keresek megoldást.
3

Ertem

janoszen · 2017. Aug. 3. (Cs), 14.23
Ertem, tehat valojaban a Te rendszered ugy nez ki, hogy minden csomaghoz ket szam tartozik: hogy mennyi a jutalek es hany honapra van lebontva (ami lehet egy is).

En ezt a feladatot kicsit maskepp oldanam meg. Tegyuk fel, hogy rendelek egy csomagot amihez 30000 Ft jutalek tartozik 3 reszre bontva. Egyreszt ezt az infot DB-ben tarolnam hogy kesobb konnyu legyen uj jutalekokat felvenni. Masreszt amikor megveszem a csomagot, akkor a 3 jutalekreszt azonnal elore beirnam egy "elojegyzes" tablaba. Ide felvinnem azt, hogy 1. kinek 2. mennyi jutalek 3. mikor 4. mely elofizetes aktivitasa eseten jar.

Vagyis a cronjobodnak annyi a feladat a hogy ezt az elojegyzes tablat nezi meg, hogy melyek azok az elojegyzesek amik meg nem lettek feldolgozva es a mai napnal korabban jarnak. Az elofizetes ID alapjan megnezed hogy tenylegesen jar-e, es ha igen, akkor tenylegesen jova is irod, majd torlod az elojegyzest.

Igy egyreszt konnyebb lesz boviteni a rendszert, masreszt egy csomo szivasba nem szaladsz bele.
4

Nem olyan egyszerű ez nekem

Termes · 2017. Aug. 3. (Cs), 14.48
Az igazsághoz tartozik, hogy van egy alaprendszer, amihez természetesen semmi közöm. Ez jól is működik, ám jött az ötlet, hogy kibővíthetném magamnak ezzel a jutalékos rendszerrel. Na, innentől nem működik a dolog :)

Ez egy cégadatbázis, melybe lehet regisztrálni cégeknek, ehhez jönnek az üzletkötők.

Az általam megálmodott szkript a már meglévő adatbázisba nyúlkálva hozná össze a dolgot. Mivel az alaprendszer yii keretrendszert használ, így megoldott, hogy nem nyúlok bele. :)

Úgy kellene megoldanom, hogy nem bántom a rendszert.

Emiatt kuszálódtam össze. Tehát a regisztráció menetébe nem tudok belenyúlni, csak a kész adatbázissal dolgozhatok.

Az egyszeri kifizetéseket le tudom kezelni, megnézem, hogy abban a hónapban van-e új regisztrált, aki fizetett a csomagért, ha van akkor jár.

Itt a 3 havi lebontást nem értem, hogyan tudnám megoldani. Hogyan követhetném nyomon? Csak akkor jár a bónusz, ha aktív a csomag és maximum 3 egymást követő hónapig jár. Tehát, ha csak az első hónapban fizet és tovább nem, akkor csak 10000 forint jár, ha kettőt fizet, akkor 20000 és ha hármat, akkor a 30000. Vagyis 10-10-10E.

Úgy oldottam meg eddig, hogy megszámoljuk, hogy hány üzletkötő van és egy hurokban szépen egymás után lefuttatjuk a lekérdezéseket. Nyilván van jobb megoldás is, de az én szintemen kellene megoldani amennyire csak lehetséges. :)
5

Nem

janoszen · 2017. Aug. 4. (P), 09.26
Figy, ilyen jutalékokat hardkódolni a legrosszabb ötlet. Az üzleti vezetés állandóan új kérésekkel (most legyen 4 hónap, stb) fog jönni és a végén egy hatalmas spagetti lesz a kód.

Nézzük részletesen. Amikor megtörténik a vásárlás, kiolvasod a csomag adatait:

SELECT
  csomag_id,
  havi_jutalek,
  jutalek_honapok
FROM
  csomagok
WHERE
  ...
Ezek után beszúrod az előjegyzést egy for loopban:

for ($i=0;$i<$jutalek_honapok;$i++) {
  sql("
    INSERT INTO jutalek_elojegyzes (
      ugynok_id,
      elofizetes_id,
      targynap
      jutalek
    VALUES (
      ?,
      ?,
      DATE_ADD(NOW(), INTERVAL ? MONTH),
      ?
    ",
    $ugynok_id,
    $elofizetes_id,
    $i,
    $havi_jutalek
  );
}
Az sql() függvény itt egy általam elképzelt valami ami a kérdőjelek helyére biztonságos módon behelyettesíti a paramétereket pl PDO-val.

Ha megnézed, ez a fenti kód egy hónap elosztással beszúrja az előjegyzés táblába a sorokat.

Na most, a cronjobodnak utána csak annyi dolga van hogy ezen végig menjen:

$rows = sql("
SELECT
  elojegyzes_id,
  ugynok_id,
  elofizetes_id,
  jutalek
FROM
  jutalek_elojegyzes
WHERE
  targynap<NOW()
");
foreach ($rows as $row) {
  if (elofizetes_aktiv($row[" elofizetes_id"], $row["targynap"])) {
     jutalek_jovair($row["ugynok_id"], $row["jutalek"]);
  }
  sql("DELETE FROM jutalek_elojegyzes WHERE elojegyzes_id=?", $row["elojegyzes_id"]);
}
És ennyi. Mennyivel egyszerűbb, nem? (Annyira egyszerű, hogy mobilon be tudtam pötyögni.) Érdemes strukturálni a kódodat, úgy sokkal kevésbé gabalyodsz bele.

Még egy megjegyzés: ha valamiért nem akarsz hozzányúlni a vásárlási folyamathoz, az sem probléma, azt is elvégezheted cronjobból, csak jegyezd fel melyik vásárlást dolgoztad már fel.
6

Wow

Termes · 2017. Aug. 4. (P), 10.07
Köszönöm a segítséget és a kritikát. Neki is ugrok.
7

Tranzakcio

janoszen · 2017. Aug. 4. (P), 11.01
Arra meg esetleg erdemes figyelni, hogy a cronjobos feldolgozast erdemes egy tranzakciobol csinalni. Ha lerohad, akkor ne legyen felig kiirt adat. :)