Merge branch 'develop' into print-format-fix

This commit is contained in:
Deepesh Garg 2020-03-27 21:39:16 +05:30 committed by GitHub
commit e86f6d0738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 408 additions and 387 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides from erpnext.hooks import regional_overrides
from frappe.utils import getdate from frappe.utils import getdate
__version__ = '12.2.0' __version__ = '12.0.0-dev'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@ -7,7 +7,20 @@ frappe.ui.form.on('Bank', {
}, },
refresh: function(frm) { refresh: function(frm) {
add_fields_to_mapping_table(frm); add_fields_to_mapping_table(frm);
}
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank' };
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if (frm.doc.__islocal) {
frm.set_df_property('address_and_contact', 'hidden', 1);
frappe.contacts.clear_address_and_contact(frm);
}
else {
frm.set_df_property('address_and_contact', 'hidden', 0);
frappe.contacts.render_address_and_contact(frm);
}
},
}); });

View File

@ -1,224 +1,137 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0, "allow_import": 1,
"allow_guest_to_view": 0, "allow_rename": 1,
"allow_import": 0, "autoname": "field:bank_name",
"allow_rename": 0, "creation": "2018-04-07 16:59:59.496668",
"autoname": "field:bank_name", "doctype": "DocType",
"beta": 0, "document_type": "Setup",
"creation": "2018-04-07 16:59:59.496668", "editable_grid": 1,
"custom": 0, "engine": "InnoDB",
"docstatus": 0, "field_order": [
"doctype": "DocType", "bank_details_section",
"document_type": "", "bank_name",
"editable_grid": 1, "swift_number",
"engine": "InnoDB", "column_break_1",
"branch_code",
"website",
"address_and_contact",
"address_html",
"column_break_13",
"contact_html",
"data_import_configuration_section",
"bank_transaction_mapping",
"section_break_4",
"plaid_access_token"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "bank_name",
"allow_in_quick_entry": 0, "fieldtype": "Data",
"allow_on_submit": 0, "label": "Bank Name",
"bold": 0, "reqd": 1,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Bank Name",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0, "fieldname": "bank_details_section",
"allow_in_quick_entry": 0, "fieldtype": "Section Break",
"allow_on_submit": 0, "label": "Bank Details"
"bold": 0, },
"collapsible": 1,
"columns": 0,
"fieldname": "data_import_configuration_section",
"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,
"label": "Data Import Configuration",
"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": 1,
"allow_in_quick_entry": 0, "fieldname": "swift_number",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "in_standard_filter": 1,
"columns": 0, "label": "SWIFT number",
"fieldname": "bank_transaction_mapping", "unique": 1
"fieldtype": "Table", },
"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": "Bank Transaction Mapping",
"length": 0,
"no_copy": 0,
"options": "Bank Transaction Mapping",
"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, "fieldname": "column_break_1",
"allow_in_quick_entry": 0, "fieldtype": "Column Break",
"allow_on_submit": 0, "search_index": 1
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"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": 1,
"allow_in_quick_entry": 0, "fieldname": "branch_code",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "in_standard_filter": 1,
"columns": 0, "label": "Branch Code",
"fieldname": "plaid_access_token", "unique": 1
"fieldtype": "Data", },
"hidden": 1, {
"ignore_user_permissions": 0, "fieldname": "address_and_contact",
"ignore_xss_filter": 0, "fieldtype": "Section Break",
"in_filter": 0, "label": "Address and Contact",
"in_global_search": 0, "options": "fa fa-map-marker"
"in_list_view": 0, },
"in_standard_filter": 0, {
"label": "Plaid Access Token", "fieldname": "address_html",
"length": 0, "fieldtype": "HTML",
"no_copy": 1, "label": "Address HTML"
"permlevel": 0, },
"precision": "", {
"print_hide": 0, "fieldname": "website",
"print_hide_if_no_value": 0, "fieldtype": "Data",
"read_only": 1, "label": "Website"
"remember_last_selected_value": 0, },
"report_hide": 0, {
"reqd": 0, "fieldname": "column_break_13",
"search_index": 0, "fieldtype": "Column Break"
"set_only_once": 0, },
"translatable": 0, {
"unique": 0 "fieldname": "contact_html",
"fieldtype": "HTML",
"label": "Contact HTML"
},
{
"collapsible": 1,
"fieldname": "data_import_configuration_section",
"fieldtype": "Section Break",
"label": "Data Import Configuration"
},
{
"fieldname": "bank_transaction_mapping",
"fieldtype": "Table",
"label": "Bank Transaction Mapping",
"options": "Bank Transaction Mapping"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
{
"fieldname": "plaid_access_token",
"fieldtype": "Data",
"hidden": 1,
"label": "Plaid Access Token",
"no_copy": 1,
"read_only": 1
} }
], ],
"has_web_view": 0, "links": [],
"hide_heading": 0, "modified": "2020-03-25 21:22:33.496264",
"hide_toolbar": 0, "modified_by": "Administrator",
"idx": 0, "module": "Accounts",
"image_view": 0, "name": "Bank",
"in_create": 0, "owner": "Administrator",
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-11-27 16:12:13.938776",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank",
"name_case": "",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "email": 1,
"delete": 1, "export": 1,
"email": 1, "print": 1,
"export": 1, "read": 1,
"if_owner": 0, "report": 1,
"import": 0, "role": "System Manager",
"permlevel": 0, "share": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "sort_field": "modified",
"read_only_onload": 0, "sort_order": "DESC",
"show_name_in_global_search": 0, "track_changes": 1
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
} }

View File

@ -5,6 +5,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
class Bank(Document): class Bank(Document):
pass def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)
def on_trash(self):
delete_contact_and_address('Bank', self.name)

View File

@ -24,8 +24,6 @@
"iban", "iban",
"column_break_12", "column_break_12",
"bank_account_no", "bank_account_no",
"branch_code",
"swift_number",
"address_and_contact", "address_and_contact",
"address_html", "address_html",
"website", "website",
@ -145,17 +143,6 @@
"label": "Bank Account No", "label": "Bank Account No",
"length": 30 "length": 30
}, },
{
"fieldname": "branch_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Branch Code"
},
{
"fieldname": "swift_number",
"fieldtype": "Data",
"label": "SWIFT number"
},
{ {
"fieldname": "address_and_contact", "fieldname": "address_and_contact",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@ -213,7 +200,7 @@
} }
], ],
"links": [], "links": [],
"modified": "2020-01-29 20:42:26.458316", "modified": "2020-01-30 20:42:26.458316",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Bank Account", "name": "Bank Account",

View File

@ -4,8 +4,8 @@
cur_frm.add_fetch('bank_account','account','account'); cur_frm.add_fetch('bank_account','account','account');
cur_frm.add_fetch('bank_account','bank_account_no','bank_account_no'); cur_frm.add_fetch('bank_account','bank_account_no','bank_account_no');
cur_frm.add_fetch('bank_account','iban','iban'); cur_frm.add_fetch('bank_account','iban','iban');
cur_frm.add_fetch('bank_account','branch_code','branch_code'); cur_frm.add_fetch('bank','branch_code','branch_code');
cur_frm.add_fetch('bank_account','swift_number','swift_number'); cur_frm.add_fetch('bank','swift_number','swift_number');
frappe.ui.form.on('Bank Guarantee', { frappe.ui.form.on('Bank Guarantee', {
setup: function(frm) { setup: function(frm) {

View File

@ -33,7 +33,9 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("party_bank_account", function() { frm.set_query("party_bank_account", function() {
return { return {
filters: { filters: {
"is_company_account":0 "is_company_account":0,
party_type: frm.doc.party_type,
party: frm.doc.party
} }
} }
}); });

View File

@ -839,7 +839,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "bank_account.branch_code", "fetch_from": "bank.branch_code",
"fieldname": "branch_code", "fieldname": "branch_code",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "hidden": 0,
@ -873,7 +873,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "bank_account.swift_number", "fetch_from": "bank.swift_number",
"fieldname": "swift_number", "fieldname": "swift_number",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "hidden": 0,

View File

@ -131,7 +131,7 @@ def get_gl_entries(filters):
gl_entries = frappe.db.sql( gl_entries = frappe.db.sql(
""" """
select select
posting_date, account, party_type, party, name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, cost_center, project, voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher, account_currency, against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields} remarks, against, is_opening {select_fields}
@ -362,6 +362,12 @@ def get_columns(filters):
currency = get_company_currency(company) currency = get_company_currency(company)
columns = [ columns = [
{
"fieldname": "gl_entry",
"fieldtype": "Link",
"options": "GL Entry",
"hidden": 1
},
{ {
"label": _("Posting Date"), "label": _("Posting Date"),
"fieldname": "posting_date", "fieldname": "posting_date",

View File

@ -34,4 +34,4 @@ def get_data():
'items': ['Pricing Rule'] 'items': ['Pricing Rule']
} }
] ]
} }

View File

@ -6,46 +6,28 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.utils.make_random import get_random from frappe.utils.make_random import get_random
from erpnext.assets.doctype.asset.asset import make_purchase_invoice, make_sales_invoice from erpnext.assets.doctype.asset.asset import make_sales_invoice
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset
def work(): def work():
frappe.set_user(frappe.db.get_global('demo_accounts_user')) frappe.set_user(frappe.db.get_global('demo_accounts_user'))
asset_list = make_asset_purchase_entry()
if not asset_list:
# fixed_asset.work() already run
return
# Enable booking asset depreciation entry automatically # Enable booking asset depreciation entry automatically
frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
# post depreciation entries as on today # post depreciation entries as on today
post_depreciation_entries() post_depreciation_entries()
# scrap a random asset # scrap a random asset
frappe.db.set_value("Company", "Wind Power LLC", "disposal_account", "Gain/Loss on Asset Disposal - WPL") frappe.db.set_value("Company", "Wind Power LLC", "disposal_account", "Gain/Loss on Asset Disposal - WPL")
asset = get_random_asset() asset = get_random_asset()
scrap_asset(asset.name) scrap_asset(asset.name)
# Sell a random asset
sell_an_asset()
def make_asset_purchase_entry(): # Sell a random asset
asset_list = frappe.get_all("Asset", filters={"purchase_invoice": ["in", ("", None)]}, sell_an_asset()
fields=["name", "item_code", "gross_purchase_amount", "company", "purchase_date"])
# make purchase invoice
for asset in asset_list:
pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount,
asset.company, asset.purchase_date)
pi.supplier = get_random("Supplier")
pi.save()
pi.submit()
return asset_list
def sell_an_asset(): def sell_an_asset():
asset = get_random_asset() asset = get_random_asset()
@ -55,8 +37,9 @@ def sell_an_asset():
if asset.value_after_depreciation else asset.gross_purchase_amount * 0.9 if asset.value_after_depreciation else asset.gross_purchase_amount * 0.9
si.save() si.save()
si.submit() si.submit()
def get_random_asset(): def get_random_asset():
return frappe.db.sql(""" select name, item_code, value_after_depreciation, gross_purchase_amount return frappe.db.sql(""" select name, item_code, value_after_depreciation, gross_purchase_amount
from `tabAsset` from `tabAsset`
where docstatus=1 and status not in ("Scrapped", "Sold") order by rand() limit 1""", as_dict=1)[0] where docstatus=1 and status not in ("Scrapped", "Sold") order by rand() limit 1""", as_dict=1)[0]

View File

@ -273,11 +273,11 @@ class TestLoan(unittest.TestCase):
penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year)) penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
lia = frappe.get_all("Loan Interest Accrual", fields=["is_paid"], lia1 = frappe.get_value("Loan Interest Accrual", {"loan": loan.name, "is_paid": 1}, 'name')
filters={"loan": loan.name}, order_by="posting_date") lia2 = frappe.get_value("Loan Interest Accrual", {"loan": loan.name, "is_paid": 0}, 'name')
self.assertTrue(lia[0].get('is_paid')) self.assertTrue(lia1)
self.assertFalse(lia[1].get('is_paid')) self.assertTrue(lia2)
def test_security_shortfall(self): def test_security_shortfall(self):
pledges = [] pledges = []

View File

@ -658,4 +658,5 @@ erpnext.patches.v12_0.set_permission_einvoicing
erpnext.patches.v12_0.set_published_in_hub_tracked_item erpnext.patches.v12_0.set_published_in_hub_tracked_item
erpnext.patches.v12_0.set_job_offer_applicant_email erpnext.patches.v12_0.set_job_offer_applicant_email
erpnext.patches.v12_0.create_irs_1099_field_united_states 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.rename_bank_reconciliation_fields # 2020-01-22 erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22

View File

@ -0,0 +1,14 @@
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('accounts', 'doctype', 'bank', force=1)
frappe.db.sql("""
UPDATE `tabBank` b, `tabBank Account` ba
SET b.swift_number = ba.swift_number, b.branch_code = ba.branch_code
WHERE b.name = ba.bank
""")
frappe.reload_doc('accounts', 'doctype', 'bank_account')
frappe.reload_doc('accounts', 'doctype', 'payment_request')

View File

@ -4,7 +4,7 @@
erpnext.TransactionController = erpnext.taxes_and_totals.extend({ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
setup: function() { setup: function() {
this._super(); this._super();
frappe.flags.hide_serial_batch_dialog = false; frappe.flags.hide_serial_batch_dialog = true;
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn); var item = frappe.get_doc(cdt, cdn);
var has_margin_field = frappe.meta.has_field(cdt, 'margin_type'); var has_margin_field = frappe.meta.has_field(cdt, 'margin_type');
@ -165,6 +165,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
return (doc.rule_applied) ? "green" : "red"; return (doc.rule_applied) ? "green" : "red";
}); });
} }
let batch_no_field = this.frm.get_docfield("items", "batch_no");
if (batch_no_field) {
batch_no_field.get_route_options_for_new_doc = function(row) {
return {
"item": row.doc.item_code
}
};
}
}, },
onload: function() { onload: function() {
var me = this; var me = this;
@ -519,6 +529,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} }
}, },
() => me.toggle_conversion_factor(item), () => me.toggle_conversion_factor(item),
() => {
if (show_batch_dialog)
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
.then((r) => {
if(r.message.has_batch_no || r.message.has_serial_no) {
frappe.flags.hide_serial_batch_dialog = false;
}
});
},
() => { () => {
if(show_batch_dialog && !frappe.flags.hide_serial_batch_dialog) { if(show_batch_dialog && !frappe.flags.hide_serial_batch_dialog) {
var d = locals[cdt][cdn]; var d = locals[cdt][cdn];
@ -528,7 +547,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
erpnext.show_serial_batch_selector(me.frm, d, (item) => { erpnext.show_serial_batch_selector(me.frm, d, (item) => {
me.frm.script_manager.trigger('qty', item.doctype, item.name); me.frm.script_manager.trigger('qty', item.doctype, item.name);
}); if (!me.frm.doc.set_warehouse)
me.frm.script_manager.trigger('warehouse', item.doctype, item.name);
}, undefined, !frappe.flags.hide_serial_batch_dialog);
} }
}, },
() => me.conversion_factor(doc, cdt, cdn, true), () => me.conversion_factor(doc, cdt, cdn, true),

View File

@ -1,23 +1,25 @@
frappe.provide('frappe.ui.form'); frappe.provide('frappe.ui.form');
erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset", let default_dimensions = {};
let doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program", "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
"Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
"Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"]; "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"];
erpnext.child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", let child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
"Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
"Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"]; "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"];
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters", method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
callback: function(r){ callback: function(r) {
erpnext.dimension_filters = r.message[0]; erpnext.dimension_filters = r.message[0];
erpnext.default_dimensions = r.message[1]; default_dimensions = r.message[1];
} }
}); });
erpnext.doctypes_with_dimensions.forEach((doctype) => { doctypes_with_dimensions.forEach((doctype) => {
frappe.ui.form.on(doctype, { frappe.ui.form.on(doctype, {
onload: function(frm) { onload: function(frm) {
erpnext.dimension_filters.forEach((dimension) => { erpnext.dimension_filters.forEach((dimension) => {
@ -27,41 +29,40 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
"is_group": 0 "is_group": 0
}); });
} }
if (Object.keys(erpnext.default_dimensions).length > 0) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
}
}
if (frm.doc.items && frm.doc.items.length && frm.doc.docstatus === 0
&& (!frm.doc.items[0][dimension['fieldname']])) {
frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
}
if (frm.doc.accounts && frm.doc.accounts.length && frm.doc.docstatus === 0
&& (!frm.doc.items[0][dimension['fieldname']])) {
frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
}
}
}); });
}); });
}, },
company: function(frm) { company: function(frm) {
if(frm.doc.company && (Object.keys(erpnext.default_dimensions).length > 0)) { if(frm.doc.company && (Object.keys(default_dimensions || {}).length > 0)
erpnext.dimension_filters.forEach((dimension) => { && default_dimensions[frm.doc.company]) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) { frm.trigger('update_dimension');
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
}
});
} }
}, },
update_dimension: function(frm) {
erpnext.dimension_filters.forEach((dimension) => {
if (frm.is_new()) {
if (frm.doc.company && Object.keys(default_dimensions || {}).length > 0
&& default_dimensions[frm.doc.company]) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
frm.set_value(dimension['fieldname'],
default_dimensions[frm.doc.company][dimension['document_type']]);
}
$.each(frm.doc.items || frm.doc.accounts || [], function(i, row) {
frappe.model.set_value(row.doctype, row.name, dimension['fieldname'],
default_dimensions[frm.doc.company][dimension['document_type']])
});
}
}
});
}
}); });
}); });
erpnext.child_docs.forEach((doctype) => { child_docs.forEach((doctype) => {
frappe.ui.form.on(doctype, { frappe.ui.form.on(doctype, {
items_add: function(frm, cdt, cdn) { items_add: function(frm, cdt, cdn) {
erpnext.dimension_filters.forEach((dimension) => { erpnext.dimension_filters.forEach((dimension) => {
@ -77,14 +78,6 @@ erpnext.child_docs.forEach((doctype) => {
}); });
}, },
company: function(frm) {
if(frm.doc.company) {
erpnext.dimension_filters.forEach((dimension) => {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
});
}
},
items_add: function(frm, cdt, cdn) { items_add: function(frm, cdt, cdn) {
erpnext.dimension_filters.forEach((dimension) => { erpnext.dimension_filters.forEach((dimension) => {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);

View File

@ -5,14 +5,13 @@ erpnext.SerialNoBatchSelector = Class.extend({
this.show_dialog = show_dialog; this.show_dialog = show_dialog;
// frm, item, warehouse_details, has_batch, oldest // frm, item, warehouse_details, has_batch, oldest
let d = this.item; let d = this.item;
if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) { this.has_batch = 0; this.has_serial_no = 0;
this.has_batch = 1;
this.setup(); if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) this.has_batch = 1;
// !(this.show_dialog == false) ensures that show_dialog is implictly true, even when undefined // !(this.show_dialog == false) ensures that show_dialog is implictly true, even when undefined
} else if(d && d.has_serial_no && !(this.show_dialog == false)) { if(d && d.has_serial_no && !(this.show_dialog == false)) this.has_serial_no = 1;
this.has_batch = 0;
this.setup(); this.setup();
}
}, },
setup: function() { setup: function() {
@ -36,16 +35,16 @@ erpnext.SerialNoBatchSelector = Class.extend({
label: __('Item Code'), label: __('Item Code'),
default: me.item_code default: me.item_code
}, },
{fieldtype:'Column Break'},
{ {
fieldname: 'warehouse', fieldname: 'warehouse',
fieldtype:'Link', fieldtype:'Link',
options: 'Warehouse', options: 'Warehouse',
reqd: me.has_batch && !me.has_serial_no ? 0 : 1,
label: __(me.warehouse_details.type), label: __(me.warehouse_details.type),
default: me.warehouse_details.name, default: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
onchange: function(e) { onchange: function(e) {
if(me.has_batch) { if(me.has_batch && !me.has_serial_no) {
fields = fields.concat(me.get_batch_fields()); fields = fields.concat(me.get_batch_fields());
} else { } else {
fields = fields.concat(me.get_serial_no_fields()); fields = fields.concat(me.get_serial_no_fields());
@ -74,15 +73,16 @@ erpnext.SerialNoBatchSelector = Class.extend({
{ {
fieldname: 'qty', fieldname: 'qty',
fieldtype:'Float', fieldtype:'Float',
read_only: me.has_batch, read_only: me.has_batch && !me.has_serial_no,
label: __(me.has_batch ? 'Total Qty' : 'Qty'), label: __(me.has_batch && !me.has_serial_no ? 'Total Qty' : 'Qty'),
default: 0 default: 0
}, },
{ {
fieldname: 'auto_fetch_button', fieldname: 'auto_fetch_button',
fieldtype:'Button', fieldtype:'Button',
hidden: me.has_batch, hidden: me.has_batch && !me.has_serial_no,
label: __('Fetch based on FIFO'), label: __('Auto Fetch'),
description: __('Fetch Serial Numbers based on FIFO'),
click: () => { click: () => {
let qty = this.dialog.fields_dict.qty.get_value(); let qty = this.dialog.fields_dict.qty.get_value();
let numbers = frappe.call({ let numbers = frappe.call({
@ -90,7 +90,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
args: { args: {
qty: qty, qty: qty,
item_code: me.item_code, item_code: me.item_code,
warehouse: me.warehouse_details.name, warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
batch_no: me.item.batch_no || null batch_no: me.item.batch_no || null
} }
}); });
@ -109,10 +109,12 @@ erpnext.SerialNoBatchSelector = Class.extend({
} }
]; ];
if (this.has_batch) { if (this.has_batch && !this.has_serial_no) {
title = __("Select Batch Numbers"); title = __("Select Batch Numbers");
fields = fields.concat(this.get_batch_fields()); fields = fields.concat(this.get_batch_fields());
} else { } else {
// if only serial no OR
// if both batch_no & serial_no then only select serial_no and auto set batches nos
title = __("Select Serial Numbers"); title = __("Select Serial Numbers");
fields = fields.concat(this.get_serial_no_fields()); fields = fields.concat(this.get_serial_no_fields());
} }
@ -122,25 +124,31 @@ erpnext.SerialNoBatchSelector = Class.extend({
fields: fields fields: fields
}); });
if (this.item.serial_no) {
this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
}
this.dialog.set_primary_action(__('Insert'), function() { this.dialog.set_primary_action(__('Insert'), function() {
me.values = me.dialog.get_values(); me.values = me.dialog.get_values();
if(me.validate()) { if(me.validate()) {
me.set_items(); frappe.run_serially([
me.dialog.hide(); () => me.update_batch_items(),
() => me.update_serial_no_item(),
() => me.update_batch_serial_no_items(),
() => {
refresh_field("items");
if (me.callback) {
return me.callback(me.item);
}
},
() => me.dialog.hide()
])
} }
}); });
if(this.show_dialog) { if(this.show_dialog) {
let d = this.item; let d = this.item;
if (d.has_serial_no && d.serial_no) { if (this.item.serial_no) {
this.dialog.set_value('serial_no', d.serial_no); this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
} }
if (d.has_batch_no && d.batch_no) { if (this.has_batch && !this.has_serial_no && d.batch_no) {
this.frm.doc.items.forEach(data => { this.frm.doc.items.forEach(data => {
if(data.item_code == d.item_code) { if(data.item_code == d.item_code) {
this.dialog.fields_dict.batches.df.data.push({ this.dialog.fields_dict.batches.df.data.push({
@ -155,7 +163,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
} }
} }
if (this.has_batch) { if (this.has_batch && !this.has_serial_no) {
this.update_total_qty(); this.update_total_qty();
} }
@ -174,7 +182,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
frappe.throw(__("Please select a warehouse")); frappe.throw(__("Please select a warehouse"));
return false; return false;
} }
if(this.has_batch) { if(this.has_batch && !this.has_serial_no) {
if(values.batches.length === 0 || !values.batches) { if(values.batches.length === 0 || !values.batches) {
frappe.throw(__("Please select batches for batched item " frappe.throw(__("Please select batches for batched item "
+ values.item_code)); + values.item_code));
@ -193,34 +201,23 @@ erpnext.SerialNoBatchSelector = Class.extend({
} else { } else {
let serial_nos = values.serial_no || ''; let serial_nos = values.serial_no || '';
if (!serial_nos || !serial_nos.replace(/\s/g, '').length) { if (!serial_nos || !serial_nos.replace(/\s/g, '').length) {
if (!this.show_dialog) { frappe.throw(__("Please enter serial numbers for serialized item "
frappe.throw(__("Please enter serial numbers for serialized item " + values.item_code));
+ values.item_code)); return false;
return false;
}
} }
return true; return true;
} }
}, },
set_items: function() { update_batch_items() {
var me = this; // clones an items if muliple batches are selected.
if(this.has_batch) { if(this.has_batch && !this.has_serial_no) {
this.values.batches.map((batch, i) => { this.values.batches.map((batch, i) => {
let batch_no = batch.batch_no; let batch_no = batch.batch_no;
let row = ''; let row = '';
if (i !== 0 && !this.batch_exists(batch_no)) { if (i !== 0 && !this.batch_exists(batch_no)) {
row = this.frm.add_child("items", { row = this.frm.add_child("items", { ...this.item });
'item_code': this.item.item_code,
'item_name': this.item.item_name,
'price_list_rate': this.item.price_list_rate,
'rate': this.item.rate,
'qty': batch.selected_qty,
'batch_no': batch_no,
'actual_qty': this.item.actual_qty,
'discount_percentage': this.item.discount_percentage
});
} else { } else {
row = this.frm.doc.items.find(i => i.batch_no === batch_no); row = this.frm.doc.items.find(i => i.batch_no === batch_no);
} }
@ -228,16 +225,59 @@ erpnext.SerialNoBatchSelector = Class.extend({
if (!row) { if (!row) {
row = this.item; row = this.item;
} }
// this ensures that qty & batch no is set
this.map_row_values(row, batch, 'batch_no', this.map_row_values(row, batch, 'batch_no',
'selected_qty', this.values.warehouse); 'selected_qty', this.values.warehouse);
}); });
} else { }
},
update_serial_no_item() {
// just updates serial no for the item
if(this.has_serial_no && !this.has_batch) {
this.map_row_values(this.item, this.values, 'serial_no', 'qty'); this.map_row_values(this.item, this.values, 'serial_no', 'qty');
} }
},
refresh_field("items"); update_batch_serial_no_items() {
this.callback && this.callback(this.item); // if serial no selected is from different batches, adds new rows for each batch.
if(this.has_batch && this.has_serial_no) {
const selected_serial_nos = this.values.serial_no.split(/\n/g).filter(s => s);
return frappe.db.get_list("Serial No", {
filters: { 'name': ["in", selected_serial_nos]},
fields: ["batch_no", "name"]
}).then((data) => {
// data = [{batch_no: 'batch-1', name: "SR-001"},
// {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
const batch_serial_map = data.reduce((acc, d) => {
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
acc[d['batch_no']].push(d['name'])
return acc
}, {})
// batch_serial_map = { "batch-1": ['SR-001'], "batch-2": ["SR-003", "SR-004"]}
Object.keys(batch_serial_map).map((batch_no, i) => {
let row = '';
const serial_no = batch_serial_map[batch_no];
if (i == 0) {
row = this.item;
this.map_row_values(row, {qty: serial_no.length, batch_no: batch_no}, 'batch_no',
'qty', this.values.warehouse);
} else if (!this.batch_exists(batch_no)) {
row = this.frm.add_child("items", { ...this.item });
row.batch_no = batch_no;
} else {
row = this.frm.doc.items.find(i => i.batch_no === batch_no);
}
const values = {
'qty': serial_no.length,
'serial_no': serial_no.join('\n')
}
this.map_row_values(row, values, 'serial_no',
'qty', this.values.warehouse);
});
})
}
}, },
batch_exists: function(batch) { batch_exists: function(batch) {
@ -287,7 +327,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
return { return {
filters: { filters: {
item_code: me.item_code, item_code: me.item_code,
warehouse: me.warehouse || me.warehouse_details.name warehouse: me.warehouse || typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : ''
}, },
query: 'erpnext.controllers.queries.get_batch_no' query: 'erpnext.controllers.queries.get_batch_no'
}; };
@ -313,11 +353,15 @@ erpnext.SerialNoBatchSelector = Class.extend({
frappe.throw(__(`Batch ${val} already selected.`)); frappe.throw(__(`Batch ${val} already selected.`));
return; return;
} }
let batch_number = me.item.batch_no ||
this.grid_row.on_grid_fields_dict.batch_no.get_value();
if (me.warehouse_details.name) { if (me.warehouse_details.name) {
frappe.call({ frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batch_qty', method: 'erpnext.stock.doctype.batch.batch.get_batch_qty',
args: { args: {
batch_no: me.item.batch_no, batch_no: batch_number,
warehouse: me.warehouse_details.name, warehouse: me.warehouse_details.name,
item_code: me.item_code item_code: me.item_code
}, },
@ -444,7 +488,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
{ {
fieldname: 'serial_no', fieldname: 'serial_no',
fieldtype: 'Small Text', fieldtype: 'Small Text',
label: __(me.has_batch ? 'Selected Batch Numbers' : 'Selected Serial Numbers'), label: __(me.has_batch && !me.has_serial_no ? 'Selected Batch Numbers' : 'Selected Serial Numbers'),
onchange: function() { onchange: function() {
me.serial_list = this.get_value() me.serial_list = this.get_value()
.replace(/\n/g, ' ').match(/\S+/g) || []; .replace(/\n/g, ' ').match(/\S+/g) || [];

View File

@ -109,7 +109,7 @@ def get_transactions(filters, as_dict=1):
WHERE gl.company = %(company)s WHERE gl.company = %(company)s
AND DATE(gl.posting_date) >= %(from_date)s AND DATE(gl.posting_date) >= %(from_date)s
AND DATE(gl.posting_date) <= %(to_date)s AND DATE(gl.posting_date) <= %(to_date)s
ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1) ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict)
return gl_entries return gl_entries
@ -160,7 +160,7 @@ def get_customers(filters):
and ccl.company = par.company and ccl.company = par.company
WHERE par.company = %(company)s WHERE par.company = %(company)s
AND par.parenttype = 'Customer'""", filters, as_dict=1, as_utf8=1) AND par.parenttype = 'Customer'""", filters, as_dict=1)
def get_suppliers(filters): def get_suppliers(filters):
@ -217,7 +217,7 @@ def get_suppliers(filters):
and con.is_primary_contact = '1' and con.is_primary_contact = '1'
WHERE par.company = %(company)s WHERE par.company = %(company)s
AND par.parenttype = 'Supplier'""", filters, as_dict=1, as_utf8=1) AND par.parenttype = 'Supplier'""", filters, as_dict=1)
def get_account_names(filters): def get_account_names(filters):

View File

@ -54,8 +54,8 @@ class Gstr1Report(object):
return self.columns, self.data return self.columns, self.data
def get_data(self): def get_data(self):
if self.filters.get("type_of_business") == "B2C Small": if self.filters.get("type_of_business") in ("B2C Small", "B2C Large"):
self.get_b2cs_data() self.get_b2c_data()
else: else:
for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv) invoice_details = self.invoices.get(inv)
@ -69,7 +69,7 @@ class Gstr1Report(object):
if taxable_value: if taxable_value:
self.data.append(row) self.data.append(row)
def get_b2cs_data(self): def get_b2c_data(self):
b2cs_output = {} b2cs_output = {}
for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
@ -84,7 +84,10 @@ class Gstr1Report(object):
"rate": "", "rate": "",
"taxable_value": 0, "taxable_value": 0,
"cess_amount": 0, "cess_amount": 0,
"type": "" "type": "",
"invoice_number": invoice_details.get("invoice_number"),
"posting_date": invoice_details.get("posting_date"),
"invoice_value": invoice_details.get("base_grand_total"),
}) })
row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin)) row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
@ -164,7 +167,7 @@ class Gstr1Report(object):
frappe.throw(_("Please set B2C Limit in GST Settings.")) frappe.throw(_("Please set B2C Limit in GST Settings."))
if self.filters.get("type_of_business") == "B2C Large": if self.filters.get("type_of_business") == "B2C Large":
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2) conditions += """ and ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit)) and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "B2C Small": elif self.filters.get("type_of_business") == "B2C Small":
@ -581,6 +584,11 @@ def get_b2b_json(res, gstin):
if not gst_in: continue if not gst_in: continue
for number, invoice in iteritems(res[gst_in]): for number, invoice in iteritems(res[gst_in]):
if not invoice[0]["place_of_supply"]:
frappe.throw(_("""{0} not entered in Invoice {1}.
Please update and try again""").format(frappe.bold("Place Of Supply"),
frappe.bold(invoice[0]['invoice_number'])))
inv_item = get_basic_invoice_detail(invoice[0]) inv_item = get_basic_invoice_detail(invoice[0])
inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0]) inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0])
inv_item["rchrg"] = invoice[0]["reverse_charge"] inv_item["rchrg"] = invoice[0]["reverse_charge"]
@ -606,6 +614,9 @@ def get_b2cs_json(data, gstin):
out = [] out = []
for d in data: for d in data:
if not d.get("place_of_supply"):
frappe.throw(_("""{0} not entered in some invoices.
Please update and try again""").format(frappe.bold("Place Of Supply")))
pos = d.get('place_of_supply').split('-')[0] pos = d.get('place_of_supply').split('-')[0]
tax_details = {} tax_details = {}
@ -642,6 +653,10 @@ def get_b2cs_json(data, gstin):
def get_b2cl_json(res, gstin): def get_b2cl_json(res, gstin):
out = [] out = []
for pos in res: for pos in res:
if not pos:
frappe.throw(_("""{0} not entered in some invoices.
Please update and try again""").format(frappe.bold("Place Of Supply")))
b2cl_item, inv = {"pos": "%02d" % int(pos.split('-')[0]), "inv": []}, [] b2cl_item, inv = {"pos": "%02d" % int(pos.split('-')[0]), "inv": []}, []
for row in res[pos]: for row in res[pos]:

View File

@ -268,9 +268,11 @@ def make_quotation(source_name, target_doc=None):
target_doc.run_method("set_other_charges") target_doc.run_method("set_other_charges")
target_doc.run_method("calculate_taxes_and_totals") target_doc.run_method("calculate_taxes_and_totals")
price_list = frappe.get_value("Customer", source_name, 'default_price_list') price_list, currency = frappe.db.get_value("Customer", {'name': source_name}, ['default_price_list', 'default_currency'])
if price_list: if price_list:
target_doc.selling_price_list = price_list target_doc.selling_price_list = price_list
if currency:
target_doc.currency = currency
return target_doc return target_doc

View File

@ -413,15 +413,20 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
*/ */
set_batch_number: function(cdt, cdn) { set_batch_number: function(cdt, cdn) {
const doc = frappe.get_doc(cdt, cdn); const doc = frappe.get_doc(cdt, cdn);
if (doc && doc.has_batch_no) { if (doc && doc.has_batch_no && doc.warehouse) {
this._set_batch_number(doc); this._set_batch_number(doc);
} }
}, },
_set_batch_number: function(doc) { _set_batch_number: function(doc) {
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
if (doc.has_serial_no && doc.serial_no) {
args['serial_no'] = doc.serial_no
}
return frappe.call({ return frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batch_no', method: 'erpnext.stock.doctype.batch.batch.get_batch_no',
args: {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)}, args: args,
callback: function(r) { callback: function(r) {
if(r.message) { if(r.message) {
frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message); frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message);

View File

@ -157,6 +157,7 @@
{ {
"fieldname": "parent_company", "fieldname": "parent_company",
"fieldtype": "Link", "fieldtype": "Link",
"ignore_user_permissions": 1,
"in_list_view": 1, "in_list_view": 1,
"label": "Parent Company", "label": "Parent Company",
"options": "Company" "options": "Company"
@ -277,6 +278,7 @@
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"", "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"",
"fieldname": "existing_company", "fieldname": "existing_company",
"fieldtype": "Link", "fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Existing Company ", "label": "Existing Company ",
"no_copy": 1, "no_copy": 1,
"options": "Company" "options": "Company"
@ -728,7 +730,7 @@
"image_field": "company_logo", "image_field": "company_logo",
"is_tree": 1, "is_tree": 1,
"links": [], "links": [],
"modified": "2020-03-18 18:09:53.534211", "modified": "2020-03-21 18:09:53.534211",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Company", "name": "Company",

View File

@ -122,8 +122,11 @@ class Batch(Document):
self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days) self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days)
if has_expiry_date and not self.expiry_date: if has_expiry_date and not self.expiry_date:
frappe.msgprint(_('Expiry date is mandatory for selected item.')) frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \
frappe.throw(_("Set item's shelf life in days, to set expiry based on manufacturing date plus shelf-life.")) .format(frappe.bold("Shelf Life in Days"),
frappe.utils.get_link_to_form("Item", self.item),
frappe.bold("Batch Expiry Date")),
title=_("Expiry Date Mandatory"))
def get_name_from_naming_series(self): def get_name_from_naming_series(self):
""" """

View File

@ -238,7 +238,7 @@ class DeliveryTrip(Document):
try: try:
directions = maps_client.directions(**directions_data) directions = maps_client.directions(**directions_data)
except Exception as e: except Exception as e:
frappe.throw(_(e)) frappe.throw(_(str(e)))
return directions[0] if directions else False return directions[0] if directions else False

View File

@ -343,7 +343,8 @@
{ {
"fieldname": "shelf_life_in_days", "fieldname": "shelf_life_in_days",
"fieldtype": "Int", "fieldtype": "Int",
"label": "Shelf Life In Days" "label": "Shelf Life In Days",
"mandatory_depends_on": "eval:doc.has_batch_no && doc.has_expiry_date"
}, },
{ {
"default": "2099-12-31", "default": "2099-12-31",
@ -1045,7 +1046,7 @@
"image_field": "image", "image_field": "image",
"links": [], "links": [],
"max_attachments": 1, "max_attachments": 1,
"modified": "2020-01-02 19:13:59.295963", "modified": "2020-03-24 16:14:36.950677",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Item", "name": "Item",

View File

@ -523,12 +523,15 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note):
return serial_nos return serial_nos
@frappe.whitelist() @frappe.whitelist()
def auto_fetch_serial_number(qty, item_code, warehouse, batch_no=None): def auto_fetch_serial_number(qty, item_code, warehouse, batch_nos=None):
serial_numbers = frappe.get_list("Serial No", filters={ import json
filters = {
"item_code": item_code, "item_code": item_code,
"warehouse": warehouse, "warehouse": warehouse,
"batch_no": batch_no,
"delivery_document_no": "", "delivery_document_no": "",
"sales_invoice": "" "sales_invoice": ""
}, limit=qty, order_by="creation") }
if batch_nos: filters["batch_no"] = ["in", json.loads(batch_nos)]
serial_numbers = frappe.get_list("Serial No", filters=filters, limit=qty, order_by="creation")
return [item['name'] for item in serial_numbers] return [item['name'] for item in serial_numbers]

View File

@ -60,7 +60,8 @@ frappe.ui.form.on('Stock Entry', {
} }
} }
if(item.s_warehouse) filters["warehouse"] = item.s_warehouse; filters["warehouse"] = item.s_warehouse || item.t_warehouse;
return { return {
query : "erpnext.controllers.queries.get_batch_no", query : "erpnext.controllers.queries.get_batch_no",
filters: filters filters: filters
@ -964,7 +965,7 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => {
} }
} }
if(item && !item.has_serial_no && item.has_batch_no) return; if(item && !item.has_serial_no && !item.has_batch_no) return;
if (frm.doc.purpose === 'Material Receipt') return; if (frm.doc.purpose === 'Material Receipt') return;
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() { frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2013-03-29 18:22:12", "creation": "2013-03-29 18:22:12",
"doctype": "DocType", "doctype": "DocType",
@ -479,8 +480,7 @@
"fieldname": "project", "fieldname": "project",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Project", "label": "Project",
"options": "Project", "options": "Project"
"read_only": 1
}, },
{ {
"fieldname": "po_detail", "fieldname": "po_detail",
@ -494,7 +494,8 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2019-08-20 14:01:02.319754", "links": [],
"modified": "2020-03-19 12:34:09.836295",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Entry Detail", "name": "Stock Entry Detail",

View File

@ -7,6 +7,8 @@ import frappe
def create_test_contact_and_address(): def create_test_contact_and_address():
frappe.db.sql('delete from tabContact') frappe.db.sql('delete from tabContact')
frappe.db.sql('delete from `tabContact Email`')
frappe.db.sql('delete from `tabContact Phone`')
frappe.db.sql('delete from tabAddress') frappe.db.sql('delete from tabAddress')
frappe.db.sql('delete from `tabDynamic Link`') frappe.db.sql('delete from `tabDynamic Link`')

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
import frappe.share import frappe.share
from frappe import _ from frappe import _
from frappe.utils import cstr, now_datetime, cint, flt, get_time from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_link_to_form
from erpnext.controllers.status_updater import StatusUpdater from erpnext.controllers.status_updater import StatusUpdater
from six import string_types from six import string_types
@ -123,8 +123,11 @@ class TransactionBase(StatusUpdater):
ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate") ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01: if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ") frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate)) .format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
.format(frappe.bold("Maintain Same Rate Throughout Sales Cycle"),
get_link_to_form("Selling Settings", "Selling Settings", frappe.bold("Selling Settings"))))
def get_link_filters(self, for_doctype): def get_link_filters(self, for_doctype):
if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype): if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):