From f0fe2582dd432d6e73111cd0e1380365663c1a5a Mon Sep 17 00:00:00 2001 From: Beate Trzensiok Date: Tue, 27 Sep 2022 11:31:12 +0200 Subject: [PATCH] Auto Invoice Generator Anpassung --- .../auto_invoice_generator.json | 18 +- .../auto_invoice_generator.py | 229 +++++++++++------- 2 files changed, 153 insertions(+), 94 deletions(-) diff --git a/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.json b/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.json index 9950c0c..b64baf5 100644 --- a/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.json +++ b/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.json @@ -7,7 +7,6 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "invoicing_grouped_by", "close_invoiced_delivery_notes_section", "close", "invoices_from_delivery_notes_section", @@ -16,15 +15,10 @@ "statistics", "date", "invoice_count", - "customer_count" + "customer_count", + "log" ], "fields": [ - { - "fieldname": "invoicing_grouped_by", - "fieldtype": "Select", - "label": "Invoicing grouped by", - "options": "\nService and Goods\nService and Goods and Sales Order" - }, { "fieldname": "close_invoiced_delivery_notes_section", "fieldtype": "Section Break", @@ -75,11 +69,17 @@ "fieldname": "statistics", "fieldtype": "Section Break", "label": "Statistics" + }, + { + "fieldname": "log", + "fieldtype": "Small Text", + "label": "Log" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-09-02 11:56:18.512522", + "migration_hash": "81a435d8fdde574c14c22be58f9e32ca", + "modified": "2022-09-22 14:23:33.413375", "modified_by": "Administrator", "module": "MSP", "name": "Auto Invoice Generator", diff --git a/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.py b/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.py index d639c42..a941d01 100644 --- a/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.py +++ b/msp/msp/doctype/auto_invoice_generator/auto_invoice_generator.py @@ -8,6 +8,7 @@ import frappe from frappe.model.document import Document from erpnext.accounts.party import set_taxes as party_st from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice +from msp.billing_tools import get_item_group_assignment_table from datetime import datetime from frappe import ValidationError, _ @@ -33,6 +34,7 @@ class AutoInvoiceGenerator(Document): frappe.db.set_value("Delivery Note", pos, "status", "Closed") frappe.msgprint( str(count)+ " delivery notes were closed") + @frappe.whitelist() def get_delivery_notes_for_invoicing(self): @@ -41,10 +43,9 @@ class AutoInvoiceGenerator(Document): #filters = {"status" : "to bill","is_return": 0, "project": ""} delivery_notes_list = frappe.get_all("Delivery Note", filters = filters, fields = ["name", "customer", "project"]) print(len(delivery_notes_list)) - dl = [x.name for x in delivery_notes_list if x.project] - print(dl) - print(len(dl)) - + #dl = [x.name for x in delivery_notes_list if x.project] + #print(dl) + #print(len(dl)) return delivery_notes_list @frappe.whitelist() def get_customer_for_invoicing(self, delivery_note): @@ -60,9 +61,22 @@ class AutoInvoiceGenerator(Document): return customer_list_exc_duplicate - def get_delivery_notes_for_customer(self, cust, delivery_notes): + def get_customer_asap_billing_mode(self): + del_not = self.get_delivery_notes_for_invoicing() + cust_list = self.get_customer_for_invoicing(del_not) + filters = {"name": ["in",cust_list], + "billing_mode": "ASAP"} + cust_list_asap = frappe.get_all("Customer", filters = filters ) + asap_cust = [x.name for x in cust_list_asap] + print(asap_cust) + return asap_cust -#Funktion listet alle Lieferscheine für den jeweiligen Kunden auf + def get_asap_invoices(self, cust_list): + pass + + + def get_delivery_notes_for_customer(self, cust, delivery_notes): + #Funktion listet alle Lieferscheine für den jeweiligen Kunden auf cust_del_note = [] for el in delivery_notes: @@ -71,107 +85,143 @@ class AutoInvoiceGenerator(Document): cust_del_note.append(el) return cust_del_note + + def get_invoicing_items_for_cust(self,cust): + #Funktion liefert eine Liste aller abrechenbaren Items für den jeweiligen Kunden + + del_not = self.get_delivery_notes_for_invoicing() + cust_doc = frappe.get_doc("Customer",cust) + delivery_note_list = self.get_delivery_notes_for_customer(cust,del_not) + #print(delivery_note_list) + if len(delivery_note_list) < 1: + frappe.msgprint("Keine abrechnenbaren Lieferscheine vorhanden") + else: + items = [] + + for dn in delivery_note_list: + + item_doc = frappe.get_doc("Delivery Note", dn["name"]) + for item in item_doc.items: + print(item.item_group) + item.dn_detail= dn["name"] + print("item.dn_detail") + print(item.dn_detail) + items.append(item) + return items + @frappe.whitelist() def get_invoice_dict(self): - - + self.get_customer_asap_billing_mode() del_not = self.get_delivery_notes_for_invoicing() - print(del_not) cust_list = self.get_customer_for_invoicing(del_not) if self.customer: customer_list = [self.customer] else: customer_list = cust_list - + print(len(customer_list)) cust_count = 0 invoice_count = 0 for cust in customer_list: - print(cust) cust_doc = frappe.get_doc("Customer",cust) invoice_in_draft = frappe.get_all("Sales Invoice", filters = {"status" : "Draft", "customer": cust}) if len(invoice_in_draft) > 0: - print("nicht bearbeitet") - print(cust) + self.log = "Für Kunde"+ " "+ cust + " wurden keine Rechnungen erstellt, da noch nicht berechnete Rechnungen in Draft vorhanden" continue else: cust_count += 1 - #if self.invoicing_grouped_by == "None": - - delivery_note_list = self.get_delivery_notes_for_customer(cust,del_not) - #print(delivery_note_list) - if len(delivery_note_list) < 1: - frappe.msgprint("Keine abrechnenbaren Lieferscheine vorhanden") - sales_order_items = [] - service_items = [] - goods_items =[] - for dn in delivery_note_list: + items = self.get_invoicing_items_for_cust(cust) + print(items) + invoicing_items = [] - item_doc = frappe.get_doc("Delivery Note", dn["name"]) - - for item in item_doc.items: - print(item.item_group) - invoice_doc_item = frappe.get_doc({ - "doctype": "Sales Invoice Item", - "item_code": item.item_code, - "description": item.description, - "qty": item.qty, - "uom" : item.uom, - "rate": item.rate, - "sales_order": item.against_sales_order, - "dn_detail": item.name, - "parent": "delivery_note", - "delivery_note": dn["name"] - - }) - print(item.dn_detail) - print(dn["name"]) - print(item.qty) - print(item.uom) - if item.item_group == "Dienstleistungen" or item.item_group == "Anfahrten" or item.item_group == "Arbeitszeiten Techniker" or item.item_group == "Zuschläge" or item.item_group == "Anwendungsentwicklung": - service_items.append(invoice_doc_item) - elif item.against_sales_order: - sales_order_items.append(invoice_doc_item) - else: - goods_items.append(invoice_doc_item) - - if self.invoicing_grouped_by == "Service and Goods and Sales Order": - self.create_invoice(cust, goods_items, "Ware " + cust_doc.customer_name) - if len(goods_items) > 0: - invoice_count += 1 - self.create_invoice(cust, service_items, "Dienstleistung " + cust_doc.customer_name) - if len(service_items) > 0: - invoice_count += 1 - #self.create_invoice(cust, sales_order_items, "Sales Order " + cust_doc.customer_name) - if len(sales_order_items) > 0: - print("Sales Order Check") - x = [i.sales_order for i in sales_order_items] - print(x) - a = list(set(x)) - for el in a: - sal_ord_it = [] - for i in sales_order_items: - if i.sales_order == el: - sal_ord_it.append(i) - self.create_invoice(cust, sal_ord_it, "Sales Order "+ el+ " " + cust_doc.customer_name) + if cust_doc.billing_mode == "ASAP": + x = self.get_delivery_notes_for_customer(cust, del_not) + for dn in x: + item_doc = frappe.get_doc("Delivery Note", dn["name"]) + items = [self.create_invoice_doc_item(item) for item in item_doc.items] + if len(items) > 0: + self.create_invoice(cust, items, "Abrechnung Lieferschein " + dn["name"]+ " " + cust_doc.customer_name) + invoice_count += 1 + elif cust_doc.billing_mode == "Collective Bill": + for item in items: + invoice_doc_item = self.create_invoice_doc_item(item) + invoicing_items.append(invoice_doc_item) + if len(invoicing_items) > 0: + self.create_invoice(cust, invoicing_items, "Sammelrechnung " + cust_doc.customer_name) invoice_count += 1 - elif self.invoicing_grouped_by == "Service and Goods": - invoice_item = sales_order_items + goods_items - self.create_invoice(cust, invoice_item, "Ware " + cust_doc.customer_name) - if len(invoice_item) > 0: - invoice_count += 1 - self.create_invoice(cust, service_items, "Dienstleistung " + cust_doc.customer_name) - if len(service_items) >0: - invoice_count += 1 - else: - invoice_item = sales_order_items + service_items + goods_items - self.create_invoice(cust, invoice_item, "Dienstleistung und Ware "+ cust_doc.customer_name) - if len(invoice_item) > 0: - invoice_count += 1 + else: + item_group_separation_dict = get_item_group_assignment_table(cust) + print(item_group_separation_dict) + separation_item_groups = [[item_group_separation_dict[x].item_group,item_group_separation_dict[x].filter] for x in range(1, len(item_group_separation_dict) + 1) ] + if cust_doc.billing_mode == "per Item Group": + for el in separation_item_groups: + print(el[1]) + a = [] + for item in items: + if item.item_group in el[1]: + invoice_doc_item = self.create_invoice_doc_item(item) + a.append(invoice_doc_item) + items.remove(item) + if len(a) > 0: + self.create_invoice(cust, a, el[0] + " " +cust_doc.customer_name) + invoice_count +=1 + + i_items = [self.create_invoice_doc_item(item) for item in items] + if len(i_items) > 0: + self.create_invoice(cust, i_items, "Abrechnung " + cust_doc.customer_name) + invoice_count += 1 + if cust_doc.billing_mode == "per Sales Order, remaining per Item Group": + sales_order_items = [] + for item in items: + if item.against_sales_order: + invoice_doc_item = self.create_invoice_doc_item(item) + sales_order_items.append(invoice_doc_item) + items.remove(item) + if len(sales_order_items) > 0: + x = [i.sales_order for i in sales_order_items] + a = list(set(x)) + for el in a: + sal_ord_it = [] + for i in sales_order_items: + if i.sales_order == el: + sal_ord_it.append(i) + self.create_invoice(cust, sal_ord_it, "Sales Order "+ el+ " " + cust_doc.customer_name) + invoice_count += 1 + for el in separation_item_groups: + print(el[1]) + a = [] + for item in items: + if item.item_group in el[1]: + invoice_doc_item = self.create_invoice_doc_item(item) + a.append(invoice_doc_item) + items.remove(item) + self.create_invoice(cust, a, el[0] + " " +cust_doc.customer_name) + + i_items = [self.create_invoice_doc_item(item) for item in items] + self.create_invoice(cust, i_items, "Abrechnung " + cust_doc.customer_name) frappe.msgprint("Für " + str(cust_count)+ " Kunden wurden " + str(invoice_count) + " Rechnungen erstellt.") self.date = datetime.today().strftime('%Y-%m-%d') self.invoice_count = invoice_count - self.customer_count = cust_count + self.customer_count = cust_count + + + def create_invoice_doc_item(self, item): + #Funktion kreiert Invoice Item aus den gegebenen Delivery Note Items + invoice_doc_item = frappe.get_doc({ + "doctype": "Sales Invoice Item", + "item_code": item.item_code, + "description": item.description, + "qty": item.qty, + "uom" : item.uom, + "rate": item.rate, + "sales_order": item.against_sales_order, + "dn_detail": item.name, + "parent": "delivery_note", + "delivery_note": item.dn_detail + }) + return invoice_doc_item + + def create_invoice(self,cust,invoice_doc_items,title): invoice_doc = frappe.get_doc({ "doctype": "Sales Invoice", @@ -181,6 +231,7 @@ class AutoInvoiceGenerator(Document): "items": invoice_doc_items }) if len(invoice_doc_items)>0: + self.validate_items(invoice_doc_items) settings_doc = frappe.get_single("Auto Invoice Generator Settings") customer_doc = frappe.get_doc("Customer", cust ) @@ -206,4 +257,12 @@ class AutoInvoiceGenerator(Document): invoice_doc.append("taxes", new_tax) invoice_doc.save() - + def validate_items(self,item_list): + print("len(item_list):") + print(len(item_list)) + print("len(set(item_list)):") + print(len(set(item_list))) + if len(item_list) == len(set(item_list)): + return True + else: + frappe.msgprint("Rechnungspositionen doppelt")