Преглед на файлове

Merge remote-tracking branch 'origin/master'

Nico Ruhnke преди 2 години
родител
ревизия
6a5f801b2b

+ 0 - 0
Image2PDF/img2pdf_with_package.py → Image2PDF/img2pdf_main.py


+ 8 - 0
README.md

@@ -0,0 +1,8 @@
+#Installings
+
+pip install img2pdf styleframe xlsxwriter pysimplegui datetime SQLAlchemy
+conda install python-docx
+
+
+## Version requirements
+SQLAlchemy 1.4 or Higher

+ 0 - 4
fast_excel_to_bill/Readme

@@ -1,4 +0,0 @@
-#Installings
-
-pip install img2pdf
-conda install python-docx

+ 0 - 53
fast_excel_to_bill/bill_doc/create_custom_bill_doc.py

@@ -1,53 +0,0 @@
-from docx import Document
-from docx.shared import Inches
-import time
-
-'https://python-docx.readthedocs.io/en/latest/user/text.html'
-
-def create_custome_doc_file():
-    '''
-    :return: Bill as Doc file
-    '''
-
-
-
-document = Document()
-
-document.add_heading('Document Title', 0)
-
-p = document.add_paragraph('A plain paragraph having some ')
-p.add_run('bold').bold = True
-p.add_run(' and some ')
-p.add_run('italic.').italic = True
-
-document.add_heading('Heading, level 1', level=1)
-document.add_paragraph('Intense quote', style='Intense Quote')
-
-document.add_paragraph(
-    'first item in unordered list', style='List Bullet'
-)
-document.add_paragraph(
-    'first item in ordered list', style='List Number'
-)
-
-records = (
-    (3, '101', 'Spam'),
-    (7, '422', 'Eggs'),
-    (4, '631', 'Spam, spam, eggs, and spam')
-)
-
-table = document.add_table(rows=1, cols=3)
-hdr_cells = table.rows[0].cells
-hdr_cells[0].text = 'Qty'
-hdr_cells[1].text = 'Id'
-hdr_cells[2].text = 'Desc'
-for qty, id, desc in records:
-    row_cells = table.add_row().cells
-    row_cells[0].text = str(qty)
-    row_cells[1].text = id
-    row_cells[2].text = desc
-
-document.add_page_break()
-
-doc_output_path = r'C:\Users\Danny\Desktop\ssd wichtige dinge D\Tools\fast_excel_to_bill\test_folder' + r'\doc_test_{}.docx'.format(time.strftime("%Y-%m-%d_H%H-M%M"))
-document.save(doc_output_path)

+ 221 - 0
fast_excel_to_bill/bill_doc/docx_builder.py

