diff --git a/erpnext/__init__.py b/erpnext/__init__.py index a4950e76c5..29e81f1676 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '9.2.19' +__version__ = '9.2.20' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index 5a6292ba3f..1042071da1 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -26,7 +26,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Series", "length": 0, @@ -432,7 +432,7 @@ "options": "
\n", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -728,7 +728,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-06-13 14:29:20.388372", + "modified": "2017-12-02 15:50:41.775006", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json index 2b7fe776ec..e6200659cf 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json @@ -19,7 +19,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "default": "Valuation and Total", + "default": "Total", "fieldname": "category", "fieldtype": "Select", "hidden": 0, @@ -679,7 +679,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-15 19:26:57.074345", + "modified": "2017-12-06 13:37:44.483509", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Taxes and Charges", diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index 890833bf86..67112b669f 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -86,17 +86,20 @@ def get_accumulated_depreciations(assets, filters): for d in assets: asset = frappe.get_doc("Asset", d.name) - asset_depreciations.setdefault(d.asset_category, frappe._dict({ - "accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation, - "depreciation_amount_during_the_period": 0, - "depreciation_eliminated_during_the_period": 0 - })) + if d.asset_category in asset_depreciations: + asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation + else: + asset_depreciations.setdefault(d.asset_category, frappe._dict({ + "accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation, + "depreciation_amount_during_the_period": 0, + "depreciation_eliminated_during_the_period": 0 + })) depr = asset_depreciations[d.asset_category] for schedule in asset.get("schedules"): if getdate(schedule.schedule_date) < getdate(filters.from_date): - if not asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date): + if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date): depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount) elif getdate(schedule.schedule_date) <= getdate(filters.to_date): depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount) diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 9eea472086..5df2a6505a 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -134,8 +134,12 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters, "account": "'" + _("Total") + "'", "account_name": "'" + _("Total") + "'", "warn_if_negative": True, + "opening_debit": 0.0, + "opening_credit": 0.0, "debit": 0.0, "credit": 0.0, + "closing_debit": 0.0, + "closing_credit": 0.0, "parent_account": None, "indent": 0, "has_value": True, @@ -156,7 +160,10 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters, total_row["debit"] += d["debit"] total_row["credit"] += d["credit"] - + total_row["opening_debit"] += d["opening_debit"] + total_row["opening_credit"] += d["opening_credit"] + total_row["closing_debit"] += (d["opening_debit"] + d["debit"]) + total_row["closing_credit"] += (d["opening_credit"] + d["credit"]) return total_row diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index 8d1fb3d4a6..0cab383176 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -232,7 +232,7 @@ class EmailDigest(Document): "new_quotations","pending_quotations","sales_order","purchase_order","pending_sales_orders","pending_purchase_orders", "invoiced_amount", "payables", "bank_balance", "credit_balance"): if self.get(key): - cache_key = "email_digest:card:{0}:{1}:{2}".format(self.company, self.frequency, key) + cache_key = "email_digest:card:{0}:{1}:{2}:{3}".format(self.company, self.frequency, key, self.from_date) card = cache.get(cache_key) if card: diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index 364f21abd5..5d3ef78f1c 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -78,7 +78,7 @@ class ItemGroup(NestedSet, WebsiteGenerator): @frappe.whitelist(allow_guest=True) def get_product_list_for_group(product_group=None, start=0, limit=10, search=None): - child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)]) + child_groups = ", ".join(['"' + frappe.db.escape(i[0]) + '"' for i in get_child_groups(product_group)]) # base query query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group, diff --git a/erpnext/stock/doctype/batch/batch.js b/erpnext/stock/doctype/batch/batch.js index 20581dccec..677d0f091c 100644 --- a/erpnext/stock/doctype/batch/batch.js +++ b/erpnext/stock/doctype/batch/batch.js @@ -70,31 +70,38 @@ frappe.ui.form.on('Batch', { // move - ask for target warehouse and make stock entry rows.find('.btn-move').on('click', function() { var $btn = $(this); - frappe.prompt({ - fieldname: 'to_warehouse', - label: __('To Warehouse'), - fieldtype: 'Link', - options: 'Warehouse' - }, - (data) => { - frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', - args: { - item_code: frm.doc.item, - batch_no: frm.doc.name, - qty: $btn.attr('data-qty'), - from_warehouse: $btn.attr('data-warehouse'), - to_warehouse: data.to_warehouse - }, - callback: (r) => { - frappe.show_alert(__('Stock Entry {0} created', - ['' + r.message.name+ ''])); - frm.refresh(); - }, - }); - }, - __('Select Target Warehouse'), - __('Move') + const fields = [ + { + fieldname: 'to_warehouse', + label: __('To Warehouse'), + fieldtype: 'Link', + options: 'Warehouse' + } + ]; + + frappe.prompt( + fields, + (data) => { + frappe.call({ + method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', + args: { + item_code: frm.doc.item, + batch_no: frm.doc.name, + qty: $btn.attr('data-qty'), + from_warehouse: $btn.attr('data-warehouse'), + to_warehouse: data.to_warehouse, + source_document: frm.doc.reference_name, + reference_doctype: frm.doc.reference_doctype + }, + callback: (r) => { + frappe.show_alert(__('Stock Entry {0} created', + ['' + r.message.name+ ''])); + frm.refresh(); + }, + }); + }, + __('Select Target Warehouse'), + __('Move') ); }); diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 6af8c09568..b656c3f0dc 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -12,6 +12,7 @@ from erpnext import set_perpetual_inventory from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError from erpnext.accounts.doctype.account.test_account import get_inventory_account + class TestPurchaseReceipt(unittest.TestCase): def setUp(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) @@ -259,7 +260,7 @@ class TestPurchaseReceipt(unittest.TestCase): item_code = frappe.db.get_value('Item', {'has_serial_no': 1}) if not item_code: - item = make_item("Test Serial Item 1", dict(has_serial_no = 1)) + item = make_item("Test Serial Item 1", dict(has_serial_no=1)) item_code = item.name serial_no = random_string(5) @@ -273,11 +274,13 @@ class TestPurchaseReceipt(unittest.TestCase): serial_no=serial_no, basic_rate=100, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, se.submit) + def get_gl_entries(voucher_type, voucher_no): return frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account desc""", (voucher_type, voucher_no), as_dict=1) + def make_purchase_receipt(**args): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) pr = frappe.new_doc("Purchase Receipt") diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py index e1ec3ee9f3..446f718f59 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py @@ -20,6 +20,16 @@ def make_stock_entry(**args): :do_not_save: Optional flag :do_not_submit: Optional flag ''' + + def process_serial_numbers(serial_nos_list): + serial_nos_list = [ + '\n'.join(serial_num['serial_no'] for serial_num in serial_nos_list) + ] + + uniques = list(set(serial_nos_list[0].split('\n'))) + + return '\n'.join(uniques) + s = frappe.new_doc("Stock Entry") args = frappe._dict(args) @@ -77,6 +87,25 @@ def make_stock_entry(**args): if not args.cost_center: args.cost_center = frappe.get_value('Company', s.company, 'cost_center') + if not args.expense_account: + args.expense_account = frappe.get_value('Company', s.company, 'stock_adjustment_account') + + # We can find out the serial number using the batch source document + serial_number = args.serial_no + + if not args.serial_no and args.qty and args.batch_no: + serial_number_list = frappe.get_list( + doctype='Stock Ledger Entry', + fields=['serial_no'], + filters={ + 'batch_no': args.batch_no, + 'warehouse': args.from_warehouse + } + ) + serial_number = process_serial_numbers(serial_number_list) + + args.serial_no = serial_number + s.append("items", { "item_code": args.item, "s_warehouse": args.source,Message Example
\n\n<p>Dear {{ doc.contact_person }},</p>\n\n<p>Requesting payment for {{ doc.doctype }}, {{ doc.name }} for {{ doc.grand_total }}.</p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n