This commit is contained in:
Mateusz Gruszczyński
2026-03-13 11:03:13 +01:00
commit 35571df778
132 changed files with 11197 additions and 0 deletions

0
app/forms/__init__.py Normal file
View File

120
app/forms/admin.py Normal file
View File

@@ -0,0 +1,120 @@
from flask_wtf import FlaskForm
from wtforms import (
BooleanField,
HiddenField,
IntegerField,
PasswordField,
SelectField,
StringField,
SubmitField,
TextAreaField,
)
from wtforms.validators import DataRequired, Email, NumberRange, Optional
class AdminUserForm(FlaskForm):
email = StringField('E-mail', validators=[DataRequired(), Email()])
name = StringField('Imię i nazwisko', validators=[DataRequired()])
role = SelectField('Rola globalna', choices=[('admin', 'Admin'), ('operator', 'Operator'), ('readonly', 'Readonly')], validators=[DataRequired()])
password = PasswordField('Hasło', validators=[Optional()])
company_id = SelectField('Dodaj dostęp do firmy', coerce=int, validators=[Optional()])
access_level = SelectField('Poziom dostępu do firmy', choices=[('full', 'Pełny'), ('readonly', 'Tylko odczyt')], validators=[Optional()])
force_password_change = BooleanField('Wymuś zmianę hasła')
is_blocked = BooleanField('Zablokowany')
submit = SubmitField('Zapisz użytkownika')
class AccessForm(FlaskForm):
company_id = SelectField('Firma', coerce=int, validators=[DataRequired()])
access_level = SelectField('Poziom dostępu', choices=[('full', 'Pełny'), ('readonly', 'Tylko odczyt')], validators=[DataRequired()])
submit = SubmitField('Zapisz dostęp')
class PasswordResetForm(FlaskForm):
password = PasswordField('Nowe hasło', validators=[DataRequired()])
force_password_change = BooleanField('Wymuś zmianę po logowaniu')
submit = SubmitField('Resetuj hasło')
class AdminCompanyForm(FlaskForm):
name = StringField('Nazwa firmy', validators=[Optional()])
tax_id = StringField('NIP', validators=[Optional()])
regon = StringField('REGON', validators=[Optional()])
address = StringField('Adres', validators=[Optional()])
bank_account = StringField('Numer rachunku bankowego', validators=[Optional()])
is_active = BooleanField('Aktywna')
sync_enabled = BooleanField('Automatyczne pobieranie')
sync_interval_minutes = StringField('Interwał sync (min)', validators=[Optional()])
note = TextAreaField('Opis / notatka', validators=[Optional()])
mock_mode = BooleanField('Włącz tryb mock dla tej firmy')
submit = SubmitField('Zapisz firmę')
fetch_submit = SubmitField('Pobierz dane z CEIDG')
def validate(self, extra_validators=None):
if not super().validate(extra_validators=extra_validators):
return False
is_fetch = bool(self.fetch_submit.data and not self.submit.data)
if is_fetch:
if not (self.tax_id.data or '').strip():
self.tax_id.errors.append('Podaj NIP, aby pobrać dane z CEIDG.')
return False
return True
if not (self.name.data or '').strip():
self.name.errors.append('To pole jest wymagane.')
return False
return True
class CeidgConfigForm(FlaskForm):
environment = HiddenField(default='production')
api_key = PasswordField('API KEY CEIDG', validators=[Optional()])
submit = SubmitField('Zapisz konfigurację CEIDG')
class LogCleanupForm(FlaskForm):
days = IntegerField('Usuń logi starsze niż (dni)', validators=[DataRequired(), NumberRange(min=1, max=3650)])
submit = SubmitField('Wyczyść logi')
class DatabaseBackupForm(FlaskForm):
submit = SubmitField('Wykonaj kopię bazy')
class GlobalMailSettingsForm(FlaskForm):
server = StringField('SMTP host', validators=[Optional()])
port = StringField('SMTP port', validators=[Optional()])
username = StringField('SMTP login', validators=[Optional()])
password = PasswordField('SMTP hasło', validators=[Optional()])
sender = StringField('Nadawca', validators=[Optional(), Email()])
security_mode = SelectField('Zabezpieczenie połączenia', choices=[('tls', 'TLS / STARTTLS'), ('ssl', 'SSL'), ('none', 'Brak')], validators=[Optional()], default='tls')
submit = SubmitField('Zapisz SMTP globalne')
class GlobalNotificationSettingsForm(FlaskForm):
pushover_user_key = StringField('Pushover user key', validators=[Optional()])
pushover_api_token = PasswordField('Pushover API token', validators=[Optional()])
min_amount = StringField('Powiadom od kwoty', validators=[Optional()])
quiet_hours = StringField('Cichy harmonogram', validators=[Optional()])
enabled = BooleanField('Włącz globalne powiadomienia')
submit = SubmitField('Zapisz Pushover globalnie')
class GlobalNfzSettingsForm(FlaskForm):
enabled = BooleanField('Włącz moduł NFZ globalnie')
submit = SubmitField('Zapisz NFZ globalnie')
class GlobalKsefDefaultsForm(FlaskForm):
environment = SelectField('Domyślne środowisko KSeF', choices=[('prod', 'PROD'), ('test', 'TEST')], validators=[Optional()])
auth_mode = SelectField('Domyślny tryb autoryzacji', choices=[('token', 'Token'), ('certificate', 'Certyfikat')])
client_id = StringField('Domyślny Client ID', validators=[Optional()])
submit = SubmitField('Zapisz domyślne parametry KSeF')
class SharedCompanyKsefForm(FlaskForm):
environment = SelectField('Środowisko współdzielonego profilu', choices=[('prod', 'PROD'), ('test', 'TEST')], validators=[Optional()])
auth_mode = SelectField('Tryb autoryzacji', choices=[('token', 'Token'), ('certificate', 'Certyfikat')])
token = PasswordField('Token', validators=[Optional()])
client_id = StringField('Client ID', validators=[Optional()])
certificate_name = StringField('Nazwa certyfikatu', validators=[Optional()])
certificate_data = PasswordField('Treść certyfikatu / base64', validators=[Optional()])
submit = SubmitField('Zapisz współdzielony profil KSeF')

