Ãëàâíàÿ    Àâòîìàòèçàöèÿ òîðãîâëè

Ïðèìå÷àíèå: çäåñü íàõîäèòñÿ îïèñàíèå ñòàðîé âåðñèè ïðîãðàììû True Shop 1.47 (ãîä âûïóñêà 2007). Ïðîãðàììà áûëà óñïåøíî âíåäðåíà è ðàáîòàëà áîëåå îäíîãî ãîäà. Ëþäÿì ïðîãðàììà ïîíðàâèëàñü è áûëî ïðèíÿòî ðåøåíèå âûïóñòèòü âòîðóþ âåðñèþ. Ïåðâàÿ âåðñèÿ ïðîãðàììû íå ñîäåðæèò èíñòàëëÿòîðà, è âîçìîæíîñòåé ó íå¸ íàìíîãî ìåíüøå, ÷åì ó âòîðîé âåðñèè (ðàç â ïÿòü). Ïîýòîìó å¸ îïèñàíèå çäåñü âûëîæåíî òîëüêî äëÿ îçíàêîìëåíèÿ. Îïèñàíèå àêòóàëüíîé âåðñèè ïðîãðàììû äëÿ àâòîìàòèçàöèè òîðãîâëè ìîæíî ïîñìîòðåòü çäåñü.







ÔÅÄÅÐÀËÜÍÎÅ ÀÃÅÍÒÑÒÂÎ ÏÎ ÎÁÐÀÇÎÂÀÍÈÞ ÐÔ

ÃÎÑÓÄÀÐÑÒÂÅÍÍÎÅ ÎÁÐÀÇÎÂÀÒÅËÜÍÎÅ Ó×ÐÅÆÄÅÍÈÅ ÂÛÑØÅÃÎ ÏÐÎÔÅÑÑÈÎÍÀËÜÍÎÃÎ ÎÁÐÀÇÎÂÀÍÈß

ÂÎËÎÃÎÄÑÊÈÉ ÃÎÑÓÄÀÐÑÒÂÅÍÍÛÉ ÏÅÄÀÃÎÃÈ×ÅÑÊÈÉ ÓÍÈÂÅÐÑÈÒÅÒ

 

 

 

 

 

 

 

 

 

ÂÛÏÓÑÊÍÀß ÊÂÀËÈÔÈÊÀÖÈÎÍÍÀß ÐÀÁÎÒÀ

 

ÍÀ ÒÅÌÓ:

 

«Àâòîìàòèçàöèÿ ðàáîòû õîçÿéñòâåííîãî ìàãàçèíà»

 

 

 

 

 

Âûïîëíèë: ñòóäåíò 5 êóðñà

ôàêóëüòåòà ÏÌèÊÒ

Ãîð÷àêîâ Èâàí Ìèõàéëîâè÷

 

Íàó÷íûé ðóêîâîäèòåëü:

ê.ò.í., ïðîôåññîð

Ðæåóöêàÿ Ñâåòëàíà Þðüåâíà

 

 

 

 

 

 

 

 

Âîëîãäà

2007

ÑÎÄÅÐÆÀÍÈÅ

ÂÂÅÄÅÍÈÅ    4

1. ÀÍÀËÈÇ ÏÐÅÄÌÅÒÍÎÉ ÎÁËÀÑÒÈ È ÎÏÐÅÄÅËÅÍÈÅ ÒÐÅÁÎÂÀÍÈÉ Ê ÑÈÑÒÅÌÅ    5

1.1. Àíàëèç êðóãà ïîëüçîâàòåëåé   5

1.3. Òðåáîâàíèÿ çàêàç÷èêà ê ïîëüçîâàòåëüñêîìó èíòåðôåéñó  7

2. ÏÐÎÅÊÒÍÀß ×ÀÑÒÜ    8

2.1. Ñèñòåìà áèçíåñ-ïðàâèë   8

2.2. Ëîãè÷åñêàÿ ñõåìà áàçû äàííûõ: 10

2.2.1. Îïèñàíèå ñòðóêòóðû òàáëèö  10

2.2.2. Íîðìàëèçàöèÿ áàçû äàííûõ  14

2.3. Àðõèòåêòóðà ñèñòåìû    16

3. ÐÅÀËÈÇÀÖÈß    17

3.1. Ôèçè÷åñêàÿ ñõåìà ÁÄ   17

3.2. Îñîáåííîñòè ðåàëèçàöèè ïðèëîæåíèÿ   19

3.3. Îïèñàíèå ïîëüçîâàòåëüñêîãî èíòåðôåéñà   20

3.4. Àëãîðèòìû    34

4. ÒÅÑÒÈÐÎÂÀÍÈÅ ÏÐÎÃÐÀÌÌÛ     52

4.1. Ïåðâûé ýòàï òåñòèðîâàíèÿ   52

4.2. Âòîðîé ýòàï òåñòèðîâàíèÿ   55

4.3. Òðåòèé ýòàï òåñòèðîâàíèÿ   56

4.4. ×åòâåðòûé ýòàï òåñòèðîâàíèÿ   56

4.5. Ïÿòûé ýòàï òåñòèðîâàíèÿ   56

5. ÁÅÇÎÏÀÑÍÎÑÒÜ ÄÀÍÍÛÕ    60

ÇÀÊËÞ×ÅÍÈÅ    61

Ñïèñîê ëèòåðàòóðû    62

ÏÐÈËÎÆÅÍÈß    63

1. Ñöåíàðèé ñîçäàíèÿ ÁÄ   63

2. Òåêñòû çàïðîñîâ, õðàíèìûõ ïðîöåäóð, òðèããåðîâ   69

3. Îáðàçåö ïðîãðàììíîãî êîäà   107

Ïðîöåäóðà GetDateOfNumber 107

Ïðîöåäóðà IsCorrectFloatString  108

Ïðîöåäóðà NaturalNumberUp999ToString  109

Ïðîöåäóðà DrawGraphLine  113

Ïðîöåäóðà DrawGraphLineWithSpline  113

Ôóíêöèè DateDays, DateSeconds áèáëèîòåêè libraryDateDaysSeconds  114

Ìîäóëü äëÿ ðàáîòû ñî ñêàíåðîì   115

Ìîäóëü äëÿ ðàáîòû ñ êàññîâûì àïïàðàòîì   118

Ìîäóëü BGL  123


ÂÂÅÄÅÍÈÅ

Öåëü äàííîé ðàáîòû çàêëþ÷àåòñÿ â àâòîìàòèçàöèè ðàáîòû íåáîëüøîãî õîçÿéñòâåííîãî ìàãàçèíà. Äàííàÿ îðãàíèçàöèÿ çàíèìàåòñÿ òåì, ÷òî ïðèâîçèò õîçòîâàðû ñ îïòîâûõ áàç, çàòåì òîðãóåò èìè. Äàííàÿ ïðîãðàììà ïîçâîëÿåò îïåðàòèâíî ôèêñèðîâàòü îñòàòêè òîâàðîâ íà ñêëàäå, öåíû íà òîâàðû, ïðîäàâàòü òîâàðû (ïðîáèâàòü ÷åêè, ïå÷àòàòü òîâàðíûå ÷åêè, ôèêñèðîâàòü ïðîäàæè â áàçå äàííûõ) è äåëàòü âîçâðàò. Òàêæå ïðîãðàììà äàåò ñòàòèñòèêó ðàáîòû ìàãàçèíà (îáùàÿ ïðèáûëüíîñòü ìàãàçèíà, çàâèñèìîñòü ÷èñëà ïîêóïàòåëåé è ïðèáûëüíîñòè îò âðåìåíè ñóòîê, îò äíÿ íåäåëè, îò ÷èñëà ìåñÿöà, îò ìåñÿöà, îò âðåìåíè ãîäà è ò. ä.). Ïðîãðàììà òàêæå ñîäåðæèò îò÷åòû, íåîáõîäèìûå äëÿ íîðìàëüíîé ðàáîòû ìàãàçèíà. Ïî æåëàíèþ çàêàç÷èêà â íåå ìîãóò áûòü äîáàâëåíû íîâûå îò÷åòû, íåîáõîäèìûå åìó, êîòîðûõ íåò â äàííîé ïðîãðàììå.

Ïîäîáíûå ïðîãðàììû óæå, êîíå÷íî, ñóùåñòâóþò, íî äàííàÿ ïðîãðàììà èìååò ïåðåä íèìè íåêîòîðûå ïðåèìóùåñòâà:

1)     Ïðîãðàììà ñîäåðæèò òîëüêî íåîáõîäèìûå ôóíêöèè è íè÷åãî ëèøíåãî, òàêæå ó íåå ïðîñòîé è ïîíÿòíûé ïîëüçîâàòåëüñêèé èíòåðôåéñ. Ïîýòîìó ñ íåé ìîãóò ðàáîòàòü ïîëüçîâàòåëè, íå î÷åíü õîðîøî ðàçáèðàþùèåñÿ â êîìïüþòåðàõ.

2)     Ïðîãðàììà ïîçâîëÿåò ìàêñèìàëüíî ëåãêî è áûñòðî ââîäèòü òîâàðû, ïðèâåçåííûå ñ îïòîâûõ áàç, à òàêæå âûïîëíÿòü ïîèñê ïî çàäàííûì ïàðàìåòðàì.

3)     Ïðîãðàììà ìîæåò áûòü äîðàáîòàíà ïî æåëàíèþ çàêàç÷èêà (èçìåíåí èíòåðôåéñ, äîáàâëåíû íîâûå âîçìîæíîñòè (íîâûå âèäû ïîèñêà, îò÷åòíîñòü, ñòàòèñòèêà)).

4)     Åñëè ó çàêàç÷èêà âîçíèêíóò êàêèå-ëèáî ïðîáëåìû ñ ïðîãðàììîé, îíè ìîãóò áûòü ðåøåíû ñ ìèíèìàëüíûìè çàòðàòàìè ñèë è ñ ìàêñèìàëüíîé ýôôåêòèâíîñòüþ (òàê êàê àâòîð ñàì ðàçðàáàòûâàë ïðîãðàììó ñ íóëÿ).


 

1. ÀÍÀËÈÇ ÏÐÅÄÌÅÒÍÎÉ ÎÁËÀÑÒÈ È ÎÏÐÅÄÅËÅÍÈÅ ÒÐÅÁÎÂÀÍÈÉ Ê ÑÈÑÒÅÌÅ

1.1. Àíàëèç êðóãà ïîëüçîâàòåëåé

Ïðîãðàììîé äîëæíû ïîëüçîâàòüñÿ ñëåäóþùèå ðàáîòíèêè ïðåäïðèÿòèÿ:

1)     Êàññèð

2)     Ìåíåäæåð

3)     Ðóêîâîäèòåëü ïðåäïðèÿòèÿ

Äëÿ êàæäîãî èç ñîòðóäíèêîâ ïðåäïðèÿòèÿ ïðîãðàììà äîëæíà îáåñïå÷èâàòü ñëåäóþùèå âîçìîæíîñòè:

1)     Êàññèðó – âîçìîæíîñòü áûñòðî íàõîäèòü íóæíóþ èíôîðìàöèþ â áàçå, ïðîäàâàòü òîâàðû è äåëàòü âîçâðàò îò ïîêóïàòåëÿ.

2)     Ìåíåäæåðó – âîçìîæíîñòü çàíîñèòü òîâàðû, ïðèâåçåííûå ñ îïòîâûõ áàç, áûñòðî íàõîäèòü íóæíóþ èíôîðìàöèþ â áàçå (êàêèå òîâàðû åñòü íà ñêëàäå, ïî êàêèì öåíàì, ñåáåñòîèìîñòü òîâàðîâ, ñòàòèñòè÷åñêèå äàííûå è ò. ä.), à òàêæå âîçìîæíîñòü ïå÷àòàòü îò÷åòû.

3)     Ðóêîâîäèòåëþ ïðåäïðèÿòèÿ – âîçìîæíîñòü áûñòðî íàõîäèòü íóæíóþ èíôîðìàöèþ â áàçå, ïðîñìàòðèâàòü ñòàòèñòèêó ðàáîòû ïðåäïðèÿòèÿ, ïå÷àòàòü îò÷åòû, èçìåíÿòü öåíû íà òîâàðû.

 

1.2. Òðåáîâàíèÿ çàêàç÷èêà ê ôóíêöèîíàëüíîñòè ïðîãðàììû

1)     Ðàáîòà êàññèðà

Ïðîöåññ ïðîäàæè òîâàðà äîëæåí âûãëÿäåòü òàê:

 ïðîöåññå ïðîäàæè êàññèð äîëæåí âèäåòü ïåðåä ñîáîé òàáëèöó ñ èíôîðìàöèåé î ïðîäàâàåìûõ òîâàðàõ. Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü êàññèðó äîáàâëÿòü çàïèñè â òàáëèöó (ñ ïîìîùüþ ââîäà ìàãàçèííîãî êîäà òîâàðà èëè ñ ïîìîùüþ ñêàíåðà, à òàêæå, åñëè ñêàíåðà íåò ïîä ðóêîé, ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü âðó÷íóþ ââåñòè ñêàí-êîä), à òàêæå èçìåíÿòü èõ è óäàëÿòü. Êàæäàÿ ñòðîêà òàáëèöû äîëæíà ñîîòâåòñòâîâàòü ïðîäàâàåìîìó òîâàðó.

 ñòðîêå äîëæíû îòîáðàæàòüñÿ ñëåäóþùèå äàííûå: ìàãàçèííûé êîä òîâàðà, íàçâàíèå òîâàðà, åäèíèöà èçìåðåíèÿ è öåíà. Òàêæå â ñòðîêå äîëæíî áûòü ïîëå äëÿ ââîäà ïðîäàâöîì êîëè÷åñòâà ïðîäàâàåìîãî òîâàðà, ïîëå äëÿ ââîäà ñêèäêè, è ïîëå, â êîòîðîì îòîáðàæàåòñÿ öåíà ñî ñêèäêîé.

Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ïðîäàâöó ââîäèòü ñêèäêó, à òàêæå èçìåíÿòü äàííûå â ïîëå, ãäå îòîáðàæàåòñÿ öåíà ñî ñêèäêîé. Ïðè ýòîì ïðîãðàììà äîëæíà àâòîìàòè÷åñêè ðàññ÷èòûâàòü ñêèäêó ïî èñõîäíîé öåíå è öåíå ñî ñêèäêîé.

 Â ñàìîì ïðàâîì ñòîëáöå êàæäîé ñòðîêè äîëæíà îòîáðàæàòüñÿ èíôîðìàöèÿ î ñòîèìîñòè ââåäåííîãî êîëè÷åñòâà òîâàðà äàííîé ñòðîêè.

Åñëè âñå äàííûå ïðîäàâåö ââåë ïðàâèëüíî, íà ýêðàíå äîëæíà îòîáðàæàòüñÿ îáùàÿ ñòîèìîñòü âñåõ ïðîäàâàåìûõ òîâàðîâ. Ïîñëå ýòîãî ïðîäàâåö äîëæåí ââåñòè ñóììó, êîòîðóþ îí ïîëó÷èë îò ïîêóïàòåëÿ, â ïîëå «Íàëè÷íûå». Ïðè ýòîì ïðîãðàììà äîëæíà ðàññ÷èòàòü ñäà÷ó.

Åñëè ñóììà â ïîëå «íàëè÷íûå» ìåíüøå îáùåé ñòîèìîñòè òîâàðîâ, ïðîãðàììà íå äîëæíà äàâàòü âîçìîæíîñòü ïðîáèòü ÷åê.

Ïîñëå òîãî, êàê ÷åê ïðîáèò, ïðîãðàììà äîëæíà ïðåäîñòàâèòü ïðîäàâöó âîçìîæíîñòü íàïå÷àòàòü òîâàðíûé ÷åê.

Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü êàññèðó âîçìîæíîñòü âîçâðàòà òîâàðà. Ïðîöåññ âîçâðàòà òîâàðà äîëæåí âûãëÿäåòü òàê:

Ïðè ïðîäàæå òîâàðà íà êàæäîì ÷åêå äîëæåí ïå÷àòàòüñÿ êîä ïîêóïêè. Ïðè âîçâðàòå òîâàðà ïðîäàâåö ââîäèò êîä ïîêóïêè, íàïèñàííûé íà ÷åêå ïîêóïàòåëÿ. Ïðè ýòîì íà ýêðàíå äîëæíû âûñâåòèòüñÿ êóïëåííûå òîâàðû. Ïðîäàâåö âûáèðàåò, êàêèå òîâàðû âîçâðàùàåò ïîêóïàòåëü è ââîäèò êîëè÷åñòâî. Ïîñëå ýòîãî ïðîãðàììà äîëæíà ïðîáèòü ÷åê âîçâðàòà.

Åñëè ïîêóïàòåëü ïðèíåñ òîâàð äëÿ âîçâðàòà, íî íå ïðèíåñ ÷åê, ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü ïðîäàâöó âîçìîæíîñòü íàéòè êîä ïîêóïêè ïî ÷àñòè íàçâàíèÿ òîâàðà, ïî àðòèêóëó, ïî ÷àñòè ñêàí-êîäà, ïî äàòå è âðåìåíè ïîêóïêè, à òàêæå ïî öåíå ïîêóïêè.

Êàññèð ìîæåò òîëüêî ïðîäàâàòü òîâàðû è äåëàòü âîçâðàò îò ïîêóïàòåëÿ. Ïðîãðàììà äîëæíà íå ïîçâîëÿòü åìó âûïîëíÿòü ïðî÷èå äåéñòâèÿ, èçìåíÿþùèå äàííûå â áàçå (ïðîñìàòðèâàòü êàññèð ìîæåò ëþáóþ èíôîðìàöèþ).

2) Ðàáîòà ìåíåäæåðà

Ìåíåäæåð îòâå÷àåò çà çàíåñåíèå èíôîðìàöèè î òîâàðàõ, çàêóïëåííûõ ìàãàçèíîì íà îïòîâûõ áàçàõ. Ïðîöåññ çàíåñåíèÿ òîâàðîâ âûãëÿäèò ñëåäóþùèì îáðàçîì:

Ìåíåäæåð ââîäèò èíôîðìàöèþ îá îïòîâîé çàêóïêå (äàòà çàêóïêè, áàçà, íà êîòîðîé çàêóïëåí òîâàð);

Çàòåì ìåíåäæåð çàíîñèò òîâàðû â îïòîâóþ çàêóïêó. Ïîêà ìåíåäæåð çàíîñèò òîâàðû â îïòîâóþ çàêóïêó, îíè íå äîëæíû áûòü äîñòóïíû äëÿ ïðîäàæè. Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ïàðàëëåëüíîãî çàíåñåíèÿ òîâàðîâ íåñêîëüêèì ïîëüçîâàòåëÿì. Ïðè ýòîì êàæäûé ïîëüçîâàòåëü äîëæåí âèäåòü òîëüêî çàíåñåííûå èì òîâàðû;

Ïîñëå òîãî, êàê âñå òîâàðû çàíåñåíû, ìåíåäæåð ñâåðÿåò ñóììó çàíåñåííûõ òîâàðîâ ñ ñóììîé, óêàçàííîé â íàêëàäíîé. Åñëè ýòè ñóììû ñîâïàäàþò, îïòîâàÿ çàêóïêà çàêðûâàåòñÿ, òîâàðû ñòàíîâÿòñÿ äîñòóïíûìè äëÿ ïðîäàæè è íåäîñòóïíûìè äëÿ èçìåíåíèÿ.

Ìåíåäæåð ìîæåò çàíîñèòü òîâàðû äâóìÿ ñïîñîáàìè.

Ïåðâûé ñïîñîá: çàíåñåíèå òîâàðà, êîòîðîãî åùå íå áûëî â äàííîì ìàãàçèíå. Ìåíåäæåð çàâîäèò íîâûé ìàãàçèííûé êîä òîâàðà, ââîäèò íàçâàíèå òîâàðà, àðòèêóë è åäèíèöó èçìåðåíèÿ, âûáèðàåò ìåñòîïîëîæåíèå òîâàðà â äåðåâå ãðóïï, çàòåì ââîäèò êîëè÷åñòâî è ñòîèìîñòü (ýòè äàííûå óêàçûâàþòñÿ â íàêëàäíîé). Çàòåì ìåíåäæåð ìîæåò ââåñòè ñêàí-êîäû äëÿ ñîçäàííîãî òîâàðà (âðó÷íóþ èëè ñ ïîìîùüþ ñêàíåðà).

Âòîðîé ñïîñîá: ìåíåäæåð âûáèðàåò ñóùåñòâóþùèé òîâàð ñ ïîìîùüþ íàâèãàöèè ïî äåðåâó ãðóïï, ñ ïîìîùüþ ââîäà ìàãàçèííîãî êîäà (åñëè îí ïîìíèò ýòîò êîä) ñóùåñòâóþùåãî òîâàðà, èëè ñ ïîìîùüþ ñêàíåðà. Âî âñåõ ýòèõ ñëó÷àÿõ íà ýêðàíå äîëæíî âûñâåòèòüñÿ íàçâàíèå ñóùåñòâóþùåãî òîâàðà, àðòèêóë, òåêóùàÿ öåíà, ñåáåñòîèìîñòü, îñòàòîê è äðóãèå äàííûå, êîòîðûå äîëæíû áûòü íåäîñòóïíûìè äëÿ èçìåíåíèÿ.

Ìåíåäæåð íå âñåãäà ïîìíèò, â êàêîé ãðóïïå äåðåâà ðàñïîëîæåí òîâàð, ïîýòîìó ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ïîèñêà ïî ÷àñòè íàçâàíèÿ, ïî ÷àñòè àðòèêóëà è ïî ÷àñòè ñêàí-êîäà.

3) Ðàáîòà ðóêîâîäèòåëÿ ïðåäïðèÿòèÿ

Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ðóêîâîäèòåëþ ïðåäïðèÿòèÿ ïðîñìàòðèâàòü ñòàòèñòèêó ðàáîòû ìàãàçèíà çà ëþáîé âûáðàííûé ïåðèîä (êàêèå òîâàðû áûëè ïðîäàíû, â êàêèõ ñëó÷àÿõ èìåëà ìåñòî ñêèäêà), à òàêæå âûâîäèòü ýòè äàííûå íà ïå÷àòü.

Ðóêîâîäèòåëü ïðåäïðèÿòèÿ äîëæåí èìåòü âîçìîæíîñòü ïðîñìîòðåòü è ðàñïå÷àòàòü îñòàòêè òîâàðîâ íà ñêëàäå (íàïðèìåð, äëÿ ïðîâåäåíèÿ èíâåíòàðèçàöèè), à òàêæå òàêæå èçìåíèòü öåíû. Ïðè ýòîì ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü âîçìîæíîñòü ïå÷àòè èçìåíåííûõ öåííèêîâ çà âûáðàííûé ïåðèîä (÷òîáû áûëà âîçìîæíîñòü ñèíõðîíèçèðîâàòü öåííèêè íà âèòðèíå è öåííèêè â áàçå).

 

1.3. Òðåáîâàíèÿ çàêàç÷èêà ê ïîëüçîâàòåëüñêîìó èíòåðôåéñó

1)     Ïðîãðàììà äîëæíà ðàáîòàòü â îïåðàöèîííîé ñèñòåìå Windows XP. Ïîëüçîâàòåëüñêèé èíòåðôåéñ äîëæåí ñîîòâåòñòâîâàòü ñòàíäàðòàì äëÿ ïðèëîæåíèé Windows (ôîðìû, êíîïêè, ïåðåêëþ÷àòåëè è ò. ä.).

2)     Èíòåðôåéñ äîëæåí áûòü ìàêñèìàëüíî ïðîñòûì è ïîíÿòíûì. Âåçäå, ãäå ìîãóò âîçíèêíóòü òðóäíîñòè, äîëæíû áûòü íàïèñàíû ïîäñêàçêè. Ïðîãðàììà äîëæíà èìåòü òîëüêî íåîáõîäèìûå ôóíêöèè è íè÷åãî ëèøíåãî.

3)     Ïîëüçîâàòåëüñêèé èíòåðôåéñ äîëæåí áûòü ïîñòðîåí òàê, ÷òîáû ìèíèìèçèðîâàòü âîçìîæíîñòü îøèáîê. Åñëè îøèáî÷íûå äàííûå âñå-òàêè çàíåñåíû, äîëæíà áûòü âîçìîæíîñòü ëåãêî è áûñòðî èõ èñïðàâèòü.

4)     Ñàìûå ÷àñòî âûïîëíÿåìûå è ðóòèííûå îïåðàöèè (íàïðèìåð, çàíåñåíèå ïðèâåçåííûõ òîâàðîâ â áàçó) äîëæíû âûïîëíÿòüñÿ ïî âîçìîæíîñòè áûñòðî è óäîáíî.

5)     Ïðîãðàììà äîëæíà ðàáîòàòü áûñòðî («áåç òîðìîçîâ»). Ñèñòåìíûå õàðàêòåðèñòèêè ìàøèíû, íà êîòîðîé áóäåò ðàáîòàòü ïðîãðàììà: Intel Celeron D 2400 Mhz, 256 Mb RAM, ÷òî äîëæíî áûòü äîñòàòî÷íî äëÿ îáåñïå÷åíèÿ äåÿòåëüíîñòè íåáîëüøîãî ìàãàçèíà, ñ íåâûñîêîé èíòåíñèâíîñòüþ ïðîäàæ.

6)     Ïðîãðàììà äîëæíà âûäàâàòü îò÷åòû â ôîðìàòå doc (äëÿ âîçìîæíîñòè ïîñëåäóþùåãî ôîðìàòèðîâàíèÿ â Microsoft Word).

7)     Ïðîãðàììà äîëæíà ïðåäîñòàâëÿòü çàùèòó îò íåñàíêöèîíèðîâàííîãî äîñòóïà. Ïðåäïîëàãàåòñÿ, ÷òî ïîëüçîâàòåëè íå î÷åíü õîðîøî ðàçáèðàþòñÿ â êîìïüþòåðàõ, à ñåðâåð îáùåäîñòóïåí, ïîýòîìó äîñòàòî÷íî çàùèòû íà óðîâíå ïðèëîæåíèÿ.


 

2. ÏÐÎÅÊÒÍÀß ×ÀÑÒÜ

2.1. Ñèñòåìà áèçíåñ-ïðàâèë

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.2. Ëîãè÷åñêàÿ ñõåìà áàçû äàííûõ:

 

Îïèðàÿñü íà ïðèâåäåííûå âûøå áèçíåñ-ïðàâèëà, ðàçðàáîòàåì ëîãè÷åñêóþ ñõåìó áàçû äàííûõ.

Ëîãè÷åñêàÿ ñõåìà áàçû äàííûõ ïðèâåäåíà íà ðèñóíêå 2.1

 

Ðèñóíîê 2.1

 

2.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

 

2.2.2. Íîðìàëèçàöèÿ áàçû äàííûõ

Ñòðóêòóðà òàáëèö â öåëîì ïðèâåäåíà ê òðåòüåé íîðìàëüíîé ôîðìå, çà èñêëþ÷åíèåì íåêîòîðûõ ïîëåé, ââåäåííûõ â òàáëèöó äëÿ óñêîðåíèÿ ðàáîòû ïðîãðàììû. Èòàê, ïîëÿ, êîòîðûå ìû íå áóäåì ó÷èòûâàòü:

·        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.3. Àðõèòåêòóðà ñèñòåìû

 

Àðõèòåêòóðà ñèñòåìû ïðèâåäåíà íà ðèñóíêå 2.2.

 

Ðèñóíîê 2.2

 

Êîìïüþòåð êàññèðà, ðàáîòàþùåãî â ìàãàçèíå, ÿâëÿåòñÿ ñåðâåðîì. Ìåíåäæåð ñ ãëàâíûì áóõãàëòåðîì ïîäñîåäèíåíû ê ñåðâåðó ÷åðåç ñåòü. Ðóêîâîäèòåëü ïðåäïðèÿòèÿ èìååò âîçìîæíîñòü ïîäñîåäèíèòü ñâîé íîóòáóê ê ñåòè è ïîñìîòðåòü, êàê èäóò äåëà, èëè âîñïîëüçîâàòüñÿ äëÿ ýòîãî êîìïüþòåðîì ìåíåäæåðà.

 èäåàëüíîì ñëó÷àå â êà÷åñòâå ñåðâåðà äîëæåí ñòîÿòü îòäåëüíûé êîìïüþòåð ñ óñòàíîâëåííûì ñåðâåðîì ÁÄ, ñ îòñóòñòâèåì íåñàíêöèîíèðîâàííîãî äîñòóïà. Íî íà äàííîì ïðåäïðèÿòèè âñåãî òðè êîìïüþòåðà, è ôèðìà íå ìîæåò ñåáå ïîçâîëèòü ïðîñòàèâàíèå îäíîãî èç íèõ. Ïîýòîìó íà ñåðâåðå áóäåò òàêæå âûïîëíÿòüñÿ äðóãàÿ ðàáîòà. Ñåðâåðîì ÿâëÿåòñÿ êîìïüþòåð êàññèðà. Ýòî ðàçóìíî ïî ñëåäóþùèì ïðè÷èíàì:

âî-ïåðâûõ, äàííûé êîìïüþòåð ñàìûé ìîùíûé èç âñåõ;

âî-âòîðûõ, îí çàïèòàí ÷åðåç èñòî÷íèê áåñïåðåáîéíîãî ïèòàíèÿ, êîòîðûé ïîäñîåäèíåí íå òîëüêî ê êîìïüþòåðó, íî è ê êàññîâîìó àïïàðàòó (÷òî ïîçâîëÿåò èçáåæàòü ñáîåâ â ïðîãðàììå â ñëó÷àå îòêëþ÷åíèÿ ýëåêòðè÷åñòâà, à òàêæå íîðìàëüíî ïðîáèòü ÷åê);

â-òðåòüèõ, êàññèðó íå ïðèäåòñÿ åæåäíåâíî ñ óòðà âêëþ÷àòü äîïîëíèòåëüíûé êîìïüþòåð, èñïîëüçóåìûé â êà÷åñòâå ñåðâåðà, äëÿ òîãî, ÷òîáû èìåòü âîçìîæíîñòü ðàáîòàòü ñ ïðîãðàììîé;

â-÷åòâåðòûõ, áîëüøóþ ÷àñòü âðåìåíè ñ ïðîãðàììîé áóäåò ðàáîòàòü èìåííî êàññèð (îòñóòñòâèå ïåðåäà÷è äàííûõ ïî ñåòè).

Íåäîñòàòêîì òàêîãî ðåøåíèÿ ÿâëÿåòñÿ ñíèæåíèå áåçîïàñíîñòè. Îïûòíûé êàññèð ëåãêî ñêîïèðóåò áàçó ñåáå äîìîé, ñ öåëüþ âíåñåíèÿ èçìåíåíèé.


3. ÐÅÀËÈÇÀÖÈß

3.1. Ôèçè÷åñêàÿ ñõåìà ÁÄ

 

 Ðèñóíîê 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 ñèìâîëàìè (äëÿ òîãî, ÷òîáû íå ïåðåãðóæàòü áàçó).

 

3.2. Îñîáåííîñòè ðåàëèçàöèè ïðèëîæåíèÿ

 

Ïðîãðàììà íàïèñàíà íà Borland Delphi.  êà÷åñòâå ðàáî÷åé âåðñèè áûëà âûáðàíà ñåäüìàÿ âåðñèÿ êîìïèëÿòîðà Delphi.  êà÷åñòâå ÑÓÁÄ âûáðàí Firebird âåðñèè 1.53.

Ïî ñóòè, ïðîãðàììà ñîñòîèò èç äâóõ ÷àñòåé: ñåðâåðíàÿ (õðàíèìûå ïðîöåäóðû) è êëèåíòñêàÿ (êîä ïðîãðàììû).

Ïðîãðàììà ðàáîòàåò ïîä îïåðàöèîííîé ñèñòåìîé Windows XP. Äëÿ íîðìàëüíîé ðàáîòû ïðîãðàììû íóæíî ðàçðåøåíèå ýêðàíà íå ìåíåå, ÷åì 1024x768, ïîääåðæêà ðåæèìà VGA (256 öâåòîâ), 64 ìåãàáàéòà îïåðàòèâíîé ïàìÿòè è ïðîöåññîð óðîâíÿ Intel Celeron 400 Mhz, õîòÿ äëÿ íîðìàëüíîé ðàáîòû ïðîãðàììû íà ñåðâåðå ëó÷øå èìåòü ìàøèíó ïîìîùíåå.

Ïðîãðàììà ïîëíîñòüþ ñîîòâåòñòâóåò ñòàíäàðòàì äëÿ ïðîãðàìì Windows (ãëàâíûå ìåíþ, êîíòåêñòíûå ìåíþ, êíîïêè, ïåðåêëþ÷àòåëè è ò. ä.). Äëÿ ðàáîòû ñ äàííîé ïðîãðàììîé òðåáóþòñÿ ìèíèìàëüíûå íàâûêè ðàáîòû ñ êîìïüþòåðîì (óìåíèå âêëþ÷èòü è âûêëþ÷èòü êîìïüþòåð, çàïóñòèòü ïðîãðàììó ñ ðàáî÷åãî ñòîëà, óìåíèå ïîëüçîâàòüñÿ ãëàâíûìè è êîíòåêñòíûìè ìåíþ, êíîïêàìè è ïåðåêëþ÷àòåëÿìè).

Ïî÷òè âñå ìàíèïóëÿöèè ñ äàííûìè ïðîèçâîäÿòñÿ ñ ïîìîùüþ õðàíèìûõ ïðîöåäóð. Òàêîé ïîäõîä ïîçâîëÿåò èçáåæàòü âíåñåíèÿ â áàçó îøèáî÷íûõ äàííûõ, òàê êàê â ïðîöåäóðàõ âñå æåñòêî ïðîâåðÿåòñÿ. Êðîìå òîãî, ýòî ïîçâîëÿåò íîðìàëüíî îðãàíèçîâàòü ìíîãîïîëüçîâàòåëüñêóþ ðàáîòó (òàê êàê ïðîâåðêè âûïîëíÿþòñÿ íà ñåðâåðå íåïîñðåäñòâåííî ïåðåä çàíåñåíèåì äàííûõ).

Ìàíèïóëÿöèè ñ äàííûìè ïðîèñõîäÿò òàê: âûçûâàåòñÿ íóæíàÿ õðàíèìàÿ ïðîöåäóðà ñ âõîäíûìè ïàðàìåòðàìè, íà âûõîä ïðîöåäóðà âûäàåò îøèáêó (ïåðåìåííàÿ òèïà integer). Åñëè îøèáêà ðàâíà íóëþ, òî äåéñòâèÿ ïðîøëè óñïåøíî, èíà÷å â çàâèñèìîñòè îò ïîëó÷åííîãî íîìåðà îøèáêè êëèåíòñêàÿ ïðîãðàììà âûäàåò ñîîòâåòñòâóþùåå ñîîáùåíèå îá îøèáêå.

Òàêèì îáðàçîì, ñåðâåðíàÿ ÷àñòü îòâå÷àåò çà ïðàâèëüíîñòü ââîäèìûõ äàííûõ, íî è êëèåíòñêàÿ ÷àñòü ïîñòðîåíà ïî âîçìîæíîñòè òàê, ÷òîáû íå äàòü ïîëüçîâàòåëþ äîïóñòèòü îøèáîê.  áîëüøèíñòâå ìåñò ïðîãðàììû âûïîëíÿåòñÿ äâå ïðîâåðêè: ñíà÷àëà íà êëèåíòå, çàòåì íà ñåðâåðå.

Âñå çàïðîñû è âñÿ ðàáîòà ñ äàííûìè (íàïðèìåð, ðàçëè÷íûå ñîðòèðîâêè) ïðîèçâîäèòñÿ íà ñåðâåðå. Ýòî ìîæíî ñåáå ïîçâîëèòü äëÿ íåáîëüøîãî ìàãàçèíà, òàê êàê ÷èñëî ïîëüçîâàòåëåé íåâåëèêî (2—3). Ïðè òàêîì ïîäõîäå óïðîùàåòñÿ ðåàëèçàöèÿ ïðîãðàììû, ê òîìó æå íå íóæíû ìîùíûå êëèåíòñêèå ìàøèíû è ñíèæàåòñÿ íàãðóçêà íà ñåòü (ïî ñåòè ïåðåäàåòñÿ òîëüêî íóæíàÿ èíôîðìàöèÿ). Òåì íå ìåíåå, ñî âðåìåíåì ïëàíèðóåòñÿ ïåðåíåñòè ÷àñòü ðàáîòû íà êëèåíòà (÷òîáû íå ïåðåãðóæàòü ñåðâåð).

 

3.3. Îïèñàíèå ïîëüçîâàòåëüñêîãî èíòåðôåéñà

 

Íà ðèñóíêå 3.2 ïðèâåäåíà îñíîâíàÿ ôîðìà ïðîãðàììû. Îíà ïîÿâëÿåòñÿ ñðàçó ïîñëå âõîäà â ïðîãðàììó.

 

Ðèñóíîê 3.2

 

Äëÿ èñïîëüçîâàíèÿ ïðîãðàììû â ðàáîòå ìàãàçèíà ÷åðåç íåå íóæíî çàíåñòè èíôîðìàöèþ î òîâàðàõ, êîòîðûìè òîðãóåò äàííûé ìàãàçèí, â áàçó. Ïðîãðàììà ïðåäîñòàâëÿåò âîçìîæíîñòü ðàçáèòü òîâàðû íà ãðóïïû äëÿ áîëåå óäîáíîé îðãàíèçàöèè ðàáîòû. Ïåðåä ïåðâûì çàíåñåíèåì èíôîðìàöèè î òîâàðàõ ðåêîìåíäóåòñÿ ïðîäóìàòü ñòðóêòóðó ãðóïï. Ïðîãðàììà ïîçâîëÿåò ñîçäàâàòü, ïåðåèìåíîâûâàòü, óäàëÿòü, ïåðåìåùàòü çàïèñè (â òîì ÷èñëå ãðóïïû, à òàêæå òîâàðû, íàõîäÿùèåñÿ â ýòèõ ãðóïïàõ) â ïðîöåññå çàíåñåíèÿ òîâàðîâ, íî äëÿ áîëüøåãî ïîðÿäêà ëó÷øå ñðàçó îïðåäåëèòü îñíîâíûå ãðóïïû. Ôîðìà äëÿ çàíåñåíèÿ ãðóïï òîâàðîâ ïðèâåäåíà íà ðèñóíêå 3.3.

Òîâàðû ïîñòàâëÿþòñÿ â ìàãàçèí ñ îïòîâûõ áàç, ïîýòîìó ïåðåä çàíåñåíèåì èíôîðìàöèè î òîâàðàõ èç î÷åðåäíîé îïòîâîé çàêóïêè íåîáõîäèìî óáåäèòüñÿ, ÷òî îïòîâàÿ áàçà, ñ êîòîðîé ïîñòàâëåíû òîâàðû, èìååòñÿ â ñïèñêå îïòîâûõ áàç ïðîãðàììû. Åñëè òàêîé çàïèñè íåò, åå íóæíî äîáàâèòü. Äëÿ ýòîãî íà îñíîâíîé ôîðìå (ðèñóíîê 3.2), ïîÿâëÿþùåéñÿ ïðè âõîäå â ïðîãðàììó, ñëåäóåò íàæàòü êíîïêó «Ðàáîòà ñ îïòîâûìè áàçàìè». Íà ýêðàíå ïîÿâèòñÿ ôîðìà äëÿ ðàáîòû ñ îïòîâûìè áàçàìè (ðèñóíîê 3.4).

Ðèñóíîê 3.3

 

Ðèñóíîê 3.4

 

 äàííîé ôîðìå ñ ïîìîùüþ êîìàíä ãëàâíîãî èëè êîíòåêñòíîãî ìåíþ ìîæíî äîáàâëÿòü, èçìåíÿòü èëè óäàëÿòü èíôîðìàöèþ îá îïòîâûõ áàçàõ.

Èòàê, íóæíûå îïòîâûå áàçû çàâåäåíû. Òåïåðü íåîáõîäèìî çàíåñòè èíôîðìàöèþ î òîâàðàõ. Äëÿ ýòîãî âûõîäèì èç ôîðìû äëÿ ðàáîòû ñ îïòîâûìè áàçàìè â ãëàâíóþ ôîðìó (ðèñóíîê 3.2) (èç ëþáîé ôîðìû äàííîé ïðîãðàììû ìîæíî âûéòè ñ ïîìîùüþ êëàâèøè <Esc>). Âûáèðàåì ïóíêò «Çàíåñåíèå òîâàðîâ». Ïîñëå íàæàòèÿ äàííîé êíîïêè íà ýêðàíå ïîÿâèòñÿ ôîðìà «Çàíåñåíèå çàêóïëåííûõ òîâàðîâ â áàçó» (ðèñóíîê 3.5):

 

Ðèñóíîê 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.21

 

Ôîðìà äëÿ ðàáîòû ñ ïîëüçîâàòåëÿìè ïðèâåäåíà íà ðèñóíêå 3.22.

 

Ðèñóíîê 3.22

 

Èìååòñÿ 2 òèïà ïîëüçîâàòåëåé: ïðîñòîé è ñ ïðàâîì ñîçäàíèÿ äðóãèõ ïîëüçîâàòåëåé. Åñëè â êîëîíêå «Ïðàâà» íàïèñàíî «3», òî ýòî àäìèíèñòðàòîð. Åñëè â êîëîíêå «Ïðàâà» íàïèñàíî «2», òî ïîëüçîâàòåëü èìååò ïðàâî ñîçäàâàòü äðóãèõ ïîëüçîâàòåëåé, íàäåëÿÿ èõ ïðàâàìè íå áîëüøèìè, ÷åì èìååò ñàì. Åñëè â êîëîíêå «Ïðàâà» íàïèñàíî «1», òî ïîëüçîâàòåëü èìååò ïðàâî ìåíÿòü ñâîé ïàðîëü. Åñëè íàïèñàíî «0», òî ïîëüçîâàòåëü âîîáùå íå èìååò íèêàêèõ ïðàâ ïî ðàáîòå ñ ïîëüçîâàòåëÿìè.

Ôîðìà äëÿ ñîçäàíèÿ ïîëüçîâàòåëÿ ïðèâåäåíà íà ðèñóíêå 3.23.

 

 

Ðèñóíîê 3.23

 

Äëÿ ñîçäàíèÿ ïîëüçîâàòåëÿ íåîáõîäèìî óêàçàòü ñâîé ïàðîëü, ââåñòè èìÿ ïîëüçîâàòåëÿ è åãî ïàðîëü, çàòåì íàäåëèòü ïîëüçîâàòåëÿ ïðàâàìè.


3.4. Àëãîðèòìû

 

Äàííàÿ ïðîãðàììà ïðîèçâîäèò ðàçëè÷íûå ìàíèïóëÿöèè ñ äàííûìè â îñíîâíîì ñ ïîìîùüþ õðàíèìûõ ïðîöåäóð. Íî âûâîä äàííûõ (òàáëèöû, äåðåâüÿ, ãðàôèêè è ò. ä.) â îñíîâíîì ïðîèçâîäèòñÿ ñ ïîìîùüþ SQL-çàïðîñîâ. Îäèí èç ñàìûõ ñëîæíûõ SQL-çàïðîñîâ âûãëÿäèò òàê:

 

select

   code_path, name_path, paths.code_ancestor,    

   count(code_good) chislo 

from paths left join goods                                               

on paths.code_path=goods.code_ancestor and CodeIsActive=1

group by code_path, name_path, paths.code_ancestor

order by name_path

 

Ýòîò çàïðîñ èñïîëüçóåòñÿ äëÿ ôîðìèðîâàíèÿ äåðåâà ãðóïï òîâàðîâ. Äåðåâî ãðóïï òîâàðîâ ïðèâåäåíî íà ðèñóíêå 3.24.

Ðèñóíîê 3.24

 

Äëÿ êàæäîé ãðóïïû íóæíî îïðåäåëèòü èìÿ (äëÿ âûâîäà íà ôîðìå), êîä ãðóïïû, êîä ïðåäêà ãðóïïû è ÷èñëî òîâàðîâ, ëåæàùèõ â äàííîé ãðóïïå. ×èñëî òîâàðîâ â ãðóïïå íóæíî äëÿ òîãî, ÷òîáû îïðåäåëèòü, ïóñòàÿ ãðóïïà .èëè íå ïóñòàÿ. Äëÿ ãðóïï, ñîäåðæàùèõ õîòü îäèí òîâàð, íà ôîðìå âûâîäèòñÿ êàðòèíêà ðÿäîì ñ íàçâàíèåì ãðóïïû. Äëÿ ïóñòûõ ãðóïï òàêîé êàðòèíêè íå âûâîäèòñÿ. Ïåðâîíà÷àëüíî çàïîëíåíèå äåðåâà ïðîèçâîäèëîñü ñëåäóþùèì îáðàçîì: âûïîëíÿëñÿ çàïðîñ 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, íî çàòî ïîääåðæèâàåò UDFUser 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), è ÷èñëî ñåêóíä, ïðîøåäøèõ ñ íà÷àëà ñóòîê. Òåêñò ïðîöåäóð òðèâèàëåí è ïðèâåäåí â Ïðèëîæåíèè.


 

4. ÒÅÑÒÈÐÎÂÀÍÈÅ ÏÐÎÃÐÀÌÌÛ

Ïåðåä âíåäðåíèåì ïðîãðàììû, åñòåñòâåííî, ïðîâîäèëîñü òåñòèðîâàíèå. Ýòî íóæíî äëÿ ïðåäîòâðàùåíèÿ ââîäà â áàçó îøèáî÷íûõ äàííûõ. Îñîáî ïðèñòàëüíîå âíèìàíèå óäåëÿëîñü òåñòèðîâàíèþ õðàíèìûõ ïðîöåäóð, òàê êàê â îñíîâíîì îò íèõ çàâèñèò íåïðîòèâîðå÷èâîñòü è ïðàâèëüíîñòü äàííûõ íà ñåðâåðå. Íî ïðàâèëüíîñòü ðàáîòû êëèåíòñêîãî ïðèëîæåíèÿ òîæå òåñòèðîâàëàñü. Òåñòèðîâàíèå ïðîâîäèëîñü â íåñêîëüêî ýòàïîâ:

 

4.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;

ïðîöåäóðà Âîçâðàò Òîâàðà íå ðàáîòàëà äîëæíûì îáðàçîì.

Íà ýòîì ïåðâûé ýòàï òåñòèðîâàíèÿ çàêîí÷åí.

 

4.2. Âòîðîé ýòàï òåñòèðîâàíèÿ

 

Ïðîâåðèì êîä ïðîãðàììû âî âñåõ ìåñòàõ, ãäå îíà ðàáîòàåò ñ áàçîé íà ïðàâèëüíîñòü ââåäåííûõ äàííûõ. Ïðîãðàììà äîëæíà ðåàãèðîâàòü íà âñå îøèáêè, êîòîðûå âûäàþò õðàíèìûå ïðîöåäóðû.

Îäíîâðåìåííî ñ ïîìîùüþ ïðîãðàììû ïîïðîáóåì âûïîëíèòü ðàçëè÷íûå äåéñòâèÿ, ïûòàÿñü ñîçäàòü îøèáêó.

 ðåçóëüòàòå íàéäåíî ñåìü îøèáîê, ïðè÷åì íå âñå èç íèõ ñâÿçàíû ñ íåêîððåêòíîé ðàáîòîé ñ áàçîé. Íèæå ïðèâåäåíû íåêîòîðûå èç îøèáîê, óñòðàíåííûõ â äàëüíåéøåì:

íà ôîðìå äëÿ çàíåñåíèÿ òîâàðîâ â ñåññèþ íå ïðîâåðÿëàñü ïðàâèëüíîñòü ââîäà íàöåíêè;

íà ôîðìå äëÿ çàíåñåíèÿ òîâàðà â ñåññèþ ïðè ââîäå êîëè÷åñòâà òîâàðà, ðàâíîãî íóëþ, ïðîèñõîäèëî äåëåíèå íà íîëü;

ïîëå äëÿ ðó÷íîãî ââîäà ñêàí-êîäà (êîòîðûé ñîñòîèò èç öèôð) íà ôîðìå äëÿ èçìåíåíèÿ òîâàðà ñåññèè äîïóñêàëî ââîä ëþáûõ ñèìâîëîâ (êîíå÷íî, â áàçó ýòîò ñêàí-êîä âñå ðàâíî íå ïîïàäàë, òàê êàê ñóùåñòâóåò åùå ïðîâåðêà íå ñåðâåðå, íî ýòî ïðèâîäèëî ê íåïîíÿòíûì «ãëþêàì»).

 

4.3. Òðåòèé ýòàï òåñòèðîâàíèÿ

 

Òðåòèé ýòàï òåñòèðîâàíèÿ. Ïðîâåðÿåì Firebird Server. Äëÿ ýòîãî çàïóñòèì äëèííóþ òðàíçàêöèþ (èç ìèëëèîíà îïåðàòîðîâ insert è update). Â ñåðåäèíå òðàíçàêöèè âûäåðíåì øíóð ïèòàíèÿ èç ðîçåòêè. Ðåçóëüòàòû äàííîãî äåéñòâèÿ ñëåäóþùèå:

ïðè ÷èñëå çàïèñåé äî 1000 áàçà äàííûõ íîðìàëüíî îòêàòûâàëàñü ê ïðåäûäóùåìó ñîñòîÿíèþ;

ïðè ÷èñëå çàïèñåé 50000 íåêîòîðûå òàáëèöû ñòàëè ÷èòàòüñÿ ñ îøèáêàìè;

ïðè ÷èñëå çàïèñåé 500000 áàçà ñòàëà çàíèìàòü íà ìîìåíò âûêëþ÷åíèÿ ïèòàíèÿ îêîëî 700 ìåãàáàéò, è ïîñëå âêëþ÷åíèÿ ïèòàíèÿ îêàçàëàñü íå÷èòàåìîé.

 ïðèíöèïå, íîðìàëüíî.  ðåàëüíîñòè ñåðâåð íå áóäåò âûïîëíÿòü òðàíçàêöèè èç 500 òûñÿ÷ îïåðàöèé, ê òîìó æå îí áóäåò çàïèòàí ÷åðåç èñòî÷íèê áåñïåðåáîéíîãî ïèòàíèÿ, è êàæäûå äâå íåäåëè äîëæíî ïðîâîäèòüñÿ ðåçåðâíîå êîïèðîâàíèå.

 

4.4. ×åòâåðòûé ýòàï òåñòèðîâàíèÿ

 

×åòâåðòûé ýòàï òåñòèðîâàíèÿ ñèëàìè ñòîðîííåãî ïðîãðàììèñòà.  ðåçóëüòàòå íàéäåíà îäíà îøèáêà: ïðè ââîäå ñêèäêè â ïîëå ñî ñêèäêîé â ôîðìå ñ ïðîäàæàìè ñêèäêà ïðîèçâîäèòñÿ íà âñå òîâàðû, à íå òîëüêî íà òó ñòðîêó, ãäå áûëà ââåäåíà ñêèäêà. Îøèáêà èñïðàâëåíà.

 

