Example #1
0
def make_raw_material_request(items, company, sales_order, project=None):
	if not frappe.has_permission("Sales Order", "write"):
		frappe.throw(_("Not permitted"), frappe.PermissionError)

	if isinstance(items, str):
		items = frappe._dict(json.loads(items))

	for item in items.get("items"):
		item["include_exploded_items"] = items.get("include_exploded_items")
		item["ignore_existing_ordered_qty"] = items.get("ignore_existing_ordered_qty")
		item["include_raw_materials_from_sales_order"] = items.get(
			"include_raw_materials_from_sales_order"
		)

	items.update({"company": company, "sales_order": sales_order})

	raw_materials = get_items_for_material_requests(items)
	if not raw_materials:
		frappe.msgprint(
			_("Material Request not created, as quantity for Raw Materials already available.")
		)
		return

	material_request = frappe.new_doc("Material Request")
	material_request.update(
		dict(
			doctype="Material Request",
			transaction_date=nowdate(),
			company=company,
			material_request_type="Purchase",
		)
	)
	for item in raw_materials:
		item_doc = frappe.get_cached_doc("Item", item.get("item_code"))

		schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
		row = material_request.append(
			"items",
			{
				"item_code": item.get("item_code"),
				"qty": item.get("quantity"),
				"schedule_date": schedule_date,
				"warehouse": item.get("warehouse"),
				"sales_order": sales_order,
				"project": project,
			},
		)

		if not (strip_html(item.get("description")) and strip_html(item_doc.description)):
			row.description = item_doc.item_name or item.get("item_code")

	material_request.insert()
	material_request.flags.ignore_permissions = 1
	material_request.run_method("set_missing_values")
	material_request.submit()
	return material_request
Example #2
0
def make_raw_material_request(items, company, sales_order, project=None):
    if not frappe.has_permission("Sales Order", "write"):
        frappe.throw(_("Not permitted"), frappe.PermissionError)

    if isinstance(items, string_types):
        items = frappe._dict(json.loads(items))

    for item in items.get('items'):
        item["include_exploded_items"] = items.get('include_exploded_items')
        item["ignore_existing_ordered_qty"] = items.get(
            'ignore_existing_ordered_qty')
        item["include_raw_materials_from_sales_order"] = items.get(
            'include_raw_materials_from_sales_order')

    items.update({'company': company, 'sales_order': sales_order})

    raw_materials = get_items_for_material_requests(items)
    if not raw_materials:
        frappe.msgprint(
            _("Material Request not created, as quantity for Raw Materials already available."
              ))
        return

    material_request = frappe.new_doc('Material Request')
    material_request.update(
        dict(doctype='Material Request',
             transaction_date=nowdate(),
             company=company,
             requested_by=frappe.session.user,
             material_request_type='Purchase'))
    for item in raw_materials:
        item_doc = frappe.get_cached_doc('Item', item.get('item_code'))

        schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
        row = material_request.append(
            'items', {
                'item_code': item.get('item_code'),
                'qty': item.get('quantity'),
                'schedule_date': schedule_date,
                'warehouse': item.get('warehouse'),
                'sales_order': sales_order,
                'project': project
            })

        if not (strip_html(item.get("description"))
                and strip_html(item_doc.description)):
            row.description = item_doc.item_name or item.get('item_code')

    material_request.insert()
    material_request.flags.ignore_permissions = 1
    material_request.run_method("set_missing_values")
    material_request.submit()
    return material_request
def send_notification(self, doc):
  '''Build recipients and send Notification'''

  context = get_context(doc)
  context = {"doc": doc, "alert": self, "comments": None, "frappe": frappe}
  if doc.get("_comments"):
    context["comments"] = json.loads(doc.get("_comments"))

  if self.is_standard:
    self.load_standard_properties(context)

  if self.channel == 'Email':
    self.send_an_email(doc, context)
  elif self.channel == 'Slack':
    self.send_a_slack_msg(doc, context)
  elif self.channel == 'FCM':
    send_via_fcm(self, doc, context)
  elif self.channel == "SMS":
    recipients = get_sms_recipients_for_notification(
        notification=self, doc=doc, context=context)
    if recipients:
      send_sms(receiver_list=recipients, msg=strip_html(
          frappe.render_template(self.message, context)), provider=self.sms_providers)

  if self.set_property_after_alert:
    frappe.db.set_value(doc.doctype, doc.name, self.set_property_after_alert,
                        self.property_value, update_modified=False)
    doc.set(self.set_property_after_alert, self.property_value)
Example #4
0
    def validate(self):
        if self.reference_doctype and self.reference_name:
            if not self.reference_owner:
                self.reference_owner = frappe.db.get_value(self.reference_doctype, self.reference_name, "owner")

                # prevent communication against a child table
            if frappe.get_meta(self.reference_doctype).istable:
                frappe.throw(
                    _("Cannot create a {0} against a child document: {1}").format(
                        _(self.communication_type), _(self.reference_doctype)
                    )
                )

        if not self.user:
            self.user = frappe.session.user

        if not self.subject:
            self.subject = strip_html((self.content or "")[:141])

        if not self.sent_or_received:
            self.sent_or_received = "Sent"

        self.set_status()
        self.set_sender_full_name()
        validate_email(self)
        validate_comment(self)
        self.set_timeline_doc()
Example #5
0
    def validate(self):
        if self.reference_doctype and self.reference_name:
            if not self.reference_owner:
                self.reference_owner = frappe.db.get_value(
                    self.reference_doctype, self.reference_name, "owner")

            # prevent communication against a child table
            if frappe.get_meta(self.reference_doctype).istable:
                frappe.throw(
                    _("Cannot create a {0} against a child document: {1}"
                      ).format(_(self.communication_type),
                               _(self.reference_doctype)))

        if not self.user:
            self.user = frappe.session.user

        if not self.subject:
            self.subject = strip_html((self.content or "")[:141])

        if not self.sent_or_received:
            self.sent_or_received = "Sent"

        self.set_status()
        self.set_sender_full_name()
        validate_email(self)
        self.set_timeline_doc()
Example #6
0
    def _get_missing_mandatory_fields(self):
        """Get mandatory fields that do not have any values"""
        def get_msg(df):
            if df.fieldtype == "Table":
                return "{}: {}: {}".format(_("Error"),
                                           _("Data missing in table"),
                                           _(df.label))

            elif self.parentfield:
                return "{}: {} {} #{}: {}: {}".format(
                    _("Error"), frappe.bold(_(self.doctype)), _("Row"),
                    self.idx, _("Value missing for"), _(df.label))

            else:
                return _("Error: Value missing for {0}: {1}").format(
                    _(df.parent), _(df.label))

        missing = []

        for df in self.meta.get("fields", {"reqd": ('=', 1)}):
            if self.get(df.fieldname) in (None, []) or not strip_html(
                    cstr(self.get(df.fieldname))).strip():
                missing.append((df.fieldname, get_msg(df)))

        # check for missing parent and parenttype
        if self.meta.istable:
            for fieldname in ("parent", "parenttype"):
                if not self.get(fieldname):
                    missing.append(
                        (fieldname, get_msg(frappe._dict(label=fieldname))))

        return missing
