diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index 85779533ea2..902b06290e4 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -439,7 +439,7 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
- "collapsible": 0,
+ "collapsible": 1,
"columns": 0,
"fieldname": "notification",
"fieldtype": "Section Break",
@@ -495,6 +495,38 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval: doc.notify_by_email",
+ "description": "To add dynamic subject, use jinja tags like\n\n
New {{ doc.doctype }} #{{ doc.name }}
",
+ "fieldname": "subject",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Subject",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -593,6 +625,69 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "depends_on": "eval:doc.notify_by_email",
+ "fieldname": "section_break_20",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Message",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Please find attached {{ doc.doctype }} #{{ doc.name }}",
+ "fieldname": "message",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Message",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "depends_on": "eval: !doc.__islocal",
"fieldname": "section_break_16",
"fieldtype": "Section Break",
"hidden": 0,
@@ -690,7 +785,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-09-14 12:09:38.471458",
+ "modified": "2017-09-28 18:27:48.522098",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index c9df7d461e5..b7ea96f0ce5 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -7,6 +7,7 @@ import frappe
import calendar
from frappe import _
from frappe.desk.form import assign_to
+from frappe.utils.jinja import validate_template
from dateutil.relativedelta import relativedelta
from frappe.utils.user import get_system_managers
from frappe.utils import cstr, getdate, split_emails, add_days, today
@@ -20,6 +21,9 @@ class Subscription(Document):
self.validate_next_schedule_date()
self.validate_email_id()
+ validate_template(self.subject or "")
+ validate_template(self.message or "")
+
def before_submit(self):
self.set_next_schedule_date()
@@ -114,7 +118,7 @@ def create_documents(data, schedule_date):
doc = make_new_document(data, schedule_date)
if data.notify_by_email and data.recipients:
print_format = data.print_format or "Standard"
- send_notification(doc, print_format, data.recipients)
+ send_notification(doc, data, print_format=print_format)
frappe.db.commit()
except Exception:
@@ -174,14 +178,25 @@ def get_next_date(dt, mcount, day=None):
return dt
-def send_notification(new_rv, print_format='Standard', recipients=None):
+def send_notification(new_rv, subscription_doc, print_format='Standard'):
"""Notify concerned persons about recurring document generation"""
print_format = print_format
- frappe.sendmail(recipients,
- subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
- message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
- attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=print_format)])
+ if not subscription_doc.subject:
+ subject = _("New {0}: #{1}").format(new_rv.doctype, new_rv.name)
+ elif "{" in subscription_doc.subject:
+ subject = frappe.render_template(subscription_doc.subject, {'doc': new_rv})
+
+ if not subscription_doc.message:
+ message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name)
+ elif "{" in subscription_doc.message:
+ message = frappe.render_template(subscription_doc.message, {'doc': new_rv})
+
+ attachments = [frappe.attach_print(new_rv.doctype, new_rv.name,
+ file_name=new_rv.name, print_format=print_format)]
+
+ frappe.sendmail(subscription_doc.recipients,
+ subject=subject, message=message, attachments=attachments)
def notify_errors(doc, doctype, party, owner, name):
recipients = get_system_managers(only_name=True)
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index 5b5cd9e6905..e5564404ece 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, flt
-import json
+import json, copy
class ItemVariantExistsError(frappe.ValidationError): pass
class InvalidItemAttributeValueError(frappe.ValidationError): pass
@@ -175,18 +175,28 @@ def copy_attributes_to_variant(item, variant):
# copy non no-copy fields
exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",
- "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate", "variant_based_on"]
+ "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"]
if item.variant_based_on=='Manufacturer':
# don't copy manufacturer values if based on part no
exclude_fields += ['manufacturer', 'manufacturer_part_no']
allow_fields = [d.field_name for d in frappe.get_all("Variant Field", fields = ['field_name'])]
+ if "variant_based_on" not in allow_fields:
+ allow_fields.append("variant_based_on")
for field in item.meta.fields:
# "Table" is part of `no_value_field` but we shouldn't ignore tables
if (field.reqd or field.fieldname in allow_fields) and field.fieldname not in exclude_fields:
if variant.get(field.fieldname) != item.get(field.fieldname):
- variant.set(field.fieldname, item.get(field.fieldname))
+ if field.fieldtype == "Table":
+ variant.set(field.fieldname, [])
+ for d in item.get(field.fieldname):
+ row = copy.deepcopy(d)
+ if row.get("name"):
+ row.name = None
+ variant.append(field.fieldname, row)
+ else:
+ variant.set(field.fieldname, item.get(field.fieldname))
variant.variant_of = item.name
variant.has_variants = 0
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 9f4c2b9c350..460ddc6210a 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -61,7 +61,7 @@ class Project(Document):
self.send_welcome_email()
def validate_project_name(self):
- if frappe.db.exists("Project", self.project_name):
+ if self.get("__islocal") and frappe.db.exists("Project", self.project_name):
frappe.throw(_("Project {0} already exists").format(self.project_name))
def validate_dates(self):
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 34e3af6102f..c3f399a5361 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -120,6 +120,8 @@ class TestItem(unittest.TestCase):
self.assertRaises(ItemVariantExistsError, variant.save)
def test_copy_fields_from_template_to_variants(self):
+ frappe.delete_doc_if_exists("Item", "_Test Variant Item-XL", force=1)
+
fields = [{'field_name': 'item_group'}, {'field_name': 'is_stock_item'}]
allow_fields = [d.get('field_name') for d in fields]
set_item_variant_settings(fields)
diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
index df78572dcb4..24f7e31a0cc 100644
--- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
+++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
@@ -5,7 +5,7 @@ frappe.ui.form.on('Item Variant Settings', {
setup: function(frm) {
const allow_fields = [];
const exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",
- "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate", "variant_based_on"];
+ "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"];
frappe.model.with_doctype('Item', () => {
frappe.get_meta('Item').fields.forEach(d => {
diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
index 0c6acd4290b..678de1a9ba7 100644
--- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
+++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py
@@ -12,7 +12,7 @@ class ItemVariantSettings(Document):
fields = frappe.get_meta('Item').fields
exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",
"show_variant_in_website", "standard_rate", "opening_stock", "image", "description",
- "variant_of", "valuation_rate", "description", "variant_based_on",
+ "variant_of", "valuation_rate", "description",
"website_image", "thumbnail", "website_specifiations", "web_long_description"]
for d in fields:
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 4bcbcc4b6f4..0aecb78ddd6 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -11,7 +11,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
-from erpnext.stock.doctype.item.test_item import set_item_variant_settings
+from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant
from frappe.tests.test_permissions import set_user_permission_doctypes
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.accounts.doctype.account.test_account import get_inventory_account
@@ -46,6 +46,7 @@ class TestStockEntry(unittest.TestCase):
make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=10)
sle = get_sle(item_code = item_code, warehouse = warehouse)[0]
+
self.assertEqual([[1, 10]], frappe.safe_eval(sle.stock_queue))
# negative qty
@@ -74,7 +75,6 @@ class TestStockEntry(unittest.TestCase):
frappe.db.set_default("allow_negative_stock", 0)
def test_auto_material_request(self):
- from erpnext.stock.doctype.item.test_item import make_item_variant
make_item_variant()
self._test_auto_material_request("_Test Item")
self._test_auto_material_request("_Test Item", material_request_type="Transfer")
@@ -82,6 +82,7 @@ class TestStockEntry(unittest.TestCase):
def test_auto_material_request_for_variant(self):
fields = [{'field_name': 'reorder_levels'}]
set_item_variant_settings(fields)
+ make_item_variant()
template = frappe.get_doc("Item", "_Test Variant Item")
if not template.reorder_levels:
diff --git a/erpnext/stock/doctype/warehouse/test_records.json b/erpnext/stock/doctype/warehouse/test_records.json
index af3bd231fc0..014cf3e5015 100644
--- a/erpnext/stock/doctype/warehouse/test_records.json
+++ b/erpnext/stock/doctype/warehouse/test_records.json
@@ -13,13 +13,6 @@
"warehouse_name": "_Test Scrap Warehouse",
"is_group": 0
},
- {
- "company": "_Test Company",
- "create_account_under": "Stock Assets - _TC",
- "doctype": "Warehouse",
- "warehouse_name": "_Test Warehouse",
- "is_group": 0
- },
{
"company": "_Test Company",
"create_account_under": "Fixed Assets - _TC",
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 0e3a4f95251..65310aa9e30 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -25,7 +25,7 @@ class TransactionBase(StatusUpdater):
if not getattr(self, 'set_posting_time', None):
now = now_datetime()
self.posting_date = now.strftime('%Y-%m-%d')
- self.posting_time = now.strftime('%H:%M:%S')
+ self.posting_time = now.strftime('%H:%M:%S.%f')
def add_calendar_event(self, opts, force=False):
if cstr(self.contact_by) != cstr(self._prev.contact_by) or \