Merge branch 'develop' of https://github.com/frappe/erpnext into develop
This commit is contained in:
commit
2848ce4b87
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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({
|
||||
|
@ -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")
|
||||
|
@ -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"),
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
})
|
@ -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) {
|
||||
|
@ -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'
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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)]
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
@ -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",
|
||||
|
@ -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"))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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')
|
@ -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')
|
@ -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):
|
||||
|
@ -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')
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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)
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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()
|
@ -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}));
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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"):
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
@ -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"))
|
||||
|
||||
|
@ -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"
|
||||
}
|
@ -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')
|
||||
)
|
||||
},
|
||||
|
||||
|
@ -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]}`
|
||||
|
@ -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"))
|
||||
|
@ -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
|
@ -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"))
|
||||
|
@ -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(),
|
||||
},
|
||||
]
|
||||
};
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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.
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user