Advertisement
ALEXANDAR_GEORGIEV

trial_balance

Dec 3rd, 2022
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 22.85 KB | Source Code | 0 0
  1. from json_file_io import JsonFileIo
  2. from Opiti.from_excel.classes.global_inc import registry    # TODO KАКВО Е ТОВА ???
  3.  
  4. from widget_factory import *
  5. from account_tree import *
  6. from excel_acc_data import *
  7.  
  8.  
  9. class TrialBalance:
  10.     def __init__(self):         # TODO acc_data_bycode = acc_data1
  11.         self.window = tk.Tk()
  12.         self.widget_factory = WidgetsFactory()
  13.         self.synthetic_value = tk.StringVar(self.window)
  14.         self.analytic_value = tk.StringVar(self.window)
  15.         self.unmapped_value = tk.StringVar(self.window)
  16.         self.level_code = None
  17.         self.acc_data = []    # dict    # Сурови данни от Excel -> Списък от речници
  18.         self.acc_data_bycode = {}    # Данни от Excel с Ключ "сметка" -> Речник в речник {10: {'code': '10', 'name':..}}
  19.         self.min_top_group_digits = 0  # Минимален брой цифри в топ групата на кода на сметките -> spin_1
  20.         self.max_top_group_digits = 0   # Максимален брой цифри в топ групата на кода на сметките -> spin_1
  21.         self.max_groups = 0 # Максимален брой групи в кода на сметките
  22.         self.min_level_spin_1 = self.min_top_group_digits
  23.         self.max_level_spin_1 = self.max_top_group_digits
  24.         self.max_level_spin_2 = self.max_groups # -1
  25.         self.code_acc = int()
  26.         self.treeview_data = dict()
  27.         self.tree = None # Променливата под която е рисувано Treeview в WidgetFactory
  28.         self.spin_1 = str()
  29.         self.spin_2 = str()
  30.         self.acc_tree = AccountTree()
  31.         self.user_acc_type = tk.StringVar(self.window) # StringVar на Radiobuttons
  32.         self.total_sum_row = ["", "Обща сума", 0, 0, 0, 0, 0, 0, ]
  33.         self.mapped_acc = {}    # Речник с маркираните сметки
  34.         self.parent_maped_acc = []  # Values на речника mapped_acc = {'100': [10]}
  35.         self.scrollbar = None
  36.         self.list_radiobuttons = {'kn': 'НК', 'da': 'ДА', 'mz': 'МЗ', 'vz': 'ВЗ', 'invest': 'Ин', 'money': 'Пари',
  37.                                   'rbp': 'РБП', 'tax_assets': 'Дан А/П', 'sk': 'СК', 'provision': 'Пров',
  38.                                   'zd': 'ЗД', 'pbp': 'ПБП', 'drugi_p': 'Др',
  39.                                   'px': 'Пх', 'rx': 'Рх', 'drugi_opr': 'Др'}
  40.         self.correction_mode = False
  41.         self.list_type_account = []  # Списък със всички видове сметки
  42.         self.list_all_code_account = []     # Списък със всички кодове на сметки
  43.                                             # ['10', '100', '12', '121', '121-13', '121-14', '121-15'.....]
  44.         # Тук pop-message-диалога ще вписва отговора на юзъра
  45.         self.pop_message_answer = None
  46.         self.is_accounts_mapped = False
  47.         self.excel_acc_data = None
  48.  
  49.     def set_pop_message_answer(self, answer):
  50.         self.pop_message_answer = answer
  51.  
  52.     def on_ok(self):
  53.         # TODO -> Проверка за немаркирани сметки
  54.         list_unmapped_accs = self.acc_tree.get_unmapped_acc(self.mapped_acc)
  55.         print("BBBB list_unmapped_accs", list_unmapped_accs)
  56.         print("BBBB len(list_unmapped_accs)", len(list_unmapped_accs))
  57.         if len(list_unmapped_accs) > 0:
  58.     # TODO -> Показва pop_message "Има немаркирани сметки ! Желаете ли да маркирате всички сметки ?" Бутони: "ДА", "НЕ"
  59.             pop_message = self.widget_factory.get_pop_message(self.window,
  60.                             lambda answer: self.set_pop_message_answer(answer),
  61.                                         "Има немаркирани сметки !\nЖелаете ли да маркирате всички сметки ?", 2, 'red')
  62.             self.window.wait_window(pop_message.pop)
  63.             # TODO -> Ако "ДА"
  64.             if self.pop_message_answer == 'yes':
  65.                 return
  66.             # TODO -> Ако "НЕ"
  67.             # TODO -> mapped_account.txt -> {"121": ["СК"], "121-13": ["СК"], "121-14": ["СК"],....}
  68.             json_file_io = JsonFileIo(file_name=registry['mapped_account_file_name'])
  69.             json_file_io.write_content(self.mapped_acc)
  70.             # TODO -> КАк се излиза от приложението Trial_balance ?? QUIT(), DESTROY(), CLOSE() ?
  71.             self.window.destroy()
  72.             return
  73.         # TODO -> Показва pop_message "Всички сметки са маркирани ! Бутон "ОК"
  74.         pop_message = self.widget_factory.get_pop_message(self.window,
  75.                         lambda answer: self.set_pop_message_answer(answer), "Всички сметки са маркирани !", 1, 'blue')
  76.         self.window.wait_window(pop_message.pop)
  77.         # TODO -> mapped_account.txt -> {"121": ["СК"], "121-13": ["СК"], "121-14": ["СК"],....}
  78.         json_file_io = JsonFileIo(file_name=registry['mapped_account_file_name'])
  79.         json_file_io.write_content(self.mapped_acc)
  80.         self.is_accounts_mapped = True  # Всички сметки са маркирани !
  81.         # TODO -> acc_data_bycode.txt -> {'10': {'code': '10', 'name':}
  82.         json_file_io = JsonFileIo(file_name=registry['acc_data_bycode_file_name'])
  83.         json_file_io.write_content(self.acc_data_bycode)
  84.  
  85.         self.window.destroy()
  86.         return
  87.  
  88.     def on_correction(self):
  89.         self.correction_mode = True
  90.  
  91.     def mark_accounts(self, acc_code):    # Приема TUPLE и прави маркиране на всички под-нива на маркираните сметки
  92.         # print('acc_code: ', acc_code)
  93.         if acc_code in self.mapped_acc:
  94.             return self.mapped_acc[acc_code]    # сметката вече е маркирана
  95.         if acc_code == 'total':
  96.             return 'total'
  97.         return None # Подлежат на маркиране само тези които са None !
  98.  
  99.     def verify_selection(self): # Забрана за маркиране
  100.         if self.correction_mode: return
  101.         selected_items = self.tree.selection()  # Прави Tuple от кодовете на маркираните сметки
  102.         # print(selected_items)
  103.         for code in selected_items:
  104.             if code is not None:
  105.                 mark_type = self.mark_accounts(code)
  106.                 # print("mark_type:", mark_type)
  107.                 if mark_type is None: pass  # Сметката не е маркирана и чака Бутон 'Запис'
  108.                 else: self.tree.selection_remove(code)
  109.         return
  110.  
  111.     def update_type_account(self):
  112.         pass
  113.  
  114.     def on_select_acc(self):
  115.         self.verify_selection()
  116.         self.update_type_account()
  117.  
  118.     def on_save(self):  # TODO -> Пълни mapped_acc{} речник с маркираните сметки
  119.         selected_acc_codes = self.tree.selection()  # Взимаме селектираните сметки
  120.         type_account = self.user_acc_type.get()     # Взимаме селектирания Радиобутон, StringVar на Radiobuttons
  121.         list_of_children_types = []                 # Списък с видовете на децата
  122.         if type_account is None or type_account == '' or len(selected_acc_codes) == 0:
  123.             return
  124.         for acc_code in selected_acc_codes: # TODO -> За всяка селектирана сметка: acc_code e '100':
  125.             is_parent = self.acc_tree.is_parent(acc_code)   # Проверяваме дали маркираната сметка е родител
  126.             if acc_code in self.mapped_acc and is_parent:   # Ако вече е маркирана и е родител
  127.                 pop_message = self.widget_factory.get_pop_message(self.window, lambda answer: self.set_pop_message_answer(answer),
  128.                                             f"Да се промени ли вида на с/ка {acc_code}\nи нейните подсметки ?", 2, 'blue')
  129.                 self.window.wait_window(pop_message.pop)    #
  130.                 if self.pop_message_answer == 'no': # Няма да променяме сметката и децата й !
  131.                     self.tree.selection_remove(acc_code) # Дали ще работи ???
  132.                     continue # Може би да размаркираме тази сметка в Treeview ???
  133.                 else:       # TODO ->  Ще променим вида на сметката и децата й !
  134.                     # TODO -> Да махнем децата от self.mapped_acc
  135.                     haves_children = self.acc_tree.get_all_children(acc_code)
  136.                     for child in haves_children:
  137.                         if child in self.mapped_acc:
  138.                             del self.mapped_acc[child]
  139.             # Маркираме сметката        type_account е маркирания радиобутон
  140.             if self.list_radiobuttons[type_account] not in self.list_type_account:
  141.                 self.list_type_account.append(self.list_radiobuttons[type_account])
  142.             self.mapped_acc[acc_code] = self.list_type_account  # mapped_acc = {'121': ['СК']}, Маркираме сметката
  143.             self.list_type_account = []
  144.             # ----Ръчно маркиране
  145.             self.tree.set(acc_code, 'type', '/'.join(self.mapped_acc[acc_code])) # Слагаме вида сметка в Treeview
  146.             # TODO -> Проверяваме дали текущата сметка е родител !!
  147.             is_parent = self.acc_tree.is_parent(acc_code)
  148.             if is_parent:
  149.                 haves_children = self.acc_tree.get_all_children(acc_code)
  150.                 # TODO -> Проверка на вида на децата !
  151.                 for child in haves_children:    # Маркиране на child
  152.                     if self.list_radiobuttons[type_account] not in self.list_type_account:
  153.                         self.list_type_account.append(self.list_radiobuttons[type_account])
  154.                     self.mapped_acc[child] = self.list_type_account
  155.                     self.list_type_account = []
  156.             # TODO -> До тук текущата сметка е маркирана и всички нейни деца вече са маркирани !
  157.             # TODO -> Автоматично маркиране на всички родители, Проверка дали текущата сметка има родител ?
  158.             is_child = self.acc_tree.is_child(acc_code)
  159.             if is_child:
  160.                 parents_codes = self.acc_tree.get_all_parents(acc_code)  #Подаваме тек с/ка и получаваме вс/ки родители
  161.                 for parent_code in parents_codes:
  162.                     # TODO -> Да вземем децата на parent_code и да проверим техните видове !
  163.                     children_of_parent_code = self.acc_tree.get_all_children(parent_code)  # Децата на всеки родител
  164.                     # TODO -> Да съберем в списък list_of_children_types, видовете на всички деца
  165.                     for child in children_of_parent_code:
  166.                         if child in self.mapped_acc: # Ако детето е вече маркирано
  167.                             diff_types = self.acc_tree.asymmetric_compare_lists(self.mapped_acc[child],
  168.                                                                                 list_of_children_types)
  169.                             if diff_types is not None:
  170.                                 list_of_children_types += diff_types
  171.                     self.mapped_acc[parent_code] = list_of_children_types
  172.                     list_of_children_types = []
  173.         self.correction_mode = False
  174.         self.fill_treeview()    # TODO -> НОВО !
  175.  
  176.     def fill_treeview(self):
  177.         self.tree.delete(*self.tree.get_children())     # Вградена функция за изтриване на Treeview
  178.         spin_1, spin_2 = int(self.synthetic_value.get()), int(self.analytic_value.get())
  179.         unmapped_spin = self.unmapped_value.get()
  180.         # TODO -> За попълване на немаркираните сметки от Бутон "ОК",
  181.         #list_unmapped_accs = self.acc_tree.get_unmapped_acc(self.mapped_acc, self.list_all_code_account)
  182.         list_unmapped_accs = self.acc_tree.get_unmapped_acc(self.mapped_acc)
  183.         print('list_unmapped_accs: ', list_unmapped_accs)
  184.         parents_with_unmapped_children = []
  185.         # parents_with_unmapped_children има смисъл да се строи само ако unmapped_spin == "немаркирани"
  186.         if unmapped_spin == "немаркирани":
  187.             for code in self.acc_data_bycode:
  188.                 if code in list_unmapped_accs:  # TypeError: argument of type 'NoneType' is not iterable
  189.                     parents = self.acc_tree.get_all_parents(code)
  190.                     for parent in parents:
  191.                         if parent not in parents_with_unmapped_children:
  192.                             parents_with_unmapped_children.append(parent)
  193.  
  194.         def check_unmapped_acc(code):
  195.             if unmapped_spin == "немаркирани":
  196.                 if code in list_unmapped_accs:
  197.                     return True
  198.                 elif code in parents_with_unmapped_children:
  199.                     return True
  200.                 return False
  201.             return True
  202.  
  203.         self.treeview_data = self.acc_data_bycode.copy()
  204.         filtered_dict = {}
  205.         # TODO Accounttree за момента не знае дали дадена сметка е синтетична или не, може да му се добави да знае
  206.         if spin_2 == 0:
  207.             for code in self.treeview_data:
  208.                 if check_unmapped_acc(code):
  209.                     groups_in_top_code = re.findall('[0-9]+', code) # ['610', '30', '9']
  210.                     if len(groups_in_top_code[0]) == spin_1 and len(groups_in_top_code) == 1:
  211.                         filtered_dict[code] = self.treeview_data[code]
  212.         else:
  213.             for code in self.treeview_data:
  214.                 if check_unmapped_acc(code):
  215.                     depth = self.acc_tree.get_depth(code)
  216.                     if spin_1 <= depth <= (spin_1 + spin_2):
  217.                         filtered_dict[code] = self.treeview_data[code]
  218.         # ---- TODO Дазалепим тотала във filtered_dict !!
  219.         count_rows = len(filtered_dict) + 1   # Брой редове за печат + 1 заради ТОТАЛ
  220.         nsd = nsc = od = oc = ksd = ksc = 0.0
  221.         for acc_code in filtered_dict:  # acc_code:  724
  222.             type = ''
  223.             if acc_code in self.mapped_acc:
  224.                 type = self.mapped_acc[acc_code]
  225.             nsd += filtered_dict[acc_code]['open_d']
  226.             nsc += filtered_dict[acc_code]['open_c']
  227.             od += filtered_dict[acc_code]['turn_d']
  228.             oc += filtered_dict[acc_code]['turn_c']
  229.             ksd += filtered_dict[acc_code]['close_d']
  230.             ksc += filtered_dict[acc_code]['close_c']
  231.             row = [
  232.                 type, # Тук ще влезе вида сметка посочен от порребителя
  233.                 acc_code,
  234.                 filtered_dict[acc_code]['name'],
  235.                 filtered_dict[acc_code]['str_open_d'],
  236.                 filtered_dict[acc_code]['str_open_c'],
  237.                 filtered_dict[acc_code]['str_turn_d'],
  238.                 filtered_dict[acc_code]['str_turn_c'],
  239.                 filtered_dict[acc_code]['str_close_d'],
  240.                 filtered_dict[acc_code]['str_close_c']]
  241.             tags = []
  242.             iid = acc_code
  243.             self.tree.insert(parent='', index=tk.END, values=row, tags=tags, iid=iid)
  244.         # -------TODO да викна функция за TOTAL и да вмъкна TOTAL в Treeview
  245.         total = ['', '', 'Обща сума:', f'{nsd:,.2f}'.replace(',', ' '), f'{nsc:,.2f}'.replace(',', ' '),
  246.                  f'{od:,.2f}'.replace(',', ' '), f'{oc:,.2f}'.replace(',', ' '), f'{ksd:,.2f}'.replace(',', ' '),
  247.                  f'{ksc:,.2f}'.replace(',', ' ')]
  248.         self.tree.insert(parent='', index=tk.END, values=total, tags=['total'], iid='total')
  249.         if count_rows > 30:
  250.             self.tree.configure(height=30)
  251.         else: self.tree.configure(height=count_rows)
  252.         self.treeview_data = {}
  253.  
  254.     def main(self):
  255.         # -----------------------------------------------------
  256.         self.window.title('Оборотна ведомост')
  257.         self.window.geometry('1254x840+150+10')
  258.         self.window.resizable(True, False)
  259.         self.window.attributes('-topmost', 'true')
  260.         widget_factory = WidgetsFactory()
  261.  
  262.         # -----------TODO BUTTONS-------------------------------
  263.         butt_save = widget_factory.get_save_button(self.window, 20, 560)
  264.         butt_save.bind('<ButtonRelease-1>', lambda e: self.on_save())
  265.         butt_ok = widget_factory.get_ok_button(self.window, 20, 600)
  266.         butt_ok.bind('<ButtonRelease-1>', lambda e: self.on_ok())
  267.         butt_correction = widget_factory.get_correction_button(self.window, 20, 764)
  268.         butt_correction.bind('<ButtonRelease-1>', lambda e: self.on_correction())
  269.         butt_help = widget_factory.get_help_button(self.window, 20, 794)
  270.         butt_help.bind('<ButtonRelease-1>', lambda e: None)
  271.         # -----------TODO LABEL_FRAMES-------------------------------
  272.         label_frame_a = widget_factory.get_label_frame(self.window, 'Актив')
  273.         label_frame_a.place(x=20, y=60)
  274.         label_frame_p = widget_factory.get_label_frame(self.window, 'Пасив')
  275.         label_frame_p.place(x=20, y=290)    # 270
  276.         label_frame_opr = widget_factory.get_label_frame(self.window, 'Пх/Рх')
  277.         label_frame_opr.place(x=20, y=445)  # 430
  278.         # -----------TODO RADIO BUTTONS-------------------------------
  279.         widget_factory.get_radio_butt(label_frame_a, 7, 'w', list_buttons={'kn': 'Невн.к-л', 'da': 'ДА', 'mz': 'МЗ',
  280.                         'vz': 'Вземания', 'invest': 'Инвест.', 'money': 'Пари', 'rbp': 'РБП', 'tax_assets': 'Дан А/П'},
  281.                                       var=self.user_acc_type)
  282.         widget_factory.get_radio_butt(label_frame_p, 7, 'w', list_buttons={'sk': 'СК', 'provision': 'Провизии',
  283.                                         'zd': 'Задълж.', 'pbp': 'ПБП', 'drugi_p': 'Други'}, var=self.user_acc_type)
  284.         widget_factory.get_radio_butt(label_frame_opr, 7, 'w', list_buttons={'px': 'Приходи', 'rx': 'Разходи',
  285.                                                                     'drugi_opr': 'Други'}, var=self.user_acc_type)
  286.         # -----------TODO LABEL-------------------------------
  287.         # place_on, x, y, text_l, w, p, color
  288.         acc_label = widget_factory.get_label(self.window, 150, 12, 'Сметки', 6, 'w')
  289.         synt_label = widget_factory.get_label(self.window, 250, 12, 'синтет.', 8, 'w')
  290.         analyt_label = widget_factory.get_label(self.window, 320, 12, 'аналит.', 8, 'w')
  291.         some_label = widget_factory.get_label(self.window, 670, 28, 'Начално салдо', 13, 'w')
  292.         some_label2 = widget_factory.get_label(self.window, 880, 28, 'Обороти', 8, 'w')
  293.         some_label3 = widget_factory.get_label(self.window, 1070, 28, 'Крайно салдо', 13, 'w')
  294.         # -----------TODO FRAME-------------------------------
  295.         tv_frame = widget_factory.get_frame(self.window)
  296.         tv_frame.place(x=150, y=50)
  297.         # -----------TODO TREEVIEW-------------------------------
  298.  
  299.         mapped_acc_data = MappedAccData()
  300.         mapped_acc_data.read_json()
  301.         self.mapped_acc = mapped_acc_data.get_mapped_acc()
  302.         print("TrialBalance: self.mapped_acc", self.mapped_acc)
  303.  
  304.         self.excel_acc_data = ExcelAccData()
  305.         self.excel_acc_data.convert_json_data()
  306.  
  307.         self.acc_data_bycode = self.excel_acc_data.get_acc_data_bycode()
  308.         self.min_top_group_digits = self.excel_acc_data.get_min_top_group_digits()
  309.         self.max_top_group_digits = self.excel_acc_data.get_max_top_group_digits()
  310.         self.max_groups = self.excel_acc_data.get_max_groups()
  311.  
  312.         for acc_code in self.acc_data_bycode:
  313.             self.acc_tree.add_code(acc_code) # Захранваме наследственото дърво
  314.             self.list_all_code_account.append(acc_code)
  315.         list_of_columns = {
  316.             'type': 'вид',
  317.             'code': 'код',
  318.             'acc_name': 'Сметка',
  319.             'open_d': 'НС Дебит',
  320.             'open_c': 'НС Кредит',
  321.             'turn_d': 'Оборот Дт',
  322.             'turn_c': 'Оборот Кт',
  323.             'close_d': 'КС Дебит',
  324.             'close_c': 'КС Кредит'
  325.         }
  326.         self.tree = widget_factory.get_treeview(tv_frame, **list_of_columns)
  327.         self.tree.tag_configure('total', font=('Timesbd', 9, 'bold')) # Общата сума наи-долу
  328.         self.tree.bind('<ButtonRelease-1>', lambda e: self.on_select_acc())
  329.         # -----------TODO SCROLLBAR-------------------------------
  330.         self.scrollbar = widget_factory.get_scrollbar(tv_frame, 'vertical', 'right', 'y')
  331.         self.scrollbar.configure(command=self.tree.yview)  # flat, groove, raised, ridge, solid, or sunken
  332.         self.tree.configure(yscrollcommand=self.scrollbar.set)
  333.         # -----------TODO SPINBOX-------------------------------
  334.         list_type = ['всички', 'немаркирани']
  335.         unmapped_acc = self.widget_factory.get_list_spinbox(self.window, list_type, 14, 'center',
  336.                                                             self.unmapped_value, 150, 30)
  337.         unmapped_acc.configure(command=self.fill_treeview)
  338.         self.unmapped_value.set(value='всички')
  339.  
  340.         synthetic_spinbox = widget_factory.get_spinbox(self.window, str(self.min_top_group_digits),
  341.                                         str(self.max_top_group_digits), 9, 'center', self.synthetic_value,  250, 30)
  342.         synthetic_spinbox.configure(command=self.fill_treeview)
  343.         self.synthetic_value.set(value='3')
  344.         analytic_spinbox = widget_factory.get_spinbox(self.window, "0", str(self.max_groups), 10, 'center',
  345.                                                       self.analytic_value, 320, 30)
  346.         analytic_spinbox.configure(command=self.fill_treeview)
  347.         self.analytic_value.set(value="0")
  348.  
  349.  
  350.         self.fill_treeview()
  351.  
  352.         self.window.update()  # Не знаем дали е полезно, но май не пречи
  353.  
  354.         self.window.mainloop()
  355.  
  356. if __name__ == '__main__':
  357.     test = TrialBalance()
  358.     test.main()
  359.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement