Merge branch 'develop' into pick-list-enhance
This commit is contained in:
commit
36459c052f
@ -193,7 +193,7 @@ def get_dimension_with_children(doctype, dimension):
|
|||||||
|
|
||||||
all_dimensions = []
|
all_dimensions = []
|
||||||
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
||||||
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
|
||||||
all_dimensions += [c.name for c in children]
|
all_dimensions += [c.name for c in children]
|
||||||
|
|
||||||
return all_dimensions
|
return all_dimensions
|
||||||
|
@ -434,7 +434,9 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
|
else:
|
||||||
|
additional_conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
|
||||||
|
|
||||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||||
|
|
||||||
|
@ -202,7 +202,9 @@ def get_conditions(filters):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
|
else:
|
||||||
|
conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
|
||||||
|
|
||||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||||
|
|
||||||
|
@ -344,16 +344,19 @@ def get_conditions(filters):
|
|||||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||||
|
|
||||||
if accounting_dimensions:
|
if accounting_dimensions:
|
||||||
|
common_condition = """
|
||||||
|
and exists(select name from `tabSales Invoice Item`
|
||||||
|
where parent=`tabSales Invoice`.name
|
||||||
|
"""
|
||||||
for dimension in accounting_dimensions:
|
for dimension in accounting_dimensions:
|
||||||
if filters.get(dimension.fieldname):
|
if filters.get(dimension.fieldname):
|
||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
|
|
||||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname)
|
||||||
where parent=`tabSales Invoice`.name
|
else:
|
||||||
and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname)
|
conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in (%({0})s))".format(dimension.fieldname)
|
||||||
|
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
@ -126,7 +126,9 @@ def get_rootwise_opening_balances(filters, report_type):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
|
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
|
||||||
|
else:
|
||||||
|
additional_conditions += "and {0} in (%({0})s)".format(dimension.fieldname)
|
||||||
|
|
||||||
query_filters.update({
|
query_filters.update({
|
||||||
dimension.fieldname: filters.get(dimension.fieldname)
|
dimension.fieldname: filters.get(dimension.fieldname)
|
||||||
|
@ -662,4 +662,6 @@ erpnext.patches.v12_0.create_irs_1099_field_united_states
|
|||||||
erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
|
erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
|
||||||
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
||||||
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
||||||
|
erpnext.patches.v12_0.recalculate_requested_qty_in_bin
|
||||||
|
erpnext.patches.v12_0.set_total_batch_quantity
|
||||||
erpnext.patches.v12_0.set_updated_purpose_in_pick_list
|
erpnext.patches.v12_0.set_updated_purpose_in_pick_list
|
||||||
|
13
erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
Normal file
13
erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
bin_details = frappe.db.sql("""
|
||||||
|
SELECT item_code, warehouse
|
||||||
|
FROM `tabBin`""",as_dict=1)
|
||||||
|
|
||||||
|
for entry in bin_details:
|
||||||
|
update_bin_qty(entry.get("item_code"), entry.get("warehouse"), {
|
||||||
|
"indented_qty": get_indented_qty(entry.get("item_code"), entry.get("warehouse"))
|
||||||
|
})
|
11
erpnext/patches/v12_0/set_total_batch_quantity.py
Normal file
11
erpnext/patches/v12_0/set_total_batch_quantity.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("stock", "doctype", "batch")
|
||||||
|
|
||||||
|
for batch in frappe.get_all("Batch", fields=["name", "batch_id"]):
|
||||||
|
batch_qty = frappe.db.get_value("Stock Ledger Entry",
|
||||||
|
{"docstatus": 1, "batch_no": batch.batch_id, "is_cancelled": "No"},
|
||||||
|
"sum(actual_qty)") or 0.0
|
||||||
|
frappe.db.set_value("Batch", batch.name, "batch_qty", batch_qty, update_modified=False)
|
@ -473,6 +473,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
item_code: item.item_code,
|
item_code: item.item_code,
|
||||||
barcode: item.barcode,
|
barcode: item.barcode,
|
||||||
serial_no: item.serial_no,
|
serial_no: item.serial_no,
|
||||||
|
batch_no: item.batch_no,
|
||||||
set_warehouse: me.frm.doc.set_warehouse,
|
set_warehouse: me.frm.doc.set_warehouse,
|
||||||
warehouse: item.warehouse,
|
warehouse: item.warehouse,
|
||||||
customer: me.frm.doc.customer || me.frm.doc.party_name,
|
customer: me.frm.doc.customer || me.frm.doc.party_name,
|
||||||
@ -637,6 +638,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
// Add the new list to the serial no. field in grid with each in new line
|
// Add the new list to the serial no. field in grid with each in new line
|
||||||
item.serial_no = valid_serial_nos.join('\n');
|
item.serial_no = valid_serial_nos.join('\n');
|
||||||
|
item.conversion_factor = item.conversion_factor || 1;
|
||||||
|
|
||||||
refresh_field("serial_no", item.name, item.parentfield);
|
refresh_field("serial_no", item.name, item.parentfield);
|
||||||
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
||||||
|
@ -1,554 +1,194 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "field:batch_id",
|
"autoname": "field:batch_id",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2013-03-05 14:50:38",
|
"creation": "2013-03-05 14:50:38",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 0,
|
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"sb_disabled",
|
||||||
|
"disabled",
|
||||||
|
"sb_batch",
|
||||||
|
"batch_id",
|
||||||
|
"item",
|
||||||
|
"item_name",
|
||||||
|
"image",
|
||||||
|
"parent_batch",
|
||||||
|
"manufacturing_date",
|
||||||
|
"column_break_3",
|
||||||
|
"batch_qty",
|
||||||
|
"stock_uom",
|
||||||
|
"expiry_date",
|
||||||
|
"source",
|
||||||
|
"supplier",
|
||||||
|
"column_break_9",
|
||||||
|
"reference_doctype",
|
||||||
|
"reference_name",
|
||||||
|
"section_break_7",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "disabled",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Check",
|
||||||
"bold": 0,
|
"label": "Disabled"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
{
|
||||||
"depends_on": "eval:doc.__islocal",
|
"depends_on": "eval:doc.__islocal",
|
||||||
"fieldname": "batch_id",
|
"fieldname": "batch_id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Batch ID",
|
"label": "Batch ID",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "batch_id",
|
"oldfieldname": "batch_id",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "item",
|
"fieldname": "item",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Item",
|
"label": "Item",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "item",
|
"oldfieldname": "item",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Item",
|
"options": "Item",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "image",
|
"fieldname": "image",
|
||||||
"fieldtype": "Attach Image",
|
"fieldtype": "Attach Image",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
"label": "image"
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "image",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.parent_batch",
|
"depends_on": "eval:doc.parent_batch",
|
||||||
"fieldname": "parent_batch",
|
"fieldname": "parent_batch",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Parent Batch",
|
"label": "Parent Batch",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Batch",
|
"options": "Batch",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "disabled",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Disabled",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Today",
|
"default": "Today",
|
||||||
"fieldname": "manufacturing_date",
|
"fieldname": "manufacturing_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"label": "Manufacturing Date"
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
{
|
||||||
"in_filter": 0,
|
"fieldname": "column_break_3",
|
||||||
"in_global_search": 0,
|
"fieldtype": "Column Break"
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Manufacturing Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "expiry_date",
|
"fieldname": "expiry_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Expiry Date",
|
"label": "Expiry Date",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "expiry_date",
|
"oldfieldname": "expiry_date",
|
||||||
"oldfieldtype": "Date",
|
"oldfieldtype": "Date"
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "source",
|
"fieldname": "source",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Source"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Source",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "supplier",
|
"fieldname": "supplier",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supplier",
|
"label": "Supplier",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Supplier",
|
"options": "Supplier",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_9",
|
"fieldname": "column_break_9",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "reference_doctype",
|
"fieldname": "reference_doctype",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Source Document Type",
|
"label": "Source Document Type",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "DocType",
|
"options": "DocType",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "reference_name",
|
"fieldname": "reference_name",
|
||||||
"fieldtype": "Dynamic Link",
|
"fieldtype": "Dynamic Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Source Document Name",
|
"label": "Source Document Name",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "reference_doctype",
|
"options": "reference_doctype",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_7",
|
"fieldname": "section_break_7",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Batch Description",
|
"label": "Batch Description",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "description",
|
"oldfieldname": "description",
|
||||||
"oldfieldtype": "Small Text",
|
"oldfieldtype": "Small Text",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0,
|
|
||||||
"width": "300px"
|
"width": "300px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sb_disabled",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sb_batch",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Batch Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "item.item_name",
|
||||||
|
"fieldname": "item_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Item Name",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "batch_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Batch Quantity",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "item.stock_uom",
|
||||||
|
"fieldname": "stock_uom",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Batch UOM",
|
||||||
|
"options": "UOM",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"icon": "fa fa-archive",
|
"icon": "fa fa-archive",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 5,
|
"max_attachments": 5,
|
||||||
"modified": "2018-08-29 06:28:57.985997",
|
"modified": "2019-10-03 22:38:45.104056",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Batch",
|
"name": "Batch",
|
||||||
"owner": "harshada@webnotestech.com",
|
"owner": "harshada@webnotestech.com",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 1,
|
"import": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Item Manager",
|
"role": "Item Manager",
|
||||||
"set_user_permissions": 1,
|
"set_user_permissions": 1,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"sort_field": "modified",
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "item",
|
"title_field": "batch_id"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
27
erpnext/stock/doctype/batch/batch_dashboard.py
Normal file
27
erpnext/stock/doctype/batch/batch_dashboard.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return {
|
||||||
|
'fieldname': 'batch_no',
|
||||||
|
'transactions': [
|
||||||
|
{
|
||||||
|
'label': _('Buy'),
|
||||||
|
'items': ['Purchase Invoice', 'Purchase Receipt']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Sell'),
|
||||||
|
'items': ['Sales Invoice', 'Delivery Note']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Move'),
|
||||||
|
'items': ['Stock Entry']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Quality'),
|
||||||
|
'items': ['Quality Inspection']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
frappe.listview_settings['Batch'] = {
|
frappe.listview_settings['Batch'] = {
|
||||||
add_fields: ["item", "expiry_date"],
|
add_fields: ["item", "expiry_date", "batch_qty", "disabled"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: (doc) => {
|
||||||
if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
|
if (doc.disabled) {
|
||||||
return [__("Expired"), "red", "expiry_date,>=,Today"]
|
return [__("Disabled"), "darkgrey", "disabled,=,1"];
|
||||||
} else if(doc.expiry_date) {
|
} else if (!doc.batch_qty) {
|
||||||
return [__("Not Expired"), "green", "expiry_date,<,Today"]
|
return [__("Empty"), "darkgrey", "batch_qty,=,0|disabled,=,0"];
|
||||||
|
} else if (doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
|
||||||
|
return [__("Expired"), "red", "expiry_date,not in,|expiry_date,<=,Today|batch_qty,>,0|disabled,=,0"]
|
||||||
} else {
|
} else {
|
||||||
return ["Not Set", "darkgrey", ""];
|
return [__("Active"), "green", "batch_qty,>,0|disabled,=,0"];
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ from frappe.exceptions import ValidationError
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
|
from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint, flt
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||||
|
|
||||||
class TestBatch(unittest.TestCase):
|
class TestBatch(unittest.TestCase):
|
||||||
@ -35,12 +35,13 @@ class TestBatch(unittest.TestCase):
|
|||||||
receipt = frappe.get_doc(dict(
|
receipt = frappe.get_doc(dict(
|
||||||
doctype='Purchase Receipt',
|
doctype='Purchase Receipt',
|
||||||
supplier='_Test Supplier',
|
supplier='_Test Supplier',
|
||||||
|
company='_Test Company',
|
||||||
items=[
|
items=[
|
||||||
dict(
|
dict(
|
||||||
item_code='ITEM-BATCH-1',
|
item_code='ITEM-BATCH-1',
|
||||||
qty=batch_qty,
|
qty=batch_qty,
|
||||||
rate=10,
|
rate=10,
|
||||||
warehouse= 'Stores - WP'
|
warehouse= 'Stores - _TC'
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)).insert()
|
)).insert()
|
||||||
@ -175,6 +176,18 @@ class TestBatch(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(get_batch_qty('batch a', '_Test Warehouse - _TC'), 90)
|
self.assertEqual(get_batch_qty('batch a', '_Test Warehouse - _TC'), 90)
|
||||||
|
|
||||||
|
def test_total_batch_qty(self):
|
||||||
|
self.make_batch_item('ITEM-BATCH-3')
|
||||||
|
existing_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
|
||||||
|
stock_entry = self.make_new_batch_and_entry('ITEM-BATCH-3', 'B100', '_Test Warehouse - _TC')
|
||||||
|
|
||||||
|
current_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
|
||||||
|
self.assertEqual(current_batch_qty, existing_batch_qty + 90)
|
||||||
|
|
||||||
|
stock_entry.cancel()
|
||||||
|
current_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))
|
||||||
|
self.assertEqual(current_batch_qty, existing_batch_qty)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_new_batch_and_entry(cls, item_name, batch_name, warehouse):
|
def make_new_batch_and_entry(cls, item_name, batch_name, warehouse):
|
||||||
'''Make a new stock entry for given target warehouse and batch name of item'''
|
'''Make a new stock entry for given target warehouse and batch name of item'''
|
||||||
@ -208,6 +221,8 @@ class TestBatch(unittest.TestCase):
|
|||||||
stock_entry.insert()
|
stock_entry.insert()
|
||||||
stock_entry.submit()
|
stock_entry.submit()
|
||||||
|
|
||||||
|
return stock_entry
|
||||||
|
|
||||||
def test_batch_name_with_naming_series(self):
|
def test_batch_name_with_naming_series(self):
|
||||||
stock_settings = frappe.get_single('Stock Settings')
|
stock_settings = frappe.get_single('Stock Settings')
|
||||||
use_naming_series = cint(stock_settings.use_naming_series)
|
use_naming_series = cint(stock_settings.use_naming_series)
|
||||||
|
@ -101,6 +101,7 @@ class Item(WebsiteGenerator):
|
|||||||
self.add_default_uom_in_conversion_factor_table()
|
self.add_default_uom_in_conversion_factor_table()
|
||||||
self.validate_conversion_factor()
|
self.validate_conversion_factor()
|
||||||
self.validate_item_type()
|
self.validate_item_type()
|
||||||
|
self.validate_naming_series()
|
||||||
self.check_for_active_boms()
|
self.check_for_active_boms()
|
||||||
self.fill_customer_code()
|
self.fill_customer_code()
|
||||||
self.check_item_tax()
|
self.check_item_tax()
|
||||||
@ -186,7 +187,7 @@ class Item(WebsiteGenerator):
|
|||||||
or frappe.db.get_single_value('Stock Settings', 'default_warehouse'))
|
or frappe.db.get_single_value('Stock Settings', 'default_warehouse'))
|
||||||
if default_warehouse:
|
if default_warehouse:
|
||||||
warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
|
warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
|
||||||
|
|
||||||
if not default_warehouse or warehouse_company != default.company:
|
if not default_warehouse or warehouse_company != default.company:
|
||||||
default_warehouse = frappe.db.get_value('Warehouse',
|
default_warehouse = frappe.db.get_value('Warehouse',
|
||||||
{'warehouse_name': _('Stores'), 'company': default.company})
|
{'warehouse_name': _('Stores'), 'company': default.company})
|
||||||
@ -522,6 +523,13 @@ class Item(WebsiteGenerator):
|
|||||||
if self.has_serial_no == 0 and self.serial_no_series:
|
if self.has_serial_no == 0 and self.serial_no_series:
|
||||||
self.serial_no_series = None
|
self.serial_no_series = None
|
||||||
|
|
||||||
|
def validate_naming_series(self):
|
||||||
|
for field in ["serial_no_series", "batch_number_series"]:
|
||||||
|
series = self.get(field)
|
||||||
|
if series and "#" in series and "." not in series:
|
||||||
|
frappe.throw(_("Invalid naming series (. missing) for {0}")
|
||||||
|
.format(frappe.bold(self.meta.get_field(field).label)))
|
||||||
|
|
||||||
def check_for_active_boms(self):
|
def check_for_active_boms(self):
|
||||||
if self.default_bom:
|
if self.default_bom:
|
||||||
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
||||||
@ -1007,8 +1015,6 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
|||||||
order by pr.posting_date desc, pr.posting_time desc, pr.name desc
|
order by pr.posting_date desc, pr.posting_time desc, pr.name desc
|
||||||
limit 1""", (item_code, cstr(doc_name)), as_dict=1)
|
limit 1""", (item_code, cstr(doc_name)), as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
|
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
|
||||||
or "1900-01-01")
|
or "1900-01-01")
|
||||||
purchase_receipt_date = getdate(last_purchase_receipt and
|
purchase_receipt_date = getdate(last_purchase_receipt and
|
||||||
@ -1016,7 +1022,7 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
|||||||
|
|
||||||
if last_purchase_order and (purchase_order_date >= purchase_receipt_date or not last_purchase_receipt):
|
if last_purchase_order and (purchase_order_date >= purchase_receipt_date or not last_purchase_receipt):
|
||||||
# use purchase order
|
# use purchase order
|
||||||
|
|
||||||
last_purchase = last_purchase_order[0]
|
last_purchase = last_purchase_order[0]
|
||||||
purchase_date = purchase_order_date
|
purchase_date = purchase_order_date
|
||||||
|
|
||||||
@ -1036,7 +1042,7 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
|||||||
"discount_percentage": flt(last_purchase.discount_percentage),
|
"discount_percentage": flt(last_purchase.discount_percentage),
|
||||||
"purchase_date": purchase_date
|
"purchase_date": purchase_date
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
conversion_rate = flt(conversion_rate) or 1.0
|
conversion_rate = flt(conversion_rate) or 1.0
|
||||||
out.update({
|
out.update({
|
||||||
|
@ -276,8 +276,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
|
|
||||||
@ -331,8 +331,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 27.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 1.5)
|
||||||
|
|
||||||
# check if per complete is as expected for Stock Entry cancelled
|
# check if per complete is as expected for Stock Entry cancelled
|
||||||
se.cancel()
|
se.cancel()
|
||||||
@ -344,8 +344,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
def test_completed_qty_for_over_transfer(self):
|
def test_completed_qty_for_over_transfer(self):
|
||||||
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
@ -425,8 +425,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
def test_incorrect_mapping_of_stock_entry(self):
|
def test_incorrect_mapping_of_stock_entry(self):
|
||||||
# submit material request of type Transfer
|
# submit material request of type Transfer
|
||||||
@ -512,7 +512,7 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
mr.submit()
|
mr.submit()
|
||||||
|
|
||||||
#testing bin value after material request is submitted
|
#testing bin value after material request is submitted
|
||||||
self.assertEqual(_get_requested_qty(), existing_requested_qty + 54.0)
|
self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0)
|
||||||
|
|
||||||
# receive items to allow issue
|
# receive items to allow issue
|
||||||
self._insert_stock_entry(60, 6, "_Test Warehouse - _TC")
|
self._insert_stock_entry(60, 6, "_Test Warehouse - _TC")
|
||||||
@ -609,6 +609,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
def test_customer_provided_parts_mr(self):
|
def test_customer_provided_parts_mr(self):
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
existing_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
|
mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
|
||||||
se = make_stock_entry(mr.name)
|
se = make_stock_entry(mr.name)
|
||||||
se.insert()
|
se.insert()
|
||||||
@ -617,7 +619,10 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEqual(se.get("items")[0].material_request, mr.name)
|
self.assertEqual(se.get("items")[0].material_request, mr.name)
|
||||||
mr = frappe.get_doc("Material Request", mr.name)
|
mr = frappe.get_doc("Material Request", mr.name)
|
||||||
mr.submit()
|
mr.submit()
|
||||||
|
current_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(mr.per_ordered, 100)
|
self.assertEqual(mr.per_ordered, 100)
|
||||||
|
self.assertEqual(existing_requested_qty, current_requested_qty)
|
||||||
|
|
||||||
def make_material_request(**args):
|
def make_material_request(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
"is_subcontracted",
|
"is_subcontracted",
|
||||||
"supplier_warehouse",
|
"supplier_warehouse",
|
||||||
"items_section",
|
"items_section",
|
||||||
|
"scan_barcode",
|
||||||
"items",
|
"items",
|
||||||
"pricing_rule_details",
|
"pricing_rule_details",
|
||||||
"pricing_rules",
|
"pricing_rules",
|
||||||
@ -1070,13 +1071,18 @@
|
|||||||
"label": "Inter Company Reference",
|
"label": "Inter Company Reference",
|
||||||
"options": "Delivery Note",
|
"options": "Delivery Note",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "scan_barcode",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Scan Barcode"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-truck",
|
"icon": "fa fa-truck",
|
||||||
"idx": 261,
|
"idx": 261,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-30 19:12:49.709711",
|
"modified": "2020-04-06 16:31:37.444891",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt",
|
"name": "Purchase Receipt",
|
||||||
|
@ -37,11 +37,19 @@ class StockLedgerEntry(Document):
|
|||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.check_stock_frozen_date()
|
self.check_stock_frozen_date()
|
||||||
self.actual_amt_check()
|
self.actual_amt_check()
|
||||||
|
self.calculate_batch_qty()
|
||||||
|
|
||||||
if not self.get("via_landed_cost_voucher"):
|
if not self.get("via_landed_cost_voucher"):
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
|
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
|
||||||
process_serial_no(self)
|
process_serial_no(self)
|
||||||
|
|
||||||
|
def calculate_batch_qty(self):
|
||||||
|
if self.batch_no:
|
||||||
|
batch_qty = frappe.db.get_value("Stock Ledger Entry",
|
||||||
|
{"docstatus": 1, "batch_no": self.batch_no, "is_cancelled": "No"},
|
||||||
|
"sum(actual_qty)") or 0
|
||||||
|
frappe.db.set_value("Batch", self.batch_no, "batch_qty", batch_qty)
|
||||||
|
|
||||||
#check for item quantity available in stock
|
#check for item quantity available in stock
|
||||||
def actual_amt_check(self):
|
def actual_amt_check(self):
|
||||||
if self.batch_no and not self.get("allow_negative_stock"):
|
if self.batch_no and not self.get("allow_negative_stock"):
|
||||||
@ -139,4 +147,3 @@ def on_doctype_update():
|
|||||||
|
|
||||||
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
|
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
|
||||||
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
|
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
|
||||||
|
|
||||||
|
@ -488,12 +488,14 @@ def get_stock_balance_for(item_code, warehouse,
|
|||||||
["has_serial_no", "has_batch_no"], as_dict=1)
|
["has_serial_no", "has_batch_no"], as_dict=1)
|
||||||
|
|
||||||
serial_nos = ""
|
serial_nos = ""
|
||||||
if item_dict.get("has_serial_no"):
|
with_serial_no = True if item_dict.get("has_serial_no") else False
|
||||||
qty, rate, serial_nos = get_qty_rate_for_serial_nos(item_code,
|
data = get_stock_balance(item_code, warehouse, posting_date, posting_time,
|
||||||
warehouse, posting_date, posting_time, item_dict)
|
with_valuation_rate=with_valuation_rate, with_serial_no=with_serial_no)
|
||||||
|
|
||||||
|
if with_serial_no:
|
||||||
|
qty, rate, serial_nos = data
|
||||||
else:
|
else:
|
||||||
qty, rate = get_stock_balance(item_code, warehouse,
|
qty, rate = data
|
||||||
posting_date, posting_time, with_valuation_rate=with_valuation_rate)
|
|
||||||
|
|
||||||
if item_dict.get("has_batch_no"):
|
if item_dict.get("has_batch_no"):
|
||||||
qty = get_batch_qty(batch_no, warehouse) or 0
|
qty = get_batch_qty(batch_no, warehouse) or 0
|
||||||
@ -504,28 +506,6 @@ def get_stock_balance_for(item_code, warehouse,
|
|||||||
'serial_nos': serial_nos
|
'serial_nos': serial_nos
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_qty_rate_for_serial_nos(item_code, warehouse, posting_date, posting_time, item_dict):
|
|
||||||
args = {
|
|
||||||
"item_code": item_code,
|
|
||||||
"warehouse": warehouse,
|
|
||||||
"posting_date": posting_date,
|
|
||||||
"posting_time": posting_time,
|
|
||||||
}
|
|
||||||
|
|
||||||
serial_nos_list = [serial_no.get("name")
|
|
||||||
for serial_no in get_available_serial_nos(args)]
|
|
||||||
|
|
||||||
qty = len(serial_nos_list)
|
|
||||||
serial_nos = '\n'.join(serial_nos_list)
|
|
||||||
args.update({
|
|
||||||
'qty': qty,
|
|
||||||
"serial_nos": serial_nos
|
|
||||||
})
|
|
||||||
|
|
||||||
rate = get_incoming_rate(args, raise_error_if_no_rate=False) or 0
|
|
||||||
|
|
||||||
return qty, rate, serial_nos
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_difference_account(purpose, company):
|
def get_difference_account(purpose, company):
|
||||||
if purpose == 'Stock Reconciliation':
|
if purpose == 'Stock Reconciliation':
|
||||||
|
@ -245,7 +245,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
'item_group_defaults': item_group_defaults,
|
'item_group_defaults': item_group_defaults,
|
||||||
'brand_defaults': brand_defaults
|
'brand_defaults': brand_defaults
|
||||||
})
|
})
|
||||||
|
|
||||||
warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)
|
warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)
|
||||||
|
|
||||||
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
||||||
@ -279,7 +279,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
|
"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
|
||||||
'has_serial_no': item.has_serial_no,
|
'has_serial_no': item.has_serial_no,
|
||||||
'has_batch_no': item.has_batch_no,
|
'has_batch_no': item.has_batch_no,
|
||||||
"batch_no": None,
|
"batch_no": args.get("batch_no"),
|
||||||
"uom": args.uom,
|
"uom": args.uom,
|
||||||
"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
|
"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
|
||||||
"qty": flt(args.qty) or 1.0,
|
"qty": flt(args.qty) or 1.0,
|
||||||
@ -377,7 +377,7 @@ def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
warehouse = args.get('warehouse')
|
warehouse = args.get('warehouse')
|
||||||
|
|
||||||
return warehouse
|
return warehouse
|
||||||
|
|
||||||
def update_barcode_value(out):
|
def update_barcode_value(out):
|
||||||
|
@ -35,7 +35,7 @@ def get_data(report_filters):
|
|||||||
gl_data = voucher_wise_gl_data.get(key) or {}
|
gl_data = voucher_wise_gl_data.get(key) or {}
|
||||||
d.account_value = gl_data.get("account_value", 0)
|
d.account_value = gl_data.get("account_value", 0)
|
||||||
d.difference_value = (d.stock_value - d.account_value)
|
d.difference_value = (d.stock_value - d.account_value)
|
||||||
if abs(d.difference_value) > 1.0/10 ** currency_precision:
|
if abs(d.difference_value) > 0.1:
|
||||||
data.append(d)
|
data.append(d)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -113,13 +113,24 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
||||||
|
|
||||||
def get_indented_qty(item_code, warehouse):
|
def get_indented_qty(item_code, warehouse):
|
||||||
indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
inward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
||||||
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
|
and mr.material_request_type in ('Purchase', 'Manufacture')
|
||||||
|
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
||||||
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
|
outward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
||||||
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
where mr_item.item_code=%s and mr_item.warehouse=%s
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
|
and mr.material_request_type in ('Material Issue', 'Material Transfer')
|
||||||
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
||||||
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
return flt(indented_qty[0][0]) if indented_qty else 0
|
inward_qty, outward_qty = flt(inward_qty[0][0]) if inward_qty else 0, flt(outward_qty[0][0]) if outward_qty else 0
|
||||||
|
indented_qty = inward_qty - outward_qty
|
||||||
|
|
||||||
|
return indented_qty
|
||||||
|
|
||||||
def get_ordered_qty(item_code, warehouse):
|
def get_ordered_qty(item_code, warehouse):
|
||||||
ordered_qty = frappe.db.sql("""
|
ordered_qty = frappe.db.sql("""
|
||||||
@ -145,9 +156,9 @@ def update_bin_qty(item_code, warehouse, qty_dict=None):
|
|||||||
from erpnext.stock.utils import get_bin
|
from erpnext.stock.utils import get_bin
|
||||||
bin = get_bin(item_code, warehouse)
|
bin = get_bin(item_code, warehouse)
|
||||||
mismatch = False
|
mismatch = False
|
||||||
for fld, val in qty_dict.items():
|
for field, value in qty_dict.items():
|
||||||
if flt(bin.get(fld)) != flt(val):
|
if flt(bin.get(field)) != flt(value):
|
||||||
bin.set(fld, flt(val))
|
bin.set(field, flt(value))
|
||||||
mismatch = True
|
mismatch = True
|
||||||
|
|
||||||
if mismatch:
|
if mismatch:
|
||||||
|
@ -74,7 +74,8 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None):
|
|||||||
return sum(sle_map.values())
|
return sum(sle_map.values())
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False):
|
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None,
|
||||||
|
with_valuation_rate=False, with_serial_no=False):
|
||||||
"""Returns stock balance quantity at given warehouse on given posting date or current date.
|
"""Returns stock balance quantity at given warehouse on given posting date or current date.
|
||||||
|
|
||||||
If `with_valuation_rate` is True, will return tuple (qty, rate)"""
|
If `with_valuation_rate` is True, will return tuple (qty, rate)"""
|
||||||
@ -84,17 +85,51 @@ def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None
|
|||||||
if not posting_date: posting_date = nowdate()
|
if not posting_date: posting_date = nowdate()
|
||||||
if not posting_time: posting_time = nowtime()
|
if not posting_time: posting_time = nowtime()
|
||||||
|
|
||||||
last_entry = get_previous_sle({
|
args = {
|
||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"warehouse":warehouse,
|
"warehouse":warehouse,
|
||||||
"posting_date": posting_date,
|
"posting_date": posting_date,
|
||||||
"posting_time": posting_time })
|
"posting_time": posting_time
|
||||||
|
}
|
||||||
|
|
||||||
|
last_entry = get_previous_sle(args)
|
||||||
|
|
||||||
if with_valuation_rate:
|
if with_valuation_rate:
|
||||||
return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
|
if with_serial_no:
|
||||||
|
serial_nos = last_entry.get("serial_no")
|
||||||
|
|
||||||
|
if (serial_nos and
|
||||||
|
len(get_serial_nos_data(serial_nos)) < last_entry.qty_after_transaction):
|
||||||
|
serial_nos = get_serial_nos_data_after_transactions(args)
|
||||||
|
|
||||||
|
return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
|
||||||
|
if last_entry else (0.0, 0.0, 0.0))
|
||||||
|
else:
|
||||||
|
return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
|
||||||
else:
|
else:
|
||||||
return last_entry.qty_after_transaction if last_entry else 0.0
|
return last_entry.qty_after_transaction if last_entry else 0.0
|
||||||
|
|
||||||
|
def get_serial_nos_data_after_transactions(args):
|
||||||
|
serial_nos = []
|
||||||
|
data = frappe.db.sql(""" SELECT serial_no, actual_qty
|
||||||
|
FROM `tabStock Ledger Entry`
|
||||||
|
WHERE
|
||||||
|
item_code = %(item_code)s and warehouse = %(warehouse)s
|
||||||
|
and timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)
|
||||||
|
order by posting_date, posting_time asc """, args, as_dict=1)
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
if d.actual_qty > 0:
|
||||||
|
serial_nos.extend(get_serial_nos_data(d.serial_no))
|
||||||
|
else:
|
||||||
|
serial_nos = list(set(serial_nos) - set(get_serial_nos_data(d.serial_no)))
|
||||||
|
|
||||||
|
return '\n'.join(serial_nos)
|
||||||
|
|
||||||
|
def get_serial_nos_data(serial_nos):
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
return get_serial_nos(serial_nos)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_latest_stock_qty(item_code, warehouse=None):
|
def get_latest_stock_qty(item_code, warehouse=None):
|
||||||
values, condition = [item_code], ""
|
values, condition = [item_code], ""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user