@@ -0,0 +1,221 @@
+from docx.api import Document
+from docx.oxml.table import CT_Tbl
+from docx.oxml.text.paragraph import CT_P
+from docx.table import _Cell, Table, _Row
+from docx.text.paragraph import Paragraph
+import time
+import re
+
+path = r'C:\Users\Danny\Desktop\ssd wichtige dinge D\Tools\fast_excel_to_bill\test_folder\Templates\templeta.docx'
+doc_output_path = r'C:\Users\Danny\Desktop\ssd wichtige dinge D\Tools\fast_excel_to_bill\test_folder' + r'\doc_test_{}.docx'.format(
+    time.strftime("%Y-%m-%d_H%H-M%M"))
+
+
+class DOCFileBuilder:
+    def __init__(self, docx_input_path='', docx_save_path=''):
+        if docx_input_path:
+            self.document = Document(docx_input_path)
+        else:
+            self.document = Document()
+        self.docx_save_path = docx_save_path
+
+    # Low Level Functions
+    def save_docx(self):
+        if self.docx_save_path == '': # Default
+            self.document.save()
+        else:
+            self.document.save(self.docx_save_path)
+
+    def get_header_footer(self):
+        self.header_ = self.document.sections[0].header
+        self.footer_ = self.document.sections[0].footer
+
+    def replace_text_in_paragraph(self, paragraph,search_str, replace_str):
+        inline = paragraph.runs
+        for i in range(len(inline)):
+            if search_str in inline[i].text:
+                text = inline[i].text.replace(search_str, replace_str)
+                inline[i].text = text
+
+    def paragraphs_in_table(self):
+        for t in self.document.tables:
+            for row in t.rows:
+                for cell in row.cells:
+                    for p in cell.paragraphs:
+                        yield p
+
+    def replace_string_in_standard_text(self, search_str, replace_str):
+        for p in self.document.paragraphs:
+            self.replace_text_in_paragraph(p,search_str,replace_str)
+
+    def replace_string_in_all_tables(self, search_str, replace_str):
+        for p in self.paragraphs_in_table():
+            self.replace_text_in_paragraph(p,search_str, replace_str)
+
+    def replace_dates_string_in_standard_text(self, replace_date_str):
+        for p in self.document.paragraphs:
+            inline = p.runs
+            for i in range(len(inline)):
+                try:
+                    found_date = re.search(r'\d\d\.\d\d\.\d+', inline[i].text).group()
+                    text = inline[i].text.replace(found_date, replace_date_str)
+                    inline[i].text = text
+                except AttributeError:
+                    pass
+
+    def delete_empty_rows_in_table(self, table, column_count):
+        for row in table.rows:
+            column_counter = 0
+            for cell in row.cells:
+                for p in cell.paragraphs:
+                    inline = p.runs
+                    for i in range(len(inline)):
+                        if inline[i].text == '':
+                            column_counter += 1
+            if column_counter == column_count:
+                remove_row(table, row)
+
+    def replace_dates_string_in_all_tables(self, replace_date_str):
+        for p in self.paragraphs_in_table():
+            inline = p.runs
+            for i in range(len(inline)):
+                try:
+                    found_date = re.search(r'\d\d\.\d\d\.\d+', inline[i].text).group()
+                    text = inline[i].text.replace(found_date, replace_date_str)
+                    inline[i].text = text
+                except AttributeError:
+                    pass
+
+    def add_heading(self, text, level, alignment=0):
+        self.title = self.document.add_heading(text, level)
+        self.title.alignment = alignment
+
+    def search_table_with_key_columns(self, keys):
+        for t in self.document.tables:
+            len_key_list = 0
+            for row in t.rows:
+                for cell in row.cells:
+                    for p in cell.paragraphs:
+                        inline = p.runs
+                        for i in range(len(inline)):
+                            for key in keys:
+                                try:
+                                    re.search(key, inline[i].text).group()
+                                    len_key_list += 1
+                                    if len_key_list == len(keys):
+                                        return t
+                                except AttributeError:
+                                    pass
+
+    def replace_rows(self, table, list_tuple):
+        # each tuple builds a row, tuple must be the same size as cells in row
+        # replacing till list of tuple is iterate through
+        # then deleting the rest
+        len_insert_rows = 0
+        for tuple in list_tuple:
+            for row in table.rows:
+                count_columns = 0
+                for count, elem in enumerate(tuple):
+                    for p in row.cells[count].paragraphs:
+                        inline = p.runs
+                        for i in range(len(inline)):
+                            if inline[i].text == '':
+                                inline[i].text = str(elem)
+                                count_columns += 1
+                if count_columns == len(tuple):
+                    len_insert_rows += 1
+                if len_insert_rows == len(list_tuple):
+                    return
+
+    # Custom Format functions
+    def replace_Leistungszeitraum(self, start_date, end_date):
+        for p in self.paragraphs_in_table():
+            inline = p.runs
+            for i in range(len(inline)):
+                try:
+                    re.search(r'Leistungszeitraum', inline[i].text).group()
+                    text = inline[i].text.replace(inline[i].text,
+                                                  'Leistungszeitraum: {} bis zum {}'.format(start_date, end_date))
+                    inline[i].text = text
+                except AttributeError:
+                    pass
+
+    # High Tier functions
+    def replace_all_dates_custom_wise(self, start_date, end_date):
+        self.replace_dates_string_in_standard_text(end_date)
+        self.replace_dates_string_in_all_tables(end_date)
+        self.replace_Leistungszeitraum(start_date, end_date)
+
+    def replace_custom_placeholder_in_doc(self, placeholder, replace_str):
+        for p in self.document.paragraphs:
+            self.replace_text_in_paragraph(p, placeholder, replace_str)
+        for p in self.paragraphs_in_table():
+            self.replace_text_in_paragraph(p, placeholder,replace_str)
+
+
+def remove_row(table, row):
+    tbl = table._tbl
+    tr = row._tr
+    tbl.remove(tr)
+
+
+
+
+
+def iter_block_items(parent):
+    """
+    Yield each paragraph and table child within *parent*, in document order.
+    Each returned value is an instance of either Table or Paragraph.
+    """
+    if isinstance(parent, Document):
+        parent_elm = parent._document_part.body._body
+    elif isinstance(parent, _Cell):
+        parent_elm = parent._tc
+    elif isinstance(parent, _Row):
+        parent_elm = parent._tr
+    else:
+        raise ValueError("something's not right")
+
+    for child in parent_elm.iterchildren():
+        if isinstance(child, CT_P):
+            yield Paragraph(child, parent)
+        if isinstance(child, CT_Tbl):
+            yield Table(child, parent)
+
+
+def find_table_text_in_standard(doc):  # not header or footer
+    table_text = []
+    for table in doc.tables:
+        for row in table.rows:
+            for cell in row.cells:
+                for paragraph in cell.paragraphs:
+                    table_text += [paragraph.text]
+    return table_text
+
+
+def create_custome_doc_file():
+    '''
+    :return: Bill as Doc file
+    '''
+    doc = DOCFileBuilder()
+    doc.add_heading('EnD-GbR', 0, 2)
+    return doc.document
+
+
+if __name__ == '__main__':
+    builder_obj = DOCFileBuilder(path)
+    builder_obj.replace_dates_string_in_standard_text('03.11.2022')
+    builder_obj.replace_dates_string_in_all_tables('03.11.2022')
+    keys = ['KW', 'Leistung', 'Zeit in Stunden', 'Betrag in Euro']
+    example_tuple = [(123123, 213123, 12312312, 445235)]
+    key_table = builder_obj.search_table_with_key_columns(keys)
+    builder_obj.replace_rows(key_table, example_tuple)
+    builder_obj.delete_empty_rows_in_table(key_table, 4)
+    builder_obj.document.add_page_break()
+    key_table = builder_obj.search_table_with_key_columns(['KW', 'Leistungsübersicht'])
+    builder_obj.delete_empty_rows_in_table(key_table, 2)
+    doc = builder_obj.document
+
+
+
+