7
app/forms/auth.py Normal file
View File

@@ -0,0 +1,7 @@
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired, Email, Length
class LoginForm(FlaskForm):
email = StringField('E-mail', validators=[DataRequired(), Email()])
password = PasswordField('Hasło', validators=[DataRequired(), Length(min=6)])
submit = SubmitField('Zaloguj')

26
app/forms/invoices.py Normal file
View File

@@ -0,0 +1,26 @@
from flask_wtf import FlaskForm
from wtforms import BooleanField, SelectField, StringField, SubmitField, TextAreaField
from wtforms.validators import Optional
class InvoiceFilterForm(FlaskForm):
month = SelectField('Miesiąc', choices=[('', 'Wszystkie')] + [(str(i), str(i)) for i in range(1, 13)], validators=[Optional()])
year = StringField('Rok', validators=[Optional()])
contractor = StringField('Kontrahent', validators=[Optional()])
nip = StringField('NIP', validators=[Optional()])
invoice_type = SelectField('Typ', choices=[('', 'Wszystkie'), ('purchase', 'Zakupowa'), ('sale', 'Sprzedażowa'), ('correction', 'Korekta')], validators=[Optional()])
status = SelectField('Status', choices=[('', 'Wszystkie'), ('new', 'Nowa'), ('read', 'Przeczytana'), ('accounted', 'Zaksięgowana'), ('sent', 'Wysłana'), ('archived', 'Archiwalna'), ('needs_attention', 'Wymaga uwagi'), ('error', 'Błąd')], validators=[Optional()])
quick_filter = SelectField('Szybki filtr', choices=[('', 'Brak'), ('this_month', 'Ten miesiąc'), ('previous_month', 'Poprzedni miesiąc'), ('unread', 'Nieprzeczytane'), ('error', 'Z błędem'), ('to_send', 'Do wysyłki')], validators=[Optional()])
min_amount = StringField('Min brutto', validators=[Optional()])
max_amount = StringField('Max brutto', validators=[Optional()])
search = StringField('Szukaj', validators=[Optional()])
submit = SubmitField('Filtruj')
class InvoiceMetaForm(FlaskForm):
status = SelectField('Status', choices=[('new', 'Nowa'), ('read', 'Przeczytana'), ('accounted', 'Zaksięgowana'), ('sent', 'Wysłana'), ('archived', 'Archiwalna'), ('needs_attention', 'Wymaga uwagi'), ('error', 'Błąd')])
tags = StringField('Tagi', validators=[Optional()])
internal_note = TextAreaField('Notatka', validators=[Optional()])
queue_accounting = BooleanField('Do księgowości')
pinned = BooleanField('Przypnij')
submit = SubmitField('Zapisz')

