From 6b657d5b138c6cb8a7d7a958fafd26bd2bad6f5f Mon Sep 17 00:00:00 2001 From: Beate Trzensiok Date: Fri, 18 Mar 2022 13:24:37 +0100 Subject: [PATCH 1/2] Anpassungen Preset, Employee und Summe --- .../veraufsstatistik_employee/__init__.py | 0 .../veraufsstatistik_employee.json | 32 ++++ .../veraufsstatistik_employee.py | 8 + .../verkaufsstatistik_report.js | 60 ++----- .../verkaufsstatistik_report.json | 42 +++-- .../verkaufsstatistik_report.py | 147 ++++++++++++++---- .../verkaufsstatistik_report_artikel.json | 3 +- 7 files changed, 202 insertions(+), 90 deletions(-) create mode 100644 msp/msp/doctype/veraufsstatistik_employee/__init__.py create mode 100644 msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.json create mode 100644 msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.py diff --git a/msp/msp/doctype/veraufsstatistik_employee/__init__.py b/msp/msp/doctype/veraufsstatistik_employee/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.json b/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.json new file mode 100644 index 0000000..e0fa353 --- /dev/null +++ b/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.json @@ -0,0 +1,32 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2022-03-17 13:43:21.255556", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "employee" + ], + "fields": [ + { + "fieldname": "employee", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Employee", + "options": "Employee" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2022-03-17 13:43:21.255556", + "modified_by": "Administrator", + "module": "MSP", + "name": "Veraufsstatistik Employee", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.py b/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.py new file mode 100644 index 0000000..146ce98 --- /dev/null +++ b/msp/msp/doctype/veraufsstatistik_employee/veraufsstatistik_employee.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, itsdave GmbH and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class VeraufsstatistikEmployee(Document): + pass diff --git a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js index 3a72b9a..de4a964 100644 --- a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js +++ b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js @@ -4,6 +4,14 @@ frappe.ui.form.on('Verkaufsstatistik Report', { refresh: function(frm) { + frm.add_custom_button('Generate Excel Sheet', () => frm.trigger('generate_excel_sheet')); + frm.add_custom_button('Generate Report', () => frm.trigger('generate_report')); + }, + generate_report: function(frm) { + frm.call('generate_report', {}, () => frm.reload_doc()); + }, + generate_excel_sheet: function(frm) { + frm.call('generate_excel_sheet', {}, () => frm.reload_doc()); moment.locale("de") // weeks start on monday frm.trigger('preset'); @@ -17,6 +25,7 @@ frappe.ui.form.on('Verkaufsstatistik Report', { // } // }); // }, + preset: function(frm) { if (!frm.doc.preset) { // No preset selected. Allow manual selection of dates. @@ -35,52 +44,9 @@ frappe.ui.form.on('Verkaufsstatistik Report', { frm.events.set_dates(frm, frappe.datetime.year_to_date()); } } - - }, - - from_date: (frm) => frm.trigger('set_to_date'), - set_to_date: function (frm) { - - const len_in_days = moment(frm.doc.to_date).diff(moment(frm.doc.from_date), 'days'); - let to_date = moment(frm.doc.from_date).add(len_in_days, 'days'); - - if (frm.doc.preset && frm.doc.preset !== 'YTD') { - // to_date is equal to the end of the week / month / year of from_date - const time_map = { - 'Last Week': 'week', - 'Last Month': 'month', - 'Last Year': 'year', - } - to_date = moment(frm.doc.from_date).endOf(time_map[frm.doc.preset]); - } - - + set_dates: function(frm, date_range) { + frm.set_value('from_date', date_range.start); + frm.set_value('to_date', date_range.end); }, - set_from_date: function(frm) { - - - if (frm.doc.to_previous_year) { - frm.toggle_enable(['from_date'], false); - let from_date = moment(frm.doc.from_date).subtract(1, 'year'); - - if (frm.doc.preset == 'Last Week') { - const week = moment(frm.doc.from_date).format('WW'); - const previous_year = (moment(frm.doc.from_date).year() - 1).toString(); - from_date = moment(`${previous_year}W${week}`); - } - - frm.set_value('from_date', from_date.format()); - } else { - frm.toggle_enable(['from_date'], true); - } - }, - - set_dates: function(frm, date_range) { - frm.set_value('from_date', date_range.start); - frm.set_value('to_date', date_range.end); - }, - - -}); - + }); diff --git a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.json b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.json index 69550c9..54cdc30 100644 --- a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.json +++ b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.json @@ -8,16 +8,19 @@ "field_order": [ "from_date", "preset", - "artikel", "column_break_4", "to_date", - "report", + "section_break_6", + "gruppiert", + "artikel", + "employee", "report_section", "report_basierend_auf", "gruppiert_nach", "section_break_10", "anzahl", "preis", + "summenzeile", "zeiteinheit_section", "resolution", "ausgabe_section", @@ -36,6 +39,7 @@ "options": "\nLast Week\nLast Month\nLast Year\nYTD" }, { + "depends_on": "eval:doc.gruppiert==\"Item\"", "fieldname": "artikel", "fieldtype": "Table MultiSelect", "label": "Artikel", @@ -50,12 +54,6 @@ "fieldtype": "Date", "label": "To Date" }, - { - "fieldname": "report", - "fieldtype": "Button", - "label": "Report", - "options": "do_report" - }, { "fieldname": "resolution", "fieldtype": "Select", @@ -89,7 +87,7 @@ "fieldname": "gruppiert_nach", "fieldtype": "Select", "label": "Gruppiert nach", - "options": "Artikel\nMitarbeiter" + "options": "Artikel\nMitarbeiter\nAlle" }, { "fieldname": "zeiteinheit_section", @@ -110,12 +108,36 @@ }, { "fieldname": "section_break_10", + "fieldtype": "Section Break", + "label": "Parameter" + }, + { + "fieldname": "section_break_6", "fieldtype": "Section Break" + }, + { + "default": "0", + "fieldname": "summenzeile", + "fieldtype": "Check", + "label": "Summenzeile" + }, + { + "depends_on": "eval:doc.gruppiert==\"Employee\"", + "fieldname": "employee", + "fieldtype": "Table MultiSelect", + "label": "Employee", + "options": "Veraufsstatistik Employee" + }, + { + "fieldname": "gruppiert", + "fieldtype": "Select", + "label": "Auswahl", + "options": "Item\nEmployee" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-03-14 16:25:40.030362", + "modified": "2022-03-18 13:14:49.834111", "modified_by": "Administrator", "module": "MSP", "name": "Verkaufsstatistik Report", diff --git a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.py b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.py index 7b259fc..f8edbd6 100644 --- a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.py +++ b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.py @@ -9,16 +9,39 @@ from datetime import datetime as dt from pprint import pprint import pandas as pd import numpy as np - - +from six import BytesIO +from frappe.utils.file_manager import save_file class VerkaufsstatistikReport(Document): @frappe.whitelist() def do_report(self): - artikel_auswahl = self.artikel - if artikel_auswahl == []: - frappe.throw('Keine Artikel ausgewählt.') - artikel_name = [a.item for a in artikel_auswahl] + + employee_tup = "" + if self.gruppiert == "Employee": + employee_auswahl = self.employee + if employee_auswahl != []: + employee_list = [x.employee for x in employee_auswahl] + filters = {"employee": ["in", employee_list]} + else: + filters = {} + employee_art = frappe.get_all( + "Employee Item Assignment", + filters= filters, + fields= ["item","employee_name"]) + #employee_artikel = [x.item for x in employee_art] + artikel_name = [x.item for x in employee_art] + employee_tup = [(x.item,x.employee_name) for x in employee_art] + print(employee_tup) + # if employee_auswahl == []: + # frappe.throw('Keine Mitarbeiter ausgewählt.') + elif self.gruppiert == "Item": + artikel_auswahl = self.artikel + print(artikel_auswahl) + artikel_name = [a.item for a in artikel_auswahl] + if artikel_auswahl == []: + frappe.throw('Keine Artikel ausgewählt.') + else: + frappe.throw('Keine Auswahl bei Gruppierung getroffen.') if self.report_basierend_auf == "Rechnung": item_list = [] si_list = frappe.get_all( @@ -34,9 +57,16 @@ class VerkaufsstatistikReport(Document): artikel_doc = frappe.get_doc("Sales Invoice", si["name"]) for artikel in artikel_doc.items: if artikel.item_code in artikel_name: - empl = str(artikel.item_name).replace("Arbeitszeit ","").replace("Herr ","").replace(" Anwendungsentwicklung","").replace("Remote-Service ","") + b = [y[0] for y in employee_tup] + if artikel.item_code in b: + employee =employee_tup[b.index(artikel.item_code )][1] + else: + employee = 0 + + #print(employee) + #empl = str(artikel.item_name).replace("Arbeitszeit ","").replace("Herr ","").replace(" Anwendungsentwicklung","").replace("Remote-Service ","") price = artikel.qty*artikel.rate - artikel_details = [si["posting_date"],empl,artikel.item_name,artikel.item_code,artikel.qty,artikel.rate, price] + artikel_details = [si["posting_date"],employee,artikel.item_name,artikel.item_code,artikel.qty,artikel.rate, price] item_list.append(artikel_details) if self.report_basierend_auf == "Lieferschein": @@ -54,21 +84,35 @@ class VerkaufsstatistikReport(Document): for artikel in artikel_doc.items: if artikel.item_code in artikel_name: - empl = str(artikel.item_name).replace("Arbeitszeit ","").replace("Herr ","").replace(" Anwendungsentwicklung","").replace("Remote-Service ","") + b = [y[0] for y in employee_tup] + if artikel.item_code in b: + employee =employee_tup[b.index(artikel.item_code )][1] + else: + employee = 0 + #empl = str(artikel.item_name).replace("Arbeitszeit ","").replace("Herr ","").replace(" Anwendungsentwicklung","").replace("Remote-Service ","") price = artikel.qty*artikel.rate - artikel_details = [dn["posting_date"],empl,artikel.item_name,artikel.item_code,artikel.qty, artikel.rate, price] + + artikel_details = [dn["posting_date"],employee,artikel.item_name,artikel.item_code,artikel.qty, artikel.rate, price] item_list.append(artikel_details) - print(artikel_details) + df = pd.DataFrame(item_list, columns = ["Datum","Mitarbeiter","Item Name","Item","Anzahl","Preis pro Einheit","Preis"]) - df['Datum'] = pd.to_datetime(df['Datum']) - df['Kalenderwoche']= df['Datum'].dt.isocalendar().week - #df['Monat']= df['Datum'].dt.month - df['Jahr'] = df['Datum'].dt.year - df['Monat'] = df['Datum'].dt.strftime("%m.%Y") + df['Date'] = pd.to_datetime(df['Datum']) + df['Datum'] = df['Date'].dt.strftime('%d.%m.%Y') + df['Kalenderwoche']= df['Date'].dt.isocalendar().week + #df['Monat']= df['Date'].dt.month + df['Jahr'] = df['Date'].dt.year + df['Monat'] = df['Date'].dt.strftime("%m.%Y") + from_date_dt = dt. strptime(self.from_date, '%Y-%m-%d') + from_date_st = from_date_dt.strftime('%d.%m.%Y') + to_date_dt = dt. strptime(self.to_date, '%Y-%m-%d') + to_date_st = to_date_dt.strftime('%d.%m.%Y') + df['Periode'] = from_date_st+ " bis " + to_date_st df.round ({"Anzahl":2,"Preis":2}) + if df.empty: + frappe.throw('Für die angegebene Periode sind keine Daten vorhanden') print(df.dtypes) if self.resolution == 'monthly': date = ['Monat'] @@ -83,7 +127,7 @@ class VerkaufsstatistikReport(Document): date = ["Jahr"] elif self.resolution == 'period': - date = [] + date = ["Periode"] else: frappe.msgprint("Bitte Zeiteinheit für Gruppierung auswählen") @@ -100,9 +144,10 @@ class VerkaufsstatistikReport(Document): if self.gruppiert_nach == "Artikel": df_pivot =df.pivot_table(index=date, columns="Item", values = values, aggfunc = np.sum, fill_value=0) - else: + elif self.gruppiert_nach == "Mitarbeiter": df_pivot =df.pivot_table(index=date, columns="Mitarbeiter", values = values, aggfunc = np.sum, fill_value=0) - + elif self.gruppiert_nach == "Alle": + df_pivot =df.pivot_table(index=date, values = values, aggfunc = np.sum, fill_value=0) # df_pivot.columns = df_pivot.columns.droplevel(0) #remove amount # df_pivot.columns.name = None #remove categories # df_pivot = df_pivot.reset_index() #index to columns @@ -125,27 +170,33 @@ class VerkaufsstatistikReport(Document): a = df_pivot.drop(date,axis=1).astype(float) a[date] = df_pivot[date] a.set_index(date, inplace = True) - #c = a.columns.tolist() - # = [lambda x : x.replace('(', '').replace(')','').replace("'",'') for x in c] - - + #print(a) - - - - #df_pivot = df_pivot.astype(float)d #df_pivot = self.add_total_row(df_pivot) # print(df_pivot) - self.report_ausgabe = self.get_styler(a).render() + + #self.report_ausgabe = self.get_styler(a).render() if item_list == []: self.report_ausgabe = '

' + ("Für die angegebene Periode sind keine Daten vorhanden") + '

' - def add_total_row(df,self): + return a + @frappe.whitelist() + def generate_report(self): + df = self.do_report() + if self.summenzeile == 1: + df= self.add_total_row(df) + if df.empty: + frappe.throw('Für die angegebene Periode sind keine Daten vorhanden') + self.report_ausgabe = self.get_styler(df).render() + self.save() + + def add_total_row(self,df): + sum_row = df.aggregate('sum') - mean_row = df.aggregate('mean') df.loc['SUM'] = sum_row - df.loc['MEAN'] = mean_row + + return df def get_styler(self,df): styles = [ dict(props=[("border-collapse", "collapse"), ("width", "100%")]), @@ -156,4 +207,36 @@ class VerkaufsstatistikReport(Document): #dict(selector=".col0", props=[("text-align", "left")]), # first column dict(selector="tbody tr:nth-of-type(odd)", props=[("background-color", "rgba(0,0,0,.05)")]), # stripes ] - return df.style.format('{:.2f}').set_table_styles(styles) \ No newline at end of file + if self.summenzeile == 1: + a = dict(selector="tr:nth-last-child(1)", props=[("font-weight", "bold")]) + styles.append(a) + return df.style.format('{:.2f}').set_table_styles(styles) + + @frappe.whitelist() + def generate_excel_sheet(self): + + df = self.do_report() + if self.summenzeile == 1: + df= self.add_total_row(df) + + if df.empty: + frappe.throw('Für die angegebene Periode sind keine Daten vorhanden') + + self.attach_as_excel(self.get_styler(df), self.doctype, self.name) + + def styler_to_excel(self,styler): + + buffer = BytesIO() + with pd.ExcelWriter(buffer, engine='xlsxwriter', date_format='DD.MM.YYYY', datetime_format='DD.MM.YYYY hh:mm') as writer: + + styler.to_excel(writer, index=True) + return buffer.getvalue() + + + + def attach_as_excel(self,styler, doctype, name): + + content = self.styler_to_excel(styler) + + filename = name + '.xlsx' + save_file(filename, content, doctype, name, None, False, 1) \ No newline at end of file diff --git a/msp/msp/doctype/verkaufsstatistik_report_artikel/verkaufsstatistik_report_artikel.json b/msp/msp/doctype/verkaufsstatistik_report_artikel/verkaufsstatistik_report_artikel.json index b9cd486..d58df1b 100644 --- a/msp/msp/doctype/verkaufsstatistik_report_artikel/verkaufsstatistik_report_artikel.json +++ b/msp/msp/doctype/verkaufsstatistik_report_artikel/verkaufsstatistik_report_artikel.json @@ -11,6 +11,7 @@ { "fieldname": "item", "fieldtype": "Link", + "in_list_view": 1, "label": "Item", "options": "Item" } @@ -18,7 +19,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-10-26 11:58:30.925182", + "modified": "2022-03-17 11:51:20.508506", "modified_by": "Administrator", "module": "MSP", "name": "Verkaufsstatistik Report Artikel", From f66fce7e4f89488944f62306b85bd5ba1a0a315b Mon Sep 17 00:00:00 2001 From: Beate Trzensiok Date: Thu, 24 Mar 2022 12:49:52 +0100 Subject: [PATCH 2/2] Preset --- .../verkaufsstatistik_report/verkaufsstatistik_report.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js index de4a964..e55b252 100644 --- a/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js +++ b/msp/msp/doctype/verkaufsstatistik_report/verkaufsstatistik_report.js @@ -3,17 +3,20 @@ frappe.ui.form.on('Verkaufsstatistik Report', { refresh: function(frm) { + moment.locale("de") // weeks start on monday + frm.trigger('preset'); frm.add_custom_button('Generate Excel Sheet', () => frm.trigger('generate_excel_sheet')); frm.add_custom_button('Generate Report', () => frm.trigger('generate_report')); }, generate_report: function(frm) { frm.call('generate_report', {}, () => frm.reload_doc()); + + }, generate_excel_sheet: function(frm) { frm.call('generate_excel_sheet', {}, () => frm.reload_doc()); - moment.locale("de") // weeks start on monday - frm.trigger('preset'); + }, // setup: function(frm) {