BIN
fast_excel_to_bill/bills/out.docx


+ 7 - 0
fast_excel_to_bill/config_for_custom_bills.py

@@ -0,0 +1,7 @@
+# Docx Builder
+docx_input_path = r'C:\Users\Danny\Desktop\EnD and Investment\Tools\fast_excel_to_bill\test_folder\Templates\templeta.docx'
+docx_output_dir_path = r'C:\Users\Danny\Desktop\EnD and Investment\Tools\fast_excel_to_bill\test_folder'
+list_of_place_holders = ['?Netto?','?zzgl.?', '?gesamt?', '?insert_date?']
+
+# Burden Date
+payment_request_range = 30

+ 52 - 2
fast_excel_to_bill/main.py

@@ -1,8 +1,58 @@
+from fast_excel_to_bill.bill_doc.docx_builder import DOCFileBuilder
+from fast_excel_to_bill import config_for_custom_bills
+from tool_lib import datetime_functions
+from datetime import datetime
+
+payment_request_range = config_for_custom_bills.payment_request_range
+year = int(datetime_functions.datetime_to_str(datetime_functions.get_current_date(), '%Y'))
+current_month_year= datetime_functions.datetime_to_str('current', '%m_%Y')
+docx_output_path = config_for_custom_bills.docx_output_dir_path+ r'\bill_{}.docx'.format(current_month_year)
+
+
 def main():
