Autor Zpráva
tee.vee
Profil *
Dobrý den, řeším takový speciální úkol jak zpracovat objednávkový formulář, který nemá pevně stanovené položky. Nastíním situaci:

Mám databázi výrobků, kde každý výrobek je přiřazen do nějaké kategorie. Dále mám databázi uživatelů, ve které každý uživatel má nastavenou jednu z kategorií (viz stejné kategorie jako pro výrobky). Dále chci vytvořit interní objednávku (tzn. budu jí zadávat sám), zvolím uživatele (tím se mi načtou dostupné pouze ty výrobky, které jsou ve stejné kategorii jako má nastavenou vybraný uživatel).

Příklad:
uzivatel1_kat1 > vyrobek_kat1_kolo1, vyrobek_kat1_kolo2, vyrobek_kat1_kolo3
uzivatel2_kat2 > vyrobek_kat2_sklo1, vyrobek_kat2_sklo2
uzivatel3_kat3 > vyrobek_kat3_sroub1, vyrobek_kat3_sroub2, vyrobek_kat3_sroub3, vyrobek_kat3_sroub4

Tím pádem formulář, ve kterém se mi zobrazí výrobky, bude mít pokaždé jiný počet položek. Jednou budu mít v kategorii třeba 3 výrobky, jindy jich tam bude třeba 10. Takhle interaktivní formulář by šlo zpracovat jednoduše, každému inputu bych přiřadil něco jako:

<input type="text" name="vyrobek[]" value="vyrobek1">
<input type="text" name="vyrobek[]" value="vyrobek2">

...a následně v PHP celý formulář (a všechny inputy) zpracoval jako pole array() způsobem:

$polozky = $_POST[vyrobek];
print_r ($polozky);

... To je ještě v pohodě, ale zásadní problém nastvává tehdy, když těch inputů mám k jednomu výrobku více, tzn. vypíšu si podrobnosti o výrobku z databáze a potřebuji u výrobku ve formuláři zapsat cenu a množství, v příkladu:


Název: Kolo1, Cena: 150, Množství: 0-20ks
Název: Kolo2, Cena: 180, Množství: 0-20ks
Název: Kolo3, Cena: 90, Množství: 0-20ks
...


- kde základní cena se mi vypíše do inputu z databáze (kde ale tuto cenu můžu právě ještě individuálně změnit) a kde musím nastavit množství (0 až 20) - přičemž pokud tam bude množství = 0, tak se nic neobjednává a tento výrobek se do objednávky nezpracuje. Takže se mi vypíše třeba 10 výrobků se základními cenami, a já si objednám pouze ty, u kterých je množství větší nebo rovno 1 kusu.

Tak jsem si říkal, že by se to mohlo udělat stejným způsobem přes ty pole, že by bylo pole cena[] a pole mnozstvi[], jenže jak z toho vyřadit ty, které mají množství 0? tak už mi nebudou souhlasit přeci položky v polích... nebo je prostě nějaký jiný efektivní způsob?

Může mi prosím někdo poradit, jak tuto komplikovanou záležitost vyřešit nebo jak to udělat jinak - a lépe?
yFang
Profil
tee.vee:
Tak jsem si říkal, že by se to mohlo udělat stejným způsobem přes ty pole, že by bylo pole cena[] a pole mnozstvi[], jenže jak z toho vyřadit ty, které mají množství 0? tak už mi nebudou souhlasit přeci položky v polích...
Tak musíš odstranit zároveň tomu odpovídající položku v poli cena. Třeba něco jako:

foreach ($_POST['mnozstvi'] as $k => $h)
{
   if( $h != 0 ) {
       $mnozstvi[] = $h;
       $cena[] = $_POST['cena'][$k];
   }
}

kde $mnozstvi a $cena jsou pole bez prvků, která mají množství 0.
tee.vee
Profil *
yFang:
ANO! jasně! TO je přesně ono... díky!

