Merge branch 'develop' into se-add-to-transit
This commit is contained in:
commit
a91d7bd4b5
@ -293,6 +293,11 @@ def validate_accounts(file_name):
|
||||
accounts_dict = {}
|
||||
for account in accounts:
|
||||
accounts_dict.setdefault(account["account_name"], account)
|
||||
if not hasattr(account, "parent_account"):
|
||||
msg = _("Please make sure the file you are using has 'Parent Account' column present in the header.")
|
||||
msg += "<br><br>"
|
||||
msg += _("Alternatively, you can download the template and fill your data in.")
|
||||
frappe.throw(msg, title=_("Parent Account Missing"))
|
||||
if account["parent_account"] and accounts_dict.get(account["parent_account"]):
|
||||
accounts_dict[account["parent_account"]]["is_group"] = 1
|
||||
|
||||
|
@ -260,7 +260,10 @@ doc_events = {
|
||||
"erpnext.regional.italy.utils.sales_invoice_on_cancel",
|
||||
"erpnext.erpnext_integrations.taxjar_integration.delete_transaction"
|
||||
],
|
||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
||||
"on_trash": "erpnext.regional.check_deletion_permission",
|
||||
"validate": [
|
||||
"erpnext.regional.india.utils.validate_document_name"
|
||||
]
|
||||
},
|
||||
"Purchase Invoice": {
|
||||
"validate": [
|
||||
@ -282,9 +285,6 @@ doc_events = {
|
||||
('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
|
||||
'validate': ['erpnext.regional.india.utils.set_place_of_supply']
|
||||
},
|
||||
('Sales Invoice', 'Purchase Invoice'): {
|
||||
'validate': ['erpnext.regional.india.utils.validate_document_name']
|
||||
},
|
||||
"Contact": {
|
||||
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
|
||||
"after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations",
|
||||
|
@ -15,6 +15,7 @@
|
||||
"hide_custom": 0,
|
||||
"icon": "hr",
|
||||
"idx": 0,
|
||||
"is_default": 0,
|
||||
"is_standard": 1,
|
||||
"label": "HR",
|
||||
"links": [
|
||||
@ -226,42 +227,12 @@
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Application",
|
||||
"link_to": "Leave Application",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Allocation",
|
||||
"link_to": "Leave Allocation",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Leave Type",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Policy",
|
||||
"link_to": "Leave Policy",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Period",
|
||||
"link_to": "Leave Period",
|
||||
"label": "Holiday List",
|
||||
"link_to": "Holiday List",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
@ -280,8 +251,28 @@
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Holiday List",
|
||||
"link_to": "Holiday List",
|
||||
"label": "Leave Period",
|
||||
"link_to": "Leave Period",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Leave Type",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Policy",
|
||||
"link_to": "Leave Policy",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Leave Policy",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Policy Assignment",
|
||||
"link_to": "Leave Policy Assignment",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
@ -290,8 +281,18 @@
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Compensatory Leave Request",
|
||||
"link_to": "Compensatory Leave Request",
|
||||
"label": "Leave Application",
|
||||
"link_to": "Leave Application",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Allocation",
|
||||
"link_to": "Leave Allocation",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
@ -317,12 +318,12 @@
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Leave Application",
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Leave Balance",
|
||||
"link_to": "Employee Leave Balance",
|
||||
"link_type": "Report",
|
||||
"is_query_report": 0,
|
||||
"label": "Compensatory Leave Request",
|
||||
"link_to": "Compensatory Leave Request",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
@ -383,16 +384,6 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Attendance",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Monthly Attendance Sheet",
|
||||
"link_to": "Monthly Attendance Sheet",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@ -420,6 +411,15 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Travel Request",
|
||||
"link_to": "Travel Request",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@ -464,6 +464,15 @@
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Driver",
|
||||
"link_to": "Driver",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
@ -541,6 +550,24 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Appointment Letter",
|
||||
"link_to": "Appointment Letter",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Appointment Letter Template",
|
||||
"link_to": "Appointment Letter Template",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@ -625,33 +652,6 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Reports",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Birthday",
|
||||
"link_to": "Employee Birthday",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employees working on a holiday",
|
||||
"link_to": "Employees working on a holiday",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@ -702,7 +702,74 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Tax and Benefits",
|
||||
"label": "Key Reports",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "Attendance",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Monthly Attendance Sheet",
|
||||
"link_to": "Monthly Attendance Sheet",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Staffing Plan",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Recruitment Analytics",
|
||||
"link_to": "Recruitment Analytics",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Analytics",
|
||||
"link_to": "Employee Analytics",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Leave Balance",
|
||||
"link_to": "Employee Leave Balance",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Leave Balance Summary",
|
||||
"link_to": "Employee Leave Balance Summary",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee Advance",
|
||||
"hidden": 0,
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Advance Summary",
|
||||
"link_to": "Employee Advance Summary",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Other Reports",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
@ -710,74 +777,44 @@
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Tax Exemption Declaration",
|
||||
"link_to": "Employee Tax Exemption Declaration",
|
||||
"link_type": "DocType",
|
||||
"label": "Employee Information",
|
||||
"link_to": "Employee Information",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Tax Exemption Proof Submission",
|
||||
"link_to": "Employee Tax Exemption Proof Submission",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee, Payroll Period",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Other Income",
|
||||
"link_to": "Employee Other Income",
|
||||
"link_type": "DocType",
|
||||
"is_query_report": 1,
|
||||
"label": "Employee Birthday",
|
||||
"link_to": "Employee Birthday",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Benefit Application",
|
||||
"link_to": "Employee Benefit Application",
|
||||
"link_type": "DocType",
|
||||
"is_query_report": 1,
|
||||
"label": "Employees Working on a Holiday",
|
||||
"link_to": "Employees working on a holiday",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"dependencies": "Daily Work Summary",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Benefit Claim",
|
||||
"link_to": "Employee Benefit Claim",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Tax Exemption Category",
|
||||
"link_to": "Employee Tax Exemption Category",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "Employee",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Employee Tax Exemption Sub Category",
|
||||
"link_to": "Employee Tax Exemption Sub Category",
|
||||
"link_type": "DocType",
|
||||
"is_query_report": 1,
|
||||
"label": "Daily Work Summary Replies",
|
||||
"link_to": "Daily Work Summary Replies",
|
||||
"link_type": "Report",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
}
|
||||
],
|
||||
"modified": "2021-01-21 13:38:38.941001",
|
||||
"modified": "2021-03-24 17:35:21.483297",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "HR",
|
||||
|
@ -33,12 +33,16 @@ class TestProject(unittest.TestCase):
|
||||
|
||||
def test_project_template_having_parent_child_tasks(self):
|
||||
project_name = "Test Project with Template - Tasks with Parent-Child Relation"
|
||||
|
||||
if frappe.db.get_value('Project', {'project_name': project_name}, 'name'):
|
||||
project_name = frappe.db.get_value('Project', {'project_name': project_name}, 'name')
|
||||
|
||||
frappe.db.sql(""" delete from tabTask where project = %s """, project_name)
|
||||
frappe.delete_doc('Project', project_name)
|
||||
|
||||
task1 = task_exists("Test Template Task Parent")
|
||||
if not task1:
|
||||
task1 = create_task(subject="Test Template Task Parent", is_group=1, is_template=1, begin=1, duration=4)
|
||||
task1 = create_task(subject="Test Template Task Parent", is_group=1, is_template=1, begin=1, duration=10)
|
||||
|
||||
task2 = task_exists("Test Template Task Child 1")
|
||||
if not task2:
|
||||
@ -53,7 +57,7 @@ class TestProject(unittest.TestCase):
|
||||
tasks = frappe.get_all('Task', ['subject','exp_end_date','depends_on_tasks', 'name', 'parent_task'], dict(project=project.name), order_by='creation asc')
|
||||
|
||||
self.assertEqual(tasks[0].subject, 'Test Template Task Parent')
|
||||
self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 4))
|
||||
self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 10))
|
||||
|
||||
self.assertEqual(tasks[1].subject, 'Test Template Task Child 1')
|
||||
self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 1, 3))
|
||||
|
@ -737,28 +737,34 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
this.frm.trigger("item_code", cdt, cdn);
|
||||
}
|
||||
else {
|
||||
var valid_serial_nos = [];
|
||||
var serialnos = [];
|
||||
// Replacing all occurences of comma with carriage return
|
||||
item.serial_no = item.serial_no.replace(/,/g, '\n');
|
||||
serialnos = item.serial_no.split("\n");
|
||||
for (var i = 0; i < serialnos.length; i++) {
|
||||
if (serialnos[i] != "") {
|
||||
valid_serial_nos.push(serialnos[i]);
|
||||
}
|
||||
}
|
||||
item.conversion_factor = item.conversion_factor || 1;
|
||||
|
||||
refresh_field("serial_no", item.name, item.parentfield);
|
||||
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
||||
frappe.model.set_value(item.doctype, item.name,
|
||||
"qty", valid_serial_nos.length / item.conversion_factor);
|
||||
frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
|
||||
if (!doc.is_return && cint(frappe.user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
||||
setTimeout(() => {
|
||||
me.update_qty(cdt, cdn);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update_qty: function(cdt, cdn) {
|
||||
var valid_serial_nos = [];
|
||||
var serialnos = [];
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
serialnos = item.serial_no.split("\n");
|
||||
for (var i = 0; i < serialnos.length; i++) {
|
||||
if (serialnos[i] != "") {
|
||||
valid_serial_nos.push(serialnos[i]);
|
||||
}
|
||||
}
|
||||
frappe.model.set_value(item.doctype, item.name,
|
||||
"qty", valid_serial_nos.length / item.conversion_factor);
|
||||
frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
|
||||
},
|
||||
|
||||
validate: function() {
|
||||
this.calculate_taxes_and_totals(false);
|
||||
},
|
||||
|
@ -787,6 +787,8 @@ class GSPConnector():
|
||||
|
||||
self.invoice.irn = res.get('Irn')
|
||||
self.invoice.ewaybill = res.get('EwbNo')
|
||||
self.invoice.ack_no = res.get('AckNo')
|
||||
self.invoice.ack_date = res.get('AckDt')
|
||||
self.invoice.signed_einvoice = dec_signed_invoice
|
||||
self.invoice.signed_qr_code = res.get('SignedQRCode')
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
frappe.provide('erpnext.stock');
|
||||
|
||||
erpnext.stock.ItemDashboard = Class.extend({
|
||||
init: function(opts) {
|
||||
init: function (opts) {
|
||||
$.extend(this, opts);
|
||||
this.make();
|
||||
},
|
||||
make: function() {
|
||||
make: function () {
|
||||
var me = this;
|
||||
this.start = 0;
|
||||
if(!this.sort_by) {
|
||||
if (!this.sort_by) {
|
||||
this.sort_by = 'projected_qty';
|
||||
this.sort_order = 'asc';
|
||||
}
|
||||
@ -16,22 +16,25 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent);
|
||||
this.result = this.content.find('.result');
|
||||
|
||||
this.content.on('click', '.btn-move', function() {
|
||||
handle_move_add($(this), "Move")
|
||||
this.content.on('click', '.btn-move', function () {
|
||||
handle_move_add($(this), "Move");
|
||||
});
|
||||
|
||||
this.content.on('click', '.btn-add', function() {
|
||||
handle_move_add($(this), "Add")
|
||||
this.content.on('click', '.btn-add', function () {
|
||||
handle_move_add($(this), "Add");
|
||||
});
|
||||
|
||||
this.content.on('click', '.btn-edit', function() {
|
||||
this.content.on('click', '.btn-edit', function () {
|
||||
let item = unescape($(this).attr('data-item'));
|
||||
let warehouse = unescape($(this).attr('data-warehouse'));
|
||||
let company = unescape($(this).attr('data-company'));
|
||||
frappe.db.get_value('Putaway Rule',
|
||||
{'item_code': item, 'warehouse': warehouse, 'company': company}, 'name', (r) => {
|
||||
frappe.set_route("Form", "Putaway Rule", r.name);
|
||||
});
|
||||
frappe.db.get_value('Putaway Rule', {
|
||||
'item_code': item,
|
||||
'warehouse': warehouse,
|
||||
'company': company
|
||||
}, 'name', (r) => {
|
||||
frappe.set_route("Form", "Putaway Rule", r.name);
|
||||
});
|
||||
});
|
||||
|
||||
function handle_move_add(element, action) {
|
||||
@ -39,23 +42,26 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
let warehouse = unescape(element.attr('data-warehouse'));
|
||||
let actual_qty = unescape(element.attr('data-actual_qty'));
|
||||
let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry')));
|
||||
let entry_type = action === "Move" ? "Material Transfer": null;
|
||||
let entry_type = action === "Move" ? "Material Transfer" : null;
|
||||
|
||||
if (disable_quick_entry) {
|
||||
open_stock_entry(item, warehouse, entry_type);
|
||||
} else {
|
||||
if (action === "Add") {
|
||||
let rate = unescape($(this).attr('data-rate'));
|
||||
erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); });
|
||||
}
|
||||
else {
|
||||
erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function() { me.refresh(); });
|
||||
erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function () {
|
||||
me.refresh();
|
||||
});
|
||||
} else {
|
||||
erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function () {
|
||||
me.refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function open_stock_entry(item, warehouse, entry_type) {
|
||||
frappe.model.with_doctype('Stock Entry', function() {
|
||||
frappe.model.with_doctype('Stock Entry', function () {
|
||||
var doc = frappe.model.get_new_doc('Stock Entry');
|
||||
if (entry_type) doc.stock_entry_type = entry_type;
|
||||
|
||||
@ -64,18 +70,18 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
row.s_warehouse = warehouse;
|
||||
|
||||
frappe.set_route('Form', doc.doctype, doc.name);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// more
|
||||
this.content.find('.btn-more').on('click', function() {
|
||||
this.content.find('.btn-more').on('click', function () {
|
||||
me.start += me.page_length;
|
||||
me.refresh();
|
||||
});
|
||||
|
||||
},
|
||||
refresh: function() {
|
||||
if(this.before_refresh) {
|
||||
refresh: function () {
|
||||
if (this.before_refresh) {
|
||||
this.before_refresh();
|
||||
}
|
||||
|
||||
@ -94,13 +100,13 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
frappe.call({
|
||||
method: this.method,
|
||||
args: args,
|
||||
callback: function(r) {
|
||||
callback: function (r) {
|
||||
me.render(r.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
render: function(data) {
|
||||
if (this.start===0) {
|
||||
render: function (data) {
|
||||
if (this.start === 0) {
|
||||
this.max_count = 0;
|
||||
this.result.empty();
|
||||
}
|
||||
@ -115,7 +121,7 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
this.max_count = this.max_count;
|
||||
|
||||
// show more button
|
||||
if (data && data.length===(this.page_length + 1)) {
|
||||
if (data && data.length === (this.page_length + 1)) {
|
||||
this.content.find('.more').removeClass('hidden');
|
||||
|
||||
// remove the last element
|
||||
@ -137,15 +143,15 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
}
|
||||
},
|
||||
|
||||
get_item_dashboard_data: function(data, max_count, show_item) {
|
||||
if(!max_count) max_count = 0;
|
||||
if(!data) data = [];
|
||||
get_item_dashboard_data: function (data, max_count, show_item) {
|
||||
if (!max_count) max_count = 0;
|
||||
if (!data) data = [];
|
||||
|
||||
data.forEach(function(d) {
|
||||
data.forEach(function (d) {
|
||||
d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
|
||||
d.pending_qty = 0;
|
||||
d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
|
||||
if(d.actual_or_pending > d.actual_qty) {
|
||||
if (d.actual_or_pending > d.actual_qty) {
|
||||
d.pending_qty = d.actual_or_pending - d.actual_qty;
|
||||
}
|
||||
|
||||
@ -161,16 +167,16 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
return {
|
||||
data: data,
|
||||
max_count: max_count,
|
||||
can_write:can_write,
|
||||
can_write: can_write,
|
||||
show_item: show_item || false
|
||||
};
|
||||
},
|
||||
|
||||
get_capacity_dashboard_data: function(data) {
|
||||
get_capacity_dashboard_data: function (data) {
|
||||
if (!data) data = [];
|
||||
|
||||
data.forEach(function(d) {
|
||||
d.color = d.percent_occupied >=80 ? "#f8814f" : "#2490ef";
|
||||
data.forEach(function (d) {
|
||||
d.color = d.percent_occupied >= 80 ? "#f8814f" : "#2490ef";
|
||||
});
|
||||
|
||||
let can_write = 0;
|
||||
@ -185,53 +191,77 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) {
|
||||
erpnext.stock.move_item = function (item, source, target, actual_qty, rate, callback) {
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: target ? __('Add Item') : __('Move Item'),
|
||||
fields: [
|
||||
{fieldname: 'item_code', label: __('Item'),
|
||||
fieldtype: 'Link', options: 'Item', read_only: 1},
|
||||
{fieldname: 'source', label: __('Source Warehouse'),
|
||||
fieldtype: 'Link', options: 'Warehouse', read_only: 1},
|
||||
{fieldname: 'target', label: __('Target Warehouse'),
|
||||
fieldtype: 'Link', options: 'Warehouse', reqd: 1},
|
||||
{fieldname: 'qty', label: __('Quantity'), reqd: 1,
|
||||
fieldtype: 'Float', description: __('Available {0}', [actual_qty]) },
|
||||
{fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 },
|
||||
fields: [{
|
||||
fieldname: 'item_code',
|
||||
label: __('Item'),
|
||||
fieldtype: 'Link',
|
||||
options: 'Item',
|
||||
read_only: 1
|
||||
},
|
||||
{
|
||||
fieldname: 'source',
|
||||
label: __('Source Warehouse'),
|
||||
fieldtype: 'Link',
|
||||
options: 'Warehouse',
|
||||
read_only: 1
|
||||
},
|
||||
{
|
||||
fieldname: 'target',
|
||||
label: __('Target Warehouse'),
|
||||
fieldtype: 'Link',
|
||||
options: 'Warehouse',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: 'qty',
|
||||
label: __('Quantity'),
|
||||
reqd: 1,
|
||||
fieldtype: 'Float',
|
||||
description: __('Available {0}', [actual_qty])
|
||||
},
|
||||
{
|
||||
fieldname: 'rate',
|
||||
label: __('Rate'),
|
||||
fieldtype: 'Currency',
|
||||
hidden: 1
|
||||
},
|
||||
],
|
||||
})
|
||||
});
|
||||
dialog.show();
|
||||
dialog.get_field('item_code').set_input(item);
|
||||
|
||||
if(source) {
|
||||
if (source) {
|
||||
dialog.get_field('source').set_input(source);
|
||||
} else {
|
||||
dialog.get_field('source').df.hidden = 1;
|
||||
dialog.get_field('source').refresh();
|
||||
}
|
||||
|
||||
if(rate) {
|
||||
if (rate) {
|
||||
dialog.get_field('rate').set_value(rate);
|
||||
dialog.get_field('rate').df.hidden = 0;
|
||||
dialog.get_field('rate').refresh();
|
||||
}
|
||||
|
||||
if(target) {
|
||||
if (target) {
|
||||
dialog.get_field('target').df.read_only = 1;
|
||||
dialog.get_field('target').value = target;
|
||||
dialog.get_field('target').refresh();
|
||||
}
|
||||
|
||||
dialog.set_primary_action(__('Submit'), function() {
|
||||
dialog.set_primary_action(__('Submit'), function () {
|
||||
var values = dialog.get_values();
|
||||
if(!values) {
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
if(source && values.qty > actual_qty) {
|
||||
if (source && values.qty > actual_qty) {
|
||||
frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
|
||||
return;
|
||||
}
|
||||
if(values.source === values.target) {
|
||||
if (values.source === values.target) {
|
||||
frappe.msgprint(__('Source and target warehouse must be different'));
|
||||
}
|
||||
|
||||
@ -239,21 +269,21 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb
|
||||
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
|
||||
args: values,
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
callback: function (r) {
|
||||
frappe.show_alert(__('Stock Entry {0} created',
|
||||
['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>']));
|
||||
['<a href="/app/stock-entry/' + r.message.name + '">' + r.message.name + '</a>']));
|
||||
dialog.hide();
|
||||
callback(r);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
$('<p style="margin-left: 10px;"><a class="link-open text-muted small">'
|
||||
+ __("Add more items or open full form") + '</a></p>')
|
||||
$('<p style="margin-left: 10px;"><a class="link-open text-muted small">' +
|
||||
__("Add more items or open full form") + '</a></p>')
|
||||
.appendTo(dialog.body)
|
||||
.find('.link-open')
|
||||
.on('click', function() {
|
||||
frappe.model.with_doctype('Stock Entry', function() {
|
||||
.on('click', function () {
|
||||
frappe.model.with_doctype('Stock Entry', function () {
|
||||
var doc = frappe.model.get_new_doc('Stock Entry');
|
||||
doc.from_warehouse = dialog.get_value('source');
|
||||
doc.to_warehouse = dialog.get_value('target');
|
||||
@ -266,6 +296,6 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb
|
||||
row.transfer_qty = dialog.get_value('qty');
|
||||
row.basic_rate = dialog.get_value('rate');
|
||||
frappe.set_route('Form', doc.doctype, doc.name);
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.model.db_query import DatabaseQuery
|
||||
from frappe.utils import flt, cint
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_data(item_code=None, warehouse=None, item_group=None,
|
||||
@ -42,11 +43,20 @@ def get_data(item_code=None, warehouse=None, item_group=None,
|
||||
limit_start=start,
|
||||
limit_page_length='21')
|
||||
|
||||
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
|
||||
|
||||
for item in items:
|
||||
item.update({
|
||||
'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name'),
|
||||
'disable_quick_entry': frappe.get_cached_value("Item", item.item_code, 'has_batch_no')
|
||||
or frappe.get_cached_value("Item", item.item_code, 'has_serial_no'),
|
||||
'item_name': frappe.get_cached_value(
|
||||
"Item", item.item_code, 'item_name'),
|
||||
'disable_quick_entry': frappe.get_cached_value(
|
||||
"Item", item.item_code, 'has_batch_no')
|
||||
or frappe.get_cached_value(
|
||||
"Item", item.item_code, 'has_serial_no'),
|
||||
'projected_qty': flt(item.projected_qty, precision),
|
||||
'reserved_qty': flt(item.reserved_qty, precision),
|
||||
'reserved_qty_for_production': flt(item.reserved_qty_for_production, precision),
|
||||
'reserved_qty_for_sub_contract': flt(item.reserved_qty_for_sub_contract, precision),
|
||||
'actual_qty': flt(item.actual_qty, precision),
|
||||
})
|
||||
|
||||
return items
|
||||
|
@ -494,7 +494,8 @@ def make_item_variant():
|
||||
|
||||
test_records = frappe.get_test_records('Item')
|
||||
|
||||
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None, customer=None, is_purchase_item=None, opening_stock=None):
|
||||
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None,
|
||||
customer=None, is_purchase_item=None, opening_stock=None, company=None):
|
||||
if not frappe.db.exists("Item", item_code):
|
||||
item = frappe.new_doc("Item")
|
||||
item.item_code = item_code
|
||||
@ -509,7 +510,7 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None,
|
||||
item.customer = customer or ''
|
||||
item.append("item_defaults", {
|
||||
"default_warehouse": warehouse or '_Test Warehouse - _TC',
|
||||
"company": "_Test Company"
|
||||
"company": company or "_Test Company"
|
||||
})
|
||||
item.save()
|
||||
else:
|
||||
|
@ -346,7 +346,7 @@ def create_delivery_note(source_name, target_doc=None):
|
||||
|
||||
if dn_item:
|
||||
dn_item.warehouse = location.warehouse
|
||||
dn_item.qty = location.picked_qty
|
||||
dn_item.qty = flt(location.picked_qty) / (flt(location.conversion_factor) or 1)
|
||||
dn_item.batch_no = location.batch_no
|
||||
dn_item.serial_no = location.serial_no
|
||||
|
||||
|
@ -9,6 +9,7 @@ test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
|
||||
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from erpnext.stock.doctype.pick_list.pick_list import create_delivery_note
|
||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation \
|
||||
import EmptyStockReconciliationItemsError
|
||||
|
||||
@ -291,6 +292,61 @@ class TestPickList(unittest.TestCase):
|
||||
self.assertEqual(pick_list.locations[1].qty, 5)
|
||||
self.assertEqual(pick_list.locations[1].sales_order_item, sales_order.items[0].name)
|
||||
|
||||
def test_pick_list_for_items_with_multiple_UOM(self):
|
||||
purchase_receipt = make_purchase_receipt(item_code="_Test Item", qty=10)
|
||||
purchase_receipt.submit()
|
||||
|
||||
sales_order = frappe.get_doc({
|
||||
'doctype': 'Sales Order',
|
||||
'customer': '_Test Customer',
|
||||
'company': '_Test Company',
|
||||
'items': [{
|
||||
'item_code': '_Test Item',
|
||||
'qty': 1,
|
||||
'conversion_factor': 5,
|
||||
'delivery_date': frappe.utils.today()
|
||||
}, {
|
||||
'item_code': '_Test Item',
|
||||
'qty': 1,
|
||||
'conversion_factor': 1,
|
||||
'delivery_date': frappe.utils.today()
|
||||
}],
|
||||
}).insert()
|
||||
sales_order.submit()
|
||||
|
||||
pick_list = frappe.get_doc({
|
||||
'doctype': 'Pick List',
|
||||
'company': '_Test Company',
|
||||
'customer': '_Test Customer',
|
||||
'items_based_on': 'Sales Order',
|
||||
'locations': [{
|
||||
'item_code': '_Test Item',
|
||||
'qty': 1,
|
||||
'stock_qty': 5,
|
||||
'conversion_factor': 5,
|
||||
'sales_order': sales_order.name,
|
||||
'sales_order_item': sales_order.items[0].name ,
|
||||
}, {
|
||||
'item_code': '_Test Item',
|
||||
'qty': 1,
|
||||
'stock_qty': 1,
|
||||
'conversion_factor': 1,
|
||||
'sales_order': sales_order.name,
|
||||
'sales_order_item': sales_order.items[1].name ,
|
||||
}]
|
||||
})
|
||||
pick_list.set_item_locations()
|
||||
pick_list.submit()
|
||||
|
||||
delivery_note = create_delivery_note(pick_list.name)
|
||||
|
||||
self.assertEqual(pick_list.locations[0].qty, delivery_note.items[0].qty)
|
||||
self.assertEqual(pick_list.locations[1].qty, delivery_note.items[1].qty)
|
||||
self.assertEqual(sales_order.items[0].conversion_factor, delivery_note.items[0].conversion_factor)
|
||||
|
||||
pick_list.cancel()
|
||||
sales_order.cancel()
|
||||
purchase_receipt.cancel()
|
||||
|
||||
# def test_pick_list_skips_items_in_expired_batch(self):
|
||||
# pass
|
||||
|
@ -179,11 +179,15 @@ class TestStockEntry(unittest.TestCase):
|
||||
def test_material_transfer_gl_entry(self):
|
||||
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
|
||||
|
||||
mtn = make_stock_entry(item_code="_Test Item", source="Stores - TCP1",
|
||||
item_code = 'Hand Sanitizer - 001'
|
||||
create_item(item_code =item_code, is_stock_item = 1,
|
||||
is_purchase_item=1, opening_stock=1000, valuation_rate=10, company=company, warehouse="Stores - TCP1")
|
||||
|
||||
mtn = make_stock_entry(item_code=item_code, source="Stores - TCP1",
|
||||
target="Finished Goods - TCP1", qty=45, company=company)
|
||||
|
||||
self.check_stock_ledger_entries("Stock Entry", mtn.name,
|
||||
[["_Test Item", "Stores - TCP1", -45.0], ["_Test Item", "Finished Goods - TCP1", 45.0]])
|
||||
[[item_code, "Stores - TCP1", -45.0], [item_code, "Finished Goods - TCP1", 45.0]])
|
||||
|
||||
source_warehouse_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user