-    get_data_from_excel=...
+    # Get Data which is necessary for the docx
+    # data_from_excel = ...
+    payment_request_date = datetime_functions.add_days_to_date(datetime_functions.get_current_date(),payment_request_range)
+    payment_request_date = datetime_functions.datetime_to_str(payment_request_date, '%d.%m.%Y')
+    # data_from_excel.append(payment_request_date)
+
+    # Create a doc file which is based on a docx template
+    builder_obj = DOCFileBuilder(config_for_custom_bills.docx_input_path, docx_output_path)
+
+    # Set Date of Template
+    current_date = datetime_functions.datetime_to_str(datetime_functions.get_current_date(), '%d.%m.%Y')
+    builder_obj.replace_dates_string_in_standard_text(current_date)
+    builder_obj.replace_dates_string_in_all_tables(current_date)
+
+    # Set Leistungszeitraum
+    last_month = datetime_functions.get_current_month_number()-1
+    month_range = datetime_functions.get_count_of_days_for_specific_month(year=year, month_number=last_month)
+    if last_month>9:
+        start_date = '01.'+ str(last_month) +'.'+ str(year)
+    else:
+        start_date = '01.' + '0' + str(last_month) + '.' + str(year)
+    end_date = datetime_functions.add_days_to_date(datetime.strptime(start_date,'%d.%m.%Y'), month_range-1)
+    end_date = datetime_functions.datetime_to_str(end_date, '%d.%m.%Y')
+    builder_obj.replace_Leistungszeitraum(start_date, end_date)
+    builder_obj.save_docx()
+    # Replace Placeholders
+    # place_holders = config_for_custom_bills.list_of_place_holders
+    # for place_holder in place_holders:
+    #     builder_obj.replace_custom_placeholder_in_doc(place_holder, data_from_excel)
+
+    # keys = ['KW', 'Leistung', 'Zeit in Stunden', 'Betrag in Euro']
+    # example_tuple = [(123123, 213123, 12312312, 445235)]
+    # key_table = builder_obj.search_table_with_key_columns(keys)
+    # builder_obj.replace_rows(key_table, example_tuple)
+    # builder_obj.delete_empty_rows_in_table(key_table, 4)
+    # builder_obj.document.add_page_break()
+    # key_table = builder_obj.search_table_with_key_columns(['KW', 'Leistungsübersicht'])
+    # builder_obj.delete_empty_rows_in_table(key_table, 2)
     data_to_bill_doc = ...
+
+    # Transform the doc file to a pdf file
     doc_to_pdf = ...
 
 
 if __name__ == '__main__':
-    main()
+    main()

+ 0 - 0
fast_excel_to_bill/test_folder/Bentomax-08.21.pdf → fast_excel_to_bill/test_folder/Templates/Bentomax-08.21.pdf


+ 0 - 0
fast_excel_to_bill/test_folder/Bentomax-Rechnungsvorlage-August.doc → fast_excel_to_bill/test_folder/Templates/Bentomax-Rechnungsvorlage-August.doc


BIN
fast_excel_to_bill/test_folder/Templates/Bentomax-Rechnungsvorlage-August.docx


+ 0 - 0
fast_excel_to_bill/test_folder/Rechnung-Juli-h1.pdf → fast_excel_to_bill/test_folder/Templates/Rechnung-Juli-h1.pdf


+ 0 - 0
fast_excel_to_bill/test_folder/TourTeam-Rechnung-Dezember.pdf → fast_excel_to_bill/test_folder/Templates/TourTeam-Rechnung-Dezember.pdf


