Merge branch 'develop' of https://github.com/frappe/erpnext into develop

This commit is contained in:
Khushal Trivedi 2020-01-13 20:59:25 +05:30
commit 2848ce4b87
52 changed files with 695 additions and 269 deletions

View File

@ -90,7 +90,6 @@
"fieldtype": "Column Break"
},
{
"default": "Customer",
"fieldname": "party_type",
"fieldtype": "Link",
"in_list_view": 1,
@ -201,7 +200,7 @@
"fieldname": "reference_type",
"fieldtype": "Select",
"label": "Reference Type",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting"
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees"
},
{
"fieldname": "reference_name",
@ -272,7 +271,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2019-10-02 12:23:21.693443",
"modified": "2020-01-13 12:41:33.968025",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
@ -281,4 +280,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@ -2,6 +2,16 @@ cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
cur_frm.add_fetch("payment_gateway_account", "message", "message")
frappe.ui.form.on("Payment Request", {
setup: function(frm) {
frm.set_query("party_type", function() {
return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
};
});
}
})
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
if (frm.doc.reference_doctype) {
frappe.call({

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest, copy, time
from frappe.utils import nowdate, flt, getdate, cint
from frappe.utils import nowdate, flt, getdate, cint, add_days
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@ -1847,6 +1847,26 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
def test_item_tax_validity(self):
item = frappe.get_doc("Item", "_Test Item 2")
if item.taxes:
item.taxes = []
item.save()
item.append("taxes", {
"item_tax_template": "_Test Item Tax Template 1",
"valid_from": add_days(nowdate(), 1)
})
item.save()
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1"
self.assertRaises(frappe.ValidationError, sales_invoice.save)
item.taxes = []
item.save()
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")

View File

@ -65,6 +65,21 @@ frappe.query_reports["Trial Balance for Party"] = {
return party_type;
}
},
{
"fieldname": "account",
"label": __("Account"),
"fieldtype": "Link",
"options": "Account",
"get_query": function() {
var company = frappe.query_report.get_filter_value('company');
return {
"doctype": "Account",
"filters": {
"company": company,
}
}
}
},
{
"fieldname": "show_zero_values",
"label": __("Show zero values"),

View File

@ -20,7 +20,7 @@ def execute(filters=None):
def get_data(filters, show_party_name):
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
if filters.get('party_type') == 'Student':
elif filters.get('party_type') == 'Student':
party_name_field = 'first_name'
elif filters.get('party_type') == 'Shareholder':
party_name_field = 'title'
@ -96,13 +96,19 @@ def get_data(filters, show_party_name):
return data
def get_opening_balances(filters):
account_filter = ''
if filters.get('account'):
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
gle = frappe.db.sql("""
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
from `tabGL Entry`
where company=%(company)s
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
group by party""", {
{account_filter}
group by party""".format(account_filter=account_filter), {
"company": filters.company,
"from_date": filters.from_date,
"party_type": filters.party_type
@ -116,6 +122,11 @@ def get_opening_balances(filters):
return opening
def get_balances_within_period(filters):
account_filter = ''
if filters.get('account'):
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
gle = frappe.db.sql("""
select party, sum(debit) as debit, sum(credit) as credit
from `tabGL Entry`
@ -123,7 +134,8 @@ def get_balances_within_period(filters):
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
and ifnull(is_opening, 'No') = 'No'
group by party""", {
{account_filter}
group by party""".format(account_filter=account_filter), {
"company": filters.company,
"from_date": filters.from_date,
"to_date": filters.to_date,

View File

@ -891,3 +891,9 @@ def get_allow_cost_center_in_entry_of_bs_account():
def generator():
return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
def get_stock_accounts(company):
return frappe.get_all("Account", filters = {
"account_type": "Stock",
"company": company
})

View File

@ -338,25 +338,12 @@ frappe.ui.form.on('Asset', {
})
},
purchase_receipt: function(frm) {
purchase_receipt: (frm) => {
frm.trigger('toggle_reference_doc');
if (frm.doc.purchase_receipt) {
if (frm.doc.item_code) {
frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
frm.set_value('company', pr_doc.company);
frm.set_value('purchase_date', pr_doc.posting_date);
const item = pr_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
frm.set_value('purchase_receipt', '');
frappe.msgprint({
title: __('Invalid Purchase Receipt'),
message: __("The selected Purchase Receipt doesn't contains selected Asset Item."),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate);
frm.set_value('location', item.asset_location);
frm.events.set_values_from_purchase_doc(frm, 'Purchase Receipt', pr_doc)
});
} else {
frm.set_value('purchase_receipt', '');
@ -368,24 +355,12 @@ frappe.ui.form.on('Asset', {
}
},
purchase_invoice: function(frm) {
purchase_invoice: (frm) => {
frm.trigger('toggle_reference_doc');
if (frm.doc.purchase_invoice) {
if (frm.doc.item_code) {
frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
frm.set_value('company', pi_doc.company);
frm.set_value('purchase_date', pi_doc.posting_date);
const item = pi_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
frm.set_value('purchase_invoice', '');
frappe.msgprint({
title: __('Invalid Purchase Invoice'),
message: __("The selected Purchase Invoice doesn't contains selected Asset Item."),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate);
frm.set_value('location', item.asset_location);
frm.events.set_values_from_purchase_doc(frm, 'Purchase Invoice', pi_doc)
});
} else {
frm.set_value('purchase_invoice', '');
@ -397,6 +372,24 @@ frappe.ui.form.on('Asset', {
}
},
set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
frm.set_value('company', purchase_doc.company);
frm.set_value('purchase_date', purchase_doc.posting_date);
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
doctype_field = frappe.scrub(doctype)
frm.set_value(doctype_field, '');
frappe.msgprint({
title: __(`Invalid ${doctype}`),
message: __(`The selected ${doctype} doesn't contains selected Asset Item.`),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('location', item.asset_location);
},
set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation
&& row.expected_value_after_useful_life) {

View File

@ -132,9 +132,10 @@ class Asset(AccountsController):
if len(movements) > 1:
frappe.throw(_('Asset has multiple Asset Movement Entries which has to be \
cancelled manually to cancel this asset.'))
movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
movement.flags.ignore_validate = True
movement.cancel()
if movements:
movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
movement.flags.ignore_validate = True
movement.cancel()
def make_asset_movement(self):
reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'

View File

@ -348,6 +348,12 @@ def get_data():
"is_query_report": True,
"name": "Subcontracted Item To Be Received",
"doctype": "Purchase Order"
},
{
"type": "report",
"is_query_report": True,
"name": "Stock and Account Value Comparison",
"doctype": "Stock Ledger Entry"
}
]
},

View File

@ -4,9 +4,9 @@
from __future__ import unicode_literals
import frappe
from frappe.desk.reportview import get_match_cond, get_filters_cond
from frappe.utils import nowdate
from frappe.utils import nowdate, getdate
from collections import defaultdict
from erpnext.stock.get_item_details import _get_item_tax_template
# searches for active employees
def employee_query(doctype, txt, searchfield, start, page_len, filters):
@ -486,7 +486,7 @@ def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters)
@frappe.whitelist()
def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
query = """
select pr.name
select pr.name
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pritem
where pr.docstatus = 1 and pritem.parent = pr.name
and pr.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
@ -499,7 +499,7 @@ def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
query = """
select pi.name
select pi.name
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` piitem
where pi.docstatus = 1 and piitem.parent = pi.name
and pi.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
@ -508,3 +508,27 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
query += " and piitem.item_code = {item_code}".format(item_code = frappe.db.escape(filters.get('item_code')))
return frappe.db.sql(query, filters)
@frappe.whitelist()
def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))
item_group = filters.get('item_group')
taxes = item_doc.taxes or []
while item_group:
item_group_doc = frappe.get_cached_doc('Item Group', item_group)
taxes += item_group_doc.taxes or []
item_group = item_group_doc.parent_item_group
if not taxes:
return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """)
else:
args = {
'item_code': filters.get('item_code'),
'posting_date': filters.get('valid_from'),
'tax_category': filters.get('tax_category')
}
taxes = _get_item_tax_template(args, taxes, for_validate=True)
return [(d,) for d in set(taxes)]

View File

@ -8,6 +8,7 @@ from frappe import _, scrub
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax
from erpnext.stock.get_item_details import _get_item_tax_template
class calculate_taxes_and_totals(object):
def __init__(self, doc):
@ -34,6 +35,7 @@ class calculate_taxes_and_totals(object):
def _calculate(self):
self.validate_conversion_rate()
self.calculate_item_values()
self.validate_item_tax_template()
self.initialize_taxes()
self.determine_exclusive_rate()
self.calculate_net_total()
@ -43,6 +45,38 @@ class calculate_taxes_and_totals(object):
self._cleanup()
self.calculate_total_net_weight()
def validate_item_tax_template(self):
for item in self.doc.get('items'):
if item.item_code and item.get('item_tax_template'):
item_doc = frappe.get_cached_doc("Item", item.item_code)
args = {
'tax_category': self.doc.get('tax_category'),
'posting_date': self.doc.get('posting_date'),
'bill_date': self.doc.get('bill_date'),
'transaction_date': self.doc.get('transaction_date')
}
item_group = item_doc.item_group
item_group_taxes = []
while item_group:
item_group_doc = frappe.get_cached_doc('Item Group', item_group)
item_group_taxes += item_group_doc.taxes or []
item_group = item_group_doc.parent_item_group
item_taxes = item_doc.taxes or []
if not item_group_taxes and (not item_taxes):
# No validation if no taxes in item or item group
continue
taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
if item.item_tax_template not in taxes:
frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format(
item.idx, frappe.bold(item.item_code)
))
def validate_conversion_rate(self):
# validate conversion rate
company_currency = erpnext.get_company_currency(self.doc.company)

View File

@ -1,4 +1,5 @@
{
"actions": [],
"creation": "2018-10-25 10:02:48.656165",
"doctype": "DocType",
"editable_grid": 1,
@ -23,48 +24,41 @@
},
{
"default": "0",
"depends_on": "eval:doc.enabled==1",
"depends_on": "enabled",
"fieldname": "automatic_sync",
"fieldtype": "Check",
"label": "Synchronize all accounts every hour"
},
{
"depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_client_id",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Plaid Client ID",
"reqd": 1
"label": "Plaid Client ID"
},
{
"depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_secret",
"fieldtype": "Password",
"in_list_view": 1,
"label": "Plaid Secret",
"reqd": 1
"label": "Plaid Secret"
},
{
"depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_public_key",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Plaid Public Key",
"reqd": 1
"label": "Plaid Public Key"
},
{
"depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_env",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Plaid Environment",
"reqd": 1
"label": "Plaid Environment"
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"depends_on": "enabled",
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
@ -74,7 +68,8 @@
}
],
"issingle": 1,
"modified": "2019-08-13 17:00:06.939422",
"links": [],
"modified": "2020-01-05 10:00:22.137832",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Plaid Settings",

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
from frappe.utils import nowdate
class ClinicalProcedureTemplate(Document):
@ -116,7 +117,7 @@ def change_item_code_from_template(item_code, doc):
"item_code": item_code})):
frappe.throw(_("Code {0} already exist").format(item_code))
else:
frappe.rename_doc("Item", doc.item_code, item_code, ignore_permissions = True)
rename_doc("Item", doc.item_code, item_code, ignore_permissions=True)
frappe.db.set_value("Clinical Procedure Template", doc.name, "item_code", item_code)
return

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
class HealthcareServiceUnitType(Document):
def validate(self):
@ -107,7 +108,7 @@ def change_item_code(item, item_code, doc_name):
if(item_exist):
frappe.throw(_("Code {0} already exist").format(item_code))
else:
frappe.rename_doc("Item", item, item_code, ignore_permissions = True)
rename_doc("Item", item, item_code, ignore_permissions=True)
frappe.db.set_value("Healthcare Service Unit Type", doc_name, "item_code", item_code)
@frappe.whitelist()

View File

@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe, json
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
from frappe import _
class LabTestTemplate(Document):
@ -112,9 +113,9 @@ def change_test_code_from_template(lab_test_code, doc):
if(item_exist):
frappe.throw(_("Code {0} already exist").format(lab_test_code))
else:
frappe.rename_doc("Item", doc.name, lab_test_code, ignore_permissions = True)
rename_doc("Item", doc.name, lab_test_code, ignore_permissions=True)
frappe.db.set_value("Lab Test Template",doc.name,"lab_test_code",lab_test_code)
frappe.rename_doc("Lab Test Template", doc.name, lab_test_code, ignore_permissions = True)
rename_doc("Lab Test Template", doc.name, lab_test_code, ignore_permissions=True)
return lab_test_code
@frappe.whitelist()

View File

@ -2,10 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('HR Settings', {
refresh: function(frm) {
},
encrypt_salary_slips_in_emails: function(frm) {
let encrypt_state = frm.doc.encrypt_salary_slips_in_emails;
frm.set_df_property('password_policy', 'reqd', encrypt_state);
@ -19,5 +15,9 @@ frappe.ui.form.on('HR Settings', {
}
frm.set_value('password_policy', policy.split(new RegExp(" |-", 'g')).filter((token) => token).join('-'));
}
},
restrict_backdated_leave_application: function(frm) {
frm.toggle_reqd("role_allowed_to_create_backdated_leave_application", frm.doc.restrict_backdated_leave_application);
}
});
});

View File

@ -23,10 +23,12 @@
"leave_settings",
"leave_approval_notification_template",
"leave_status_notification_template",
"role_allowed_to_create_backdated_leave_application",
"column_break_18",
"leave_approver_mandatory_in_leave_application",
"show_leaves_of_all_department_members_in_calendar",
"auto_leave_encashment",
"restrict_backdated_leave_application",
"hiring_settings",
"check_vacancies"
],
@ -169,13 +171,26 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
},
{
"default": "0",
"fieldname": "restrict_backdated_leave_application",
"fieldtype": "Check",
"label": "Restrict Backdated Leave Application"
},
{
"depends_on": "eval:doc.restrict_backdated_leave_application == 1",
"fieldname": "role_allowed_to_create_backdated_leave_application",
"fieldtype": "Link",
"label": "Role Allowed to Create Backdated Leave Application",
"options": "Role"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2019-12-31 14:28:32.004121",
"modified": "2020-01-06 18:46:30.189815",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",

View File

@ -79,6 +79,12 @@ class LeaveApplication(Document):
frappe.throw(_("{0} applicable after {1} working days").format(self.leave_type, leave_type.applicable_after))
def validate_dates(self):
if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"):
if self.from_date and self.from_date < frappe.utils.today():
allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application")
if allowed_role not in frappe.get_roles():
frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role))
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
frappe.throw(_("To date cannot be before from date"))

View File

@ -645,7 +645,6 @@ erpnext.patches.v12_0.set_expense_account_in_landed_cost_voucher_taxes
erpnext.patches.v12_0.replace_accounting_with_accounts_in_home_settings
erpnext.patches.v12_0.set_payment_entry_status
erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields
erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template
erpnext.patches.v12_0.add_export_type_field_in_party_master
erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger
erpnext.patches.v12_0.update_price_or_product_discount

View File

@ -4,19 +4,18 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
from frappe.model.utils.rename_field import rename_field
def execute():
# Rename and reload the Land Unit and Linked Land Unit doctypes
if frappe.db.table_exists('Land Unit') and not frappe.db.table_exists('Location'):
rename_doc('DocType', 'Land Unit', 'Location', force=True)
frappe.rename_doc('DocType', 'Land Unit', 'Location', force=True)
frappe.reload_doc('assets', 'doctype', 'location')
if frappe.db.table_exists('Linked Land Unit') and not frappe.db.table_exists('Linked Location'):
rename_doc('DocType', 'Linked Land Unit', 'Linked Location', force=True)
frappe.rename_doc('DocType', 'Linked Land Unit', 'Linked Location', force=True)
frappe.reload_doc('assets', 'doctype', 'linked_location')

View File

@ -3,9 +3,9 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
def execute():
if frappe.db.table_exists("Asset Adjustment") and not frappe.db.table_exists("Asset Value Adjustment"):
rename_doc('DocType', 'Asset Adjustment', 'Asset Value Adjustment', force=True)
frappe.rename_doc('DocType', 'Asset Adjustment', 'Asset Value Adjustment', force=True)
frappe.reload_doc('assets', 'doctype', 'asset_value_adjustment')

View File

@ -2,9 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
from frappe.model.rename_doc import rename_doc
import frappe
def execute():
rename_doc('DocType', 'Health Insurance', 'Employee Health Insurance', force=True)
frappe.rename_doc('DocType', 'Health Insurance', 'Employee Health Insurance', force=True)
frappe.reload_doc('hr', 'doctype', 'employee_health_insurance')

View File

@ -1,6 +1,5 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
from frappe.model.utils.rename_field import rename_field
from frappe.modules import scrub, get_doctype_module
@ -37,7 +36,7 @@ doc_rename_map = {
def execute():
for dt in doc_rename_map:
if frappe.db.exists('DocType', dt):
rename_doc('DocType', dt, doc_rename_map[dt], force=True)
frappe.rename_doc('DocType', dt, doc_rename_map[dt], force=True)
for dn in field_rename_map:
if frappe.db.exists('DocType', dn):

View File

@ -2,18 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
from frappe.model.rename_doc import rename_doc
from frappe.model.utils.rename_field import rename_field
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
rename_doc('DocType', 'Production Order', 'Work Order', force=True)
frappe.rename_doc('DocType', 'Production Order', 'Work Order', force=True)
frappe.reload_doc('manufacturing', 'doctype', 'work_order')
rename_doc('DocType', 'Production Order Item', 'Work Order Item', force=True)
frappe.rename_doc('DocType', 'Production Order Item', 'Work Order Item', force=True)
frappe.reload_doc('manufacturing', 'doctype', 'work_order_item')
rename_doc('DocType', 'Production Order Operation', 'Work Order Operation', force=True)
frappe.rename_doc('DocType', 'Production Order Operation', 'Work Order Operation', force=True)
frappe.reload_doc('manufacturing', 'doctype', 'work_order_operation')
frappe.reload_doc('projects', 'doctype', 'timesheet')

View File

@ -1,6 +1,5 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
from frappe.model.utils.rename_field import rename_field
from frappe import _
from frappe.utils.nestedset import rebuild_tree
@ -9,7 +8,7 @@ def execute():
if frappe.db.table_exists("Supplier Group"):
frappe.reload_doc('setup', 'doctype', 'supplier_group')
elif frappe.db.table_exists("Supplier Type"):
rename_doc("DocType", "Supplier Type", "Supplier Group", force=True)
frappe.rename_doc("DocType", "Supplier Type", "Supplier Group", force=True)
frappe.reload_doc('setup', 'doctype', 'supplier_group')
frappe.reload_doc("accounts", "doctype", "pricing_rule")
frappe.reload_doc("accounts", "doctype", "tax_rule")

View File

@ -60,10 +60,10 @@ def execute():
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice'
]
for dt in doctypes:
for d in frappe.db.sql("""select name, parenttype, parent, item_code, item_tax_rate from `tab{0} Item`
where ifnull(item_tax_rate, '') not in ('', '{{}}')
where ifnull(item_tax_rate, '') not in ('', '{{}}')
and item_tax_template is NULL""".format(dt), as_dict=1):
item_tax_map = json.loads(d.item_tax_rate)
item_tax_template_name = get_item_tax_template(item_tax_templates,
@ -98,12 +98,15 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
company = get_company(parts[-1], parenttype, parent)
parent_account = frappe.db.get_value("Account",
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
if not parent_account:
parent_account = frappe.db.get_value("Account",
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 1, "company": company})
filters = {
"account_name": account_name,
"company": company,
"account_type": "Tax",
"parent_account": parent_account
}
"company": company,
"account_type": "Tax",
"parent_account": parent_account
}
tax_type = frappe.db.get_value("Account", filters)
if not tax_type:
account = frappe.new_doc("Account")

View File

@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
doctypes = {
'Price Discount Slab': 'Promotional Scheme Price Discount',
@ -16,6 +15,6 @@ doctypes = {
def execute():
for old_doc, new_doc in doctypes.items():
if not frappe.db.table_exists(new_doc) and frappe.db.table_exists(old_doc):
rename_doc('DocType', old_doc, new_doc)
frappe.rename_doc('DocType', old_doc, new_doc)
frappe.reload_doc("accounts", "doctype", frappe.scrub(new_doc))
frappe.delete_doc("DocType", old_doc)

View File

@ -1,5 +0,0 @@
import frappe
def execute():
frappe.db.set_value("Accounts Settings", None, "add_taxes_from_item_tax_template", 1)
frappe.db.set_default("add_taxes_from_item_tax_template", 1)

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.rename_doc import rename_doc
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
@ -20,11 +21,11 @@ def execute():
if frappe.db.exists("Domain", domain):
merge=True
frappe.rename_doc("Domain", translated_domain, domain, ignore_permissions=True, merge=merge)
rename_doc("Domain", translated_domain, domain, ignore_permissions=True, merge=merge)
domain_settings = frappe.get_single("Domain Settings")
active_domains = [d.domain for d in domain_settings.active_domains]
try:
for domain in active_domains:
domain = frappe.get_doc("Domain", domain)

View File

@ -107,6 +107,12 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
filters:{ 'item_code': row.item_code }
}
});
if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
return me.set_query_for_item_tax_template(doc, cdt, cdn)
});
}
},
refresh: function(doc) {

View File

@ -968,7 +968,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
qty: function(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
this.conversion_factor(doc, cdt, cdn, true);
this.conversion_factor(doc, cdt, cdn, false);
this.apply_pricing_rule(item, true);
},
@ -1700,6 +1700,29 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
},
set_query_for_item_tax_template: function(doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if(!item.item_code) {
frappe.throw(__("Please enter Item Code to get item taxes"));
} else {
let filters = {
'item_code': item.item_code,
'valid_from': doc.transaction_date || doc.bill_date || doc.posting_date,
'item_group': item.item_group,
}
if (doc.tax_category)
filters['tax_category'] = doc.tax_category;
return {
query: "erpnext.controllers.queries.get_tax_template",
filters: filters
}
}
},
payment_terms_template: function() {
var me = this;
const doc = this.frm.doc;

View File

@ -25,5 +25,9 @@ def update_item_document(items, taxes):
item_to_be_updated.taxes = []
for tax in taxes:
tax = frappe._dict(tax)
item_to_be_updated.append("taxes", {'item_tax_template': tax.item_tax_template, 'tax_category': tax.tax_category})
item_to_be_updated.append("taxes", {
'item_tax_template': tax.item_tax_template,
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
item_to_be_updated.save()

View File

@ -6,7 +6,7 @@
frappe.ui.form.on("Sales Order", {
setup: function(frm) {
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Delivery Note': 'Delivery Note',
'Pick List': 'Pick List',
'Sales Invoice': 'Invoice',
'Material Request': 'Material Request',
@ -135,7 +135,6 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
if(doc.status !== 'Closed') {
if(doc.status !== 'On Hold') {
allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
&& !this.frm.doc.skip_delivery_note
@ -697,4 +696,4 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
});
}
});
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));

View File

@ -376,6 +376,9 @@ class SalesOrder(SellingController):
def get_work_order_items(self, for_raw_material_request=0):
'''Returns items with BOM that already do not have a linked work order'''
items = []
item_codes = [i.item_code for i in self.items]
product_bundle_parents = [pb.new_item_code for pb in frappe.get_all("Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"])]
for table in [self.items, self.packed_items]:
for i in table:
bom = get_default_bom_item(i.item_code)
@ -387,7 +390,7 @@ class SalesOrder(SellingController):
else:
pending_qty = stock_qty
if pending_qty:
if pending_qty and i.item_code not in product_bundle_parents:
if bom:
items.append(dict(
name= i.name,

View File

@ -84,6 +84,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
return me.set_query_for_batch(doc, cdt, cdn)
});
}
if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
return me.set_query_for_item_tax_template(doc, cdt, cdn)
});
}
},
refresh: function() {

View File

@ -76,7 +76,7 @@ class AuthorizationControl(TransactionBase):
add_cond = ''
auth_value = av_dis
if val == 1: add_cond += " and system_user = '"+session['user'].replace("'", "\\'")+"'"
if val == 1: add_cond += " and system_user = '"+ frappe.db.escape(session['user'])+"'"
elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.get_roles())+"')")
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
@ -85,7 +85,7 @@ class AuthorizationControl(TransactionBase):
if doc_obj:
if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
else: customer = doc_obj.customer_name
add_cond = " and master_name = '"+cstr(customer).replace("'", "\\'")+"'"
add_cond = " and master_name = '"+ frappe.db.escape(customer) +"'"
if based_on == 'Itemwise Discount':
if doc_obj:
for t in doc_obj.get("items"):

View File

@ -49,7 +49,7 @@ frappe.ui.form.on("Item", {
if (!frm.doc.is_fixed_asset) {
erpnext.item.make_dashboard(frm);
}
if (frm.doc.is_fixed_asset) {
frm.trigger('is_fixed_asset');
frm.trigger('auto_create_assets');
@ -136,14 +136,14 @@ frappe.ui.form.on("Item", {
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
},
gst_hsn_code: function(frm){
if(!frm.doc.taxes){
frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc=>{
frm.doc.taxes = [];
gst_hsn_code: function(frm) {
if(!frm.doc.taxes || !frm.doc.taxes.length) {
frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
$.each(hsn_doc.taxes || [], function(i, tax) {
let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
a.item_tax_template = tax.item_tax_template;
a.tax_category = tax.tax_category;
a.valid_from = tax.valid_from;
frm.refresh_field('taxes');
});
});

View File

@ -11,7 +11,6 @@ from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsE
InvalidItemAttributeValueError, get_variant)
from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode
from erpnext.stock.doctype.item.item import get_uom_conv_factor
from frappe.model.rename_doc import rename_doc
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.get_item_details import get_item_details
@ -348,7 +347,7 @@ class TestItem(unittest.TestCase):
make_stock_entry(item_code="Test Item for Merging 2", target="_Test Warehouse 1 - _TC",
qty=1, rate=100)
rename_doc("Item", "Test Item for Merging 1", "Test Item for Merging 2", merge=True)
frappe.rename_doc("Item", "Test Item for Merging 1", "Test Item for Merging 2", merge=True)
self.assertFalse(frappe.db.exists("Item", "Test Item for Merging 1"))

View File

@ -1,107 +1,50 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-02-22 01:28:01",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 1,
"actions": [],
"creation": "2013-02-22 01:28:01",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item_tax_template",
"tax_category",
"valid_from"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_tax_template",
"fieldtype": "Link",
"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": "Item Tax Template",
"length": 0,
"no_copy": 0,
"oldfieldname": "tax_type",
"oldfieldtype": "Link",
"options": "Item Tax Template",
"permlevel": 0,
"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": 0
},
"fieldname": "item_tax_template",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Tax Template",
"oldfieldname": "tax_type",
"oldfieldtype": "Link",
"options": "Item Tax Template",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "",
"fieldname": "tax_category",
"fieldtype": "Link",
"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": "Tax Category",
"length": 0,
"no_copy": 0,
"oldfieldname": "tax_rate",
"oldfieldtype": "Currency",
"options": "Tax Category",
"permlevel": 0,
"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
"fieldname": "tax_category",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Tax Category",
"oldfieldname": "tax_rate",
"oldfieldtype": "Currency",
"options": "Tax Category"
},
{
"fieldname": "valid_from",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Valid From"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-12-21 23:52:40.798944",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Tax",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0,
"track_views": 0
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2019-12-28 21:54:40.807849",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Tax",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -230,7 +230,8 @@ frappe.ui.form.on('Material Request', {
make_purchase_order: function(frm) {
frappe.prompt(
{fieldname:'default_supplier', label: __('For Default Supplier (optional)'), fieldtype: 'Link', options: 'Supplier'},
{fieldname:'default_supplier', label: __('For Default Supplier (optional)'), description: __('Selected Supplier\
must be the Default Supplier of one of the items below.'), fieldtype: 'Link', options: 'Supplier'},
(values) => {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@ -238,7 +239,8 @@ frappe.ui.form.on('Material Request', {
args: { default_supplier: values.default_supplier },
run_link_triggers: true
});
}
},
__('Enter Supplier')
)
},

View File

@ -103,9 +103,8 @@ class StockEntry(StockController):
if self.work_order and self.purpose == "Material Consumption for Manufacture":
self.validate_work_order_status()
else:
self.update_work_order()
self.update_work_order()
self.update_stock_ledger()
self.make_gl_entries_on_cancel()
self.update_cost_in_project()
@ -479,10 +478,16 @@ class StockEntry(StockController):
def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost):
if self.purpose in ["Manufacture", "Repack"]:
for d in self.get("items"):
if d.transfer_qty and (d.bom_no or d.t_warehouse) and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse):
if (d.transfer_qty and (d.bom_no or d.t_warehouse) and raw_material_cost
and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
if (not d.basic_rate and self.work_order and
frappe.db.get_single_value("Manufacturing Settings", "material_consumption")):
d.basic_rate = get_valuation_rate_for_finished_good_entry(self.work_order) or 0
d.basic_amount = d.basic_rate * d.qty
def distribute_additional_costs(self):
if self.purpose == "Material Issue":
self.additional_costs = []
@ -833,7 +838,6 @@ class StockEntry(StockController):
(self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
and frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1):
self.get_unconsumed_raw_materials()
else:
if not self.fg_completed_qty:
frappe.throw(_("Manufacturing Quantity is mandatory"))
@ -1152,20 +1156,17 @@ class StockEntry(StockController):
se_child.s_warehouse = item_dict[d].get("from_warehouse")
se_child.t_warehouse = item_dict[d].get("to_warehouse")
se_child.item_code = item_dict[d].get('item_code') or cstr(d)
se_child.item_name = item_dict[d]["item_name"]
se_child.description = item_dict[d]["description"]
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
se_child.stock_uom = stock_uom
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
se_child.expense_account = item_dict[d].get("expense_account")
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
se_child.subcontracted_item = item_dict[d].get("main_item_code")
se_child.original_item = item_dict[d].get("original_item")
se_child.po_detail = item_dict[d].get("po_detail")
if item_dict[d].get("idx"):
se_child.idx = item_dict[d].get("idx")
for field in ["idx", "po_detail", "original_item",
"expense_account", "description", "item_name"]:
if item_dict[d].get(field):
se_child.set(field, item_dict[d].get(field))
if se_child.s_warehouse==None:
se_child.s_warehouse = self.from_warehouse
@ -1470,6 +1471,24 @@ def get_used_alternative_items(purchase_order=None, work_order=None):
return used_alternative_items
def get_valuation_rate_for_finished_good_entry(work_order):
work_order_qty = flt(frappe.get_cached_value("Work Order",
work_order, 'material_transferred_for_manufacturing'))
field = "(SUM(total_outgoing_value) / %s) as valuation_rate" % (work_order_qty)
stock_data = frappe.get_all("Stock Entry",
fields = field,
filters = {
"docstatus": 1,
"purpose": "Material Transfer for Manufacture",
"work_order": work_order
}
)
if stock_data:
return stock_data[0].valuation_rate
@frappe.whitelist()
def get_uom_details(item_code, uom, qty):
"""Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`

View File

@ -1,18 +1,22 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
from frappe.model.rename_doc import rename_doc
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
import unittest
import frappe
from frappe.utils import cint
from erpnext import set_perpetual_inventory
from frappe.test_runner import make_test_records
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
import erpnext
import frappe
import unittest
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext import set_perpetual_inventory
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
test_records = frappe.get_test_records('Warehouse')
class TestWarehouse(unittest.TestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
@ -41,7 +45,7 @@ class TestWarehouse(unittest.TestCase):
# Rename with abbr
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
@ -50,7 +54,7 @@ class TestWarehouse(unittest.TestCase):
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
@ -58,7 +62,7 @@ class TestWarehouse(unittest.TestCase):
# Another rename with multiple dashes
if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"):
frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
frappe.rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
def test_warehouse_merging(self):
set_perpetual_inventory(1)
@ -78,7 +82,7 @@ class TestWarehouse(unittest.TestCase):
{"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty"))
)
rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC",
frappe.rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC",
"Test Warehouse for Merging 2 - _TC", merge=True)
self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC"))

View File

@ -177,7 +177,26 @@ def convert_to_group_or_ledger():
return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
def get_child_warehouses(warehouse):
p_warehouse = frappe.get_doc("Warehouse", warehouse)
lft, rgt = frappe.get_cached_value("Warehouse", warehouse, [lft, rgt])
return frappe.db.sql_list("""select name from `tabWarehouse`
where lft >= %s and rgt =< %s""", (p_warehouse.lft, p_warehouse.rgt))
where lft >= %s and rgt =< %s""", (lft, rgt))
def get_warehouses_based_on_account(account, company=None):
warehouses = []
for d in frappe.get_all("Warehouse", fields = ["name", "is_group"],
filters = {"account": account}):
if d.is_group:
warehouses.extend(get_child_warehouses(d.name))
else:
warehouses.append(d.name)
if (not warehouses and company and
frappe.get_cached_value("Company", company, "default_inventory_account") == account):
warehouses = [d.name for d in frappe.get_all("Warehouse", filters={'is_group': 0})]
if not warehouses:
frappe.throw(_("Warehouse not found against the account {0}")
.format(account))
return warehouses

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, throw
from frappe.utils import flt, cint, add_days, cstr, add_months
from frappe.utils import flt, cint, add_days, cstr, add_months, getdate
import json, copy
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type
from erpnext.setup.utils import get_exchange_rate
@ -52,6 +52,16 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
out = get_basic_details(args, item, overwrite_warehouse)
if isinstance(doc, string_types):
doc = json.loads(doc)
if doc and doc.get('doctype') == 'Purchase Invoice':
args['bill_date'] = doc.get('bill_date')
if doc:
args['posting_date'] = doc.get('posting_date')
args['transaction_date'] = doc.get('transaction_date')
get_item_tax_template(args, item, out)
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
else out.get("item_tax_template"), as_json=True)
@ -395,7 +405,34 @@ def get_item_tax_template(args, item, out):
item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
item_group = item_group_doc.parent_item_group
def _get_item_tax_template(args, taxes, out):
def _get_item_tax_template(args, taxes, out={}, for_validate=False):
taxes_with_validity = []
taxes_with_no_validity = []
for tax in taxes:
if tax.valid_from:
# In purchase Invoice first preference will be given to supplier invoice date
# if supplier date is not present then posting date
validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
if getdate(tax.valid_from) <= getdate(validation_date):
taxes_with_validity.append(tax)
else:
taxes_with_no_validity.append(tax)
if taxes_with_validity:
taxes = sorted(taxes_with_validity, key = lambda i: i.valid_from, reverse=True)
else:
taxes = taxes_with_no_validity
if for_validate:
return [tax.item_tax_template for tax in taxes if (cstr(tax.tax_category) == cstr(args.get('tax_category')) \
and (tax.item_tax_template not in taxes))]
# all templates have validity and no template is valid
if not taxes_with_validity and (not taxes_with_no_validity):
return None
for tax in taxes:
if cstr(tax.tax_category) == cstr(args.get("tax_category")):
out["item_tax_template"] = tax.item_tax_template
@ -573,7 +610,7 @@ def get_item_price(args, item_code, ignore_party=False):
return frappe.db.sql(""" select name, price_list_rate, uom
from `tabItem Price` {conditions}
order by uom desc, min_qty desc """.format(conditions=conditions), args)
order by uom desc, min_qty desc, valid_from desc """.format(conditions=conditions), args)
def get_price_list_rate_for(args, item_code):
"""
@ -606,10 +643,15 @@ def get_price_list_rate_for(args, item_code):
if desired_qty and check_packing_list(price_list_rate[0][0], desired_qty, item_code):
item_price_data = price_list_rate
else:
for field in ["customer", "supplier", "min_qty"]:
for field in ["customer", "supplier"]:
del item_price_args[field]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
if not general_price_list_rate:
del item_price_args["min_qty"]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
if not general_price_list_rate and args.get("uom") != args.get("stock_uom"):
item_price_args["uom"] = args.get("stock_uom")
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))

View File

@ -0,0 +1,37 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Stock and Account Value Comparison"] = {
"filters": [
{
"label": __("Company"),
"fieldname": "company",
"fieldtype": "Link",
"options": "Company",
"reqd": 1,
"default": frappe.defaults.get_user_default("Company")
},
{
"label": __("Account"),
"fieldname": "account",
"fieldtype": "Link",
"options": "Account",
get_query: function() {
var company = frappe.query_report.get_filter_value('company');
return {
filters: {
"account_type": "Stock",
"company": company
}
}
}
},
{
"label": __("As On Date"),
"fieldname": "as_on_date",
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
},
]
};

View File

@ -0,0 +1,28 @@
{
"add_total_row": 1,
"creation": "2020-01-09 14:42:45.254751",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2020-01-09 14:42:45.254751",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock and Account Value Comparison",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Stock Ledger Entry",
"report_name": "Stock and Account Value Comparison",
"report_type": "Script Report",
"roles": [
{
"role": "Stock User"
},
{
"role": "Accounts Manager"
}
]
}

View File

@ -0,0 +1,131 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _
from erpnext.accounts.utils import get_stock_accounts
from erpnext.accounts.utils import get_currency_precision
from erpnext.stock.doctype.warehouse.warehouse import get_warehouses_based_on_account
def execute(filters=None):
if not erpnext.is_perpetual_inventory_enabled(filters.company):
frappe.throw(_("Perpetual inventory required for the company {0} to view this report.")
.format(filters.company))
data = get_data(filters)
columns = get_columns(filters)
return columns, data
def get_data(report_filters):
data = []
filters = {
"company": report_filters.company,
"posting_date": ("<=", report_filters.as_on_date)
}
currency_precision = get_currency_precision() or 2
stock_ledger_entries = get_stock_ledger_data(report_filters, filters)
voucher_wise_gl_data = get_gl_data(report_filters, filters)
for d in stock_ledger_entries:
key = (d.voucher_type, d.voucher_no)
gl_data = voucher_wise_gl_data.get(key) or {}
d.account_value = gl_data.get("account_value", 0)
d.difference_value = (d.stock_value - d.account_value)
if abs(d.difference_value) > 1.0/10 ** currency_precision:
data.append(d)
return data
def get_stock_ledger_data(report_filters, filters):
if report_filters.account:
warehouses = get_warehouses_based_on_account(report_filters.account,
report_filters.warehouse)
filters["warehouse"] = ("in", warehouses)
return frappe.get_all("Stock Ledger Entry", filters=filters,
fields = ["name", "voucher_type", "voucher_no",
"sum(stock_value_difference) as stock_value", "posting_date", "posting_time"],
group_by = "voucher_type, voucher_no",
order_by = "posting_date ASC, posting_time ASC")
def get_gl_data(report_filters, filters):
if report_filters.account:
stock_accounts = [report_filters.account]
else:
stock_accounts = [k.name
for k in get_stock_accounts(report_filters.company)]
filters.update({
"account": ("in", stock_accounts)
})
if filters.get("warehouse"):
del filters["warehouse"]
gl_entries = frappe.get_all("GL Entry", filters=filters,
fields = ["name", "voucher_type", "voucher_no",
"sum(debit_in_account_currency) - sum(credit_in_account_currency) as account_value"],
group_by = "voucher_type, voucher_no")
voucher_wise_gl_data = {}
for d in gl_entries:
key = (d.voucher_type, d.voucher_no)
voucher_wise_gl_data[key] = d
return voucher_wise_gl_data
def get_columns(filters):
return [
{
"label": _("Stock Ledger ID"),
"fieldname": "name",
"fieldtype": "Link",
"options": "Stock Ledger Entry",
"width": "80"
},
{
"label": _("Posting Date"),
"fieldname": "posting_date",
"fieldtype": "Date"
},
{
"label": _("Posting Time"),
"fieldname": "posting_time",
"fieldtype": "Time"
},
{
"label": _("Voucher Type"),
"fieldname": "voucher_type",
"width": "110"
},
{
"label": _("Voucher No"),
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
"options": "voucher_type",
"width": "110"
},
{
"label": _("Stock Value"),
"fieldname": "stock_value",
"fieldtype": "Currency",
"width": "120"
},
{
"label": _("Account Value"),
"fieldname": "account_value",
"fieldtype": "Currency",
"width": "120"
},
{
"label": _("Difference Value"),
"fieldname": "difference_value",
"fieldtype": "Currency",
"width": "120"
}
]

View File

@ -264,7 +264,7 @@ def get_item_details(items, sle, filters):
`tabItem` item
%s
where
item.name in (%s) and ifnull(item.disabled, 0) = 0
item.name in (%s)
""" % (cf_field, cf_join, ','.join(['%s'] *len(items))), items, as_dict=1)
for item in res:

View File

@ -212,7 +212,7 @@ class update_entries_after(object):
def get_serialized_values(self, sle):
incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty)
serial_no = cstr(sle.serial_no).split("\n")
serial_nos = cstr(sle.serial_no).split("\n")
if incoming_rate < 0:
# wrong incoming rate
@ -224,9 +224,8 @@ class update_entries_after(object):
elif actual_qty < 0:
# In case of delivery/stock issue, get average purchase rate
# of serial nos of current entry
stock_value_change = -1 * flt(frappe.get_all("Serial No",
fields=["sum(purchase_rate)"],
filters = {'name': ('in', serial_no)}, as_list=1)[0][0])
outgoing_value = self.get_incoming_value_for_serial_nos(sle, serial_nos)
stock_value_change = -1 * outgoing_value
new_stock_qty = self.qty_after_transaction + actual_qty
@ -244,6 +243,36 @@ class update_entries_after(object):
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
currency=erpnext.get_company_currency(sle.company))
def get_incoming_value_for_serial_nos(self, sle, serial_nos):
# get rate from serial nos within same company
all_serial_nos = frappe.get_all("Serial No",
fields=["purchase_rate", "name", "company"],
filters = {'name': ('in', serial_nos)})
incoming_values = sum([flt(d.purchase_rate) for d in all_serial_nos if d.company==sle.company])
# Get rate for serial nos which has been transferred to other company
invalid_serial_nos = [d.name for d in all_serial_nos if d.company!=sle.company]
for serial_no in invalid_serial_nos:
incoming_rate = frappe.db.sql("""
select incoming_rate
from `tabStock Ledger Entry`
where
company = %s
and actual_qty > 0
and (serial_no = %s
or serial_no like %s
or serial_no like %s
or serial_no like %s
)
order by posting_date desc
limit 1
""", (sle.company, serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'))
incoming_values += flt(incoming_rate[0][0]) if incoming_rate else 0
return incoming_values
def get_moving_average_values(self, sle):
actual_qty = flt(sle.actual_qty)
new_stock_qty = flt(self.qty_after_transaction) + actual_qty

View File

@ -304,7 +304,7 @@ apps/erpnext/erpnext/selling/report/sales_partner_target_variance_based_on_item_
DocType: BOM,Total Cost,Gesamtkosten
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.js,Allocation Expired!,Zuteilung abgelaufen!
DocType: Soil Analysis,Ca/K,Ca / K
DocType: Leave Type,Maximum Carry Forwarded Leaves,Maximale Anzahl weitergeleiteter Blätter
DocType: Leave Type,Maximum Carry Forwarded Leaves,Obergrenze für übertragbaren Urlaub erreicht
DocType: Salary Slip,Employee Loan,MItarbeiterdarlehen
DocType: Additional Salary,HR-ADS-.YY.-.MM.-,HR-ADS-.YY .-. MM.-
DocType: Fee Schedule,Send Payment Request Email,Zahlungaufforderung per E-Mail versenden
@ -893,7 +893,7 @@ DocType: Supplier Scorecard Standing,Notify Other,Andere benachrichtigen
DocType: Vital Signs,Blood Pressure (systolic),Blutdruck (systolisch)
apps/erpnext/erpnext/controllers/buying_controller.py,{0} {1} is {2},{0} {1} ist {2}
DocType: Item Price,Valid Upto,Gültig bis
DocType: Leave Type,Expire Carry Forwarded Leaves (Days),Verfallsdatum für weitergeleitete Blätter (Tage)
DocType: Leave Type,Expire Carry Forwarded Leaves (Days),Verfallsdatum für übertragenen Urlaub (Tage)
DocType: Training Event,Workshop,Werkstatt
DocType: Supplier Scorecard Scoring Standing,Warn Purchase Orders,Warnung Bestellungen
apps/erpnext/erpnext/utilities/user_progress.py,List a few of your customers. They could be organizations or individuals.,Bitte ein paar Kunden angeben. Dies können Firmen oder Einzelpersonen sein.
@ -1103,7 +1103,7 @@ apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py,
DocType: Payroll Entry,Select Payment Account to make Bank Entry,Wählen Sie ein Zahlungskonto für die Buchung
apps/erpnext/erpnext/config/accounting.py,Opening and Closing,Öffnen und Schließen
DocType: Hotel Settings,Default Invoice Naming Series,Standard-Rechnungsnummernkreis
apps/erpnext/erpnext/utilities/activation.py,"Create Employee records to manage leaves, expense claims and payroll","Erstellen Sie Mitarbeiterdaten Blätter, Spesenabrechnung und Gehaltsabrechnung zu verwalten"
apps/erpnext/erpnext/utilities/activation.py,"Create Employee records to manage leaves, expense claims and payroll","Erstellen Sie Mitarbeiterdaten für Urlaubs, Spesenabrechnung und Gehaltsabrechnung zu verwalten"
apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js,An error occurred during the update process,Während des Aktualisierungsprozesses ist ein Fehler aufgetreten
DocType: Restaurant Reservation,Restaurant Reservation,Restaurant Reservierung
apps/erpnext/erpnext/public/js/hub/Sidebar.vue,Your Items,Ihre Artikel
@ -1548,7 +1548,7 @@ DocType: Share Transfer,To Shareholder,An den Aktionär
apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py,{0} against Bill {1} dated {2},{0} zu Rechnung {1} vom {2}
apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py,From State,Aus dem Staat
apps/erpnext/erpnext/utilities/user_progress.py,Setup Institution,Einrichtung Einrichtung
apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.py,Allocating leaves...,Blätter zuordnen...
apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.py,Allocating leaves...,Urlaub zuordnen...
DocType: Program Enrollment,Vehicle/Bus Number,Fahrzeug / Bus Nummer
apps/erpnext/erpnext/public/js/call_popup/call_popup.js,Create New Contact,Neuen Kontakt erstellen
apps/erpnext/erpnext/education/doctype/course/course.js,Course Schedule,Kurstermine
@ -1806,7 +1806,7 @@ apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py,Chemical,Chemische
DocType: Salary Component Account,Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.,"Standard Bank / Geldkonto wird automatisch in Gehalts Journal Entry aktualisiert werden, wenn dieser Modus ausgewählt ist."
DocType: Quiz,Latest Attempt,Letzter Versuch
DocType: Quiz Result,Quiz Result,Quiz-Ergebnis
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total leaves allocated is mandatory for Leave Type {0},Die Gesamtzahl der zugewiesenen Blätter ist für Abwesenheitsart {0} erforderlich.
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total leaves allocated is mandatory for Leave Type {0},Die Gesamtzahl der zugewiesenen Urlaube ist für Abwesenheitsart {0} erforderlich.
apps/erpnext/erpnext/controllers/sales_and_purchase_return.py,Row # {0}: Rate cannot be greater than the rate used in {1} {2},"Row # {0}: Die Rate kann nicht größer sein als die Rate, die in {1} {2}"
apps/erpnext/erpnext/utilities/user_progress.py,Meter,Meter
DocType: Workstation,Electricity Cost,Stromkosten
@ -1916,7 +1916,7 @@ apps/erpnext/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html,Go to
apps/erpnext/erpnext/templates/pages/order.js,Pay Remaining,Verbleibende Bezahlung
DocType: Purchase Invoice Item,Manufacturer,Hersteller
DocType: Landed Cost Item,Purchase Receipt Item,Kaufbeleg-Artikel
DocType: Leave Allocation,Total Leaves Encashed,Insgesamt Blätter umkränzt
DocType: Leave Allocation,Total Leaves Encashed,Summe ausbezahlter Urlaubstage
DocType: POS Profile,Sales Invoice Payment,Ausgangsrechnung-Zahlungen
DocType: Quality Inspection Template,Quality Inspection Template Name,Name der Qualitätsinspektionsvorlage
DocType: Project,First Email,Erste E-Mail
@ -2540,7 +2540,7 @@ Used for Taxes and Charges",Die Tabelle Steuerdetails wird aus dem Artikelstamm
apps/erpnext/erpnext/hr/doctype/employee/employee.py,Employee cannot report to himself.,Mitarbeiter können nicht an sich selbst Bericht erstatten
apps/erpnext/erpnext/templates/pages/order.html,Rate:,Bewertung:
DocType: Bank Account,Change this date manually to setup the next synchronization start date,"Ändern Sie dieses Datum manuell, um das nächste Startdatum für die Synchronisierung festzulegen"
DocType: Leave Type,Max Leaves Allowed,Max Blätter erlaubt
DocType: Leave Type,Max Leaves Allowed,Höchstzahl erlaubter Urlaubstage
DocType: Account,"If the account is frozen, entries are allowed to restricted users.","Wenn das Konto gesperrt ist, sind einem eingeschränkten Benutzerkreis Buchungen erlaubt."
DocType: Email Digest,Bank Balance,Kontostand
apps/erpnext/erpnext/controllers/accounts_controller.py,Accounting Entry for {0}: {1} can only be made in currency: {2},Eine Buchung für {0}: {1} kann nur in der Währung: {2} vorgenommen werden
@ -2990,7 +2990,7 @@ DocType: Student Group Creation Tool,Separate course based Group for every Batch
apps/erpnext/erpnext/config/support.py,Single unit of an Item.,Einzelnes Element eines Artikels
DocType: Fee Category,Fee Category,Gebührenkategorie
DocType: Agriculture Task,Next Business Day,Nächster Arbeitstag
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Allocated Leaves,Zugewiesene Blätter
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Allocated Leaves,Genehmigter Urlaub
DocType: Drug Prescription,Dosage by time interval,Dosierung nach Zeitintervall
apps/erpnext/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html,Total Taxable Value,Steuerpflichtiger Gesamtwert
DocType: Cash Flow Mapper,Section Header,Abschnitt Kopfzeile
@ -3774,10 +3774,10 @@ apps/erpnext/erpnext/public/js/templates/address_list.html,New Address,Neue Adre
DocType: Quality Inspection,Sample Size,Stichprobenumfang
apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py,Please enter Receipt Document,Bitte geben Sie Eingangsbeleg
apps/erpnext/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py,All items have already been invoiced,Alle Artikel sind bereits abgerechnet
apps/erpnext/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py,Leaves Taken,Blätter genommen
apps/erpnext/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py,Leaves Taken,Urlaubstage genommen
apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.py,Please specify a valid 'From Case No.',"Bitte eine eine gültige ""Von Fall Nr."" angeben"
apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center_tree.js,Further cost centers can be made under Groups but entries can be made against non-Groups,"Weitere Kostenstellen können unter Gruppen angelegt werden, aber Buchungen können zu nicht-Gruppen erstellt werden"
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period,Die insgesamt zugewiesenen Blätter sind mehr Tage als die maximale Zuweisung von {0} Abwesenheitsart für den Mitarbeiter {1} in der Periode
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period,Die insgesamt zugewiesenen Urlaubstage sind mehr Tage als die maximale Zuweisung von {0} Abwesenheitsart für den Mitarbeiter {1} in der Periode
DocType: Branch,Branch,Betrieb
apps/erpnext/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html,"Other outward supplies(Nil rated,Exempted)","Sonstige Auslandslieferungen (ohne Rating, ausgenommen)"
DocType: Soil Analysis,Ca/(K+Ca+Mg),Ca / (K + Ca + Mg)
@ -4097,7 +4097,7 @@ DocType: Work Order,Actual End Date,Tatsächliches Enddatum
DocType: Cash Flow Mapping,Is Finance Cost Adjustment,Ist Finanzkostenanpassung
DocType: BOM,Operating Cost (Company Currency),Betriebskosten (Gesellschaft Währung)
DocType: Authorization Rule,Applicable To (Role),Anwenden auf (Rolle)
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Pending Leaves,Ausstehende Blätter
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Pending Leaves,Schwebende Urlaubstage
DocType: BOM Update Tool,Replace BOM,Erstelle Stückliste
apps/erpnext/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py,Code {0} already exist,Code {0} existiert bereits
DocType: Patient Encounter,Procedures,Verfahren
@ -4342,7 +4342,7 @@ apps/erpnext/erpnext/accounts/report/asset_depreciations_and_balances/asset_depr
DocType: Sales Invoice,Is Return (Credit Note),ist Rücklieferung (Gutschrift)
apps/erpnext/erpnext/manufacturing/doctype/job_card/job_card.js,Start Job,Job starten
apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py,Serial no is required for the asset {0},Für Vermögenswert {0} ist eine Seriennr. Erforderlich.
DocType: Leave Control Panel,Allocate Leaves,Blätter zuweisen
DocType: Leave Control Panel,Allocate Leaves,Urlaubstage zuweisen
apps/erpnext/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py,Disabled template must not be default template,Deaktivierte Vorlage darf nicht Standardvorlage sein
DocType: Pricing Rule,Price or Product Discount,Preis- oder Produktrabatt
apps/erpnext/erpnext/manufacturing/doctype/production_plan/production_plan.py,For row {0}: Enter planned qty,Für Zeile {0}: Geben Sie die geplante Menge ein
@ -4440,7 +4440,7 @@ DocType: Loan,Loan Application,Kreditantrag
DocType: Crop,Scientific Name,Wissenschaftlicher Name
DocType: Healthcare Service Unit,Service Unit Type,Serviceeinheitstyp
DocType: Bank Account,Branch Code,Bankleitzahl / BIC
apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py,Total Leaves,insgesamt Blätter
apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py,Total Leaves,summe der Urlaubstage
DocType: Customer,"Reselect, if the chosen contact is edited after save","Wählen Sie erneut, wenn der ausgewählte Kontakt nach dem Speichern bearbeitet wird"
DocType: Quality Procedure,Parent Procedure,Übergeordnetes Verfahren
DocType: Patient Encounter,In print,in Druckbuchstaben
@ -5658,7 +5658,7 @@ apps/erpnext/erpnext/education/report/course_wise_assessment_report/course_wise_
DocType: Depreciation Schedule,Finance Book Id,Finanzbuch-ID
DocType: Item,Safety Stock,Sicherheitsbestand
DocType: Healthcare Settings,Healthcare Settings,Gesundheitswesen
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Total Allocated Leaves,Insgesamt zugeteilte Blätter
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Total Allocated Leaves,Insgesamt zugeteilte Urlaubstage
apps/erpnext/erpnext/projects/doctype/task/task.py,Progress % for a task cannot be more than 100.,Fortschritt-% eines Vorgangs darf nicht größer 100 sein.
DocType: Stock Reconciliation Item,Before reconciliation,Vor Ausgleich
apps/erpnext/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py,To {0},An {0}
@ -5769,7 +5769,7 @@ apps/erpnext/erpnext/accounts/doctype/bank_account/test_bank_account.py,BankAcco
DocType: Normal Test Items,Normal Test Items,Normale Testartikel
DocType: QuickBooks Migrator,Company Settings,Unternehmenseinstellungen
DocType: Additional Salary,Overwrite Salary Structure Amount,Gehaltsstruktur überschreiben
DocType: Leave Ledger Entry,Leaves,Blätter
DocType: Leave Ledger Entry,Leaves,Urlaubstage
DocType: Student Language,Student Language,Student Sprache
DocType: Cash Flow Mapping,Is Working Capital,Ist Arbeitskapital
apps/erpnext/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js,Submit Proof,Nachweis einreichen
@ -6362,7 +6362,7 @@ apps/erpnext/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax
DocType: Sales Partner,Contact Desc,Kontakt-Beschr.
DocType: Email Digest,Send regular summary reports via Email.,Regelmäßig zusammenfassende Berichte per E-Mail senden.
apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py,Please set default account in Expense Claim Type {0},Bitte setzen Sie Standardkonto in Kostenabrechnung Typ {0}
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Available Leaves,Verfügbare Blätter
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Available Leaves,Verfügbare Urlaubstage
DocType: Assessment Result,Student Name,Name des Studenten
DocType: Hub Tracked Item,Item Manager,Artikel-Manager
apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py,Payroll Payable,Payroll Kreditoren
@ -7508,7 +7508,7 @@ DocType: Pricing Rule,Percentage,Prozentsatz
apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py,Item {0} must be a stock Item,Artikel {0} muss ein Lagerartikel sein
DocType: Manufacturing Settings,Default Work In Progress Warehouse,Standard-Fertigungslager
apps/erpnext/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js,"Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?","Schedules für {0} Überlappungen, möchten Sie nach Überlappung überlappender Slots fortfahren?"
apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.js,Grant Leaves,Grant Blätter
apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.js,Grant Leaves,Urlaubstage gewähren
DocType: Restaurant,Default Tax Template,Standardsteuervorlage
apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py,{0} Students have been enrolled,{0} Studenten wurden angemeldet
DocType: Fees,Student Details,Studenten Details

Can't render this file because it is too large.

View File

@ -164,8 +164,8 @@ def validate_uom_is_integer(doc, uom_field, qty_fields, child_dt=None):
qty_fields = [qty_fields]
distinct_uoms = list(set([d.get(uom_field) for d in doc.get_all_children()]))
integer_uoms = filter(lambda uom: frappe.db.get_value("UOM", uom,
"must_be_whole_number", cache=True) or None, distinct_uoms)
integer_uoms = list(filter(lambda uom: frappe.db.get_value("UOM", uom,
"must_be_whole_number", cache=True) or None, distinct_uoms))
if not integer_uoms:
return