Advertisement
ALEXANDAR_GEORGIEV

up_down_dictionary

Nov 2nd, 2022
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 44.16 KB | Source Code | 0 0
  1. from tkinter import *
  2. # from tkinter.ttk import * изпада в комфликт по отношение настройките на frame с tkinter
  3. from tkinter import ttk
  4. from tkinter.ttk import Treeview, Combobox
  5. from tkinter.ttk import Style
  6. import re
  7.  
  8. from Opiti.from_excel.classes.global_inc import registry
  9. from json_file_io import JsonFileIo
  10.  
  11.  
  12. class AccountTree():
  13.     def __init__(self):
  14.         self.struct = {}  # Родословно дърво сметки
  15.         self.children = None
  16.         self.top_digits = {}  # На коя сметка колко цифри има в първата група
  17.         self.groups = {}  # На коя сметка колко групи има
  18.         self.top_group_max_digits_count = None
  19.         self.max_groups_count = None
  20.  
  21.     # code е нешо от типа "123-456-789"
  22.     def add_code(self, code):
  23.         self.children = None  # Нулираме кеша на родители-деца
  24.         # "123-456-789" дава ["123", "456", "789"]
  25.         groups_digits = re.findall('[0-9]+', code)
  26.         # "123-456-789" дава ["-", "-"]
  27.         groups_seps = re.findall('[^0-9]+', code)
  28.         groups_digits_len = len(groups_digits)
  29.  
  30.         # Следим
  31.         if self.max_groups_count is None:
  32.             self.max_groups_count = groups_digits_len
  33.         elif groups_digits_len > self.max_groups_count:
  34.             self.max_groups_count = groups_digits_len
  35.  
  36.             # От този код трябва да построим този клон:
  37.         #1
  38.         #12
  39.         #123
  40.         #123-456
  41.         #123-456-789
  42.  
  43.         # Напр 123  # groups_digits е списък с групите
  44.         top_group_digits = groups_digits[0]  # Първата група
  45.         #print("top_group_digits", top_group_digits)
  46.         top_group_digits_len = len(top_group_digits)  # Брой цифри в 1-вата група
  47.  
  48.         # В ancestors ще трупаме [сметка, родител, пра-родител и т.н.] но по цели групи от цифри
  49.         ancestors = []
  50.         ancestors_top_group_digits = []
  51.         ancestors_groups = []
  52.         # За ["123", "456", "789"] len1 ще мине през 3, 2, 1
  53.         for len1 in range(groups_digits_len, 0, -1):
  54.             # len1=3 дава ["123", "456", "789"]
  55.             # len1=2 дава ["123", "456"]
  56.             # len1=1 дава ["123"]
  57.             code1 = ""
  58.             # len1=3, то idx ше мине през 0, 1, 2
  59.             # len1=2, то idx ше мине през 0, 1
  60.             # len1=1, то idx ше мине през 0
  61.             for idx in range(len1):
  62.                 if code1 != "":
  63.                     code1 += groups_seps[idx - 1]
  64.                     pass
  65.                 code1 += groups_digits[idx]
  66.             ancestors.append(code1)
  67.             ancestors_top_group_digits.append(top_group_digits_len)
  68.             ancestors_groups.append(len1)
  69.  
  70.             #print("code1", code1)
  71.         # print("След анализ на групите: ancestors", ancestors)
  72.  
  73.  
  74.         # Следим коя е най-дългата първа група
  75.         if self.top_group_max_digits_count is None:
  76.             self.top_group_max_digits_count = top_group_digits_len
  77.         elif top_group_digits_len > self.top_group_max_digits_count:
  78.             self.top_group_max_digits_count = top_group_digits_len
  79.  
  80.         # В следния цикъл добавяме в ancestors и родителите на 1-вата група до една цифра
  81.         #print("top_group_digits_len", top_group_digits_len)
  82.         for len1 in range(top_group_digits_len-1, 0, -1):
  83.             #print("len1", len1)
  84.             code1 = top_group_digits[0: len1]
  85.             ancestors.append(code1)
  86.             ancestors_top_group_digits.append(len1)
  87.             ancestors_groups.append(1)
  88.         # print("След анализ на първата група: ancestors", ancestors)
  89.  
  90.         # В тази точка ancestors съдържа всички прародители до 1 цифра
  91.         # Сега обхождаме ancestors, за да добавим връзките дете-към-родител в self.struct
  92.         ancestors_len = len(ancestors)
  93.         for idx in range(ancestors_len):
  94.             child = ancestors[idx]
  95.             child_top_group_digits_len = ancestors_top_group_digits[idx]
  96.             child_groups = ancestors_groups[idx]
  97.             parent_idx = idx + 1
  98.             if parent_idx < ancestors_len:  # Бащата присъства в списъка
  99.                 parent = ancestors[parent_idx]  # Вземаме бащата от списъка
  100.             else:  # Бащата не е в списъка
  101.                 parent = ""  # Затова бащата е коренът
  102.  
  103.             if child in self.struct:
  104.                 # Няма нужда са се минава нататък през родителите му, понеже те вече са вписани
  105.                 #print(f"Вече е вписано, че {child} има родител {parent}, пропускаме останалото родословие")
  106.                 break
  107.             else:
  108.                 self.struct[child] = parent
  109.                 self.top_digits[child] = child_top_group_digits_len
  110.                 self.groups[child] = child_groups
  111.         # print('ancestors', ancestors)
  112.     def get_max_groups_count(self):
  113.         return self.max_groups_count
  114.  
  115.     def get_top_group_max_digits_count(self):
  116.         return self.top_group_max_digits_count
  117.  
  118.     def get_top_group_digits(self, code):
  119.         return self.top_digits[code]
  120.  
  121.     def get_groups(self, code):
  122.         return self.groups[code]
  123.  
  124.     def print_struct(self):
  125.         #up_struct = {x: y for y, x in self.struct.items()}  # ДА, ама НЕ, не може да се повтарят KEYS !!!
  126.         print('struct', self.struct)
  127.         #print('up_struct', up_struct)
  128.         # equal_parent = [value for value in self.struct if self.struct[value] == self.struct[value]]
  129.         # print('equal_parent', equal_parent)
  130.         # for value in equal_parent:
  131.         #     print(value, ':', self.struct[value])
  132.  
  133.         up_struct = {}
  134.         key_up_struct = ''
  135.         for key in self.struct:
  136.             if self.struct[key] == self.struct[key]:
  137.                 key_up_struct = self.struct[key]
  138.                 if key_up_struct in up_struct:
  139.                     up_struct[key_up_struct] += [key]
  140.                 elif key_up_struct not in up_struct:
  141.                     up_struct[key_up_struct] = [key]
  142.  
  143.         print('up_struct', up_struct)
  144.  
  145.  
  146.     # Връща list с само преките деца на даден code
  147.     def get_children(self, code):
  148.  
  149.         if self.children is None:
  150.             self.children = {}
  151.             # Ще бъде речник с изброени преки деца на всяка сметка {"150": ["150-1", "150-2", ...], ...}
  152.             for child in self.struct:
  153.                 parent = self.struct[child]
  154.                 if parent not in self.children:
  155.                     self.children[parent] = []
  156.                 self.children[parent].append(child)
  157.  
  158.         #print("self.children", self.children)
  159.  
  160.         if code in self.children: # Ако кодът има деца...
  161.             return self.children[code]  # връшаме ги
  162.  
  163.         # Щом сме стигнали дотук, кодът няма деца
  164.         return []   # Затова връщаме празен списък
  165.  
  166.     # Връща list с всички деца, внуци и т.н. на даден код
  167.     def get_all_children(self, code, max_depth = 999):
  168.         if max_depth == 0:
  169.             return []
  170.         max_depth -= 1
  171.         processed = []
  172.         children = self.get_children(code)
  173.         #print(f"АААААА {code} има за деца {children}")
  174.         depth = 0
  175.         while depth < max_depth:
  176.             children1 = []
  177.             for child in children:
  178.                 children1.append(child)
  179.                 if child in processed:  # вече сме добавили преките деца на това дете
  180.                     continue  # затова пропускаме
  181.                 children2 = self.get_children(child)
  182.                 #print(f"Ниво {depth}: {child} има за деца {children2}")
  183.                 processed.append(child)
  184.                 for child2 in children2:
  185.                     children1.append(child2)
  186.             #print(f"Заместваме {children} с {children1}")
  187.             children = children1
  188.             depth += 1
  189.         return children
  190.  
  191.     def get_parent(self, acc_code):
  192.         # print(f"acc_code {acc_code}")
  193.         if acc_code is None:
  194.             return None
  195.         if acc_code in self.struct[acc_code]:
  196.             return self.struct[acc_code]
  197.  
  198.     # В TrialBalanceFilter на много места се искаме да знаем дали code1 е дете на code2.
  199.     # Там правим сложни аналзи на групи цифри -- те трябва да се махнат.
  200.     # ТАМ има self.acc_tree, което е обект от клас AccountTree
  201.     # AccountTree tрябва да се сдобие с методи като is_child() по-долу,
  202.     # kойто да отговаря на тоя въпрос като използва своя self.struct
  203.     def is_child(self, child, parent):
  204.         # Трябва да връша true или false
  205.         pass
  206.     def is_parent(self, child, parent):
  207.         # Трябва да връша true или false
  208.         pass
  209.  
  210.     # Проверява колко нива е детето под родителя
  211.     def get_depth(self, child, parent):
  212.         pass
  213.  
  214.  
  215.  
  216. class TrialBalanceFilter(Tk):
  217.     def __init__(self):
  218.         super().__init__()
  219.         self.check_assets = IntVar()
  220.         self.check_amort = IntVar()
  221.         self.sel = int()
  222.         self.last_code_entry = None
  223.         self.last_amount_entry = None
  224.         self.entry_asset_prd_amount = IntVar()
  225.         self.acc_data = {}  # Сурови данни от Ексел
  226.         self.acc_data1 = {}  # Данни от Ексел, но в речник за ускорен достъп по код на сметката
  227.         self.acc_tree = AccountTree()  # Дърво на кодовете
  228.         self.scr_bar = None
  229.         self.account = None
  230.         self.calc_text = None
  231.         self.btn_plus = None
  232.         self.btn_min = None
  233.         self.var = IntVar()
  234.         self.current_value = StringVar()
  235.         self.current_value_tree = StringVar()
  236.         self.level_code = None
  237.         self.level_code_tree = None
  238.         self.level_tree = []
  239.         self.spin_box_tree_values = ["0"]
  240.         self.spin_box_tree = None
  241.         self.label_frame = None
  242.         self.label_frame_p = None
  243.         self.label_frame_r = None
  244.         self.v = StringVar()
  245.         self.v.trace("w", lambda *args: self.on_change_radio())
  246.         self.radiobutton_list = {'da': "ДА", 'mz': "МЗ", 'wz_zd': "Вземания", 'invest': "Инвест", 'money': "Пари", 'rbp': "РБП", 'drugi_a': "Други",
  247.                                  'sk': "СК", 'provision': 'Провизии', 'zd': "Задълж.", 'pbp': "ПБП", 'drugi_p': "Други",
  248.                                  'px': "Приходи", 'rx': 'Разходи', 'drugi_pr': "Други"
  249.                                  }
  250.         self.radios = {}
  251.  
  252.         self.mapped_types = {}  # Само тези, които потребителя директно е мапнал
  253.         self.eff_mapped_types = {}  # Всички, които са мапнати директно от потребителя или автоматично от нас
  254.  
  255.         self.correction_mode = False
  256.  
  257.     def on_change_radio(self):
  258.         # print("Стойността на реадиобутона сега е ", self.v.get())
  259.         pass
  260.  
  261.     def on_save(self):
  262.         mapped_type = self.v.get()
  263.         # print("Активният реадиобутон е ", mapped_type)
  264.         selected_acc_codes = self.treeview_acc.selection()
  265.         # print(f"Избрани са сметките {selected_acc_codes}")
  266.         # TODO Избраните сметки да се запомни типа в речник
  267.         # СЛЕДВА:
  268.         # Да се провери дали родителите на новомаркираните сметки имат същия тип.
  269.         # Ако имат същия тип -- добре
  270.         # Ако имат друг тип, родителите да получат тип "смесен"
  271.         for acc_code in selected_acc_codes:  # Цикъл през iid-тата на избраните редове
  272.             self.mapped_types[acc_code] = mapped_type
  273.             # На реда с iid=acc_code в колоната "type" слагаме човешкия етикет за mapped_type
  274.             self.treeview_acc.set(acc_code, "type", self.radiobutton_list[mapped_type])
  275.  
  276.         # print("self.mapped_types", self.mapped_types)
  277.  
  278.         self.disable_correction_mode()
  279.  
  280.         # Избрания тип да се отрази в колоната "вид"
  281.         # Всички с вид или да се деактивират и/или ако в селекцията има сметки с вид, да не работят бутоните
  282.         # Радиобутините се изчистват и забраняват
  283.  
  284.         # При маркирането на елемент, се маркират и деца/родители,
  285.         # Затова трябва наново да препопълни TreeView-то
  286.         # или поне да се ъпдейтне колоната с типа.
  287.         # Засега препопълваме:
  288.         self.populate_accounts()
  289.  
  290.     def on_correction(self):
  291.         self.enable_correction_mode()
  292.  
  293.     def enable_correction_mode(self):
  294.         self.correction_mode = True
  295.         # print("Изкл корекции")
  296.  
  297.     def disable_correction_mode(self):
  298.         self.correction_mode = False
  299.         # print("Вкл корекции")
  300.  
  301.     def radio_b(self):
  302.         self.v.set(' ')
  303.         place = self.label_frame
  304.         y = 0
  305.         for radio in self.radiobutton_list:
  306.             # print(f"radio {radio}")
  307.             self.radios[radio] = Radiobutton(place, text=self.radiobutton_list[radio], variable=self.v, value=radio, state='disabled' )
  308.             self.radios[radio].grid(row=y, column=0, padx=10, sticky='w')
  309.             y += 1
  310.             if 6 < y < 12:
  311.                 place = self.label_frame_p
  312.             elif 11 < y < 16:
  313.                 place = self.label_frame_r
  314.  
  315.     def update_account_type_radio(self):
  316.         selected_items = self.treeview_acc.selection()
  317.         #print(selected_items)
  318.         if len(selected_items) == 0:
  319.             # TODO Всички радиобутони да се забранят
  320.             for radioKey in self.radios:
  321.                 #print(f"radioKey {radioKey} self.radios[radioKey] {self.radios[radioKey]}")
  322.                 self.radios[radioKey].configure(state="disabled")
  323.         else:
  324.             for radioKey in self.radios:
  325.                 #print(f"radioKey {radioKey} self.radios[radioKey] {self.radios[radioKey]}")
  326.                 self.radios[radioKey].configure(state="normal")
  327.  
  328.     # Проверява дали сред избраните има вече маркирани/мапнати и ги де-избира
  329.     def verify_selection(self):
  330.         # print(f"verify_selection: correction_mode is {self.correction_mode}")
  331.         # Ако сме в режим корекция, няма да се бъркаме в селекцията на потребителя
  332.         # и той ще може да редактира дори вече маркираните/мапнати сметки
  333.         if (self.correction_mode):
  334.             # print("Режим корекция е включен, не пипаме селекцията")
  335.             return
  336.  
  337.         # print("Режим корекция не е включен, проверяваме селекцията")
  338.  
  339.         #print(f"{__name__}() .eff_mapped_types {self.eff_mapped_types}")
  340.  
  341.         selected_items = self.treeview_acc.selection()
  342.         # print("selected_items BBBB", selected_items)
  343.         for code in selected_items:
  344.             if code is not None:
  345.                 eff_type = self.get_eff_type(code)
  346.                 if eff_type is None:
  347.                     pass
  348.                 else:
  349.                     self.treeview_acc.selection_remove(code)
  350.             #if code in self.eff_mapped_types:
  351.             #    self.treeview_acc.selection_remove(code)
  352.  
  353.     def on_selected_acc(self):
  354.         self.verify_selection()
  355.         self.update_account_type_radio()
  356.  
  357.     def get_eff_type(self, acc_code):
  358.  
  359.         if acc_code is None:
  360.             return None
  361.  
  362.         # Ако типа е маркиран директно от юзъра, връщаме директно тоя тип
  363.         if acc_code in self.mapped_types:
  364.             return self.mapped_types[acc_code]
  365.  
  366.         # Ако юзъра е маркирал (пра)родител, връщаме типа на (пра)родителя
  367.         # Ще се качваме нагоре към родител и пра-родител докато:
  368.         #   * срещнем маркиран родител -- тогава ще върнем типа му
  369.         #   * опрем в корена -- значи нито един (пра)родител няма туп
  370.         parent = acc_code
  371.         # print(self.acc_tree)
  372.         while True:
  373.             # Един родител нагоре
  374.             parent = self.acc_tree.get_parent(parent)
  375.             # Опрели сме до корена
  376.             if parent is None:
  377.                 break  # Няма повече родители
  378.             if parent == "":
  379.                 break  # Няма повече родители
  380.  
  381.             # Намерили сме маркиран родител
  382.             if parent in self.mapped_types:
  383.                 return self.mapped_types[parent]
  384.  
  385.         # Засега си милим, че тук няма нужда да се гледат типовете на децата
  386.  
  387.         # Не сме намерили маркиран родител/дете, значи нямаме тип
  388.         return None
  389.  
  390.  
  391.     def update_eff_mapped_types(self):
  392.         self.eff_mapped_types = {}
  393.  
  394.         # Автоматично маркиране:
  395.         # A. Маркирани-от-юзъра сметки
  396.         # B. Всички немаркирани-от-юзъра деца на маркирани-от-юзъра сметки (най-близък маркиран-от-юзъра родител!)
  397.         # C. Немаркирани-от-юзъра родители, на когото всички деца са маркирани от юзъра с един тип (преки деца!)
  398.  
  399.         # Забрана срещу маркиране:
  400.         # A. Всички автоматично маркирани
  401.         # C. Немаркирани-от-юзъра родители, чиито всички деца са маркирани (преки деца!)
  402.  
  403.         for acc_code, acc_type in self.mapped_types.items():
  404.             # Кода е маркиран от юзъра, запомняме го:
  405.             self.eff_mapped_types[acc_code] = acc_type
  406.             children_codes = self.acc_tree.get_all_children(acc_code)
  407.             for child_code in children_codes:
  408.                 # Ако детето е посочено от юзъра, не го пипаме
  409.                 if child_code in self.mapped_types:
  410.                     continue
  411.                 # Детето не е посочено от юзъра, присвояваме му типа на родителя
  412.                 self.eff_mapped_types[child_code] = acc_type
  413.  
  414.     def populate_accounts(self):
  415.         #print("Сега ще извкаме self.current_value.get() А")
  416.         self.level_code = self.current_value.get()
  417.         #print("Сега ще извкаме self.current_value.get() Б")
  418.         self.level_code = self.current_value.get()
  419.         self.level_code = int(self.level_code)
  420.         self.level_code_tree = self.current_value_tree.get()
  421.         self.level_code_tree = int(self.level_code_tree)
  422.  
  423.         # TODO Пълним Treeview
  424.         self.treeview_acc.delete(*self.treeview_acc.get_children())
  425.         found_rows = []
  426.         total_sum_row = [
  427.             "", # code
  428.             "Обща сума", # name
  429.             0, #open_d
  430.             0, #open_c
  431.             0, #open_c
  432.             0, #turn_c
  433.             0, #close_d
  434.             0, #close_c
  435.         ]
  436.  
  437.         # Събиране на редовете според първия спин-бокс  БЛОК А
  438.         for code in self.acc_data1:
  439.             if code is None:
  440.                 continue
  441.  
  442.             acc_row = self.acc_data1[code]
  443.             # print("acc_row", acc_row)
  444.             top_group_digits = self.acc_tree.get_top_group_digits(code)
  445.             groups = self.acc_tree.get_groups(code)
  446.             if groups == 1 and top_group_digits == self.level_code:
  447.                 found_rows.append([
  448.                     code,
  449.                     acc_row['name'],
  450.                     acc_row['open_d'],
  451.                     acc_row['open_c'],
  452.                     acc_row['turn_d'],
  453.                     acc_row['turn_c'],
  454.                     acc_row['close_d'],
  455.                     acc_row['close_c'],
  456.                 ])
  457.                 # print("total_sum_row AAA", total_sum_row)
  458.                 if acc_row['open_d'] is not None:
  459.                     total_sum_row[2] += acc_row['open_d']
  460.                 if acc_row['open_c'] is not None:
  461.                     # print("+acc_row[open_c]", acc_row['open_c'])
  462.                     total_sum_row[3] += acc_row['open_c']
  463.                 if acc_row['turn_d'] is not None:
  464.                     total_sum_row[4] += acc_row['turn_d']
  465.                 if acc_row['turn_c'] is not None:
  466.                     total_sum_row[5] += acc_row['turn_c']
  467.                 if acc_row['close_d'] is not None:
  468.                     total_sum_row[6] += acc_row['close_d']
  469.                 if acc_row['close_c'] is not None:
  470.                     total_sum_row[7] += acc_row['close_c']
  471.  
  472.                 # Добавяме наследниците
  473.  
  474.  
  475.         # Генерираме изкуствен ред със сумите
  476.         for i in range(2, 8):
  477.             total_sum_row[i] = f"{total_sum_row[i]:.2f}"
  478.         # print("total_sum_row final", total_sum_row)
  479.         # print("acc_data", self.acc_data)
  480.         # Към списъка с намерените добавяме реда с общите суми:
  481.         found_rows.append(total_sum_row)
  482.  
  483.         # Събиране редове от следващите нива -- до дълбочината сочена от втория спин-бокс
  484.  
  485.         if self.level_code in [1, 2]:  # Първи спин-бокс 1 или 2      БЛОК Б1
  486.             # Тук втория спин-бокс ще бъде ограничен 0 или 1
  487.             if self.level_code_tree == 0:
  488.                 # print("Втория спин-бокс е 0, не вмъкваме редове")
  489.                 pass  # Няма нужда да вмъкваме нови редове
  490.             elif self.level_code_tree == 1:
  491.                 # print("Втория спин-бокс е 1, ще вмъкваме редове")
  492.                 found_rows1 = []
  493.                 for row in found_rows:
  494.                     found_rows1.append(row)
  495.                     parent_code = row[0]
  496.                     parent_code_len = len(parent_code)
  497.                     # print("parent_code", parent_code, "parent_code_len", parent_code_len)
  498.                     for i in range(0, len(self.acc_data)):
  499.                         if isinstance(self.acc_data[i]['code'], str):
  500.                             child_code = self.acc_data[i]['code']
  501.                             child_code_len = len(child_code)
  502.                             # print("child_code", child_code, "child_code_len", child_code_len)
  503.                             groups_digits = re.findall('[0-9]+', self.acc_data[i]['code'])
  504.                             len_diff = child_code_len - parent_code_len
  505.                             # child_code.startswith(parent_code) OK кода на детето да започва с този на родителя
  506.                             # и да е дълъг с 1 цифра повече
  507.                             # len(groups_digits) == 1 ОК се състои от 1 група цифри
  508.                             if len(groups_digits) == 1 and child_code.startswith(parent_code) and len_diff == 1:
  509.                                 # if len(self.acc_data[i]['code']) == self.level_code:
  510.                                 found_rows1.append([
  511.                                     self.acc_data[i]['code'],
  512.                                     self.acc_data[i]['name'],
  513.                                     self.acc_data[i]['open_d'],
  514.                                     self.acc_data[i]['open_c'],
  515.                                     self.acc_data[i]['turn_d'],
  516.                                     self.acc_data[i]['turn_c'],
  517.                                     self.acc_data[i]['close_d'],
  518.                                     self.acc_data[i]['close_c'],
  519.                                 ])
  520.                 # Подменяме оригиналния списък с новия
  521.                 found_rows = found_rows1
  522.  
  523.         else: # Първи спин-бокс 3 и по-високо, втория може да е всякакъв      БЛОК Б2
  524.             # Напр ако втория спин-бокс казва 2, това ще се завърти 2 пъти:
  525.             parent_codes = []
  526.             for depth in range(0, self.level_code_tree):  #range(0, 1)
  527.                 found_rows2 = []
  528.                 added_children = 0
  529.                 for row in found_rows:
  530.                     found_rows2.append(row)
  531.                     parent_code = row[0]
  532.                     parent_groups_digits = re.findall('[0-9]+', parent_code)
  533.                     parent_groups_digits_len = len(parent_groups_digits)
  534.                     if parent_code == "":  # Пропускаме, понеже това е реда с тотала
  535.                         continue
  536.                     if parent_code in parent_codes:  # Пропускаме, ако преките деца на този родител са вече добавени
  537.                         continue
  538.                     # Ако code="101-3", то code_groups_digits=["101", "3"]
  539.                     # Желан брой грипи цифри, които искаме детето да има
  540.                     #print("parent_code", parent_code, "len(self.acc_data)", len(self.acc_data))
  541.                     for i in range(0, len(self.acc_data)):
  542.                         added_children = 0
  543.                         if isinstance(self.acc_data[i]['code'], str):
  544.                             child_code = self.acc_data[i]['code']
  545.                             #print("child_code", child_code)
  546.                             groups_digits = re.findall('[0-9]+', self.acc_data[i]['code'])
  547.                             groups_digits_len = len(groups_digits)
  548.  
  549.                             diff_groups_len = groups_digits_len - parent_groups_digits_len
  550.                             # child_code.startswith(parent_code) OK кода на детето да започва с този на родителя
  551.                             # groups_digits_len = wanted_groups_count ОК Броя групи цифри в кода на детето да е равен на желания
  552.                             is_child = True
  553.                             if diff_groups_len == 1:  # Първо условие е детето да има точно 1 група повече от родителя
  554.                                 # Проверяваме дали първите групи на детето съвпадат с родителските
  555.                                 for idx in range(parent_groups_digits_len):
  556.                                     parent_digits = parent_groups_digits[idx]
  557.                                     child_digits = groups_digits[idx]
  558.                                     if parent_digits != child_digits:  # Дори една група да не съвпада...
  559.                                         is_child = False  # ...значи не е дете
  560.                                         break
  561.                             else:  # Детето е с неподходящ брой групи...
  562.                                 is_child = False  # ...значи не е дете
  563.  
  564.                             if is_child:
  565.                                 if child_code in ["100", "401-74-13", "601-11-1"]:
  566.                                     pass
  567.                                     # print(f"Добавяме дете {child_code} заради родител {parent_code}")
  568.  
  569.                                 #print(f"Добавяме дете {child_code} към родител {parent_code}")
  570.                                 added_children += 1
  571.                                 # if len(self.acc_data[i]['code']) == self.level_code:
  572.                                 found_rows2.append([
  573.                                     self.acc_data[i]['code'],
  574.                                     self.acc_data[i]['name'],
  575.                                     self.acc_data[i]['open_d'],
  576.                                     self.acc_data[i]['open_c'],
  577.                                     self.acc_data[i]['turn_d'],
  578.                                     self.acc_data[i]['turn_c'],
  579.                                     self.acc_data[i]['close_d'],
  580.                                     self.acc_data[i]['close_c'],
  581.                                 ])
  582.                     # Запомняме, че вече сме добавили преките деца на този родител
  583.                     parent_codes.append(parent_code)
  584.                 # print("len(self.acc_data)", len(self.acc_data))
  585.                 # print(f"depth {depth} Предното ниво имаше {len(found_rows)} с добавени {added_children} деца новото ниво редовете са {len(found_rows2)}")
  586.                 found_rows = found_rows2
  587.  
  588.         # TODO Поставяне на намерените редове в таблицата
  589.         count_rows = len(found_rows)
  590.         # self.treeview_acc.config(height=count_rows)
  591.         # print('found_rows', found_rows)
  592.         self.eff_mapped_types = {}
  593.         i = 0
  594.         for found_row in found_rows:
  595.             code = found_row[0]  # Код за който се чудим има ли зададен тип
  596.             type = None
  597.             type_human = ""
  598.             if code in self.mapped_types:  # Има зададен тип директно за този код
  599.                 type = self.mapped_types[code]
  600.                 type_human = self.radiobutton_list[type]
  601.             else:  # Няма зададен тип директно за този код
  602.                 # Затова ще търсим дали сред мапнатите кодове има родител на този, за който се чудим
  603.                 groups_digits = re.findall('[0-9]+', code)
  604.                 groups_digits_len = len(groups_digits)
  605.                 if groups_digits_len == 1:  # Чудим се за код, който има само 1 група цифри
  606.                     for mapped_code in self.mapped_types:
  607.                         if code.startswith(mapped_code):
  608.                             type = self.mapped_types[mapped_code]
  609.                             type_human = self.radiobutton_list[type]
  610.                             break
  611.                 else:  # Чудим се за код, който има повече от 1 група цифри -- дали е дете на мапнат код
  612.                     for mapped_code in self.mapped_types:  # Върви през всички кодове, мапнати от потребителя
  613.                         mapped_groups_digits = re.findall('[0-9]+', mapped_code)  # Групи цифри в код, мапнат от потребителя
  614.                         mapped_groups_digits_len = len(mapped_groups_digits)  # Брой групи цифри
  615.                         if mapped_groups_digits_len < groups_digits_len:  # Кода за който се чудим може да е дете на мапнат код
  616.                             # Да проверим дали групите съвпадат
  617.                             is_child = True
  618.                             for idx in range(mapped_groups_digits_len):
  619.                                 parent_digits = mapped_groups_digits[idx]
  620.                                 child_digits = groups_digits[idx]
  621.                                 if parent_digits != child_digits:
  622.                                     is_child = False
  623.                                     break
  624.  
  625.                             if is_child:
  626.                                 type = self.mapped_types[mapped_code]
  627.                                 type_human = self.radiobutton_list[type]
  628.                                 break
  629.                 # На този етап сме проверили дали code е дете на мапнат код
  630.                 if type is None:  # Не е дете -- значи трябва да проверим дали е родител на мапнати кодове
  631.                     pass
  632.  
  633.             if type is not None:  # Успели сме да намерим тип
  634.                 self.eff_mapped_types[code] = type
  635.  
  636.             found_row5 = []
  637.             found_row5.append(type_human)
  638.             found_row5.append(found_row[0])
  639.             found_row5.append(found_row[1])
  640.             found_row5.append(found_row[2])
  641.             found_row5.append(found_row[3])
  642.             found_row5.append(found_row[4])
  643.             found_row5.append(found_row[5])
  644.             found_row5.append(found_row[6])
  645.             found_row5.append(found_row[7])
  646.             iid = found_row[0]
  647.             tags = []
  648.             if found_row[0] == "":
  649.                 tags = ["total"]
  650.                 iid = "total"
  651.             self.treeview_acc.insert('', END, values=found_row5, tags=tags, iid=iid)  # Добавя ред в Treeview
  652.             i += 1
  653.             if count_rows > 30:
  654.                 self.treeview_acc.configure(height=30)
  655.             else:
  656.                 self.treeview_acc.configure(height=count_rows)
  657.  
  658.         # print("self.eff_mapped_types", self.eff_mapped_types)
  659.  
  660.     def spin_box_select(self):
  661.         # print("Викаме elf.current_value.get() В")
  662.         self.level_code = self.current_value.get()
  663.         self.level_code = int(self.level_code)
  664.  
  665.         self.populate_accounts()
  666.  
  667.     def filter(self):   # TODO Начало
  668.         json_file_io = JsonFileIo(file_name=registry["trial_balance_file_name"])
  669.         self.acc_data = json_file_io.read_content()
  670.  
  671.         # Инициализираме дървото с всички кодове от Ексел
  672.         for acc_row in self.acc_data:
  673.             acc_code = acc_row["code"]
  674.             self.acc_data1[acc_code] = acc_row
  675.             # Прескачаме реда със сумата, както и евентуални паразитни редове без код
  676.             if acc_code is None or acc_code == "":
  677.                 continue
  678.             self.acc_tree.add_code(acc_code)
  679.  
  680.         self.acc_tree.print_struct()
  681.  
  682.  
  683.         self.title('Оборотна ведомост')
  684.         self.geometry('1200x840+200+10')  # 1060
  685.         self.resizable(False, False)
  686.         self.attributes('-topmost', 'true')
  687.  
  688.         # TODO Label frame, Видове сметки
  689.         self.label_frame = LabelFrame(self, text='Актив', relief=GROOVE, bd=2, width=10, font=('Timesbd', 9, 'italic'), fg='blue')
  690.         self.label_frame.place(x=20, y=60)
  691.         self.label_frame_p = LabelFrame(self, text='Пасив', relief=GROOVE, bd=2, width=10, font=('Timesbd', 9, 'italic'), fg='blue')
  692.         self.label_frame_p.place(x=20, y=270)
  693.         self.label_frame_r = LabelFrame(self, text='Пх/Рх', relief=GROOVE, bd=2, width=10, font=('Timesbd', 9, 'italic'), fg='blue')
  694.         self.label_frame_r.place(x=20, y=430)
  695.  
  696.         # TODO Radio buttons
  697.         self.radio_b()
  698.  
  699.         # TODO Spinbox Синтетични сметки
  700.         spin_box_max = self.acc_tree.get_top_group_max_digits_count()
  701.         spin_box = Spinbox(self, from_=1, to=spin_box_max,
  702.             width=8, justify='center', textvariable=self.current_value, wrap=True)
  703.         self.current_value.set(value='3')
  704.         self.current_value.trace("w", lambda *args: self.spin_box_select())  # Закача реакция при промяна на спинбокса
  705.         self.current_value.trace("r", lambda *args: print("Някой чете стойността"))  # За дебъг
  706.         spin_box.place(x=200, y=30)
  707.  
  708.         # TODO Spinbox Аналитични сметки
  709.         spin_box_max = self.acc_tree.get_max_groups_count() - 1
  710.         self.spin_box_tree = Spinbox(self, command=self.populate_accounts, from_=0, to=spin_box_max,
  711.             width=8, justify='center', textvariable=self.current_value_tree, wrap=True)
  712.         self.current_value_tree.set(value='0')
  713.         self.spin_box_tree.place(x=280, y=30)
  714.  
  715.         # TODO TREEVIEW
  716.         self.tv_frame = Frame(self)
  717.         self.tv_frame.place(x=150, y=50)
  718.         cols = ("type", "code", "acc_name", "open_d", 'open_c', 'turn_d', 'turn_c', 'close_d', 'close_c')
  719.         self.treeview_acc = Treeview(self.tv_frame, columns=cols, show="headings", height=0)
  720.         self.treeview_acc.heading('# 1', text='вид', anchor='w')
  721.         self.treeview_acc.heading('# 2', text='код', anchor='w')
  722.         self.treeview_acc.heading('# 3', text='сметка', anchor='w')
  723.         self.treeview_acc.heading('# 4', text='НС Дебит', anchor='center')
  724.         self.treeview_acc.heading('# 5', text='НС Кредит', anchor='center')
  725.         self.treeview_acc.heading('# 6', text='Об. Дебит', anchor='center')
  726.         self.treeview_acc.heading('# 7', text='Об. Кредит', anchor='center')
  727.         self.treeview_acc.heading('# 8', text='КС Дебит', anchor='center')
  728.         self.treeview_acc.heading('# 9', text='КС Кредит', anchor='center')
  729.         self.treeview_acc.tag_configure('total', font=('Timesbd', 9, 'bold'))
  730.         self.treeview_acc.bind('<ButtonRelease-1>', lambda e: self.on_selected_acc())
  731.  
  732.         # treeview_acc.configure(background='SystemButtonFace')   # 'systemWindowBody'
  733.         style = Style(self)  # #D3D3D3, 'default', 'alt', 'clam', #40E0D0
  734.         style.theme_use('default')
  735.         # print("style.theme_use() AAA", style.theme_use())
  736.         style.configure('Treeview',
  737.                         background='lightgrey',
  738.                         foreground='black',
  739.                         rowheight=25,
  740.                         fieldbackground='red'
  741.                         )
  742.  
  743.         # Change selected color
  744.         style.map('Treeview', background=[('selected', 'blue')])
  745.         # TODO Scroll_bar
  746.         self.scr_bar = Scrollbar(self.tv_frame, orient=VERTICAL)
  747.         self.scr_bar.pack(side=RIGHT, fill=Y)
  748.         self.treeview_acc.config(yscrollcommand=self.scr_bar.set)
  749.         self.scr_bar.config(command=self.treeview_acc.yview, bg="red", activebackground="orange")
  750.         self.treeview_acc.column("type", width=60, anchor='w')
  751.         self.treeview_acc.column("code", width=60, anchor='w')
  752.         self.treeview_acc.column("acc_name", width=300, anchor='w')
  753.         self.treeview_acc.column("open_d", width=100, anchor='e')
  754.         self.treeview_acc.column("open_c", width=100, anchor='e')
  755.         self.treeview_acc.column("turn_d", width=100, anchor='e')
  756.         self.treeview_acc.column("turn_c", width=100, anchor='e')
  757.         self.treeview_acc.column("close_d", width=100, anchor='e')
  758.         self.treeview_acc.column("close_c", width=100, anchor='e')
  759.         self.treeview_acc.pack(side=LEFT)
  760.  
  761.         self.spin_box_select()
  762.  
  763.         # TODO Button Запис
  764.         butt_save = Button(self, text='Запис', font=('Bookman Old Style Bold', 9), fg='red', height=1, width=11)
  765.         butt_save.place(x=20, y=550)
  766.         butt_save.bind('<ButtonRelease-1>', lambda e: self.on_save())
  767.  
  768.         # TODO Button OK
  769.         butt_ok = Button(self, text='OK', font=('Bookman Old Style Bold', 8), fg='green', height=1, width=11)
  770.         butt_ok.place(x=20, y=580)
  771.         butt_ok.bind('<ButtonRelease-1>')
  772.         # TODO Button Корекции
  773.         butt_ok = Button(self, text='Корекции', font=('Bookman Old Style Bold', 8), fg='darkred', height=1, width=10)
  774.         butt_ok.place(x=20, y=764)
  775.         butt_ok.bind('<ButtonRelease-1>', lambda e: self.on_correction())
  776.         # TODO Button Помощ
  777.         butt_help = Button(self, text='Помощ', font=('Bookman Old Style Bold', 8), fg='black', height=1, width=10)
  778.         butt_help.place(x=20, y=794)
  779.         butt_help.bind('<ButtonRelease-1>')
  780.  
  781.  
  782.  
  783.         self.mainloop()
  784.  
  785.  
  786. if __name__ == '__main__':
  787.  
  788.     #acc_tree = AccountTree()
  789.     #acc_tree.add_code("123-456.789/435 0987")
  790.     #acc_tree.print_struct()
  791.     #acc_tree.add_code("123-456.789/435 0987 888 999")
  792.     #acc_tree.print_struct()
  793.     #acc_tree.add_code("123-456.789/435 0989")
  794.  
  795.     # code = "123"
  796.     # children = acc_tree.get_children(code)
  797.     # print(f'children of {code}: ', children)
  798.     # code = "123-456.789/435"
  799.     # children = acc_tree.get_children(code)
  800.     # print(f'children of {code}: ', children)
  801.     #
  802.     # code = "123"
  803.     # depth = 0
  804.     # children = acc_tree.get_all_children(code, depth)
  805.     # print(f'Всички деца на {code} до дълбочина {depth}: ', children)
  806.     #
  807.     # code = "123"
  808.     # depth = 1
  809.     # children = acc_tree.get_all_children(code, depth)
  810.     # print(f'Всички деца на {code} до дълбочина {depth}: ', children)
  811.     #
  812.     # code = "123"
  813.     # depth = 2
  814.     # children = acc_tree.get_all_children(code, depth)
  815.     # print(f'Всички деца на {code} до дълбочина {depth}: ', children)
  816.     #
  817.     # code = "123"
  818.     # depth = 3
  819.     # children = acc_tree.get_all_children(code, depth)
  820.     # print(f'Всички деца на {code} до дълбочина {depth}: ', children)
  821.  
  822.     # acc_tree.print_struct()
  823.     # code = "123-456.789/435 0989"
  824.     # a = acc_tree.get_top_group_digits(code)
  825.     # b = acc_tree.get_groups(code)
  826.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  827.     # code = "123-456.789/435"
  828.     # a = acc_tree.get_top_group_digits(code)
  829.     # b = acc_tree.get_groups(code)
  830.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  831.     # code = "123-456.789"
  832.     # a = acc_tree.get_top_group_digits(code)
  833.     # b = acc_tree.get_groups(code)
  834.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  835.     # code = "123-456"
  836.     # a = acc_tree.get_top_group_digits(code)
  837.     # b = acc_tree.get_groups(code)
  838.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  839.     # code = "123"
  840.     # a = acc_tree.get_top_group_digits(code)
  841.     # b = acc_tree.get_groups(code)
  842.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  843.     # code = "12"
  844.     # a = acc_tree.get_top_group_digits(code)
  845.     # b = acc_tree.get_groups(code)
  846.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  847.     # code = "1"
  848.     # a = acc_tree.get_top_group_digits(code)
  849.     # b = acc_tree.get_groups(code)
  850.     # print(f"Сметка {code} има {a} цифри в топ-групата и {b} групи общо" )
  851.  
  852.  
  853.     calc = TrialBalanceFilter()
  854.     calc.filter()
  855.  
  856.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement