Merge branch 'hotfix' into fix-barcode-scanning-ux

This commit is contained in:
Faris Ansari 2019-02-12 18:31:06 +05:30 committed by GitHub
commit 795102125c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 93 additions and 66 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '11.1.4'
__version__ = '11.1.5'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -128,9 +128,13 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
# start_date: 1st of the last month or the start date
# end_date: end_date or today-1
enable_check = "enable_deferred_revenue" \
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
gl_entries = []
for item in doc.get('items'):
if not item.get(enable_check): continue
skip = False
last_gl_entry, booking_start_date, booking_end_date, skip = \
get_booking_dates(doc, item, start_date, end_date)

View File

@ -171,7 +171,7 @@ class PaymentEntry(AccountsController):
if not frappe.db.exists(self.party_type, self.party):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
if self.party_account:
if self.party_account and self.party_type in ("Customer", "Supplier"):
self.validate_account_type(self.party_account,
[erpnext.get_party_account_type(self.party_type)])
@ -689,7 +689,7 @@ def get_party_details(company, party_type, party, date, cost_center=None):
account_currency = get_account_currency(party_account)
account_balance = get_balance_on(party_account, date, cost_center=cost_center)
_party_name = "title" if party_type == "Student" else party_type.lower() + "_name"
_party_name = "title" if party_type in ("Student", "Shareholder") else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
if party_type in ["Customer", "Supplier"]:

View File

@ -193,7 +193,7 @@ def get_invoice_po_pr_map(invoice_list):
pi_items = frappe.db.sql("""
select parent, purchase_order, purchase_receipt, po_detail, project
from `tabPurchase Invoice Item`
where parent in (%s) and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')
where parent in (%s)
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
invoice_po_pr_map = {}

View File

@ -1812,8 +1812,9 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "company.default_finance_book",
"fieldname": "default_finance_book",
"fieldtype": "Read Only",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -1824,12 +1825,12 @@
"label": "Default Finance Book",
"length": 0,
"no_copy": 0,
"options": "company.default_finance_book",
"options": "Finance Book",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1882,7 +1883,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-15 16:12:48.314196",
"modified": "2019-02-12 11:29:01.747819",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@ -28,7 +28,7 @@ class WoocommerceSettings(Document):
if not frappe.get_value("Custom Field",{"name":i[0]}) or not frappe.get_value("Custom Field",{"name":i[1]}):
create_custom_field_id_and_check_status = True
break;
break
if create_custom_field_id_and_check_status:

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@ -55,7 +56,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "item_code",
"fieldtype": "Read Only",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -71,7 +72,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -707,7 +708,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-08 13:00:06.260997",
"modified": "2019-02-12 11:37:18.713344",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Clinical Procedure Template",

View File

@ -19,7 +19,6 @@ frappe.ui.form.on('Employee Advance', {
filters: {
"root_type": "Asset",
"is_group": 0,
"account_type": "Payable",
"company": frm.doc.company
}
};

View File

@ -195,7 +195,7 @@
"columns": 0,
"fetch_from": "employee.branch",
"fieldname": "branch",
"fieldtype": "Read Only",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -208,11 +208,11 @@
"no_copy": 0,
"oldfieldname": "branch",
"oldfieldtype": "Link",
"options": "",
"options": "Branch",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1906,7 +1906,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-30 11:28:11.774739",
"modified": "2019-02-12 11:24:20.848207",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip",

View File

@ -13,16 +13,16 @@ def execute(filters=None):
data = get_bom_stock(filters)
qty_to_make = filters.get("qty_to_make")
for rows in data:
item_map = get_item_details(rows[0])
reqd_qty = qty_to_make * rows[3]
last_pur_price = frappe.db.get_value("Item", rows[0], "last_purchase_rate")
if rows[4] > 0:
diff_qty = rows[4] - reqd_qty
summ_data.append([rows[0], rows[1], item_map[rows[0]]["manufacturer"], item_map[rows[0]]["manufacturer_part_no"], rows[3], rows[4], reqd_qty, diff_qty, last_pur_price])
for row in data:
item_map = get_item_details(row.item_code)
reqd_qty = qty_to_make * row.actual_qty
last_pur_price = frappe.db.get_value("Item", row.item_code, "last_purchase_rate")
if row.to_build > 0:
diff_qty = row.to_build - reqd_qty
summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, row.to_build, reqd_qty, diff_qty, last_pur_price])
else:
diff_qty = 0 - reqd_qty
summ_data.append([rows[0], rows[1], item_map[rows[0]]["manufacturer"], item_map[rows[0]]["manufacturer_part_no"], rows[3], "0.000", reqd_qty, diff_qty, last_pur_price])
summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, "0.000", reqd_qty, diff_qty, last_pur_price])
return columns, summ_data
@ -72,8 +72,8 @@ def get_bom_stock(filters):
bom_item.item_code,
bom_item.description,
bom_item.{qty_field},
sum(ledger.actual_qty) as actual_qty,
sum(FLOOR(ledger.actual_qty / bom_item.{qty_field}))as to_build
ifnull(sum(ledger.actual_qty), 0) as actual_qty,
ifnull(sum(FLOOR(ledger.actual_qty / bom_item.{qty_field})), 0) as to_build
FROM
{table} AS bom_item
LEFT JOIN `tabBin` AS ledger
@ -83,7 +83,7 @@ def get_bom_stock(filters):
WHERE
bom_item.parent = '{bom}' and bom_item.parenttype='BOM'
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom))
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1)
def get_item_details(item_code):
items = frappe.db.sql("""select it.item_group, it.item_name, it.stock_uom, it.name, it.brand, it.description, it.manufacturer_part_no, it.manufacturer from tabItem it where it.item_code = %s""", item_code, as_dict=1)

View File

@ -585,3 +585,4 @@ erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
erpnext.patches.v11_0.renamed_from_to_fields_in_project
erpnext.patches.v11_0.add_permissions_in_gst_settings
erpnext.patches.v11_1.setup_guardian_role
execute:frappe.delete_doc('DocType', 'Notification Control')

View File

@ -27,8 +27,10 @@ def execute():
for company in companies:
copy_doc = frappe.copy_doc(department_doc)
copy_doc.update({"company": company.name})
copy_doc.insert()
try:
copy_doc.insert()
except frappe.DuplicateEntryError:
pass
# append list of new department for each company
comp_dict[company.name][department.name] = copy_doc.name

View File

@ -66,11 +66,11 @@ class Project(Document):
def validate(self):
self.validate_project_name()
self.validate_dates()
self.validate_weights()
self.sync_tasks()
self.tasks = []
self.load_tasks()
self.validate_dates()
self.send_welcome_email()
self.update_percent_complete()
@ -79,6 +79,24 @@ class Project(Document):
frappe.throw(_("Project {0} already exists").format(frappe.safe_decode(self.project_name)))
def validate_dates(self):
if self.tasks:
for d in self.tasks:
if self.expected_start_date:
if d.start_date and getdate(d.start_date) < getdate(self.expected_start_date):
frappe.throw(_("Start date of task <b>{0}</b> cannot be less than <b>{1}</b> expected start date <b>{2}</b>")
.format(d.title, self.name, self.expected_start_date))
if d.end_date and getdate(d.end_date) < getdate(self.expected_start_date):
frappe.throw(_("End date of task <b>{0}</b> cannot be less than <b>{1}</b> expected start date <b>{2}</b>")
.format(d.title, self.name, self.expected_start_date))
if self.expected_end_date:
if d.start_date and getdate(d.start_date) > getdate(self.expected_end_date):
frappe.throw(_("Start date of task <b>{0}</b> cannot be greater than <b>{1}</b> expected end date <b>{2}</b>")
.format(d.title, self.name, self.expected_end_date))
if d.end_date and getdate(d.end_date) > getdate(self.expected_end_date):
frappe.throw(_("End date of task <b>{0}</b> cannot be greater than <b>{1}</b> expected end date <b>{2}</b>")
.format(d.title, self.name, self.expected_end_date))
if self.expected_start_date and self.expected_end_date:
if getdate(self.expected_end_date) < getdate(self.expected_start_date):
frappe.throw(_("Expected End Date can not be less than Expected Start Date"))

View File

@ -44,12 +44,6 @@ class Task(NestedSet):
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
if(self.project):
if frappe.db.exists("Project", self.project):
expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
if self.exp_end_date and expected_end_date and getdate(self.exp_end_date) > getdate(expected_end_date) :
frappe.throw(_("Expected end date cannot be after Project: <b>'{0}'</b> Expected end date").format(self.project), EndDateCannotBeGreaterThanProjectEndDateError)
def validate_status(self):
if self.status!=self.get_db_value("status") and self.status == "Closed":
for d in self.depends_on:

View File

@ -5,7 +5,7 @@ import frappe
import unittest
from frappe.utils import getdate, nowdate, add_days
from erpnext.projects.doctype.task.task import CircularReferenceError, EndDateCannotBeGreaterThanProjectEndDateError
from erpnext.projects.doctype.task.task import CircularReferenceError
class TestTask(unittest.TestCase):
def test_circular_reference(self):
@ -97,15 +97,6 @@ class TestTask(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
def test_end_date_validation(self):
task_end = create_task("Testing_Enddate_validation", add_days(nowdate(), 35), add_days(nowdate(), 45), save=False)
pro = frappe.get_doc("Project", task_end.project)
pro.expected_end_date = add_days(nowdate(), 40)
pro.save()
self.assertRaises(EndDateCannotBeGreaterThanProjectEndDateError, task_end.save)
def create_task(subject, start=None, end=None, depends_on=None, project=None, save=True):
if not frappe.db.exists("Task", subject):
task = frappe.new_doc('Task')

View File

@ -81,9 +81,9 @@ class MaterialRequest(BuyingController):
def set_title(self):
'''Set title as comma separated list of items'''
items = ', '.join([d.item_name for d in self.items][:4])
self.title = _('{0} for {1}'.format(self.material_request_type, items))[:100]
if not self.title:
items = ', '.join([d.item_name for d in self.items][:3])
self.title = _('{0} Request for {1}').format(self.material_request_type, items)[:100]
def on_submit(self):
# frappe.db.set(self, 'status', 'Submitted')

View File

@ -914,6 +914,11 @@ class StockEntry(StockController):
filters={'parent': self.work_order, 'item_code': item_code},
fields=["required_qty", "consumed_qty"]
)
if not req_items:
frappe.msgprint(_("Did not found transfered item {0} in Work Order {1}, the item not added in Stock Entry")
.format(item_code, self.work_order))
continue
req_qty = flt(req_items[0].required_qty)
req_qty_each = flt(req_qty / manufacturing_qty)
consumed_qty = flt(req_items[0].consumed_qty)

View File

@ -259,6 +259,7 @@ class StockReconciliation(StockController):
def submit(self):
if len(self.items) > 100:
msgprint(_("The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Draft stage"))
self.queue_action('submit')
else:
self._submit()

View File

@ -157,6 +157,8 @@ def get_children(doctype, parent=None, company=None, is_root=False):
# return warehouses
for wh in warehouses:
wh["balance"] = get_stock_value_from_bin(warehouse=wh.value)
if company:
wh["company_currency"] = frappe.db.get_value('Company', company, 'default_currency')
return warehouses
@frappe.whitelist()

View File

@ -173,15 +173,15 @@ def get_item_warehouse_map(filters, sle):
qty_dict.val_rate = d.valuation_rate
qty_dict.bal_qty += qty_diff
qty_dict.bal_val += value_diff
iwb_map = filter_items_with_no_transactions(iwb_map)
return iwb_map
def filter_items_with_no_transactions(iwb_map):
for (company, item, warehouse) in sorted(iwb_map):
qty_dict = iwb_map[(company, item, warehouse)]
no_transactions = True
float_precision = cint(frappe.db.get_default("float_precision")) or 3
for key, val in iteritems(qty_dict):
@ -189,7 +189,7 @@ def filter_items_with_no_transactions(iwb_map):
qty_dict[key] = val
if key != "val_rate" and val:
no_transactions = False
if no_transactions:
iwb_map.pop((company, item, warehouse))
@ -216,20 +216,28 @@ def get_item_details(items, sle, filters):
if not items:
items = list(set([d.item_code for d in sle]))
if items:
cf_field = cf_join = ""
if filters.get("include_uom"):
cf_field = ", ucd.conversion_factor"
cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom=%(include_uom)s"
if not items:
return item_details
for item in frappe.db.sql("""
select item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom{cf_field}
from `tabItem` item
cf_field = cf_join = ""
if filters.get("include_uom"):
cf_field = ", ucd.conversion_factor"
cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom='%s'" \
% frappe.db.escape(filters.get("include_uom"))
item_codes = ', '.join(['"' + frappe.db.escape(i, percent=False) + '"' for i in items])
res = frappe.db.sql("""
select
item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom {cf_field}
from
`tabItem` item
{cf_join}
where item.name in ({names}) and ifnull(item.disabled, 0) = 0
""".format(cf_field=cf_field, cf_join=cf_join, names=', '.join(['"' + frappe.db.escape(i, percent=False) + '"' for i in items])),
{"include_uom": filters.get("include_uom")}, as_dict=1):
item_details.setdefault(item.name, item)
where
item.name in ({item_codes}) and ifnull(item.disabled, 0) = 0
""".format(cf_field=cf_field, cf_join=cf_join, item_codes=item_codes), as_dict=1)
for item in res:
item_details.setdefault(item.name, item)
if filters.get('show_variant_attributes', 0) == 1:
variant_values = get_variant_values_for(list(item_details))