4.5. Ïÿòûé ýòàï òåñòèðîâàíèÿ

 

Ïÿòûé ýòàï òåñòèðîâàíèÿ: ïèøåì ïðîöåäóðó äëÿ ââîäà áîëüøîãî êîëè÷åñòâà òîâàðîâ â áàçó. Ñ ïîìîùüþ ýòîé ïðîöåäóðû çàíîñèì â áàçó îêîëî 5000 íàèìåíîâàíèé òîâàðîâ â 100 ñåññèé îïòîâîé çàêóïêè íîìåð òðè. Ïðè ýòîì ñîçäàåòñÿ 100 ãðóïï òîâàðîâ. Ïðîöåäóðà ýìóëèðóåò ðåàëüíîå çàíåñåíèå òîâàðîâ, ïîýòîìó îòñóòñòâèå îøèáîê ìîæåò áûòü ïîäòâåðæäåíèåì êîððåêòíîé ðàáîòû ïðîãðàììû. Ïðè ýòîì èìåíà òîâàðîâ è ãðóïï ôîðìèðóåì ñëó÷àéíûì îáðàçîì, è äåëàåì äëèííûìè (÷òîáû ïðîãðàììà «òîðìîçèëà»). Âûïîëíèì äàííóþ ïðîöåäóðó 10 ðàç, è â áàçå áóäåò íàõîäèòüñÿ îêîëî 50000 òîâàðîâ â 1000 ãðóïï, çàíåñåííûõ ñ ïîìîùüþ 1000 ñåññèé.

Òåïåðü îòêðîåì äåðåâî ãðóïï òîâàðîâ. Íà ýòî óõîäèò îêîëî 10 ñåêóíä, ÷òî ñëèøêîì äîëãî. Èùåì ïðè÷èíû òàêîãî ïîâåäåíèÿ ïðîãðàììû. Ïðè ôîðìèðîâàíèè äåðåâà ãðóïï îïðåäåëÿåòñÿ òàêæå çàïîëíåííîñòü ãðóïï òîâàðàìè (åñëè â ãðóïïå åñòü òîâàðû, òî ãðóïïà ñ êàðòèíêîé, èíà÷å áåç êàðòèíêè). Äëÿ ôîðìèðîâàíèÿ äåðåâà ãðóïï èñïîëüçóåòñÿ ñëåäóþùèé çàïðîñ:

 

select

   code_path, name_path, paths.code_ancestor,    

   count(code_good) chislo 

from paths left join goods

on paths.code_path=goods.code_ancestor and CodeIsActive=1

group by code_path, name_path, paths.code_ancestor

order by name_path

 

Çäåñü, âîçìîæíî, ïîìîæåò èíäåêñ äëÿ òàáëèöû goods ïî ïîëþ code_ancestor.  Ñîçäàåì èíäåêñ äëÿ òàáëèöû goods:

create index IndexGoods4 on goods(code_ancestor)

Òåïåðü äåðåâî ôîðìèðóåòñÿ îêîëî 1 ñåêóíäû. Ýòî óæå ïðèåìëåìî. Èòàê, ìîæíî ñ÷èòàòü, ÷òî âûâîä äåðåâà îïòèìèçèðîâàí.

Òåïåðü ïðîáóåì îòêðûòü êàêóþ-ëèáî ãðóïïó ñ òîâàðàìè. Ãðóïïà îòêðûâàåòñÿ íåîïðàâäàííî äîëãî. Ñìîòðèì íà òåêñò çàïðîñà äëÿ çàïîëíåíèÿ ñïèñêà òîâàðîâ:

 

select * from goods join TitleUnits on

   goods.code_unit=TitleUnits.code_unit

where code_ancestor=:code_ancestor and CodeIsActive=1

order by name_good

Âðîäå, íè÷åãî îñîáåííîãî. Òàáëèöà TitleUnits ìàëåíüêàÿ (òðè çàïèñè, òàê êàê â íåé õðàíÿòñÿ åäèíèöû èçìåðåíèÿ). Òàáëèöà goods ñîäåðæèò 50000 çàïèñåé, íî âåäü ýòî íåìíîãî! Âñå äîëæíî ðàáîòàòü áûñòðî! Âûïîëíÿåì äàííûé çàïðîñ â IBExpert, è ïîëó÷àåì âðåìÿ ðàáîòû 0,00 ñåêóíä! Çíà÷èò, íå â ýòîì äåëî. Ïðè îòêðûòèè ôîðìû âûïîëíÿåòñÿ ñëåäóþùàÿ ïðîöåäóðà (îíà íóæíà äëÿ çàïîëíåíèÿ ñåòêè è óñòàíîâêè êóðñîðà â íóæíîå ìåñòî):

 

procedure RefreshDataAndSetCursor(name_good: string);

{óñòàíàâëèâàåò êóðñîð êóäà íóæíî}

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;

 

Êîíå÷íî, ýòó ïðîöåäóðó ìîæíî «ïðè÷åñàòü» (óáðàòü ëèøíèå ïåðåìåííûå, è ò. ä.), íî äëÿ íàãëÿäíîñòè â äàííîé ðàáîòå ëó÷øå ïîäõîäèò «ñûðîé» âèä. Òåïåðü ïîòåñòèðóåì ïðîãðàììó. Ïðîöåññû îòêðûòèÿ ôîðìû, äîáàâëåíèÿ, óäàëåíèÿ è èçìåíåíèÿ òîâàðîâ ñòàëè ïî÷òè ìãíîâåííûìè.

Àíàëîãè÷íûì îáðàçîì îïòèìèçèðóåì äðóãèå ìåñòà ïðîãðàììû. Ïîñëå äàííîãî ýòàïà ïðîãðàììà ñòàëà ïðèãîäíîé ê âíåäðåíèþ.

Øåñòîé ýòàï òåñòèðîâàíèÿ ïðîõîäèë óæå ïîñëå âíåäðåíèÿ ïðîãðàììû íà ðåàëüíûõ ïîëüçîâàòåëÿõ. Ñåðüåçíûõ îøèáîê íà äàííîì ýòàïå íå îáíàðóæåíî, íî èñïðàâëåíî íåñêîëüêî ìåëêèõ íåäî÷åòîâ.

 


 

5. ÁÅÇÎÏÀÑÍÎÑÒÜ ÄÀÍÍÛÕ

Àðõèòåêòóðà ñåòè íà ïðåäïðèÿòèè ïðîäóáëèðîâàíà íà ðèñóíêå 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


 

ÏÐÈËÎÆÅÍÈß

1. Ñöåíàðèé ñîçäàíèÿ ÁÄ

 

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);

 

2. Òåêñòû çàïðîñîâ, õðàíèìûõ ïðîöåäóð, òðèããåðîâ

 

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';

 

3. Îáðàçåö ïðîãðàììíîãî êîäà

 

Ïðîöåäóðà GetDateOfNumber

 

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;

 

Ïðîöåäóðà IsCorrectFloatString

 

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;

 

Ïðîöåäóðà NaturalNumberUp999ToString

 

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;

 

Ïðîöåäóðà DrawGraphLine

 

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;

 

Ïðîöåäóðà DrawGraphLineWithSpline

 

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;

 

Ôóíêöèè DateDays, DateSeconds áèáëèîòåêè libraryDateDaysSeconds

 

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.

 

Ìîäóëü BGL

 

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.

 




Rambler's Top100 HotLog