Aktualizacja wcześniejszego mojego projektu i dodanie zmian polegających na uwzględnieniu wszystkich rodzajów paliw zatankowanych w danym okresie.
Program będzie wyświetlał na początku ilości zatankowanego paliwa z podziałem na jego rodzaje rodzaje np.
*** Zestawienie paliwa za okres od 1 do 31.10.2023 ***
1 GAZ LPG. 173.09 ltr
2 OLEJ NAPĘDOWY CN27102011. 6318.06 ltr
Wpisz numer opcji lub q aby wyjść:
Po wpisaniu wybranej opcji pojawia się zestawienie wybranego paliwa z podziałem na samochody np.
*** Zestawienie dla paliwa: OLEJ NAPĘDOWY CN27102011. ***
Num. rej. Ilość
1 AAA00123 722.00
2 AAA04225 192.02
3 AAA2X22 59.00
4 AAA52YT 578.03
5 AAA5P19 71.00
6 AAA5W41 841.00
7 AAA85K3 1209.01
8 AAA85YY 879.00
9 AAAFX95 826.00
10 AAAPM20 56.00
11 AAARG00 187.00
12 AAARU44 698.00
Zakupione paliwo: 6318.06 ltr
Wpisz numer rej. lub p aby powrócić do głównego menu:
Po wybraniu dowolnego fragmentu numeru rejestracyjnego, bez rozróżnienia wielkości liter pokazuje się kolejny ekran, np.
*** Tankowania dla pojazdu: AAARG00 ***
Data Ilość Netto Brutto
02-11-2023 43.00 ltr 5.12 6.30
06-11-2023 42.00 ltr 5.24 6.44
07-11-2023 20.00 ltr 5.29 6.51
10-11-2023 27.00 ltr 5.20 6.40
14-11-2023 27.00 ltr 5.17 6.36
21-11-2023 28.00 ltr 5.09 6.26
Suma tankowań dla pojazdu: 187.00 ltr
Wpisz p aby powrócić do wcześniejszego menu:
Pobrany plik programu Excel zawiera między innymi następujące kolumny: „Dane kontrahenta”, „Numer WZ”, „Data”, „Godzina”, „Licznik”, „Numer rejestracyjny”, „Numer karty”, „Nazwa towaru”, „Odbiorca” itd.
Każdy wiersz zawiera dane o konkretnym tankowaniu.
Korzystać będę tylko z danych z paru kolumn tzn. „Data”, „Numer rejestracyjny”, „Nazwa towaru” – zawierająca rodzaj pobranego paliwa, „Ilość” – ilość zatankowanego paliwa, oraz „Cena brutto” i „Cena netto”.
W tym celu tworzę klasę Reports(), która będzie zawierać wczytane raporty tankowań:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
@ author: Sławomir Kwiatkowski
@ date: 2023.11.18
'''
class Reports():
pass
if __name__ == '__main__':
Reports()
W metodzie __init__() dokonuję inicjalizacji dla modułu colorama, następnie metoda: load_last_report() wczytuje ostatni plik Excela zawierający najnowsze raporty tankowań, a następnie uruchomiona jest metoda main() klasy tzn.
def __init__(self):
colorama.init(autoreset=True)
last_report = self.load_last_report()
self.main(last_report)
Metoda load_last_report() pobiera najnowszy plik excela z podkatalogu 'Dane’ i zwraca ramkę Pandas tzn.
def load_last_report(self):
current_dir = os.path.dirname(os.path.abspath(__file__))
data_dir = os.path.join(current_dir, 'Dane')
reports = glob.glob(os.path.join(data_dir, '*.xlsx'))
last_report = max(reports, key=os.path.getctime)
path_to_last_report = os.path.join(data_dir, last_report)
return pd.read_excel(path_to_last_report)
Należy uzupełnić wymagane importy tzn.
import os
import glob
import colorama
import pandas as pd
Wydzieliłem prywatną metodę do „czyszczenia” konsoli tzn.
def _clear_screen(self):
os.system('cls' if os.name == 'nt' else 'clear')
W metodzie main() klasy Reports wyświetlam krótki nagłówek copyright, a następnie wypisuję zsumowane paliwo, w zależności od rodzaju paliwa tzn.
def main(self, report):
self._clear_screen()
copyright = {'author:': 'Sławomir Kwiatkowski', 'Date:': '18-11-2023' }
for item in copyright:
print(f'{colorama.Fore.RED} {item} {copyright[item]}'.rjust(120))
self.main_header(report['Data'].min(), report['Data'].max())
fuel_grp = report.groupby('Nazwa towaru')
fuel_grp_sums = fuel_grp['Ilość'].sum()
for i, sum in enumerate(fuel_grp_sums.items(), start=1):
print(i, sum[0], f'{sum[1]:.2f}', 'ltr', '\n')
W metodzie main() następnie wczytuję opcję wybraną przez użytkownika tzn. numer wybranego paliwa, dla którego wyświetlić szczegółowe dane lub „q” aby wyjść z programu tzn.
while True:
choice = input('Wpisz numer opcji lub q aby wyjść: ')
if choice == 'q':
self._clear_screen()
raise SystemExit
if choice.isnumeric() and choice!='0':
try:
fuel= fuel_grp_sums.index[int(choice)-1]
self.fuel_description(report, fuel)
break
except:
pass
self.main(report)
Metoda main() zawiera też wywołanie nagłówka tzn. main_header(), który wyświetla napis o zakresie dat, z którego pochodzą dane tankowań tzn. data pierwszego tankowania i data ostatniego tankowania:
def main_header(self, start_date, end_date):
print(colorama.Fore.YELLOW +'*** Zestawienie paliwa za okres od {} do {}.{}.{} ***\n'
.format(start_date.day,
end_date.day,
end_date.month,
end_date.year
))
Jeśli użytkownik wybierze numer paliwa, dla którego chce wyświetlić szczegółowy opis, to wyświetla się kolejny ekran, zawierające dane o sumach tankowań wybranego paliwa dla poszczególnych pojazdów tzn.
def fuel_description(self, report, fuel):
self._clear_screen()
print(colorama.Fore.YELLOW + f'*** Zestawienie dla paliwa: {fuel} ***\n')
filt = report['Nazwa towaru'] == fuel
cars_group = report[filt].groupby('Numer rejestracyjny')
cars_group_sums = cars_group['Ilość'].sum().reset_index()
cars_group_sums.index +=1
cars_group_sums.rename(columns={'Numer rejestracyjny': 'Num. rej.'}, inplace=True)
print(cars_group_sums, '\n')
print('Zakupione paliwo: ', cars_group_sums.sum()[1], 'ltr \n')
Metoda ta zawiera również możliwość wybrania fragmentu numeru rejestracyjnego, aby wyświetlić szczegóły tankowań danego paliwa dla wybranego auta lub przejście do wcześniejszego ekranu po wciśnięciu „p”.
while True:
choice = input('Wpisz numer rej. lub p aby powrócić do głównego menu: ')
if choice == 'p':
break
for key, value in cars_group['Ilość']:
if choice.upper() in key:
self.car_description(key, value, report, fuel)
break
self.fuel_description(report, fuel)
self.main()
Po wybraniu dowolnego fragmentu numeru rejestracyjnego, metoda car_description() wyświetla szczegółowe dane dla danego auta tzn. datę tankowania, ilość zatankowanego paliwa oraz cenę netto i brutto tzn.
def car_description(self, key, value, report, fuel):
self._clear_screen()
print(colorama.Fore.YELLOW + f'*** Tankowania dla pojazdu: {key} ***\n')
header = ['Data', 'Ilość', 'Netto', 'Brutto']
for item in header:
print(f'{item:<13}', end="")
print()
total = 0
line = 1
for i, v in zip(value.index, value.values):
output = f'{report.loc[i, "Data"]:%d-%m-%Y}' \
f'{v:>8.2f} ltr' \
f'{report.loc[i, "Cena netto"]:>8.2f}' \
f'{report.loc[i, "Cena brutto"]:>15.2f}'
total += v
print(colorama.Fore.BLACK + colorama.Back.WHITE + output
) if line % 2 else print(output)
line += 1
print(f'\n Suma tankowań dla pojazdu: {total:.2f} ltr \n')
while True:
choice = input('Wpisz p aby powrócić do wcześniejszego menu: ')
if choice == 'p':
break
self.car_description(key, value, report, fuel)
self.fuel_description(report, fuel)