class GenerateTagForm(MainForm): def __init__(self): super().__init__() self.window.title("SS Fashion Tuty - Generate Tag") # variables self.select_first_row_threshold = 10 self.selected_row = list() self.product_name_list = list() self.product_type_list = list() self.product_size_list = list() self.product_sell_price_list = list() # self.product_actual_price_list = list() self.selected_products_counter = 0 # widgets self.filter_ety_product_name = None self.filter_ety_product_type = None self.filter_ety_product_size = None self.filter_ety_product_sell_price = None # self.filter_ety_product_actual_price = None self.products_tree = None self.selected_products_tree = None # self.purchase_date = None # self.ety_garment_name = None self.qty_window = None self.image_label = None # widget variables self.var_product_code = tk.StringVar() self.var_product_name = tk.StringVar() self.var_product_type = tk.StringVar() self.var_product_size = tk.StringVar() self.var_selling_price = tk.DoubleVar() # self.var_actual_price = tk.DoubleVar() self.var_sheet_count = tk.IntVar() self.var_selected_quantity = tk.IntVar() self.var_available_quantity = tk.IntVar() self.var_quantity = tk.IntVar(value=1) self.load_generate_tag_purchase_form() # shortcuts self.window.bind("<F5>", lambda event: self.filter_product(event)) self.window.bind("<F1>", lambda event: self.select_first_row(event)) def load_generate_tag_purchase_form(self): for index in range(1, 9): self.menubar.entryconfig(index, state=tk.DISABLED) self.show_menu(MainForm.is_admin_user) self.update_username() products = LkpProductName.get_all_product_names() for product in products: self.product_name_list.append(product.product_name) products = LkpProductType.get_all_product_types() for product in products: self.product_type_list.append(product.product_type) products = LkpProductSize.get_all_product_sizes() for product in products: self.product_size_list.append(product.product_size) products = Product.get_product_sell_price_list() for product in products: self.product_sell_price_list.append( str(round(product.selling_price, 2))) # ********** Sub Containers ********* left_container = tk.Frame(self.content_container, bd=5, padx=5, pady=2, relief=tk.RIDGE, bg=self.clr_yellow) left_container.pack(fill='both', expand=True, side=tk.LEFT) right_container = tk.Frame(self.content_container, bd=5, padx=5, pady=5, relief=tk.RIDGE, bg=self.clr_yellow) right_container.pack(fill='both', expand=True, side=tk.RIGHT) # left_container elements left_top_button_container = tk.Frame(left_container, relief=tk.RIDGE, bg=self.clr_yellow) left_top_button_container.pack(fill='both', expand=True, side=tk.TOP) products_tree_container = tk.Frame(left_container, pady=3, bg=self.clr_yellow, relief=tk.RIDGE) products_tree_container.pack(fill='both', expand=True, side=tk.TOP) # right_container elements right_top_button_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_top_button_container.pack(fill='both', expand=True, side=tk.TOP) right_tree_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_tree_container.pack(fill='both', expand=True, side=tk.TOP) right_bottom_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_bottom_container.pack(fill='both', expand=True, side=tk.TOP) # ********** left_search_container elements ********* filter_lbl_product_name = tk.Label(left_top_button_container, text="Name: ", bg=self.clr_yellow) filter_lbl_product_name.grid(row=0, column=0, sticky="nw", padx=1, pady=1) self.filter_ety_product_name = AutocompleteEntry( left_top_button_container, width=15, completevalues=self.product_name_list) self.filter_ety_product_name.grid(row=1, column=0, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_name.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_type = tk.Label(left_top_button_container, text="Type: ", bg=self.clr_yellow) filter_lbl_product_type.grid(row=0, column=1, sticky="nw", padx=1, pady=1) self.filter_ety_product_type = AutocompleteEntry( left_top_button_container, width=18, completevalues=self.product_type_list) self.filter_ety_product_type.grid(row=1, column=1, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_type.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_size = tk.Label(left_top_button_container, text="Size: ", bg=self.clr_yellow) filter_lbl_product_size.grid(row=0, column=2, sticky="nw", padx=1, pady=1) self.filter_ety_product_size = AutocompleteEntry( left_top_button_container, width=12, completevalues=self.product_size_list) self.filter_ety_product_size.grid(row=1, column=2, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_size.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_price = tk.Label(left_top_button_container, text="Sell Price: ", bg=self.clr_yellow) filter_lbl_product_price.grid(row=0, column=3, sticky="nw", padx=1, pady=1) self.filter_ety_product_sell_price = AutocompleteEntry( left_top_button_container, width=8, completevalues=self.product_sell_price_list) self.filter_ety_product_sell_price.grid(row=1, column=3, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_sell_price.bind( "<Return>", lambda event: self.filter_product(event)) # filter_lbl_product_actual_price = tk.Label(left_top_button_container, text="Act. Price: ", bg=self.clr_yellow) # filter_lbl_product_actual_price.grid(row=0, column=4, sticky="nw", padx=1, pady=1) # self.filter_ety_product_actual_price = AutocompleteEntry(left_top_button_container, width=8, # completevalues=self.product_actual_price_list) # self.filter_ety_product_actual_price.grid(row=1, column=4, sticky="nw", padx=2, pady=1, ipady=6) # self.filter_ety_product_actual_price.bind("<Return>", lambda event: self.filter_product(event)) btn_filter = tk.Button(left_top_button_container, text="Apply Filter [F5]", bg=self.clr_fuchsia, fg='white', command=self.filter_product) btn_filter.grid(row=1, column=4, sticky="news", padx=2, pady=1) btn_clear_filter = tk.Button(left_top_button_container, text="Clear", command=self.reload_products) btn_clear_filter.grid(row=1, column=5, sticky="news", padx=2, pady=1) # ********** tree_containers elements ********* header = ('CODE', 'PRODUCT_NAME', 'PRODUCT_TYPE', 'SIZE', 'PRICE', 'QTY', '') self.products_tree = ttk.Treeview(products_tree_container, columns=header, height=20, show="headings", selectmode="browse") vsb = ttk.Scrollbar(products_tree_container, orient="vertical", command=self.products_tree.yview) hsb = ttk.Scrollbar(products_tree_container, orient="horizontal", command=self.products_tree.xview) style = ttk.Style() style.configure("Treeview.Heading", font=('Calibri', 12)) style.configure("Treeview", font=('Calibri', 10), rowheight=25) self.products_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.products_tree.grid(column=0, row=0, sticky='nsew', in_=products_tree_container) vsb.grid(column=1, row=0, sticky='ns', in_=products_tree_container) hsb.grid(column=0, row=1, sticky='ew', in_=products_tree_container) products_tree_container.grid_columnconfigure(0, weight=1) products_tree_container.grid_rowconfigure(0, weight=1) self.products_tree.heading("0", text="CODE") self.products_tree.heading("1", text="PRODUCT_NAME") self.products_tree.heading("2", text="PRODUCT_TYPE") self.products_tree.heading("3", text="SIZE") self.products_tree.heading("4", text="PRICE") self.products_tree.heading("5", text="QTY") self.products_tree.column(0, anchor='center', width="100") self.products_tree.column(1, anchor=tk.W, width="120") self.products_tree.column(2, anchor=tk.W, width="150") self.products_tree.column(3, anchor='center', width="50") self.products_tree.column(4, anchor=tk.E, width="50") self.products_tree.column(5, anchor='center', width="20") self.products_tree.column(6, anchor='center', width="1") self.reload_products() numeric_cols = ['PRICE', 'QTY'] for col in header: if col in numeric_cols: self.products_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.products_tree, _col, numeric_sort=True, reverse=False)) else: self.products_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.products_tree, _col, numeric_sort=False, reverse=False)) # ********** Right Tree Details ********* lbl_selected_quantity = tk.Label(right_top_button_container, text="Quantity:", bg=self.clr_yellow) lbl_selected_quantity.grid(row=0, column=0, rowspan=2, sticky="se", padx=2, pady=1) lbl_selected_quantity.config(font=("calibri bold", 18)) ety_selected_quantity = tk.Entry( right_top_button_container, width=5, textvariable=self.var_selected_quantity, disabledbackground=self.clr_limegreen, disabledforeground="white", justify=tk.CENTER, state='disabled') ety_selected_quantity.grid(row=0, column=1, rowspan=2, sticky="se", padx=2, pady=1) ety_selected_quantity.config(font=("calibri bold", 18)) btn_generate_tag = tk.Button(right_top_button_container, text="Generate Tag", bg=self.clr_fuchsia, fg='white', command=self.generate_tag) btn_generate_tag.grid(row=0, column=2, rowspan=2, sticky="se", padx=2, pady=1) btn_clear = tk.Button(right_top_button_container, text="Clear", command=self.clear_all) btn_clear.grid(row=0, column=3, rowspan=2, sticky="se", padx=2, pady=1) purchase_tree_container = tk.Frame(right_tree_container, pady=1, relief=tk.RIDGE, bg=self.clr_yellow) purchase_tree_container.pack(fill='both', expand=True, side=tk.RIGHT) header = ('#', 'product_code', 'product_name', 'type', 'size', 'selling_price', 'quantity', 'dummy') self.selected_products_tree = ttk.Treeview(purchase_tree_container, columns=header, height=10, show="headings", selectmode="browse") vsb = ttk.Scrollbar(purchase_tree_container, orient="vertical", command=self.selected_products_tree.yview) hsb = ttk.Scrollbar(purchase_tree_container, orient="horizontal", command=self.selected_products_tree.xview) self.selected_products_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.selected_products_tree.grid(column=0, row=0, sticky='nsew') vsb.grid(column=1, row=0, sticky='ns') hsb.grid(column=0, row=1, sticky='ew') purchase_tree_container.grid_columnconfigure(0, weight=1) purchase_tree_container.grid_rowconfigure(0, weight=1) self.selected_products_tree.heading("0", text="#") self.selected_products_tree.heading("1", text="Code") self.selected_products_tree.heading("2", text="Product") self.selected_products_tree.heading("3", text="Type") self.selected_products_tree.heading("4", text="Size") self.selected_products_tree.heading("5", text="Price") self.selected_products_tree.heading("6", text="Qty") self.selected_products_tree.heading("7", text="") self.selected_products_tree.column(0, anchor='center', minwidth=25, width=25) self.selected_products_tree.column(1, anchor=tk.W, minwidth=40, width=110) self.selected_products_tree.column(2, anchor=tk.W, minwidth=80, width=100) # Product self.selected_products_tree.column(3, anchor=tk.W, minwidth=110, width=110) # Type self.selected_products_tree.column(4, anchor='center', minwidth=50, width=50) # Size self.selected_products_tree.column(5, anchor=tk.E, minwidth=50, width=50) # Price self.selected_products_tree.column(6, anchor='center', minwidth=40, width=40) # Qty self.selected_products_tree.column(7, anchor='center', width=1) self.selected_products_tree["displaycolumns"] = (0, 1, 2, 3, 4, 5, 6, 7) self.selected_products_tree.bind( '<Double-1>', lambda event: self.remove_product(event)) self.products_tree.tag_configure("evenrow_active", background='#fbefcc') self.products_tree.tag_configure("oddrow_active", background='white', foreground='black') self.products_tree.tag_configure("evenrow_inactive", background='#fbefcc', foreground='red') self.products_tree.tag_configure("oddrow_inactive", background='white', foreground='red') self.products_tree.bind('<<TreeviewSelect>>', self.on_tree_select) self.products_tree.bind('<Double-1>', lambda event: self.get_quantity(event)) self.products_tree.bind('<Return>', lambda event: self.get_quantity(event)) # ********** bottom_container elements ********* image_container = tk.Frame(right_bottom_container, pady=1, bd=5, relief=tk.RIDGE, bg=self.clr_yellow) image_container.pack(fill='both', expand=True, side=tk.TOP) img = ImageTk.PhotoImage( Image.open(f"images/Sample.png").resize((250, 250), Image.ANTIALIAS)) # img = ImageTk.PhotoImage(Image.open(f"images/Sample.png")) self.image_label = tk.Label(image_container, image=img, bg=self.clr_yellow) self.image_label.image = img self.image_label.pack(side="bottom", fill="both", expand="yes") def remove_product(self, event): selected_row = event.widget.selection()[0] self.selected_products_tree.delete(selected_row) self.selected_products_counter = 0 for child in self.selected_products_tree.get_children(): self.selected_products_counter = self.selected_products_counter + 1 row = self.selected_products_tree.item(child)["values"] row[0] = self.selected_products_counter self.selected_products_tree.delete(child) self.selected_products_tree.insert("", tk.END, values=row) self.calculate_total_amount_and_sheet() def select_first_row(self, event=None): element_id = self.products_tree.get_children()[0] self.products_tree.focus_set() self.products_tree.focus(element_id) self.products_tree.selection_set(element_id) def generate_tag(self): if int(self.var_selected_quantity.get()) < 1 or int( self.var_selected_quantity.get()) > 15: messagebox.showerror("SS Fashion Tuty", f"Selected Quantity should be '1' to '15'!") print(f"Selected Quantity should be '1' to '15'!") return filename = f"images/price_tags/{datetime.strftime(datetime.now(), '%d_%b_%Y_%H%M%S')}.png" large_font = ImageFont.truetype('consolab.ttf', 16) normal_font = ImageFont.truetype('consolab.ttf', 14) image = Image.new(mode="RGB", size=(565, 500), color="white") draw = ImageDraw.Draw(image) start_x = 15 start_y = 15 rect_width = 165 rect_height = 80 qr_rect_width = 45 gap_x = 18 gap_y = 18 pcode_x = 10 pcode_y = rect_height - 18 pname_y = 2 col_num = 0 row_num = 0 for child in self.selected_products_tree.get_children(): product_code = self.selected_products_tree.item(child)["values"][1] product_name = str( self.selected_products_tree.item(child)["values"][2])[:13] product_type = str( self.selected_products_tree.item(child)["values"][3])[:13] if product_type == "-": product_type = str( self.selected_products_tree.item(child)["values"] [2])[13:26] product_size = str( self.selected_products_tree.item(child)["values"][4])[:8] sell_price = self.selected_products_tree.item(child)["values"][5] quantity = self.selected_products_tree.item(child)["values"][6] QRGenerator.generate_qr(product_code) while quantity > 0: # shape = [(start_x, start_y), (start_x + rect_width, start_y + rect_height)] # draw.rectangle(shape, fill="#ffffff", outline="#ABB2B9", width=2) qr_image = Image.open(f"images/qr_codes/{product_code}.png") image.paste(qr_image, (start_x + 2, start_y + 5)) draw.text((start_x + qr_rect_width + 15, start_y + pname_y), product_name, font=normal_font, fill=(0, 0, 0)) draw.text( (start_x + qr_rect_width + 15, start_y + pname_y + 15), product_type, font=normal_font, fill=(0, 0, 0)) draw.text( (start_x + qr_rect_width + 15, start_y + pname_y + 30), f"SIZE:{product_size}", font=normal_font, fill=(0, 0, 0)) draw.text( (start_x + qr_rect_width + 25, start_y + pname_y + 45), f"Rs.{sell_price}", font=large_font, fill=(0, 0, 0)) draw.text((start_x + pcode_x, start_y + pcode_y), product_code, font=large_font, fill=(0, 0, 0)) start_x = start_x + rect_width + gap_x quantity = quantity - 1 col_num += 1 if col_num == 3: row_num += 1 start_y = start_y + rect_height + gap_y start_x = 15 col_num = 0 if row_num == 5: break image.save(filename) # img = ImageTk.PhotoImage(Image.open(f"images/Sample.png")) # self.image_label = tk.Label(image_container, image=img) # self.image_label.image = img # self.image_label.pack(side="bottom", fill="both", expand="yes") # img = ImageTk.PhotoImage(Image.open(filename)) # self.image_label.image = img # img = ImageTk.PhotoImage(file=filename) img = ImageTk.PhotoImage( Image.open(filename).resize((260, 260), Image.ANTIALIAS)) self.image_label['image'] = img img.image = img # self.image_label.pack(side="bottom", fill="both", expand="yes") # os.system(filename) # purchase_date = datetime.strptime(self.purchase_date.get(), "%Y-%m-%d") # garment_name = self.ety_garment_name.get().strip() # # if garment_name == "" or garment_name is None: # messagebox.showerror("SS Fashion Tuty", f"Garment Name is missing!") # print(f"Garment Name is missing!") # return # # if self.selected_products_tree.get_children(): # for child in self.selected_products_tree.get_children(): # product_code = self.selected_products_tree.item(child)["values"][1] # quantity = self.selected_products_tree.item(child)["values"][6] # # purchase = (purchase_date, garment_name, product_code, quantity) # Purchase.add_purchase(purchase) # # stock = (product_code, quantity) # Stock.upload_stock(stock) # # if StockTimeline.get_timeline(product_code=product_code): # activity = "Add Purchase" # else: # activity = "Opening Stock" # # StockTimeline.add_timeline(entry_date=purchase_date, product_code=product_code, activity=activity, # change=f"+{quantity}") # # messagebox.showinfo("SS Fashion Tuty", f"Purchase added Successfully!") # self.clear_all() def filter_product(self, event=None): product_name = self.filter_ety_product_name.get().strip() product_type = self.filter_ety_product_type.get().strip() product_size = self.filter_ety_product_size.get().strip() selling_price = str(self.filter_ety_product_sell_price.get().strip()) if selling_price: selling_price = float(selling_price) else: selling_price = 0.0 products = Product.search_products(product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) self.products_tree.delete(*self.products_tree.get_children()) if products: row_num = 0 for product in products: stock = Stock.get_stock(product_code=product.product_code) quantity = "0" if stock: quantity = stock.quantity row_num += 1 row = (product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), quantity) if row_num % 2 == 0: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_inactive', product.product_code)) else: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_inactive', product.product_code)) if row_num <= self.select_first_row_threshold: self.select_first_row() else: pass def clear_all(self): # self.ety_garment_name.delete(0, tk.END) self.selected_products_counter = 0 self.selected_products_tree.delete( *self.selected_products_tree.get_children()) self.var_sheet_count.set(format_decimal(0, locale='en_US')) self.var_selected_quantity.set(format_decimal(0, locale='en_US')) self.reload_products() self.selected_row = list() def calculate_total_amount_and_sheet(self): total_sheet = 0 total_quantity = 0 for child in self.selected_products_tree.get_children(): total_sheet += int( self.selected_products_tree.item(child)["values"][6]) total_quantity += int( self.selected_products_tree.item(child)["values"][6]) self.var_sheet_count.set(format_decimal(total_sheet, locale='en_US')) self.var_selected_quantity.set( format_decimal(total_quantity, locale='en_US')) def get_quantity(self, event): self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] if isinstance(product, str): return available_quantity = product[5] self.var_available_quantity.set(available_quantity) self.window.wm_attributes("-disabled", True) self.qty_window = tk.Toplevel(self.window) self.qty_window.overrideredirect(True) self.qty_window.bind("<FocusOut>", self.on_focus_out_qty_window) # Gets the requested values of the height and width. window_width = self.qty_window.winfo_reqwidth() window_height = self.qty_window.winfo_reqheight() # Gets both half the screen width/height and window width/height position_right = int(self.qty_window.winfo_screenwidth() / 2 - window_width / 2) position_down = int(self.qty_window.winfo_screenheight() / 2 - window_height / 2) # Positions the window in the center of the page. self.qty_window.geometry("+{}+{}".format(position_right, position_down)) qty_container = tk.Frame(self.qty_window, bd=20, padx=10, pady=5, relief=tk.RIDGE, bg=self.clr_limegreen) qty_container.pack(expand=True, side=tk.TOP, anchor="n") lbl_quantity = tk.Label(qty_container, text="Quantity:", bg=self.clr_limegreen) lbl_quantity.grid(row=0, column=0, columnspan=2, padx=5, pady=2) ety_quantity = tk.Entry(qty_container, width=5, textvariable=self.var_quantity) ety_quantity.grid(row=1, column=0, padx=5, pady=2) if self.var_available_quantity.get() <= self.stock_alert_value: ety_available_quantity = tk.Entry( qty_container, width=5, textvariable=self.var_available_quantity, disabledbackground="red", disabledforeground="white", justify=tk.CENTER, state='disabled') else: ety_available_quantity = tk.Entry( qty_container, width=5, textvariable=self.var_available_quantity, justify=tk.CENTER, state='disabled') ety_available_quantity.grid(row=1, column=1, padx=5, pady=2) ety_quantity.delete(0, tk.END) ety_quantity.insert(tk.END, 1) self.var_quantity.set(1) ety_quantity.focus() ety_quantity.selection_range(0, tk.END) btn_ok = tk.Button(qty_container, text='Add', width=10, bg=self.clr_fuchsia, fg='white', command=lambda: self.cleanup_qty_window(event)) btn_ok.grid(row=2, column=0, columnspan=2, padx=5, pady=5) self.qty_window.bind('<Return>', lambda evnt: self.cleanup_qty_window(event)) self.qty_window.bind( '<Escape>', lambda evnt: self.cleanup_qty_window(event, add_quantity=False)) def on_focus_out_qty_window(self, event=None): self.window.wm_attributes("-disabled", False) self.qty_window.destroy() def cleanup_qty_window(self, event, add_quantity=True): quantity = int(self.var_quantity.get()) self.window.wm_attributes("-disabled", False) self.qty_window.destroy() if add_quantity: self.var_quantity.set(quantity) self.add_to_selected_list(event) def add_to_selected_list(self, event): quantity = self.var_quantity.get() self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] active_product = Product.get_product_status(product_code=product[0]) if not active_product: msg_box = messagebox.askquestion( "SS Fashion Tuty", "In-Active product! - Do you want to add this Product to selected list?", icon='question') if msg_box == 'no': return for child in self.selected_products_tree.get_children(): if self.selected_products_tree.item( child)["values"][1] == product[0]: prev_quantity = self.selected_products_tree.item( child)["values"][6] quantity += prev_quantity self.selected_products_tree.set(child, "#7", quantity) break else: self.selected_products_counter = self.selected_products_counter + 1 row = (self.selected_products_counter, product[0], product[1], product[2], product[3], product[4], quantity) self.selected_products_tree.insert("", tk.END, values=row) self.calculate_total_amount_and_sheet() if len(self.products_tree.selection()) > 0: self.products_tree.selection_remove( self.products_tree.selection()[0]) def reload_products(self): self.filter_ety_product_name.delete(0, tk.END) self.filter_ety_product_type.delete(0, tk.END) self.filter_ety_product_size.delete(0, tk.END) self.filter_ety_product_sell_price.delete(0, tk.END) self.products_tree.delete(*self.products_tree.get_children()) products = Product.get_all_products() row_num = 0 for product in products: row_num += 1 stock = Stock.get_stock(product_code=product.product_code) quantity = "0" if stock: quantity = stock.quantity row = (product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), quantity) if row_num % 2 == 0: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_inactive', product.product_code)) else: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_inactive', product.product_code)) def on_tree_select(self, event): self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] if product: self.var_product_code.set(product[0]) self.var_product_name.set(product[1]) self.var_product_type.set(product[2]) self.var_product_size.set(product[3]) self.var_selling_price.set(product[4])
class ViewSalesForm(MainForm): def __init__(self): super().__init__() self.window.title("SS Fashion Tuty - View Sales") # variables self.selected_row = list() self.product_name_list = list() self.product_type_list = list() self.product_size_list = list() self.product_sell_price_list = list() self.billno_list = list() # widgets self.ety_filter_product_name = None self.ety_filter_product_type = None self.ety_filter_product_size = None self.ety_filter_product_sell_price = None self.ety_filter_bill_number = None self.ety_filter_product_code_1 = None self.ety_filter_product_code_2 = None self.ety_filter_product_code_3 = None self.ety_filter_product_code_4 = None self.sales_tree = None self.from_date = None self.to_date = None self.sales_from_date = None self.sales_to_date = None # widget variables self.var_sales_date = tk.StringVar() self.var_bill_number = tk.StringVar() self.var_product_code = tk.StringVar() self.var_product_name = tk.StringVar() self.var_product_type = tk.StringVar() self.var_product_size = tk.StringVar() self.var_selling_price = tk.DoubleVar() self.var_quantity = tk.IntVar() self.var_sold_quantity = tk.IntVar() self.var_sales_amount = tk.DoubleVar() self.var_search_product_code_1 = tk.StringVar() self.var_search_product_code_2 = tk.StringVar() self.var_search_product_code_3 = tk.StringVar() self.var_search_product_code_4 = tk.StringVar() self.var_chk_include_date = tk.IntVar() self.load_view_sales_form() def load_view_sales_form(self): for index in range(1, 9): self.menubar.entryconfig(index, state=tk.DISABLED) self.show_menu(MainForm.is_admin_user) self.update_username() products = Product.get_product_name_list() for product in products: self.product_name_list.append(product.product_name) products = Product.get_product_type_list() for product in products: self.product_type_list.append(product.product_type) products = Product.get_product_size_list() for product in products: self.product_size_list.append(product.product_size) products = Product.get_product_sell_price_list() for product in products: self.product_sell_price_list.append( str(round(product.selling_price, 2))) bills = Sales.get_bill_number_list() for bill in bills: self.billno_list.append(str(bill.bill_number)) # ********** Sub Containers ********* left_container = tk.Frame(self.content_container, bd=5, padx=2, pady=2, relief=tk.RIDGE, bg=self.clr_yellow) left_container.pack(fill='both', expand=True, side=tk.LEFT) right_container = tk.Frame(self.content_container, padx=2, relief=tk.RIDGE, bg=self.clr_yellow) right_container.pack(fill='both', expand=True, side=tk.RIGHT) # left_container main elements button_container = tk.Frame(left_container, padx=2, pady=2, relief=tk.RIDGE, bg=self.clr_yellow) button_container.pack(fill='both', expand=True, side=tk.TOP) sales_tree_container = tk.Frame(left_container, padx=2, pady=2, relief=tk.RIDGE, bg=self.clr_yellow) sales_tree_container.pack(fill='both', expand=True, side=tk.TOP) # button_container date_container = tk.Frame(button_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) date_container.pack(fill='both', expand=True, anchor='w', side=tk.LEFT) name_filter_container = tk.Frame(button_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) name_filter_container.pack(fill='both', expand=True, anchor='w', side=tk.TOP) code_filter_container = tk.Frame(button_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) code_filter_container.pack(fill='both', expand=True, anchor='w', side=tk.LEFT) billno_filter_container = tk.Frame(button_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) billno_filter_container.pack(fill='both', expand=True, anchor='w', side=tk.RIGHT) # ********** button_container elements ********* date_container.grid_rowconfigure(0, weight=1) date_container.grid_rowconfigure(6, weight=1) date_container.grid_columnconfigure(0, weight=1) date_container.grid_columnconfigure(2, weight=1) lbl_from_date = tk.Label(date_container, text='From Date: ', bg=self.clr_yellow) lbl_from_date.grid(row=1, column=1, sticky="nw", padx=1, pady=1) self.from_date = DateEntry(date_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2, width=10) self.from_date.grid(row=2, column=1, sticky="sw", padx=2, pady=1, ipady=3) lbl_to_date = tk.Label(date_container, text='To Date: ', bg=self.clr_yellow) lbl_to_date.grid(row=3, column=1, sticky="nw", padx=1, pady=1) self.to_date = DateEntry(date_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2, width=10) self.to_date.grid(row=4, column=1, sticky="sw", padx=2, pady=1, ipady=3) include_date = tk.Checkbutton(date_container, text='Include Date', variable=self.var_chk_include_date, onvalue=1, offvalue=0, bg=self.clr_yellow) include_date.grid(row=5, column=1, sticky="sw", padx=2, pady=1) # name_filter_container elements name_filter_container.grid_rowconfigure(0, weight=1) name_filter_container.grid_rowconfigure(3, weight=1) name_filter_container.grid_columnconfigure(0, weight=1) name_filter_container.grid_columnconfigure(7, weight=1) filter_lbl_product_name = tk.Label(name_filter_container, text="Name: ", bg=self.clr_yellow) filter_lbl_product_name.grid(row=1, column=1, sticky="nw", padx=1, pady=1) self.ety_filter_product_name = AutocompleteEntry( name_filter_container, width=15, completevalues=self.product_name_list) self.ety_filter_product_name.grid(row=2, column=1, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_name.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_type = tk.Label(name_filter_container, text="Type: ", bg=self.clr_yellow) filter_lbl_product_type.grid(row=1, column=2, sticky="nw", padx=1, pady=1) self.ety_filter_product_type = AutocompleteEntry( name_filter_container, width=20, completevalues=self.product_type_list) self.ety_filter_product_type.grid(row=2, column=2, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_type.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_size = tk.Label(name_filter_container, text="Size: ", bg=self.clr_yellow) filter_lbl_product_size.grid(row=1, column=3, sticky="nw", padx=1, pady=1) self.ety_filter_product_size = AutocompleteEntry( name_filter_container, width=8, completevalues=self.product_size_list) self.ety_filter_product_size.grid(row=2, column=3, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_size.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_price = tk.Label(name_filter_container, text="Price: ", bg=self.clr_yellow) filter_lbl_product_price.grid(row=1, column=4, sticky="nw", padx=1, pady=1) self.ety_filter_product_sell_price = AutocompleteEntry( name_filter_container, width=8, completevalues=self.product_sell_price_list) self.ety_filter_product_sell_price.grid(row=2, column=4, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_sell_price.bind( "<Return>", lambda event: self.filter_product(event)) btn_filter = tk.Button(name_filter_container, text="Apply Filter", bg=self.clr_fuchsia, fg='white', command=self.filter_product) btn_filter.grid(row=2, column=5, sticky="sw", padx=2, pady=1) btn_clear_filter = tk.Button(name_filter_container, text="Clear Filter", command=self.reload_sales) btn_clear_filter.grid(row=2, column=6, sticky="news", padx=2, pady=1) code_filter_container.grid_rowconfigure(0, weight=1) code_filter_container.grid_rowconfigure(3, weight=1) code_filter_container.grid_columnconfigure(0, weight=1) code_filter_container.grid_columnconfigure(7, weight=1) lbl_search_product_code = tk.Label(code_filter_container, text="Product Code: ", bg=self.clr_yellow) lbl_search_product_code.grid(row=1, column=1, columnspan=3, sticky="nw", padx=1, pady=1) self.ety_filter_product_code_1 = MaxLengthEntry( code_filter_container, maxlength=3, width=4, textvariable=self.var_search_product_code_1) self.ety_filter_product_code_1.grid(row=2, column=1, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_1.bind( '<Return>', lambda event: self.validate_entry(event, 3)) self.ety_filter_product_code_2 = MaxLengthEntry( code_filter_container, maxlength=3, width=4, textvariable=self.var_search_product_code_2) self.ety_filter_product_code_2.grid(row=2, column=2, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_2.bind( '<Return>', lambda event: self.validate_entry(event, 3)) self.ety_filter_product_code_3 = MaxLengthEntry( code_filter_container, maxlength=2, width=3, textvariable=self.var_search_product_code_3) self.ety_filter_product_code_3.grid(row=2, column=3, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_3.bind( '<Return>', lambda event: self.validate_entry(event, 2)) self.ety_filter_product_code_4 = MaxLengthEntry( code_filter_container, maxlength=4, width=5, textvariable=self.var_search_product_code_4) self.ety_filter_product_code_4.grid(row=2, column=4, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_4.bind( '<Return>', lambda event: self.validate_entry(event, 4)) btn_filter_product_code = tk.Button(code_filter_container, text="Apply Filter", bg=self.clr_fuchsia, fg='white', command=self.filter_product_code) btn_filter_product_code.grid(row=2, column=5, sticky="sw", padx=2, pady=1) btn_filter_product_code.bind( '<Return>', lambda event: self.filter_product_code(event)) btn_clear_filter = tk.Button(code_filter_container, text="Clear Filter", command=self.reload_sales) btn_clear_filter.grid(row=2, column=6, sticky="news", padx=2, pady=1) # billno_filter_container elements billno_filter_container.grid_rowconfigure(0, weight=1) billno_filter_container.grid_rowconfigure(3, weight=1) billno_filter_container.grid_columnconfigure(0, weight=1) billno_filter_container.grid_columnconfigure(4, weight=1) filter_lbl_bill_number = tk.Label(billno_filter_container, text="Bill No: ", bg=self.clr_yellow) filter_lbl_bill_number.grid(row=1, column=1, sticky="nw", padx=1, pady=1) self.ety_filter_bill_number = AutocompleteEntry( billno_filter_container, width=8, completevalues=self.billno_list) self.ety_filter_bill_number.grid(row=2, column=1, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_bill_number.bind( "<Return>", lambda event: self.filter_bill_number(event)) btn_apply_filter = tk.Button(billno_filter_container, text="Apply Filter", bg=self.clr_fuchsia, fg='white', command=self.filter_bill_number) btn_apply_filter.grid(row=2, column=2, sticky="news", padx=2, pady=1) btn_apply_filter.bind('<Return>', lambda event: self.filter_bill_number(event)) btn_clear_filter = tk.Button(billno_filter_container, text="Clear Filter", command=self.reload_sales) btn_clear_filter.grid(row=2, column=3, sticky="news", padx=2, pady=1) # ********** tree_containers elements ********* header = ('SALES_DATE', 'BILL_NO', 'PRODUCT_CODE', 'PRODUCT_NAME', 'PRODUCT_TYPE', 'SIZE', 'PRICE', 'QTY', '') self.sales_tree = ttk.Treeview(sales_tree_container, columns=header, height=20, show="headings", selectmode="browse") vsb = ttk.Scrollbar(sales_tree_container, orient="vertical", command=self.sales_tree.yview) hsb = ttk.Scrollbar(sales_tree_container, orient="horizontal", command=self.sales_tree.xview) self.sales_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) style = ttk.Style() style.configure("Treeview.Heading", font=('Calibri', 12)) style.configure("Treeview", font=('Calibri', 12), rowheight=25) self.sales_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.sales_tree.grid(column=0, row=0, sticky='nsew', in_=sales_tree_container) vsb.grid(column=1, row=0, sticky='ns', in_=sales_tree_container) hsb.grid(column=0, row=1, sticky='ew', in_=sales_tree_container) sales_tree_container.grid_columnconfigure(0, weight=1) sales_tree_container.grid_rowconfigure(0, weight=1) self.sales_tree.heading("0", text="SALES_DATE") self.sales_tree.heading("1", text="BILL_NO") self.sales_tree.heading("2", text="PRODUCT_CODE") self.sales_tree.heading("3", text="PRODUCT_NAME") self.sales_tree.heading("4", text="PRODUCT_TYPE") self.sales_tree.heading("5", text="SIZE") self.sales_tree.heading("6", text="PRICE") self.sales_tree.heading("7", text="QTY") self.sales_tree.column(0, anchor=tk.W, width="140") self.sales_tree.column(1, anchor=tk.W, width="80") self.sales_tree.column(2, anchor=tk.W, width="120") self.sales_tree.column(3, anchor=tk.W, width="140") self.sales_tree.column(4, anchor=tk.W, width="180") self.sales_tree.column(5, anchor='center', width="50") self.sales_tree.column(6, anchor=tk.E, width="80") self.sales_tree.column(7, anchor='center', width="50") self.sales_tree.column(8, anchor='center', width="2") self.reload_sales() numeric_cols = ['BILL_NO', 'PRICE', 'QTY'] for col in header: if col in numeric_cols: self.sales_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.sales_tree, _col, numeric_sort=True, reverse=False)) else: self.sales_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.sales_tree, _col, numeric_sort=False, reverse=False)) self.sales_tree.tag_configure("evenrow", background='#fbefcc') self.sales_tree.tag_configure("oddrow", background='white', foreground='black') self.sales_tree.bind('<<TreeviewSelect>>', self.on_tree_select) # ********** Sales Details ********* sales_details_container = tk.Frame(right_container, bd=5, pady=3, padx=10, relief=tk.RIDGE, bg=self.clr_yellow) sales_details_container.pack(fill='both', expand=True, side=tk.TOP) sales_stats_container = tk.Frame(right_container, bd=5, pady=3, padx=10, relief=tk.RIDGE, bg=self.clr_yellow) sales_stats_container.pack(fill='both', expand=True, side=tk.TOP, anchor='center') sales_details_container.grid_columnconfigure(0, weight=1) sales_details_container.grid_columnconfigure(3, weight=1) lbl_product_details = tk.Label(sales_details_container, text="Sales Details", bg=self.clr_blueiris, fg="white") lbl_product_details.grid(row=0, column=1, columnspan=2, sticky="news", padx=3, pady=3) lbl_product_details.config(font=("Calibri bold", 14)) lbl_sales_date = tk.Label(sales_details_container, text="Sales Date: ", bg=self.clr_yellow) lbl_sales_date.grid(row=1, column=1, sticky="nw", padx=3, pady=1) ety_sales_date = tk.Entry(sales_details_container, textvariable=self.var_sales_date, state='disabled') ety_sales_date.grid(row=1, column=2, sticky="nw", padx=3, pady=1) lbl_bill_number = tk.Label(sales_details_container, text="Bill No: ", bg=self.clr_yellow) lbl_bill_number.grid(row=2, column=1, sticky="nw", padx=3, pady=1) ety_bill_number = tk.Entry(sales_details_container, width=8, textvariable=self.var_bill_number, state='disabled') ety_bill_number.grid(row=2, column=2, columnspan=2, sticky="nw", padx=3, pady=1) lbl_product_code = tk.Label(sales_details_container, text="Product Code: ", bg=self.clr_yellow) lbl_product_code.grid(row=3, column=1, sticky="nw", padx=3, pady=1) ety_product_code = tk.Entry(sales_details_container, width=15, textvariable=self.var_product_code, state='disabled') ety_product_code.grid(row=3, column=2, columnspan=2, sticky="nw", padx=3, pady=1) lbl_product_name = tk.Label(sales_details_container, text="Product Name: ", bg=self.clr_yellow) lbl_product_name.grid(row=4, column=1, sticky="nw", padx=3, pady=1) ety_product_name = tk.Entry(sales_details_container, textvariable=self.var_product_name, state='disabled') ety_product_name.grid(row=4, column=2, columnspan=2, sticky="nw", padx=3, pady=1) lbl_product_type = tk.Label(sales_details_container, text="Product Type: ", bg=self.clr_yellow) lbl_product_type.grid(row=5, column=1, sticky="nw", padx=3, pady=1) ety_product_type = tk.Entry(sales_details_container, textvariable=self.var_product_type, state='disabled') ety_product_type.grid(row=5, column=2, columnspan=2, sticky="nw", padx=3, pady=1) lbl_product_size = tk.Label(sales_details_container, text="Size: ", bg=self.clr_yellow) lbl_product_size.grid(row=6, column=1, sticky="nw", padx=3, pady=1) ety_product_size = tk.Entry(sales_details_container, width=12, textvariable=self.var_product_size, state='disabled') ety_product_size.grid(row=6, column=2, columnspan=2, sticky="nw", padx=3, pady=1) lbl_selling_price = tk.Label(sales_details_container, text="Price: ", bg=self.clr_yellow) lbl_selling_price.grid(row=7, column=1, sticky="nw", padx=3, pady=1) ety_selling_price = tk.Entry(sales_details_container, width=8, textvariable=self.var_selling_price, state='disabled') ety_selling_price.grid(row=7, column=2, sticky="nw", padx=3, pady=1) lbl_quantity = tk.Label(sales_details_container, text="Quantity: ", bg=self.clr_yellow) lbl_quantity.grid(row=8, column=1, sticky="nw", padx=3, pady=1) ety_quantity = tk.Entry(sales_details_container, width=5, textvariable=self.var_quantity, state='disabled') ety_quantity.grid(row=8, column=2, sticky="nw", padx=3, pady=1) # sales_stats_container element sales_stats_container.grid_columnconfigure(0, weight=1) sales_stats_container.grid_columnconfigure(3, weight=1) lbl_sales_stats = tk.Label(sales_stats_container, text="Sales Stats", bg=self.clr_blueiris, fg="white") lbl_sales_stats.grid(row=0, column=1, columnspan=2, sticky="news", padx=3, pady=5) lbl_sales_stats.config(font=("Calibri bold", 14)) lbl_from_date = tk.Label(sales_stats_container, text='From Date: ', bg=self.clr_yellow) lbl_from_date.grid(row=1, column=1, sticky="nw", padx=1, pady=5) self.sales_from_date = DateEntry(sales_stats_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2, width=10) self.sales_from_date.grid(row=1, column=2, sticky="sw", padx=2, pady=5, ipady=3) lbl_to_date = tk.Label(sales_stats_container, text='To Date: ', bg=self.clr_yellow) lbl_to_date.grid(row=2, column=1, sticky="nw", padx=1, pady=5) self.sales_to_date = DateEntry(sales_stats_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='back', borderwidth=2, width=10) self.sales_to_date.grid(row=2, column=2, sticky="sw", padx=2, pady=5, ipady=3) lbl_sold_quantity = tk.Label(sales_stats_container, text="Quantity: ", bg=self.clr_yellow) lbl_sold_quantity.grid(row=3, column=1, sticky="nw", padx=3, pady=5) ety_sold_quantity = tk.Entry(sales_stats_container, width=5, textvariable=self.var_sold_quantity, state='disabled') ety_sold_quantity.grid(row=3, column=2, sticky="nw", padx=3, pady=5) lbl_sales_amount = tk.Label(sales_stats_container, text="Amount: ", bg=self.clr_yellow) lbl_sales_amount.grid(row=4, column=1, sticky="nw", padx=3, pady=5) ety_sales_amount = tk.Entry(sales_stats_container, width=10, textvariable=self.var_sales_amount, state='disabled') ety_sales_amount.grid(row=4, column=2, sticky="nw", padx=3, pady=5) btn_get_sales_data = tk.Button(sales_stats_container, text="Get Sales Data", bg=self.clr_fuchsia, fg='white', command=self.get_sales_data) btn_get_sales_data.grid(row=5, column=1, columnspan=2, sticky="news", padx=2, pady=5) btn_get_sales_data.bind('<Return>', lambda event: self.get_sales_data(event)) def get_sales_data(self, event=None): from_date = self.sales_from_date.get() to_date = self.sales_to_date.get() sold_quantity, total_sales_amount = Sales.get_sales_data( from_date=from_date, to_date=to_date) if sold_quantity is None: sold_quantity = 0 if total_sales_amount is None: total_sales_amount = 0 self.var_sold_quantity.set(sold_quantity) self.var_sales_amount.set( format_currency(total_sales_amount, 'INR', locale='en_IN')) @staticmethod def validate_entry(event=None, length=0): if len(event.widget.get().strip()) == length: event.widget.tk_focusNext().focus() def filter_product(self, event=None): product_name = self.ety_filter_product_name.get().strip() product_type = self.ety_filter_product_type.get().strip() product_size = self.ety_filter_product_size.get().strip() selling_price = str(self.ety_filter_product_sell_price.get().strip()) if selling_price: selling_price = float(selling_price) else: selling_price = 0.0 if self.var_chk_include_date.get(): rows = Sales.search_sales(from_date=self.from_date.get(), to_date=self.to_date.get(), product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) else: rows = Sales.search_sales(product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) self.sales_tree.delete(*self.sales_tree.get_children()) sl_no = 0 for row in rows: product = row.Product sale = row.Sales sl_no = sl_no + 1 rw = (datetime.strftime(sale.sales_date, '%d-%b-%Y %H:%M:%S'), sale.bill_number, sale.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), sale.quantity) if sl_no % 2 == 0: self.sales_tree.insert("", tk.END, values=rw, tags=('evenrow', sale.product_code)) else: self.sales_tree.insert("", tk.END, values=rw, tags=('oddrow', sale.product_code)) def filter_bill_number(self, event=None): bill_number = self.ety_filter_bill_number.get().strip() if bill_number and bill_number != "": rows = Sales.search_bill_number(bill_number=bill_number) if len(rows) == 0: messagebox.showerror("SS Fashion Tuty", f"Bill_number: {bill_number} not found!") print(f"Bill_number: {bill_number} not found!") else: self.sales_tree.delete(*self.sales_tree.get_children()) sl_no = 0 for row in rows: product = row.Product sale = row.Sales sl_no = sl_no + 1 rw = (datetime.strftime(sale.sales_date, '%d-%b-%Y %H:%M:%S'), sale.bill_number, sale.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), sale.quantity) if sl_no % 2 == 0: self.sales_tree.insert("", tk.END, values=rw, tags=('evenrow', sale.product_code)) else: self.sales_tree.insert("", tk.END, values=rw, tags=('oddrow', sale.product_code)) else: self.reload_sales() def filter_product_code(self, event=None): product_code = f"{self.ety_filter_product_code_1.get().strip()}" \ f"-{self.ety_filter_product_code_2.get().strip()}" \ f"-{self.ety_filter_product_code_3.get().strip()}" \ f"-{self.ety_filter_product_code_4.get().strip()}" if product_code != "---": if self.var_chk_include_date.get(): rows = Sales.search_product_code( product_code=product_code, from_date=self.from_date.get(), to_date=self.to_date.get(), ) else: rows = Sales.search_product_code(product_code=product_code) if rows is None: messagebox.showerror( "SS Fashion Tuty", f"Product_code: {product_code} not found!") print(f"Product_code: {product_code} not found!") else: self.sales_tree.delete(*self.sales_tree.get_children()) sl_no = 0 for row in rows: product = row.Product sale = row.Sales sl_no = sl_no + 1 rw = (datetime.strftime(sale.sales_date, '%d-%b-%Y %H:%M:%S'), sale.bill_number, sale.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), sale.quantity) if sl_no % 2 == 0: self.sales_tree.insert("", tk.END, values=rw, tags=('evenrow', sale.product_code)) else: self.sales_tree.insert("", tk.END, values=rw, tags=('oddrow', sale.product_code)) def reload_sales(self): self.ety_filter_product_name.delete(0, tk.END) self.ety_filter_product_type.delete(0, tk.END) self.ety_filter_product_size.delete(0, tk.END) self.ety_filter_product_sell_price.delete(0, tk.END) self.ety_filter_product_code_1.delete(0, tk.END) self.ety_filter_product_code_2.delete(0, tk.END) self.ety_filter_product_code_3.delete(0, tk.END) self.ety_filter_product_code_4.delete(0, tk.END) self.ety_filter_bill_number.delete(0, tk.END) self.sales_tree.delete(*self.sales_tree.get_children()) rows = Sales.get_all_sales() sl_no = 0 for row in rows: product = row.Product sale = row.Sales sl_no = sl_no + 1 rw = (datetime.strftime(sale.sales_date, '%d-%b-%Y %H:%M:%S'), sale.bill_number, sale.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), sale.quantity) if sl_no % 2 == 0: self.sales_tree.insert("", tk.END, values=rw, tags=('evenrow', sale.product_code)) else: self.sales_tree.insert("", tk.END, values=rw, tags=('oddrow', sale.product_code)) def on_tree_select(self, event): self.selected_row = event.widget.selection() sales = self.sales_tree.item(self.selected_row)['values'] if sales: self.var_sales_date.set(sales[0]) self.var_bill_number.set(sales[1]) self.var_product_code.set(sales[2]) self.var_product_name.set(sales[3]) self.var_product_type.set(sales[4]) self.var_product_size.set(sales[5]) self.var_selling_price.set(sales[6]) self.var_quantity.set(sales[7])
class PurchaseReportForm(MainForm): def __init__(self): super().__init__() self.search_product_id = tk.StringVar() self.filter_ety_product_name = None self.filter_ety_product_type = None self.ety_search_product_id = None # local variables self.tree = None self.selected = list() self.product_name_list = list() self.product_type_list = list() self.load_view_report_form() def load_view_report_form(self): self.update_username() products = Product.get_product_name_list() for product in products: self.product_name_list.append(product.product_name) products = Product.get_product_type_list() for product in products: self.product_type_list.append(product.product_type) # ********** Sub Containers ********* left_container = tk.Frame(self.content_container, bd=5, padx=5, pady=5, relief=tk.RIDGE, bg='#62b6e2') left_container.pack(fill='both', expand=True, side=tk.LEFT) left_button_container = tk.Frame(left_container, relief=tk.RIDGE, bg='#62b6e2') left_button_container.pack(fill='both', expand=True, side=tk.TOP) search_container = tk.Frame(left_button_container, relief=tk.RIDGE, bg='#62b6e2') search_container.pack(fill='x', expand=True, side=tk.LEFT) filter_container = tk.Frame(left_button_container, relief=tk.RIDGE, bg='#62b6e2') filter_container.pack(fill='x', expand=True, side=tk.LEFT) # ********** left_search_container elements ********* search_lbl_product_id = tk.Label(search_container, text="ID: ", bg='#62b6e2') search_lbl_product_id.grid(row=0, column=0, sticky="nw", padx=1, pady=1) self.ety_search_product_id = tk.Entry( search_container, width=10, textvariable=self.search_product_id) self.ety_search_product_id.grid(row=1, column=0, sticky="nw", padx=2, pady=1, ipady=6) self.ety_search_product_id.bind( '<Return>', lambda event: self.search_report(event)) btn_search = tk.Button(search_container, text="Search", command=self.search_report) btn_search.grid(row=1, column=1, sticky="sw", padx=2, pady=1) filter_lbl_product_name = tk.Label(filter_container, text="Name: ", bg='#62b6e2') filter_lbl_product_name.grid(row=0, column=0, sticky="nw", padx=5, pady=5) self.filter_ety_product_name = AutocompleteEntry( filter_container, completevalues=self.product_name_list, state='disabled') self.filter_ety_product_name.grid(row=1, column=0, sticky="nw", padx=5, pady=5, ipady=6) self.filter_ety_product_name.bind( "<Return>", lambda event: self.filter_report(event)) filter_lbl_product_type = tk.Label(filter_container, text="Type: ", bg='#62b6e2') filter_lbl_product_type.grid(row=0, column=1, sticky="nw", padx=5, pady=5) self.filter_ety_product_type = AutocompleteEntry( filter_container, completevalues=self.product_type_list, state='disabled') self.filter_ety_product_type.grid(row=1, column=1, sticky="nw", padx=5, pady=5, ipady=6) self.filter_ety_product_type.grid(row=1, column=1, sticky="nw", padx=5, pady=5, ipady=6) self.filter_ety_product_type.bind( "<Return>", lambda event: self.filter_report(event)) btn_filter = tk.Button(filter_container, text="Apply Filter", command=self.filter_report, state='disabled') btn_filter.grid(row=1, column=2, sticky="sw", padx=2, pady=1) btn_clear_filter = tk.Button(filter_container, text="Clear Filter", command=self.reload_report) btn_clear_filter.grid(row=1, column=3, sticky="sw", padx=2, pady=1) btn_export = tk.Button(filter_container, text="Export to Excel", command=self.export_data) btn_export.grid(row=1, column=4, sticky="se", padx=15, pady=1) # ********** left_container ********* tree_container = tk.Frame(left_container, pady=3, bg='#62b6e2') tree_container.pack(fill='both', expand=True, side=tk.TOP) header = ('#', 'date', 'product_id', 'product_name', 'product_type', 'product_size', 'selling_price', 'actual_price', 'quantity', 'total_amount', 'dummy') self.tree = ttk.Treeview(tree_container, columns=header, show="headings", height=15, selectmode="browse") vsb = ttk.Scrollbar(tree_container, orient="vertical", command=self.tree.yview) hsb = ttk.Scrollbar(orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) style = ttk.Style() style.configure("Treeview.Heading", font=('Calibri', 12)) style.configure("Treeview", font=('Calibri', 12), rowheight=25) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.tree.grid(column=0, row=0, sticky='nsew', in_=tree_container) vsb.grid(column=1, row=0, sticky='ns', in_=tree_container) hsb.grid(column=0, row=1, sticky='ew', in_=tree_container) tree_container.grid_columnconfigure(0, weight=1) tree_container.grid_rowconfigure(0, weight=1) self.tree.heading("0", text="#") self.tree.heading("1", text="DATE") self.tree.heading("2", text="ID") self.tree.heading("3", text="PRODUCT_NAME") self.tree.heading("4", text="PRODUCT_TYPE") self.tree.heading("5", text="SIZE") self.tree.heading("6", text="SELL_PRICE") self.tree.heading("7", text="ACTUAL_PRICE") self.tree.heading("8", text="QTY") self.tree.heading("9", text="TOTAL_AMOUNT") self.tree.column(0, anchor='center', width="50") self.tree.column(1, anchor=tk.W, width="100") self.tree.column(2, anchor='center', width="50") self.tree.column(3, anchor=tk.W, width="150") self.tree.column(4, anchor=tk.W, width="200") self.tree.column(5, anchor='center', width="100") self.tree.column(6, anchor=tk.E, width="120") self.tree.column(7, anchor=tk.E, width="120") self.tree.column(8, anchor='center', width="80") self.tree.column(9, anchor=tk.E, width="120") self.tree.column(10, anchor='center', width="5") self.reload_report() btn_close = tk.Button(self.footer_container, text="Close", width='20', command=self.window.destroy) btn_close.pack(padx=5, pady=5) self.tree.tag_configure("evenrow", background='#fbefcc') self.tree.tag_configure("oddrow", background='white', foreground='black') self.tree.bind('<<TreeviewSelect>>', self.on_tree_select) def filter_report(self, event=None): product_name = self.filter_ety_product_name.get().strip() product_type = self.filter_ety_product_type.get().strip() rows = Stock.search_stock(product_name=product_name, product_type=product_type) self.tree.delete(*self.tree.get_children()) if len(rows): sl_no = 0 for row in rows: product = row.Product stock = row.Stock sl_no = sl_no + 1 quantity = "-" if stock: quantity = stock.quantity rw = (sl_no, product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), round(product.actual_price, 2), quantity) if sl_no % 2 == 0: self.tree.insert("", tk.END, values=rw, tags=('evenrow', product.product_code)) else: self.tree.insert("", tk.END, values=rw, tags=('oddrow', product.product_code)) else: pass def export_data(self): rows = self.tree.get_children() my_dict = defaultdict(list) for row in rows: my_dict["SL_NO"].append(self.tree.item(row)["values"][0]) my_dict["DATE"].append(self.tree.item(row)["values"][1]) my_dict["P_ID"].append(self.tree.item(row)["values"][2]) my_dict["PRODUCT_NAME"].append(self.tree.item(row)["values"][3]) my_dict["PRODUCT_TYPE"].append(self.tree.item(row)["values"][4]) my_dict["SIZE"].append(self.tree.item(row)["values"][5]) my_dict["SELL_PRICE"].append(self.tree.item(row)["values"][6]) my_dict["ACTUAL_PRICE"].append(self.tree.item(row)["values"][7]) my_dict["QUANTITY"].append(self.tree.item(row)["values"][8]) my_dict["TOTAL_AMOUNT"].append(self.tree.item(row)["values"][9]) my_dict = pd.DataFrame.from_dict(my_dict) try: my_dict.to_excel('SalesReport.xlsx', engine='xlsxwriter', index=False) except: print("Close the file than retry") def reload_report(self): self.filter_ety_product_name.delete(0, tk.END) self.filter_ety_product_type.delete(0, tk.END) self.tree.delete(*self.tree.get_children()) sales = Sales.sales_report_daily() sl_no = 0 for sale in sales: sl_no += 1 product = Product.get_product(sale.product_code) rw = (sl_no, sale.sales_date, product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), round(product.actual_price, 2), sale.quantity, round(product.selling_price * sale.quantity, 2)) if sl_no % 2 == 0: self.tree.insert("", tk.END, values=rw, tags=('evenrow', product.product_code)) else: self.tree.insert("", tk.END, values=rw, tags=('oddrow', product.product_code)) def search_report(self, event=None): product_id = self.search_product_id.get().strip() row = Stock.search_stock(product_id=product_id) if len(row): self.tree.selection_set(self.tree.tag_has(str(product_id))) self.tree.focus_set() self.tree.focus(self.selected) else: print('No items matched!') def on_tree_select(self, event): self.selected = event.widget.selection()
class ViewPurchaseForm(MainForm): def __init__(self): super().__init__() self.window.title("SS Fashion Tuty - View Purchase") # variables self.selected_row = list() self.garment_list = list() self.product_name_list = list() self.product_type_list = list() self.product_size_list = list() self.product_sell_price_list = list() # widgets self.from_date = None self.to_date = None self.ety_filter_product_code_1 = None self.ety_filter_product_code_2 = None self.ety_filter_product_code_3 = None self.ety_filter_product_code_4 = None self.ety_filter_garment_name = None self.ety_filter_product_name = None self.ety_filter_product_type = None self.ety_filter_product_size = None self.ety_filter_product_sell_price = None self.purchase_tree = None self.summary_tree = None # widget variables self.var_purchase_date = tk.StringVar() self.var_garment_name = tk.StringVar() self.var_product_code = tk.StringVar() self.var_product_name = tk.StringVar() self.var_product_type = tk.StringVar() self.var_product_size = tk.StringVar() self.var_selling_price = tk.DoubleVar() self.var_quantity = tk.IntVar() self.var_amount = tk.DoubleVar() self.var_include_date = tk.IntVar() self.var_search_product_code_1 = tk.StringVar() self.var_search_product_code_2 = tk.StringVar() self.var_search_product_code_3 = tk.StringVar() self.var_search_product_code_4 = tk.StringVar() self.var_total_quantity = tk.IntVar() self.var_total_amount = tk.StringVar() self.load_view_purchase_form() def load_view_purchase_form(self): for index in range(1, 9): self.menubar.entryconfig(index, state=tk.DISABLED) self.show_menu(MainForm.is_admin_user) self.update_username() self.reload_lookup() # ********** Sub Containers ********* top_container = tk.Frame(self.content_container, padx=2, pady=1, relief=tk.RIDGE, bg=self.clr_yellow) top_container.pack(fill='both', expand=True, side=tk.TOP) bottom_container = tk.Frame(self.content_container, padx=2, pady=1, relief=tk.RIDGE, bg=self.clr_yellow) bottom_container.pack(fill='both', expand=True, side=tk.TOP) # top_container elements top_button_container = tk.Frame(top_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) top_button_container.pack(fill='both', expand=True, side=tk.TOP) purchase_tree_container = tk.Frame(top_container, bd=2, pady=3, bg=self.clr_yellow, relief=tk.RIDGE) purchase_tree_container.pack(fill='both', expand=True, side=tk.TOP) # bottom_container elements purchase_details_container = tk.Frame(bottom_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) purchase_details_container.pack(fill='both', expand=True, side=tk.LEFT) purchase_summary_container = tk.Frame(bottom_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) purchase_summary_container.pack(fill='both', expand=True, anchor='w', side=tk.RIGHT) purchase_summary_tree_container = tk.Frame(bottom_container, bd=2, relief=tk.RIDGE, bg=self.clr_yellow) purchase_summary_tree_container.pack(fill='both', expand=True, side=tk.RIGHT) # ********** top_button_container elements ********* lbl_from_date = tk.Label(top_button_container, text='From Date:', bg=self.clr_yellow) lbl_from_date.grid(row=0, column=0, sticky="nw", padx=1, pady=1) self.from_date = DateEntry(top_button_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2, width=10) self.from_date.grid(row=1, column=0, sticky="sw", padx=2, pady=1, ipady=3) lbl_to_date = tk.Label(top_button_container, text='To Date:', bg=self.clr_yellow) lbl_to_date.grid(row=0, column=1, sticky="nw", padx=1, pady=1) self.to_date = DateEntry(top_button_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2, width=10) self.to_date.grid(row=1, column=1, sticky="sw", padx=2, pady=1, ipady=3) lbl_search_product_code = tk.Label(top_button_container, text="Product Code:", bg=self.clr_yellow) lbl_search_product_code.grid(row=0, column=2, columnspan=3, sticky="nw", padx=1, pady=1) self.ety_filter_product_code_1 = MaxLengthEntry(top_button_container, maxlength=3, width=4, textvariable=self.var_search_product_code_1) self.ety_filter_product_code_1.grid(row=1, column=2, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_1.bind('<Return>', lambda event: self.validate_entry(event, 3)) self.ety_filter_product_code_2 = MaxLengthEntry(top_button_container, maxlength=3, width=4, textvariable=self.var_search_product_code_2) self.ety_filter_product_code_2.grid(row=1, column=3, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_2.bind('<Return>', lambda event: self.validate_entry(event, 3)) self.ety_filter_product_code_3 = MaxLengthEntry(top_button_container, maxlength=2, width=3, textvariable=self.var_search_product_code_3) self.ety_filter_product_code_3.grid(row=1, column=4, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_3.bind('<Return>', lambda event: self.validate_entry(event, 2)) self.ety_filter_product_code_4 = MaxLengthEntry(top_button_container, maxlength=4, width=5, textvariable=self.var_search_product_code_4) self.ety_filter_product_code_4.grid(row=1, column=5, sticky="nw", padx=2, pady=2, ipady=5) self.ety_filter_product_code_4.bind('<Return>', lambda event: self.validate_entry(event, 4)) filter_lbl_garment_name = tk.Label(top_button_container, text="Garment Name:", bg=self.clr_yellow) filter_lbl_garment_name.grid(row=0, column=6, sticky="nw", padx=1, pady=1) self.ety_filter_garment_name = AutocompleteEntry(top_button_container, width=15, completevalues=self.garment_list) self.ety_filter_garment_name.grid(row=1, column=6, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_garment_name.bind("<Return>", lambda event: self.filter_purchase(event)) filter_lbl_product_name = tk.Label(top_button_container, text="Name:", bg=self.clr_yellow) filter_lbl_product_name.grid(row=0, column=7, sticky="nw", padx=1, pady=1) self.ety_filter_product_name = AutocompleteEntry(top_button_container, width=18, completevalues=self.product_name_list) self.ety_filter_product_name.grid(row=1, column=7, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_name.bind("<Return>", lambda event: self.filter_purchase(event)) filter_lbl_product_type = tk.Label(top_button_container, text="Type:", bg=self.clr_yellow) filter_lbl_product_type.grid(row=0, column=8, sticky="nw", padx=1, pady=1) self.ety_filter_product_type = AutocompleteEntry(top_button_container, width=20, completevalues=self.product_type_list) self.ety_filter_product_type.grid(row=1, column=8, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_type.bind("<Return>", lambda event: self.filter_purchase(event)) filter_lbl_product_size = tk.Label(top_button_container, text="Size:", bg=self.clr_yellow) filter_lbl_product_size.grid(row=0, column=9, sticky="nw", padx=1, pady=1) self.ety_filter_product_size = AutocompleteEntry(top_button_container, width=12, completevalues=self.product_size_list) self.ety_filter_product_size.grid(row=1, column=9, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_size.bind("<Return>", lambda event: self.filter_purchase(event)) filter_lbl_product_price = tk.Label(top_button_container, text="Price:", bg=self.clr_yellow) filter_lbl_product_price.grid(row=0, column=10, sticky="nw", padx=1, pady=1) self.ety_filter_product_sell_price = AutocompleteEntry(top_button_container, width=10, completevalues=self.product_sell_price_list) self.ety_filter_product_sell_price.grid(row=1, column=10, sticky="nw", padx=2, pady=1, ipady=6) self.ety_filter_product_sell_price.bind("<Return>", lambda event: self.filter_purchase(event)) chk_include_date = tk.Checkbutton(top_button_container, text='Include Date', variable=self.var_include_date, onvalue=1, offvalue=0, bg=self.clr_yellow) chk_include_date.grid(row=0, column=11, columnspan=2, sticky="sw", padx=2, pady=1) btn_filter = tk.Button(top_button_container, text="Apply Filter", bg=self.clr_fuchsia, fg='white', command=self.filter_purchase) btn_filter.grid(row=1, column=11, sticky="sw", padx=2, pady=1) btn_clear_filter = tk.Button(top_button_container, text="Clear", command=self.reload_purchase) btn_clear_filter.grid(row=1, column=12, sticky="news", padx=2, pady=1) # ********** tree_containers elements ********* header = ('#', 'PURCHASE_DATE', 'GARMENT_NAME', 'PRODUCT_CODE', 'PRODUCT_NAME', 'PRODUCT_TYPE', 'SIZE', 'PRICE', 'QTY', 'AMOUNT', '') self.purchase_tree = ttk.Treeview(purchase_tree_container, columns=header, height=8, show="headings", selectmode="browse") vsb = ttk.Scrollbar(purchase_tree_container, orient="vertical", command=self.purchase_tree.yview) hsb = ttk.Scrollbar(purchase_tree_container, orient="horizontal", command=self.purchase_tree.xview) self.purchase_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) style = ttk.Style() style.configure("Treeview.Heading", font=('Calibri', 12)) style.configure("Treeview", font=('Calibri', 12), rowheight=25) self.purchase_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.purchase_tree.grid(column=0, row=0, sticky='nsew', in_=purchase_tree_container) vsb.grid(column=1, row=0, sticky='ns', in_=purchase_tree_container) hsb.grid(column=0, row=1, sticky='ew', in_=purchase_tree_container) purchase_tree_container.grid_columnconfigure(0, weight=1) purchase_tree_container.grid_rowconfigure(0, weight=1) self.purchase_tree.heading("0", text="#") self.purchase_tree.heading("1", text="PURCHASE_DATE") self.purchase_tree.heading("2", text="GARMENT_NAME") self.purchase_tree.heading("3", text="PRODUCT_CODE") self.purchase_tree.heading("4", text="PRODUCT_NAME") self.purchase_tree.heading("5", text="PRODUCT_TYPE") self.purchase_tree.heading("6", text="SIZE") self.purchase_tree.heading("7", text="PRICE") self.purchase_tree.heading("8", text="QTY") self.purchase_tree.heading("9", text="AMOUNT") self.purchase_tree.column(0, anchor='center', width="20") self.purchase_tree.column(1, anchor=tk.W, width="120") self.purchase_tree.column(2, anchor=tk.W, width="200") self.purchase_tree.column(3, anchor=tk.W, width="120") self.purchase_tree.column(4, anchor=tk.W, width="140") self.purchase_tree.column(5, anchor=tk.W, width="180") self.purchase_tree.column(6, anchor='center', width="80") self.purchase_tree.column(7, anchor=tk.E, width="80") self.purchase_tree.column(8, anchor='center', width="50") self.purchase_tree.column(9, anchor=tk.E, width="120") self.purchase_tree.column(10, anchor='center', width="2") self.reload_purchase() numeric_cols = ['#', 'PRICE', 'QTY', 'AMOUNT'] for col in header: if col in numeric_cols: self.purchase_tree.heading(col, text=col, command=lambda _col=col: self.sort_treeview( self.purchase_tree, _col, numeric_sort=True, reverse=False)) else: self.purchase_tree.heading(col, text=col, command=lambda _col=col: self.sort_treeview( self.purchase_tree, _col, numeric_sort=False, reverse=False)) self.purchase_tree.tag_configure("evenrow", background='#fbefcc') self.purchase_tree.tag_configure("oddrow", background='white', foreground='black') self.purchase_tree.bind('<<TreeviewSelect>>', self.on_tree_select) # ********** Purchase Details ********* purchase_details_container.grid_columnconfigure(0, weight=1) purchase_details_container.grid_columnconfigure(3, weight=1) lbl_purchase_details = tk.Label(purchase_details_container, text="Product Details", bg=self.clr_blueiris, fg="white") lbl_purchase_details.grid(row=0, column=1, columnspan=2, sticky="news", padx=3, pady=3) lbl_purchase_details.config(font=("Calibri bold", 12)) lbl_purchase_date = tk.Label(purchase_details_container, text="Purchase Date: ", bg=self.clr_yellow) lbl_purchase_date.grid(row=1, column=1, sticky="nw", padx=3, pady=1) ety_purchase_date = tk.Entry(purchase_details_container, width=15, textvariable=self.var_purchase_date, state='disabled') ety_purchase_date.grid(row=1, column=2, sticky="nw", padx=3, pady=1) lbl_garment_name = tk.Label(purchase_details_container, text="Garment Name: ", bg=self.clr_yellow) lbl_garment_name.grid(row=2, column=1, sticky="nw", padx=3, pady=1) ety_garment_name = tk.Entry(purchase_details_container, textvariable=self.var_garment_name, state='disabled') ety_garment_name.grid(row=2, column=2, sticky="nw", padx=3, pady=1) lbl_product_code = tk.Label(purchase_details_container, text="Product Code: ", bg=self.clr_yellow) lbl_product_code.grid(row=3, column=1, sticky="nw", padx=3, pady=1) ety_product_code = tk.Entry(purchase_details_container, width=15, textvariable=self.var_product_code, state='disabled') ety_product_code.grid(row=3, column=2, sticky="nw", padx=3, pady=1) lbl_product_name = tk.Label(purchase_details_container, text="Product Name: ", bg=self.clr_yellow) lbl_product_name.grid(row=4, column=1, sticky="nw", padx=3, pady=1) ety_product_name = tk.Entry(purchase_details_container, textvariable=self.var_product_name, state='disabled') ety_product_name.grid(row=4, column=2, sticky="nw", padx=3, pady=1) lbl_product_type = tk.Label(purchase_details_container, text="Product Type: ", bg=self.clr_yellow) lbl_product_type.grid(row=5, column=1, sticky="nw", padx=3, pady=1) ety_product_type = tk.Entry(purchase_details_container, textvariable=self.var_product_type, state='disabled') ety_product_type.grid(row=5, column=2, sticky="nw", padx=3, pady=1) lbl_product_size = tk.Label(purchase_details_container, text="Size: ", bg=self.clr_yellow) lbl_product_size.grid(row=6, column=1, sticky="nw", padx=3, pady=1) ety_product_size = tk.Entry(purchase_details_container, width=10, textvariable=self.var_product_size, state='disabled') ety_product_size.grid(row=6, column=2, sticky="nw", padx=3, pady=1) lbl_selling_price = tk.Label(purchase_details_container, text="Price: ", bg=self.clr_yellow) lbl_selling_price.grid(row=7, column=1, sticky="nw", padx=3, pady=1) ety_selling_price = tk.Entry(purchase_details_container, width=10, textvariable=self.var_selling_price, state='disabled') ety_selling_price.grid(row=7, column=2, sticky="nw", padx=3, pady=1) lbl_quantity = tk.Label(purchase_details_container, text="Quantity: ", bg=self.clr_yellow) lbl_quantity.grid(row=8, column=1, sticky="nw", padx=3, pady=1) ety_quantity = tk.Entry(purchase_details_container, width=5, textvariable=self.var_quantity, state='disabled') ety_quantity.grid(row=8, column=2, sticky="nw", padx=3, pady=1) lbl_amount = tk.Label(purchase_details_container, text="Amount: ", bg=self.clr_yellow) lbl_amount.grid(row=9, column=1, sticky="nw", padx=3, pady=1) ety_amount = tk.Entry(purchase_details_container, width=10, textvariable=self.var_amount, state='disabled') ety_amount.grid(row=9, column=2, sticky="nw", padx=3, pady=1) purchase_summary_container.grid_columnconfigure(0, weight=1) purchase_summary_container.grid_columnconfigure(2, weight=1) lbl_purchase_summary = tk.Label(purchase_summary_container, text="Purchase Summary", bg=self.clr_blueiris, fg="white") lbl_purchase_summary.grid(row=0, column=1, sticky="news", padx=3, pady=3) lbl_purchase_summary.config(font=("Calibri bold", 14)) lbl_purchase_date = tk.Label(purchase_summary_container, text="Purchase Date:", bg=self.clr_yellow) lbl_purchase_date.grid(row=1, column=1, sticky="nw", padx=3, pady=1) ety_purchase_date = tk.Entry(purchase_summary_container, width=12, textvariable=self.var_purchase_date, state='disabled') ety_purchase_date.grid(row=2, column=1, sticky="nw", padx=3, pady=1, ipady=6) lbl_total_quantity = tk.Label(purchase_summary_container, text="Total Quantity:", bg=self.clr_yellow) lbl_total_quantity.grid(row=3, column=1, sticky="nw", padx=3, pady=1) ety_total_quantity = tk.Entry(purchase_summary_container, width=12, textvariable=self.var_total_quantity, state='disabled') ety_total_quantity.grid(row=4, column=1, sticky="nw", padx=3, pady=1, ipady=6) lbl_total_amount = tk.Label(purchase_summary_container, text="Total Amount:", bg=self.clr_yellow) lbl_total_amount.grid(row=5, column=1, sticky="nw", padx=3, pady=1) ety_total_amount = tk.Entry(purchase_summary_container, width=12, textvariable=self.var_total_amount, state='disabled') ety_total_amount.grid(row=6, column=1, sticky="nw", padx=3, pady=1, ipady=6) self.var_total_amount.set(format_currency(0, 'INR', locale='en_IN')) btn_get_purchase_summary = tk.Button(purchase_summary_container, text="Get Purchase Summary", bg=self.clr_fuchsia, fg='white', command=self.get_purchase_summary) btn_get_purchase_summary.grid(row=7, column=1, sticky="news", padx=3, pady=10) # monthly_summary_tree_container summary_tree = tk.Frame(purchase_summary_tree_container, pady=1, relief=tk.RIDGE, bg=self.clr_yellow) summary_tree.pack(fill='both', expand=True, side=tk.RIGHT) header = ('#', 'PRODUCT_CODE', 'PRODUCT', 'TYPE', 'SIZE', 'PRICE', 'QTY', 'AMOUNT', '') self.summary_tree = ttk.Treeview(summary_tree, columns=header, height=5, show="headings", selectmode="browse") vsb = ttk.Scrollbar(summary_tree, orient="vertical", command=self.summary_tree.yview) hsb = ttk.Scrollbar(summary_tree, orient="horizontal", command=self.summary_tree.xview) self.summary_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.summary_tree.grid(column=0, row=0, sticky='nsew') vsb.grid(column=1, row=0, sticky='ns') hsb.grid(column=0, row=1, sticky='ew') summary_tree.grid_columnconfigure(0, weight=1) summary_tree.grid_rowconfigure(0, weight=1) self.summary_tree.heading("0", text="#") self.summary_tree.heading("1", text="PRODUCT_CODE") self.summary_tree.heading("2", text="PRODUCT") self.summary_tree.heading("3", text="TYPE") self.summary_tree.heading("4", text="SIZE") self.summary_tree.heading("5", text="PRICE") self.summary_tree.heading("6", text="QTY") self.summary_tree.heading("7", text="AMOUNT") self.summary_tree.heading("8", text="") self.summary_tree.column(0, anchor='center', minwidth=30, width=30) self.summary_tree.column(1, anchor=tk.W, minwidth=50, width=120) self.summary_tree.column(2, anchor=tk.W, minwidth=80, width=100) # Product self.summary_tree.column(3, anchor=tk.W, minwidth=130, width=130) # Type self.summary_tree.column(4, anchor='center', minwidth=50, width=50) # Size self.summary_tree.column(5, anchor=tk.E, minwidth=60, width=60) # Price self.summary_tree.column(6, anchor='center', minwidth=40, width=40) # Qty self.summary_tree.column(7, anchor=tk.E, minwidth=80, width=80) # Amount self.summary_tree.column(8, anchor='center', width=1) self.summary_tree["displaycolumns"] = (0, 1, 2, 3, 4, 5, 6, 7, 8) numeric_cols = ['#', 'PRICE', 'QTY', 'AMOUNT'] for col in header: if col in numeric_cols: self.summary_tree.heading(col, text=col, command=lambda _col=col: self.sort_treeview( self.summary_tree, _col, numeric_sort=True, reverse=False)) else: self.summary_tree.heading(col, text=col, command=lambda _col=col: self.sort_treeview( self.summary_tree, _col, numeric_sort=False, reverse=False)) self.summary_tree.tag_configure("evenrow", background='#fbefcc') self.summary_tree.tag_configure("oddrow", background='white', foreground='black') def get_purchase_summary(self): selected_row = self.purchase_tree.item(self.purchase_tree.selection())['values'] if selected_row: sel_purchase_date = str(datetime.strptime(selected_row[1], '%d-%b-%Y'))[:10] sel_garment_name = selected_row[2] rows = Purchase.get_purchase_summary(purchase_date=sel_purchase_date, garment_name=sel_garment_name) self.summary_tree.delete(*self.summary_tree.get_children()) if rows: row_num = 0 total_quantity = 0 total_amount = 0.0 for row in rows: row_num += 1 purchase, product = row rw = ( row_num, purchase.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), purchase.quantity, round(product.selling_price * purchase.quantity, 2)) total_quantity = total_quantity + int(purchase.quantity) total_amount = total_amount + float(product.selling_price * purchase.quantity) if row_num % 2 == 0: self.summary_tree.insert("", tk.END, values=rw, tags=('evenrow', product.product_code)) else: self.summary_tree.insert("", tk.END, values=rw, tags=('oddrow', product.product_code)) self.var_total_quantity.set(total_quantity) self.var_total_amount.set(format_currency(total_amount, 'INR', locale='en_IN')) def reload_lookup(self): garments = Purchase.get_all_garment_name() for garment in garments: self.garment_list.append(garment.garment_name) products = LkpProductName.get_all_product_names() for product in products: self.product_name_list.append(product.product_name) products = LkpProductType.get_all_product_types() for product in products: self.product_type_list.append(product.product_type) products = LkpProductSize.get_all_product_sizes() for product in products: self.product_size_list.append(product.product_size) products = Product.get_product_sell_price_list() for product in products: self.product_sell_price_list.append(str(round(product.selling_price, 2))) @staticmethod def validate_entry(event=None, length=0): if len(event.widget.get().strip()) == length: event.widget.tk_focusNext().focus() def filter_purchase(self, event=None): product_code = f"{self.ety_filter_product_code_1.get().strip()}" \ f"-{self.ety_filter_product_code_2.get().strip()}" \ f"-{self.ety_filter_product_code_3.get().strip()}" \ f"-{self.ety_filter_product_code_4.get().strip()}" garment_name = self.ety_filter_garment_name.get().strip() product_name = self.ety_filter_product_name.get().strip() product_type = self.ety_filter_product_type.get().strip() product_size = self.ety_filter_product_size.get().strip() selling_price = str(self.ety_filter_product_sell_price.get().strip()) product_code = product_code.replace("---", "") # if product code is not entered if selling_price: selling_price = float(selling_price) else: selling_price = 0.0 if product_code == "" and garment_name == "" and product_name == "" and product_type == "" \ and product_size == "" and selling_price == 0.0 and not self.var_include_date.get(): self.reload_purchase() else: if self.var_include_date.get(): rows = Purchase.search_purchase(from_date=self.from_date.get(), to_date=self.to_date.get(), product_code=product_code, garment_name=garment_name, product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) else: rows = Purchase.search_purchase(product_code=product_code, garment_name=garment_name, product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) self.purchase_tree.delete(*self.purchase_tree.get_children()) if rows: row_num = 0 for row in rows: row_num += 1 purchase, product = row purchase_date = datetime.strftime(purchase.purchase_date, '%d-%b-%Y') rw = ( row_num, purchase_date, purchase.garment_name, purchase.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), purchase.quantity, round(product.selling_price * purchase.quantity, 2)) if row_num % 2 == 0: self.purchase_tree.insert("", tk.END, values=rw, tags=('evenrow', product.product_code)) else: self.purchase_tree.insert("", tk.END, values=rw, tags=('oddrow', product.product_code)) else: pass def reload_purchase(self): self.var_include_date.set(0) self.ety_filter_product_code_1.delete(0, tk.END) self.ety_filter_product_code_2.delete(0, tk.END) self.ety_filter_product_code_3.delete(0, tk.END) self.ety_filter_product_code_4.delete(0, tk.END) self.ety_filter_garment_name.delete(0, tk.END) self.ety_filter_product_name.delete(0, tk.END) self.ety_filter_product_type.delete(0, tk.END) self.ety_filter_product_size.delete(0, tk.END) self.ety_filter_product_sell_price.delete(0, tk.END) self.purchase_tree.delete(*self.purchase_tree.get_children()) rows = Purchase.get_all_purchase() row_num = 0 for row in rows: row_num += 1 purchase, product = row purchase_date = datetime.strftime(purchase.purchase_date, '%d-%b-%Y') rw = (row_num, purchase_date, purchase.garment_name, purchase.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), purchase.quantity, round(product.selling_price * purchase.quantity, 2)) if row_num % 2 == 0: self.purchase_tree.insert("", tk.END, values=rw, tags=('evenrow', product.product_code)) else: self.purchase_tree.insert("", tk.END, values=rw, tags=('oddrow', product.product_code)) def on_tree_select(self, event): self.selected_row = event.widget.selection() purchase = self.purchase_tree.item(self.selected_row)['values'] if purchase: self.var_purchase_date.set(purchase[1]) self.var_garment_name.set(purchase[2]) self.var_product_code.set(purchase[3]) self.var_product_name.set(purchase[4]) self.var_product_type.set(purchase[5]) self.var_product_size.set(purchase[6]) self.var_selling_price.set(purchase[7]) self.var_quantity.set(purchase[8]) self.var_amount.set(purchase[9])
class AddPurchaseForm(MainForm): def __init__(self): super().__init__() self.window.title("SS Fashion Tuty - Add Purchase") # variables self.select_first_row_threshold = 10 self.selected_row = list() self.product_name_list = list() self.product_type_list = list() self.product_size_list = list() self.product_sell_price_list = list() self.product_category_list = list() self.product_actual_price_list = list() self.purchase_counter = 0 # widgets self.filter_ety_product_name = None self.filter_ety_product_type = None self.filter_ety_product_size = None self.filter_ety_product_sell_price = None self.filter_ety_product_actual_price = None self.cbo_product_category = None self.products_tree = None self.purchase_tree = None self.purchase_date = None self.ety_garment_name = None self.qty_window = None # widget variables self.var_product_code = tk.StringVar() self.var_product_name = tk.StringVar() self.var_product_type = tk.StringVar() self.var_product_size = tk.StringVar() self.var_selling_price = tk.DoubleVar() self.var_actual_price = tk.DoubleVar() self.var_purchase_amount = tk.StringVar() self.var_purchase_quantity = tk.IntVar() self.var_available_quantity = tk.IntVar() self.var_quantity = tk.IntVar(value=1) self.load_add_purchase_form() # shortcuts self.window.bind("<F3>", lambda event: self.copy_to_new(event)) self.window.bind("<F4>", lambda event: self.add_new_product(event)) self.window.bind("<F5>", lambda event: self.filter_product(event)) self.window.bind("<F1>", lambda event: self.select_first_row(event)) def load_add_purchase_form(self): for index in range(1, 9): self.menubar.entryconfig(index, state=tk.DISABLED) self.show_menu(MainForm.is_admin_user) self.update_username() products = LkpProductName.get_all_product_names() for product in products: self.product_name_list.append(product.product_name) products = LkpProductType.get_all_product_types() for product in products: self.product_type_list.append(product.product_type) products = LkpProductSize.get_all_product_sizes() for product in products: self.product_size_list.append(product.product_size) products = Product.get_product_sell_price_list() for product in products: self.product_sell_price_list.append( str(round(product.selling_price, 2))) categories = ProductCategory.get_all_categories() for category in categories: self.product_category_list.append(category.category) # ********** Sub Containers ********* left_container = tk.Frame(self.content_container, bd=5, padx=5, pady=2, relief=tk.RIDGE, bg=self.clr_yellow) left_container.pack(fill='both', expand=True, side=tk.LEFT) right_container = tk.Frame(self.content_container, bd=5, padx=5, pady=5, relief=tk.RIDGE, bg=self.clr_yellow) right_container.pack(fill='both', expand=True, side=tk.RIGHT) # left_container elements left_top_button_container = tk.Frame(left_container, relief=tk.RIDGE, bg=self.clr_yellow) left_top_button_container.pack(fill='both', expand=True, side=tk.TOP) products_tree_container = tk.Frame(left_container, pady=3, bg=self.clr_yellow, relief=tk.RIDGE) products_tree_container.pack(fill='both', expand=True, side=tk.TOP) # right_container elements right_top_button_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_top_button_container.pack(fill='both', expand=True, side=tk.TOP) right_tree_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_tree_container.pack(fill='both', expand=True, side=tk.TOP) right_bottom_button_container = tk.Frame(right_container, relief=tk.RIDGE, bg=self.clr_yellow) right_bottom_button_container.pack(fill='both', expand=True, side=tk.TOP) # ********** left_search_container elements ********* filter_lbl_product_name = tk.Label(left_top_button_container, text="Name: ", bg=self.clr_yellow) filter_lbl_product_name.grid(row=0, column=0, sticky="nw", padx=1, pady=1) self.filter_ety_product_name = AutocompleteEntry( left_top_button_container, width=15, completevalues=self.product_name_list) self.filter_ety_product_name.grid(row=1, column=0, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_name.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_type = tk.Label(left_top_button_container, text="Type: ", bg=self.clr_yellow) filter_lbl_product_type.grid(row=0, column=1, sticky="nw", padx=1, pady=1) self.filter_ety_product_type = AutocompleteEntry( left_top_button_container, width=18, completevalues=self.product_type_list) self.filter_ety_product_type.grid(row=1, column=1, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_type.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_size = tk.Label(left_top_button_container, text="Size: ", bg=self.clr_yellow) filter_lbl_product_size.grid(row=0, column=2, sticky="nw", padx=1, pady=1) self.filter_ety_product_size = AutocompleteEntry( left_top_button_container, width=12, completevalues=self.product_size_list) self.filter_ety_product_size.grid(row=1, column=2, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_size.bind( "<Return>", lambda event: self.filter_product(event)) filter_lbl_product_price = tk.Label(left_top_button_container, text="Sell Price: ", bg=self.clr_yellow) filter_lbl_product_price.grid(row=0, column=3, sticky="nw", padx=1, pady=1) self.filter_ety_product_sell_price = AutocompleteEntry( left_top_button_container, width=8, completevalues=self.product_sell_price_list) self.filter_ety_product_sell_price.grid(row=1, column=3, sticky="nw", padx=2, pady=1, ipady=6) self.filter_ety_product_sell_price.bind( "<Return>", lambda event: self.filter_product(event)) # filter_lbl_product_actual_price = tk.Label(left_top_button_container, text="Act. Price: ", bg=self.clr_yellow) # filter_lbl_product_actual_price.grid(row=0, column=4, sticky="nw", padx=1, pady=1) # self.filter_ety_product_actual_price = AutocompleteEntry(left_top_button_container, width=8, # completevalues=self.product_actual_price_list) # self.filter_ety_product_actual_price.grid(row=1, column=4, sticky="nw", padx=2, pady=1, ipady=6) # self.filter_ety_product_actual_price.bind("<Return>", lambda event: self.filter_product(event)) lbl_product_category = tk.Label(left_top_button_container, text="Category:", bg=self.clr_yellow) lbl_product_category.grid(row=0, column=4, sticky="nw", padx=1, pady=1) self.cbo_product_category = ttk.Combobox( left_top_button_container, width=7, values=self.product_category_list) self.cbo_product_category.grid(row=1, column=4, sticky="nw", padx=2, pady=1, ipady=6) btn_filter = tk.Button(left_top_button_container, text="Apply Filter [F5]", bg=self.clr_fuchsia, fg='white', command=self.filter_product) btn_filter.grid(row=1, column=5, sticky="news", padx=2, pady=1) btn_clear_filter = tk.Button(left_top_button_container, text="Clear", command=self.reload_products) btn_clear_filter.grid(row=1, column=6, sticky="news", padx=2, pady=1) btn_add_new = tk.Button(left_top_button_container, text="Add New [F4]", bg=self.clr_limegreen, command=self.add_new_product) btn_add_new.grid(row=0, column=5, sticky="news", padx=1, pady=1) btn_copy = tk.Button(left_top_button_container, text="Copy [F3]", bg=self.clr_blueiris, fg='white', command=self.copy_to_new) btn_copy.grid(row=0, column=6, sticky="news", padx=1, pady=1) # ********** tree_containers elements ********* header = ('CODE', 'PRODUCT_NAME', 'PRODUCT_TYPE', 'SIZE', 'PRICE', 'QTY', '') self.products_tree = ttk.Treeview(products_tree_container, columns=header, height=20, show="headings", selectmode="browse") vsb = ttk.Scrollbar(products_tree_container, orient="vertical", command=self.products_tree.yview) hsb = ttk.Scrollbar(products_tree_container, orient="horizontal", command=self.products_tree.xview) style = ttk.Style() style.configure("Treeview.Heading", font=('Calibri', 12)) style.configure("Treeview", font=('Calibri', 10), rowheight=25) self.products_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.products_tree.grid(column=0, row=0, sticky='nsew', in_=products_tree_container) vsb.grid(column=1, row=0, sticky='ns', in_=products_tree_container) hsb.grid(column=0, row=1, sticky='ew', in_=products_tree_container) products_tree_container.grid_columnconfigure(0, weight=1) products_tree_container.grid_rowconfigure(0, weight=1) self.products_tree.heading("0", text="CODE") self.products_tree.heading("1", text="PRODUCT_NAME") self.products_tree.heading("2", text="PRODUCT_TYPE") self.products_tree.heading("3", text="SIZE") self.products_tree.heading("4", text="PRICE") self.products_tree.heading("5", text="QTY") self.products_tree.column(0, anchor='center', width="100") self.products_tree.column(1, anchor=tk.W, width="120") self.products_tree.column(2, anchor=tk.W, width="150") self.products_tree.column(3, anchor='center', width="50") self.products_tree.column(4, anchor=tk.E, width="50") self.products_tree.column(5, anchor='center', width="20") self.products_tree.column(6, anchor='center', width="1") self.products_tree.bind("<F3>", lambda event: self.copy_to_new(event)) self.reload_products() numeric_cols = ['PRICE', 'QTY'] for col in header: if col in numeric_cols: self.products_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.products_tree, _col, numeric_sort=True, reverse=False)) else: self.products_tree.heading(col, text=col, command=lambda _col=col: self. sort_treeview(self.products_tree, _col, numeric_sort=False, reverse=False)) # ********** Right Tree Details ********* lbl_purchase_date = tk.Label(right_top_button_container, text='Purchase Date: ', bg=self.clr_yellow) lbl_purchase_date.grid(row=0, column=0, sticky="nw", padx=1, pady=1) self.purchase_date = DateEntry(right_top_button_container, date_pattern='yyyy-mm-dd', background='yellow', foreground='black', borderwidth=2) self.purchase_date.grid(row=1, column=0, sticky="nw", padx=2, pady=1, ipady=3) lbl_garment_name = tk.Label(right_top_button_container, text='Garment Name: ', bg=self.clr_yellow) lbl_garment_name.grid(row=0, column=1, sticky="nw", padx=1, pady=1) self.ety_garment_name = tk.Entry(right_top_button_container) self.ety_garment_name.grid(row=1, column=1, sticky="nw", padx=2, pady=1, ipady=3) btn_add_purchase = tk.Button(right_top_button_container, text="Add Purchase", bg=self.clr_fuchsia, fg='white', command=self.add_purchase) btn_add_purchase.grid(row=0, column=2, rowspan=2, sticky="se", padx=2, pady=1) btn_clear = tk.Button(right_top_button_container, text="Clear", command=self.clear_all) btn_clear.grid(row=0, column=3, rowspan=2, sticky="se", padx=2, pady=1) purchase_tree_container = tk.Frame(right_tree_container, pady=1, relief=tk.RIDGE, bg=self.clr_yellow) purchase_tree_container.pack(fill='both', expand=True, side=tk.RIGHT) header = ('#', 'product_code', 'product_name', 'type', 'size', 'selling_price', 'quantity', 'amount', 'dummy') self.purchase_tree = ttk.Treeview(purchase_tree_container, columns=header, height=15, show="headings", selectmode="browse") vsb = ttk.Scrollbar(purchase_tree_container, orient="vertical", command=self.purchase_tree.yview) hsb = ttk.Scrollbar(purchase_tree_container, orient="horizontal", command=self.purchase_tree.xview) self.purchase_tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.purchase_tree.grid(column=0, row=0, sticky='nsew') vsb.grid(column=1, row=0, sticky='ns') hsb.grid(column=0, row=1, sticky='ew') purchase_tree_container.grid_columnconfigure(0, weight=1) purchase_tree_container.grid_rowconfigure(0, weight=1) self.purchase_tree.heading("0", text="#") self.purchase_tree.heading("1", text="Code") self.purchase_tree.heading("2", text="Product") self.purchase_tree.heading("3", text="Type") self.purchase_tree.heading("4", text="Size") self.purchase_tree.heading("5", text="Price") self.purchase_tree.heading("6", text="Qty") self.purchase_tree.heading("7", text="Amount") self.purchase_tree.heading("8", text="") self.purchase_tree.column(0, anchor='center', minwidth=25, width=25) self.purchase_tree.column(1, anchor=tk.W, minwidth=40, width=110) self.purchase_tree.column(2, anchor=tk.W, minwidth=80, width=100) # Product self.purchase_tree.column(3, anchor=tk.W, minwidth=110, width=110) # Type self.purchase_tree.column(4, anchor='center', minwidth=50, width=50) # Size self.purchase_tree.column(5, anchor=tk.E, minwidth=50, width=50) # Price self.purchase_tree.column(6, anchor='center', minwidth=40, width=40) # Qty self.purchase_tree.column(7, anchor=tk.E, minwidth=60, width=60) # Amount self.purchase_tree.column(8, anchor='center', width=1) self.purchase_tree["displaycolumns"] = (0, 1, 2, 3, 4, 5, 6, 7, 8) self.purchase_tree.bind('<Double-1>', lambda event: self.remove_product(event)) self.products_tree.tag_configure("evenrow_active", background='#fbefcc') self.products_tree.tag_configure("oddrow_active", background='white', foreground='black') self.products_tree.tag_configure("evenrow_inactive", background='#fbefcc', foreground='red') self.products_tree.tag_configure("oddrow_inactive", background='white', foreground='red') self.products_tree.bind('<<TreeviewSelect>>', self.on_tree_select) self.products_tree.bind('<Double-1>', lambda event: self.get_quantity(event)) self.products_tree.bind('<Return>', lambda event: self.get_quantity(event)) # ********** bottom_button_container elements ********* lbl_purchase_quantity = tk.Label( right_bottom_button_container, fg=self.clr_limegreen, relief=tk.RAISED, textvariable=self.var_purchase_quantity) lbl_purchase_quantity.pack(side=tk.LEFT, fill='x', expand=True, padx=1, pady=1) lbl_purchase_quantity.config(font=("calibri bold", 30)) lbl_purchase_amount = tk.Label(right_bottom_button_container, fg=self.clr_blueiris, relief=tk.RAISED, textvariable=self.var_purchase_amount) lbl_purchase_amount.pack(side=tk.LEFT, fill='x', expand=True, padx=1, pady=1) lbl_purchase_amount.config(font=("calibri bold", 30)) def remove_product(self, event): selected_row = event.widget.selection()[0] self.purchase_tree.delete(selected_row) self.purchase_counter = 0 for child in self.purchase_tree.get_children(): self.purchase_counter = self.purchase_counter + 1 row = self.purchase_tree.item(child)["values"] row[0] = self.purchase_counter self.purchase_tree.delete(child) self.purchase_tree.insert("", tk.END, values=row) self.calculate_total_amount_and_quantity() def select_first_row(self, event=None): element_id = self.products_tree.get_children()[0] self.products_tree.focus_set() self.products_tree.focus(element_id) self.products_tree.selection_set(element_id) def copy_to_new(self, event=None): if self.selected_row: product = self.products_tree.item(self.selected_row)['values'] if product: self.filter_ety_product_name.delete(0, tk.END) self.filter_ety_product_name.insert(0, product[1]) self.filter_ety_product_type.delete(0, tk.END) self.filter_ety_product_type.insert(0, product[2]) self.filter_ety_product_size.delete(0, tk.END) self.filter_ety_product_size.insert(0, product[3]) self.filter_ety_product_sell_price.delete(0, tk.END) self.filter_ety_product_sell_price.insert(0, product[4]) product_category = ProductCategory.get_category_by_code( product[0][:3]) self.cbo_product_category.current( self.product_category_list.index(product_category)) def add_new_product(self, event=None): product_name = self.filter_ety_product_name.get().strip() product_type = self.filter_ety_product_type.get().strip() product_size = self.filter_ety_product_size.get().strip() product_category = self.cbo_product_category.get().strip() try: selling_price = round( float(self.filter_ety_product_sell_price.get().strip()), 2) except (ValueError, TclError): selling_price = 0.0 try: actual_price = round(self.var_actual_price.get(), 2) except TclError: actual_price = 0.0 if len(product_name) == 0: messagebox.showerror("SS Fashion Tuty", f"Product_Name is missing!") print(f"Product_Name is missing!") return if selling_price == "" or selling_price <= 0: messagebox.showerror("SS Fashion Tuty", f"Selling Price is missing!") print(f"selling price is missing!") return if product_category == "" or product_category is None: messagebox.showerror("SS Fashion Tuty", f"Category is missing!") print(f"Category is missing!") return if len(product_type) == 0: product_type = "-" if len(product_size) == 0: product_size = "-" existing_product_category = LkpProductName.get_product_category( product_name=product_name) if existing_product_category and product_category != existing_product_category: print( f"'{product_name}' already in '{existing_product_category}' category!" ) messagebox.showerror( "SS Fashion Tuty", f"'{product_name}' already in '{existing_product_category}' category!" f"\nPlease rename the Product Name and try again!") return product_name_code = LkpProductName.get_code(product_name=product_name) if product_name_code is None: product_name_code = LkpProductName.create_lookup( product_name, product_category) product_type_code = LkpProductType.get_code(product_type=product_type) if product_type_code is None: product_type_code = LkpProductType.create_lookup(product_type) product_size_code = LkpProductSize.get_code(product_size=product_size) if product_size_code is None: product_size_code = LkpProductSize.create_lookup(product_size) product_price_code = str(int(selling_price)).zfill(4) product_code = f"{product_name_code}-{product_type_code}-{product_size_code}-{product_price_code}" product = (product_code, product_name, product_type, product_size, selling_price, actual_price) product_list = Product.search_products(product_code, product_name, product_type, product_size, selling_price) if product_list: print(f"Product: '{product}' is already exists!") messagebox.showerror( "SS Fashion Tuty", f"Product already exists! \nProduct_Code: {product_code}") else: Product.add_product(product) self.reload_products() print(f"Product: {product} is added!") product = Product.search_products(product_code=product_code) if product: self.products_tree.selection_set( self.products_tree.tag_has(product.product_code)) self.products_tree.focus_set() self.products_tree.event_generate('<Return>') def add_purchase(self): purchase_date = datetime.strptime(self.purchase_date.get(), "%Y-%m-%d") garment_name = self.ety_garment_name.get().strip() if garment_name == "" or garment_name is None: messagebox.showerror("SS Fashion Tuty", f"Garment Name is missing!") print(f"Garment Name is missing!") return if self.purchase_tree.get_children(): for child in self.purchase_tree.get_children(): product_code = self.purchase_tree.item(child)["values"][1] quantity = self.purchase_tree.item(child)["values"][6] purchase = (purchase_date, garment_name, product_code, quantity) Purchase.add_purchase(purchase) stock = (product_code, quantity) Stock.upload_stock(stock) if StockTimeline.get_timeline(product_code=product_code): activity = "Add Purchase" else: activity = "Opening Stock" StockTimeline.add_timeline(entry_date=purchase_date, product_code=product_code, activity=activity, change=f"+{quantity}") messagebox.showinfo("SS Fashion Tuty", f"Purchase added Successfully!") self.clear_all() def filter_product(self, event=None): product_name = self.filter_ety_product_name.get().strip() product_type = self.filter_ety_product_type.get().strip() product_size = self.filter_ety_product_size.get().strip() selling_price = str(self.filter_ety_product_sell_price.get().strip()) if selling_price: selling_price = float(selling_price) else: selling_price = 0.0 products = Product.search_products(product_name=product_name, product_type=product_type, product_size=product_size, selling_price=selling_price) self.products_tree.delete(*self.products_tree.get_children()) if products: row_num = 0 for product in products: stock = Stock.get_stock(product_code=product.product_code) quantity = "0" if stock: quantity = stock.quantity row_num += 1 row = (product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), quantity) if row_num % 2 == 0: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_inactive', product.product_code)) else: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_inactive', product.product_code)) if row_num <= self.select_first_row_threshold: self.select_first_row() else: pass def clear_all(self): self.ety_garment_name.delete(0, tk.END) self.purchase_counter = 0 self.purchase_tree.delete(*self.purchase_tree.get_children()) self.var_purchase_amount.set(format_currency(0, 'INR', locale='en_IN')) self.var_purchase_quantity.set(format_decimal(0, locale='en_US')) self.reload_products() self.selected_row = list() def calculate_total_amount_and_quantity(self): total_amount = 0 total_quantity = 0 for child in self.purchase_tree.get_children(): total_amount += float(self.purchase_tree.item(child)["values"][7]) total_quantity += int(self.purchase_tree.item(child)["values"][6]) self.var_purchase_amount.set( format_currency(total_amount, 'INR', locale='en_IN')) self.var_purchase_quantity.set( format_decimal(total_quantity, locale='en_US')) def get_quantity(self, event): self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] if isinstance(product, str): return available_quantity = product[5] self.var_available_quantity.set(available_quantity) self.window.wm_attributes("-disabled", True) self.qty_window = tk.Toplevel(self.window) self.qty_window.overrideredirect(True) self.qty_window.bind("<FocusOut>", self.on_focus_out_qty_window) # Gets the requested values of the height and width. window_width = self.qty_window.winfo_reqwidth() window_height = self.qty_window.winfo_reqheight() # Gets both half the screen width/height and window width/height position_right = int(self.qty_window.winfo_screenwidth() / 2 - window_width / 2) position_down = int(self.qty_window.winfo_screenheight() / 2 - window_height / 2) # Positions the window in the center of the page. self.qty_window.geometry("+{}+{}".format(position_right, position_down)) qty_container = tk.Frame(self.qty_window, bd=20, padx=10, pady=5, relief=tk.RIDGE, bg=self.clr_limegreen) qty_container.pack(expand=True, side=tk.TOP, anchor="n") lbl_quantity = tk.Label(qty_container, text="Quantity:", bg=self.clr_limegreen) lbl_quantity.grid(row=0, column=0, columnspan=2, padx=5, pady=2) ety_quantity = tk.Entry(qty_container, width=5, textvariable=self.var_quantity) ety_quantity.grid(row=1, column=0, padx=5, pady=2) if self.var_available_quantity.get() <= self.stock_alert_value: ety_available_quantity = tk.Entry( qty_container, width=5, textvariable=self.var_available_quantity, disabledbackground="red", disabledforeground="white", justify=tk.CENTER, state='disabled') else: ety_available_quantity = tk.Entry( qty_container, width=5, textvariable=self.var_available_quantity, justify=tk.CENTER, state='disabled') ety_available_quantity.grid(row=1, column=1, padx=5, pady=2) ety_quantity.delete(0, tk.END) ety_quantity.insert(tk.END, 1) self.var_quantity.set(1) ety_quantity.focus() ety_quantity.selection_range(0, tk.END) btn_ok = tk.Button(qty_container, text='Add', width=10, bg=self.clr_fuchsia, fg='white', command=lambda: self.cleanup_qty_window(event)) btn_ok.grid(row=2, column=0, columnspan=2, padx=5, pady=5) self.qty_window.bind('<Return>', lambda evnt: self.cleanup_qty_window(event)) self.qty_window.bind( '<Escape>', lambda evnt: self.cleanup_qty_window(event, add_quantity=False)) def on_focus_out_qty_window(self, event=None): self.window.wm_attributes("-disabled", False) self.qty_window.destroy() def cleanup_qty_window(self, event, add_quantity=True): quantity = int(self.var_quantity.get()) self.window.wm_attributes("-disabled", False) self.qty_window.destroy() if add_quantity: self.var_quantity.set(quantity) self.add_to_purchase_list(event) def add_to_purchase_list(self, event): quantity = self.var_quantity.get() self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] active_product = Product.get_product_status(product_code=product[0]) if not active_product: msg_box = messagebox.askquestion( "SS Fashion Tuty", "In-Active product! - Do you want to activate this Product?", icon='question') if msg_box == 'yes': Product.activate_product(product_code=product[0]) self.reload_products() else: return for child in self.purchase_tree.get_children(): if self.purchase_tree.item(child)["values"][1] == product[0]: prev_quantity = self.purchase_tree.item(child)["values"][6] price = self.purchase_tree.item(child)["values"][5] quantity += prev_quantity self.purchase_tree.set(child, "#7", quantity) self.purchase_tree.set(child, "#8", float(price) * quantity) break else: self.purchase_counter = self.purchase_counter + 1 row = (self.purchase_counter, product[0], product[1], product[2], product[3], round(float(product[4]), 2), quantity, round(float(product[4]), 2) * quantity) self.purchase_tree.insert("", tk.END, values=row) self.calculate_total_amount_and_quantity() if len(self.products_tree.selection()) > 0: self.products_tree.selection_remove( self.products_tree.selection()[0]) def reload_products(self): self.cbo_product_category.delete(0, "end") self.filter_ety_product_name.delete(0, tk.END) self.filter_ety_product_type.delete(0, tk.END) self.filter_ety_product_size.delete(0, tk.END) self.filter_ety_product_sell_price.delete(0, tk.END) self.products_tree.delete(*self.products_tree.get_children()) products = Product.get_all_products() row_num = 0 for product in products: row_num += 1 stock = Stock.get_stock(product_code=product.product_code) quantity = "0" if stock: quantity = stock.quantity row = (product.product_code, product.product_name, product.product_type, product.product_size, round(product.selling_price, 2), quantity) if row_num % 2 == 0: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('evenrow_inactive', product.product_code)) else: if product.is_active: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_active', product.product_code)) else: self.products_tree.insert("", tk.END, values=row, tags=('oddrow_inactive', product.product_code)) def on_tree_select(self, event): self.selected_row = event.widget.selection() product = self.products_tree.item(self.selected_row)['values'] if product: self.var_product_code.set(product[0]) self.var_product_name.set(product[1]) self.var_product_type.set(product[2]) self.var_product_size.set(product[3]) self.var_selling_price.set(product[4])