Ïðèìå÷àíèå: çäåñü íàõîäèòñÿ îïèñàíèå ñòàðîé âåðñèè ïðîãðàììû True Shop 1.47 (ãîä âûïóñêà 2007). Ïðîãðàììà áûëà óñïåøíî âíåäðåíà è ðàáîòàëà áîëåå îäíîãî ãîäà. Ëþäÿì ïðîãðàììà ïîíðàâèëàñü è áûëî ïðèíÿòî ðåøåíèå âûïóñòèòü âòîðóþ âåðñèþ. Ïåðâàÿ âåðñèÿ ïðîãðàììû íå ñîäåðæèò èíñòàëëÿòîðà, è âîçìîæíîñòåé ó íå¸ íàìíîãî ìåíüøå, ÷åì ó âòîðîé âåðñèè (ðàç â ïÿòü). Ïîýòîìó å¸ îïèñàíèå çäåñü âûëîæåíî òîëüêî äëÿ îçíàêîìëåíèÿ. Îïèñàíèå àêòóàëüíîé âåðñèè ïðîãðàììû äëÿ àâòîìàòèçàöèè òîðãîâëè ìîæíî ïîñìîòðåòü çäåñü.
ÔÅÄÅÐÀËÜÍÎÅ ÀÃÅÍÒÑÒÂÎ ÏÎ ÎÁÐÀÇÎÂÀÍÈÞ ÐÔ
ÃÎÑÓÄÀÐÑÒÂÅÍÍÎÅ ÎÁÐÀÇÎÂÀÒÅËÜÍÎÅ Ó×ÐÅÆÄÅÍÈÅ
ÂÛÑØÅÃÎ ÏÐÎÔÅÑÑÈÎÍÀËÜÍÎÃÎ ÎÁÐÀÇÎÂÀÍÈß
ÂÎËÎÃÎÄÑÊÈÉ ÃÎÑÓÄÀÐÑÒÂÅÍÍÛÉ ÏÅÄÀÃÎÃÈ×ÅÑÊÈÉ
ÓÍÈÂÅÐÑÈÒÅÒ
ÂÛÏÓÑÊÍÀß ÊÂÀËÈÔÈÊÀÖÈÎÍÍÀß ÐÀÁÎÒÀ
ÍÀ ÒÅÌÓ:
«Àâòîìàòèçàöèÿ ðàáîòû õîçÿéñòâåííîãî
ìàãàçèíà»
Âûïîëíèë: ñòóäåíò 5 êóðñà
ôàêóëüòåòà ÏÌèÊÒ
Ãîð÷àêîâ Èâàí Ìèõàéëîâè÷
Íàó÷íûé ðóêîâîäèòåëü:
ê.ò.í., ïðîôåññîð
Ðæåóöêàÿ Ñâåòëàíà Þðüåâíà
Âîëîãäà
2007
1. ÀÍÀËÈÇ
ÏÐÅÄÌÅÒÍÎÉ ÎÁËÀÑÒÈ È ÎÏÐÅÄÅËÅÍÈÅ ÒÐÅÁÎÂÀÍÈÉ Ê ÑÈÑÒÅÌÅ
1.1. Àíàëèç
êðóãà ïîëüçîâàòåëåé
1.3. Òðåáîâàíèÿ
çàêàç÷èêà ê ïîëüçîâàòåëüñêîìó èíòåðôåéñó
2.2. Ëîãè÷åñêàÿ
ñõåìà áàçû äàííûõ:
2.2.1. Îïèñàíèå ñòðóêòóðû
òàáëèö
2.2.2. Íîðìàëèçàöèÿ áàçû äàííûõ
3.2. Îñîáåííîñòè
ðåàëèçàöèè ïðèëîæåíèÿ
3.3. Îïèñàíèå
ïîëüçîâàòåëüñêîãî èíòåðôåéñà
4.4.
×åòâåðòûé ýòàï òåñòèðîâàíèÿ
2. Òåêñòû çàïðîñîâ, õðàíèìûõ ïðîöåäóð, òðèããåðîâ
Ïðîöåäóðà IsCorrectFloatString
Ïðîöåäóðà NaturalNumberUp999ToString
Ïðîöåäóðà DrawGraphLineWithSpline
Ôóíêöèè DateDays, DateSeconds áèáëèîòåêè libraryDateDaysSeconds
Ìîäóëü äëÿ ðàáîòû ñ êàññîâûì
àïïàðàòîì
Öåëü äàííîé ðàáîòû çàêëþ÷àåòñÿ
â àâòîìàòèçàöèè ðàáîòû íåáîëüøîãî õîçÿéñòâåííîãî ìàãàçèíà. Äàííàÿ îðãàíèçàöèÿ
çàíèìàåòñÿ òåì, ÷òî ïðèâîçèò õîçòîâàðû ñ îïòîâûõ áàç, çàòåì òîðãóåò èìè. Äàííàÿ
ïðîãðàììà ïîçâîëÿåò îïåðàòèâíî ôèêñèðîâàòü îñòàòêè òîâàðîâ íà ñêëàäå, öåíû íà
òîâàðû, ïðîäàâàòü òîâàðû (ïðîáèâàòü ÷åêè, ïå÷àòàòü òîâàðíûå ÷åêè, ôèêñèðîâàòü
ïðîäàæè â áàçå äàííûõ) è äåëàòü âîçâðàò. Òàêæå ïðîãðàììà äàåò ñòàòèñòèêó ðàáîòû
ìàãàçèíà (îáùàÿ ïðèáûëüíîñòü ìàãàçèíà, çàâèñèìîñòü ÷èñëà ïîêóïàòåëåé è
ïðèáûëüíîñòè îò âðåìåíè ñóòîê, îò äíÿ íåäåëè, îò ÷èñëà ìåñÿöà, îò ìåñÿöà, îò
âðåìåíè ãîäà è ò. ä.). Ïðîãðàììà òàêæå ñîäåðæèò îò÷åòû, íåîáõîäèìûå äëÿ
íîðìàëüíîé ðàáîòû ìàãàçèíà. Ïî æåëàíèþ çàêàç÷èêà â íåå ìîãóò áûòü äîáàâëåíû
íîâûå îò÷åòû, íåîáõîäèìûå åìó, êîòîðûõ íåò â äàííîé ïðîãðàììå.
Ïîäîáíûå ïðîãðàììû óæå,
êîíå÷íî, ñóùåñòâóþò, íî äàííàÿ ïðîãðàììà èìååò ïåðåä íèìè íåêîòîðûå
ïðåèìóùåñòâà:
1) Ïðîãðàììà ñîäåðæèò òîëüêî
íåîáõîäèìûå ôóíêöèè è íè÷åãî ëèøíåãî, òàêæå ó íåå ïðîñòîé è ïîíÿòíûé
ïîëüçîâàòåëüñêèé èíòåðôåéñ. Ïîýòîìó ñ íåé ìîãóò ðàáîòàòü ïîëüçîâàòåëè, íå î÷åíü
õîðîøî ðàçáèðàþùèåñÿ â êîìïüþòåðàõ.
2) Ïðîãðàììà ïîçâîëÿåò
ìàêñèìàëüíî ëåãêî è áûñòðî ââîäèòü òîâàðû, ïðèâåçåííûå ñ îïòîâûõ áàç, à òàêæå
âûïîëíÿòü ïîèñê ïî çàäàííûì ïàðàìåòðàì.
3) Ïðîãðàììà ìîæåò áûòü
äîðàáîòàíà ïî æåëàíèþ çàêàç÷èêà (èçìåíåí èíòåðôåéñ, äîáàâëåíû íîâûå âîçìîæíîñòè
(íîâûå âèäû ïîèñêà, îò÷åòíîñòü, ñòàòèñòèêà)).
4) Åñëè ó çàêàç÷èêà âîçíèêíóò
êàêèå-ëèáî ïðîáëåìû ñ ïðîãðàììîé, îíè ìîãóò áûòü ðåøåíû ñ ìèíèìàëüíûìè
çàòðàòàìè ñèë è ñ ìàêñèìàëüíîé ýôôåêòèâíîñòüþ (òàê êàê àâòîð ñàì ðàçðàáàòûâàë
ïðîãðàììó ñ íóëÿ).
Ïðîãðàììîé
äîëæíû ïîëüçîâàòüñÿ ñëåäóþùèå ðàáîòíèêè ïðåäïðèÿòèÿ:
Äëÿ êàæäîãî èç ñîòðóäíèêîâ ïðåäïðèÿòèÿ ïðîãðàììà äîëæíà îáåñïå÷èâàòü ñëåäóþùèå âîçìîæíîñòè:
1) Êàññèðó – âîçìîæíîñòü áûñòðî
íàõîäèòü íóæíóþ èíôîðìàöèþ â áàçå, ïðîäàâàòü òîâàðû è äåëàòü âîçâðàò îò
ïîêóïàòåëÿ.
2) Ìåíåäæåðó – âîçìîæíîñòü
çàíîñèòü òîâàðû, ïðèâåçåííûå ñ îïòîâûõ áàç, áûñòðî íàõîäèòü íóæíóþ èíôîðìàöèþ â
áàçå (êàêèå òîâàðû åñòü íà ñêëàäå, ïî êàêèì öåíàì, ñåáåñòîèìîñòü òîâàðîâ,
ñòàòèñòè÷åñêèå äàííûå è ò. ä.), à òàêæå âîçìîæíîñòü ïå÷àòàòü îò÷åòû.
3) Ðóêîâîäèòåëþ ïðåäïðèÿòèÿ –
âîçìîæíîñòü áûñòðî íàõîäèòü íóæíóþ èíôîðìàöèþ â áàçå, ïðîñìàòðèâàòü ñòàòèñòèêó
ðàáîòû ïðåäïðèÿòèÿ, ïå÷àòàòü îò÷åòû, èçìåíÿòü öåíû íà òîâàðû.
1.2. Òðåáîâàíèÿ çàêàç÷èêà ê
ôóíêöèîíàëüíîñòè ïðîãðàììû
1) Ðàáîòà êàññèðà
Ïðîöåññ ïðîäàæè òîâàðà
äîëæåí âûãëÿäåòü òàê:
 ïðîöåññå ïðîäàæè êàññèð
äîëæåí âèäåòü ïåðåä ñîáîé òàáëèöó ñ èíôîðìàöèåé î ïðîäàâàåìûõ òîâàðàõ.
Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü êàññèðó äîáàâëÿòü çàïèñè â òàáëèöó
(ñ ïîìîùüþ ââîäà ìàãàçèííîãî êîäà òîâàðà èëè ñ ïîìîùüþ ñêàíåðà, à òàêæå, åñëè
ñêàíåðà íåò ïîä ðóêîé, ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü âðó÷íóþ
ââåñòè ñêàí-êîä), à òàêæå èçìåíÿòü èõ è óäàëÿòü. Êàæäàÿ ñòðîêà òàáëèöû äîëæíà
ñîîòâåòñòâîâàòü ïðîäàâàåìîìó òîâàðó.
 ñòðîêå äîëæíû îòîáðàæàòüñÿ
ñëåäóþùèå äàííûå: ìàãàçèííûé êîä òîâàðà, íàçâàíèå òîâàðà, åäèíèöà èçìåðåíèÿ è
öåíà. Òàêæå â ñòðîêå äîëæíî áûòü ïîëå äëÿ ââîäà ïðîäàâöîì êîëè÷åñòâà
ïðîäàâàåìîãî òîâàðà, ïîëå äëÿ ââîäà ñêèäêè, è ïîëå, â êîòîðîì îòîáðàæàåòñÿ öåíà
ñî ñêèäêîé.
Ïðîãðàììà äîëæíà
ïðåäîñòàâëÿòü âîçìîæíîñòü ïðîäàâöó ââîäèòü ñêèäêó, à òàêæå èçìåíÿòü äàííûå â
ïîëå, ãäå îòîáðàæàåòñÿ öåíà ñî ñêèäêîé. Ïðè ýòîì ïðîãðàììà äîëæíà àâòîìàòè÷åñêè
ðàññ÷èòûâàòü ñêèäêó ïî èñõîäíîé öåíå è öåíå ñî ñêèäêîé.
 ñàìîì ïðàâîì ñòîëáöå êàæäîé ñòðîêè äîëæíà
îòîáðàæàòüñÿ èíôîðìàöèÿ î ñòîèìîñòè ââåäåííîãî êîëè÷åñòâà òîâàðà äàííîé ñòðîêè.
Åñëè âñå äàííûå ïðîäàâåö
ââåë ïðàâèëüíî, íà ýêðàíå äîëæíà îòîáðàæàòüñÿ îáùàÿ ñòîèìîñòü âñåõ ïðîäàâàåìûõ
òîâàðîâ. Ïîñëå ýòîãî ïðîäàâåö äîëæåí ââåñòè ñóììó, êîòîðóþ îí ïîëó÷èë îò
ïîêóïàòåëÿ, â ïîëå «Íàëè÷íûå». Ïðè ýòîì ïðîãðàììà äîëæíà ðàññ÷èòàòü ñäà÷ó.
Åñëè ñóììà â ïîëå «íàëè÷íûå»
ìåíüøå îáùåé ñòîèìîñòè òîâàðîâ, ïðîãðàììà íå äîëæíà äàâàòü âîçìîæíîñòü ïðîáèòü
÷åê.
Ïîñëå òîãî, êàê ÷åê ïðîáèò,
ïðîãðàììà äîëæíà ïðåäîñòàâèòü ïðîäàâöó âîçìîæíîñòü íàïå÷àòàòü òîâàðíûé ÷åê.
Ïðîãðàììà äîëæíà
ïðåäîñòàâëÿòü êàññèðó âîçìîæíîñòü âîçâðàòà òîâàðà. Ïðîöåññ âîçâðàòà òîâàðà
äîëæåí âûãëÿäåòü òàê:
Ïðè ïðîäàæå òîâàðà íà êàæäîì
÷åêå äîëæåí ïå÷àòàòüñÿ êîä ïîêóïêè. Ïðè âîçâðàòå òîâàðà ïðîäàâåö ââîäèò êîä
ïîêóïêè, íàïèñàííûé íà ÷åêå ïîêóïàòåëÿ. Ïðè ýòîì íà ýêðàíå äîëæíû âûñâåòèòüñÿ
êóïëåííûå òîâàðû. Ïðîäàâåö âûáèðàåò, êàêèå òîâàðû âîçâðàùàåò ïîêóïàòåëü è
ââîäèò êîëè÷åñòâî. Ïîñëå ýòîãî ïðîãðàììà äîëæíà ïðîáèòü ÷åê âîçâðàòà.
Åñëè ïîêóïàòåëü ïðèíåñ òîâàð
äëÿ âîçâðàòà, íî íå ïðèíåñ ÷åê, ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü ïðîäàâöó
âîçìîæíîñòü íàéòè êîä ïîêóïêè ïî ÷àñòè íàçâàíèÿ òîâàðà, ïî àðòèêóëó, ïî ÷àñòè
ñêàí-êîäà, ïî äàòå è âðåìåíè ïîêóïêè, à òàêæå ïî öåíå ïîêóïêè.
Êàññèð ìîæåò òîëüêî
ïðîäàâàòü òîâàðû è äåëàòü âîçâðàò îò ïîêóïàòåëÿ. Ïðîãðàììà äîëæíà íå ïîçâîëÿòü
åìó âûïîëíÿòü ïðî÷èå äåéñòâèÿ, èçìåíÿþùèå äàííûå â áàçå (ïðîñìàòðèâàòü êàññèð
ìîæåò ëþáóþ èíôîðìàöèþ).
2) Ðàáîòà ìåíåäæåðà
Ìåíåäæåð îòâå÷àåò çà
çàíåñåíèå èíôîðìàöèè î òîâàðàõ, çàêóïëåííûõ ìàãàçèíîì íà îïòîâûõ áàçàõ. Ïðîöåññ
çàíåñåíèÿ òîâàðîâ âûãëÿäèò ñëåäóþùèì îáðàçîì:
Ìåíåäæåð ââîäèò èíôîðìàöèþ
îá îïòîâîé çàêóïêå (äàòà çàêóïêè, áàçà, íà êîòîðîé çàêóïëåí òîâàð);
Çàòåì ìåíåäæåð çàíîñèò
òîâàðû â îïòîâóþ çàêóïêó. Ïîêà ìåíåäæåð çàíîñèò òîâàðû â îïòîâóþ çàêóïêó, îíè
íå äîëæíû áûòü äîñòóïíû äëÿ ïðîäàæè. Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü
ïàðàëëåëüíîãî çàíåñåíèÿ òîâàðîâ íåñêîëüêèì ïîëüçîâàòåëÿì. Ïðè ýòîì êàæäûé
ïîëüçîâàòåëü äîëæåí âèäåòü òîëüêî çàíåñåííûå èì òîâàðû;
Ïîñëå òîãî, êàê âñå òîâàðû
çàíåñåíû, ìåíåäæåð ñâåðÿåò ñóììó çàíåñåííûõ òîâàðîâ ñ ñóììîé, óêàçàííîé â
íàêëàäíîé. Åñëè ýòè ñóììû ñîâïàäàþò, îïòîâàÿ çàêóïêà çàêðûâàåòñÿ, òîâàðû
ñòàíîâÿòñÿ äîñòóïíûìè äëÿ ïðîäàæè è íåäîñòóïíûìè äëÿ èçìåíåíèÿ.
Ìåíåäæåð ìîæåò çàíîñèòü
òîâàðû äâóìÿ ñïîñîáàìè.
Ïåðâûé ñïîñîá: çàíåñåíèå
òîâàðà, êîòîðîãî åùå íå áûëî â äàííîì ìàãàçèíå. Ìåíåäæåð çàâîäèò íîâûé
ìàãàçèííûé êîä òîâàðà, ââîäèò íàçâàíèå òîâàðà, àðòèêóë è åäèíèöó èçìåðåíèÿ,
âûáèðàåò ìåñòîïîëîæåíèå òîâàðà â äåðåâå ãðóïï, çàòåì ââîäèò êîëè÷åñòâî è
ñòîèìîñòü (ýòè äàííûå óêàçûâàþòñÿ â íàêëàäíîé). Çàòåì ìåíåäæåð ìîæåò ââåñòè
ñêàí-êîäû äëÿ ñîçäàííîãî òîâàðà (âðó÷íóþ èëè ñ ïîìîùüþ ñêàíåðà).
Âòîðîé ñïîñîá: ìåíåäæåð
âûáèðàåò ñóùåñòâóþùèé òîâàð ñ ïîìîùüþ íàâèãàöèè ïî äåðåâó ãðóïï, ñ ïîìîùüþ
ââîäà ìàãàçèííîãî êîäà (åñëè îí ïîìíèò ýòîò êîä) ñóùåñòâóþùåãî òîâàðà, èëè ñ
ïîìîùüþ ñêàíåðà. Âî âñåõ ýòèõ ñëó÷àÿõ íà ýêðàíå äîëæíî âûñâåòèòüñÿ íàçâàíèå
ñóùåñòâóþùåãî òîâàðà, àðòèêóë, òåêóùàÿ öåíà, ñåáåñòîèìîñòü, îñòàòîê è äðóãèå
äàííûå, êîòîðûå äîëæíû áûòü íåäîñòóïíûìè äëÿ èçìåíåíèÿ.
Ìåíåäæåð íå âñåãäà ïîìíèò, â
êàêîé ãðóïïå äåðåâà ðàñïîëîæåí òîâàð, ïîýòîìó ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü
âîçìîæíîñòü ïîèñêà ïî ÷àñòè íàçâàíèÿ, ïî ÷àñòè àðòèêóëà è ïî ÷àñòè ñêàí-êîäà.
3) Ðàáîòà ðóêîâîäèòåëÿ
ïðåäïðèÿòèÿ
Ïðîãðàììà äîëæíà
ïðåäîñòàâëÿòü âîçìîæíîñòü ðóêîâîäèòåëþ ïðåäïðèÿòèÿ ïðîñìàòðèâàòü ñòàòèñòèêó
ðàáîòû ìàãàçèíà çà ëþáîé âûáðàííûé ïåðèîä (êàêèå òîâàðû áûëè ïðîäàíû, â êàêèõ
ñëó÷àÿõ èìåëà ìåñòî ñêèäêà), à òàêæå âûâîäèòü ýòè äàííûå íà ïå÷àòü.
Ðóêîâîäèòåëü ïðåäïðèÿòèÿ
äîëæåí èìåòü âîçìîæíîñòü ïðîñìîòðåòü è ðàñïå÷àòàòü îñòàòêè òîâàðîâ íà ñêëàäå
(íàïðèìåð, äëÿ ïðîâåäåíèÿ èíâåíòàðèçàöèè), à òàêæå òàêæå èçìåíèòü öåíû. Ïðè
ýòîì ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ïå÷àòè èçìåíåííûõ öåííèêîâ çà
âûáðàííûé ïåðèîä (÷òîáû áûëà âîçìîæíîñòü ñèíõðîíèçèðîâàòü öåííèêè íà âèòðèíå è
öåííèêè â áàçå).
1) Ïðîãðàììà äîëæíà ðàáîòàòü â
îïåðàöèîííîé ñèñòåìå Windows XP. Ïîëüçîâàòåëüñêèé èíòåðôåéñ
äîëæåí ñîîòâåòñòâîâàòü ñòàíäàðòàì äëÿ ïðèëîæåíèé Windows (ôîðìû, êíîïêè, ïåðåêëþ÷àòåëè è ò. ä.).
2) Èíòåðôåéñ äîëæåí áûòü
ìàêñèìàëüíî ïðîñòûì è ïîíÿòíûì. Âåçäå, ãäå ìîãóò âîçíèêíóòü òðóäíîñòè, äîëæíû
áûòü íàïèñàíû ïîäñêàçêè. Ïðîãðàììà äîëæíà èìåòü òîëüêî íåîáõîäèìûå ôóíêöèè è
íè÷åãî ëèøíåãî.
3) Ïîëüçîâàòåëüñêèé èíòåðôåéñ
äîëæåí áûòü ïîñòðîåí òàê, ÷òîáû ìèíèìèçèðîâàòü âîçìîæíîñòü îøèáîê. Åñëè
îøèáî÷íûå äàííûå âñå-òàêè çàíåñåíû, äîëæíà áûòü âîçìîæíîñòü ëåãêî è áûñòðî èõ
èñïðàâèòü.
4) Ñàìûå ÷àñòî âûïîëíÿåìûå è
ðóòèííûå îïåðàöèè (íàïðèìåð, çàíåñåíèå ïðèâåçåííûõ òîâàðîâ â áàçó) äîëæíû
âûïîëíÿòüñÿ ïî âîçìîæíîñòè áûñòðî è óäîáíî.
5) Ïðîãðàììà äîëæíà ðàáîòàòü
áûñòðî («áåç òîðìîçîâ»). Ñèñòåìíûå õàðàêòåðèñòèêè ìàøèíû, íà êîòîðîé áóäåò
ðàáîòàòü ïðîãðàììà: Intel Celeron D 2400 Mhz, 256
Mb RAM, ÷òî äîëæíî áûòü äîñòàòî÷íî
äëÿ îáåñïå÷åíèÿ äåÿòåëüíîñòè íåáîëüøîãî ìàãàçèíà, ñ íåâûñîêîé èíòåíñèâíîñòüþ
ïðîäàæ.
6) Ïðîãðàììà äîëæíà âûäàâàòü
îò÷åòû â ôîðìàòå doc (äëÿ
âîçìîæíîñòè ïîñëåäóþùåãî ôîðìàòèðîâàíèÿ â Microsoft Word).
7) Ïðîãðàììà äîëæíà
ïðåäîñòàâëÿòü çàùèòó îò íåñàíêöèîíèðîâàííîãî äîñòóïà. Ïðåäïîëàãàåòñÿ, ÷òî
ïîëüçîâàòåëè íå î÷åíü õîðîøî ðàçáèðàþòñÿ â êîìïüþòåðàõ, à ñåðâåð îáùåäîñòóïåí,
ïîýòîìó äîñòàòî÷íî çàùèòû íà óðîâíå ïðèëîæåíèÿ.
1) Äëÿ êàæäîãî òîâàðà äîëæåí
õðàíèòüñÿ ìàãàçèííûé êîä òîâàðà (÷èñëî îò 10000 äî 999999), àðòèêóë (îáû÷íî íå
äëèííåå 10 ñèìâîëîâ), à òàêæå ñêàí-êîäû. Ñêàí-êîäû ñîñòîÿò èç 13 öèôð. Äëÿ êàæäîãî
ìàãàçèííîãî êîäà òîâàðà ìîæåò áûòü íåñêîëüêî ñêàí-êîäîâ, à òàêæå äëÿ îäíîãî
ñêàí-êîäà ìîæåò áûòü íåñêîëüêî ìàãàçèííûõ êîäîâ. Ïðîãðàììà äîëæíà äàâàòü
âîçìîæíîñòü çàâåñòè äëÿ êàæäîãî êîäà òîâàðà äî 6 ñêàí-êîäîâ.
2) Òîâàðû ìîãóò áûòü êàê
øòó÷íûìè (ìîæíî ïðîäàòü òîëüêî öåëîå êîëè÷åñòâî òîâàðà (íàïðèìåð, êîâðèêè äëÿ
âàííîé)), òàê è âåùåñòâåííûìè (ìîæíî ïðîäàòü ÷àñòü åäèíèöû òîâàðà (íàïðèìåð, 75
ñàíòèìåòðîâ ïðîâîäà, êîãäà äëèíà ïðîâîäà èçìåðÿåòñÿ â ìåòðàõ). Ïðîãðàììà äîëæíà
äàâàòü âîçìîæíîñòü ïðîäàòü íå öåëîå êîëè÷åñòâî âåùåñòâåííîãî òîâàðà, è íå
äîëæíà äàâàòü âîçìîæíîñòè ïðîäàòü íå öåëîå êîëè÷åñòâî øòó÷íîãî òîâàðà.
Ïîäàâëÿþùåå áîëüøèíñòâî òîâàðîâ – øòó÷íûå (ìàãàçèí õîçÿéñòâåííûé). Èìåííî íà
íèõ â îñíîâíîì ñëåäóåò îðèåíòèðîâàòüñÿ ïðè ðàçðàáîòêå èíòåðôåéñà ïðîãðàììû.
3) Òîâàðû çàêóïàþòñÿ íà îïòîâûõ
áàçàõ. Ïðîãðàììà äîëæíà õðàíèòü ñïèñîê îïòîâûõ áàç (äîëæíî õðàíèòüñÿ íàçâàíèå
áàçû, àäðåñ, ÔÈÎ ìåíåäæåðà, òåëåôîí ìåíåäæåðà è òåëåôîí ãëàâíîãî áóõãàëòåðà).
Òàêæå äîëæíà áûòü äîñòóïíà èíôîðìàöèÿ î òîì, íà êàêóþ ñóììó áûëî çàêóïëåíî
òîâàðîâ íà òîé èëè èíîé îïòîâîé áàçå.
4) Çàíåñåíèå òîâàðîâ,
ïðèâåçåííûõ ñ îïòîâîé áàçû, ïðîèçâîäèòñÿ ñëåäóþùèì îáðàçîì: ñíà÷àëà çàâîäèòñÿ
îïòîâàÿ çàêóïêà. Â íåé äîëæíû ôèêñèðîâàòüñÿ äàòà è âðåìÿ çàêóïêè, à òàêæå
îïòîâàÿ áàçà. Çàòåì â îïòîâîé çàêóïêå ñîçäàåòñÿ ñåññèÿ, â êîòîðóþ çàíîñÿòñÿ
òîâàðû. Ïîêà ñåññèÿ íå çàêðûòà, çàíåñåííûå òîâàðû íå äîñòóïíû äëÿ ïðîäàæè. Êàê
òîëüêî ñåññèÿ ñòàíîâèòñÿ çàêðûòîé, çàíåñåííûå òîâàðû ñòàíîâÿòñÿ äîñòóïíûìè äëÿ
ïðîäàæè. Äîëæíà áûòü âîçìîæíîñòü ñîçäàíèÿ íåñêîëüêèõ ñåññèé äëÿ ïàðàëëåëüíîãî
çàíåñåíèÿ òîâàðîâ íåñêîëüêèìè ïîëüçîâàòåëÿìè, à òàêæå äëÿ âîçìîæíîñòè çàêðûòèÿ
ñåññèé, êîãäà íå âñå òîâàðû îïòîâîé çàêóïêè çàíåñåíû (÷òîáû áûëà âîçìîæíîñòü
òîðãîâàòü). Òàêæå ïîñëå çàêðûòèÿ ñåññèè öåíû íà òîâàðû, çàíåñåííûå ïîä ñòàðûìè
êîäàìè, èçìåíÿþòñÿ ïî ñëåäóþùåìó ïðèíöèïó: åñëè íîâàÿ öåíà áîëüøå ñòàðîé,
óñòàíàâëèâàåòñÿ íîâàÿ öåíà, èíà÷å îñòàåòñÿ ñòàðàÿ öåíà. Äîëæíà áûòü âîçìîæíîñòü
ïîñìîòðåòü èçìåíèâøèåñÿ öåííèêè çà çàäàííîå êîëè÷åñòâî äíåé.
5) Òîâàðû çàíîñÿòñÿ â ñåññèþ
îäíèì èç ñëåäóþùèõ ñïîñîáîâ:
5.1. Çàâîäèòñÿ íîâûé êîä òîâàðà,
êîòîðîãî äî ýòîãî íåáûëî â áàçå, è ïîä íèì çàíîñÿòñÿ íàçâàíèå òîâàðà, àðòèêóë,
ìåñòîïîëîæåíèå, êîëè÷åñòâî è ñòîèìîñòü äàííîãî êîëè÷åñòâà òîâàðà (èìåííî îíà
óêàçûâàåòñÿ â íàêëàäíîé). Çàòåì çàíîñÿòñÿ ñêàí-êîäû (îäèí èëè íåñêîëüêî).
Äîëæíà áûòü âîçìîæíîñòü çàíîñèòü ñêàí-êîäû ñ ïîìîùüþ ñêàíåðà èëè âðó÷íóþ. Çàòåì
çàíîñèòñÿ íàöåíêà òîâàðà, ïîñëå ÷åãî äîëæíà àâòîìàòè÷åñêè âû÷èñëÿòüñÿ ðîçíè÷íàÿ
öåíà, èëè çàíîñèòñÿ öåíà, òîãäà äîëæíà àâòîìàòè÷åñêè ôîðìèðîâàòüñÿ íàöåíêà. Íàöåíêà
íå ìîæåò áûòü áîëüøå 1000%.
5.2. Òîâàð çàíîñèòñÿ ïîä ñòàðûì
êîäîì (åñëè òàêîé òîâàð óæå áûë çàíåñåí â ïðîãðàììó). Ïðè çàíåñåíèè òîâàðà
ïîëüçîâàòåëü äîëæåí èìåòü âîçìîæíîñòü íàéòè êîä òîâàðà â Ñïðàâî÷íèêå Òîâàðîâ,
ëèáî íàéòè êîä ïî ÷àñòè íàçâàíèÿ, ïî ÷àñòè àðòèêóëà, èëè ïî ÷àñòè ñêàí-êîäà.
Ïðè ýòîì íà ýêðàíå äîëæíà îòîáðàæàòüñÿ ñòàðàÿ öåíà òîâàðà (êîòîðàÿ ñåé÷àñ èìååò
ìåñòî â ìàãàçèíå). Âñå îñòàëüíûå ïàðàìåòðû çàíîñÿòñÿ òàêæå, êàê è ïðè ïåðâîì
ñïîñîáå. Ïðè ýòîì ïîëÿ ñ íàçâàíèåì òîâàðà, àðòèêóëîì è ìåñòîïîëîæåíèåì
áëîêèðóþòñÿ îò èçìåíåíèé.
Ïîëüçîâàòåëü äîëæåí èìåòü
âîçìîæíîñòü çàíîñèòü òîâàðû ëþáûì èç ýòèõ ñïîñîáîâ.
6) Ïðîãðàììà äîëæíà
àâòîìàòè÷åñêè îêðóãëÿòü ðîçíè÷íóþ öåíó òîâàðà ïî ñëåäóþùèì ïðàâèëàì: åñëè òîâàð
ñòîèò ìåíåå 5 ðóáëåé, îêðóãëÿåì öåíó äî 10 êîïååê; åñëè òîâàð ñòîèò îò 5 äî 20
ðóáëåé, îêðóãëÿåì öåíó äî 50 êîïååê; åñëè òîâàð ñòîèò áîëüøå 20 ðóáëåé,
îêðóãëÿåì öåíó äî ðóáëÿ.
7) Äîëæíà áûòü âîçìîæíîñòü
ðàçáèòü âñå òîâàðû ïî ãðóïïàì â âèäå äåðåâà ñ ãëóáèíîé âëîæåííîñòè íå ìåíåå
8-10.
8) Ïðîãðàììà äîëæíà äàâàòü âîçìîæíîñòü
ïðîäàæè òîâàðîâ ïîêóïàòåëÿì. Ïðè ýòîì ïðîäàâåö ìîæåò ñäåëàòü ñêèäêó íà
îòäåëüíûå òîâàðû ïîêóïêè (îäíà ïîêóïêà ìîæåò ñîäåðæàòü íåñêîëüêî òîâàðîâ).
Êðîìå ýòîãî, ïðîäàâåö äîëæåí èìåòü âîçìîæíîñòü ïðîñòî èçìåíèòü öåíó ïðîäàæè
(ñêèäêà íà ãëàçîê). Ýòî áûâàåò íóæíî, êîãäà öåíà íà âèòðèíå íå ñîâïàäàåò ñ
öåíîé â áàçå, à òàêæå êîãäà íóæíî ñäåëàòü ñêèäêó íà îïðåäåëåííóþ ñóììó, èëè
âðó÷íóþ îêðóãëèòü êîïåéêè. Ïðè èçìåíåíèè öåíû òîâàðà äîëæíà àâòîìàòè÷åñêè
âû÷èñëÿòüñÿ ñêèäêà, è íàîáîðîò, ïðè èçìåíåíèè íàöåíêè äîëæíà àâòîìàòè÷åñêè
âû÷èñëÿòüñÿ öåíà òîâàðà (îêðóãëåíèå äî 1 êîïåéêè). Ââåäåíèå òîâàðîâ äëÿ ïðîäàæè
ìîæåò îñóùåñòâëÿòüñÿ ñëåäóþùèìè ñïîñîáàìè: ââîäèòñÿ âðó÷íóþ êîä òîâàðà, èëè
ââîäèòñÿ ñêàí-êîä (âðó÷íóþ èëè ñ ïîìîùüþ ñêàíåðà). Ïðè ýòîì äîëæíà áûòü âîçìîæíîñòü
ïîèñêà êîäà òîâàðà ïî íàçâàíèþ è àðòèêóëó (èíîãäà áûâàþò òîâàðû, íà êîòîðûå
ïî÷åìó-òî íåò íè ñêàí-êîäà, íè ìàãàçèííîãî êîäà, íè äàæå öåíû). Ïðè ýòîì
ïðîäàæè âåäóòñÿ â îäíó ñìåíó, êàññèð îäèí.
9) Ïðîãðàììà äîëæíà äàâàòü
âîçìîæíîñòü äåëàòü âîçâðàò òîâàðà îò ïîêóïàòåëÿ. Ïðè ýòîì äîëæíà èìåòüñÿ
âîçìîæíîñòü ïîèñêà ïîêóïàòåëÿ, êóïèâøåãî äàííûå òîâàðû. Ïîñëå ýòîãî íà ýêðàíå
äîëæíà âûñâå÷èâàòüñÿ èíôîðìàöèÿ î êóïëåííûõ òîâàðàõ. Âîçâðàò ìîæåò
ïðîèçâîäèòüñÿ íåîãðàíè÷åííîå êîëè÷åñòâî ðàç, ïîêà îáúåì âîçâðàòà íå ïðåâûøàåò
îáúåì ïîêóïêè.
10) Ïðîãðàììà äîëæíà õðàíèòü âñþ
ââåäåííóþ èíôîðìàöèþ (êàêèå òîâàðû ñ êàêîé áàçû êîãäà áûëè ïðèâåçåíû, äàòû
îïòîâûõ çàêóïîê, äåðåâî òîâàðîâ, ÷òî è êîãäà áûëî ïðîäàíî, äàòó è âðåìÿ
ïðîäàæè, òîâàðû, èìåþùèåñÿ íà ñêëàäå, âîçìîæíîñòü îñòàâëÿòü ïðèìå÷àíèÿ äëÿ
êóïëåííûõ òîâàðîâ) äëÿ ïîñëåäóþùåãî àíàëèçà. Íè÷åãî íå äîëæíî óäàëÿòüñÿ èç
áàçû.
11) Òàêæå íóæíà âîçìîæíîñòü
äåëàòü ïðèìå÷àíèÿ ê îïòîâûì áàçàì, ê ïðîäàæàì (íàïðèìåð, òàêîå: «ìóæ÷èíà 35 ëåò
êóïèë âåäðî ñ òðåùèíîé íà êðûøêå»).
12) Îáúåìû äàííûõ áóäóò òàêèìè:
êîëè÷åñòâî ãðóïï òîâàðîâ – äî äâóõ òûñÿ÷. Êîëè÷åñòâî íàèìåíîâàíèé òîâàðîâ – äî
äâàäöàòè òûñÿ÷. Êîëè÷åñòâî ïðîäàæ â äåíü – äî ñòà (îáû÷íî ìåíüøå). Ïðîãðàììà
äîëæíà íîðìàëüíî ñïðàâëÿòüñÿ ñ òàêèìè îáúåìàìè äàííûõ «áåç òîðìîçîâ».
Îïèðàÿñü íà ïðèâåäåííûå âûøå
áèçíåñ-ïðàâèëà, ðàçðàáîòàåì ëîãè÷åñêóþ ñõåìó áàçû äàííûõ.
Ëîãè÷åñêàÿ ñõåìà áàçû äàííûõ ïðèâåäåíà íà ðèñóíêå
2.1
Ðèñóíîê 2.1
Áàçà äàííûõ ñîäåðæèò 16
îñíîâíûõ òàáëèö. Êàæäàÿ èç òàáëèö èìååò ñâîå íàçíà÷åíèå:
1)
Òàáëèöà goods (Ñïðàâî÷íèê Òîâàðîâ). Ïîæàëóé, ñàìàÿ îñíîâíàÿ
òàáëèöà. Õðàíèò ñïèñîê òîâàðîâ, èìåþùèõñÿ â äàííîì ìàãàçèíå, èëè áûâøèõ
êîãäà-ëèáî â äàííîì ìàãàçèíå. Áûëî ïðèíÿòî ðåøåíèå íå èñïîëüçîâàòü êîä òîâàðà â
êà÷åñòâå óíèêàëüíîãî çíà÷åíèÿ êëþ÷à (òàê êàê â ïîñëåäóþùåì áóäåò äîáàâëåíà
âîçìîæíîñòü îñâîáîæäàòü ñòàðûå êîäû òîâàðîâ (òîâàðû, êîòîðûìè ìàãàçèí óæå äàâíî
íå òîðãóåò), ïðè ýòîì ñîõðàíèòñÿ èíôîðìàöèÿ î òîì, êàêèå òîâàðû â òî âðåìÿ
ïðîäàâàëèñü. Ïðè ýòîì åñëè CodeIsActive=1, òî ìàãàçèí òàêèì òîâàðîì òîðãóåò, èíà÷å ýòîò êîä óæå íå
èñïîëüçóåòñÿ. Òàêèì îáðàçîì, åñëè CodeIsActive=1, òî ïîëå code_good îäíîçíà÷íî èäåíòèôèöèðóåò
òîâàð, ÷òî è òðåáóåòñÿ. Ïîëå number_good óíèêàëüíî è ïîëíîñòüþ
ñêðûòî îò âñåõ ïîëüçîâàòåëåé ïðîãðàììû. Ïîëå art ñîäåðæèò àðòèêóë òîâàðà. Ýòî ïîëå íå óíèêàëüíî, íî
ïî íåìó ìîæåò îñóùåñòâëÿòüñÿ ïîèñê. Ïîëå name_good ñîäåðæèò íàçâàíèå òîâàðà.
Òàáëèöà Òîâàðû òàêæå ñîäåðæèò ïîëå code_ancestor (êîä ãðóïïû) äëÿ
îïðåäåëåíèÿ ãðóïïû, â êîòîðîé îí ëåæèò (íàïðèìåð, òîâàð ìîæåò ëåæàòü â ãðóïïå
“Ñòðîéìàòåðèàëû\Äåðåâî\Äîñêè îáðåçíûå”). Ýòîò êîä (code_ancestor) îáÿçàòåëüíî åñòü â òàáëèöå
paths (Ãðóïïû), åñëè code_ancestor¹0 (òî åñòü åñëè ïàïêà íå
ÿâëÿåòñÿ êîðíåì äåðåâà), è ïî íåìó ìîæíî îäíîçíà÷íî îïðåäåëèòü ìåñòîïîëîæåíèå
ãðóïïû â äåðåâå ãðóïï, à òàêæå åå íàçâàíèå. Ïîëå code_unit îáîçíà÷àåò êîä åäèíèöû
èçìåðåíèÿ òîâàðà, êîòîðûé õðàíèòñÿ â òàáëèöå TitleUnits. Áûëî ïðèíÿòî ðåøåíèå íå õðàíèòü íàçâàíèå åäèíèöû
èçìåðåíèÿ â òàáëèöå goods
(Òîâàðû), òàê êàê âîçìîæåí îøèáî÷íûé ââîä åäèíèöû èçìåðåíèÿ (íàïðèìåð,
ïîëüçîâàòåëü ìîæåò ãäå-òî ââåñòè “êã”, ãäå-òî “Êã”, è ò. ä.), à òàêæå ïî òîé
ïðè÷èíå, ÷òî åäèíèöà èçìåðåíèÿ îïðåäåëÿåò òèï òîâàðà (øòó÷íûé èëè
âåùåñòâåííûé). Ýòîò òèï ìîæåò áûòü îäèí ðàç çàäàí äëÿ êàæäîé åäèíèöû èçìåðåíèÿ.
Îí îïðåäåëÿåò, äàâàòü âîçìîæíîñòü ïðîäàâöó òîðãîâàòü íå öåëûì êîëè÷åñòâîì
òîâàðà, èëè íå äàâàòü. È íàêîíåö, ïîëå scan_codes õðàíèò ñêàí-êîäû äàííîãî
òîâàðà. Ýòî ïîëå äåíîðìàëèçóåò ñòðóêòóðó òàáëèö, íî îíî íóæíî äëÿ óñêîðåíèÿ
âûâîäà ñïèñêà òîâàðîâ íà ôîðìó (âîîáùå, ñêàí-êîäû äëÿ äàííîãî òîâàðà õðàíÿòñÿ â
òàáëèöå ScanCodes).
2)
Òàáëèöà TitleUnits (Åäèíèöû èçìåðåíèÿ). Õðàíèò åäèíèöû èçìåðåíèÿ
òîâàðîâ, èñïîëüçóåìûå â ïðîãðàììå. Ïîëå code_unit îäíîçíà÷íî îïðåäåëÿåò
åäèíèöó èçìåðåíèÿ, è îíî óíèêàëüíî. Ïîëå name_unit ñîäåðæèò íàçâàíèå
åäèíèöû èçìåðåíèÿ (íàïðèìåð, “ì”, “øò”, “êã”). Ïîëå IsActive îïðåäåëÿåò,
äîñòóïíà ëè äàííàÿ åäèíèöà èçìåðåíèÿ äëÿ âûáîðà èç ñïèñêà ïðè çàíåñåíèè
òîâàðîâ. Ïîëå IsMaterial õðàíèò èíôîðìàöèþ î òîì, øòó÷íûé òîâàð èëè
âåùåñòâåííûé.
3)
Òàáëèöà paths (Ãðóïïû òîâàðîâ). Õðàíèò ñòðóêòóðó äåðåâà ãðóïï
òîâàðîâ. Äåðåâî ñëóæèò äëÿ óäîáñòâà íàâèãàöèè ïî òîâàðàì. Ïîëå code_path îïðåäåëÿåò ãðóïïó òîâàðîâ;
ïîëå code_ancestor – ïðåäêà ãðóïïû. Ïðåäîê
ãðóïïû òàêæå ñîäåðæèòñÿ â ãðóïïå paths,
åñëè îí íå ðàâåí íóëþ (â òàêîì ñëó÷àå ïðåäêîì ÿâëÿåòñÿ êîðíåâîé êàòàëîã). Ïî
êîäó ãðóïïû ìîæíî îäíîçíà÷íî âû÷èñëèòü ïîëíîå èìÿ ãðóïïû. Ïîëå name_path õðàíèò íàçâàíèå ãðóïïû.
4)
Òàáëèöà ScanCodes (Ñêàí-êîäû òîâàðîâ). Õðàíèò ñïèñîê ñêàí-êîäîâ äëÿ
äàííîãî íîìåðà òîâàðà. ×èñëî ñêàí-êîäîâ ìîæåò áûòü íå áîëåå 12. Ëþáîé èç ýòèõ
ñêàí-êîäîâ èäåíòèôèöèðóåò íîìåð òîâàðà, à ñëåäîâàòåëüíî, è åãî êîä (õîòÿ íå
âñåãäà îäíîçíà÷íî).  ñëó÷àå íåîäíîçíà÷íîñòè îäíîìó ñêàí-êîäó ñîîòâåòñòâóåò
íåñêîëüêî ìàãàçèííûõ êîäîâ, è ïîëüçîâàòåëü äîëæåí âûáðàòü íóæíûé (ïðîãðàììà
ïðåäîñòàâëÿåò òàêóþ âîçìîæíîñòü).
5)
Òàáëèöà StoreHouse (Ñêëàä). Õðàíèò èíôîðìàöèþ
î òîâàðàõ, èìåþùèõñÿ â íàëè÷èè, à òàêæå î òîì, ñêîëüêî òîâàðà áûëî ïðîäàíî.
Ïîëå number_good îáîçíà÷àåò íîìåð òîâàðà
(ññûëêà íà òàáëèöó goods).
Ïîëå first_price îáîçíà÷àåò ñåáåñòîèìîñòü
òîâàðà (âû÷èñëÿåòñÿ êàê ñóììà, êîòîðàÿ ïîòðà÷åíà íà ïîêóïêó äàííîãî òîâàðà,
äåëåííàÿ íà êîëè÷åñòâî äàííîãî òîâàðà). Ïîëå price îáîçíà÷àåò òåêóùóþ ðîçíè÷íóþ öåíó òîâàðà (öåíó, ïî
êîòîðîé òîâàð ïðîäàåòñÿ â ìàãàçèíå). Öåíà óñòàíàâëèâàåòñÿ ðóêîâîäèòåëåì
ïðåäïðèÿòèÿ, à òàêæå ïðîãðàììîé ïðè çàíåñåíèè òîâàðîâ, ïðèâåçåííûõ ñ îïòîâûõ
áàç. Ïîëå sold õðàíèò èíôîðìàöèþ î òîì,
ñêîëüêî òîâàðà áûëî ïðîäàíî çà âñå âðåìÿ ñóùåñòâîâàíèÿ äàííîãî number_good. Ýòî, êîíå÷íî äåíîðìàëèçóåò
áàçó, íî çàòî óñêîðÿåò ðàáîòó ïðîãðàììû.
6)
Òàáëèöà WholesaleBases (Îïòîâûå áàçû). Õðàíèò èíôîðìàöèþ îá îïòîâûõ áàçàõ,
íà êîòîðûõ ìàãàçèí çàêóïàë òîâàðû. Ïîëå code_base ÿâëÿåòñÿ êëþ÷åâûì è
îäíîçíà÷íî èäåíòèôèöèðóåò áàçó. Ïîëå name_base õðàíèò íàçâàíèå áàçû. Îñòàëüíûå
ïîëÿ (address, FIOman, PhoneMan, PhoneBK) õðàíÿò, ñîîòâåòñòâåííî,
àäðåñ îïòîâîé áàçû, ÔÈÎ ìåíåäæåðà, òåëåôîí ìåíåäæåðà è òåëåôîí ãëàâíîãî
áóõãàëòåðà.
7)
Òàáëèöà purchases (Îïòîâûå çàêóïêè) õðàíèò
èíôîðìàöèþ î òîì, êàêèå çàêóïêè è êîãäà áûëè ñäåëàíû. Ïîëå code_base ññûëàåòñÿ íà òàáëèöó WholesaleBases (ÎïòîâûåÁàçû), è îçíà÷àåò
îïòîâóþ áàçó, ãäå áûëà ñäåëàíà çàêóïêà. Òàêæå õðàíèòñÿ äàòà äàííîé çàêóïêè.
Ïîëå summa îçíà÷àåò òî, íà êàêóþ ñóììó
áûëî çàêóïëåíî òîâàðîâ. Ýòî äåíîðìàëèçóåò áàçó, íî çàòî óñêîðÿåò ðàáîòó
ïðîãðàììû.
8)
Òàáëèöà sessions (Ñåññèè). Òîâàð, êîòîðûé
ïðèâåçåí ñ îïòîâîé áàçû íå îáÿçàòåëüíî çàíîñèòü â îäíó òàáëèöó ñïëîøíûì
ñïèñêîì. Òîâàð ìîæíî çàíåñòè â íåñêîëüêî ñåññèé, ÷òîáû òàáëèöà ñ çàíåñåííûìè
òîâàðàìè íå áûëà ñëèøêîì áîëüøîé äëÿ âûâîäà íà ýêðàí, à òàêæå äëÿ ïàðàëëåëüíîãî
çàíåñåíèÿ òîâàðîâ íåñêîëüêèìè ïîëüçîâàòåëÿìè (÷òîáû îíè íå ìåøàëè äðóã äðóãó).
Ïîëå code_purchase ññûëàåòñÿ íà òàáëèöó purchases (Îïòîâûå çàêóïêè), îçíà÷àåò
êîä îïòîâîé çàêóïêè. Ïîëå addition ïîçâîëÿåò çàäàòü íàöåíêó (â ïðîöåíòàõ) ïî óìîë÷àíèþ äëÿ òîâàðîâ äàííîé
ñåññèè (÷òîáû åå íå ââîäèòü ïðè çàíåñåíèè êàæäîãî òîâàðà). Ïîëå date0
îçíà÷àåò äàòó ñîçäàíèÿ ñåññèè, à ïîëå date1 îçíà÷àåò äàòó çàêðûòèÿ
ñåññèè (åñëè îíà çàêðûòà). Åñëè accepted=0, òî òîâàð ìîæíî çàíîñèòü â
äàííóþ ñåññèþ, óäàëÿòü èç äàííîé ñåññèè (òî åñòü ñåññèÿ íå çàêðûòà). Ïîêà
òîâàðû çàíîñÿòñÿ â ñåññèþ, èìè íåëüçÿ òîðãîâàòü. Ïîñëå çàêðûòèÿ ñåññèè òîâàðû
ñòàíîâÿòñÿ äîñòóïíûìè äëÿ ïðîäàæè, ïðè ýòîì ïðîèñõîäÿò èçìåíåíèÿ â òàáëèöå StoreHouse (Ñêëàä). Ïîñëå çàêðûòèÿ ñåññèè
â íå¸ óæå íåëüçÿ äîçàíîñèòü òîâàðû. Ïîëå summa îçíà÷àåò ñóììó çàêóïëåííûõ òîâàðîâ äëÿ äàííîé
ñåññèè. Îíî äåíîðìàëèçóåò áàçó, íî óñêîðÿåò ðàáîòó ïðîãðàììû. Äåòàëüíàÿ
èíôîðìàöèÿ î òîì, êàêèå òîâàðû áûëè çàíåñåíû â òåêóùåé ñåññèè õðàíèòñÿ â
òàáëèöå StructureSession.
9)
Òàáëèöà StructureSession (ÑòðóêòóðàÑåññèè). Ýòî
òàáëèöà, ïîä÷èíåííàÿ òàáëèöå sessions, ñîäåðæèò äåòàëüíóþ èíôîðìàöèþ î òîì, êàêèå òîâàðû ñ êàêîé íàöåíêîé
áûëè çàíåñåíû â äàííóþ ñåññèþ (ñåññèþ ñ êîäîì code_session). Õðàíèò number_good, êîòîðîå ññûëàåòñÿ íà
òàáëèöó goods (Òîâàðû), è îçíà÷àåò òîâàð,
êîòîðûé çàíåñëè. Ïîëÿ quantity, first_price, addition îçíà÷àþò, ñîîòâåòñòâåííî,
êîëè÷åñòâî, îïòîâóþ öåíó (â ïðîöåíòàõ) è ìàãàçèííóþ íàöåíêó äëÿ äàííîãî òîâàðà
(ïî óìîë÷àíèþ îíà ðàâíà çíà÷åíèþ, çàäàííîìó â òàáëèöå sessions), íî äëÿ êàæäîãî òîâàðà
äàííîé ñåññèè íàöåíêà ìîæåò áûòü ñâîåé. Ïîëå scan_codes îçíà÷àåò ñïèñîê ñêàí-êîäîâ
äëÿ äàííîãî òîâàðà. Äåíîðìàëèçóåò áàçó, íî óñêîðÿåò ðàáîòó ïðîãðàììû (âîîáùå,
ñêàí-êîäû äëÿ äàííîé ñåññèè õðàíÿòñÿ â òàáëèöå ScanCodesForSession, òàê êàê èõ íåëüçÿ çàíîñèòü â
òàáëèöó ScanCodes, ïîòîìó ÷òî áèçíåñ-ïðàâèëà
çàïðåùàþò òîðãîâàòü çàíîñèìûìè òîâàðàìè, ïîêà ñåññèÿ íå çàêðûòà).
10)Òàáëèöà ScanCodesForSession (Ñêàí-êîäû äëÿ ñåññèè) õðàíèò ñïèñîê ñêàí-êîäîâ äëÿ òîâàðîâ ñåññèè (òî
åñòü ïîêà ñåññèÿ íå çàêðûòà, êîäû íå àêòèâíû).
11)Òàáëèöà ChangedPrices (Èçìåíåííûå öåíû). Õðàíèò öåíû íà òîâàðû, êîòîðûå áûëè èçìåíåíû, è
äàòó ïîñëåäíåãî èçìåíåíèÿ. Íóæíî, íàïðèìåð, êîãäà ðóêîâîäèòåëü ïðåäïðèÿòèÿ
ïîìåíÿåò öåíû òîâàðîâ íà Ñêëàäå, ÷òîáû ïðîãðàììà ìîãëà âûäàòü èíôîðìàöèþ, êàêèå
öåííèêè èçìåíèëèñü çà ïîñëåäíèå íåñêîëüêî äíåé (÷èñëî äíåé çàäàåòñÿ), à òàêæå
êîãäà ïîñëå çàêðûòèÿ ñåññèè ìåíÿþòñÿ öåííèêè íà íåêîòîðûå òîâàðû.
12)Òàáëèöà sales
(Ïðîäàæè). Ïîëå code_sale ÿâëÿåòñÿ êëþ÷åâûì è
îäíîçíà÷íî èäåíòèôèöèðóåò ïðîäàæó. Ïîëå date_sale îçíà÷àåò äàòó ïðîäàæè. Ïîëå
summa îçíà÷àåò ñóììó äàííîé
ïðîäàæè (äåíîðìàëèçóåò áàçó, íî óñêîðÿåò ðàáîòó ïðîãðàììû (íàïðèìåð, ïðè âûâîäå
áîëüøîãî ñïèñêà ïðîäàæ)). Ïîëå cash
îçíà÷àåò ñóììó, êîòîðîé ðàñïëàòèëñÿ ïîêóïàòåëü (ìîæåò ïðèãîäèòüñÿ ïðè ïîèñêå
êîäà ïðîäàæè, êîãäà ïîêóïàòåëü âîçâðàùàåò òîâàð áåç ÷åêà). Äåòàëüíàÿ èíôîðìàöèÿ
î òîì, êàêèå òîâàðû áûëè ïðîäàíû â òåêóùåé ïðîäàæå, õðàíèòñÿ â òàáëèöå StructureSale.
13)Òàáëèöà StructureSale (Ñòðóêòóðà ïðîäàæè). Õðàíèò
äåòàëüíóþ èíôîðìàöèþ î òîì, êàêèå òîâàðû áûëè ïðîäàíû â äàííîé ïðîäàæå. Ïîëå number_good ññûëàåòñÿ íà òàáëèöó goods è îçíà÷àåò íàçâàíèå òîâàðà.
Ïîëÿ quantity, first_price, price, discount, soldbyprice îçíà÷àþò, ñîîòâåòñòâåííî,
êîëè÷åñòâî ïðîäàííîãî çà äàííóþ ïîêóïêó òîâàðà, çàêóïî÷íóþ öåíó, öåíó,
ðîçíè÷íóþ öåíó òîâàðà íà ìîìåíò ïðîäàæè, ñêèäêó (â ïðîöåíòàõ) è öåíó, ïî
êîòîðîé òîâàð áûë ïðîäàí. Ïîëå summa
îçíà÷àåò ñóììó, íà êîòîðóþ ïðîäàí äàííûé òîâàð. Ïðè ýòîì èìååòñÿ íåêîòîðàÿ
èçáûòî÷íîñòü, íî îíà îïðàâäàíà. summa
íå âñåãäà ðàâíà ïðîèçâåäåíèþ quantity*soldbyprice. Ðàâåíñòâî âûïîëíÿåòñÿ
ñòðîãî, êîãäà ïðîäàåòñÿ öåëîå êîëè÷åñòâî òîâàðà. Ïðè ïðîäàæå âåùåñòâåííîãî
êîëè÷åñòâà òîâàðà ìîæåò âîçíèêíóòü òàêàÿ ñèòóàöèÿ: íàïðèìåð, öåíà òîâàðà 1,01
ðóá., êîëè÷åñòâî 1,5. Òîãäà ñóììà áóäåò 1,52 ðóá., ÷òî íå ðàâíî 1,515. Òàêæå soldbyprice íå âñåãäà ðàâíî price*(100-discount)/100. Íàïðèìåð, òîâàð ñòîèò
1,90. Ïðîäàâåö äåëàåò ñêèäêó 15%. Òîâàð äîëæåí ñòîèòü 1,615, íî ñòîèò 1,62. Íî
â áàçå âñå ðàâíî áóäåò õðàíèòüñÿ ñêèäêà 15% (ïðîäàâåö èìåííî åå äåëàë). À ïîëå soldbyprice íóæíî äëÿ ïîèñêà êîäà
ïðîäàæè ïî öåíå (ïðè ýòîì ïîëå soldbyprice ìîæíî èíäåêñèðîâàòü, à âûðàæåíèå price*(100-discount)/100 â Firebird íå èíäåêñèðóåòñÿ. Â
ïðèíöèïå, ïðè æåëàíèè ìîæíî îáîéòèñü áåç íåêîòîðûõ ïîëåé, è âû÷èñëÿòü èõ, íî
ýòî çàìåäëèò ðàáîòó ïðîãðàììû.
14)Òàáëèöà returns2 (âîçâðàòû). Õðàíèò èíôîðìàöèþ î âîçâðàòàõ îò ïîêóïàòåëÿ. Âîçâðàò ïðîèçâîäèòñÿ ñëåäóþùèì îáðàçîì: ïîêóïàòåëü ïðèíîñèò ÷åê, íà êîòîðîì íàïèñàí êîä ïðîäàæè, ïî íåìó ïðîäàâåö äåëàåò âîçâðàò. Ïîëå code_sale êàê ðàç áóäåò õðàíèòü êîä ïðîäàæè, äëÿ êîòîðîãî äåëàåòñÿ âîçâðàò. Ïîëå date_return õðàíèò äàòó ïðîäàæè. Ïîëå summa õðàíèò ñóììó âîçâðàòà. Äåíîðìàëèçóåò áàçó, íî óñêîðÿåò ðàáîòó ïðîãðàììû. Äåòàëüíàÿ èíôîðìàöèÿ î òîì, êàêèå òîâàðû áûëè ïðîäàíû, õðàíèòñÿ â òàáëèöå StructureReturn.
15)Òàáëèöà StructureReturn2 (Ñòðóêòóðà âîçâðàòà).
Õðàíèò äåòàëüíóþ èíôîðìàöèþ î òîì, êàêèå òîâàðû áûëè âîçâðàùåíû ïðè äàííîì
âîçâðàòå. Õðàíèòñÿ íîìåð òîâàðà, êîëè÷åñòâî è ñóììà âîçâðàòà.
16)Òàáëèöà notes (ïðèìå÷àíèÿ). Õðàíèò
ïðèìå÷àíèÿ ê îïòîâûì áàçàì, îïòîâûì çàêóïêàì, ñåññèÿì, ïðîäàæàì è âîçâðàòàì.
Áûëî ðåøåíî íå çàâîäèòü äëÿ êàæäîé òàáëèöû ïîä÷èíåííóþ òàáëèöó ñ ïðèìå÷àíèÿìè,
à ïèñàòü ïðèìå÷àíèÿ êî âñåì òàáëèöàì â îäíó òàáëèöó, òàê êàê ïðåäïîëàãàåòñÿ,
÷òî ïðèìå÷àíèé áóäåò íåìíîãî. code_note – êîä ïðèìå÷àíèÿ. number_table – íîìåð òàáëèöû, äëÿ
êîòîðîé ýòî ïðèìå÷àíèå. KeyFromTable – êëþ÷åâîå ïîëå òàáëèöû äëÿ êîòîðîé ñäåëàíî äàííîå ïðèìå÷àíèå (äëÿ
òàáëèöû WholesaleBases ýòî code_base; äëÿ òàáëèöû purchases ýòî code_purchase; äëÿ òàáëèöû sessions ýòî code_session; äëÿ òàáëèöû sales ýòî code_sale; äëÿ òàáëèöû returns ýòî code_return. text – òåêñò ïðèìå÷àíèÿ.
Íàçâàíèÿ è íîìåðà îñíîâíûõ òàáëèö áàçû ïðèâåäåíû â òàáëèöå 2.1.
1) TitleUnits |
2) goods |
Òàáëèöà 2.1 |
3) WholesaleBases |
4) purchases |
|
5) sessions |
6) StructureSession |
|
7) StoreHouse |
8) sales |
|
9) StructureSale |
10) paths |
|
11) notes |
15) ScanCodes |
|
16) ScanCodesForSession |
18) returns2 |
|
19) StructureReturn2 |
22) ChangedPrices |
Ñòðóêòóðà
òàáëèö â öåëîì ïðèâåäåíà ê òðåòüåé íîðìàëüíîé ôîðìå, çà èñêëþ÷åíèåì íåêîòîðûõ
ïîëåé, ââåäåííûõ â òàáëèöó äëÿ óñêîðåíèÿ ðàáîòû ïðîãðàììû. Èòàê, ïîëÿ, êîòîðûå
ìû íå áóäåì ó÷èòûâàòü:
·
goods (ïîëå scan_codes)
·
purchases (ïîëå summa)
·
sessions (ïîëå summa)
·
StructureSession (ïîëå scan_codes)
·
StoreHouse (ïîëÿ quantity, sold, êîíå÷íî
âû÷èñëÿåìûå íî èõ î÷åíü äîëãî âû÷èñëÿòü. Äëÿ ýòîãî íóæíî ïðîéòèñü ïî îáúåìíûì
òàáëèöàì StructureSession è StructureSale, ÷òî îòíèìàåò î÷åíü ìíîãî
âðåìåíè, òàê êàê ýòî ñàìûå áîëüøèå òàáëèöû. Ê òîìó æå èíôîðìàöèÿ èç íèõ áóäåò
âðåìÿ îò âðåìåíè ñëèâàòüñÿ (èíà÷å ÷åðåç íåñêîëüêî ëåò òàì áóäóò ìèëëèîíû
çàïèñåé))
·
sales (ïîëå summa)
·
StructureSale (â ïðèíöèïå áåç ïîëåé soldbyprice è summa ìîæíî áûëî áû îáîéòèñü)
·
ScanCodesForSession (ïîëå primarykey)
·
returns2 (ïîëå
summa)
·
StructureReturn2 (ïîëå summa ìîæíî âû÷èñëèòü, çàãëÿíóâ â
òàáëèöó sales è ïîñìîòðåâ, çà ñêîëüêî áûë
ïðîäàí òîâàð, çàòåì ïîëó÷åííîå çíà÷åíèå óìíîæèòü íà êîëè÷åñòâî è âûïîëíèòü
îêðóãëåíèå. Íî ýòî íåäîïóñòèìî äîëãî).
1ÍÔ – òðåáóåò, ÷òîáû êàæäîå
ïîëå òàáëèöû áàçû äàííûõ áûëî íå äåëèìûì è íå ñîäåðæàëî ïîâòîðÿþùèõñÿ ãðóïï.
Íåäåëèìîñòü ïîëÿ îçíà÷àåò, ÷òî ñîäåðæàùèåñÿ â íåì çíà÷åíèÿ íå äîëæíû äåëèòüñÿ
íà áîëåå ìåëêèå. Ïîâòîðÿþùèìèñÿ ñ÷èòàþòñÿ ïîëÿ, êîòîðûå ñîäåðæàò îäèíàêîâûå ïî
ñìûñëó çíà÷åíèÿ.
 íàøåé ñòðóêòóðå òàáëèö íåò
ïîâòîðÿþùèõñÿ ãðóïï (ìîæíî ëåãêî ïðîâåðèòü, ïðîñìîòðåâ âñå òàáëèöû). Ïî÷òè âñå
ïîëÿ, êðîìå ïîëåé â òàáëèöå WholesaleBases ÿâëÿþòñÿ íåäåëèìûìè. Íàïðèìåð, ïîëå address íå ÿâëÿåòñÿ íåäåëèìûì, òàê êàê ñîäåðæèò ðàçíîðîäíóþ
èíôîðìàöèþ (òåêñòîâîå íàçâàíèå óëèöû è ÷èñëîâîå íàçâàíèå äîìà è êâàðòèðû).
Òàêæå FIOman (ÔÈÎ ìåíåäæåðà) ñîñòîèò è
ôàìèëèè, èìåíè è îò÷åñòâà. Íî èíôîðìàöèÿ ýòà ÷èñòî ñïðàâî÷íàÿ, ïîýòîìó
ðàçäåëÿòü ýòî íèãäå íå ïîòðåáóåòñÿ, ïîýòîìó ìîæíî ñ÷èòàòü, ÷òî 1ÍÔ èìååò
ìåñòî.
2ÍÔ – òðåáóåò, ÷òîáû âñå ïîëÿ
òàáëèöû çàâèñåëè îò ïåðâè÷íîãî êëþ÷à, ò.å. ÷òîáû ïåðâè÷íûé êëþ÷, îäíîçíà÷íî
îïðåäåëÿë çàïèñü è íå áûë èçáûòî÷åí.
Î÷åâèäíî, âî âñåõ òàáëèöàõ,
ãäå åñòü ïåðâè÷íûå êëþ÷è, îíè îäíîçíà÷íî îïðåäåëÿþò çàïèñü. Ïåðâè÷íûõ êëþ÷åé
íåò òîëüêî â òàáëèöå ScanCodes. Íî òàì îíè è íå íóæíû.
3ÍÔ – òðåáóåò ÷òîáû, â òàáëèöå íå èìåëîñü
òðàíçèòèâíûõ çàâèñèìîñòåé ìåæäó íå êëþ÷åâûìè ïîëÿìè, ò.å. ÷òîáû çíà÷åíèå ëþáîãî
ïîëÿ íå âõîäÿùåãî â ïåðâè÷íûé êëþ÷ íå çàâèñåëî îò çíà÷åíèÿ äðóãîãî ïîëÿ, òàê æå
íå âõîäÿùåãî â ïåðâè÷íûé êëþ÷!
Ïðîàíàëèçèðîâàâ âñå òàáëèöû
è èñêëþ÷èâ ïîëÿ êîòîðûå ìû äîãîâîðèëèñü íå ó÷èòûâàòü, ìîæíî óáåäèòüñÿ, ÷òî òàê
îíî è åñòü.
Àðõèòåêòóðà
ñèñòåìû ïðèâåäåíà íà ðèñóíêå 2.2.
|
Ðèñóíîê 2.2 |
Êîìïüþòåð êàññèðà, ðàáîòàþùåãî
â ìàãàçèíå, ÿâëÿåòñÿ ñåðâåðîì. Ìåíåäæåð ñ ãëàâíûì áóõãàëòåðîì ïîäñîåäèíåíû ê
ñåðâåðó ÷åðåç ñåòü. Ðóêîâîäèòåëü ïðåäïðèÿòèÿ èìååò âîçìîæíîñòü ïîäñîåäèíèòü
ñâîé íîóòáóê ê ñåòè è ïîñìîòðåòü, êàê èäóò äåëà, èëè âîñïîëüçîâàòüñÿ äëÿ ýòîãî
êîìïüþòåðîì ìåíåäæåðà.
 èäåàëüíîì ñëó÷àå â
êà÷åñòâå ñåðâåðà äîëæåí ñòîÿòü îòäåëüíûé êîìïüþòåð ñ óñòàíîâëåííûì ñåðâåðîì ÁÄ,
ñ îòñóòñòâèåì íåñàíêöèîíèðîâàííîãî äîñòóïà. Íî íà äàííîì ïðåäïðèÿòèè âñåãî òðè
êîìïüþòåðà, è ôèðìà íå ìîæåò ñåáå ïîçâîëèòü ïðîñòàèâàíèå îäíîãî èç íèõ. Ïîýòîìó
íà ñåðâåðå áóäåò òàêæå âûïîëíÿòüñÿ äðóãàÿ ðàáîòà. Ñåðâåðîì ÿâëÿåòñÿ êîìïüþòåð
êàññèðà. Ýòî ðàçóìíî ïî ñëåäóþùèì ïðè÷èíàì:
âî-ïåðâûõ, äàííûé êîìïüþòåð
ñàìûé ìîùíûé èç âñåõ;
âî-âòîðûõ, îí çàïèòàí ÷åðåç
èñòî÷íèê áåñïåðåáîéíîãî ïèòàíèÿ, êîòîðûé ïîäñîåäèíåí íå òîëüêî ê êîìïüþòåðó, íî
è ê êàññîâîìó àïïàðàòó (÷òî ïîçâîëÿåò èçáåæàòü ñáîåâ â ïðîãðàììå â ñëó÷àå
îòêëþ÷åíèÿ ýëåêòðè÷åñòâà, à òàêæå íîðìàëüíî ïðîáèòü ÷åê);
â-òðåòüèõ, êàññèðó íå
ïðèäåòñÿ åæåäíåâíî ñ óòðà âêëþ÷àòü äîïîëíèòåëüíûé êîìïüþòåð, èñïîëüçóåìûé â
êà÷åñòâå ñåðâåðà, äëÿ òîãî, ÷òîáû èìåòü âîçìîæíîñòü ðàáîòàòü ñ ïðîãðàììîé;
â-÷åòâåðòûõ, áîëüøóþ ÷àñòü
âðåìåíè ñ ïðîãðàììîé áóäåò ðàáîòàòü èìåííî êàññèð (îòñóòñòâèå ïåðåäà÷è äàííûõ
ïî ñåòè).
Íåäîñòàòêîì òàêîãî ðåøåíèÿ
ÿâëÿåòñÿ ñíèæåíèå áåçîïàñíîñòè. Îïûòíûé êàññèð ëåãêî ñêîïèðóåò áàçó ñåáå äîìîé,
ñ öåëüþ âíåñåíèÿ èçìåíåíèé.
Ðèñóíîê 3.1
Îáúÿñíèì, ïî÷åìó áûëè âûáðàíû èìåííî òàêèå òèïû äàííûõ:
1) Òàáëèöà goods (Òîâàðû). Ïî èäåå, íàçâàíèå
òîâàðà (name_good) âðÿä ëè áóäåò ðàçìåðîì
áîëüøå 80 ñèìâîëîâ, ïîýòîìó áûëî ðåøåíî îñòàíîâèòüñÿ èìåííî íà ýòîé öèôðå.
Àðòèêóë (art) òàêæå âðÿä ëè áóäåò èìåòü
äëèíó áîëåå 20 (îáû÷íî ó íåãî äëèíà ìåíüøå 10). À ïîëå scan_codes õðàíèò âñå ñêàí-êîäû äëÿ
äàííîãî òîâàðà â ñòðîêîâîì ôîðìàòå ñ ïðîáåëàìè-ðàçäåëèòåëÿìè (ýòî ïîëå íóæíî
òîëüêî äëÿ óñêîðåíèÿ âûâîäà áîëüøèõ îáúåìîâ èíôîðìàöèè), ïîýòîìó áûëî ðåøåíî
ñäåëàòü åãî ñ çàïàñîì (varchar(255)).
2) Òàáëèöà TitleUnits (ÅäèíèöûÈçìåðåíèÿ): code_unit – êëþ÷åâîå ïîëå, ïðè ýòîì
àâòîèíêðåìåíòíîå. Äëÿ íàçâàíèÿ åäèíèöû èçìåðåíèÿ ëîãè÷íî âûáðàòü òèï varchar äëèíû 20, òàê êàê âðÿä ëè ìîãóò ïîòðåáîâàòüñÿ
åäèíèöû èçìåðåíèÿ, èìåþùèå áîëüøóþ äëèíó (âîîáùå, âðÿä ëè èõ äëèíà áóäåò
ñîäåðæàòü áîëåå 5 ñèìâîëîâ, òàê êàê íàçâàíèÿ åäèíèö èçìåðåíèÿ âûãëÿäÿò òàê:
“øò”, “êã”, “ì”). Ïîëå IsActive îáîçíà÷àåò, äîñòóïíà ëè â äàííûé ìîìåíò óêàçàííàÿ åäèíèöà èçìåðåíèÿ.
Åñëè IsActive=0,
òî ïîëüçîâàòåëü å¸ íå ñìîæåò âíîñèòü, íî îíà áóäåò ïðèñóòñòâîâàòü â òåõ
òîâàðàõ, êóäà óæå âíåñåíà. Åñëè IsActive=1, òî åäèíèöà èçìåðåíèÿ
àêòèâíà. Âîîáùå, áûëî áû ëîãè÷íî âûáðàòü òèï boolean, íî òàê êàê Firebird åãî íå ïîääåðæèâàåò, áûë âûáðàí òèï integer. Ïîëå IsMaterial (åäèíèöà èçìåðåíèÿ ÿâëÿåòñÿ
âåùåñòâåííîé, åñëè IsMaterial=1) òîæå äîëæíî áûëî èìåòü òèï
boolean, íî ïî èçâåñòíîé ïðè÷èíå
(òèï boolean íå ïîääåðæèâàåòñÿ ñåðâåðîì Firebird), áûë âûáðàí òèï integer.
3) Òàáëèöà paths (Ãðóïïû). Äëÿ íàçâàíèÿ
ãðóïïû òèï varchar(80)
âïîëíå ïîäõîäèò.
4) Â òàáëèöå ScanCodes áûëî ðåøåíî ñäåëàòü scan_code ñòðîêîâûì òèïîì, êîòîðûé,
îäíàêî, ìîæåò ñîäåðæàòü òîëüêî 13-çíà÷íûå ÷èñëà. Òèï integer äëÿ ýòîé öåëè íå ïîäõîäèò,
òàê êàê ìîæåò õðàíèòü òîëüêî 9-çíà÷íûå ÷èñëà.
5) Òàáëèöà StoreHouse (Ñêëàä) õðàíèò òîëüêî òî,
÷òî åñòü íà ñêëàäå. Åñëè òîâàð ëåæèò íà ñêëàäå, òî îí íå çíàåò, ñ êàêîé îïòîâîé áàçû îí áûë çàêóïëåí. Ïîýòîìó
äîñòàòî÷íî õðàíèòü åãî êîëè÷åñòâî (quantity), ñåáåñòîèìîñòü (first_price) (ñðåäíåâçâåøåííîå çíà÷åíèå
çàêóïî÷íûõ öåí, åñëè òîâàð áûë ïðèâåçåí íåîäíîêðàòíî ïî ðàçíûì öåíàì), öåíó (price) è êîëè÷åñòâî ïðîäàííîãî
òîâàðà (sold). Åñëè òîâàð ñûïó÷èé
(íàïðèìåð, ñàõàðíûé ïåñîê), òî ïðè èíâåíòàðèçàöèè áóäåò âèäíî, ñêîëüêî äàííîãî
òîâàðà áûëî ïðîäàíî, è ñêîëüêî îñòàëîñü. Íàïðèìåð, åñëè áûëî ïðîäàíî 500 êã
ñàõàðíîãî ïåñêà, òî íåäîñòà÷à â 2 êã âïîëíå äîïóñòèìà, íî åñëè áûëî ïðîäàíî 20
êã ïåñêà, òî åñòü ïîâîä çàäóìàòüñÿ.
6) Òàáëèöà WholesaleBases õðàíèò ñïèñîê îïòîâûõ áàç,
íà êîòîðûõ ìàãàçèí çàêóïàë òîâàðû. Äëÿ íàçâàíèÿ îïòîâîé áàçû âïîëíå äîñòàòî÷íî
ñòðîêîâîãî ïîëÿ äëèíîé 80, à â ñòðîêó äëèíîé 40 ñèìâîëîâ ìîæíî çàïèñàòü
íåñêîëüêî òåëåôîííûõ íîìåðîâ.
7) Â òàáëèöå purchases ïîëå summa íóæíî òîëüêî äëÿ óñêîðåíèÿ
âûâîäà äàííûõ. Îíî õðàíèò ñóììó, íà êîòîðóþ áûëè çàêóïëåíû òîâàðû äàííîé
îïòîâîé çàêóïêè. Ïîýòîìó îíî èìååò òèï float.
8) Â òàáëèöå sessions ïîëå accepted äîëæíî áûëî èìåòü òèï boolean, íî çà íåèìåíèåì äàííîãî
òèïà èñïîëüçóåòñÿ integer.
Ïîëÿ addition (íàöåíêà) è summa (ñóììà) öåëåñîîáðàçíî
ñäåëàòü âåùåñòâåííûìè, òàê êàê íàöåíêà íå îáÿçàíà áûòü öåëûì ÷èñëîì (ìîæåò
áûòü, íàïðèìåð, 72,5%), à äåíüãè áûëî ðåøåíî õðàíèòü â âåùåñòâåííîì ôîðìàòå.
9) Òàáëèöà
StructureSession (ÑòðóêòóðàÑåññèè). Ïîëå scan_codes õðàíèò ñïèñîê ñêàí-êîäîâ,
êîòîðûå áóäóò äîñòóïíû äëÿ äàííîãî òîâàðà ïîñëå çàíåñåíèÿ ñåññèè. Îíî
àíàëîãè÷íî ïîëþ scan_codes òàáëèöû goods. Òàê êàê òîâàð ìîæåò áûòü
øòó÷íûì èëè âåùåñòâåííûì, áûëî ðåøåíî õðàíèòü êîëè÷åñòâî òîâàðà â âåùåñòâåííîì
ôîðìàòå. Ïîëå first_price õðàíèò çàêóïî÷íóþ öåíó,
ïîýòîìó ðàçóìíî èñïîëüçîâàòü òèï float.
Ïîëå addition õðàíèò íàöåíêó, êîòîðàÿ
ìîæåò áûòü íå öåëûì ÷èñëîì, ïîýòîìó òèï float äëÿ íåãî ïîäõîäèò.
10) Òèïû òàáëèöû ScanCodesForSession àíàëîãè÷íû òèïàì òàáëèöû ScanCodes. Òàáëèöà ScanCodesForSession íóæíà òîëüêî äëÿ âðåìåííîãî
õðàíåíèÿ ñêàí-êîäîâ íåçàêðûòûõ ñåññèé.
11) Òàáëèöà ChangedPrices õðàíèò èçìåíåííûå öåííèêè è
äàòó ïîñëåäíåãî èçìåíåíèÿ. Äëÿ äàòû ðàçóìíî èñïîëüçîâàòü òèï timestamp, à äëÿ õðàíåíèÿ íîâîé öåíû
– òèï float.
12) Òàáëèöà sales (Ïðîäàæè) íå òðåáóåò
ïîÿñíåíèé.
13)  òàáëèöå StructureSale (ÑòðóêòóðàÏðîäàæè)
öåëåñîîáðàçíî ïî èçâåñòíûì ïðè÷èíàì (ñì. ïîÿñíåíèÿ äëÿ òàáëèö StoreHouse è StructureSession) õðàíèòü êîëè÷åñòâî,
çàêóïî÷íóþ öåíó, ðîçíè÷íóþ öåíó, ñêèäêó äëÿ ïîêóïàòåëÿ, à òàêæå öåíó, ïî
êîòîðîé áûë ïðîäàí òîâàð è ñòîèìîñòü òîâàðà â âåùåñòâåííîì ôîðìàòå.
14) Òàáëèöà returns2
(Âîçâðàòû) íå òðåáóåò ïîÿñíåíèé.
15) Òàáëèöà StructureReturn2
õðàíèò âîçâðàùåííûå òîâàðû, à òàêæå èõ êîëè÷åñòâî è ñóììó. Äëÿ ïîñëåäíèõ
ðàçóìíî èñïîëüçîâàòü òèï float.
16) Äëÿ òàáëèöû notes (Ïðèìå÷àíèÿ) ðåøåíî áûëî
îãðàíè÷èòü ðàçìåð ïðèìå÷àíèÿ 80 ñèìâîëàìè (äëÿ òîãî, ÷òîáû íå ïåðåãðóæàòü
áàçó).
Ïðîãðàììà íàïèñàíà íà Borland Delphi.
 êà÷åñòâå ðàáî÷åé âåðñèè áûëà âûáðàíà ñåäüìàÿ âåðñèÿ êîìïèëÿòîðà Delphi.  êà÷åñòâå ÑÓÁÄ
âûáðàí Firebird âåðñèè 1.53.
Ïî ñóòè, ïðîãðàììà ñîñòîèò èç äâóõ ÷àñòåé: ñåðâåðíàÿ (õðàíèìûå
ïðîöåäóðû) è êëèåíòñêàÿ (êîä ïðîãðàììû).
Ïðîãðàììà ðàáîòàåò ïîä îïåðàöèîííîé ñèñòåìîé Windows XP. Äëÿ íîðìàëüíîé ðàáîòû ïðîãðàììû íóæíî ðàçðåøåíèå
ýêðàíà íå ìåíåå, ÷åì 1024x768, ïîääåðæêà ðåæèìà VGA (256 öâåòîâ), 64 ìåãàáàéòà îïåðàòèâíîé ïàìÿòè
è ïðîöåññîð óðîâíÿ Intel Celeron 400 Mhz, õîòÿ äëÿ íîðìàëüíîé ðàáîòû ïðîãðàììû íà ñåðâåðå
ëó÷øå èìåòü ìàøèíó ïîìîùíåå.
Ïðîãðàììà ïîëíîñòüþ ñîîòâåòñòâóåò ñòàíäàðòàì äëÿ ïðîãðàìì Windows
(ãëàâíûå ìåíþ, êîíòåêñòíûå ìåíþ, êíîïêè, ïåðåêëþ÷àòåëè è ò. ä.). Äëÿ ðàáîòû ñ
äàííîé ïðîãðàììîé òðåáóþòñÿ ìèíèìàëüíûå íàâûêè ðàáîòû ñ êîìïüþòåðîì (óìåíèå
âêëþ÷èòü è âûêëþ÷èòü êîìïüþòåð, çàïóñòèòü ïðîãðàììó ñ ðàáî÷åãî ñòîëà, óìåíèå
ïîëüçîâàòüñÿ ãëàâíûìè è êîíòåêñòíûìè ìåíþ, êíîïêàìè è ïåðåêëþ÷àòåëÿìè).
Ïî÷òè âñå ìàíèïóëÿöèè ñ äàííûìè ïðîèçâîäÿòñÿ ñ ïîìîùüþ õðàíèìûõ
ïðîöåäóð. Òàêîé ïîäõîä ïîçâîëÿåò èçáåæàòü âíåñåíèÿ â áàçó îøèáî÷íûõ äàííûõ, òàê
êàê â ïðîöåäóðàõ âñå æåñòêî ïðîâåðÿåòñÿ. Êðîìå òîãî, ýòî ïîçâîëÿåò íîðìàëüíî
îðãàíèçîâàòü ìíîãîïîëüçîâàòåëüñêóþ ðàáîòó (òàê êàê ïðîâåðêè âûïîëíÿþòñÿ íà
ñåðâåðå íåïîñðåäñòâåííî ïåðåä çàíåñåíèåì äàííûõ).
Ìàíèïóëÿöèè ñ äàííûìè ïðîèñõîäÿò òàê: âûçûâàåòñÿ íóæíàÿ õðàíèìàÿ
ïðîöåäóðà ñ âõîäíûìè ïàðàìåòðàìè, íà âûõîä ïðîöåäóðà âûäàåò îøèáêó (ïåðåìåííàÿ
òèïà integer). Åñëè îøèáêà ðàâíà íóëþ, òî äåéñòâèÿ ïðîøëè óñïåøíî,
èíà÷å â çàâèñèìîñòè îò ïîëó÷åííîãî íîìåðà îøèáêè êëèåíòñêàÿ ïðîãðàììà âûäàåò
ñîîòâåòñòâóþùåå ñîîáùåíèå îá îøèáêå.
Òàêèì îáðàçîì, ñåðâåðíàÿ ÷àñòü îòâå÷àåò çà ïðàâèëüíîñòü ââîäèìûõ
äàííûõ, íî è êëèåíòñêàÿ ÷àñòü ïîñòðîåíà ïî âîçìîæíîñòè òàê, ÷òîáû íå äàòü
ïîëüçîâàòåëþ äîïóñòèòü îøèáîê. Â áîëüøèíñòâå ìåñò ïðîãðàììû âûïîëíÿåòñÿ äâå
ïðîâåðêè: ñíà÷àëà íà êëèåíòå, çàòåì íà ñåðâåðå.
Âñå çàïðîñû è âñÿ ðàáîòà ñ
äàííûìè (íàïðèìåð, ðàçëè÷íûå ñîðòèðîâêè) ïðîèçâîäèòñÿ íà ñåðâåðå. Ýòî ìîæíî
ñåáå ïîçâîëèòü äëÿ íåáîëüøîãî ìàãàçèíà, òàê êàê ÷èñëî ïîëüçîâàòåëåé íåâåëèêî
(2—3). Ïðè òàêîì ïîäõîäå óïðîùàåòñÿ ðåàëèçàöèÿ ïðîãðàììû, ê òîìó æå íå íóæíû
ìîùíûå êëèåíòñêèå ìàøèíû è ñíèæàåòñÿ íàãðóçêà íà ñåòü (ïî ñåòè ïåðåäàåòñÿ
òîëüêî íóæíàÿ èíôîðìàöèÿ). Òåì íå ìåíåå, ñî âðåìåíåì ïëàíèðóåòñÿ ïåðåíåñòè
÷àñòü ðàáîòû íà êëèåíòà (÷òîáû íå ïåðåãðóæàòü ñåðâåð).
Íà ðèñóíêå 3.2 ïðèâåäåíà îñíîâíàÿ ôîðìà ïðîãðàììû. Îíà ïîÿâëÿåòñÿ ñðàçó
ïîñëå âõîäà â ïðîãðàììó.
|
Ðèñóíîê 3.2 |
Äëÿ èñïîëüçîâàíèÿ ïðîãðàììû â ðàáîòå ìàãàçèíà ÷åðåç íåå íóæíî çàíåñòè
èíôîðìàöèþ î òîâàðàõ, êîòîðûìè òîðãóåò äàííûé ìàãàçèí, â áàçó. Ïðîãðàììà
ïðåäîñòàâëÿåò âîçìîæíîñòü ðàçáèòü òîâàðû íà ãðóïïû äëÿ áîëåå óäîáíîé
îðãàíèçàöèè ðàáîòû. Ïåðåä ïåðâûì çàíåñåíèåì èíôîðìàöèè î òîâàðàõ ðåêîìåíäóåòñÿ ïðîäóìàòü
ñòðóêòóðó ãðóïï. Ïðîãðàììà ïîçâîëÿåò ñîçäàâàòü, ïåðåèìåíîâûâàòü, óäàëÿòü,
ïåðåìåùàòü çàïèñè (â òîì ÷èñëå ãðóïïû, à òàêæå
òîâàðû, íàõîäÿùèåñÿ â ýòèõ ãðóïïàõ) â ïðîöåññå çàíåñåíèÿ òîâàðîâ, íî äëÿ
áîëüøåãî ïîðÿäêà ëó÷øå ñðàçó îïðåäåëèòü îñíîâíûå ãðóïïû. Ôîðìà äëÿ çàíåñåíèÿ
ãðóïï òîâàðîâ ïðèâåäåíà íà ðèñóíêå 3.3.
Òîâàðû ïîñòàâëÿþòñÿ â ìàãàçèí ñ îïòîâûõ áàç, ïîýòîìó ïåðåä çàíåñåíèåì
èíôîðìàöèè î òîâàðàõ èç î÷åðåäíîé îïòîâîé çàêóïêè íåîáõîäèìî óáåäèòüñÿ, ÷òî
îïòîâàÿ áàçà, ñ êîòîðîé ïîñòàâëåíû òîâàðû, èìååòñÿ â ñïèñêå îïòîâûõ áàç
ïðîãðàììû. Åñëè òàêîé çàïèñè íåò, åå íóæíî äîáàâèòü. Äëÿ ýòîãî íà îñíîâíîé
ôîðìå (ðèñóíîê 3.2), ïîÿâëÿþùåéñÿ ïðè âõîäå â ïðîãðàììó, ñëåäóåò íàæàòü êíîïêó
«Ðàáîòà ñ îïòîâûìè áàçàìè». Íà ýêðàíå ïîÿâèòñÿ ôîðìà äëÿ ðàáîòû ñ îïòîâûìè áàçàìè
(ðèñóíîê 3.4).
Ðèñóíîê 3.3
Ðèñóíîê 3.4
 äàííîé ôîðìå ñ ïîìîùüþ êîìàíä ãëàâíîãî èëè êîíòåêñòíîãî ìåíþ ìîæíî
äîáàâëÿòü, èçìåíÿòü èëè óäàëÿòü èíôîðìàöèþ îá îïòîâûõ áàçàõ.
Èòàê, íóæíûå îïòîâûå áàçû çàâåäåíû. Òåïåðü íåîáõîäèìî çàíåñòè
èíôîðìàöèþ î òîâàðàõ. Äëÿ ýòîãî âûõîäèì èç ôîðìû äëÿ ðàáîòû ñ îïòîâûìè áàçàìè â
ãëàâíóþ ôîðìó (ðèñóíîê 3.2) (èç ëþáîé ôîðìû äàííîé ïðîãðàììû ìîæíî âûéòè ñ
ïîìîùüþ êëàâèøè <Esc>). Âûáèðàåì ïóíêò «Çàíåñåíèå òîâàðîâ». Ïîñëå íàæàòèÿ äàííîé êíîïêè íà
ýêðàíå ïîÿâèòñÿ ôîðìà «Çàíåñåíèå çàêóïëåííûõ òîâàðîâ â áàçó» (ðèñóíîê 3.5):
Íà ðèñóíêå 3.5 ïðèâåäåíî îòîáðàæåíèå ñïèñêà îïòîâûõ çàêóïîê â ôîðìå.
Ïðè ïîñòàâêå òîâàðîâ ñ îïòîâîé áàçû, íóæíî çàâåñòè îïòîâóþ çàêóïêó. Äåëàåòñÿ
ýòî ñ ïîìîùüþ êîìàíä ãëàâíîãî èëè êîíòåêñòíîãî ìåíþ. Ïðîöåññ ñîçäàíèÿ îïòîâîé
çàêóïêè âûãëÿäèò ñëåäóþùèì îáðàçîì (ðèñóíîê 3.6).
Íóæíî âûáðàòü èç ñïèñêà îïòîâóþ áàçó, ïðè îòñóòñòâèè ñâåäåíèé î áàçå â
ñïèñêå (ñì. «Ðàáîòà ñ îïòîâûìè áàçàìè»). Äàòà îïòîâîé çàêóïêè óñòàíàâëèâàåòñÿ
àâòîìàòè÷åñêè êàê òåêóùàÿ, íî åå ìîæíî èçìåíèòü.
Ïîñëå ñîçäàíèÿ îïòîâîé çàêóïêè â íåå ìîæíî çàíîñèòü òîâàðû. Äëÿ òîãî,
÷òîáû íà÷àòü çàíîñèòü òîâàðû, â äàííîé îïòîâîé çàêóïêå íóæíî ñîçäàòü ñåññèþ.
Ñåññèè íóæíû äëÿ óäîáñòâà çàíåñåíèÿ òîâàðîâ. Îïòîâàÿ çàêóïêà ìîæåò ñîäåðæàòü
áîëüøîå êîëè÷åñòâî òîâàðîâ, è â òàêîì ñëó÷àå óäîáíåå ðàçáèòü òîâàðû ïî ñåññèÿì,
÷åì çàíîñèòü èõ áîëüøèì ñïèñêîì. Êðîìå òîãî, ýòî î÷åíü ïîìîãàåò ïðè çàíåñåíèè
òîâàðîâ îïòîâîé çàêóïêè íåñêîëüêèìè ïîëüçîâàòåëÿìè îäíîâðåìåííî.  ýòîì ñëó÷àå
êàæäûé ïîëüçîâàòåëü áóäåò âèäåòü òîëüêî òå òîâàðû, êîòîðûå îí çàíåñ. Ïðè ýòîì
ïîêà ñåññèÿ íå çàêðûòà, òîâàðû íåäîñòóïíû äëÿ ïðîäàæè â ìàãàçèíå. Ýòî íóæíî äëÿ
òîãî, ÷òîáû ïðåäîòâðàòèòü íåñîâïàäåíèå öåííèêîâ íà âèòðèíå è â áàçå.
Ðèñóíîê 3.6
Ðèñóíîê 3.7
Ïîñëå çàêðûòèÿ ñåññèè îòâåòñòâåííûé çà öåíû ÷åëîâåê äîëæåí çàìåíèòü
ñòàðûå öåííèêè íà âèòðèíå íà íîâûå. Ñïèñîê òîâàðîâ, íà êîòîðûå íóæíî ïîìåíÿòü
öåííèêè, ïðîãðàììà âûäàåò â âèäå äîêóìåíòà Microsoft Word. Ñîçäàòü ñåññèþ ìîæíî ñ ïîìîùüþ êîìàíä ãëàâíîãî èëè êîíòåêñòíîãî ìåíþ.
Ïðîöåññ ñîçäàíèÿ ñåññèè ïðîñò, è íå òðåáóåò èëëþñòðàöèé. Ïðè ñîçäàíèè ñåññèè
íåîáõîäèìî òîëüêî óêàçàòü ìàãàçèííóþ íàöåíêó íà òîâàðû. Ïðè çàíåñåíèè òîâàðîâ â
äàííóþ ñåññèþ ðîçíè÷íàÿ öåíà áóäåò ôîðìèðîâàòüñÿ àâòîìàòè÷åñêè. Êîíå÷íî, ïðè
æåëàíèè åå ìîæíî áóäåò èçìåíèòü (è íàöåíêó òîæå).
Èòàê, ñåññèÿ ñîçäàíà. Ïðè
äâîéíîì ùåë÷êå ìûøüþ ïî ñîçäàííîé ñåññèè íà ýêðàíå ïîÿâèòñÿ ôîðìà äëÿ çàíåñåíèÿ
òîâàðîâ (ðèñóíîê 3.7).
Ïîêà â ñåññèþ íå çàíåñåíî íè îäíîãî òîâàðà. Îòêðûòü ôîðìó äëÿ
äîáàâëåíèÿ òîâàðà â ñåññèþ ìîæíî ñ ïîìîùüþ êîìàíä ãëàâíîãî èëè êîíòåêñòíîãî
ìåíþ, èëè ñ ïîìîùüþ êëàâèøè <ïðîáåë>. Ïîñëå äàííûõ äåéñòâèé íà ýêðàíå
ïîÿâèòñÿ ôîðìà äëÿ çàíåñåíèÿ òîâàðà (ðèñóíîê 3.8):
Ðèñóíîê
3.8
Ðèñóíîê 3.9
Òîâàðû ìîæíî çàíîñèòü íåñêîëüêèìè ñïîñîáàìè. Ðàññìîòðèì ïåðâûé ñïîñîá.
Îí èñïîëüçóåòñÿ, êîãäà çàíîñÿòñÿ íîâûå òîâàðû, êîòîðûõ â ìàãàçèíå åùå íåò.
Ââîäèì íîâûé ìàãàçèííûé êîä òîâàðà âðó÷íóþ, èëè ñ ïîìîùüþ êíîïêè «Çàâåñòè íîâûé
êîä òîâàðà». Çàòåì ââîäèì íàçâàíèå òîâàðà, àðòèêóë, êîëè÷åñòâî, âûáèðàåì
åäèíèöó èçìåðåíèÿ («øò», «ì» èëè «êã»). Ïîñëå ýòîãî ââîäèì ñòîèìîñòü äàííîãî
êîëè÷åñòâà òîâàðîâ, óêàçàííóþ â íàêëàäíîé. Ïîñëå âûïîëíåíèÿ äàííûõ äåéñòâèé
ôîðìà äîëæíà ïðèíÿòü ïðèìåðíî ñëåäóþùèé âèä (öåíà è ñåáåñòîèìîñòü ñôîðìèðîâàëèñü
àâòîìàòè÷åñêè) (ðèñóíîê 3.9).
Ïîñëå ýòîãî íóæíî óêàçàòü ìåñòîïîëîæåíèå òîâàðà. Äåëàåòñÿ ýòî ñëåäóþùèì
îáðàçîì: íàæèìàåì êëàâèøó «Çàäàòü», íà ýêðàíå ïîÿâëÿåòñÿ ôîðìà, ïðèâåäåííàÿ íà
ðèñóíêå 3.3 (Ñïðàâî÷íèê òîâàðîâ).
Ùåëêíåì äâà ðàçà ïî òîé ãðóïïå äåðåâà, êóäà íóæíî çàíåñòè òîâàð, è
äàííàÿ ôîðìà çàêðîåòñÿ, è íà ýêðàíå îòîáðàçèòñÿ ïðåäûäóùàÿ, íî óæå ñ
îïðåäåëåííîé ãðóïïîé (ðèñóíîê 3.9):
Ðèñóíîê 3.10
Òåïåðü ñ ïîìîùüþ ñêàíåðà èëè âðó÷íóþ çàâåäåì ñêàí-êîäû äëÿ äàííîãî
òîâàðà. Ýòè ñêàí-êîäû áóäóò èñïîëüçîâàòüñÿ äëÿ ðàñïîçíàâàíèÿ òîâàðîâ ñ ïîìîùüþ
ñêàíåðà ïðè òîðãîâëå â ìàãàçèíå. Ïîñëå ýòîãî íàæèìàåì «Çàíåñòè», è åñëè âñå
ïîëÿ çàïîëíåíû ïðàâèëüíî, â ñåññèþ äîáàâèòñÿ òîâàð, è íà ýêðàíå îòîáðàçèòñÿ
ñëåäóþùåå (ðèñóíîê 3.11).
Òåïåðü ìîæíî çàíîñèòü ñëåäóþùèé òîâàð.
Îïèøåì òåïåðü âòîðîé ñïèñîá çàíåñåíèÿ òîâàðà. Íà ôîðìå çàíåñåíèÿ òîâàðà
ââåäåì êîä ñóùåñòâóþùåãî â áàçå òîâàðà, èëè ïðîñêàíèðóåì åãî. Åñëè òîâàð ñ
äàííûì êîäîì óæå ñóùåñòâóåò, âñå íåîáõîäèìûå ïîëÿ áóäóò çàïîëíåíû
àâòîìàòè÷åñêè, è èõ íåëüçÿ áóäåò èçìåíèòü. Ôîðìà ïðè ýòîì áóäåò âûãëÿäåòü
ñëåäóþùèì îáðàçîì (ðèñóíîê 3.12).
Ðèñóíîê 3.11
Ðèñóíîê
3.12
Ïîñëå ýòîãî îñòàåòñÿ òîëüêî
ââåñòè êîëè÷åñòâî, ñóììó, èñïðàâèòü öåíó.  ñëó÷àå, åñëè íîâàÿ öåíà
íåçíà÷èòåëüíî îòëè÷àåòñÿ îò ñòàðîé, êîòîðàÿ òàêæå ïîêàçûâàåòñÿ íà ýêðàíå, öåíó
ìîæíî îñòàâèòü ïðåæíåé, ÷òîáû íå ìåíÿòü âïîñëåäñòâèè öåííèêè íà âèòðèíå.
Åñëè òîâàð íå ñêàíèðóåòñÿ, à
ìàãàçèííûé êîä òîâàðà íåèçâåñòåí (íåâîçìîæíî ôèçè÷åñêè çàïîìíèòü òàêîå
êîëè÷åñòâî êîäîâ!), òî òîâàð ìîæíî âûáðàòü èç Ñïðàâî÷íèêà. Äåëàåòñÿ ýòî
ñëåäóþùèì îáðàçîì: íàæèìàåì êëàâèøó «Âûáðàòü ñóùåñòâóþùèé òîâàð èç
ñïðàâî÷íèêà», â îòêðûâøåìñÿ îêíå âûáèðàåì ãðóïïó, ãäå ëåæèò òîâàð, à â íåé
âûáèðàåì òîâàð. Ïîñëå ýòîãî íóæíûå ïîëÿ íà ôîðìå çàíåñåíèÿ òîâàðà çàïîëíÿòñÿ
àâòîìàòè÷åñêè òàêæå, êàê åñëè áû ìû âðó÷íóþ ââåëè êîä òîâàðà.
Èòàê, òîâàðû â ñåññèþ çàíåñåíû.
Òåïåðü íóæíî ïðîâåðèòü ïðàâèëüíîñòü çàíåñåíèÿ. Ìåòîäîâ ïðîâåðêè íåñêîëüêî, îäèí
èç íèõ òàêîé:
òîâàðû íóæíî çàíîñèòü ïî îäíîé
ñòðàíèöå íàêëàäíîé â îäíó ñåññèþ (òî åñòü çàâîäèòü ñòîëüêî ñåññèé, ñêîëüêî
ñòðàíèö â íàêëàäíîé);
çàòåì ñâåðèòü îáùóþ ñòîèìîñòü
òîâàðîâ;
çàòåì çàêðûòü ñåññèþ.
Òåïåðü òîâàðàìè, çàíåñåííûìè â
äàííóþ ñåññèþ, ìîæíî òîðãîâàòü, íî äî ýòîãî íåîáõîäèìî èçìåíèòü íåêîòîðûå
öåííèêè. Ïîðÿäîê èçâëå÷åíèÿ èç ïðîãðàììû ñïèñêà èçìåíèâøèõñÿ öåííèêîâ áóäåò
îïèñàí äàëåå.
Ôîðìà äëÿ òîðãîâëè òîâàðàìè
ïðèâåäåíà íà ðèñóíêå 3.13.
Ðèñóíîê
3.13
Äàííàÿ ôîðìà ïðåäîñòàâëÿåò
âîçìîæíîñòü îñóùåñòâèòü ñëåäóþùåå:
· Ââåñòè
òîâàðû äëÿ ïðîäàæè ñ ïîìîùüþ êîäà òîâàðà èëè ñêàí-êîäà.
· Ñäåëàòü
ñêèäêó ñ ïîìîùüþ ââîäà ñêèäêè èëè ñ ïîìîùüþ èçìåíåíèÿ öåíû.
· Ïîäñ÷èòàòü
àâòîìàòè÷åñêè îáùóþ ñóììó ïîêóïêè. ×òîáû ïðîáèòü ÷åê, îáÿçàòåëüíî íóæíî ââåñòè
íàëè÷íûå. Ýòî íóæíî, âî-ïåðâûõ, ïîòîìó ÷òî íå âñå óìåþò õîðîøî ñ÷èòàòü â óìå, è
âñå ðàâíî íóæåí áûë áû êàëüêóëÿòîð. Âî-âòîðûõ, ýòî äîïîëíèòåëüíàÿ ãàðàíòèÿ
òîãî, ÷òî ïðîäàâåö íå çàáóäåò âçÿòü äåíüãè îò ïîêóïàòåëÿ.
· Íàïå÷àòàòü
òîâàðíûé ÷åê, íî íå ðàíåå, ÷åì áóäåò ïðîáèò êàññîâûé ÷åê. Ïîñëå òîãî, êàê
êàññîâûé ÷åê ïðîáèò, íà ôîðìå óæå íè÷åãî íåëüçÿ ìåíÿòü.
· Ââåñòè
ïðèìå÷àíèå ê ïîêóïêå (íàïðèìåð, «ó ÷àøêè èìååòñÿ ñêîë íà ðó÷êå») äëÿ
ïîñëåäóþùåãî ïîèñêà ïðè âîçìîæíîì âîçâðàòå òîâàðà â ìàãàçèí.
· Îáñëóæèòü
íåñêîëüêî ïîêóïàòåëåé áåç íåîáõîäèìîñòè çàïóñêàòü âòîðóþ êîïèþ ïðîãðàììû.
Äîñòèãíóòî ýòî ñ ïîìîùüþ âêëàäîê. Êàæäàÿ âêëàäêà èìååò ñâîè êîìïîíåíòû.
· Îñóùåñòâèòü
ïîèñê òîâàðà ïî ÷àñòè íàçâàíèÿ, ïî àðòèêóëó è ïî ÷àñòè ñêàí-êîäà. Åñëè ââåäåí
öåëûé ñêàí-êîä (13 öèôð), òî ïîèñê âåäåòñÿ ñ âåðîÿòíîñòüþ íåñîâïàäåíèÿ
íåñêîëüêèõ öèôð ñêàí-êîäà (ýòî ìîæåò áûòü ïîëåçíî, åñëè ïðè çàíåñåíèè òîâàðà ñêàí-êîä
áûë ââåäåí íåïðàâèëüíî). Âèä ôîðìû äëÿ ïîèñêà òîâàðà ïðèâåäåí íà ðèñóíêå 3.14.
Ðèñóíîê 3.14
Ïðîãðàììà ïîçâîëÿåò îñóùåñòâëÿòü âîçâðàò òîâàðà. Ïðîöåññ âîçâðàòà
òîâàðà âûãëÿäèò ñëåäóþùèì îáðàçîì: íà êàæäîì ÷åêå íàïèñàí êîä ïîêóïêè
(ðèñóíîê 3.15). Äëÿ âîçâðàòà òîâàðà ïðîäàâåö äîëæåí ââåñòè äàííûé êîä ïîêóïêè íà ôîðìå äëÿ âîçâðàòà òîâàðîâ, è íà ýêðàíå áóäóò îòîáðàæåíû òîâàðû äàííîé ïîêóïêè. Âèä ôîðìû ïðèâåäåí íà ðèñóíêå 3.16. |
|
Ðèñóíîê 3.15
Ðèñóíîê 3.16
Íà ýêðàíå îòîáðàæåíû òîâàðû, òàêæå ïðîïèñàííûå â ÷åêå ïîêóïàòåëÿ. Â
ãðàôå «êîëè÷åñòâî» çàïèñàíî êîëè÷åñòâî òîâàðà, êîòîðîå áûëî êóïëåíî
ïåðâîíà÷àëüíî.  ãðàôå «îñòàòîê» çàïèñàíî êîëè÷åñòâî òîâàðà äàííîé ïîêóïêè,
êîòîðîå åùå èìååòñÿ ó ïîêóïàòåëÿ (îñòàëüíîå îí óæå âåðíóë â ìàãàçèí). Äëÿ âîçâðàòà
òîâàðà íóæíî ââåñòè êîëè÷åñòâî âîçâðàùàåìûõ òîâàðîâ, çàòåì íàæàòü êíîïêó
«Âîçâðàò òîâàðà». Ïðîãðàììà ïðåäîñòàâëÿåò âîçìîæíîñòü ïðîèçâîäèòü âîçâðàò ïî
÷åêó íåîãðàíè÷åííîå êîëè÷åñòâî ðàç, ïîêà îáúåì âîçâðàòà íå ïðåâûñèò îáúåì
ïîêóïêè.
Ðèñóíîê 3.17
Åñëè ïîêóïàòåëü ïðèíåñ òîâàð äëÿ âîçâðàòà áåç ÷åêà, òî
ñëåäóåò èñêàòü êîä ïîêóïêè ïî áàçå. Äëÿ ýòîãî èìååòñÿ ñïåöèàëüíàÿ ôîðìà
(ðèñóíîê 3.17). Ïîêóïàòåëü ìîæåò ïîìíèòü, çà êàêóþ ñóììó îí êóïèë äàííûé òîâàð,
êàêèìè êóïþðàìè ðàñïëà÷èâàëñÿ, êîãäà îí êóïèë ýòîò òîâàð (äàòà è âðåìÿ), êàêèå
òîâàðû îí ïîêóïàë ñîâìåñòíî ñ âîçâðàùàåìûì. Ïîèñê òàêæå ìîæåò ïðîèçâîäèòüñÿ ïî
÷àñòè íàçâàíèÿ òîâàðà, ïî ñêàí-êîäó è ïî ÷àñòè àðòèêóëà.
Ïîñëå òîãî, êàê ïîêóïêà èäåíòèôèöèðîâàíà, ïî ñòðîêå ñ äàííûì êîäîì
ïîêóïêè íóæíî ñäåëàòü äâîéíîé ùåë÷îê, è òîãäà êîä ïîêóïêè àâòîìàòè÷åñêè
ïåðåéäåò íà ôîðìó äëÿ âîçâðàòà òîâàðà.
Ðóêîâîäèòåëü ïðåäïðèÿòèÿ ìîæåò ïðîñìîòðåòü òîâàðû,
õðàíÿùèåñÿ íà Ñêëàäå. Äëÿ ýòîãî â ãëàâíîé ôîðìå ïðîãðàììû (ðèñóíîê 3.2) ñëåäóåò
íàæàòü êíîïêó «Ðàáîòà ñ òîâàðàìè íà Ñêëàäå». Çàòåì íóæíî âûáðàòü ãðóïïó, â
êîòîðîé íóæíî ïðîñìîòðåòü òîâàðû. Ïîñëå äâîéíîãî ùåë÷êà íà ýêðàíå îòîáðàçèòñÿ
ôîðìà, ïðèâåäåííàÿ íà ðèñóíêå 3.18.
Ðóêîâîäèòåëü ïðåäïðèÿòèÿ ñ ïîìîùüþ äàííîé ôîðìû ìîæåò
ïðîñìîòðåòü òîâàðû, ðàñïå÷àòàòü èõ, à òàêæå èçìåíèòü öåíû.
Ðèñóíîê 3.18
Íà ïðåäûäóùåé ôîðìå (êîòîðàÿ âûñâå÷èâàåòñÿ ïîñëå íàæàòèÿ íà
ãëàâíîé ôîðìå êíîïêè «Ðàáîòà ñ òîâàðàìè íà Ñêëàäå») ìîæíî òàêæå ðàñïå÷àòàòü
äåðåâî ãðóïï òîâàðîâ, ðàñïå÷àòàòü âñå òîâàðû ìàãàçèíà èëè âûáðàííîé ãðóïïû â
âèäå äåðåâà, à òàêæå ïîñìîòðåòü èçìåíåííûå öåííèêè.
Ôîðìà äëÿ ïðîñìîòðà èçìåíåííûõ öåííèêîâ ïðèâåäåíà íà
ðèñóíêå 3.19.
Ðóêîâîäèòåëü ïðåäïðèÿòèÿ ìîæåò ïðîñìîòðåòü èçìåíåííûå öåííèêè íà
òîâàðû, çà ëþáîé ïðåäøåñòâóþùèé ïåðèîä.
Ðèñóíîê 3.19
Ðèñóíîê 3.20
Ðóêîâîäèòåëü ïðåäïðèÿòèÿ ìîæåò ïðîñìîòðåòü èòîãè ëþáîãî äíÿ. Ôîðìà äëÿ
ïðîñìîòðà èòîãîâ äíÿ ïðèâåäåíà íà ðèñóíêå 3.20.
Äàííàÿ ôîðìà ïîçâîëÿåò ïðîñìîòðåòü òîâàðû, ïðîäàííûå çà
îïðåäåëåííûé ïåðèîä, à òàêæå ðàçëè÷íóþ ñòàòèñòèêó (íàïðèìåð, çàâèñèìîñòü
îáîðîòà è ïðèáûëè îò âðåìåíè). Òàêæå èç äàííîé ôîðìû ìîæíî èçìåíÿòü öåííèêè.
Äëÿ òîãî, ÷òîáû ëþáîé ïîëüçîâàòåëü ïðîãðàììû íå ìîã äåëàòü
ëþáûå äåéñòâèÿ, èìååòñÿ âîçìîæíîñòü ñîçäàòü íåñêîëüêèõ ïîëüçîâàòåëåé è íàäåëèòü
èõ ðàçëè÷íûìè ïðàâàìè. Ôîðìà äëÿ âõîäà â ïðîãðàììó ïðèâåäåíà íà ðèñóíêå 3.21.
|
Ôîðìà äëÿ ðàáîòû ñ
ïîëüçîâàòåëÿìè ïðèâåäåíà íà ðèñóíêå 3.22.
|
Èìååòñÿ 2 òèïà ïîëüçîâàòåëåé: ïðîñòîé è ñ ïðàâîì ñîçäàíèÿ äðóãèõ
ïîëüçîâàòåëåé. Åñëè â êîëîíêå «Ïðàâà» íàïèñàíî «3», òî ýòî àäìèíèñòðàòîð. Åñëè
â êîëîíêå «Ïðàâà» íàïèñàíî «2», òî ïîëüçîâàòåëü èìååò ïðàâî ñîçäàâàòü äðóãèõ
ïîëüçîâàòåëåé, íàäåëÿÿ èõ ïðàâàìè íå áîëüøèìè, ÷åì èìååò ñàì. Åñëè â êîëîíêå
«Ïðàâà» íàïèñàíî «1», òî ïîëüçîâàòåëü èìååò ïðàâî ìåíÿòü ñâîé ïàðîëü. Åñëè
íàïèñàíî «0», òî ïîëüçîâàòåëü âîîáùå íå èìååò íèêàêèõ ïðàâ ïî ðàáîòå ñ
ïîëüçîâàòåëÿìè.
Ôîðìà äëÿ ñîçäàíèÿ ïîëüçîâàòåëÿ ïðèâåäåíà íà ðèñóíêå 3.23.
Ðèñóíîê 3.23
Äëÿ ñîçäàíèÿ ïîëüçîâàòåëÿ íåîáõîäèìî óêàçàòü ñâîé ïàðîëü, ââåñòè èìÿ
ïîëüçîâàòåëÿ è åãî ïàðîëü, çàòåì íàäåëèòü ïîëüçîâàòåëÿ ïðàâàìè.
Äàííàÿ ïðîãðàììà ïðîèçâîäèò
ðàçëè÷íûå ìàíèïóëÿöèè ñ äàííûìè â îñíîâíîì ñ ïîìîùüþ õðàíèìûõ ïðîöåäóð. Íî
âûâîä äàííûõ (òàáëèöû, äåðåâüÿ, ãðàôèêè è ò. ä.) â îñíîâíîì ïðîèçâîäèòñÿ ñ
ïîìîùüþ SQL-çàïðîñîâ. Îäèí èç ñàìûõ
ñëîæíûõ SQL-çàïðîñîâ âûãëÿäèò òàê:
Äëÿ êàæäîé ãðóïïû íóæíî
îïðåäåëèòü èìÿ (äëÿ âûâîäà íà ôîðìå), êîä ãðóïïû, êîä ïðåäêà ãðóïïû è ÷èñëî
òîâàðîâ, ëåæàùèõ â äàííîé ãðóïïå. ×èñëî òîâàðîâ â ãðóïïå íóæíî äëÿ òîãî, ÷òîáû
îïðåäåëèòü, ïóñòàÿ ãðóïïà .èëè íå ïóñòàÿ. Äëÿ ãðóïï, ñîäåðæàùèõ õîòü îäèí
òîâàð, íà ôîðìå âûâîäèòñÿ êàðòèíêà ðÿäîì ñ íàçâàíèåì ãðóïïû. Äëÿ ïóñòûõ ãðóïï
òàêîé êàðòèíêè íå âûâîäèòñÿ. Ïåðâîíà÷àëüíî çàïîëíåíèå äåðåâà ïðîèçâîäèëîñü
ñëåäóþùèì îáðàçîì: âûïîëíÿëñÿ çàïðîñ select * from paths.
Çàòåì äëÿ êàæäîé èç ãðóïï âûïîëíÿëñÿ çàïðîñ ñ öåëüþ âûÿñíåíèÿ, ïóñòàÿ îíà èëè
íåò: select count(*) from goods where code_ancestor=:code_path. Òàêèì îáðàçîì, âûïîëíÿëîñü
ñòîëüêî çàïðîñîâ, ñêîëüêî ãðóïï â äåðåâå. Íî óæå ïðè ñòà ãðóïïàõ ïðîãðàììà
ñòàëà «òîðìîçèòü». Ïîýòîìó áûëî ïðèíÿòî ðåøåíèå ïðèäóìàòü îäèí ñëîæíûé çàïðîñ
äëÿ ñåðâåðà, ïîëó÷åííûå äàííûå îáðàáàòûâàòü óæå íà êëèåíòå ñ ïîìîùüþ ñðåäñòâ
ÿçûêà Delphi. Çàïîëíåíèå äåðåâà ãðóïï
ïðîèçâîäèòñÿ ñëåäóþùèì îáðàçîì:
Îáúÿâëÿåì íåîáõîäèìûå òèïû
äëÿ çàêà÷êè äàííûõ ñ ñåðâåðà íà êëèåíò:
const
step=50;
type
tMassiv=record
code_path:
integer;
code_ancestor: integer;
chislo:
integer;
name_path: string;
end;
var
massiv: array of tMassiv;
LengthMassiv: integer; RealLengthMassiv: integer;
Èòàê, òèï äàííûõ tMassiv õðàíèò òî, ÷òî âûäàåò òîò
ñàìûé ñëîæíûé çàïðîñ (êîä ãðóïïû, êîä ïðåäêà, ÷èñëî òîâàðîâ â ãðóïïå è íàçâàíèå
ãðóïïû). Ìàññèâ îáúÿâëåí ïåðåìåííîãî ðàçìåðà, òàê êàê íåèçâåñòíî, êàêîå
êîëè÷åñòâî çàïèñåé âûäàñò ñåðâåð. step
– øàã óâåëè÷åíèÿ ðàçìåðà ìàññèâà ïîñëå äîáàâëåíèÿ â íåãî ýëåìåíòîâ. Ýòî íóæíî,
÷òîáû ïðè êàæäîì äîáàâëåíèè äàííûõ íå óâåëè÷èâàòü ðàçìåð ìàññèâà íà åäèíèöó
(÷òî îòíèìàåò âðåìÿ). LengthMassiv – ýòî ëîãè÷åñêàÿ äëèíà ìàññèâà (ñêîëüêî ýëåìåíòîâ â íåãî çàêà÷àíî). RealLengthMassiv – ôèçè÷åñêàÿ äëèíà ìàññèâà
(ñêîëüêî ýëåìåíòîâ â íåãî ìîæåò áûòü çàêà÷àíî). Èìåííî ýòî çíà÷åíèå
óâåëè÷èâàåòñÿ øàãàìè, èìåþùèìè ðàçìåð step. Âîò ïðîöåäóðà äëÿ çàïîëíåíèÿ äàííîãî ìàññèâà:
procedure FillingMassiv;
begin
with Form2 do begin
TR_SelectPaths.Active:=false; TR_SelectPaths.Active:=true;
Q_SelectPaths.Close; Q_SelectPaths.Open;
LengthMassiv:=0;
SetLength(massiv,
step);
RealLengthMassiv:=step;
Q_SelectPaths.First;
while not Q_SelectPaths.Eof do begin
if LengthMassiv=RealLengthMassiv then begin
inc(RealLengthMassiv, step);
SetLength(massiv, RealLengthMassiv);
end;
massiv[LengthMassiv].code_path:=
Q_SelectPaths.FieldValues['code_path'];
massiv[LengthMassiv].code_ancestor :=
Q_SelectPaths.FieldValues['code_ancestor'];
massiv[LengthMassiv].name_path :=
Q_SelectPaths.FieldValues['name_path'];
massiv[LengthMassiv].chislo:=Q_SelectPaths.FieldValues['chislo'];
inc(LengthMassiv);
Q_SelectPaths.Next;
end;
end;
end;
Q_SelectPaths – ýòî òîò ñàìûé ñëîæíûé
çàïðîñ. Èòàê, ìàññèâ çàïîëíåí. Òåïåðü íóæíî çàïîëíèòü äåðåâî. Çàïîëíåíèå äåðåâà
ïðîèçâîäèòñÿ ðåêóðñèâíî ñ ïîìîùüþ ñòàíäàðòíîé ïðîöåäóðû äîáàâëåíèÿ ýëåìåíòà â
äåðåâî AddChildObject. Âûáîð ïîòîìêîâ äëÿ êàæäîé
ãðóïïû ïðîèçâîäèòñÿ ïîëíûì ïåðåáîðîì. Ýòî, êîíå÷íî, íåîïòèìàëüíî, íî ïðè 2000
ãðóïï ñêîðîñòü âïîëíå ïðèåìëåìà, à áîëüøå âðÿä ëè ïîíàäîáèòñÿ (ðåàëüíî â
ìàãàçèíå èñïîëüçóåòñÿ ãäå-òî 200 ãðóïï). Ïðè íåîáõîäèìîñòè ýòîò ïðîöåññ ìîæíî
çíà÷èòåëüíî óñêîðèòü, åñëè èñïîëüçîâàòü âìåñòî ìàññèâà, íàïðèìåð, äåðåâî. Âîò ïðîöåäóðà äëÿ çàïîëíåíèÿ äåðåâà:
procedure FillingTree;
var
i: integer;
procedure Add0(where:
TTreeNode; what: integer);
//êóäà_äîáàâëÿåì
è ÷òî_äîáàâëÿåì -- ïàðàìåòðû ïðîöåäóðû
var
code_path:
integer;
name_path: string;
p: TTreeNode;
i, j:
integer;
ExistSubPaths: boolean;
begin
with Form2 do begin
for i:=0 to LengthMassiv-1 do begin
if massiv[i].code_ancestor=what
then begin
//Äîñòàåì
èç ìàññèâà êîä ïàïêè è íàçâàíèå ïàïêè
code_path:=massiv[i].code_path;
name_path:=massiv[i].name_path;
//Äîáàâëÿåì äàííûé ýëåìåíò â äåðåâî
p:=TreeView1.Items.AddChildObject
(where, name_path, pointer(code_path));
//Îïðåäåëÿåì,
êàêèå ïàïêè íåïóñòûå è äåëàåì ðèñóíêè
if massiv[i].chislo=0 then p.StateIndex:=0
else p.StateIndex:=1;
ExistSubPaths:=false;
for j:=0 to LengthMassiv-1 do begin
if
massiv[j].code_ancestor=code_path then
ExistSubPaths:=true;
end;
if ExistSubPaths then Add0(p, code_path);
end;
end;
end;
end;
begin
FormActivate0;
with Form2 do begin
//ñîçäàåì êîðåíü äåðåâà
TreeView1.Items.Clear;
TreeView1.StateImages:=ImageList1;
TreeView1.Items.Add(nil, 'Ñòðóêòóðà òîâàðîâ ìàãàçèíà
"Èäåàë"');
//çàïîëíÿåì
äèíàìè÷åñêèé ìàññèâ ýëåìåíòàìè
FillingMassiv;
//òåïåðü çàïîëíÿåì äåðåâî
Add0(Form2.TreeView1.Items.Item[0], 0);
TreeView1.Items.Item[0].Expanded:=true;
end;
FilledTree:=true;
end;
 ïðîãðàììå (ðàçäåë
ñòàòèñòèêè ðàáîòû ìàãàçèíà) åñòü îäèí èíòåðåñíûé ãðàôèê – çàâèñèìîñòü ïðîöåíòà
ïðèáûëè îò ïðîöåíòà ïîêóïàòåëåé, ïðèâåäåííûé íà ðèñóíêå 3.25.
|
Ðèñóíîê 3.25 |
Èç äàííîãî ãðàôèêà âèäíî,
÷òî 20% ïîêóïàòåëåé ïðèíîñÿò 70% ïðèáûëè. 10% ïîêóïàòåëåé ïðèíîñÿò 55% ïðèáûëè.
Çàêîí 20-80 ïî÷òè ðàáîòàåò!
 ïðîãðàììå òàêæå
èñïîëüçîâàëèñü ðàçëè÷íûå àëãîðèòìû. Âîò, ê ïðèìåðó, ïðîöåäóðà, êîòîðàÿ óäàëÿåò
ó íàòóðàëüíîãî ÷èñëà ëèøíèå âïåðåäèñòîÿùèå íóëè:
procedure
DeleteFrontZeros(var s: string);
{óäàëÿåò
âïåðåäèñòîÿùèå íóëè ó íàòóðàëüíîãî ÷èñëà}
var
i:
integer; {ïîçèöèÿ ïîñëåäíåãî íåíóæíîãî íóëÿ}
begin
September.DoStringOnlyDigits(s);
i:=0;
while (i+1<=length(s)) and (s[i+1]='0') do inc(i);
delete(s, 1,
i);
if s='' then s:='0';
end;
Ýòà ïðîöåäóðà î÷åíü ÷àñòî
èñïîëüçîâàëàñü â ïðîãðàììå äëÿ êîððåêöèè ââåäåííûõ ïîëüçîâàòåëåì öåëûõ ÷èñåë.
Îáû÷íî âûçîâ äàííîé ïðîöåäóðû ïðèâÿçûâàëñÿ ê ñîáûòèþ OnExit ïîëÿ ââîäà.
Ýòà ïðîöåäóðà èñïîëüçóåò
ïðîöåäóðó DoStringOnlyDigits. Åå öåëü ñîñòîèò â òîì,
÷òîáû óáðàòü èç ñòðîêè âñå ñèìâîëû, íå ÿâëÿþùèåñÿ öèôðàìè. Äàííàÿ ïðîöåäóðà
î÷åíü ÷àñòî èñïîëüçîâàëàñü îòäåëüíî – äëÿ ðàçðåøåíèÿ ââîäà ïîëüçîâàòåëþ òîëüêî
öèôð. Åå âûçîâ ïðèâÿçûâàëñÿ ê ñîáûòèþ OnChange. Òåêñò ïðîöåäóðû òðèâèàëåí, ïîýòîìó ïðèâîäèòü åãî
íå áóäåì.
 ïðîãðàììå â íåñêîëüêèõ
ìåñòàõ èñïîëüçîâàëñÿ ðó÷íîé ââîä ÷èñëà, ìåñÿöà è ãîäà. Ïîëüçîâàòåëü ìîã íåâåðíî
ââåñòè ýòè äàííûå. Äëÿ òîãî, ÷òîáû íå ïèñàòü âî âñåõ íåîáõîäèìûõ ìåñòàõ
ïðîãðàììû êîä äëÿ ïðîâåðêè ïðàâèëüíîñòè ââîäà äàòû, áûëà ñîçäàíà ôóíêöèÿ,
ïðîâåðÿþùàÿ ïðàâèëüíîñòü ââîäà äàòû. Âîò åå èíòåðôåéñ:
function
IsCorrectDate(day, month, year: integer): boolean;
Òåêñò
ïðîöåäóðû òðèâèàëåí, ïîýòîìó íåò íåîáõîäèìîñòè åãî ïðèâîäèòü.
 íåêîòîðûõ ìåñòàõ ïðîãðàììû
áûëà íåîáõîäèìîñòü âûâåñòè ñïèñîê òîâàðîâ çà ïîñëåäíèå n äíåé, ãäå ÷èñëî n çàäàåòñÿ ïîëüçîâàòåëåì. Äëÿ
òîãî, ÷òîáû ïîñ÷èòàòü äàòó íà÷àëà ïåðèîäà, ïîíàäîáèëàñü ôóíêöèÿ, âîçâðàùàþùàÿ
àáñîëþòíûé íîìåð äíÿ ïî ÷èñëó, ìåñÿöó è ãîäó, à òàêæå îáðàòíàÿ ôóíêöèÿ. Çà
òî÷êó îòñ÷åòà áûëî ðåøåíî ïðèíÿòü 1 ÿíâàðÿ 1901 ãîäà. Íîìåð ýòîãî äíÿ 1. Îò
íåãî è èäåò îòñ÷åò. Âîò ôóíêöèÿ, êîòîðàÿ âû÷èñëÿåò íîìåð äíÿ, íà÷èíàÿ ñ 1
ÿíâàðÿ 1901 ãîäà ïî ÷èñëó, ìåñÿöó è ãîäó :
function GetNumberOfDate(day,
month, year: integer): integer;
{âîçâðàùàåò
íîìåð äíÿ íà÷èíàÿ ñ 01.01.1901 (åãî íîìåð 1)}
var
years: integer;
{ñêîëüêî ïîëíûõ ëåò ïðîøëî}
HighYears: integer; {ñêîëüêî
ïîëíûõ âèñîêîñíûõ ëåò ïðîøëî}
days: integer;
{ñêîëüêî äíåé ñ íà÷àëà ãîäà ïðîøëî}
begin
if not
September.IsCorrectDate(day, month, year) then
September.Error('September.GetNumberfDate: äàòà
íåêîððåêòíà');
{íà÷èíàåì âñå ñ 1 ÿíâàðÿ
1901 ãîäà -- 1-é äåíü}
years:=year-1901;
HighYears:=years div 4;
days:=0;
if month>=2 then inc(days, 31);
if month>=3 then begin
if year mod 4=0 then inc(days, 29)
else inc(days, 28);
end;
if month>=4 then inc(days, 31);
if month>=5 then inc(days, 30);
if month>=6 then inc(days, 31);
if month>=7 then inc(days, 30);
if month>=8 then inc(days, 31);
if month>=9 then inc(days, 31);
if month>=10 then inc(days, 30);
if month>=11 then inc(days, 31);
if month>=12 then inc(days, 30);
days:=days+day;
GetNumberOfDate:=365*years+HighYears+days;
end;
Âðÿä ëè ïðîãðàììà áóäåò
èñïîëüçîâàòüñÿ áîëåå 93 ëåò, ïîýòîìó òî, ÷òî 2100-é ãîä íå âèñîêîñíûé ìîæíî íå
ó÷èòûâàòü. Âîò èíòåðôåéñ îáðàòíîé ïðîöåäóðû, êîòîðàÿ ïî íîìåðó äíÿ îïðåäåëÿåò
äàòó:
procedure
GetDateOfNumber(num_day: integer; var day, month, year: integer);
Òåêñò äàííîé ïðîöåäóðû
ïðèâåäåí â Ïðèëîæåíèè.
 ïðîãðàììå ïðèìåíÿëèñü
çíàíèÿ êóðñà «ßçûêè ïðîãðàììèðîâàíèÿ è ìåòîäû òðàíñëÿöèè». Íàïðèìåð, â
ïðîöåäóðå, êîòîðàÿ ðàñïîçíàåò ñòðîêó ñ çàïèñüþ äàòû (ïðåîáðàçóåò òåêñòîâóþ
çàïèñü äàòû â íàáîð èç ïÿòè ïåðåìåííûõ: ÷èñëî, ìåñÿö, ãîä, ÷àñû è ìèíóòû):
procedure StringToDate
(s: string;
var day, month, year, hour, minute: integer);
const
EOT=#9;
var
ch: char; {òåêóùèé ñèìâîë ñòðîêè}
i: integer; {íîìåð
òåêóùåãî ñèìâîëà}
res: string;
procedure ResetText;
begin
s:=s+EOT;
i:=1;
ch:=s[1];
end;
procedure NextCh;
begin
inc(i);
ch:=s[i];
end;
procedure error(mess: string);
begin
September.Error('September.StringToDate: '+mess+' (s='+s+')');
end;
procedure procWord(var
Ident: string);
begin
if ch in RussianLetters then begin
Ident:=ch;
NextCh;
end
else error('Îæèäàåòñÿ ðóññêàÿ áóêâà');
while ch in RussianLetters do begin
Ident:=Ident+ch;
NextCh;
end;
end;
procedure RecognizeDate;
var
i: integer;
name_month: string;
begin
name_month:='';
//ðàñïîçíàåì ÷èñëî
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if ch in ['0'..'9'] then
begin
day :=
ord(ch) - ord('0');
NextCh;
end
else error('×èñëî ìåñÿöà
äîëæíî íà÷èíàòüñÿ ñ öèôðû!');
while ch in ['0'..'9'] do begin
day :=
10*day + (ord(ch)-ord('0'));
NextCh;
if day>31 then error('×èñëî ìåñÿöà
íå ìîæåò áûòü áîëüøå 31!');
end;
//ðàñïîçíàåì ìåñÿö
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if ch='.' then begin
NextCh;
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
if ch in ['0'..'9'] then begin
month
:= ord(ch) - ord('0');
NextCh;
while ch in ['0'..'9'] do begin
month := 10*month + (ord(ch)-ord('0'));
NextCh;
if month>12 then error('Íîìåð ìåñÿöà
íå ìîæåò áûòü áîëüøå 12!');
end;
end;
end
else if ch in RussianLetters then begin
procWord(name_month);
September.StringToLowRegister(name_month);
month:=0;
for i:=1 to 12 do begin
if (name_month=months[i]) or (name_month=months2[i]) then month:=i;
end;
if month=0 then error('íåêîððåêòíàÿ
çàïèñü íîìåðà ìåñÿöà');
end
else
error('îæèäàåòñÿ òî÷êà â êà÷åñòâå ðàçäåëèòåëÿ ìåæäó ÷èñëîì '+
'è íîìåðîì
ìåñÿöà èëè íàçâàíèå ìåñÿöà ðóññêèìè áóêâàìè!');
//ðàñïîçíàåì ãîä
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if
length(name_month)=0 then begin
if ch='.'
then NextCh
else error('îæèäàåòñÿ
"."');
end;
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if ch in ['1'..'2']
then begin
year :=
ord(ch) - ord('0');
NextCh;
end
else error('îæèäàåòñÿ öèôðà "1" èëè "2"');
while ch in ['0'..'9']
do begin
year :=
10*year + (ord(ch)-ord('0'));
NextCh;
if year>2100 then error('Íîìåð ãîäà
íå ìîæåò áûòü áîëüøå 2100');
end;
if year<1900 then error('Íîìåð ãîäà
íå ìîæåò áûòü ìåíüøå 1900');
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if ch in ['ã','Ã']
then begin
NextCh;
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
if ch='.'
then NextCh;
end;
//ðàñïîçíàåì ÷àñû
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
if ch in ['0'..'9']
then begin
hour :=
ord(ch) - ord('0');
NextCh;
end
else error('îæèäàåòñÿ öèôðà â ÷àñå');
while ch in ['0'..'9']
do begin
hour := 10*hour
+ (ord(ch)-ord('0'));
NextCh;
end;
//ðàñïîçíàåì ìèíóòû
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
if ch=':'
then NextCh
else error('îæèäàåòñÿ äâîåòî÷èå');
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
if ch in ['0'..'9']
then begin
minute :=
ord(ch) - ord('0');
NextCh;
end
else error('îæèäàåòñÿ öèôðà â ìèíóòå');
while ch in ['0'..'9']
do begin
minute :=
10*minute + (ord(ch)-ord('0'));
NextCh;
end;
while ch=' ' do
NextCh; //ïðîïóñêàåì ïðîáåëû
if ch=':'
then NextCh;
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
while ch in ['0'..'9']
do NextCh;
while ch=' '
do NextCh; //ïðîïóñêàåì
ïðîáåëû
end;
begin
ResetText;
RecognizeDate;
if ch<>EOT then error('îæèäàåòñÿ êîíåö òåêñòà');
if not
September.IsCorrectDate(day, month, year) then
September.Error
('September.StringToDate: äàòà ÿâëÿåòñÿ íåêîððåêòíîé: '+s);
end;
Ïðè ðàçðàáîòêå ïðîãðàììû
÷àñòî âîçíèêàëà íåîáõîäèìîñòü ïðîâåðèòü, ÿâëÿåòñÿ ëè ñòðîêà êîððåêòíûì âåùåñòâåííûì
÷èñëîì (áåç ñèìâîëîâ e, E). Äëÿ ýòèõ öåëåé áûëà
íàïèñàíà ñïåöèàëüíàÿ ôóíêöèÿ. Âîò åå èíòåðôåéñ:
function
IsCorrectFloatString(s: string):
boolean;
Ïðè íàïèñàíèè ôóíêöèè
èñïîëüçîâàëèñü òðèâèàëüíûå çíàíèÿ êóðñà «ßçûêè ïðîãðàììèðîâàíèÿ è ìåòîäû òðàíñëÿöèè».
Åå òåêñò ïðèâåäåí â Ïðèëîæåíèè.
 ïðîãðàììå ïðè îòîáðàæåíèè
äåíåæíûõ ñóìì (îñîáåííî, áîëüøèõ) íóæíà íàãëÿäíîñòü. Òî åñòü, ÷èñëî íå äîëæíî
âûâîäèòüñÿ â ñòàíäàðòíîé ôîðìå (áåç ïðîáåëîâ, ñ òî÷êîé äëÿ ðàçäåëåíèÿ ðóáëåé è
êîïååê). Áûëî ïðèíÿòî ðåøåíèå ðàçäåëÿòü ðóáëè è êîïåéêè çàïÿòîé, à ðàçðÿäû
÷èñëà – ïðîáåëîì. Íàïðèìåð, ÷èñëî 19888283.25 áóäåò çàïèñàíî êàê «19 188
283,25». Ïðèâåäåííàÿ íèæå ïðîöåäóðà ïðåîáðàçóåò ÷èñëà, ïî ìîäóëþ íå áîëüøèå
òðèëëèîíà òðèëëèîíîâ, â ñòðîêó (ñ òî÷íîñòüþ äî 15 ðàçðÿäîâ, áîëüøå òèï double íå äàåò):
procedure
FloatToMoneyString(x: float; var s: string);
const
exact=24; {÷èñëî
ìîæåò áûòü äî 1e24}
var
minus: boolean; {ÿâëÿåòñÿ
ëè ÷èñëî îòðèöàòåëüíûì}
{ðàçðÿäû ÷èñëà
(ïåðâûé -- êîïåéêè è ò. ä.)}
digits: array [1..26] of integer;
LastDigit:
float; {ïîñëåäíÿÿ öèôðà ÷èñëà}
digit: integer; {ïîñëåäíÿÿ öèôðà ÷èñëà (îêðóãëåííàÿ)}
LengthNumber: integer; {äëèíà ÷èñëà (ó÷èòûâàÿ êîïåéêè)}
NumberTriads: integer; {÷èñëî òðèàä â ÷èñëå}
ostatok: integer; {ñêîëüêî
öèôð îñòàëîñü çàïèñàòü}
i: integer;
begin
if x>=0.0 then minus:=false
else begin minus:=true; x:=-x; end;
if x>1.0e24 then September.Error
('September.FloatToMoneyString: Ñëèøêîì áîëüøîå ÷èñëî!');
x:=100.0*x+0.5; {÷èñëî
êîïååê, îêðóãëåííîå äî êîïåéêè}
{ïðåîáðàçóåì ÷èñëî â ìàññèâ öèôð}
LengthNumber:=0; {îáùàÿ
äëèíà ÷èñëà (ñ êîïåéêàìè)}
for i:=1 to 26 do begin
LastDigit
:= 10.0*frac(x/10.0);
digit :=
trunc(LastDigit);
digits[i]
:= digit;
if digit<>0 then LengthNumber:=i;
x := (x - LastDigit)/10.0 + 0.1;
end;
{óáèðàåì âñå öèôðû,
êðîìå 15 çíà÷àùèõ öèôð}
for
i:=LengthNumber-15 downto 1 do digits[i]:=0;
{ïðåîáðàçóåì ìàññèâ öèôð â
äåíåæíîå ÷èñëî}
if LengthNumber=0
then s:='0,00'
else if LengthNumber=1 then s:='0,0'+inttostr(digits[1])
else if LengthNumber=2 then
s:='0,'+inttostr(digits[2])+inttostr(digits[1])
else begin
s:=','+inttostr(digits[2])+inttostr(digits[1]);
NumberTriads := (LengthNumber-3) div 3;
{òðèàäû íóæíû
äëÿ ïðàâèëüíîé ðàññòàíîâêè ïðîáåëîâ â ÷èñëå}
for i:=1 to
NumberTriads do begin
s:=inttostr(digits[3*i+2])+inttostr(digits[3*i+1])+
inttostr(digits[3*i])+s;
s:=' '+s;
end;
ostatok :=
(LengthNumber-2)-3*NumberTriads;
for i:=ostatok downto 1 do
s:=inttostr(digits[LengthNumber-i+1])+s;
end;
if minus then s:='-'+s;
end;
Äëÿ òîãî, ÷òîáû êîððåêòíî
âûâîäèòü â ïðîãðàììå äàííûå òèïà «2 ðóáëÿ», «5 ðóáëåé», íóæíî îïðåäåëèòü òèï
÷èñëà. Åñëè òèï ÷èñëà 1, òî îêîí÷àíèå áóäåò «ðóáëü». Åñëè òèï ÷èñëà 2, òî
îêîí÷àíèå áóäåò «ðóáëÿ». Èíà÷å îêîí÷àíèå áóäåò «ðóáëåé». Íèæå ïðèâåäåíà
ïðîöåäóðà äëÿ îïðåäåëåíèÿ òèïà íàòóðàëüíîãî ÷èñëà:
function
TypeOfNumber(x: integer): integer;
{1-ãîä 2-ãîäà 3-ëåò}
var
tip: integer;
begin
tip:=3;
if x div 10<>1 then begin
case x mod 10 of
1:
tip:=1;
2,3,4:
tip:=2;
end;
end;
TypeOfNumber:=tip;
end;
 ïðîãðàììå âñòðå÷àþòñÿ
ìåñòà, ãäå íóæíî ñëîâàìè íàïèñàòü äåíåæíóþ ñóììó (íàïðèìåð, â òîâàðíîì ÷åêå).
Äëÿ ýòîãî áûëà íàïèñàíà
ñïåöèàëüíàÿ ôóíêöèÿ. Äëÿ íàïèñàíèÿ äàííîé ôóíêöèè ïîòðåáîâàëîñü íàïèñàòü
íåñêîëüêî äîïîëíèòåëüíûõ ôóíêöèé.
Ôóíêöèÿ, ïðèâåäåííàÿ íèæå,
âûäàåò òåêñòîâóþ çàïèñü íàòóðàëüíîãî ÷èñëà îò 0 äî 99. Âõîäíûìè ïàðàìåòðàìè
ôóíêöèè ÿâëÿþòñÿ äàííîå ÷èñëî è òèï ðåçóëüòàòà. Åñëè tip=1, òî ïðîöåäóðà âûäàñò
ðåçóëüòàò â âèäå «äâàäöàòü äâà», èíà÷å â âèäå «äâàäöàòü äâå»:
function
NaturalNumberUp99ToString(x, tip: integer): string;
var
digits: array[0..9] of string;
var
s: string; {ñòðîêà
ðåçóëüòàòà}
tens, units: integer; {äåñÿòêè è åäèíèöû}
begin
if not ((x>=0) and (x<=99)) then
September.Error
('September.NaturalNumberUp99ToString: x must between 0 and
99');
if tip=1 then begin
digits[0]:='íîëü'; digits[1]:='îäèí';
digits[2]:='äâà'; digits[3]:='òðè';
digits[4]:='÷åòûðå'; digits[5]:='ïÿòü';
digits[6]:='øåñòü'; digits[7]:='ñåìü';
digits[8]:='âîñåìü'; digits[9]:='äåâÿòü';
end
else if tip=2 then begin
digits[0]:='íîëü';
digits[1]:='îäíà';
digits[2]:='äâå'; digits[3]:='òðè';
digits[4]:='÷åòûðå'; digits[5]:='ïÿòü';
digits[6]:='øåñòü'; digits[7]:='ñåìü';
digits[8]:='âîñåìü'; digits[9]:='äåâÿòü';
end;
tens:=x div 10;
units:=x mod 10;
if tens=0 then begin
s:=digits[units];
end
else if tens=1 then begin
case units of
0: s:='äåñÿòü';
1: s:='îäèííàäöàòü';
2: s:='äâåíàäöàòü';
3: s:='òðèíàäöàòü';
4: s:='÷åòûðíàäöàòü';
5: s:='ïÿòíàäöàòü';
6: s:='øåñòíàäöàòü';
7: s:='ñåìíàäöàòü';
8: s:='âîñåìíàäöàòü';
9: s:='äåâÿòíàäöàòü';
end;
end
else begin
case tens of
2: s:='äâàäöàòü';
3: s:='òðèäöàòü';
4: s:='ñîðîê';
5: s:='ïÿòüäåñÿò';
6: s:='øåñòüäåñÿò';
7: s:='ñåìüäåñÿò';
8: s:='âîñåìüäåñÿò';
9: s:='äåâÿíîñòî';
end;
if units<>0
then s:=s+' '+digits[units];
end;
NaturalNumberUp99ToString:=s;
end;
Ôóíêöèÿ äëÿ ïðåîáðàçîâàíèÿ
÷èñëà îò 0 äî 999 â òåêñòîâóþ çàïèñü âûãëÿäèò àíàëîãè÷íî, âîò åå èíòåðôåéñ:
function
NaturalNumberUp999ToString(x, tip: integer): string;
Òåêñò
äàííîé ôóíêöèè ïðèâåäåí â Ïðèëîæåíèè. Ñ ïîìîùüþ äâóõ âûøåïðèâåäåííûõ ôóíêöèé
áûëà íàïèñàíà ôóíêöèÿ äëÿ òåêñòîâîé çàïèñè äåíåæíûõ ñóìì, ïî ìîäóëþ íå
ïðåâûøàþùèõ 999 êâàäðèëëèîíîâ (ïðèìåðíî ). Âîò åå èíòåðôåéñ:
function
FloatToLettersMoneyString(x: float): string;
Åå
êîä íå î÷åíü ñëîæíûé, íî äîâîëüíî îáúåìíûé, ïîýòîìó áûëî ïðèíÿòî ðåøåíèå òàêæå
âûíåñòè åãî â Ïðèëîæåíèå.
Ïðè ðàçðàáîòêå ïðîãðàììû
òàêæå ïðèìåíÿëèñü çíàíèÿ èç êóðñà «Êîìïüþòåðíàÿ ãðàôèêà». Ïðè íàïèñàíèè
ïðîãðàììû âîçíèêëà íåîáõîäèìîñòü îòîáðàæàòü ãðàôèêè (ïîäîáíî Microsoft Excel). Áûëî ïðèíÿòî ðåøåíèå
ðàçðàáîòàòü ñîáñòâåííûé êîìïîíåíò. Äëÿ ðèñîâàíèÿ ãðàôèêîâ íóæíû ýëåìåíòàðíûå
ïðîöåäóðû (ðèñîâàíèå òî÷åê, ëèíèé, î÷èñòêà ýêðàíà, âûâîä òåêñòà, è ò. ä.). Áûëî
ïðèíÿòî ðåøåíèå ðàçìåñòèòü èõ â îòäåëüíîì ìîäóëå BGL.
Âîò îñíîâíûå ïàðàìåòðû
ìîäóëÿ BGL:
const
SizeX=1024; SizeY=768; {ðàçìåð ýêðàíà}
getmaxx=SizeX-1; getmaxy=SizeY-1;
type
tBuf=array [0..getmaxy, 0..getmaxx] of integer;
cc, bc: integer; {îñíîâíîé
öâåò è öâåò ôîíà}
var
Buf: tBuf; {áóôåð, ãäå ñòðîèòñÿ èçîáðàæåíèå}
Ðèñîâàíèå ïðîèçâîäèòñÿ â
áóôåðå, èç êîòîðîãî ñ ïîìîùüþ íåñëîæíûõ ïðîöåäóð çàòåì ìîæíî áóäåò ñêîïèðîâàòü
ïîñòðîåííîå èçîáðàæåíèå êóäà íóæíî. SizeX, SizeY – ðàçìåðû îáëàñòè âûâîäà. getmaxx è getmaxy – ìàêñèìàëüíûå êîîðäèíàòû
ïî îñÿì x è y ñîîòâåòñòâåííî. Buf – áóôåð, â êîòîðîì ñòðîèòñÿ
èçîáðàæåíèå. cc – îñíîâíîé öâåò
(èñïîëüçóåòñÿ äëÿ ðèñîâàíèÿ òî÷åê, ëèíèé, îêðóæíîñòåé è ò. ä.), à bc – öâåò ôîíà (èñïîëüçóåòñÿ
ïðîöåäóðîé ClearDevice, êîòîðàÿ î÷èùàåò ýêðàí).
Âîò ïðîöåäóðà äëÿ âûâîäà èçîáðàæåíèÿ (çäåñü èñïîëüçóåòñÿ àëãîðèòì Áðåçåíõåìà):
procedure DrawLine(x1, y1, x2, y2: integer);
var
dx, dy, d,
inc1, inc2, s: integer;
a, a2:
integer;
buf0: array [0..SizeX*SizeY-1] of integer absolute buf;
begin
dx:=abs(x2-x1); dy:=abs(y2-y1);
if dx>dy then begin
inc1:=2*dy; inc2:=2*(dy-dx);
d:=2*dy-dx;
if x1<x2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if y1<y2 then s:=SizeX+1
else s:=-SizeX+1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if y1>y2 then s:=SizeX+1
else s:=-SizeX+1;
end;
buf0[a]:=cc;
while a<>a2 do begin
if d>0 then begin
a:=a+s;
d:=d+inc2;
end
else begin
a:=a+1;
d:=d+inc1;
end;
buf0[a]:=cc;
end;
end {dx>dy}
else begin
inc1:=2*dx; inc2:=2*(dx-dy);
d:=2*dx-dy;
if y1<y2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if x1<x2 then s:=SizeX+1
else s:=SizeX-1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if x1>x2 then s:=SizeX+1
else s:=SizeX-1;
end;
buf0[a]:=cc;
while a<>a2 do begin
if d>0 then begin
a:=a+s;
d:=d+inc2;
end
else begin
a:=a+SizeX;
d:=d+inc1;
end;
buf0[a]:=cc;
end;
end;
end;
Òàê êàê ïðîöåäóðà äëÿ âûâîäà
ëèíèé èñïîëüçóåòñÿ äîâîëüíî ÷àñòî, áûëî ïðèíÿòî ðåøåíèå åå îïòèìèçèðîâàòü. Äëÿ
îïòèìèçàöèè ïðèìåíÿëñÿ ÿçûê àññåìáëåðà (ïðèìåíÿëèñü çíàíèÿ êóðñà «Àðõèòåêòóðà
ÝÂÌ è ÿçûê Àññåìáëåðà»). Îïòèìèçèðîâàëñÿ òîëüêî âíóòðåííèé öèêë, òàê êàê èìåííî
îí áîëüøå âñåãî âëèÿåò íà âðåìÿ âûïîëíåíèÿ ïðîöåäóðû.
Îïòèìèçèðîâàííàÿ ïðîöåäóðà
ðàáîòàåò çíà÷èòåëüíî áûñòðåå (â 23 ðàçà ïðè âûâîäå äëèííûõ ëèíèé). Òåêñò
ïðîöåäóðû äîâîëüíî äëèííûé, ïîýòîìó îí ïðèâåäåí â Ïðèëîæåíèè.
Ïðîöåäóðà DrawLine ðèñóåò, íå èñïîëüçóÿ
îòñå÷åíèå. Åñëè êîîðäèíàòû ëèíèè âûéäóò çà ïðåäåëû ýêðàíà, ïðîèçîéäåò îøèáêà è
ïðîãðàììà àâàðèéíî çàâåðøèò ðàáîòó. ×òîáû òàêîãî íå ïðîèñõîäèëî, èñïîëüçóåì
ïðîöåäóðó äëÿ îòñå÷åíèÿ ëèíèé (àëãîðèòì Èâàíà Ñàçåðëåíäà). õleft, ytop, xright, ybottom – îêíî, ïî êîòîðîìó
ïðîèçâîäèòñÿ îòñå÷åíèå. (xleft, ytop) –
ëåâûé âåðõíèé óãîë; (xright, ybottom) –
ïðàâûé íèæíèé óãîë. Âîò òåêñò ïðîöåäóðû:
procedure line(x1, y1,
x2, y2: longint);
type
tCode=set of 0..3;
procedure Coding(x, y:
integer; var code: tCode);
begin
code:=[];
if x<xleft then code:=code+[0]
else if x>xright then code:=code+[1];
if y<ytop then code:=code+[2]
else if y>ybottom then code:=code+[3];
end;
var
code1, code2:
tCode;
inside:
boolean;
x, y:
integer;
code: tCode;
reg1, reg2,
reg3, reg4: integer;
begin
x1:=x1+xleft;
x2:=x2+xleft;
y1:=y1+ytop;
y2:=y2+ytop;
Coding(x1,
y1, code1);
Coding(x2,
y2, code2);
inside:=code1+code2=[];
while not inside and (code1*code2=[]) do
begin
if code1=[] then begin
reg1:=x1; reg3:=y1;
reg2:=x2; reg4:=y2;
x1:=reg2; y1:=reg4;
x2:=reg1; y2:=reg3;
code:=code1; code1:=code2; code2:=code;
end;
if x1<xleft then begin {îòñå÷åíèå ñëåâà}
y1:=y1+round((y2-y1)/(x2-x1)*(xleft-x1));
x1:=xleft;
end
else if
x1>xright then begin {îòñå÷åíèå ñïðàâà}
y1:=y1+round((y2-y1)/(x2-x1)*(xright-x1));
x1:=xright;
end
else if y1<ytop then begin {îòñå÷åíèå ñâåðõó}
x1:=x1+round((x2-x1)/(y2-y1)*(ytop-y1));
y1:=ytop;
end
else if y1>ybottom then begin {îòñå÷åíèå ñíèçó}
x1:=x1+round((x2-x1)/(y2-y1)*(ybottom-y1));
y1:=ybottom;
end;
Coding(x1,
y1, code1);
inside:=(code1+code2)=[];
end;
if inside then DrawLine(x1, y1, x2, y2);
end;
Äàííàÿ ïðîöåäóðà ïîñëåäîâàòåëüíî
îòñåêàåò ó ëèíèè êðàÿ, âûõîäÿùèå ëåâûé, ïðàâûé, âåðõíèé è íèæíèé îãðàíè÷èòåëè,
çàòåì ðèñóåò îáðåçàííóþ ëèíèþ.
 ïðîãðàììå åñòü êîìïîíåíò
äëÿ âûâîäà ãðàôèêîâ. Ãðàôèê ñòðîèòñÿ â âèäå ëîìàíûõ ëèíèé (ðèñóíîê 3.26).
|
Ðèñóíîê
3.26 |
Íåïëîõî áûëî áû ïðîâåñòè
ñãëàæèâàíèå. Äëÿ ñãëàæèâàíèÿ ïðèìåíèì ñïëàéí-èíòåðïîëÿöèþ. Ìåòîä âûãëÿäèò òàê:
îòðåçîê ïî îñè àðãóìåíòà ôóíêöèè ðàçáèâàåòñÿ íà íåñêîëüêî ÷àñòåé. Äëÿ êàæäîé
÷àñòè ñòðîèòñÿ êóáè÷åñêîå óðàâíåíèå. Ïðè ýòîì ó èòîãîâîé ëèíèè óáèðàþòñÿ ðåçêèå
óãëû ëîìàíîé çà ñ÷åò ðàâåíñòâà ïðîèçâîäíûõ ñîñåäíèõ ñïëàéíîâ â îáùèõ òî÷êàõ.
Ïóñòü ó íàñ åñòü îòðåçîê. Ðàçîáúåì åãî íà ÷àñòåé .  äàííûõ òî÷êàõ ôóíêöèÿ (åå ìû è ñîáèðàåìñÿ
ñãëàæèâàòü) ïðèíèìàåò çíà÷åíèÿ . Äëÿ êàæäîãî èç îòðåçêîâ íóæíî
îïðåäåëèòü ôóíêöèþ, êîòîðàÿ îïðåäåëÿåòñÿ ÷åòûðüìÿ êîýôôèöèåíòàìè (êàê ìíîãî÷ëåí
òðåòüåé ñòåïåíè: . Òî åñòü íóæíî îïðåäåëèòü êîýôôèöèåíòîâ: (ýòè êîýôôèöèåíòû
îïðåäåëÿþò ôóíêöèè). Äëÿ ýòîãî íóæíî ñîñòàâèòü óðàâíåíèé:
1) Î÷åâèäíî, âñå ôóíêöèè
îòðåçêîâ íà ëåâîì êîíöå îòðåçêà äîëæíû ïðèíèìàòü çíà÷åíèÿ òàêèå æå, êàê
èòîãîâàÿ ôóíêöèÿ:
………………………………...
2) Î÷åâèäíî, âñå ôóíêöèè îòðåçêîâ íà ïðàâîì êîíöå
îòðåçêà äîëæíû ïðèíèìàòü çíà÷åíèÿ òàêèå æå, êàê èòîãîâàÿ ôóíêöèÿ:
………………………………...
Ïîñëå ïðèðàâíèâàíèÿ ôóíêöèé
â èõ ïðàâûõ è ëåâûõ òî÷êàõ ïîëó÷èëîñü óðàâíåíèé. Òàê êàê
èòîãîâàÿ ëèíèÿ äîëæíà áûòü ãëàäêîé, ïðîèçâîäíûå ôóíêöèé ñîñåäíèõ îòðåçêîâ â èõ
îáùèõ òî÷êàõ äîëæíû áûòü ðàâíû:
……………………………………………………………….
Òàê êàê íóæíî åùå óðàâíåíèé, ïðèðàâíÿåì
âòîðûå ïðîèçâîäíûå. Çàîäíî ýòî äîïîëíèòåëüíî óëó÷øèò ãëàäêîñòü ôóíêöèé:
………………………………………….
Ïîëó÷èëîñü óðàâíåíèé. Íóæíî åùå
äâà, ïîýòîìó ïðèðàâíÿåì ê íóëþ âòîðóþ ïðîèçâîäíóþ ïåðâîé ôóíêöèè â òî÷êå , à òàêæå âòîðóþ ïðîèçâîäíóþ -é ôóíêöèè â òî÷êå :
……………………..
Èòàê, ïîëó÷èëîñü óðàâíåíèé ïåðâîé
ñòåïåíè. Ïðîùå âñåãî òàêóþ ñèñòåìó ðåøèòü, «çàáèâ» êîýôôèöèåíòû â ìàòðèöó, à
çàòåì íàéòè ðåøåíèå ìåòîäîì Ãàóññà. Èìåííî òàê è ïîñòóïèì.
Íà ðèñóíêå 3.27 ïðèâåäåí òîò
æå ñàìûé ãðàôèê, íî óæå ñ ïðèìåíåíèåì ñãëàæèâàíèÿ.
|
Ðèñóíîê
3.27 |
Ïðàâäà, íà íåêîòîðûõ
ãðàôèêàõ ñãëàæèâàíèå ïðèìåíÿòü íåëüçÿ, òàê êàê ýòî çàòðóäíÿåò âîñïðèÿòèå
èñòèííûõ çíà÷åíèé. Ïîýòîìó â êîìïîíåíò âñòðîåíà âîçìîæíîñòü ðó÷íîãî
âêëþ÷åíèÿ/âûêëþ÷åíèÿ ñãëàæèâàíèÿ.
Êîíå÷íî, ñóùåñòâóþò áîëåå
îïòèìàëüíûå àëãîðèòìû äëÿ ïîñòðîåíèÿ ñïëàéíîâ, íî â äàííîé ïðîãðàììå ïðè ñîòíå
òî÷åê â ãðàôèêå ïðîáëåìà áûñòðîäåéñòâèÿ íå ñòîèò (ñãëàæèâàíèå ïðîèñõîäèò áåç
çàäåðæåê äàæå íà ñëàáûõ ìàøèíàõ (íàïðèìåð, Intel Celeron
400 Mhz, 64 Mb RAM)).
Òåêñò ïðîöåäóðû òðèâèàëåí,
ïîýòîìó ïðèâåäåí â Ïðèëîæåíèè. Â äàííîé ïðîöåäóðå èñïîëüçîâàëñÿ ìåòîä Ãàóññà.
Íèæå ïðèâåäåíû ñòðóêòóðû äàííûõ äëÿ ðåàëèçàöèè ìåòîäà Ãàóññà:
type
tMatrix=array [1..l0, 1..l0] of float;
tMatrix0=array [1..l0] of float;
Íèæåïðèâåäåííàÿ ïðîöåäóðà
ðåøàåò ñèñòåìó ëèíåéíûõ óðàâíåíèé ìåòîäîì Ãàóññà. Äëÿ èñïîëüçîâàíèÿ äàííîé
ïðîöåäóðû íåîáõîäèìî «çàáèòü» ìàòðèöó êîýôôèöèåíòîâ ïðè íåèçâåñòíûõ â ìàòðèöó M, è
ìàòðèöó ñâîáîäíûõ êîýôôèöèåíòîâ â ìàòðèöó M0. Ïðîöåäóðà âûäàñò ìàòðèöó
ðåøåíèé ñèñòåìû S.
procedure GaussSolve(M:
tMatrix; M0: tMatrix0; l: integer; var
S: tMatrix0);
procedure ExchangeFloat(var f1, f2: float);
var
buf: float;
begin
buf:=f1;
f1:=f2;
f2:=buf;
end;
var
ValueMaxModule: float;
StringMaxModule: integer;
i, j, CS{CurrentString}: integer;
know: integer;
begin
for CS:=1 to l-1 do begin
StringMaxModule:=CS;
ValueMaxModule:=M[CS, CS];
for j:=CS+1 to l do
if abs(M[j, CS])>ValueMaxModule then begin
ValueMaxModule:=abs(M[j, CS]);
StringMaxModule:=j;
end;
for i:=CS to l do ExchangeFloat(M[CS, i], M[StringMaxModule, i]);
ExchangeFloat(M0[CS], M0[StringMaxModule]);
M0[CS]:=M0[CS]/M[CS, CS];
for i:=l downto CS do M[CS, i]:=M[CS, i]/M[CS, CS];
for j:=CS+1 to l do begin
M0[j]:=M0[j]-M0[CS]*M[j, CS];
for i:=l downto CS do M[j, i]:=M[j, i]-M[CS, i]*M[j, CS];
end;
end;
for know:=l downto 1 do begin
S[know]:=M0[know]/M[know, know];
for i:=l downto know+1 do
S[know]:=S[know]-(M[know, i]/M[know, know])*S[i];
end;
end;
 ïðîãðàììå åñòü äåðåâî
ãðóïï äëÿ óäîáñòâà íàâèãàöèè ïî òîâàðàì. Èíîãäà òðåáóåòñÿ îïðåäåëèòü ïîëíîå èìÿ
ãðóïïû, èçâåñòåí êîä ãðóïïû. Ìîæíî, êîíå÷íî, ýòî ñäåëàòü ñ ïîìîùüþ íåñêîëüêèõ
âûçîâîâ çàïðîñà îïðåäåëåíèÿ èìåíè ïàïêè ïî êîäó, íî ãîðàçäî ýôôåêòèâíåå ñîçäàòü
äëÿ òîãî õðàíèìóþ ïðîöåäóðó íà ñåðâåðå. Íèæå ïðèâåäåíà äàííàÿ ïðîöåäóðà:
create
procedure procDoFullNamePathFromCodePath(code_path integer)
returns(name_path varchar(1000), error integer) as
declare variable vrem integer;
/*
error=1 -- this code_path is not exist
*/
begin
error=0;
if (code_path=0) then begin name_path=''; exit;
end
select count(*) from paths where
code_path=:code_path into vrem;
if (vrem=0) then begin error=1; exit;
end
execute
procedure procDoFullNamePathFromCodePath0(code_path, '')
returning_values(name_path);
end
Äàííàÿ ïðîöåäóðà ïðîâåðÿåò,
ñóùåñòâóåò ëè êîä óêàçàííîé ãðóïïû, è åñëè íå ñóùåñòâóåò, âûäàåò îøèáêó. Çàòåì
âûçûâàåòñÿ ðåêóðñèâíàÿ ïðîöåäóðà äëÿ îïðåäåëåíèÿ íàçâàíèÿ ãðóïïû ïî åå êîäó:
create
procedure procDoFullNamePathFRomCodePath0(
code_path integer,
name_path0 varchar(1000))
returns(name_path varchar(1000)) as
declare variable code_ancestor integer;
begin
select name_path from paths
where code_path=:code_path into :name_path;
if (name_path0<>'') then
name_path=name_path||'\'||name_path0;
select code_ancestor from paths
where code_path=:code_path
into :code_ancestor;
if (code_ancestor<>0) then begin
execute procedure
procDoFullNamePathFromCodePath0
(code_ancestor, name_path)
returning_values(name_path);
end
end
Èíîãäà òðåáóåòñÿ ïîëó÷èòü
ñëó÷àéíîå ÷èñëî íà ñåðâåðå. Ñåðâåð Firebird íå ñîäåðæèò ôóíêöèé íàïîäîáèå random, íî çàòî ïîääåðæèâàåò UDF – User Defined Functions.
Ñ ïîìîùüþ ýòîãî ñðåäñòâà ïðîãðàììèñò ìîæåò ñàì íàïèñàòü íóæíûå åìó ôóíêöèè,
êîòîðûå íå ÿâëÿþòñÿ ñòàíäàðòíûìè äëÿ ñåðâåðà Firebird. Ýòè ôóíêöèè äîëæíû áûòü ñêîïèðîâàíû íà ñåðâåð â
âèäå dll-áèáëèîòåê, êîòîðûå ìîæíî
íàïèñàòü íà áîëüøèíñòâå èç ñåðüåçíûõ ÿçûêîâ ïðîãðàììèðîâàíèÿ. Âîò òåêñò
áèáëèîòåêè äëÿ îïðåäåëåíèÿ ôóíêöèè random (íàïèñàí íà Delphi):
library libraryRandom;
uses
SysUtils;
var
pred:
longint;
function random(var x: integer): integer; cdecl; export;
const
a1=635786523;
a2=634789253;
b1=945362785;
b2=328498355;
var
next: int64;
reg1, reg2,
reg3, reg4: longint;
begin
next:=pred;
reg1:=0;
reg2:=0; reg3:=0; reg4:=0;
asm
push ebx; push eax; push ecx; push edx; push edi; push esi;
mov esi, dword ptr next; {esi=0}
mov edi, dword ptr next+4; {edi=0}
{edi:esi=next}
mov eax, a2; mul esi; mov
reg4, eax; mov reg3, edx; {reg4:reg3=0}
mov eax, a2; mul edi; add reg3, eax; adc reg2, edx; adc reg1, 0;
mov eax, a1; mul esi; add reg3, eax; adc reg2, edx; adc reg1, 0;
mov eax, a1; mul edi; add reg2, eax; adc reg1, edx; {reg1:reg2=0}
mov eax, reg1; mov ebx, reg2; mov ecx,
reg3; mov edx, reg4;
{eax:ebx:ecx:edx -- chislo}
add edx, b2; adc ecx, b1; and ecx,
1073741823;
mov dword ptr next+4, ecx;
mov dword ptr next, edx;
pop esi; pop edi; pop edx; pop ecx; pop eax; pop ebx;
end;
pred:=next;
Result:=next mod x;
end;
exports random;
begin
pred:=0;
end.
Äàííàÿ ôóíêöèÿ ãåíåðèðóåò
ïîñëåäîâàòåëüíîñòü ñëó÷àéíûé ÷èñåë ïî ñëåäóþùåìó àëãîðèòìó: , ãäå – ïîëîæèòåëüíîå ÷èñëî,
äåëÿùååñÿ íà 4 ñ îñòàòêîì 1, – íå÷åòíîå ÷èñëî, à – ñòåïåíü äâîéêè (2,
4, 8, 16, 32, 64,…).  êà÷åñòâå ïåðèîäà áûëà âçÿòà òðèäöàòàÿ ñòåïåíü äâîéêè
(îêîëî ìèëëèàðäà). ×òîáû ôóíêöèÿ çàðàáîòàëà, íåäîñòàòî÷íî ïðîñòî ñêîïèðîâàòü åå
íà ñåðâåð. Íóæíî åå åùå ïðîïèñàòü â áàçå:
declare
external function random integer
returns integer
by value
entry_point 'random' module_name 'libraryRandom.dll';
Äàííàÿ çàïèñü îçíà÷àåò
ñëåäóþùåå: îïðåäåëèòü ôóíêöèþ random
(ïîä òàêèì èìåíåì îíà áóäåò èìåòü ìåñòî íà ñåðâåðå), âîçâðàùàþùóþ öåëî÷èñëåííîå
çíà÷åíèå ïî çíà÷åíèþ (áûâàåò åùå ïî ññûëêå). module_name 'libraryRandom.dll' – èìÿ áèáëèîòåêè, îòêóäà
ýêñïîðòèðóåì ôóíêöèþ; entry_point 'random' – ýêñïîðòèðóåìàÿ ôóíêöèÿ.
 ñåðâåðíîé ÷àñòè ïðîãðàììû
òàêæå èñïîëüçóþòñÿ ôóíêöèè DateDays è DateSeconds (ðàáîòàþò ñ äàòîé è
âðåìåíåì). Îíè îïðåäåëÿþò, ñîîòâåòñòâåííî, ÷èñëî äíåé, ïðîøåäøèõ ñ 1 ÿíâàðÿ
1901 ãîäà (ýòîò äåíü èäåò ïîä íîìåðîì 1), è ÷èñëî ñåêóíä, ïðîøåäøèõ ñ íà÷àëà
ñóòîê. Òåêñò ïðîöåäóð òðèâèàëåí è ïðèâåäåí â Ïðèëîæåíèè.
Ïåðåä âíåäðåíèåì ïðîãðàììû, åñòåñòâåííî, ïðîâîäèëîñü òåñòèðîâàíèå. Ýòî
íóæíî äëÿ ïðåäîòâðàùåíèÿ ââîäà â áàçó îøèáî÷íûõ äàííûõ. Îñîáî ïðèñòàëüíîå
âíèìàíèå óäåëÿëîñü òåñòèðîâàíèþ õðàíèìûõ ïðîöåäóð, òàê êàê â îñíîâíîì îò íèõ
çàâèñèò íåïðîòèâîðå÷èâîñòü è ïðàâèëüíîñòü äàííûõ íà ñåðâåðå. Íî ïðàâèëüíîñòü
ðàáîòû êëèåíòñêîãî ïðèëîæåíèÿ òîæå òåñòèðîâàëàñü. Òåñòèðîâàíèå ïðîâîäèëîñü â
íåñêîëüêî ýòàïîâ:
Ïîñëå îêîí÷àíèÿ íàïèñàíèÿ ïðåäâàðèòåëüíîé âåðñèè ïðîãðàììû, ãîòîâîé ê
âíåäðåíèþ, áûëè èçâëå÷åíû èç áàçû è íàïå÷àòàíû òåêñòû âñåõ õðàíèìûõ ïðîöåäóð.
Ïåðâîî÷åðåäíîé öåëüþ áûëà ïðîâåðêà ïðàâèëüíîñòè ðàáîòû âñåõ õðàíèìûõ ïðîöåäóð
ïðè ðàçëè÷íûõ âõîäíûõ äàííûõ. Ñíà÷àëà ïðîâîäèëàñü âèçóàëüíàÿ ïðîâåðêà
ïðàâèëüíîñòè íàïèñàíèÿ ïðîöåäóðû, çàòåì òåñòèðîâàíèå ïóòåì âíåñåíèÿ â ïðîöåäóðó
ðàçëè÷íûõ äàííûõ, âûçûâàþùèõ èñêëþ÷èòåëüíûå ñèòóàöèè.
Âîò, ê ïðèìåðó, ïðîöåäóðà äëÿ äîáàâëåíèÿ òîâàðà â Ñïðàâî÷íèê Òîâàðîâ:
create
procedure procAddGood(
code_good integer, art varchar(20),
code_ancestor
integer,
name_good varchar(80),
code_unit integer)
returns(error integer, new_number_good integer) as
declare variable vrem integer;
declare variable scan_code varchar(20);
/*
error=1
-- this code_good already exists
error=2 -- articul must not be empty
error=3 -- incorrect code_ancestor (path not exists)
error=4 -- name_good must not be empty
error=5 -- this code_unit is not exist
error=6 -- good with this name_good already exists
error=7 -- code_good must not be less than 10000
error=8 -- the good cannot have more than 12 scan_codes
error=9 -- length(name_good) must not be less than 3
*/
begin
error=0;
select count(*) from goods
where CodeIsActive=1 and code_good=:code_good
into vrem;
if (vrem<>0) then begin error=1; exit;
end
if (art='') then begin error=2; exit;
end
select count(*) from paths where code_path=:code_ancestor into
vrem;
if (vrem=0) then begin error=3; exit;
end
if (name_good='') then begin error=4; exit;
end
if (LengthString(name_good)<3) then begin error=9; exit; end
select count(*) from TitleUnits where
code_unit=:code_unit into vrem;
if (vrem=0) then begin error=5; exit;
end
select count(*) from goods
where
code_ancestor=:code_ancestor and
name_good=:name_good and
CodeIsActive=1
into vrem;
if (vrem<>0) then begin error=6; exit;
end
if (code_good<10000) then begin error=7; exit; end
/*write data to database*/
new_number_good=gen_id(genGoods,
1);
insert into goods
values(:new_number_good, :code_good, 1,
:art,
:code_ancestor, :name_good, :code_unit,'');
vrem=0;
for select scan_code from ScanCodes2
into :scan_code as cursor cur1 do begin
vrem=vrem+1;
if (vrem=13) then begin
error=1/0;
when any do begin error=8; exit; end
end
insert into ScanCodes
values(:new_number_good, :scan_code);
update goods
set scan_codes=scan_codes||:scan_code||'
'
where
number_good=:new_number_good;
end
end
Ïðîàíàëèçèðóåì âõîäíûå è
âûõîäíûå äàííûå, è ïîäóìàåì, êàêèå ìîãóò áûòü îøèáî÷íûå ñèòóàöèè. Íà âõîäå
ïðîöåäóðà èìååò êîä òîâàðà, àðòèêóë, êîä ãðóïïû, íàçâàíèå òîâàðà è êîä åäèíèöû
èçìåðåíèÿ. Âîçâðàùàåò îíà íîìåð îøèáêè è íîâûé êîä òîâàðà â ñëó÷àå óäà÷è (error=0).
Âîçìîæíû ñëåäóþùèå îøèáî÷íûå
ñèòóàöèè:
1. Òàêîé êîä òîâàðà êàê code_good ìîæåò óæå ñóùåñòâîâàòü.
2. Ââîäèìûé êîä òîâàðà ìîæåò
áûòü ìåíüøå 10000.
3. Àðòèêóë ìîæåò áûòü ïóñòûì.
4. Ãðóïïû ñ êîäîì code_ancestor ìîæåò íå ñóùåñòâîâàòü.
5. Íàçâàíèå òîâàðà ìîæåò áûòü
ïóñòûì.
6. Íàçâàíèå òîâàðà ìîæåò áûòü
êîðî÷å òðåõ ñèìâîëîâ (áûëî ïðèíÿòî ðåøåíèå íå äîïóñêàòü íàçâàíèÿ òîâàðîâ êîðî÷å
òðåõ ñèìâîëîâ).
7. Åäèíèöà èçìåðåíèÿ ñ êîäîì code_unit ìîæåò íå ñóùåñòâîâàòü â òàáëèöå
TitleUnits.
8. Â äàííîé ãðóïïå ìîæåò
ñóùåñòâîâàòü òîâàð ñ äàííûì íàçâàíèåì.
9. Òîâàð ìîæåò èìåòü áîëåå 12
ñêàí-êîäîâ (ïðîãðàììà çàíîñèò òîâàð ñëåäóþùèì îáðàçîì: ñíà÷àëà âî âðåìåííûå
òàáëèöû çàíîñÿòñÿ ñêàí-êîäû, çàòåì çàíîñèòñÿ ñàì òîâàð, çàòåì ïåðåíîñÿòñÿ
ñêàí-êîäû èç âðåìåííîé òàáëèöû, ïîýòîìó äàííàÿ ïðîöåäóðà «çíàåò» ïðî ñêàí-êîäû,
õîòÿ îíà íå ïîëó÷àåò èõ â âèäå âõîäíûõ ïàðàìåòðîâ).
Òåïåðü, êîãäà ìû
îïðåäåëèëèñü, êàêèå èñêëþ÷èòåëüíûå ñèòóàöèè ìîãóò ñóùåñòâîâàòü, ðàññìîòðèì,
êàêèå èñêëþ÷èòåëüíûå ñèòóàöèè óæå áûëè ïðåäóñìîòðåíû äî ýòàïà òåñòèðîâàíèÿ (òî
åñòü íà ýòàïå íàïèñàíèÿ ïðîãðàììû). Âîò îíè:
1) error=1 -- this code_good already exists
2) error=2 -- articul must not be empty
3) error=3 -- incorrect code_ancestor (path not exists)
4) error=4 -- name_good must not be empty
5) error=5 -- this code_unit is not exist
6) error=6 -- good with this name_good already exists
7) error=7 -- code_good must not be less than 10000
8) error=8 -- the good cannot have more than 12 scan_codes
9) error=9 -- length(name_good) must not be less than 3
Èõ òîæå îêàçàëîñü äåâÿòü,
ïðè ýòîì òåõ æå ñàìûõ. Ñêîðåå âñåãî, äðóãèõ èñêëþ÷èòåëüíûõ ñèòóàöèé íå ìîæåò
áûòü. Òåïåðü ïðîâåðèì ïðîöåäóðó ïóòåì âíåñåíèÿ â íåå ðàçëè÷íûõ äàííûõ,
ïðèâîäÿùèõ ê îøèáêàì (ñ ïîìîùüþ IBExpert):
1) Ïîïûòàåìñÿ âûçâàòü îøèáêó 1:
âíåñòè â áàçó òîâàð ñ óæå èìåþùèìñÿ êîäîì. Äëÿ ýòîãî íàïèøåì (òîâàð ñ êîäîì
10000 èìååòñÿ â áàçå):
execute procedure procAddGood(10000, 'art', 1,
'name_good', 1);
Ïîëó÷èëè: error=1; new_number_good=null.
 ïðèíöèïå, òàê
è äîëæíî áûòü.
2)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 2, òî åñòü âíåñòè â áàçó òîâàð ñ ïóñòûì àðòèêóëîì. Äëÿ ýòîãî
íàïèøåì ñëåäóþùåå:
execute procedure procAddGood(50000, '', 1,
'name_good', 1);
Ïîëó÷èëè: error=2; new_number_good=null.
Âñå íîðìàëüíî.
3)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 3, òî åñòü âíåñòè íåêîððåêòíûé êîä ãðóïïû äëÿ òîâàðà. Äëÿ ýòîãî
íàïèøåì ñëåäóþùåå:
execute
procedure procAddGood(50000, 'art', 10000, 'name_good', 1);
Ïîëó÷èëè: error=3;
new_number_good=null. Â ïðèíöèïå, íîðìàëüíî.
4)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 4, òî åñòü âíåñòè â áàçó òîâàð ñ ïóñòûì èìåíåì. Äëÿ ýòîãî
íàïèøåì ñëåäóþùåå:
execute
procedure procAddGood(50000, 'art', 1, '', 1);
Ïîëó÷èëè: error=4;
new_number_good=null. Òàê è äîëæíî áûòü.
5)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 5, òî åñòü âíåñòè â áàçó òîâàð ñ åäèíèöåé èçìåðåíèÿ,
íåîïðåäåëåííîé â òàáëèöå TitleUnits.
Äëÿ ýòîãî íàïèøåì ñëåäóþùåå:
execute
procedure procAddGood(50000, 'art', 1, 'name_good', 10000);
Ïîëó÷èëè: error=5;
new_name_good=null. Íîðìàëüíî.
6)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 6, òî åñòü âíåñòè â áàçó òîâàð ñ óæå ñóùåñòâóþùèì èìåíåì. Äëÿ
ýòîãî íàïèøåì ñëåäóþùåå (â ãðóïïå ñ êîäîì 1 èìååòñÿ òîâàð, êîòîðûé íàçûâàåòñÿ
«Øòîðà äëÿ âàííîé»):
execute procedure procAddGood(50000, 'art', 1, 'Øòîðà
äëÿ âàííîé', 1);
Ïîëó÷èëè: error=6;
new_name_good=null. Òàê è äîëæíî áûòü.
7)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 7, òî åñòü âíåñòè â áàçó òîâàð ñ êîäîì, ìåíüøèì 10000. Äëÿ ýòîãî
íàïèøåì ñëåäóþùåå:
execute
procedure procAddGood(9999, 'art', 1, 'name_good', 1);
Ïîëó÷èëè: error=7;
new_name_good=null. Âñå íîðìàëüíî.
8)
Ïîïûòàåìñÿ
âûçâàòü îøèáêó 8, òî åñòü âíåñòè â áàçó òîâàð ñ ÷èñëîì ñêàí-êîäîâ, áîëüøèì 12.
Äëÿ ýòîãî âûïîëíèì òàêóþ ïîñëåäîâàòåëüíîñòü äåéñòâèé:
delete from ScanCodes2;
insert into ScanCodes2 values('0000000000000');
insert into ScanCodes2 values('0000000000001');
insert into ScanCodes2 values('0000000000002');
insert into ScanCodes2 values('0000000000003');
insert into ScanCodes2 values('0000000000004');
insert into ScanCodes2 values('0000000000005');
insert into ScanCodes2 values('0000000000006');
insert into ScanCodes2 values('0000000000007');
insert into ScanCodes2 values('0000000000008');
insert into ScanCodes2 values('0000000000009');
insert into ScanCodes2 values('0000000000010');
insert into ScanCodes2 values('0000000000011');
insert into ScanCodes2 values('0000000000012');
insert into ScanCodes2 values('0000000000013');
execute procedure procAddGood(50000, 'art', 1, 'name_good', 1);
Ïîëó÷èëè: error=8; new_name_good=8099. Âñå ïðàâèëüíî. new_number_good ¹ null,
òàê êàê îøèáêà âîçíèêëà óæå ïîñëå îïðåäåëåíèÿ êîäà òîâàðà. Íî òîâàð íå çàíåñåí
â áàçó. Â ýòîì ìîæíî óáåäèòüñÿ, îòêðûâ òàáëèöó goods, èëè âûïîëíèòü çàïðîñ: select * from goods where number_good=8099.
9) Ïîïûòàåìñÿ âíåñòè òîâàð ñ
íàçâàíèåì êîðî÷å òðåõ ñèìâîëîâ (íî íå ïóñòûì). Äëÿ ýòîãî íàïèøåì ñëåäóþùåå:
execute procedure
procAddGood(50000, 'art', 1, 'na', 1);
Ïîëó÷èëè: error=9;
new_name_good=null. Âñå íîðìàëüíî.
Èòàê, ïðîöåäóðà
ïðîòåñòèðîâàíà ñ ïîìîùüþ IBExpert. Òåïåðü ïðîòåñòèðóåì ïðîöåäóðó ñ ïîìîùüþ ïðîãðàììû. Äëÿ ýòîãî çàïóñòèì
ôîðìó äëÿ çàíåñåíèÿ òîâàðîâ è ïîïûòàåìñÿ âíåñòè â áàçó òîâàð ñ íåâåðíûìè
äàííûìè. Óáåäèìñÿ, ÷òî ýòî íåâîçìîæíî, èíà÷å èñïðàâèì íàéäåííûå îøèáêè.
 ðåçóëüòàòå òåñòèðîâàíèÿ
âñåõ ïðîöåäóð íàéäåíî ñëåäóþùèå òðè îøèáêè, êîòîðûå â äàëüíåéøåì óñòðàíåíû:
ïðè èçìåíåíèè ñåáåñòîèìîñòè
òîâàðà ñåññèè ñóììà ñåáåñòîèìîñòåé òîâàðîâ ñåññèè íå îáíîâëÿëàñü;
ïðè çàêðûòèè ñåññèè êîãäà â
ñåññèè èìåþòñÿ òîâàðû ñ íóëåâûì êîëè÷åñòâîì ïðîèñõîäèò îøèáêà division by zero;
ïðîöåäóðà Âîçâðàò Òîâàðà íå
ðàáîòàëà äîëæíûì îáðàçîì.
Íà ýòîì ïåðâûé ýòàï òåñòèðîâàíèÿ çàêîí÷åí.
Ïðîâåðèì êîä ïðîãðàììû âî
âñåõ ìåñòàõ, ãäå îíà ðàáîòàåò ñ áàçîé íà ïðàâèëüíîñòü ââåäåííûõ äàííûõ.
Ïðîãðàììà äîëæíà ðåàãèðîâàòü íà âñå îøèáêè, êîòîðûå âûäàþò õðàíèìûå ïðîöåäóðû.
Îäíîâðåìåííî ñ ïîìîùüþ
ïðîãðàììû ïîïðîáóåì âûïîëíèòü ðàçëè÷íûå äåéñòâèÿ, ïûòàÿñü ñîçäàòü îøèáêó.
 ðåçóëüòàòå íàéäåíî ñåìü
îøèáîê, ïðè÷åì íå âñå èç íèõ ñâÿçàíû ñ íåêîððåêòíîé ðàáîòîé ñ áàçîé. Íèæå
ïðèâåäåíû íåêîòîðûå èç îøèáîê, óñòðàíåííûõ â äàëüíåéøåì:
íà ôîðìå äëÿ çàíåñåíèÿ
òîâàðîâ â ñåññèþ íå ïðîâåðÿëàñü ïðàâèëüíîñòü ââîäà íàöåíêè;
íà ôîðìå äëÿ çàíåñåíèÿ
òîâàðà â ñåññèþ ïðè ââîäå êîëè÷åñòâà òîâàðà, ðàâíîãî íóëþ, ïðîèñõîäèëî äåëåíèå
íà íîëü;
ïîëå äëÿ ðó÷íîãî ââîäà
ñêàí-êîäà (êîòîðûé ñîñòîèò èç öèôð) íà ôîðìå äëÿ èçìåíåíèÿ òîâàðà ñåññèè
äîïóñêàëî ââîä ëþáûõ ñèìâîëîâ (êîíå÷íî, â áàçó ýòîò ñêàí-êîä âñå ðàâíî íå
ïîïàäàë, òàê êàê ñóùåñòâóåò åùå ïðîâåðêà íå ñåðâåðå, íî ýòî ïðèâîäèëî ê
íåïîíÿòíûì «ãëþêàì»).
Òðåòèé ýòàï òåñòèðîâàíèÿ.
Ïðîâåðÿåì Firebird Server.
Äëÿ ýòîãî çàïóñòèì äëèííóþ òðàíçàêöèþ (èç ìèëëèîíà îïåðàòîðîâ insert è update). Â ñåðåäèíå òðàíçàêöèè
âûäåðíåì øíóð ïèòàíèÿ èç ðîçåòêè. Ðåçóëüòàòû äàííîãî äåéñòâèÿ ñëåäóþùèå:
ïðè ÷èñëå çàïèñåé äî 1000
áàçà äàííûõ íîðìàëüíî îòêàòûâàëàñü ê ïðåäûäóùåìó ñîñòîÿíèþ;
ïðè ÷èñëå çàïèñåé 50000
íåêîòîðûå òàáëèöû ñòàëè ÷èòàòüñÿ ñ îøèáêàìè;
ïðè ÷èñëå çàïèñåé 500000
áàçà ñòàëà çàíèìàòü íà ìîìåíò âûêëþ÷åíèÿ ïèòàíèÿ îêîëî 700 ìåãàáàéò, è ïîñëå
âêëþ÷åíèÿ ïèòàíèÿ îêàçàëàñü íå÷èòàåìîé.
 ïðèíöèïå, íîðìàëüíî. Â
ðåàëüíîñòè ñåðâåð íå áóäåò âûïîëíÿòü òðàíçàêöèè èç 500 òûñÿ÷ îïåðàöèé, ê òîìó æå
îí áóäåò çàïèòàí ÷åðåç èñòî÷íèê áåñïåðåáîéíîãî ïèòàíèÿ, è êàæäûå äâå íåäåëè
äîëæíî ïðîâîäèòüñÿ ðåçåðâíîå êîïèðîâàíèå.
×åòâåðòûé ýòàï òåñòèðîâàíèÿ
ñèëàìè ñòîðîííåãî ïðîãðàììèñòà. Â ðåçóëüòàòå íàéäåíà îäíà îøèáêà: ïðè ââîäå
ñêèäêè â ïîëå ñî ñêèäêîé â ôîðìå ñ ïðîäàæàìè ñêèäêà ïðîèçâîäèòñÿ íà âñå òîâàðû,
à íå òîëüêî íà òó ñòðîêó, ãäå áûëà ââåäåíà ñêèäêà. Îøèáêà èñïðàâëåíà.
Ïÿòûé ýòàï òåñòèðîâàíèÿ:
ïèøåì ïðîöåäóðó äëÿ ââîäà áîëüøîãî êîëè÷åñòâà òîâàðîâ â áàçó. Ñ ïîìîùüþ ýòîé
ïðîöåäóðû çàíîñèì â áàçó îêîëî 5000 íàèìåíîâàíèé òîâàðîâ â 100 ñåññèé îïòîâîé
çàêóïêè íîìåð òðè. Ïðè ýòîì ñîçäàåòñÿ 100 ãðóïï òîâàðîâ. Ïðîöåäóðà ýìóëèðóåò
ðåàëüíîå çàíåñåíèå òîâàðîâ, ïîýòîìó îòñóòñòâèå îøèáîê ìîæåò áûòü ïîäòâåðæäåíèåì
êîððåêòíîé ðàáîòû ïðîãðàììû. Ïðè ýòîì èìåíà òîâàðîâ è ãðóïï ôîðìèðóåì ñëó÷àéíûì
îáðàçîì, è äåëàåì äëèííûìè (÷òîáû ïðîãðàììà «òîðìîçèëà»). Âûïîëíèì äàííóþ
ïðîöåäóðó 10 ðàç, è â áàçå áóäåò íàõîäèòüñÿ îêîëî 50000 òîâàðîâ â 1000 ãðóïï,
çàíåñåííûõ ñ ïîìîùüþ 1000 ñåññèé.
{óñòàíàâëèâàåò êóðñîð êóäà íóæíî}
var
ExistNumberGood: integer; {0 – íåò; 1 -- åñòü}
name_good0: string;
begin
with Form3 do begin
TR_SelectGoodsOfPath.Active:=false;
TR_SelectGoodsOfPath.Active:=true;
Q_ExistNumberGood.Close;
Q_ExistNumberGood.ParamByName('name_good').Value:=name_good;
Q_ExistNumberGood.ParamByName('code_ancestor').Value := code_path;
Q_ExistNumberGood.Open;
ExistNumberGood:=Q_ExistNumberGood.RecordCount;
Q_SelectGoodsOfPath.Close;
Q_SelectGoodsOfPath.ParamByName('code_ancestor').Value := code_path;
Q_SelectGoodsOfPath.Open;
Q_SelectGoodsOfPath.First;
if ExistNumberGood<>0 then begin
name_good0:=Q_SelectGoodsOfPath.FieldValues['name_good'];
while not Q_SelectGoodsOfPath.Eof and (name_good0<>name_good)
do begin
Q_SelectGoodsOfPath.Next;
name_good0:=Q_SelectGoodsOfPath.FieldValues['name_good'];
end;
end
else begin
if not Q_SelectGoodsOfPath.Eof
then begin
name_good0:=Q_SelectGoodsOfPath.FieldValues['name_good'];
while not Q_SelectGoodsOfPath.Eof do
begin
if name_good0<name_good then
Q_SelectGoodsOfPath.Next
else Break;
name_good0:=Q_SelectGoodsOfPath.FieldValues['name_good'];
end;
end;
end;
RefreshTree(code_path);
CodeCutForAdd:=0;
end;
end;
Äóìàåì, êàêèå äåéñòâèÿ ìîãóò
âûçûâàòü «òîðìîçà». Âî-ïåðâûõ, ýòî çàïðîñ Q_ExistNumberGood. Âîò
åãî òåêñò:
select * from goods
where
name_good=:name_good and CodeIsActive=1 and
code_ancestor=:code_ancestor
Ýòîò çàïðîñ äîëæåí
âûïîëíÿòüñÿ áûñòðî, òàê êàê èñïîëüçóåòñÿ òîëüêî îäíà òàáëèöà èç 50000 çàïèñåé,
è äàæå ïîëíûé ïåðåáîð íå äîëæåí âûçûâàòü ïðîáëåì. Òåì áîëåå, ïîëå code_ancestor òàáëèöû goods èíäåêñèðîâàíî. Òåì íå ìåíåå, ïðîâåðèì åãî â IBExpert è óáåäèìñÿ, ÷òî åãî
âûïîëíåíèå çàíèìàåò 0,00 ñåêóíä.
Q_SelectGoodsOfPath êàê ðàç çàíèìàåòñÿ
çàïîëíåíèåì ñïèñêà òîâàðîâ. Åãî óæå ïðîâåðèëè ðàíåå, îí âûïîëíÿåòñÿ 0,00
ñåêóíä. Öèêë èç 50 èòåðàöèé (èìåííî ñòîëüêî òîâàðîâ â ïðîâåðÿåìîé ãðóïïå) íå
ìîæåò çàíèìàòü ìíîãî âðåìåíè, ïîýòîìó ïðè÷èíà ìîæåò áûòü òîëüêî â ïðîöåäóðå RefreshTree, êîòîðàÿ çàíèìàåòñÿ
îáíîâëåíèåì êàðòèíîê äåðåâà íà ôîðìå ñ ãðóïïàìè òîâàðîâ (÷òîáû íå
ïåðåðèñîâûâàòü êàæäûé ðàç äåðåâî ïðè îòêðûòèè ôîðìû). Óáèðàåì âûçîâ ýòîé
ïðîöåäóðû. Òåïåðü îòêðûòèå ãðóïïû ñ òîâàðàìè ïðîèñõîäèò î÷åíü áûñòðî. Ïîýòîìó â
äàëüíåéøåì áóäåì âûïîëíÿòü âûçîâ ïðîöåäóðû RefreshTree òîëüêî ïîñëå îïåðàöèé äîáàâëåíèÿ, èëè óäàëåíèÿ
òîâàðà (òîãäà äåéñòâèòåëüíî åñòü ÷òî îáíîâëÿòü), à íå ïîñëå êàæäîãî äåéñòâèÿ.
Çàòåì ïîïûòàåìñÿ îïòèìèçèðîâàòü è ýòó ïðîöåäóðó. Íèæå ïðèâåäåí òåêñò äàííîé
ïðîöåäóðû:
procedure
RefreshTree(code_path: integer);
var
i, j:
integer;
code_path0:
integer;
chislo:
integer;
p: TTreeNode;
begin
with Form3 do begin
for i:=0 to Form2.TreeView1.Items.Count-1 do begin
p :=
Form2.TreeView1.Items.Item[i];
code_path0 := integer(p.Data);
TR_CountGoodsInPath.Active:=false; TR_CountGoodsInPath.Active:=true;
Q_CountGoodsInPath.Close;
Q_CountGoodsInPath.ParamByName('code_path').Value:=code_path;
Q_CountGoodsInPath.Open;
chislo:=Q_CountGoodsInPath.RecordCount;
for j:=0 to LengthMassiv-1 do begin
if massiv[j].code_path=code_path then massiv[j].chislo:=chislo;
end;
if
code_path0=code_path then begin
p.StateIndex:=0;
if chislo=0 then p.StateIndex:=0
else p.StateIndex:=1;
end;
end;
end;
end;
Íàâåðíîå, ïðîáëåìà â çàïðîñå
Q_CountGoodsInPath. Âîò òåêñò äàííîãî çàïðîñà:
select * from goods
where
code_ancestor=:code_path and CodeIsActive=1
 äàííîì çàïðîñå íåò
ñîåäèíåíèé òàáëèö, à òàáëèöà goods ñîäåðæèò 50000 çàïèñåé.
«Òîðìîçèòü» íå äîëæíî. Â IBExpert äàííûé çàïðîñ âûïîëíÿåòñÿ
0,00 ñåêóíä. Íàâåðíîå, âñÿ ïðîáëåìà â òîì, ÷òî çàïðîñ âûïîëíÿåòñÿ â öèêëå.
Ïðè÷åì ÷èñëî èòåðàöèé ðàâíî ÷èñëó ãðóïï äåðåâà. À ÷èñëî ãðóïï äåðåâà áîëüøå
òûñÿ÷è, ïîýòîìó âûïîëíÿåòñÿ îêîëî òûñÿ÷è çàïðîñîâ. Õîòÿ âðåìÿ âûïîëíåíèÿ
êàæäîãî â îòäåëüíîñòè 0,00 ñåêóíä, â ñóììå ýòî äàåò êàê ðàç òå ñàìûå òðè
ñåêóíäû îæèäàíèÿ. Íî äàííóþ ïðîöåäóðó ëåãêî ìîæíî îïòèìèçèðîâàòü, òàê êàê îíà
ïåðåñ÷èòûâàåò ÷èñëî òîâàðîâ â êàæäîé èç ãðóïï äåðåâà. Áóäåì ïåðåñ÷èòûâàòü
òîëüêî êîëè÷åñòâî òîâàðîâ òåêóùåé ãðóïïû (ãðóïïû ñ êîäîì code_path). Òåêñò îïòèìèçèðîâàííîé
ïðîöåäóðû áóäåò òàêèì:
procedure RefreshTree(code_path: integer);
var
i, j:
integer;
code_path0:
integer;
chislo:
integer;
p: TTreeNode;
begin
with Form3 do begin
for i:=0 to Form2.TreeView1.Items.Count-1 do begin
p :=
Form2.TreeView1.Items.Item[i];
code_path0 := integer(p.Data);
if code_path=code_path0 then begin
TR_CountGoodsInPath.Active:=false;
TR_CountGoodsInPath.Active:=true;
Q_CountGoodsInPath.Close;
Q_CountGoodsInPath.ParamByName('code_path').Value:=code_path;
Q_CountGoodsInPath.Open;
chislo:=Q_CountGoodsInPath.RecordCount;
for j:=0 to LengthMassiv-1 do begin
if massiv[j].code_path=code_path then
massiv[j].chislo:=chislo;
end;
if
code_path0=code_path then begin
p.StateIndex:=0;
if chislo=0 then p.StateIndex:=0
else
p.StateIndex:=1;
end;
end;
end;
end;
end;
Êîíå÷íî, ýòó ïðîöåäóðó ìîæíî
«ïðè÷åñàòü» (óáðàòü ëèøíèå ïåðåìåííûå, è ò. ä.), íî äëÿ íàãëÿäíîñòè â äàííîé
ðàáîòå ëó÷øå ïîäõîäèò «ñûðîé» âèä. Òåïåðü ïîòåñòèðóåì ïðîãðàììó. Ïðîöåññû
îòêðûòèÿ ôîðìû, äîáàâëåíèÿ, óäàëåíèÿ è èçìåíåíèÿ òîâàðîâ ñòàëè ïî÷òè ìãíîâåííûìè.
Àíàëîãè÷íûì îáðàçîì
îïòèìèçèðóåì äðóãèå ìåñòà ïðîãðàììû. Ïîñëå äàííîãî ýòàïà ïðîãðàììà ñòàëà
ïðèãîäíîé ê âíåäðåíèþ.
Øåñòîé ýòàï òåñòèðîâàíèÿ
ïðîõîäèë óæå ïîñëå âíåäðåíèÿ ïðîãðàììû íà ðåàëüíûõ ïîëüçîâàòåëÿõ. Ñåðüåçíûõ
îøèáîê íà äàííîì ýòàïå íå îáíàðóæåíî, íî èñïðàâëåíî íåñêîëüêî ìåëêèõ íåäî÷åòîâ.
Àðõèòåêòóðà
ñåòè íà ïðåäïðèÿòèè ïðîäóáëèðîâàíà íà ðèñóíêå 32.
Ðèñóíîê
32
Âñå êîìïüþòåðû èñïîëüçóþòñÿ,
ôèðìà íå ìîæåò ñåáå ïîçâîëèòü âûäåëèòü îäèí äëÿ ñåðâåðà è íå ïîëüçîâàòüñÿ èì.
Ïîýòîìó áàçó äàííûõ ïðàêòè÷åñêè íåâîçìîæíî çàùèòèòü îò íåñàíêöèîíèðîâàííîãî
êîïèðîâàíèÿ.
Êàê èçâåñòíî, ïàðîëè ñåðâåðà
Firebird õðàíÿòñÿ íà ñåðâåðå (à íå â
áàçå äàííûõ). Ïîýòîìó ëþáîé ÷åëîâåê, êîòîðûé õîðîøî ðàçáèðàåòñÿ â êîìïüþòåðàõ,
ìîæåò ñêîïèðîâàòü áàçó íà ôëåøêó, óíåñòè åå äîìîé, òàì ïîñòàâèòü Firebird Server
è ïîëó÷èòü ê íåé äîñòóï ïîä èìåíåì ïîëüçîâàòåëÿ sysdba è ïàðîëåì masterkey. Îí ìîæåò ïîìåíÿòü â áàçå âñå, ÷òî çàõî÷åò, è çàòåì
åå ïîäìåíèòü.
Ïîëüçîâàòåëÿ sysdba èç áàçû íèêàê íå óäàëèòü. Ïîýòîìó áûëî ïðèíÿòî
ðåøåíèå íå äåëàòü çàùèòó îò ëþäåé, õîðîøî ðàçáèðàþùèõñÿ â êîìïüþòåðå, à ñäåëàòü
çàùèòó îò îáû÷íûõ ïîëüçîâàòåëåé íà óðîâíå ïðîãðàììû. Äîñòóï ê ñåðâåðó âñå
ïîëüçîâàòåëè ïîëó÷àþò ÷åðåç ó÷åòíóþ çàïèñü sysdba, ñ èçìåíåííûì ïàðîëåì.
Âñå ïàðîëè õðàíÿòñÿ â áàçå
äàííûõ â çàøèôðîâàííîì ñ ïîìîùüþ àëãîðèòìà MD5 âèäå. Ýòî íóæíî, ÷òîáû
ðàçáèðàþùèåñÿ â êîìïüþòåðàõ ëþäè íå ìîãëè óçíàòü ïàðîëü.
Ïðè âõîäå ïîëüçîâàòåëÿ â
ñèñòåìó ïðîãðàììà ïðîâåðÿåò, ÷òî ââåäåííûé ïàðîëü ñîâïàäàåò ñ ïàðîëåì íà ñåðâåðå,
è äîïóñêàåò ïîëüçîâàòåëÿ â ñèñòåìó ñ ïðàâàìè, êîòîðûå òàêæå ïðîïèñàíû íà
ñåðâåðå.
Ïðåäñòàâëåííàÿ
ïðîãðàììà óæå íà äàííîì ýòàïå ìîæåò ïðèìåíÿòüñÿ äëÿ ðàáîòû â íåáîëüøèõ
ìàãàçèíàõ. Íî â íàñòîÿùåå âðåìÿ îíà íå ÿâëÿåòñÿ ïîëíîñòüþ çàâåðøåííûì
ïðîäóêòîì. Â äàëüíåéøåì ïëàíèðóåòñÿ óñîâåðøåíñòâîâàòü äàííóþ ïðîãðàììó è
ñäåëàòü åå ïðèãîäíîé äëÿ ìàññîâîãî âíåäðåíèÿ. Îñíîâíûå ïëàíû ïî ìîäåðíèçàöèè
ïðîãðàììû òàêîâû:
1)
Îïòèìèçàöèÿ íåêîòîðûõ SQL-çàïðîñîâ è õðàíèìûõ ïðîöåäóð.
2)
Ïåðåíåñåíèå ÷àñòè ðàáîòû ñ ñåðâåðà íà êëèåíòñêèå ìàøèíû
(÷òîáû íå ïåðåãðóæàòü ñåðâåð).
3)
Äîðàáîòêà ñèñòåìû áåçîïàñíîñòè (ñîçäàíèå çàùèòû íà óðîâíå
ñåðâåðà, äîðàáîòêà çàùèòû íà óðîâíå ïðîãðàììû).
4)
Äîðàáîòêà ïðîãðàììû äëÿ ðåàëèçàöèè âîçìîæíîñòè ïàðàëëåëüíîé
ðàáîòû íåñêîëüêèõ êàññèðîâ â íåñêîëüêî ñìåí.
5)
Ñîçäàíèå ïàêåòà àâòîìàòè÷åñêîé èíñòàëëÿöèè.
6)
Äîáàâëåíèå ôóíêöèé, îò÷åòîâ, èçìåíåíèå èíòåðôåéñà ïðîãðàììû
â ñîîòâåòñòâèè ñ òðåáîâàíèÿìè ïîòåíöèàëüíûõ çàêàç÷èêîâ
1) Çóáêîâ Ñ. Â. Àññåìáëåð äëÿ DOS, Windows è UNIX. – Ì.: ÄÌÊ Ïðåññ, 2000
2) Þðîâ Â. È. Assembler: Ñïåöèàëüíûé ñïðàâî÷íèê. 2-å èçä. – ÑÏá.: Ïèòåð, 2004. – 412 ñ.:
èë.
3) Î. Ë. Ãîëèöûíà, Í. Â. Ìàêñèìîâ, È. È. Ïîïîâ Áàçû äàííûõ:
Ó÷åáíîå ïîñîáèå. – Ì.: ÔÎÐÓÌ: ÈÍÔÐÀ-Ì, 2006. – 352 ñ.: èë. – (Ïðîôåññèîíàëüíîå
îáðàçîâàíèå).
4) Ôàðîíîâ Â. Â. Ïðîãðàììèðîâàíèå áàç äàííûõ â Delphi 7. Ó÷åáíûé êóðñ. – ÑÏá.: Ïèòåð, 2006. – 459 ñ.: èë.
5) Êîðíÿêîâ Â. Í. Ïðîãðàììèðîâàíèå äîêóìåíòîâ è
ïðèëîæåíèé MS Office â Delphi. – ÑÏá.:
ÁÕÂ-Ïåòåðáóðã, 2006. – 496 ñ.: èë.
6) Ñâåðäëîâ Ñ. Ç. ßçûêè ïðîãðàììèðîâàíèÿ è ìåòîäû òðàíñëÿöèè: ó÷åá. ïîñîáèå äëÿ âóçîâ
ïî íàïðàâëåíèþ “Ïðèêëàäíàÿ ìàòåìàòèêà è èíôîðìàòèêà”/Ñ. Ç. Ñâåðäëîâ.-Ì. [è
äð.]:Ïèòåð,2007.-638 ñ.:èë.
7)
Áèëëèã Âëàäèìèð Àðíîëüäîâè÷ Îñíîâû îôèñíîãî
ïðîãðàììèðîâàíèÿ è äîêóìåíòû Word. Ýëåêòðîííûé ðåñóðñ: http://www.intuit.ru/department/office/vbaword/
8) Áèëëèã Âëàäèìèð Àðíîëüäîâè÷ Îñíîâû îôèñíîãî ïðîãðàììèðîâàíèÿ è äîêóìåíòû Excel.
Ýëåêòðîííûé ðåñóðñ: http://www.intuit.ru/department/office/vbaexcel/
9) Îëåã Êóêàðöåâ Êàê íàó÷èòüñÿ ïèñàòü UDF äëÿ IB Database çà 21 ìèí. Ýëåêòðîííûé
ðåñóðñ: http://www.lcard.ru/~nail/database/ib_udf.html
10)Àíòîí Ãðèãîðüåâ Íåî÷åâèäíûå îñîáåííîñòè âåùåñòâåííûõ ÷èñåë. Ýëåêòðîííûé ðåñóðñ: http://www.www.delphikingdom.ru/asp/viewitem.asp?catalogid=374
11)alglib.ru Èíòåðïîëÿöèÿ ôóíêöèè êóáè÷åñêèìè ñïëàéíàìè. Ýëåêòðîííûé ðåñóðñ: http://alglib.sources.ru/interpolation/spline3.php
12)Êóçüìåíêî Äìèòðèé ×àñòûå âîïðîñû è îòâåòû ïî InterBase / Firebird / Yaffil. Ýëåêòðîííûé ðåñóðñ: http://www.ibase.ru/ibfaq.htm
13)Êîðîëåâñòâî Delphi.
Ýëåêòðîííûé ðåñóðñ: http://www.delphikingdom.com/
14)Èãîðü Àëåêñååâ Delphi. Ñîçäàíèå êîìïîíåíòîâ. Ýëåêòðîííûé ðåñóðñ: http://progs.biz/delphi/components/components01.aspx
15)Èãîðü Àëåêñååâ Delphi. VCL. Ýëåêòðîííûé ðåñóðñ: http://progs.biz/delphi/vcl/vcl01.aspx
16)sedinko.ru Äîêóìåíòàöèÿ. Delphi. Ýëåêòðîííûé ðåñóðñ: http://www.sedinko.ru/delphi/
17)Matthias Fichtner
Ðåàëèçàöèÿ àëãîðèòìà MD5. Ýëåêòðîííûé ðåñóðñ: http://files.myref.ru/10/myref-1092629683.zip
CREATE GENERATOR GENTITLEUNITS ;
CREATE GENERATOR GENGOODS ;
CREATE GENERATOR GENWHOLESALEBASES ;
CREATE GENERATOR GENPURCHASES ;
CREATE GENERATOR GENSESSIONS ;
CREATE GENERATOR GENSTRUCTURESESSION ;
CREATE GENERATOR GENSALES ;
CREATE GENERATOR GENSTRUCTURESALE ;
CREATE GENERATOR GENPATHS ;
CREATE GENERATOR GENNOTES ;
CREATE GENERATOR GENACTIONS ;
CREATE GENERATOR GENSAVES ;
CREATE GENERATOR GENRETURNS ;
CREATE GENERATOR GENSTRUCTURERETURN ;
CREATE GENERATOR GENGOODSFORCUT ;
CREATE GENERATOR GENNUMBERGOODSFORSELECT ;
CREATE GENERATOR GENSEARCHCODESALENUMBERGOOD ;
CREATE GENERATOR GENPROGRAMUSERS ;
CREATE TABLE TITLEUNITS (
CODE_UNIT INTEGER
NOT NULL,
NAME_UNIT
VARCHAR(20) NOT NULL,
ISACTIVE
INTEGER NOT NULL,
ISMATERIAL
INTEGER NOT NULL);
/*
Primary Key */
ALTER TABLE TITLEUNITS ADD CONSTRAINT INTEG_5
PRIMARY KEY (CODE_UNIT);
CREATE TABLE GOODS (
NUMBER_GOOD
INTEGER NOT NULL,
CODE_GOOD
INTEGER NOT NULL,
CODEISACTIVE
INTEGER NOT NULL,
ART
VARCHAR(20) NOT NULL,
CODE_ANCESTOR INTEGER NOT NULL,
NAME_GOOD
VARCHAR(80) NOT NULL,
CODE_UNIT
INTEGER NOT NULL,
SCAN_CODES
VARCHAR(255));
/*
Primary Key */
ALTER TABLE GOODS ADD CONSTRAINT INTEG_13
PRIMARY KEY (NUMBER_GOOD);
CREATE TABLE DATE1 (
DATE0
TIMESTAMP);
CREATE TABLE WHOLESALEBASES (
CODE_BASE
INTEGER NOT NULL,
NAME_BASE
VARCHAR(80) NOT NULL,
ADDRESS VARCHAR(80) NOT NULL,
FIOMAN
VARCHAR(80) NOT NULL,
PHONEMAN
VARCHAR(40) NOT NULL,
PHONEBK
VARCHAR(40) NOT NULL);
/*
Primary Key */
ALTER TABLE WHOLESALEBASES ADD CONSTRAINT INTEG_20
PRIMARY KEY (CODE_BASE);
CREATE TABLE PURCHASES (
CODE_PURCHASE
INTEGER NOT NULL,
CODE_BASE
INTEGER NOT NULL,
DATE_PURCHASE
TIMESTAMP NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE PURCHASES ADD CONSTRAINT INTEG_25
PRIMARY KEY (CODE_PURCHASE);
CREATE TABLE SESSIONS (
CODE_SESSION
INTEGER NOT NULL,
CODE_PURCHASE
INTEGER NOT NULL,
ACCEPTED INTEGER NOT NULL,
ADDITION
DOUBLE PRECISION NOT NULL,
DATE0
TIMESTAMP NOT NULL,
DATE1
TIMESTAMP NOT NULL,
SUMMA
DOUBLE PRECISION);
/*
Primary Key */
ALTER TABLE SESSIONS ADD CONSTRAINT INTEG_32
PRIMARY KEY (CODE_SESSION);
CREATE TABLE STRUCTURESESSION (
PRIMARYKEY
INTEGER NOT NULL,
CODE_SESSION
INTEGER NOT NULL,
NUMBER_GOOD INTEGER NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
FIRST_PRICE
DOUBLE PRECISION NOT NULL,
ADDITION
DOUBLE PRECISION NOT NULL,
SCAN_CODES
VARCHAR(255));
/* Primary
Key */
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
INTEG_39 PRIMARY KEY (PRIMARYKEY);
CREATE TABLE STOREHOUSE (
NUMBER_GOOD
INTEGER NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
FIRST_PRICE DOUBLE PRECISION NOT NULL,
PRICE
DOUBLE PRECISION NOT NULL,
SOLD
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE STOREHOUSE ADD CONSTRAINT INTEG_45
PRIMARY KEY (NUMBER_GOOD);
CREATE TABLE SALES (
CODE_SALE
INTEGER NOT NULL,
TYPE_SALE
INTEGER NOT NULL,
DATE_SALE
TIMESTAMP NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL,
CASH DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE SALES ADD CONSTRAINT INTEG_51
PRIMARY KEY (CODE_SALE);
CREATE TABLE STRUCTURESALE (
PRIMARYKEY
INTEGER NOT NULL,
CODE_SALE
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
FIRST_PRICE
DOUBLE PRECISION NOT NULL,
PRICE
DOUBLE PRECISION NOT NULL,
DISCOUNT DOUBLE PRECISION NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL,
SOLDBYPRICE
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE STRUCTURESALE ADD CONSTRAINT
INTEG_60 PRIMARY KEY (PRIMARYKEY);
CREATE TABLE PATHS (
CODE_PATH
INTEGER NOT NULL,
CODE_ANCESTOR
INTEGER NOT NULL,
NAME_PATH
VARCHAR(80) NOT NULL);
/*
Primary Key */
ALTER TABLE PATHS ADD CONSTRAINT INTEG_64
PRIMARY KEY (CODE_PATH);
CREATE TABLE NOTES (
CODE_NOTE
INTEGER NOT NULL,
NUMBER_TABLE
INTEGER NOT NULL,
KEYFROMTABLE
INTEGER NOT NULL,
TEXT
VARCHAR(80) NOT NULL);
/*
Primary Key */
ALTER TABLE NOTES ADD CONSTRAINT INTEG_69
PRIMARY KEY (CODE_NOTE);
CREATE TABLE ACTIONS (
CODE_ACTION
INTEGER NOT NULL,
DATE_ACTION
TIMESTAMP NOT NULL,
TEXT
VARCHAR(160) NOT NULL);
/*
Primary Key */
ALTER TABLE ACTIONS ADD CONSTRAINT INTEG_148
PRIMARY KEY (CODE_ACTION);
CREATE TABLE SAVES (
CODE_SAVE
INTEGER NOT NULL,
WAY
VARCHAR(1000) NOT NULL,
DATE_SAVE TIMESTAMP NOT NULL);
/*
Primary Key */
ALTER TABLE SAVES ADD CONSTRAINT INTEG_77
PRIMARY KEY (CODE_SAVE);
CREATE TABLE PROPERTIES (
CODE_PROPERTY
INTEGER NOT NULL,
NAME_PROPERTY
VARCHAR(255) NOT NULL,
VAL INTEGER NOT NULL);
/*
Primary Key */
ALTER TABLE PROPERTIES ADD CONSTRAINT INTEG_81
PRIMARY KEY (CODE_PROPERTY);
CREATE TABLE SCANCODES (
NUMBER_GOOD
INTEGER NOT NULL,
SCAN_CODE
VARCHAR(20) NOT NULL);
CREATE TABLE SCANCODESFORSESSION (
PRIMARYKEY
INTEGER NOT NULL,
CODE_SESSION
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
SCAN_CODE
VARCHAR(20) NOT NULL);
CREATE TABLE SESSIONSCLOSED (
CODE_SESSION
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
OLD_PRICE
DOUBLE PRECISION NOT NULL,
NEW_PRICE
DOUBLE PRECISION NOT NULL);
CREATE TABLE SCANCODES2 (
SCAN_CODE
VARCHAR(20) NOT NULL);
CREATE TABLE RETURNS2 (
CODE_RETURN
INTEGER NOT NULL,
CODE_SALE
INTEGER NOT NULL,
DATE_RETURN
TIMESTAMP NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL,
CASH
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE RETURNS2 ADD CONSTRAINT INTEG_126
PRIMARY KEY (CODE_RETURN);
CREATE TABLE STRUCTURERETURN2 (
PRIMARYKEY
INTEGER NOT NULL,
CODE_RETURN
INTEGER NOT NULL,
CODE_STRUCTURESALE
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
PRICE
DOUBLE PRECISION NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
INTEG_134 PRIMARY KEY (PRIMARYKEY);
CREATE TABLE GOODSFORRETURN (
NUMBER_GOOD
INTEGER NOT NULL,
CODE_GOOD
INTEGER NOT NULL,
NAME_GOOD
VARCHAR(80) NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
REMAINDER DOUBLE PRECISION NOT NULL,
ISMATERIAL
INTEGER NOT NULL,
CODE_UNIT
INTEGER NOT NULL,
NAME_UNIT
VARCHAR(20) NOT NULL,
PRICE
DOUBLE PRECISION NOT NULL,
CODESTRUCTURESALE INTEGER NOT NULL,
DAY0
INTEGER NOT NULL,
MONTH0
INTEGER NOT NULL,
YEAR0
INTEGER NOT NULL,
HOUR0
INTEGER NOT NULL,
MINUTE0 INTEGER NOT NULL);
CREATE TABLE NUMBERGOODSFORSELECT (
CODE_SEARCH
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL);
CREATE TABLE GOODSFORCUT (
CODE_CUT
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL);
CREATE TABLE SEARCHCODESALES (
CODE_SEANCE
INTEGER NOT NULL,
CODE_SALE
INTEGER NOT NULL);
CREATE TABLE SCANCODESFORSESSION2 (
SCAN_CODE VARCHAR(20) NOT NULL);
CREATE TABLE CHANGEDPRICES (
NUMBER_GOOD
INTEGER NOT NULL,
NEW_PRICE
DOUBLE PRECISION,
DATE_CHANGE
TIMESTAMP);
CREATE TABLE CHANGEDPRICESFORPERIOD (
NUMBER_GOOD INTEGER,
CODE_SEANCE
INTEGER NOT NULL);
CREATE TABLE RESUMEOFDAY (
NUMBER_GOOD
INTEGER NOT NULL,
FIRST_PRICE
DOUBLE PRECISION NOT NULL,
PRICE DOUBLE PRECISION NOT NULL,
SOLDBYPRICE
DOUBLE PRECISION NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
DATE_SALE
TIMESTAMP NOT NULL,
CODE_SEANCE
INTEGER NOT NULL,
HOUR0
INTEGER NOT NULL);
CREATE TABLE SALES0 (
CODE_SALE
INTEGER NOT NULL,
TYPE_SALE
INTEGER NOT NULL,
DATE_SALE
TIMESTAMP NOT NULL,
SUMMA DOUBLE PRECISION NOT NULL,
CASH
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE SALES0 ADD CONSTRAINT INTEG_219
PRIMARY KEY (CODE_SALE);
CREATE TABLE USERS (
CODE_SEANCE
INTEGER NOT NULL,
DATE_SEANCE
TIMESTAMP NOT NULL);
CREATE TABLE RETURNS20 (
CODE_RETURN
INTEGER NOT NULL,
CODE_SALE
INTEGER NOT NULL,
DATE_RETURN
TIMESTAMP NOT NULL,
SUMMA DOUBLE PRECISION NOT NULL,
CASH
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE RETURNS20 ADD CONSTRAINT INTEG_240
PRIMARY KEY (CODE_RETURN);
CREATE TABLE STRUCTURESALE0 (
PRIMARYKEY INTEGER NOT NULL,
CODE_SALE
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
FIRST_PRICE
DOUBLE PRECISION NOT NULL,
PRICE DOUBLE PRECISION NOT
NULL,
DISCOUNT
DOUBLE PRECISION NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL,
SOLDBYPRICE
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
INTEG_228 PRIMARY KEY (PRIMARYKEY);
CREATE TABLE STRUCTURERETURN20 (
PRIMARYKEY
INTEGER NOT NULL,
CODE_RETURN
INTEGER NOT NULL,
CODE_STRUCTURESALE
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
PRICE
DOUBLE PRECISION NOT NULL,
QUANTITY
DOUBLE PRECISION NOT NULL,
SUMMA
DOUBLE PRECISION NOT NULL);
/*
Primary Key */
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
INTEG_247 PRIMARY KEY (PRIMARYKEY);
CREATE TABLE SEARCHNUMBERGOODS (
CODE_SEANCE
INTEGER NOT NULL,
NUMBER_GOOD
INTEGER NOT NULL,
EXACTLY INTEGER NOT NULL);
CREATE TABLE SCANCODES3 (
NUMBER_GOOD
INTEGER NOT NULL,
SCAN_CODE
VARCHAR(20) NOT NULL);
CREATE TABLE GRAFIKWEEK (
CODE_SEANCE
INTEGER,
DAY_OF_WEEK INTEGER,
SUMMA
DOUBLE PRECISION,
PRIBIL
DOUBLE PRECISION);
CREATE TABLE GRAFIKHOURBUYERS (
CODE_SEANCE
INTEGER NOT NULL,
HOUR0
INTEGER NOT NULL,
NUM_BUYERS INTEGER NOT NULL);
CREATE TABLE GRAFIKPERCENTBUYERSPRIBIL (
CODE_SEANCE
INTEGER,
NUM_BUYERS
INTEGER NOT NULL,
PRIBIL
DOUBLE PRECISION NOT NULL);
CREATE TABLE PROGRAMUSERS (
CODE_USER
INTEGER NOT NULL,
NAME_USER
VARCHAR(80) NOT NULL,
PSSWD
VARCHAR(80),
RIGHTS
INTEGER NOT NULL);
ALTER TABLE GOODS ADD CONSTRAINT INTEG_92
FOREIGN KEY (CODE_UNIT)
REFERENCES TITLEUNITS(CODE_UNIT)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE PURCHASES ADD CONSTRAINT INTEG_93
FOREIGN KEY (CODE_BASE)
REFERENCES WHOLESALEBASES(CODE_BASE)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SESSIONS ADD CONSTRAINT INTEG_94
FOREIGN KEY (CODE_PURCHASE)
REFERENCES PURCHASES(CODE_PURCHASE)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
INTEG_95 FOREIGN KEY (CODE_SESSION)
REFERENCES SESSIONS(CODE_SESSION)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
INTEG_96 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STOREHOUSE ADD CONSTRAINT INTEG_97 FOREIGN
KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESALE ADD CONSTRAINT
INTEG_98 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESALE ADD CONSTRAINT
INTEG_99 FOREIGN KEY (CODE_SALE)
REFERENCES SALES(CODE_SALE)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SCANCODES ADD CONSTRAINT INTEG_100
FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
INTEG_101 FOREIGN KEY (CODE_SESSION)
REFERENCES SESSIONS(CODE_SESSION)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
INTEG_102 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
INTEG_103 FOREIGN KEY (PRIMARYKEY)
REFERENCES STRUCTURESESSION(PRIMARYKEY)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
INTEG_104 FOREIGN KEY (CODE_SESSION)
REFERENCES SESSIONS(CODE_SESSION)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
INTEG_105 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE RETURNS2 ADD CONSTRAINT INTEG_127
FOREIGN KEY (CODE_SALE)
REFERENCES SALES(CODE_SALE)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
INTEG_137 FOREIGN KEY (CODE_RETURN)
REFERENCES RETURNS2(CODE_RETURN)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
INTEG_139 FOREIGN KEY (CODE_STRUCTURESALE)
REFERENCES STRUCTURESALE(PRIMARYKEY)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
INTEG_140 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE NUMBERGOODSFORSELECT ADD CONSTRAINT
INTEG_200 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE GOODSFORCUT ADD CONSTRAINT
INTEG_166 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE CHANGEDPRICES ADD CONSTRAINT
INTEG_183 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE CHANGEDPRICESFORPERIOD ADD
CONSTRAINT INTEG_206 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE RESUMEOFDAY ADD CONSTRAINT
INTEG_213 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
INTEG_231 FOREIGN KEY (NUMBER_GOOD)
REFERENCES GOODS(NUMBER_GOOD)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
INTEG_235 FOREIGN KEY (CODE_SALE)
REFERENCES SALES0(CODE_SALE)
ON
UPDATE RESTRICT ON DELETE CASCADE;
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
INTEG_257 FOREIGN KEY (CODE_RETURN)
REFERENCES RETURNS20(CODE_RETURN)
ON
UPDATE RESTRICT ON DELETE CASCADE;
/* Check Constraints */
ALTER TABLE TITLEUNITS ADD CONSTRAINT C1_001
check (code_unit>=0);
ALTER TABLE TITLEUNITS ADD CONSTRAINT C1_002
check ((IsActive=0) or (IsActive=1));
ALTER TABLE TITLEUNITS ADD CONSTRAINT C1_003
check (name_unit<>'');
ALTER TABLE TITLEUNITS ADD CONSTRAINT C1_004
check ((IsMaterial=0) or (IsMaterial=1));
ALTER TABLE GOODS ADD CONSTRAINT C2_001 check
(number_good>=0);
ALTER TABLE GOODS ADD CONSTRAINT C2_002 check
((code_good>=10000) and (code_good<=999999));
ALTER TABLE GOODS ADD CONSTRAINT C2_003 check
((CodeIsActive=0) or (CodeIsActive=1));
ALTER TABLE GOODS ADD CONSTRAINT C2_004 check
(code_ancestor>=0);
ALTER TABLE GOODS ADD CONSTRAINT C2_005 check
(code_unit>=1);
ALTER TABLE WHOLESALEBASES ADD CONSTRAINT
C3_001 check (code_base>=0);
ALTER TABLE PURCHASES ADD CONSTRAINT C4_001
check (code_purchase>=0);
ALTER TABLE PURCHASES ADD CONSTRAINT C4_002
check (code_base>=1);
ALTER TABLE PURCHASES ADD CONSTRAINT C4_003
check (summa>=0.0);
ALTER TABLE SESSIONS ADD CONSTRAINT C5_001
check (code_session>=0);
ALTER TABLE SESSIONS ADD CONSTRAINT C5_002
check (code_purchase>=1);
ALTER TABLE SESSIONS ADD CONSTRAINT C5_003
check ((accepted=0) or (accepted=1));
ALTER TABLE SESSIONS ADD CONSTRAINT C5_004
check (summa>=0.0);
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
C6_001 check (primarykey>=0);
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
C6_002 check (code_session>=1);
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
C6_003 check (number_good>=1);
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
C6_005 check (first_price>=0.0);
ALTER TABLE STRUCTURESESSION ADD CONSTRAINT
C6_004 check (quantity>=0.0);
ALTER TABLE STOREHOUSE ADD CONSTRAINT C7_001
check (number_good>=0);
ALTER TABLE STOREHOUSE ADD CONSTRAINT C7_002
check (quantity>=-0.0001);
ALTER TABLE STOREHOUSE ADD CONSTRAINT C7_003
check (first_price>=0.0);
ALTER TABLE STOREHOUSE ADD CONSTRAINT C7_004
check (price>=0.0);
ALTER TABLE SALES ADD CONSTRAINT C8_001 check
(code_sale>=0);
ALTER TABLE SALES ADD CONSTRAINT C8_002 check
((type_sale=0) or (type_sale=1));
ALTER TABLE SALES ADD CONSTRAINT C8_003 check
(summa>=0.0);
ALTER TABLE SALES ADD CONSTRAINT C8_004 check
(cash>=0.0);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_001
check (primarykey>=0);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_002
check (code_sale>=0.0);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_003
check (number_good>=1);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_004
check (quantity>=0.0);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_005
check (first_price>=0.0);
ALTER TABLE STRUCTURESALE ADD CONSTRAINT C9_006
check (price>=0.0);
ALTER TABLE PATHS ADD CONSTRAINT C10_001 check
(code_path>=1);
ALTER TABLE PATHS ADD CONSTRAINT C10_002 check
(code_ancestor>=0);
ALTER TABLE NOTES ADD CONSTRAINT C11_001 check
(code_note>=0);
ALTER TABLE NOTES ADD CONSTRAINT C11_003 check
(KeyFromTable>=1);
ALTER TABLE NOTES ADD CONSTRAINT C11_002 check
((number_table>=1) and (number_table<=80));
ALTER TABLE ACTIONS ADD CONSTRAINT C12_001
check (code_action>=0);
ALTER TABLE SAVES ADD CONSTRAINT C13_001 check
(code_save>=0);
ALTER TABLE PROPERTIES ADD CONSTRAINT C14_001
check (code_property>=0);
ALTER TABLE SCANCODES ADD CONSTRAINT C15_001
check (number_good>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C16_001 check (code_session>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C16_002 check (number_good>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C16_003 check (primarykey>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C23_001 check (code_session>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C23_002 check (number_good>=1);
ALTER TABLE SCANCODESFORSESSION ADD CONSTRAINT
C23_003 check (primarykey>=1);
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
C17_001 check (code_session>=1);
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
C17_002 check (number_good>=1);
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
C17_003 check (old_price>=0.0);
ALTER TABLE SESSIONSCLOSED ADD CONSTRAINT
C17_004 check (new_price>=0.0);
ALTER TABLE RETURNS2 ADD CONSTRAINT C18_001
check (code_return>=1);
ALTER TABLE RETURNS2 ADD CONSTRAINT C18_002
check (code_sale>=1);
ALTER TABLE RETURNS2 ADD CONSTRAINT C18_003
check (summa>=0.0);
ALTER TABLE RETURNS2 ADD CONSTRAINT C18_004
check (cash>=0.0);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_001 check (primarykey>=1);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_002 check (code_return>=1);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_003 check (code_StructureSale>=1);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_004 check (number_good>=1);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_005 check (price>=0.0);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_006 check (quantity>=0.0);
ALTER TABLE STRUCTURERETURN2 ADD CONSTRAINT
C19_007 check (summa>=0.0);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_001 check (number_good>=1);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_002 check (name_good<>'');
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_003 check (quantity>=0.0);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_004 check (remainder>=-0.0001);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_005 check ((IsMaterial=0) or (IsMaterial=1));
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_006 check (code_unit>=1);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT C20_007
check (name_unit<>'');
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_008 check (price>=0.0);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_009 check (CodeStructureSale>=1);
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_010 check ((day0>=1) and (day0<=31));
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_011 check ((month0>=1) and (month0<=12));
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_012 check ((year0>=2000) and (year0<=2020));
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_013 check ((hour0>=0) and (hour0<=23));
ALTER TABLE GOODSFORRETURN ADD CONSTRAINT
C20_014 check ((minute0>=0) and (minute0<=59));
ALTER TABLE NUMBERGOODSFORSELECT ADD CONSTRAINT
C24_001 check (code_search>=1);
ALTER TABLE NUMBERGOODSFORSELECT ADD CONSTRAINT
C24_002 check (number_good>=1);
ALTER TABLE GOODSFORCUT ADD CONSTRAINT C21_001
check (code_cut>=1);
ALTER TABLE GOODSFORCUT ADD CONSTRAINT C21_002
check (number_good>=1);
ALTER TABLE GOODSFORCUT ADD CONSTRAINT C21_004
check (code_cut>=1);
ALTER TABLE GOODSFORCUT ADD CONSTRAINT C21_005
check (number_good>=1);
ALTER TABLE SEARCHCODESALES ADD CONSTRAINT
C32_001 check (code_seance>=1);
ALTER TABLE SEARCHCODESALES ADD CONSTRAINT
C32_002 check (code_sale>=1);
ALTER TABLE CHANGEDPRICES ADD CONSTRAINT
C22_001 check (number_good>=1);
ALTER TABLE CHANGEDPRICES ADD CONSTRAINT
C22_002 check (new_price>=0.0);
ALTER TABLE CHANGEDPRICESFORPERIOD ADD
CONSTRAINT C26_001 check(number_good>=1);
ALTER TABLE RESUMEOFDAY ADD CONSTRAINT C27_001
check (number_good>=1);
ALTER TABLE RESUMEOFDAY ADD CONSTRAINT C27_002
check (first_price>=0.0);
ALTER TABLE RESUMEOFDAY ADD CONSTRAINT C27_003
check (price>=0.0);
ALTER TABLE RESUMEOFDAY ADD CONSTRAINT C27_004
check (soldbyprice>=0.0);
ALTER TABLE SALES0 ADD CONSTRAINT C28_001 check
(code_sale>=0);
ALTER TABLE SALES0 ADD CONSTRAINT C28_002 check
((type_sale=0) or (type_sale=1));
ALTER TABLE SALES0 ADD CONSTRAINT C28_003 check
(summa>=0.0);
ALTER TABLE SALES0 ADD CONSTRAINT C28_004 check
(cash>=0.0);
ALTER TABLE RETURNS20 ADD CONSTRAINT C30_001
check (code_return>=1);
ALTER TABLE RETURNS20 ADD CONSTRAINT C30_002
check (code_sale>=1);
ALTER TABLE RETURNS20 ADD CONSTRAINT C30_003
check (summa>=0.0);
ALTER TABLE RETURNS20 ADD CONSTRAINT C30_004
check (cash>=0.0);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_001 check (primarykey>=0);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_002 check (code_sale>=0.0);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_003 check (number_good>=1);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_004 check (quantity>=0.0);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_005 check (first_price>=0.0);
ALTER TABLE STRUCTURESALE0 ADD CONSTRAINT
C29_006 check (price>=0.0);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_001 check (primarykey>=1);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_002 check (code_return>=1);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_003 check (code_StructureSale>=1);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_004 check (number_good>=1);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_005 check (price>=0.0);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_006 check (quantity>=0.0);
ALTER TABLE STRUCTURERETURN20 ADD CONSTRAINT
C31_007 check (summa>=0.0);
ALTER TABLE SEARCHNUMBERGOODS ADD CONSTRAINT
C33_001 check (code_seance>=1);
ALTER TABLE SEARCHNUMBERGOODS ADD CONSTRAINT
C33_002 check (number_good>=1);
/* Unique Constraints */
ALTER TABLE WHOLESALEBASES ADD CONSTRAINT
C3_002 UNIQUE (NAME_BASE);
ALTER TABLE PATHS ADD CONSTRAINT C10_003 UNIQUE
(CODE_ANCESTOR,NAME_PATH);
ALTER TABLE NOTES ADD CONSTRAINT C11_004 UNIQUE
(NUMBER_TABLE,KEYFROMTABLE);
ALTER TABLE GOODSFORCUT ADD CONSTRAINT C21_003
UNIQUE (CODE_CUT,NUMBER_GOOD);
SET
TERM ^ ;
CREATE PROCEDURE GETDATE
RETURNS (
DAY0 INTEGER,
MONTH0
INTEGER,
YEAR0 INTEGER,
HOUR0 INTEGER,
MINUTE0
INTEGER)
AS
declare variable date0 timestamp;
begin
date0=current_timestamp;
delete from
date1;
insert into
date1(date0) values (:date0);
select
extract(day from date0) from date1 into day0;
select
extract(month from date0) from date1 into month0;
select
extract(year from date0) from date1 into year0;
select
extract(hour from date0) from date1 into hour0;
select
extract(minute from date0) from date1 into minute0;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE LEN(
STR
VARCHAR(1000) )
RETURNS (
LEN INTEGER)
AS
declare variable pat varchar(1000);
begin
len = null;
if (str is
null) then exit;
pat = '';
len = 0;
while (not
str like pat) do begin
pat = pat
|| '_';
len = len
+ 1;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE THISSYMBOLISDIGIT(
S
VARCHAR(1000),
NUM INTEGER,
LEN INTEGER )
RETURNS (
ANSWER
INTEGER)
AS
declare variable vrem varchar(1000);
declare
variable len_vrem integer;
declare
variable cycle integer;
declare
variable i integer;
begin
answer=0;
cycle=0;
while
(cycle<=9) do begin
vrem='';
i=1;
while
(i<num) do begin
vrem=vrem||'_';
i=i+1;
end
vrem =
vrem||cycle;
i=i+1;
while
(i<=len) do begin
vrem=vrem||'_';
i=i+1;
end
if (s like
vrem) then begin answer=1; exit; end
cycle=cycle+1;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE STRINGHASONLYDIGITS(
S
VARCHAR(1000) )
RETURNS (
ANSWER
INTEGER)
AS
declare variable len integer;
declare
variable i integer;
declare
variable vrem integer;
begin
answer=1;
execute
procedure len(s) returning_values len;
if (len=0)
then exit;
i=1;
while
(i<=len) do begin
execute
procedure ThisSymbolIsDigit(s, i, len) returning_values(vrem);
if
(vrem=0) then begin answer=0; exit; end
i=i+1;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE TRUNC(
CHISLO DOUBLE
PRECISION )
RETURNS (
CHISLO2 DOUBLE
PRECISION)
AS
declare variable milliards integer;
declare
variable x integer;
begin
chislo2=0;
if
(chislo<1e9) then begin
x=chislo-0.49999999999999;
chislo2=x;
end
else if
(chislo<1e18) then begin
milliards=(chislo/1e9)-0.5;
chislo=chislo-1e9*milliards;
x=chislo-0.49999999999999;
chislo2=1e9*milliards+x;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE CHISLOISFLOAT(
CHISLO DOUBLE
PRECISION )
RETURNS (
ANSWER
INTEGER)
AS
declare variable trunc_chislo double precision;
declare
variable razn double precision;
begin
if
(chislo<0.0) then chislo=-chislo;
execute
procedure trunc(chislo) returning_values(trunc_chislo);
razn=chislo-trunc_chislo;
if
(((razn>=0.000) and (razn<=0.0001)) or ((razn>=0.9999) and
(razn<=1.0000))) then answer=0;
else
answer=1;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDTITLEUNIT(
NAME_UNIT
VARCHAR(20),
ISMATERIAL
INTEGER )
RETURNS (
NEW_CODE_UNIT
INTEGER,
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this name_unit already exists
error=2 --
name_unit cannot be empty
error=3 --
IsMaterial must be 0 or 1
*/
begin
error=0;
if
(name_unit='') then begin
error=2;
exit;
end
if
((IsMaterial<>0) and (IsMaterial<>1)) then begin error=3; exit; end
select
count(*) from TitleUnits
where
name_unit=:name_unit and IsActive=1 into vrem;
if
(vrem<>0) then error=1;
else begin
new_code_unit = gen_id(genTitleUnits, 1);
insert
into TitleUnits values (:new_code_unit, :name_unit, 1, :IsMaterial);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE ROUND(
CHISLO DOUBLE
PRECISION )
RETURNS (
CHISLO2 DOUBLE
PRECISION)
AS
begin
chislo=chislo+0.5;
execute
procedure trunc(chislo) returning_values(chislo2);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDOWHOLEPRICE(
P1 DOUBLE
PRECISION )
RETURNS (
P2 DOUBLE
PRECISION)
AS
begin
p1=p1+0.001;
if
(p1<=1.00) then begin
p1=100.0*p1;
execute
procedure round(p1) returning_values(p2);
p2=p2/100.0;
end
else if
(p1<=5.00) then begin
p1=10.0*(p1+0.029);
execute
procedure round(p1) returning_values(p2);
p2=p2/10.0;
end
else if
(p1<=20.00) then begin
p1=2.0*(p1+0.145);
execute
procedure round(p1) returning_values(p2);
p2=p2/2.0;
end
else begin
p1=1.0*(p1+0.29);
execute
procedure round(p1) returning_values(p2);
p2=p2/1.0;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCRENAMEPATH(
CODE_PATH
INTEGER,
NEW_NAME_PATH
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_ancestor integer;
/*
error=1 --
name_path must not be empty
error=2 --
this code_path is not exist
error=3 --
this name_path is already exists
error=4 --
length(name_path) must more than 3
*/
begin
error=0;
if
(new_name_path='') then begin error=1; exit; end
if
(LengthString(new_name_path)<3) then begin error=4; exit; end
select
count(*) from paths where code_path=:code_path into vrem;
if (vrem=0)
then begin error=2; exit; end
select
code_ancestor from paths where code_path=:code_path into code_ancestor;
select
count(*) from paths
where
(code_ancestor=:code_ancestor) and (code_path<>:code_path) and
(name_path=:new_name_path) into vrem;
if
(vrem<>0) then begin error=3; exit; end
update paths
set name_path=:new_name_path where code_path=:code_path;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDWHOLESALEBASE(
NAME_BASE
VARCHAR(80),
ADDRESS
VARCHAR(80),
FIOMAN
VARCHAR(80),
PHONEMAN
VARCHAR(40),
PHONEBK
VARCHAR(40),
NOTE
VARCHAR(80) )
RETURNS (
NEW_CODE_BASE
INTEGER,
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable new_code_note integer;
/*
error=1 --
name_base is empty
error=2 --
address is empty
error=3 --
FIOman is empty
error=4 --
PhoneMan is empty
error=5 --
PhoneBK is empty
error=6 --
this name_base already exists
*/
begin
error=0;
if
(name_base='') then begin error=1; exit; end
if
(address='') then begin error=2; exit; end
if
(FIOman='') then begin error=3; exit; end
if
(PhoneMan='') then begin error=4; exit; end
if
(PhoneBK='') then begin error=5; exit; end
select
count(*) from WholesaleBases where name_base=:name_base into vrem;
if
(vrem<>0) then begin error=6; exit; end
new_code_base=gen_id(genWholesaleBases, 1);
insert into
WholesaleBases
values
(:new_code_base, :name_base, :address, :FIOman, :PhoneMan, :PhoneBK);
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values(:new_code_note, 3, :new_code_base, :note);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELWHOLESALEBASE(
CODE_BASE
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this wholesale base is not exist
error=2 --
this base use in table purchases
*/
begin
error=0;
select
count(*) from WholesaleBases where code_base=:code_base into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from purchases where code_base=:code_base into vrem;
if
(vrem<>0) then begin error=2; exit; end
delete from
WholesaleBases where code_base=:code_base;
delete from
notes where number_table=3 and KeyFromTable=:code_base;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEWHOLESALEBASE(
CODE_BASE
INTEGER,
NAME_BASE
VARCHAR(80),
ADDRESS VARCHAR(80),
FIOMAN
VARCHAR(80),
PHONEMAN
VARCHAR(40),
PHONEBK
VARCHAR(40),
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable new_code_note integer;
/*
error=1 --
name_base is empty
error=2 --
address is empty
error=3 --
FIOman is empty
error=4 --
PhoneMan is empty
error=5 --
PhoneBK is empty
error=6 --
this name_base already exists
error=7 --
this code_base is not exist
*/
begin
error=0;
if
(name_base='') then begin error=1; exit; end
if
(address='') then begin error=2; exit; end
if
(FIOman='') then begin error=3; exit; end
if
(PhoneMan='') then begin error=4; exit; end
if
(PhoneBK='') then begin error=5; exit; end
select
count(*) from WholesaleBases where code_base=:code_base into vrem;
if (vrem=0)
then begin error=7; exit; end
select
count(*) from WholesaleBases
where
(code_base<>:code_base) and (name_base=:name_base) into vrem;
if
(vrem<>0) then begin error=6; exit; end
/*write data
to database*/
update
WholesaleBases set
name_base=:name_base, address=:address,
FIOman=:FIOman, PhoneMan=:PhoneMan, PhoneBK=:PhoneBK
where
code_base=:code_base;
/*write
note*/
select
count(*) from notes
where
(number_table=3) and (KeyFromTable=:code_base) into vrem;
if (vrem=0)
then begin
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values (:new_code_note, 3, :code_base, :note);
end
end
else begin
if
(note<>'') then begin
update
notes set text=:note where (number_table=3) and (KeyFromTable=:code_base);
end
else begin
delete
from notes where (number_table=3) and (KeyFromTable=:code_base);
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGECODEGOOD(
OLD_CODE_GOOD
INTEGER,
NEW_CODE_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable number_good integer;
/*
error=1 --
this old_code_good is not exist
error=2 --
this old_code_good exist more than once
error=3 --
this new_code_good already exists
error=4 --
this good already exists on StoreHouse. Impossible to change code.
*/
begin
error=0;
select
count(*) from goods
where
code_good=:old_code_good and CodeIsActive=1
into vrem;
if (vrem=0)
then begin error=1; exit; end
if
(vrem>1) then begin error=2; exit; end
select
number_good from goods
where
code_good=:old_code_good and CodeIsActive=1
into
:number_good;
select
count(*) from goods where
code_good=:new_code_good and CodeIsActive=1
into vrem;
if
(vrem<>0) then begin error=3; exit; end
select
count(*) from StoreHouse where number_good=:number_good into vrem;
if
(vrem<>0) then begin error=4; exit; end
update goods
set code_good=:new_code_good where number_good=:number_good;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEPURCHASENOTE(
CODE_PURCHASE
INTEGER,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable new_code_note integer;
/*
error=1 --
this code_purchase is not exist
*/
begin
error=0;
select
count(*) from purchases where code_purchase=:code_purchase into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from notes
where (number_table=4)
and (KeyFromTable=:code_purchase) into vrem;
if (vrem=0)
then begin
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values(:new_code_note, 4, :code_purchase, :note);
end
end
else begin
if
(note='') then begin
delete
from notes where number_table=4 and KeyFromTable=:code_purchase;
end
else begin
update
notes set text=:note where number_table=4 and KeyFromTable=:code_purchase;
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDSESSION(
CODE_PURCHASE
INTEGER,
ADDITION
DOUBLE PRECISION,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable new_code_session integer;
declare
variable new_code_note integer;
declare
variable vrem integer;
declare
variable date0 timestamp;
/*
error=1 --
this code_purchase is not exist
error=2 --
addition bust between -100% and 10000%
*/
begin
error=0;
select
count(*) from purchases where code_purchase=:code_purchase into vrem;
if (vrem=0)
then begin error=1; exit; end
if
((addition<-100.0) or (addition>10000.0)) then begin error=2; exit; end
date0 =
current_timestamp;
new_code_session=gen_id(genSessions, 1);
insert into
sessions values (:new_code_session, :code_purchase, 0, :addition,
:date0,
:date0, 0.0);
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values (:new_code_note, 5, :new_code_session, :note);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGESESSIONNOTE(
CODE_SESSION
INTEGER,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable new_code_note integer;
/*
error=1 --
this code_session is not exist
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from notes where (number_table=5) and (KeyFromTable=:code_session)
into vrem;
if (vrem=0)
then begin
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values(:new_code_note, 5, :code_session, :note);
end
end
else begin
if
(note='') then begin
delete
from notes where number_table=5 and KeyFromTable=:code_session;
end
else begin
update
notes set text=:note where number_table=5 and KeyFromtable=:code_session;
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEADDITIONOFSESSION(
CODE_SESSION INTEGER,
ADDITION
DOUBLE PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this code_session is not exist
error=2 --
addition bust between -100% and 10000%
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
if
((addition<-100.0) or (addition>10000.0)) then begin error=2; exit; end
update
sessions set addition=:addition where code_session=:code_session;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDPATH(
CODE_ANCESTOR
INTEGER,
NAME_PATH
VARCHAR(80) )
RETURNS (
ERROR INTEGER,
NEW_CODE_PATH
INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
name_path is empty
error=2 --
this code_ancestor is not exist
error=3 --
this name_path already exists
*/
begin
error=0;
if
(name_path='') then begin error=1; exit; end
if
(code_ancestor<>0) then begin
select
count(*) from paths where code_path=:code_ancestor into vrem;
if
(vrem=0) then begin error=2; exit; end
end
select
count(*) from paths
where
code_ancestor=:code_ancestor and name_path=:name_path
into vrem;
if
(vrem<>0) then begin error=3; exit; end
new_code_path=gen_id(genPaths, 1);
insert into
paths values(:new_code_path, :code_ancestor, :name_path);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDSCANCODE(
SCAN_CODE
VARCHAR(20) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable scan_code0 varchar(20);
declare variable
scan_codes varchar(255);
/*
error=2 --
length of scan_code must be 13
error=3 --
scan_code must have only digits
*/
begin
error=0;
/*checkings*/
if
(LengthString(scan_code)<>13) then begin error=2; exit; end
execute
procedure StringHasOnlyDigits(scan_code) returning_values(vrem);
if (vrem=0)
then begin error=3; exit; end
/*write data
to database*/
insert into
ScanCodes2 values (:scan_code);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDOFULLNAMEPATHFROMCODEPATH0(
CODE_PATH
INTEGER,
NAME_PATH0
VARCHAR(1000) )
RETURNS (
NAME_PATH
VARCHAR(1000))
AS
declare variable code_ancestor integer;
begin
select
name_path from paths where code_path=:code_path into :name_path;
if
(name_path0<>'') then name_path = name_path||'\'||name_path0;
select
code_ancestor from paths where code_path=:code_path into :code_ancestor;
if
(code_ancestor<>0) then begin
execute
procedure procDoFullNamePathFromCodePath0(code_ancestor, name_path)
returning_values(name_path);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDOFULLNAMEPATHFROMCODEPATH(
CODE_PATH
INTEGER )
RETURNS (
NAME_PATH
VARCHAR(1000),
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this code_path is not exist
*/
begin
error=0;
if
(code_path=0) then begin name_path=''; exit; end
select
count(*) from paths where code_path=:code_path into vrem;
if (vrem=0)
then begin error=1; exit; end
execute
procedure procDoFullNamePathFromCodePath0(code_path, '')
returning_values(name_path);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELGOOD(
NUMBER_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this number_good is not exist
error=2 --
this good exist on StoreHouse
error=3 --
this good exist on unaccepted session
*/
begin
error=0;
/*checking
that good exists*/
select
count(*) from goods where number_good=:number_good and CodeIsActive=1 into
vrem;
if (vrem=0)
then begin error=1; exit; end
/*checking
that good(number_good) is not exist on StoreHouse*/
select
count(*) from StoreHouse where number_good=:number_good into vrem;
if
(vrem<>0) then begin error=2; exit; end
/*checking
that good(number_good) is not exist on unaccepted session*/
select
count(*) from sessions join StructureSession
on
sessions.code_session=StructureSession.code_session
where
sessions.accepted=0 and StructureSession.number_good=:number_good
into vrem;
if
(vrem<>0) then begin error=3; exit; end
/*other actions*/
update goods
set CodeIsActive=0, scan_codes='' where number_good=:number_good;
delete from
ScanCodes where number_good=:number_good;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDGOOD(
CODE_GOOD
INTEGER,
ART
VARCHAR(20),
CODE_ANCESTOR
INTEGER,
NAME_GOOD
VARCHAR(80),
CODE_UNIT
INTEGER )
RETURNS (
ERROR INTEGER,
NEW_NUMBER_GOOD INTEGER)
AS
declare variable vrem integer;
declare
variable scan_code varchar(20);
/*
error=1 --
this code_good already exists
error=2 --
articul must not be empty
error=3 --
incorrect code_ancestor (path not exists)
error=4 --
name_good must not be empty
error=5 --
this code_unit is not exist
error=6 --
good with this name_good already exists
error=7 --
code_good must not be less than 10000
error=8 --
the good cannot have more than 12 sacn_codes
error=9 --
length(name_good) must not be less than 3
*/
begin
error=0;
select
count(*) from goods where CodeIsActive=1 and code_good=:code_good into vrem;
if
(vrem<>0) then begin error=1; exit; end
if (art='')
then begin error=2; exit; end
select
count(*) from paths where code_path=:code_ancestor into vrem;
if (vrem=0)
then begin error=3; exit; end
if
(name_good='') then begin error=4; exit; end
if (LengthString(name_good)<3)
then begin error=9; exit; end
select
count(*) from TitleUnits where code_unit=:code_unit into vrem;
if (vrem=0)
then begin error=5; exit; end
select
count(*) from goods
where
code_ancestor=:code_ancestor and name_good=:name_good and CodeIsActive=1
into vrem;
if
(vrem<>0) then begin error=6; exit; end
if
(code_good<10000) then begin error=7; exit; end
/*write data
to database*/
new_number_good=gen_id(genGoods, 1);
insert into
goods
values(:new_number_good, :code_good, 1, :art, :code_ancestor,
:name_good, :code_unit,'');
vrem=0;
for select
scan_code from ScanCodes2
into
:scan_code as cursor cur1 do begin
vrem=vrem+1;
if
(vrem=13) then begin error=1/0; when any do begin error=8; exit; end end
insert
into ScanCodes
values(:new_number_good, :scan_code);
update
goods
set
scan_codes=scan_codes||:scan_code||' '
where
number_good=:new_number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE CLEARDATABASE
AS
declare variable vrem integer;
begin
vrem=gen_id(genActions, 0); vrem=gen_id(genActions, -vrem);
vrem=gen_id(genGoods, 0); vrem=gen_id(genGoods, -vrem);
vrem=gen_id(genGoodsForCut, 0); vrem=gen_id(genGoodsForCut, -vrem);
vrem=gen_id(genNotes, 0); vrem=gen_id(genNotes, -vrem);
vrem=gen_id(genNumberGoodsForSelect, 0);
vrem=gen_id(genNumberGoodsForSelect, -vrem);
vrem=gen_id(genPaths, 0); vrem=gen_id(genPaths, -vrem);
vrem=gen_id(genPurchases, 0); vrem=gen_id(genPurchases, -vrem);
vrem=gen_id(genReturns, 0);
vrem=gen_id(genReturns, -vrem);
vrem=gen_id(genSales, 0); vrem=gen_id(genSales, -vrem);
vrem=gen_id(genSaves, 0); vrem=gen_id(genSaves, -vrem);
vrem=gen_id(genSearchCodeSaleNumberGood, 0);
vrem=gen_id(genSearchCodeSaleNumberGood, -vrem);
vrem=gen_id(genSessions, 0); vrem=gen_id(genSessions, -vrem);
vrem=gen_id(genStructureReturn, 0); vrem=gen_id(genStructureReturn,
-vrem);
vrem=gen_id(genStructureSale, 0); vrem=gen_id(genStructureSale, -vrem);
vrem=gen_id(genStructureSession, 0); vrem=gen_id(genStructureSession,
-vrem);
vrem=gen_id(genTitleUnits, 0); vrem=gen_id(genTitleUnits, -vrem);
vrem=gen_id(genWholesaleBases, 0); vrem=gen_id(genWholesaleBases,
-vrem);
delete from
actions;
delete from
ChangedPrices;
delete from
ChangedPricesForPeriod;
delete from
date1;
delete from
goods;
delete from
GoodsForCut;
delete from
GoodsForReturn;
delete from
notes;
delete from
NumberGoodsForSelect;
delete from
paths;
delete from
properties;
delete from
purchases;
delete from
ResumeOfDay;
delete from
returns2;
delete from
returns20;
delete from
sales;
delete from
sales0;
delete from
saves;
delete from
ScanCodes;
delete from
ScanCodes2;
delete from
ScanCodesForSession;
delete from
ScanCodesForSession2;
delete from
SearchCodeSales;
delete from
SearchNumberGoods;
delete from
sessions;
delete from
SessionsClosed;
delete from
StoreHouse;
delete from
StructureReturn2;
delete from
StructureReturn20;
delete from
StructureSale;
delete from
StructureSale0;
delete from
StructureSession;
delete from
TitleUnits;
delete from
users;
delete from
WholesaleBases;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELETEEMPTYSESSION(
CODE_SESSION
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this code_session is not exist
error=2 --
impossible delete session which not empty
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from StructureSession where code_session=:code_session into vrem;
if
(vrem<>0) then begin error=2; exit; end
delete from
sessions where code_session=:code_session;
delete from
notes where number_table=5 and KeyFromTable=:code_session;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELUSELESSNOTES
AS
declare variable number_table integer;
declare
variable KeyFromTable integer;
declare
variable vrem integer;
begin
/*WholesaleBases purchases sessions sales returns2*/
for select
number_table, KeyFromTable from notes
into
:number_table, :KeyFromTable as cursor cur1 do begin
if
(number_table=3) then begin /*WholesaleBases*/
select
count(*) from WholesaleBases where code_base=:KeyFromTable
into
vrem;
end
if
(number_table=4) then begin /*purchases*/
select
count(*) from purchases where code_purchase=:KeyFromTable
into
vrem;
end
if (number_table=5)
then begin /*sessions*/
select
count(*) from sessions where code_session=:KeyFromTable
into
vrem;
end
if
(number_table=8) then begin /*sales*/
select
count(*) from sales where code_sale=:KeyFromTable
into vrem;
end
if
(number_table=18) then begin /*returns2*/
select
count(*) from returns2 where code_return=:KeyFromTable
into
vrem;
end
if
(vrem=0) then begin
delete
from notes
where
number_table=:number_table and KeyFromTable=:KeyFromTable;
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCMINNEWCODERETURN(
CODE_SALE
INTEGER )
RETURNS (
CODE_RETURN
INTEGER)
AS
declare variable date_return timestamp;
begin
code_return=gen_id(genReturns,
1);
date_return=current_timestamp;
insert into
returns20 values(:code_return, :code_sale, :date_return, 0.0, 0.0);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCNEWCODENUMBERGOODSFORSELECT
RETURNS (
CODE_SEARCH
INTEGER)
AS
begin
code_search=gen_id(genNumberGoodsForSelect, 1);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDGOODTONGFORSELECT(
CODE_SEARCH
INTEGER,
NUMBER_GOOD
INTEGER )
AS
begin
insert into
NumberGoodsForSelect values(:code_search, :number_good);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE SUPERKA
AS
declare variable number_good integer;
declare
variable first_price double precision;
declare
variable price double precision;
declare
variable addition double precision;
begin
delete from StoreHouse;
update
sessions set accepted=0 where code_session=1;
for select
number_good, first_price from StructureSession
where
code_session=1
into
:number_good, :price as cursor cur1 do begin
if
(price<>0.0) then begin
first_price=0.625*price;
first_price=100.0*first_price;
execute
procedure round(first_price)
returning_values(first_price);
first_price=0.01*first_price;
addition=100.0*(price-first_price)/first_price;
end
else begin
first_price=0.0;
addition=0.0;
end
update
StructureSession
set
first_price=:first_price, addition=:addition
where
code_session=1 and number_good=:number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCNEWNAMEPATH(
CODE_ANCESTOR
INTEGER )
RETURNS (
ERROR INTEGER,
NEW_NAME_PATH
VARCHAR(80))
AS
declare variable vrem integer;
declare
variable base_name_path varchar(80);
declare
variable number integer;
/*
error=1 --
this code_ancestor is not exist
*/
begin
error=0;
select
count(*) from paths where code_path=:code_ancestor into vrem;
if
(code_ancestor=0) then vrem=1;
if (vrem=0)
then begin error=1; exit; end
base_name_path='Íîâàÿ
ïàïêà';
select count(*)
from paths
where
name_path=:base_name_path and code_ancestor=:code_ancestor
into vrem;
new_name_path=base_name_path;
number=0;
while
(vrem<>0) do begin
number=number+1;
new_name_path=base_name_path||' ('||number||')';
select count(*) from paths
where
name_path=:new_name_path and code_ancestor=:code_ancestor
into vrem;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCREHSUMMSOFSESSANDPURCH
AS
declare variable vrem integer;
declare
variable code_purchase integer;
declare
variable code_session integer;
declare
variable summa0 double precision;
begin
for select
code_purchase from purchases
into
:code_purchase as cursor cur1 do begin
for select
code_session from sessions
where
code_purchase=:code_purchase
into
:code_session as cursor cur2 do begin
select
count(*), sum(quantity*first_price) from StructureSession
where
code_session=:code_session
into
vrem, summa0;
if
(vrem=0) then summa0=0.0;
update
sessions set summa=:summa0 where code_session=:code_session;
end
select
count(*), sum(summa) from sessions
where
code_purchase=:code_purchase
into vrem,
summa0;
if
(vrem=0) then summa0=0.0;
update purchases
set summa=:summa0 where code_purchase=:code_purchase;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE SUPERKA2
AS
declare variable number_good integer;
declare
variable scan_code varchar(20);
declare
variable vrem integer;
begin
for select
number_good, scan_code from ScanCodes
into
:number_good, :scan_code as cursor cur1 do begin
select
count(*) from ScanCodes3 where number_good=:number_good and
scan_code=:scan_code
into vrem;
if
(vrem=0) then begin
insert into ScanCodes3 values(:number_good,
:scan_code);
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCENDRETURN(
CODE_RETURN
INTEGER,
COMMONSUMMA
DOUBLE PRECISION,
CASH DOUBLE
PRECISION,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_sale integer;
declare
variable CommonSumma2 double precision;
declare
variable diff double precision;
declare
variable date_return timestamp;
declare
variable new_code_note integer;
/*variables
for main cycle (cursor cur1)*/
declare
variable number_good integer;
declare
variable code_StructureSale integer;
declare
variable first_price double precision;
declare
variable price double precision;
declare
variable quantity double precision;
declare
variable summa double precision;
/*variables
for forming new first_price and quantity on StoreHouse*/
declare
variable first_price2 double precision;
declare
variable quantity2 double precision;
declare variable
sold2 double precision;
declare
variable first_price3 double precision;
declare
variable quantity3 double precision;
/*other
variables*/
declare
variable x1 double precision;
declare
variable x2 double precision;
declare
variable x3 double precision;
declare
variable x4 double precision;
declare
variable x5 double precision;
declare
variable x6 double precision;
declare
variable x7 double precision;
/*
error=1 --
this code_return is not exist
error=2 --
the same goods must not be exist in StructureReturn
error=3 --
the summa incorrect calculated in program
error=4 --
error StoreHouse: sold<quantity...
error=5 --
cash<CommonSumma
*/
begin
error=0;
select
count(*) from returns20 where code_return=:code_return into vrem;
if (vrem=0)
then begin error=1; exit; end
select
code_sale from returns20 where code_return=:code_return into code_sale;
if
(cash+0.001<CommonSumma) then begin error=5; exit; end
CommonSumma2=0.0;
for select
StructureSale.number_good,
StructureReturn20.code_StructureSale,
StructureSale.first_price,
StructureReturn20.price,
StructureReturn20.quantity,
StructureReturn20.summa
from
StructureReturn20 join StructureSale
on
StructureReturn20.code_StructureSale=StructureSale.primarykey
where
StructureReturn20.code_return=:code_return
into
number_good, code_StructureSale, first_price, price, quantity, summa
as cursor
cur1 do begin
select
count(*) from StructureReturn20
where
code_return=:code_return and code_StructureSale=:code_StructureSale
into vrem;
if
(vrem>1) then begin error=1/0; when any do begin error=2; exit; end end
CommonSumma2=CommonSumma2+summa;
select
first_price, quantity, sold from StoreHouse
where
number_good=:number_good
into
first_price2, quantity2, sold2;
if
(sold2+0.0001<quantity) then begin
error=1/0; when any do begin error=4; exit; end
end
if
(quantity<0.0) then quantity=0.0;
if (quantity2<0.0)
then quantity2=0.0;
quantity3=quantity+quantity2;
if
(quantity3<>0.0) then
first_price3=(first_price*quantity+first_price2*quantity2)/quantity3;
else
first_price=0.0;
update
StoreHouse
set
quantity=:quantity3, sold=sold-:quantity, first_price=:first_price3
where
number_good=:number_good;
end
diff=abs(CommonSumma-CommonSumma2);
if
(diff>0.001) then begin error=1/0; when any do begin error=3; exit; end end
select
date_return from returns20 where code_return=:code_return into date_return;
/*write data
to main tables*/
select
count(*) from StructureReturn20 where code_return=:code_return into vrem;
if
((vrem<>0) or (note<>'')) then begin
insert
into returns2
values(:code_return, :code_sale, :date_return, :CommonSumma, :cash);
for select
primarykey, code_return, code_StructureSale, number_good,
price,
quantity, summa from StructureReturn20
where
code_return=:code_return
into x1,
x2, x3, x4, x5, x6, x7
do begin
insert
into StructureReturn2 values(:x1, :x2, :x3, :x4, :x5, :x6, :x7);
end
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes (code_note, number_table, KeyFromTable, text) values
(:new_code_note, 18, :code_return, :note);
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCALLOWADDSCANCODE(
CODE_SESSION
INTEGER,
NUMBER_GOOD
INTEGER,
SCAN_CODE
VARCHAR(20) )
RETURNS (
W1 INTEGER,
W2 INTEGER)
AS
declare variable vrem integer;
/*
w1 -- this
scan_code exist in table ScanCodes for goods
w2 -- this
scan_code exist in table ScanCodesForSession
*/
begin
w1=0; w2=0;
/*warning1*/
select
count(*) from goods join ScanCodes
on goods.number_good=ScanCodes.number_good
where
number_good<>:number_good and CodeIsActive=1 and scan_code=:scan_code
into vrem;
if
(vrem<>0) then w1=1;
/*warning2*/
select
count(*) from StructureSession join ScanCodesForSession
on
StructureSession.primarykey=ScanCodesForSession.primarykey join sessions
on
StructureSession.code_session=sessions.code_session join goods
on
StructureSession.number_good=goods.number_good
where
goods.CodeIsActive=1 and sessions.accepted=0 and
(StructureSession.code_session<>:code_session or
StructureSession.number_good<>:number_good) and
ScanCodesForSession.scan_code=:scan_code into vrem;
if
(vrem<>0) then vrem=1;
w2=vrem;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE SUPERKA3
AS
declare variable number_good integer;
declare
variable scan_code varchar(20);
declare
variable vrem integer;
begin
delete from
ScanCodes;
for select
number_good, scan_code from ScanCodes3
into
:number_good, :scan_code as cursor cur1 do begin
insert
into ScanCodes values(:number_good, :scan_code);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCMINNEWCODESALE
RETURNS (
CODE_SALE
INTEGER)
AS
declare variable date0 timestamp;
begin
code_sale=gen_id(genSales, 1);
date0=current_timestamp;
insert into
sales0 values (:code_sale, 0, :date0, 0.0, 0.0);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCMOVEPATH(
WHAT_MOVE
INTEGER,
WHERE_MOVE
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_path integer;
declare
variable name_path varchar(80);
/*
error=1 --
path, where we move what_move must not be equal what_move
error=2 --
path, where we move what_move, found in path what_move
error=3 -- in
path, where we move what_path already exist path with this name_path
*/
begin
error=0;
if
(what_move=where_move) then begin error=1; exit; end
code_path=where_move;
while
(code_path<>0) do begin
select
code_ancestor from paths where code_path=:code_path into code_path;
if
(code_path=what_move) then begin error=2; exit; end
end
select
name_path from paths where code_path=:what_move into name_path;
select
count(*) from paths
where
code_ancestor=:where_move and name_path=:name_path
into vrem;
if (vrem<>0)
then begin error=3; exit; end
update paths
set code_ancestor=:where_move where code_path=:what_move;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDGOODTOCUT(
CODE_CUT
INTEGER,
NUMBER_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this number_good is not exist
*/
begin
error=0;
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=1; exit; end
insert into
GoodsForCut values(:code_cut, :number_good);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELGOODFROMCUT(
CODE_CUT
INTEGER,
NUMBER_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this number_good is not exist
*/
begin
error=0;
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=1; exit; end
delete from
GoodsForCut where code_cut=:code_cut and number_good=:number_good;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCGETNEWCODECUT
RETURNS (
CODE_CUT
INTEGER)
AS
begin
code_cut=gen_id(genGoodsForCut, 1);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCLEARUSERS(
CODE_SEANCE
INTEGER )
AS
declare variable vrem integer;
declare
variable date_seance timestamp;
declare variable days integer;
declare
variable seconds integer;
declare
variable code_seance0 integer;
declare
variable date_seance0 timestamp;
declare
variable days0 integer;
declare
variable seconds0 integer;
declare
variable diff integer;
begin
select
count(*) from users where code_seance=:code_seance into vrem;
if (vrem=0)
then begin
insert
into users values(:code_seance, current_timestamp);
end
else begin
update
users set date_seance=current_timestamp
where
code_seance=:code_seance;
end
date_seance=current_timestamp;
days=DateDays(date_seance);
seconds=DateSeconds(date_seance);
for select
code_seance, date_seance from users
into
:code_seance0, :date_seance0 as cursor cur1 do begin
days0=DateDays(date_seance0);
seconds0=DateSeconds(date_seance0);
diff=0;
diff=86400*(days-days0);
diff=diff+(seconds-seconds0);
if
(diff>=60) then begin
delete
from users where code_seance=:code_seance0;
delete
from ResumeOfDay where code_seance=:code_seance0;
delete
from ChangedPricesForPeriod where code_seance=:code_seance0;
delete
from SearchCodeSales where code_seance=:code_seance0;
delete
from SearchNumberGoods where code_seance=:code_seance0;
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELTITLEUNIT(
CODE_UNIT
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
begin
error=0;
select
count(*) from TitleUnits
where
code_unit=:code_unit
into vrem;
if (vrem=0)
then begin error=1; exit; end
update
TitleUnits set IsActive=0 where code_unit=:code_unit;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGETITLEUNIT(
CODE_UNIT
INTEGER,
NAME_UNIT
VARCHAR(20) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this name_unit already exists
error=2 --
name_unit cannot be empty
error=3 --
this code_unit is not exist
*/
begin
error=0;
select
count(*) from TitleUnits where code_unit=:code_unit into vrem;
if (vrem=0)
then begin error=3; exit; end
if
(name_unit='') then begin error=2; exit; end
select
count(*) from TitleUnits
where
(code_unit<>:code_unit) and (name_unit=:name_unit) and (IsActive=1)
into vrem;
if (vrem=0)
then begin
update
TitleUnits set name_unit=:name_unit where code_unit=:code_unit;
end
else begin
error=1;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCMINNEWCODEGOOD(
MIN_CODE
INTEGER )
RETURNS (
CODE_GOOD
INTEGER)
AS
declare variable vrem integer;
declare
variable first integer; /*boolean*/
declare
variable x integer;
declare
variable y integer;
begin
first=1;
y=0;
for select
code_good from goods where CodeIsActive=1 and code_good>=:min_code
order by
code_good
into :vrem as
cursor cur do begin
if
(first=1) then begin
y=vrem;
x=y;
first=0;
if
(y>min_code) then begin code_good=min_code; exit; end
end
else begin
x=vrem;
if
(x=y+1) then y=x;
else
begin
code_good=y+1;
exit;
end
end
end
if (y=0) then
code_good=min_code;
else
code_good=y+1;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE SUPERKA4
AS
declare variable number_good integer;
declare
variable scan_code varchar(255);
declare
variable scan_codes varchar(255);
begin
for select
number_good from goods
into
:number_good as cursor cur1 do begin
scan_codes='';
for select
scan_code from ScanCodes where number_good=:number_good
into
:scan_code as cursor cur2 do begin
scan_codes=scan_codes||scan_code||' ';
end
update
goods set scan_codes=:scan_codes
where
number_good=:number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCBRINGGOODTOSTRUCTURESALE(
CODE_SALE
INTEGER,
CODE_GOOD
INTEGER,
QUANTITY
DOUBLE PRECISION,
PRICE DOUBLE
PRECISION,
DISCOUNT
DOUBLE PRECISION,
SUMMA DOUBLE
PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable primarykey integer; /*for StructureSale*/
declare
variable number_good integer; /*for this good*/
declare
variable code_unit integer; /*for this
good*/
declare
variable IsMaterial integer; /*for this
good*/
/*real
first_price, price and quantity on StoreHouse*/
declare
variable first_price2 double precision;
declare
variable price2 double precision;
declare
variable quantity2 double precision;
declare
variable soldbyprice double precision;
/*other
variables*/
declare
variable vrem integer;
declare
variable x double precision;
/*
error=1 --
this code_sale is not exist
error=2 --
this code_good is not exist
error=3 --
error in table goods (this code_good exist more than ones)
error=4 --
quantity must be more or equal zero
error=5 --
quantity must be whole number (good is whole)
error=6 --
good with this number_good is not exist on StoreHouse
error=7 --
price must not be less than zero
error=8 --
discount must not be more than 100%
error=9 --
price on screen and on StoreHouse must be equal
error=10 --
error summa
error=11 --
this quantity of good is not exist on StoreHouse
*/
begin
error=0;
/*checking
code_sale, code_good*/
select
count(*) from sales0 where code_sale=:code_sale into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from goods where code_good=:code_good and CodeIsActive=1 into vrem;
if (vrem=0)
then begin error=2; exit; end
if
(vrem>1) then begin error=3; exit; end
/*define
number_good, code_unit, IsMaterial*/
select
number_good, code_unit from goods
where
code_good=:code_good and CodeIsActive=1
into
number_good, code_unit;
select
IsMaterial from TitleUnits where code_unit=:code_unit into IsMaterial;
/*checking
quantity*/
if
(quantity<0.0) then begin error=4; exit; end
if
(IsMaterial=0) then begin
execute
procedure ChisloIsFloat(quantity) returning_values (vrem);
if
(vrem=1) then begin error=5; exit; end
end
/*checking
that number_good exist on StoreHouse*/
select count(*)
from StoreHouse where number_good=:number_good into vrem;
if (vrem=0)
then begin error=6; exit; end
/*checking
price, discount*/
if
(price<0.0) then begin error=7; exit; end
if
(discount>100.0) then begin error=8; exit; end
/*more difficult
errors*/
select
first_price, price, quantity from StoreHouse
where
number_good=:number_good
into
first_price2, price2, quantity2;
/*checking
difference of price on screen and in database*/
if
(abs(price2-price)>0.001) then begin error=9; exit; end /*error price*/
/*checking
that summa is right calculated*/
x =
abs(quantity*price*(100.0-discount)/100.0 - summa);
if
(x>0.011) then begin error=10; exit; end
/*checking
that this quantity of good exist on StoreHouse*/
if (quantity2+0.0001<quantity)
then begin error=11; exit; end
/*write data
to database*/
primarykey=gen_id(genStructureSale, 1);
if
(quantity<>0.0) then begin
soldbyprice=price*(100.0-discount)/100.0;
insert
into StructureSale0(primarykey, code_sale, number_good, quantity,
first_price, price, discount, summa, soldbyprice)
values
(:primarykey, :code_sale, :number_good, :quantity,
:first_price2, :price, :discount, :summa, :soldbyprice);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEGOOD(
NUMBER_GOOD
INTEGER,
ART
VARCHAR(20),
NAME_GOOD
VARCHAR(80),
CODE_UNIT
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_ancestor integer;
declare
variable fl double precision;
declare
variable fl2 double precision;
declare
variable vrem2 integer;
declare
variable scan_code varchar(20);
/*
error=1 --
this number_good is not exist
error=2 --
art must not be empty
error=3 --
name_good must not be empty
error=4 --
this code_unit is not exist
error=5 --
this name_good already exists
error=6 --
name_good must have length not less than 3
error=7 --
impossible change material good to whole good (StoreHouse)
error=8 --
impossible change material good to whole good (StructureSale)
error=9 --
impossible change material good to whole good (StructureSession)
error=10 --
the good cannot have more than 12 scan_codes
*/
begin
error=0;
/*first five
errors*/
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=1; exit; end
if (art='')
then begin error=2; exit; end
if
(name_good='') then begin error=3; exit; end
select
count(*) from TitleUnits where code_unit=:code_unit into vrem;
if (vrem=0)
then begin error=4; exit; end
select
code_ancestor from goods where number_good=:number_good into code_ancestor;
select
count(*) from goods where code_ancestor=:code_ancestor and
number_good<>:number_good and name_good=:name_good and CodeIsActive=1
into vrem;
if
(vrem<>0) then begin error=5; exit; end
/*next errors
(after five)*/
if
(LengthString(name_good)<3) then begin error=6; exit; end
/*errors with
change code_unit*/
select
IsMaterial from TitleUnits where code_unit=:code_unit into vrem;
select
IsMaterial from goods join TitleUnits
on
goods.code_unit=TitleUnits.code_unit
where
goods.number_good=:number_good
into vrem2;
if ((vrem2=1)
and (vrem=0)) then begin /*change material unit to whole unit*/
/*StoreHouse*/
select
count(*) from StoreHouse where number_good=:number_good into vrem;
if
(vrem<>0) then begin
for
select sold, quantity from StoreHouse where number_good=:number_good
into
fl, fl2 as cursor cur do begin
execute procedure ChisloIsFloat(fl)
returning_values(vrem);
if
(vrem=1) then begin error=7; exit; end
execute procedure ChisloIsFloat(fl2) returning_values(vrem);
if
(vrem=1) then begin error=7; exit; end
end
end
/*StructureSale*/
select
count(*) from StructureSale where number_good=:number_good into vrem;
if
(vrem<>0) then begin
for
select quantity from StructureSale where number_good=:number_good
into fl
as cursor cur do begin
execute procedure ChisloIsFloat(fl) returning_values(vrem);
if
(vrem=1) then begin error=8; exit; end
end
end
/*StructureSession*/
select
count(*) from StructureSession where number_good=:number_good into vrem;
if
(vrem<>0) then begin
for
select quantity from StructureSession where number_good=:number_good
into fl
as cursor cur do begin
execute procedure ChisloIsFloat(fl) returning_values(vrem);
if
(vrem=1) then begin error=9; exit; end
end
end
end
/*ChangeGood*/
delete from
ScanCodes where number_good=:number_good;
update goods
set art=:art, name_good=:name_good, code_unit=:code_unit, scan_codes=''
where
number_good=:number_good;
vrem=0;
for select
scan_code from ScanCodes2
into
:scan_code as cursor cur1 do begin
vrem=vrem+1;
if
(vrem=13) then begin error=1/0; when any do begin error=10; exit; end end
insert
into ScanCodes
values(:number_good, :scan_code);
update
goods
set
scan_codes=scan_codes||:scan_code||' '
where
number_good=:number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELETEEMPTYPURCHASE(
CODE_PURCHASE
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_session integer;
/*
error=1 --
this code_purchase is not exist
error=2 --
this purchase have sessions, which not empty. delete impossible
*/
begin
error=0;
select
count(*) from purchases where code_purchase=:code_purchase into vrem;
if (vrem=0)
then begin error=1; exit; end
for select
code_session from sessions
where
code_purchase=:code_purchase
into
:code_session as cursor cur1 do begin
select
count(*) from StructureSession where code_session=:code_session into vrem;
if
(vrem<>0) then begin error=1/0; when any do begin error=2; exit; end end
delete
from sessions where code_session=:code_session;
delete
from notes where number_table=5 and KeyFromTable=:code_session;
end
delete from
purchases where code_purchase=:code_purchase;
delete from
notes where number_table=4 and KeyFromTable=:code_purchase;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDEXISTGOODTOSTRUCTSESSION(
CODE_SESSION INTEGER,
CODE_GOOD
INTEGER,
QUANTITY
DOUBLE PRECISION,
FIRST_PRICE
DOUBLE PRECISION,
ADDITION
DOUBLE PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable number_good integer;
declare
variable code_unit integer;
declare
variable StructureSessionHasGood integer;
declare
variable IsMaterial integer;
declare
variable new_primarykey integer;
declare
variable scan_code varchar(20); /*for cursor cur1*/
declare
variable summa0 double precision; /*for update summa of session*/
declare
variable code_purchase integer;
/*
error=1 --
this code_session is not exist
error=2 --
this code_good is not exist
error=3 --
quantity<0
error=4 --
first_price<0
error=5 --
quantity is float but good is not float
error=6 --
old_first_price<>first_price
error=7 --
old_addition<>addition
error=8 --
good already exist in this session
error=9 --
addition must between -100% an 10000%
error=10 --
number of scan_codes must not be more than 12
error=11 --
impossimble add good to closed session
*/
begin
error=0;
/*checking
that code_session is exist*/
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
accepted from sessions where code_session=:code_session into vrem;
if (vrem=1)
then begin error=11; exit; end
/*checking
that code_good is exist*/
select
count(*) from goods where code_good=:code_good and CodeIsActive=1 into vrem;
if (vrem=0)
then begin error=2; exit; end
/*define
number_good and code_unit*/
select
number_good, code_unit from goods
where
code_good=:code_good and CodeIsActive=1
into
number_good, code_unit;
/*define
StructureSessionHasGood*/
select
count(*) from StructureSession
where
(code_session=:code_session) and (number_good=:number_good)
into
StructureSessionHasGood;
/*checking
that quantity>=0 and first_price>=0*/
if
(quantity<0.0) then begin error=3; exit; end
if
(first_price<0.0) then begin error=4; exit; end
/*checking
addition*/
if
((addition<-100.0) or (addition>10000.00)) then begin error=9; exit; end
/*checking
floating of good*/
select
IsMaterial from TitleUnits where code_unit=:code_unit into IsMaterial;
if
(IsMaterial=0) then begin
execute
procedure ChisloIsFloat(quantity) returning_values(vrem);
if
(vrem=1) then begin error=5; exit; end
end
/*insert or
update StructureSession*/
if
(StructureSessionHasGood=0) then begin /*good is not exist in StructureSession*/
new_primarykey=gen_id(genStructureSession, 1);
delete
from ScanCodesForSession where
code_session=:code_session and number_good=:number_good;
insert
into StructureSession
values(:new_primarykey, :code_session, :number_good, :quantity,
:first_price, :addition,
'');
select
count(*) from ScanCodes where number_good=:number_good into vrem;
for select
scan_code from ScanCodesForSession2
into
:scan_code as cursor cur1 do begin
vrem=vrem+1;
if (vrem=13)
then begin error=1/0; when any do begin error=10; exit; end end
insert
into ScanCodesForSession
values(:new_primarykey, :code_session, :number_good, :scan_code);
update
StructureSession
set
scan_codes=scan_codes||:scan_code||' '
where
primarykey=:new_primarykey;
end
summa0=quantity*first_price;
update
sessions set summa=summa+:summa0 where code_session=:code_session;
select
code_purchase from sessions where code_session=:code_session into
code_purchase;
update
purchases set summa=summa+:summa0 where code_purchase=:code_purchase;
end
else begin
/*good exists in StructureSession*/
error=8;
exit;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCFILLINGGOODSFORRETURN(
CODE_SALE
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable x double precision;
/*variables
for main cycle (cursor cur1)*/
declare
variable number_good integer;
declare
variable code_good integer;
declare
variable name_good varchar(80);
declare
variable quantity double precision;
declare
variable remainder double precision;
declare
variable IsMaterial integer;
declare
variable code_unit integer;
declare
variable name_unit varchar(20);
declare
variable price double precision;
declare
variable discount double precision;
declare
variable CodeStructureSale integer;
declare
variable day0 integer;
declare
variable month0 integer;
declare
variable year0 integer;
declare
variable hour0 integer;
declare
variable minute0 integer;
begin
error=0;
delete from
GoodsForReturn;
for select
number_good, code_good, name_good, quantity,
IsMaterial,
code_unit, name_unit, price, discount, primarykey,
extract(day
from date_sale), extract(month from date_sale), extract(year from date_sale),
extract(hour
from date_sale), extract(minute from date_sale)
from sales
join StructureSale
on
sales.code_sale=StructureSale.code_sale join goods
on
StructureSale.number_good=goods.number_good join TitleUnits
on
goods.code_unit=TitleUnits.code_unit
where
sales.code_sale=:code_sale
into
number_good, code_good, name_good, quantity,
IsMaterial,
code_unit, name_unit, price, discount, CodeStructureSale,
day0, month0,
year0, hour0, minute0
as cursor
cur1 do begin
price=price*(100.0-discount)/100.0;
select
count(*) from returns2 join StructureReturn2
on
returns2.code_return=StructureReturn2.code_return
where
StructureReturn2.code_StructureSale=:CodeStructureSale
into vrem;
remainder=quantity;
if
(vrem<>0) then begin
select
sum(quantity) from StructureReturn2
where
StructureReturn2.code_StructureSale=:CodeStructureSale
into x;
end
else
x=0.0;
remainder=remainder-x;
insert
into GoodsForReturn
values(:number_good, :code_good, :name_good, :quantity, :remainder,
:IsMaterial, :code_unit, :name_unit, :price, :CodeStructureSale,
:day0,
:month0, :year0, :hour0, :minute0);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCPASTECUTGOODS(
CODE_CUT
INTEGER,
CODE_PATH
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable number_good integer;
declare
variable name_good varchar(80);
/*
error=1 --
this code_cut is not exist
error=2 --
this code_path is not exist
error=3 --
some goods what we want to paste is not exist
error=4 -- in
path, where we want to paste, exist goods with names like pasted goods
*/
begin
error=0;
select
count(*) from GoodsForCut where code_cut=:code_cut into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from paths where code_path=:code_path into vrem;
if (vrem=0)
then begin error=2; exit; end
for select
number_good from GoodsForCut
where
code_cut=:code_cut
into
:number_good as cursor cur1 do begin
/*checking
that good with number_good is exist*/
select
count(*) from goods where number_good=:number_good and CodeIsActive=1 into
vrem;
if
(vrem=0) then begin error=1/0; when any do begin error=3; exit; end end
/*define
name_good*/
select
name_good from goods where number_good=:number_good into name_good;
/*move
good with number_good to path with code_path*/
select
count(*) from goods
where
code_ancestor=:code_path and CodeIsActive=1 and name_good=:name_good
into vrem;
if
(vrem<>0) then begin error=1/0; when any do begin error=4; exit; end end
/*move
good with number_good*/
update goods
set code_ancestor=:code_path where number_good=:number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCENDSALE(
CODE_SALE
INTEGER,
SUMMA DOUBLE
PRECISION,
CASH DOUBLE
PRECISION,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable summa2 double precision; /*calculate summa*/
declare
variable difference double precision;
declare
variable date_sale timestamp;
/*variables
of main cycle (cursor cur1)*/
declare
variable number_good integer;
declare
variable addon double precision;
declare
variable quantity double precision;
declare
variable new_code_note integer;
/*variables
of main cycle (cursor cur2)*/
declare
variable primarykey integer;
declare
variable first_price double precision;
declare
variable price double precision;
declare
variable discount double precision;
declare
variable summa0 double precision;
declare
variable soldbyprice double precision;
/*
error=1 --
this code_sale is not exist
error=2 --
the same goods must not be exist in StructureSale
error=3 --
error summa
error=4 --
cash<summa
*/
begin
error=0;
select
count(*) from sales0 where code_sale=:code_sale into vrem;
if (vrem=0)
then begin error=1; exit; end
summa2=0.0;
for select
number_good, summa, quantity from StructureSale0
where
code_sale=:code_sale into :number_good, :addon, :quantity
as cursor
cur1 do begin
error=0;
select
count(*) from StructureSale0
where
code_sale=:code_sale and number_good=:number_good
into vrem;
if
(vrem>1) then begin error=1/0; when any do begin error=2; exit; end end
summa2=summa2+addon;
/*change
data*/
update
StoreHouse
set
quantity=quantity-:quantity, sold=sold+:quantity
where
number_good=:number_good;
end
difference=abs(summa2-summa);
if
(difference>0.001) then begin error=1/0; when any do begin error=3; exit;
end end
if
(cash+0.001<summa) then begin error=1/0; when any do begin error=4; exit; end
end
/*change
data*/
select
date_sale from sales0 where code_sale=:code_sale into date_sale;
select
count(*) from StructureSale0
where
code_sale=:code_sale
into vrem;
if
((vrem<>0) or (note<>'')) then begin
insert
into sales values(:code_sale, 0, :date_sale, :summa, :cash);
for select
primarykey, number_good, quantity, first_price, price, discount, summa,
soldbyprice
from
StructureSale0
where
code_sale=:code_sale
into
primarykey, number_good, quantity, first_price, price, discount, summa0,
soldbyprice
as cursor
cur2 do begin
insert
into StructureSale
values(:primarykey, :code_sale, :number_good, :quantity,
:first_price, :price, :discount, :summa0, :soldbyprice);
end
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes (code_note, number_table, KeyFromTable, text) values
(:new_code_note, 8, :code_sale, :note);
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEPURCHASE(
CODE_PURCHASE
INTEGER,
CODE_BASE
INTEGER,
DAY0 INTEGER,
MONTH0
INTEGER,
YEAR0 INTEGER,
HOUR0 INTEGER,
MINUTE0
INTEGER,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable s varchar(80);
declare
variable old_note varchar(80);
declare
variable new_code_note integer;
declare
variable code_session integer;
declare
variable date_session timestamp;
declare
variable date0 timestamp;
declare variable
date1 timestamp;
/*
error=1 --
this code_base is not exist
error=2 --
incorrect day
error=3 --
incorrect month
error=4 --
year must be between 2000 and 2020
error=5 --
incorrect hour
error=6 --
incorrect minute
error=7 --
incorrect date
*/
begin
error=0;
/*checking
code_base*/
select
count(*) from WholesaleBases where code_base=:code_base into vrem;
if (vrem=0)
then begin error=1; exit; end
/*checking
date*/
if
((day0<0) or (day0>31)) then begin error=2; exit; end
if
((month0<0) or (month0>12)) then begin error=3; exit; end
if
((year0<2000) or (year0>2020)) then begin error=4; exit; end
if
((hour0<0) or (hour0>23)) then begin error=5; exit; end
if
((minute0<0) or (minute0>59)) then begin error=6; exit; end
if
(((month0=4) or (month0=6) or (month0=9) or (month0=11)) and (day0=31)) then
begin
error=7;
exit;
end
if
((month0=2) and (day0>29)) then begin error=7; exit; end
vrem=year0-4*(year0/4); /*vrem=year0 mod 4*/
if
((vrem<>0) and (month0=2) and (day0=29)) then begin error=7; exit; end
s =
day0||'.'||month0||'.'||year0||' '||hour0||':'||minute0;
/*write data
to database*/
update
purchases set date_purchase=:s, code_base=:code_base
where
code_purchase=:code_purchase;
select
count(*) from notes
where
number_table=4 and KeyFromTable=:code_purchase
into vrem;
if (vrem=0)
then begin
if
(note<>'') then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values(:new_code_note, 4, :code_purchase, :note);
end
end
else begin
if
(note='') then begin
delete
from notes where number_table=4 and KeyFromTable=:code_purchase;
end
else begin
update
notes set text=:note
where
number_table=4 and KeyFromTable=:code_purchase;
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDSCANCODEFORSESSION(
SCAN_CODE
VARCHAR(20) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=3 --
scan_code must have 13 symbols
error=4 --
scan_code must have only digits
*/
begin
error=0;
if
(LengthString(scan_code)<>13) then begin error=3; exit; end
execute
procedure StringHasOnlyDigits(scan_code) returning_values(vrem);
if (vrem=0)
then begin error=4; exit; end
insert into
ScanCodesForSession2 values (:scan_code);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCSHOWCHANGEDPRICESFORPERIOD(
CODE_SEANCE
INTEGER,
DAYS INTEGER,
HOURS INTEGER
)
AS
/*days must equal 0 or hours must equal 0*/
/*if days<>0 then hours ignore*/
declare
variable date0 timestamp;
declare
variable NowDays integer;
declare
variable NowSeconds integer;
declare
variable ChangeDays integer;
declare
variable ChangeSeconds integer;
/*variables
for main cycle (cursor cur1)*/
declare
variable number_good integer;
declare
variable date_change timestamp;
begin
date0=current_timestamp;
NowDays=DateDays(date0);
NowSeconds=DateSeconds(date0);
delete from
ChangedPricesForPeriod where code_seance=:code_seance;
if ((days=0)
and (hours=0)) then exit;
for select
number_good, date_change from ChangedPrices
into
:number_good, :date_change as cursor cur1 do begin
ChangeDays=DateDays(date_change);
ChangeSeconds=DateSeconds(date_change);
if
(days<>0) then begin
if
(NowDays-days+1<=ChangeDays) then begin
insert into ChangedPricesForPeriod values(:number_good, :code_seance);
end
end
else begin
if
(24*3600*(NowDays-ChangeDays)+(NowSeconds-ChangeSeconds)<=3600*hours) then
begin
insert into ChangedPricesForPeriod values(:number_good, :code_seance);
end
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDPURCHASE(
DAY0 INTEGER,
MONTH0
INTEGER,
YEAR0 INTEGER,
HOUR0 INTEGER,
MINUTE0
INTEGER,
CODE_BASE
INTEGER,
NOTE
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable s varchar(100);
declare
variable new_code_purchase integer;
declare
variable new_code_note integer;
/*
error=1 --
this code_base is not exist
error=2 --
incorrect day
error=3 --
incorrect month
error=4 --
year must be between 2000 and 2020
error=5 --
incorrect hour
error=6 --
incorrect minute
error=7 --
incorrect date
*/
begin
error=0;
select
count(*) from WholesaleBases where code_base=:code_base into vrem;
if (vrem=0)
then begin error=1; exit; end
/*checking
date*/
if
((day0<0) or (day0>31)) then begin error=2; exit; end
if
((month0<0) or (month0>12)) then begin error=3; exit; end
if
((year0<2000) or (year0>2020)) then begin error=4; exit; end
if
((hour0<0) or (hour0>23)) then begin error=5; exit; end
if
((minute0<0) or (minute0>59)) then begin error=6; exit; end
if
(((month0=4) or (month0=6) or (month0=9) or (month0=11)) and (day0=31)) then
begin
error=7;
exit;
end
if
((month0=2) and (day0>29)) then begin error=7; exit; end
vrem=year0-4*(year0/4); /*vrem=year0 mod 4*/
if
((vrem<>0) and (month0=2) and (day0=29)) then begin error=7; exit; end
/*write data
to database*/
s =
day0||'.'||month0||'.'||year0||' '||hour0||':'||minute0;
new_code_purchase = gen_id(genPurchases, 1);
insert into
purchases values (:new_code_purchase, :code_base, :s, 0.0);
if (note<>'')
then begin
new_code_note=gen_id(genNotes, 1);
insert
into notes values (:new_code_note, 4, :new_code_purchase, :note);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELGOODFROMSTRUCTSESSION(
CODE_SESSION
INTEGER,
NUMBER_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable quantity double precision;
declare
variable first_price double precision;
declare
variable summa0 double precision;
declare
variable code_purchase integer;
/*
error=1 --
this code_session is not exist
error=2 --
this session is closed; deleting impossible
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select accepted from sessions where
code_session=:code_session into vrem;
if (vrem=1)
then begin error=2; exit; end
select
quantity, first_price from StructureSession
where
code_session=:code_session and number_good=:number_good
into
:quantity, :first_price;
delete from
StructureSession
where
code_session=:code_session and number_good=:number_good;
delete from
ScanCodesForSession
where
code_session=:code_session and number_good=:number_good;
summa0=quantity*first_price;
update
sessions set summa=summa-:summa0 where code_session=:code_session;
select
code_purchase from sessions where code_session=:code_session into
code_purchase;
update
purchases set summa=summa-:summa0 where code_purchase=:code_purchase;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELEMPTYPATH(
CODE_PATH
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this code_path is not exist
error=2 --
this path includes other paths
error=3 --
this path includes some goods
*/
begin
error=0;
select
count(*) from paths where code_path=:code_path into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from paths where code_ancestor=:code_path into vrem;
if
(vrem<>0) then begin error=2; exit; end
select
count(*) from goods
where
code_ancestor=:code_path and CodeIsActive=1
into vrem;
if
(vrem<>0) then begin error=3; exit; end
delete from
paths where code_path=:code_path;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDNEWGOODTOSTRUCTSESSION(
CODE_SESSION
INTEGER,
CODE_GOOD
INTEGER,
ART
VARCHAR(20),
CODE_ANCESTOR
INTEGER,
NAME_GOOD
VARCHAR(80),
CODE_UNIT
INTEGER,
QUANTITY
DOUBLE PRECISION,
FIRST_PRICE
DOUBLE PRECISION,
ADDITION
DOUBLE PRECISION )
RETURNS (
ERROR INTEGER,
NEW_NUMBER_GOOD INTEGER)
AS
declare variable vrem integer;
declare
variable IsMaterial integer;
declare
variable new_primarykey integer;
declare
variable scan_code varchar(20); /*for cursor cur1*/
declare
variable summa0 double precision;
declare
variable code_purchase integer;
/*
error=1 --
this code_session is not exist
error=2 --
this code_good already exist
error=3 --
code_good<10000
error=4 --
art must not be empty
error=5 --
name_good must not be empty
error=6 --
this code_ancestor is not exist
error=7 --
this code_unit is not exist
error=8 --
quantity<0
error=9 --
first_price<0
error=10 --
the good is not float but quantity is float
error=11 --
the good with this name_good already exist
error=12 --
addition must between -100% and 10000%
error=13 --
number of scan_codes must not be more than 12
error=14 --
impossimble add good to closed session
error=15 --
length(name_good) must not be less than 3
*/
begin
error=0;
/*checking
code_session*/
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
accepted from sessions where code_session=:code_session into vrem;
if (vrem=1)
then begin error=14; exit; end
/*checking
code_good*/
select
count(*) from goods where code_good=:code_good and CodeIsActive=1 into vrem;
if
(vrem<>0) then begin error=2; exit; end
if
(code_good<10000) then begin error=3; exit; end
/*checking
art and name_good*/
if (art='')
then begin error=4; exit; end
if
(name_good='') then begin error=5; exit; end
if
(LengthString(name_good)<3) then begin error=15; exit; end
/*checking
code_ancestor*/
select
count(*) from paths where code_path=:code_ancestor into vrem;
if (vrem=0)
then begin error=6; exit; end
/*checking
code_unit*/
select
count(*) from TitleUnits where code_unit=:code_unit into vrem;
if (vrem=0)
then begin error=7; exit; end
/*checking
quantity and first_price*/
if (quantity<0.0)
then begin error=8; exit; end
if
(first_price<0.0) then begin error=9; exit; end
/*checking
floating of good and quantity*/
select
IsMaterial from TitleUnits where code_unit=:code_unit into IsMaterial;
if
(IsMaterial=0) then begin
execute
procedure ChisloIsFloat(quantity) returning_values(vrem);
if
(vrem=1) then begin error=10; exit; end
end
/*checking
that not the same name_good*/
select
count(*) from goods
where
name_good=:name_good and code_ancestor=:code_ancestor and CodeIsActive=1
into vrem;
if
(vrem<>0) then begin error=11; exit; end
/*checking
addition*/
if
((addition<-100.0) or (addition>10000.00)) then begin error=12; exit; end
/*record data
to database*/
new_number_good=gen_id(genGoods, 1);
insert into
goods
values(:new_number_good, :code_good, 1, :art, :code_ancestor,
:name_good, :code_unit,'');
new_primarykey=gen_id(genStructureSession, 1);
insert into
StructureSession
values(:new_primarykey, :code_session, :new_number_good, :quantity,
:first_price, :addition,'');
vrem=0;
for select
scan_code from ScanCodesForSession2
into
:scan_code as cursor cur1 do begin
vrem=vrem+1;
if
(vrem=13) then begin error=1/0; when any do begin error=13; exit; end end
insert
into ScanCodesForSession
values(:new_primarykey, :code_session, :new_number_good, :scan_code);
update
StructureSession
set
scan_codes=scan_codes||:scan_code||' '
where
primarykey=:new_primarykey;
end
summa0=quantity*first_price;
update
sessions set summa=summa+:summa0 where code_session=:code_session;
select
code_purchase from sessions where code_session=:code_session into
code_purchase;
update
purchases set summa=summa+:summa0 where code_purchase=:code_purchase;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCNEWCODESEANCE
RETURNS (
CODE_SEANCE
INTEGER)
AS
begin
code_seance=gen_id(genSearchCodeSaleNumberGood, 1);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGESESSIONGOOD(
CODE_SESSION
INTEGER,
NUMBER_GOOD
INTEGER,
QUANTITY
DOUBLE PRECISION,
ADDITION
DOUBLE PRECISION,
FIRST_PRICE
DOUBLE PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable primarykey integer;
declare
variable vrem integer;
declare
variable IsMaterial integer;
declare
variable scan_code varchar(20);
declare
variable delta_summa double precision;
declare
variable old_first_price double precision;
declare
variable old_quantity double precision;
declare
variable code_purchase integer;
/*
error=1 --
this code_session is not exist
error=2 --
this number_good is not exist
error=3 --
quantity must not be less than zero
error=4 --
addition must be between -100 and 10000
error=5 --
first_price must not be less than zero
error=6 -- if
good is whole then quantity must be whole number
error=7 --
the good cannot have more than 12 scan-codes
error=8 --
session is accepted!
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0) then
begin error=1; exit; end
select
accepted from sessions where code_session=:code_session into vrem;
if (vrem=1)
then begin error=8; exit; end
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=2; exit; end
if
(quantity<0.0) then begin error=3; exit; end
if
((addition<-100.0) or (addition>10000.0)) then begin error=4; exit; end
if
(first_price<0.0) then begin error=5; exit; end
/*checking
that if good is whole then quantity is whole*/
select
IsMaterial from goods join TitleUnits
on
goods.code_unit=TitleUnits.code_unit
where
goods.number_good=:number_good
into
IsMaterial;
if
(IsMaterial=0) then begin
execute
procedure ChisloIsFloat(quantity) returning_values(vrem);
if (vrem=1) then begin error=6; exit; end
end
delete from
ScanCodesForSession
where
code_session=:code_session and number_good=:number_good;
update
StructureSession set scan_codes=''
where
code_session=:code_session and number_good=:number_good;
select
count(*) from ScanCodes where number_good=:number_good into vrem;
select
primarykey from StructureSession
where
code_session=:code_session and number_good=:number_good
into
:primarykey;
for select
scan_code from ScanCodesForSession2
into
:scan_code as cursor cur1 do begin
vrem=vrem+1;
if
(vrem=13) then begin error=1/0; when any do begin error=7; exit; end end
insert
into ScanCodesForSession
values(:primarykey, :code_session, :number_good, :scan_code);
update
StructureSession
set
scan_codes=scan_codes||:scan_code||' '
where
code_session=:code_session and number_good=:number_good;
end
/*write data
to database*/
select
first_price, quantity from StructureSession
where code_session=:code_session
and number_good=:number_good
into
:old_first_price, :old_quantity;
update
StructureSession
set
quantity=:quantity, addition=:addition, first_price=:first_price
where
code_session=:code_session and number_good=:number_good;
delta_summa=quantity*first_price-old_quantity*old_first_price;
update
sessions set summa=summa+:delta_summa where code_session=:code_session;
select
code_purchase from sessions where code_session=:code_session into
:code_purchase;
update purchases
set summa=summa+:delta_summa where code_purchase=:code_purchase;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCBRINGGOODTOSTRUCTURERETURN(
CODE_RETURN
INTEGER,
CODE_STRUCTURESALE INTEGER,
NUMBER_GOOD
INTEGER,
PRICE DOUBLE
PRECISION,
QUANTITY
DOUBLE PRECISION,
SUMMA DOUBLE
PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_sale integer;
declare
variable IsMaterial integer;
declare
variable returned_quantity double precision;
declare
variable diff double precision;
declare
variable primarykey integer; /*for write data to database*/
declare
variable quantity2 double precision;
declare
variable price2 double precision; /*real price of sale*/
declare
variable discount2 double precision;
/*
error=1 --
this code_return is not exist
error=2 --
this code_StructureSale incorrect
error=3 --
this number_good incorrect
error=4 --
the good is whole therefore quantity must be whole number
error=5 --
the quantity of whole good is too many
error=6 --
the real good already returned
error=7 --
summa incorrect calculated in program
error=8 --
the quantity of real good is too many
error=9 --
incorrect price (it must be equal sale_price
error=10 --
code_StructureSale is incorrect
*/
begin
error=0;
/*checking
code_return, code_StructureSale, number_good*/
select
count(*) from returns20 where code_return=:code_return into vrem;
if (vrem=0)
then begin error=1; exit; end
select
code_sale from returns20 where code_return=:code_return into code_sale;
select
primarykey from StructureSale
where
code_sale=:code_sale and number_good=:number_good
into vrem;
if
(vrem<>code_StructureSale) then begin error=10; exit; end
select
count(*) from StructureSale
where
code_sale=:code_sale and primarykey=:code_StructureSale
into vrem;
if (vrem=0)
then begin error=2; exit; end
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=3; exit; end
/*checking
that quantity is whole*/
select
IsMaterial from goods join TitleUnits
on
goods.code_unit=TitleUnits.code_unit
where
number_good=:number_good
into
IsMaterial;
if
(IsMaterial=0) then begin
execute
procedure ChisloIsFloat(quantity) returning_values (vrem);
if
(vrem=1) then begin error=4; exit; end
end
/*checking
that qunatity is not more than allow return*/
select
quantity from StructureSale
where
primarykey=:code_StructureSale
into
:quantity2;
select
sum(quantity), count(*) from returns2 join StructureReturn2
on
returns2.code_return=StructureReturn2.code_return
where
code_StructureSale=:code_StructureSale
into
returned_quantity, vrem;
if (vrem=0)
then returned_quantity=0.0;
if
(IsMaterial=0) then begin /*quantity is whole number*/
if
(quantity>quantity2-returned_quantity+0.0001) then begin
error=5; exit;
end
end
else begin
if
(quantity>quantity2-returned_quantity+0.0001) then begin
error=8; exit;
end
end
/*checking
price*/
select price,
discount from StructureSale
where
StructureSale.primarykey=:code_StructureSale
into price2,
discount2;
if
(abs(price-price2*(100.0-discount2)/100.0)>=0.001) then begin error=9; exit;
end
/*checking
summa*/
if
(abs(summa-price*quantity)>0.011) then begin error=11; exit; end
/*write data
to database*/
primarykey=gen_id(genStructureReturn, 1);
if
(quantity<>0.0) then begin
insert
into StructureReturn20
values
(:primarykey, :code_return, :code_StructureSale, :number_good,
:price,
:quantity, :summa);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEPRICEONSTOREHOUSE(
NUMBER_GOOD
INTEGER,
NEW_PRICE
DOUBLE PRECISION )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
this number_good is not exist
error=2 --
price must not be less than zero
*/
begin
error=0;
select
count(*) from StoreHouse where number_good=:number_good into vrem;
if (vrem=0)
then begin error=1; exit; end
if
(new_price<0.0) then begin error=2; exit; end
update
StoreHouse set price=:new_price where number_good=:number_good;
delete from
ChangedPrices where number_good=:number_good;
insert into
ChangedPrices values(:number_good, :new_price, current_timestamp);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCLEARHARDTABLES
AS
begin
delete from
ResumeOfDay;
delete from
ChangedPricesForPeriod;
delete from
SearchCodeSales;
delete from
SearchNumberGoods;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCSEARCHSTOREHOUSEGOODS(
CODE_SEANCE
INTEGER,
NAME_GOOD
VARCHAR(80),
ART
VARCHAR(20),
SCAN_CODE
VARCHAR(20),
EXACTLY
INTEGER )
AS
declare variable number_good integer;
declare
variable exactly0 integer;
declare
variable scan_code0 varchar(20);
declare
variable vrem integer;
begin
name_good='%'||ToUpperCase(name_good)||'%';
art='%'||art||'%';
delete from
SearchNumberGoods where code_seance=:code_seance;
if
(scan_code='') then begin
for select
goods.number_good from StoreHouse join goods on
StoreHouse.number_good=goods.number_good
where
ToUpperCase(name_good) like :name_good and
art
like :art
into
number_good as cursor cur1 do begin
insert
into SearchNumberGoods
values(:code_seance, :number_good, 0);
end
end
else if
(LengthString(scan_code)<>13) then begin
scan_code='%'||scan_code||'%';
for select
goods.number_good from StoreHouse join goods on
StoreHouse.number_good=goods.number_good join ScanCodes
on
goods.number_good=ScanCodes.number_good
where
ToUpperCase(name_good) like :name_good and
art
like :art and
scan_code like :scan_code
into
number_good as cursor cur1 do begin
select count(*) from SearchNumberGoods
where
code_seance=:code_seance and number_good=:number_good
into
vrem;
if
(vrem=0) then begin
insert into SearchNumberGoods
values(:code_seance, :number_good, 0);
end
end
end
else begin
for select
goods.number_good, ScanCodes.scan_code
from
StoreHouse join goods on
StoreHouse.number_good=goods.number_good join ScanCodes
on
goods.number_good=ScanCodes.number_good
where
ToUpperCase(name_good) like :name_good and
art
like :art
into
number_good, scan_code0 as cursor cur1 do begin
/*exactly0=SameScanCodes(scan_code, scan_code0, :exactly)=1;*/
exactly0=SameScanCodes(scan_code, scan_code0);
if
(exactly0<=exactly) then begin
select count(*) from SearchNumberGoods
where code_seance=:code_seance and number_good=:number_good
into
vrem;
if
(vrem=0) then begin
insert into SearchNumberGoods
values(:code_seance, :number_good, :exactly0);
end
else
begin
select exactly from SearchNumberGoods
where code_seance=:code_seance and number_good=:number_good
into vrem;
if (exactly0<vrem) then begin
update SearchNumberGoods set exactly=:exactly0
where code_seance=:code_seance and number_good=:number_good;
end
end
end
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCADDUSER(
NAME_USER
VARCHAR(80),
PSSWD
VARCHAR(80),
RIGHTS INTEGER
)
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable code_user integer;
/*
error=1 --
this name_user already exists
error=2 --
name_user must not be empty
*/
begin
error=0;
select
count(*) from ProgramUsers where name_user=:name_user into vrem;
if
(vrem<>0) then begin error=1; exit; end
if
(name_user='') then begin error=2; exit; end
code_user=gen_id(genProgramUsers, 1);
insert into
ProgramUsers values(:code_user, :name_user, :psswd, :rights);
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCDELUSER(
CODE_USER
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
impossible drop Administrator
error=2 --
deleting user not exist
*/
begin
error=0;
if
(code_user=0) then begin error=1; exit; end
select
count(*) from ProgramUsers where code_user=:code_user into vrem;
if (vrem=0)
then begin error=2; exit; end
delete from
ProgramUsers where code_user=:code_user;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGESCANCODESINSESSION(
CODE_SESSION
INTEGER,
NUMBER_GOOD
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
declare
variable primarykey integer;
declare
variable scan_code varchar(20);
declare
variable scan_codes varchar(255);
/*
error=1 --
this code_session is not exist in sessions
error=2 --
this number_good is not exist in goods
error=3 --
this (code_session, number_good) are not exist in StructureSession
error=4 --
the good cannot has more than 12 scan_codes
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
count(*) from goods where number_good=:number_good into vrem;
if (vrem=0)
then begin error=2; exit; end
select
count(*) from StructureSession
where
code_session=:code_session and number_good=:number_good
into vrem;
if (vrem=0)
then begin error=3; exit; end
select
primarykey from StructureSession
where
code_session=:code_session and number_good=:number_good
into
:primarykey;
delete from
ScanCodesForSession
where
code_session=:code_session and number_good=:number_good;
scan_codes='';
vrem=0;
for select
scan_code from ScanCodes2 into :scan_code as cursor cur1 do begin
if
(vrem=12) then begin error=1/0; when any do begin error=4; exit; end end
insert
into ScanCodesForSession
values(:primarykey, :code_session, :number_good, :scan_code);
vrem=vrem+1;
scan_codes=scan_codes||scan_code||' ';
end
update
StructureSession set scan_codes=:scan_codes
where
code_session=:code_session and number_good=:number_good;
/*bring new
scan_codes into table GOODS*/
for select
scan_code from ScanCodesForSession
where
code_session=:code_session and number_good=:number_good
into
:scan_code as cursor cur2 do begin
select
count(*) from ScanCodes
where
number_good=:number_good and scan_code=:scan_code
into vrem;
if
(vrem=0) then begin
select
count(*) from ScanCodes where number_good=:number_good into vrem;
if
(vrem=12) then begin error=1/0; when any do begin error=2; exit; end end
insert
into ScanCodes values(:number_good, :scan_code);
end
end
scan_codes='';
for select
scan_code from ScanCodes where number_good=:number_good
into
:scan_code as cursor cur3 do begin
scan_codes=scan_codes||scan_code||' ';
end
update goods
set scan_codes=:scan_codes where number_good=:number_good;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCLOSESESSION(
CODE_SESSION
INTEGER,
CLOSESESSION
INTEGER )
RETURNS (
ERROR INTEGER,
CHISLO
INTEGER)
AS
/*
CloseSession=0 -- show changed prices only after close session
CloseSession=1 -- we want to close session
*/
declare variable vrem integer;
/*variables
of main cycle (cursor cur1)*/
declare
variable number_good integer;
declare
variable quantity double precision;
declare
variable first_price double precision;
declare
variable addition double precision;
/*variables
of inside cycle (cursor cur2)*/
declare
variable scan_code varchar(20);
/*variables
for do new_price*/
declare
variable q1 double precision;
declare
variable p01 double precision;
declare
variable p1 double precision;
declare
variable q2 double precision;
declare
variable p02 double precision;
declare
variable a2 double precision;
declare variable p2 double precision;
declare
variable q3 double precision;
declare
variable p03 double precision;
declare
variable p3 double precision;
/*other
variables*/
declare
variable code_good integer;
declare
variable date1 timestamp;
declare
variable GoodExistOnStoreHouse integer;
declare
variable PriceChanged integer;
declare
variable date_change timestamp;
/*
error=1 --
this code_session is not exist
error=2 --
for this code_good(chislo) too many scan_codes
error=3 --
quantity of bringing good must be more than zero (code_good in chislo)
*/
begin
error=0;
chislo=0; /*returning values*/
date_change=current_timestamp;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
select
accepted from sessions where code_session=:code_session into vrem;
if (vrem=1)
then exit;
/*CloseSession=0 or CloseSession=1*/
delete from
SessionsClosed where code_session=:code_session;
/*main
cycle*/
for select
number_good, quantity, first_price, addition
from
StructureSession where code_session=:code_session
into
number_good, quantity, first_price, addition
as cursor
cur1 do begin
/*define
code_good, NumScanCodes1, NumScanCodes2*/
select code_good from goods where
number_good=:number_good into code_good;
/*bringing
scan_codes*/
for select
scan_code from ScanCodesForSession
where
code_session=:code_session and number_good=:number_good
into
scan_code as cursor cur2 do begin
if
(CloseSession=1) then begin
select count(*) from ScanCodes
where number_good=:number_good and scan_code=:scan_code
into
vrem;
if
(vrem=0) then begin
select count(*) from ScanCodes where number_good=:number_good into vrem;
if (vrem=12) then begin
error=1/0; when any do begin error=2; exit; end
end
insert into ScanCodes values (:number_good, :scan_code);
update goods set scan_codes=scan_codes||:scan_code||' '
where number_good=:number_good;
end
end
end
/*move
goods from session to StoreHouse*/
/*define
q1, p01, p1, q2, p02, p2*/
select
count(*) from StoreHouse
where
number_good=:number_good
into
GoodExistOnStoreHouse;
if
(GoodExistOnStoreHouse<>0) then begin
select
quantity, first_price, price from StoreHouse
where
number_good=:number_good
into q1, p01, p1;
end
else begin
q1=0.0; p01=0.0; p1=0.0; end
q2=quantity; p02=first_price; a2=addition;
p2=p02*(1.0+a2/100.0);
execute
procedure procDoWholePrice(p2) returning_values (p2);
/*define
q3, p03*/
if
(q2<0.0) then begin
error=1/0; when any do begin error=3; chislo=code_good; exit; end
end
if
(q1<0.0) then begin
update
StoreHouse set quantity=0.0 where quantity<0.0;
q1=0.0;
end
q3=q1+q2;
if (q3<>0.0)
then p03=(q1*p01+q2*p02)/q3;
else
p03=0.0;
/*define
p3, PriceChanged*/
if
(GoodExistOnStoreHouse=0) then p3=p2;
else begin
if
(p1>=p2) then p3=p1; else p3=p2;
if
(p1>=1.00) then begin
if
((p3/p1)<=1.01) then begin p3=p1; PriceChanged=0; end
else
PriceChanged=1;
end
else
PriceChanged=1;
end
/*bringing
goods to StoreHouse*/
if
(GoodExistOnStoreHouse<>0) then begin
if
(PriceChanged=1) then begin
insert into SessionsClosed values (:code_session, :number_good, :p1,
:p3);
end
if
(CloseSession=1) then begin
update StoreHouse set quantity=:q3, first_price=:p03, price=:p3
where number_good=:number_good;
end
if
((CloseSession=1) and (PriceChanged=1)) then begin
delete from ChangedPrices where number_good=:number_good;
insert into ChangedPrices values(:number_good, :p3, :date_change);
end
end
else begin
insert
into SessionsClosed values (:code_session, :number_good, 0.0, :p3);
if
(CloseSession=1) then begin
insert into StoreHouse (number_good, quantity, first_price, price, sold)
values (:number_good, :q3, :p03, :p3, 0.0);
delete from ChangedPrices where number_good=:number_good;
insert into ChangedPrices values(:number_good, :p3, :date_change);
end
end
end
/*close
session and set date of closing*/
if (CloseSession=1)
then begin
date1 =
current_timestamp;
update
sessions set accepted=1, date1=:date1 where code_session=:code_session;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCFORMRESUMEOFDAY(
CODE_SEANCE
INTEGER,
DAY_BEGIN INTEGER,
DAY_END
INTEGER )
AS
declare variable date0 timestamp;
declare
variable number_good integer;
declare
variable first_price double precision;
declare
variable price double precision;
declare
variable soldbyprice double precision;
declare
variable quantity double precision;
declare
variable summa double precision;
declare
variable x integer;
begin
delete from
ResumeOfDay where code_seance=:code_seance;
for select
number_good, quantity, first_price, price,
StructureSale.summa, date_sale
from sales
join StructureSale
on
sales.code_sale=StructureSale.code_sale join goods
on
StructureSale.number_good=goods.number_good
into
:number_good, :quantity, :first_price, :price, :summa, :date0
as cursor
cur1 do begin
if (quantity<>0.0) then
soldbyprice=summa/quantity;
else
soldbyprice=0.0;
if
(((DateDays(date0)>=day_begin) and (DateDays(date0)<=day_end)) and
(summa<>0.0))
then begin
x=(DateSeconds(:date0)+1800)/3600;
insert
into ResumeOfDay
values(:number_good, :first_price, :price, :soldbyprice, :quantity,
:date0,
:code_seance, :x);
end
end
for select
goods.number_good as number_good,
StructureReturn2.quantity as quantity,
StructureSale.first_price
as first_price,
StructureSale.price as price,
StructureSale.soldbyprice as soldbyprice,
returns2.date_return as date0
from returns2
join StructureReturn2
on
returns2.code_return=StructureReturn2.code_return join StructureSale
on
StructureReturn2.code_StructureSale=StructureSale.primarykey join goods
on
StructureSale.number_good=goods.number_good
into
:number_good, :quantity, :first_price, :price, :soldbyprice, :date0
as cursor
cur2 do begin
if (((DateDays(date0)>=day_begin)
and (DateDays(date0)<=day_end)) and (summa<>0.0))
then begin
x=(DateSeconds(:date0)+1800)/3600;
quantity=-quantity;
insert
into ResumeOfDay
values(:number_good, :first_price, :price, :soldbyprice, :quantity,
:date0,
:code_seance, :x);
end
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE SUPERKA5(
CODE_GOOD
INTEGER,
NEW_PRICE
DOUBLE PRECISION )
AS
declare variable number_good integer;
begin
select
number_good from goods where code_good=:code_good into number_good;
update
StoreHouse set first_price=:new_price, price=:new_price
where
number_good=:number_good;
update
StructureSession set first_price=:new_price, addition=0.0
where
code_session=1 and number_good=:number_good;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCFORMGRAFIKWEEK(
CODE_SEANCE
INTEGER,
DAY_BEGIN
INTEGER,
DAY_END
INTEGER )
AS
declare variable day_of_week integer;
declare
variable summa double precision;
declare
variable pribil double precision;
begin
execute
procedure procFormResumeOfDay(:code_seance, :day_begin, :day_end);
delete from
GrafikWeek where code_seance=:code_seance;
day_of_week=1;
while
(day_of_week<=7) do begin
insert
into GrafikWeek values(:code_seance, :day_of_week, 0.0, 0.0);
day_of_week=day_of_week+1;
end
for select
DateDays(date_sale),
sum(quantity*soldbyprice),
sum(quantity*(soldbyprice-first_price))
from
ResumeOfDay
where
code_seance=:code_seance
group by DateDays(date_sale)
into
:day_of_week, summa, pribil as cursor cur1 do begin
day_of_week=(day_of_week-2)-7*((day_of_week-2)/7)+1;
update
GrafikWeek
set
summa=summa+:summa, pribil=pribil+:pribil
where
code_seance=:code_seance and day_of_week=:day_of_week;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCFORMGRAFIKHOURBUYERS(
CODE_SEANCE
INTEGER,
DAY_BEGIN
INTEGER,
DAY_END
INTEGER )
AS
declare variable i integer;
declare
variable x integer;
begin
execute
procedure procFormResumeOfDay
(code_seance,
day_begin, day_end);
delete from
GrafikHourBuyers where code_seance=:code_seance;
i=0;
while
(i<>25) do begin
insert
into GrafikHourBuyers
values(:code_seance, :i, 0);
i=i+1;
end
for select
DateSeconds(date_sale) from sales
where
DateDays(date_sale)>=:day_begin and
DateDays(date_sale)<=:day_end
into :x as
cursor cur1 do begin
x=(x+1800)/3600;
update
GrafikHourBuyers
set
num_buyers=num_buyers+1
where
code_seance=:code_seance and hour0=:x;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCGRAFIKPERCENTBUYERSPRIBIL(
CODE_SEANCE
INTEGER,
DAY_BEGIN
INTEGER,
DAY_END
INTEGER )
RETURNS (
NUM INTEGER,
SUMMA DOUBLE
PRECISION)
AS
declare variable pribil double precision;
begin
delete from
GrafikPercentBuyersPribil
where
code_seance=:code_seance;
num=0;
summa=0.0;
for select
sum(quantity*(soldbyprice-first_price))
from sales
join StructureSale
on sales.code_sale=StructureSale.code_sale
where
soldbyprice>=first_price and
DateDays(date_sale)>=:day_begin and DateDays(date_sale)<=:day_end
group by
sales.code_sale
order by
-sum(quantity*(soldbyprice-first_price))
into :pribil
as cursor cur1 do begin
num=num+1;
summa=summa+pribil;
insert
into GrafikPercentBuyersPribil
values(:code_seance, :num, :summa);
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCHANGEUSERPASSWORD(
CODE_USER
INTEGER,
PSSWD
VARCHAR(80) )
RETURNS (
ERROR INTEGER)
AS
declare variable vrem integer;
/*
error=1 --
changed user not exist
*/
begin
error=0;
select
count(*) from ProgramUsers where code_user=:code_user into vrem;
if (vrem=0)
then begin error=1; exit; end
update ProgramUsers
set psswd=:psswd where code_user=:code_user;
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCCLOSESESSION3(
CODE_SESSION
INTEGER )
RETURNS (
ERROR INTEGER)
AS
declare variable number_good integer;
declare
variable vrem integer;
declare
variable scan_code varchar(20);
declare
variable scan_codes varchar(255);
/*
error=1 --
this code_session is not exist
error=2 --
the good cannot has more than 12 scan_codes
*/
begin
error=0;
select
count(*) from sessions where code_session=:code_session into vrem;
if (vrem=0)
then begin error=1; exit; end
for select
number_good from StructureSession where code_session=:code_session
into
:number_good as cursor cur1 do begin
for select
scan_code from ScanCodesForSession
where code_session=:code_session and
number_good=:number_good
into
:scan_code as cursor cur2 do begin
select
count(*) from ScanCodes
where
number_good=:number_good and scan_code=:scan_code
into
vrem;
if
(vrem=0) then begin
select count(*) from ScanCodes where number_good=:number_good into vrem;
if
(vrem=12) then begin error=1/0; when any do begin error=2; exit; end end
insert into ScanCodes values(:number_good, :scan_code);
end
end
scan_codes='';
for select
scan_code from ScanCodes where number_good=:number_good
into
:scan_code as cursor cur3 do begin
scan_codes=scan_codes||scan_code||' ';
end
update
goods set scan_codes=:scan_codes where number_good=:number_good;
end
end^
SET TERM ;^
SET TERM ^ ;
CREATE PROCEDURE PROCSTARTSEARCH(
CODE_SEANCE
INTEGER,
DAY0 INTEGER,
DAY1 INTEGER,
SECOND0
INTEGER,
SECOND1
INTEGER,
PRICE0 DOUBLE
PRECISION,
PRICE1 DOUBLE
PRECISION,
PRICE2 DOUBLE
PRECISION,
SCAN_CODE
VARCHAR(20),
ART
VARCHAR(20),
NAME_GOOD
VARCHAR(80) )
AS
declare variable vrem integer;
declare
variable code_sale integer;
declare
variable number_good2 integer;
declare
variable soldbyprice double precision;
declare
variable art2 varchar(20);
declare
variable price3 double precision;
declare
variable price4 double precision;
declare
variable million integer;
declare
variable CodeSeancePlusMillion integer;
begin
million=1000000;
CodeSeancePlusMillion=code_seance+million;
delete from
SearchCodeSales where code_seance=:code_seance;
delete from
SearchNumberGoods where code_seance=:code_seance;
if
(price0<-0.5) then price0=0.0;
price0=price0-0.001;
price2=price2+0.001;
if
(price1>-0.5) then begin
price3=price1-0.001;
price4=price1+0.001;
end
for select
sales.code_sale as code_sale,
StructureSale.soldbyprice as soldbyprice
from sales
join StructureSale
on
sales.code_sale=StructureSale.code_sale
where
(DateDays(date_sale)>=:day0) and (DateDays(date_sale)<=:day1) and
(DateSeconds(date_sale)>=:second0) and
(DateSeconds(date_sale)<=:second1)
into
:code_sale, :soldbyprice
as cursor
cur1 do begin
if
(price1>-0.5) then begin /*limited by price*/
if
(price2>-0.5) then begin /*limited by maximum*/
if
((soldbyprice>=price3) and (soldbyprice<=price4) and
(soldbyprice>=price0) and (soldbyprice<=price2))
then
begin
select
count(*) from SearchCodeSales
where code_seance=:code_seance and code_sale=:code_sale
into vrem;
if (vrem=0) then begin
insert into SearchCodeSales values(:CodeSeancePlusMillion, :code_sale);
end
end
end
else
begin
if
((soldbyprice>=price3) and (soldbyprice<=price4) and
(soldbyprice>=price0))
then
begin
select count(*) from SearchCodeSales
where code_seance=:code_seance and code_sale=:code_sale
into vrem;
if (vrem=0) then begin
insert into SearchCodeSales values(:CodeSeancePlusMillion, :code_sale);
end
end
end
end
else begin
if
(price2>-0.5) then begin
if
((soldbyprice<=price2) and (soldbyprice>=price0)) then begin
select count(*) from SearchCodeSales
where code_seance=:code_seance and code_sale=:code_sale
into vrem;
if (vrem=0) then begin
insert into SearchCodeSales values(:CodeSeancePlusMillion, :code_sale);
end
end
end
else if
(soldbyprice>=price0) then begin
select count(*) from SearchCodeSales
where code_seance=:code_seance and code_sale=:code_sale
into
vrem;
if
(vrem=0) then begin
insert into SearchCodeSales values(:CodeSeancePlusMillion, :code_sale);
end
end
end
end
name_good=ToUpperCase(name_good);
name_good='%'||name_good||'%';
art=ToUpperCase(art);
art='%'||art||'%';
if
(scan_code='') then begin
for select
distinct(goods.number_good) from StructureSale join SearchCodeSales
on
StructureSale.code_sale=SearchCodeSales.code_sale join goods
on
StructureSale.number_good=goods.number_good
where
ToUpperCase(goods.name_good) like :name_good and
ToUpperCase(goods.art) like :art and
SearchCodeSales.code_seance=:CodeSeancePlusMillion
into
:number_good2 as cursor cur2 do begin
insert
into SearchNumberGoods values(:code_seance, :number_good2, 0);
end
end
else if
(LengthString(scan_code)<>13) then begin
scan_code='%'||scan_code||'%';
for select
distinct(goods.number_good) from goods join ScanCodes
on
goods.number_good=ScanCodes.number_good join StructureSale
on
goods.number_good=StructureSale.number_good join SearchCodeSales
on
StructureSale.code_sale=SearchCodeSales.code_sale
where
ScanCodes.scan_code like :scan_code and
ToUpperCase(goods.name_good) like :name_good and
ToUpperCase(goods.art) like :art and
SearchCodeSales.code_seance=:CodeSeancePlusMillion
into
:number_good2 as cursor cur3 do begin
insert
into SearchNumberGoods values(:code_seance, :number_good2, 0);
end
end
else begin
for select
distinct(goods.number_good) from goods join ScanCodes
on
goods.number_good=ScanCodes.number_good join StructureSale
on
goods.number_good=StructureSale.number_good join SearchCodeSales
on
StructureSale.code_sale=SearchCodeSales.code_sale
where
ScanCodes.scan_code=:scan_code and
ToUpperCase(goods.name_good) like :name_good and
ToUpperCase(goods.art) like :art and
SearchCodeSales.code_seance=:CodeSeancePlusMillion
into
:number_good2 as cursor cur4 do begin
insert
into SearchNumberGoods values(:code_seance, :number_good2, 0);
end
end
/*delete
useless code_sales*/
for select
StructureSale.code_sale
from sales
join StructureSale
on
sales.code_sale=StructureSale.code_sale join SearchCodeSales
on
sales.code_sale=SearchCodeSales.code_sale join SearchNumberGoods
on
SearchNumberGoods.number_good=StructureSale.number_good
where
SearchNumberGoods.code_seance=:code_seance and
SearchCodeSales.code_seance=:CodeSeancePlusMillion
into
:code_sale as cursor cur5 do begin
select
count(*) from SearchCodeSales
where
code_seance=:code_seance and code_sale=:code_sale
into vrem;
if
(vrem=0) then begin
insert
into SearchCodeSales
values(:code_seance, :code_sale);
end
end
delete from
SearchCodeSales where code_seance=:CodeSeancePlusMillion;
end^
SET TERM ;^
/* UDFs */
DECLARE EXTERNAL FUNCTION LENGTHSTRING
CSTRING(254)
RESULTS INTEGER BY VALUE
ENTRY_POINT 'LengthString' MODULE_NAME
'libraryLengthString.dll';
DECLARE EXTERNAL FUNCTION SUBSTRING
CSTRING(256),INTEGER,INTEGER
RESULTS CSTRING(256)
ENTRY_POINT 'SubString' MODULE_NAME
'librarySubString.dll';
DECLARE EXTERNAL FUNCTION RANDOM
INTEGER
RESULTS INTEGER BY VALUE
ENTRY_POINT 'random' MODULE_NAME 'libraryRandom.dll';
DECLARE EXTERNAL FUNCTION DATEDAYS
TIMESTAMP
RESULTS INTEGER BY VALUE
ENTRY_POINT 'DateDays' MODULE_NAME
'librarydateDaysSeconds.dll';
DECLARE EXTERNAL FUNCTION DATESECONDS
TIMESTAMP
RESULTS INTEGER BY VALUE
ENTRY_POINT 'DateSeconds' MODULE_NAME
'librarydateDaysSeconds.dll';
DECLARE EXTERNAL FUNCTION ROUNDCOPECKS
DOUBLE PRECISION
RESULTS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'RoundCopecks' MODULE_NAME
'libraryRoundCopecks.dll';
DECLARE EXTERNAL FUNCTION TOUPPERCASE
CSTRING(254)
RESULTS CSTRING(254) FREE_IT
ENTRY_POINT 'ToUpperCase' MODULE_NAME
'libraryToUpperCase.dll';
DECLARE EXTERNAL FUNCTION ABS
DOUBLE PRECISION
RESULTS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'abs' MODULE_NAME 'libraryAbs.dll';
DECLARE EXTERNAL FUNCTION SAMESCANCODES
CSTRING(20),CSTRING(20)
RESULTS INTEGER BY VALUE
ENTRY_POINT 'SameScanCodes' MODULE_NAME
'librarySameScanCodes';
procedure
GetDateOfNumber(num_day: integer; var day, month, year: integer);
{íà÷èíàåì âñå ñ 1 ÿíâàðÿ 1901 ãîäà -- 1-é äåíü}
var
Blocks4years:
integer;
begin
if num_day<1 then
September.Error
('September.GetDateOfNumber:
num_day must be not be less than 1');
day:=1;
month:=1; year:=1901;
num_day:=num_day-1; {ñêîëüêî äíåé
åùå íóæíî ïðèáàâèòü}
Blocks4years:=num_day
div 1461;
year:=year+4*Blocks4years;
num_day:=num_day-1461*Blocks4years;
while num_day<>0 do begin
case month of
1: if day<>31 then inc(day) else begin
month:=2; day:=1; end;
2: if year mod 4<>0 then begin
{ãîä íå âèñîêîñíûé}
if day<>28 then inc(day) else begin
month:=3; day:=1; end;
end
else begin {ãîä
âèñîêîñíûé}
if day<>29 then inc(day) else begin
month:=3; day:=1; end;
end;
3: if day<>31 then inc(day) else begin
month:=4; day:=1; end;
4: if day<>30 then inc(day) else begin
month:=5; day:=1; end;
5: if day<>31 then inc(day) else begin
month:=6; day:=1; end;
6: if day<>30 then inc(day) else begin
month:=7; day:=1; end;
7: if day<>31 then inc(day) else begin
month:=8; day:=1; end;
8: if day<>31 then inc(day) else begin
month:=9; day:=1; end;
9: if day<>30 then inc(day) else begin
month:=10; day:=1; end;
10: if day<>31 then inc(day) else begin
month:=11; day:=1; end;
11: if day<>30 then inc(day) else begin
month:=12; day:=1; end;
12: if day<>31 then inc(day) else begin
inc(year); month:=1; day:=1;
end;
end;
dec(num_day);
end;
end;
function IsCorrectFloatString(s: string): boolean;
{ïðîâåðÿåò, ÿâëÿåòñÿ ëè ñòðîêà
êîððåêòíûì âåùåñòâåííûì ÷èñëîì
(áåç ñèìâîëîâ e, E)}
const
EOT=#9;
var
ch: char; {òåêóùèé
ñèìâîë ñòðîêè}
i: integer; {íîìåð
òåêóùåãî ñèìâîëà}
err: boolean; {áûëà ëè
îøèáêà}
procedure ResetText;
begin
s:=s+EOT;
i:=1;
ch:=s[1];
end;
procedure NextCh;
begin
inc(i);
ch:=s[i];
end;
procedure error; {ñèíòàêñè÷åñêàÿ îøèáêà}
begin
i:=length(s);
ch:=s[i];
err:=true;
end;
procedure NaturalNumber;
begin
if ch in
['0'..'9'] then NextCh
else
error;
while
ch in ['0'..'9'] do NextCh;
end;
procedure FloatNumber;
begin
if ch in
['+','-'] then NextCh;
NaturalNumber;
if
(ch='.') or (ch=',') then begin
NextCh;
NaturalNumber;
end;
end;
begin
err:=false;
ResetText;
FloatNumber;
if
ch<>EOT then err:=true;
IsCorrectFloatString:=not err;
end;
function NaturalNumberUp999ToString(x, tip: integer): string;
var
hundreds, units: integer; {ñîòíè è åäèíèöû}
s1, s2: string;
s: string; {ñòðîêà ðåçóëüòàòà}
begin
if not ((x>=0) and (x<=999)) then
September.Error
('September.NaturalNumberUp999ToString: x must between 0
and 999');
hundreds:=x div 100;
units:=x mod 100;
if hundreds=0 then
s:=NaturalNumberUp99ToString(units, tip)
else begin
case hundreds of
1:
s:='ñòî';
2: s:='äâåñòè';
3: s:='òðèñòà';
4: s:='÷åòûðåñòà';
5: s:='ïÿòüñîò';
6: s:='øåñòüñîò';
7: s:='ñåìüñîò';
8: s:='âîñåìüñîò';
9: s:='äåâÿòüñîò';
end;
if
units<>0 then s:=s+'
'+NaturalNumberUp99ToString(units, tip);
end;
NaturalNumberUp999ToString:=s;
end;
Ïðîöåäóðà FloatToLettersMoneyString
function
FloatToLettersMoneyString(x: float): string;
{÷èñëî ìîæåò áûòü ìàêñèìóì 18-çíà÷íûì}
var
{ìàññèâ öèôð ÷èñëà (âìåñòå ñ êîïåéêàìè)}
digits: array
[1..80] of integer; NumDigits:
integer;
function func(i: integer): integer;
{i=0
-- âîçâðàùàåò ðóáëè i=1
-- òûñÿñè i=2
-- ìèëëèîíû
i=3 -- ìèëëèàðäû i=4
-- òðèëëèîíû i=5
-- êâàäðèëëèîíû}
var
d1, d2, d3: integer;
f: integer;
begin
d1:=NumDigits-4-3*i;
d2:=NumDigits-3-3*i;
d3:=NumDigits-2-3*i;
f:=0;
if
d1>=1 then f:=f+100*digits[d1];
if d2>=1 then f:=f+10*digits[d2];
if d3>=1 then f:=f+digits[d3];
func:=f;
end;
var
copecks,
roubles, thousands, millions, milliards,
trillions,
kvadrillions: string;
{òèï çàïèñè ñëîâà
"ðóáëåé" (0 -- ''; 1 -- ðóáëü; 2 -- ðóáëÿ; 3 -- ðóáëåé}
TypeRoubles:
integer;
s: string; {ðåçóëüòàò}
y: integer;
i: integer;
begin
{èçâëåêàåì èç
÷èñëà ìàññèâ öèôð}
September.FloatToMoneyString(x,
s);
NumDigits:=0;
for i:=1 to length(s) do begin
if (s[i]>='0') and (s[i]<='9') then
begin
inc(NumDigits);
digits[NumDigits]:=ord(s[i])-ord('0');
end;
end;
if NumDigits>20 then
September.Error('Error September.FloatToLettersMoneyString: '+
+'chislo
is too long');
TypeRoubles:=0; {èçíà÷àëüíî
ñëîâî ïóñòîå}
{îïðåäåëÿåì
êâàäðèëëèîíû}
y:=func(5);
if y<>0 then
begin
if y<>0 then kvadrillions:=NaturalNumberUp999ToString(y, 1)+' '
else kvadrillions:='';
TypeRoubles:=3;
{òåïåðü íàäî ïèñàòü "ðóáëåé"}
case TypeOfNumber(y) of
1:
kvadrillions:=kvadrillions+'êâàäðèëëèîí ';
2:
kvadrillions:=kvadrillions+'êâàäðèëëèîíà ';
3:
kvadrillions:=kvadrillions+'êâàäðèëëèîíîâ ';
end;
end
else
kvadrillions:='';
{îïðåäåëÿåì òðèëëèîíû}
y:=func(4);
if y<>0 then
begin
if y<>0
then
trillions:=NaturalNumberUp999ToString(y, 1)+' '
else trillions:='';
TypeRoubles:=3;
{òåïåðü íàäî ïèñàòü "ðóáëåé"}
case TypeOfNumber(y) of
1:
trillions:=trillions+'òðèëëèîí ';
2:
trillions:=trillions+'òðèëëèîíà ';
3:
trillions:=trillions+'òðèëëèîíîâ ';
end;
end
else
trillions:='';
{îïðåäåëÿåì ìèëëèàðäû}
y:=func(3);
if y<>0 then
begin
if
y<>0 then
milliards:=NaturalNumberUp999ToString(y, 1)+' '
else milliards:='';
TypeRoubles:=3;
{òåïåðü íàäî ïèñàòü "ðóáëåé"}
case TypeOfNumber(y) of
1:
milliards:=milliards+'ìèëëèàðä ';
2:
milliards:=milliards+'ìèëëèàðäà ';
3:
milliards:=milliards+'ìèëëèàðäîâ ';
end;
end
else
milliards:='';
{îïðåäåëÿåì ìèëëèîíû}
y:=func(2);
if y<>0 then
begin
if y<>0 then millions:=NaturalNumberUp999ToString(y, 1)+' '
else millions:='';
TypeRoubles:=3;
{òåïåðü íàäî ïèñàòü "ðóáëåé"}
case TypeOfNumber(y) of
1:
millions:=millions+'ìèëëèîí ';
2:
millions:=millions+'ìèëëèîíà ';
3:
millions:=millions+'ìèëëèîíîâ ';
end;
end
else
millions:='';
{îïðåäåëÿåì òûñÿ÷è}
y:=func(1);
if y<>0 then
begin
if
y<>0 then
thousands:=NaturalNumberUp999ToString(y, 2)+' '
else thousands:='';
TypeRoubles:=3;
{òåïåðü íàäî ïèñàòü "ðóáëåé"}
case TypeOfNumber(y) of
1:
thousands:=thousands+'òûñÿ÷à ';
2:
thousands:=thousands+'òûñÿ÷è ';
3:
thousands:=thousands+'òûñÿ÷ ';
end;
end
else
thousands:='';
{îïðåäåëÿåì ðóáëè}
y:=func(0);
if y<>0 then
begin
roubles:=NaturalNumberUp999ToString(y, 1)+' ';
{òåïåðü òèï ñëîâà îïðåäåëÿåòñÿ
÷èñëîì ðóáëåé}
TypeRoubles:=TypeOfNumber(y);
end
else
roubles:='';
{îïðåäåëÿÿåì êîïåéêè}
y:=10*digits[NumDigits-1]+digits[NumDigits];
copecks:=inttostr(y);
if y<10 then copecks:='0'+copecks;
case TypeOfNumber(y) of
1:
copecks:=copecks+' êîïåéêà';
2:
copecks:=copecks+' êîïåéêè';
3:
copecks:=copecks+' êîïååê';
end;
{ñîáèðàåì ÷èñëî}
s:=kvadrillions+trillions+milliards+millions+thousands+roubles;
case TypeRoubles of
0:
s:=s+'';
1:
s:=s+'ðóáëü ';
2: s:=s+'ðóáëÿ
';
3:
s:=s+'ðóáëåé ';
end;
s:=s+copecks;
FloatToLettersMoneyString:=s;
end;
Ïðîöåäóðà DrawLine
procedure DrawLine(x1, y1, x2, y2: integer);
var
dx, dy, d, inc1, inc2, s: integer;
a, a2: integer;
buf0: array
[0..SizeX*SizeY-1] of integer absolute buf;
begin
dx:=abs(x2-x1); dy:=abs(y2-y1);
if
dx>dy then begin
inc1:=2*dy; inc2:=2*(dy-dx);
d:=2*dy-dx;
if
x1<x2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if
y1<y2 then s:=SizeX+1
else
s:=-SizeX+1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if
y1>y2 then s:=SizeX+1
else
s:=-SizeX+1;
end;
asm
lea ebx, buf0;
mov edx, dword ptr cc; {dx -- CurrentColor}
shl a, 2; shl a2, 2;
add a, ebx; add a2, ebx;
mov ebx, a; {ebx -- CurrentAddr}
mov ecx, a2; {ecx -- MaxAddr}
mov edi, d; {edi -- d}
mov esi, s; shl esi, 2; {esi -- s*4}
mov
eax, inc2; {eax -- inc2}
mov dword ptr [ebx], edx;
@BeginWhile:
cmp ebx, ecx; je @EndWhile;
cmp edi, 0; jle @ElseIf;
add ebx, esi;
add edi, eax;
jmp @EndIf;
@ElseIf:
add ebx, 4;
add edi, inc1;
@EndIf:
mov dword ptr [ebx], edx;
jmp @BeginWhile;
@EndWhile:
end;
end
{dx>dy}
else
begin
inc1:=2*dx; inc2:=2*(dx-dy);
d:=2*dx-dy;
if y1<y2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if
x1<x2 then s:=SizeX+1
else
s:=SizeX-1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if
x1>x2 then s:=SizeX+1
else
s:=SizeX-1;
end;
asm
lea ebx, buf0;
mov edx, dword ptr cc; {dx --
CurrentColor}
shl a, 2; shl a2, 2;
add a, ebx; add a2, ebx;
mov ebx, a; {ebx -- CurrentAddr}
mov ecx, a2; {ecx -- MaxAddr}
mov edi, d; {edi -- d}
mov esi, s; shl esi, 2; {esi -- s*4}
mov eax, inc2; {eax -- inc2}
mov dword ptr [ebx], edx;
@BeginWhile:
cmp ebx, ecx; je @EndWhile;
cmp edi, 0; jle @ElseIf;
add ebx, esi;
add edi, eax;
jmp @EndIf;
@ElseIf:
add ebx, 4*SizeX;
add edi, inc1;
@EndIf:
mov dword ptr [ebx], edx;
jmp @BeginWhile;
@EndWhile:
end;
end;
end;
procedure DrawGraphLine(NumGrafik: integer);
{ðèñóåì ëèíèþ ãðàôèêà áåç
ñïëàéíà}
var
i, j: integer;
x1, y1, x2, y2: float;
start, stop: integer;
begin
for i:=0 to
GraphLines[NumGrafik].NumberPoints-2 do
begin
x1:=GraphLines[NumGrafik].Points[i].x;
y1:=GraphLines[NumGrafik].Points[i].y;
x2:=GraphLines[NumGrafik].Points[i+1].x;
y2:=GraphLines[NumGrafik].Points[i+1].y;
cc:=GraphLines[NumGrafik].ColorLine;
stop:=GraphLines[NumGrafik].WidthLine div 2;
start:=stop-GraphLines[NumGrafik].WidthLine+1;
for
j:=start to stop do
GraphLine0(x1, y1+j/ScaleY, x2,
y2+j/ScaleY);
end;
end;
procedure
DrawGraphLineWithSpline(NumGrafik: integer);
var
n: integer; {÷èñëî òî÷åê íà
î÷åðåäíîé ëèíèè äëÿ ãðàôèêà}
M: TMatrix; M0: TMatrix0; {ìàòðèöû äëÿ
ìåòîäà Ãàóññà}
x, y: array [0..MaxN] of float; {òî÷êè ëèíèè
ãðàôèêà}
{êîýôôèöèåíòû äëÿ
êóáè÷åñêèõ óðàâíåíèé ñïëàéíîâ}
a, b, c, d: array
[1..MaxN] of float;
x1, y1, x2, y2: float; {êîîðäèíàòû äëÿ
ðèñîâàíèÿ ëèíèé}
u, v: float; {âðåìåííûå
ïåðåìåííûå}
k, MaxK: integer; {ïåðåìåííûå,
çàäàþò êîëè÷åñòâî ëèíèé íà ó÷àñòîê ñïëàéíà}
i, line, j: integer;
start, stop: integer; {äëÿ ðèñîâàíèÿ
òîëñòûõ ëèíèé}
begin
{÷èñëî òî÷åê íà î÷åðåäíîé ëèíèè
ãðàôèêà}
n:=GraphLines[NumGrafik].NumberPoints;
{î÷èùàåì ìàòðèöû äëÿ
ïîñëåäóþùåãî çàïîëíåíèÿ}
MultScalarMatrix(M, 0.0); {îáíóëåíèå
ìàòðèöû}
MultScalarMatrix0(M0, 0.0); {îáíóëåíèå
âåêòîðà ðåøåíèé}
{ïåðåíîñèì ìàññèâ ñ
òî÷êàìè èç ñòðóêòóðû ëèíèè â x[] è y[] (äëÿ óäîáñòâà)}
for i:=0 to
n-1 do begin
x[i]:=GraphLines[NumGrafik].Points[i].x;
y[i]:=GraphLines[NumGrafik].Points[i].y;
end;
{çàïîëíÿåì ìàòðèöû Ãàóññà
èêñàìè è èãðåêàìè â íóæíûõ ìåñòàõ}
for i:=0 to
n-1 do begin
line:=i+1;
M[line,4*i+1]:=x[i]*x[i]*x[i];
M[line,4*i+2]:=x[i]*x[i];
M[line,4*i+3]:=x[i];
M[line,4*i+4]:=1.0;
M0[line]:=y[i];
end;
for
i:=1 to n do begin
line:=i+n;
M[line,4*(i-1)+1]:=x[i]*x[i]*x[i];
M[line,4*(i-1)+2]:=x[i]*x[i];
M[line,4*(i-1)+3]:=x[i];
M[line,4*(i-1)+4]:=1.0;
M0[line]:=y[i];
end;
for
i:=1 to n-1 do begin
line:=i+2*n;
M[line,4*(i-1)+1]:=3.0*x[i]*x[i];
M[line,4*(i-1)+2]:=2.0*x[i];
M[line,4*(i-1)+3]:=1.0;
M[line,4*i+1]:=-3.0*x[i]*x[i];
M[line,4*i+2]:=-2.0*x[i];
M[line,4*i+3]:=-1.0;
end;
for
i:=1 to n-1 do begin
line:=i+3*n-1;
M[line,4*(i-1)+1]:=6.0*x[i];
M[line,4*(i-1)+2]:=2.0;
M[line,4*i+1]:=-6.0*x[i];
M[line,4*i+2]:=-2.0;
end;
line:=4*n-1;
M[line,1]:=6.0*x[0];
M[line,2]:=2.0;
line:=4*n;
M[line,4*(n-1)+1]:=6.0*x[n];
M[line,4*(n-1)+1]:=2.0;
{íàõîäèì ðåøåíèå ìåòîäîì
Ãàóññà}
GaussSolve(M, M0,
4*n, M0);
{ïåðåíîñèì äàííûå èç ìàòðèöû ñ ðåøåíèåì M0 â ìàññèâû a[],b[],c[],d[]}
for i:=1 to n do begin
a[i]:=M0[4*(i-1)+1];
b[i]:=M0[4*(i-1)+2];
c[i]:=M0[4*(i-1)+3];
d[i]:=M0[4*(i-1)+4];
end;
{òåïåðü ðèñóåì ãðàôèê èñõîäÿ èç
êóáè÷åñêèõ óðàâíåíèé ñïëàéíîâ ñ
ïîëó÷åííûìè êîýôôèöèåíòàìè}
for i:=1 to n-1 do begin
MaxK:=round((x[i]-x[i-1])*ScaleX);
for k:=0 to MaxK-1 do begin
u:=x[i-1]+(x[i]-x[i-1])/MaxK*k;
v:=x[i-1]+(x[i]-x[i-1])/MaxK*(k+1);
x1:=u; y1:=a[i]*u*u*u+b[i]*u*u+c[i]*u+d[i];
x2:=v; y2:=a[i]*v*v*v+b[i]*v*v+c[i]*v+d[i];
cc:=GraphLines[NumGrafik].ColorLine;
stop:=GraphLines[NumGrafik].WidthLine div 2;
start:=stop-GraphLines[NumGrafik].WidthLine+1;
for j:=start to stop do
GraphLine0(x1, y1+j/ScaleY, x2, y2+j/ScaleY);
end;
end;
end;
library libraryDateDaysSeconds;
uses SysUtils;
const //êîíñòàíòû
òðàíñëÿöèè äàòû:
MSecsPerDay10=MSecsPerDay*10; //ìèëëèñåêóíä â ñóòêàõ * 10
IBDateDelta=15384;
//ðàçíèöà â äíÿõ ìåæäó äàòàìè Delphi è InterBase
type
PIBDateTime=^TIBDateTime;
TIBDateTime=record
Days, //Date:
Days since 17 November 1858
MSec10: Integer; //Time:
Millisecond * 10 since midnigth
end;
function DateDays(var date: TIBDateTime): integer; cdecl; export;
//íîìåð äíÿ íà÷èíàÿ ñ 1 ÿíâàðÿ 1901 ãîäà
var
date0: TDateTime;
y: double absolute date0;
begin
with date do
date0:=Days-IBDateDelta+MSec10/MSecsPerDay10;
Result:=trunc(y);
end;
function DateSeconds(var date: TIBDateTime): integer; cdecl;
export;
//ñêîëüêî öåëûõ ñåêóíä ïðîøëî ñ íà÷àëà ñóòîê
var
date0: TDateTime;
y: double absolute date0;
begin
with
date do
date0:=Days-IBDateDelta+MSec10/MSecsPerDay10;
Result:=trunc(86400.0*(y-trunc(y)));
end;
exports DateSeconds;
exports DateDays;
begin
end.
UNIT
Skaner;
INTERFACE
USES
SysUtils, Windows, Messages, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, ToolWin, ActnMan, ActnCtrls,
ActnMenus, ExtCtrls,
Math, StdCtrls, Buttons, IniFiles, StrUtils,
September;
procedure
ReadFromPort(var s: TEdit);
procedure
TerminateReadFromPort;
procedure
AddKeyToVirtualPort(Key: integer);
IMPLEMENTATION
type
TThread2 = class(TThread)
private
protected
public
Keys: array [0..63] of integer;
Len: integer;
procedure Execute; override;
end;
var
f: array[1..9] of THandle;
Thread: TThread2;
NumPort: integer; //íîìåð îòêðûòîãî ïîðòà
Edit: {^}TEdit; //ïîëå ââîäà äëÿ èçìåíåíèÿ
{AllowTerminate0, }SkanerOpened01: boolean;
function OpenPort:
boolean;
var
DCB: tDCB;
TimeOut: COMMTimeOuts;
begin
OpenPort:=true;
f[NumPort] := Windows.CreateFile(PChar('COM'+inttostr(NumPort)),
GENERIC_READ or
GENERIC_WRITE, FILE_SHARE_READ or
FILE_SHARE_WRITE,
nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if f[NumPort]=INVALID_HANDLE_VALUE then
begin
OpenPort:=false;
end;
if not Windows.GetCommState(f[NumPort], DCB)
then begin
OpenPort:=false;
end;
DCB.BaudRate := CBR_9600;
DCB.Parity := NOPARITY;
DCB.ByteSize := 8;
DCB.StopBits := ONESTOPBIT;
DCB.Flags := 20625;
DCB.DCBlength := 256;
DCB.EofChar := chr(10);
if not SetCommState(f[NumPort], DCB) then
begin
//raise Exception.Create('Error setting
port state');
OpenPort:=false;
end;
if not PurgeComm(f[NumPort], PURGE_TXCLEAR
or PURGE_RXCLEAR) then begin
//raise Exception.Create('Error purging
port');
OpenPort:=false;
end;
if not SetCommMask(f[NumPort], EV_RXCHAR)
then begin
//raise Exception.Create('Error setting
port mask');
OpenPort:=false;
end;
if not SetupComm(f[NumPort], 256, 256) then
begin
OpenPort:=false;
end;
if PurgeComm(f[NumPort], PURGE_TXABORT or
PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR) then begin
end
else OpenPort:=false;
Windows.GetCommTimeouts(f[NumPort],
TimeOut);
TimeOut.ReadIntervalTimeout:=10;
TimeOut.ReadTotalTimeoutMultiplier:=10;
TimeOut.ReadTotalTimeoutConstant:=100;
Windows.SetCommTimeouts(f[NumPort],
TimeOut);
end;
procedure ClosePort;
begin
{ September.Message('Çàêðûâàåì
ïîðò'+inttostr(NumPort));}
Windows.CloseHandle(f[NumPort]);
end;
var
second: boolean;
procedure
ReadFromPort0(var s: TEdit);
label
label1;
var
bytes: array [0..14] of byte;
readed0: cardinal;
readed: integer;
Buf: array [0..14] of byte;
i: integer;
s0: string;
x: Cardinal;
OK: boolean;
begin
if NumPort<>0 then begin {ExistSkaner}
label1:
readed:=0;
for i:=0 to 14 do bytes[i]:=48;
repeat
ReadFile(f[NumPort], Buf, 15, readed0,
nil);
for i:=readed to readed+readed0-1 do
begin
if i<=14 then
bytes[i]:=Buf[i-readed];
end;
readed:=readed+readed0;
{ if second then readed:=15;}
until readed>=15;
s0:='';
if
not ((bytes[12]>=ord('0')) and (bytes[12]<=ord('9'))) then begin
for i:=11 downto 0 do
bytes[i+1]:=bytes[i];
bytes[0]:=ord('0');
end;
for i:=0 to 12 do s0:=s0+chr(bytes[i]);
for i:=13 to 20 do s0:=s0+chr(ord('a')+random(26));
{ repeat
OK:=false;
try
}
s.Text := s0;
{ OK:=true;
except
end;
until OK;}
PurgeComm(f[NumPort], PURGE_TXABORT or
PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);
sleep(100);
goto label1;
end
else begin
Thread.Len:=0;
for i:=0 to 63 do Thread.Keys[i]:=48;
repeat
s0:='';
for i:=0 to Thread.Len-1 do begin
if Thread.Keys[i]=17 then
s0:=s0+'C'
else s0:=s0+chr(Thread.Keys[i]);
end;
if Length(s0)=14 then begin
delete(s0, 1, 1);
for i:=13 to 20 do
s0:=s0+chr(ord('a')+random(26));
s.Text:=s0;
Thread.Len:=0;
end;
sleep(100);
until false;
end;
end;
procedure
TThread2.Execute;
begin
ReadFromPort0(Edit{^});
end;
procedure
ReadFromPort(var s: TEdit);
var
fl: text;
OK: boolean;
iter: integer;
begin
if not SkanerOpened01 then begin
assign(fl, 'PortSkaner.txt'); reset(fl);
readln(fl, NumPort);
close(fl);
iter:=0;
repeat
if iter<>0 then ClosePort;
if NumPort<>0 then OK:=OpenPort
{ExistSkaner}
else OK:=true;
if not OK then NumPort:=0;
inc(iter);
until (NumPort<>0) or (iter=10);
{
September.Message(inttostr(NumPort));}
{ Thread := TThread2.Create(true);
Thread.FreeOnTerminate := true;
Thread.Priority := tpLower;
Thread.Resume;}
Thread.FreeOnTerminate := true;
Thread.Priority := tpLower;
Thread.Resume;
end;
SkanerOpened01:=true;
Edit := {Addr(}s{)};
{ Thread.Suspend;}
{second:=not second;}
end;
procedure
TerminateReadFromPort;
begin
{ if NumPort<>0 then ClosePort;
Thread.Suspend;
Thread.Terminate;
Thread.DoTerminate;}
end;
procedure
AddKeyToVirtualPort(Key: integer);
var
i: integer;
sdvig: integer;
begin
if (Key>=96) and (Key<=105) then
Key:=Key-48;
if Key=September.klCtrl then begin
if Thread.Len=0 then begin
Thread.Len := 1;
Thread.Keys[0] := klCtrl;
end
else if Thread.Len<14 then begin
sdvig:=14-Thread.Len;
for i:=Thread.Len-1 downto 1 do
Thread.Keys[i+sdvig]:=Thread.Keys[i];
for i:=1 to sdvig do
Thread.Keys[i]:=48;
Thread.Len:=14;
end
else if Thread.Len=14 then begin
//íè÷åãî íå äåëàåì
end
else
September.Error('Skaner.AddKeyToVirtualPort');
end
else if (Key>=48) and (Key<=57) then
begin
if (Thread.Len<>0) and
(Thread.Len<14) then begin
Thread.Keys[Thread.Len]:=Key;
inc(Thread.Len);
end;
end
else if (Key<>0) then begin
Thread.Len:=0;
end;
end;
BEGIN
{second:=false;}
Thread := TThread2.Create(true);
SkanerOpened01:=false;
{AllowTerminate0:=false;}
{ Thread := TThread2.Create(true);}
END.
UNIT KKM;
INTERFACE
uses ComObj,
September;
var
ExistKKM: boolean=true;
function
Connect(Password, ComNumber, BaudRateNumber, Timeout: integer): boolean;
function Connect3:
integer;
function CheckKKM:
boolean; {ïðîâåðÿåì ñîåäèíåíèå ñ êàññîâûì àïïàðàòîì}
function
PrintFiveEmptyStrings: boolean; {íàïå÷àòàòü ïÿòü ïóñòûõ ñòðîê}
function
PrintString(s: string): boolean; {íàïå÷àòàòü ñòðîêó}
function
PrintWideString(s: string): boolean; {íàïå÷àòàòü æèðíóþ ñòðîêó}
function CutCheck:
boolean; {îòðåçàòü ÷åê}
function CancelCheck:
boolean; {àííóëèðîâàòü ÷åê}{íå íàäî ðåçàòü}
function
PrintReportWithoutCleaning: boolean; {ñíÿòü îò÷åò áåç ãàøåíèÿ}{íå íàäî ðåçàòü}
function
PrintReportWithCleaning: boolean; {ñíÿòü îò÷åò ñ ãàøåíèåì}{íå íàäî ðåçàòü}
function
CashIncome(n: float): boolean; {âíåñåíèå äåíåã â êàññó}
function
CashOutcome(n: float): boolean; {çàáîð äåíåã èç êàññû}
function
DefineSummInKass(var summ: float): boolean; {óçíàòü, ñêîëüêî äåíåã â êàññå}
function Sale(good:
string; price, quantity: float): boolean; {ïðîäàæà òîâàðà}
function
ReturnSale(good: string; price, quantity: float): boolean; {âîçâðàò òîâàðà}
function
CloseCheck(summ: float): boolean;{íå íàäî ðåçàòü}
function Beep:
boolean; {ïèïèêíóòü}
function OpenDrawer: boolean;
{îòêðûòü äåíåæíûé ÿùèê}
function
PrintBarCode(BK: string): boolean; {ïå÷àòü øòðèõ-êîäà}
IMPLEMENTATION
uses UnitPrintCheque;
const
namef='cheque.txt';
var
FileOpened: boolean=false;
Driver: OLEVariant;
f: text;
saled: float;
WasSaled: boolean;
function
Connect(Password, ComNumber, BaudRateNumber, Timeout: integer): boolean;
var
x: integer;
begin
Driver := CreateOleObject('Addin.DrvFR');
try
Driver.Password := Password;
Driver.ComNumber := ComNumber;
Driver.BaudRate := BaudRateNumber; {6:
115200}
Driver.Timeout := Timeout;
x:=Driver.Connect;
finally
end;
Connect:=x=0;
end;
function Connect3:
integer;
var
i: integer; {íîìåð COM-ïîðòà}
begin
saled:=0.0;
if not ExistKKM then begin
if FileOpened then begin
FileOpened:=false;
close(f);
end;
assign(f, namef);
Connect3:=1; {ïîäñîåäèíèëèñü!}
Exit;
end;
Connect3:=0;
for i:=1 to 8 do begin {i -- íîìåð
com-ïîðòà}
if Connect(30, i, 6, 100) then begin
Connect3:=i;
exit;
end;
end;
end;
function CheckKKM:
boolean; {ïðîâåðÿåì ñîåäèíåíèå ñ êàññîâûì àïïàðàòîì}
var
Connected: integer;
begin
Connected:=KKM.Connect3;
CheckKKM:=Connected<>0;
end;
procedure OpenFile;
begin
if not FileOpened then begin assign(f,
namef); rewrite(f); FileOpened:=true; end;
end;
procedure CloseFile;
begin
if FileOpened then close(f);
FileOpened:=false;
end;
function
PrintFiveEmptyStrings: boolean;
var
i: integer;
begin
if not ExistKKM then begin
OpenFile;
for i:=1 to 5 do writeln(f);
PrintFiveEmptyStrings:=true;
end
else begin
Driver.StringForPrinting := ' ';
for i:=1 to 5 do Driver.PrintString;
PrintFiveEmptyStrings:=Driver.ResultCode=0;
end;
end;
function
PrintString(s: string): boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, s);
PrintString:=true;
end
else begin
if s<>'' then begin
Driver.StringForPrinting := s;
Driver.PrintString;
PrintString:=Driver.ResultCode=0;
end
else PrintString:=true;
end;
end;
function
PrintWideString(s: string): boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, s);
PrintWideString:=true;
end
else begin
if s<>'' then begin
Driver.StringForPrinting := s;
Driver.PrintWideString;
PrintWideString:=Driver.ResultCode=0;
end
else PrintWideString:=true;
end;
end;
function CutCheck:
boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, '!!! -- ×ÅÊ ÎÁÐÅÇÀÍ -- !!!');
CutCheck:=true;
CloseFile; FormPrintCheque.ShowModal;
end
else begin
Driver.CutCheck;
CutCheck:=Driver.ResultCode=0;
end;
end;
function CancelCheck:
boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, '!!! -- ×ÅÊ ÎÒÌÅÍÅÍ -- !!!');
CancelCheck:=true;
CloseFile; FormPrintCheque.ShowModal;
end
else begin
Driver.CancelCheck;
CancelCheck:=Driver.ResultCode=0;
end;
end;
function
PrintReportWithoutCleaning: boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, 'Íå ìîãó íàïå÷àòàòü îò÷åò áåç ãàøåíèÿ áåç
êàññîâîãî àïïàðàòà!');
PrintReportWithoutCleaning:=true;
CloseFile; FormPrintCheque.ShowModal;
end
else begin
Driver.PrintReportWithoutCleaning;
PrintReportWithoutCleaning:=Driver.ResultCode=0;
end;
end;
function
PrintReportWithCleaning: boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, 'Íå ìîãó íàïå÷àòàòü îò÷åò ñ ãàøåíèåì áåç êàññîâîãî
àïïàðàòà!');
PrintReportWithCleaning:=true;
CloseFile; FormPrintCheque.ShowModal;
end
else begin
Driver.PrintReportWithCleaning;
PrintReportWithCleaning:=Driver.ResultCode=0;
end;
end;
function
CashIncome(n: float): boolean;
var
s: string;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, 'Â êàññó âíåñåíû äåíüãè!');
September.FloatToMoneyString(n, s);
writeln(f, '('+s+' ðóáëåé)');
CashIncome:=true;
end
else begin
Driver.Summ1 := n;
Driver.CashIncome;
CashIncome:=Driver.ResultCode=0;
end;
end;
function
CashOutcome(n: float): boolean;
var
s: string;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, 'Èç êàññû çàáðàíû äåíüãè!');
September.FloatToMoneyString(n, s);
writeln(f, '('+s+' ðóáëåé)');
CashOutcome:=true;
end
else begin
Driver.Summ1 := n;
Driver.CashOutcome;
CashOutcome:=Driver.ResultCode=0;
end;
end;
function
DefineSummInKass(var summ: float): boolean;
begin
if not ExistKKM then begin
summ:=5000.00;
DefineSummInKass:=true;
end
else begin
Driver.RegisterNumber := 241;
Driver.GetCashReg;
if Driver.ResultCode=0 then begin
summ:=Driver.ContentsOfCashRegister;
DefineSummInKass:=true;
end
else DefineSummInKass:=false;
end;
end;
function Sale(good:
string; price, quantity: float): boolean;
var
s: string;
s0: string;
summa: float;
begin
WasSaled:=true;
if not ExistKKM then begin
OpenFile;
if length(good)>36 then
SetLength(good, 36);
writeln(f, good);
summa:=September.CalculateSumma(price,
quantity);
if (quantity>=0.9999) and
(quantity<=1.0001) then begin
September.FloatToMoneyString(price,
s);
s:='='+s;
while length(s)<>36 do s:=' '+s;
writeln(f, s);
end
else begin
str(quantity:0:3, s);
September.FloatToMoneyString(price,
s0);
s:=s+' X '+s0;
while length(s)<>36 do s:=' '+s;
September.DotsToCommas(s);
writeln(f, s);
September.FloatToMoneyString(summa,
s);
s:='='+s;
while length(s)<>36 do s:=' '+s;
writeln(f, s);
end;
saled:=saled+summa;
Sale:=true;
end
else begin
if length(good)>36 then
SetLength(good, 36);
Driver.StringForPrinting := good;
Driver.Quantity := quantity; {êîëè÷åñòâî}
Driver.Price := price; {öåíà}
Driver.Sale;
Sale:=Driver.ResultCode=0;
{ September.Message(Driver.ResultCode);}
end;
end;
function
ReturnSale(good: string; price, quantity: float): boolean;
var
s: string;
s0: string;
summa: float;
begin
WasSaled:=false;
if not ExistKKM then begin
OpenFile;
if length(good)>36 then
SetLength(good, 36);
writeln(f, good);
summa:=September.CalculateSumma(price,
quantity);
if (quantity>=0.9999) and
(quantity<=1.0001) then begin
September.FloatToMoneyString(price,
s);
s:='='+s;
while length(s)<>36 do s:=' '+s;
writeln(f, s);
end
else begin
str(quantity:0:3, s);
September.FloatToMoneyString(price,
s0);
s:=s+' X '+s0;
while length(s)<>36 do s:=' '+s;
September.DotsToCommas(s);
writeln(f, s);
September.FloatToMoneyString(summa,
s);
s:='='+s;
while length(s)<>36 do s:=' '+s;
writeln(f, s);
end;
saled:=saled+summa;
ReturnSale:=true;
end
else begin
if length(good)>36 then
SetLength(good, 36);
Driver.StringForPrinting := good;
Driver.Quantity := quantity; {êîëè÷åñòâî}
Driver.Price := price; {öåíà}
Driver.ReturnSale;
ReturnSale:=Driver.ResultCode=0;
end;
end;
function
CloseCheck(summ: float): boolean;
var
s: string;
begin
if not ExistKKM then begin
{ str(saled:0:3, s);
September.Message(s);}
if (WasSaled and
(abs(saled-summ)>=0.001)) or (not WasSaled and (abs(saled-summ)>=0.001))
then begin
CloseCheck:=false;
end
else begin
OpenFile;
writeln(f, '====================================');
September.FloatToMoneyString(summ, s);
while length(s)<32 do s:=' '+s;
s:='ÈÒÎÃ'+s;
writeln(f, s);
if WasSaled then writeln(f, '!!! ---
×ÅÊ ÏÎÊÓÏÊÈ ÇÀÊÐÛÒ --- !!!')
else writeln(f, '!!! --- ×ÅÊ ÂÎÇÂÐÀÒÀ ÇÀÊÐÛÒ --- !!!');
CloseCheck:=true;
CloseFile; FormPrintCheque.ShowModal;
end;
end
else begin
if WasSaled then
Driver.StringForPrinting:='
ÑÏÀÑÈÁÎ ÇÀ ÏÎÊÓÏÊÓ! '
else Driver.StringForPrinting:='';
Driver.Summ1:=summ;
Driver.CloseCheck;
CloseCheck:=Driver.ResultCode=0;
end;
end;
function Beep:
boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, '!!! -- ÏÈÏÈÊÍÓËÈ -- !!!');
Beep:=true;
end
else begin
Driver.Beep;
Beep:=Driver.ResultCode=0;
end;
end;
function OpenDrawer:
boolean;
begin
if not ExistKKM then begin
OpenFile;
writeln(f, '!!! ÄÅÍÅÆÍÛÉ ßÙÈÊ ÎÒÊÐÛËÈ !!!');
OpenDrawer:=true;
end
else begin
Driver.OpenDrawer;
OpenDrawer:=Driver.ResultCode=0;
end;
end;
function PrintBarCode(BK:
string): boolean;
begin
delete(BK, 13, 1);
Driver.BarCode:=BK;
Driver.PrintBarCode;
end;
END.
UNIT BGL;
INTERFACE
USES
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, IBStoredProc, StdCtrls, DB,
IBDatabase, IBCustomDataSet,
IBQuery, Grids, DBGrids, September, Menus,
ExtCtrls, TeeProcs, TeEngine, Chart;
const
SizeX=1024; SizeY=768;
getmaxx=SizeX-1; getmaxy=SizeY-1;
red=65536; green=256; blue=1;
white=red+green+blue;
type
tBuf=array [0..getmaxy, 0..getmaxx] of
integer;
tFont=record
width, height: integer;
TextMassiv: array [0..255, 0..63, 0..31]
of boolean;
end;
var
Buf: TBuf;
fonts: array[8..20] of tFont;
cc, bc: integer;
ColorText, ColorBGText: integer;
xleft, xright, ytop, ybottom: integer;
wherex, wherey: longint;
FontSize: integer;
TransparentText: boolean;
procedure
BufToBitMap(var BitMap: TBitMap);
procedure
BitMapToBuf(var BitMap: TBitMap);
procedure
ClearDevice;
procedure
DrawLine(x1, y1, x2, y2: longint);
procedure SetColor(r,
g, b: integer);
procedure
SetBgColor(r, g, b: integer);
procedure line(x1,
y1, x2, y2: longint);
procedure
SetViewPort(xl, yt, xr, yb: longint);
procedure putpixel(x,
y: longint);
procedure InitText;
procedure gotoxy(x,
y: longint);
procedure
textbackground(r, g, b: longint);
procedure
textcolor(r, g, b: longint);
procedure putchar(ch:
char);
procedure writes(s:
string);
procedure
DoFontFromBMPFile(FontSize: integer);
IMPLEMENTATION
var
x, y: integer;
procedure
BufToBitMap(var BitMap: TBitMap);
var
r, g, b: integer;
color: integer;
begin
for x:=0 to BitMap.Width-1 do begin
for y:=0 to BitMap.Height-1 do begin
color:=Buf[y,x];
b:=color and 255;
g:=(color and (255*green)) div green;
r:=(color and (255*red)) div red;
color:=r*blue+g*green+b*red;
BitMap.Canvas.Pixels[x,y]:=color;
end;
end;
end;
procedure
BitMapToBuf(var BitMap: TBitMap);
var
r, g, b: integer;
color: integer;
begin
for x:=0 to BitMap.Width-1 do begin
for y:=0 to BitMap.Height-1 do begin
color:=BitMap.Canvas.Pixels[x,y];
b:=color and 255;
g:=(color and (255*green)) div green;
r:=(color and (255*red)) div red;
color:=r*blue+g*green+b*red;
Buf[y,x]:=color;
end;
end;
end;
procedure
ClearDevice;
begin
for y:=0 to getmaxy do
for x:=0 to getmaxx do
Buf[y,x]:=bc;
end;
procedure
DoBWColor(var x: integer);
var
c: integer;
b: array[0..3] of byte absolute x;
begin
c:=x;
x:=(65536+256+1)*((3*b[2]+6*b[1]+b[0]) div
10);
end;
procedure
DrawLine(x1, y1, x2, y2: integer);
var
dx, dy, d, inc1, inc2, s: integer;
a, a2: integer;
buf0: array [0..SizeX*SizeY-1] of integer
absolute buf;
begin
dx:=abs(x2-x1); dy:=abs(y2-y1);
if dx>dy then begin
inc1:=2*dy; inc2:=2*(dy-dx);
d:=2*dy-dx;
if x1<x2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if y1<y2 then s:=SizeX+1
else s:=-SizeX+1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if y1>y2 then s:=SizeX+1
else s:=-SizeX+1;
end;
asm
lea ebx, buf0;
mov edx, dword ptr cc; {dx --
CurrentColor}
shl a, 2; shl a2, 2;
add a, ebx; add a2, ebx;
mov ebx, a; {ebx -- CurrentAddr}
mov ecx, a2; {ecx -- MaxAddr}
mov edi, d; {edi -- d}
mov esi, s; shl esi, 2; {esi --
s*4}
mov eax, inc2; {eax -- inc2}
mov dword ptr [ebx], edx;
@BeginWhile:
cmp ebx, ecx; je @EndWhile;
cmp edi, 0; jle @ElseIf;
add ebx, esi;
add edi, eax;
jmp @EndIf;
@ElseIf:
add ebx, 4;
add edi, inc1;
@EndIf:
mov dword ptr [ebx], edx;
jmp @BeginWhile;
@EndWhile:
end;
end {dx>dy}
else begin
inc1:=2*dx; inc2:=2*(dx-dy);
d:=2*dx-dy;
if
y1<y2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if x1<x2 then s:=SizeX+1
else s:=SizeX-1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if x1>x2 then s:=SizeX+1
else s:=SizeX-1;
end;
asm
lea ebx, buf0;
mov edx, dword ptr cc; {dx --
CurrentColor}
shl a, 2; shl a2, 2;
add a, ebx; add a2, ebx;
mov ebx, a; {ebx -- CurrentAddr}
mov ecx, a2; {ecx -- MaxAddr}
mov edi, d; {edi -- d}
mov esi, s; shl esi, 2; {esi --
s*4}
mov eax, inc2; {eax -- inc2}
mov dword ptr [ebx], edx;
@BeginWhile:
cmp ebx, ecx; je @EndWhile;
cmp edi, 0; jle @ElseIf;
add ebx, esi;
add edi, eax;
jmp @EndIf;
@ElseIf:
add ebx, 4*SizeX;
add edi, inc1;
@EndIf:
mov dword ptr [ebx], edx;
jmp @BeginWhile;
@EndWhile:
end;
end;
end;
(*
procedure
DrawLine(x1, y1, x2, y2: integer);
var
dx, dy, d, inc1, inc2, s: integer;
a, a2: integer;
buf0: array [0..SizeX*SizeY-1] of integer
absolute buf;
begin
dx:=abs(x2-x1); dy:=abs(y2-y1);
if dx>dy then begin
inc1:=2*dy; inc2:=2*(dy-dx);
d:=2*dy-dx;
if x1<x2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if y1<y2 then s:=SizeX+1
else s:=-SizeX+1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if y1>y2 then s:=SizeX+1
else s:=-SizeX+1;
end;
buf0[a]:=cc;
while a<>a2 do begin
if d>0 then begin
a:=a+s;
d:=d+inc2;
end
else begin
a:=a+1;
d:=d+inc1;
end;
buf0[a]:=cc;
end;
end {dx>dy}
else begin
inc1:=2*dx; inc2:=2*(dx-dy);
d:=2*dx-dy;
if y1<y2 then begin
a:=SizeX*y1+x1;
a2:=SizeX*y2+x2;
if x1<x2 then s:=SizeX+1 {!!!}
else s:=SizeX-1;
end
else begin
a:=SizeX*y2+x2; a2:=SizeX*y1+x1;
if x1>x2 then s:=SizeX+1 {!!!}
else s:=SizeX-1;
end;
buf0[a]:=cc;
while a<>a2 do begin
if d>0 then begin
a:=a+s;
d:=d+inc2;
end
else begin
a:=a+SizeX;
d:=d+inc1;
end;
buf0[a]:=cc;
end;
end;
end;
*)
procedure SetColor(r,
g, b: integer);
begin
cc:=r*red+g*green+b*blue;
end;
procedure
SetBgColor(r, g, b: integer);
begin
bc:=r*red+g*green+b*blue;
end;
procedure line(x1,
y1, x2, y2: longint);
type
tCode=set of 0..3;
procedure Coding(x,
y: integer; var code: tCode);
begin
code:=[];
if x<xleft then code:=code+[0]
else if x>xright then code:=code+[1];
if y<ytop then code:=code+[2]
else if y>ybottom then code:=code+[3];
end;
var
code1, code2: tCode;
inside: boolean;
x, y: integer;
code: tCode;
reg1, reg2, reg3, reg4: integer;
begin
x1:=x1+xleft; x2:=x2+xleft;
y1:=y1+ytop; y2:=y2+ytop;
Coding(x1, y1, code1);
Coding(x2, y2, code2);
inside:=code1+code2=[];
while not inside and (code1*code2=[]) do
begin
if code1=[] then begin
reg1:=x1; reg3:=y1; reg2:=x2;
reg4:=y2;
x1:=reg2; y1:=reg4; x2:=reg1;
y2:=reg3;
code:=code1; code1:=code2;
code2:=code;
end;
if x1<xleft then begin {îòñå÷åíèå
ñëåâà}
y1:=y1+round((y2-y1)/(x2-x1)*(xleft-x1));
x1:=xleft;
end
else if x1>xright then begin
{îòñå÷åíèå ñïðàâà}
y1:=y1+round((y2-y1)/(x2-x1)*(xright-x1));
x1:=xright;
end
else if y1<ytop then begin {îòñå÷åíèå
ñâåðõó}
x1:=x1+round((x2-x1)/(y2-y1)*(ytop-y1));
y1:=ytop;
end
else if y1>ybottom then begin
{îòñå÷åíèå ñíèçó}
x1:=x1+round((x2-x1)/(y2-y1)*(ybottom-y1));
y1:=ybottom;
end;
Coding(x1, y1, code1);
inside:=(code1+code2)=[];
end;
if inside then DrawLine(x1, y1, x2, y2);
end;
procedure
SetViewPort(xl, yt, xr, yb: longint);
begin
if (xl>=0) and (xr<=getmaxx) and
(xl<xr) and
(yt>=0) and (yb<=getmaxy) and
(yt<yb)
then begin
xleft:=xl;
xright:=xr;
ytop:=yt;
ybottom:=yb;
end
else begin
if xl<0 then September.error('Error
SetViewPort (xleft<0)');
if yt<0 then September.error('Error
SetViewPort (ytop<0)');
if xr>getmaxx then
September.error('Error SetViewPort (xright>getmaxx)');
if yb>getmaxy then September.error('Error
SetViewPort (ybottom>getmaxy)');
if xl>=xr then September.error('Error
SetViewPort (xleft>=xright)');
if yt>=yb then September.error('Error
SetViewPort (ytop>=ybottom)');
end;
end;
procedure putpixel(x,
y: longint);
begin
line(x, y, x, y);
end;
procedure InitText;
var
f: text;
size: integer;
symbol: integer;
ch: char;
x, y: integer;
namef: string;
begin
for size:=8 to 8 do begin
namef:='font'+inttostr(size)+'_'+inttostr(fonts[size].width)+'_'+inttostr(fonts[size].height);
assign(f, 'myfonts\'+namef+'.gaz');
reset(f);
for symbol:=0 to 255 do
for y:=0 to 63 do
for x:=0 to 31 do
fonts[size].TextMassiv[symbol,y,x]:=false;
for symbol:=32 to 255 do begin
for y:=0 to fonts[size].height-1 do
begin
for x:=0 to fonts[size].width-1 do
begin
read(f, ch);
if ch='W' then
fonts[size].TextMassiv[symbol,y,x]:=true;
end;
readln(f);
end;
readln(f);
end;
close(f);
end;
end;
procedure gotoxy(x,
y: longint);
begin
wherex:=x;
wherey:=y;
end;
procedure
textbackground(r, g, b: longint);
begin
ColorBGText:=r*red+g*green+b*blue;
end;
procedure
textcolor(r, g, b: longint);
begin
ColorText:=r*red+g*green+b*blue;
end;
procedure putchar(ch:
char);
var
x, y: longint;
OldBC, OldCC: longint;
begin
OldBC:=bc; OldCC:=cc;
for x:=0 to Fonts[FontSize].width-1 do begin
for y:=0 to Fonts[FontSize].height-1 do
begin
if (x>=0) and (x<=getmaxx) and
(y>=0) and (y<=getmaxy) then begin
if
fonts[FontSize].TextMassiv[ord(ch), y, x] then begin
cc:=ColorText;
putpixel(WhereX+x+xleft,
WhereY+y+ytop);
end
else if not TransparentText then
begin
cc:=ColorBGText;
putpixel(WhereX+x+xleft,
WhereY+y+ytop);
end;
end;
end;
end;
bc:=OldBC; cc:=OldCC;
end;
procedure writes(s:
string);
var
i:
longint;
begin
i:=length(s);
for i:=1 to length(s) do begin
putchar(s[i]);
inc(wherex, fonts[FontSize].width);
end;
end;
procedure
DoFontFromBMPFile(FontSize: integer);
var
f: text;
namef: string;
BitMap: TBitMap;
x, y: integer;
StartX, StartY: integer;
symbol: integer;
w, h: integer;
begin
w:=fonts[FontSize].width;
h:=fonts[FontSize].height;
namef:='font'+inttostr(FontSize)+'_'+inttostr(w)+'_'+inttostr(h);
BitMap:=TBitmap.Create;
BitMap.LoadFromFile('myfonts\'+namef+'.bmp');
assign(f, 'myfonts\'+namef+'.gaz');
rewrite(f);
for symbol:=32 to 255 do begin
StartX:=w*((symbol-32) mod 16);
StartY:=h*((symbol-32) div 16);
for y:=StartY to StartY+h-1 do begin
for x:=StartX to StartX+w-1 do begin
if BitMap.Canvas.Pixels[x,y]=0 then
write(f, 'W')
else write(f, ' ');
end;
writeln(f);
end;
writeln(f);
end;
close(f);
end;
BEGIN
cc:=0; bc:=255*(red+green+blue);
ColorText:=cc; ColorBgText:=bc;
SetViewPort(0, 0, getmaxx, getmaxy);
TransparentText:=false; FontSize:=8;
fonts[8].width:=7; fonts[8].height:=14;
InitText;
for y:=0 to getmaxy do
for x:=0 to getmaxx do
Buf[y,x]:=random(255);
END.