Merge pull request #2275 from ankitjavalkarwork/fix2164
Add Delivery Qty to Sales Invoice From Delivery Note, Misc fixes
This commit is contained in:
commit
30a0e3e8b4
@ -131,8 +131,10 @@ class SalesInvoice(SellingController):
|
|||||||
'keyword':'Delivered',
|
'keyword':'Delivered',
|
||||||
'second_source_dt': 'Delivery Note Item',
|
'second_source_dt': 'Delivery Note Item',
|
||||||
'second_source_field': 'qty',
|
'second_source_field': 'qty',
|
||||||
'second_join_field': 'prevdoc_detail_docname',
|
'second_join_field': 'so_detail',
|
||||||
'overflow_type': 'delivery'
|
'overflow_type': 'delivery',
|
||||||
|
'extra_cond': """ and exists(select name from `tabSales Invoice`
|
||||||
|
where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)"""
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_portal_page(self):
|
def get_portal_page(self):
|
||||||
@ -627,9 +629,11 @@ def make_delivery_note(source_name, target_doc=None):
|
|||||||
"Sales Invoice Item": {
|
"Sales Invoice Item": {
|
||||||
"doctype": "Delivery Note Item",
|
"doctype": "Delivery Note Item",
|
||||||
"field_map": {
|
"field_map": {
|
||||||
"name": "prevdoc_detail_docname",
|
"name": "si_detail",
|
||||||
"parent": "against_sales_invoice",
|
"parent": "against_sales_invoice",
|
||||||
"serial_no": "serial_no"
|
"serial_no": "serial_no",
|
||||||
|
"sales_order": "against_sales_order",
|
||||||
|
"so_detail": "so_detail"
|
||||||
},
|
},
|
||||||
"postprocess": update_item
|
"postprocess": update_item
|
||||||
},
|
},
|
||||||
|
@ -334,8 +334,8 @@ class SellingController(StockController):
|
|||||||
# But in this case reserved qty should only be reduced by 10 and not 12
|
# But in this case reserved qty should only be reduced by 10 and not 12
|
||||||
|
|
||||||
already_delivered_qty = self.get_already_delivered_qty(self.name,
|
already_delivered_qty = self.get_already_delivered_qty(self.name,
|
||||||
d.against_sales_order, d.prevdoc_detail_docname)
|
d.against_sales_order, d.so_detail)
|
||||||
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
|
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.so_detail)
|
||||||
|
|
||||||
if already_delivered_qty + d.qty > so_qty:
|
if already_delivered_qty + d.qty > so_qty:
|
||||||
reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
|
reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
|
||||||
@ -377,7 +377,7 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
def get_already_delivered_qty(self, dn, so, so_detail):
|
def get_already_delivered_qty(self, dn, so, so_detail):
|
||||||
qty = frappe.db.sql("""select sum(qty) from `tabDelivery Note Item`
|
qty = frappe.db.sql("""select sum(qty) from `tabDelivery Note Item`
|
||||||
where prevdoc_detail_docname = %s and docstatus = 1
|
where so_detail = %s and docstatus = 1
|
||||||
and against_sales_order = %s
|
and against_sales_order = %s
|
||||||
and parent != %s""", (so_detail, so, dn))
|
and parent != %s""", (so_detail, so, dn))
|
||||||
return qty and flt(qty[0][0]) or 0.0
|
return qty and flt(qty[0][0]) or 0.0
|
||||||
|
@ -153,16 +153,21 @@ class StatusUpdater(Document):
|
|||||||
args['second_source_condition'] = ""
|
args['second_source_condition'] = ""
|
||||||
if args.get('second_source_dt') and args.get('second_source_field') \
|
if args.get('second_source_dt') and args.get('second_source_field') \
|
||||||
and args.get('second_join_field'):
|
and args.get('second_join_field'):
|
||||||
|
if not args.get("second_source_extra_cond"):
|
||||||
|
args["second_source_extra_cond"] = ""
|
||||||
|
|
||||||
args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
|
args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
|
||||||
from `tab%(second_source_dt)s`
|
from `tab%(second_source_dt)s`
|
||||||
where `%(second_join_field)s`="%(detail_id)s"
|
where `%(second_join_field)s`="%(detail_id)s"
|
||||||
and (docstatus=1)), 0)""" % args
|
and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args
|
||||||
|
|
||||||
if args['detail_id']:
|
if args['detail_id']:
|
||||||
|
if not args.get("extra_cond"): args["extra_cond"] = ""
|
||||||
|
|
||||||
frappe.db.sql("""update `tab%(target_dt)s`
|
frappe.db.sql("""update `tab%(target_dt)s`
|
||||||
set %(target_field)s = (select sum(%(source_field)s)
|
set %(target_field)s = (select sum(%(source_field)s)
|
||||||
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
||||||
and (docstatus=1 %(cond)s)) %(second_source_condition)s
|
and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
|
||||||
where name='%(detail_id)s'""" % args)
|
where name='%(detail_id)s'""" % args)
|
||||||
|
|
||||||
# get unique transactions to update
|
# get unique transactions to update
|
||||||
@ -171,12 +176,13 @@ class StatusUpdater(Document):
|
|||||||
args['name'] = name
|
args['name'] = name
|
||||||
|
|
||||||
# update percent complete in the parent table
|
# update percent complete in the parent table
|
||||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
if args.get('target_parent_field'):
|
||||||
set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
|
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||||
ifnull(%(target_field)s, 0), %(target_field)s,
|
set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
|
||||||
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
|
ifnull(%(target_field)s, 0), %(target_field)s,
|
||||||
from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
|
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
|
||||||
where name='%(name)s'""" % args)
|
from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
|
||||||
|
where name='%(name)s'""" % args)
|
||||||
|
|
||||||
# update field
|
# update field
|
||||||
if args.get('status_field'):
|
if args.get('status_field'):
|
||||||
|
@ -84,3 +84,4 @@ erpnext.patches.v4_2.cost_of_production_cycle
|
|||||||
erpnext.patches.v4_2.seprate_manufacture_and_repack
|
erpnext.patches.v4_2.seprate_manufacture_and_repack
|
||||||
erpnext.patches.v4_2.party_model
|
erpnext.patches.v4_2.party_model
|
||||||
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
||||||
|
erpnext.patches.v5_0.update_dn_against_doc_fields
|
||||||
|
13
erpnext/patches/v5_0/update_dn_against_doc_fields.py
Normal file
13
erpnext/patches/v5_0/update_dn_against_doc_fields.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc('stock', 'doctype', 'delivery_note_item')
|
||||||
|
|
||||||
|
frappe.db.sql("""update `tabDelivery Note Item` set so_detail = prevdoc_detail_docname
|
||||||
|
where ifnull(against_sales_order, '') != ''""")
|
||||||
|
|
||||||
|
frappe.db.sql("""update `tabDelivery Note Item` set si_detail = prevdoc_detail_docname
|
||||||
|
where ifnull(against_sales_invoice, '') != ''""")
|
@ -294,7 +294,7 @@ def make_delivery_note(source_name, target_doc=None):
|
|||||||
"doctype": "Delivery Note Item",
|
"doctype": "Delivery Note Item",
|
||||||
"field_map": {
|
"field_map": {
|
||||||
"rate": "rate",
|
"rate": "rate",
|
||||||
"name": "prevdoc_detail_docname",
|
"name": "so_detail",
|
||||||
"parent": "against_sales_order",
|
"parent": "against_sales_order",
|
||||||
},
|
},
|
||||||
"postprocess": update_item,
|
"postprocess": update_item,
|
||||||
|
@ -34,12 +34,10 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
self.assertRaises(frappe.ValidationError, make_delivery_note,
|
self.assertRaises(frappe.ValidationError, make_delivery_note,
|
||||||
so.name)
|
so.name)
|
||||||
|
|
||||||
sales_order = frappe.get_doc("Sales Order", so.name)
|
dn = self.make_next_doc_testcase(so, "Delivery Note")
|
||||||
sales_order.submit()
|
|
||||||
dn = make_delivery_note(so.name)
|
|
||||||
|
|
||||||
self.assertEquals(dn.doctype, "Delivery Note")
|
self.assertEquals(dn.doctype, "Delivery Note")
|
||||||
self.assertEquals(len(dn.get("delivery_note_details")), len(sales_order.get("sales_order_details")))
|
self.assertEquals(len(dn.get("delivery_note_details")), len(so.get("sales_order_details")))
|
||||||
|
|
||||||
def test_make_sales_invoice(self):
|
def test_make_sales_invoice(self):
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||||
@ -49,22 +47,77 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
self.assertRaises(frappe.ValidationError, make_sales_invoice,
|
self.assertRaises(frappe.ValidationError, make_sales_invoice,
|
||||||
so.name)
|
so.name)
|
||||||
|
|
||||||
sales_order = frappe.get_doc("Sales Order", so.name)
|
si = self.make_next_doc_testcase(so, "Sales Invoice")
|
||||||
sales_order.submit()
|
|
||||||
si = make_sales_invoice(so.name)
|
|
||||||
|
|
||||||
self.assertEquals(si.doctype, "Sales Invoice")
|
self.assertEquals(si.doctype, "Sales Invoice")
|
||||||
self.assertEquals(len(si.get("entries")), len(sales_order.get("sales_order_details")))
|
self.assertEquals(len(si.get("entries")), len(so.get("sales_order_details")))
|
||||||
self.assertEquals(len(si.get("entries")), 1)
|
self.assertEquals(len(si.get("entries")), 1)
|
||||||
|
|
||||||
si.debit_to = "_Test Receivable - _TC"
|
si.set("debit_to", "_Test Receivable - _TC")
|
||||||
si.posting_date = "2013-10-10"
|
si.set("posting_date", "2013-10-10")
|
||||||
si.insert()
|
si.insert()
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
si1 = make_sales_invoice(so.name)
|
si1 = self.make_next_doc_testcase(so, "Sales Invoice")
|
||||||
self.assertEquals(len(si1.get("entries")), 0)
|
self.assertEquals(len(si1.get("entries")), 0)
|
||||||
|
|
||||||
|
def test_update_qty(self):
|
||||||
|
so = frappe.copy_doc(test_records[0]).insert()
|
||||||
|
|
||||||
|
dn = self.make_next_doc_testcase(so, "Delivery Note")
|
||||||
|
|
||||||
|
dn.get("delivery_note_details")[0].qty = 6
|
||||||
|
dn.posting_date = "2013-10-10"
|
||||||
|
dn.insert()
|
||||||
|
|
||||||
|
delivery_note = frappe.get_doc("Delivery Note", dn.name)
|
||||||
|
delivery_note.submit()
|
||||||
|
|
||||||
|
sales_order = frappe.get_doc("Sales Order", so.name)
|
||||||
|
|
||||||
|
self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 6)
|
||||||
|
|
||||||
|
#Check delivered_qty after make_sales_invoice without update_stock checked
|
||||||
|
si1 = self.make_next_doc_testcase(sales_order, "Sales Invoice")
|
||||||
|
|
||||||
|
si1.set("debit_to", "_Test Receivable - _TC")
|
||||||
|
si1.set("posting_date", "2013-10-10")
|
||||||
|
si1.get("entries")[0].qty = 1
|
||||||
|
si1.insert()
|
||||||
|
si1.submit()
|
||||||
|
|
||||||
|
sales_order = frappe.get_doc("Sales Order", sales_order.name)
|
||||||
|
|
||||||
|
self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 6)
|
||||||
|
|
||||||
|
#Check delivered_qty after make_sales_invoice with update_stock checked
|
||||||
|
si2 = self.make_next_doc_testcase(sales_order, "Sales Invoice")
|
||||||
|
|
||||||
|
si2.set("debit_to", "_Test Receivable - _TC")
|
||||||
|
si2.set("posting_date", "2013-10-10")
|
||||||
|
si2.set("update_stock", 1)
|
||||||
|
si2.get("entries")[0].qty = 3
|
||||||
|
si2.insert()
|
||||||
|
si2.submit()
|
||||||
|
|
||||||
|
sales_order = frappe.get_doc("Sales Order", sales_order.name)
|
||||||
|
|
||||||
|
self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 9)
|
||||||
|
|
||||||
|
def make_next_doc_testcase(self, so, next_doc = None):
|
||||||
|
|
||||||
|
if so.docstatus < 1:
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
if next_doc == "Delivery Note":
|
||||||
|
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
||||||
|
next_doc = make_delivery_note(so.name)
|
||||||
|
|
||||||
|
if next_doc == "Sales Invoice":
|
||||||
|
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||||
|
next_doc = make_sales_invoice(so.name)
|
||||||
|
|
||||||
|
return next_doc
|
||||||
|
|
||||||
def create_so(self, so_doc = None):
|
def create_so(self, so_doc = None):
|
||||||
if not so_doc:
|
if not so_doc:
|
||||||
@ -85,7 +138,7 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0]))
|
dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0]))
|
||||||
dn.get("delivery_note_details")[0].item_code = so.get("sales_order_details")[0].item_code
|
dn.get("delivery_note_details")[0].item_code = so.get("sales_order_details")[0].item_code
|
||||||
dn.get("delivery_note_details")[0].against_sales_order = so.name
|
dn.get("delivery_note_details")[0].against_sales_order = so.name
|
||||||
dn.get("delivery_note_details")[0].prevdoc_detail_docname = so.get("sales_order_details")[0].name
|
dn.get("delivery_note_details")[0].so_detail = so.get("sales_order_details")[0].name
|
||||||
if delivered_qty:
|
if delivered_qty:
|
||||||
dn.get("delivery_note_details")[0].qty = delivered_qty
|
dn.get("delivery_note_details")[0].qty = delivered_qty
|
||||||
dn.insert()
|
dn.insert()
|
||||||
|
@ -25,7 +25,7 @@ class DeliveryNote(SellingController):
|
|||||||
self.status_updater = [{
|
self.status_updater = [{
|
||||||
'source_dt': 'Delivery Note Item',
|
'source_dt': 'Delivery Note Item',
|
||||||
'target_dt': 'Sales Order Item',
|
'target_dt': 'Sales Order Item',
|
||||||
'join_field': 'prevdoc_detail_docname',
|
'join_field': 'so_detail',
|
||||||
'target_field': 'delivered_qty',
|
'target_field': 'delivered_qty',
|
||||||
'target_parent_dt': 'Sales Order',
|
'target_parent_dt': 'Sales Order',
|
||||||
'target_parent_field': 'per_delivered',
|
'target_parent_field': 'per_delivered',
|
||||||
@ -34,6 +34,22 @@ class DeliveryNote(SellingController):
|
|||||||
'percent_join_field': 'against_sales_order',
|
'percent_join_field': 'against_sales_order',
|
||||||
'status_field': 'delivery_status',
|
'status_field': 'delivery_status',
|
||||||
'keyword': 'Delivered',
|
'keyword': 'Delivered',
|
||||||
|
'second_source_dt': 'Sales Invoice Item',
|
||||||
|
'second_source_field': 'qty',
|
||||||
|
'second_join_field': 'so_detail',
|
||||||
|
'overflow_type': 'delivery',
|
||||||
|
'second_source_extra_cond': """ and exists(select name from `tabSales Invoice`
|
||||||
|
where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)"""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'source_dt': 'Delivery Note Item',
|
||||||
|
'target_dt': 'Sales Invoice Item',
|
||||||
|
'join_field': 'si_detail',
|
||||||
|
'target_field': 'delivered_qty',
|
||||||
|
'target_parent_dt': 'Sales Invoice',
|
||||||
|
'target_ref_field': 'qty',
|
||||||
|
'source_field': 'qty',
|
||||||
|
'percent_join_field': 'against_sales_invoice',
|
||||||
'overflow_type': 'delivery'
|
'overflow_type': 'delivery'
|
||||||
}]
|
}]
|
||||||
|
|
||||||
@ -113,7 +129,7 @@ class DeliveryNote(SellingController):
|
|||||||
if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
|
if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
|
||||||
super(DeliveryNote, self).validate_with_previous_doc(self.tname, {
|
super(DeliveryNote, self).validate_with_previous_doc(self.tname, {
|
||||||
fn[0] + " Item": {
|
fn[0] + " Item": {
|
||||||
"ref_dn_field": "prevdoc_detail_docname",
|
"ref_dn_field": "so_detail",
|
||||||
"compare_fields": [["rate", "="]],
|
"compare_fields": [["rate", "="]],
|
||||||
"is_child_table": True
|
"is_child_table": True
|
||||||
}
|
}
|
||||||
@ -312,7 +328,7 @@ def make_sales_invoice(source_name, target_doc=None):
|
|||||||
"field_map": {
|
"field_map": {
|
||||||
"name": "dn_detail",
|
"name": "dn_detail",
|
||||||
"parent": "delivery_note",
|
"parent": "delivery_note",
|
||||||
"prevdoc_detail_docname": "so_detail",
|
"so_detail": "so_detail",
|
||||||
"against_sales_order": "sales_order",
|
"against_sales_order": "sales_order",
|
||||||
"serial_no": "serial_no"
|
"serial_no": "serial_no"
|
||||||
},
|
},
|
||||||
|
@ -373,11 +373,11 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "prevdoc_detail_docname",
|
"fieldname": "so_detail",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"in_filter": 1,
|
"in_filter": 1,
|
||||||
"label": "Against Document Detail No",
|
"label": "Against Sales Order Item",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "prevdoc_detail_docname",
|
"oldfieldname": "prevdoc_detail_docname",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
@ -388,6 +388,18 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"width": "150px"
|
"width": "150px"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "si_detail",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"in_filter": 1,
|
||||||
|
"label": "Against Sales Invoice Item",
|
||||||
|
"no_copy": 1,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "installed_qty",
|
"fieldname": "installed_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
@ -426,7 +438,7 @@
|
|||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-09-09 05:35:37.460939",
|
"modified": "2014-10-08 11:11:59.411329",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note Item",
|
"name": "Delivery Note Item",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user