351 lines
15 KiB
Python
351 lines
15 KiB
Python
import flet as ft
|
|
import requests
|
|
import json
|
|
from datetime import datetime
|
|
from helpers.document_status import DocumentsStatus
|
|
from helpers.emails import send_gmail
|
|
|
|
class Documents:
|
|
def __init__(self, page: ft.Page, home):
|
|
self.page = page
|
|
self.home = home # Keep reference to home for potential page updates
|
|
self.base_url = self.page.session.store.get('api_base_url')
|
|
self.token = self.page.session.store.get('token')
|
|
self.user = self.page.session.store.get('user')
|
|
self.user_id = self.user['id'] if self.user else None # Assuming user object has 'id'
|
|
|
|
self.all_requests = [] # To store all fetched requests
|
|
self.current_selected_request = None # To store the request currently displayed in details
|
|
|
|
# 1. "Solicita document personalizat" button and popup
|
|
self.request_text_field = ft.TextField(
|
|
label="Descrie solicitarea ta",
|
|
multiline=True,
|
|
min_lines=5,
|
|
max_lines=7,
|
|
expand=True
|
|
)
|
|
self.new_request_dialog = ft.AlertDialog(
|
|
modal=True,
|
|
title=ft.Text("Solicita document personalizat"),
|
|
content=ft.Column(
|
|
[
|
|
self.request_text_field,
|
|
ft.Text("Vei fi notificat cu privire la statusul solicitării și prețul stabilit de expert.")
|
|
],
|
|
tight=True,
|
|
height=200
|
|
),
|
|
actions=[
|
|
ft.FilledButton("Solicita", on_click=self._submit_new_request),
|
|
ft.FilledButton("Anuleaza", on_click=self._close_dialog, bgcolor=ft.Colors.GREY)
|
|
],
|
|
actions_alignment=ft.MainAxisAlignment.END
|
|
)
|
|
|
|
# 2. Search bar
|
|
self.search_bar = ft.TextField(
|
|
label="Cauta in solicitarile mele",
|
|
on_change=self._on_search_change, # Use on_change for live filtering
|
|
expand=True
|
|
)
|
|
|
|
# 3. List of requests
|
|
self.requests_list_view = ft.ListView(
|
|
expand=True,
|
|
spacing=10,
|
|
padding=10
|
|
)
|
|
self.no_requests_message = ft.Text(
|
|
"Nu aveti nici o solicitare activa. Pentru a crea o solicitare apasati butonul 'Solicita document personalizat'.",
|
|
text_align=ft.TextAlign.CENTER,
|
|
color=ft.Colors.GREY_600,
|
|
size=16
|
|
)
|
|
|
|
# 4. Details view for a selected request
|
|
self.request_details_text = ft.Text("", selectable=True)
|
|
self.request_status_text = ft.Text("")
|
|
self.request_price_text = ft.Text("")
|
|
self.pay_button = ft.FilledButton(
|
|
"Plateste",
|
|
on_click=self._on_pay_button_click,
|
|
disabled=True, # Will be enabled based on status
|
|
visible=False # Initially hidden
|
|
)
|
|
self.comment_text_field = ft.TextField(
|
|
label="Adauga un comentariu",
|
|
multiline=True,
|
|
min_lines=2,
|
|
max_lines=4,
|
|
expand=True
|
|
)
|
|
self.add_comment_button = ft.FilledButton(
|
|
"Adauga Comentariu",
|
|
on_click=self._add_comment_to_request,
|
|
disabled=True # Disabled until a request is selected
|
|
)
|
|
self.selected_request_details_column = ft.Column(
|
|
[
|
|
ft.Text("Detalii Solicitare", size=20, weight=ft.FontWeight.BOLD),
|
|
ft.Divider(),
|
|
ft.Text("Text Solicitare:", weight=ft.FontWeight.BOLD),
|
|
self.request_details_text,
|
|
ft.Text("Status:", weight=ft.FontWeight.BOLD),
|
|
self.request_status_text,
|
|
ft.Text("Pret:", weight=ft.FontWeight.BOLD),
|
|
self.request_price_text,
|
|
self.pay_button,
|
|
ft.Divider(),
|
|
ft.Text("Adauga Comentariu:", weight=ft.FontWeight.BOLD),
|
|
ft.Row([self.comment_text_field, self.add_comment_button]),
|
|
],
|
|
expand=True,
|
|
visible=False # Initially hidden
|
|
)
|
|
|
|
# Initial data load
|
|
self._load_requests()
|
|
|
|
def _load_requests(self):
|
|
"""Fetches requests from the API and updates the UI."""
|
|
if not self.user_id:
|
|
print("User ID not available. Cannot load requests.")
|
|
return
|
|
|
|
try:
|
|
response = requests.get(
|
|
f"{self.base_url}/documents/customs/requests/client",
|
|
headers={'Authorization': f'Bearer {self.token}'}
|
|
)
|
|
if response.status_code == 200:
|
|
self.all_requests = response.json()[::-1]
|
|
self._populate_requests_list(self.all_requests)
|
|
else:
|
|
print(f"Error fetching client requests: {response.status_code} - {response.text}")
|
|
self.requests_list_view.controls = [self.no_requests_message]
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Network error fetching client requests: {e}")
|
|
self.requests_list_view.controls = [self.no_requests_message]
|
|
self.page.update()
|
|
|
|
def _populate_requests_list(self, requests_to_display):
|
|
"""Populates the ListView with request items."""
|
|
if not requests_to_display:
|
|
self.requests_list_view.controls = [self.no_requests_message]
|
|
self.selected_request_details_column.visible = False
|
|
self.add_comment_button.disabled = True
|
|
self.comment_text_field.value = ""
|
|
self.comment_text_field.disabled = True
|
|
return
|
|
|
|
items = []
|
|
for req in requests_to_display:
|
|
items.append(
|
|
ft.Container(
|
|
content=ft.Column(
|
|
[
|
|
ft.Text(f"Solicitare ID: {req['id']}", weight=ft.FontWeight.BOLD),
|
|
ft.Text(f"Status: {DocumentsStatus.get_label(req['status'])}"),
|
|
ft.Text(f"Data: {req['created_at'].split('T')[0] if req['created_at'] else 'N/A'}"),
|
|
]
|
|
),
|
|
padding=10,
|
|
border_radius=5,
|
|
bgcolor=ft.Colors.BLUE_50 if req['status'] == DocumentsStatus.NEW else ft.Colors.GREY_100,
|
|
ink=True,
|
|
on_click=lambda e, request_data=req: self._display_request_details(request_data)
|
|
)
|
|
)
|
|
self.requests_list_view.controls = items
|
|
self.selected_request_details_column.visible = False # Hide details when list is repopulated
|
|
self.add_comment_button.disabled = True
|
|
self.comment_text_field.value = ""
|
|
self.comment_text_field.disabled = True
|
|
self.page.update()
|
|
|
|
def _display_request_details(self, request_summary):
|
|
"""Preia datele proaspete de la server pentru solicitarea selectată."""
|
|
try:
|
|
response = requests.get(
|
|
f"{self.base_url}/documents/customs/requests/{request_summary['id']}",
|
|
headers={'Authorization': f'Bearer {self.token}'}
|
|
)
|
|
if response.status_code == 200:
|
|
request_data = response.json()
|
|
self.current_selected_request = request_data
|
|
self.request_details_text.value = request_data.get('request_text', 'N/A')
|
|
self.request_status_text.value = DocumentsStatus.get_label(request_data.get('status', 'N/A'))
|
|
self.request_price_text.value = f"{request_data.get('price', 0.0):.2f} Lei" if request_data.get('price') else "N/A"
|
|
|
|
# Handle Pay button visibility and state
|
|
if request_data.get('status') == DocumentsStatus.WAITING_FOR_PAYMENT:
|
|
self.pay_button.visible = True
|
|
self.pay_button.disabled = False
|
|
else:
|
|
self.pay_button.visible = False
|
|
self.pay_button.disabled = True
|
|
|
|
# Enable comment section
|
|
self.add_comment_button.disabled = False
|
|
self.comment_text_field.disabled = False
|
|
self.comment_text_field.value = "" # Clear previous comment input
|
|
|
|
self.selected_request_details_column.visible = True
|
|
self.page.update()
|
|
except Exception as e:
|
|
print(f"Error fetching request details: {e}")
|
|
|
|
def _open_new_request_dialog(self, e):
|
|
self.request_text_field.value = "" # Clear previous input
|
|
self.page.show_dialog(self.new_request_dialog)
|
|
self.page.update()
|
|
|
|
def _submit_new_request(self, e):
|
|
request_text = self.request_text_field.value.strip()
|
|
if not request_text:
|
|
# Optionally show an error message to the user
|
|
print("Request text cannot be empty.")
|
|
return
|
|
|
|
try:
|
|
response = requests.post(
|
|
f"{self.base_url}/documents/customs/requests/add",
|
|
json={"request_text": request_text},
|
|
headers={'Authorization': f'Bearer {self.token}'}
|
|
)
|
|
if response.status_code == 201:
|
|
print("Request submitted successfully!")
|
|
req_id = response.json().get("id")
|
|
# Notificăm BA/Management despre o solicitare nouă
|
|
try:
|
|
subject = f"Solicitare nouă document personalizat: #{req_id}"
|
|
body = (
|
|
f"Clientul {self.user.get('email')} a creat o solicitare nouă.\n\n"
|
|
f"Descriere solicitare:\n{request_text}\n\n"
|
|
f"Vă rugăm să accesați panoul de administrare pentru preluare."
|
|
)
|
|
#send_gmail(to_email="office@juridicbloc.ro", subject=subject, body=body)
|
|
send_gmail(to_email="macamete.robert@gmail.com", subject=subject, body=body)
|
|
except Exception as mail_err:
|
|
print(f"Eroare notificare mail: {mail_err}")
|
|
|
|
self._close_dialog(e)
|
|
self._load_requests() # Reload the list to show the new request
|
|
else:
|
|
print(f"Error submitting request: {response.status_code} - {response.text}")
|
|
except requests.exceptions.RequestException as err:
|
|
print(f"Network error submitting request: {err}")
|
|
self.page.update()
|
|
|
|
def _add_comment_to_request(self, e):
|
|
if not self.current_selected_request:
|
|
print("No request selected to add a comment.")
|
|
return
|
|
|
|
comment = self.comment_text_field.value.strip()
|
|
if not comment:
|
|
print("Comment text cannot be empty.")
|
|
return
|
|
|
|
request_id = self.current_selected_request['id']
|
|
current_request_text = self.current_selected_request.get('request_text', '')
|
|
|
|
# Append new comment with timestamp
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
new_request_text = f"{current_request_text}\n\n--- Comentariu client ({timestamp}):\n{comment}"
|
|
|
|
try:
|
|
response = requests.put(
|
|
f"{self.base_url}/documents/customs/requests/update/{request_id}",
|
|
json={"request_text": new_request_text}, # Only sending request_text for update
|
|
headers={'Authorization': f'Bearer {self.token}'}
|
|
)
|
|
if response.status_code == 200:
|
|
print("Comment added successfully!")
|
|
# Update the local request object and re-display details
|
|
self.current_selected_request['request_text'] = new_request_text
|
|
self._display_request_details(self.current_selected_request)
|
|
|
|
# Notificăm Expertul (BA) dacă este alocat
|
|
try:
|
|
subject = f"Comentariu nou la solicitarea #{request_id}"
|
|
body = (
|
|
f"Clientul {self.user.get('email')} a adăugat un comentariu la "
|
|
f"solicitarea #{request_id}.\n\n"
|
|
f"Mesaj:\n{comment}"
|
|
)
|
|
#send_gmail(to_email="office@juridicbloc.ro", subject=subject, body=body)
|
|
send_gmail(to_email='macamete.robert@gmail.com', subject=subject, body=body)
|
|
except Exception as mail_err:
|
|
print(f"Eroare notificare expert: {mail_err}")
|
|
|
|
self.comment_text_field.value = "" # Clear comment field
|
|
else:
|
|
print(f"Error adding comment: {response.status_code} - {response.text}")
|
|
except requests.exceptions.RequestException as err:
|
|
print(f"Network error adding comment: {err}")
|
|
self.page.update()
|
|
|
|
def _on_search_change(self, e):
|
|
query = self.search_bar.value.strip().lower()
|
|
if query:
|
|
filtered_requests = [
|
|
req for req in self.all_requests
|
|
if query in req.get('request_text', '').lower() or
|
|
query in req.get('status', '').lower() or
|
|
query in str(req.get('id', '')).lower()
|
|
]
|
|
else:
|
|
filtered_requests = self.all_requests
|
|
self._populate_requests_list(filtered_requests)
|
|
|
|
def _on_pay_button_click(self, e):
|
|
# Placeholder for payment logic
|
|
print(f"Payment button clicked for request ID: {self.current_selected_request['id']}")
|
|
self.page.show_dialog(ft.SnackBar(
|
|
ft.Text("Funcționalitatea de plată va fi implementată ulterior."),
|
|
))
|
|
self.page.update()
|
|
|
|
def _close_dialog(self, e):
|
|
self.page.pop_dialog()
|
|
self.page.update()
|
|
|
|
def build(self):
|
|
return ft.Container(
|
|
content=ft.Row(
|
|
[
|
|
# Left Column: New Request Button and Requests List
|
|
ft.Column(
|
|
[
|
|
ft.FilledButton(
|
|
"Solicita document personalizat",
|
|
icon=ft.Icons.ADD_TASK,
|
|
on_click=self._open_new_request_dialog,
|
|
width=300
|
|
),
|
|
ft.Divider(),
|
|
self.requests_list_view,
|
|
],
|
|
width=350,
|
|
expand=False,
|
|
alignment=ft.MainAxisAlignment.START
|
|
),
|
|
ft.VerticalDivider(width=1),
|
|
# Right Column: Search Bar and Request Details
|
|
ft.Column(
|
|
[
|
|
ft.Row([self.search_bar]),
|
|
ft.Divider(),
|
|
self.selected_request_details_column,
|
|
],
|
|
expand=True
|
|
)
|
|
],
|
|
expand=True
|
|
),
|
|
expand=True,
|
|
padding=10
|
|
)
|