[Fix] Sales invoice serial no validation issue
This commit is contained in:
parent
2df7db0346
commit
7e14996995
@ -343,13 +343,6 @@ cur_frm.cscript.hide_fields = function(doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
|
|
||||||
'warehouse', 'expense_account', 'quality_inspection']
|
|
||||||
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
|
|
||||||
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
|
|
||||||
|
|
||||||
|
|
||||||
// India related fields
|
// India related fields
|
||||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||||
|
@ -18,6 +18,7 @@ from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timeshe
|
|||||||
from erpnext.accounts.doctype.asset.depreciation \
|
from erpnext.accounts.doctype.asset.depreciation \
|
||||||
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
|
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
|
||||||
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@ -812,9 +813,16 @@ class SalesInvoice(SellingController):
|
|||||||
"""
|
"""
|
||||||
validate serial number agains Delivery Note and Sales Invoice
|
validate serial number agains Delivery Note and Sales Invoice
|
||||||
"""
|
"""
|
||||||
|
self.set_serial_no_against_delivery_note()
|
||||||
self.validate_serial_against_delivery_note()
|
self.validate_serial_against_delivery_note()
|
||||||
self.validate_serial_against_sales_invoice()
|
self.validate_serial_against_sales_invoice()
|
||||||
|
|
||||||
|
def set_serial_no_against_delivery_note(self):
|
||||||
|
for item in self.items:
|
||||||
|
if item.serial_no and item.delivery_note and \
|
||||||
|
item.qty != len(get_serial_nos(item.serial_no)):
|
||||||
|
item.serial_no = get_delivery_note_serial_no(item.item_code, item.qty, item.delivery_note)
|
||||||
|
|
||||||
def validate_serial_against_delivery_note(self):
|
def validate_serial_against_delivery_note(self):
|
||||||
"""
|
"""
|
||||||
validate if the serial numbers in Sales Invoice Items are same as in
|
validate if the serial numbers in Sales Invoice Items are same as in
|
||||||
@ -826,14 +834,18 @@ class SalesInvoice(SellingController):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
|
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
|
||||||
dn_serial_nos = set(serial_nos.split("\n"))
|
dn_serial_nos = set(get_serial_nos(serial_nos))
|
||||||
|
|
||||||
serial_nos = item.serial_no or ""
|
serial_nos = item.serial_no or ""
|
||||||
si_serial_nos = set(serial_nos.split("\n"))
|
si_serial_nos = set(get_serial_nos(serial_nos))
|
||||||
|
|
||||||
if si_serial_nos - dn_serial_nos:
|
if si_serial_nos - dn_serial_nos:
|
||||||
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
||||||
|
|
||||||
|
if item.serial_no and cint(item.qty) != len(si_serial_nos):
|
||||||
|
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.".format(
|
||||||
|
item.idx, item.qty, item.item_code, len(si_serial_nos))))
|
||||||
|
|
||||||
def validate_serial_against_sales_invoice(self):
|
def validate_serial_against_sales_invoice(self):
|
||||||
""" check if serial number is already used in other sales invoice """
|
""" check if serial number is already used in other sales invoice """
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
|
@ -1424,7 +1424,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval: parent.update_stock",
|
"depends_on": "",
|
||||||
"fieldname": "warehouse_and_reference",
|
"fieldname": "warehouse_and_reference",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2166,7 +2166,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-07-06 17:54:03.347700",
|
"modified": "2017-07-17 17:54:48.246507",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Item",
|
"name": "Sales Invoice Item",
|
||||||
|
@ -14,6 +14,7 @@ from erpnext.controllers.selling_controller import SellingController
|
|||||||
from frappe.desk.notifications import clear_doctype_notifications
|
from frappe.desk.notifications import clear_doctype_notifications
|
||||||
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
||||||
from frappe.contacts.doctype.address.address import get_company_address
|
from frappe.contacts.doctype.address.address import get_company_address
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@ -390,6 +391,9 @@ def make_sales_invoice(source_name, target_doc=None):
|
|||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
|
target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
|
||||||
|
if source_doc.serial_no and source_parent.per_billed > 0:
|
||||||
|
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
|
||||||
|
target_doc.qty, source_parent.name)
|
||||||
|
|
||||||
doc = get_mapped_doc("Delivery Note", source_name, {
|
doc = get_mapped_doc("Delivery Note", source_name, {
|
||||||
"Delivery Note": {
|
"Delivery Note": {
|
||||||
|
@ -170,6 +170,10 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
"delivery_document_no": dn.name
|
"delivery_document_no": dn.name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
si = make_sales_invoice(dn.name)
|
||||||
|
si.insert(ignore_permissions=True)
|
||||||
|
self.assertEquals(dn.items[0].serial_no, si.items[0].serial_no)
|
||||||
|
|
||||||
dn.cancel()
|
dn.cancel()
|
||||||
|
|
||||||
self.check_serial_no_values(serial_no, {
|
self.check_serial_no_values(serial_no, {
|
||||||
@ -177,6 +181,22 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
"delivery_document_no": ""
|
"delivery_document_no": ""
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_serialized_partial_sales_invoice(self):
|
||||||
|
se = make_serialized_item()
|
||||||
|
serial_no = get_serial_nos(se.get("items")[0].serial_no)
|
||||||
|
serial_no = '\n'.join(serial_no)
|
||||||
|
|
||||||
|
dn = create_delivery_note(item_code="_Test Serialized Item With Series", qty=2, serial_no=serial_no)
|
||||||
|
|
||||||
|
si = make_sales_invoice(dn.name)
|
||||||
|
si.items[0].qty = 1
|
||||||
|
si.submit()
|
||||||
|
self.assertEquals(si.items[0].qty, 1)
|
||||||
|
|
||||||
|
si = make_sales_invoice(dn.name)
|
||||||
|
si.submit()
|
||||||
|
self.assertEquals(si.items[0].qty, len(get_serial_nos(si.items[0].serial_no)))
|
||||||
|
|
||||||
def test_serialize_status(self):
|
def test_serialize_status(self):
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
serial_no = frappe.get_doc({
|
serial_no = frappe.get_doc({
|
||||||
|
@ -337,3 +337,17 @@ def update_maintenance_status():
|
|||||||
doc = frappe.get_doc("Serial No", serial_no[0])
|
doc = frappe.get_doc("Serial No", serial_no[0])
|
||||||
doc.set_maintenance_status()
|
doc.set_maintenance_status()
|
||||||
frappe.db.set_value('Serial No', doc.name, 'maintenance_status', doc.maintenance_status)
|
frappe.db.set_value('Serial No', doc.name, 'maintenance_status', doc.maintenance_status)
|
||||||
|
|
||||||
|
def get_delivery_note_serial_no(item_code, qty, delivery_note):
|
||||||
|
serial_nos = ''
|
||||||
|
dn_serial_nos = frappe.db.sql_list(""" select name from `tabSerial No`
|
||||||
|
where item_code = %(item_code)s and delivery_document_no = %(delivery_note)s
|
||||||
|
and sales_invoice is null limit {0}""".format(cint(qty)), {
|
||||||
|
'item_code': item_code,
|
||||||
|
'delivery_note': delivery_note
|
||||||
|
})
|
||||||
|
|
||||||
|
if dn_serial_nos and len(dn_serial_nos)>0:
|
||||||
|
serial_nos = '\n'.join(dn_serial_nos)
|
||||||
|
|
||||||
|
return serial_nos
|
Loading…
x
Reference in New Issue
Block a user