Example #7
0
	def _get_missing_mandatory_fields(self):
		"""Get mandatory fields that do not have any values"""
		def get_msg(df):
			if df.fieldtype == "Table":
				return "{}: {}: {}".format(_("Error"), _("Data missing in table"), _(df.label))

			elif self.parentfield:
				return "{}: {} {} #{}: {}: {}".format(_("Error"), frappe.bold(_(self.doctype)),
					_("Row"), self.idx, _("Value missing for"), _(df.label))

			else:
				return _("Error: Value missing for {0}: {1}").format(_(df.parent), _(df.label))

		missing = []

		for df in self.meta.get("fields", {"reqd": ('=', 1)}):
			if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip():
				missing.append((df.fieldname, get_msg(df)))

		# check for missing parent and parenttype
		if self.meta.istable:
			for fieldname in ("parent", "parenttype"):
				if not self.get(fieldname):
					missing.append((fieldname, get_msg(frappe._dict(label=fieldname))))

		return missing
Example #8
0
	def set_title_and_header(self, context):
		"""Extract and set title and header from content or context."""
		if not "no_header" in context:
			if "<!-- no-header -->" in context.main_section:
				context.no_header = 1

		if "<!-- title:" in context.main_section:
			context.title = re.findall('<!-- title:([^>]*) -->', context.main_section)[0].strip()

		if context.get("page_titles") and context.page_titles.get(context.pathname):
			context.title = context.page_titles.get(context.pathname)[0]

		# header
		if context.no_header and "header" in context:
			context.header = ""

		if not context.no_header:
			# if header not set and no h1 tag in the body, set header as title
			if not context.header and "<h1" not in context.main_section:
				context.header = context.title

			# add h1 tag to header
			if context.get("header") and not re.findall("<h.>", context.header):
				context.header = "<h1>" + context.header + "</h1>"

		# if title not set, set title from header
		if not context.title and context.header:
			context.title = strip_html(context.header)
Example #9
0
def set_title_and_header(out, context):
    """Extract and set title and header from content or context."""
    out["no_header"] = context.get(
        "no_header", 0) or ("<!-- no-header -->" in out.get("content", ""))

    if "<!-- title:" in out.get("content", ""):
        out["title"] = re.findall('<!-- title:([^>]*) -->',
                                  out.get("content"))[0].strip()

    if "title" not in out:
        out["title"] = context.get("title")

    if context.get("page_titles") and context.page_titles.get(
            context.pathname):
        out["title"] = context.page_titles.get(context.pathname)[0]

    # header
    if out["no_header"]:
        out["header"] = ""
    else:
        if "title" not in out and out.get("header"):
            out["title"] = out["header"]

        if not out.get("header") and "<h1" not in out.get("content", ""):
            if out.get("title"):
                out["header"] = out["title"]

        if out.get("header") and not re.findall("<h.>", out["header"]):
            out["header"] = "<h1>" + out["header"] + "</h1>"

    if not out.get("header"):
        out["no_header"] = 1

    out["title"] = strip_html(out.get("title") or "")
Example #10
0
def set_title_and_header(out, context):
	"""Extract and set title and header from content or context."""
	out["no_header"] = context.get("no_header", 0) or ("<!-- no-header -->" in out.get("content", ""))

	if "<!-- title:" in out.get("content", ""):
		out["title"] = re.findall('<!-- title:([^>]*) -->', out.get("content"))[0].strip()

	if "title" not in out:
		out["title"] = context.get("title")

	if context.get("page_titles") and context.page_titles.get(context.pathname):
		out["title"] = context.page_titles.get(context.pathname)[0]

	# header
	if out["no_header"]:
		out["header"] = ""
	else:
		if "title" not in out and out.get("header"):
			out["title"] = out["header"]

		if not out.get("header") and "<h1" not in out.get("content", ""):
			if out.get("title"):
				out["header"] = out["title"]

		if out.get("header") and not re.findall("<h.>", out["header"]):
			out["header"] = "<h1>" + out["header"] + "</h1>"

	if not out.get("header"):
		out["no_header"] = 1

	out["title"] = strip_html(out.get("title") or "")
Example #11
0
    def _get_missing_mandatory_fields(self):
        """Get mandatory fields that do not have any values"""
        def get_msg(df):
            if df.fieldtype == "Table":
                return "{}: {}: {}".format(_("Error"),
                                           _("Data missing in table"),
                                           _(df.label))

            elif self.parentfield:
                return "{}: {} #{}: {}: {}".format(_("Error"), _("Row"),
                                                   self.idx,
                                                   _("Value missing for"),
                                                   _(df.label))

            else:
                return "{}: {}: {}".format(_("Error"), _("Value missing for"),
                                           _(df.label))

        missing = []

        for df in self.meta.get("fields", {"reqd": 1}):
            if self.get(df.fieldname) in (None, []) or not strip_html(
                    cstr(self.get(df.fieldname))).strip():
                missing.append((df.fieldname, get_msg(df)))

        return missing
Example #12
0
    def set_title_and_header(self, context):
        """Extract and set title and header from content or context."""
        if not "no_header" in context:
            if "<!-- no-header -->" in context.main_section:
                context.no_header = 1

        if not context.title:
            context.title = extract_title(context.main_section,
                                          context.path_name)

        # header
        if context.no_header and "header" in context:
            context.header = ""

        if not context.no_header:
            # if header not set and no h1 tag in the body, set header as title
            if not context.header and "<h1" not in context.main_section:
                context.header = context.title

            # add h1 tag to header
            if context.get("header") and not re.findall(
                    "<h.>", context.header):
                context.header = "<h1>" + context.header + "</h1>"

        # if title not set, set title from header
        if not context.title and context.header:
            context.title = strip_html(context.header)
Example #13
0
def send_notification_email(doc):

	if doc.type == 'Energy Point' and doc.email_content is None:
		return

	from frappe.utils import get_url_to_form, strip_html

	doc_link = get_url_to_form(doc.document_type, doc.document_name)
	header = get_email_header(doc)
	email_subject = strip_html(doc.subject)

	frappe.sendmail(
		recipients = doc.for_user,
		subject = email_subject,
		template = "new_notification",
		args = {
			'body_content': doc.subject,
			'description': doc.email_content,
			'document_type': doc.document_type,
			'document_name': doc.document_name,
			'doc_link': doc_link
		},
		header = [header, 'orange'],
		now=frappe.flags.in_test
	)
Example #14
0
def has_value(df, doc):
	value = doc.get(df.fieldname)
	if value in (None, ""):
		return False

	elif isinstance(value, basestring) and not strip_html(value).strip():
		return False

	return True
Example #15
0
def has_value(df, doc):
    value = doc.get(df.fieldname)
    if value in (None, ""):
        return False

    elif isinstance(value, basestring) and not strip_html(value).strip():
        return False

    return True
Example #16
0
def has_value(df, doc):
    value = doc.get(df.fieldname)
    if value in (None, ""):
        return False

    elif isinstance(value, string_types) and not strip_html(value).strip():
        return False

    elif isinstance(value, list) and not len(value):
        return False

    return True
Example #17
0
    def set_metatags(self, context):
        context.metatags = {
            "name":
            context.title,
            "description":
            context.description or strip_html(
                (context.main_section or "").replace("\n", " "))[:500]
        }

        image = find_first_image(context.main_section or "")
        if image:
            context.metatags["image"] = image
Example #18
0
def has_value(df, doc):
	value = doc.get(df.fieldname)
	if value in (None, ""):
		return False

	elif isinstance(value, string_types) and not strip_html(value).strip():
		return False

	elif isinstance(value, list) and not len(value):
		return False

	return True
Example #19
0
def render_blocks(context):
	"""returns a dict of block name and its rendered content"""

	out = {}

	env = frappe.get_jenv()

	def _render_blocks(template_path):
		source = frappe.local.jloader.get_source(frappe.local.jenv, template_path)[0]
		for referenced_template_path in meta.find_referenced_templates(env.parse(source)):
			if referenced_template_path:
				_render_blocks(referenced_template_path)

		template = frappe.get_template(template_path)
		for block, render in template.blocks.items():
			out[block] = scrub_relative_urls(concat(render(template.new_context(context))))

	_render_blocks(context["template_path"])

	# default blocks if not found
	if "title" not in out and out.get("header"):
		out["title"] = out["header"]

	if "title" not in out:
		out["title"] = context.get("title")

	if "header" not in out and out.get("title"):
		out["header"] = out["title"]

	if not out["header"].startswith("<h"):
		out["header"] = "<h2>" + out["header"] + "</h2>"

	if "breadcrumbs" not in out:
		out["breadcrumbs"] = scrub_relative_urls(
			frappe.get_template("templates/includes/breadcrumbs.html").render(context))

	if "<!-- no-sidebar -->" in out.get("content", ""):
		out["no_sidebar"] = 1

	if "sidebar" not in out and not out.get("no_sidebar"):
		out["sidebar"] = scrub_relative_urls(
			frappe.get_template("templates/includes/sidebar.html").render(context))

	out["title"] = strip_html(out.get("title") or "")

	# remove style and script tags from blocks
	out["style"] = re.sub("</?style[^<>]*>", "", out.get("style") or "")
	out["script"] = re.sub("</?script[^<>]*>", "", out.get("script") or "")

	return out
Example #20
0
def has_value(df, doc):
    value = doc.get(df.fieldname)
    if value in (None, ""):
        return False

    elif isinstance(value, str) and not strip_html(value).strip():
        if df.fieldtype in ["Text", "Text Editor"]:
            return True

        return False

    elif isinstance(value, list) and not len(value):
        return False

    return True
Example #21
0
    def set_fetch_from_value(self, doctype, df, values):
        fetch_from_fieldname = df.fetch_from.split('.')[-1]
        value = values[fetch_from_fieldname]
        if df.fieldtype == 'Small Text' or df.fieldtype == 'Text' or df.fieldtype == 'Data':
            if fetch_from_fieldname in default_fields:
                from frappe.model.meta import get_default_df
                fetch_from_df = get_default_df(fetch_from_fieldname)
            else:
                fetch_from_df = frappe.get_meta(doctype).get_field(
                    fetch_from_fieldname)

            fetch_from_ft = fetch_from_df.get('fieldtype')
            if fetch_from_ft == 'Text Editor' and value:
                value = unescape_html(strip_html(value))
        setattr(self, df.fieldname, value)
Example #22
0
def column_has_value(data, fieldname):
    """Check if at least one cell in column has non-zero and non-blank value"""
    has_value = False

    for row in data:
        value = row.get(fieldname)
        if value:
            if isinstance(value, basestring):
                if strip_html(value).strip():
                    has_value = True
                    break
            else:
                has_value = True
                break

    return has_value
Example #23
0
def column_has_value(data, fieldname):
	"""Check if at least one cell in column has non-zero and non-blank value"""
	has_value = False

	for row in data:
		value = row.get(fieldname)
		if value:
			if isinstance(value, string_types):
				if strip_html(value).strip():
					has_value = True
					break
			else:
				has_value = True
				break

	return has_value
Example #24
0
    def test_custom_doctype_medical_record(self):
        # tests for medical record creation of standard doctypes in test_patient_medical_record.py
        patient = create_patient()
        doc = create_doc(patient)
        # check for medical record
        medical_rec = frappe.db.exists("Patient Medical Record", {
            "status": "Open",
            "reference_name": doc.name
        })
        self.assertTrue(medical_rec)

        medical_rec = frappe.get_doc("Patient Medical Record", medical_rec)
        expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format(
            frappe.utils.format_date(getdate()))
        self.assertEqual(strip_html(medical_rec.subject), expected_subject)
        self.assertEqual(medical_rec.patient, patient)
        self.assertEqual(medical_rec.communication_date, getdate())
Example #25
0
	def validate(self):
		self.validate_reference()

		if not self.user:
			self.user = frappe.session.user

		if not self.subject:
			self.subject = strip_html((self.content or "")[:141])

		if not self.sent_or_received:
			self.seen = 1
			self.sent_or_received = "Sent"

		self.set_status()
		self.set_sender_full_name()

		validate_email(self)
		set_timeline_doc(self)
Example #26
0
	def validate(self):
		self.validate_reference()

		if not self.user:
			self.user = frappe.session.user

		if not self.subject:
			self.subject = strip_html((self.content or "")[:141])

		if not self.sent_or_received:
			self.seen = 1
			self.sent_or_received = "Sent"

		self.set_status()
		self.set_sender_full_name()

		validate_email(self)
		set_timeline_doc(self)
Example #27
0
def column_has_value(data, fieldname, col_df):
	"""Check if at least one cell in column has non-zero and non-blank value"""
	has_value = False

	if col_df.fieldtype in ['Float', 'Currency'] and not col_df.print_hide_if_no_value:
		return True

	for row in data:
		value = row.get(fieldname)
		if value:
			if isinstance(value, string_types):
				if strip_html(value).strip():
					has_value = True
					break
			else:
				has_value = True
				break

	return has_value
Example #28
0
def column_has_value(data, fieldname, col_df):
	"""Check if at least one cell in column has non-zero and non-blank value"""
	has_value = False

	if col_df.fieldtype in ['Float', 'Currency'] and not col_df.print_hide_if_no_value:
		return True

	for row in data:
		value = row.get(fieldname)
		if value:
			if isinstance(value, string_types):
				if strip_html(value).strip():
					has_value = True
					break
			else:
				has_value = True
				break

	return has_value
Example #29
0
    def validate(self):
        if not self.item_name:
            self.item_name = self.item_code

        if not strip_html(cstr(self.description)).strip():
            self.description = self.item_name

        self.validate_uom()
        self.validate_description()
        self.add_default_uom_in_conversion_factor_table()
        self.validate_conversion_factor()
        self.validate_item_type()
        self.validate_naming_series()
        self.check_for_active_boms()
        self.fill_customer_code()
        self.check_item_tax()
        self.validate_barcode()
        self.validate_warehouse_for_reorder()
        self.update_bom_item_desc()
        self.synced_with_hub = 0

        self.validate_has_variants()
        self.validate_attributes_in_variants()
        self.validate_stock_exists_for_template_item()
        self.validate_attributes()
        self.validate_variant_attributes()
        self.validate_variant_based_on_change()
        self.validate_fixed_asset()
        self.clear_retain_sample()
        self.validate_retain_sample()
        self.validate_uom_conversion_factor()
        self.validate_customer_provided_part()
        self.update_defaults_from_item_group()
        self.validate_item_defaults()
        self.validate_auto_reorder_enabled_in_stock_settings()
        self.cant_change()
        self.validate_item_tax_net_rate_range()
        set_item_tax_from_hsn_code(self)

        if not self.is_new():
            self.old_item_group = frappe.db.get_value(self.doctype, self.name,
                                                      "item_group")
Example #30
0
	def set_fetch_from_value(self, doctype, df, values):
		fetch_from_fieldname = df.fetch_from.split('.')[-1]
		value = values[fetch_from_fieldname]
		if df.fieldtype in ['Small Text', 'Text', 'Data']:
			if fetch_from_fieldname in default_fields:
				from frappe.model.meta import get_default_df
				fetch_from_df = get_default_df(fetch_from_fieldname)
			else:
				fetch_from_df = frappe.get_meta(doctype).get_field(fetch_from_fieldname)

			if not fetch_from_df:
				frappe.throw(
					_('Please check the value of "Fetch From" set for field {0}').format(frappe.bold(df.label)),
					title = _('Wrong Fetch From value')
				)

			fetch_from_ft = fetch_from_df.get('fieldtype')
			if fetch_from_ft == 'Text Editor' and value:
				value = unescape_html(strip_html(value))
		setattr(self, df.fieldname, value)
Example #31
0
	def _get_missing_mandatory_fields(self):
		"""Get mandatory fields that do not have any values"""
		def get_msg(df):
			if df.fieldtype == "Table":
				return "{}: {}: {}".format(_("Error"), _("Data missing in table"), _(df.label))

			elif self.parentfield:
				return "{}: {} #{}: {}: {}".format(_("Error"), _("Row"), self.idx,
					_("Value missing for"), _(df.label))

			else:
				return "{}: {}: {}".format(_("Error"), _("Value missing for"), _(df.label))

		missing = []

		for df in self.meta.get("fields", {"reqd": 1}):
			if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip():
				missing.append((df.fieldname, get_msg(df)))

		return missing
Example #32
0
    def validate(self):
        if self.reference_doctype and self.reference_name:
            if not self.reference_owner:
                self.reference_owner = frappe.db.get_value(
                    self.reference_doctype, self.reference_name, "owner")

            # prevent communication against a child table
            if frappe.get_meta(self.reference_doctype).istable:
                frappe.throw(
                    _("Cannot create a {0} against a child document: {1}"
                      ).format(_(self.communication_type),
                               _(self.reference_doctype)))

            # Prevent circular linking of Communication DocTypes
            if self.reference_doctype == "Communication":
                circular_linking = False
                doc = get_parent_doc(self)
                while doc.reference_doctype == "Communication":
                    if get_parent_doc(doc).name == self.name:
                        circular_linking = True
                        break
                    doc = get_parent_doc(doc)
                if circular_linking:
                    frappe.throw(
                        _("Please make sure the Reference Communication Docs are not circularly linked."
                          ), frappe.CircularLinkingError)

        if not self.user:
            self.user = frappe.session.user

        if not self.subject:
            self.subject = strip_html((self.content or "")[:141])

        if not self.sent_or_received:
            self.seen = 1
            self.sent_or_received = "Sent"

        self.set_status()
        self.set_sender_full_name()
        validate_email(self)
        set_timeline_doc(self)
Example #33
0
    def validate(self):
        self.validate_reference()

        if not self.user:
            self.user = frappe.session.user

        if not self.subject:
            self.subject = strip_html((self.content or "")[:141])

        if not self.sent_or_received:
            self.seen = 1
            self.sent_or_received = "Sent"

        self.set_status()
        self.set_sender_full_name()

        validate_email(self)

        if self.communication_medium == "Email":
            self.set_timeline_links()
            self.deduplicate_timeline_links()
Example #34
0
	def validate(self):
		if self.reference_doctype and self.reference_name:
			if not self.reference_owner:
				self.reference_owner = frappe.db.get_value(self.reference_doctype, self.reference_name, "owner")

			# prevent communication against a child table
			if frappe.get_meta(self.reference_doctype).istable:
				frappe.throw(_("Cannot create a {0} against a child document: {1}")
					.format(_(self.communication_type), _(self.reference_doctype)))

			# Prevent circular linking of Communication DocTypes
			if self.reference_doctype == "Communication":
				circular_linking = False
				doc = get_parent_doc(self)
				while doc.reference_doctype == "Communication":
					if get_parent_doc(doc).name==self.name:
						circular_linking = True
						break
					doc = get_parent_doc(doc)
				if circular_linking:
					frappe.throw(_("Please make sure the Reference Communication Docs are not circularly linked."), frappe.CircularLinkingError)

		if not self.user:
			self.user = frappe.session.user

		if not self.subject:
			self.subject = strip_html((self.content or "")[:141])

		if not self.sent_or_received:
			self.seen = 1
			self.sent_or_received = "Sent"

		self.set_status()
		self.set_sender_full_name()
		validate_email(self)
		set_timeline_doc(self)
