diff --git a/.idea/GeneratorCSV.iml b/.idea/GeneratorCSV.iml deleted file mode 100644 index a94fbfe..0000000 --- a/.idea/GeneratorCSV.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 20fc29e..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index adbabba..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 1b13c30..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index aaff619..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1574872723273 - - - - - - - - - - \ No newline at end of file diff --git a/__pycache__/format.cpython-36.pyc b/__pycache__/format.cpython-36.pyc deleted file mode 100644 index 14c6217..0000000 Binary files a/__pycache__/format.cpython-36.pyc and /dev/null differ diff --git a/__pycache__/format.cpython-38.pyc b/__pycache__/format.cpython-38.pyc deleted file mode 100644 index 4cdd0af..0000000 Binary files a/__pycache__/format.cpython-38.pyc and /dev/null differ diff --git a/__pycache__/moduly.cpython-36.pyc b/__pycache__/moduly.cpython-36.pyc deleted file mode 100644 index d943174..0000000 Binary files a/__pycache__/moduly.cpython-36.pyc and /dev/null differ diff --git a/__pycache__/moduly.cpython-38.pyc b/__pycache__/moduly.cpython-38.pyc deleted file mode 100644 index 9dcb6b2..0000000 Binary files a/__pycache__/moduly.cpython-38.pyc and /dev/null differ diff --git a/assets/documentation-page/about-program/icon.png b/assets/documentation-page/about-program/icon.png new file mode 100644 index 0000000..e0314ab Binary files /dev/null and b/assets/documentation-page/about-program/icon.png differ diff --git a/assets/documentation-page/description/format-danych.png b/assets/documentation-page/description/format-danych.png new file mode 100644 index 0000000..d6b65f5 Binary files /dev/null and b/assets/documentation-page/description/format-danych.png differ diff --git a/assets/documentation-page/description/generator-csv.png b/assets/documentation-page/description/generator-csv.png new file mode 100644 index 0000000..0475cda Binary files /dev/null and b/assets/documentation-page/description/generator-csv.png differ diff --git a/assets/documentation-page/description/o-programie.png b/assets/documentation-page/description/o-programie.png new file mode 100644 index 0000000..9285df6 Binary files /dev/null and b/assets/documentation-page/description/o-programie.png differ diff --git a/assets/documentation-page/description/ustawienia.png b/assets/documentation-page/description/ustawienia.png new file mode 100644 index 0000000..1c335c5 Binary files /dev/null and b/assets/documentation-page/description/ustawienia.png differ diff --git a/assets/documentation-page/icon.ico b/assets/documentation-page/icon.ico new file mode 100644 index 0000000..49f2657 Binary files /dev/null and b/assets/documentation-page/icon.ico differ diff --git a/assets/documentation-page/icon.png b/assets/documentation-page/icon.png new file mode 100644 index 0000000..e0314ab Binary files /dev/null and b/assets/documentation-page/icon.png differ diff --git a/assets/documentation-page/instruction/example-input-data.png b/assets/documentation-page/instruction/example-input-data.png new file mode 100644 index 0000000..ad321b9 Binary files /dev/null and b/assets/documentation-page/instruction/example-input-data.png differ diff --git a/assets/documentation-page/instruction/generate-input-file-settings.png b/assets/documentation-page/instruction/generate-input-file-settings.png new file mode 100644 index 0000000..cbd2c1c Binary files /dev/null and b/assets/documentation-page/instruction/generate-input-file-settings.png differ diff --git a/assets/documentation-page/instruction/generate-output-file-settings.png b/assets/documentation-page/instruction/generate-output-file-settings.png new file mode 100644 index 0000000..0487107 Binary files /dev/null and b/assets/documentation-page/instruction/generate-output-file-settings.png differ diff --git a/assets/documentation-page/instruction/input-name.png b/assets/documentation-page/instruction/input-name.png new file mode 100644 index 0000000..94522b6 Binary files /dev/null and b/assets/documentation-page/instruction/input-name.png differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..e0314ab Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/tab-icons/about.png b/assets/tab-icons/about.png new file mode 100644 index 0000000..b43f70e Binary files /dev/null and b/assets/tab-icons/about.png differ diff --git a/assets/tab-icons/format.png b/assets/tab-icons/format.png new file mode 100644 index 0000000..449443d Binary files /dev/null and b/assets/tab-icons/format.png differ diff --git a/assets/tab-icons/generate.png b/assets/tab-icons/generate.png new file mode 100644 index 0000000..aeaa409 Binary files /dev/null and b/assets/tab-icons/generate.png differ diff --git a/assets/tab-icons/icon.png b/assets/tab-icons/icon.png new file mode 100644 index 0000000..e0314ab Binary files /dev/null and b/assets/tab-icons/icon.png differ diff --git a/assets/tab-icons/settings.png b/assets/tab-icons/settings.png new file mode 100644 index 0000000..09f4cbb Binary files /dev/null and b/assets/tab-icons/settings.png differ diff --git a/changelog.txt b/changelog.txt deleted file mode 100644 index 84f0073..0000000 --- a/changelog.txt +++ /dev/null @@ -1,21 +0,0 @@ -1.0 -- Pierwsza wersja programu składająca się z 4 części - -2.0 -- Podstawowy tekstowy interfejs -- Scalenie programu w jeden -- Aktualizacja formatu plików z danymi -- Wstępne przystosowanie do działania w czteroletnim liceum i w trzyletniej szkole branżowej -- Aktualizacja kodowania - -3.0 -- Wprowadzenie pełnego graficznego interfejsu w środowisku tkinter -- Wstępne obsługiwanie wyjątków -- Przeniesienie modułów do oddzielnego pliku -- Stworzenie pliku 'format.py' ze skryptem przetwarzającym dane - przystosowanie programu do ewentualnych zmian w formacie plików z danymi -- Przeniesienie ukrytych ustawień do pliku 'config.cfg' - -3.0.1 -- Poprawka błędu - pole 3 i 4 nie mają już przypisanej tej samej zmiennej tekstowej -- Przydzielenie wersji, autorów, tytułu programu i lat pracy do zmiennych globalnych środowiska graficznego - diff --git a/config.cfg b/config.cfg deleted file mode 100644 index 675c8af..0000000 --- a/config.cfg +++ /dev/null @@ -1 +0,0 @@ -Kodowanie: utf-8 \ No newline at end of file diff --git a/configs/config.cfg b/configs/config.cfg new file mode 100644 index 0000000..5faa0a3 --- /dev/null +++ b/configs/config.cfg @@ -0,0 +1,12 @@ +secret(S) = entersecretstringhere +mailOutputCoding(Sc) = utf-8 +officeOutputCoding(Sc) = utf-8 +domain(S) = losobolew.pl +quota(I) = 500 +country(S) = Rzeczypospolita Polska +schoolData(MSAs) = [LO, 4, 0]|[BS, 3, 1] +schoolyearStart(D) = 01.09.* *:*:* +ifHeadlineInMail(B) = 0 +headlineInMail(S) = mailHeadline +ifHeadlineInOffice(B) = 0 +headlineInOffice(S) = officeHeadline \ No newline at end of file diff --git a/configs/style.cfg b/configs/style.cfg new file mode 100644 index 0000000..ba31d34 --- /dev/null +++ b/configs/style.cfg @@ -0,0 +1,152 @@ +windowWidth(I) = 1200 +windowHeight(I) = 720 +windowWidthResizable(B) = 0 +windowHeightResizable(B) = 0 +windowMainBG(C) = #21242D +mainIcon(P) = icon.ico +mainMenuBG(C) = #21242D +mainMenuPosition(FAposition) = wn +tabFramesBorderWidth(I) = 0 +unselectedTabBG(C) = #21242D +menuTabsBorderWidth(I) = 0 +menuTabsPadding(I) = 10 +selectedTabBG(C) = #333842 +disabledTabBG(C) = #333842 +tabFrameBG(C) = #21242D +headerFont(F) = Segoe UI;15 +headerBG(C) = #333842 +headerTextColor(C) = #C0C0C0 +headerPadding(I) = 10 +headerTextAnchor(FAanchor) = center +contentTabFrameBG(C) = #21242D +layoutFrameBG(C) = #21242D +label1BG(C) = #21242D +label1TextColor(C) = #C0C0C0 +label1Font(F) = Segoe UI;10 +label2BG(C) = #21242D +label2TextColor(C) = #C0C0C0 +label2Font(F) = Segoe UI;9 +label3BG(C) = #21242D +label3TextColor(C) = #C0C0C0 +label3Font(F) = Segoe UI;7 +label4BG(C) = #21242D +label4TextColor(C) = #C0C0C0 +label4Font(F) = Segoe UI;25 +combobox1ArrowColor(C) = #C0C0C0 +combobox1ButtonColor(C) = #333842 +combobox1BorderColor(C) = #21242D +combobox1FieldBackground(C) = #333842 +combobox1TextColor(C) = #C0C0C0 +combobox1Relief(FArelief) = flat +combobox1BorderWidth(I) = 0 +combobox1Padding(I) = 5 +combobox1ListBoxBackground(C) = #333842 +combobox1ListBoxForeground(C) = #C0C0C0 +combobox1ListBoxSelectBackground(C) = #737373 +combobox1ListBoxSelectForeground(C) = #FFFFFF +combobox2ArrowColor(C) = #C0C0C0 +combobox2ButtonColor(C) = #333842 +combobox2BorderColor(C) = #21242D +combobox2FieldBackground(C) = #333842 +combobox2TextColor(C) = #C0C0C0 +combobox2Relief(FArelief) = flat +combobox2BorderWidth(I) = 0 +combobox2Padding(I) = 7 +combobox2ListBoxBackground(C) = #333842 +combobox2ListBoxForeground(C) = #C0C0C0 +combobox2ListBoxSelectBackground(C) = #737373 +combobox2ListBoxSelectForeground(C) = #FFFFFF +button1TextAnchor(FAanchor) = center +button1Background(C) = #333842 +button1Foreground(C) = #C0C0C0 +button1Padding(I) = 4 +separator1BG(C) = #21242D +spinbox1ArrowColor(C) = #C0C0C0 +spinbox1FieldBackground(C) = #333842 +spinbox1Relief(FArelief) = flat +spinbox1BorderWidth(I) = 0 +spinbox1TextColor(C) = #C0C0C0 +spinbox1ButtonColor(C) = #333842 +spinbox1Padding(I) = 7 +entry1FieldBackground(C) = #333842 +entry1Relief(FArelief) = flat +entry1BorderWidth(I) = 0 +entry1Padding(I) = 7 +entry1TextColor(C) = #C0C0C0 +iconTabIcon(P) = assets/tab-icons/icon.png +tabIconsSize(I) = 30 +generateTabIcon(P) = assets/tab-icons/generate.png +headerFill(FAfill) = x +tabFramePadding(I) = 10 +contentTabFrameFill(FAfill) = both +contentTabFrameExpand(I) = 1 +outsidelayoutFramesPadX(I) = 6 +GIFFrameSeparators(I) = 16 +generateFilesLabelWidth(I) = 15 +generateFilesLabelAnchor(FAanchor) = center +generateInputFilesPadding(I) = 6 +generateHorizontalSeparatorPadY(I) = 10 +generateOutputFilesPadding(I) = 6 +generateStartButtonPadding(I) = 10 +generateStartButtonPadY(I) = 6 +formatTabIcon(P) = assets/tab-icons/format.png +loadingListPadX(I) = 12 +loadingButtonWidth(I) = 15 +formatHorizontalSeparatorPadY(I) = 10 +formatVerticalSeparatorPadY(I) = 10 +EPOSTypeFramePadY(I) = 0 +EPOSPersonSeparatorFramePadY(I) = 0 +EPOSRowSeparatorFramePadY(I) = 0 +EPOSDataSeparatorFramePadY(I) = 7 +EPOSLabelWidth(I) = 30 +EPOSLabelAnchor(FAanchor) = center +radiobutton1Background(C) = #21242D +radiobutton1TextColor(C) = #C0C0C0 +radiobutton1IndicatorBackground(C) = #21242D +checkbutton1Background(C) = #21242D +checkbutton1TextColor(C) = #C0C0C0 +checkbutton1IndicatorBackground(C) = #21242D +text1Background(C) = #333842 +text1TextColor(C) = #C0C0C0 +text1Relief(FArelief) = flat +EPDataLocalizationPadX(I) = 6 +EPDataLocalizationPadY(I) = 6 +editingPresetButtonsPadY(I) = 6 +editingPresetSaveButtonWidth(I) = 25 +editingPresetCancelButtonWidth(I) = 25 +settingsTabIcon(P) = assets/tab-icons/settings.png +settingsHorizontalSeparatorPadY(I) = 10 +settingsVerticalSeparatorPadY(I) = 10 +settingsCodeLabelWidth(I) = 35 +settingsCodeLabelAnchor(FAanchor) = w +settingsOtherLabelWidth(I) = 35 +settingsOtherLabelAnchor(FAanchor) = w +settingsHeadlineLabelWidth(I) = 35 +settingsHeadlineLabelAnchor(FAanchor) = w +settingsSchoolDataLabelAnchor(FAanchor) = center +settingsButtonsPadY(I) = 6 +settingsButtonSaveWidth(I) = 20 +settingsButtonCancelWidth(I) = 15 +settingsButtonPDUOWidth(I) = 35 +settingsButtonPDUWWidth(I) = 35 +settingsButtonZPFWidth(I) = 35 +aboutTabIcon(P) = assets/tab-icons/about.png +button2TextAnchor(FAanchor) = center +button2Background(C) = #21242D +button2Padding(I) = 0 +aboutLogoButtonImg(P) = assets/icon.png +aboutLogoButtonImgSize(I) = 250 +aboutInstructionButtonWidth(I) = 25 +aboutOtherInfoFramePadX(I) = 10 +ZPFWindowWidth(I) = 500 +ZPFWindowHeight(I) = 400 +ZPFWindowWidthResizable(B) = 0 +ZPFWindowHeightResizable(B) = 0 +ZPFWindowMainBG(C) = #21242D +listbox1BG(C) = #333842 +listbox1TextColor(C) = #C0C0C0 +listbox1Relief(FArelief) = flat +listbox1BorderWidth(I) = 0 +listbox1ActiveStyle(FAactivestyle) = none +listbox1HighlightThickness(I) = 0 +listbox1SelectBG(C) = #4F4F4F \ No newline at end of file diff --git a/documentation/about_program.html b/documentation/about_program.html new file mode 100644 index 0000000..18375ee --- /dev/null +++ b/documentation/about_program.html @@ -0,0 +1,115 @@ + + + + + + + Generator CSV + + +

