Advertisement
ALEXANDAR_GEORGIEV

account_tree

Dec 3rd, 2022 (edited)
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.13 KB | Source Code | 0 0
  1. import re
  2.  
  3.  
  4. class AccountTree():
  5.     def __init__(self):
  6.         self.struct = {}  # На Всяко дете, кой е прекия родител
  7.         self.children = None
  8.         self.top_digits = {}  # На коя сметка колко цифри има в първата група
  9.         self.groups = {}  # На коя сметка колко групи има
  10.         self.top_group_min_digits_count = None  # Беше None
  11.         self.top_group_max_digits_count = None  # Беше None
  12.         self.max_groups_count = None  # Беше None
  13.         self.max_depth = None
  14.         self.all_accs = []
  15.         self.all_real_accs = []
  16.  
  17.     # code е нешо от типа "123-456-789"
  18.     def add_code(self, code):  # TODO IZPOLZWAM 1 Прави STRUCT !!!
  19.         if code not in self.all_real_accs:
  20.             self.all_real_accs.append(code)
  21.         self.children = None  # Нулираме кеша на родители-деца
  22.         # "123-456-789" дава ["123", "456", "789"]
  23.         groups_digits = re.findall('[0-9]+', code)
  24.         # "123-456-789" дава ["-", "-"]
  25.         groups_seps = re.findall('[^0-9]+', code)
  26.         groups_digits_len = len(groups_digits)
  27.         # Следим максималния брой аналитични сметки
  28.         if self.max_groups_count is None:
  29.             self.max_groups_count = groups_digits_len
  30.         elif groups_digits_len > self.max_groups_count:  # МОже би трябва да е IF ???
  31.             self.max_groups_count = groups_digits_len
  32.             # От този код трябва да построим този клон:
  33.         # 1
  34.         # 12     -------TODO----- ВАЖНО -> ТОП родителя е този, който е подаден от Excel с най-малко цифри !!!
  35.         # 123    -------TODO---- -> Няма смисъл да раздробяваме на по-малки кодове сметките в Оборотната ведомост !
  36.         # 123-456
  37.         # 123-456-789
  38.         # Напр 123  # groups_digits е списък с групите
  39.         top_group_digits = groups_digits[0]  # Първата група
  40.         # print("top_group_digits", top_group_digits)
  41.         top_group_digits_len = len(top_group_digits)  # Брой цифри в 1-вата група
  42.         # В ancestors ще трупаме [сметка, родител, пра-родител и т.н.] но по цели групи от цифри
  43.         ancestors = []
  44.         ancestors_top_group_digits = []
  45.         ancestors_groups = []
  46.         # За ["123", "456", "789"] len1 ще мине през 3, 2, 1
  47.         for len1 in range(groups_digits_len, 0, -1):
  48.             # len1=3 дава ["123", "456", "789"]
  49.             # len1=2 дава ["123", "456"]
  50.             # len1=1 дава ["123"]
  51.             code1 = ""
  52.             # len1=3, то idx ше мине през 0, 1, 2
  53.             # len1=2, то idx ше мине през 0, 1
  54.             # len1=1, то idx ше мине през 0
  55.             for idx in range(len1):
  56.                 if code1 != "":
  57.                     code1 += groups_seps[idx - 1]
  58.                     pass
  59.                 code1 += groups_digits[idx]
  60.             ancestors.append(code1)
  61.             ancestors_top_group_digits.append(top_group_digits_len)
  62.             ancestors_groups.append(len1)
  63.         # Следим коя е най-дългата първа група
  64.         if self.top_group_max_digits_count is None:
  65.             self.top_group_max_digits_count = top_group_digits_len
  66.         elif top_group_digits_len > self.top_group_max_digits_count:
  67.             self.top_group_max_digits_count = top_group_digits_len
  68.         # Следим коя е най-късата първа група
  69.         if self.top_group_min_digits_count is None:
  70.             self.top_group_min_digits_count = top_group_digits_len
  71.         elif top_group_digits_len < self.top_group_min_digits_count:
  72.             self.top_group_min_digits_count = top_group_digits_len
  73.         # В следния цикъл добавяме в ancestors и родителите на 1-вата група до една цифра
  74.         for len1 in range(top_group_digits_len - 1, 0, -1):
  75.             # print("len1", len1)
  76.             code1 = top_group_digits[0: len1]
  77.             ancestors.append(code1)
  78.             ancestors_top_group_digits.append(len1)
  79.             ancestors_groups.append(1)
  80.         # В тази точка ancestors съдържа всички прародители до 1 цифра
  81.         # Сега обхождаме ancestors, за да добавим връзките дете-към-родител в self.struct
  82.         ancestors_len = len(ancestors)
  83.         if self.max_depth is None:
  84.             self.max_depth = ancestors_len
  85.         elif ancestors_len > self.max_depth:
  86.             self.max_depth = ancestors_len
  87.         for idx in range(ancestors_len):
  88.             child = ancestors[idx]
  89.             child_top_group_digits_len = ancestors_top_group_digits[idx]
  90.             child_groups = ancestors_groups[idx]
  91.             parent_idx = idx + 1
  92.             if parent_idx < ancestors_len:  # Бащата присъства в списъка
  93.                 parent = ancestors[parent_idx]  # Вземаме бащата от списъка
  94.             else:  # Бащата не е в списъка
  95.                 parent = ""  # Затова бащата е коренът
  96.             if child in self.struct:
  97.                 # Няма нужда са се минава нататък през родителите му, понеже те вече са вписани
  98.                 break
  99.             else:
  100.                 if len(child) > 0 and child not in self.all_accs: # TODO -> НЕ СЪДЪРЖА ВСИЧКИ СМЕТКИ !!!
  101.                     self.all_accs.append(parent)
  102.                 if len(parent) > 0 and parent not in self.all_accs:
  103.                     self.all_accs.append(parent)
  104.  
  105.                 self.struct[child] = parent
  106.                 self.top_digits[child] = child_top_group_digits_len
  107.                 self.groups[child] = child_groups
  108.  
  109.     def get_max_groups_count(self):
  110.         return self.max_groups_count
  111.  
  112.     def get_top_group_max_digits_count(self):
  113.         return self.top_group_max_digits_count
  114.  
  115.     def get_top_group_digits(self, code):
  116.         return self.top_digits[code]
  117.  
  118.     def get_groups(self, code):
  119.         return self.groups[code]
  120.  
  121.     def get_max_depth(self):
  122.         return self.max_depth
  123.  
  124.     # Връща дълбочината на дадена сметка в дървото
  125.     def get_depth(self, code):  # TODO Izpolzwam 2
  126.         if code not in self.struct:  # Няма таква сметка
  127.             return None
  128.         # Такава сметка има
  129.         depth = 0
  130.         next_code = code
  131.         while next_code in self.struct:
  132.             depth += 1
  133.             next_code = self.struct[next_code]
  134.         return depth
  135.  
  136.     def print_struct(self):  # TODO up_struct = children ????
  137.         print('struct', self.struct)  # struct {'10-100-20-25': '10-100-20', '10-100-20': '10-100', '10-100': '10', '10': '1', '1': ''}
  138.         up_struct = {}
  139.         for key in self.struct:
  140.             if self.struct[key] == self.struct[key]:
  141.                 key_up_struct = self.struct[key]
  142.                 if key_up_struct in up_struct:
  143.                     up_struct[key_up_struct] += [key]
  144.                 elif key_up_struct not in up_struct:
  145.                     up_struct[key_up_struct] = [key]
  146.         # Сортиране на децата -> List in value
  147.         for parent_acc in up_struct:
  148.             up_struct[parent_acc].sort()
  149.  
  150.     # Връща list с само преките деца на даден code
  151.     def get_children(self, code):
  152.         if self.children is None:
  153.             self.children = {}
  154.             # Ще бъде речник с изброени преки деца на всяка сметка {"150": ["150-1", "150-2", ...], ...}
  155.             for child in self.struct:
  156.                 parent = self.struct[child]
  157.                 if parent not in self.children:
  158.                     self.children[parent] = []
  159.                 self.children[parent].append(child)
  160.         if code in self.children:  # Ако кодът има деца...
  161.             return self.children[code]  # връшаме ги Връща лист !
  162.         # Щом сме стигнали дотук, кодът няма деца
  163.         return []  # Затова връщаме празен списък
  164.  
  165.     # Връща list с всички деца, внуци и т.н. на даден код
  166.     def get_all_children(self, code, max_depth=None):
  167.         if max_depth is None:
  168.             max_depth = self.max_depth
  169.         if max_depth == 0:
  170.             return []
  171.         max_depth -= 1
  172.         processed = []
  173.         children = self.get_children(code)
  174.         # print(f"АААААА {code} има за деца {children}")
  175.         depth = 0
  176.         while depth < max_depth:
  177.             # print(f"get_all_children() depth {depth}")
  178.             children1 = []
  179.             children_on_this_depth = 0
  180.             for child in children:
  181.                 children1.append(child)
  182.                 if child in processed:  # вече сме добавили преките деца на това дете
  183.                     continue  # затова пропускаме
  184.                 children2 = self.get_children(child)
  185.                 # print(f"Ниво {depth}: {child} има за деца {children2}")
  186.                 children_on_this_depth += len(children2)
  187.                 processed.append(child)
  188.                 for child2 in children2:
  189.                     children1.append(child2)
  190.             if children_on_this_depth == 0:
  191.                 break
  192.             children = children1
  193.             depth += 1
  194.         return children
  195.  
  196.     def get_parent(self, acc_code):
  197.         if acc_code is None or acc_code == '':
  198.             return None
  199.         if acc_code in self.struct:  # Писано от мен
  200.             return self.struct[acc_code]
  201.  
  202.     def get_all_parents(self, acc_code):
  203.         parents = []
  204.         # Почваме от даения код, вземаме родителя, после неговия родител и т.н. докато опрем в корена
  205.         browse_code = acc_code
  206.         while True:
  207.             parent = self.get_parent(browse_code)
  208.             if parent == "" or parent == None or len(parent) < self.top_group_min_digits_count:  # Опряли сме в корена на дървото
  209.                 break  # няма повече родители
  210.             parents.append(parent)  # Добавяме родителя в списъка с предци
  211.             browse_code = parent
  212.         return parents
  213.  
  214.     # Листа на дървото = тези които нямат деца = най-дълбоки деца
  215.     def get_leaves(self):
  216.         # всички които имат родители са KEY в struct
  217.         # всики които имат деца са VALUE в struct
  218.         # значи листа са тези които ги няма в стойностите, но ги има в ключовете
  219.         values = self.struct.values() # list1
  220.         keys = self.struct.keys()  # list2
  221.         #leaves = има в keys, но ги няма в values
  222.         leaves = set(keys).difference(values)
  223.         return leaves
  224.  
  225.     def get_leaves_bycode(self, list_accs: list):
  226.         list_leaves_bycode = []
  227.         # TODO -> Подавам код и проверяван дали е родител
  228.         print('get_leaves_bycode list_accs: ', list_accs)
  229.         for leaf in list_accs:
  230.             is_parent = self.is_parent(leaf)
  231.             if not is_parent:
  232.                 list_leaves_bycode.append(leaf)
  233.         return list_leaves_bycode
  234.  
  235.     def get_all_deepest_parents(self):
  236.         leaves = self.get_leaves()
  237.         deepest_parents = []
  238.         for leaf in leaves:
  239.             parent = self.get_parent(leaf)
  240.             if parent in deepest_parents:   # Добавено от мен.
  241.                 continue
  242.             deepest_parents.append(parent)
  243.         return deepest_parents
  244.  
  245.     def get_deepest_parents(self, acc_code):
  246.         all_children = self.get_all_children(acc_code)  # Всичко под acc
  247.         leaves = self.get_leaves()  # Всички листа на цялото дърво
  248.         leaves_under_acc = list(set(all_children).intersection(leaves))
  249.         # Остава минем през всяко листо в leaves_under_acc и да му вземем родителя
  250.         deepest_parents = []  # Тук ще трупаме родителите на листата
  251.         for leaf in leaves_under_acc:
  252.             parent = self.get_parent(leaf)  # родител на листото
  253.             if parent not in deepest_parents:  # избягваме повторения
  254.                 deepest_parents.append(parent)  # добавяме родителя на листото
  255.         return deepest_parents
  256.  
  257.     def get_top_parents(self):
  258.         zero = self.get_children('')  # top1 ще съдържа децата на корена -- т.е. на практика едноцифрените
  259.         top_parents = []  # Тука ще изсипем децата на децата на корена -- т.е. на практика двуцифрените
  260.         for child in zero:  # за всяко дете на корена
  261.             # взимаме му децата и ги изсипваме в tops2
  262.             top_parents += self.get_children(child)
  263.         return top_parents
  264.  
  265.     def get_top_parents_of_type(self, mapp_accs, acc_type):
  266.         leaves = self.get_leaves()
  267.         found = []
  268.         for leaf in leaves:
  269.             ancestors = self.get_all_parents(leaf) # връща ги от най-дълбок към най-висок
  270.             oldest_of_type = None
  271.             for ancestor in ancestors:
  272.                 if ancestor in mapp_accs:
  273.                     ancestor_types = mapp_accs[ancestor]
  274.                     if len(ancestor_types) == 1 and ancestor_types[0] == acc_type:
  275.                         oldest_of_type = ancestor
  276.             if oldest_of_type is not None and oldest_of_type not in found:
  277.                 found.append(oldest_of_type)
  278.         return found
  279.  
  280.     def is_child(self, acc_code):
  281.         test_for_parent = self.get_parent(acc_code)
  282.         if test_for_parent is None:
  283.             return False
  284.         return True
  285.  
  286.     def is_parent(self, acc_code):
  287.         print('is_parent(self, acc_code)', acc_code)
  288.         test_for_children = self.get_children(acc_code)
  289.         if len(test_for_children) > 0:
  290.             return True
  291.         return False
  292.  
  293.     def compare_lists(self, list_1, list_2):
  294.         l1 = list_1.sort()
  295.         l2 = list_2.sort()
  296.         if l1==l2:
  297.             return True
  298.         return False
  299.  
  300.     def asymmetric_compare_lists(self, list_1, list_2):
  301.         diff_1 = list(set(list_1) - set(list_2))
  302.         if len(diff_1) > 0:
  303.             return diff_1
  304.         return None
  305.  
  306.     def get_all_acc(self):
  307.         return self.all_accs # TODO -> НЕ РАБОТИ !
  308.  
  309.     def get_unmapped_acc(self, mapp_accs):
  310.         list_unmapped_acc = []
  311.         for code in self.all_accs:
  312.             if code not in mapp_accs:
  313.                 if code not in list_unmapped_acc:
  314.                     list_unmapped_acc.append(code)
  315.         return list_unmapped_acc
  316.  
  317.     def get_unadded_acc(self, added_accs, all_accs):
  318.         list_unadded_acc = []
  319.         for code in all_accs:
  320.             if code not in added_accs:
  321.                 if code not in list_unadded_acc:
  322.                     list_unadded_acc.append(code)
  323.         return list_unadded_acc
  324.  
  325.     def is_real_acc(self, acc_code):
  326.         if acc_code in self.all_real_accs:
  327.             return True
  328.         return False
  329.  
  330.     def get_real_accounts(self, acc_codes):
  331.         return [a for a in acc_codes if a in self.all_real_accs]
  332.  
  333.  
  334. if __name__ == '__main__':
  335.     acc_tree = AccountTree()
  336.     test = acc_tree.is_parent("10")
  337.     print(test)
  338.     acc_tree.add_code("200-1")
  339.     acc_tree.print_struct()
  340.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement