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,
|
||||
"icon": "stock",
|
||||
"idx": 0,
|
||||
"is_default": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Stock",
|
||||
"links": [
|
||||
@ -653,9 +654,44 @@
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"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",
|
||||
"module": "Stock",
|
||||
"name": "Stock",
|
||||
|
Loading…
Reference in New Issue
Block a user