import flet as ft from dbActions.orders import Orders from dbActions.products import Products from dbActions.company import Company from dbActions.users import Users from dbActions.fidelity_cards import FidelityCards from dbActions.netopia import Netopia from helpers.emails import send_gmail from helpers.netopia import start_card_payment import re class Cart: def __init__(self, page: ft.Page): self.page = page self.user = self.page.session.get('user') self.orders_manager = Orders() self.productsDB = Products() self.company_manager = Company() self.user_manager = Users() self.card_manager = FidelityCards() self.netopia_manager = Netopia() self.products = [] self.is_second_address = None self.is_company = None self.pret_total = ft.Text("Pret total: 0", weight=ft.FontWeight.BOLD) self.delete_dialog = ft.AlertDialog( title=ft.Text("Stergeti?"), actions=[ ft.FilledButton("Da", on_click=self.on_confirm_delete_btn_click), ft.FilledButton("Nu", on_click=self.on_cancel_delete_btn_click, bgcolor=ft.Colors.GREY) ] ) self.on_hold_orders = self.orders_manager.get_on_hold_order(self.user['id']) if self.on_hold_orders: self.order_products = self.orders_manager.get_order_products(self.on_hold_orders['id']) for product in self.order_products: self.products.append( { 'product':self.productsDB.get(product['prdouct_id']), 'quantity':product['quantity'] } ) self.product_list = ft.ListView( controls=self.create_list(self.products, self.on_delete_product_click), spacing=10, expand=5 ) self.payment = ft.RadioGroup( content=ft.Row( [ ft.Radio(value="ramburs", label="Ramburs la curier"), ft.Radio(value="plata_online_cu_cardul", label="Plata online cu cardul"), ] ), on_change=self.on_payment_value_change ) self.payment_message = ft.Text("") self.error_message = ft.Text( color=ft.Colors.RED ) self.confirm_dialog = ft.AlertDialog( title=ft.Text("Confirma"), actions=[ ft.FilledButton( "Da", on_click=self.on_confim_btn_click ), ft.FilledButton( "Nu", on_click=self.on_cancel_btn_click, bgcolor=ft.Colors.GREY ) ] ) self.all_orders = self.orders_manager.get_orders_for_user(self.page.session.get('user')['id']) self.all_orders = self.all_orders[::-1] self.orders_manager_list = ft.ListView( controls=self.create_history_list(self.all_orders), spacing=10, expand=True ) self.user = self.page.session.get("user") self.company = self.company_manager.get_company(self.user['id']) self.first_name = ft.TextField( label="Prenume", value=self.user['name'].split('~')[0] if "@default.com" not in self.user['email'] and '~' in self.user['email'] else None ) self.last_name = ft.TextField( label="Nume", value=self.user['name'].split('~')[1] if "@default.com" not in self.user['email'] and '~' in self.user['email'] else None ) self.email = ft.TextField( label="E-mail", value=self.user['email'] if "@default.com" not in self.user['email'] else None, read_only=True if "@default.com" not in self.user['email'] else False ) self.phone = ft.TextField( label="Telefon", value=self.user['phone'] if "@default.com" not in self.user['email'] else None ) self.address = ft.TextField( label="Strada si numar", multiline=True, min_lines=3, max_lines=5, value = self.user['address'].split("~")[0].split("%")[1] if self.user['address'] and "~" in self.user['address'] else '' ) self.city = ft.TextField( label="Oras", value = self.user['address'].split("~")[0].split('%')[0] if self.user['address'] and "~" in self.user['address'] else '' ) self.company_name = ft.TextField( label="Denumire firma", value=self.company['name'] if self.company else '' ) self.vat = ft.TextField( label="CUI", value=self.company['vat'] if self.company else '' ) self.register_number = ft.TextField( label="Numar registru comert", value=self.company['register_number'] if self.company else '' ) self.company_address = ft.TextField( label="Sediu", multiline=True, min_lines=3, max_lines=5, value=self.company['address'] if self.company else '') self.second_address_placeholder = ft.Column() self.second_address = ft.TextField( label="Adresa de livrare (str, nr, oras, judet)", multiline=True, min_lines=3, max_lines=5, value=self.user['address'].split("~")[1] if self.user['address'] and "~" in self.user['address'] and len(self.user['address'].split("~"))>1 else '' ) self.second_address_placeholder =ft.Column() self.order_placeholder =ft.Column() if self.user['address'] and len(self.user['address'].split("~"))>1 : self.is_second_address = True self.second_address_placeholder.controls.append(self.second_address) if self.company: self.is_company = True self.order_placeholder.controls.append(self.company_name) self.order_placeholder.controls.append(self.vat) self.order_placeholder.controls.append(self.register_number) self.order_placeholder.controls.append(self.company_address) self.delivery_details = ft.Column( [ ft.Text( "Detaili de livrare", weight=ft.FontWeight.BOLD ), self.first_name, self.last_name, self.email, self.phone, self.address, self.city, ft.Divider(), ft.Text("Adresa de livrare difera de adresa de domiciliu?", text_align=ft.TextAlign.CENTER), ft.Button("Adauga adresa livrare", width=500, on_click=self.on_second_address_btn_click), self.second_address_placeholder, ft.Divider(), ft.Button("Doriti Factura?", width=500, on_click=self.on_order_btn_click), self.order_placeholder, ft.Text( "Metoda de plata", weight=ft.FontWeight.BOLD ), self.payment, self.payment_message, ft.Row([self.error_message],alignment=ft.MainAxisAlignment.CENTER), ft.Row( [ ft.FilledButton( "Comanda", width=150, on_click=self.open_confirm_dialog ) ], alignment=ft.MainAxisAlignment.CENTER ) ], expand=5, alignment=ft.MainAxisAlignment.START ) if self.page.width < 600: self.cart_placeholder = ft.Column( [ self.product_list, self.delivery_details ] ) else: self.cart_placeholder = ft.Row( [ self.product_list, self.delivery_details ], vertical_alignment=ft.CrossAxisAlignment.START ) self.order_list_placeholder = ft.Column() self.order_list_placeholder.controls.append(self.orders_manager_list) self.item_to_be_deleted = None self.page.add(self.delete_dialog) self.page.add(self.confirm_dialog) discount_cards= self.card_manager.get_all_fidelity_cards() _card_id = None for card in discount_cards: if card['phone_number'] == self.user['phone']: _card_id = card['card_id'] break self.card_id = ft.Text(f"Card de reducere nr. {_card_id}" if _card_id else '', weight=ft.FontWeight.BOLD) def on_second_address_btn_click(self, e): self.is_second_address = True self.second_address_placeholder.controls.append(self.second_address) self.second_address_placeholder.update() def on_order_btn_click(self, e): self.is_company = True self.order_placeholder.controls.append(self.company_name) self.order_placeholder.controls.append(self.vat) self.order_placeholder.controls.append(self.register_number) self.order_placeholder.controls.append(self.company_address) self.order_placeholder.update() def on_payment_value_change(self, e): print(e.data) if e.data == 'plata_online_cu_cardul': pass else: pass def get_order_products(self, id): products = self.orders_manager.get_order_products(id) total = 0 all_products = [] for product in products: item = self.productsDB.get(product['prdouct_id']) total += item['price'] name = item['name'] if name not in all_products: all_products.append(name) try: self.pret_total.value = f'Pret total: {total}' self.pret_total.update() except: pass return ft.Text( value=' '.join(all_products) ) def on_go_back_button_click(self, e): self.page.go("/") def create_list(self, items, on_click_handler): """Helper to create list items for a column.""" return [ ft.Container( content=ft.Row( [ ft.Column( [ ft.Row( [ ft.Icon(ft.Icons.ARROW_RIGHT, size=20), ft.Row( [ ft.Image( src=item['product']['image'], width=100, height=100, fit=ft.ImageFit.COVER, border_radius=10 ), ft.Column( [ ft.Text(f"Denumire Produs: {item['product']['name']}", weight=ft.FontWeight.BOLD), ft.Text(f"Cantitate: {item['quantity']}"), ft.Text(f"Descriere: {item['product']['description']}", size=12 , color=ft.Colors.GREY), ] ) ] ) ] ), ] ), ft.Row( [ ft.FilledButton("Sterge",on_click=lambda e, id=item: on_click_handler(id), bgcolor=ft.Colors.RED), ] ) ], alignment=ft.MainAxisAlignment.SPACE_BETWEEN, ), width=300, bgcolor=ft.Colors.BROWN_50, padding=10, border_radius=8, border = ft.border.all(1, ft.Colors.GREY), ) for item in items ] def create_history_list(self, items): status_value = { 'new':'Noua', 'on_hold':'In asteptare', 'in_progress': 'In lucru', 'completed':'Complete' } return [ ft.Container( content=ft.Column( [ ft.Row( [ ft.Icon(ft.Icons.ARROW_RIGHT, size=20), ft.Text(value="Numar comanda: "), ft.Text(value=item['id']) ] ), ft.Row( [ ft.Text( value='Status: ' ), ft.Text( value=status_value[item['status']] ) ] ), ft.Row( [ ft.Text( value='Produse: ' ), self.get_order_products(item['id']) ] ) ], alignment=ft.MainAxisAlignment.START, ), width=300, bgcolor=ft.Colors.BROWN_50, padding=10, border_radius=8, border = ft.border.all(1, ft.Colors.GREY), ) for item in items ] def on_delete_product_click(self, item): print('Delte item', item) self.page.open(self.delete_dialog) self.page.update() self.item_to_be_deleted = item['product']['id'] def on_confirm_delete_btn_click(self, e): print("confirm delete item", self.item_to_be_deleted) #remove item self.orders_manager.remove_product_from_order(self.on_hold_orders['id'], self.item_to_be_deleted) #update list self.order_products = self.orders_manager.get_order_products(self.on_hold_orders['id']) self.products = [] for product in self.order_products: self.products.append( { 'product':self.productsDB.get(product['prdouct_id']), 'quantity':product['quantity'] } ) self.product_list.controls.clear() self.product_list.controls = self.create_list(self.products, self.on_delete_product_click) self.product_list.update() self.item_to_be_deleted = None self.page.close(self.delete_dialog) def on_cancel_delete_btn_click(self, e): print("cancel item deletion: ", self.item_to_be_deleted) self.item_to_be_deleted = None self.page.close(self.delete_dialog) def open_confirm_dialog(self, e): print('open dialog') print(self.on_hold_orders) if self.on_hold_orders: self.error_message.value = '' self.error_message.update() self.page.open(self.confirm_dialog) else: self.error_message.value = "Nu aveti nici un produs in cos!" self.error_message.update() def on_cancel_btn_click(self, e): self.page.close(self.confirm_dialog) def check_second_address_inserted(self, address): if address is None or len(address)< 1: self.error_message.value = "Va rugam inserati adresa de livrare!" self.error_message.color = ft.Colors.RED self.error_message.update() print('Second address found') return True print('Second address not found') return False def check_company_data_inserted(self, company_name, vat, register_number, company_address): found = False if company_name is None or len(company_name)< 1: print("Comapny name not found") found = True if vat is None or len(vat)< 1: print("Vat not found") found = True if register_number is None or len(register_number)< 1: print("Register number not found") found = True if company_address is None or len(company_address)< 1: print("Company address not found") found = True if found: self.error_message.value = "Toate campurile sunt obligatori!" self.error_message.color = ft.Colors.RED self.error_message.update() return found def check_inserted_user_data(self, username, phone, address, email, city): found = False if username is None or len(username)< 1: print('Username not found') found = True if phone is None or len(phone)< 1: print("Phone not found") found = True if address is None or len(address)< 1: print("Adress not found") found = True if city is None or len(city)< 1: print("City not found") found = True if email is None or len(email)<1: print("email not found") found = True if found: self.error_message.value = "Toate campurile sunt obligatori!" self.error_message.color = ft.Colors.RED self.error_message.update() return found def check_email_is_valid(self, email): email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' if re.fullmatch(email_regex, email) is not None: self.error_message.value = "" self.error_message.update() return True else: self.error_message.value = "Va rugam inserati un e-mail valid!" self.error_message.update() return False def create_update_user_details(self): username = self.first_name.value + "~" + self.last_name.value phone = self.phone.value address = self.city.value+"%"+self.address.value email = self.email.value if self.is_second_address: print("Second address has been selected (button click)") if self.check_second_address_inserted(self.second_address.value): return False address = self.city.value+"%"+self.address.value + '~' + self.second_address.value if self.check_inserted_user_data(username, phone, self.address.value, email, self.city.value): return False if not self.check_email_is_valid(email): return False if '@default.com' in self.user['email']: print("User is default @default.com in name") try: user_id = self.user_manager.invite_user( email, username, phone, address ) self.user = self.user_manager.get(user_id) print("User invited") self.page.session.set("user", self.user) self.orders_manager.update_order_user_id(user_id, self.on_hold_orders['id']) except: print("Unable to create user, user already exists") self.error_message.value = "Exita deja un utilizator cu aceasta adresa de email!" return False else: self.user_manager.update_user_data(username, phone, address, self.user['id']) if self.is_company: print("Compani selected (company button has been pressed)") if self.check_company_data_inserted(self.company_name.value, self.vat.value, self.register_number.value, self.company_address.value): return if self.company: company['name'] = self.company_name.value company['vat'] = self.vat.value company['register_number'] = self.register_number.value company['address'] = self.company_address.value self.company_manager.update_company(company) else: company = { 'user_id' : self.user['id'], 'name': self.company_name.value, 'vat': self.vat.value, 'register_number': self.register_number.value, 'address': self.company_address.value } self.company_manager.add_company(company) if self.payment.value == None: self.error_message.value = "Va rugam selectati metoda de plata!" self.error_message.color = ft.Colors.RED self.error_message.update() return False return True def create_history(self): if '@default.com' not in self.user['email']: self.all_orders = self.orders_manager.get_orders_for_user(self.page.session.get('user')['id']) self.all_orders = self.all_orders[::-1] buffer = [] for order in self.all_orders: if order['status'] != 'on_hold': buffer.append(order) self.orders_manager_list.controls.clear() self.orders_manager_list.controls = self.create_history_list(buffer) self.orders_manager_list.update() def notify_admin_and_client(self): users = self.user_manager.get_all() admins = [] for user in users: if user['role'] == 'admin': admins.append(user) for admin in admins: send_gmail( to_email=admin['email'], subject="Comanda noua pe tainagustului.ro", body=f''' Ati primit o noua comanda de la {self.user['email']}. Va rugam accesati wwww.tainagusutului.ro pentru detalii. ''' ) send_gmail( to_email=self.user['email'], subject="Multumim pentru comanda!", body=f''' Buna ziua, Comanda a fost primita si va fi livrata in cel mai scurt timp. Va multumim, Echipa tainagustului.ro ''' ) def save_order_ntp_id(self, order_id, netopia_id): self.netopia_manager.add_netopia_card(order_id, netopia_id) def online_pay(self, order_id): if self.payment.value == "plata_online_cu_cardul": print("The user seelected card payment") order_products = [] products_ids = self.orders_manager.get_order_products(order_id) for prod in products_ids: p = self.productsDB.get(prod['prdouct_id']) order_products.append( { 'name':p['name'], 'code':p['id'], 'category':p['category_id'], 'price':p['price'], 'vat':0, } ) print(order_products) response = start_card_payment( order_id=order_id, amount=self.pret_total.value.split(": ")[1], currency='RON', description="Comanda noua", customer={ 'email':self.email.value, 'phone':self.phone.value, 'firstName':self.first_name.value, 'lastName':self.last_name.value, 'city':self.city.value, 'country': 642, 'address':self.address.value, 'county':'', 'zipCode':'' }, products=order_products ) print(type(response)) # Extract URL & ntpID from SDK response payment_url = response.payment['paymentURL'] ntp_id = response.payment['ntpID'] # 1) Persist mapping (VERY IMPORTANT for IPN/status reconciliation) if ntp_id: self.save_order_ntp_id(order_id, ntp_id) # implement in your DB layer # 2) Open hosted payment page if payment_url: self.page.launch_url(payment_url, web_window_name="_blank") self.page.go("/payment/redirect") # your UX page else: self.page.snack_bar = ft.SnackBar(ft.Text("Nu am primit URL-ul de plată.")) self.page.snack_bar.open = True self.page.update() def on_confim_btn_click(self, e): self.error_message.color = ft.Colors.RED self.error_message.update() #create / update user details: print("Confirm button Selected ") self.page.close(self.confirm_dialog) if self.create_update_user_details(): print('User details updated') order_id = self.on_hold_orders['id'] self.orders_manager.update_order_status("new", self.on_hold_orders['id']) print('Order status is set to new') self.products = [] self.on_hold_orders = self.orders_manager.get_on_hold_order(self.user['id']) if self.on_hold_orders: self.order_products = self.orders_manager.get_order_products(self.on_hold_orders['id']) for product in self.order_products: self.products.append( { 'product':self.productsDB.get(product['prdouct_id']), 'quantity':product['quantity'] } ) self.product_list.controls.clear() self.product_list.controls = self.create_list(self.products, self.on_delete_product_click) self.product_list.update() #hiostory self.create_history() self.error_message.value = "Comanda a fost trimisa cu success!" self.error_message.color = ft.Colors.GREEN self.error_message.update() #online pay self.online_pay(order_id) #notify admin self.notify_admin_and_client() def build(self): return ft.Container( content=ft.Column( [ ft.Row( [ ft.Row( [ ft.Icon( ft.Icons.SHOPPING_CART_CHECKOUT, size=40, ), ft.Column( [ self.pret_total, self.card_id, # ft.Text( # "Produse adugate:", # weight=ft.FontWeight.BOLD, # size=15 # ), ] ) ] ), ft.FilledButton( text="Inapoi", icon=ft.Icons.ARROW_BACK, on_click=self.on_go_back_button_click ) ], alignment=ft.MainAxisAlignment.SPACE_BETWEEN ), ft.Divider(), self.cart_placeholder, self.order_list_placeholder, ft.Text() ], expand=True, scroll=ft.ScrollMode.ADAPTIVE ), expand=True, width=1000, padding=10 )