Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2023, AgriTheory and contributors
// For license information, please see license.txt
/* eslint-disable */

frappe.query_reports['Pick List Tool'] = {
filters: [
{
fieldname: 'company',
label: __('Company'),
fieldtype: 'Link',
options: 'Company',
default: frappe.defaults.get_user_default('Company'),
reqd: 1,
},
{
fieldname: 'status',
label: __('Status'),
fieldtype: 'Select',
options: ['', 'Already Picked', 'Not Picked', 'Unshipped'],
},
{
fieldname: 'delivery_date_start',
label: __('Delivery Date (start)'),
fieldtype: 'Date',
},
{
fieldname: 'delivery_date_end',
label: __('Delivery Date (end)'),
fieldtype: 'Date',
},
{
fieldname: 'warehouse',
label: __('Warehouse'),
fieldtype: 'MultiSelectList',
options: 'Warehouse',
get_data: function (txt) {
return frappe.db.get_link_options('Warehouse', txt, {
company: frappe.query_report.get_filter_value('company'),
is_group: 1,
})
},
},
{
fieldname: 'customer',
label: __('Customer'),
fieldtype: 'Link',
options: 'Customer',
},
],
formatter: function (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data)
if (column.fieldname == 'sales_order' && data && data.sales_order) {
value = value.bold()
} else if (column.fieldname == 'per_picked' && data && data.per_picked !== null) {
if (data.per_picked == 100) {
value = "<span style='color:green'>" + value + '</span>'
} else {
value = "<span style='color:red'>" + value + '</span>'
}
} else if (column.fieldname == 'total_stock' && data && data.total_stock !== null) {
if (data.total_stock == 'Total Availability') {
value = "<span style='color:green'>" + value + '</span>'
} else {
value = "<span style='color:red'>" + value + '</span>'
}
}
return value
},
onload: report => {
report.page.add_button('Check Stock', () => {
check_stock()
})
report.page.add_button('Print Pick', () => {
print_pick()
})
report.page.add_inner_button(
__('Pick List'),
function () {
create_pick_list()
},
__('Create')
)
report.page.add_inner_button(
__('Pick List & Delivery Note'),
function () {
create_pick_list_delivery_note()
},
__('Create')
)
},
}

async function check_stock() {
let values = frappe.query_report.get_filter_values()
await frappe
.xcall('inventory_tools.inventory_tools.report.pick_list_tool.pick_list_tool.check_stock', {
filters: values,
})
.then(r => {})
}
function print_pick() {
if (!frappe.query_report.filters || frappe.query_report.get_filter_value('status') != 'Already Picked') {
frappe.msgprint('Only can print Already Picked')
return
}
}

function create_pick_list() {}
function create_pick_list_delivery_note() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2023-10-13 08:52:27.178388",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"modified": "2023-10-13 08:52:27.178388",
"modified_by": "Administrator",
"module": "Inventory Tools",
"name": "Pick List Tool",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Pick List",
"report_name": "Pick List Tool",
"report_type": "Script Report",
"roles": [
{
"role": "Stock Manager"
},
{
"role": "Stock User"
},
{
"role": "Manufacturing Manager"
},
{
"role": "Manufacturing User"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Copyright (c) 2023, AgriTheory and contributors
# For license information, please see license.txt
import json
from itertools import groupby

import frappe
from erpnext.stock.doctype.pick_list.pick_list import get_available_item_locations
from frappe.query_builder import DocType
from frappe.utils.nestedset import get_descendants_of


def execute(filters=None):
return get_columns(), get_report_output(filters)


def get_report_output(filters=None, ignore_validation=True):
SalesOrder = DocType("Sales Order")
SalesOrderItem = DocType("Sales Order Item")
query = (
frappe.qb.from_(SalesOrder)
.join(SalesOrderItem)
.on(SalesOrder.name == SalesOrderItem.parent)
.select(
SalesOrder.name.as_("sales_order"),
SalesOrder.per_picked,
SalesOrderItem.item_code,
SalesOrderItem.warehouse,
SalesOrderItem.delivery_date,
SalesOrderItem.qty.as_("so_qty"),
)
.where(SalesOrder.docstatus == 1)
.where(SalesOrder.company == filters.company)
)

if filters.status:
if filters.status == "Already Picked":
query = query.where(SalesOrder.per_picked == 100)
elif filters.status == "Not Picked":
query = query.where(SalesOrder.per_picked < 100)
elif filters.status == "Unshipped":
query = query.where(SalesOrder.per_delivered < 100)
if filters.customer:
query = query.where(SalesOrder.customer == filters.customer)
if filters.delivery_date_start:
query = query.where(SalesOrderItem.delivery_date >= filters.delivery_date_start)
if filters.delivery_date_end:
query = query.where(SalesOrderItem.delivery_date <= filters.delivery_date_end)
if filters.warehouse:
from_warehouses = get_descendants_of("Warehouse", filters.warehouse)
else:
from_warehouses = frappe.get_all("Warehouse", pluck="name")

query = query.where(SalesOrderItem.warehouse.isin(from_warehouses))
data = query.run(as_dict=1)
output = []

for sales_order, _rows in groupby(data, lambda x: x.get("sales_order")):
rows = list(_rows)
output.append(
{"sales_order": sales_order, "indent": 0, "per_picked": f'{rows[0]["per_picked"]} %'}
)
for row in rows:
del row["sales_order"]
del row["per_picked"]
qty_available = get_available_item_locations(
row["item_code"],
from_warehouses,
row["so_qty"],
filters.company,
ignore_validation=ignore_validation,
picked_item_details=None,
)
row["total_stock"] = "Total Availability" if qty_available else "Not Total Availability"
output.append({**row, "indent": 1})

return output


def get_columns():
return [
{
"fieldname": "sales_order",
"fieldtype": "Link",
"options": "Sales Order",
"label": "Sales Order",
"width": "200px",
},
{
"fieldname": "item_code",
"fieldtype": "Link",
"options": "Item",
"label": "Item",
"width": "250px",
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"options": "Warehouse",
"label": "Warehouse",
"width": "250px",
},
{
"fieldname": "so_qty",
"label": "SO Qty",
"fieldtype": "Data",
},
{
"fieldname": "delivery_date",
"label": "Delivery Date",
"fieldtype": "Date",
"width": "120px",
},
{
"fieldname": "per_picked",
"label": "% Picked",
"fieldtype": "Data",
"width": "100px",
},
{
"fieldname": "total_stock",
"fieldtype": "Data",
"label": "Total Stock",
"width": "150px",
},
]


@frappe.whitelist()
def check_stock(filters):
filters = frappe._dict(json.loads(filters)) if isinstance(filters, str) else filters
get_report_output(filters=filters, ignore_validation=False)