From c306b214150639f15683af6bf8415c69e1f94f77 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 16:32:24 +0530 Subject: [PATCH] [merge fixes] --- .../purchase_order/purchase_order.json | 204 ++++++++++++++++++ .../doctype/purchase_order/purchase_order.py | 16 ++ .../purchase_order_item.json | 9 +- erpnext/controllers/selling_controller.py | 2 +- erpnext/public/js/utils/party.js | 2 +- .../doctype/sales_order/sales_order.js | 15 +- .../doctype/sales_order/sales_order.json | 65 +++++- .../doctype/sales_order/sales_order.py | 54 +++++ .../doctype/sales_order/sales_order_list.js | 35 ++- .../sales_order_item/sales_order_item.json | 22 ++ 10 files changed, 399 insertions(+), 25 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 904b762e1d..d0b454ef1c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -147,6 +147,52 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer", + "no_copy": 0, + "options": "Customer", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.order_type==\"Drop Shipment\"", + "fieldname": "customer_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Name", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -168,6 +214,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_address_display", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Address", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -189,6 +257,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -210,6 +300,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_mobile", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Mobile No", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -231,6 +343,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_email", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact Email", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -326,6 +460,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "drop_ship", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Drop Ship", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1400,6 +1556,30 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.drop_ship==1", + "fieldname": "customer_address", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Address", + "no_copy": 0, + "options": "Address", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1442,6 +1622,30 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.drop_ship==1", + "fieldname": "customer_contact_person", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact Person", + "no_copy": 0, + "options": "Contact", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 0affd78f9b..234c643642 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -162,6 +162,14 @@ class PurchaseOrder(BuyingController): clear_doctype_notifications(self) def on_submit(self): + if self.drop_ship == 1: + self.status_updater[0].update({ + "target_parent_dt": "Sales Order", + "target_parent_field": "per_ordered", + "target_dt": "Sales Order Item", + 'target_field': 'ordered_qty' + }) + super(PurchaseOrder, self).on_submit() purchase_controller = frappe.get_doc("Purchase Common") @@ -176,6 +184,14 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): + if self.drop_ship == 1: + self.status_updater[0].update({ + "target_parent_dt": "Sales Order", + "target_parent_field": "per_ordered", + "target_dt": "Sales Order Item", + 'target_field': 'ordered_qty' + }) + pc_obj = frappe.get_doc('Purchase Common') self.check_for_stopped_status(pc_obj) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index ecc41d2059..70e08e5d26 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -848,7 +848,7 @@ "bold": 0, "collapsible": 0, "fieldname": "prevdoc_doctype", - "fieldtype": "Data", + "fieldtype": "Link", "hidden": 1, "ignore_user_permissions": 0, "in_filter": 0, @@ -857,6 +857,7 @@ "no_copy": 1, "oldfieldname": "prevdoc_doctype", "oldfieldtype": "Data", + "options": "DocType", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -871,16 +872,16 @@ "bold": 0, "collapsible": 0, "fieldname": "prevdoc_docname", - "fieldtype": "Link", + "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 0, - "label": "Material Request No", + "label": "Reference Name", "no_copy": 1, "oldfieldname": "prevdoc_docname", "oldfieldtype": "Link", - "options": "Material Request", + "options": "prevdoc_doctype", "permlevel": 0, "print_hide": 1, "print_width": "120px", diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index b087b8a884..d7f287be49 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -143,7 +143,7 @@ class SellingController(StockController): throw(_("Total allocated percentage for sales team should be 100")) def validate_order_type(self): - valid_types = ["Sales", "Maintenance", "Shopping Cart"] + valid_types = ["Sales", "Maintenance", "Shopping Cart", "Drop Shipment"] if not self.order_type: self.order_type = "Sales" elif self.order_type not in valid_types: diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 427cd89c22..510938a9d1 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -7,7 +7,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { method = "erpnext.accounts.party.get_party_details"; } if(!args) { - if(frm.doc.customer) { + if(frm.doctype != "Purchase Order" && frm.doc.customer) { args = { party: frm.doc.customer, party_type: "Customer", diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 4a047e41ae..f46c16a510 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -25,7 +25,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // doc.per_billed); // indent - if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1) + if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && doc.drop_ship!=1) cur_frm.add_custom_button(__('Material Request'), this.make_material_request); if(flt(doc.per_billed)==0) { @@ -37,19 +37,22 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order']) // maintenance - if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) { + if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1 && doc.drop_ship!=1) { cur_frm.add_custom_button(__('Maint. Visit'), this.make_maintenance_visit); cur_frm.add_custom_button(__('Maint. Schedule'), this.make_maintenance_schedule); } // delivery note - if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1) + if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && doc.drop_ship!=1) cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary"); // sales invoice if(flt(doc.per_billed, 2) < 100) { cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary"); } + + if(doc.drop_ship==1 && flt(doc.per_ordered, 2) < 100) + cur_frm.add_custom_button(__('Make Shipment'), cur_frm.cscript.make_drop_shipment); } else { // un-stop @@ -145,6 +148,12 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( frappe.set_route("Form", doclist[0].doctype, doclist[0].name); } }); + }, + make_drop_shipment: function(){ + frappe.model.open_mapped_doc({ + method: "erpnext.selling.doctype.sales_order.sales_order.make_drop_shipment", + frm: cur_frm + }) } }); diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 5bc8ef4727..97f5d36989 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -86,7 +86,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Series", + "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", @@ -234,13 +234,14 @@ "bold": 0, "collapsible": 0, "default": "Sales", + "depends_on": "eval:doc.drop_ship!=1", "fieldname": "order_type", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Order Type", + "label": "Order Type", "no_copy": 0, "oldfieldname": "order_type", "oldfieldtype": "Select", @@ -254,6 +255,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "drop_ship", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Drop Ship", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -381,6 +404,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "depends_on": "eval:doc.drop_ship!=1", "description": "", "fieldname": "po_no", "fieldtype": "Data", @@ -1134,7 +1158,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Apply Additional Discount On", + "label": "Apply Additional Discount On", "no_copy": 0, "options": "\nGrand Total\nNet Total", "permlevel": 0, @@ -1808,7 +1832,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Source", + "label": "Source", "no_copy": 0, "oldfieldname": "source", "oldfieldtype": "Select", @@ -1973,7 +1997,7 @@ "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, - "label": "Status", + "label": "Status", "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", @@ -1998,7 +2022,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Delivery Status", + "label": "Delivery Status", "no_copy": 1, "options": "Not Delivered\nFully Delivered\nPartly Delivered\nClosed\nNot Applicable", "permlevel": 0, @@ -2036,6 +2060,29 @@ "unique": 0, "width": "100px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "per_ordered", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 1, + "in_list_view": 1, + "label": "% Ordered", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "100px" + }, { "allow_on_submit": 0, "bold": 0, @@ -2092,7 +2139,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Billing Status", + "label": "Billing Status", "no_copy": 1, "options": "Not Billed\nFully Billed\nPartly Billed\nClosed", "permlevel": 0, @@ -2326,7 +2373,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Recurring Type", + "label": "Recurring Type", "no_copy": 1, "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "permlevel": 0, @@ -2553,7 +2600,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-03 07:39:10.525609", + "modified": "2015-10-15 15:27:34.592276", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 6cc12c53a9..25c8182649 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -488,3 +488,57 @@ def get_events(start, end, filters=None): "end": end }, as_dict=True, update={"allDay": 0}) return data + +@frappe.whitelist() +def make_drop_shipment(source_name, target_doc=None): + def postprocess(source, target): + set_missing_values(source, target) + + def set_missing_values(source, target): + target.address_display = "" + target.contact_display = "" + target.contact_mobile = "" + target.contact_email = "" + target.ignore_pricing_rule = 1 + target.run_method("set_missing_values") + target.run_method("calculate_taxes_and_totals") + + def update_item(source, target, source_parent): + target.base_amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.base_rate) + target.amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.rate) + target.qty = flt(source.qty) - flt(source.ordered_qty) + + doclist = get_mapped_doc("Sales Order", source_name, { + "Sales Order": { + "doctype": "Purchase Order", + "field_map": { + "address_display": "customer_address_display", + "contact_display": "customer_contact_display", + "contact_mobile": "customer_contact_mobile", + "contact_email": "customer_contact_email", + "contact_person": "customer_contact_person" + }, + "validation": { + "docstatus": ["=", 1] + } + }, + "Sales Order Item": { + "doctype": "Purchase Order Item", + "field_map": [ + ["name", "prevdoc_detail_docname"], + ["parent", "prevdoc_docname"], + ["parenttype", "prevdoc_doctype"], + ["uom", "stock_uom"] + ], + "postprocess": update_item, + "condition": lambda doc: doc.delivered_qty < doc.qty + }, + "Sales Taxes and Charges": { + "doctype": "Purchase Taxes and Charges", + "add_if_empty": True + } + }, target_doc, postprocess) + + + + return doclist diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index aab168eb98..312f8785e1 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -1,16 +1,16 @@ frappe.listview_settings['Sales Order'] = { add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date", "per_delivered", "per_billed", - "status", "order_type"], + "status", "order_type", "per_ordered", "drop_ship"], get_indicator: function(doc) { if(doc.status==="Stopped") { return [__("Stopped"), "darkgrey", "status,=,Stopped"]; - } else if (doc.order_type !== "Maintenance" + } else if (doc.order_type !== "Maintenance" && doc.drop_ship !=1 && flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) { // to bill & overdue return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Stopped"]; - } else if (doc.order_type !== "Maintenance" + } else if (doc.order_type !== "Maintenance" && doc.drop_ship !=1 && flt(doc.per_delivered, 2) < 100 && doc.status!=="Stopped") { // not delivered @@ -20,22 +20,43 @@ frappe.listview_settings['Sales Order'] = { return [__("To Deliver and Bill"), "orange", "per_delivered,<,100|per_billed,<,100|status,!=,Stopped"]; } else { - // not billed + // not delivered return [__("To Deliver"), "orange", "per_delivered,<,100|per_billed,=,100|status,!=,Stopped"]; } - } else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100) - && flt(doc.per_billed, 2) < 100 && doc.status!=="Stopped") { + } else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100 || + (doc.drop_ship == 1 && flt(doc.per_ordered, 2) == 100 ) ) && flt(doc.per_billed, 2) < 100 + && doc.status!=="Stopped") { // to bill - return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped"]; + return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped|per_ordered,<,100"]; } else if((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100) && flt(doc.per_billed, 2) == 100 && doc.status!=="Stopped") { return [__("Completed"), "green", "per_delivered,=,100|per_billed,=,100|status,!=,Stopped"]; + } else if ( doc.drop_ship == 1 && flt(doc.per_delivered, 2) < 100 + && frappe.datetime.get_diff(doc.delivery_date) < 0) { + // to bill & overdue + return [__("Overdue"), "red", "per_ordered,<,100|delivery_date,<,Today|status,!=,Stopped"]; + + } else if ( doc.drop_ship == 1 && flt(doc.per_ordered, 2) < 100 && doc.status!=="Stopped") { + // not ordered + + if(flt(doc.per_billed, 2) < 100) { + // not delivered & not billed + + return [__("To Order and Bill"), "orange", + "per_ordered,<,100|per_billed,<,100|status,!=,Stopped"]; + } else { + // not ordered + + return [__("To Deliver"), "orange", + "per_ordered,<,100|per_billed,=,100|status,!=,Stopped"]; + } + } }, onload: function(listview) { diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index c7e9e2f78c..4192100510 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -917,6 +917,28 @@ "unique": 0, "width": "70px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "ordered_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Ordered Qty", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0,