víceméně bych to mohl rozšířit o něco takového:

foreach ($_POST['mnozstvi'] as $k => $h)
{
   if( $h != 0 ) {
       $mnozstvi[] = $h;
       $cena[] = $_POST['cena'][$k];
       $nazev[] = $_POST['nazev'][$k];
       
       //zacnu postupne vybirat obsah poli od prvniho (nulta pozice)
       $pocatek = 0;
       
       //ulozim si data z pole do stringu
       $sqlnazev = $nazev[$pocatek];
       $sqlcena = $cena[$pocatek];
       $sqlmnozstvi = $mnozstvi[$pocatek];
       
       //zjistim novy radek v sql (pokud nastaveno na AI)
       $newIDrow = "(SELECT MAX(id) FROM tabulka)";
       
       //provedu zapis jedne polozky objednavky do databaze
       $insertsq = sprintf("INSERT INTO tabulka (id, nazev, cena, mnozstvi) VALUES ('%s', '%s', '%s', '%s')",
            mysql_real_escape_string($newIDrow),
            mysql_real_escape_string($sqlnazev),
            mysql_real_escape_string($sqlcena),
            mysql_real_escape_string($sqlmnozstvi));
    mysql_query($insertsq);
       
       //zvysim string $pocatek o dalsi cislo
       $pocatek++;
   }
}

Takhle to už vypadá i dobře, ale nefunguje to úplně korektně. String $pocatek zůstává ve výše uvedeném kódu stále na 0, to znamená pokud vyberu třeba 4 položky, 4x se mi vloží do databáze to stejné (takže se $pocatek prostě nezvyšuje). Snažil jsem se vložit na celou operaci ještě while cyklus, spočítat si přes count($mnozstvi) - což spočítalo celkový počet záznamů ve vyhovujícím poli (to je také dobře), ale nepochopil jsem proč první dva záznamy pole byly stejné, pokud jsem si celkově zvolil třeba 4 položky - tzn vypadalo to takto:

[0] - název: kolo1, cena: 250, množství: 3;
[1] - název: kolo1, cena: 250, množství: 3;
[2] - název: kolo2, cena: 280, množství: 1;
[3] - název: kolo3, cena: 170, množství: 5;

(přitom čtvrtá položka se jednoduše nezobrazila, a pokud jsem $pocatek misto 0 dal na 1, nevypisovalo se zase vůbec nic. Spíš mi nejde na rozum, proč jsou dva řádky zdvojené...). Dělám ještě někde nějakou zásadní chybu? Děkuji za pomoc
Tori
Profil
tee.vee:
Proměnná $pocatek se při každém průchodu cyklem nastavuje na nulu, tzn. první položku pole. Kontrolujte, co vrací mysql_query, jestli se vůbec insert provedl - pokud je na sloupci ID unikátní klíč, tak by měl dotaz opakovaně selhávat.

Jestli správně chápu, funguje to takto: máte tabulku produktů. Vytvoříte objednávku a do ní přiřazujete produkty, které mohou v objednávce mít jinou cenu, než v tabulce produktů. Takže si vypíšete do formuláře všechny tomuto uživateli dostupné produkty, zadáte objednané množství a můžete změnit cenu. Tak správně?
Pak bych měla tabulku objednávky (ID objednávky - PK, ID uživatele - FK, datum, stav, ...), a tabulku objednané zboží (ID objednávky - FK, ID zboží - FK, cena, množství, primární klíč přes sloupce ID objednávky+ID zboží).
Ve formuláři přidávání zboží do objednávky se bude imho líp pracovat s položkami, když budete znát ID zboží:
echo 'Zboží: ' . $row['nazev']
    .'Cena: <input type="text" name="vyrobek[' . $row['id_zbozi'] . '][cena]" value="' . $row['cena'] . '">'
    .'Množství: <input type="text" name="vyrobek[' . $row['id_zbozi'] . '][mnozstvi]" value="0">'
    .' (dostupné množství ' . $row['mnozstvi'] . ' ks)';