Example #35
0
def render_blocks(context):
	"""returns a dict of block name and its rendered content"""

	out = {}

	env = frappe.get_jenv()

	def _render_blocks(template_path):
		source = frappe.local.jloader.get_source(frappe.local.jenv, template_path)[0]
		for referenced_template_path in meta.find_referenced_templates(env.parse(source)):
			if referenced_template_path:
				_render_blocks(referenced_template_path)

		template = frappe.get_template(template_path)
		for block, render in template.blocks.items():
			out[block] = scrub_relative_urls(concat(render(template.new_context(context))))

	_render_blocks(context["template"])

	# default blocks if not found
	if "title" not in out and out.get("header"):
		out["title"] = out["header"]

	if "title" not in out:
		out["title"] = context.get("title")

	if "header" not in out and out.get("title"):
		out["header"] = out["title"]

	if out.get("header") and not out["header"].startswith("<h"):
		out["header"] = "<h2>" + out["header"] + "</h2>"

	if "breadcrumbs" not in out:
		out["breadcrumbs"] = scrub_relative_urls(
			frappe.get_template("templates/includes/breadcrumbs.html").render(context))

	if "meta_block" not in out:
		out["meta_block"] = frappe.get_template("templates/includes/meta_block.html").render(context)


	out["no_sidebar"] = context.get("no_sidebar", 0)

	if "<!-- no-sidebar -->" in out.get("content", ""):
		out["no_sidebar"] = 1

	if "<!-- title:" in out.get("content", ""):
		out["title"] = re.findall('<!-- title:([^>]*) -->', out.get("content"))[0].strip()

	if "{index}" in out.get("content", "") and context.get("children"):
		html = frappe.get_template("templates/includes/static_index.html").render({
				"items": context["children"]})
		out["content"] = out["content"].replace("{index}", html)

	if "{next}" in out.get("content", ""):
		next_item = context.doc.get_next()
		if next_item:
			if next_item.name[0]!="/": next_item.name = "/" + next_item.name
			html = '''<p><br><a href="{name}" class="btn btn-primary">
				{title} <i class="icon-chevron-right"></i></a>
			</p>'''.format(**next_item)
			out["content"] = out["content"].replace("{next}", html)

	if "sidebar" not in out and not out.get("no_sidebar"):
		out["sidebar"] = scrub_relative_urls(
			frappe.get_template("templates/includes/sidebar.html").render(context))

	out["title"] = strip_html(out.get("title") or "")

	# remove style and script tags from blocks
	out["style"] = re.sub("</?style[^<>]*>", "", out.get("style") or "")
	out["script"] = re.sub("</?script[^<>]*>", "", out.get("script") or "")

	return out
Example #36
0
def create_sales_invoice(order_dict, order, ebay_site_id, site_id_order,
                         msgprint_log, changes):
    """
    Create a Sales Invoice from the eBay order.
    """
    updated_db = False

    ebay_order_id = order_dict['ebay_order_id']
    ebay_user_id = order_dict['ebay_user_id']

    order_fields = db_get_ebay_doc("eBay order",
                                   ebay_order_id,
                                   fields=[
                                       "name", "customer", "customer_name",
                                       "address", "ebay_order_id"
                                   ],
                                   log=changes,
                                   none_ok=False)

    db_cust_name = order_fields['customer']

    # Get from existing linked sales order
    sinv_fields = db_get_ebay_doc("Sales Invoice",
                                  ebay_order_id,
                                  fields=["name"],
                                  log=changes,
                                  none_ok=True)

    if sinv_fields is not None:
        # Linked sales invoice exists
        debug_msgprint('Sales Invoice already exists: ' + ebay_user_id +
                       ' : ' + sinv_fields['name'])
        changes.append({
            "ebay_change": "Sales Invoice already exists",
            "ebay_user_id": ebay_user_id,
            "customer_name": order_fields['customer_name'],
            "customer": db_cust_name,
            "address": order_fields['address'],
            "ebay_order": order_fields['name']
        })
        return

    # No linked sales invoice - check for old unlinked sales invoice
    test_title = db_cust_name + "-" + ebay_order_id
    query = frappe.get_all("Sales Invoice", filters={"title": test_title})
    if len(query) > 2:
        raise ErpnextEbaySyncError(
            "Multiple Sales Invoices with title {}!".format(test_title))
    if len(query) == 1:
        # Old sales invoice without link - don't interfere
        debug_msgprint('Old Sales Invoice exists: ' + ebay_user_id + ' : ' +
                       query[0]['name'])
        changes.append({
            "ebay_change": "Old Sales Invoice exists",
            "ebay_user_id": ebay_user_id,
            "customer_name": order_fields['customer_name'],
            "customer": db_cust_name,
            "address": order_fields['address'],
            "ebay_order": order_fields['name']
        })
        return

    if order['OrderStatus'] != 'Completed':
        # This order has not been paid yet
        # Consequently we will not generally have a shipping address, and
        # so cannot correctly assign VAT. We will therefore not create
        # the sales invoice yet.
        debug_msgprint('Order has not yet been paid: ' + ebay_user_id + ' : ' +
                       order_fields['ebay_order_id'])
        changes.append({
            "ebay_change": "Order not yet paid",
            "ebay_user_id": ebay_user_id,
            "customer_name": order_fields['customer_name'],
            "customer": db_cust_name,
            "address": order_fields['address'],
            "ebay_order": order_fields['name']
        })
        return
    # Create a sales invoice

    # eBay date format: YYYY-MM-DDTHH:MM:SS.SSSZ
    posting_date = datetime.datetime.strptime(
        order['CreatedTime'][:-1] + 'UTC', '%Y-%m-%dT%H:%M:%S.%f%Z')
    order_status = order['OrderStatus']
    item_list = []
    payments = []
    taxes = []

    amount_paid_dict = order['AmountPaid']
    if amount_paid_dict['_currencyID'] == 'GBP':
        amount_paid = float(amount_paid_dict['value'])
    else:
        amount_paid = -1.0

    sku_list = []

    sum_inc_vat = 0.0
    sum_exc_vat = 0.0
    sum_vat = 0.0
    sum_paid = 0.0
    shipping_cost = 0.0

    transactions = order['TransactionArray']['Transaction']
    cust_email = transactions[0]['Buyer']['Email']

    # Find the correct VAT rate
    country_name = order['ShippingAddress']['CountryName']
    if country_name is None:
        raise ErpnextEbaySyncError(
            'No country for this order for user {}!'.format(ebay_user_id))
    income_account = determine_income_account(country_name)
    vat_rate = VAT_RATES[income_account]

    # TODO
    # Transaction.BuyerCheckoutMessage
    # Transaction.FinalValueFee
    # isGSP = TransactionArray.Transaction.ContainingOrder.IsMultiLegShipping
    # Transaction.ContainingOrder.MonetaryDetails.Payments.Payment.PaymentStatus
    # Transaction.MonetaryDetails.Payments.Payment.PaymentStatus

    for transaction in transactions:

        if transaction['Buyer']['Email'] != cust_email:
            raise ValueError('Multiple emails for this buyer?')

        # Vat Status
        #NoVATTax	VAT is not applicable
        #VATExempt	Residence in a country with VAT and user is registered as VAT-exempt
        #VATTax	Residence in a country with VAT and user is not registered as VAT-exempt
        #vat_status = transaction['Buyer']['VATStatus']

        shipping_cost_dict = transaction['ActualShippingCost']
        handling_cost_dict = transaction['ActualHandlingCost']
        if shipping_cost_dict['_currencyID'] == 'GBP':
            shipping_cost += float(shipping_cost_dict['value'])
        if handling_cost_dict['_currencyID'] == 'GBP':
            shipping_cost += float(handling_cost_dict['value'])

        qty = float(transaction['QuantityPurchased'])
        try:
            sku = transaction['Item']['SKU']
            sku_list.append(sku)
            # Only allow valid SKU
        except KeyError:
            debug_msgprint(
                'Order {} failed: One of the items did not have an SKU'.format(
                    ebay_order_id))
            sync_error(changes,
                       'An item did not have an SKU',
                       ebay_user_id,
                       customer_name=db_cust_name)
            raise ErpnextEbaySyncError(
                'An item did not have an SKU for user {}'.format(ebay_user_id))
        if not frappe.db.exists('Item', sku):
            debug_msgprint('Item not found?')
            raise ErpnextEbaySyncError('Item {} not found for user {}'.format(
                sku, ebay_user_id))

        ebay_price = float(transaction['TransactionPrice']['value'])
        if ebay_price <= 0.0:
            raise ValueError('TransactionPrice Value <= 0.0')

        inc_vat = ebay_price
        exc_vat = round(float(inc_vat) / (1.0 + vat_rate), 2)
        vat = inc_vat - exc_vat

        sum_inc_vat += inc_vat
        sum_exc_vat += exc_vat
        sum_vat += vat * qty
        sum_paid += inc_vat * qty

        # Get item description in case it is empty, and we need to insert
        # filler text to avoid MandatoryError
        description = frappe.get_value('Item', sku, 'description')
        if not strip_html(cstr(description)).strip():
            description = '(no item description)'

        item_list.append({
            "item_code": sku,
            "description": description,
            "warehouse": "Mamhilad - URTL",
            "qty": qty,
            "rate": exc_vat,
            "valuation_rate": 0.0,
            "income_account": income_account,
            "expense_account": "Cost of Goods Sold - URTL",
            "cost_center": "Main - URTL"
        })

    if shipping_cost > 0.0001:
        # Add a single line item for shipping services

        inc_vat = shipping_cost
        exc_vat = round(float(inc_vat) / (1.0 + vat_rate), 2)
        vat = inc_vat - exc_vat

        sum_inc_vat += inc_vat
        sum_exc_vat += exc_vat
        sum_vat += vat
        sum_paid += inc_vat

        item_list.append({
            "item_code": SHIPPING_ITEM,
            "description": "Shipping costs (from eBay)",
            "warehouse": "Mamhilad - URTL",
            "qty": 1.0,
            "rate": exc_vat,
            "valuation_rate": 0.0,
            "income_account": income_account,
            "expense_account": "Shipping - URTL"
        })

    # Taxes are a single line item not each transaction
    if VAT_RATES[income_account] > 0.00001:
        taxes.append({
            "charge_type":
            "Actual",
            "description":
            "VAT {}%".format(VAT_PERCENT[income_account]),
            "account_head":
            "VAT - URTL",
            "rate":
            VAT_PERCENT[income_account],
            "tax_amount":
            sum_vat
        })

    checkout = order['CheckoutStatus']
    if checkout['Status'] == 'Complete':
        if checkout['PaymentMethod'] in ('PayOnPickup', 'CashOnPickup'):
            # Cash on delivery - may not yet be paid (set to zero)
            payments.append({"mode_of_payment": "Cash", "amount": 0.0})
        elif checkout['PaymentMethod'] == 'PayPal':
            # PayPal - add amount as it has been paid
            if amount_paid > 0.0:
                payments.append({
                    "mode_of_payment": "Paypal",
                    "amount": amount_paid
                })
        elif checkout['PaymentMethod'] == 'PersonalCheck':
            # Personal cheque - may not yet be paid (set to zero)
            payments.append({"mode_of_payment": "Cheque", "amount": 0.0})
        elif checkout['PaymentMethod'] == 'MOCC':
            # Postal order/banker's draft - may not yet be paid (set to zero)
            payments.append({"mode_of_payment": "eBay", "amount": 0.0})

    title = 'eBay: {} [{}]'.format(order_fields['customer_name'],
                                   ', '.join(sku_list))

    sinv_dict = {
        "doctype": "Sales Invoice",
        "naming_series": "SINV-",
        "title": title,
        "customer": db_cust_name,
        "ebay_order_id": ebay_order_id,
        "ebay_site_id": site_id_order,
        "contact_email": cust_email,
        "posting_date": posting_date,
        "posting_time": "00:00:00",
        "due_date": posting_date,
        "set_posting_time": 1,
        "selling_price_list": "Standard Selling",
        "price_list_currency": "GBP",
        "price_list_exchange_rate": 1,
        "ignore_pricing_rule": 1,
        "apply_discount_on": "Net Total",
        "status": "Draft",
        "update_stock": 1,
        "is_pos": 1,
        "taxes": taxes,
        "payments": payments,
        "items": item_list,
        "notification_email_address": cust_email,
        "notify_by_email": 1
    }

    sinv = frappe.get_doc(sinv_dict)

    sinv.insert()
    #si.submit()

    if abs(amount_paid - sum_paid) > 0.005:
        sinv.add_comment('sync_orders: Unable to match totals - ' +
                         'please check this order manually.')

    updated_db = True

    debug_msgprint('Adding Sales Invoice: ' + ebay_user_id + ' : ' + sinv.name)
    changes.append({
        "ebay_change": "Adding Sales Invoice",
        "ebay_user_id": ebay_user_id,
        "customer_name": order_fields['customer_name'],
        "customer": db_cust_name,
        "address": order_fields['address'],
        "ebay_order": order_fields['name']
    })

    if ebay_site_id and (ebay_site_id != site_id_order):
        msgprint_log.append(
            'WARNING: Sales Invoice {} originated from eBay site {}'.format(
                sinv.name, site_id_order))

    # Commit changes to database
    if updated_db:
        frappe.db.commit()

    return
