def get_open_count(doctype, name): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) links = meta.get_dashboard_data() # compile all items in a list items = [] for group in links.transactions: items.extend(group.get('items')) out = [] for d in items: if d in links.get('internal_links', {}): # internal link continue filters = get_filters_for(d) fieldname = links.get('non_standard_fieldnames', {}).get(d, links.fieldname) data = {'name': d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len( frappe.get_all(d, fields='name', filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data['open_count'] = total total = len( frappe.get_all(d, fields='name', filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data['count'] = total out.append(data) out = { 'count': out, } module = frappe.get_meta_module(doctype) if hasattr(module, 'get_timeline_data'): out['timeline_data'] = module.get_timeline_data(doctype, name) return out
def get_open_count(doctype, name, items=None): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' if frappe.flags.in_migrate or frappe.flags.in_install: return { "count": [] } if items is None: items = [] frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) links = meta.get_dashboard_data() # compile all items in a list if not items: for group in links.transactions: items.extend(group.get("items")) if not isinstance(items, list): items = json.loads(items) out = [] for d in items: if d in links.get("internal_links", {}): # internal link continue filters = get_filters_for(d) fieldname = links.get("non_standard_fieldnames", {}).get(d, links.get('fieldname')) data = {"name": d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len(frappe.get_all(d, fields="name", filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data["open_count"] = total total = len(frappe.get_all(d, fields="name", filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data["count"] = total out.append(data) out = { "count": out, } module = frappe.get_meta_module(doctype) if hasattr(module, "get_timeline_data"): out["timeline_data"] = module.get_timeline_data(doctype, name) return out
def get_open_count(doctype, name, items=[]): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' if frappe.flags.in_migrate or frappe.flags.in_install: return { 'count': [] } frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) links = meta.get_dashboard_data() # compile all items in a list if not items: for group in links.transactions: items.extend(group.get('items')) if not isinstance(items, list): items = json.loads(items) out = [] for d in items: if d in links.get('internal_links', {}): # internal link continue filters = get_filters_for(d) fieldname = links.get('non_standard_fieldnames', {}).get(d, links.fieldname) data = {'name': d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len(frappe.get_all(d, fields='name', filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data['open_count'] = total total = len(frappe.get_all(d, fields='name', filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data['count'] = total out.append(data) out = { 'count': out, } module = frappe.get_meta_module(doctype) if hasattr(module, 'get_timeline_data'): out['timeline_data'] = module.get_timeline_data(doctype, name) return out
def set_sender_field_and_subject_field(self): '''Identify the sender and subject fields from the `append_to` DocType''' # set subject_field and sender_field meta_module = frappe.get_meta_module(self.append_to) meta = frappe.get_meta(self.append_to) self.subject_field = getattr(meta_module, "subject_field", "subject") if not meta.get_field(self.subject_field): self.subject_field = None self.sender_field = getattr(meta_module, "sender_field", "sender") if not meta.get_field(self.sender_field): self.sender_field = None
def set_thread(self, communication, email): """Appends communication to parent based on thread ID. Will extract parent communication and will link the communication to the reference of that communication. Also set the status of parent transaction to Open or Replied. If no thread id is found and `append_to` is set for the email account, it will create a new parent transaction (e.g. Issue)""" in_reply_to = (email.mail.get("In-Reply-To") or "").strip(" <>") parent = None if self.append_to: # set subject_field and sender_field meta_module = frappe.get_meta_module(self.append_to) meta = frappe.get_meta(self.append_to) subject_field = getattr(meta_module, "subject_field", "subject") if not meta.get_field(subject_field): subject_field = None sender_field = getattr(meta_module, "sender_field", "sender") if not meta.get_field(sender_field): sender_field = None if in_reply_to: if "@{0}".format(frappe.local.site) in in_reply_to: # reply to a communication sent from the system in_reply_to, domain = in_reply_to.split("@", 1) if frappe.db.exists("Communication", in_reply_to): parent = frappe.get_doc("Communication", in_reply_to) # set in_reply_to of current communication communication.in_reply_to = in_reply_to if parent.reference_name: parent = frappe.get_doc(parent.reference_doctype, parent.reference_name) if not parent and self.append_to and sender_field: if subject_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = strip(re.sub("^\s*(Re|RE)[^:]*:\s*", "", email.subject)) parent = frappe.db.get_all(self.append_to, filters={ sender_field: email.from_email, subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") # match only subject field # when the from_email is of a user in the system # and subject is atleast 10 chars long if not parent and len(subject) > 10 and is_system_user(email.from_email): parent = frappe.db.get_all(self.append_to, filters={ subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe.get_doc(self.append_to, parent[0].name) if not parent and self.append_to and self.append_to!="Communication": # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if subject_field: parent.set(subject_field, email.subject) if sender_field: parent.set(sender_field, email.from_email) parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value(self.append_to, {sender_field: email.from_email}) if parent_name: parent.name = parent_name else: parent = None # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True communication.is_first = True if parent: communication.reference_doctype = parent.doctype communication.reference_name = parent.name
def set_thread(self, communication, email): """Appends communication to parent based on thread ID. Will extract parent communication and will link the communication to the reference of that communication. Also set the status of parent transaction to Open or Replied. If no thread id is found and `append_to` is set for the email account, it will create a new parent transaction (e.g. Issue)""" in_reply_to = (email.mail.get("In-Reply-To") or "").strip(" <>") parent = None if self.append_to: # set subject_field and sender_field meta_module = frappe.get_meta_module(self.append_to) meta = frappe.get_meta(self.append_to) subject_field = getattr(meta_module, "subject_field", "subject") if not meta.get_field(subject_field): subject_field = None sender_field = getattr(meta_module, "sender_field", "sender") if not meta.get_field(sender_field): sender_field = None if in_reply_to: if "@{0}".format(frappe.local.site) in in_reply_to: # reply to a communication sent from the system in_reply_to, domain = in_reply_to.split("@", 1) if frappe.db.exists("Communication", in_reply_to): parent = frappe.get_doc("Communication", in_reply_to) # set in_reply_to of current communication communication.in_reply_to = in_reply_to if parent.reference_name: parent = frappe.get_doc(parent.reference_doctype, parent.reference_name) if not parent and self.append_to and sender_field: if subject_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = strip( re.sub("^\s*(Re|RE)[^:]*:\s*", "", email.subject)) parent = frappe.db.get_all( self.append_to, filters={ sender_field: email.from_email, subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") # match only subject field # when the from_email is of a user in the system # and subject is atleast 10 chars long if not parent and len(subject) > 10 and is_system_user( email.from_email): parent = frappe.db.get_all( self.append_to, filters={ subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe.get_doc(self.append_to, parent[0].name) if not parent and self.append_to and self.append_to != "Communication": # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if subject_field: parent.set(subject_field, email.subject) if sender_field: parent.set(sender_field, email.from_email) parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value( self.append_to, {sender_field: email.from_email}) if parent_name: parent.name = parent_name else: parent = None # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True communication.is_first = True if parent: communication.reference_doctype = parent.doctype communication.reference_name = parent.name
def set_thread(self, communication, email): """Appends communication to parent based on thread ID. Will extract parent communication and will link the communication to the reference of that communication. Also set the status of parent transaction to Open or Replied. If no thread id is found and `append_to` is set for the email account, it will create a new parent transaction (e.g. Issue)""" in_reply_to = (email.mail.get("In-Reply-To") or "") parent = None if self.append_to: # set subject_field and sender_field meta_module = frappe.get_meta_module(self.append_to) meta = frappe.get_meta(self.append_to) subject_field = getattr(meta_module, "subject_field", "subject") if not meta.get_field(subject_field): subject_field = None sender_field = getattr(meta_module, "sender_field", "sender") if not meta.get_field(sender_field): sender_field = None matched = False if in_reply_to: # reply to a communication sent from the system reply_found = frappe.db.get_value("Communication", {"message_id": in_reply_to}, ["name", "reference_doctype", "reference_name"], order_by="creation", as_dict=1) if reply_found: # set in_reply_to of current communication communication.in_reply_to = reply_found.name if frappe.db.exists(reply_found.reference_doctype, reply_found.reference_name): communication.reference_doctype = reply_found.reference_doctype communication.reference_name = reply_found.reference_name matched = True if email.message_id: first = frappe.db.get_value("Communication", {"message_id": email.message_id},["name", "reference_doctype", "reference_name"], order_by="creation", as_dict=1) if first: #set timeline hide to parent doc so are linked communication.timeline_hide = first.name if frappe.db.exists(first.reference_doctype, first.reference_name): communication.reference_doctype = first.reference_doctype communication.reference_name = first.reference_name matched = True if not matched: if not parent and self.append_to and sender_field: if subject_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = strip(re.sub("^\s*(Re|RE)[^:]*:\s*", "", email.subject)) parent = frappe.db.get_all(self.append_to, filters={ sender_field: email.from_email, subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") # match only subject field # when the from_email is of a user in the system # and subject is atleast 10 chars long if not parent and len(subject) > 10 and is_system_user(email.from_email): parent = frappe.db.get_all(self.append_to, filters={ subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe.get_doc(self.append_to, parent[0].name) if not parent: # try match doctype based on subject if ':' in email.subject: try: subject = strip(re.sub("(^\s*(Fw|FW|fwd)[^:]*:|\s*(Re|RE)[^:]*:\s*)*","", email.subject)) if ':' in subject: reference_doctype,reference_name = subject.split(': ',1) parent = frappe.get_doc(reference_doctype,reference_name) except: try: ref = re.search("((?<=New Leave Application: ).*(?= - Employee:))",email.subject).group(0) parent = frappe.get_doc("Leave Application",ref) except: pass if not parent and self.append_to and self.append_to!="Communication": # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if subject_field: parent.set(subject_field, email.subject) if sender_field: parent.set(sender_field, email.from_email) parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value(self.append_to, {sender_field: email.from_email}) if parent_name: parent.name = parent_name else: parent = None # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True communication.is_first = True if parent: communication.reference_doctype = parent.doctype communication.reference_name = parent.name # check if message is notification and disable notifications for this message isnotification = email.mail.get("isnotification") if isnotification: if "notification" in isnotification: communication.unread_notification_sent = 1
# -*- coding: utf-8 -*- # Copyright (c) 2021, Lin To and Contributors # See license.txt from __future__ import unicode_literals import frappe import unittest from accounting.test_helpers import get_doc_names, get_autonamed_items from accounting.test_helpers import delete_all_docs, check_if_doc_exists from accounting.test_helpers import get_item_autoname get_account_name = frappe.get_meta_module("Account").get_account_name class TestSalesInvoice(unittest.TestCase): @classmethod def setUpClass(cls): cls.doc_handler = DocHandler() for ( company, customer, items, receiving_account, stock_account, posting_date, ) in _test_records: cls.doc_handler.create_and_insert_sales_invoice( company, customer, items, receiving_account, stock_account, posting_date) cls.doc_handler.save_and_submit_docs()
def set_thread(self, communication, email): """Appends communication to parent based on thread ID. Will extract parent communication and will link the communication to the reference of that communication. Also set the status of parent transaction to Open or Replied. If no thread id is found and `append_to` is set for the email account, it will create a new parent transaction (e.g. Issue)""" in_reply_to = (email.mail.get("In-Reply-To") or "").strip(" <>") parent = None if self.append_to: # set subject_field and sender_field meta_module = frappe.get_meta_module(self.append_to) meta = frappe.get_meta(self.append_to) subject_field = getattr(meta_module, "subject_field", "subject") if not meta.get_field(subject_field): subject_field = None sender_field = getattr(meta_module, "sender_field", "sender") if not meta.get_field(sender_field): sender_field = None if in_reply_to: if "@" in in_reply_to: # reply to a communication sent from the system in_reply_to = in_reply_to.split("@", 1)[0] if frappe.db.exists("Communication", in_reply_to): parent = frappe.get_doc("Communication", in_reply_to) if parent.reference_name: if self.append_to: # parent must reference only if name matches if parent.reference_doctype==self.append_to: # parent same as parent of last communication parent = frappe.get_doc(parent.reference_doctype, parent.reference_name) else: parent = frappe.get_doc(parent.reference_doctype, parent.reference_name) if not parent and self.append_to and subject_field and sender_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = re.sub("Re[^:]*:\s*", "", email.subject) parent = frappe.db.get_all(self.append_to, filters={ sender_field: email.from_email, subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe.get_doc(self.append_to, parent[0].name) if not parent and self.append_to: # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if subject_field: parent.set(subject_field, email.subject) if sender_field: parent.set(sender_field, email.from_email) parent.flags.ignore_mandatory = True parent.insert(ignore_permissions=True) communication.is_first = True if parent: communication.reference_doctype = parent.doctype communication.reference_name = parent.name
def get_open_count(doctype, name, links): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) #links = meta.get_dashboard_data() links = frappe._dict({ 'fieldname': 'party', 'transactions': [ { 'label': _('Outward Sample'), 'items': ['Outward Sample'] }, { 'label': _('Inward Sample'), 'items': ['Inward Sample'] }, ] }) #frappe.msgprint(str(links)) #links = frappe._dict(links) #return {'count':0} # compile all items in a list items = [] for group in links.transactions: items.extend(group.get('items')) out = [] for d in items: if d in links.get('internal_links', {}): # internal link continue filters = get_filters_for(d) fieldname = links.get('non_standard_fieldnames', {}).get(d, links.fieldname) #return fieldname data = {'name': d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len(frappe.get_all(d, fields='name', filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data['open_count'] = total total = len(frappe.get_all(d, fields='name', filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data['count'] = total out.append(data) out = { 'count': out, } module = frappe.get_meta_module(doctype) if hasattr(module, 'get_timeline_data'): out['timeline_data'] = module.get_timeline_data(doctype, name) return out # if isinstance(doc, string_types): # doc = json.loads(doc) # so_list = [d['sales_order'] for d in doc['sales_orders'] if d['sales_order']] # sample_list = [d['outward_sample'] for d in doc['finish_items'] if d['outward_sample']] # if not sample_list: # frappe.msgprint(_("Please enter Sales Orders in the above table")) # return [] # for sample in sample_list: # sample_doc = frappe.get_doc("Outward Sample",sample) # items_list = [d.item_code for d in sample_doc.details] # for item_code in items_list: # items = frappe.db.sql("""select item as item_code,name as bom_no from `tabBOM` where item = '%s' and is_active = 1 and is_default = 1 and docstatus= 1"""%item_code,as_dict=1) # if doc['item_code']: # item_condition = ' and so_item.item_code = "{0}"'.format(frappe.db.escape( doc['item_code'])) # packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse, # (((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty) # as pending_qty, pi.parent_item, so_item.name # from `tabSales Order Item` so_item, `tabPacked Item` pi # where so_item.parent = pi.parent and so_item.docstatus = 1 # and pi.parent_item = so_item.item_code # and so_item.parent in (%s) and so_item.qty > so_item.work_order_qty # and exists (select name from `tabBOM` bom where bom.item=pi.item_code # and bom.is_active = 1) %s""" % \ # (", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1) # add_items(items,packed_items) # # calculate_total_planned_qty() # def add_items(self, items): # self.set('po_items', []) # for data in items: # item_details = get_item_details(data.item_code) # pi = self.append('po_items', { # 'include_exploded_items': 1, # 'warehouse': data.warehouse, # 'item_code': data.item_code, # 'description': item_details and item_details.description or '', # 'stock_uom': item_details and item_details.stock_uom or '', # 'bom_no': item_details and item_details.bom_no or '', # 'planned_qty': data.pending_qty, # 'pending_qty': data.pending_qty, # 'planned_start_date': now_datetime(), # 'product_bundle_item': data.parent_item # }) # if self.get_items_from == "Sales Order": # pi.sales_order = data.parent # pi.sales_order_item = data.name # elif self.get_items_from == "Material Request": # pi.material_request = data.parent # pi.material_request_item = data.name # # def calculate_total_planned_qty(self): # # self.total_planned_qty = 0 # # for d in self.po_items: # # self.total_planned_qty += flt(d.planned_qty)