Esempio n. 1
0
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])
Esempio n. 2
0
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 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])
Esempio n. 4
0
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()
Esempio n. 5
0
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])
Esempio n. 6
0
class IsogeoSearchForm(ttk.Frame):
    def __init__(self, master=None, async_loop=None):
        tk.Frame.__init__(self, master)
        self.async_loop = async_loop

        # basics
        # master.resizable(width=True, height=True)
        master.title(
            "Isogeo Python SDK v{} - Sample desktop search form".format(pysdk_version)
        )
        master.focus_force()
        self.grid(sticky="NSWE")
        self.grid_propagate(1)

        # styling
        self.style = ttk.Style(self)

        self.s1 = tk.PhotoImage(
            master=self, name="search1", data=data, format="gif -index 0"
        )
        self.s2 = tk.PhotoImage(
            master=self, name="search2", data=data, format="gif -index 1"
        )

        self.style.element_create(
            "Search.field",
            "image",
            "search1",
            ("focus", "search2"),
            border=[22, 7, 14],
            sticky="ew",
        )

        self.style.layout(
            "Search.entry",
            [
                (
                    "Search.field",
                    {
                        "sticky": "nswe",
                        "border": 1,
                        "children": [
                            (
                                "Entry.padding",
                                {
                                    "sticky": "nswe",
                                    "children": [
                                        ("Entry.textarea", {"sticky": "nswe"})
                                    ],
                                },
                            )
                        ],
                    },
                )
            ],
        )
        self.style.configure("Search.entry")

        # frames
        fr_global = ttk.Frame(self, name="global")
        fr_search = ttk.Frame(self, name="search_form")

        # UI vars
        self.app_name = StringVar(fr_global, "Sample desktop form")
        self.app_total = StringVar(fr_global, "0")
        self.app_url = StringVar(fr_global, "http://isogeo-api-pysdk.readthedocs.io")
        self.app_results = StringVar(fr_search, "0")

        # -- WIDGETS CREATION -------------------------------------------------
        # add widgets
        lbl_app_name = tk.Label(fr_global, textvariable=self.app_name)
        lbl_app_total = ttk.Label(fr_global, textvariable=self.app_total)
        btn_app_url = ttk.Button(
            fr_global,
            text="APP Website",
            command=lambda: self.worker_allocator(
                async_loop=self.async_loop, to_do="open_web", **{"url": self.app_url}
            ),
        )

        lbl_actions = ttk.Label(fr_search, text="Linked action")
        lbl_contacts = ttk.Label(fr_search, text="Contact")
        lbl_formats = ttk.Label(fr_search, text="Source format")
        lbl_inspires = ttk.Label(fr_search, text="INSPIRE theme")
        lbl_keywords = ttk.Label(fr_search, text="Keyword")
        lbl_licenses = ttk.Label(fr_search, text="License")
        lbl_owners = ttk.Label(fr_search, text="Owner")
        lbl_shares = ttk.Label(fr_search, text="Share")
        lbl_srs = ttk.Label(fr_search, text="Source spatial reference system")
        lbl_types = ttk.Label(fr_search, text="Type")

        # add form widgets
        self.ent_search = AutocompleteEntry(
            fr_search, style="Search.entry", width=20, completevalues=list()
        )

        self.cb_actions = AutocompleteCombobox(fr_search)
        self.cb_contacts = AutocompleteCombobox(fr_search)
        self.cb_formats = AutocompleteCombobox(fr_search)
        self.cb_inspires = AutocompleteCombobox(fr_search)
        self.cb_keywords = AutocompleteCombobox(fr_search)
        self.cb_licenses = AutocompleteCombobox(fr_search)
        self.cb_owners = AutocompleteCombobox(fr_search)
        self.cb_shares = AutocompleteCombobox(fr_search)
        self.cb_srs = AutocompleteCombobox(fr_search)
        self.cb_types = AutocompleteCombobox(fr_search)

        lbl_results = ttk.Label(fr_search, textvariable=self.app_results)

        btn_reset = ttk.Button(
            master,
            text="Reset",
            command=lambda: self.worker_allocator(
                async_loop=self.async_loop, to_do="form_clear", **{"clear": 1}
            ),
        )
        btn_close = ttk.Button(master, text="Close", command=master.destroy)

        # after UI build
        self.worker_allocator(
            async_loop=self.async_loop, to_do="form_clear", **{"clear": 1}
        )

        # -- WIDGETS PLACEMENT ------------------------------------------------
        d_pad = {"padx": 5, "pady": 5, "sticky": "NSEW"}

        lbl_app_name.grid(row=0, column=0, **d_pad)
        btn_app_url.grid(row=1, column=0, **d_pad)
        lbl_app_total.grid(row=2, column=0, **d_pad)

        self.ent_search.grid(row=1, columnspan=3, **d_pad)

        self.cb_actions.grid(row=3, column=0, **d_pad)
        self.cb_contacts.grid(row=3, column=1, **d_pad)
        self.cb_formats.grid(row=3, column=2, **d_pad)
        self.cb_inspires.grid(row=5, column=0, **d_pad)
        self.cb_keywords.grid(row=5, column=1, **d_pad)
        self.cb_licenses.grid(row=5, column=2, **d_pad)
        self.cb_owners.grid(row=7, column=0, **d_pad)
        self.cb_shares.grid(row=7, column=1, **d_pad)
        self.cb_srs.grid(row=7, column=2, **d_pad)
        self.cb_types.grid(row=9, column=1, **d_pad)

        lbl_actions.grid(row=2, column=0, **d_pad)
        lbl_contacts.grid(row=2, column=1, **d_pad)
        lbl_formats.grid(row=2, column=2, **d_pad)
        lbl_inspires.grid(row=4, column=0, **d_pad)
        lbl_keywords.grid(row=4, column=1, **d_pad)
        lbl_licenses.grid(row=4, column=2, **d_pad)
        lbl_owners.grid(row=6, column=0, **d_pad)
        lbl_shares.grid(row=6, column=1, **d_pad)
        lbl_srs.grid(row=6, column=2, **d_pad)
        lbl_types.grid(row=8, column=1, **d_pad)

        lbl_results.grid(row=22, column=0, columnspan=2, **d_pad)

        fr_global.grid(row=0, columnspan=1, **d_pad)
        fr_search.grid(row=1, columnspan=1, **d_pad)

        btn_reset.grid(row=2, column=0, sticky="NSW", padx=5, pady=5)
        btn_close.grid(row=2, column=0, sticky="NSE", padx=5, pady=5)

        # connecting comboboxes event
        self.cb_actions.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_contacts.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_formats.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_inspires.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_keywords.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_licenses.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_owners.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_shares.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_srs.bind("<<ComboboxSelected>>", self.cbs_manager)
        self.cb_types.bind("<<ComboboxSelected>>", self.cbs_manager)

    # -- TASKS HUB ------------------------------------------------------------
    def cbs_manager(self, event):
        self.worker_allocator(
            async_loop=self.async_loop, to_do="form_update", **{"clear": 0}
        )

    def worker_allocator(self, async_loop, to_do, **kwargs):
        """ Handler starting the asyncio part. """
        d = kwargs
        threading.Thread(
            target=self._asyncio_thread, args=(async_loop, to_do, d)
        ).start()

    def _asyncio_thread(self, async_loop, to_do, kwargus):
        if to_do == "form_clear":
            async_loop.run_until_complete(self.fill_form(clear=1))
        elif to_do == "form_update":
            async_loop.run_until_complete(self.fill_form(clear=0))
        elif to_do == "open_web":
            async_loop.run_until_complete(self.open_url(kwargus.get("url").get()))
        else:
            pass

    # -- ASYNC METHODS --------------------------------------------------------
    async def open_url(self, url):
        open_new_tab(url)

    async def fill_form(self, clear=0):
        if not hasattr(self, "isogeo"):
            self._init_isogeo()
        else:
            logging.info("App is already connected to Isogeo API")
            pass

        # search
        if clear:
            # clear
            self.ent_search.delete(0, "end")
            self.cb_actions.set("")
            self.cb_contacts.set("")
            self.cb_formats.set("")
            self.cb_inspires.set("")
            self.cb_keywords.set("")
            self.cb_licenses.set("")
            self.cb_owners.set("")
            self.cb_shares.set("")
            self.cb_srs.set("")
            self.cb_types.set("")
            # new search
            search = self.isogeo.search(
                self.token, page_size=0, whole_share=0, augment=1, tags_as_dicts=1
            )
            app_total = results_total = search.get("total")
            self.app_total.set("Total: {} metadata".format(app_total))
        else:
            query = self.ent_search.get() + " "
            query += self.tags.get("actions").get(self.cb_actions.get(), "") + " "
            query += self.tags.get("contacts").get(self.cb_contacts.get(), "") + " "
            query += self.tags.get("formats").get(self.cb_formats.get(), "") + " "
            query += self.tags.get("inspires").get(self.cb_inspires.get(), "") + " "
            query += self.tags.get("keywords").get(self.cb_keywords.get(), "") + " "
            query += self.tags.get("licenses").get(self.cb_licenses.get(), "") + " "
            query += self.tags.get("owners").get(self.cb_owners.get(), "") + " "
            query += self.tags.get("shares").get(self.cb_shares.get(), "") + " "
            query += self.tags.get("srs").get(self.cb_srs.get(), "") + " "
            query += self.tags.get("types").get(self.cb_types.get(), "") + " "
            search = self.isogeo.search(
                self.token,
                page_size=0,
                whole_share=0,
                augment=1,
                tags_as_dicts=1,
                query=query,
            )
            results_total = search.get("total")
            logging.debug(search.get("query"))
        self.tags = search.get("tags")

        # set values
        self.app_results.set("Results count: {} metadata".format(results_total))
        self.ent_search.set_completion_list(list(self.tags.get("keywords").values()))
        self.cb_actions.set_completion_list(list(self.tags.get("actions")))
        self.cb_contacts.set_completion_list(list(self.tags.get("contacts")))
        self.cb_formats.set_completion_list(list(self.tags.get("formats")))
        self.cb_inspires.set_completion_list(list(self.tags.get("inspires")))
        self.cb_keywords.set_completion_list(list(self.tags.get("keywords")))
        self.cb_licenses.set_completion_list(list(self.tags.get("licenses")))
        self.cb_owners.set_completion_list(list(self.tags.get("owners")))
        self.cb_shares.set_completion_list(list(self.tags.get("shares")))
        self.cb_srs.set_completion_list(list(self.tags.get("srs")))
        self.cb_types.set_completion_list(list(self.tags.get("types")))

    def _init_isogeo(self):
        api_credentials = utils.credentials_loader("client_secrets.json")
        self.isogeo = Isogeo(
            client_id=api_credentials.get("client_id"),
            client_secret=api_credentials.get("client_secret"),
        )
        self.token = self.isogeo.connect()
        # app properties
        self.isogeo.get_app_properties(self.token)
        self.app_props = self.isogeo.app_properties
        self.app_name.set(
            "Authenticated application: {}".format(self.app_props.get("name"))
        )
        self.app_url.set(self.app_props.get("url", "https://www.isogeo.com"))