This commit is contained in:
Dave 2022-04-20 14:42:00 +02:00
commit df8bef2b97
7 changed files with 206 additions and 91 deletions

View File

@ -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
}

View File

@ -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

View File

@ -3,10 +3,21 @@
frappe.ui.form.on('Verkaufsstatistik Report', { frappe.ui.form.on('Verkaufsstatistik Report', {
refresh: function(frm) { refresh: function(frm) {
moment.locale("de") // weeks start on monday moment.locale("de") // weeks start on monday
frm.trigger('preset'); 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());
}, },
// setup: function(frm) { // setup: function(frm) {
// frm.set_query("artikel",function(){ // frm.set_query("artikel",function(){
@ -17,6 +28,7 @@ frappe.ui.form.on('Verkaufsstatistik Report', {
// } // }
// }); // });
// }, // },
preset: function(frm) { preset: function(frm) {
if (!frm.doc.preset) { if (!frm.doc.preset) {
// No preset selected. Allow manual selection of dates. // No preset selected. Allow manual selection of dates.
@ -35,52 +47,9 @@ frappe.ui.form.on('Verkaufsstatistik Report', {
frm.events.set_dates(frm, frappe.datetime.year_to_date()); 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_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) { set_dates: function(frm, date_range) {
frm.set_value('from_date', date_range.start); frm.set_value('from_date', date_range.start);
frm.set_value('to_date', date_range.end); frm.set_value('to_date', date_range.end);
}, },
}); });

View File

@ -8,16 +8,19 @@
"field_order": [ "field_order": [
"from_date", "from_date",
"preset", "preset",
"artikel",
"column_break_4", "column_break_4",
"to_date", "to_date",
"report", "section_break_6",
"gruppiert",
"artikel",
"employee",
"report_section", "report_section",
"report_basierend_auf", "report_basierend_auf",
"gruppiert_nach", "gruppiert_nach",
"section_break_10", "section_break_10",
"anzahl", "anzahl",
"preis", "preis",
"summenzeile",
"zeiteinheit_section", "zeiteinheit_section",
"resolution", "resolution",
"ausgabe_section", "ausgabe_section",
@ -36,6 +39,7 @@
"options": "\nLast Week\nLast Month\nLast Year\nYTD" "options": "\nLast Week\nLast Month\nLast Year\nYTD"
}, },
{ {
"depends_on": "eval:doc.gruppiert==\"Item\"",
"fieldname": "artikel", "fieldname": "artikel",
"fieldtype": "Table MultiSelect", "fieldtype": "Table MultiSelect",
"label": "Artikel", "label": "Artikel",
@ -50,12 +54,6 @@
"fieldtype": "Date", "fieldtype": "Date",
"label": "To Date" "label": "To Date"
}, },
{
"fieldname": "report",
"fieldtype": "Button",
"label": "Report",
"options": "do_report"
},
{ {
"fieldname": "resolution", "fieldname": "resolution",
"fieldtype": "Select", "fieldtype": "Select",
@ -89,7 +87,7 @@
"fieldname": "gruppiert_nach", "fieldname": "gruppiert_nach",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Gruppiert nach", "label": "Gruppiert nach",
"options": "Artikel\nMitarbeiter" "options": "Artikel\nMitarbeiter\nAlle"
}, },
{ {
"fieldname": "zeiteinheit_section", "fieldname": "zeiteinheit_section",
@ -110,12 +108,36 @@
}, },
{ {
"fieldname": "section_break_10", "fieldname": "section_break_10",
"fieldtype": "Section Break",
"label": "Parameter"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break" "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, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2022-03-14 16:25:40.030362", "modified": "2022-03-18 13:14:49.834111",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "MSP", "module": "MSP",
"name": "Verkaufsstatistik Report", "name": "Verkaufsstatistik Report",

View File

@ -9,16 +9,39 @@ from datetime import datetime as dt
from pprint import pprint from pprint import pprint
import pandas as pd import pandas as pd
import numpy as np import numpy as np
from six import BytesIO
from frappe.utils.file_manager import save_file
class VerkaufsstatistikReport(Document): class VerkaufsstatistikReport(Document):
@frappe.whitelist() @frappe.whitelist()
def do_report(self): def do_report(self):
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 artikel_auswahl = self.artikel
print(artikel_auswahl)
artikel_name = [a.item for a in artikel_auswahl]
if artikel_auswahl == []: if artikel_auswahl == []:
frappe.throw('Keine Artikel ausgewählt.') frappe.throw('Keine Artikel ausgewählt.')
artikel_name = [a.item for a in artikel_auswahl] else:
frappe.throw('Keine Auswahl bei Gruppierung getroffen.')
if self.report_basierend_auf == "Rechnung": if self.report_basierend_auf == "Rechnung":
item_list = [] item_list = []
si_list = frappe.get_all( si_list = frappe.get_all(
@ -34,9 +57,16 @@ class VerkaufsstatistikReport(Document):
artikel_doc = frappe.get_doc("Sales Invoice", si["name"]) artikel_doc = frappe.get_doc("Sales Invoice", si["name"])
for artikel in artikel_doc.items: for artikel in artikel_doc.items:
if artikel.item_code in artikel_name: 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 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) item_list.append(artikel_details)
if self.report_basierend_auf == "Lieferschein": if self.report_basierend_auf == "Lieferschein":
@ -54,21 +84,35 @@ class VerkaufsstatistikReport(Document):
for artikel in artikel_doc.items: for artikel in artikel_doc.items:
if artikel.item_code in artikel_name: 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 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) 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 = pd.DataFrame(item_list, columns = ["Datum","Mitarbeiter","Item Name","Item","Anzahl","Preis pro Einheit","Preis"])
df['Datum'] = pd.to_datetime(df['Datum']) df['Date'] = pd.to_datetime(df['Datum'])
df['Kalenderwoche']= df['Datum'].dt.isocalendar().week df['Datum'] = df['Date'].dt.strftime('%d.%m.%Y')
#df['Monat']= df['Datum'].dt.month df['Kalenderwoche']= df['Date'].dt.isocalendar().week
df['Jahr'] = df['Datum'].dt.year #df['Monat']= df['Date'].dt.month
df['Monat'] = df['Datum'].dt.strftime("%m.%Y") 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}) df.round ({"Anzahl":2,"Preis":2})
if df.empty:
frappe.throw('Für die angegebene Periode sind keine Daten vorhanden')
print(df.dtypes) print(df.dtypes)
if self.resolution == 'monthly': if self.resolution == 'monthly':
date = ['Monat'] date = ['Monat']
@ -83,7 +127,7 @@ class VerkaufsstatistikReport(Document):
date = ["Jahr"] date = ["Jahr"]
elif self.resolution == 'period': elif self.resolution == 'period':
date = [] date = ["Periode"]
else: else:
frappe.msgprint("Bitte Zeiteinheit für Gruppierung auswählen") frappe.msgprint("Bitte Zeiteinheit für Gruppierung auswählen")
@ -100,9 +144,10 @@ class VerkaufsstatistikReport(Document):
if self.gruppiert_nach == "Artikel": if self.gruppiert_nach == "Artikel":
df_pivot =df.pivot_table(index=date, columns="Item", values = values, aggfunc = np.sum, fill_value=0) 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) 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 = df_pivot.columns.droplevel(0) #remove amount
# df_pivot.columns.name = None #remove categories # df_pivot.columns.name = None #remove categories
# df_pivot = df_pivot.reset_index() #index to columns # 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 = df_pivot.drop(date,axis=1).astype(float)
a[date] = df_pivot[date] a[date] = df_pivot[date]
a.set_index(date, inplace = True) a.set_index(date, inplace = True)
#c = a.columns.tolist()
# = [lambda x : x.replace('(', '').replace(')','').replace("'",'') for x in c]
#print(a) #print(a)
#df_pivot = df_pivot.astype(float)d #df_pivot = df_pivot.astype(float)d
#df_pivot = self.add_total_row(df_pivot) #df_pivot = self.add_total_row(df_pivot)
# print(df_pivot) # print(df_pivot)
self.report_ausgabe = self.get_styler(a).render()
#self.report_ausgabe = self.get_styler(a).render()
if item_list == []: if item_list == []:
self.report_ausgabe = '<p>' + ("Für die angegebene Periode sind keine Daten vorhanden") + '</p>' self.report_ausgabe = '<p>' + ("Für die angegebene Periode sind keine Daten vorhanden") + '</p>'
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') sum_row = df.aggregate('sum')
mean_row = df.aggregate('mean')
df.loc['SUM'] = sum_row df.loc['SUM'] = sum_row
df.loc['MEAN'] = mean_row
return df
def get_styler(self,df): def get_styler(self,df):
styles = [ styles = [
dict(props=[("border-collapse", "collapse"), ("width", "100%")]), 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=".col0", props=[("text-align", "left")]), # first column
dict(selector="tbody tr:nth-of-type(odd)", props=[("background-color", "rgba(0,0,0,.05)")]), # stripes dict(selector="tbody tr:nth-of-type(odd)", props=[("background-color", "rgba(0,0,0,.05)")]), # stripes
] ]
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) 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)

View File

@ -11,6 +11,7 @@
{ {
"fieldname": "item", "fieldname": "item",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1,
"label": "Item", "label": "Item",
"options": "Item" "options": "Item"
} }
@ -18,7 +19,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-10-26 11:58:30.925182", "modified": "2022-03-17 11:51:20.508506",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "MSP", "module": "MSP",
"name": "Verkaufsstatistik Report Artikel", "name": "Verkaufsstatistik Report Artikel",