15
app/forms/issued.py Normal file
View File

@@ -0,0 +1,15 @@
from flask_wtf import FlaskForm
from wtforms import BooleanField, DecimalField, SelectField, StringField, SubmitField
from wtforms.validators import DataRequired, Optional
class IssuedInvoiceForm(FlaskForm):
customer_id = SelectField('Klient', coerce=int, validators=[DataRequired()])
numbering_template = SelectField('Format numeracji', choices=[('monthly', 'Miesięczny'), ('yearly', 'Roczny'), ('custom', 'Własny')], validators=[DataRequired()])
invoice_number = StringField('Numer faktury', validators=[Optional()])
product_id = SelectField('Towar / usługa', coerce=int, validators=[DataRequired()])
quantity = DecimalField('Ilość', validators=[DataRequired()], default=1)
unit_net = DecimalField('Cena netto', validators=[Optional()])
split_payment = BooleanField('Split payment')
save_submit = SubmitField('Generuj fakturę')
submit = SubmitField('Wyślij do KSeF')

41
app/forms/nfz.py Normal file
View File

@@ -0,0 +1,41 @@
from flask_wtf import FlaskForm
from wtforms import DateField, DecimalField, SelectField, StringField, SubmitField
from wtforms.validators import DataRequired, Optional
NFZ_BRANCH_CHOICES = [
('1070001057-00018', 'Dolnośląski OW NFZ'),
('1070001057-00021', 'Kujawsko-Pomorski OW NFZ'),
('1070001057-00034', 'Lubelski OW NFZ'),
('1070001057-00047', 'Lubuski OW NFZ'),
('1070001057-00050', 'Łódzki OW NFZ'),
('1070001057-00063', 'Małopolski OW NFZ'),
('1070001057-00076', 'Mazowiecki OW NFZ'),
('1070001057-00089', 'Opolski OW NFZ'),
('1070001057-00092', 'Podkarpacki OW NFZ'),
('1070001057-00106', 'Podlaski OW NFZ'),
('1070001057-00119', 'Pomorski OW NFZ'),
('1070001057-00122', 'Śląski OW NFZ'),
('1070001057-00135', 'Świętokrzyski OW NFZ'),
('1070001057-00148', 'Warmińsko-Mazurski OW NFZ'),
('1070001057-00151', 'Wielkopolski OW NFZ'),
('1070001057-00164', 'Zachodniopomorski OW NFZ'),
('1070001057-00177', 'Centrala NFZ'),
]
class NfzInvoiceForm(FlaskForm):
customer_id = SelectField('Odbiorca techniczny', coerce=int, validators=[DataRequired()])
product_id = SelectField('Towar / usługa', coerce=int, validators=[DataRequired()])
invoice_number = StringField('Numer faktury', validators=[Optional()])
nfz_branch_id = SelectField('Oddział NFZ (IDWew)', choices=NFZ_BRANCH_CHOICES, validators=[DataRequired()])
settlement_from = DateField('Okres rozliczeniowy od', validators=[DataRequired()], format='%Y-%m-%d')
settlement_to = DateField('Okres rozliczeniowy do', validators=[DataRequired()], format='%Y-%m-%d')
template_identifier = StringField('Identyfikator szablonu', validators=[Optional()])
provider_identifier = StringField('Identyfikator świadczeniodawcy', validators=[DataRequired()])
service_code = StringField('Kod zakresu / wyróżnik / kod świadczenia', validators=[DataRequired()])
contract_number = StringField('Numer umowy / aneksu', validators=[DataRequired()])
quantity = DecimalField('Ilość', validators=[DataRequired()], default=1)
unit_net = DecimalField('Cena netto', validators=[DataRequired()])
save_submit = SubmitField('Zapisz roboczo')
submit = SubmitField('Zapisz i wyślij do KSeF')

73
app/forms/settings.py Normal file
View File