+
+
+
+
+ +
+
+
+
+

+ +

+ Generator CSV +

+ +

+ Wersja 4.0 (Build 20254) +

+ +

+
+ © styczeń 2019 - wrzesień 2020
+
+ Mateusz Skoczek
+
+ dla ZSP Sobolew
+

+ +
+
+
+
+
+
+
+
+
+
+ +

Historia wersji

+ +

Wersja 1.0

+
+ +
+
+
+ +

Wersja 2.0

+
+ +
+
+
+ +

Wersja 3.0

+
+ +
+
+
+ +

Wersja 3.0.1

+
+ +
+
+
+ +

Wersja 4.0 (work in progress)

+
+ +
+
+
+ + \ No newline at end of file diff --git a/documentation/content.css b/documentation/content.css new file mode 100644 index 0000000..19859c5 --- /dev/null +++ b/documentation/content.css @@ -0,0 +1,104 @@ +h1 { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 35px; + text-align: center; +} + +h2 { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 25px; + text-align: center; +} + +h5 { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 15px; +} + +p { + color: #C0C0C0; + font-family: 'Segoe UI'; +} + +#description-text { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 17px; + line-height: 25px; + text-align: center; +} + +#description-image { + text-align: center; +} + +#about-program-image { + text-align: center; +} +#about-program-main-text { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 17px; + line-height: 25px; + text-align: center; +} + +#about-program-text-centered { + text-align: center; +} + +#about-program-changelog-main-version { + color: #C0C0C0; + font-family: 'Segoe UI'; + font-size: 17px; + font-weight: 600; +} + +td { + color: #C0C0C0; + font-family: 'Segoe UI'; +} + +th { + color: #C0C0C0; + font-family: 'Segoe UI'; +} + +.accordion { + background-color: #333842; + color: #444; + cursor: pointer; + padding: 18px; + width: 100%; + text-align: left; + border: none; + outline: none; + transition: 0.4s; + color: #C0C0C0; + font-size: 18px; + font-family: 'Segoe UI'; +} + +.active, .accordion:hover { + background-color: #3a3f4b; +} + +.panel { + padding: 0 18px; + background-color: #2e313b; + display: none; + overflow: hidden; +} + +li { + color: #C0C0C0; + font-family: 'Segoe UI'; +} + +code { + color: #C0C0C0; + font-size: large; +} \ No newline at end of file diff --git a/documentation/description.html b/documentation/description.html new file mode 100644 index 0000000..290677b --- /dev/null +++ b/documentation/description.html @@ -0,0 +1,18 @@ + + + + + + + Generator CSV + + +

Program "Generator CSV" służy do przetwarzania plików danymi uczniów/nauczycieli i generowania plików wyjściowych w formacie pozwalającym na import danych na stronie szkoły oraz portal.office.com

+
+
+


+


+


+


+ + \ No newline at end of file diff --git a/documentation/index.html b/documentation/index.html new file mode 100644 index 0000000..915b1cb --- /dev/null +++ b/documentation/index.html @@ -0,0 +1,30 @@ + + + + + + + Generator CSV + + +
+
+ +
+

GENERATOR CSV

+
+ +
+
+ +
+
+ + \ No newline at end of file diff --git a/documentation/instruction.html b/documentation/instruction.html new file mode 100644 index 0000000..7e1a31e --- /dev/null +++ b/documentation/instruction.html @@ -0,0 +1,163 @@ + + + + + + + Generator CSV + + + +
+

Dane dla przykładu:

+
+

W praktyce układ danych wygląda tak (* - nieznaczące dla programu dane):

+

[imię] [nazwisko]
[klasa] [szkoła]
[login], [haslo*]

+

Uruchom program i otwórz zakładkę FORMAT DANYCH. W pierwszej kolejności należy nadać nazwę presetowi formatu w polu zaznaczonym poniżej lub wybrać preset już istniejący z listy rozwijanej

+
+

Aby przejśc do edycji presetu należy wcisnąć przycisk WCZYTAJ

+
+
Typ osoby
+

Wybierz odpowiednią opcję w zależności od tego jakich osób dane znajdują się w pliku wejściowym

+
Separator pomiędzy danymi
+

W tym polu należy wpisać znaki, które oddzielają zbiór danych pojeńczych osób. Jeżeli zbiór danych odziela znak końca wiersza (wciśnięcie ENTER) należy wpisać <enter> (ilość zależna od ilości znaków końca wiersza). Niedozwolone znaki to litery, cyfry oraz * i \. Dla przykładowych danych będzie to "<enter><enter>"

+
Separator pomiędzy wierszami
+

W tym polu należy wpisać znaki, które oddzielają wiersze. Zazwyczaj jest to jeden znak końca wiersza. Jeżeli wiersze odziela znak końca wiersza (wciśnięcie ENTER) należy wpisać <enter> (ilość zależna od ilości znaków końca wiersza). Niedozwolone znaki to litery, cyfry oraz * i \. Dla przykładowych danych będzie to "<enter>"

+
Separatory pomiędzy danymi
+

W tym polu należy wpisać znaki, które oddzielają pojedyńcze dane. Każdy kolejny separator musi być zapisany w następnej linijce. Jeżeli dane odziela znak końca wiersza (wciśnięcie ENTER) należy wpisać <enter> (ilość zależna od ilości znaków końca wiersza). Niedozwolone znaki to litery, cyfry oraz * i \. Dla przykładowych danych będzie to (znaki są podkreślone aby je wyróżnić):
"""
, 

"""

+
Prawa kolumna - pozycja danych w zbiorze
+

W tej sekcji należy dla każdego typu danych ustawić jego położenie w zbiorze. Typy SZKOŁA i KLASA nie są istotne jeżeli w sekcji TYP OSOBY zosła zaznaczona opcja Nauczyciele. Dla przykładowych danych uczniów bedzie to:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WierszPozycja
w wierszu
Login31
Imię11
Nazwisko12
Szkoła22
Klasa21
+
Prawa kolumna - Kodowanie
+

W tym polu należy wybrać kodowanie pliku wejściowego.

+
+

Aby zapisać preset należy wcisnąć przycisk ZAPISZ. Aby anulować tworzenie należy wcisnąć przycisk Anuluj

+
+ + +
+

Uruchom program i przejdź do zakładki USTAWIENIA.

+
+
Kodowanie wyjściowe dla pliku poczty
+

W tym polu należy wybrać kodowanie, w jakim ma być zapisany plik csv z danymi uczniów do importu w panelu administracyjnym serwisu szkoły

+
Kodowanie wyjściowe dla pliku office
+

W tym polu należy wybrać kodowanie, w jakim ma być zapisany plik csv z danymi uczniów do importu w panelu administracyjnym serwisu portal.office.com

+
Domena (używana w mailu)
+

W tym polu należy wpisać domenę serwisu szkoły. Będzie ona używana w mailu każdego uzytkownika. Przykład: jan.kowalski2023a@losobolew.pl

+
Quota (MB)
+

W tym polu należy wpisać ilość miejsca (w megabajtach) przeznaczoną dla każdego użytkownika na przechowywanie maili. Te dane są używane w pliku wyjściowym poczty. Przykład: jan.kowalski2023a@losobolew.pl,1234567u:JK,500

+
Kraj (zapisany w danych na office)
+

W tym polu należy wpisać nazwę kraju zamieszkania użytkowników. Będzie ona wykorzystywana w pliku wyjściowym office oraz widoczna w profilu użytkownika w serwisie office. Przykład: jan.kowalski2023a@losobolew.pl,Jan,Kowalski,Jan Kowalski,uczeń,1b LO,,,,,,,,,Rzeczpospolita Polska

+
Nagłówek dla pliku wyjściowego poczty
+

Jeżeli chcesz aby w pierwszej linii pliku wyjściowego dla poczty znajdował się nagłowek, zaznacz opcję "Umieść w pliku". Zawartość nagłówka można edytować w polu tekstowym po lewej.

+
Nagłówek dla pliku wyjściowego office
+

Jeżeli chcesz aby w pierwszej linii pliku wyjściowego dla office znajdował się nagłowek, zaznacz opcję "Umieść w pliku". Zawartość nagłówka można edytować w polu tekstowym po lewej.

+
Rozpoczęcie roku szkolnego (DD | MM)
+

W tych polach należy wpisać datę rozpoczęcia roku szkolnego (z reguły). W pierwszym polu (po lewo) należy wpisać dzień, a w drugim (po prawo) miesiąc. Te dane są używane do obliczania roku w znaczniku klasy (przykłądowy znacznik klasy: 2023a). W przypadku generowania plików na nowy rok szkolny przed jego rozpoczęciem, należy wprowadzić datę dzisiejszą lub wcześniejszą.

+
Dane o szkołach
+

W tym polu należy wprowadzić dane każdej szkoły w zespole szkół (po jednej szkole w linijce). Wymagane są trzy "kolumny danych". Są one odzielone znakami " | ".
W pierwszej kolumnie należy wpisać oznaczenie szkoły (dowolne bez spacji, najlepiej jak najkrótsze). Te dane będą używane w znaczniku klasy, jeżeli w trzeciej kolumnie została wybrana opcja "1".
W drugiej kolmnie należy wpisać liczbę klas w danej szkole. Te dane używane są do obliczenia roku w znaczniku klasy.
W trzeciej kolumnie można wybrać opcję "1" lub "0" (Prawda/Fałsz). Wybierz "1" jeżeli chcesz, aby w znaczniku klasy znajdowało się oznaczenie szkoły (przykład: 2023bs). Wybierz "0" jeżeli chcesz, aby w znaczniku klasy znajdowała się litera klasy (przykład: 2023a).

+
+

Aby zapisać ustawienia należy wcisnąć przycisk ZAPISZ. Aby anulować zmiany wciśnij przycisk Anuluj

+
+ + +
+
Krok 1
+

W pierwszej kolejności należy przygotować pliki wejściowe oraz stworzyć presety formatu dla tych plików, według instrukcji w sekcji "Tworzenie/edytowanie format presetu dla danego pliku źródłowego" (jednego presetu formatu można używac do kilku plików jeżeli pliki mają ten sam format i to samo kodowanie)

+
Krok 2
+

Przejdź do zakładki GENERATOR CSV. Możesz przetworzyć naraz 4 pliki wejściowe. Dla każdego pliku należy wybrać jego lokalizację (wpisać ją w polu, oznaczonym kolorem czerwonym na poniższym zdjęciu, lub otworzyć okno wyboru lokalizacji za pomocą przycisku "Przeglądaj" i tam wybrać plik. Następnie należy wybrać preset formatu, odpowiedni dla pliku wejściowego, w polu oznaczonym kolorem zielonym na poniższym zdjęciu.

+
+
Krok 3
+

Wybierz lokalizację zapisu pliku wyjściowego dla serwisu szkoły, wpisując lokalizację wraz z nazwą pliku w polu, oznaczonym kolorem czerwonym na poniższym zdjęciu, lub otwierając okno wyboru lokalizacji za pomocą przycisku "Przeglądaj" obok tego pola i tam wybierając plik.
Wybierz lokalizację zapisu pliku wyjściowego dla serwisu portal.office.com, wpisując lokalizację wraz z nazwą pliku w polu, oznaczonym kolorem zielonym na poniższym zdjęciu, lub otwierając okno wyboru lokalizacji za pomocą przycisku "Przeglądaj" obok tego pola i tam wybierając plik.

+
+
Krok 4
+

Aby rozpocząć generowanie wciśnij przycisk START i potwierdź komunikat. Pliki wyjściowe zostaną zapisane w wybranych lokalizacjach. Przed importem upewnij się że w plikach nie występują błędy.

+
+ + +
+
Krok 1
+

Uruchom program i przejdź do zakładki USTAWIENIA.

+
Krok 2
+

Naciśnij przycisk "Zarządzaj presetami formatu".

+
Krok 3
+

Zaznacz presety formatu które chcesz usunąć.

+
Krok 4
+

Naciśnij przycisk "Usuń zaznaczone"

+
+ + +
+
Krok 1
+

Uruchom program i przejdź do zakładki USTAWIENIA.

+
Krok 2
+

Naciśnij przycisk "Przywróć domyślne ustawienia ogólne". Po potwierdzeniu i ponownym uruchomieniu programu, ustawienia zostaną przywrócone do ustawień fabrycznych.

+
+ + +
+
Krok 1
+

Uruchom program i przejdź do zakładki USTAWIENIA.

+
Krok 2
+

Naciśnij przycisk "Przywróć domyślne ustawienia wyglądu". Po potwierdzeniu i ponownym uruchomieniu programu, wygląd zostanie przywrócony do ustawień fabrycznych.

+
+ + +
+
Krok 1
+

Otwórz menu start i wpisz "%appdata%"

+
Krok 2
+

Przejdź do folderu "Generator CSV"

+
Krok 3
+

Za ustawienia programu odpowiedzialny jest plik "config.cfg", a za wygląd plik "style.cfg". Użyj dowolnego edytora plików tekstowych, do edycji tych plików. Więcej informacji o tych plikach znajduje się w Dokumentacji technicznej.
Aby przywrócić te pliki do stanu fabrycznego wykonaj kroki z sekcji odpowiednio "Przywracanie domyślnych ustawień ogólnych programu" lub "Przywracanie domyślnego wyglądu programu"

+
+ + + + \ No newline at end of file diff --git a/documentation/main.css b/documentation/main.css new file mode 100644 index 0000000..74bac21 --- /dev/null +++ b/documentation/main.css @@ -0,0 +1,80 @@ +body, html{ + background-color: #21242D; + margin: 0px; + height: 100%; + width: 100%; +} + + +header { + width: 100%; + position: sticky; +} + +#header-image { + background-color: #333842; + width: 100px; + height: 100px; + float: left; + padding: 25px; +} + +#header-text { + background-color: #333842; + overflow: auto; + line-height: 40px; + font-family: 'Segoe UI'; + color: #C0C0C0; + font-size: 30px; + padding: 25px; +} + + + + +nav { + width: 100%; +} + +#menu-ul { + width: 100%; + height: 50px; + padding: 0; + margin: 0; + list-style: none; +} + +#menu-li a { + display: block; + float: left; + text-align: center; + font-family: 'Segoe UI'; + margin-right: 0.05%; + margin-left: 0.05%; + font-size: 20px; + width: 24.9%; + line-height: 50px; + text-decoration: none; + color: #C0C0C0; + background-color: #2e313b; +} + +#menu-li a:hover { + color: #C0C0C0; + background: #333842; +} + + + +section { + width: 100%; +} + +iframe { + float: left; + width: 100%; + border: none; + height: calc(100% - 220px); + overflow: scroll; + position: absolute; +} \ No newline at end of file diff --git a/documentation/program_documentation.html b/documentation/program_documentation.html new file mode 100644 index 0000000..790af67 --- /dev/null +++ b/documentation/program_documentation.html @@ -0,0 +1,388 @@ + + + + + + + Generator CSV + + + +
+

Aby móc uruchomić aplikację w wersji developerskiej należy pobrać Pythona (wersja zalecana: 3.8.5) oraz wymagane biblioteki (wymienione w sekcji 'generator.pyw - Import bibliotek')

+
+ + +
+

+ Biblioteki główne
+
+ W tej sekcji importowane są wszystkie biblioteki niezwiązane z interfejsem graficznych
+

+

+

+
+ Biblioteki interfejsu graficznego
+
+ W tej sekcji importowane są wszystkie biblioteki związane z interfejsem graficznym +
+

+

+
+ + +
+

+ Informacje o programie
+
+ programName - Zmienna definująca nazwę programu
+ programVersion - Zmienna definiująca główną wersję programu
+ programVersionStage - Zmienna definiująca etap rozwoju programu. Wersja stabilna definiowana jest przez pusty string
+ programVersionBuild - Zmienna definiująca numer buildu programu. Zapisany jest on w formacie '[ostatnie dwie cyfry roku][numer dnia w roku]'
+ programCustomer - Zmienna definiująca nazwę organizacji zlecającej stworzenie programu
+ programAuthors - Lista zawierająca nazwy osób rozwijających program.
+ programToW - Lista zawierająca informacje na temat czasu rozwoju programu. Format: ['miesiąc rozpoczęcia prac', 'rok rozpoczęcia prac', 'aktualny dla rozwoju danej wersji miesiąc', 'aktualny dla rozwoju danej wersji rok']
+
+
+ Dozwolone kodowanie plików
+
+ allowedCoding - Lista zawierająca wspierane kodowania plików. Są one wyświetlane w rozwijanych listach wyboru kodowania pliku.
+
+
+ Dozwolone znaki
+
+ allowedCharactersInSeparator - Lista zawierająca znaki które można wpisać w pola dotyczące separatorów osób, linii i danych
+
+
+ Katalog APPDATA
+
+ appdataPath - zmienna definiująca ścieżkę do folderu %appdata% +

+
+ + +
+

+ Lista komunikatów
+
+ Słownik MSGlist zawiera listę komunikatów. Format: '[kod dialogowy]' : '[komunikat]'. Kod dialogowy składa się z [jednoznakowego znacznika rodzaju okna dialogowego][czterocyfrowego numeru komunikatu]
+
+
+ Rodzaje okien dialogowych: +

+

+

+
+ Funkcja odpowiedzialna za wywoływanie komunikatów dialogowych
+
+ Wywoływanie funkcji: MSG([kod dialogowy],[True - Zakończ działanie programu po zamknięciu okna dialogowego/False - Kontynuuj działanie programu po zamknięciu okna dialogowego],[dodatkowe informacje wyświetlane w komunikacie - opcjonalnie])
+
+ + try:
+     optionalInfo[0]
+ except:
+     optionalInfo = ['']
+
+ Sprawdza czy zostały wpisane 'dodatkowe informacje wyświetlane w komunikacie' i jeżeli nie, definiuje listę, w której znajduje się pusty string (ma to na celu uniknięcia błędu podczas próby wywołania dodatkowych informacji przez dalszą część funkcji)
+
+ + if code[0] == 'E/I/W':
+     TKmsb.showerror/showinfo/showwarning('
[tytuł komunikatu]', '%s\n%s' % (MSGlist[code], optionalInfo[0]))
+
+ Wywoływanie danego rodzaju komunikatu na podstawie jednoznakowego znacznika rodzaju okna dialogowego.
+
+ + if terminate:
+     SS.exit(0)
+
+ Zakończenie działania programu po zamknięciu okna dialogowego, jeżeli została ustawiona opdowiednia opcja.
+
+ + elif code[0] == 'A':
+     if TKmsb.askokcancel('Pytanie', '%s\n%s' % (MSGlist[code], optionalInfo[0])):
+         return True
+     else:
+         return False
+
+ Funkcja zwraca wartość boolean w przypadku wywołania komunikatu zapytania +

+
+ + +
+

+ Klasa checkAppdata odpowiedzialna jest za sprawdzenie poprawności i, w razie potrzeby, doprowadzenie go do stanu poprawności. +
+
+ Główna funkcja programu
+
+ 1. Czy w folderze %appdata% istnieje folder programu (Generator CSV)?
+ Jeżeli nie istnieje, uruchamiana jest funckja __buildAppdata (odpowiedzialna za zbudowanie całości katalogu programu).
+ 2. Czy w folderze programu istnieje plik 'version' (przechowuje on numer buildu programu, w którym został zbudowany katalog programu)?
+ Jeżeli nie istnieje, uruchamiane jest okno dialogowe zapytania z pytaniem czy pozwolić na zresetowanie katalogu programu i kontynuować ładowanie programu
+ 3. Czy numer buildu programu w pliku 'version' jest zgodny z numerem buildu zawartym w zmiennej VAR.programVersionBuild
+ Jeżeli nie, uruchamiane jest okno dialogowe zapytania z pytaniem czy pozwolić na zresetowanie katalogu programu i kontynuować ładowanie programu
+ Jeżeli tak, sprawdzane są poszczególne pliki i foldery które powinny być zawarte w folderze, i jeżeli któryś plik/folder nie znajduje się w folderze, wywołuje się funkcje mające na celu przywrócenie/utworzenie tych plików/folderów (odpowiednio: __restoreCFG dla plików konfiguracyjnych, __createFormatPresetsDir dla folderu przechowującego format presety)
+
+
+ Budowanie katalogu programu (__buildAppdata)
+
+ Funkcja ta, jest odpowiedzialna za zbudowanie całości katalogu programu w folderze %appdata%.
+ 1. Tworzenie katalogu 'Generator CSV'
+ 2. Tworzenie pliku 'version' i zapisanie w nim numeru buildu.
+ 3. Inicjacja funkcji __restoreCFG (w celu skopiowania pliku 'config.cfg' z głównego katalogu programu do katalogu 'Generator CSV' w folderze %appdata%).
+ 4. Inicjacja funkcji __restoreCFG (w celu skopiowania pliku 'style.cfg' z głównego katalogu programu do katalogu 'Generator CSV' w folderze %appdata%).
+ 5. Inicjacja funkcji __createFormatPresetsDir (w celu stworzenia folderu 'format-presets' przechowującego format presety)
+
+
+ Resetowanie katalogu programu (__resetAppdata)
+
+ Funkcja ta, jest odpowiedzialna za przywrócenie katalogu programu w folderze %appdata% do stanu podstawowego oraz stworzenie kopii zapasowej starego katalogu.
+ 1. W przypadku gdy w katalogu istnieje jeszcze starsza kopia zapasowa folderu, kopia ta jest usuwana.
+ 2. Nazwa katalogu programu jest zmieniana na taką z dopiskiem '_old'.
+ 3. Inicjacja funkcji __buildAppdata w celu zbudowania nowego katalogu programu
+ 4. Skopiowanie katalogu 'Generator CSV_old' do nowego katalogu 'Generator CSV'
+
+
+ Przywracanie plików konfiguracyjnych (__restoreCFG)
+
+ Funkcja ta, jest odpowiedzialna za skopiowanie pliku konfiguracyjnego (.cfg) o danej nazwie z głównego katalogu programu do katalogu programu w folderze %appdata%
+
+
+ Tworzenie katalogu przechowującego format presety (__createFormatPresetsDir)
+
+ Funkcja ta, jest odpowiedzialna za utworzenie folderu 'format-presets', przechowującego format presety, w katalogu programu w folderze %appdata% +

+
+ + +
+

+ Klasa CFG odpowiedzialna jest za zarządzanie plikiem konfiguracyjnym 'config.cfg'
+
+
+ Odczytywanie pojedyńczej zmiennej z pliku (R)
+
+ Funkcja ta, jest odpowiedzialna za odczytanie zawartości danego recordu i sprawdzenie jego poprawności
+ 1. Inicjacja funkcji __checkIfFileExist w celu sprawdzenia czy plik 'config.cfg' istnieje
+ 2. Zczytanie i zapisanie wszystkich danych z pliku 'config.cfg' do słownika content w formacie: 'nazwa zmiennej' : ['zmienna', 'typ zmiennej']
+ 3. Inicjacja funckji __checkIfRecordExist w celu sprawdzenia czy w słowniku content znajduje się żądany record
+ 4. Inicjacja, odpowiedniej dla typu zmiennej, funkcji mającej na celu sprawdzenie jej poprawności i jej przetworzenie
+ 5. Funkcja zwraca wartość zmiennej.
+
+
+ Zapisywanie zmian w pliku (W)
+
+ Funkcja ta jest odpowiedzialna za sprawdzenie, przetworzenie i zapisanie zmian w pliku konfiguracyjnych.
+ 1. Inicjacja funkcji __checkIfFileExist w celu sprawdzenia czy plik 'config.cfg' istnieje
+ 2. Zczytanie i zapisanie wszystkich danych z pliku 'config.cfg' do słownika content w formacie: 'nazwa zmiennej' : ['zmienna', 'typ zmiennej']
+ 3. Inicjacja, odpowiedniej dla typu zmiennej, funkcji mającej na celu sprawdzenie jej poprawności i jej przetworzenie, dla każdego recordu ze słownika changes
+ 4. Nadpisanie zmiennej ze słownika content, wartością var.
+ 5. Zapisanie zawartości słownika content w pliku 'config.cfg'
+ 6. Funkcja zwraca True jeżeli operacja została wykonana pomyślnie lub False jeżeli wystąpił błąd
+
+
+ Funkcje sprawdzające istnienie
+
+ __checkIfFileExist - funkcja sprawdza czy plik istnieje i możliwe jest jego nadpisanie (w przypadku zapisu)
+ __checkIfRecordExist - funkcja sprawdza czy record istnieje w słowniku content
+
+
+ Funkcje sprawdzające poprawność recordu
+
+ Funkcje te odpowiadają za sprawdzenie poprawności zmiennej i w razie potrzeby przetwarzają ją na pożądaną formę. +

+
+ + +
+

+ Klasa GUI odpowiedzialna jest za zarządzanie plikiem konfiguracyjnym 'style.cfg'
+
+
+ Odczytywanie pojedyńczej zmiennej z pliku (R)
+
+ Funkcja ta, jest odpowiedzialna za odczytanie zawartości danego recordu i sprawdzenie jego poprawności
+ 1. Inicjacja funkcji __checkIfFileExist w celu sprawdzenia czy plik 'style.cfg' istnieje
+ 2. Zczytanie i zapisanie wszystkich danych z pliku 'style.cfg' do słownika content w formacie: 'nazwa zmiennej' : ['zmienna', 'typ zmiennej']
+ 3. Inicjacja funkcji __checkIfRecordExist w celu sprawdzenia czy w słowniku content znajduje się żądany record
+ 4. Inicjacja, odpowiedniej dla typu zmiennej, funkcji mającej na celu sprawdzenie jej poprawności i jej przetworzenie
+ Funkcja zwraca wartość zmiennej.
+
+
+ Funkcje sprawdzające istnienie
+
+ __checkIfFileExist - funkcja sprawdza czy plik istnieje
+ __checkIfRecordExist - funkcja sprawdza czy record istnieje w słowniku content
+
+
+ Funkcje sprawdzające poprawność recordu
+
+ Funkcje te odpowiadają za sprawdzenie poprawności zmiennej i w razie potrzeby przetwarzają ją na pożądaną formę. +

+
+ + +
+

+ Klasa FMT odpowiedzialna jest za zarządzanie plikami formatu (.fmt)
+
+
+ Odczytywanie pojedyńczej zmiennej z pliku (R)
+
+ Funkcja ta, jest odpowiedzialna za odczytanie zawartości danego recordu i sprawdzenie jego poprawności
+ 1. Inicjacja funkcji __checkIfFolderExist w celu sprawdzenia czy folder 'format-presets' istnieje
+ 2. Sprawdzenie czy podany plik formatu (preset) znajduje się w folderze 'format-presets' (funkcja getList zwraca listę plików formatu w folderze 'format-presets')
+ Jeżeli nie, wartość zmiennej jest wybierana ze słownika content (zawierającego podstawowe wartości zmiennych)
+ Jeżeli tak: + 3. Zczytanie i zapisanie wszystkich danych z wybranego pliku formatu do słownika content w formacie: 'nazwa zmiennej' : ['zmienna', 'typ zmiennej']
+ 4. Inicjacja funkcji __checkIfRecordExist w celu sprawdzenia czy w słowniku content znajduje się żądany record
+ 5. Inicjacja, odpowiedniej dla typu zmiennej, funkcji mającej na celu sprawdzenie jej poprawności i jej przetworzenie
+ Funkcja zwraca wartość zmiennej.
+
+
+ Zapisywanie zmian w pliku (W)
+
+ Funkcja ta jest odpowiedzialna za sprawdzenie, przetworzenie i zapisanie zmian w pliku konfiguracyjnych.
+ 1. Inicjacja funkcji __checkIfFolderExist w celu sprawdzenia czy folder 'format-presets' istnieje
+ 2. Sprawdzenie czy podany plik formatu (preset) znajduje się w folderze 'format-presets' (funkcja getList zwraca listę plików formatu w folderze 'format-presets')
+ Jeżeli nie, tworzony jest słownik content z zawartością podstawową + Jeżeli tak: Zczytanie i zapisanie wszystkich danych z wybranego pliku formatu do słownika content w formacie: 'nazwa zmiennej' : ['zmienna', 'typ zmiennej']
+ 3. Inicjacja, odpowiedniej dla typu zmiennej, funkcji mającej na celu sprawdzenie jej poprawności i jej przetworzenie, dla każdego recordu ze słownika changes
+ 4. Nadpisanie zmiennej ze słownika content, wartością var.
+ 5. Zapisanie zawartości słownika content w pliku 'config.cfg'
+ 6. Funkcja zwraca True jeżeli operacja została wykonana pomyślnie lub False jeżeli wystąpił błąd
+
+
+ Funkcja zwracająca listę presetów (getList)
+
+ Funkcja ta odpowiedzialna jest za stworzenie listy plików .fmt w folderze 'format-presets' oraz za jej zwrócenie.
+
+
+ Funkcje sprawdzające istnienie
+
+ __checkIfFolderExist - funkcja sprawdza czy folder 'format-presets' istnieje (inicjuje checkAppdata)
+ __checkIfRecordExist - funkcja sprawdza czy record istnieje w słowniku content
+
+
+ Funkcje sprawdzające poprawność recordu
+
+ Funkcje te odpowiadają za sprawdzenie poprawności zmiennej i w razie potrzeby przetwarzają ją na pożądaną formę. +

+
+ + +
+

+ Klasa dataProcess odpowiedzialna za przetwarzanie plików wejściowych i generowanie plików wyjściowych
+
+
+ Główna funkcja klasy (start)
+
+ Funkcja ta odpowiedzialna za zainicjowanie kolejnych funkcji w odpowiedniej kolejności oraz zwrócenie informacji o błędach lub pomyślnym wykonaniu polecenia
+ 1. Inicjacja funkcji __checkIfAtLeastOneInputFileIsFilled w celu sprawdzenia czy przynajmniej jedno pole plików wejściowych zostało wypełnione
+ 2. Inicjacja funkcji __checkIfInputFilesIsReadable w celu sprawdzenia czy pliki wejściowe, do których ścieżki zostały podane, są możliwe do odczytania
+ 3. Inicjacja funkcji __checkIfInputFilesFormatPresetsExist w celu sprawdzenia czy format presety, które zostały wybrane, istnieją
+ 4. Inicjacja funkcji __getData w celu zebrania danych z plików wejściowych
+ 5. Dla każdego zbioru danych - for x in data (dla każdej osoby), inicjacja funkcji __checkLogin, __checkFname, __checkLname, oraz dla uczniów __checkSchool, __checkClass, w celu sprawdzenia poprawności danych
+ 6. Inicjacja funkcji __processData w celu przetworzenia danych w linie gotowe do zapisania w plikach wyjściowych
+ 7. Inicjacja funkcji __checkIfCreatingOutputFilesIsPossible w celu sprawdzenia czy możliwe jest utworzenie plików wyjściowych
+ 8. Inicjacja funkcji __saveData w celu zapisania danych w plikach wyjściowych
+ Funkcja zwraca listę zawierającą zmienne boolean potwierdzające w którym momencie zakończyło się wykonywanie funkcji (z powodu błędu lub pomyślnego ukończenia operacji)
+
+
+ Funkcje sprawdzające istnienie +
+ __checkIfAtLeastOneInputFileIsFilled - sprawdza czy przynajmniej jedno pole plików wejściowych zostało wypełnione oraz zwraca dane z wypełnionych pól
+ __checkIfInputFilesIsReadable - sprawdza czy pliki wejściowe są możliwe do odczytania
+ __checkIfInputFilesFormatPresetsExist - sprawdza czy wybrane format presety istnieją
+ __checkIfCreatingOutputFilesIsPossible - sprawdza czy utworzenie plików wyjściowych jest możliwe
+
+
+ Funkcje sprawdzające poprawność +
+ Funkcje te sprawdzają poprawność określonych typów danych. +
+
+ Wyodrębnienie danych z plików (__getData)
+
+ Funkcja odpowiedzialna jest za wyodrębnienie danych z pliku (path) na podstawie określonego format presetu (format) + Dla każdego zbioru ścieżek plików wejściowych i format presetów (for x in input):
+ 1. Pobranie danych z pliku formatu (za pomocą funkcji FMT.R)
+ 2. Pobranie zawartości z pliku wyjściowego i podzielenie ich na zbiory danych pojedyńczych osób (.split(personseparator))
+ Dla każdego zbioru danych pojedyńczych osób (for x in file):
+ 3. Dzielenie zbioru danych na linie (x.split(linesSeparator))
+ 4. Dla każdej linii: dzielenie danych na pojedyńcze segmenty separatorami z listy dataSeparators
+ 5. Wyodrębnienie wymaganych danych ze zbioru
+ 6. Dodanie danych pojedyńczej osoby do listy data
+
+
+ Przetworzenie danych (__processData)
+
+ Funkcja odpowiedzialna jest za przetworzenie danych w linie gotowe do zapisania w plikach wyjściowych
+ Funkcja zwraca listę [mailData, officeData]
+
+
+ Zapisanie danych (__saveData)
+
+ Funkcja odpowiedzialna jest za zapisanie danych w plikach wyjściowych dla poczty i dla office +

+
+ + +
+

+ Klasa GUI odpowiada za interfejs programu
+
+
+ 1. Główna funkcja programu
+
+ - Stworzenie okna
+ - Inicjacja styli kontrolek
+ - Kontrolki
+
+
+ Akcje przycisków
+
+ Funkcje inicjowane przez naciśnięcie przycisków +

+
+ + + + \ No newline at end of file diff --git a/format.py b/format.py deleted file mode 100644 index 69472dc..0000000 --- a/format.py +++ /dev/null @@ -1,141 +0,0 @@ -# Oznaczenia zmiennych: -# K - Klasa -# N - Nazwisko -# I - Imie -# L - Login do librusa - - - - - -import codecs as cd - -def SprawdzKlasa(K): - if len(K.split(' ')) != 2: # Wywołuje błąd jeżeli napis nie dzieli się w pożądanym formacie - blad = int('x') # - - for x in range(0,10): # - if K[1:].find(str(x)) != -1: # Wywołuje bląd jeżeli w nazwie klasy (poza numerem klasy) znajduje się liczba - blad = int('x') # - - numery_niedozwolone = [0,9,8,7,6,5,4] # Określa numery klas które nie istnieją - - for x in numery_niedozwolone: # - if K[0] == str(x): # Wywołuje błąd jeżeli numer klasy jest równy numerowi niedozwolonemu - blad = int('x') # - - szkoly = ['BS', 'LO'] # Określa istniejące szkoly - - if K.split(' ')[1] not in szkoly: # Wywołuje błąd jeżeli szkola nie należy do szkół istniejących - blad = int('x') # - - oddzialy = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'w', 'y', 'z'] # Określa istniejące oddzialy - - if K[1] not in oddzialy: # Wywołuje błąd jeżeli oddział nie należy do oddziałów istniejących - blad = int('x') # - - -def SprawdzNazwisko(N): - for a in N: - for x in range(0,10): # - if a.find(str(x)) != -1: # Wywoluje blad jeżeli nazwisko zawiera liczbę - blad = int('x') # - - -def SprawdzImie(I): - for x in range(0,10): # - if I.find(str(x)) != -1: # Wywoluje blad jeżeli imie zawiera liczbę - blad = int('x') # - - -def SprawdzLogin(L, CzyUczen): - if CzyUczen and L[-1] != 'u': # Wywoluje blad jeżeli login ucznia nie zawiera na końcu 'u' - blad = int('x') # - - if CzyUczen: # - blad = int(L[:-1]) # Wywoluje blad jeżeli login (-'u' dla ucznia) nie jest liczbą - else: # - blad = int(L) # - - - - -def przetworz(dane): - dane = dane.split('\n\n') # dzielenie danych na pojedyńcze osoby - - przetworzone = [] # tworzenie kontenera na przetworzone dane - - for osoba in dane: # - try: # - x = int(osoba[0]) # - except ValueError: # Sprawdza czy osoba jest nauczycielem czy uczniem - CzyUczen = False # - else: # - CzyUczen = True # - - # Dla uczniów - if CzyUczen: - K = osoba.split(', ')[0].split(' ')[:2] - K = K[0] + ' ' + K[1] - N = osoba.split(', ')[0].split(' ')[2:] - I = osoba.split(', ')[1].split(' ')[0] - L = osoba.split(', ')[1].split(' ')[2] - - # Sprawdzenie poprawności - SprawdzKlasa(K) - SprawdzNazwisko(N) - SprawdzImie(I) - SprawdzLogin(L, CzyUczen) - - dane = [K, N, I, L, CzyUczen] - przetworzone.append(dane) - # Dla nauczycieli - else: - N = osoba.split(', ')[0].split(' ') - I = osoba.split(', ')[1].split(' ')[-4] - L = osoba.split(', ')[1].split(' ')[-2] - - # Sprawdzenie poprawnosci - SprawdzNazwisko(N) - SprawdzImie(I) - SprawdzLogin(L, CzyUczen) - - dane = [N, I, L, CzyUczen] - przetworzone.append(dane) - return przetworzone - - - - - - -# Legenda do części dokumentacji poniżej: -# X - Dane nieznaczące -# Q - Pusta linia - - -# Format danych dla uczniów: -# , -# - -# Przykład: -# 1a BS Nowak, Adam 1234567u -# - - -# Format danych dla nauczycieli: -# , -# - -# Przykład: -# Nowak, Adam 1234567 -# - - - - -# Inne: -# - skrypt akceptuje prefix 'ks.', nieuwzględnia go w przetwarzaniu -# - skrypt akceptuje nazwiska holenderskie (typu 'van X', 'van der X' itp.) i uwzględnia je w przetwarzaniu -# - skrypt nie akceptuje nazwisk złożonych (np. Nowak-Kowalska) -# - skrypt wymaga kodowania ANSI diff --git a/generator.exe b/generator.exe new file mode 100644 index 0000000..fdf6093 Binary files /dev/null and b/generator.exe differ diff --git a/generator.py b/generator.py deleted file mode 100644 index f6919a6..0000000 --- a/generator.py +++ /dev/null @@ -1,415 +0,0 @@ -# GeneratorCSV -# Wersja 3.0.1 -# by Mateusz Skoczek -# luty 2019 - grudzień 2019 -# dla ZSP Sobolew - - - - - - - - - - -## Defincja błędów ############################################################################## - -# E001 - Brak pliku składowego -E001x00 = "Brak pliku formatu 'moduly.py'.\nPrzywróć plik. (E001x00)" -E001x01 = "Brak pliku formatu 'format.py'.\nPrzywróć plik. (E001x01)" -E001x02 = "Brak pliku konfiguracyjnego 'config.cfg'.\nPrzywróć plik. (E001x02)" -E001x03 = "Brak pliku 'instrukcja.txt'.\nPrzywróć plik. (E001x03)" - -# E002 - Błąd pliku składowego -E002x02 = "Nieokreślony błąd pliku konfiguracyjnego 'config.cfg'.\nPrzywróć domyślny plik lub popraw ustawienia. (E002x02)" -E002x021 = "Błąd pliku konfiguracyjnego 'config.cfg'.\nPodane kodowanie nie jest obsługiwane\nPrzywróć domyślny plik lub popraw ustawienia. (E002x021)" - -# E003 - Błąd lokalizacji plików I/O -E003x01 = "Nie podano lokalizacji plików do importu. (E003x01)" -E003x02 = "Nie podano lokalizacji zapisu wygenerowanych plików. (E003x02)" -E003x111 = "Plik podany w sciezce 1 nie istnieje (E003x111)" -E003x112 = "Plik podany w sciezce 2 nie istnieje (E003x112)" -E003x113 = "Plik podany w sciezce 3 nie istnieje (E003x113)" -E003x114 = "Plik podany w sciezce 4 nie istnieje (E003x114)" - -#_______________________________________________________________________________________________# - - - - - - - - - - -## Import bibliotek zewnętrznych ################################################################ - -import tkinter as tk -import codecs as cd -import os -import time as tm -import sys as ss - -# Definicja składowych biblioteki interfejsu graficznego -from tkinter import filedialog as TKfld -from tkinter import messagebox as TKmsb - -#_______________________________________________________________________________________________# - - - - - - - - - - -## Weryfikacja istnienia plików składowych programu ############################################# - -try: - x = open('moduly.py') -except FileNotFoundError: - Message = 'Wystąpił błąd!\n' + E001x00 - tk.showerror('Błąd', Message) - ss.exit(0) - -try: - x = open('format.py') -except FileNotFoundError: - Message = 'Wystąpił błąd!\n' + E001x01 - tk.showerror('Błąd', Message) - ss.exit(0) - -#_______________________________________________________________________________________________# - - - - - - - - - - -## Import modułów programu ###################################################################### - -# Import modułów składowych programu -from moduly import ErrorDialog as MDerr -from moduly import FileCheck as MDfck -from moduly import PolishLetterRemover as MDplr -from moduly import ClassTagCreator as MDctc - -# Import skryptu przetwarzającego dane -import format as ft - -#_______________________________________________________________________________________________# - - - - - - - - - - - -## Weryfikacja istnienia plików składowych ###################################################### - -MDfck('format.py', E001x01) -MDfck('config.cfg', E001x02) -MDfck('instrukcja.txt', E001x03) - -#_______________________________________________________________________________________________# - - - - - - - - - - - -## Wczytywanie pliku konfiguracyjnego ########################################################### - -try: - with open('config.cfg', 'r') as config: - config = config.read().split('\n') - Kodowanie = str(config[0].strip('Kodowanie: ')) - TypyKodowania = ['utf-8', 'cp1252', 'iso-8859-1'] - if Kodowanie not in TypyKodowania: - MDerr(E002x021) -except: - MDerr(E002x02) - -#_______________________________________________________________________________________________# - - - - - - - - - - - -## Inicjacja skryptu przetwarzającego dane ###################################################### - -def Main(): - if TKmsb.askokcancel('Ostrzeżenie', "Czy na pewno chcesz rozpocząć generowanie?\nProgram utworzy w podanej lokalizacji pliki 'email.csv' i 'office.csv'.\nJeżeli w podanej lokalizacji istnieją pliki o takich nazwach zostaną one nadpisane."): - sciezka1 = Pole1.get() - sciezka1_puste = True - sciezka2 = Pole2.get() - sciezka2_puste = True - sciezka3 = Pole3.get() - sciezka3_puste = True - sciezka4 = Pole3.get() - sciezka4_puste = True - sciezkaExport = PoleExport.get() - sciezkaExport_puste = True - - if sciezka1 != '': - sciezka1_puste = False - if sciezka2 != '': - sciezka2_puste = False - if sciezka3 != '': - sciezka3_puste = False - if sciezka4 != '': - sciezka4_puste = False - if sciezkaExport != '': - sciezkaExport_puste = False - - if sciezka1_puste and sciezka2_puste and sciezka3_puste and sciezka4_puste: - MDerr(E003x01) - if sciezkaExport_puste: - MDerr(E003x02) - - KontenerDanych = [] - if not sciezka1_puste: - try: - x = open(sciezka1) - except FileNotFoundError: - MDerr(E003x111) - else: - with open(sciezka1, 'r') as plik1: - KontenerDanych += ft.przetworz(plik1.read()) - if not sciezka2_puste: - try: - x = open(sciezka2) - except FileNotFoundError: - MDerr(E003x112) - else: - with open(sciezka2, 'r') as plik2: - KontenerDanych += ft.przetworz(plik2.read()) - if not sciezka3_puste: - try: - x = open(sciezka3) - except FileNotFoundError: - MDerr(E003x113) - else: - with open(sciezka3, 'r') as plik3: - KontenerDanych += ft.przetworz(plik3.read()) - if not sciezka4_puste: - try: - x = open(sciezka4) - except FileNotFoundError: - MDerr(E003x114) - else: - with open(sciezka4, 'r') as plik4: - KontenerDanych += ft.przetworz(plik4.read()) - - KontenerEmail = [] - KontenerOffice = [] - for osoba in KontenerDanych: - if osoba[-1]: - Klasa = osoba[0] - Imie = osoba[2] - Inicjaly = Imie[0] - Nazwisko = '' - NazwiskoDoEmaila = '' - for x in osoba[1]: - Nazwisko += x + ' ' - NazwiskoDoEmaila += ('.' + x) - Inicjaly += x[0] - Nazwisko = Nazwisko[:-1] - ZnacznikKlasy = MDctc(Klasa) - Login = osoba[3] - Adres = MDplr(Imie).lower() + MDplr(NazwiskoDoEmaila).lower() + ZnacznikKlasy + '@losobolew.pl' - Email = Adres + ',' + Login + ':' + MDplr(Inicjaly) + ',500' - Office = Adres + ',' + Imie + ',' + Nazwisko + ',' + Imie + ' ' + Nazwisko + ',uczeń,' + Klasa + ',,,,,,,,,Rzeczypospolita Polska' - KontenerEmail.append(Email) - KontenerOffice.append(Office) - else: - Imie = osoba[1] - Inicjaly = Imie[0] - Nazwisko = '' - NazwiskoDoEmaila = '' - for x in osoba[0]: - Nazwisko += x + ' ' - NazwiskoDoEmaila += ('.' + x) - Inicjaly += x[0] - Nazwisko = Nazwisko[:-1] - Login = osoba[2] - Adres = MDplr(Imie).lower() + MDplr(NazwiskoDoEmaila).lower() + '@losobolew.pl' - Email = Adres + ',' + Login + ':' + MDplr(Inicjaly) + ',500' - Office = Adres + ',' + Imie + ',' + Nazwisko + ',' + Imie + ' ' + Nazwisko + ',nauczyciel,,,,,,,,,,Rzeczpospolita Polska' - KontenerEmail.append(Email) - KontenerOffice.append(Office) - sciezkaEmail = sciezkaExport + '/email.csv' - sciezkaOffice = sciezkaExport + '/office.csv' - with cd.open(sciezkaEmail, 'w', Kodowanie) as plikEmail: - for x in KontenerEmail: - plikEmail.writelines(x + '\n') - plikEmail.close() - with cd.open(sciezkaOffice, 'w', Kodowanie) as plikOffice: - for x in KontenerOffice: - plikOffice.writelines(x + '\n') - plikOffice.close() - TKmsb.showinfo('Zakończono', 'Operacja zakończona pomyślnie') - ss.exit(0) - else: - ss.exit(0) - - -#_______________________________________________________________________________________________# - - - - - - - - - - - -## Inicjacja okna ############################################################################### - -# Zmienne globalne środowiska graficznego -SzerokoscOpisu = 17 -SzerokoscPola = 91 -TytulProgramu = 'GeneratorCSV' -Autorzy = 'Mateusz Skoczek' -Wersja = '3.0.1' -Lata = '2019' - -# Tworzenie okna -OknoGlowne = tk.Tk() -OknoGlowne.title(TytulProgramu) -OknoGlowne.resizable(width = False, height = False) - -# Nazwa programu -Tytul = tk.Label(OknoGlowne, text = TytulProgramu, font = ('Segoe UI Semilight', 20), borderwidth = 7, justify = 'center', bg = 'Gainsboro', width = 47) -Tytul.grid(row = 0) - - -# Tworzenie frame dla ścieżek plików do importu -Ramka1 = tk.LabelFrame(OknoGlowne, text = 'Pliki do importu zawierające dane') -Ramka1.grid(row = 1) - -# Ścieżka pliku do importu 1 -wiersz1 = 0 -text1 = tk.StringVar() -OpisPola1 = tk.Label(Ramka1, text = 'Plik z danymi (1)', justify = 'left', width = SzerokoscOpisu) -OpisPola1.grid(row = wiersz1, column = 0) -Pole1 = tk.Entry(Ramka1, textvariable = text1, width = SzerokoscPola) -Pole1.grid(row = wiersz1, column = 1) -def Browse1_Dialog(): - Browse1.filename = TKfld.askopenfilename(initialdir="/", title="Wybierz plik", filetypes=(("Pliki txt", "*.txt"), ("Wszystkie pliki", "*.*"))) - Pole1.delete(0, 'end') - Pole1.insert(0, Browse1.filename) -Browse1 = tk.Button(Ramka1, text = '...', command = Browse1_Dialog, background = 'silver', relief = 'flat') -Browse1.grid(row = wiersz1, column = 2, padx = 5, pady = 3) - -# Ścieżka pliku do importu 2 -wiersz2 = 1 -text2 = tk.StringVar() -OpisPola2 = tk.Label(Ramka1, text = 'Plik z danymi (2)', justify = 'left', width = SzerokoscOpisu) -OpisPola2.grid(row = wiersz2, column = 0) -Pole2 = tk.Entry(Ramka1, textvariable = text2, width = SzerokoscPola) -Pole2.grid(row = wiersz2, column = 1) -def Browse2_Dialog(): - Browse2.filename = TKfld.askopenfilename(initialdir="/", title="Wybierz plik", filetypes=(("Pliki txt", "*.txt"), ("Wszystkie pliki", "*.*"))) - Pole2.delete(0, 'end') - Pole2.insert(0, Browse2.filename) -Browse2 = tk.Button(Ramka1, text = '...', command = Browse2_Dialog, background = 'silver', relief = 'flat') -Browse2.grid(row = wiersz2, column = 2, padx = 5, pady = 3) - -# Ścieżka pliku do importu 3 -wiersz3 = 2 -text3 = tk.StringVar() -OpisPola3 = tk.Label(Ramka1, text = 'Plik z danymi (3)', justify = 'left', width = SzerokoscOpisu) -OpisPola3.grid(row = wiersz3, column = 0) -Pole3 = tk.Entry(Ramka1, textvariable = text3, width = SzerokoscPola) -Pole3.grid(row = wiersz3, column = 1) -def Browse3_Dialog(): - Browse3.filename = TKfld.askopenfilename(initialdir="/", title="Wybierz plik", filetypes=(("Pliki txt", "*.txt"), ("Wszystkie pliki", "*.*"))) - Pole3.delete(0, 'end') - Pole3.insert(0, Browse3.filename) -Browse3 = tk.Button(Ramka1, text = '...', command = Browse3_Dialog, background = 'silver', relief = 'flat') -Browse3.grid(row = wiersz3, column = 2, padx = 5, pady = 3) - -# Ścieżka pliku do importu 4 -wiersz4 = 3 -text4 = tk.StringVar() -OpisPola4 = tk.Label(Ramka1, text = 'Plik z danymi (4)', justify = 'left', width = SzerokoscOpisu) -OpisPola4.grid(row = wiersz4, column = 0) -Pole4 = tk.Entry(Ramka1, textvariable = text4, width = SzerokoscPola) -Pole4.grid(row = wiersz4, column = 1) -def Browse4_Dialog(): - Browse4.filename = TKfld.askopenfilename(initialdir="/", title="Wybierz plik", filetypes=(("Pliki txt", "*.txt"), ("Wszystkie pliki", "*.*"))) - Pole4.delete(0, 'end') - Pole4.insert(0, Browse4.filename) -Browse4 = tk.Button(Ramka1, text = '...', command = Browse4_Dialog, background = 'silver', relief = 'flat') -Browse4.grid(row = wiersz4, column = 2, padx = 5, pady = 3) - - -# Tworzenie frame dla plików export -Ramka2 = tk.LabelFrame(OknoGlowne, text = 'Ustawienia eksportu') -Ramka2.grid(row = 2) - -# Ścieżka folderu do zapisu wygenerowanych plików -text4 = tk.StringVar() -OpisPolaExport = tk.Label(Ramka2, text = 'Lokalizacja', justify = 'left', width = SzerokoscOpisu) -OpisPolaExport.grid(row = 0, column = 0) -PoleExport = tk.Entry(Ramka2, textvariable = text4, width = SzerokoscPola) -PoleExport.grid(row = 0, column = 1) -def BrowseExport_Dialog(): - BrowseExport.filename = TKfld.askdirectory() - PoleExport.delete(0, 'end') - PoleExport.insert(0, BrowseExport.filename) -BrowseExport = tk.Button(Ramka2, text = '...', command = BrowseExport_Dialog, background = 'silver', relief = 'flat') -BrowseExport.grid(row = 0, column = 2, padx = 5, pady = 3) - - -# Przycisk START -Przycisk = tk.Button(OknoGlowne, text = 'START', justify = 'center', width = 50, command = Main, relief = 'flat', background = 'silver') -Przycisk.grid(row = 3, pady = 15) - - -# Pasek dolny -PasekDolny = tk.LabelFrame(OknoGlowne, bd = 0, background = 'Gainsboro') -PasekDolny.grid(row = 4) -info = TytulProgramu + ' ' + Wersja + ' | © ' + Autorzy + ' '+ Lata + ' dla ZSP Sobolew' -InfoLabel = tk.Label(PasekDolny, text = info, justify = 'left', width = 93, anchor = 'w', background = 'Gainsboro') -InfoLabel.grid(row= 0, column = 0) -def InfoOpen(): - try: - x = open('instrukcja.txt') - except FileNotFoundError: - MDerr(E001x03) - else: - os.system("notepad instrukcja.txt") -Przycisk = tk.Button(PasekDolny, text = 'Instrukcja', justify = 'center', foreground = 'blue', relief = 'flat', command = InfoOpen, background = 'Gainsboro') -Przycisk.grid(row = 0, column = 1) - - -tk.mainloop() - -#_______________________________________________________________________________________________# diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..49f2657 Binary files /dev/null and b/icon.ico differ diff --git a/instrukcja.txt b/instrukcja.txt deleted file mode 100644 index ae55ab1..0000000 --- a/instrukcja.txt +++ /dev/null @@ -1,107 +0,0 @@ -Program tworzy pliki .csv potrzebne do stworzenia kont uczniów i nauczycieli na szkolnej poczcie i Office 365. -Obecnie program obsługuje tylko 4 pliki z danymi. Program tworzy pliki 'email.csv' do eksportu dla szkolnej poczty oraz 'office.csv' do eksportu dla kont office. -Obecna wersja: 3.0 -Autorzy: Mateusz Skoczek -dla ZSP Sobolew -luty 2019 - grudzień 2019 - - - - - -Format domyślny plików z danymi: - -Legenda: -X - Dane nieznaczące -Q - Pusta linia - -Uczniowie: -# , -# - -# Przykład: -# 1a BS Nowak, Adam 1234567u -# - -Nauczyciele: -# , -# - -# Przykład: -# Nowak, Adam 1234567 -# - -Format można edytować w pliku 'format.py'. Więcej info na dole. - - - - - -Format domyślny pliku 'office.csv': -Uczniowie: -# ,,,,uczeń,,,,,,,,,,Rzeczpospolita Polska - -# Przykład: -# adam.nowak@losobolew.pl,Adam,Nowak,Adam Nowak,uczeń,1a BS,,,,,,,,,Rzeczpospolita Polska - -Nauczyciele: -# ,,,,nauczyciel,,,,,,,,,,Rzeczpospolita Polska - -# Przykład: -# adam.nowak@losobolew.pl,Adam,Nowak,Adam Nowak,nauczyciel,,,,,,,,,,Rzeczpospolita Polska - - - - - -Format domyślny pliku 'email.csv': -Uczniowie: -# ,,500 -| -v -# .@losobolew.pl,:,500 - -# Przykład: -# adam.nowak2021bs@losobolew.pl,1234567u,500 - -Nauczyciele: -# ,,500 -| -v -# .@losobolew.pl,:,500 - -# Przykład: -# adam.nowak@losobolew.pl,1234567,500 - - - - - -Dalsze pojęcia: -błąd programu - błąd programu objawiający się komunikatem -krytyczny błąd programu - nieoczekiwany błąd programu nieobjawiający się komunikatem - - - - - -Pliki: - -changelog.txt -Informacje o zmianach w poszczególnych wersjach programu. - -generator.py -Główny plik programu. Jakiekolwiek naruszenie jego zawartości może spowodować krytyczny błąd programu. - -instrukcja.txt -Plik z instrukcją użytkowania. Usunięcie tego pliku spowoduje błąd programu. - -config.cfg -Plik zawiera ukryte ustawienia programu. Można go edytować, ale należy robić to z rozwagą. Usunięcie go spowoduje błąd programu. -1: Obsługiwane kodowania: 'utf-8', 'cp1252', 'iso-8859-1' - -moduly.py -Plik zawierający moduły niezbędne do działania programu. Usunięcie pliku spowoduje błąd programu. Naruszenie jego zawartości może spowodować krytyczny błąd programu. - -format.py -Plik ten jest skryptem przetwarzającym dane. W razie zmiany formatu pliku z danymi należy go edytować, lecz nie powinna tego robić osoba początkująca, gdyż błędny kod może spowodować krytyczny błąd programu lub niepożądane wyniki. Usunięcie pliku spowoduje błąd programu. \ No newline at end of file diff --git a/moduly.py b/moduly.py deleted file mode 100644 index d98987d..0000000 --- a/moduly.py +++ /dev/null @@ -1,51 +0,0 @@ -import sys as ss -import time as tm -from tkinter import messagebox as TKmsb - -def ErrorDialog(KodBledu): - Message = 'Wystąpił błąd!\n' + KodBledu - TKmsb.showerror('Błąd', Message) - ss.exit(0) - -def FileCheck(Plik, KodBledu): - try: - x = open(Plik) - except FileNotFoundError: - ErrorDialog(KodBledu) - -def PolishLetterRemover(text): - text1 = text.replace('ę', 'e') - text2 = text1.replace('ó', 'o') - text3 = text2.replace('ą', 'a') - text4 = text3.replace('ś', 's') - text5 = text4.replace('ł', 'l') - text6 = text5.replace('ż', 'z') - text7 = text6.replace('ź', 'z') - text8 = text7.replace('ć', 'c') - text9 = text8.replace('ń', 'n') - text10 = text9.replace('Ę', 'E') - text11 = text10.replace('Ó', 'O') - text12 = text11.replace('Ą', 'A') - text13 = text12.replace('Ś', 'S') - text14 = text13.replace('Ł', 'L') - text15 = text14.replace('Ż', 'Z') - text16 = text15.replace('Ź', 'Z') - text17 = text16.replace('Ć', 'C') - text = text17.replace('Ń', 'N') - return text - -def ClassTagCreator(Klasa): - czas = tm.localtime() - miesiac = czas[1] - if miesiac >= 9: - rokpodst = czas[0] - else: - rokpodst = czas[0] - 1 - nrklasy = int(Klasa[0]) - literaklasy = Klasa[1] - szkola = Klasa.split(' ')[1] - if szkola == 'BS': - znacznik = str((4 - nrklasy) + rokpodst) + szkola - else: - znacznik = str((5 - nrklasy) + rokpodst) + literaklasy - return znacznik \ No newline at end of file