+ 0 - 0
fast_excel_to_bill/test_folder/Zeitplanner.xlsx → fast_excel_to_bill/test_folder/Templates/Zeitplanner.xlsx


BIN
fast_excel_to_bill/test_folder/Templates/templeta.docx


BIN
fast_excel_to_bill/test_folder/Templates/templeta.pdf


+ 0 - 1
time_recoder/Readme

@@ -1 +0,0 @@
-pip install styleframe xlsxwriter pysimplegui datetime SQLAlchemy

+ 2 - 2
time_recoder/save_recorded_time_in_table.py

@@ -8,10 +8,10 @@ from time import time
 
 def create_recorded_time_dict(worked_time, income, task):
     return {'Name': NAME,
-            'Datum': str(datetime_functions.get_current_date()) ,
+            'Datum': datetime_functions.datetime_to_str(datetime_functions.get_current_date(),'%d/%m/%Y') ,
             'Arbeitszeit': worked_time,
             'Einkommen': income,
-            'Kalenderwoche': datetime_functions.get_calendarweek_from_datetime(datetime_functions.get_current_date()),
+            'Kalenderwoche': datetime_functions.datetime_to_str(datetime_functions.get_current_date(), '%V'),
             'Task': task}
 
 

+ 2 - 1
time_recoder/time_recoder_config.py

@@ -1,4 +1,5 @@
+DB_PATH = r'C:\Users\Danny\Desktop\EnD and Investment\Tools\time_recoder\time_recorder_database'
 HOURLY_WAGE_IN_EURO = 28
-PATH = r'C:\Users\Danny\Desktop\ssd wichtige dinge D\Tools\time_recoder\time_recorded_tables\worked_time_table.xlsx'
+PATH = r'C:\Users\Danny\Desktop\EnD and Investment\Tools\time_recoder\time_recorded_tables\work_time_danny.xlsx'
 TEST_CASE = True
 NAME = 'Daniel Krauel'

+ 1 - 1
time_recoder/time_recoder_gui/time_recorder_gui_config.py

@@ -1,4 +1,4 @@
-
+DB_PATH = r'C:\Users\Danny\Desktop\EnD and Investment\Tools\time_recoder\time_recorder_database'
 PAUSE_BUTTON_TEXT = 'Pause Timer'
 START_BUTTON_TEXT = 'Start Timer'
 STOP_BUTTON_TEXT = 'Stop Timer'

BIN
time_recoder/time_recorded_tables/Septemnber.xlsx


BIN
time_recoder/time_recorded_tables/example.xlsx


+ 38 - 3
tool_lib/datetime_functions.py

@@ -1,7 +1,42 @@
 import datetime
+from calendar import monthrange, month_name
 
-def get_calendarweek_from_datetime(datetime_obj):
-    return datetime_obj.strftime('%V')
+
+
+def datetime_to_str(datetime_obj, format):
+    '''
+    :param format:
+    %V = Calendar Week
+    %d/%m%Y
+    :return:
+    '''
+    if datetime_obj == 'current':
+        datetime_obj = datetime.datetime.now()
+        return datetime_obj.strftime(format)
+    else:
+        return datetime_obj.strftime(format)
 
 def get_current_date():
-    return datetime.date.today()
+    return datetime.datetime.now()
+
+def get_current_month_number():
+    current_date = datetime.datetime.now()
+    return int(current_date.strftime("%m"))
+
+def add_days_to_date(datetime_obj,count):
+    return datetime_obj + datetime.timedelta(days= count)
+
+def substract_days_to_current_date(count):
+    return datetime.datetime.now() - datetime.timedelta(days= count)
+
+def get_count_of_days_for_specific_month(year, month_number):
+    '''
+    :param year: As Int, ex. 2012
+    :param month_number:  As Int, ex. February == 2
+    :return:
+    '''
+    return monthrange(year,month_number)[1] # [0] contains the week day
+
+
+
+