Zpracování formuláře by vypadalo nějak takhle:
$id_objednavky = ...; // nějak zjistíte, asi skryté pole formuláře
$values = '';
foreach ($_POST['vyrobek'] as $id_zbozi => $zbozi) {
    if ($zbozi['mnozstvi'] > 0) {
        $values .= sprintf('(%d, %d, %f, %d), ',
            $id_objednavky,
            $id_zbozi,
            $_POST['vyrobek'][$id_zbozi]['cena'],
            $_POST['vyrobek'][$id_zbozi]['mnozstvi']
        );
    }
}
if ($values) {
    $sql = 'INSERT INTO objednaneZbozi (id_objednavky, id_zbozi, cena, mnozstvi) VALUES ' . rtrim($values, ', ');
    // ... ulozeni
}
tee.vee
Profil *
Tori:
Ahoj, je to víceméně přesně tak, jak říkáš - děkuji za ukázku. Vyzkoušel jsem Tvé řešení a funguje dobře, až na malý detail - $id_zbozi v sobě nemá žádnou hodnotu - tedy má - zapisuje stále a jen nulu (což je špatně, mělo by to být ID výrobku). Ostatní položky se zapisují však dobře - hodnoty se přenesou.

Chtěl jsem ještě přidat zapisování názvu výrobku (principiálně by to mělo být stejné jako u jiných položek), udělal jsem si:

<input type="hidden" name="vyrobek['".$article['id']."'][nazev]" value="".$article['article_name']."" />

což vypíše vše tak jak má a do proměnné $values jsem přidal:

...
$_POST['vyrobek'][$id_zbozi]['nazev'],
...

... a do sprintf jsem zkoušel přidat jiné typy ale buď se zápis do databáze neprovedl vůbec, nebo s nulovou hodnotou. Snažil jsem se podle manuálu ohledně sprintf dohledat nějakou funkční variantu ale dohromady se mi to zkloubit nepovedlo :/ Tuším, že v tom bude nějaká školácká chyba nebo moje hloupost... ještě jednou děkuji za pomoc.
Tori
Profil
tee.vee:
A jo, omlouvám se, přidala jsem navíc apostrofy do atributu name, nemají tam být, proto se to vyhodnocovalo jako nula. Nejsou escapované uvozovky.
echo "<input type=\"hidden\" name=\"vyrobek[".$article['id']."][nazev]\" value=\"".$article['article_name']."\" />";

Ad název, který se nevkládá: Doplnit jste název sloupce na ř.14? Je hodnota do $values zadaná ve stejném pořadí, jako název sloupce? Nechybí zástupný znak na ř.5? Jinak nemusí tam být nutně sprintf, stačí prostě skládat řetězec a vkládané hodnoty z formuláře escapovat.
tee.vee
Profil
Tori:
Děkuji, apostrofy jsou vyřešeny - bylo to opravdu tím, také jsem to přehlédnul :)

Já bych tam klidně nechal tento typ řetězce, poupravil jsem i ten název ale stále to nefunguje - podle mě je chyba v tom zvoleném typu, teď tam mám %d a s ním to vypisuje nulu. Pořadí jsem kontroloval, to by mělo být v pořáku, jako by mělo být pořadí sloupců v tabulce.

Ve finále jsem to upravil takto:

            $id_objednavky = $orderID; //načtení ID objednávky
            $values = '';
            foreach ($_POST['vyrobek'] as $id_zbozi => $zbozi) {
                if ($zbozi['mnozstvi'] > 0) {
                    $values .= sprintf('(%d, %d, %d, %f, %d), ',
                        $id_objednavky,
                        $id_zbozi,
                        $_POST['vyrobek'][$id_zbozi]['nazev'],
                        $_POST['vyrobek'][$id_zbozi]['cena'],
                        $_POST['vyrobek'][$id_zbozi]['mnozstvi']
                    );
                }
            }
            if ($values) {
                $sql = 'INSERT INTO objednanezbozi (id_objednavky, id_vyrobku, nazev_vyrobku, cena_vyrobku, mnozstvi_vyrobku) VALUES ' . rtrim($values, ', ');
                mysql_query($sql);
            }