Example #37
0
def create_sales_invoice(order_dict, order, ebay_site_id, site_id_order,
                         msgprint_log, changes):
    """
    Create a Sales Invoice from the eBay order.
    """
    updated_db = False

    # Don't create SINV from incomplete order
    if (order['OrderStatus'] != 'Completed'
            or order['CheckoutStatus']['Status'] != 'Complete'):
        return

    ebay_order_id = order_dict['ebay_order_id']
    ebay_user_id = order_dict['ebay_user_id']

    order_fields = db_get_ebay_doc(
        "eBay order", ebay_order_id,
        fields=["name", "customer", "customer_name",
                "address", "ebay_order_id"],
        log=changes, none_ok=False)

    db_cust_name = order_fields['customer']

    # Get from existing linked sales order
    sinv_fields = db_get_ebay_doc(
        "Sales Invoice", ebay_order_id, fields=["name"],
        log=changes, none_ok=True)

    if sinv_fields is not None:
        # Linked sales invoice exists
        debug_msgprint('Sales Invoice already exists: '
                       + ebay_user_id + ' : ' + sinv_fields['name'])
        changes.append({"ebay_change": "Sales Invoice already exists",
                        "ebay_user_id": ebay_user_id,
                        "customer_name": order_fields['customer_name'],
                        "customer": db_cust_name,
                        "address": order_fields['address'],
                        "ebay_order": order_fields['name']})
        return

    # No linked sales invoice - check for old unlinked sales invoice
    test_title = db_cust_name + "-" + ebay_order_id
    query = frappe.get_all("Sales Invoice", filters={"title": test_title})
    if len(query) > 2:
        raise ErpnextEbaySyncError(
            "Multiple Sales Invoices with title {}!".format(test_title))
    if len(query) == 1:
        # Old sales invoice without link - don't interfere
        debug_msgprint('Old Sales Invoice exists: '
                       + ebay_user_id + ' : ' + query[0]['name'])
        changes.append({"ebay_change": "Old Sales Invoice exists",
                        "ebay_user_id": ebay_user_id,
                        "customer_name": order_fields['customer_name'],
                        "customer": db_cust_name,
                        "address": order_fields['address'],
                        "ebay_order": order_fields['name']})
        return

    # Create a sales invoice

    # eBay date format: YYYY-MM-DDTHH:MM:SS.SSSZ
    if 'PaidTime' in order:
        paid_datetime = order['PaidTime'][:-1] + 'UTC'
    else:
        paid_datetime = order['CreatedTime'][:-1] + 'UTC'
    posting_date = datetime.datetime.strptime(paid_datetime,
                                              '%Y-%m-%dT%H:%M:%S.%f%Z')
    order_status = order['OrderStatus']
    buyer_checkout_message = order.get('BuyerCheckoutMessage', None)
    if buyer_checkout_message:
        buyer_checkout_message = html.escape(buyer_checkout_message,
                                             quote=False)

    item_list = []
    payments = []
    taxes = []

    amount_paid_dict = order['AmountPaid']
    currency = amount_paid_dict['_currencyID']
    amount_paid = float(amount_paid_dict['value'])
    default_currency = get_default_currency()
    if currency != default_currency:
        conversion_rate = get_exchange_rate(currency, default_currency,
                                            posting_date.date())
    else:
        conversion_rate = 1.0

    sku_list = []

    sum_inc_vat = 0.0
    sum_exc_vat = 0.0
    sum_vat = 0.0
    sum_to_pay = 0.0
    shipping_cost = 0.0
    ebay_car = 0.0  # eBay Collect and Remit sales taxes

    transactions = order['TransactionArray']['Transaction']
    cust_email = transactions[0]['Buyer']['Email']

    # Find the correct VAT rate
    country = frappe.db.get_value('Address', order_dict['address'], 'country')
    if country is None:
        raise ErpnextEbaySyncError(
            'No country for this order for user {}!'.format(ebay_user_id))
    income_account = determine_income_account(country)
    vat_rate = VAT_RATES[income_account]

    # TODO
    # isGSP = TransactionArray.Transaction.ContainingOrder.IsMultiLegShipping
    # Transaction.ContainingOrder.MonetaryDetails.Payments.Payment.PaymentStatus
    # Transaction.MonetaryDetails.Payments.Payment.PaymentStatus

    for transaction in transactions:

        if transaction['Buyer']['Email'] != cust_email:
            raise ValueError('Multiple emails for this buyer?')

        # Vat Status
        #NoVATTax	VAT is not applicable
        #VATExempt	Residence in a country with VAT and user is registered as VAT-exempt
        #VATTax	Residence in a country with VAT and user is not registered as VAT-exempt
        #vat_status = transaction['Buyer']['VATStatus']

        shipping_cost_dict = transaction['ActualShippingCost']
        handling_cost_dict = transaction['ActualHandlingCost']
        final_value_fee_dict = transaction['FinalValueFee']

        if shipping_cost_dict['_currencyID'] == currency:
            shipping_cost += float(shipping_cost_dict['value'])
        else:
            raise ErpnextEbaySyncError('Inconsistent currencies in order!')
        if handling_cost_dict['_currencyID'] == currency:
            shipping_cost += float(handling_cost_dict['value'])
        else:
            raise ErpnextEbaySyncError('Inconsistent currencies in order!')

        # Final Value Fee currently limited to being in *default* currency or
        # sale currency, and does not include any VAT (for EU sellers).
        if final_value_fee_dict['_currencyID'] == default_currency:
            # final value fee typically in seller currency
            base_final_value_fee = float(final_value_fee_dict['value'])
            final_value_fee = base_final_value_fee / conversion_rate
        elif final_value_fee_dict['_currencyID'] == currency:
            final_value_fee = float(final_value_fee_dict['value'])
            base_final_value_fee = final_value_fee * conversion_rate
        else:
            raise ErpnextEbaySyncError('Inconsistent currencies in order!')

        if transaction['eBayCollectAndRemitTax'] == 'true':
            ebay_car_dict = (
                transaction['eBayCollectAndRemitTaxes']['TotalTaxAmount'])
            if ebay_car_dict['_currencyID'] == currency:
                ebay_car += float(ebay_car_dict['value'])
            else:
                raise ErpnextEbaySyncError('Inconsistent currencies in order!')

        qty = float(transaction['QuantityPurchased'])
        try:
            sku = transaction['Item']['SKU']
            sku_list.append(sku)
            # Only allow valid SKU
        except KeyError:
            debug_msgprint(
                'Order {} failed: One of the items did not have an SKU'.format(
                    ebay_order_id))
            sync_error(changes, 'An item did not have an SKU',
                       ebay_user_id, customer_name=db_cust_name)
            raise ErpnextEbaySyncError(
                'An item did not have an SKU for user {}'.format(ebay_user_id))
        if not frappe.db.exists('Item', sku):
            debug_msgprint('Item not found?')
            raise ErpnextEbaySyncError(
                'Item {} not found for user {}'.format(sku, ebay_user_id))

        ebay_price = float(transaction['TransactionPrice']['value'])
        if ebay_price <= 0.0:
            raise ValueError('TransactionPrice Value <= 0.0')

        inc_vat = ebay_price
        exc_vat = round(float(inc_vat) / (1.0 + vat_rate), 2)
        vat = inc_vat - exc_vat

        sum_inc_vat += inc_vat
        sum_exc_vat += exc_vat
        sum_vat += vat * qty
        sum_to_pay += inc_vat * qty

        # Get item description in case it is empty, and we need to insert
        # filler text to avoid MandatoryError
        description = frappe.get_value('Item', sku, 'description')
        if not strip_html(cstr(description)).strip():
            description = '(no item description)'

        item_list.append({
                "item_code": sku,
                "description": description,
                "warehouse": WAREHOUSE,
                "qty": qty,
                "rate": exc_vat,
                "ebay_final_value_fee": final_value_fee,
                "base_ebay_final_value_fee": base_final_value_fee,
                "valuation_rate": 0.0,
                "income_account": income_account,
                "expense_account": f"Cost of Goods Sold - {COMPANY_ACRONYM}",
                "cost_center": f"Main - {COMPANY_ACRONYM}"
         })

    # Add a single line item for shipping services
    if shipping_cost > 0.0001:

        inc_vat = shipping_cost
        exc_vat = round(float(inc_vat) / (1.0 + vat_rate), 2)
        vat = inc_vat - exc_vat

        sum_inc_vat += inc_vat
        sum_exc_vat += exc_vat
        sum_vat += vat
        sum_to_pay += inc_vat

        item_list.append({
            "item_code": SHIPPING_ITEM,
            "description": "Shipping costs (from eBay)",
            "warehouse": WAREHOUSE,
            "qty": 1.0,
            "rate": exc_vat,
            "valuation_rate": 0.0,
            "income_account": income_account,
            "expense_account": f"Shipping - {COMPANY_ACRONYM}"
        })

    # Add a single line item for eBay Collect and Remit taxes
    if ebay_car > 0.0001:
        item_list.append({
            "item_code": CAR_ITEM,
            "description": "eBay Collect and Remit taxes",
            "warehouse": WAREHOUSE,
            "qty": 1.0,
            "rate": ebay_car,
            "valuation_rate": 0.0,
            "income_account": income_account,
            "expense_account": f"Cost of Goods Sold - {COMPANY_ACRONYM}"
        })
        sum_to_pay += ebay_car

    # Taxes are a single line item not each transaction
    if VAT_RATES[income_account] > 0.00001:
        taxes.append({
                    "charge_type": "Actual",
                    "description": "VAT {}%".format(VAT_PERCENT[income_account]),
                    "account_head": f"VAT - {COMPANY_ACRONYM}",
                    "rate": VAT_PERCENT[income_account],
                    "tax_amount": sum_vat})

    checkout = order['CheckoutStatus']
    submit_on_pay = False
    if checkout['PaymentMethod'] in ('PayOnPickup', 'CashOnPickup'):
        # Cash on delivery - may not yet be paid (set to zero)
        payments.append({"mode_of_payment": "Cash",
                         "amount": 0.0})
    elif checkout['PaymentMethod'] == 'PayPal':
        # PayPal - add amount as it has been paid
        paypal_acct = f'PayPal {currency}'
        if not frappe.db.exists('Mode of Payment', paypal_acct):
            raise ErpnextEbaySyncError(
                f'Mode of Payment "{paypal_acct}" does not exist!')
        if amount_paid > 0.0:
            payments.append({"mode_of_payment": paypal_acct,
                            "amount": amount_paid})
            submit_on_pay = True
    elif checkout['PaymentMethod'] == 'PersonalCheck':
        # Personal cheque - may not yet be paid (set to zero)
        payments.append({"mode_of_payment": "Cheque",
                         "amount": 0.0})
    elif checkout['PaymentMethod'] == 'MOCC':
        # Postal order/banker's draft - may not yet be paid (set to zero)
        payments.append({"mode_of_payment": "eBay",
                         "amount": 0.0})

    title = 'eBay: {} [{}]'.format(
        order_fields['customer_name'],
        ', '.join(sku_list))

    sinv_dict = {
        "doctype": "Sales Invoice",
        "naming_series": "SINV-",
        "title": title,
        "customer": db_cust_name,
        "shipping_address_name": order_dict['address'],
        "ebay_order_id": ebay_order_id,
        "ebay_site_id": site_id_order,
        "buyer_message": buyer_checkout_message,
        "contact_email": cust_email,
        "posting_date": posting_date.date(),
        "posting_time": posting_date.time(),
        "due_date": posting_date,
        "set_posting_time": 1,
        "currency": currency,
        "conversion_rate": conversion_rate,
        "ignore_pricing_rule": 1,
        "apply_discount_on": "Net Total",
        "status": "Draft",
        "update_stock": 1,
        "is_pos": 1,
        "taxes": taxes,
        "payments": payments,
        "items": item_list}

    sinv = frappe.get_doc(sinv_dict)

    sinv.insert()

    if abs(amount_paid - sum_to_pay) > 0.005:
        sinv.add_comment(
            'Comment',
            text='sync_orders: Unable to match totals - please check this '
                 + f'order manually ({amount_paid} != {sum_to_pay})')
    elif submit_on_pay:
        # This is an order which adds up and has an approved payment method
        # Submit immediately
        sinv.submit()

    updated_db = True

    debug_msgprint('Adding Sales Invoice: ' + ebay_user_id + ' : ' + sinv.name)
    changes.append({"ebay_change": "Adding Sales Invoice",
                    "ebay_user_id": ebay_user_id,
                    "customer_name": order_fields['customer_name'],
                    "customer": db_cust_name,
                    "address": order_fields['address'],
                    "ebay_order": order_fields['name']})

    # Commit changes to database
    if updated_db:
        frappe.db.commit()

    return
