From 77532cc8db7da062cb5f822e70f52aecc3c11def Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Jan 2016 15:44:55 +0530 Subject: [PATCH 1/4] [fix] Total Amount in Journal Entry --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index a64548b46d..9c39f0d5a7 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -351,6 +351,7 @@ class JournalEntry(AccountsController): def set_print_format_fields(self): total_amount = 0.0 bank_account_currency = None + self.pay_to_recd_from = None for d in self.get('accounts'): if d.party_type and d.party: if not self.pay_to_recd_from: @@ -360,7 +361,10 @@ class JournalEntry(AccountsController): elif frappe.db.get_value("Account", d.account, "account_type") in ["Bank", "Cash"]: total_amount += (d.debit_in_account_currency or d.credit_in_account_currency) bank_account_currency = d.account_currency - + + if not self.pay_to_recd_from: + total_amount = 0 + self.set_total_amount(total_amount, bank_account_currency) def set_total_amount(self, amt, currency): From 787e59c37e5475bde598ad42e5c2d0d13aa75f5c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Jan 2016 15:45:15 +0530 Subject: [PATCH 2/4] [fix] BOM Autonaming --- erpnext/manufacturing/doctype/bom/bom.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 7c47cb8aff..6cfbc99ca6 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -4,17 +4,15 @@ from __future__ import unicode_literals import frappe from frappe.utils import cint, cstr, flt - from frappe import _ from frappe.model.document import Document from operator import itemgetter class BOM(Document): - def autoname(self): last_name = frappe.db.sql("""select max(name) from `tabBOM` - where name like "BOM/%s/%%" """ % frappe.db.escape(self.item)) + where name like "BOM/{0}/%%" and item=%s""".format(frappe.db.escape(self.item)), self.item) if last_name: idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1 else: From 34d2822483d782e391071fdcfa77a22ca1077a7e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Jan 2016 15:45:49 +0530 Subject: [PATCH 3/4] Fixes in get_item_details and test cases --- .../doctype/pricing_rule/pricing_rule.py | 30 +++++++++++++++---- .../doctype/pricing_rule/test_pricing_rule.py | 13 ++++---- erpnext/controllers/accounts_controller.py | 4 +-- .../doctype/sales_order/test_sales_order.py | 6 ++-- erpnext/stock/doctype/item/test_item.py | 3 +- erpnext/stock/get_item_details.py | 17 ++++++----- 6 files changed, 49 insertions(+), 24 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 494e70c02b..fcc1f92173 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -97,7 +97,10 @@ def apply_pricing_rule(args): args = json.loads(args) args = frappe._dict(args) - + + if not args.transaction_type: + set_transaction_type(args) + # list of dictionaries out = [] @@ -134,13 +137,17 @@ def get_pricing_rule_for_item(args): if not args.item_group: frappe.throw(_("Item Group not mentioned in item master for item {0}").format(args.item_code)) - if args.customer and not (args.customer_group and args.territory): - customer = frappe.db.get_value("Customer", args.customer, ["customer_group", "territory"]) - if customer: - args.customer_group, args.territory = customer + if args.transaction_type=="selling": + if args.customer and not (args.customer_group and args.territory): + customer = frappe.db.get_value("Customer", args.customer, ["customer_group", "territory"]) + if customer: + args.customer_group, args.territory = customer + + args.supplier = args.supplier_type = None elif args.supplier and not args.supplier_type: args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") + args.customer = args.customer_group = args.territory = None pricing_rules = get_pricing_rules(args) pricing_rule = filter_pricing_rules(args, pricing_rules) @@ -212,7 +219,7 @@ def get_pricing_rules(args): and {transaction_type} = 1 {conditions} order by priority desc, name desc""".format( item_group_condition=item_group_condition, - transaction_type= "selling" if (args.customer or args.lead) else "buying", + transaction_type= args.transaction_type, conditions=conditions), values, as_dict=1) def filter_pricing_rules(args, pricing_rules): @@ -270,3 +277,14 @@ def apply_internal_priority(pricing_rules, field_set, args): if filtered_rules: break return filtered_rules or pricing_rules + +def set_transaction_type(args): + if args.doctype in ("Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"): + args.transaction_type = "selling" + elif args.doctype in ("Material Request", "Supplier Quotation", "Purchase Order", + "Purchase Receipt", "Purchase Invoice"): + args.transaction_type = "buying" + elif args.customer: + args.transaction_type = "selling" + else: + args.transaction_type = "buying" \ No newline at end of file diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 6edfaffbe4..bdd743125a 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -31,21 +31,22 @@ class TestPricingRule(unittest.TestCase): "company": "_Test Company", "price_list": "_Test Price List", "currency": "_Test Currency", - "parenttype": "Sales Order", + "doctype": "Sales Order", "conversion_rate": 1, "price_list_currency": "_Test Currency", "plc_conversion_rate": 1, "order_type": "Sales", "customer": "_Test Customer", - "doctype": "Sales Order Item", "name": None }) details = get_item_details(args) self.assertEquals(details.get("discount_percentage"), 10) - + prule = frappe.get_doc(test_record.copy()) prule.applicable_for = "Customer" + prule.title = "_Test Pricing Rule for Customer" self.assertRaises(MandatoryError, prule.insert) + prule.customer = "_Test Customer" prule.discount_percentage = 20 prule.insert() @@ -55,16 +56,18 @@ class TestPricingRule(unittest.TestCase): prule = frappe.get_doc(test_record.copy()) prule.apply_on = "Item Group" prule.item_group = "All Item Groups" + prule.title = "_Test Pricing Rule for Item Group" prule.discount_percentage = 15 prule.insert() - - args.customer = None + + args.customer = "_Test Customer 1" details = get_item_details(args) self.assertEquals(details.get("discount_percentage"), 10) prule = frappe.get_doc(test_record.copy()) prule.applicable_for = "Campaign" prule.campaign = "_Test Campaign" + prule.title = "_Test Pricing Rule for Campaign" prule.discount_percentage = 5 prule.priority = 8 prule.insert() diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index c3da6b294c..5c84112df4 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -152,8 +152,8 @@ class AccountsController(TransactionBase): args = parent_dict.copy() args.update(item.as_dict()) - args["doctype"] = parent_dict.get("doctype") - args["name"] = parent_dict.get("name") + args["doctype"] = self.doctype + args["name"] = self.name if not args.get("transaction_date"): args["transaction_date"] = args.get("posting_date") diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 3501f525d8..c6ea618eb0 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -334,15 +334,15 @@ class TestSalesOrder(unittest.TestCase): existing_ordered_qty = bin[0].ordered_qty if bin else 0.0 existing_reserved_qty = bin[0].reserved_qty if bin else 0.0 - bin = frappe.get_all("Bin", filters={"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, - fields=["reserved_qty"]) + bin = frappe.get_all("Bin", filters={"item_code": dn_item.item_code, + "warehouse": "_Test Warehouse - _TC"}, fields=["reserved_qty"]) existing_reserved_qty_for_dn_item = bin[0].reserved_qty if bin else 0.0 #create so, po and partial dn so = make_sales_order(item_list=so_items, do_not_submit=True) so.submit() - + po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier') po.submit() diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 7538260c6e..e5392d451b 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -93,13 +93,14 @@ class TestItem(unittest.TestCase): "price_list_currency": "_Test Currency", "plc_conversion_rate": 1, "order_type": "Sales", + "customer": "_Test Customer" }) for key, value in to_check.iteritems(): self.assertEquals(value, details.get(key)) def test_make_item_variant(self): - frappe.delete_doc_if_exists("Item", "_Test Variant Item-L") + frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1) variant = create_variant("_Test Variant Item", {"Test Size": "Large"}) variant.save() diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 3819337349..cc80d1ee44 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -6,7 +6,7 @@ import frappe from frappe import _, throw from frappe.utils import flt, cint, add_days, cstr import json -from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item +from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type from erpnext.setup.utils import get_exchange_rate from frappe.model.meta import get_field_precision @@ -84,6 +84,8 @@ def process_args(args): args.item_code = get_item_code(barcode=args.barcode) elif not args.item_code and args.serial_no: args.item_code = get_item_code(serial_no=args.serial_no) + + set_transaction_type(args) return args @@ -107,7 +109,7 @@ def validate_item_details(args, item): from erpnext.stock.doctype.item.item import validate_end_of_life validate_end_of_life(item.name, item.end_of_life, item.disabled) - if args.customer or args.doctype=="Opportunity": + if args.transaction_type=="selling": # validate if sales item or service item if args.get("order_type") == "Maintenance": if item.is_service_item != 1: @@ -119,7 +121,7 @@ def validate_item_details(args, item): if cint(item.has_variants): throw(_("Item {0} is a template, please select one of its variants").format(item.name)) - elif args.supplier and args.doctype != "Material Request": + elif args.transaction_type=="buying" and args.doctype != "Material Request": # validate if purchase item or subcontracted item if item.is_purchase_item != 1: throw(_("Item {0} must be a Purchase Item").format(item.name)) @@ -219,7 +221,7 @@ def get_price_list_rate(args, item_doc, out): out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \ / flt(args.conversion_rate) - if not out.price_list_rate and args.supplier: + if not out.price_list_rate and args.transaction_type=="buying": from erpnext.stock.doctype.item.item import get_last_purchase_details out.update(get_last_purchase_details(item_doc.name, args.name, args.conversion_rate)) @@ -251,7 +253,7 @@ def get_price_list_rate_for(price_list, item_code): def validate_price_list(args): if args.get("price_list"): if not frappe.db.get_value("Price List", - {"name": args.price_list, "selling" if (args.customer or args.lead) else "buying": 1, "enabled": 1}): + {"name": args.price_list, args.transaction_type: 1, "enabled": 1}): throw(_("Price List {0} is disabled").format(args.price_list)) else: throw(_("Price List not selected")) @@ -283,10 +285,11 @@ def validate_conversion_rate(args, meta): frappe._dict({"fields": args}))) def get_party_item_code(args, item_doc, out): - if args.customer: + if args.transaction_type=="selling" and args.customer: customer_item_code = item_doc.get("customer_items", {"customer_name": args.customer}) out.customer_item_code = customer_item_code[0].ref_code if customer_item_code else None - else: + + if args.transaction_type=="buying" and args.supplier: item_supplier = item_doc.get("supplier_items", {"supplier": args.supplier}) out.supplier_part_no = item_supplier[0].supplier_part_no if item_supplier else None From 9824e22ce158edb30ed851a12685d8b26ec1fdb6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Jan 2016 16:48:25 +0530 Subject: [PATCH 4/4] [fix] Price list rate applied via set_missing_values --- erpnext/crm/doctype/opportunity/opportunity.py | 3 --- erpnext/selling/doctype/quotation/quotation.js | 3 ++- .../stock/doctype/material_request/material_request.py | 9 ++------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index a21ebdee4b..866b982716 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -9,7 +9,6 @@ from frappe.model.mapper import get_mapped_doc from erpnext.setup.utils import get_exchange_rate from erpnext.utilities.transaction_base import TransactionBase from erpnext.accounts.party import get_party_account_currency -from erpnext.stock.get_item_details import apply_price_list subject_field = "title" sender_field = "contact_email" @@ -193,8 +192,6 @@ def make_quotation(source_name, target_doc=None): quotation.currency = party_account_currency or company_currency quotation.conversion_rate = exchange_rate - quotation.update(apply_price_list(quotation.as_dict(), as_doc = True)) - quotation.run_method("set_missing_values") quotation.run_method("calculate_taxes_and_totals") diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index aad462890c..83cec04635 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -25,7 +25,8 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({ cur_frm.add_custom_button(__('Lost'), cur_frm.cscript['Declare Order Lost'], __("Status")); } - + + cur_frm.page.set_inner_btn_group_as_primary(__("Make")); } if (this.frm.doc.docstatus===0) { diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 19c7415391..74a8fa146c 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -11,7 +11,6 @@ from frappe.utils import cstr, flt, getdate from frappe import _ from frappe.model.mapper import get_mapped_doc from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty -from erpnext.stock.get_item_details import apply_price_list from erpnext.controllers.buying_controller import BuyingController @@ -24,7 +23,7 @@ class MaterialRequest(BuyingController): return _("{0}: {1}").format(self.status, self.material_request_type) def check_if_already_pulled(self): - pass#if self.[d.sales_order_no for d in self.get('items')] + pass def validate_qty_against_so(self): so_items = {} # Format --> {'SO/00001': {'Item/001': 120, 'Item/002': 24}} @@ -183,7 +182,6 @@ def update_item(obj, target, source_parent): @frappe.whitelist() def make_purchase_order(source_name, target_doc=None): def postprocess(source, target_doc): - target_doc.update(apply_price_list(target_doc.as_dict(), as_doc = True)) set_missing_values(source, target_doc) doclist = get_mapped_doc("Material Request", source_name, { @@ -225,9 +223,7 @@ def make_purchase_order_based_on_supplier(source_name, target_doc=None): target_doc.set("items", [d for d in target_doc.get("items") if d.get("item_code") in supplier_items and d.get("qty") > 0]) - - target_doc.update(apply_price_list(target_doc.as_dict(), as_doc = True)) - + set_missing_values(source, target_doc) for mr in material_requests: @@ -271,7 +267,6 @@ def get_material_requests_based_on_supplier(supplier): @frappe.whitelist() def make_supplier_quotation(source_name, target_doc=None): def postprocess(source, target_doc): - target_doc.update(apply_price_list(target_doc.as_dict(), as_doc = True)) set_missing_values(source, target_doc) doclist = get_mapped_doc("Material Request", source_name, {