Merge pull request #25696 from rohitwaghchaure/incorrect-serial-no-qty-valuation-report
feat: Incorrect valuation rate report for serialized items
This commit is contained in:
commit
b4863bfa50
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Incorrect Balance Qty After Transaction"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
label: __("Company"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
fieldname: "company",
|
||||||
|
options: "Company",
|
||||||
|
default: frappe.defaults.get_user_default("Company"),
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Item Code'),
|
||||||
|
fieldtype: 'Link',
|
||||||
|
fieldname: 'item_code',
|
||||||
|
options: 'Item'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Warehouse'),
|
||||||
|
fieldtype: 'Link',
|
||||||
|
fieldname: 'warehouse'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-05-12 16:47:58.717853",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-05-12 16:48:28.347575",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Stock",
|
||||||
|
"name": "Incorrect Balance Qty After Transaction",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Incorrect Balance Qty After Transaction",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Stock User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Stock Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Purchase User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from six import iteritems
|
||||||
|
from frappe.utils import flt
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns, data = [], []
|
||||||
|
columns = get_columns()
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = get_stock_ledger_entries(filters)
|
||||||
|
itewise_balance_qty = {}
|
||||||
|
|
||||||
|
for row in data:
|
||||||
|
key = (row.item_code, row.warehouse)
|
||||||
|
itewise_balance_qty.setdefault(key, []).append(row)
|
||||||
|
|
||||||
|
res = validate_data(itewise_balance_qty)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def validate_data(itewise_balance_qty):
|
||||||
|
res = []
|
||||||
|
for key, data in iteritems(itewise_balance_qty):
|
||||||
|
row = get_incorrect_data(data)
|
||||||
|
if row:
|
||||||
|
res.append(row)
|
||||||
|
res.append({})
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_incorrect_data(data):
|
||||||
|
balance_qty = 0.0
|
||||||
|
for row in data:
|
||||||
|
balance_qty += row.actual_qty
|
||||||
|
if row.voucher_type == "Stock Reconciliation" and not row.batch_no:
|
||||||
|
balance_qty = flt(row.qty_after_transaction)
|
||||||
|
|
||||||
|
row.expected_balance_qty = balance_qty
|
||||||
|
if abs(flt(row.expected_balance_qty) - flt(row.qty_after_transaction)) > 0.5:
|
||||||
|
row.differnce = abs(flt(row.expected_balance_qty) - flt(row.qty_after_transaction))
|
||||||
|
return row
|
||||||
|
|
||||||
|
def get_stock_ledger_entries(report_filters):
|
||||||
|
filters = {}
|
||||||
|
fields = ['name', 'voucher_type', 'voucher_no', 'item_code', 'actual_qty',
|
||||||
|
'posting_date', 'posting_time', 'company', 'warehouse', 'qty_after_transaction', 'batch_no']
|
||||||
|
|
||||||
|
for field in ['warehouse', 'item_code', 'company']:
|
||||||
|
if report_filters.get(field):
|
||||||
|
filters[field] = report_filters.get(field)
|
||||||
|
|
||||||
|
return frappe.get_all('Stock Ledger Entry', fields = fields, filters = filters,
|
||||||
|
order_by = 'timestamp(posting_date, posting_time) asc, creation asc')
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [{
|
||||||
|
'label': _('Id'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'name',
|
||||||
|
'options': 'Stock Ledger Entry',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Posting Date'),
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'width': 110
|
||||||
|
}, {
|
||||||
|
'label': _('Voucher Type'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'voucher_type',
|
||||||
|
'options': 'DocType',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Voucher No'),
|
||||||
|
'fieldtype': 'Dynamic Link',
|
||||||
|
'fieldname': 'voucher_no',
|
||||||
|
'options': 'voucher_type',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Item Code'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'item_code',
|
||||||
|
'options': 'Item',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Warehouse'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'warehouse',
|
||||||
|
'options': 'Warehouse',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Expected Balance Qty'),
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'fieldname': 'expected_balance_qty',
|
||||||
|
'width': 170
|
||||||
|
}, {
|
||||||
|
'label': _('Actual Balance Qty'),
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'fieldname': 'qty_after_transaction',
|
||||||
|
'width': 150
|
||||||
|
}, {
|
||||||
|
'label': _('Difference'),
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'fieldname': 'differnce',
|
||||||
|
'width': 110
|
||||||
|
}]
|
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Incorrect Serial No Valuation"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
label: __('Item Code'),
|
||||||
|
fieldtype: 'Link',
|
||||||
|
fieldname: 'item_code',
|
||||||
|
options: 'Item',
|
||||||
|
get_query: function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'has_serial_no': 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('From Date'),
|
||||||
|
fieldtype: 'Date',
|
||||||
|
fieldname: 'from_date',
|
||||||
|
reqd: 1,
|
||||||
|
default: frappe.defaults.get_user_default("year_start_date")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('To Date'),
|
||||||
|
fieldtype: 'Date',
|
||||||
|
fieldname: 'to_date',
|
||||||
|
reqd: 1,
|
||||||
|
default: frappe.defaults.get_user_default("year_end_date")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-05-13 13:07:00.767845",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"json": "{}",
|
||||||
|
"modified": "2021-05-13 13:07:00.767845",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Stock",
|
||||||
|
"name": "Incorrect Serial No Valuation",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Incorrect Serial No Valuation",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Stock User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Stock Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,148 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import copy
|
||||||
|
from frappe import _
|
||||||
|
from six import iteritems
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns, data = [], []
|
||||||
|
columns = get_columns()
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = get_stock_ledger_entries(filters)
|
||||||
|
serial_nos_data = prepare_serial_nos(data)
|
||||||
|
data = get_incorrect_serial_nos(serial_nos_data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def prepare_serial_nos(data):
|
||||||
|
serial_no_wise_data = {}
|
||||||
|
for row in data:
|
||||||
|
if not row.serial_nos:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for serial_no in get_serial_nos(row.serial_nos):
|
||||||
|
sle = copy.deepcopy(row)
|
||||||
|
sle.serial_no = serial_no
|
||||||
|
sle.qty = 1 if sle.actual_qty > 0 else -1
|
||||||
|
sle.valuation_rate = sle.valuation_rate if sle.actual_qty > 0 else sle.valuation_rate * -1
|
||||||
|
serial_no_wise_data.setdefault(serial_no, []).append(sle)
|
||||||
|
|
||||||
|
return serial_no_wise_data
|
||||||
|
|
||||||
|
def get_incorrect_serial_nos(serial_nos_data):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
total_value = frappe._dict({'qty': 0, 'valuation_rate': 0, 'serial_no': frappe.bold(_('Balance'))})
|
||||||
|
|
||||||
|
for serial_no, data in iteritems(serial_nos_data):
|
||||||
|
total_dict = frappe._dict({'qty': 0, 'valuation_rate': 0, 'serial_no': frappe.bold(_('Total'))})
|
||||||
|
|
||||||
|
if check_incorrect_serial_data(data, total_dict):
|
||||||
|
result.extend(data)
|
||||||
|
|
||||||
|
total_value.qty += total_dict.qty
|
||||||
|
total_value.valuation_rate += total_dict.valuation_rate
|
||||||
|
|
||||||
|
result.append(total_dict)
|
||||||
|
result.append({})
|
||||||
|
|
||||||
|
result.append(total_value)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_incorrect_serial_data(data, total_dict):
|
||||||
|
incorrect_data = False
|
||||||
|
for row in data:
|
||||||
|
total_dict.qty += row.qty
|
||||||
|
total_dict.valuation_rate += row.valuation_rate
|
||||||
|
|
||||||
|
if ((total_dict.qty == 0 and abs(total_dict.valuation_rate) > 0) or total_dict.qty < 0):
|
||||||
|
incorrect_data = True
|
||||||
|
|
||||||
|
return incorrect_data
|
||||||
|
|
||||||
|
def get_stock_ledger_entries(report_filters):
|
||||||
|
fields = ['name', 'voucher_type', 'voucher_no', 'item_code', 'serial_no as serial_nos', 'actual_qty',
|
||||||
|
'posting_date', 'posting_time', 'company', 'warehouse', '(stock_value_difference / actual_qty) as valuation_rate']
|
||||||
|
|
||||||
|
filters = {'serial_no': ("is", "set")}
|
||||||
|
|
||||||
|
if report_filters.get('item_code'):
|
||||||
|
filters['item_code'] = report_filters.get('item_code')
|
||||||
|
|
||||||
|
if report_filters.get('from_date') and report_filters.get('to_date'):
|
||||||
|
filters['posting_date'] = ('between', [report_filters.get('from_date'), report_filters.get('to_date')])
|
||||||
|
|
||||||
|
return frappe.get_all('Stock Ledger Entry', fields = fields, filters = filters,
|
||||||
|
order_by = 'timestamp(posting_date, posting_time) asc, creation asc')
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [{
|
||||||
|
'label': _('Company'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'company',
|
||||||
|
'options': 'Company',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Id'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'name',
|
||||||
|
'options': 'Stock Ledger Entry',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Posting Date'),
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'width': 90
|
||||||
|
}, {
|
||||||
|
'label': _('Posting Time'),
|
||||||
|
'fieldtype': 'Time',
|
||||||
|
'fieldname': 'posting_time',
|
||||||
|
'width': 90
|
||||||
|
}, {
|
||||||
|
'label': _('Voucher Type'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'voucher_type',
|
||||||
|
'options': 'DocType',
|
||||||
|
'width': 100
|
||||||
|
}, {
|
||||||
|
'label': _('Voucher No'),
|
||||||
|
'fieldtype': 'Dynamic Link',
|
||||||
|
'fieldname': 'voucher_no',
|
||||||
|
'options': 'voucher_type',
|
||||||
|
'width': 110
|
||||||
|
}, {
|
||||||
|
'label': _('Item Code'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'item_code',
|
||||||
|
'options': 'Item',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Warehouse'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'warehouse',
|
||||||
|
'options': 'Warehouse',
|
||||||
|
'width': 120
|
||||||
|
}, {
|
||||||
|
'label': _('Serial No'),
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'fieldname': 'serial_no',
|
||||||
|
'options': 'Serial No',
|
||||||
|
'width': 100
|
||||||
|
}, {
|
||||||
|
'label': _('Qty'),
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'fieldname': 'qty',
|
||||||
|
'width': 80
|
||||||
|
}, {
|
||||||
|
'label': _('Valuation Rate (In / Out)'),
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'fieldname': 'valuation_rate',
|
||||||
|
'width': 110
|
||||||
|
}]
|
@ -15,6 +15,7 @@
|
|||||||
"hide_custom": 0,
|
"hide_custom": 0,
|
||||||
"icon": "stock",
|
"icon": "stock",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
|
"is_default": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "Stock",
|
"label": "Stock",
|
||||||
"links": [
|
"links": [
|
||||||
@ -653,9 +654,44 @@
|
|||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Incorrect Data Report",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Card Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Incorrect Serial No Qty and Valuation",
|
||||||
|
"link_to": "Incorrect Serial No Valuation",
|
||||||
|
"link_type": "Report",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Incorrect Balance Qty After Transaction",
|
||||||
|
"link_to": "Incorrect Balance Qty After Transaction",
|
||||||
|
"link_type": "Report",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Stock and Account Value Comparison",
|
||||||
|
"link_to": "Stock and Account Value Comparison",
|
||||||
|
"link_type": "Report",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2020-12-01 13:38:36.282890",
|
"modified": "2021-05-13 13:10:24.914983",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock",
|
"name": "Stock",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user