@@ -0,0 +1,73 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField
from wtforms import BooleanField, IntegerField, PasswordField, RadioField, SelectField, StringField, SubmitField
from wtforms.validators import DataRequired, Email, Optional
class KSeFSettingsForm(FlaskForm):
source_mode = RadioField('Źródło ustawień', choices=[('user', 'Moje ustawienia'), ('global', 'Profil współdzielony firmy')], default='user')
environment = SelectField(
'Środowisko KSeF',
choices=[('prod', 'PROD'), ('test', 'TEST')],
validators=[Optional()],
)
auth_mode = SelectField('Tryb autoryzacji', choices=[('token', 'Token'), ('certificate', 'Certyfikat')])
token = PasswordField('Token', validators=[Optional()])
client_id = StringField('Client ID', validators=[Optional()])
certificate_file = FileField('Certyfikat', validators=[Optional(), FileAllowed(['pem', 'crt', 'cer', 'p12', 'pfx'], 'Dozwolone: pem, crt, cer, p12, pfx')])
submit = SubmitField('Zapisz KSeF')
class MailSettingsForm(FlaskForm):
source_mode = RadioField('Źródło SMTP', choices=[('global', 'Użyj ustawień globalnych'), ('user', 'Podaj indywidualne ustawienia')], default='global')
server = StringField('SMTP host', validators=[Optional()])
port = StringField('SMTP port', validators=[Optional()])
username = StringField('SMTP login', validators=[Optional()])
password = PasswordField('SMTP hasło', validators=[Optional()])
sender = StringField('Nadawca', validators=[Optional(), Email()])
security_mode = SelectField('Zabezpieczenie połączenia', choices=[('tls', 'TLS / STARTTLS'), ('ssl', 'SSL'), ('none', 'Brak')], validators=[Optional()], default='tls')
test_recipient = StringField('Adres testowy', validators=[Optional(), Email()])
submit = SubmitField('Zapisz SMTP')
test_submit = SubmitField('Wyślij test maila')
class NotificationSettingsForm(FlaskForm):
source_mode = RadioField('Źródło Pushover', choices=[('global', 'Użyj ustawień globalnych'), ('user', 'Podaj indywidualne ustawienia')], default='global')
pushover_user_key = StringField('Pushover user key', validators=[Optional()])
pushover_api_token = PasswordField('Pushover API token', validators=[Optional()])
min_amount = StringField('Powiadom od kwoty', validators=[Optional()])
quiet_hours = StringField('Cichy harmonogram, np. 22:00-07:00', validators=[Optional()])
enabled = BooleanField('Włącz powiadomienia')
submit = SubmitField('Zapisz powiadomienia')
test_submit = SubmitField('Wyślij test Pushover')
class AppearanceSettingsForm(FlaskForm):
theme_preference = SelectField('Motyw interfejsu', choices=[('light', 'Jasny'), ('dark', 'Ciemny')], validators=[DataRequired()])
submit = SubmitField('Zapisz wygląd')
class CompanyForm(FlaskForm):
name = StringField('Nazwa firmy', validators=[DataRequired()])
tax_id = StringField('NIP', validators=[Optional()])
sync_enabled = BooleanField('Włącz harmonogram pobierania')
sync_interval_minutes = IntegerField('Interwał sync (min)', validators=[Optional()])
bank_account = StringField('Numer rachunku bankowego', validators=[Optional()])
read_only_mode = BooleanField('Tryb tylko odczyt (R/O)')
submit = SubmitField('Zapisz firmę')
class UserForm(FlaskForm):
email = StringField('E-mail', validators=[DataRequired(), Email()])
name = StringField('Imię i nazwisko', validators=[DataRequired()])
password = PasswordField('Hasło', validators=[Optional()])
role = SelectField('Rola globalna', choices=[('admin', 'Admin'), ('operator', 'Operator'), ('readonly', 'Readonly')])
company_id = SelectField('Firma', coerce=int, validators=[Optional()])
access_level = SelectField('Dostęp do firmy', choices=[('full', 'Pełny'), ('readonly', 'Tylko odczyt')])
submit = SubmitField('Dodaj / przypisz użytkownika')
class NfzModuleSettingsForm(FlaskForm):
source_mode = RadioField('Źródło konfiguracji NFZ', choices=[('global', 'Użyj ustawień globalnych'), ('user', 'Ustaw indywidualnie')], default='global')
enabled = BooleanField('Włącz moduł faktur NFZ')
submit = SubmitField('Zapisz moduł NFZ')