Example #38
0
def render_blocks(context):
    """returns a dict of block name and its rendered content"""

    out = {}

    env = frappe.get_jenv()

    def _render_blocks(template_path):
        source = frappe.local.jloader.get_source(frappe.local.jenv,
                                                 template_path)[0]
        for referenced_template_path in meta.find_referenced_templates(
                env.parse(source)):
            if referenced_template_path:
                _render_blocks(referenced_template_path)

        template = frappe.get_template(template_path)
        for block, render in template.blocks.items():
            out[block] = scrub_relative_urls(
                concat(render(template.new_context(context))))

    _render_blocks(context["template"])

    # default blocks if not found
    if "title" not in out and out.get("header"):
        out["title"] = out["header"]

    if "title" not in out:
        out["title"] = context.get("title")

    if "header" not in out and out.get("title"):
        out["header"] = out["title"]

    if out.get("header") and not out["header"].startswith("<h"):
        out["header"] = "<h2>" + out["header"] + "</h2>"

    if "breadcrumbs" not in out:
        out["breadcrumbs"] = scrub_relative_urls(
            frappe.get_template("templates/includes/breadcrumbs.html").render(
                context))

    if "meta_block" not in out:
        out["meta_block"] = frappe.get_template(
            "templates/includes/meta_block.html").render(context)

    out["no_sidebar"] = context.get("no_sidebar", 0)

    if "<!-- no-sidebar -->" in out.get("content", ""):
        out["no_sidebar"] = 1

    if "<!-- title:" in out.get("content", ""):
        out["title"] = re.findall('<!-- title:([^>]*) -->',
                                  out.get("content"))[0].strip()

    if "{index}" in out.get("content", "") and context.get("children"):
        html = frappe.get_template(
            "templates/includes/static_index.html").render(
                {"items": context["children"]})
        out["content"] = out["content"].replace("{index}", html)

    if "{next}" in out.get("content", ""):
        next_item = context.doc.get_next()
        if next_item:
            if next_item.name[0] != "/": next_item.name = "/" + next_item.name
            html = '''<p><br><a href="{name}" class="btn btn-primary">
				{title} <i class="icon-chevron-right"></i></a>
			</p>'''.format(**next_item)
            out["content"] = out["content"].replace("{next}", html)

    if "sidebar" not in out and not out.get("no_sidebar"):
        out["sidebar"] = scrub_relative_urls(
            frappe.get_template("templates/includes/sidebar.html").render(
                context))

    out["title"] = strip_html(out.get("title") or "")

    # remove style and script tags from blocks
    out["style"] = re.sub("</?style[^<>]*>", "", out.get("style") or "")
    out["script"] = re.sub("</?script[^<>]*>", "", out.get("script") or "")

    return out