- zde jsem se snad nedopustil žádné chyby... jen si pořád nejsem jistý tím datovým typem...
Tori
Profil

$values .= sprintf('(%d, %d, "%s", %f, %d), ',
                        $id_objednavky,
                        $id_zbozi,
                        mysql_real_escape_string($_POST['vyrobek'][$id_zbozi]['nazev']),
                        $_POST['vyrobek'][$id_zbozi]['cena'],
                        $_POST['vyrobek'][$id_zbozi]['mnozstvi']
                    );
- je to řetězec.
tee.vee
Profil
Tori:
Jasné, teď už to funguje! Perfektní, děkuji mockrát.

Víceméně tímto je hlavní problém vyřešen.

Zeptám se ještě k tématu - ale jen obecně - v případě, kdybych chtěl rovnou přepočítat ceny s množstvím, je výhodnější to udělat hned při zpracování jednotlivích polí před samotným zápisem do databáze, nebo bude efektivnější přepočítat si hodnoty někde zvlášť z již uložených hodnot (z databáze). Víceméně, teoreticky, když mám dvě tabulky (do jedné ukládám obecné informace o objednávce - kdo, kdy, za kolik, ... a do druhé pouze položky konkrétních objednávek - id objednávky, id zboží, cenu za kus, množství). Bude tam muset být právě stejnak nějaká funkce, která mi vezme celou objednávku (všechny objednané položky), vynásobí cenu za kus * objednané množství, a výsledné částky sečte do celkové ceny (úplně za celou objednávku).

Teď si tak říkám, že by bylo možná ještě lepší, kdyby se v tabulce položek objednávek přidal ještě jeden sloupec s přepočtenou cenou (rovnou cena za kus * množství). Pak by mi stačilo sečíst jen sloupec s výslednými cenami a udělat z toho cenu celkovou... je to dobrá myšlenka?
Tori
Profil
tee.vee:
v případě, kdybych chtěl rovnou přepočítat ceny s množstvím, je výhodnější to udělat hned při zpracování jednotlivích polí před samotným zápisem do databáze, nebo bude efektivnější přepočítat si hodnoty někde zvlášť z již uložených hodnot (z databáze)
Tohle můžete udělat jen tehdy, pokud odesíláte formulářem celou objednávku a dostanete z něj všechny potřebné hodnoty. V ostatních případech (smazání jedné položky z objednávky, AJAXem řešená změna objednaného množství jedné položky apod.) to musíte dopočítat podle hodnot z DB. Myslím, že by to mělo jít jedním UPDATEm, ale nevím odhadnout, jestli i v případě, že objednané produkty mají různou DPH. Anebo vlastně můžete udržovat obsah košíku/objednávky zároveň v session, pak byste to mohl snadno přepočítávat v PHP i při těch změnách jediné položky.
(Možná by v tabulce objednaného zboží měl být ještě sloupec DPH a v tabulce objednávek sloupce pro celkovou cenu s i bez DPH.)

Osobně bych doplňování celkové ceny JavaScriptem ve formuláři nechala jen jako vylepšení UI pro uživatele a při ukládání to stejně přepočítala podle jednotkové ceny * množství * DPH. Ale je to jen můj názor. K ukládání ceny za kus*množství vám lépe poradí někdo jiný, nemám zkušenosti s eshopy.
tee.vee
Profil
Tori:
Dobrý den, děkuji za vyjádření, principiálně mi to je jasné jak píšete.

Ještě jednou bych Vám chtěl poděkovat za pomoc při řešení tohoto komplexního zpracování.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0