[Fix] Sales invoice serial no validation issue

This commit is contained in:
Rohit Waghchaure 2017-07-17 19:00:18 +05:30
parent 2df7db0346
commit 7e14996995
6 changed files with 54 additions and 11 deletions

View File

@ -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']);

View File

@ -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:

View File

@ -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",

View File

@ -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": {

View File

@ -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({

View File

@ -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