diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 03186ff8e18..659054d24ca 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__ = '11.1.31' +__version__ = '11.1.32' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 13fcb0b6212..8ea3a1adac1 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -8,7 +8,9 @@ import frappe.defaults from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from frappe.utils import flt, add_days, nowdate, getdate from erpnext.stock.doctype.item.test_item import make_item -from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt, make_purchase_invoice, make_rm_stock_entry as make_subcontract_transfer_entry) +from erpnext.buying.doctype.purchase_order.purchase_order \ + import (make_purchase_receipt, make_purchase_invoice as make_pi_from_po, make_rm_stock_entry as make_subcontract_transfer_entry) +from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice as make_pi_from_pr from erpnext.stock.doctype.material_request.test_material_request import make_material_request from erpnext.stock.doctype.material_request.material_request import make_purchase_order from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry @@ -62,7 +64,7 @@ class TestPurchaseOrder(unittest.TestCase): frappe.db.set_value('Item', '_Test Item', 'tolerance', 50) - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) pi.update_stock = 1 pi.items[0].qty = 12 pi.insert() @@ -89,7 +91,7 @@ class TestPurchaseOrder(unittest.TestCase): create_pr_against_po(po.name) - make_purchase_invoice(po.name) + make_pi_from_po(po.name) existing_ordered_qty = get_ordered_qty() existing_requested_qty = get_requested_qty() @@ -111,29 +113,37 @@ class TestPurchaseOrder(unittest.TestCase): def test_update_qty(self): po = create_purchase_order() - make_pr_against_po(po.name, 6) + pr = make_pr_against_po(po.name, 2) po.load_from_db() - self.assertEqual(po.get("items")[0].received_qty, 6) + self.assertEqual(po.get("items")[0].received_qty, 2) - # Check received_qty after make_purchase_invoice without update_stock checked - pi1 = make_purchase_invoice(po.name) - pi1.get("items")[0].qty = 6 + # Check received_qty after making PI from PR without update_stock checked + pi1 = make_pi_from_pr(pr.name) + pi1.get("items")[0].qty = 2 pi1.insert() pi1.submit() po.load_from_db() - self.assertEqual(po.get("items")[0].received_qty, 6) + self.assertEqual(po.get("items")[0].received_qty, 2) - # Check received_qty after make_purchase_invoice with update_stock checked - pi2 = make_purchase_invoice(po.name) + # Check received_qty after making PI from PO with update_stock checked + pi2 = make_pi_from_po(po.name) pi2.set("update_stock", 1) pi2.get("items")[0].qty = 3 pi2.insert() pi2.submit() po.load_from_db() - self.assertEqual(po.get("items")[0].received_qty, 9) + self.assertEqual(po.get("items")[0].received_qty, 5) + + # Check received_qty after making PR from PO + pr = make_pr_against_po(po.name, 1) + + po.load_from_db() + self.assertEqual(po.get("items")[0].received_qty, 6) + + def test_return_against_purchase_order(self): po = create_purchase_order() @@ -143,7 +153,7 @@ class TestPurchaseOrder(unittest.TestCase): po.load_from_db() self.assertEqual(po.get("items")[0].received_qty, 6) - pi2 = make_purchase_invoice(po.name) + pi2 = make_pi_from_po(po.name) pi2.set("update_stock", 1) pi2.get("items")[0].qty = 3 pi2.insert() @@ -175,10 +185,10 @@ class TestPurchaseOrder(unittest.TestCase): def test_make_purchase_invoice(self): po = create_purchase_order(do_not_submit=True) - self.assertRaises(frappe.ValidationError, make_purchase_invoice, po.name) + self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name) po.submit() - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) self.assertEqual(pi.doctype, "Purchase Invoice") self.assertEqual(len(pi.get("items", [])), 1) @@ -186,7 +196,7 @@ class TestPurchaseOrder(unittest.TestCase): def test_make_purchase_invoice_with_terms(self): po = create_purchase_order(do_not_save=True) - self.assertRaises(frappe.ValidationError, make_purchase_invoice, po.name) + self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name) po.update( {"payment_terms_template": "_Test Payment Term Template"} @@ -199,7 +209,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEqual(getdate(po.payment_schedule[0].due_date), getdate(po.transaction_date)) self.assertEqual(po.payment_schedule[1].payment_amount, 2500.0) self.assertEqual(getdate(po.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30)) - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) pi.save() self.assertEqual(pi.doctype, "Purchase Invoice") @@ -337,7 +347,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertTrue(po.get('payment_schedule')) - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) self.assertFalse(pi.get('payment_schedule')) @@ -348,7 +358,7 @@ class TestPurchaseOrder(unittest.TestCase): po.submit() self.assertTrue(po.get('payment_schedule')) - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) pi.insert() self.assertTrue(pi.get('payment_schedule')) @@ -428,7 +438,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6) # Make Purchase Invoice - pi = make_purchase_invoice(po.name) + pi = make_pi_from_po(po.name) pi.update_stock = 1 pi.supplier_warehouse = "_Test Warehouse 1 - _TC" pi.insert() diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index b7d2bad17ab..cb505189bdc 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -34,8 +34,8 @@ status_map = { ], "Sales Order": [ ["Draft", None], - ["To Deliver and Bill", "eval:self.per_delivered < 100 and self.per_billed < 100 and self.docstatus == 1 and self.order_type in ['Sales', 'Shopping Cart']"], - ["To Bill", "eval:self.per_delivered == 100 or self.order_type == 'Maintenance' and self.per_billed < 100 and self.docstatus == 1"], + ["To Deliver and Bill", "eval:self.per_delivered < 100 and self.per_billed < 100 and self.docstatus == 1"], + ["To Bill", "eval:self.per_delivered == 100 and self.per_billed < 100 and self.docstatus == 1"], ["To Deliver", "eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1"], ["Completed", "eval:self.per_delivered == 100 and self.per_billed == 100 and self.docstatus == 1"], ["Completed", "eval:self.order_type == 'Maintenance' and self.per_billed == 100 and self.docstatus == 1"], diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index 5fae858efeb..8818935e39e 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -75,12 +75,13 @@ def prepare_invoice(invoice, progressive_number): invoice.tax_data = tax_data #Check if stamp duty (Bollo) of 2 EUR exists. - stamp_duty_charge_row = next((tax for tax in invoice.taxes if tax.charge_type == _("Actual") and tax.tax_amount == 2.0 ), None) + stamp_duty_charge_row = next((tax for tax in invoice.taxes if tax.charge_type == "Actual" and tax.tax_amount == 2.0 ), None) if stamp_duty_charge_row: invoice.stamp_duty = stamp_duty_charge_row.tax_amount for item in invoice.e_invoice_items: - if item.tax_rate == 0.0 and item.tax_amount == 0.0: + if (item.tax_rate == 0.0 and item.tax_amount == 0.0 + and item.charge_type != 'Actual' and tax_data.get("0.0")): item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"] customer_po_data = {} @@ -222,7 +223,7 @@ def sales_invoice_validate(doc): #Validate customer details customer = frappe.get_doc("Customer", doc.customer) - if customer.customer_type == _("Individual"): + if customer.customer_type == "Individual": doc.customer_fiscal_code = customer.fiscal_code if not doc.customer_fiscal_code: frappe.throw(_("Please set Fiscal Code for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing")) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 8532a9433b1..6cdb4f88840 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -140,12 +140,15 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } // delivery note - if(flt(doc.per_delivered, 6) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) { + if(flt(doc.per_delivered, 6) < 100 && allow_delivery) { this.frm.add_custom_button(__('Delivery'), function() { me.make_delivery_note_based_on_delivery_date(); }, __("Make")); - this.frm.add_custom_button(__('Work Order'), - function() { me.make_work_order() }, __("Make")); + if(["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1){ + this.frm.add_custom_button(__('Work Order'), + function() { me.make_work_order() }, __("Make")); + + } this.frm.page.set_inner_btn_group_as_primary(__("Make")); } diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 69c2100862a..ea53f939c62 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -31,17 +31,25 @@ frappe.listview_settings['Sales Order'] = { "per_delivered,<,100|per_billed,=,100|status,!=,Closed"]; } - } else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 6) == 100) + } else if ((flt(doc.per_delivered, 6) == 100) && flt(doc.grand_total) !== 0 && flt(doc.per_billed, 6) < 100 && doc.status !== "Closed") { // to bill return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Closed"]; - } else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 6) == 100) + } else if ((flt(doc.per_delivered, 6) === 100) && (flt(doc.grand_total) === 0 || flt(doc.per_billed, 6) == 100) && doc.status !== "Closed") { - return [__("Completed"), "green", "per_delivered,=,100|per_billed,=,100|status,!=,Closed"]; + + }else if (doc.order_type === "Maintenance" && flt(doc.per_delivered, 6) < 100 && doc.status !== "Closed"){ + + if(flt(doc.per_billed, 6) < 100 ){ + return [__("To Deliver and Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Closed"]; + }else if(flt(doc.per_billed, 6) == 100){ + return [__("To Deliver"), "orange", "per_delivered,=,100|per_billed,=,100|status,!=,Closed"]; + } } + }, onload: function(listview) { var method = "erpnext.selling.doctype.sales_order.sales_order.close_or_unclose_sales_orders"; diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 7e5f80e858f..5b8be0ceba3 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -3127,7 +3127,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2019-05-12 15:26:11.503507", + "modified": "2019-05-21 15:26:11.503507", "modified_by": "Administrator", "module": "Setup", "name": "Company", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 24a71128465..23f7ed1889d 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -64,7 +64,10 @@ class DeliveryNote(SellingController): 'second_source_dt': 'Sales Invoice Item', 'second_source_field': '-1 * qty', 'second_join_field': 'so_detail', - 'extra_cond': """ and exists (select name from `tabDelivery Note` where name=`tabDelivery Note Item`.parent and is_return=1)""" + 'extra_cond': """ and exists (select name from `tabDelivery Note` + where name=`tabDelivery Note Item`.parent and is_return=1)""", + 'second_source_extra_cond': """ and exists (select name from `tabSales Invoice` + where name=`tabSales Invoice Item`.parent and is_return=1 and update_stock=1)""" }) def before_print(self): diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 47d61f847f1..44b711b865e 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -231,6 +231,8 @@ def update_completed_and_requested_qty(stock_entry, method): mr_obj.update_requested_qty(mr_item_rows) def set_missing_values(source, target_doc): + if target_doc.doctype == "Purchase Order" and getdate(target_doc.schedule_date) < getdate(nowdate()): + target_doc.schedule_date = None target_doc.run_method("set_missing_values") target_doc.run_method("calculate_taxes_and_totals") @@ -238,6 +240,8 @@ def update_item(obj, target, source_parent): target.conversion_factor = obj.conversion_factor target.qty = flt(flt(obj.stock_qty) - flt(obj.ordered_qty))/ target.conversion_factor target.stock_qty = (target.qty * target.conversion_factor) + if getdate(target.schedule_date) < getdate(nowdate()): + target.schedule_date = None @frappe.whitelist() def update_status(name, status): @@ -322,7 +326,8 @@ def make_purchase_order_based_on_supplier(source_name, target_doc=None): def postprocess(source, target_doc): target_doc.supplier = source_name - target_doc.schedule_date = add_days(nowdate(), 1) + if getdate(target_doc.schedule_date) < getdate(nowdate()): + target_doc.schedule_date = 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]) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 378f1f6187a..5c1f573c457 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -36,7 +36,9 @@ class PurchaseReceipt(BuyingController): 'second_source_field': 'received_qty', 'second_join_field': 'po_detail', 'percent_join_field': 'purchase_order', - 'overflow_type': 'receipt' + 'overflow_type': 'receipt', + 'second_source_extra_cond': """ and exists(select name from `tabPurchase Invoice` + where name=`tabPurchase Invoice Item`.parent and update_stock = 1)""" }] if cint(self.is_return): self.status_updater.append({ @@ -48,7 +50,10 @@ class PurchaseReceipt(BuyingController): 'second_source_dt': 'Purchase Invoice Item', 'second_source_field': '-1 * qty', 'second_join_field': 'po_detail', - 'extra_cond': """ and exists (select name from `tabPurchase Receipt` where name=`tabPurchase Receipt Item`.parent and is_return=1)""" + 'extra_cond': """ and exists (select name from `tabPurchase Receipt` + where name=`tabPurchase Receipt Item`.parent and is_return=1)""", + 'second_source_extra_cond': """ and exists (select name from `tabPurchase Invoice` + where name=`tabPurchase Invoice Item`.parent and is_return=1 and update_stock=1)""" }) def validate(self):