diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json
index a2497838eed..2c5231491cd 100644
--- a/erpnext/accounts/desk_page/accounting/accounting.json
+++ b/erpnext/accounts/desk_page/accounting/accounting.json
@@ -43,7 +43,7 @@
{
"hidden": 0,
"label": "Bank Statement",
- "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
+ "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"label\": \"Bank Clearance\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
@@ -98,7 +98,7 @@
"idx": 0,
"is_standard": 1,
"label": "Accounting",
- "modified": "2020-06-19 12:42:44.054598",
+ "modified": "2020-09-03 10:37:07.865801",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
@@ -158,4 +158,4 @@
"type": "Dashboard"
}
]
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
index 2800c195cee..1ec6805ae0c 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
+++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.js
@@ -10,13 +10,15 @@ frappe.ui.form.on('Process Deferred Accounting', {
}
};
});
+ },
- if (frm.doc.company) {
+ type: function(frm) {
+ if (frm.doc.company && frm.doc.type) {
frm.set_query("account", function() {
return {
filters: {
'company': frm.doc.company,
- 'root_type': 'Liability',
+ 'root_type': frm.doc.type === 'Income' ? 'Liability' : 'Asset',
'is_group': 0
}
};
diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
index 4daafef3ec5..457e98ca549 100644
--- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
+++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.json
@@ -60,6 +60,7 @@
"reqd": 1
},
{
+ "depends_on": "eval: doc.type",
"fieldname": "account",
"fieldtype": "Link",
"label": "Account",
@@ -73,9 +74,10 @@
"reqd": 1
}
],
+ "index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-02-06 18:18:09.852844",
+ "modified": "2020-09-03 18:07:02.463754",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Deferred Accounting",
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 3ec4d306c35..f547ca619bd 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -71,7 +71,22 @@ frappe.query_reports["Budget Variance Report"] = {
fieldtype: "Check",
default: 0,
},
- ]
+ ],
+ "formatter": function (value, row, column, data, default_formatter) {
+ value = default_formatter(value, row, column, data);
+
+ if (column.fieldname.includes('variance')) {
+
+ if (data[column.fieldname] < 0) {
+ value = "" + value + "";
+ }
+ else if (data[column.fieldname] > 0) {
+ value = "" + value + "";
+ }
+ }
+
+ return value;
+ }
}
erpnext.dimension_filters.forEach((dimension) => {
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 0599707446c..f735d87a764 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -43,8 +43,11 @@ def execute(filters=None):
def validate_filters(filters, account_details):
- if not filters.get('company'):
- frappe.throw(_('{0} is mandatory').format(_('Company')))
+ if not filters.get("company"):
+ frappe.throw(_("{0} is mandatory").format(_("Company")))
+
+ if not filters.get("from_date") and not filters.get("to_date"):
+ frappe.throw(_("{0} and {1} are mandatory").format(frappe.bold(_("From Date")), frappe.bold(_("To Date"))))
if filters.get("account") and not account_details.get(filters.account):
frappe.throw(_("Account {0} does not exists").format(filters.account))
@@ -141,7 +144,7 @@ def get_gl_entries(filters, accounting_dimensions):
if filters and filters.get('cost_center'):
select_fields_with_percentage = """, debit*(DCC_allocation.percentage_allocation/100) as debit, credit*(DCC_allocation.percentage_allocation/100) as credit, debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency """
-
+
distributed_cost_center_query = """
UNION ALL
SELECT name as gl_entry,
@@ -155,7 +158,7 @@ def get_gl_entries(filters, accounting_dimensions):
against_voucher_type,
against_voucher,
account_currency,
- remarks, against,
+ remarks, against,
is_opening, `tabGL Entry`.creation {select_fields_with_percentage}
FROM `tabGL Entry`,
(
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.json b/erpnext/accounts/report/gross_profit/gross_profit.json
index 9cfb0627d30..cd6bac2d77d 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.json
+++ b/erpnext/accounts/report/gross_profit/gross_profit.json
@@ -1,24 +1,23 @@
{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2013-02-25 17:03:34",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 3,
- "is_standard": "Yes",
- "modified": "2017-02-24 20:12:22.464240",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Gross Profit",
- "owner": "Administrator",
- "ref_doctype": "Sales Invoice",
- "report_name": "Gross Profit",
- "report_type": "Script Report",
+ "add_total_row": 1,
+ "creation": "2013-02-25 17:03:34",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 3,
+ "is_standard": "Yes",
+ "modified": "2020-08-13 11:26:39.112352",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Gross Profit",
+ "owner": "Administrator",
+ "ref_doctype": "Sales Invoice",
+ "report_name": "Gross Profit",
+ "report_type": "Script Report",
"roles": [
{
"role": "Accounts Manager"
- },
+ },
{
"role": "Accounts User"
}
diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
index 3de9526c4f2..019cefc0bd1 100644
--- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
@@ -11,6 +11,8 @@ from erpnext.stock.doctype.item.test_item import make_item
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
+from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity
+from erpnext.crm.doctype.opportunity.opportunity import make_request_for_quotation as make_rfq
class TestRequestforQuotation(unittest.TestCase):
def test_quote_status(self):
@@ -110,6 +112,23 @@ class TestRequestforQuotation(unittest.TestCase):
self.assertEqual(supplier_quotation.items[0].qty, 5)
self.assertEqual(supplier_quotation.items[0].stock_qty, 10)
+ def test_make_rfq_from_opportunity(self):
+ opportunity = make_opportunity(with_items=1)
+ supplier_data = get_supplier_data()
+ rfq = make_rfq(opportunity.name)
+
+ self.assertEqual(len(rfq.get("items")), len(opportunity.get("items")))
+ rfq.message_for_supplier = 'Please supply the specified items at the best possible rates.'
+
+ for item in rfq.items:
+ item.warehouse = "_Test Warehouse - _TC"
+
+ for data in supplier_data:
+ rfq.append('suppliers', data)
+
+ rfq.status = 'Draft'
+ rfq.submit()
+
def make_request_for_quotation(**args):
"""
:param supplier_data: List containing supplier data
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 6096053136a..47b05f306b7 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -267,6 +267,9 @@ def make_quotation(source_name, target_doc=None):
@frappe.whitelist()
def make_request_for_quotation(source_name, target_doc=None):
+ def update_item(obj, target, source_parent):
+ target.conversion_factor = 1.0
+
doclist = get_mapped_doc("Opportunity", source_name, {
"Opportunity": {
"doctype": "Request for Quotation"
@@ -277,7 +280,8 @@ def make_request_for_quotation(source_name, target_doc=None):
["name", "opportunity_item"],
["parent", "opportunity"],
["uom", "uom"]
- ]
+ ],
+ "postprocess": update_item
}
}, target_doc)
diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py
index 33d90076c4a..04cd8a26cad 100644
--- a/erpnext/crm/doctype/opportunity/test_opportunity.py
+++ b/erpnext/crm/doctype/opportunity/test_opportunity.py
@@ -82,7 +82,8 @@ def make_opportunity(**args):
if args.with_items:
opp_doc.append('items', {
"item_code": args.item_code or "_Test Item",
- "qty": args.qty or 1
+ "qty": args.qty or 1,
+ "uom": "_Test UOM"
})
opp_doc.insert()
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index bab0dfb6b43..b051b3243fd 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -2,6 +2,17 @@
// For license information, please see license.txt
frappe.ui.form.on('Job Card', {
+ setup: function(frm) {
+ frm.set_query('operation', function() {
+ return {
+ query: 'erpnext.manufacturing.doctype.job_card.job_card.get_operations',
+ filters: {
+ 'work_order': frm.doc.work_order
+ }
+ };
+ });
+ },
+
refresh: function(frm) {
frappe.flags.pause_job = 0;
frappe.flags.resume_job = 0;
@@ -20,12 +31,60 @@ frappe.ui.form.on('Job Card', {
}
}
+ frm.trigger("toggle_operation_number");
+
if (frm.doc.docstatus == 0 && (frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
- && (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
+ && (frm.doc.items || !frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
frm.trigger("prepare_timer_buttons");
}
},
+ operation: function(frm) {
+ frm.trigger("toggle_operation_number");
+
+ if (frm.doc.operation && frm.doc.work_order) {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.job_card.job_card.get_operation_details",
+ args: {
+ "work_order":frm.doc.work_order,
+ "operation":frm.doc.operation
+ },
+ callback: function (r) {
+ if (r.message) {
+ if (r.message.length == 1) {
+ frm.set_value("operation_id", r.message[0].name);
+ } else {
+ let args = [];
+
+ r.message.forEach((row) => {
+ args.push({ "label": row.idx, "value": row.name });
+ });
+
+ let description = __("Operation {0} added multiple times in the work order {1}",
+ [frm.doc.operation, frm.doc.work_order]);
+
+ frm.set_df_property("operation_row_number", "options", args);
+ frm.set_df_property("operation_row_number", "description", description);
+ }
+
+ frm.trigger("toggle_operation_number");
+ }
+ }
+ })
+ }
+ },
+
+ operation_row_number(frm) {
+ if (frm.doc.operation_row_number) {
+ frm.set_value("operation_id", frm.doc.operation_row_number);
+ }
+ },
+
+ toggle_operation_number(frm) {
+ frm.toggle_display("operation_row_number", !frm.doc.operation_id && frm.doc.operation);
+ frm.toggle_reqd("operation_row_number", !frm.doc.operation_id && frm.doc.operation);
+ },
+
prepare_timer_buttons: function(frm) {
frm.trigger("make_dashboard");
if (!frm.doc.job_started) {
@@ -35,9 +94,9 @@ frappe.ui.form.on('Job Card', {
fieldname: 'employee'}, d => {
if (d.employee) {
frm.set_value("employee", d.employee);
+ } else {
+ frm.events.start_job(frm);
}
-
- frm.events.start_job(frm);
}, __("Enter Value"), __("Start"));
} else {
frm.events.start_job(frm);
@@ -82,9 +141,7 @@ frappe.ui.form.on('Job Card', {
frm.set_value('current_time' , 0);
}
- frm.save("Save", () => {}, "", () => {
- frm.doc.time_logs.pop(-1);
- });
+ frm.save();
},
complete_job: function(frm, completed_time, completed_qty) {
@@ -116,6 +173,8 @@ frappe.ui.form.on('Job Card', {
employee: function(frm) {
if (frm.doc.job_started && !frm.doc.current_time) {
frm.trigger("reset_timer");
+ } else {
+ frm.events.start_job(frm);
}
},
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index fba670c1c15..087ab6b484b 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -11,6 +11,7 @@
"bom_no",
"workstation",
"operation",
+ "operation_row_number",
"column_break_4",
"posting_date",
"company",
@@ -291,11 +292,15 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "operation_row_number",
+ "fieldtype": "Select",
+ "label": "Operation Row Number"
}
],
"is_submittable": 1,
- "links": [],
- "modified": "2020-04-20 15:14:00.273441",
+ "modified": "2020-08-24 15:21:21.398267",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",
@@ -347,7 +352,6 @@
"write": 1
}
],
- "quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "operation",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index c29d4ba3d5c..8855e0acf59 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -15,10 +15,13 @@ from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings
class OverlapError(frappe.ValidationError): pass
+class OperationMismatchError(frappe.ValidationError): pass
+
class JobCard(Document):
def validate(self):
self.validate_time_logs()
self.set_status()
+ self.validate_operation_id()
def validate_time_logs(self):
self.total_completed_qty = 0.0
@@ -209,11 +212,10 @@ class JobCard(Document):
for_quantity, time_in_mins = 0, 0
from_time_list, to_time_list = [], []
- field = "operation_id" if self.operation_id else "operation"
+ field = "operation_id"
data = frappe.get_all('Job Card',
fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
- filters = {"docstatus": 1, "work_order": self.work_order,
- "workstation": self.workstation, field: self.get(field)})
+ filters = {"docstatus": 1, "work_order": self.work_order, field: self.get(field)})
if data and len(data) > 0:
for_quantity = data[0].completed_qty
@@ -226,14 +228,13 @@ class JobCard(Document):
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
WHERE
jctl.parent = jc.name and jc.work_order = %s
- and jc.workstation = %s and jc.{0} = %s and jc.docstatus = 1
- """.format(field), (self.work_order, self.workstation, self.get(field)), as_dict=1)
+ and jc.{0} = %s and jc.docstatus = 1
+ """.format(field), (self.work_order, self.get(field)), as_dict=1)
wo = frappe.get_doc('Work Order', self.work_order)
- work_order_field = "name" if field == "operation_id" else field
for data in wo.operations:
- if data.get(work_order_field) == self.get(field) and data.workstation == self.workstation:
+ if data.get("name") == self.get(field):
data.completed_qty = for_quantity
data.actual_operation_time = time_in_mins
data.actual_start_time = time_data[0].start_time if time_data else None
@@ -306,6 +307,37 @@ class JobCard(Document):
if update_status:
self.db_set('status', self.status)
+ def validate_operation_id(self):
+ if (self.get("operation_id") and self.get("operation_row_number") and self.operation and self.work_order and
+ frappe.get_cached_value("Work Order Operation", self.operation_row_number, "name") != self.operation_id):
+ work_order = frappe.bold(get_link_to_form("Work Order", self.work_order))
+ frappe.throw(_("Operation {0} does not belong to the work order {1}")
+ .format(frappe.bold(self.operation), work_order), OperationMismatchError)
+
+@frappe.whitelist()
+def get_operation_details(work_order, operation):
+ if work_order and operation:
+ return frappe.get_all("Work Order Operation", fields = ["name", "idx"],
+ filters = {
+ "parent": work_order,
+ "operation": operation
+ }
+ )
+
+@frappe.whitelist()
+def get_operations(doctype, txt, searchfield, start, page_len, filters):
+ if filters.get("work_order"):
+ args = {"parent": filters.get("work_order")}
+ if txt:
+ args["operation"] = ("like", "%{0}%".format(txt))
+
+ return frappe.get_all("Work Order Operation",
+ filters = args,
+ fields = ["distinct operation as operation"],
+ limit_start = start,
+ limit_page_length = page_len,
+ order_by="idx asc", as_list=1)
+
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):
def update_item(obj, target, source_parent):
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py
index ca05fea0f6f..b6a6c33d37f 100644
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py
@@ -4,6 +4,72 @@
from __future__ import unicode_literals
import unittest
+import frappe
+from frappe.utils import random_string
+from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
+from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
+from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError
class TestJobCard(unittest.TestCase):
- pass
+ def test_job_card(self):
+ data = frappe.get_cached_value('BOM',
+ {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
+
+ if data:
+ bom, bom_item = data
+
+ work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
+
+ job_cards = frappe.get_all('Job Card',
+ filters = {'work_order': work_order.name}, fields = ["operation_id", "name"])
+
+ if job_cards:
+ job_card = job_cards[0]
+ frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id)
+
+ doc = frappe.get_doc("Job Card", job_card.name)
+ doc.operation_id = "Test Data"
+ self.assertRaises(OperationMismatchError, doc.save)
+
+ for d in job_cards:
+ frappe.delete_doc("Job Card", d.name)
+
+ def test_job_card_with_different_work_station(self):
+ data = frappe.get_cached_value('BOM',
+ {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
+
+ if data:
+ bom, bom_item = data
+
+ work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
+
+ job_cards = frappe.get_all('Job Card',
+ filters = {'work_order': work_order.name},
+ fields = ["operation_id", "workstation", "name", "for_quantity"])
+
+ job_card = job_cards[0]
+
+ if job_card:
+ workstation = frappe.db.get_value("Workstation",
+ {"name": ("not in", [job_card.workstation])}, "name")
+
+ if not workstation or job_card.workstation == workstation:
+ workstation = make_workstation(workstation_name=random_string(5)).name
+
+ doc = frappe.get_doc("Job Card", job_card.name)
+ doc.workstation = workstation
+ doc.append("time_logs", {
+ "from_time": "2009-01-01 12:06:25",
+ "to_time": "2009-01-01 12:37:25",
+ "time_in_mins": "31.00002",
+ "completed_qty": job_card.for_quantity
+ })
+ doc.submit()
+
+ completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty")
+ self.assertEqual(completed_qty, job_card.for_quantity)
+
+ doc.cancel()
+
+ for d in job_cards:
+ frappe.delete_doc("Job Card", d.name)
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 2260befb3f8..b7c7c328697 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -7,7 +7,7 @@ import unittest
import frappe
from frappe.utils import flt, time_diff_in_hours, now, add_months, cint, today
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
-from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
+from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
from erpnext.stock.doctype.stock_entry import test_stock_entry
from erpnext.stock.utils import get_bin
diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py
index 21692608548..8266cf7b779 100644
--- a/erpnext/manufacturing/doctype/workstation/test_workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py
@@ -20,3 +20,18 @@ class TestWorkstation(unittest.TestCase):
"_Test Workstation 1", "Operation 1", "2013-02-02 05:00:00", "2013-02-02 20:00:00")
self.assertRaises(WorkstationHolidayError, check_if_within_operating_hours,
"_Test Workstation 1", "Operation 1", "2013-02-01 10:00:00", "2013-02-02 20:00:00")
+
+def make_workstation(**args):
+ args = frappe._dict(args)
+
+ try:
+ doc = frappe.get_doc({
+ "doctype": "Workstation",
+ "workstation_name": args.workstation_name
+ })
+
+ doc.insert()
+
+ return doc
+ except frappe.DuplicateEntryError:
+ return frappe.get_doc("Workstation", args.workstation_name)
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 4b9c566f041..771babef6a1 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -724,3 +724,4 @@ erpnext.patches.v12_0.update_state_code_for_daman_and_diu
erpnext.patches.v12_0.rename_lost_reason_detail
erpnext.patches.v13_0.drop_razorpay_payload_column
erpnext.patches.v13_0.update_start_end_date_for_old_shift_assignment
+erpnext.patches.v13_0.setting_custom_roles_for_some_regional_reports
diff --git a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
new file mode 100644
index 00000000000..ecc7822e1d7
--- /dev/null
+++ b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py
@@ -0,0 +1,10 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.regional.india.setup import add_custom_roles_for_reports
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ add_custom_roles_for_reports()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/stock_entry_enhancements.py b/erpnext/patches/v13_0/stock_entry_enhancements.py
index dcc4f956f77..0bdcc9c0e88 100644
--- a/erpnext/patches/v13_0/stock_entry_enhancements.py
+++ b/erpnext/patches/v13_0/stock_entry_enhancements.py
@@ -24,4 +24,8 @@ def execute():
if not frappe.db.exists('Warehouse Type', 'Transit'):
doc = frappe.new_doc('Warehouse Type')
doc.name = 'Transit'
- doc.insert()
\ No newline at end of file
+ doc.insert()
+
+ frappe.reload_doc("stock", "doctype", "stock_entry_type")
+ frappe.delete_doc_if_exists("Stock Entry Type", "Send to Warehouse")
+ frappe.delete_doc_if_exists("Stock Entry Type", "Receive at Warehouse")
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index a4cc68b3e2c..cb76c87b625 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -503,11 +503,11 @@ erpnext.buying.get_items_from_product_bundle = function(frm) {
if(!r.exc && r.message) {
remove_empty_first_row(frm);
- for ( var i=0; i< r.message.length; i++ ) {
+ for (var i=0; i< r.message.length; i++) {
var d = frm.add_child("items");
var item = r.message[i];
- for ( var key in item) {
- if ( !is_null(item[key]) ) {
+ for (var key in item) {
+ if (!is_null(item[key]) && key !== "doctype") {
d[key] = item[key];
}
}
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 290694a7899..cbcd6e3203a 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -73,6 +73,19 @@ def add_custom_roles_for_reports():
]
)).insert()
+ for report_name in ('HSN-wise-summary of outward supplies', 'GSTR-1', 'GSTR-2'):
+
+ if not frappe.db.get_value('Custom Role', dict(report=report_name)):
+ frappe.get_doc(dict(
+ doctype='Custom Role',
+ report=report_name,
+ roles= [
+ dict(role='Accounts User'),
+ dict(role='Accounts Manager'),
+ dict(role='Auditor')
+ ]
+ )).insert()
+
def add_permissions():
for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
add_permission(doctype, 'All', 0)
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index fbccc6b0780..3b6a28f52c0 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -6,6 +6,9 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
shipping_address: function(frm) {
frm.trigger('get_tax_template');
},
+ supplier_address: function(frm) {
+ frm.trigger('get_tax_template');
+ },
tax_category: function(frm) {
frm.trigger('get_tax_template');
},
diff --git a/erpnext/regional/report/gstr_1/gstr_1.json b/erpnext/regional/report/gstr_1/gstr_1.json
index 2012bb8840b..75aed8cffcc 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.json
+++ b/erpnext/regional/report/gstr_1/gstr_1.json
@@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
- "modified": "2019-06-30 19:33:59.769385",
+ "modified": "2019-09-03 19:33:59.769385",
"modified_by": "Administrator",
"module": "Regional",
"name": "GSTR-1",
@@ -16,15 +16,5 @@
"ref_doctype": "GL Entry",
"report_name": "GSTR-1",
"report_type": "Script Report",
- "roles": [
- {
- "role": "Accounts User"
- },
- {
- "role": "Accounts Manager"
- },
- {
- "role": "Auditor"
- }
- ]
+ "roles": []
}
\ No newline at end of file
diff --git a/erpnext/regional/report/gstr_2/gstr_2.json b/erpnext/regional/report/gstr_2/gstr_2.json
index 929ed914d83..b70d0f9416b 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.json
+++ b/erpnext/regional/report/gstr_2/gstr_2.json
@@ -1,29 +1,19 @@
{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2018-01-29 12:59:55.650445",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 0,
- "is_standard": "Yes",
- "modified": "2018-01-29 12:59:55.650445",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "GSTR-2",
- "owner": "Administrator",
- "ref_doctype": "GL Entry",
- "report_name": "GSTR-2",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Accounts User"
- },
- {
- "role": "Accounts Manager"
- },
- {
- "role": "Auditor"
- }
- ]
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2018-01-29 12:59:55.650445",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2018-09-03 12:59:55.650445",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GSTR-2",
+ "owner": "Administrator",
+ "ref_doctype": "GL Entry",
+ "report_name": "GSTR-2",
+ "report_type": "Script Report",
+ "roles": []
}
\ No newline at end of file
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.json b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.json
index 124a7201349..cc6ad574af7 100644
--- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.json
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.json
@@ -1,28 +1,18 @@
{
- "add_total_row": 0,
- "creation": "2018-04-26 10:49:29.159400",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 0,
- "is_standard": "Yes",
- "modified": "2019-04-26 12:59:38.603649",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "HSN-wise-summary of outward supplies",
- "owner": "Administrator",
- "ref_doctype": "Sales Invoice",
- "report_name": "HSN-wise-summary of outward supplies",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Accounts User"
- },
- {
- "role": "Accounts Manager"
- },
- {
- "role": "Auditor"
- }
- ]
+ "add_total_row": 0,
+ "creation": "2018-04-26 10:49:29.159400",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2019-09-03 12:59:38.603649",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "HSN-wise-summary of outward supplies",
+ "owner": "Administrator",
+ "ref_doctype": "Sales Invoice",
+ "report_name": "HSN-wise-summary of outward supplies",
+ "report_type": "Script Report",
+ "roles": []
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 911fe511ae8..1f955fcd52e 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -396,13 +396,12 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
credit_controller_users = get_users_with_role(credit_controller_role or "Sales Master Manager")
# form a list of emails and names to show to the user
- credit_controller_users = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users]
-
- if not credit_controller_users:
+ credit_controller_users_formatted = [get_formatted_email(user).replace("<", "(").replace(">", ")") for user in credit_controller_users]
+ if not credit_controller_users_formatted:
frappe.throw(_("Please contact your administrator to extend the credit limits for {0}.".format(customer)))
message = """Please contact any of the following users to extend the credit limits for {0}:
-